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