File:  [ELWIX - Embedded LightWeight unIX -] / suX / src / sux.c
Revision 1.3.2.3: download - view: text, annotated - select for diffs - revision graph
Tue Apr 9 08:56:57 2013 UTC (11 years, 3 months ago) by misho
Branches: sux3_0
Diff to: branchpoint 1.3: preferred, unified
added new option

    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.3.2.3 2013/04/09 08:56:57 misho Exp $
    7:  *
    8:  *************************************************************************/
    9: #include "global.h"
   10: 
   11: 
   12: cfg_root_t cfg;
   13: int Verbose;
   14: struct tagProc proc;
   15: FILE *lf;
   16: 
   17: 
   18: static inline void
   19: Log(int lvl, const char *fmt, ...)
   20: {
   21: 	va_list lst, cp;
   22: 
   23: 	EVERBS(lvl) {
   24: 		va_start(lst, fmt);
   25: 		va_copy(cp, lst);
   26: 		vfprintf(lf, fmt, lst);
   27: 		va_end(lst);
   28: 		fprintf(lf, "\n");
   29: 		vsyslog(LOG_WARNING, fmt, cp);
   30: 		va_end(cp);
   31: 	}
   32: }
   33: 
   34: static inline void
   35: Err(const char *fmt, ...)
   36: {
   37: 	va_list lst, cp;
   38: 
   39: 	va_start(lst, fmt);
   40: 	va_copy(cp, lst);
   41: 	vfprintf(lf, fmt, lst);
   42: 	va_end(lst);
   43: 	fprintf(lf, "\n");
   44: 	vsyslog(LOG_ERR, fmt, cp);
   45: 	va_end(cp);
   46: }
   47: 
   48: static void
   49: initProg()
   50: {
   51: 	char d[MAXPATHLEN];
   52: 
   53: 	AIT_SET_I16(&proc.proc_uid, getuid());
   54: 	AIT_SET_I16(&proc.proc_gid, getgid());
   55: 	AIT_SET_I32(&proc.proc_prio, getpriority(PRIO_PROCESS, 0));
   56: 	getcwd(d, sizeof d);
   57: 	AIT_SET_STR(&proc.proc_dir, d);
   58: 
   59: #if 0
   60: 	lf = fopen(DEFAULT_LOG, "a");
   61: 	if (!lf)
   62: #endif
   63: 		lf = stdout;
   64: 
   65: 	openlog(PACKAGE_NAME, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER);
   66: }
   67: 
   68: static void
   69: endProg()
   70: {
   71: 	AIT_FREE_VAL(&proc.proc_uid);
   72: 	AIT_FREE_VAL(&proc.proc_gid);
   73: 	AIT_FREE_VAL(&proc.proc_prio);
   74: 	AIT_FREE_VAL(&proc.proc_class);
   75: 	AIT_FREE_VAL(&proc.proc_dir);
   76: 	AIT_FREE_VAL(&proc.proc_name);
   77: 	AIT_FREE_VAL(&proc.proc_cmd);
   78: }
   79: 
   80: static void
   81: Usage()
   82: {
   83: 	printf(	" -= suX =- suExecutor designed for web based applicaions\n"
   84: 		"(C)`11 AITNET ltd - Sofia/Bulgaria - <office@aitnet.org>\n\n"
   85: 		" Syntax: %s [options] <program> [arguments]\n"
   86: 		"\t-u <user>\t\t\tUser for suID\n"
   87: 		"\t-g <group>\t\t\tGroup for suID\n"
   88: 		"\t-p <priority (-20..20)>\t\tExecute with priority\n"
   89: 		"\t-d <directory>\t\t\tDirectory for suID\n"
   90: 		"\t-C <directory>\t\t\tChroot to directory\n"
   91: 		"\t-c <cfgfile>\t\t\tConfig file\n"
   92: 		"\t-l <logfile>\t\t\tLog file path (default:/var/log/suX.log)\n"
   93: 		"\t-o\t\t\t\tForce set UID,GID and Priority for program\n"
   94: 		"\t-v\t\t\t\tVerbose, (more -v, more verbosity)\n"
   95: 		"\t-h\t\t\t\tThis help screen!\n\n", PACKAGE_NAME);
   96: }
   97: 
   98: static inline int
   99: setUIDGID(char flg, const char *name)
  100: {
  101: 	struct stat sb;
  102: 
  103: 	if (stat(name, &sb) == -1) {
  104: 		ESYSERR(0);
  105: 		return -1;
  106: 	}
  107: 
  108: 	if (!(flg & SUX_GET_UID))
  109: 		AIT_SET_I16(&proc.proc_uid, sb.st_uid);
  110: 	if (!(flg & SUX_GET_GID))
  111: 		AIT_SET_I16(&proc.proc_gid, sb.st_gid);
  112: 
  113: 	return 0;
  114: }
  115: 
  116: static inline int
  117: SetClass()
  118: {
  119: 	login_cap_t *cap;
  120: 	struct passwd *pass;
  121: 
  122: 	pass = getpwuid(AIT_GET_I16(&proc.proc_uid));
  123: 	if (!pass) {
  124: 		Err("Error:: User with this UID %d not found", AIT_GET_I16(&proc.proc_uid));
  125: 		endpwent();
  126: 		return -1;
  127: 	} else 
  128: 		AIT_SET_STR(&proc.proc_class, pass->pw_class);
  129: 
  130: 	cap = login_getclass(AIT_GET_STR(&proc.proc_class));
  131: 	if (!cap) {
  132: 		Err("Error:: Cant get login class %s", AIT_GET_STR(&proc.proc_class));
  133: 		endpwent();
  134: 		return -1;
  135: 	}
  136: 
  137: 	if (setusercontext(cap, pass, AIT_GET_I16(&proc.proc_uid), LOGIN_SETALL)) {
  138: 		Err("Error:: Cant set login class %s", AIT_GET_STR(&proc.proc_class));
  139: 		login_close(cap);
  140: 		endpwent();
  141: 		return -1;
  142: 	}
  143: 
  144: 	login_close(cap);
  145: 	endpwent();
  146: 	return 0;
  147: }
  148: 
  149: static int
  150: LoadCfgData(char flg)
  151: {
  152: 	const char *str;
  153: 	char mode = 0;
  154: 
  155: 	str = cfg_getAttribute(&cfg, "global", "mode");
  156: 	if (!str) {
  157: 		Err("Error:: Unknown mode ...");
  158: 		return -1;
  159: 	}
  160: 	if (!strcasecmp(str, "SCRIPT")) {
  161: 		mode = 1;
  162: 		if (setUIDGID(flg, AIT_GET_STR(&proc.proc_name)) == -1)
  163: 			return -1;
  164: 	} else if (!strcasecmp(str, "FILE")) {
  165: 		mode = 2;
  166: 		if (setUIDGID(flg, AIT_GET_STR(&proc.proc_name)) == -1)
  167: 			return -1;
  168: 	} else if (!strcasecmp(str, "DIR") && 
  169: 			(str = cfg_getAttribute(&cfg, "global", "directory"))) {
  170: 		mode = 3;
  171: 		if (!(flg & SUX_GET_DIR))
  172: 			AIT_SET_STR(&proc.proc_dir, str);
  173: 
  174: 		if (setUIDGID(flg, AIT_GET_STR(&proc.proc_dir)) == -1)
  175: 			return -1;
  176: 	} else {
  177: 		Err("Error:: Unknown mode %s", str);
  178: 		return -1;
  179: 	}
  180: 	if (!(flg & SUX_GET_PRIO)) {
  181: 		str = cfg_getAttribute(&cfg, "global", "priority");
  182: 		if (str)
  183: 			AIT_SET_I32(&proc.proc_prio, strtol(str, NULL, 10));
  184: 	}
  185: 
  186: 	/* find associate extension */
  187: 	str = strrchr(AIT_GET_STR(&proc.proc_name), '.');
  188: 	if (str) {
  189: 		str++;
  190: 		str = (*str) ? str : "default";
  191: 		switch (cfg_loadAttribute(&cfg, "associate", str, &proc.proc_cmd, NULL)) {
  192: 			case -1:
  193: 				ELIBERR(cfg);
  194: 				return -1;
  195: 			case 0:
  196: 				cfg_loadAttribute(&cfg, "associate", "default", &proc.proc_cmd, DEFAULT_CMD);
  197: 		}
  198: 	} else
  199: 		AIT_SET_STR(&proc.proc_cmd, DEFAULT_CMD);
  200: 
  201: 	return 0;
  202: }
  203: 
  204: static int
  205: Run(char **argv, char flg)
  206: {
  207: 	char **args, *cmd;
  208: 	array_t *acmd, *aarg;
  209: 	int n;
  210: 
  211: 	if (!argv)
  212: 		return -1;
  213: 
  214: 	n = array_Args(AIT_GET_STR(&proc.proc_cmd), 0, " \t", &acmd);
  215: 	if (n < 1)
  216: 		return -1;
  217: 	if (!(aarg = array_From((const char***) &argv, 0))) {
  218: 		array_Destroy(&acmd);
  219: 		return -1;
  220: 	} else if (*array(acmd, 0, char*) == '!') {
  221: 		if (array_Grow(acmd, 0, 0)) {
  222: 			array_Destroy(&aarg);
  223: 			array_Destroy(&acmd);
  224: 			return -1;
  225: 		}
  226: 		cmd = array(aarg, 0, char*);
  227: 	} else
  228: 		cmd = array(acmd, 0, char*);
  229: 
  230: 	if (array_Concat(acmd, aarg) == -1) {
  231: 		array_Destroy(&aarg);
  232: 		array_Destroy(&acmd);
  233: 		return -1;
  234: 	}
  235: 	array_Destroy(&aarg);
  236: 	if (!(args = array_To(acmd))) {
  237: 		array_Destroy(&acmd);
  238: 		return -1;
  239: 	}
  240: 	array_Destroy(&acmd);
  241: 
  242: 	if (SetClass()) {
  243: 		if (args)
  244: 			e_free(args);
  245: 		return -1;
  246: 	}
  247: 
  248: 	if (flg & SUX_GET_FORCE) {
  249: 		if (setgid(AIT_GET_I16(&proc.proc_gid)) == -1) {
  250: 			ESYSERR(0);
  251: 			if (args)
  252: 				free(args);
  253: 			return -1;
  254: 		}
  255: 		if (setuid(AIT_GET_I16(&proc.proc_uid)) == -1) {
  256: 			ESYSERR(0);
  257: 			if (args)
  258: 				free(args);
  259: 			return -1;
  260: 		}
  261: 		if (setpriority(PRIO_PROCESS, 0, AIT_GET_I32(&proc.proc_prio)) == -1) {
  262: 			ESYSERR(0);
  263: 			if (args)
  264: 				free(args);
  265: 			return -1;
  266: 		}
  267: 	}
  268: 
  269: 	Log(0, "UID:GID=%d:%d Prio=%d Class=%s Name=%s Dir=%s Cmd=%s Script=%s", 
  270: 			proc.proc_uid, proc.proc_gid, proc.proc_prio, AIT_GET_STR(&proc.proc_class), 
  271: 			AIT_GET_STR(&proc.proc_name), AIT_GET_STR(&proc.proc_dir), 
  272: 			AIT_GET_STR(&proc.proc_cmd), getenv("PATH_TRANSLATED"));
  273: 
  274: 	EVERBS(3) {
  275: 		char **el = args - 1;
  276: 		while (*++el)
  277: 			Log(3, "args: %s", *el);
  278: 	}
  279: 
  280: 	fflush(lf);
  281: 
  282: 	execve(cmd, args, environ);
  283: 	if (args)
  284: 		free(args);
  285: 	ESYSERR(0);
  286: 	return -1;
  287: }
  288: 
  289: 
  290: int
  291: main(int argc, char **argv)
  292: {
  293: 	char ch, *str, *wrk, szCfg[MAXPATHLEN], **pp, flg = 0;
  294: 	struct passwd *pass;
  295: 	struct group *grp;
  296: 	FILE *f;
  297: 
  298: 	initProg();
  299: 	strlcpy(szCfg, DEFAULT_CONFIG, sizeof szCfg);
  300: 
  301: 	while ((ch = getopt(argc, argv, "hvoC:c:u:g:p:d:l:")) != -1)
  302: 		switch (ch) {
  303: 			case 'l':
  304: 				f = fopen(optarg, "a");
  305: 				if (!f) {
  306: 					Err("Error:: logfile #%d - %s", errno, strerror(errno));
  307: 					return 1;
  308: 				} else
  309: 					if (fileno(lf) > 2)
  310: 						fclose(lf);
  311: 				lf = f;
  312: 				break;
  313: 			case 'd':
  314: 				AIT_SET_STR(&proc.proc_dir, optarg);
  315: 				flg |= SUX_GET_DIR;
  316: 				break;
  317: 			case 'p':
  318: 				AIT_SET_I32(&proc.proc_prio, strtol(optarg, NULL, 0));
  319: 				flg |= SUX_GET_PRIO;
  320: 				break;
  321: 			case 'g':
  322: 				setgrent();
  323: 				grp = getgrnam(optarg);
  324: 				if (grp) {
  325: 					AIT_SET_I16(&proc.proc_gid, grp->gr_gid);
  326: 					flg |= SUX_GET_GID;
  327: 				} else
  328: 					Err("Error:: Group not found!");
  329: 				endgrent();
  330: 				break;
  331: 			case 'u':
  332: 				setpwent();
  333: 				pass = getpwnam(optarg);
  334: 				if (pass) {
  335: 					AIT_SET_I16(&proc.proc_uid, pass->pw_uid);
  336: 					flg |= SUX_GET_UID;
  337: 				} else
  338: 					Err("Error:: User not found!");
  339: 				endpwent();
  340: 				break;
  341: 			case 'c':
  342: 				strlcpy(szCfg, optarg, sizeof szCfg);
  343: 				break;
  344: 			case 'C':
  345: 				if (chroot(optarg) == -1)
  346: 					Err("Error:: chroot to dir");
  347: 				if ((str = getenv("PATH_TRANSLATED")))
  348: 					if ((wrk = strstr(str, optarg)))
  349: 						setenv("PATH_TRANSLATED", str + strlen(optarg), 42);
  350: 				break;
  351: 			case 'o':
  352: 				flg |= SUX_GET_FORCE;
  353: 				break;
  354: 			case 'v':
  355: 				e_incVerbose;
  356: 				break;
  357: 			case 'h':
  358: 			default:
  359: 				Usage();
  360: 				endProg();
  361: 				if (fileno(lf) > 2)
  362: 					fclose(lf);
  363: 				return 1;
  364: 		}
  365: 	argc -= optind;
  366: 	argv += optind;
  367: 
  368: 	EVERBS(2) {
  369: 		for (pp = argv; *pp; pp++)
  370: 			Log(2, "Args=%s\n", *pp);
  371: 		for (pp = environ; *pp; pp++)
  372: 			Log(2, "Envs=%s\n", *pp);
  373: 	}
  374: 
  375: 	if (!argc) {
  376: 		if (!(str = getenv("PATH_TRANSLATED"))) {
  377: 			Usage();
  378: 			endProg();
  379: 			if (fileno(lf) > 2)
  380: 				fclose(lf);
  381: 			return 1;
  382: 		} else
  383: 			AIT_SET_STR(&proc.proc_name, str);
  384: 	} else
  385: 		AIT_SET_STR(&proc.proc_name, *argv);
  386: 	Log(2, "Try to load config %s", szCfg);
  387: 	if (cfgLoadConfig(szCfg, &cfg)) {
  388: 		ELIBERR(cfg);
  389: 		endProg();
  390: 		if (fileno(lf) > 2)
  391: 			fclose(lf);
  392: 		return 2;
  393: 	} else
  394: 		if (LoadCfgData(flg) == -1) {
  395: 			cfgUnloadConfig(&cfg);
  396: 			endProg();
  397: 			if (fileno(lf) > 2)
  398: 				fclose(lf);
  399: 			closelog();
  400: 			return 3;
  401: 		}
  402: 	cfgUnloadConfig(&cfg);
  403: 
  404: 	if (Run(argv, flg) == -1) {
  405: 		endProg();
  406: 		if (fileno(lf) > 2)
  407: 			fclose(lf);
  408: 		closelog();
  409: 		return 4;
  410: 	}
  411: 
  412: 	endProg();
  413: 	if (fileno(lf) > 2)
  414: 		fclose(lf);
  415: 	closelog();
  416: 	return 0;
  417: }

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