Annotation of suX/src/sux.c, revision 1.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.4     ! misho       6:  * $Id: sux.c,v 1.3.2.6 2013/04/09 15:51:11 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: {
        !            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.4     ! misho      63:        char d[MAXPATHLEN];
        !            64: 
        !            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));
        !            68:        AIT_INIT_VAL2(&proc.proc_class, string);
        !            69:        getcwd(d, sizeof d);
        !            70:        AIT_SET_STR(&proc.proc_dir, d);
        !            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.4     ! 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.4     ! 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.4     ! misho     119:                ESYSERR(0);
1.1       misho     120:                return -1;
                    121:        }
                    122: 
1.4     ! misho     123:        if (!(flg & SUX_GET_UID))
        !           124:                AIT_SET_I16(&proc.proc_uid, sb.st_uid);
        !           125:        if (!(flg & SUX_GET_GID))
        !           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:        struct passwd *pass;
1.4     ! misho     135:        int ret = 0;
1.1       misho     136: 
1.4     ! misho     137:        pass = getpwuid(AIT_GET_I16(&proc.proc_uid));
1.1       misho     138:        if (!pass) {
1.4     ! 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.4     ! misho     143:                AIT_SET_STR(&proc.proc_class, pass->pw_class);
1.1       misho     144: 
1.4     ! misho     145:        if (setusercontext(NULL, pass, AIT_GET_I16(&proc.proc_uid), 
        !           146:                                LOGIN_SETRESOURCES | LOGIN_SETGROUP | LOGIN_SETLOGIN | 
        !           147:                                LOGIN_SETPRIORITY)) {
        !           148:                Err("Error:: Cant set login class %s", AIT_GET_STR(&proc.proc_class));
        !           149:                ret = -1;
1.1       misho     150:        }
                    151: 
                    152:        endpwent();
1.4     ! misho     153:        return ret;
1.1       misho     154: }
                    155: 
                    156: static int
                    157: LoadCfgData(char flg)
                    158: {
1.4     ! misho     159:        const char *str;
        !           160:        char mode = 0;
1.1       misho     161: 
1.4     ! misho     162:        str = cfg_getAttribute(&cfg, "global", "mode");
1.1       misho     163:        if (!str) {
                    164:                Err("Error:: Unknown mode ...");
                    165:                return -1;
                    166:        }
                    167:        if (!strcasecmp(str, "SCRIPT")) {
                    168:                mode = 1;
1.4     ! misho     169:                if (setUIDGID(flg, AIT_GET_STR(&proc.proc_name)) == -1)
1.1       misho     170:                        return -1;
                    171:        } else if (!strcasecmp(str, "FILE")) {
                    172:                mode = 2;
1.4     ! misho     173:                if (setUIDGID(flg, AIT_GET_STR(&proc.proc_name)) == -1)
1.1       misho     174:                        return -1;
                    175:        } else if (!strcasecmp(str, "DIR") && 
1.4     ! misho     176:                        (str = cfg_getAttribute(&cfg, "global", "directory"))) {
1.1       misho     177:                mode = 3;
1.4     ! misho     178:                if (!(flg & SUX_GET_DIR))
        !           179:                        AIT_SET_STR(&proc.proc_dir, str);
1.1       misho     180: 
1.4     ! misho     181:                if (setUIDGID(flg, AIT_GET_STR(&proc.proc_dir)) == -1)
1.1       misho     182:                        return -1;
                    183:        } else {
                    184:                Err("Error:: Unknown mode %s", str);
                    185:                return -1;
                    186:        }
1.4     ! misho     187:        if (!(flg & SUX_GET_PRIO)) {
        !           188:                str = cfg_getAttribute(&cfg, "global", "priority");
1.1       misho     189:                if (str)
1.4     ! misho     190:                        AIT_SET_I32(&proc.proc_prio, strtol(str, NULL, 10));
1.1       misho     191:        }
                    192: 
                    193:        /* find associate extension */
1.4     ! misho     194:        str = strrchr(AIT_GET_STR(&proc.proc_name), '.');
1.1       misho     195:        if (str) {
                    196:                str++;
                    197:                str = (*str) ? str : "default";
1.4     ! misho     198:                switch (cfg_loadAttribute(&cfg, "associate", str, &proc.proc_cmd, NULL)) {
1.1       misho     199:                        case -1:
1.4     ! misho     200:                                ELIBERR(cfg);
1.1       misho     201:                                return -1;
                    202:                        case 0:
1.4     ! misho     203:                                cfg_loadAttribute(&cfg, "associate", "default", &proc.proc_cmd, DEFAULT_CMD);
1.1       misho     204:                }
                    205:        } else
1.4     ! misho     206:                AIT_SET_STR(&proc.proc_cmd, DEFAULT_CMD);
1.1       misho     207: 
                    208:        return 0;
                    209: }
                    210: 
                    211: static int
