Annotation of suX/src/sux.c, revision 1.4.2.1
1.1 misho 1: /*************************************************************************
2: * (C) 2011 AITNET - Sofia/Bulgaria - <office@aitbg.com>
3: * by Michael Pounov <misho@aitbg.com>
4: *
5: * $Author: misho $
1.4.2.1 ! misho 6: * $Id: sux.c,v 1.4 2013/04/09 15:59:44 misho Exp $
1.1 misho 7: *
8: *************************************************************************/
9: #include "global.h"
10:
11:
1.4 misho 12: cfg_root_t cfg;
1.1 misho 13: int Verbose;
14: struct tagProc proc;
1.2 misho 15: FILE *lf;
1.1 misho 16:
17:
18: static inline void
19: Log(int lvl, const char *fmt, ...)
20: {
1.2 misho 21: va_list lst, cp;
1.1 misho 22:
1.4 misho 23: EVERBS(lvl) {
1.1 misho 24: va_start(lst, fmt);
1.2 misho 25: va_copy(cp, lst);
26: vfprintf(lf, fmt, lst);
1.1 misho 27: va_end(lst);
1.2 misho 28: fprintf(lf, "\n");
29: vsyslog(LOG_WARNING, fmt, cp);
30: va_end(cp);
1.1 misho 31: }
32: }
33:
34: static inline void
35: Err(const char *fmt, ...)
36: {
1.2 misho 37: va_list lst, cp;
1.1 misho 38:
39: va_start(lst, fmt);
1.2 misho 40: va_copy(cp, lst);
41: vfprintf(lf, fmt, lst);
1.1 misho 42: va_end(lst);
1.2 misho 43: fprintf(lf, "\n");
44: vsyslog(LOG_ERR, fmt, cp);
45: va_end(cp);
1.1 misho 46: }
47:
1.4 misho 48: static inline void
49: DumpProc(const char *txt)
50: {
1.4.2.1 ! misho 51: Log(0, "%s:: uid:gid=%d:%d UID:GID=%d:%d Prio=%d Class=%s Name=%s Dir=%s Cmd=%s "
! 52: "Script=%s From=%s:%s Get=%s", txt ? txt : __func__,
! 53: geteuid(), getegid(), AIT_GET_I16(&proc.proc_uid),
1.4 misho 54: AIT_GET_I16(&proc.proc_gid), AIT_GET_I32(&proc.proc_prio),
55: AIT_GET_STR(&proc.proc_class), AIT_GET_STR(&proc.proc_name),
56: AIT_GET_STR(&proc.proc_dir), AIT_GET_STR(&proc.proc_cmd),
57: getenv("PATH_TRANSLATED"), getenv("REMOTE_ADDR"),
58: getenv("REMOTE_PORT"), getenv("REQUEST_URI"));
59: }
60:
1.4.2.1 ! misho 61: static int
1.1 misho 62: initProg()
63: {
1.4 misho 64: AIT_SET_I16(&proc.proc_uid, getuid());
65: AIT_SET_I16(&proc.proc_gid, getgid());
66: AIT_SET_I32(&proc.proc_prio, getpriority(PRIO_PROCESS, 0));
67: AIT_INIT_VAL2(&proc.proc_class, string);
1.4.2.1 ! misho 68: AIT_INIT_VAL2(&proc.proc_dir, string);
1.4 misho 69: AIT_INIT_VAL2(&proc.proc_name, string);
70: AIT_INIT_VAL2(&proc.proc_cmd, string);
1.1 misho 71:
1.2 misho 72: #if 0
73: lf = fopen(DEFAULT_LOG, "a");
74: if (!lf)
75: #endif
76: lf = stdout;
77:
78: openlog(PACKAGE_NAME, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER);
1.4.2.1 ! misho 79: return 0;
1.1 misho 80: }
81:
82: static void
1.4 misho 83: endProg()
84: {
85: AIT_FREE_VAL(&proc.proc_uid);
86: AIT_FREE_VAL(&proc.proc_gid);
87: AIT_FREE_VAL(&proc.proc_prio);
88: AIT_FREE_VAL(&proc.proc_class);
89: AIT_FREE_VAL(&proc.proc_dir);
90: AIT_FREE_VAL(&proc.proc_name);
91: AIT_FREE_VAL(&proc.proc_cmd);
92: }
93:
94: static void
1.1 misho 95: Usage()
96: {
97: printf( " -= suX =- suExecutor designed for web based applicaions\n"
98: "(C)`11 AITNET ltd - Sofia/Bulgaria - <office@aitnet.org>\n\n"
99: " Syntax: %s [options] <program> [arguments]\n"
100: "\t-u <user>\t\t\tUser for suID\n"
101: "\t-g <group>\t\t\tGroup for suID\n"
102: "\t-p <priority (-20..20)>\t\tExecute with priority\n"
103: "\t-d <directory>\t\t\tDirectory for suID\n"
1.3 misho 104: "\t-C <directory>\t\t\tChroot to directory\n"
105: "\t-c <cfgfile>\t\t\tConfig file\n"
1.2 misho 106: "\t-l <logfile>\t\t\tLog file path (default:/var/log/suX.log)\n"
1.4 misho 107: "\t-o\t\t\t\tForce set UID,GID and Priority for program\n"
1.1 misho 108: "\t-v\t\t\t\tVerbose, (more -v, more verbosity)\n"
109: "\t-h\t\t\t\tThis help screen!\n\n", PACKAGE_NAME);
110: }
111:
112: static inline int
113: setUIDGID(char flg, const char *name)
114: {
115: struct stat sb;
1.4.2.1 ! misho 116: struct passwd *pass;
! 117: short uid, gid;
1.1 misho 118:
1.4.2.1 ! misho 119: if (name) {
! 120: if (stat(name, &sb) == -1) {
! 121: ESYSERR(0);
! 122: return -1;
! 123: }
! 124: uid = sb.st_uid;
! 125: gid = sb.st_gid;
! 126: } else {
! 127: pass = getpwnam(getenv("SUX_USER"));
! 128: if (!pass) {
! 129: Err("Error:: User %s not found", getenv("SUX_USER"));
! 130: endpwent();
! 131: return -1;
! 132: }
! 133: uid = pass->pw_uid;
! 134: gid = pass->pw_gid;
! 135: endpwent();
1.1 misho 136: }
137:
1.4 misho 138: if (!(flg & SUX_GET_UID))
1.4.2.1 ! misho 139: AIT_SET_I16(&proc.proc_uid, uid);
1.4 misho 140: if (!(flg & SUX_GET_GID))
1.4.2.1 ! misho 141: AIT_SET_I16(&proc.proc_gid, gid);
1.1 misho 142:
143: return 0;
144: }
145:
146: static inline int
1.4.2.1 ! misho 147: setClassDir()
1.1 misho 148: {
149: struct passwd *pass;
1.4 misho 150: int ret = 0;
1.1 misho 151:
1.4 misho 152: pass = getpwuid(AIT_GET_I16(&proc.proc_uid));
1.1 misho 153: if (!pass) {
1.4 misho 154: Err("Error:: User with this UID %d not found", AIT_GET_I16(&proc.proc_uid));
1.4.2.1 ! misho 155: ret = -1;
! 156: } else {
1.4 misho 157: AIT_SET_STR(&proc.proc_class, pass->pw_class);
1.4.2.1 ! misho 158: AIT_SET_STR(&proc.proc_dir, pass->pw_dir);
1.1 misho 159:
1.4.2.1 ! misho 160: if (setusercontext(NULL, pass, AIT_GET_I16(&proc.proc_uid),
! 161: LOGIN_SETLOGIN | LOGIN_SETGROUP | LOGIN_SETUSER |
! 162: LOGIN_SETPRIORITY | LOGIN_SETRESOURCES)) {
! 163: Err("Error:: Can't set login class %s", AIT_GET_STR(&proc.proc_class));
! 164: ret = -1;
! 165: }
1.1 misho 166: }
167:
168: endpwent();
1.4 misho 169: return ret;
1.1 misho 170: }
171:
172: static int
173: LoadCfgData(char flg)
174: {
1.4 misho 175: const char *str;
176: char mode = 0;
1.1 misho 177:
1.4 misho 178: str = cfg_getAttribute(&cfg, "global", "mode");
1.1 misho 179: if (!str) {
180: Err("Error:: Unknown mode ...");
181: return -1;
182: }
1.4.2.1 ! misho 183: if (!strcasecmp(str, "SCRIPT") && getenv("SUX_USER")) {
1.1 misho 184: mode = 1;
1.4.2.1 ! misho 185: if (setUIDGID(flg, NULL) == -1)
1.1 misho 186: return -1;
187: } else if (!strcasecmp(str, "FILE")) {
188: mode = 2;
1.4 misho 189: if (setUIDGID(flg, AIT_GET_STR(&proc.proc_name)) == -1)
1.1 misho 190: return -1;
1.4.2.1 ! misho 191: } else if (!strcasecmp(str, "DIR")) {
1.1 misho 192: mode = 3;
1.4.2.1 ! misho 193: str = AIT_GET_STR(&proc.proc_dir) ? AIT_GET_STR(&proc.proc_dir) : ".";
! 194: if (setUIDGID(flg, str) == -1)
1.1 misho 195: return -1;
196: } else {
197: Err("Error:: Unknown mode %s", str);
198: return -1;
199: }
1.4 misho 200: if (!(flg & SUX_GET_PRIO)) {
201: str = cfg_getAttribute(&cfg, "global", "priority");
1.1 misho 202: if (str)
1.4 misho 203: AIT_SET_I32(&proc.proc_prio, strtol(str, NULL, 10));
1.1 misho 204: }
205:
206: /* find associate extension */
1.4 misho 207: str = strrchr(AIT_GET_STR(&proc.proc_name), '.');
1.1 misho 208: if (str) {
209: str++;
210: str = (*str) ? str : "default";
1.4 misho 211: switch (cfg_loadAttribute(&cfg, "associate", str, &proc.proc_cmd, NULL)) {
1.1 misho 212: case -1:
1.4 misho 213: ELIBERR(cfg);
1.1 misho 214: return -1;
215: case 0:
1.4.2.1 ! misho 216: cfg_loadAttribute(&cfg, "associate", "default",
! 217: &proc.proc_cmd, DEFAULT_CMD);
1.1 misho 218: }
219: } else
1.4 misho 220: AIT_SET_STR(&proc.proc_cmd, DEFAULT_CMD);
1.1 misho 221:
222: return 0;
223: }
224:
225: static int
1.4 misho 226: Run(char **argv, char flg)
1.1 misho 227: {
228: char **args, *cmd;
229: array_t *acmd, *aarg;
230: int n;
231:
232: if (!argv)
233: return -1;
234:
1.4 misho 235: n = array_Args(AIT_GET_STR(&proc.proc_cmd), 0, " \t", &acmd);
1.1 misho 236: if (n < 1)
237: return -1;
1.4 misho 238: if (!(aarg = array_From((const char***) &argv, 0))) {
239: array_Destroy(&acmd);
1.1 misho 240: return -1;
1.4 misho 241: } else if (*array(acmd, 0, char*) == '!') {
242: if (array_Grow(acmd, 0, 0)) {
243: array_Destroy(&aarg);
244: array_Destroy(&acmd);
1.1 misho 245: return -1;
246: }
1.4 misho 247: cmd = array(aarg, 0, char*);
1.1 misho 248: } else
1.4 misho 249: cmd = array(acmd, 0, char*);
1.1 misho 250:
1.4 misho 251: if (array_Concat(acmd, aarg) == -1) {
252: array_Destroy(&aarg);
253: array_Destroy(&acmd);
1.1 misho 254: return -1;
255: }
1.4 misho 256: array_Destroy(&aarg);
257: if (!(args = array_To(acmd))) {
258: array_Destroy(&acmd);
1.1 misho 259: return -1;
260: }
1.4 misho 261: array_Destroy(&acmd);
1.1 misho 262:
1.4.2.1 ! misho 263: if (setClassDir()) {
1.1 misho 264: if (args)
1.4 misho 265: e_free(args);
1.1 misho 266: return -1;
267: }
268:
1.4 misho 269: if (flg & SUX_GET_FORCE) {
270: if (setegid(AIT_GET_I16(&proc.proc_gid)) == -1)
271: goto err;
272: if (seteuid(AIT_GET_I16(&proc.proc_uid)) == -1)
273: goto err;
274: if (setpriority(PRIO_PROCESS, 0, AIT_GET_I32(&proc.proc_prio)) == -1)
275: goto err;
1.1 misho 276: }
1.2 misho 277:
1.4 misho 278: DumpProc(__func__);
1.1 misho 279:
1.4 misho 280: EVERBS(3) {
1.1 misho 281: char **el = args - 1;
282: while (*++el)
283: Log(3, "args: %s", *el);
284: }
285:
1.2 misho 286: fflush(lf);
287:
1.1 misho 288: execve(cmd, args, environ);
1.4 misho 289: err:
290: ESYSERR(0);
1.1 misho 291: if (args)
1.4 misho 292: e_free(args);
1.1 misho 293: return -1;
294: }
295:
296:
297: int
298: main(int argc, char **argv)
299: {
1.3 misho 300: char ch, *str, *wrk, szCfg[MAXPATHLEN], **pp, flg = 0;
1.1 misho 301: struct passwd *pass;
302: struct group *grp;
1.2 misho 303: FILE *f;
1.1 misho 304:
1.2 misho 305: initProg();
1.1 misho 306: strlcpy(szCfg, DEFAULT_CONFIG, sizeof szCfg);
307:
1.4 misho 308: while ((ch = getopt(argc, argv, "hvoC:c:u:g:p:d:l:")) != -1)
1.1 misho 309: switch (ch) {
1.2 misho 310: case 'l':
311: f = fopen(optarg, "a");
312: if (!f) {
313: Err("Error:: logfile #%d - %s", errno, strerror(errno));
314: return 1;
315: } else
316: if (fileno(lf) > 2)
317: fclose(lf);
318: lf = f;
319: break;
1.1 misho 320: case 'd':
1.4 misho 321: AIT_SET_STR(&proc.proc_dir, optarg);
322: flg |= SUX_GET_DIR;
1.1 misho 323: break;
324: case 'p':
1.4 misho 325: AIT_SET_I32(&proc.proc_prio, strtol(optarg, NULL, 0));
326: flg |= SUX_GET_PRIO;
1.1 misho 327: break;
328: case 'g':
329: setgrent();
330: grp = getgrnam(optarg);
331: if (grp) {
1.4 misho 332: AIT_SET_I16(&proc.proc_gid, grp->gr_gid);
333: flg |= SUX_GET_GID;
1.1 misho 334: } else
335: Err("Error:: Group not found!");
336: endgrent();
337: break;
338: case 'u':
339: setpwent();
340: pass = getpwnam(optarg);
341: if (pass) {
1.4 misho 342: AIT_SET_I16(&proc.proc_uid, pass->pw_uid);
343: flg |= SUX_GET_UID;
1.1 misho 344: } else
345: Err("Error:: User not found!");
346: endpwent();
347: break;
348: case 'c':
349: strlcpy(szCfg, optarg, sizeof szCfg);
350: break;
1.3 misho 351: case 'C':
352: if (chroot(optarg) == -1)
353: Err("Error:: chroot to dir");
354: if ((str = getenv("PATH_TRANSLATED")))
355: if ((wrk = strstr(str, optarg)))
356: setenv("PATH_TRANSLATED", str + strlen(optarg), 42);
357: break;
1.4 misho 358: case 'o':
359: flg |= SUX_GET_FORCE;
360: break;
1.1 misho 361: case 'v':
1.4 misho 362: e_incVerbose;
1.1 misho 363: break;
364: case 'h':
365: default:
366: Usage();
1.4 misho 367: endProg();
1.2 misho 368: if (fileno(lf) > 2)
369: fclose(lf);
1.1 misho 370: return 1;
371: }
372: argc -= optind;
373: argv += optind;
1.2 misho 374:
1.4 misho 375: EVERBS(2) {
1.2 misho 376: for (pp = argv; *pp; pp++)
377: Log(2, "Args=%s\n", *pp);
378: for (pp = environ; *pp; pp++)
379: Log(2, "Envs=%s\n", *pp);
380: }
381:
1.1 misho 382: if (!argc) {
383: if (!(str = getenv("PATH_TRANSLATED"))) {
384: Usage();
1.4 misho 385: endProg();
1.2 misho 386: if (fileno(lf) > 2)
387: fclose(lf);
1.1 misho 388: return 1;
389: } else
1.4 misho 390: AIT_SET_STR(&proc.proc_name, str);
1.1 misho 391: } else
1.4 misho 392: AIT_SET_STR(&proc.proc_name, *argv);
1.1 misho 393: Log(2, "Try to load config %s", szCfg);
1.4 misho 394: if (cfgLoadConfig(szCfg, &cfg)) {
395: ELIBERR(cfg);
396: endProg();
1.2 misho 397: if (fileno(lf) > 2)
398: fclose(lf);
1.1 misho 399: return 2;
400: } else
401: if (LoadCfgData(flg) == -1) {
1.4 misho 402: cfgUnloadConfig(&cfg);
403: endProg();
1.2 misho 404: if (fileno(lf) > 2)
405: fclose(lf);
1.1 misho 406: closelog();
407: return 3;
408: }
1.4 misho 409: cfgUnloadConfig(&cfg);
1.1 misho 410:
1.4 misho 411: if (Run(argv, flg) == -1) {
412: endProg();
1.2 misho 413: if (fileno(lf) > 2)
414: fclose(lf);
1.1 misho 415: closelog();
416: return 4;
417: }
418:
1.4 misho 419: endProg();
1.2 misho 420: if (fileno(lf) > 2)
421: fclose(lf);
1.1 misho 422: closelog();
423: return 0;
424: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>