xref: /illumos-gate/usr/src/uts/common/syscall/sidsys.c (revision f48205be61a214698b763ff550ab9e657525104c)
1*f48205beScasper /*
2*f48205beScasper  * CDDL HEADER START
3*f48205beScasper  *
4*f48205beScasper  * 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.
7*f48205beScasper  *
8*f48205beScasper  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*f48205beScasper  * or http://www.opensolaris.org/os/licensing.
10*f48205beScasper  * See the License for the specific language governing permissions
11*f48205beScasper  * and limitations under the License.
12*f48205beScasper  *
13*f48205beScasper  * When distributing Covered Code, include this CDDL HEADER in each
14*f48205beScasper  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*f48205beScasper  * If applicable, add the following below this CDDL HEADER, with the
16*f48205beScasper  * fields enclosed by brackets "[]" replaced with your own identifying
17*f48205beScasper  * information: Portions Copyright [yyyy] [name of copyright owner]
18*f48205beScasper  *
19*f48205beScasper  * CDDL HEADER END
20*f48205beScasper  */
21*f48205beScasper 
22*f48205beScasper /*
23*f48205beScasper  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*f48205beScasper  * Use is subject to license terms.
25*f48205beScasper  */
26*f48205beScasper 
27*f48205beScasper #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*f48205beScasper 
29*f48205beScasper /*
30*f48205beScasper  * SID system call.
31*f48205beScasper  */
32*f48205beScasper 
33*f48205beScasper #include <sys/sid.h>
34*f48205beScasper #include <sys/cred.h>
35*f48205beScasper #include <sys/errno.h>
36*f48205beScasper #include <sys/systm.h>
37*f48205beScasper #include <sys/policy.h>
38*f48205beScasper #include <sys/door.h>
39*f48205beScasper 
40*f48205beScasper static kmutex_t idmap_mutex;
41*f48205beScasper 
42*f48205beScasper typedef struct idmap_reg {
43*f48205beScasper 	door_handle_t 	idmap_door;
44*f48205beScasper 	int		idmap_flags;
45*f48205beScasper 	int		idmap_ref;
46*f48205beScasper } idmap_reg_t;
47*f48205beScasper 
48*f48205beScasper static idmap_reg_t *idmap_ptr;
49*f48205beScasper 
50*f48205beScasper static int idmap_unreg_dh(door_handle_t);
51*f48205beScasper 
52*f48205beScasper static void
53*f48205beScasper idmap_freeone(idmap_reg_t *p)
54*f48205beScasper {
55*f48205beScasper 	ASSERT(p->idmap_ref == 0);
56*f48205beScasper 	ASSERT(MUTEX_HELD(&idmap_mutex));
57*f48205beScasper 
58*f48205beScasper 	door_ki_rele(p->idmap_door);
59*f48205beScasper 	if (idmap_ptr == p)
60*f48205beScasper 		idmap_ptr = NULL;
61*f48205beScasper 
62*f48205beScasper 	kmem_free(p, sizeof (*p));
63*f48205beScasper }
64*f48205beScasper 
65*f48205beScasper static int
66*f48205beScasper idmap_do_call(sidmap_call_t *callp, size_t callsz, void **resp, size_t *respsz)
67*f48205beScasper {
68*f48205beScasper 	door_arg_t da;
69*f48205beScasper 	idmap_reg_t *p;
70*f48205beScasper 	int ret;
71*f48205beScasper 	int dres;
72*f48205beScasper 
73*f48205beScasper 	mutex_enter(&idmap_mutex);
74*f48205beScasper 	p = idmap_ptr;
75*f48205beScasper 	if (p != NULL) {
76*f48205beScasper 		p->idmap_ref++;
77*f48205beScasper 	} else {
78*f48205beScasper 		mutex_exit(&idmap_mutex);
79*f48205beScasper 		return (-1);
80*f48205beScasper 	}
81*f48205beScasper 	mutex_exit(&idmap_mutex);
82*f48205beScasper 
83*f48205beScasper 	da.data_ptr = (char *)callp;
84*f48205beScasper 	da.data_size = callsz;
85*f48205beScasper 	da.desc_ptr = NULL;
86*f48205beScasper 	da.desc_num = 0;
87*f48205beScasper 	da.rbuf = *resp;
88*f48205beScasper 	da.rsize = *respsz;
89*f48205beScasper 
90*f48205beScasper 	while ((dres = door_ki_upcall(p->idmap_door, &da)) != 0) {
91*f48205beScasper 		switch (dres) {
92*f48205beScasper 		case EINTR:
93*f48205beScasper 		case EAGAIN:
94*f48205beScasper 			delay(1);
95*f48205beScasper 			continue;
96*f48205beScasper 		case EINVAL:
97*f48205beScasper 		case EBADF:
98*f48205beScasper 			(void) idmap_unreg_dh(p->idmap_door);
99*f48205beScasper 			/* FALLTHROUGH */
100*f48205beScasper 		default:
101*f48205beScasper 			ret = -1;
102*f48205beScasper 			goto out;
103*f48205beScasper 		}
104*f48205beScasper 	}
105*f48205beScasper 	*resp = da.rbuf;
106*f48205beScasper 	*respsz = da.rsize;
107*f48205beScasper 	ret = 0;
108*f48205beScasper out:
109*f48205beScasper 	mutex_enter(&idmap_mutex);
110*f48205beScasper 	if (--p->idmap_ref == 0)
111*f48205beScasper 		idmap_freeone(p);
112*f48205beScasper 	mutex_exit(&idmap_mutex);
113*f48205beScasper 	return (ret);
114*f48205beScasper }
115*f48205beScasper 
116*f48205beScasper /*
117*f48205beScasper  * Current code only attempts to map ids to sids.
118*f48205beScasper  */
119*f48205beScasper int
120*f48205beScasper idmap_call_byid(uid_t id, ksid_t *ksid)
121*f48205beScasper {
122*f48205beScasper 	sidmap_call_t call;
123*f48205beScasper 	domsid_t res, *resp = &res;
124*f48205beScasper 	size_t respsz = sizeof (res);
125*f48205beScasper 
126*f48205beScasper 	call.sc_type = SIDSYS_ID2SID;
127*f48205beScasper 	call.sc_val.sc_id = id;
128*f48205beScasper 
129*f48205beScasper 	if (idmap_do_call(&call, sizeof (call), (void **)&resp, &respsz) != 0)
130*f48205beScasper 		return (-1);
131*f48205beScasper 
132*f48205beScasper 	ksid->ks_domain = ksid_lookupdomain(resp->ds_dom);
133*f48205beScasper 	ksid->ks_rid = resp->ds_rid;
134*f48205beScasper 
135*f48205beScasper 	/* Larger SID return value; this usually happens */
136*f48205beScasper 	if (resp != &res)
137*f48205beScasper 		kmem_free(resp, respsz);
138*f48205beScasper 
139*f48205beScasper 	return (0);
140*f48205beScasper }
141*f48205beScasper 
142*f48205beScasper uid_t
143*f48205beScasper idmap_call_bysid(ksid_t *ksid)
144*f48205beScasper {
145*f48205beScasper 	ksiddomain_t *domp = ksid->ks_domain;
146*f48205beScasper 	sidmap_call_t *callp;
147*f48205beScasper 	uid_t res = (uid_t)-1;
148*f48205beScasper 	uid_t *resp = &res;
149*f48205beScasper 	size_t callsz;
150*f48205beScasper 	size_t respsz = sizeof (res);
151*f48205beScasper 
152*f48205beScasper 	callsz = sizeof (sidmap_call_t) + domp->kd_len;
153*f48205beScasper 
154*f48205beScasper 	callp = kmem_alloc(callsz, KM_SLEEP);
155*f48205beScasper 	callp->sc_type = SIDSYS_SID2ID;
156*f48205beScasper 	bcopy(domp->kd_name, callp->sc_val.sc_sid.ds_dom, domp->kd_len);
157*f48205beScasper 	callp->sc_val.sc_sid.ds_rid = ksid->ks_rid;
158*f48205beScasper 
159*f48205beScasper 	if (idmap_do_call(callp, callsz, (void **)&resp, &respsz) != 0)
160*f48205beScasper 		goto out;
161*f48205beScasper 
162*f48205beScasper 	/* Should never happen; the original buffer should be large enough */
163*f48205beScasper 	if (resp != &res) {
164*f48205beScasper 		kmem_free(resp, respsz);
165*f48205beScasper 		goto out;
166*f48205beScasper 	}
167*f48205beScasper 
168*f48205beScasper 	if (respsz != sizeof (uid_t))
169*f48205beScasper 		res = (uid_t)-1;
170*f48205beScasper 
171*f48205beScasper out:
172*f48205beScasper 	kmem_free(callp, callsz);
173*f48205beScasper 	return (res);
174*f48205beScasper }
175*f48205beScasper 
176*f48205beScasper static int
177*f48205beScasper idmap_reg(int did)
178*f48205beScasper {
179*f48205beScasper 	door_handle_t dh;
180*f48205beScasper 	idmap_reg_t *idmp;
181*f48205beScasper 	int err;
182*f48205beScasper 
183*f48205beScasper 	if ((err = secpolicy_idmap(CRED())) != 0)
184*f48205beScasper 		return (set_errno(err));
185*f48205beScasper 
186*f48205beScasper 	dh = door_ki_lookup(did);
187*f48205beScasper 
188*f48205beScasper 	if (dh == NULL)
189*f48205beScasper 		return (set_errno(EBADF));
190*f48205beScasper 
191*f48205beScasper 	idmp = kmem_alloc(sizeof (*idmp), KM_SLEEP);
192*f48205beScasper 
193*f48205beScasper 	idmp->idmap_door = dh;
194*f48205beScasper 	mutex_enter(&idmap_mutex);
195*f48205beScasper 	if (idmap_ptr != NULL) {
196*f48205beScasper 		if (--idmap_ptr->idmap_ref == 0)
197*f48205beScasper 			idmap_freeone(idmap_ptr);
198*f48205beScasper 	}
199*f48205beScasper 	idmp->idmap_flags = 0;
200*f48205beScasper 	idmp->idmap_ref = 1;
201*f48205beScasper 	idmap_ptr = idmp;
202*f48205beScasper 	mutex_exit(&idmap_mutex);
203*f48205beScasper 	return (0);
204*f48205beScasper }
205*f48205beScasper 
206*f48205beScasper static int
207*f48205beScasper idmap_unreg_dh(door_handle_t dh)
208*f48205beScasper {
209*f48205beScasper 	mutex_enter(&idmap_mutex);
210*f48205beScasper 	if (idmap_ptr == NULL || idmap_ptr->idmap_door != dh) {
211*f48205beScasper 		mutex_exit(&idmap_mutex);
212*f48205beScasper 		return (EINVAL);
213*f48205beScasper 	}
214*f48205beScasper 
215*f48205beScasper 	if (idmap_ptr->idmap_flags != 0) {
216*f48205beScasper 		mutex_exit(&idmap_mutex);
217*f48205beScasper 		return (EAGAIN);
218*f48205beScasper 	}
219*f48205beScasper 	idmap_ptr->idmap_flags = 1;
220*f48205beScasper 	if (--idmap_ptr->idmap_ref == 0)
221*f48205beScasper 		idmap_freeone(idmap_ptr);
222*f48205beScasper 	mutex_exit(&idmap_mutex);
223*f48205beScasper 	return (0);
224*f48205beScasper }
225*f48205beScasper 
226*f48205beScasper static int
227*f48205beScasper idmap_unreg(int did)
228*f48205beScasper {
229*f48205beScasper 	door_handle_t dh = door_ki_lookup(did);
230*f48205beScasper 	int res;
231*f48205beScasper 
232*f48205beScasper 	if (dh == NULL)
233*f48205beScasper 		return (set_errno(EINVAL));
234*f48205beScasper 
235*f48205beScasper 	res = idmap_unreg_dh(dh);
236*f48205beScasper 	door_ki_rele(dh);
237*f48205beScasper 
238*f48205beScasper 	if (res != 0)
239*f48205beScasper 		return (set_errno(res));
240*f48205beScasper 	return (0);
241*f48205beScasper }
242*f48205beScasper 
243*f48205beScasper static boolean_t
244*f48205beScasper its_my_door(void)
245*f48205beScasper {
246*f48205beScasper 	mutex_enter(&idmap_mutex);
247*f48205beScasper 	if (idmap_ptr != NULL) {
248*f48205beScasper 		struct door_info info;
249*f48205beScasper 		int err = door_ki_info(idmap_ptr->idmap_door, &info);
250*f48205beScasper 		if (err == 0 && info.di_target == curproc->p_pid) {
251*f48205beScasper 			mutex_exit(&idmap_mutex);
252*f48205beScasper 			return (B_TRUE);
253*f48205beScasper 		}
254*f48205beScasper 	}
255*f48205beScasper 	mutex_exit(&idmap_mutex);
256*f48205beScasper 	return (B_FALSE);
257*f48205beScasper }
258*f48205beScasper 
259*f48205beScasper static uint64_t
260*f48205beScasper allocids(int flag, int nuids, int ngids)
261*f48205beScasper {
262*f48205beScasper 	rval_t r;
263*f48205beScasper 	uid_t su = 0;
264*f48205beScasper 	gid_t sg = 0;
265*f48205beScasper 	int err;
266*f48205beScasper 
267*f48205beScasper 	if (!its_my_door())
268*f48205beScasper 		return (set_errno(EPERM));
269*f48205beScasper 
270*f48205beScasper 	if (nuids < 0 || ngids < 0)
271*f48205beScasper 		return (set_errno(EINVAL));
272*f48205beScasper 
273*f48205beScasper 	if (flag != 0 || nuids > 0)
274*f48205beScasper 		err = eph_uid_alloc(flag, &su, nuids);
275*f48205beScasper 	if (err == 0 && (flag != 0 || ngids > 0))
276*f48205beScasper 		err = eph_gid_alloc(flag, &sg, ngids);
277*f48205beScasper 
278*f48205beScasper 	if (err != 0)
279*f48205beScasper 		return (set_errno(EOVERFLOW));
280*f48205beScasper 
281*f48205beScasper 	r.r_val1 = su;
282*f48205beScasper 	r.r_val2 = sg;
283*f48205beScasper 	return (r.r_vals);
284*f48205beScasper }
285*f48205beScasper 
286*f48205beScasper uint64_t
287*f48205beScasper sidsys(int op, int flag, int nuids, int ngids)
288*f48205beScasper {
289*f48205beScasper 	switch (op) {
290*f48205beScasper 	case SIDSYS_ALLOC_IDS:
291*f48205beScasper 		return (allocids(flag, nuids, ngids));
292*f48205beScasper 	case SIDSYS_IDMAP_REG:
293*f48205beScasper 		return (idmap_reg(flag));
294*f48205beScasper 	case SIDSYS_IDMAP_UNREG:
295*f48205beScasper 		return (idmap_unreg(flag));
296*f48205beScasper 	default:
297*f48205beScasper 		return (set_errno(EINVAL));
298*f48205beScasper 	}
299*f48205beScasper }
300