File:  [ELWIX - Embedded LightWeight unIX -] / suX / src / sux.c
Revision 1.7: download - view: text, annotated - select for diffs - revision graph
Thu Jun 18 23:03:53 2015 UTC (9 years ago) by misho
Branches: MAIN
CVS tags: sux3_4, SUX3_3, HEAD
version 3.3

    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.7 2015/06/18 23:03:53 misho Exp $
    7:  *
    8:  *************************************************************************
    9: The ELWIX and AITNET software is distributed under the following
   10: terms:
   11: 
   12: All of the documentation and software included in the ELWIX and AITNET
   13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
   14: 
   15: Copyright 2004 - 2015
   16: 	by Michael Pounov <misho@elwix.org>.  All rights reserved.
   17: 
   18: Redistribution and use in source and binary forms, with or without
   19: modification, are permitted provided that the following conditions
   20: are met:
   21: 1. Redistributions of source code must retain the above copyright
   22:    notice, this list of conditions and the following disclaimer.
   23: 2. Redistributions in binary form must reproduce the above copyright
   24:    notice, this list of conditions and the following disclaimer in the
   25:    documentation and/or other materials provided with the distribution.
   26: 3. All advertising materials mentioning features or use of this software
   27:    must display the following acknowledgement:
   28: This product includes software developed by Michael Pounov <misho@elwix.org>
   29: ELWIX - Embedded LightWeight unIX and its contributors.
   30: 4. Neither the name of AITNET nor the names of its contributors
   31:    may be used to endorse or promote products derived from this software
   32:    without specific prior written permission.
   33: 
   34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
   35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   37: ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   44: SUCH DAMAGE.
   45: */
   46: #include "global.h"
   47: 
   48: 
   49: cfg_root_t cfg;
   50: int Verbose;
   51: struct tagProc proc;
   52: FILE *lf;
   53: 
   54: 
   55: static inline void
   56: Log(int lvl, const char *fmt, ...)
   57: {
   58: 	va_list lst, cp;
   59: 
   60: 	EVERBS(lvl) {
   61: 		va_start(lst, fmt);
   62: 		va_copy(cp, lst);
   63: 		vfprintf(lf, fmt, lst);
   64: 		va_end(lst);
   65: 		fprintf(lf, "\n");
   66: 		vsyslog(LOG_INFO, fmt, cp);
   67: 		va_end(cp);
   68: 	}
   69: }
   70: 
   71: static inline void
   72: Err(const char *fmt, ...)
   73: {
   74: 	va_list lst, cp;
   75: 
   76: 	va_start(lst, fmt);
   77: 	va_copy(cp, lst);
   78: 	vfprintf(lf, fmt, lst);
   79: 	va_end(lst);
   80: 	fprintf(lf, "\n");
   81: 	vsyslog(LOG_ERR, fmt, cp);
   82: 	va_end(cp);
   83: }
   84: 
   85: static inline void
   86: DumpProc(const char *txt)
   87: {
   88: 	Log(1, "%s:: uid:gid=%d:%d UID:GID=%d:%d Prio=%d Class=%s Name=%s Dir=%s Cmd=%s "
   89: 			"Script=%s From=%s:%s Get=%s", txt ? txt : __func__, 
   90: 			geteuid(), getegid(), AIT_GET_I16(&proc.proc_uid), 
   91: 			AIT_GET_I16(&proc.proc_gid), AIT_GET_I32(&proc.proc_prio), 
   92: 			AIT_GET_STR(&proc.proc_class), AIT_GET_STR(&proc.proc_name), 
   93: 			AIT_GET_STR(&proc.proc_dir), AIT_GET_STR(&proc.proc_cmd), 
   94: 			getenv("PATH_TRANSLATED"), getenv("REMOTE_ADDR"), 
   95: 			getenv("REMOTE_PORT"), getenv("REQUEST_URI"));
   96: }
   97: 
   98: static int
   99: initProg()
  100: {
  101: 	AIT_SET_I16(&proc.proc_uid, getuid());
  102: 	AIT_SET_I16(&proc.proc_gid, getgid());
  103: 	AIT_SET_I32(&proc.proc_prio, getpriority(PRIO_PROCESS, 0));
  104: 	AIT_INIT_VAL2(&proc.proc_class, string);
  105: 	AIT_INIT_VAL2(&proc.proc_dir, string);
  106: 	AIT_INIT_VAL2(&proc.proc_name, string);
  107: 	AIT_INIT_VAL2(&proc.proc_cmd, string);
  108: 
  109: #if 0
  110: 	lf = fopen(DEFAULT_LOG, "a");
  111: 	if (!lf)
  112: #endif
  113: 		lf = stdout;
  114: 
  115: 	openlog(PACKAGE_NAME, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER);
  116: 	return 0;
  117: }
  118: 
  119: static void
  120: endProg()
  121: {
  122: 	AIT_FREE_VAL(&proc.proc_uid);
  123: 	AIT_FREE_VAL(&proc.proc_gid);
  124: 	AIT_FREE_VAL(&proc.proc_prio);
  125: 	AIT_FREE_VAL(&proc.proc_class);
  126: 	AIT_FREE_VAL(&proc.proc_dir);
  127: 	AIT_FREE_VAL(&proc.proc_name);
  128: 	AIT_FREE_VAL(&proc.proc_cmd);
  129: }
  130: 
  131: static void
  132: Usage()
  133: {
  134: 	printf(	" -= suX =- suExecutor designed for web based applicaions\n"
  135: 		"(C)`11 AITNET ltd - Sofia/Bulgaria - <office@aitnet.org>\n\n"
  136: 		" Syntax: %s [options] <program|-> [arguments]\n"
  137: 		"\t-u <user>\t\t\tUser for suID\n"
  138: 		"\t-g <group>\t\t\tGroup for suID\n"
  139: 		"\t-p <priority (-20..20)>\t\tExecute with priority\n"
  140: 		"\t-d <directory>\t\t\tDirectory for suID\n"
  141: 		"\t-C <directory>\t\t\tChroot to directory\n"
  142: 		"\t-c <cfgfile>\t\t\tConfig file\n"
  143: 		"\t-l <logfile>\t\t\tLog file path (default:/var/log/suX.log)\n"
  144: 		"\t-o\t\t\t\tForce set UID,GID and Priority for program\n"
  145: 		"\t-v\t\t\t\tVerbose, (more -v, more verbosity)\n"
  146: 		"\t-h\t\t\t\tThis help screen!\n\n", PACKAGE_NAME);
  147: }
  148: 
  149: static inline int
  150: setUIDGID(char flg, const char *name)
  151: {
  152: 	struct stat sb;
  153: 	struct passwd *pass;
  154: 	short uid, gid;
  155: 
  156: 	if (name) {
  157: 		if (stat(name, &sb) == -1) {
  158: 			ESYSERR(0);
  159: 			return -1;
  160: 		}
  161: 		uid = sb.st_uid;
  162: 		gid = sb.st_gid;
  163: 	} else {
  164: 		pass = getpwnam(getenv("SUX_USER") ? getenv("SUX_USER") : DEFAULT_SUX_USER);
  165: 		if (!pass) {
  166: 			Err("Error:: User %s not found", getenv("SUX_USER"));
  167: 			endpwent();
  168: 			return -1;
  169: 		}
  170: 		uid = pass->pw_uid;
  171: 		gid = pass->pw_gid;
  172: 		endpwent();
  173: 	}
  174: 
  175: 	if (!(flg & SUX_GET_UID))
  176: 		AIT_SET_I16(&proc.proc_uid, uid);
  177: 	if (!(flg & SUX_GET_GID))
  178: 		AIT_SET_I16(&proc.proc_gid, gid);
  179: 
  180: 	return 0;
  181: }
  182: 
  183: static inline int
  184: setClassDir()
  185: {
  186: 	struct passwd *pass;
  187: 	int ret = 0;
  188: 
  189: 	pass = getpwuid(AIT_GET_I16(&proc.proc_uid));
  190: 	if (!pass) {
  191: 		Err("Error:: User with this UID %d not found", AIT_GET_I16(&proc.proc_uid));
  192: 		ret = -1;
  193: 	} else {
  194: 		AIT_SET_STR(&proc.proc_class, pass->pw_class);
  195: 		AIT_SET_STR(&proc.proc_dir, pass->pw_dir);
  196: 
  197: 		if (setusercontext(NULL, pass, AIT_GET_I16(&proc.proc_uid), 
  198: 					LOGIN_SETLOGIN | LOGIN_SETGROUP | LOGIN_SETUSER | 
  199: 					LOGIN_SETPRIORITY | LOGIN_SETRESOURCES)) {
  200: 			Err("Error:: Can't set login class %s", AIT_GET_STR(&proc.proc_class));
  201: 			ret = -1;
  202: 		}
  203: 	}
  204: 
  205: 	endpwent();
  206: 	return ret;
  207: }
  208: 
  209: static int
  210: LoadCfgData(char flg)
  211: {
  212: 	const char *str;
  213: 	char mode = 0;
  214: 
  215: 	str = cfg_getAttribute(&cfg, "global", "mode");
  216: 	if (!str) {
  217: 		Err("Error:: Unknown mode ...");
  218: 		return -1;
  219: 	}
  220: 	if (!strcasecmp(str, "SCRIPT")) {
  221: 		mode = 1;
  222: 		if (setUIDGID(flg, (getenv("SUX_USER") ? NULL : getenv("PATH_TRANSLATED"))) == -1)
  223: 			return -1;
  224: 	} else if (!strcasecmp(str, "FILE")) {
  225: 		mode = 2;
  226: 		if (setUIDGID(flg, AIT_GET_STR(&proc.proc_name)) == -1)
  227: 			return -1;
  228: 	} else if (!strcasecmp(str, "DIR")) {
  229: 		mode = 3;
  230: 		str = AIT_GET_STR(&proc.proc_dir) ? AIT_GET_STR(&proc.proc_dir) : ".";
  231: 		if (setUIDGID(flg, str) == -1)
  232: 			return -1;
  233: 	} else {
  234: 		Err("Error:: Unknown mode %s", str);
  235: 		return -1;
  236: 	}
  237: 	if (!(flg & SUX_GET_PRIO)) {
  238: 		str = cfg_getAttribute(&cfg, "global", "priority");
  239: 		if (str)
  240: 			AIT_SET_I32(&proc.proc_prio, strtol(str, NULL, 10));
  241: 	}
  242: 
  243: 	/* find associate extension */
  244: 	str = strrchr(AIT_GET_STR(&proc.proc_name), '.');
  245: 	if (str) {
  246: 		str++;
  247: 		str = (*str) ? str : "default";
  248: 		switch (cfg_loadAttribute(&cfg, "associate", str, &proc.proc_cmd, NULL)) {
  249: 			case -1:
  250: 				ELIBERR(cfg);
  251: 				return -1;
  252: 			case 0:
  253: 				cfg_loadAttribute(&cfg, "associate", "default", 
  254: 						&proc.proc_cmd, DEFAULT_CMD);
  255: 		}
  256: 	} else
  257: 		AIT_SET_STR(&proc.proc_cmd, DEFAULT_CMD);
  258: 
  259: 	return 0;
  260: }
  261: 
  262: static int
  263: Run(char **argv, char flg)
  264: {
  265: 	char **args, *cmd;
  266: 	array_t *acmd, *aarg;
  267: 	int n;
  268: 
  269: 	if (!argv)
  270: 		return -1;
  271: 
  272: 	n = array_Args(AIT_GET_STR(&proc.proc_cmd), 0, " \t", &acmd);
  273: 	if (n < 1)
  274: 		return -1;
  275: 	if (!(aarg = array_From((const char***) &argv, 0))) {
  276: 		array_Destroy(&acmd);
  277: 		return -1;
  278: 	}
  279: 	/* '!' exclude associated wrapper aka direct args execution */
  280: 	if (*array(acmd, 0, char*) == '!') {
  281: 		if (array_Grow(acmd, 0, 0)) {
  282: 			array_Destroy(&aarg);
  283: 			array_Destroy(&acmd);
  284: 			return -1;
  285: 		}
  286: 		cmd = array(aarg, 0, char*);
  287: 	} else
  288: 		cmd = array(acmd, 0, char*);
  289: 
  290: 	if (!(flg & SUX_GET_STDIN) && array_Concat(acmd, aarg) == -1) {
  291: 		array_Destroy(&aarg);
  292: 		array_Destroy(&acmd);
  293: 		return -1;
  294: 	}
  295: 	array_Destroy(&aarg);
  296: 	if (!(args = array_To(acmd))) {
  297: 		array_Destroy(&acmd);
  298: 		return -1;
  299: 	}
  300: 	array_Destroy(&acmd);
  301: 
  302: 	if (setClassDir()) {
  303: 		if (args)
  304: 			e_free(args);
  305: 		return -1;
  306: 	}
  307: 
  308: 	if (flg & SUX_GET_FORCE) {
  309: 		if (setegid(AIT_GET_I16(&proc.proc_gid)) == -1)
  310: 			goto err;
  311: 		if (seteuid(AIT_GET_I16(&proc.proc_uid)) == -1)
  312: 			goto err;
  313: 		if (setpriority(PRIO_PROCESS, 0, AIT_GET_I32(&proc.proc_prio)) == -1)
  314: 			goto err;
  315: 	}
  316: 
  317: 	EVERBS(3) {
  318: 		char **el = args - 1;
  319: 		while (*++el)
  320: 			Log(3, "args: %s", *el);
  321: 	}
  322: 
  323: 	DumpProc(__func__);
  324: 
  325: 	fflush(lf);
  326: 
  327: 	execve(cmd, args, environ);
  328: err:
  329: 	ESYSERR(0);
  330: 	if (args)
  331: 		e_free(args);
  332: 	return -1;
  333: }
  334: 
  335: 
  336: int
  337: main(int argc, char **argv)
  338: {
  339: 	char ch, *str, *wrk, szCfg[MAXPATHLEN], **pp, flg = 0;
  340: 	struct passwd *pass;
  341: 	struct group *grp;
  342: 	FILE *f;
  343: 
  344: 	initProg();
  345: 	strlcpy(szCfg, DEFAULT_CONFIG, sizeof szCfg);
  346: 
  347: 	while ((ch = getopt(argc, argv, "hvoC:c:u:g:p:d:l:")) != -1)
  348: 		switch (ch) {
  349: 			case 'l':
  350: 				f = fopen(optarg, "a");
  351: 				if (!f) {
  352: 					Err("Error:: logfile #%d - %s", errno, strerror(errno));
  353: 					return 1;
  354: 				} else
  355: 					if (fileno(lf) > 2)
  356: 						fclose(lf);
  357: 				lf = f;
  358: 				break;
  359: 			case 'd':
  360: 				AIT_SET_STR(&proc.proc_dir, optarg);
  361: 				flg |= SUX_GET_DIR;
  362: 				break;
  363: 			case 'p':
  364: 				AIT_SET_I32(&proc.proc_prio, strtol(optarg, NULL, 0));
  365: 				flg |= SUX_GET_PRIO;
  366: 				break;
  367: 			case 'g':
  368: 				setgrent();
  369: 				grp = getgrnam(optarg);
  370: 				if (grp) {
  371: 					AIT_SET_I16(&proc.proc_gid, grp->gr_gid);
  372: 					flg |= SUX_GET_GID;
  373: 				} else
  374: 					Err("Error:: Group not found!");
  375: 				endgrent();
  376: 				break;
  377: 			case 'u':
  378: 				setpwent();
  379: 				pass = getpwnam(optarg);
  380: 				if (pass) {
  381: 					AIT_SET_I16(&proc.proc_uid, pass->pw_uid);
  382: 					flg |= SUX_GET_UID;
  383: 				} else
  384: 					Err("Error:: User not found!");
  385: 				endpwent();
  386: 				break;
  387: 			case 'c':
  388: 				strlcpy(szCfg, optarg, sizeof szCfg);
  389: 				break;
  390: 			case 'C':
  391: 				if (chroot(optarg) == -1)
  392: 					Err("Error:: chroot to dir");
  393: 				if ((str = getenv("PATH_TRANSLATED")))
  394: 					if ((wrk = strstr(str, optarg)))
  395: 						setenv("PATH_TRANSLATED", str + strlen(optarg), 42);
  396: 				break;
  397: 			case 'o':
  398: 				flg |= SUX_GET_FORCE;
  399: 				break;
  400: 			case 'v':
  401: 				e_incVerbose;
  402: 				break;
  403: 			case 'h':
  404: 			default:
  405: 				Usage();
  406: 				endProg();
  407: 				if (fileno(lf) > 2)
  408: 					fclose(lf);
  409: 				return 1;
  410: 		}
  411: 	argc -= optind;
  412: 	argv += optind;
  413: 
  414: 	EVERBS(2) {
  415: 		for (pp = argv; *pp; pp++)
  416: 			Log(2, "Args=%s\n", *pp);
  417: 		for (pp = environ; *pp; pp++)
  418: 			Log(2, "Envs=%s\n", *pp);
  419: 	}
  420: 
  421: 	if (!argc) {
  422: 		if (!(str = getenv("PATH_TRANSLATED"))) {
  423: 			Usage();
  424: 			endProg();
  425: 			if (fileno(lf) > 2)
  426: 				fclose(lf);
  427: 			return 1;
  428: 		} else
  429: 			AIT_SET_STR(&proc.proc_name, str);
  430: 	} else if (strcmp(*argv, "-"))
  431: 		AIT_SET_STR(&proc.proc_name, *argv);
  432: 	else {
  433: 		flg |= SUX_GET_STDIN;
  434: 		AIT_SET_STR(&proc.proc_name, "-.stdin");	/* hack for associate to stdin */
  435: 	}
  436: 	Log(2, "Try to load config %s", szCfg);
  437: 	if (cfgLoadConfig(szCfg, &cfg)) {
  438: 		ELIBERR(cfg);
  439: 		endProg();
  440: 		if (fileno(lf) > 2)
  441: 			fclose(lf);
  442: 		return 2;
  443: 	} else
  444: 		if (LoadCfgData(flg) == -1) {
  445: 			cfgUnloadConfig(&cfg);
  446: 			endProg();
  447: 			if (fileno(lf) > 2)
  448: 				fclose(lf);
  449: 			closelog();
  450: 			return 3;
  451: 		}
  452: 	cfgUnloadConfig(&cfg);
  453: 
  454: 	if (Run(argv, flg) == -1) {
  455: 		endProg();
  456: 		if (fileno(lf) > 2)
  457: 			fclose(lf);
  458: 		closelog();
  459: 		return 4;
  460: 	}
  461: 
  462: 	endProg();
  463: 	if (fileno(lf) > 2)
  464: 		fclose(lf);
  465: 	closelog();
  466: 	return 0;
  467: }

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