Annotation of suX/src/sux.c, revision 1.3.2.1
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.1 ! misho 6: * $Id: sux.c,v 1.3 2013/04/09 07:37:50 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.1 misho 53: proc.proc_uid = getuid();
54: proc.proc_gid = getgid();
55: 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))
96: proc.proc_uid = sb.st_uid;
97: if (!(flg & 2))
98: proc.proc_gid = sb.st_gid;
99:
100: return 0;
101: }
102:
103: static inline int
104: SetClass()
105: {
106: login_cap_t *cap;
107: struct passwd *pass;
108:
109: pass = getpwuid(proc.proc_uid);
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:
124: if (setusercontext(cap, pass, 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)
170: proc.proc_prio = strtol(str, NULL, 10);
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':
305: proc.proc_prio = strtol(optarg, NULL, 0);
306: flg |= 4;
307: break;
308: case 'g':
309: setgrent();
310: grp = getgrnam(optarg);
311: if (grp) {
312: proc.proc_gid = grp->gr_gid;
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) {
322: proc.proc_uid = pass->pw_uid;
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>