File:  [ELWIX - Embedded LightWeight unIX -] / suX / src / sux.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri May 20 16:02:05 2011 UTC (13 years, 1 month ago) by misho
Branches: misho
CVS tags: sux2_0, start
suX WWW wrapper suexec helper project

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>