xref: /illumos-gate/usr/src/cmd/pfexec/pfexec.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <errno.h>
30*7c478bd9Sstevel@tonic-gate #include <deflt.h>
31*7c478bd9Sstevel@tonic-gate #include <locale.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
34*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
35*7c478bd9Sstevel@tonic-gate #include <unistd.h>
36*7c478bd9Sstevel@tonic-gate #include <ctype.h>
37*7c478bd9Sstevel@tonic-gate #include <pwd.h>
38*7c478bd9Sstevel@tonic-gate #include <grp.h>
39*7c478bd9Sstevel@tonic-gate #include <string.h>
40*7c478bd9Sstevel@tonic-gate #include <exec_attr.h>
41*7c478bd9Sstevel@tonic-gate #include <user_attr.h>
42*7c478bd9Sstevel@tonic-gate #include <auth_attr.h>
43*7c478bd9Sstevel@tonic-gate #include <prof_attr.h>
44*7c478bd9Sstevel@tonic-gate #include <errno.h>
45*7c478bd9Sstevel@tonic-gate #include <priv.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #include <bsm/adt.h>
48*7c478bd9Sstevel@tonic-gate #include <bsm/adt_event.h>
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate #ifndef	TEXT_DOMAIN			/* Should be defined by cc -D */
51*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
52*7c478bd9Sstevel@tonic-gate #endif
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate extern int cannot_audit(int);
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate static char *pathsearch(char *);
57*7c478bd9Sstevel@tonic-gate static int getrealpath(const char *, char *);
58*7c478bd9Sstevel@tonic-gate static int checkattrs(char *, int, char *[]);
59*7c478bd9Sstevel@tonic-gate static void sanitize_environ();
60*7c478bd9Sstevel@tonic-gate static uid_t get_uid(char *);
61*7c478bd9Sstevel@tonic-gate static gid_t get_gid(char *);
62*7c478bd9Sstevel@tonic-gate static priv_set_t *get_privset(const char *);
63*7c478bd9Sstevel@tonic-gate static priv_set_t *get_granted_privs(uid_t);
64*7c478bd9Sstevel@tonic-gate static void get_default_privs(priv_set_t *);
65*7c478bd9Sstevel@tonic-gate static void get_profile_privs(char *, char **, int *, priv_set_t *);
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate static int isnumber(char *);
68*7c478bd9Sstevel@tonic-gate static void usage(void);
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate extern char **environ;
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate #define	PROFLIST_SEP	","
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate int
75*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
76*7c478bd9Sstevel@tonic-gate {
77*7c478bd9Sstevel@tonic-gate 	char		*cmd;
78*7c478bd9Sstevel@tonic-gate 	char		**cmdargs;
79*7c478bd9Sstevel@tonic-gate 	char		cmd_realpath[MAXPATHLEN];
80*7c478bd9Sstevel@tonic-gate 	int		c;
81*7c478bd9Sstevel@tonic-gate 	char 		*pset = NULL;
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
84*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "P:")) != EOF) {
87*7c478bd9Sstevel@tonic-gate 		switch (c) {
88*7c478bd9Sstevel@tonic-gate 		case 'P':
89*7c478bd9Sstevel@tonic-gate 			if (pset == NULL) {
90*7c478bd9Sstevel@tonic-gate 				pset = optarg;
91*7c478bd9Sstevel@tonic-gate 				break;
92*7c478bd9Sstevel@tonic-gate 			}
93*7c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
94*7c478bd9Sstevel@tonic-gate 		default:
95*7c478bd9Sstevel@tonic-gate 			usage();
96*7c478bd9Sstevel@tonic-gate 		}
97*7c478bd9Sstevel@tonic-gate 	}
98*7c478bd9Sstevel@tonic-gate 	argc -= optind;
99*7c478bd9Sstevel@tonic-gate 	argv += optind;
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	if (argc < 1)
102*7c478bd9Sstevel@tonic-gate 		usage();
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 	cmd = argv[0];
105*7c478bd9Sstevel@tonic-gate 	cmdargs = &argv[0];
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	if (pset != NULL) {
108*7c478bd9Sstevel@tonic-gate 		uid_t uid = getuid();
109*7c478bd9Sstevel@tonic-gate 		priv_set_t *wanted = get_privset(pset);
110*7c478bd9Sstevel@tonic-gate 		priv_set_t *granted;
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 		adt_session_data_t *ah;		/* audit session handle */
113*7c478bd9Sstevel@tonic-gate 		adt_event_data_t *event;	/* event to be generated */
114*7c478bd9Sstevel@tonic-gate 		char cwd[MAXPATHLEN];
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 		granted = get_granted_privs(uid);
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 		/* Audit use */
119*7c478bd9Sstevel@tonic-gate 		if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
120*7c478bd9Sstevel@tonic-gate 			perror("pfexec: adt_start_session");
121*7c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
122*7c478bd9Sstevel@tonic-gate 		}
123*7c478bd9Sstevel@tonic-gate 		if ((event = adt_alloc_event(ah, ADT_prof_cmd)) == NULL) {
124*7c478bd9Sstevel@tonic-gate 			perror("pfexec: adt_alloc_event");
125*7c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
126*7c478bd9Sstevel@tonic-gate 		}
127*7c478bd9Sstevel@tonic-gate 		if ((event->adt_prof_cmd.cwdpath =
128*7c478bd9Sstevel@tonic-gate 		    getcwd(cwd, sizeof (cwd))) == NULL) {
129*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
130*7c478bd9Sstevel@tonic-gate 			    gettext("pfexec: can't add cwd path\n"));
131*7c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
132*7c478bd9Sstevel@tonic-gate 		}
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.cmdpath = cmd;
135*7c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.argc = argc - 1;
136*7c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.argv = &argv[1];
137*7c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.envp = environ;
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 		if (granted != NULL) {
140*7c478bd9Sstevel@tonic-gate 			priv_intersect(granted, wanted);
141*7c478bd9Sstevel@tonic-gate 			event->adt_prof_cmd.inherit_set = wanted;
142*7c478bd9Sstevel@tonic-gate 			if (adt_put_event(event, ADT_SUCCESS,
143*7c478bd9Sstevel@tonic-gate 			    ADT_SUCCESS) != 0) {
144*7c478bd9Sstevel@tonic-gate 				perror("pfexec: adt_put_event");
145*7c478bd9Sstevel@tonic-gate 				exit(EXIT_FAILURE);
146*7c478bd9Sstevel@tonic-gate 			}
147*7c478bd9Sstevel@tonic-gate 			if (setppriv(PRIV_ON, PRIV_INHERITABLE, wanted) != 0) {
148*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
149*7c478bd9Sstevel@tonic-gate 						gettext("setppriv(): %s\n"),
150*7c478bd9Sstevel@tonic-gate 						strerror(errno));
151*7c478bd9Sstevel@tonic-gate 				exit(EXIT_FAILURE);
152*7c478bd9Sstevel@tonic-gate 			}
153*7c478bd9Sstevel@tonic-gate 			/* Trick exec into thinking we're not suid */
154*7c478bd9Sstevel@tonic-gate 			(void) setppriv(PRIV_ON, PRIV_PERMITTED, wanted);
155*7c478bd9Sstevel@tonic-gate 			priv_freeset(event->adt_prof_cmd.inherit_set);
156*7c478bd9Sstevel@tonic-gate 		} else {
157*7c478bd9Sstevel@tonic-gate 			if (adt_put_event(event, ADT_SUCCESS,
158*7c478bd9Sstevel@tonic-gate 			    ADT_SUCCESS) != 0) {
159*7c478bd9Sstevel@tonic-gate 				perror("pfexec: adt_put_event");
160*7c478bd9Sstevel@tonic-gate 				exit(EXIT_FAILURE);
161*7c478bd9Sstevel@tonic-gate 			}
162*7c478bd9Sstevel@tonic-gate 		}
163*7c478bd9Sstevel@tonic-gate 		adt_free_event(event);
164*7c478bd9Sstevel@tonic-gate 		(void) adt_end_session(ah);
165*7c478bd9Sstevel@tonic-gate 		(void) setreuid(uid, uid);
166*7c478bd9Sstevel@tonic-gate 		(void) execvp(cmd, cmdargs);
167*7c478bd9Sstevel@tonic-gate 		perror(cmd);
168*7c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
169*7c478bd9Sstevel@tonic-gate 	}
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	if ((cmd = pathsearch(cmd)) == NULL)
172*7c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	if (getrealpath(cmd, cmd_realpath) == 0)
175*7c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	if (checkattrs(cmd_realpath, argc, argv) == 0)
178*7c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	(void) execv(cmd, cmdargs);
181*7c478bd9Sstevel@tonic-gate 	/*
182*7c478bd9Sstevel@tonic-gate 	 * We'd be here only if execv fails.
183*7c478bd9Sstevel@tonic-gate 	 */
184*7c478bd9Sstevel@tonic-gate 	perror("pfexec");
185*7c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
186*7c478bd9Sstevel@tonic-gate /* LINTED */
187*7c478bd9Sstevel@tonic-gate }
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate /*
191*7c478bd9Sstevel@tonic-gate  * gets realpath for cmd.
192*7c478bd9Sstevel@tonic-gate  * return 1 on success, 0 on failure.
193*7c478bd9Sstevel@tonic-gate  */
194*7c478bd9Sstevel@tonic-gate static int
195*7c478bd9Sstevel@tonic-gate getrealpath(const char *cmd, char *cmd_realpath)
196*7c478bd9Sstevel@tonic-gate {
197*7c478bd9Sstevel@tonic-gate 	if (realpath(cmd, cmd_realpath) == NULL) {
198*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
199*7c478bd9Sstevel@tonic-gate 		    gettext("pfexec: can't get real path of ``%s''\n"), cmd);
200*7c478bd9Sstevel@tonic-gate 		return (0);
201*7c478bd9Sstevel@tonic-gate 	}
202*7c478bd9Sstevel@tonic-gate 	return (1);
203*7c478bd9Sstevel@tonic-gate }
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate /*
206*7c478bd9Sstevel@tonic-gate  * gets execution attributed for cmd, sets uids/gids, checks environ.
207*7c478bd9Sstevel@tonic-gate  * returns 1 on success, 0 on failure.
208*7c478bd9Sstevel@tonic-gate  */
209*7c478bd9Sstevel@tonic-gate static int
210*7c478bd9Sstevel@tonic-gate checkattrs(char *cmd_realpath, int argc, char *argv[])
211*7c478bd9Sstevel@tonic-gate {
212*7c478bd9Sstevel@tonic-gate 	char			*value;
213*7c478bd9Sstevel@tonic-gate 	uid_t			uid, euid;
214*7c478bd9Sstevel@tonic-gate 	gid_t			gid = -1;
215*7c478bd9Sstevel@tonic-gate 	gid_t			egid = -1;
216*7c478bd9Sstevel@tonic-gate 	struct passwd		*pwent;
217*7c478bd9Sstevel@tonic-gate 	execattr_t		*exec;
218*7c478bd9Sstevel@tonic-gate 	priv_set_t		*lset = NULL;
219*7c478bd9Sstevel@tonic-gate 	priv_set_t		*iset = NULL;
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	adt_session_data_t	*ah;		/* audit session handle */
222*7c478bd9Sstevel@tonic-gate 	adt_event_data_t	*event;		/* event to be generated */
223*7c478bd9Sstevel@tonic-gate 	char			cwd[MAXPATHLEN];
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	uid = euid = getuid();
226*7c478bd9Sstevel@tonic-gate 	if ((pwent = getpwuid(uid)) == NULL) {
227*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%d: ", (int)uid);
228*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("can't get passwd entry\n"));
229*7c478bd9Sstevel@tonic-gate 		return (0);
230*7c478bd9Sstevel@tonic-gate 	}
231*7c478bd9Sstevel@tonic-gate 	/* Set up to audit use */
232*7c478bd9Sstevel@tonic-gate 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
233*7c478bd9Sstevel@tonic-gate 		perror("pfexec: adt_start_session");
234*7c478bd9Sstevel@tonic-gate 		return (0);
235*7c478bd9Sstevel@tonic-gate 	}
236*7c478bd9Sstevel@tonic-gate 	if ((event = adt_alloc_event(ah, ADT_prof_cmd)) == NULL) {
237*7c478bd9Sstevel@tonic-gate 		perror("pfexec: adt_alloc_event");
238*7c478bd9Sstevel@tonic-gate 		return (0);
239*7c478bd9Sstevel@tonic-gate 	}
240*7c478bd9Sstevel@tonic-gate 	if ((event->adt_prof_cmd.cwdpath = getcwd(cwd, sizeof (cwd))) == NULL) {
241*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("pfexec: can't add cwd path\n"));
242*7c478bd9Sstevel@tonic-gate 		return (0);
243*7c478bd9Sstevel@tonic-gate 	}
244*7c478bd9Sstevel@tonic-gate 	/*
245*7c478bd9Sstevel@tonic-gate 	 * Get the exec attrs: uid, gid, euid and egid
246*7c478bd9Sstevel@tonic-gate 	 */
247*7c478bd9Sstevel@tonic-gate 	if ((exec = getexecuser(pwent->pw_name,
248*7c478bd9Sstevel@tonic-gate 	    KV_COMMAND, (char *)cmd_realpath, GET_ONE)) == NULL) {
249*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: ", cmd_realpath);
250*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
251*7c478bd9Sstevel@tonic-gate 		    gettext("can't get execution attributes\n"));
252*7c478bd9Sstevel@tonic-gate 		return (0);
253*7c478bd9Sstevel@tonic-gate 	}
254*7c478bd9Sstevel@tonic-gate 	if ((value = kva_match(exec->attr, EXECATTR_UID_KW)) != NULL) {
255*7c478bd9Sstevel@tonic-gate 		euid = uid = get_uid(value);
256*7c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.proc_euid = uid;
257*7c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.proc_ruid = uid;
258*7c478bd9Sstevel@tonic-gate 	}
259*7c478bd9Sstevel@tonic-gate 	if ((value = kva_match(exec->attr, EXECATTR_GID_KW)) != NULL) {
260*7c478bd9Sstevel@tonic-gate 		egid = gid = get_gid(value);
261*7c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.proc_egid = gid;
262*7c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.proc_rgid = gid;
263*7c478bd9Sstevel@tonic-gate 	}
264*7c478bd9Sstevel@tonic-gate 	if ((value = kva_match(exec->attr, EXECATTR_EUID_KW)) != NULL) {
265*7c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.proc_euid = euid = get_uid(value);
266*7c478bd9Sstevel@tonic-gate 	}
267*7c478bd9Sstevel@tonic-gate 	if ((value = kva_match(exec->attr, EXECATTR_EGID_KW)) != NULL) {
268*7c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.proc_egid = egid = get_gid(value);
269*7c478bd9Sstevel@tonic-gate 	}
270*7c478bd9Sstevel@tonic-gate 	if ((value = kva_match(exec->attr, EXECATTR_LPRIV_KW)) != NULL) {
271*7c478bd9Sstevel@tonic-gate 		lset = get_privset(value);
272*7c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.limit_set = lset;
273*7c478bd9Sstevel@tonic-gate 	}
274*7c478bd9Sstevel@tonic-gate 	if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) != NULL) {
275*7c478bd9Sstevel@tonic-gate 		iset = get_privset(value);
276*7c478bd9Sstevel@tonic-gate 		event->adt_prof_cmd.inherit_set = iset;
277*7c478bd9Sstevel@tonic-gate 	}
278*7c478bd9Sstevel@tonic-gate 	if (euid == uid || iset != NULL) {
279*7c478bd9Sstevel@tonic-gate 		sanitize_environ();
280*7c478bd9Sstevel@tonic-gate 	}
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	/* Finish audit info */
283*7c478bd9Sstevel@tonic-gate 	event->adt_prof_cmd.cmdpath = cmd_realpath;
284*7c478bd9Sstevel@tonic-gate 	event->adt_prof_cmd.argc = argc - 1;
285*7c478bd9Sstevel@tonic-gate 	event->adt_prof_cmd.argv = &argv[1];
286*7c478bd9Sstevel@tonic-gate 	event->adt_prof_cmd.envp = environ;
287*7c478bd9Sstevel@tonic-gate 	if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
288*7c478bd9Sstevel@tonic-gate 		perror("pfexec: adt_put_event");
289*7c478bd9Sstevel@tonic-gate 		return (0);
290*7c478bd9Sstevel@tonic-gate 	}
291*7c478bd9Sstevel@tonic-gate 	adt_free_event(event);
292*7c478bd9Sstevel@tonic-gate 	(void) adt_end_session(ah);
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate set_attrs:
295*7c478bd9Sstevel@tonic-gate 	/*
296*7c478bd9Sstevel@tonic-gate 	 * Set gids/uids and privileges.
297*7c478bd9Sstevel@tonic-gate 	 *
298*7c478bd9Sstevel@tonic-gate 	 */
299*7c478bd9Sstevel@tonic-gate 	if ((gid != -1) || (egid != -1)) {
300*7c478bd9Sstevel@tonic-gate 		if ((setregid(gid, egid) == -1)) {
301*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: ", cmd_realpath);
302*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("can't set gid\n"));
303*7c478bd9Sstevel@tonic-gate 			return (0);
304*7c478bd9Sstevel@tonic-gate 		}
305*7c478bd9Sstevel@tonic-gate 	}
306*7c478bd9Sstevel@tonic-gate 	if (lset != NULL && setppriv(PRIV_SET, PRIV_LIMIT, lset) != 0 ||
307*7c478bd9Sstevel@tonic-gate 	    iset != NULL && setppriv(PRIV_ON, PRIV_INHERITABLE, iset) != 0) {
308*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: can't set privileges\n"),
309*7c478bd9Sstevel@tonic-gate 			cmd_realpath);
310*7c478bd9Sstevel@tonic-gate 		return (0);
311*7c478bd9Sstevel@tonic-gate 	}
312*7c478bd9Sstevel@tonic-gate 	if (setreuid(uid, euid) == -1) {
313*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: ", cmd_realpath);
314*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("can't set uid\n"));
315*7c478bd9Sstevel@tonic-gate 		return (0);
316*7c478bd9Sstevel@tonic-gate 	}
317*7c478bd9Sstevel@tonic-gate 	if (iset != NULL && getppriv(PRIV_INHERITABLE, iset) == 0)
318*7c478bd9Sstevel@tonic-gate 		(void) setppriv(PRIV_SET, PRIV_PERMITTED, iset);
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	free_execattr(exec);
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	return (1);
323*7c478bd9Sstevel@tonic-gate }
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate /*
327*7c478bd9Sstevel@tonic-gate  * cleans up environ. code from su.c
328*7c478bd9Sstevel@tonic-gate  */
329*7c478bd9Sstevel@tonic-gate static void
330*7c478bd9Sstevel@tonic-gate sanitize_environ()
331*7c478bd9Sstevel@tonic-gate {
332*7c478bd9Sstevel@tonic-gate 	char	**pp = environ;
333*7c478bd9Sstevel@tonic-gate 	char	**qq, *p;
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	while ((p = *pp) != NULL) {
336*7c478bd9Sstevel@tonic-gate 		if (*p == 'L' && p[1] == 'D' && p[2] == '_') {
337*7c478bd9Sstevel@tonic-gate 			for (qq = pp; (*qq = qq[1]) != NULL; qq++) {
338*7c478bd9Sstevel@tonic-gate 				;
339*7c478bd9Sstevel@tonic-gate 			}
340*7c478bd9Sstevel@tonic-gate 		} else {
341*7c478bd9Sstevel@tonic-gate 			pp++;
342*7c478bd9Sstevel@tonic-gate 		}
343*7c478bd9Sstevel@tonic-gate 	}
344*7c478bd9Sstevel@tonic-gate }
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate static uid_t
348*7c478bd9Sstevel@tonic-gate get_uid(char *value)
349*7c478bd9Sstevel@tonic-gate {
350*7c478bd9Sstevel@tonic-gate 	struct passwd *passwd_ent;
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	if ((passwd_ent = getpwnam(value)) != NULL)
353*7c478bd9Sstevel@tonic-gate 		return (passwd_ent->pw_uid);
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 	if (isnumber(value))
356*7c478bd9Sstevel@tonic-gate 		return (atoi(value));
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "pfexec: %s: ", value);
359*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("can't get user entry\n"));
360*7c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
361*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
362*7c478bd9Sstevel@tonic-gate }
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate static uid_t
366*7c478bd9Sstevel@tonic-gate get_gid(char *value)
367*7c478bd9Sstevel@tonic-gate {
368*7c478bd9Sstevel@tonic-gate 	struct group *group_ent;
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 	if ((group_ent = getgrnam(value)) != NULL)
371*7c478bd9Sstevel@tonic-gate 		return (group_ent->gr_gid);
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	if (isnumber(value))
374*7c478bd9Sstevel@tonic-gate 		return (atoi(value));
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "pfexec: %s: ", value);
377*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("can't get group entry\n"));
378*7c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
379*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
380*7c478bd9Sstevel@tonic-gate }
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate static int
384*7c478bd9Sstevel@tonic-gate isnumber(char *s)
385*7c478bd9Sstevel@tonic-gate {
386*7c478bd9Sstevel@tonic-gate 	int c;
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	if (*s == '\0')
389*7c478bd9Sstevel@tonic-gate 		return (0);
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	while ((c = *s++) != '\0') {
392*7c478bd9Sstevel@tonic-gate 		if (!isdigit(c)) {
393*7c478bd9Sstevel@tonic-gate 			return (0);
394*7c478bd9Sstevel@tonic-gate 		}
395*7c478bd9Sstevel@tonic-gate 	}
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 	return (1);
398*7c478bd9Sstevel@tonic-gate }
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate static priv_set_t *
401*7c478bd9Sstevel@tonic-gate get_privset(const char *s)
402*7c478bd9Sstevel@tonic-gate {
403*7c478bd9Sstevel@tonic-gate 	priv_set_t *res;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	if ((res = priv_str_to_set(s, ",", NULL)) == NULL) {
406*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: bad privilege set\n", s);
407*7c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
408*7c478bd9Sstevel@tonic-gate 	}
409*7c478bd9Sstevel@tonic-gate 	return (res);
410*7c478bd9Sstevel@tonic-gate }
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate static void
413*7c478bd9Sstevel@tonic-gate usage(void)
414*7c478bd9Sstevel@tonic-gate {
415*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("pfexec [-P privset] cmd [arg ..]\n"));
416*7c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
417*7c478bd9Sstevel@tonic-gate }
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate /*
421*7c478bd9Sstevel@tonic-gate  * This routine exists on failure and returns NULL if no granted privileges
422*7c478bd9Sstevel@tonic-gate  * are set.
423*7c478bd9Sstevel@tonic-gate  */
424*7c478bd9Sstevel@tonic-gate static priv_set_t *
425*7c478bd9Sstevel@tonic-gate get_granted_privs(uid_t uid)
426*7c478bd9Sstevel@tonic-gate {
427*7c478bd9Sstevel@tonic-gate 	struct passwd *pwent;
428*7c478bd9Sstevel@tonic-gate 	userattr_t *ua;
429*7c478bd9Sstevel@tonic-gate 	char *profs;
430*7c478bd9Sstevel@tonic-gate 	priv_set_t *res;
431*7c478bd9Sstevel@tonic-gate 	char *profArray[MAXPROFS];
432*7c478bd9Sstevel@tonic-gate 	int profcnt = 0;
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	res = priv_allocset();
435*7c478bd9Sstevel@tonic-gate 	if (res == NULL) {
436*7c478bd9Sstevel@tonic-gate 		perror("priv_allocset");
437*7c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
438*7c478bd9Sstevel@tonic-gate 	}
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 	priv_emptyset(res);
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	if ((pwent = getpwuid(uid)) == NULL) {
443*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%d: ", (int)uid);
444*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("can't get passwd entry\n"));
445*7c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
446*7c478bd9Sstevel@tonic-gate 	}
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	ua = getusernam(pwent->pw_name);
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	if (ua != NULL && ua->attr != NULL &&
451*7c478bd9Sstevel@tonic-gate 	    (profs = kva_match(ua->attr, USERATTR_PROFILES_KW)) != NULL) {
452*7c478bd9Sstevel@tonic-gate 		get_profile_privs(profs, profArray, &profcnt, res);
453*7c478bd9Sstevel@tonic-gate 		free_proflist(profArray, profcnt);
454*7c478bd9Sstevel@tonic-gate 	}
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	get_default_privs(res);
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	if (ua != NULL)
459*7c478bd9Sstevel@tonic-gate 		free_userattr(ua);
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	return (res);
462*7c478bd9Sstevel@tonic-gate }
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate static void
465*7c478bd9Sstevel@tonic-gate get_default_privs(priv_set_t *pset)
466*7c478bd9Sstevel@tonic-gate {
467*7c478bd9Sstevel@tonic-gate 	char *profs = NULL;
468*7c478bd9Sstevel@tonic-gate 	char *profArray[MAXPROFS];
469*7c478bd9Sstevel@tonic-gate 	int profcnt = 0;
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 	if (defopen(AUTH_POLICY) == 0) {
472*7c478bd9Sstevel@tonic-gate 		/* get privileges from default profiles */
473*7c478bd9Sstevel@tonic-gate 		profs = defread(DEF_PROF);
474*7c478bd9Sstevel@tonic-gate 		if (profs != NULL) {
475*7c478bd9Sstevel@tonic-gate 			get_profile_privs(profs, profArray, &profcnt, pset);
476*7c478bd9Sstevel@tonic-gate 			free_proflist(profArray, profcnt);
477*7c478bd9Sstevel@tonic-gate 		}
478*7c478bd9Sstevel@tonic-gate 	}
479*7c478bd9Sstevel@tonic-gate 	(void) defopen(NULL);
480*7c478bd9Sstevel@tonic-gate }
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate static void
483*7c478bd9Sstevel@tonic-gate get_profile_privs(char *profiles, char **profArray, int *profcnt,
484*7c478bd9Sstevel@tonic-gate 	priv_set_t *pset)
485*7c478bd9Sstevel@tonic-gate {
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 	char		*prof;
488*7c478bd9Sstevel@tonic-gate 	char		*lasts;
489*7c478bd9Sstevel@tonic-gate 	profattr_t	*pa;
490*7c478bd9Sstevel@tonic-gate 	char		*privs;
491*7c478bd9Sstevel@tonic-gate 	int		i;
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	for (prof = strtok_r(profiles, PROFLIST_SEP, &lasts);
494*7c478bd9Sstevel@tonic-gate 	    prof != NULL;
495*7c478bd9Sstevel@tonic-gate 	    prof = strtok_r(NULL, PROFLIST_SEP, &lasts))
496*7c478bd9Sstevel@tonic-gate 		getproflist(prof, profArray, profcnt);
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	/* get the privileges from list of profiles */
499*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < *profcnt; i++) {
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 		if ((pa = getprofnam(profArray[i])) == NULL) {
502*7c478bd9Sstevel@tonic-gate 			/*
503*7c478bd9Sstevel@tonic-gate 			 *  this should never happen.
504*7c478bd9Sstevel@tonic-gate 			 *  unless the database has an undefined profile
505*7c478bd9Sstevel@tonic-gate 			 */
506*7c478bd9Sstevel@tonic-gate 			continue;
507*7c478bd9Sstevel@tonic-gate 		}
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 		/* get privs from this profile */
510*7c478bd9Sstevel@tonic-gate 		privs = kva_match(pa->attr, PROFATTR_PRIVS_KW);
511*7c478bd9Sstevel@tonic-gate 		if (privs != NULL) {
512*7c478bd9Sstevel@tonic-gate 			priv_set_t *tmp = priv_str_to_set(privs, ",", NULL);
513*7c478bd9Sstevel@tonic-gate 			if (tmp != NULL) {
514*7c478bd9Sstevel@tonic-gate 				priv_union(tmp, pset);
515*7c478bd9Sstevel@tonic-gate 				priv_freeset(tmp);
516*7c478bd9Sstevel@tonic-gate 			}
517*7c478bd9Sstevel@tonic-gate 		}
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 		free_profattr(pa);
520*7c478bd9Sstevel@tonic-gate 	}
521*7c478bd9Sstevel@tonic-gate }
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate /*
524*7c478bd9Sstevel@tonic-gate  * This function can return either the first argument or dynamically
525*7c478bd9Sstevel@tonic-gate  * allocated memory.  Reuse with care.
526*7c478bd9Sstevel@tonic-gate  */
527*7c478bd9Sstevel@tonic-gate static char *
528*7c478bd9Sstevel@tonic-gate pathsearch(char *cmd)
529*7c478bd9Sstevel@tonic-gate {
530*7c478bd9Sstevel@tonic-gate 	char *path, *dir;
531*7c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 	/*
534*7c478bd9Sstevel@tonic-gate 	 * Implement shell like PATH searching; if the pathname contains
535*7c478bd9Sstevel@tonic-gate 	 * one or more slashes, don't search the path, even if the '/'
536*7c478bd9Sstevel@tonic-gate 	 * isn't the first character. (E.g., ./command or dir/command)
537*7c478bd9Sstevel@tonic-gate 	 * No path equals to a search in ".", just like the shell.
538*7c478bd9Sstevel@tonic-gate 	 */
539*7c478bd9Sstevel@tonic-gate 	if (strchr(cmd, '/') != NULL)
540*7c478bd9Sstevel@tonic-gate 		return (cmd);
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	path = getenv("PATH");
543*7c478bd9Sstevel@tonic-gate 	if (path == NULL)
544*7c478bd9Sstevel@tonic-gate 		return (cmd);
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 	/*
547*7c478bd9Sstevel@tonic-gate 	 * We need to copy $PATH because our sub processes may need it.
548*7c478bd9Sstevel@tonic-gate 	 */
549*7c478bd9Sstevel@tonic-gate 	path = strdup(path);
550*7c478bd9Sstevel@tonic-gate 	if (path == NULL) {
551*7c478bd9Sstevel@tonic-gate 		perror("pfexec: strdup $PATH");
552*7c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
553*7c478bd9Sstevel@tonic-gate 	}
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":")) {
556*7c478bd9Sstevel@tonic-gate 		if (snprintf(buf, sizeof (buf), "%s/%s", dir, cmd) >=
557*7c478bd9Sstevel@tonic-gate 		    sizeof (buf)) {
558*7c478bd9Sstevel@tonic-gate 			continue;
559*7c478bd9Sstevel@tonic-gate 		}
560*7c478bd9Sstevel@tonic-gate 		if (access(buf, X_OK) == 0) {
561*7c478bd9Sstevel@tonic-gate 			free(path);
562*7c478bd9Sstevel@tonic-gate 			return (strdup(buf));
563*7c478bd9Sstevel@tonic-gate 		}
564*7c478bd9Sstevel@tonic-gate 	}
565*7c478bd9Sstevel@tonic-gate 	free(path);
566*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: Command not found\n"), cmd);
567*7c478bd9Sstevel@tonic-gate 	return (NULL);
568*7c478bd9Sstevel@tonic-gate }
569