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