xref: /illumos-gate/usr/src/cmd/pfexec/pfexec.c (revision f48205be)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*f48205beScasper  * Common Development and Distribution License (the "License").
6*f48205beScasper  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*f48205beScasper  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <errno.h>
297c478bd9Sstevel@tonic-gate #include <deflt.h>
307c478bd9Sstevel@tonic-gate #include <locale.h>
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <unistd.h>
357c478bd9Sstevel@tonic-gate #include <ctype.h>
367c478bd9Sstevel@tonic-gate #include <pwd.h>
377c478bd9Sstevel@tonic-gate #include <grp.h>
387c478bd9Sstevel@tonic-gate #include <string.h>
397c478bd9Sstevel@tonic-gate #include <exec_attr.h>
407c478bd9Sstevel@tonic-gate #include <user_attr.h>
417c478bd9Sstevel@tonic-gate #include <auth_attr.h>
427c478bd9Sstevel@tonic-gate #include <prof_attr.h>
437c478bd9Sstevel@tonic-gate #include <errno.h>
447c478bd9Sstevel@tonic-gate #include <priv.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include <bsm/adt.h>
477c478bd9Sstevel@tonic-gate #include <bsm/adt_event.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #ifndef	TEXT_DOMAIN			/* Should be defined by cc -D */
507c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
517c478bd9Sstevel@tonic-gate #endif
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate extern int cannot_audit(int);
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate static char *pathsearch(char *);
567c478bd9Sstevel@tonic-gate static int getrealpath(const char *, char *);
577c478bd9Sstevel@tonic-gate static int checkattrs(char *, int, char *[]);
587c478bd9Sstevel@tonic-gate static void sanitize_environ();
597c478bd9Sstevel@tonic-gate static uid_t get_uid(char *);
607c478bd9Sstevel@tonic-gate static gid_t get_gid(char *);
617c478bd9Sstevel@tonic-gate static priv_set_t *get_privset(const char *);
627c478bd9Sstevel@tonic-gate static priv_set_t *get_granted_privs(uid_t);
637c478bd9Sstevel@tonic-gate static void get_default_privs(priv_set_t *);
647c478bd9Sstevel@tonic-gate static void get_profile_privs(char *, char **, int *, priv_set_t *);
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate static int isnumber(char *);
677c478bd9Sstevel@tonic-gate static void usage(void);
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate extern char **environ;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate #define	PROFLIST_SEP	","
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate int
747c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate 	char		*cmd;
777c478bd9Sstevel@tonic-gate 	char		**cmdargs;
787c478bd9Sstevel@tonic-gate 	char		cmd_realpath[MAXPATHLEN];
797c478bd9Sstevel@tonic-gate 	int		c;
807c478bd9Sstevel@tonic-gate 	char 		*pset = NULL;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
837c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "P:")) != EOF) {
867c478bd9Sstevel@tonic-gate 		switch (c) {
877c478bd9Sstevel@tonic-gate 		case 'P':
887c478bd9Sstevel@tonic-gate 			if (pset == NULL) {
897c478bd9Sstevel@tonic-gate 				pset = optarg;
907c478bd9Sstevel@tonic-gate 				break;
917c478bd9Sstevel@tonic-gate 			}
927c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
937c478bd9Sstevel@tonic-gate 		default:
947c478bd9Sstevel@tonic-gate 			usage();
957c478bd9Sstevel@tonic-gate 		}
967c478bd9Sstevel@tonic-gate 	}
977c478bd9Sstevel@tonic-gate 	argc -= optind;
987c478bd9Sstevel@tonic-gate 	argv += optind;
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	if (argc < 1)
1017c478bd9Sstevel@tonic-gate 		usage();
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	cmd = argv[0];
1047c478bd9Sstevel@tonic-gate 	cmdargs = &argv[0];
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	if (pset != NULL) {
1077c478bd9Sstevel@tonic-gate 		uid_t uid = getuid();
1087c478bd9Sstevel@tonic-gate 		priv_set_t *wanted = get_privset(pset);
1097c478bd9Sstevel@tonic-gate 		priv_set_t *granted;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 		adt_session_data_t *ah;		/* audit session handle */
1127c478bd9Sstevel@tonic-gate 		adt_event_data_t *event;	/* event to be generated */
1137c478bd9Sstevel@tonic-gate 		char cwd[MAXPATHLEN];
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 		granted = get_granted_privs(uid);
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 		/* Audit use */
1187c478bd9Sstevel@tonic-gate 		if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
1197c478bd9Sstevel@tonic-gate 			perror("pfexec: adt_start_session");
1207c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
1217c478bd9Sstevel@tonic-gate 		}
1227c478bd9Sstevel@tonic-gate 		if ((event = adt_alloc_event(ah, ADT_prof_cmd)) == NULL) {
1237c478bd9Sstevel@tonic-gate 			perror("pfexec: adt_alloc_event");
1247c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
1257c478bd9Sstevel@tonic-gate 		}
1267c478bd9Sstevel@tonic-gate 		if ((event->adt_prof_cmd.cwdpath =
1277c478bd9Sstevel@tonic-gate 		    getcwd(cwd, sizeof (cwd))) == NULL) {
1287c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1297c478bd9Sstevel@tonic-gate 			    gettext("pfexec: can't add cwd path\n"));
1307c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
1317c478bd9Sstevel@tonic-gate 		}
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.cmdpath = cmd;
1347c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.argc = argc - 1;
1357c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.argv = &argv[1];
1367c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.envp = environ;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 		if (granted != NULL) {
1397c478bd9Sstevel@tonic-gate 			priv_intersect(granted, wanted);
1407c478bd9Sstevel@tonic-gate 			event->adt_prof_cmd.inherit_set = wanted;
1417c478bd9Sstevel@tonic-gate 			if (adt_put_event(event, ADT_SUCCESS,
1427c478bd9Sstevel@tonic-gate 			    ADT_SUCCESS) != 0) {
1437c478bd9Sstevel@tonic-gate 				perror("pfexec: adt_put_event");
1447c478bd9Sstevel@tonic-gate 				exit(EXIT_FAILURE);
1457c478bd9Sstevel@tonic-gate 			}
1467c478bd9Sstevel@tonic-gate 			if (setppriv(PRIV_ON, PRIV_INHERITABLE, wanted) != 0) {
1477c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1487c478bd9Sstevel@tonic-gate 						gettext("setppriv(): %s\n"),
1497c478bd9Sstevel@tonic-gate 						strerror(errno));
1507c478bd9Sstevel@tonic-gate 				exit(EXIT_FAILURE);
1517c478bd9Sstevel@tonic-gate 			}
1527c478bd9Sstevel@tonic-gate 			/* Trick exec into thinking we're not suid */
1537c478bd9Sstevel@tonic-gate 			(void) setppriv(PRIV_ON, PRIV_PERMITTED, wanted);
1547c478bd9Sstevel@tonic-gate 			priv_freeset(event->adt_prof_cmd.inherit_set);
1557c478bd9Sstevel@tonic-gate 		} else {
1567c478bd9Sstevel@tonic-gate 			if (adt_put_event(event, ADT_SUCCESS,
1577c478bd9Sstevel@tonic-gate 			    ADT_SUCCESS) != 0) {
1587c478bd9Sstevel@tonic-gate 				perror("pfexec: adt_put_event");
1597c478bd9Sstevel@tonic-gate 				exit(EXIT_FAILURE);
1607c478bd9Sstevel@tonic-gate 			}
1617c478bd9Sstevel@tonic-gate 		}
1627c478bd9Sstevel@tonic-gate 		adt_free_event(event);
1637c478bd9Sstevel@tonic-gate 		(void) adt_end_session(ah);
1647c478bd9Sstevel@tonic-gate 		(void) setreuid(uid, uid);
1657c478bd9Sstevel@tonic-gate 		(void) execvp(cmd, cmdargs);
1667c478bd9Sstevel@tonic-gate 		perror(cmd);
1677c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
1687c478bd9Sstevel@tonic-gate 	}
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	if ((cmd = pathsearch(cmd)) == NULL)
1717c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	if (getrealpath(cmd, cmd_realpath) == 0)
1747c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	if (checkattrs(cmd_realpath, argc, argv) == 0)
1777c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	(void) execv(cmd, cmdargs);
1807c478bd9Sstevel@tonic-gate 	/*
1817c478bd9Sstevel@tonic-gate 	 * We'd be here only if execv fails.
1827c478bd9Sstevel@tonic-gate 	 */
1837c478bd9Sstevel@tonic-gate 	perror("pfexec");
1847c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
1857c478bd9Sstevel@tonic-gate /* LINTED */
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate  * gets realpath for cmd.
1917c478bd9Sstevel@tonic-gate  * return 1 on success, 0 on failure.
1927c478bd9Sstevel@tonic-gate  */
1937c478bd9Sstevel@tonic-gate static int
1947c478bd9Sstevel@tonic-gate getrealpath(const char *cmd, char *cmd_realpath)
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate 	if (realpath(cmd, cmd_realpath) == NULL) {
1977c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1987c478bd9Sstevel@tonic-gate 		    gettext("pfexec: can't get real path of ``%s''\n"), cmd);
1997c478bd9Sstevel@tonic-gate 		return (0);
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 	return (1);
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate /*
2057c478bd9Sstevel@tonic-gate  * gets execution attributed for cmd, sets uids/gids, checks environ.
2067c478bd9Sstevel@tonic-gate  * returns 1 on success, 0 on failure.
2077c478bd9Sstevel@tonic-gate  */
2087c478bd9Sstevel@tonic-gate static int
2097c478bd9Sstevel@tonic-gate checkattrs(char *cmd_realpath, int argc, char *argv[])
2107c478bd9Sstevel@tonic-gate {
2117c478bd9Sstevel@tonic-gate 	char			*value;
2127c478bd9Sstevel@tonic-gate 	uid_t			uid, euid;
213*f48205beScasper 	gid_t			gid = (gid_t)-1;
214*f48205beScasper 	gid_t			egid = (gid_t)-1;
2157c478bd9Sstevel@tonic-gate 	struct passwd		*pwent;
2167c478bd9Sstevel@tonic-gate 	execattr_t		*exec;
2177c478bd9Sstevel@tonic-gate 	priv_set_t		*lset = NULL;
2187c478bd9Sstevel@tonic-gate 	priv_set_t		*iset = NULL;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	adt_session_data_t	*ah;		/* audit session handle */
2217c478bd9Sstevel@tonic-gate 	adt_event_data_t	*event;		/* event to be generated */
2227c478bd9Sstevel@tonic-gate 	char			cwd[MAXPATHLEN];
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	uid = euid = getuid();
2257c478bd9Sstevel@tonic-gate 	if ((pwent = getpwuid(uid)) == NULL) {
2267c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%d: ", (int)uid);
2277c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("can't get passwd entry\n"));
2287c478bd9Sstevel@tonic-gate 		return (0);
2297c478bd9Sstevel@tonic-gate 	}
2307c478bd9Sstevel@tonic-gate 	/* Set up to audit use */
2317c478bd9Sstevel@tonic-gate 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
2327c478bd9Sstevel@tonic-gate 		perror("pfexec: adt_start_session");
2337c478bd9Sstevel@tonic-gate 		return (0);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 	if ((event = adt_alloc_event(ah, ADT_prof_cmd)) == NULL) {
2367c478bd9Sstevel@tonic-gate 		perror("pfexec: adt_alloc_event");
2377c478bd9Sstevel@tonic-gate 		return (0);
2387c478bd9Sstevel@tonic-gate 	}
2397c478bd9Sstevel@tonic-gate 	if ((event->adt_prof_cmd.cwdpath = getcwd(cwd, sizeof (cwd))) == NULL) {
2407c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("pfexec: can't add cwd path\n"));
2417c478bd9Sstevel@tonic-gate 		return (0);
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 	/*
2447c478bd9Sstevel@tonic-gate 	 * Get the exec attrs: uid, gid, euid and egid
2457c478bd9Sstevel@tonic-gate 	 */
2467c478bd9Sstevel@tonic-gate 	if ((exec = getexecuser(pwent->pw_name,
2477c478bd9Sstevel@tonic-gate 	    KV_COMMAND, (char *)cmd_realpath, GET_ONE)) == NULL) {
2487c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: ", cmd_realpath);
2497c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2507c478bd9Sstevel@tonic-gate 		    gettext("can't get execution attributes\n"));
2517c478bd9Sstevel@tonic-gate 		return (0);
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 	if ((value = kva_match(exec->attr, EXECATTR_UID_KW)) != NULL) {
2547c478bd9Sstevel@tonic-gate 		euid = uid = get_uid(value);
2557c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.proc_euid = uid;
2567c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.proc_ruid = uid;
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 	if ((value = kva_match(exec->attr, EXECATTR_GID_KW)) != NULL) {
2597c478bd9Sstevel@tonic-gate 		egid = gid = get_gid(value);
2607c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.proc_egid = gid;
2617c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.proc_rgid = gid;
2627c478bd9Sstevel@tonic-gate 	}
2637c478bd9Sstevel@tonic-gate 	if ((value = kva_match(exec->attr, EXECATTR_EUID_KW)) != NULL) {
2647c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.proc_euid = euid = get_uid(value);
2657c478bd9Sstevel@tonic-gate 	}
2667c478bd9Sstevel@tonic-gate 	if ((value = kva_match(exec->attr, EXECATTR_EGID_KW)) != NULL) {
2677c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.proc_egid = egid = get_gid(value);
2687c478bd9Sstevel@tonic-gate 	}
2697c478bd9Sstevel@tonic-gate 	if ((value = kva_match(exec->attr, EXECATTR_LPRIV_KW)) != NULL) {
2707c478bd9Sstevel@tonic-gate 		lset = get_privset(value);
2717c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.limit_set = lset;
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate 	if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) != NULL) {
2747c478bd9Sstevel@tonic-gate 		iset = get_privset(value);
2757c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.inherit_set = iset;
2767c478bd9Sstevel@tonic-gate 	}
2777c478bd9Sstevel@tonic-gate 	if (euid == uid || iset != NULL) {
2787c478bd9Sstevel@tonic-gate 		sanitize_environ();
2797c478bd9Sstevel@tonic-gate 	}
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	/* Finish audit info */
2827c478bd9Sstevel@tonic-gate 	event->adt_prof_cmd.cmdpath = cmd_realpath;
2837c478bd9Sstevel@tonic-gate 	event->adt_prof_cmd.argc = argc - 1;
2847c478bd9Sstevel@tonic-gate 	event->adt_prof_cmd.argv = &argv[1];
2857c478bd9Sstevel@tonic-gate 	event->adt_prof_cmd.envp = environ;
2867c478bd9Sstevel@tonic-gate 	if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
2877c478bd9Sstevel@tonic-gate 		perror("pfexec: adt_put_event");
2887c478bd9Sstevel@tonic-gate 		return (0);
2897c478bd9Sstevel@tonic-gate 	}
2907c478bd9Sstevel@tonic-gate 	adt_free_event(event);
2917c478bd9Sstevel@tonic-gate 	(void) adt_end_session(ah);
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate set_attrs:
2947c478bd9Sstevel@tonic-gate 	/*
2957c478bd9Sstevel@tonic-gate 	 * Set gids/uids and privileges.
2967c478bd9Sstevel@tonic-gate 	 *
2977c478bd9Sstevel@tonic-gate 	 */
298*f48205beScasper 	if ((gid != (gid_t)-1) || (egid != (gid_t)-1)) {
2997c478bd9Sstevel@tonic-gate 		if ((setregid(gid, egid) == -1)) {
3007c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: ", cmd_realpath);
3017c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("can't set gid\n"));
3027c478bd9Sstevel@tonic-gate 			return (0);
3037c478bd9Sstevel@tonic-gate 		}
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 	if (lset != NULL && setppriv(PRIV_SET, PRIV_LIMIT, lset) != 0 ||
3067c478bd9Sstevel@tonic-gate 	    iset != NULL && setppriv(PRIV_ON, PRIV_INHERITABLE, iset) != 0) {
3077c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: can't set privileges\n"),
3087c478bd9Sstevel@tonic-gate 			cmd_realpath);
3097c478bd9Sstevel@tonic-gate 		return (0);
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 	if (setreuid(uid, euid) == -1) {
3127c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: ", cmd_realpath);
3137c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("can't set uid\n"));
3147c478bd9Sstevel@tonic-gate 		return (0);
3157c478bd9Sstevel@tonic-gate 	}
3167c478bd9Sstevel@tonic-gate 	if (iset != NULL && getppriv(PRIV_INHERITABLE, iset) == 0)
3177c478bd9Sstevel@tonic-gate 		(void) setppriv(PRIV_SET, PRIV_PERMITTED, iset);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	free_execattr(exec);
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	return (1);
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate /*
3267c478bd9Sstevel@tonic-gate  * cleans up environ. code from su.c
3277c478bd9Sstevel@tonic-gate  */
3287c478bd9Sstevel@tonic-gate static void
3297c478bd9Sstevel@tonic-gate sanitize_environ()
3307c478bd9Sstevel@tonic-gate {
3317c478bd9Sstevel@tonic-gate 	char	**pp = environ;
3327c478bd9Sstevel@tonic-gate 	char	**qq, *p;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	while ((p = *pp) != NULL) {
3357c478bd9Sstevel@tonic-gate 		if (*p == 'L' && p[1] == 'D' && p[2] == '_') {
3367c478bd9Sstevel@tonic-gate 			for (qq = pp; (*qq = qq[1]) != NULL; qq++) {
3377c478bd9Sstevel@tonic-gate 				;
3387c478bd9Sstevel@tonic-gate 			}
3397c478bd9Sstevel@tonic-gate 		} else {
3407c478bd9Sstevel@tonic-gate 			pp++;
3417c478bd9Sstevel@tonic-gate 		}
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate static uid_t
3477c478bd9Sstevel@tonic-gate get_uid(char *value)
3487c478bd9Sstevel@tonic-gate {
3497c478bd9Sstevel@tonic-gate 	struct passwd *passwd_ent;
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	if ((passwd_ent = getpwnam(value)) != NULL)
3527c478bd9Sstevel@tonic-gate 		return (passwd_ent->pw_uid);
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	if (isnumber(value))
3557c478bd9Sstevel@tonic-gate 		return (atoi(value));
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "pfexec: %s: ", value);
3587c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("can't get user entry\n"));
3597c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
3607c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate static uid_t
3657c478bd9Sstevel@tonic-gate get_gid(char *value)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	struct group *group_ent;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	if ((group_ent = getgrnam(value)) != NULL)
3707c478bd9Sstevel@tonic-gate 		return (group_ent->gr_gid);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	if (isnumber(value))
3737c478bd9Sstevel@tonic-gate 		return (atoi(value));
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "pfexec: %s: ", value);
3767c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("can't get group entry\n"));
3777c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
3787c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate static int
3837c478bd9Sstevel@tonic-gate isnumber(char *s)
3847c478bd9Sstevel@tonic-gate {
3857c478bd9Sstevel@tonic-gate 	int c;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	if (*s == '\0')
3887c478bd9Sstevel@tonic-gate 		return (0);
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	while ((c = *s++) != '\0') {
3917c478bd9Sstevel@tonic-gate 		if (!isdigit(c)) {
3927c478bd9Sstevel@tonic-gate 			return (0);
3937c478bd9Sstevel@tonic-gate 		}
3947c478bd9Sstevel@tonic-gate 	}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	return (1);
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate static priv_set_t *
4007c478bd9Sstevel@tonic-gate get_privset(const char *s)
4017c478bd9Sstevel@tonic-gate {
4027c478bd9Sstevel@tonic-gate 	priv_set_t *res;
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	if ((res = priv_str_to_set(s, ",", NULL)) == NULL) {
4057c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: bad privilege set\n", s);
4067c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
4077c478bd9Sstevel@tonic-gate 	}
4087c478bd9Sstevel@tonic-gate 	return (res);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate static void
4127c478bd9Sstevel@tonic-gate usage(void)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("pfexec [-P privset] cmd [arg ..]\n"));
4157c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate /*
4207c478bd9Sstevel@tonic-gate  * This routine exists on failure and returns NULL if no granted privileges
4217c478bd9Sstevel@tonic-gate  * are set.
4227c478bd9Sstevel@tonic-gate  */
4237c478bd9Sstevel@tonic-gate static priv_set_t *
4247c478bd9Sstevel@tonic-gate get_granted_privs(uid_t uid)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	struct passwd *pwent;
4277c478bd9Sstevel@tonic-gate 	userattr_t *ua;
4287c478bd9Sstevel@tonic-gate 	char *profs;
4297c478bd9Sstevel@tonic-gate 	priv_set_t *res;
4307c478bd9Sstevel@tonic-gate 	char *profArray[MAXPROFS];
4317c478bd9Sstevel@tonic-gate 	int profcnt = 0;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	res = priv_allocset();
4347c478bd9Sstevel@tonic-gate 	if (res == NULL) {
4357c478bd9Sstevel@tonic-gate 		perror("priv_allocset");
4367c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	priv_emptyset(res);
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	if ((pwent = getpwuid(uid)) == NULL) {
4427c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%d: ", (int)uid);
4437c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("can't get passwd entry\n"));
4447c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
4457c478bd9Sstevel@tonic-gate 	}
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	ua = getusernam(pwent->pw_name);
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	if (ua != NULL && ua->attr != NULL &&
4507c478bd9Sstevel@tonic-gate 	    (profs = kva_match(ua->attr, USERATTR_PROFILES_KW)) != NULL) {
4517c478bd9Sstevel@tonic-gate 		get_profile_privs(profs, profArray, &profcnt, res);
4527c478bd9Sstevel@tonic-gate 		free_proflist(profArray, profcnt);
4537c478bd9Sstevel@tonic-gate 	}
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	get_default_privs(res);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	if (ua != NULL)
4587c478bd9Sstevel@tonic-gate 		free_userattr(ua);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	return (res);
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate static void
4647c478bd9Sstevel@tonic-gate get_default_privs(priv_set_t *pset)
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate 	char *profs = NULL;
4677c478bd9Sstevel@tonic-gate 	char *profArray[MAXPROFS];
4687c478bd9Sstevel@tonic-gate 	int profcnt = 0;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	if (defopen(AUTH_POLICY) == 0) {
4717c478bd9Sstevel@tonic-gate 		/* get privileges from default profiles */
4727c478bd9Sstevel@tonic-gate 		profs = defread(DEF_PROF);
4737c478bd9Sstevel@tonic-gate 		if (profs != NULL) {
4747c478bd9Sstevel@tonic-gate 			get_profile_privs(profs, profArray, &profcnt, pset);
4757c478bd9Sstevel@tonic-gate 			free_proflist(profArray, profcnt);
4767c478bd9Sstevel@tonic-gate 		}
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 	(void) defopen(NULL);
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate static void
4827c478bd9Sstevel@tonic-gate get_profile_privs(char *profiles, char **profArray, int *profcnt,
4837c478bd9Sstevel@tonic-gate 	priv_set_t *pset)
4847c478bd9Sstevel@tonic-gate {
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	char		*prof;
4877c478bd9Sstevel@tonic-gate 	char		*lasts;
4887c478bd9Sstevel@tonic-gate 	profattr_t	*pa;
4897c478bd9Sstevel@tonic-gate 	char		*privs;
4907c478bd9Sstevel@tonic-gate 	int		i;
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	for (prof = strtok_r(profiles, PROFLIST_SEP, &lasts);
4937c478bd9Sstevel@tonic-gate 	    prof != NULL;
4947c478bd9Sstevel@tonic-gate 	    prof = strtok_r(NULL, PROFLIST_SEP, &lasts))
4957c478bd9Sstevel@tonic-gate 		getproflist(prof, profArray, profcnt);
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	/* get the privileges from list of profiles */
4987c478bd9Sstevel@tonic-gate 	for (i = 0; i < *profcnt; i++) {
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 		if ((pa = getprofnam(profArray[i])) == NULL) {
5017c478bd9Sstevel@tonic-gate 			/*
5027c478bd9Sstevel@tonic-gate 			 *  this should never happen.
5037c478bd9Sstevel@tonic-gate 			 *  unless the database has an undefined profile
5047c478bd9Sstevel@tonic-gate 			 */
5057c478bd9Sstevel@tonic-gate 			continue;
5067c478bd9Sstevel@tonic-gate 		}
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 		/* get privs from this profile */
5097c478bd9Sstevel@tonic-gate 		privs = kva_match(pa->attr, PROFATTR_PRIVS_KW);
5107c478bd9Sstevel@tonic-gate 		if (privs != NULL) {
5117c478bd9Sstevel@tonic-gate 			priv_set_t *tmp = priv_str_to_set(privs, ",", NULL);
5127c478bd9Sstevel@tonic-gate 			if (tmp != NULL) {
5137c478bd9Sstevel@tonic-gate 				priv_union(tmp, pset);
5147c478bd9Sstevel@tonic-gate 				priv_freeset(tmp);
5157c478bd9Sstevel@tonic-gate 			}
5167c478bd9Sstevel@tonic-gate 		}
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 		free_profattr(pa);
5197c478bd9Sstevel@tonic-gate 	}
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate /*
5237c478bd9Sstevel@tonic-gate  * This function can return either the first argument or dynamically
5247c478bd9Sstevel@tonic-gate  * allocated memory.  Reuse with care.
5257c478bd9Sstevel@tonic-gate  */
5267c478bd9Sstevel@tonic-gate static char *
5277c478bd9Sstevel@tonic-gate pathsearch(char *cmd)
5287c478bd9Sstevel@tonic-gate {
5297c478bd9Sstevel@tonic-gate 	char *path, *dir;
5307c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	/*
5337c478bd9Sstevel@tonic-gate 	 * Implement shell like PATH searching; if the pathname contains
5347c478bd9Sstevel@tonic-gate 	 * one or more slashes, don't search the path, even if the '/'
5357c478bd9Sstevel@tonic-gate 	 * isn't the first character. (E.g., ./command or dir/command)
5367c478bd9Sstevel@tonic-gate 	 * No path equals to a search in ".", just like the shell.
5377c478bd9Sstevel@tonic-gate 	 */
5387c478bd9Sstevel@tonic-gate 	if (strchr(cmd, '/') != NULL)
5397c478bd9Sstevel@tonic-gate 		return (cmd);
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	path = getenv("PATH");
5427c478bd9Sstevel@tonic-gate 	if (path == NULL)
5437c478bd9Sstevel@tonic-gate 		return (cmd);
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	/*
5467c478bd9Sstevel@tonic-gate 	 * We need to copy $PATH because our sub processes may need it.
5477c478bd9Sstevel@tonic-gate 	 */
5487c478bd9Sstevel@tonic-gate 	path = strdup(path);
5497c478bd9Sstevel@tonic-gate 	if (path == NULL) {
5507c478bd9Sstevel@tonic-gate 		perror("pfexec: strdup $PATH");
5517c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
5527c478bd9Sstevel@tonic-gate 	}
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":")) {
5557c478bd9Sstevel@tonic-gate 		if (snprintf(buf, sizeof (buf), "%s/%s", dir, cmd) >=
5567c478bd9Sstevel@tonic-gate 		    sizeof (buf)) {
5577c478bd9Sstevel@tonic-gate 			continue;
5587c478bd9Sstevel@tonic-gate 		}
5597c478bd9Sstevel@tonic-gate 		if (access(buf, X_OK) == 0) {
5607c478bd9Sstevel@tonic-gate 			free(path);
5617c478bd9Sstevel@tonic-gate 			return (strdup(buf));
5627c478bd9Sstevel@tonic-gate 		}
5637c478bd9Sstevel@tonic-gate 	}
5647c478bd9Sstevel@tonic-gate 	free(path);
5657c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: Command not found\n"), cmd);
5667c478bd9Sstevel@tonic-gate 	return (NULL);
5677c478bd9Sstevel@tonic-gate }
568