File:  [ELWIX - Embedded LightWeight unIX -] / suX / src / sux.c
Revision 1.6: download - view: text, annotated - select for diffs - revision graph
Wed Jun 17 14:14:17 2015 UTC (9 years ago) by misho
Branches: MAIN
CVS tags: sux3_3, SUX3_2, HEAD
version 3.2

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

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