Annotation of suX/src/sux.c, revision 1.5.2.2

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.5.2.2 ! misho       6:  * $Id: sux.c,v 1.5.2.1 2015/06/15 15:52:34 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");
1.5.2.1   misho      29:                vsyslog(LOG_INFO, fmt, cp);
1.2       misho      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.5.2.1   misho      51:        Log(1, "%s:: uid:gid=%d:%d UID:GID=%d:%d Prio=%d Class=%s Name=%s Dir=%s Cmd=%s "
1.5       misho      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.5       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.5       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.5       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"
1.5.2.2 ! misho      99:                " Syntax: %s [options] <program|-> [arguments]\n"
1.1       misho     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.5       misho     116:        struct passwd *pass;
                    117:        short uid, gid;
1.1       misho     118: 
1.5       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 {
1.5.2.2 ! misho     127:                pass = getpwnam(getenv("SUX_USER") ? getenv("SUX_USER") : DEFAULT_SUX_USER);
1.5       misho     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.5       misho     139:                AIT_SET_I16(&proc.proc_uid, uid);
1.4       misho     140:        if (!(flg & SUX_GET_GID))
1.5       misho     141:                AIT_SET_I16(&proc.proc_gid, gid);
1.1       misho     142: 
                    143:        return 0;
                    144: }
                    145: 
                    146: static inline int
1.5       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.5       misho     155:                ret = -1;
                    156:        } else {
1.4       misho     157:                AIT_SET_STR(&proc.proc_class, pass->pw_class);
1.5       misho     158:                AIT_SET_STR(&proc.proc_dir, pass->pw_dir);
1.1       misho     159: 
1.5       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.5.2.1   misho     183:        if (!strcasecmp(str, "SCRIPT")) {
1.1       misho     184:                mode = 1;
1.5.2.1   misho     185:                if (setUIDGID(flg, (getenv("SUX_USER") ? NULL : getenv("PATH_TRANSLATED"))) == -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.5       misho     191:        } else if (!strcasecmp(str, "DIR")) {
1.1       misho     192:                mode = 3;
1.5       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.5       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.5.2.2 ! misho     241:        }
        !           242:        /* '!' exclude associated wrapper aka direct args execution */
        !           243:        if (*array(acmd, 0, char*) == '!') {
1.4       misho     244:                if (array_Grow(acmd, 0, 0)) {
                    245:                        array_Destroy(&aarg);
                    246:                        array_Destroy(&acmd);
1.1       misho     247:                        return -1;
                    248:                }
1.4       misho     249:                cmd = array(aarg, 0, char*);
1.1       misho     250:        } else
1.4       misho     251:                cmd = array(acmd, 0, char*);
1.1       misho     252: 
1.5.2.2 ! misho     253:        if (!(flg & SUX_GET_STDIN) && array_Concat(acmd, aarg) == -1) {
1.4       misho     254:                array_Destroy(&aarg);
                    255:                array_Destroy(&acmd);
1.1       misho     256:                return -1;
                    257:        }
1.4       misho     258:        array_Destroy(&aarg);
                    259:        if (!(args = array_To(acmd))) {
                    260:                array_Destroy(&acmd);
1.1       misho     261:                return -1;
                    262:        }
1.4       misho     263:        array_Destroy(&acmd);
1.1       misho     264: 
1.5       misho     265:        if (setClassDir()) {
1.1       misho     266:                if (args)
1.4       misho     267:                        e_free(args);
1.1       misho     268:                return -1;
                    269:        }
                    270: 
1.4       misho     271:        if (flg & SUX_GET_FORCE) {
                    272:                if (setegid(AIT_GET_I16(&proc.proc_gid)) == -1)
                    273:                        goto err;
                    274:                if (seteuid(AIT_GET_I16(&proc.proc_uid)) == -1)
                    275:                        goto err;
                    276:                if (setpriority(PRIO_PROCESS, 0, AIT_GET_I32(&proc.proc_prio)) == -1)
                    277:                        goto err;
1.1       misho     278:        }
1.2       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.5.2.1   misho     286:        DumpProc(__func__);
                    287: 
1.2       misho     288:        fflush(lf);
                    289: 
1.1       misho     290:        execve(cmd, args, environ);
1.4       misho     291: err:
                    292:        ESYSERR(0);
1.1       misho     293:        if (args)
1.4       misho     294:                e_free(args);
1.1       misho     295:        return -1;
                    296: }
                    297: 
                    298: 
                    299: int
                    300: main(int argc, char **argv)
                    301: {
1.3       misho     302:        char ch, *str, *wrk, szCfg[MAXPATHLEN], **pp, flg = 0;
1.1       misho     303:        struct passwd *pass;
                    304:        struct group *grp;
1.2       misho     305:        FILE *f;
1.1       misho     306: 
1.2       misho     307:        initProg();
1.1       misho     308:        strlcpy(szCfg, DEFAULT_CONFIG, sizeof szCfg);
                    309: 
1.4       misho     310:        while ((ch = getopt(argc, argv, "hvoC:c:u:g:p:d:l:")) != -1)
1.1       misho     311:                switch (ch) {
1.2       misho     312:                        case 'l':
                    313:                                f = fopen(optarg, "a");
                    314:                                if (!f) {
                    315:                                        Err("Error:: logfile #%d - %s", errno, strerror(errno));
                    316:                                        return 1;
                    317:                                } else
                    318:                                        if (fileno(lf) > 2)
                    319:                                                fclose(lf);
                    320:                                lf = f;
                    321:                                break;
1.1       misho     322:                        case 'd':
1.4       misho     323:                                AIT_SET_STR(&proc.proc_dir, optarg);
                    324:                                flg |= SUX_GET_DIR;
1.1       misho     325:                                break;
                    326:                        case 'p':
1.4       misho     327:                                AIT_SET_I32(&proc.proc_prio, strtol(optarg, NULL, 0));
                    328:                                flg |= SUX_GET_PRIO;
1.1       misho     329:                                break;
                    330:                        case 'g':
                    331:                                setgrent();
                    332:                                grp = getgrnam(optarg);
                    333:                                if (grp) {
1.4       misho     334:                                        AIT_SET_I16(&proc.proc_gid, grp->gr_gid);
                    335:                                        flg |= SUX_GET_GID;
1.1       misho     336:                                } else
                    337:                                        Err("Error:: Group not found!");
                    338:                                endgrent();
                    339:                                break;
                    340:                        case 'u':
                    341:                                setpwent();
                    342:                                pass = getpwnam(optarg);
                    343:                                if (pass) {
1.4       misho     344:                                        AIT_SET_I16(&proc.proc_uid, pass->pw_uid);
                    345:                                        flg |= SUX_GET_UID;
1.1       misho     346:                                } else
                    347:                                        Err("Error:: User not found!");
                    348:                                endpwent();
                    349:                                break;
                    350:                        case 'c':
                    351:                                strlcpy(szCfg, optarg, sizeof szCfg);
                    352:                                break;
1.3       misho     353:                        case 'C':
                    354:                                if (chroot(optarg) == -1)
                    355:                                        Err("Error:: chroot to dir");
                    356:                                if ((str = getenv("PATH_TRANSLATED")))
                    357:                                        if ((wrk = strstr(str, optarg)))
                    358:                                                setenv("PATH_TRANSLATED", str + strlen(optarg), 42);
                    359:                                break;
1.4       misho     360:                        case 'o':
                    361:                                flg |= SUX_GET_FORCE;
                    362:                                break;
1.1       misho     363:                        case 'v':
1.4       misho     364:                                e_incVerbose;
1.1       misho     365:                                break;
                    366:                        case 'h':
                    367:                        default:
                    368:                                Usage();
1.4       misho     369:                                endProg();
1.2       misho     370:                                if (fileno(lf) > 2)
                    371:                                        fclose(lf);
1.1       misho     372:                                return 1;
                    373:                }
                    374:        argc -= optind;
                    375:        argv += optind;
1.2       misho     376: 
1.4       misho     377:        EVERBS(2) {
1.2       misho     378:                for (pp = argv; *pp; pp++)
                    379:                        Log(2, "Args=%s\n", *pp);
                    380:                for (pp = environ; *pp; pp++)
                    381:                        Log(2, "Envs=%s\n", *pp);
                    382:        }
                    383: 
1.1       misho     384:        if (!argc) {
                    385:                if (!(str = getenv("PATH_TRANSLATED"))) {
                    386:                        Usage();
1.4       misho     387:                        endProg();
1.2       misho     388:                        if (fileno(lf) > 2)
                    389:                                fclose(lf);
1.1       misho     390:                        return 1;
                    391:                } else
1.4       misho     392:                        AIT_SET_STR(&proc.proc_name, str);
1.5.2.2 ! misho     393:        } else if (strcmp(*argv, "-"))
1.4       misho     394:                AIT_SET_STR(&proc.proc_name, *argv);
1.5.2.2 ! misho     395:        else {
        !           396:                flg |= SUX_GET_STDIN;
        !           397:                AIT_SET_STR(&proc.proc_name, "-.stdin");        /* hack for associate to stdin */
        !           398:        }
1.1       misho     399:        Log(2, "Try to load config %s", szCfg);
1.4       misho     400:        if (cfgLoadConfig(szCfg, &cfg)) {
                    401:                ELIBERR(cfg);
                    402:                endProg();
1.2       misho     403:                if (fileno(lf) > 2)
                    404:                        fclose(lf);
1.1       misho     405:                return 2;
                    406:        } else
                    407:                if (LoadCfgData(flg) == -1) {
1.4       misho     408:                        cfgUnloadConfig(&cfg);
                    409:                        endProg();
1.2       misho     410:                        if (fileno(lf) > 2)
                    411:                                fclose(lf);
1.1       misho     412:                        closelog();
                    413:                        return 3;
                    414:                }
1.4       misho     415:        cfgUnloadConfig(&cfg);
1.1       misho     416: 
1.4       misho     417:        if (Run(argv, flg) == -1) {
                    418:                endProg();
1.2       misho     419:                if (fileno(lf) > 2)
                    420:                        fclose(lf);
1.1       misho     421:                closelog();
                    422:                return 4;
                    423:        }
                    424: 
1.4       misho     425:        endProg();
1.2       misho     426:        if (fileno(lf) > 2)
                    427:                fclose(lf);
1.1       misho     428:        closelog();
                    429:        return 0;
                    430: }

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