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