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