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