1.4     ! misho     212: Run(char **argv, char flg)
1.1       misho     213: {
                    214:        char **args, *cmd;
                    215:        array_t *acmd, *aarg;
                    216:        int n;
                    217: 
                    218:        if (!argv)
                    219:                return -1;
                    220: 
1.4     ! misho     221:        n = array_Args(AIT_GET_STR(&proc.proc_cmd), 0, " \t", &acmd);
1.1       misho     222:        if (n < 1)
                    223:                return -1;
1.4     ! misho     224:        if (!(aarg = array_From((const char***) &argv, 0))) {
        !           225:                array_Destroy(&acmd);
1.1       misho     226:                return -1;
1.4     ! misho     227:        } else if (*array(acmd, 0, char*) == '!') {
        !           228:                if (array_Grow(acmd, 0, 0)) {
        !           229:                        array_Destroy(&aarg);
        !           230:                        array_Destroy(&acmd);
1.1       misho     231:                        return -1;
                    232:                }
1.4     ! misho     233:                cmd = array(aarg, 0, char*);
1.1       misho     234:        } else
1.4     ! misho     235:                cmd = array(acmd, 0, char*);
1.1       misho     236: 
1.4     ! misho     237:        if (array_Concat(acmd, aarg) == -1) {
        !           238:                array_Destroy(&aarg);
        !           239:                array_Destroy(&acmd);
1.1       misho     240:                return -1;
                    241:        }
1.4     ! misho     242:        array_Destroy(&aarg);
        !           243:        if (!(args = array_To(acmd))) {
        !           244:                array_Destroy(&acmd);
1.1       misho     245:                return -1;
                    246:        }
1.4     ! misho     247:        array_Destroy(&acmd);
1.1       misho     248: 
                    249:        if (SetClass()) {
                    250:                if (args)
1.4     ! misho     251:                        e_free(args);
1.1       misho     252:                return -1;
                    253:        }
                    254: 
1.4     ! misho     255:        if (flg & SUX_GET_FORCE) {
        !           256:                /*
        !           257:                if (setegid(AIT_GET_I16(&proc.proc_gid)) == -1)
        !           258:                        goto err;
        !           259:                if (seteuid(AIT_GET_I16(&proc.proc_uid)) == -1)
        !           260:                        goto err;
        !           261:                        */
        !           262:                if (setpriority(PRIO_PROCESS, 0, AIT_GET_I32(&proc.proc_prio)) == -1)
        !           263:                        goto err;
1.1       misho     264:        }
1.2       misho     265: 
1.4     ! misho     266:        DumpProc(__func__);
1.1       misho     267: 
1.4     ! misho     268:        EVERBS(3) {
1.1       misho     269:                char **el = args - 1;
                    270:                while (*++el)
                    271:                        Log(3, "args: %s", *el);
                    272:        }
                    273: 
1.2       misho     274:        fflush(lf);
                    275: 
1.1       misho     276:        execve(cmd, args, environ);
1.4     ! misho     277: err:
        !           278:        ESYSERR(0);
1.1       misho     279:        if (args)
1.4     ! misho     280:                e_free(args);
1.1       misho     281:        return -1;
                    282: }
                    283: 
                    284: 
                    285: int
                    286: main(int argc, char **argv)
                    287: {
1.3       misho     288:        char ch, *str, *wrk, szCfg[MAXPATHLEN], **pp, flg = 0;
1.1       misho     289:        struct passwd *pass;
                    290:        struct group *grp;
1.2       misho     291:        FILE *f;
1.1       misho     292: 
1.2       misho     293:        initProg();
1.1       misho     294:        strlcpy(szCfg, DEFAULT_CONFIG, sizeof szCfg);
                    295: 
1.4     ! misho     296:        while ((ch = getopt(argc, argv, "hvoC:c:u:g:p:d:l:")) != -1)
1.1       misho     297:                switch (ch) {
1.2       misho     298:                        case 'l':
                    299:                                f = fopen(optarg, "a");
                    300:                                if (!f) {
                    301:                                        Err("Error:: logfile #%d - %s", errno, strerror(errno));
                    302:                                        return 1;
                    303:                                } else
                    304:                                        if (fileno(lf) > 2)
                    305:                                                fclose(lf);
                    306:                                lf = f;
                    307:                                break;
1.1       misho     308:                        case 'd':
1.4     ! misho     309:                                AIT_SET_STR(&proc.proc_dir, optarg);
        !           310:                                flg |= SUX_GET_DIR;
1.1       misho     311:                                break;
                    312:                        case 'p':
1.4     ! misho     313:                                AIT_SET_I32(&proc.proc_prio, strtol(optarg, NULL, 0));
        !           314:                                flg |= SUX_GET_PRIO;
1.1       misho     315:                                break;
                    316:                        case 'g':
                    317:                                setgrent();
                    318:                                grp = getgrnam(optarg);
                    319:                                if (grp) {
1.4     ! misho     320:                                        AIT_SET_I16(&proc.proc_gid, grp->gr_gid);
        !           321:                                        flg |= SUX_GET_GID;
1.1       misho     322:                                } else
                    323:                                        Err("Error:: Group not found!");
                    324:                                endgrent();
                    325:                                break;
                    326:                        case 'u':
                    327:                                setpwent();
                    328:                                pass = getpwnam(optarg);
                    329:                                if (pass) {
1.4     ! misho     330:                                        AIT_SET_I16(&proc.proc_uid, pass->pw_uid);
        !           331:                                        flg |= SUX_GET_UID;
1.1       misho     332:                                } else
                    333:                                        Err("Error:: User not found!");
                    334:                                endpwent();
                    335:                                break;
                    336:                        case 'c':
                    337:                                strlcpy(szCfg, optarg, sizeof szCfg);
                    338:                                break;
1.3       misho     339:                        case 'C':
                    340:                                if (chroot(optarg) == -1)
                    341:                                        Err("Error:: chroot to dir");
                    342:                                if ((str = getenv("PATH_TRANSLATED")))
                    343:                                        if ((wrk = strstr(str, optarg)))
                    344:                                                setenv("PATH_TRANSLATED", str + strlen(optarg), 42);
                    345:                                break;
1.4     ! misho     346:                        case 'o':
        !           347:                                flg |= SUX_GET_FORCE;
        !           348:                                break;
1.1       misho     349:                        case 'v':
1.4     ! misho     350:                                e_incVerbose;
1.1       misho     351:                                break;
                    352:                        case 'h':
                    353:                        default:
                    354:                                Usage();
1.4     ! misho     355:                                endProg();
1.2       misho     356:                                if (fileno(lf) > 2)
                    357:                                        fclose(lf);
1.1       misho     358:                                return 1;
                    359:                }
                    360:        argc -= optind;
                    361:        argv += optind;
1.2       misho     362: 
1.4     ! misho     363:        EVERBS(2) {
1.2       misho     364:                for (pp = argv; *pp; pp++)
                    365:                        Log(2, "Args=%s\n", *pp);
                    366:                for (pp = environ; *pp; pp++)
                    367:                        Log(2, "Envs=%s\n", *pp);
                    368:        }
                    369: 
1.1       misho     370:        if (!argc) {
                    371:                if (!(str = getenv("PATH_TRANSLATED"))) {
                    372:                        Usage();
1.4     ! misho     373:                        endProg();
1.2       misho     374:                        if (fileno(lf) > 2)
                    375:                                fclose(lf);
1.1       misho     376:                        return 1;
                    377:                } else
1.4     ! misho     378:                        AIT_SET_STR(&proc.proc_name, str);
1.1       misho     379:        } else
1.4     ! misho     380:                AIT_SET_STR(&proc.proc_name, *argv);
1.1       misho     381:        Log(2, "Try to load config %s", szCfg);
1.4     ! misho     382:        if (cfgLoadConfig(szCfg, &cfg)) {
        !           383:                ELIBERR(cfg);
        !           384:                endProg();
1.2       misho     385:                if (fileno(lf) > 2)
                    386:                        fclose(lf);
1.1       misho     387:                return 2;
                    388:        } else
                    389:                if (LoadCfgData(flg) == -1) {
1.4     ! misho     390:                        cfgUnloadConfig(&cfg);
        !           391:                        endProg();
1.2       misho     392:                        if (fileno(lf) > 2)
                    393:                                fclose(lf);
1.1       misho     394:                        closelog();
                    395:                        return 3;
                    396:                }
1.4     ! misho     397:        cfgUnloadConfig(&cfg);
1.1       misho     398: 
1.4     ! misho     399:        if (Run(argv, flg) == -1) {
        !           400:                endProg();
1.2       misho     401:                if (fileno(lf) > 2)
                    402:                        fclose(lf);
1.1       misho     403:                closelog();
                    404:                return 4;
                    405:        }
                    406: 
1.4     ! misho     407:        endProg();
1.2       misho     408:        if (fileno(lf) > 2)
                    409:                fclose(lf);
1.1       misho     410:        closelog();
                    411:        return 0;
                    412: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>