1: /*************************************************************************
2: * (C) 2011 AITNET - Sofia/Bulgaria - <office@aitbg.com>
3: * by Michael Pounov <misho@aitbg.com>
4: *
5: * $Author: misho $
6: * $Id: sux.c,v 1.5 2013/04/10 00:04:11 misho Exp $
7: *
8: *************************************************************************/
9: #include "global.h"
10:
11:
12: cfg_root_t cfg;
13: int Verbose;
14: struct tagProc proc;
15: FILE *lf;
16:
17:
18: static inline void
19: Log(int lvl, const char *fmt, ...)
20: {
21: va_list lst, cp;
22:
23: EVERBS(lvl) {
24: va_start(lst, fmt);
25: va_copy(cp, lst);
26: vfprintf(lf, fmt, lst);
27: va_end(lst);
28: fprintf(lf, "\n");
29: vsyslog(LOG_WARNING, fmt, cp);
30: va_end(cp);
31: }
32: }
33:
34: static inline void
35: Err(const char *fmt, ...)
36: {
37: va_list lst, cp;
38:
39: va_start(lst, fmt);
40: va_copy(cp, lst);
41: vfprintf(lf, fmt, lst);
42: va_end(lst);
43: fprintf(lf, "\n");
44: vsyslog(LOG_ERR, fmt, cp);
45: va_end(cp);
46: }
47:
48: static inline void
49: DumpProc(const char *txt)
50: {
51: Log(0, "%s:: uid:gid=%d:%d UID:GID=%d:%d Prio=%d Class=%s Name=%s Dir=%s Cmd=%s "
52: "Script=%s From=%s:%s Get=%s", txt ? txt : __func__,
53: geteuid(), getegid(), AIT_GET_I16(&proc.proc_uid),
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:
61: static int
62: initProg()
63: {
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);
68: AIT_INIT_VAL2(&proc.proc_dir, string);
69: AIT_INIT_VAL2(&proc.proc_name, string);
70: AIT_INIT_VAL2(&proc.proc_cmd, string);
71:
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);
79: return 0;
80: }
81:
82: static void
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
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"
99: " Syntax: %s [options] <program> [arguments]\n"
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"
104: "\t-C <directory>\t\t\tChroot to directory\n"
105: "\t-c <cfgfile>\t\t\tConfig file\n"
106: "\t-l <logfile>\t\t\tLog file path (default:/var/log/suX.log)\n"
107: "\t-o\t\t\t\tForce set UID,GID and Priority for program\n"
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;
116: struct passwd *pass;
117: short uid, gid;
118:
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 {
127: pass = getpwnam(getenv("SUX_USER"));
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();
136: }
137:
138: if (!(flg & SUX_GET_UID))
139: AIT_SET_I16(&proc.proc_uid, uid);
140: if (!(flg & SUX_GET_GID))
141: AIT_SET_I16(&proc.proc_gid, gid);
142:
143: return 0;
144: }
145:
146: static inline int
147: setClassDir()
148: {
149: struct passwd *pass;
150: int ret = 0;
151:
152: pass = getpwuid(AIT_GET_I16(&proc.proc_uid));
153: if (!pass) {
154: Err("Error:: User with this UID %d not found", AIT_GET_I16(&proc.proc_uid));
155: ret = -1;
156: } else {
157: AIT_SET_STR(&proc.proc_class, pass->pw_class);
158: AIT_SET_STR(&proc.proc_dir, pass->pw_dir);
159:
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: }
166: }
167:
168: endpwent();
169: return ret;
170: }
171:
172: static int
173: LoadCfgData(char flg)
174: {
175: const char *str;
176: char mode = 0;
177:
178: str = cfg_getAttribute(&cfg, "global", "mode");
179: if (!str) {
180: Err("Error:: Unknown mode ...");
181: return -1;
182: }
183: if (!strcasecmp(str, "SCRIPT") && getenv("SUX_USER")) {
184: mode = 1;
185: if (setUIDGID(flg, NULL) == -1)
186: return -1;
187: } else if (!strcasecmp(str, "FILE")) {
188: mode = 2;
189: if (setUIDGID(flg, AIT_GET_STR(&proc.proc_name)) == -1)
190: return -1;
191: } else if (!strcasecmp(str, "DIR")) {
192: mode = 3;
193: str = AIT_GET_STR(&proc.proc_dir) ? AIT_GET_STR(&proc.proc_dir) : ".";
194: if (setUIDGID(flg, str) == -1)
195: return -1;
196: } else {
197: Err("Error:: Unknown mode %s", str);
198: return -1;
199: }
200: if (!(flg & SUX_GET_PRIO)) {
201: str = cfg_getAttribute(&cfg, "global", "priority");
202: if (str)
203: AIT_SET_I32(&proc.proc_prio, strtol(str, NULL, 10));
204: }
205:
206: /* find associate extension */
207: str = strrchr(AIT_GET_STR(&proc.proc_name), '.');
208: if (str) {
209: str++;
210: str = (*str) ? str : "default";
211: switch (cfg_loadAttribute(&cfg, "associate", str, &proc.proc_cmd, NULL)) {
212: case -1:
213: ELIBERR(cfg);
214: return -1;
215: case 0:
216: cfg_loadAttribute(&cfg, "associate", "default",
217: &proc.proc_cmd, DEFAULT_CMD);
218: }
219: } else
220: AIT_SET_STR(&proc.proc_cmd, DEFAULT_CMD);
221:
222: return 0;
223: }
224:
225: static int
226: Run(char **argv, char flg)
227: {
228: char **args, *cmd;
229: array_t *acmd, *aarg;
230: int n;
231:
232: if (!argv)
233: return -1;
234:
235: n = array_Args(AIT_GET_STR(&proc.proc_cmd), 0, " \t", &acmd);
236: if (n < 1)
237: return -1;
238: if (!(aarg = array_From((const char***) &argv, 0))) {
239: array_Destroy(&acmd);
240: return -1;
241: } else if (*array(acmd, 0, char*) == '!') {
242: if (array_Grow(acmd, 0, 0)) {
243: array_Destroy(&aarg);
244: array_Destroy(&acmd);
245: return -1;
246: }
247: cmd = array(aarg, 0, char*);
248: } else
249: cmd = array(acmd, 0, char*);
250:
251: if (array_Concat(acmd, aarg) == -1) {
252: array_Destroy(&aarg);
253: array_Destroy(&acmd);
254: return -1;
255: }
256: array_Destroy(&aarg);
257: if (!(args = array_To(acmd))) {
258: array_Destroy(&acmd);
259: return -1;
260: }
261: array_Destroy(&acmd);
262:
263: if (setClassDir()) {
264: if (args)
265: e_free(args);
266: return -1;
267: }
268:
269: if (flg & SUX_GET_FORCE) {
270: if (setegid(AIT_GET_I16(&proc.proc_gid)) == -1)
271: goto err;
272: if (seteuid(AIT_GET_I16(&proc.proc_uid)) == -1)
273: goto err;
274: if (setpriority(PRIO_PROCESS, 0, AIT_GET_I32(&proc.proc_prio)) == -1)
275: goto err;
276: }
277:
278: DumpProc(__func__);
279:
280: EVERBS(3) {
281: char **el = args - 1;
282: while (*++el)
283: Log(3, "args: %s", *el);
284: }
285:
286: fflush(lf);
287:
288: execve(cmd, args, environ);
289: err:
290: ESYSERR(0);
291: if (args)
292: e_free(args);
293: return -1;
294: }
295:
296:
297: int
298: main(int argc, char **argv)
299: {
300: char ch, *str, *wrk, szCfg[MAXPATHLEN], **pp, flg = 0;
301: struct passwd *pass;
302: struct group *grp;
303: FILE *f;
304:
305: initProg();
306: strlcpy(szCfg, DEFAULT_CONFIG, sizeof szCfg);
307:
308: while ((ch = getopt(argc, argv, "hvoC:c:u:g:p:d:l:")) != -1)
309: switch (ch) {
310: case 'l':
311: f = fopen(optarg, "a");
312: if (!f) {
313: Err("Error:: logfile #%d - %s", errno, strerror(errno));
314: return 1;
315: } else
316: if (fileno(lf) > 2)
317: fclose(lf);
318: lf = f;
319: break;
320: case 'd':
321: AIT_SET_STR(&proc.proc_dir, optarg);
322: flg |= SUX_GET_DIR;
323: break;
324: case 'p':
325: AIT_SET_I32(&proc.proc_prio, strtol(optarg, NULL, 0));
326: flg |= SUX_GET_PRIO;
327: break;
328: case 'g':
329: setgrent();
330: grp = getgrnam(optarg);
331: if (grp) {
332: AIT_SET_I16(&proc.proc_gid, grp->gr_gid);
333: flg |= SUX_GET_GID;
334: } else
335: Err("Error:: Group not found!");
336: endgrent();
337: break;
338: case 'u':
339: setpwent();
340: pass = getpwnam(optarg);
341: if (pass) {
342: AIT_SET_I16(&proc.proc_uid, pass->pw_uid);
343: flg |= SUX_GET_UID;
344: } else
345: Err("Error:: User not found!");
346: endpwent();
347: break;
348: case 'c':
349: strlcpy(szCfg, optarg, sizeof szCfg);
350: break;
351: case 'C':
352: if (chroot(optarg) == -1)
353: Err("Error:: chroot to dir");
354: if ((str = getenv("PATH_TRANSLATED")))
355: if ((wrk = strstr(str, optarg)))
356: setenv("PATH_TRANSLATED", str + strlen(optarg), 42);
357: break;
358: case 'o':
359: flg |= SUX_GET_FORCE;
360: break;
361: case 'v':
362: e_incVerbose;
363: break;
364: case 'h':
365: default:
366: Usage();
367: endProg();
368: if (fileno(lf) > 2)
369: fclose(lf);
370: return 1;
371: }
372: argc -= optind;
373: argv += optind;
374:
375: EVERBS(2) {
376: for (pp = argv; *pp; pp++)
377: Log(2, "Args=%s\n", *pp);
378: for (pp = environ; *pp; pp++)
379: Log(2, "Envs=%s\n", *pp);
380: }
381:
382: if (!argc) {
383: if (!(str = getenv("PATH_TRANSLATED"))) {
384: Usage();
385: endProg();
386: if (fileno(lf) > 2)
387: fclose(lf);
388: return 1;
389: } else
390: AIT_SET_STR(&proc.proc_name, str);
391: } else
392: AIT_SET_STR(&proc.proc_name, *argv);
393: Log(2, "Try to load config %s", szCfg);
394: if (cfgLoadConfig(szCfg, &cfg)) {
395: ELIBERR(cfg);
396: endProg();
397: if (fileno(lf) > 2)
398: fclose(lf);
399: return 2;
400: } else
401: if (LoadCfgData(flg) == -1) {
402: cfgUnloadConfig(&cfg);
403: endProg();
404: if (fileno(lf) > 2)
405: fclose(lf);
406: closelog();
407: return 3;
408: }
409: cfgUnloadConfig(&cfg);
410:
411: if (Run(argv, flg) == -1) {
412: endProg();
413: if (fileno(lf) > 2)
414: fclose(lf);
415: closelog();
416: return 4;
417: }
418:
419: endProg();
420: if (fileno(lf) > 2)
421: fclose(lf);
422: closelog();
423: return 0;
424: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>