Annotation of suX/src/sux.c, revision 1.1.1.1.2.4
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.4! misho 6: * $Id: sux.c,v 1.1.1.1.2.3 2011/05/20 16:38: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.4! misho 244: 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 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:
1.1.1.1.2.4! misho 253: fflush(lf);
! 254:
1.1 misho 255: execve(cmd, args, environ);
256: if (args)
257: free(args);
258: Err("Error:: in exec() #%d - %s", errno, strerror(errno));
259: return -1;
260: }
261:
262:
263: int
264: main(int argc, char **argv)
265: {
1.1.1.1.2.3 misho 266: char ch, *str, szCfg[MAXPATHLEN], flg = 0;
1.1 misho 267: struct passwd *pass;
268: struct group *grp;
1.1.1.1.2.2 misho 269: FILE *f;
1.1 misho 270:
1.1.1.1.2.2 misho 271: initProg();
1.1 misho 272: strlcpy(szCfg, DEFAULT_CONFIG, sizeof szCfg);
273:
1.1.1.1.2.2 misho 274: while ((ch = getopt(argc, argv, "hvc:u:g:p:d:l:")) != -1)
1.1 misho 275: switch (ch) {
1.1.1.1.2.2 misho 276: case 'l':
1.1.1.1.2.3 misho 277: f = fopen(optarg, "a");
1.1.1.1.2.2 misho 278: if (!f) {
279: Err("Error:: logfile #%d - %s", errno, strerror(errno));
280: return 1;
281: } else
1.1.1.1.2.3 misho 282: if (fileno(lf) > 2)
1.1.1.1.2.2 misho 283: fclose(lf);
284: lf = f;
285: break;
1.1 misho 286: case 'd':
287: strlcpy(proc.proc_dir, optarg, sizeof proc.proc_dir);
288: flg |= 8;
289: break;
290: case 'p':
291: proc.proc_prio = strtol(optarg, NULL, 0);
292: flg |= 4;
293: break;
294: case 'g':
295: setgrent();
296: grp = getgrnam(optarg);
297: if (grp) {
298: proc.proc_gid = grp->gr_gid;
299: flg |= 2;
300: } else
301: Err("Error:: Group not found!");
302: endgrent();
303: break;
304: case 'u':
305: setpwent();
306: pass = getpwnam(optarg);
307: if (pass) {
308: proc.proc_uid = pass->pw_uid;
309: flg |= 1;
310: } else
311: Err("Error:: User not found!");
312: endpwent();
313: break;
314: case 'c':
315: strlcpy(szCfg, optarg, sizeof szCfg);
316: break;
317: case 'v':
318: Verbose++;
319: break;
320: case 'h':
321: default:
322: Usage();
1.1.1.1.2.3 misho 323: if (fileno(lf) > 2)
1.1.1.1.2.2 misho 324: fclose(lf);
1.1 misho 325: return 1;
326: }
327: argc -= optind;
328: argv += optind;
329: if (!argc) {
330: if (!(str = getenv("PATH_TRANSLATED"))) {
331: Usage();
1.1.1.1.2.3 misho 332: if (fileno(lf) > 2)
1.1.1.1.2.2 misho 333: fclose(lf);
1.1 misho 334: return 1;
335: } else
336: strlcpy(proc.proc_name, str, sizeof proc.proc_name);
337: } else
338: strlcpy(proc.proc_name, *argv, sizeof proc.proc_name);
339: Log(2, "Try to load config %s", szCfg);
340: if (LoadConfig(szCfg, &cfg)) {
341: Err("Error:: can`t load config #%d - %s\n", cfg_GetErrno(), cfg_GetError());
1.1.1.1.2.3 misho 342: if (fileno(lf) > 2)
1.1.1.1.2.2 misho 343: fclose(lf);
1.1 misho 344: return 2;
345: } else
346: if (LoadCfgData(flg) == -1) {
347: UnloadConfig(&cfg);
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: closelog();
351: return 3;
352: }
353: UnloadConfig(&cfg);
354:
355: if (Run(argv) == -1) {
1.1.1.1.2.3 misho 356: if (fileno(lf) > 2)
1.1.1.1.2.2 misho 357: fclose(lf);
1.1 misho 358: closelog();
359: return 4;
360: }
361:
1.1.1.1.2.3 misho 362: if (fileno(lf) > 2)
1.1.1.1.2.2 misho 363: fclose(lf);
1.1 misho 364: closelog();
365: return 0;
366: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>