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

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