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