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