Annotation of suX/src/sux.c, revision 1.7
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.7 ! misho 6: * $Id: sux.c,v 1.6.2.1 2015/06/18 22:15:47 misho Exp $
1.1 misho 7: *
1.7 ! misho 8: *************************************************************************
! 9: The ELWIX and AITNET software is distributed under the following
! 10: terms:
! 11:
! 12: All of the documentation and software included in the ELWIX and AITNET
! 13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
! 14:
! 15: Copyright 2004 - 2015
! 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
! 17:
! 18: Redistribution and use in source and binary forms, with or without
! 19: modification, are permitted provided that the following conditions
! 20: are met:
! 21: 1. Redistributions of source code must retain the above copyright
! 22: notice, this list of conditions and the following disclaimer.
! 23: 2. Redistributions in binary form must reproduce the above copyright
! 24: notice, this list of conditions and the following disclaimer in the
! 25: documentation and/or other materials provided with the distribution.
! 26: 3. All advertising materials mentioning features or use of this software
! 27: must display the following acknowledgement:
! 28: This product includes software developed by Michael Pounov <misho@elwix.org>
! 29: ELWIX - Embedded LightWeight unIX and its contributors.
! 30: 4. Neither the name of AITNET nor the names of its contributors
! 31: may be used to endorse or promote products derived from this software
! 32: without specific prior written permission.
! 33:
! 34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
! 35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 44: SUCH DAMAGE.
! 45: */
1.1 misho 46: #include "global.h"
47:
48:
1.4 misho 49: cfg_root_t cfg;
1.1 misho 50: int Verbose;
51: struct tagProc proc;
1.2 misho 52: FILE *lf;
1.1 misho 53:
54:
55: static inline void
56: Log(int lvl, const char *fmt, ...)
57: {
1.2 misho 58: va_list lst, cp;
1.1 misho 59:
1.4 misho 60: EVERBS(lvl) {
1.1 misho 61: va_start(lst, fmt);
1.2 misho 62: va_copy(cp, lst);
63: vfprintf(lf, fmt, lst);
1.1 misho 64: va_end(lst);
1.2 misho 65: fprintf(lf, "\n");
1.6 misho 66: vsyslog(LOG_INFO, fmt, cp);
1.2 misho 67: va_end(cp);
1.1 misho 68: }
69: }
70:
71: static inline void
72: Err(const char *fmt, ...)
73: {
1.2 misho 74: va_list lst, cp;
1.1 misho 75:
76: va_start(lst, fmt);
1.2 misho 77: va_copy(cp, lst);
78: vfprintf(lf, fmt, lst);
1.1 misho 79: va_end(lst);
1.2 misho 80: fprintf(lf, "\n");
81: vsyslog(LOG_ERR, fmt, cp);
82: va_end(cp);
1.1 misho 83: }
84:
1.4 misho 85: static inline void
86: DumpProc(const char *txt)
87: {
1.6 misho 88: Log(1, "%s:: uid:gid=%d:%d UID:GID=%d:%d Prio=%d Class=%s Name=%s Dir=%s Cmd=%s "
1.5 misho 89: "Script=%s From=%s:%s Get=%s", txt ? txt : __func__,
90: geteuid(), getegid(), AIT_GET_I16(&proc.proc_uid),
1.4 misho 91: AIT_GET_I16(&proc.proc_gid), AIT_GET_I32(&proc.proc_prio),
92: AIT_GET_STR(&proc.proc_class), AIT_GET_STR(&proc.proc_name),
93: AIT_GET_STR(&proc.proc_dir), AIT_GET_STR(&proc.proc_cmd),
94: getenv("PATH_TRANSLATED"), getenv("REMOTE_ADDR"),
95: getenv("REMOTE_PORT"), getenv("REQUEST_URI"));
96: }
97:
1.5 misho 98: static int
1.1 misho 99: initProg()
100: {
1.4 misho 101: AIT_SET_I16(&proc.proc_uid, getuid());
102: AIT_SET_I16(&proc.proc_gid, getgid());
103: AIT_SET_I32(&proc.proc_prio, getpriority(PRIO_PROCESS, 0));
104: AIT_INIT_VAL2(&proc.proc_class, string);
1.5 misho 105: AIT_INIT_VAL2(&proc.proc_dir, string);
1.4 misho 106: AIT_INIT_VAL2(&proc.proc_name, string);
107: AIT_INIT_VAL2(&proc.proc_cmd, string);
1.1 misho 108:
1.2 misho 109: #if 0
110: lf = fopen(DEFAULT_LOG, "a");
111: if (!lf)
112: #endif
113: lf = stdout;
114:
115: openlog(PACKAGE_NAME, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER);
1.5 misho 116: return 0;
1.1 misho 117: }
118:
119: static void
1.4 misho 120: endProg()
121: {
122: AIT_FREE_VAL(&proc.proc_uid);
123: AIT_FREE_VAL(&proc.proc_gid);
124: AIT_FREE_VAL(&proc.proc_prio);
125: AIT_FREE_VAL(&proc.proc_class);
126: AIT_FREE_VAL(&proc.proc_dir);
127: AIT_FREE_VAL(&proc.proc_name);
128: AIT_FREE_VAL(&proc.proc_cmd);
129: }
130:
131: static void
1.1 misho 132: Usage()
133: {
134: printf( " -= suX =- suExecutor designed for web based applicaions\n"
135: "(C)`11 AITNET ltd - Sofia/Bulgaria - <office@aitnet.org>\n\n"
1.6 misho 136: " Syntax: %s [options] <program|-> [arguments]\n"
1.1 misho 137: "\t-u <user>\t\t\tUser for suID\n"
138: "\t-g <group>\t\t\tGroup for suID\n"
139: "\t-p <priority (-20..20)>\t\tExecute with priority\n"
140: "\t-d <directory>\t\t\tDirectory for suID\n"
1.3 misho 141: "\t-C <directory>\t\t\tChroot to directory\n"
142: "\t-c <cfgfile>\t\t\tConfig file\n"
1.2 misho 143: "\t-l <logfile>\t\t\tLog file path (default:/var/log/suX.log)\n"
1.4 misho 144: "\t-o\t\t\t\tForce set UID,GID and Priority for program\n"
1.1 misho 145: "\t-v\t\t\t\tVerbose, (more -v, more verbosity)\n"
146: "\t-h\t\t\t\tThis help screen!\n\n", PACKAGE_NAME);
147: }
148:
149: static inline int
150: setUIDGID(char flg, const char *name)
151: {
152: struct stat sb;
1.5 misho 153: struct passwd *pass;
154: short uid, gid;
1.1 misho 155:
1.5 misho 156: if (name) {
157: if (stat(name, &sb) == -1) {
158: ESYSERR(0);
159: return -1;
160: }
161: uid = sb.st_uid;
162: gid = sb.st_gid;
163: } else {
1.6 misho 164: pass = getpwnam(getenv("SUX_USER") ? getenv("SUX_USER") : DEFAULT_SUX_USER);
1.5 misho 165: if (!pass) {
166: Err("Error:: User %s not found", getenv("SUX_USER"));
167: endpwent();
168: return -1;
169: }
170: uid = pass->pw_uid;
171: gid = pass->pw_gid;
172: endpwent();
1.1 misho 173: }
174:
1.4 misho 175: if (!(flg & SUX_GET_UID))
1.5 misho 176: AIT_SET_I16(&proc.proc_uid, uid);
1.4 misho 177: if (!(flg & SUX_GET_GID))
1.5 misho 178: AIT_SET_I16(&proc.proc_gid, gid);
1.1 misho 179:
180: return 0;
181: }
182:
183: static inline int
1.5 misho 184: setClassDir()
1.1 misho 185: {
186: struct passwd *pass;
1.4 misho 187: int ret = 0;
1.1 misho 188:
1.4 misho 189: pass = getpwuid(AIT_GET_I16(&proc.proc_uid));
1.1 misho 190: if (!pass) {
1.4 misho 191: Err("Error:: User with this UID %d not found", AIT_GET_I16(&proc.proc_uid));
1.5 misho 192: ret = -1;
193: } else {
1.4 misho 194: AIT_SET_STR(&proc.proc_class, pass->pw_class);
1.5 misho 195: AIT_SET_STR(&proc.proc_dir, pass->pw_dir);
1.1 misho 196:
1.5 misho 197: if (setusercontext(NULL, pass, AIT_GET_I16(&proc.proc_uid),
198: LOGIN_SETLOGIN | LOGIN_SETGROUP | LOGIN_SETUSER |
199: LOGIN_SETPRIORITY | LOGIN_SETRESOURCES)) {
200: Err("Error:: Can't set login class %s", AIT_GET_STR(&proc.proc_class));
201: ret = -1;
202: }
1.1 misho 203: }
204:
205: endpwent();
1.4 misho 206: return ret;
1.1 misho 207: }
208:
209: static int
210: LoadCfgData(char flg)
211: {
1.4 misho 212: const char *str;
213: char mode = 0;
1.1 misho 214:
1.4 misho 215: str = cfg_getAttribute(&cfg, "global", "mode");
1.1 misho 216: if (!str) {
217: Err("Error:: Unknown mode ...");
218: return -1;
219: }
1.6 misho 220: if (!strcasecmp(str, "SCRIPT")) {
1.1 misho 221: mode = 1;
1.6 misho 222: if (setUIDGID(flg, (getenv("SUX_USER") ? NULL : getenv("PATH_TRANSLATED"))) == -1)
1.1 misho 223: return -1;
224: } else if (!strcasecmp(str, "FILE")) {
225: mode = 2;
1.4 misho 226: if (setUIDGID(flg, AIT_GET_STR(&proc.proc_name)) == -1)
1.1 misho 227: return -1;
1.5 misho 228: } else if (!strcasecmp(str, "DIR")) {
1.1 misho 229: mode = 3;
1.5 misho 230: str = AIT_GET_STR(&proc.proc_dir) ? AIT_GET_STR(&proc.proc_dir) : ".";
231: if (setUIDGID(flg, str) == -1)
1.1 misho 232: return -1;
233: } else {
234: Err("Error:: Unknown mode %s", str);
235: return -1;
236: }
1.4 misho 237: if (!(flg & SUX_GET_PRIO)) {
238: str = cfg_getAttribute(&cfg, "global", "priority");
1.1 misho 239: if (str)
1.4 misho 240: AIT_SET_I32(&proc.proc_prio, strtol(str, NULL, 10));
1.1 misho 241: }
242:
243: /* find associate extension */
1.4 misho 244: str = strrchr(AIT_GET_STR(&proc.proc_name), '.');
1.1 misho 245: if (str) {
246: str++;
247: str = (*str) ? str : "default";
1.4 misho 248: switch (cfg_loadAttribute(&cfg, "associate", str, &proc.proc_cmd, NULL)) {
1.1 misho 249: case -1:
1.4 misho 250: ELIBERR(cfg);
1.1 misho 251: return -1;
252: case 0:
1.5 misho 253: cfg_loadAttribute(&cfg, "associate", "default",
254: &proc.proc_cmd, DEFAULT_CMD);
1.1 misho 255: }
256: } else
1.4 misho 257: AIT_SET_STR(&proc.proc_cmd, DEFAULT_CMD);
1.1 misho 258:
259: return 0;
260: }
261:
262: static int
1.4 misho 263: Run(char **argv, char flg)
1.1 misho 264: {
265: char **args, *cmd;
266: array_t *acmd, *aarg;
267: int n;
268:
269: if (!argv)
270: return -1;
271:
1.4 misho 272: n = array_Args(AIT_GET_STR(&proc.proc_cmd), 0, " \t", &acmd);
1.1 misho 273: if (n < 1)
274: return -1;
1.4 misho 275: if (!(aarg = array_From((const char***) &argv, 0))) {
276: array_Destroy(&acmd);
1.1 misho 277: return -1;
1.6 misho 278: }
279: /* '!' exclude associated wrapper aka direct args execution */
280: if (*array(acmd, 0, char*) == '!') {
1.4 misho 281: if (array_Grow(acmd, 0, 0)) {
282: array_Destroy(&aarg);
283: array_Destroy(&acmd);
1.1 misho 284: return -1;
285: }
1.4 misho 286: cmd = array(aarg, 0, char*);
1.1 misho 287: } else
1.4 misho 288: cmd = array(acmd, 0, char*);
1.1 misho 289:
1.6 misho 290: if (!(flg & SUX_GET_STDIN) && array_Concat(acmd, aarg) == -1) {
1.4 misho 291: array_Destroy(&aarg);
292: array_Destroy(&acmd);
1.1 misho 293: return -1;
294: }
1.4 misho 295: array_Destroy(&aarg);
296: if (!(args = array_To(acmd))) {
297: array_Destroy(&acmd);
1.1 misho 298: return -1;
299: }
1.4 misho 300: array_Destroy(&acmd);
1.1 misho 301:
1.5 misho 302: if (setClassDir()) {
1.1 misho 303: if (args)
1.4 misho 304: e_free(args);
1.1 misho 305: return -1;
306: }
307:
1.4 misho 308: if (flg & SUX_GET_FORCE) {
309: if (setegid(AIT_GET_I16(&proc.proc_gid)) == -1)
310: goto err;
311: if (seteuid(AIT_GET_I16(&proc.proc_uid)) == -1)
312: goto err;
313: if (setpriority(PRIO_PROCESS, 0, AIT_GET_I32(&proc.proc_prio)) == -1)
314: goto err;
1.1 misho 315: }
1.2 misho 316:
1.4 misho 317: EVERBS(3) {
1.1 misho 318: char **el = args - 1;
319: while (*++el)
320: Log(3, "args: %s", *el);
321: }
322:
1.6 misho 323: DumpProc(__func__);
324:
1.2 misho 325: fflush(lf);
326:
1.1 misho 327: execve(cmd, args, environ);
1.4 misho 328: err:
329: ESYSERR(0);
1.1 misho 330: if (args)
1.4 misho 331: e_free(args);
1.1 misho 332: return -1;
333: }
334:
335:
336: int
337: main(int argc, char **argv)
338: {
1.3 misho 339: char ch, *str, *wrk, szCfg[MAXPATHLEN], **pp, flg = 0;
1.1 misho 340: struct passwd *pass;
341: struct group *grp;
1.2 misho 342: FILE *f;
1.1 misho 343:
1.2 misho 344: initProg();
1.1 misho 345: strlcpy(szCfg, DEFAULT_CONFIG, sizeof szCfg);
346:
1.4 misho 347: while ((ch = getopt(argc, argv, "hvoC:c:u:g:p:d:l:")) != -1)
1.1 misho 348: switch (ch) {
1.2 misho 349: case 'l':
350: f = fopen(optarg, "a");
351: if (!f) {
352: Err("Error:: logfile #%d - %s", errno, strerror(errno));
353: return 1;
354: } else
355: if (fileno(lf) > 2)
356: fclose(lf);
357: lf = f;
358: break;
1.1 misho 359: case 'd':
1.4 misho 360: AIT_SET_STR(&proc.proc_dir, optarg);
361: flg |= SUX_GET_DIR;
1.1 misho 362: break;
363: case 'p':
1.4 misho 364: AIT_SET_I32(&proc.proc_prio, strtol(optarg, NULL, 0));
365: flg |= SUX_GET_PRIO;
1.1 misho 366: break;
367: case 'g':
368: setgrent();
369: grp = getgrnam(optarg);
370: if (grp) {
1.4 misho 371: AIT_SET_I16(&proc.proc_gid, grp->gr_gid);
372: flg |= SUX_GET_GID;
1.1 misho 373: } else
374: Err("Error:: Group not found!");
375: endgrent();
376: break;
377: case 'u':
378: setpwent();
379: pass = getpwnam(optarg);
380: if (pass) {
1.4 misho 381: AIT_SET_I16(&proc.proc_uid, pass->pw_uid);
382: flg |= SUX_GET_UID;
1.1 misho 383: } else
384: Err("Error:: User not found!");
385: endpwent();
386: break;
387: case 'c':
388: strlcpy(szCfg, optarg, sizeof szCfg);
389: break;
1.3 misho 390: case 'C':
391: if (chroot(optarg) == -1)
392: Err("Error:: chroot to dir");
393: if ((str = getenv("PATH_TRANSLATED")))
394: if ((wrk = strstr(str, optarg)))
395: setenv("PATH_TRANSLATED", str + strlen(optarg), 42);
396: break;
1.4 misho 397: case 'o':
398: flg |= SUX_GET_FORCE;
399: break;
1.1 misho 400: case 'v':
1.4 misho 401: e_incVerbose;
1.1 misho 402: break;
403: case 'h':
404: default:
405: Usage();
1.4 misho 406: endProg();
1.2 misho 407: if (fileno(lf) > 2)
408: fclose(lf);
1.1 misho 409: return 1;
410: }
411: argc -= optind;
412: argv += optind;
1.2 misho 413:
1.4 misho 414: EVERBS(2) {
1.2 misho 415: for (pp = argv; *pp; pp++)
416: Log(2, "Args=%s\n", *pp);
417: for (pp = environ; *pp; pp++)
418: Log(2, "Envs=%s\n", *pp);
419: }
420:
1.1 misho 421: if (!argc) {
422: if (!(str = getenv("PATH_TRANSLATED"))) {
423: Usage();
1.4 misho 424: endProg();
1.2 misho 425: if (fileno(lf) > 2)
426: fclose(lf);
1.1 misho 427: return 1;
428: } else
1.4 misho 429: AIT_SET_STR(&proc.proc_name, str);
1.6 misho 430: } else if (strcmp(*argv, "-"))
1.4 misho 431: AIT_SET_STR(&proc.proc_name, *argv);
1.6 misho 432: else {
433: flg |= SUX_GET_STDIN;
434: AIT_SET_STR(&proc.proc_name, "-.stdin"); /* hack for associate to stdin */
435: }
1.1 misho 436: Log(2, "Try to load config %s", szCfg);
1.4 misho 437: if (cfgLoadConfig(szCfg, &cfg)) {
438: ELIBERR(cfg);
439: endProg();
1.2 misho 440: if (fileno(lf) > 2)
441: fclose(lf);
1.1 misho 442: return 2;
443: } else
444: if (LoadCfgData(flg) == -1) {
1.4 misho 445: cfgUnloadConfig(&cfg);
446: endProg();
1.2 misho 447: if (fileno(lf) > 2)
448: fclose(lf);
1.1 misho 449: closelog();
450: return 3;
451: }
1.4 misho 452: cfgUnloadConfig(&cfg);
1.1 misho 453:
1.4 misho 454: if (Run(argv, flg) == -1) {
455: endProg();
1.2 misho 456: if (fileno(lf) > 2)
457: fclose(lf);
1.1 misho 458: closelog();
459: return 4;
460: }
461:
1.4 misho 462: endProg();
1.2 misho 463: if (fileno(lf) > 2)
464: fclose(lf);
1.1 misho 465: closelog();
466: return 0;
467: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>