/************************************************************************* * (C) 2011 AITNET - Sofia/Bulgaria - * by Michael Pounov * * $Author: misho $ * $Id: sux.c,v 1.1 2011/05/20 16:02:05 misho Exp $ * *************************************************************************/ #include "global.h" sl_config cfg; int Verbose; struct tagProc proc; static inline void Log(int lvl, const char *fmt, ...) { va_list lst; if (lvl <= Verbose) { va_start(lst, fmt); vsyslog(LOG_WARNING, fmt, lst); va_end(lst); } } static inline void Err(const char *fmt, ...) { va_list lst; va_start(lst, fmt); vsyslog(LOG_ERR, fmt, lst); va_end(lst); } static void initProg() { proc.proc_uid = getuid(); proc.proc_gid = getgid(); proc.proc_prio = getpriority(PRIO_PROCESS, 0); getcwd(proc.proc_dir, sizeof proc.proc_dir); openlog(PACKAGE_NAME, LOG_CONS | LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_USER); } static void Usage() { printf( " -= suX =- suExecutor designed for web based applicaions\n" "(C)`11 AITNET ltd - Sofia/Bulgaria - \n\n" " Syntax: %s [options] [arguments]\n" "\t-u \t\t\tUser for suID\n" "\t-g \t\t\tGroup for suID\n" "\t-p \t\tExecute with priority\n" "\t-d \t\t\tDirectory for suID\n" "\t-v\t\t\t\tVerbose, (more -v, more verbosity)\n" "\t-h\t\t\t\tThis help screen!\n\n", PACKAGE_NAME); } static inline int setUIDGID(char flg, const char *name) { struct stat sb; if (stat(name, &sb) == -1) { Err("Error:: %s stat #%d - %s", name, errno, strerror(errno)); return -1; } if (!(flg & 1)) proc.proc_uid = sb.st_uid; if (!(flg & 2)) proc.proc_gid = sb.st_gid; return 0; } static inline int SetClass() { login_cap_t *cap; struct passwd *pass; pass = getpwuid(proc.proc_uid); if (!pass) { Err("Error:: User with this UID %d not found", proc.proc_uid); endpwent(); return -1; } else strlcpy(proc.proc_class, pass->pw_class, sizeof proc.proc_class); cap = login_getclass(proc.proc_class); if (!cap) { Err("Error:: Cant get login class %s", proc.proc_class); endpwent(); return -1; } if (setusercontext(cap, pass, proc.proc_uid, LOGIN_SETALL)) { Err("Error:: Cant set login class %s", proc.proc_class); login_close(cap); endpwent(); return -1; } login_close(cap); endpwent(); return 0; } static int LoadCfgData(char flg) { char *str, mode = 0; str = (char*) cfg_GetAttribute(&cfg, CFG("global"), CFG("mode")); if (!str) { Err("Error:: Unknown mode ..."); return -1; } if (!strcasecmp(str, "SCRIPT")) { mode = 1; if (setUIDGID(flg, proc.proc_name) == -1) return -1; } else if (!strcasecmp(str, "FILE")) { mode = 2; if (setUIDGID(flg, proc.proc_name) == -1) return -1; } else if (!strcasecmp(str, "DIR") && (str = (char*) cfg_GetAttribute(&cfg, CFG("global"), CFG("directory")))) { mode = 3; if (!(flg & 8)) strlcpy(proc.proc_dir, str, sizeof proc.proc_dir); if (setUIDGID(flg, proc.proc_dir) == -1) return -1; } else { Err("Error:: Unknown mode %s", str); return -1; } if (!(flg & 4)) { str = (char*) cfg_GetAttribute(&cfg, CFG("global"), CFG("priority")); if (str) proc.proc_prio = strtol(str, NULL, 10); } /* find associate extension */ str = strrchr(proc.proc_name, '.'); if (str) { str++; str = (*str) ? str : "default"; switch (cfg_LoadAttribute(&cfg, CFG("associate"), CFG(str), CFG(proc.proc_cmd), sizeof proc.proc_cmd, NULL)) { case -1: Err("Error:: can`t load attribute #%d - %s\n", cfg_GetErrno(), cfg_GetError()); return -1; case 0: cfg_LoadAttribute(&cfg, CFG("associate"), CFG("default"), CFG(proc.proc_cmd), sizeof proc.proc_cmd, DEFAULT_CMD); } } else strlcpy(proc.proc_cmd, DEFAULT_CMD, sizeof proc.proc_cmd); return 0; } static int Run(char **argv) { char **args, *cmd; array_t *acmd, *aarg; int n; if (!argv) return -1; n = io_arrayMake(proc.proc_cmd, 0, " \t", &acmd); if (n < 1) return -1; if (!(aarg = io_arrayFrom((const char**) argv, 0))) { io_arrayDestroy(&acmd); return -1; } else if (*io_arrayGet(acmd, 0, char*) == '!') { if (io_arrayGrow(acmd, 0)) { io_arrayDestroy(&aarg); io_arrayDestroy(&acmd); return -1; } cmd = io_arrayGet(aarg, 0, char*); } else cmd = io_arrayGet(acmd, 0, char*); if (io_arrayConcat(acmd, aarg) == -1) { io_arrayDestroy(&aarg); io_arrayDestroy(&acmd); return -1; } io_arrayDestroy(&aarg); if (!(args = io_arrayTo(acmd))) { io_arrayDestroy(&acmd); return -1; } io_arrayDestroy(&acmd); if (SetClass()) { if (args) free(args); return -1; } if (setgid(proc.proc_gid) == -1) { Err("Error:: setgid #%d - %s\n", errno, strerror(errno)); if (args) free(args); return -1; } if (setuid(proc.proc_uid) == -1) { Err("Error:: setuid #%d - %s\n", errno, strerror(errno)); if (args) free(args); return -1; } if (setpriority(PRIO_PROCESS, 0, proc.proc_prio) == -1) { Err("Error:: setpriority #%d - %s\n", errno, strerror(errno)); if (args) free(args); return -1; } if (3 <= Verbose) { char **el = args - 1; while (*++el) Log(3, "args: %s", *el); } execve(cmd, args, environ); if (args) free(args); Err("Error:: in exec() #%d - %s", errno, strerror(errno)); return -1; } int main(int argc, char **argv) { char ch, *str, szCfg[MAXPATHLEN], flg = 0; struct passwd *pass; struct group *grp; initProg(*argv); strlcpy(szCfg, DEFAULT_CONFIG, sizeof szCfg); while ((ch = getopt(argc, argv, "hvc:u:g:p:d:")) != -1) switch (ch) { case 'd': strlcpy(proc.proc_dir, optarg, sizeof proc.proc_dir); flg |= 8; break; case 'p': proc.proc_prio = strtol(optarg, NULL, 0); flg |= 4; break; case 'g': setgrent(); grp = getgrnam(optarg); if (grp) { proc.proc_gid = grp->gr_gid; flg |= 2; } else Err("Error:: Group not found!"); endgrent(); break; case 'u': setpwent(); pass = getpwnam(optarg); if (pass) { proc.proc_uid = pass->pw_uid; flg |= 1; } else Err("Error:: User not found!"); endpwent(); break; case 'c': strlcpy(szCfg, optarg, sizeof szCfg); flg++; break; case 'v': Verbose++; break; case 'h': default: Usage(); return 1; } argc -= optind; argv += optind; if (!argc) { if (!(str = getenv("PATH_TRANSLATED"))) { Usage(); return 1; } else strlcpy(proc.proc_name, str, sizeof proc.proc_name); } else strlcpy(proc.proc_name, *argv, sizeof proc.proc_name); Log(2, "Try to load config %s", szCfg); if (LoadConfig(szCfg, &cfg)) { Err("Error:: can`t load config #%d - %s\n", cfg_GetErrno(), cfg_GetError()); return 2; } else if (LoadCfgData(flg) == -1) { UnloadConfig(&cfg); closelog(); return 3; } UnloadConfig(&cfg); Log(1, "UID:GID=%d:%d Prio=%d Class=%s Name=%s Dir=%s Cmd=%s\n", proc.proc_uid, proc.proc_gid, proc.proc_prio, proc.proc_class, proc.proc_name, proc.proc_dir, proc.proc_cmd); if (Run(argv) == -1) { closelog(); return 4; } closelog(); return 0; }