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>