xref: /titanic_52/usr/src/cmd/pfexecd/pfexecd.c (revision 134a1f4e3289b54e0f980e9cf05352e419a60bee)
1*134a1f4eSCasper H.S. Dik /*
2*134a1f4eSCasper H.S. Dik  * CDDL HEADER START
3*134a1f4eSCasper H.S. Dik  *
4*134a1f4eSCasper H.S. Dik  * The contents of this file are subject to the terms of the
5*134a1f4eSCasper H.S. Dik  * Common Development and Distribution License (the "License").
6*134a1f4eSCasper H.S. Dik  * You may not use this file except in compliance with the License.
7*134a1f4eSCasper H.S. Dik  *
8*134a1f4eSCasper H.S. Dik  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*134a1f4eSCasper H.S. Dik  * or http://www.opensolaris.org/os/licensing.
10*134a1f4eSCasper H.S. Dik  * See the License for the specific language governing permissions
11*134a1f4eSCasper H.S. Dik  * and limitations under the License.
12*134a1f4eSCasper H.S. Dik  *
13*134a1f4eSCasper H.S. Dik  * When distributing Covered Code, include this CDDL HEADER in each
14*134a1f4eSCasper H.S. Dik  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*134a1f4eSCasper H.S. Dik  * If applicable, add the following below this CDDL HEADER, with the
16*134a1f4eSCasper H.S. Dik  * fields enclosed by brackets "[]" replaced with your own identifying
17*134a1f4eSCasper H.S. Dik  * information: Portions Copyright [yyyy] [name of copyright owner]
18*134a1f4eSCasper H.S. Dik  *
19*134a1f4eSCasper H.S. Dik  * CDDL HEADER END
20*134a1f4eSCasper H.S. Dik  *
21*134a1f4eSCasper H.S. Dik  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
22*134a1f4eSCasper H.S. Dik  *
23*134a1f4eSCasper H.S. Dik  */
24*134a1f4eSCasper H.S. Dik 
25*134a1f4eSCasper H.S. Dik #define	_POSIX_PTHREAD_SEMANTICS 1
26*134a1f4eSCasper H.S. Dik 
27*134a1f4eSCasper H.S. Dik #include <sys/param.h>
28*134a1f4eSCasper H.S. Dik #include <sys/klpd.h>
29*134a1f4eSCasper H.S. Dik #include <sys/syscall.h>
30*134a1f4eSCasper H.S. Dik #include <sys/systeminfo.h>
31*134a1f4eSCasper H.S. Dik 
32*134a1f4eSCasper H.S. Dik #include <alloca.h>
33*134a1f4eSCasper H.S. Dik #include <ctype.h>
34*134a1f4eSCasper H.S. Dik #include <deflt.h>
35*134a1f4eSCasper H.S. Dik #include <door.h>
36*134a1f4eSCasper H.S. Dik #include <errno.h>
37*134a1f4eSCasper H.S. Dik #include <grp.h>
38*134a1f4eSCasper H.S. Dik #include <priv.h>
39*134a1f4eSCasper H.S. Dik #include <pwd.h>
40*134a1f4eSCasper H.S. Dik #include <regex.h>
41*134a1f4eSCasper H.S. Dik #include <secdb.h>
42*134a1f4eSCasper H.S. Dik #include <signal.h>
43*134a1f4eSCasper H.S. Dik #include <stdio.h>
44*134a1f4eSCasper H.S. Dik #include <stdlib.h>
45*134a1f4eSCasper H.S. Dik #include <string.h>
46*134a1f4eSCasper H.S. Dik #include <syslog.h>
47*134a1f4eSCasper H.S. Dik #include <unistd.h>
48*134a1f4eSCasper H.S. Dik 
49*134a1f4eSCasper H.S. Dik #include <auth_attr.h>
50*134a1f4eSCasper H.S. Dik #include <exec_attr.h>
51*134a1f4eSCasper H.S. Dik #include <prof_attr.h>
52*134a1f4eSCasper H.S. Dik #include <user_attr.h>
53*134a1f4eSCasper H.S. Dik 
54*134a1f4eSCasper H.S. Dik static int doorfd = -1;
55*134a1f4eSCasper H.S. Dik 
56*134a1f4eSCasper H.S. Dik static size_t repsz, setsz;
57*134a1f4eSCasper H.S. Dik 
58*134a1f4eSCasper H.S. Dik static uid_t get_uid(const char *, boolean_t *, char *);
59*134a1f4eSCasper H.S. Dik static gid_t get_gid(const char *, boolean_t *, char *);
60*134a1f4eSCasper H.S. Dik static priv_set_t *get_privset(const char *, boolean_t *, char *);
61*134a1f4eSCasper H.S. Dik static priv_set_t *get_granted_privs(uid_t);
62*134a1f4eSCasper H.S. Dik 
63*134a1f4eSCasper H.S. Dik /*
64*134a1f4eSCasper H.S. Dik  * Remove the isaexec path of an executable if we can't find the
65*134a1f4eSCasper H.S. Dik  * executable at the first attempt.
66*134a1f4eSCasper H.S. Dik  */
67*134a1f4eSCasper H.S. Dik 
68*134a1f4eSCasper H.S. Dik static regex_t regc;
69*134a1f4eSCasper H.S. Dik static boolean_t cansplice = B_TRUE;
70*134a1f4eSCasper H.S. Dik 
71*134a1f4eSCasper H.S. Dik static void
72*134a1f4eSCasper H.S. Dik init_isa_regex(void)
73*134a1f4eSCasper H.S. Dik {
74*134a1f4eSCasper H.S. Dik 	char *isalist;
75*134a1f4eSCasper H.S. Dik 	size_t isalen = 255;		/* wild guess */
76*134a1f4eSCasper H.S. Dik 	size_t len;
77*134a1f4eSCasper H.S. Dik 	long ret;
78*134a1f4eSCasper H.S. Dik 	char *regexpr;
79*134a1f4eSCasper H.S. Dik 	char *p;
80*134a1f4eSCasper H.S. Dik 
81*134a1f4eSCasper H.S. Dik 	/*
82*134a1f4eSCasper H.S. Dik 	 * Extract the isalist(5) for userland from the kernel.
83*134a1f4eSCasper H.S. Dik 	 */
84*134a1f4eSCasper H.S. Dik 	isalist = malloc(isalen);
85*134a1f4eSCasper H.S. Dik 	do {
86*134a1f4eSCasper H.S. Dik 		ret = sysinfo(SI_ISALIST, isalist, isalen);
87*134a1f4eSCasper H.S. Dik 		if (ret == -1l) {
88*134a1f4eSCasper H.S. Dik 			free(isalist);
89*134a1f4eSCasper H.S. Dik 			return;
90*134a1f4eSCasper H.S. Dik 		}
91*134a1f4eSCasper H.S. Dik 		if (ret > isalen) {
92*134a1f4eSCasper H.S. Dik 			isalen = ret;
93*134a1f4eSCasper H.S. Dik 			isalist = realloc(isalist, isalen);
94*134a1f4eSCasper H.S. Dik 		} else
95*134a1f4eSCasper H.S. Dik 			break;
96*134a1f4eSCasper H.S. Dik 	} while (isalist != NULL);
97*134a1f4eSCasper H.S. Dik 
98*134a1f4eSCasper H.S. Dik 
99*134a1f4eSCasper H.S. Dik 	if (isalist == NULL)
100*134a1f4eSCasper H.S. Dik 		return;
101*134a1f4eSCasper H.S. Dik 
102*134a1f4eSCasper H.S. Dik 	/* allocate room for the regex + (/())/[^/]*$ + needed \\. */
103*134a1f4eSCasper H.S. Dik #define	LEFT	"(/("
104*134a1f4eSCasper H.S. Dik #define	RIGHT	"))/[^/]*$"
105*134a1f4eSCasper H.S. Dik 
106*134a1f4eSCasper H.S. Dik 	regexpr = alloca(ret * 2 + sizeof (LEFT RIGHT));
107*134a1f4eSCasper H.S. Dik 	(void) strcpy(regexpr, LEFT);
108*134a1f4eSCasper H.S. Dik 	len = strlen(regexpr);
109*134a1f4eSCasper H.S. Dik 
110*134a1f4eSCasper H.S. Dik 	for (p = isalist; *p; p++) {
111*134a1f4eSCasper H.S. Dik 		switch (*p) {
112*134a1f4eSCasper H.S. Dik 		case '+':
113*134a1f4eSCasper H.S. Dik 		case '|':
114*134a1f4eSCasper H.S. Dik 		case '*':
115*134a1f4eSCasper H.S. Dik 		case '[':
116*134a1f4eSCasper H.S. Dik 		case ']':
117*134a1f4eSCasper H.S. Dik 		case '{':
118*134a1f4eSCasper H.S. Dik 		case '}':
119*134a1f4eSCasper H.S. Dik 		case '\\':
120*134a1f4eSCasper H.S. Dik 			regexpr[len++] = '\\';
121*134a1f4eSCasper H.S. Dik 		default:
122*134a1f4eSCasper H.S. Dik 			regexpr[len++] = *p;
123*134a1f4eSCasper H.S. Dik 			break;
124*134a1f4eSCasper H.S. Dik 		case ' ':
125*134a1f4eSCasper H.S. Dik 		case '\t':
126*134a1f4eSCasper H.S. Dik 			regexpr[len++] = '|';
127*134a1f4eSCasper H.S. Dik 			break;
128*134a1f4eSCasper H.S. Dik 		}
129*134a1f4eSCasper H.S. Dik 	}
130*134a1f4eSCasper H.S. Dik 
131*134a1f4eSCasper H.S. Dik 	free(isalist);
132*134a1f4eSCasper H.S. Dik 	regexpr[len] = '\0';
133*134a1f4eSCasper H.S. Dik 	(void) strcat(regexpr, RIGHT);
134*134a1f4eSCasper H.S. Dik 
135*134a1f4eSCasper H.S. Dik 	if (regcomp(&regc, regexpr, REG_EXTENDED) != 0)
136*134a1f4eSCasper H.S. Dik 		return;
137*134a1f4eSCasper H.S. Dik 
138*134a1f4eSCasper H.S. Dik 	cansplice = B_TRUE;
139*134a1f4eSCasper H.S. Dik }
140*134a1f4eSCasper H.S. Dik 
141*134a1f4eSCasper H.S. Dik #define	NMATCH	2
142*134a1f4eSCasper H.S. Dik 
143*134a1f4eSCasper H.S. Dik static boolean_t
144*134a1f4eSCasper H.S. Dik removeisapath(char *path)
145*134a1f4eSCasper H.S. Dik {
146*134a1f4eSCasper H.S. Dik 	regmatch_t match[NMATCH];
147*134a1f4eSCasper H.S. Dik 
148*134a1f4eSCasper H.S. Dik 	if (!cansplice || regexec(&regc, path, NMATCH, match, 0) != 0)
149*134a1f4eSCasper H.S. Dik 		return (B_FALSE);
150*134a1f4eSCasper H.S. Dik 
151*134a1f4eSCasper H.S. Dik 	/*
152*134a1f4eSCasper H.S. Dik 	 * The first match includes the whole matched expression including the
153*134a1f4eSCasper H.S. Dik 	 * end of the string.  The second match includes the "/" + "isa" and
154*134a1f4eSCasper H.S. Dik 	 * that is the part we need to remove.
155*134a1f4eSCasper H.S. Dik 	 */
156*134a1f4eSCasper H.S. Dik 
157*134a1f4eSCasper H.S. Dik 	if (match[1].rm_so == -1)
158*134a1f4eSCasper H.S. Dik 		return (B_FALSE);
159*134a1f4eSCasper H.S. Dik 
160*134a1f4eSCasper H.S. Dik 	/* match[0].rm_eo == strlen(path) */
161*134a1f4eSCasper H.S. Dik 	(void) memmove(path + match[1].rm_so, path + match[1].rm_eo,
162*134a1f4eSCasper H.S. Dik 	    match[0].rm_eo - match[1].rm_eo + 1);
163*134a1f4eSCasper H.S. Dik 
164*134a1f4eSCasper H.S. Dik 	return (B_TRUE);
165*134a1f4eSCasper H.S. Dik }
166*134a1f4eSCasper H.S. Dik 
167*134a1f4eSCasper H.S. Dik static int
168*134a1f4eSCasper H.S. Dik register_pfexec(int fd)
169*134a1f4eSCasper H.S. Dik {
170*134a1f4eSCasper H.S. Dik 	int ret = syscall(SYS_privsys, PRIVSYS_PFEXEC_REG, fd);
171*134a1f4eSCasper H.S. Dik 
172*134a1f4eSCasper H.S. Dik 	return (ret);
173*134a1f4eSCasper H.S. Dik }
174*134a1f4eSCasper H.S. Dik 
175*134a1f4eSCasper H.S. Dik /* ARGSUSED */
176*134a1f4eSCasper H.S. Dik static void
177*134a1f4eSCasper H.S. Dik unregister_pfexec(int sig)
178*134a1f4eSCasper H.S. Dik {
179*134a1f4eSCasper H.S. Dik 	if (doorfd != -1)
180*134a1f4eSCasper H.S. Dik 		(void) syscall(SYS_privsys, PRIVSYS_PFEXEC_UNREG, doorfd);
181*134a1f4eSCasper H.S. Dik 	_exit(0);
182*134a1f4eSCasper H.S. Dik }
183*134a1f4eSCasper H.S. Dik 
184*134a1f4eSCasper H.S. Dik static int
185*134a1f4eSCasper H.S. Dik alldigits(const char *s)
186*134a1f4eSCasper H.S. Dik {
187*134a1f4eSCasper H.S. Dik 	int c;
188*134a1f4eSCasper H.S. Dik 
189*134a1f4eSCasper H.S. Dik 	if (*s == '\0')
190*134a1f4eSCasper H.S. Dik 		return (0);
191*134a1f4eSCasper H.S. Dik 
192*134a1f4eSCasper H.S. Dik 	while ((c = *s++) != '\0') {
193*134a1f4eSCasper H.S. Dik 		if (!isdigit(c)) {
194*134a1f4eSCasper H.S. Dik 			return (0);
195*134a1f4eSCasper H.S. Dik 		}
196*134a1f4eSCasper H.S. Dik 	}
197*134a1f4eSCasper H.S. Dik 
198*134a1f4eSCasper H.S. Dik 	return (1);
199*134a1f4eSCasper H.S. Dik }
200*134a1f4eSCasper H.S. Dik 
201*134a1f4eSCasper H.S. Dik static uid_t
202*134a1f4eSCasper H.S. Dik get_uid(const char *v, boolean_t *ok, char *path)
203*134a1f4eSCasper H.S. Dik {
204*134a1f4eSCasper H.S. Dik 	struct passwd *pwd, pwdm;
205*134a1f4eSCasper H.S. Dik 	char buf[1024];
206*134a1f4eSCasper H.S. Dik 
207*134a1f4eSCasper H.S. Dik 	if (getpwnam_r(v, &pwdm, buf, sizeof (buf), &pwd) == 0 && pwd != NULL)
208*134a1f4eSCasper H.S. Dik 		return (pwd->pw_uid);
209*134a1f4eSCasper H.S. Dik 
210*134a1f4eSCasper H.S. Dik 	if (alldigits(v))
211*134a1f4eSCasper H.S. Dik 		return (atoi(v));
212*134a1f4eSCasper H.S. Dik 
213*134a1f4eSCasper H.S. Dik 	*ok = B_FALSE;
214*134a1f4eSCasper H.S. Dik 	syslog(LOG_ERR, "%s: %s: unknown username\n", path, v);
215*134a1f4eSCasper H.S. Dik 	return ((uid_t)-1);
216*134a1f4eSCasper H.S. Dik }
217*134a1f4eSCasper H.S. Dik 
218*134a1f4eSCasper H.S. Dik static uid_t
219*134a1f4eSCasper H.S. Dik get_gid(const char *v, boolean_t *ok, char *path)
220*134a1f4eSCasper H.S. Dik {
221*134a1f4eSCasper H.S. Dik 	struct group *grp, grpm;
222*134a1f4eSCasper H.S. Dik 	char buf[1024];
223*134a1f4eSCasper H.S. Dik 
224*134a1f4eSCasper H.S. Dik 	if (getgrnam_r(v, &grpm, buf, sizeof (buf), &grp) == 0 && grp != NULL)
225*134a1f4eSCasper H.S. Dik 		return (grp->gr_gid);
226*134a1f4eSCasper H.S. Dik 
227*134a1f4eSCasper H.S. Dik 	if (alldigits(v))
228*134a1f4eSCasper H.S. Dik 		return (atoi(v));
229*134a1f4eSCasper H.S. Dik 
230*134a1f4eSCasper H.S. Dik 	*ok = B_FALSE;
231*134a1f4eSCasper H.S. Dik 	syslog(LOG_ERR, "%s: %s: unknown groupname\n", path, v);
232*134a1f4eSCasper H.S. Dik 	return ((gid_t)-1);
233*134a1f4eSCasper H.S. Dik }
234*134a1f4eSCasper H.S. Dik 
235*134a1f4eSCasper H.S. Dik static priv_set_t *
236*134a1f4eSCasper H.S. Dik get_privset(const char *s, boolean_t *ok, char *path)
237*134a1f4eSCasper H.S. Dik {
238*134a1f4eSCasper H.S. Dik 	priv_set_t *res;
239*134a1f4eSCasper H.S. Dik 
240*134a1f4eSCasper H.S. Dik 	if ((res = priv_str_to_set(s, ",", NULL)) == NULL) {
241*134a1f4eSCasper H.S. Dik 		syslog(LOG_ERR, "%s: %s: bad privilege set\n", path, s);
242*134a1f4eSCasper H.S. Dik 		if (ok != NULL)
243*134a1f4eSCasper H.S. Dik 			*ok = B_FALSE;
244*134a1f4eSCasper H.S. Dik 	}
245*134a1f4eSCasper H.S. Dik 	return (res);
246*134a1f4eSCasper H.S. Dik }
247*134a1f4eSCasper H.S. Dik 
248*134a1f4eSCasper H.S. Dik /*ARGSUSED*/
249*134a1f4eSCasper H.S. Dik static int
250*134a1f4eSCasper H.S. Dik ggp_callback(const char *prof, kva_t *attr, void *ctxt, void *vres)
251*134a1f4eSCasper H.S. Dik {
252*134a1f4eSCasper H.S. Dik 	priv_set_t *res = vres;
253*134a1f4eSCasper H.S. Dik 	char *privs;
254*134a1f4eSCasper H.S. Dik 
255*134a1f4eSCasper H.S. Dik 	if (attr == NULL)
256*134a1f4eSCasper H.S. Dik 		return (0);
257*134a1f4eSCasper H.S. Dik 
258*134a1f4eSCasper H.S. Dik 	/* get privs from this profile */
259*134a1f4eSCasper H.S. Dik 	privs = kva_match(attr, PROFATTR_PRIVS_KW);
260*134a1f4eSCasper H.S. Dik 	if (privs != NULL) {
261*134a1f4eSCasper H.S. Dik 		priv_set_t *tmp = priv_str_to_set(privs, ",", NULL);
262*134a1f4eSCasper H.S. Dik 		if (tmp != NULL) {
263*134a1f4eSCasper H.S. Dik 			priv_union(tmp, res);
264*134a1f4eSCasper H.S. Dik 			priv_freeset(tmp);
265*134a1f4eSCasper H.S. Dik 		}
266*134a1f4eSCasper H.S. Dik 	}
267*134a1f4eSCasper H.S. Dik 
268*134a1f4eSCasper H.S. Dik 	return (0);
269*134a1f4eSCasper H.S. Dik }
270*134a1f4eSCasper H.S. Dik 
271*134a1f4eSCasper H.S. Dik /*
272*134a1f4eSCasper H.S. Dik  * This routine exists on failure and returns NULL if no granted privileges
273*134a1f4eSCasper H.S. Dik  * are set.
274*134a1f4eSCasper H.S. Dik  */
275*134a1f4eSCasper H.S. Dik static priv_set_t *
276*134a1f4eSCasper H.S. Dik get_granted_privs(uid_t uid)
277*134a1f4eSCasper H.S. Dik {
278*134a1f4eSCasper H.S. Dik 	priv_set_t *res;
279*134a1f4eSCasper H.S. Dik 	struct passwd *pwd, pwdm;
280*134a1f4eSCasper H.S. Dik 	char buf[1024];
281*134a1f4eSCasper H.S. Dik 
282*134a1f4eSCasper H.S. Dik 	if (getpwuid_r(uid, &pwdm, buf, sizeof (buf), &pwd) != 0 || pwd == NULL)
283*134a1f4eSCasper H.S. Dik 		return (NULL);
284*134a1f4eSCasper H.S. Dik 
285*134a1f4eSCasper H.S. Dik 	res = priv_allocset();
286*134a1f4eSCasper H.S. Dik 	if (res == NULL)
287*134a1f4eSCasper H.S. Dik 		return (NULL);
288*134a1f4eSCasper H.S. Dik 
289*134a1f4eSCasper H.S. Dik 	priv_emptyset(res);
290*134a1f4eSCasper H.S. Dik 
291*134a1f4eSCasper H.S. Dik 	(void) _enum_profs(pwd->pw_name, ggp_callback, NULL, res);
292*134a1f4eSCasper H.S. Dik 
293*134a1f4eSCasper H.S. Dik 	return (res);
294*134a1f4eSCasper H.S. Dik }
295*134a1f4eSCasper H.S. Dik 
296*134a1f4eSCasper H.S. Dik static void
297*134a1f4eSCasper H.S. Dik callback_forced_privs(pfexec_arg_t *pap)
298*134a1f4eSCasper H.S. Dik {
299*134a1f4eSCasper H.S. Dik 	execattr_t *exec;
300*134a1f4eSCasper H.S. Dik 	char *value;
301*134a1f4eSCasper H.S. Dik 	priv_set_t *fset;
302*134a1f4eSCasper H.S. Dik 	void *res = alloca(setsz);
303*134a1f4eSCasper H.S. Dik 
304*134a1f4eSCasper H.S. Dik 	/* Empty set signifies no forced privileges. */
305*134a1f4eSCasper H.S. Dik 	priv_emptyset(res);
306*134a1f4eSCasper H.S. Dik 
307*134a1f4eSCasper H.S. Dik 	exec = getexecprof("Forced Privilege", KV_COMMAND, pap->pfa_path,
308*134a1f4eSCasper H.S. Dik 	    GET_ONE);
309*134a1f4eSCasper H.S. Dik 
310*134a1f4eSCasper H.S. Dik 	if (exec == NULL && removeisapath(pap->pfa_path)) {
311*134a1f4eSCasper H.S. Dik 		exec = getexecprof("Forced Privilege", KV_COMMAND,
312*134a1f4eSCasper H.S. Dik 		    pap->pfa_path, GET_ONE);
313*134a1f4eSCasper H.S. Dik 	}
314*134a1f4eSCasper H.S. Dik 
315*134a1f4eSCasper H.S. Dik 	if (exec == NULL) {
316*134a1f4eSCasper H.S. Dik 		(void) door_return(res, setsz, NULL, 0);
317*134a1f4eSCasper H.S. Dik 		return;
318*134a1f4eSCasper H.S. Dik 	}
319*134a1f4eSCasper H.S. Dik 
320*134a1f4eSCasper H.S. Dik 	if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) == NULL ||
321*134a1f4eSCasper H.S. Dik 	    (fset = get_privset(value, NULL, pap->pfa_path)) == NULL) {
322*134a1f4eSCasper H.S. Dik 		free_execattr(exec);
323*134a1f4eSCasper H.S. Dik 		(void) door_return(res, setsz, NULL, 0);
324*134a1f4eSCasper H.S. Dik 		return;
325*134a1f4eSCasper H.S. Dik 	}
326*134a1f4eSCasper H.S. Dik 
327*134a1f4eSCasper H.S. Dik 	priv_copyset(fset, res);
328*134a1f4eSCasper H.S. Dik 	priv_freeset(fset);
329*134a1f4eSCasper H.S. Dik 
330*134a1f4eSCasper H.S. Dik 	free_execattr(exec);
331*134a1f4eSCasper H.S. Dik 	(void) door_return(res, setsz, NULL, 0);
332*134a1f4eSCasper H.S. Dik }
333*134a1f4eSCasper H.S. Dik 
334*134a1f4eSCasper H.S. Dik static void
335*134a1f4eSCasper H.S. Dik callback_user_privs(pfexec_arg_t *pap)
336*134a1f4eSCasper H.S. Dik {
337*134a1f4eSCasper H.S. Dik 	priv_set_t *gset, *wset;
338*134a1f4eSCasper H.S. Dik 	uint32_t res;
339*134a1f4eSCasper H.S. Dik 
340*134a1f4eSCasper H.S. Dik 	wset = (priv_set_t *)&pap->pfa_buf;
341*134a1f4eSCasper H.S. Dik 	gset = get_granted_privs(pap->pfa_uid);
342*134a1f4eSCasper H.S. Dik 
343*134a1f4eSCasper H.S. Dik 	res = priv_issubset(wset, gset);
344*134a1f4eSCasper H.S. Dik 	priv_freeset(gset);
345*134a1f4eSCasper H.S. Dik 
346*134a1f4eSCasper H.S. Dik 	(void) door_return((char *)&res, sizeof (res), NULL, 0);
347*134a1f4eSCasper H.S. Dik }
348*134a1f4eSCasper H.S. Dik 
349*134a1f4eSCasper H.S. Dik static void
350*134a1f4eSCasper H.S. Dik callback_pfexec(pfexec_arg_t *pap)
351*134a1f4eSCasper H.S. Dik {
352*134a1f4eSCasper H.S. Dik 	pfexec_reply_t *res = alloca(repsz);
353*134a1f4eSCasper H.S. Dik 	uid_t uid, euid, uuid;
354*134a1f4eSCasper H.S. Dik 	gid_t gid, egid;
355*134a1f4eSCasper H.S. Dik 	struct passwd pw, *pwd;
356*134a1f4eSCasper H.S. Dik 	char buf[1024];
357*134a1f4eSCasper H.S. Dik 	execattr_t *exec;
358*134a1f4eSCasper H.S. Dik 	char *value;
359*134a1f4eSCasper H.S. Dik 	priv_set_t *lset, *iset;
360*134a1f4eSCasper H.S. Dik 	size_t mysz = repsz - 2 * setsz;
361*134a1f4eSCasper H.S. Dik 	char *path = pap->pfa_path;
362*134a1f4eSCasper H.S. Dik 
363*134a1f4eSCasper H.S. Dik 	uuid = pap->pfa_uid;
364*134a1f4eSCasper H.S. Dik 
365*134a1f4eSCasper H.S. Dik 	if (getpwuid_r(uuid, &pw, buf, sizeof (buf), &pwd) != 0 || pwd == NULL)
366*134a1f4eSCasper H.S. Dik 		goto stdexec;
367*134a1f4eSCasper H.S. Dik 
368*134a1f4eSCasper H.S. Dik 	exec = getexecuser(pwd->pw_name, KV_COMMAND, path, GET_ONE);
369*134a1f4eSCasper H.S. Dik 
370*134a1f4eSCasper H.S. Dik 	if (exec == NULL && removeisapath(path))
371*134a1f4eSCasper H.S. Dik 		exec = getexecuser(pwd->pw_name, KV_COMMAND, path, GET_ONE);
372*134a1f4eSCasper H.S. Dik 
373*134a1f4eSCasper H.S. Dik 	if (exec == NULL) {
374*134a1f4eSCasper H.S. Dik 		res->pfr_allowed = B_FALSE;
375*134a1f4eSCasper H.S. Dik 		goto ret;
376*134a1f4eSCasper H.S. Dik 	}
377*134a1f4eSCasper H.S. Dik 
378*134a1f4eSCasper H.S. Dik 	if (exec->attr == NULL)
379*134a1f4eSCasper H.S. Dik 		goto stdexec;
380*134a1f4eSCasper H.S. Dik 
381*134a1f4eSCasper H.S. Dik 	/* Found in execattr, so clearly we can use it */
382*134a1f4eSCasper H.S. Dik 	res->pfr_allowed = B_TRUE;
383*134a1f4eSCasper H.S. Dik 
384*134a1f4eSCasper H.S. Dik 	uid = euid = (uid_t)-1;
385*134a1f4eSCasper H.S. Dik 	gid = egid = (gid_t)-1;
386*134a1f4eSCasper H.S. Dik 	lset = iset = NULL;
387*134a1f4eSCasper H.S. Dik 
388*134a1f4eSCasper H.S. Dik 	/*
389*134a1f4eSCasper H.S. Dik 	 * If there's an error in parsing uid, gid, privs, then return
390*134a1f4eSCasper H.S. Dik 	 * failure.
391*134a1f4eSCasper H.S. Dik 	 */
392*134a1f4eSCasper H.S. Dik 	if ((value = kva_match(exec->attr, EXECATTR_UID_KW)) != NULL)
393*134a1f4eSCasper H.S. Dik 		euid = uid = get_uid(value, &res->pfr_allowed, path);
394*134a1f4eSCasper H.S. Dik 
395*134a1f4eSCasper H.S. Dik 	if ((value = kva_match(exec->attr, EXECATTR_GID_KW)) != NULL)
396*134a1f4eSCasper H.S. Dik 		egid = gid = get_gid(value, &res->pfr_allowed, path);
397*134a1f4eSCasper H.S. Dik 
398*134a1f4eSCasper H.S. Dik 	if ((value = kva_match(exec->attr, EXECATTR_EUID_KW)) != NULL)
399*134a1f4eSCasper H.S. Dik 		euid = get_uid(value, &res->pfr_allowed, path);
400*134a1f4eSCasper H.S. Dik 
401*134a1f4eSCasper H.S. Dik 	if ((value = kva_match(exec->attr, EXECATTR_EGID_KW)) != NULL)
402*134a1f4eSCasper H.S. Dik 		egid = get_gid(value, &res->pfr_allowed, path);
403*134a1f4eSCasper H.S. Dik 
404*134a1f4eSCasper H.S. Dik 	if ((value = kva_match(exec->attr, EXECATTR_LPRIV_KW)) != NULL)
405*134a1f4eSCasper H.S. Dik 		lset = get_privset(value, &res->pfr_allowed, path);
406*134a1f4eSCasper H.S. Dik 
407*134a1f4eSCasper H.S. Dik 	if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) != NULL)
408*134a1f4eSCasper H.S. Dik 		iset = get_privset(value, &res->pfr_allowed, path);
409*134a1f4eSCasper H.S. Dik 
410*134a1f4eSCasper H.S. Dik 	/*
411*134a1f4eSCasper H.S. Dik 	 * Remove LD_* variables in the kernel when the runtime linker might
412*134a1f4eSCasper H.S. Dik 	 * use them later on because the uids are equal.
413*134a1f4eSCasper H.S. Dik 	 */
414*134a1f4eSCasper H.S. Dik 	res->pfr_scrubenv = (uid != (uid_t)-1 && euid == uid) ||
415*134a1f4eSCasper H.S. Dik 	    (gid != (gid_t)-1 && egid == gid) || iset != NULL;
416*134a1f4eSCasper H.S. Dik 
417*134a1f4eSCasper H.S. Dik 	res->pfr_euid = euid;
418*134a1f4eSCasper H.S. Dik 	res->pfr_ruid = uid;
419*134a1f4eSCasper H.S. Dik 	res->pfr_egid = egid;
420*134a1f4eSCasper H.S. Dik 	res->pfr_rgid = gid;
421*134a1f4eSCasper H.S. Dik 
422*134a1f4eSCasper H.S. Dik 	/* Now add the privilege sets */
423*134a1f4eSCasper H.S. Dik 	res->pfr_ioff = res->pfr_loff = 0;
424*134a1f4eSCasper H.S. Dik 	if (iset != NULL) {
425*134a1f4eSCasper H.S. Dik 		res->pfr_ioff = mysz;
426*134a1f4eSCasper H.S. Dik 		priv_copyset(iset, PFEXEC_REPLY_IPRIV(res));
427*134a1f4eSCasper H.S. Dik 		mysz += setsz;
428*134a1f4eSCasper H.S. Dik 		priv_freeset(iset);
429*134a1f4eSCasper H.S. Dik 	}
430*134a1f4eSCasper H.S. Dik 	if (lset != NULL) {
431*134a1f4eSCasper H.S. Dik 		res->pfr_loff = mysz;
432*134a1f4eSCasper H.S. Dik 		priv_copyset(lset, PFEXEC_REPLY_LPRIV(res));
433*134a1f4eSCasper H.S. Dik 		mysz += setsz;
434*134a1f4eSCasper H.S. Dik 		priv_freeset(lset);
435*134a1f4eSCasper H.S. Dik 	}
436*134a1f4eSCasper H.S. Dik 
437*134a1f4eSCasper H.S. Dik 	res->pfr_setcred = uid != (uid_t)-1 || euid != (uid_t)-1 ||
438*134a1f4eSCasper H.S. Dik 	    egid != (gid_t)-1 || gid != (gid_t)-1 || iset != NULL ||
439*134a1f4eSCasper H.S. Dik 	    lset != NULL;
440*134a1f4eSCasper H.S. Dik 
441*134a1f4eSCasper H.S. Dik 	/* If the real uid changes, we stop running under a profile shell */
442*134a1f4eSCasper H.S. Dik 	res->pfr_clearflag = uid != (uid_t)-1 && uid != uuid;
443*134a1f4eSCasper H.S. Dik 	free_execattr(exec);
444*134a1f4eSCasper H.S. Dik ret:
445*134a1f4eSCasper H.S. Dik 	(void) door_return((char *)res, mysz, NULL, 0);
446*134a1f4eSCasper H.S. Dik 	return;
447*134a1f4eSCasper H.S. Dik 
448*134a1f4eSCasper H.S. Dik stdexec:
449*134a1f4eSCasper H.S. Dik 	res->pfr_scrubenv = B_FALSE;
450*134a1f4eSCasper H.S. Dik 	res->pfr_setcred = B_FALSE;
451*134a1f4eSCasper H.S. Dik 	res->pfr_allowed = B_TRUE;
452*134a1f4eSCasper H.S. Dik 
453*134a1f4eSCasper H.S. Dik 	(void) door_return((char *)res, mysz, NULL, 0);
454*134a1f4eSCasper H.S. Dik }
455*134a1f4eSCasper H.S. Dik 
456*134a1f4eSCasper H.S. Dik /* ARGSUSED */
457*134a1f4eSCasper H.S. Dik static void
458*134a1f4eSCasper H.S. Dik callback(void *cookie, char *argp, size_t asz, door_desc_t *dp, uint_t ndesc)
459*134a1f4eSCasper H.S. Dik {
460*134a1f4eSCasper H.S. Dik 	/* LINTED ALIGNMENT */
461*134a1f4eSCasper H.S. Dik 	pfexec_arg_t *pap = (pfexec_arg_t *)argp;
462*134a1f4eSCasper H.S. Dik 
463*134a1f4eSCasper H.S. Dik 	if (asz < sizeof (pfexec_arg_t) || pap->pfa_vers != PFEXEC_ARG_VERS) {
464*134a1f4eSCasper H.S. Dik 		(void) door_return(NULL, 0, NULL, 0);
465*134a1f4eSCasper H.S. Dik 		return;
466*134a1f4eSCasper H.S. Dik 	}
467*134a1f4eSCasper H.S. Dik 
468*134a1f4eSCasper H.S. Dik 	switch (pap->pfa_call) {
469*134a1f4eSCasper H.S. Dik 	case PFEXEC_EXEC_ATTRS:
470*134a1f4eSCasper H.S. Dik 		callback_pfexec(pap);
471*134a1f4eSCasper H.S. Dik 		break;
472*134a1f4eSCasper H.S. Dik 	case PFEXEC_FORCED_PRIVS:
473*134a1f4eSCasper H.S. Dik 		callback_forced_privs(pap);
474*134a1f4eSCasper H.S. Dik 		break;
475*134a1f4eSCasper H.S. Dik 	case PFEXEC_USER_PRIVS:
476*134a1f4eSCasper H.S. Dik 		callback_user_privs(pap);
477*134a1f4eSCasper H.S. Dik 		break;
478*134a1f4eSCasper H.S. Dik 	default:
479*134a1f4eSCasper H.S. Dik 		syslog(LOG_ERR, "Bad Call: %d\n", pap->pfa_call);
480*134a1f4eSCasper H.S. Dik 		break;
481*134a1f4eSCasper H.S. Dik 	}
482*134a1f4eSCasper H.S. Dik 
483*134a1f4eSCasper H.S. Dik 	/*
484*134a1f4eSCasper H.S. Dik 	 * If the door_return(ptr, size, NULL, 0) fails, make sure we
485*134a1f4eSCasper H.S. Dik 	 * don't lose server threads.
486*134a1f4eSCasper H.S. Dik 	 */
487*134a1f4eSCasper H.S. Dik 	(void) door_return(NULL, 0, NULL, 0);
488*134a1f4eSCasper H.S. Dik }
489*134a1f4eSCasper H.S. Dik 
490*134a1f4eSCasper H.S. Dik int
491*134a1f4eSCasper H.S. Dik main(void)
492*134a1f4eSCasper H.S. Dik {
493*134a1f4eSCasper H.S. Dik 	const priv_impl_info_t *info;
494*134a1f4eSCasper H.S. Dik 
495*134a1f4eSCasper H.S. Dik 	(void) signal(SIGINT, unregister_pfexec);
496*134a1f4eSCasper H.S. Dik 	(void) signal(SIGQUIT, unregister_pfexec);
497*134a1f4eSCasper H.S. Dik 	(void) signal(SIGTERM, unregister_pfexec);
498*134a1f4eSCasper H.S. Dik 	(void) signal(SIGHUP, unregister_pfexec);
499*134a1f4eSCasper H.S. Dik 
500*134a1f4eSCasper H.S. Dik 	info = getprivimplinfo();
501*134a1f4eSCasper H.S. Dik 	if (info == NULL)
502*134a1f4eSCasper H.S. Dik 		exit(1);
503*134a1f4eSCasper H.S. Dik 
504*134a1f4eSCasper H.S. Dik 	if (fork() > 0)
505*134a1f4eSCasper H.S. Dik 		_exit(0);
506*134a1f4eSCasper H.S. Dik 
507*134a1f4eSCasper H.S. Dik 	openlog("pfexecd", LOG_PID, LOG_DAEMON);
508*134a1f4eSCasper H.S. Dik 	setsz = info->priv_setsize * sizeof (priv_chunk_t);
509*134a1f4eSCasper H.S. Dik 	repsz = 2 * setsz + sizeof (pfexec_reply_t);
510*134a1f4eSCasper H.S. Dik 
511*134a1f4eSCasper H.S. Dik 	init_isa_regex();
512*134a1f4eSCasper H.S. Dik 
513*134a1f4eSCasper H.S. Dik 	doorfd = door_create(callback, NULL, DOOR_REFUSE_DESC);
514*134a1f4eSCasper H.S. Dik 
515*134a1f4eSCasper H.S. Dik 	if (doorfd == -1 || register_pfexec(doorfd) != 0) {
516*134a1f4eSCasper H.S. Dik 		perror("doorfd");
517*134a1f4eSCasper H.S. Dik 		exit(1);
518*134a1f4eSCasper H.S. Dik 	}
519*134a1f4eSCasper H.S. Dik 
520*134a1f4eSCasper H.S. Dik 	/* LINTED CONSTCOND */
521*134a1f4eSCasper H.S. Dik 	while (1)
522*134a1f4eSCasper H.S. Dik 		(void) sigpause(SIGINT);
523*134a1f4eSCasper H.S. Dik 
524*134a1f4eSCasper H.S. Dik 	return (0);
525*134a1f4eSCasper H.S. Dik }
526