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