xref: /xnu-8796.101.5/bsd/kern/kern_authorization.c (revision aca3beaa3dfbd42498b42c5e5ce20a938e6554e5)
1*aca3beaaSApple OSS Distributions /*
2*aca3beaaSApple OSS Distributions  * Copyright (c) 2004-2016 Apple Inc. All rights reserved.
3*aca3beaaSApple OSS Distributions  *
4*aca3beaaSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*aca3beaaSApple OSS Distributions  *
6*aca3beaaSApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*aca3beaaSApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*aca3beaaSApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*aca3beaaSApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*aca3beaaSApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*aca3beaaSApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*aca3beaaSApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*aca3beaaSApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*aca3beaaSApple OSS Distributions  *
15*aca3beaaSApple OSS Distributions  * Please obtain a copy of the License at
16*aca3beaaSApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*aca3beaaSApple OSS Distributions  *
18*aca3beaaSApple OSS Distributions  * The Original Code and all software distributed under the License are
19*aca3beaaSApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*aca3beaaSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*aca3beaaSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*aca3beaaSApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*aca3beaaSApple OSS Distributions  * Please see the License for the specific language governing rights and
24*aca3beaaSApple OSS Distributions  * limitations under the License.
25*aca3beaaSApple OSS Distributions  *
26*aca3beaaSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*aca3beaaSApple OSS Distributions  */
28*aca3beaaSApple OSS Distributions 
29*aca3beaaSApple OSS Distributions /*
30*aca3beaaSApple OSS Distributions  * Centralized authorisation framework.
31*aca3beaaSApple OSS Distributions  */
32*aca3beaaSApple OSS Distributions 
33*aca3beaaSApple OSS Distributions #include <sys/appleapiopts.h>
34*aca3beaaSApple OSS Distributions #include <sys/param.h>  /* XXX trim includes */
35*aca3beaaSApple OSS Distributions #include <sys/acct.h>
36*aca3beaaSApple OSS Distributions #include <sys/systm.h>
37*aca3beaaSApple OSS Distributions #include <sys/ucred.h>
38*aca3beaaSApple OSS Distributions #include <sys/proc_internal.h>
39*aca3beaaSApple OSS Distributions #include <sys/timeb.h>
40*aca3beaaSApple OSS Distributions #include <sys/times.h>
41*aca3beaaSApple OSS Distributions #include <sys/malloc.h>
42*aca3beaaSApple OSS Distributions #include <sys/vnode_internal.h>
43*aca3beaaSApple OSS Distributions #include <sys/kauth.h>
44*aca3beaaSApple OSS Distributions #include <sys/stat.h>
45*aca3beaaSApple OSS Distributions 
46*aca3beaaSApple OSS Distributions #include <security/audit/audit.h>
47*aca3beaaSApple OSS Distributions 
48*aca3beaaSApple OSS Distributions #include <sys/mount.h>
49*aca3beaaSApple OSS Distributions #include <sys/sysproto.h>
50*aca3beaaSApple OSS Distributions #include <mach/message.h>
51*aca3beaaSApple OSS Distributions 
52*aca3beaaSApple OSS Distributions #include <kern/locks.h>
53*aca3beaaSApple OSS Distributions 
54*aca3beaaSApple OSS Distributions 
55*aca3beaaSApple OSS Distributions /*
56*aca3beaaSApple OSS Distributions  * Authorization scopes.
57*aca3beaaSApple OSS Distributions  */
58*aca3beaaSApple OSS Distributions 
59*aca3beaaSApple OSS Distributions LCK_GRP_DECLARE(kauth_lck_grp, "kauth");
60*aca3beaaSApple OSS Distributions static LCK_MTX_DECLARE(kauth_scope_mtx, &kauth_lck_grp);
61*aca3beaaSApple OSS Distributions #define KAUTH_SCOPELOCK()       lck_mtx_lock(&kauth_scope_mtx);
62*aca3beaaSApple OSS Distributions #define KAUTH_SCOPEUNLOCK()     lck_mtx_unlock(&kauth_scope_mtx);
63*aca3beaaSApple OSS Distributions 
64*aca3beaaSApple OSS Distributions /*
65*aca3beaaSApple OSS Distributions  * We support listeners for scopes that have not been registered yet.
66*aca3beaaSApple OSS Distributions  * If a listener comes in for a scope that is not active we hang the listener
67*aca3beaaSApple OSS Distributions  * off our kauth_dangling_listeners list and once the scope becomes active we
68*aca3beaaSApple OSS Distributions  * remove it from kauth_dangling_listeners and add it to the active scope.
69*aca3beaaSApple OSS Distributions  */
70*aca3beaaSApple OSS Distributions struct kauth_listener {
71*aca3beaaSApple OSS Distributions 	TAILQ_ENTRY(kauth_listener)     kl_link;
72*aca3beaaSApple OSS Distributions 	const char *                            kl_identifier;
73*aca3beaaSApple OSS Distributions 	kauth_scope_callback_t          kl_callback;
74*aca3beaaSApple OSS Distributions 	void *                                          kl_idata;
75*aca3beaaSApple OSS Distributions };
76*aca3beaaSApple OSS Distributions 
77*aca3beaaSApple OSS Distributions /* XXX - kauth_todo - there is a race if a scope listener is removed while we
78*aca3beaaSApple OSS Distributions  * we are in the kauth_authorize_action code path.  We intentionally do not take
79*aca3beaaSApple OSS Distributions  * a scope lock in order to get the best possible performance.  we will fix this
80*aca3beaaSApple OSS Distributions  * post Tiger.
81*aca3beaaSApple OSS Distributions  * Until the race is fixed our kext clients are responsible for all active
82*aca3beaaSApple OSS Distributions  * requests that may be in their callback code or on the way to their callback
83*aca3beaaSApple OSS Distributions  * code before they free kauth_listener.kl_callback or kauth_listener.kl_idata.
84*aca3beaaSApple OSS Distributions  * We keep copies of these in our kauth_local_listener in an attempt to limit
85*aca3beaaSApple OSS Distributions  * our expose to unlisten race.
86*aca3beaaSApple OSS Distributions  */
87*aca3beaaSApple OSS Distributions struct kauth_local_listener {
88*aca3beaaSApple OSS Distributions 	kauth_listener_t                        kll_listenerp;
89*aca3beaaSApple OSS Distributions 	kauth_scope_callback_t          kll_callback;
90*aca3beaaSApple OSS Distributions 	void *                                          kll_idata;
91*aca3beaaSApple OSS Distributions };
92*aca3beaaSApple OSS Distributions typedef struct kauth_local_listener *kauth_local_listener_t;
93*aca3beaaSApple OSS Distributions 
94*aca3beaaSApple OSS Distributions static TAILQ_HEAD(, kauth_listener) kauth_dangling_listeners =
95*aca3beaaSApple OSS Distributions     TAILQ_HEAD_INITIALIZER(kauth_dangling_listeners);
96*aca3beaaSApple OSS Distributions 
97*aca3beaaSApple OSS Distributions /*
98*aca3beaaSApple OSS Distributions  * Scope listeners need to be reworked to be dynamic.
99*aca3beaaSApple OSS Distributions  * We intentionally used a static table to avoid locking issues with linked
100*aca3beaaSApple OSS Distributions  * lists.  The listeners may be called quite often.
101*aca3beaaSApple OSS Distributions  * XXX - kauth_todo
102*aca3beaaSApple OSS Distributions  */
103*aca3beaaSApple OSS Distributions #define KAUTH_SCOPE_MAX_LISTENERS  15
104*aca3beaaSApple OSS Distributions 
105*aca3beaaSApple OSS Distributions struct kauth_scope {
106*aca3beaaSApple OSS Distributions 	TAILQ_ENTRY(kauth_scope)        ks_link;
107*aca3beaaSApple OSS Distributions 	volatile struct kauth_local_listener  ks_listeners[KAUTH_SCOPE_MAX_LISTENERS];
108*aca3beaaSApple OSS Distributions 	const char *                            ks_identifier;
109*aca3beaaSApple OSS Distributions 	kauth_scope_callback_t          ks_callback;
110*aca3beaaSApple OSS Distributions 	void *                                          ks_idata;
111*aca3beaaSApple OSS Distributions 	u_int                                           ks_flags;
112*aca3beaaSApple OSS Distributions };
113*aca3beaaSApple OSS Distributions 
114*aca3beaaSApple OSS Distributions /* values for kauth_scope.ks_flags */
115*aca3beaaSApple OSS Distributions #define KS_F_HAS_LISTENERS              (1 << 0)
116*aca3beaaSApple OSS Distributions 
117*aca3beaaSApple OSS Distributions static TAILQ_HEAD(, kauth_scope) kauth_scopes = TAILQ_HEAD_INITIALIZER(kauth_scopes);
118*aca3beaaSApple OSS Distributions 
119*aca3beaaSApple OSS Distributions static int kauth_add_callback_to_scope(kauth_scope_t sp, kauth_listener_t klp);
120*aca3beaaSApple OSS Distributions static void     kauth_scope_init(void);
121*aca3beaaSApple OSS Distributions static kauth_scope_t kauth_alloc_scope(const char *identifier, kauth_scope_callback_t callback, void *idata);
122*aca3beaaSApple OSS Distributions static kauth_listener_t kauth_alloc_listener(const char *identifier, kauth_scope_callback_t callback, void *idata);
123*aca3beaaSApple OSS Distributions #if 0
124*aca3beaaSApple OSS Distributions static int      kauth_scope_valid(kauth_scope_t scope);
125*aca3beaaSApple OSS Distributions #endif
126*aca3beaaSApple OSS Distributions 
127*aca3beaaSApple OSS Distributions kauth_scope_t   kauth_scope_process;
128*aca3beaaSApple OSS Distributions static int      kauth_authorize_process_callback(kauth_cred_t _credential, void *_idata, kauth_action_t _action,
129*aca3beaaSApple OSS Distributions     uintptr_t arg0, uintptr_t arg1, __unused uintptr_t arg2, __unused uintptr_t arg3);
130*aca3beaaSApple OSS Distributions kauth_scope_t   kauth_scope_generic;
131*aca3beaaSApple OSS Distributions static int      kauth_authorize_generic_callback(kauth_cred_t _credential, void *_idata, kauth_action_t _action,
132*aca3beaaSApple OSS Distributions     uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3);
133*aca3beaaSApple OSS Distributions kauth_scope_t   kauth_scope_fileop;
134*aca3beaaSApple OSS Distributions 
135*aca3beaaSApple OSS Distributions extern int              cansignal(struct proc *, kauth_cred_t, struct proc *, int);
136*aca3beaaSApple OSS Distributions extern char *   get_pathbuff(void);
137*aca3beaaSApple OSS Distributions extern void             release_pathbuff(char *path);
138*aca3beaaSApple OSS Distributions 
139*aca3beaaSApple OSS Distributions /*
140*aca3beaaSApple OSS Distributions  * Initialization.
141*aca3beaaSApple OSS Distributions  */
142*aca3beaaSApple OSS Distributions void
kauth_init(void)143*aca3beaaSApple OSS Distributions kauth_init(void)
144*aca3beaaSApple OSS Distributions {
145*aca3beaaSApple OSS Distributions 	/* bring up kauth subsystem components */
146*aca3beaaSApple OSS Distributions 	kauth_scope_init();
147*aca3beaaSApple OSS Distributions }
148*aca3beaaSApple OSS Distributions 
149*aca3beaaSApple OSS Distributions static void
kauth_scope_init(void)150*aca3beaaSApple OSS Distributions kauth_scope_init(void)
151*aca3beaaSApple OSS Distributions {
152*aca3beaaSApple OSS Distributions 	kauth_scope_process = kauth_register_scope(KAUTH_SCOPE_PROCESS, kauth_authorize_process_callback, NULL);
153*aca3beaaSApple OSS Distributions 	kauth_scope_generic = kauth_register_scope(KAUTH_SCOPE_GENERIC, kauth_authorize_generic_callback, NULL);
154*aca3beaaSApple OSS Distributions 	kauth_scope_fileop = kauth_register_scope(KAUTH_SCOPE_FILEOP, NULL, NULL);
155*aca3beaaSApple OSS Distributions }
156*aca3beaaSApple OSS Distributions 
157*aca3beaaSApple OSS Distributions /*
158*aca3beaaSApple OSS Distributions  * Scope registration.
159*aca3beaaSApple OSS Distributions  */
160*aca3beaaSApple OSS Distributions 
161*aca3beaaSApple OSS Distributions static kauth_scope_t
kauth_alloc_scope(const char * identifier,kauth_scope_callback_t callback,void * idata)162*aca3beaaSApple OSS Distributions kauth_alloc_scope(const char *identifier, kauth_scope_callback_t callback, void *idata)
163*aca3beaaSApple OSS Distributions {
164*aca3beaaSApple OSS Distributions 	kauth_scope_t   sp;
165*aca3beaaSApple OSS Distributions 
166*aca3beaaSApple OSS Distributions 	/*
167*aca3beaaSApple OSS Distributions 	 * Allocate and populate the scope structure.
168*aca3beaaSApple OSS Distributions 	 */
169*aca3beaaSApple OSS Distributions 	sp = kalloc_type(struct kauth_scope, Z_WAITOK | Z_ZERO | Z_NOFAIL);
170*aca3beaaSApple OSS Distributions 	sp->ks_flags = 0;
171*aca3beaaSApple OSS Distributions 	sp->ks_identifier = identifier;
172*aca3beaaSApple OSS Distributions 	sp->ks_idata = idata;
173*aca3beaaSApple OSS Distributions 	sp->ks_callback = callback;
174*aca3beaaSApple OSS Distributions 	return sp;
175*aca3beaaSApple OSS Distributions }
176*aca3beaaSApple OSS Distributions 
177*aca3beaaSApple OSS Distributions static kauth_listener_t
kauth_alloc_listener(const char * identifier,kauth_scope_callback_t callback,void * idata)178*aca3beaaSApple OSS Distributions kauth_alloc_listener(const char *identifier, kauth_scope_callback_t callback, void *idata)
179*aca3beaaSApple OSS Distributions {
180*aca3beaaSApple OSS Distributions 	kauth_listener_t lsp;
181*aca3beaaSApple OSS Distributions 
182*aca3beaaSApple OSS Distributions 	/*
183*aca3beaaSApple OSS Distributions 	 * Allocate and populate the listener structure.
184*aca3beaaSApple OSS Distributions 	 */
185*aca3beaaSApple OSS Distributions 	lsp = kalloc_type(struct kauth_listener, Z_WAITOK | Z_NOFAIL);
186*aca3beaaSApple OSS Distributions 	lsp->kl_identifier = identifier;
187*aca3beaaSApple OSS Distributions 	lsp->kl_idata = idata;
188*aca3beaaSApple OSS Distributions 	lsp->kl_callback = callback;
189*aca3beaaSApple OSS Distributions 	return lsp;
190*aca3beaaSApple OSS Distributions }
191*aca3beaaSApple OSS Distributions 
192*aca3beaaSApple OSS Distributions kauth_scope_t
kauth_register_scope(const char * identifier,kauth_scope_callback_t callback,void * idata)193*aca3beaaSApple OSS Distributions kauth_register_scope(const char *identifier, kauth_scope_callback_t callback, void *idata)
194*aca3beaaSApple OSS Distributions {
195*aca3beaaSApple OSS Distributions 	kauth_scope_t           sp, tsp;
196*aca3beaaSApple OSS Distributions 	kauth_listener_t        klp;
197*aca3beaaSApple OSS Distributions 
198*aca3beaaSApple OSS Distributions 	if ((sp = kauth_alloc_scope(identifier, callback, idata)) == NULL) {
199*aca3beaaSApple OSS Distributions 		return NULL;
200*aca3beaaSApple OSS Distributions 	}
201*aca3beaaSApple OSS Distributions 
202*aca3beaaSApple OSS Distributions 	/*
203*aca3beaaSApple OSS Distributions 	 * Lock the list and insert.
204*aca3beaaSApple OSS Distributions 	 */
205*aca3beaaSApple OSS Distributions 	KAUTH_SCOPELOCK();
206*aca3beaaSApple OSS Distributions 	TAILQ_FOREACH(tsp, &kauth_scopes, ks_link) {
207*aca3beaaSApple OSS Distributions 		/* duplicate! */
208*aca3beaaSApple OSS Distributions 		if (strncmp(tsp->ks_identifier, identifier,
209*aca3beaaSApple OSS Distributions 		    strlen(tsp->ks_identifier) + 1) == 0) {
210*aca3beaaSApple OSS Distributions 			KAUTH_SCOPEUNLOCK();
211*aca3beaaSApple OSS Distributions 			kfree_type(struct kauth_scope, sp);
212*aca3beaaSApple OSS Distributions 			return NULL;
213*aca3beaaSApple OSS Distributions 		}
214*aca3beaaSApple OSS Distributions 	}
215*aca3beaaSApple OSS Distributions 	TAILQ_INSERT_TAIL(&kauth_scopes, sp, ks_link);
216*aca3beaaSApple OSS Distributions 
217*aca3beaaSApple OSS Distributions 	/*
218*aca3beaaSApple OSS Distributions 	 * Look for listeners waiting for this scope, move them to the active scope
219*aca3beaaSApple OSS Distributions 	 * listener table.
220*aca3beaaSApple OSS Distributions 	 * Note that we have to restart the scan every time we remove an entry
221*aca3beaaSApple OSS Distributions 	 * from the list, since we can't remove the current item from the list.
222*aca3beaaSApple OSS Distributions 	 */
223*aca3beaaSApple OSS Distributions restart:
224*aca3beaaSApple OSS Distributions 	TAILQ_FOREACH(klp, &kauth_dangling_listeners, kl_link) {
225*aca3beaaSApple OSS Distributions 		if (strncmp(klp->kl_identifier, sp->ks_identifier,
226*aca3beaaSApple OSS Distributions 		    strlen(klp->kl_identifier) + 1) == 0) {
227*aca3beaaSApple OSS Distributions 			/* found a match on the dangling listener list.  add it to the
228*aca3beaaSApple OSS Distributions 			 * the active scope.
229*aca3beaaSApple OSS Distributions 			 */
230*aca3beaaSApple OSS Distributions 			if (kauth_add_callback_to_scope(sp, klp) == 0) {
231*aca3beaaSApple OSS Distributions 				TAILQ_REMOVE(&kauth_dangling_listeners, klp, kl_link);
232*aca3beaaSApple OSS Distributions 			} else {
233*aca3beaaSApple OSS Distributions #if 0
234*aca3beaaSApple OSS Distributions 				printf("%s - failed to add listener to scope \"%s\" \n", __FUNCTION__, sp->ks_identifier);
235*aca3beaaSApple OSS Distributions #endif
236*aca3beaaSApple OSS Distributions 				break;
237*aca3beaaSApple OSS Distributions 			}
238*aca3beaaSApple OSS Distributions 			goto restart;
239*aca3beaaSApple OSS Distributions 		}
240*aca3beaaSApple OSS Distributions 	}
241*aca3beaaSApple OSS Distributions 
242*aca3beaaSApple OSS Distributions 	KAUTH_SCOPEUNLOCK();
243*aca3beaaSApple OSS Distributions 	return sp;
244*aca3beaaSApple OSS Distributions }
245*aca3beaaSApple OSS Distributions 
246*aca3beaaSApple OSS Distributions 
247*aca3beaaSApple OSS Distributions 
248*aca3beaaSApple OSS Distributions void
kauth_deregister_scope(kauth_scope_t scope)249*aca3beaaSApple OSS Distributions kauth_deregister_scope(kauth_scope_t scope)
250*aca3beaaSApple OSS Distributions {
251*aca3beaaSApple OSS Distributions 	int             i;
252*aca3beaaSApple OSS Distributions 
253*aca3beaaSApple OSS Distributions 	KAUTH_SCOPELOCK();
254*aca3beaaSApple OSS Distributions 
255*aca3beaaSApple OSS Distributions 	TAILQ_REMOVE(&kauth_scopes, scope, ks_link);
256*aca3beaaSApple OSS Distributions 
257*aca3beaaSApple OSS Distributions 	/* relocate listeners back to the waiting list */
258*aca3beaaSApple OSS Distributions 	for (i = 0; i < KAUTH_SCOPE_MAX_LISTENERS; i++) {
259*aca3beaaSApple OSS Distributions 		if (scope->ks_listeners[i].kll_listenerp != NULL) {
260*aca3beaaSApple OSS Distributions 			TAILQ_INSERT_TAIL(&kauth_dangling_listeners, scope->ks_listeners[i].kll_listenerp, kl_link);
261*aca3beaaSApple OSS Distributions 			scope->ks_listeners[i].kll_listenerp = NULL;
262*aca3beaaSApple OSS Distributions 			/*
263*aca3beaaSApple OSS Distributions 			 * XXX - kauth_todo - WARNING, do not clear kll_callback or
264*aca3beaaSApple OSS Distributions 			 * kll_idata here.  they are part of our scope unlisten race hack
265*aca3beaaSApple OSS Distributions 			 */
266*aca3beaaSApple OSS Distributions 		}
267*aca3beaaSApple OSS Distributions 	}
268*aca3beaaSApple OSS Distributions 	KAUTH_SCOPEUNLOCK();
269*aca3beaaSApple OSS Distributions 	kfree_type(struct kauth_scope, scope);
270*aca3beaaSApple OSS Distributions 
271*aca3beaaSApple OSS Distributions 	return;
272*aca3beaaSApple OSS Distributions }
273*aca3beaaSApple OSS Distributions 
274*aca3beaaSApple OSS Distributions kauth_listener_t
kauth_listen_scope(const char * identifier,kauth_scope_callback_t callback,void * idata)275*aca3beaaSApple OSS Distributions kauth_listen_scope(const char *identifier, kauth_scope_callback_t callback, void *idata)
276*aca3beaaSApple OSS Distributions {
277*aca3beaaSApple OSS Distributions 	kauth_listener_t klp;
278*aca3beaaSApple OSS Distributions 	kauth_scope_t   sp;
279*aca3beaaSApple OSS Distributions 
280*aca3beaaSApple OSS Distributions 	if ((klp = kauth_alloc_listener(identifier, callback, idata)) == NULL) {
281*aca3beaaSApple OSS Distributions 		return NULL;
282*aca3beaaSApple OSS Distributions 	}
283*aca3beaaSApple OSS Distributions 
284*aca3beaaSApple OSS Distributions 	/*
285*aca3beaaSApple OSS Distributions 	 * Lock the scope list and check to see whether this scope already exists.
286*aca3beaaSApple OSS Distributions 	 */
287*aca3beaaSApple OSS Distributions 	KAUTH_SCOPELOCK();
288*aca3beaaSApple OSS Distributions 	TAILQ_FOREACH(sp, &kauth_scopes, ks_link) {
289*aca3beaaSApple OSS Distributions 		if (strncmp(sp->ks_identifier, identifier,
290*aca3beaaSApple OSS Distributions 		    strlen(sp->ks_identifier) + 1) == 0) {
291*aca3beaaSApple OSS Distributions 			/* scope exists, add it to scope listener table */
292*aca3beaaSApple OSS Distributions 			if (kauth_add_callback_to_scope(sp, klp) == 0) {
293*aca3beaaSApple OSS Distributions 				KAUTH_SCOPEUNLOCK();
294*aca3beaaSApple OSS Distributions 				return klp;
295*aca3beaaSApple OSS Distributions 			}
296*aca3beaaSApple OSS Distributions 			/* table already full */
297*aca3beaaSApple OSS Distributions 			KAUTH_SCOPEUNLOCK();
298*aca3beaaSApple OSS Distributions 			kfree_type(struct kauth_listener, klp);
299*aca3beaaSApple OSS Distributions 			return NULL;
300*aca3beaaSApple OSS Distributions 		}
301*aca3beaaSApple OSS Distributions 	}
302*aca3beaaSApple OSS Distributions 
303*aca3beaaSApple OSS Distributions 	/* scope doesn't exist, put on waiting list. */
304*aca3beaaSApple OSS Distributions 	TAILQ_INSERT_TAIL(&kauth_dangling_listeners, klp, kl_link);
305*aca3beaaSApple OSS Distributions 
306*aca3beaaSApple OSS Distributions 	KAUTH_SCOPEUNLOCK();
307*aca3beaaSApple OSS Distributions 
308*aca3beaaSApple OSS Distributions 	return klp;
309*aca3beaaSApple OSS Distributions }
310*aca3beaaSApple OSS Distributions 
311*aca3beaaSApple OSS Distributions void
kauth_unlisten_scope(kauth_listener_t listener)312*aca3beaaSApple OSS Distributions kauth_unlisten_scope(kauth_listener_t listener)
313*aca3beaaSApple OSS Distributions {
314*aca3beaaSApple OSS Distributions 	kauth_scope_t           sp;
315*aca3beaaSApple OSS Distributions 	kauth_listener_t        klp;
316*aca3beaaSApple OSS Distributions 	int                                     i, listener_count, do_free;
317*aca3beaaSApple OSS Distributions 
318*aca3beaaSApple OSS Distributions 	KAUTH_SCOPELOCK();
319*aca3beaaSApple OSS Distributions 
320*aca3beaaSApple OSS Distributions 	/* search the active scope for this listener */
321*aca3beaaSApple OSS Distributions 	TAILQ_FOREACH(sp, &kauth_scopes, ks_link) {
322*aca3beaaSApple OSS Distributions 		do_free = 0;
323*aca3beaaSApple OSS Distributions 		if ((sp->ks_flags & KS_F_HAS_LISTENERS) != 0) {
324*aca3beaaSApple OSS Distributions 			listener_count = 0;
325*aca3beaaSApple OSS Distributions 			for (i = 0; i < KAUTH_SCOPE_MAX_LISTENERS; i++) {
326*aca3beaaSApple OSS Distributions 				if (sp->ks_listeners[i].kll_listenerp == listener) {
327*aca3beaaSApple OSS Distributions 					sp->ks_listeners[i].kll_listenerp = NULL;
328*aca3beaaSApple OSS Distributions 					do_free = 1;
329*aca3beaaSApple OSS Distributions 					/*
330*aca3beaaSApple OSS Distributions 					 * XXX - kauth_todo - WARNING, do not clear kll_callback or
331*aca3beaaSApple OSS Distributions 					 * kll_idata here.  they are part of our scope unlisten race hack
332*aca3beaaSApple OSS Distributions 					 */
333*aca3beaaSApple OSS Distributions 				} else if (sp->ks_listeners[i].kll_listenerp != NULL) {
334*aca3beaaSApple OSS Distributions 					listener_count++;
335*aca3beaaSApple OSS Distributions 				}
336*aca3beaaSApple OSS Distributions 			}
337*aca3beaaSApple OSS Distributions 			if (do_free) {
338*aca3beaaSApple OSS Distributions 				if (listener_count == 0) {
339*aca3beaaSApple OSS Distributions 					sp->ks_flags &= ~KS_F_HAS_LISTENERS;
340*aca3beaaSApple OSS Distributions 				}
341*aca3beaaSApple OSS Distributions 				KAUTH_SCOPEUNLOCK();
342*aca3beaaSApple OSS Distributions 				kfree_type(struct kauth_listener, listener);
343*aca3beaaSApple OSS Distributions 				return;
344*aca3beaaSApple OSS Distributions 			}
345*aca3beaaSApple OSS Distributions 		}
346*aca3beaaSApple OSS Distributions 	}
347*aca3beaaSApple OSS Distributions 
348*aca3beaaSApple OSS Distributions 	/* if not active, check the dangling list */
349*aca3beaaSApple OSS Distributions 	TAILQ_FOREACH(klp, &kauth_dangling_listeners, kl_link) {
350*aca3beaaSApple OSS Distributions 		if (klp == listener) {
351*aca3beaaSApple OSS Distributions 			TAILQ_REMOVE(&kauth_dangling_listeners, klp, kl_link);
352*aca3beaaSApple OSS Distributions 			KAUTH_SCOPEUNLOCK();
353*aca3beaaSApple OSS Distributions 			kfree_type(struct kauth_listener, listener);
354*aca3beaaSApple OSS Distributions 			return;
355*aca3beaaSApple OSS Distributions 		}
356*aca3beaaSApple OSS Distributions 	}
357*aca3beaaSApple OSS Distributions 
358*aca3beaaSApple OSS Distributions 	KAUTH_SCOPEUNLOCK();
359*aca3beaaSApple OSS Distributions 	return;
360*aca3beaaSApple OSS Distributions }
361*aca3beaaSApple OSS Distributions 
362*aca3beaaSApple OSS Distributions /*
363*aca3beaaSApple OSS Distributions  * Authorization requests.
364*aca3beaaSApple OSS Distributions  *
365*aca3beaaSApple OSS Distributions  * Returns:	0			Success
366*aca3beaaSApple OSS Distributions  *		EPERM			Operation not permitted
367*aca3beaaSApple OSS Distributions  *
368*aca3beaaSApple OSS Distributions  * Imputed:	*arg3, modified		Callback return - depends on callback
369*aca3beaaSApple OSS Distributions  *					modification of *arg3, if any
370*aca3beaaSApple OSS Distributions  */
371*aca3beaaSApple OSS Distributions int
kauth_authorize_action(kauth_scope_t scope,kauth_cred_t credential,kauth_action_t action,uintptr_t arg0,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3)372*aca3beaaSApple OSS Distributions kauth_authorize_action(kauth_scope_t scope, kauth_cred_t credential, kauth_action_t action,
373*aca3beaaSApple OSS Distributions     uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
374*aca3beaaSApple OSS Distributions {
375*aca3beaaSApple OSS Distributions 	int result, ret, i;
376*aca3beaaSApple OSS Distributions 
377*aca3beaaSApple OSS Distributions 	/* ask the scope */
378*aca3beaaSApple OSS Distributions 	if (scope->ks_callback != NULL) {
379*aca3beaaSApple OSS Distributions 		result = scope->ks_callback(credential, scope->ks_idata, action, arg0, arg1, arg2, arg3);
380*aca3beaaSApple OSS Distributions 	} else {
381*aca3beaaSApple OSS Distributions 		result = KAUTH_RESULT_DEFER;
382*aca3beaaSApple OSS Distributions 	}
383*aca3beaaSApple OSS Distributions 
384*aca3beaaSApple OSS Distributions 	/* check with listeners */
385*aca3beaaSApple OSS Distributions 	if ((scope->ks_flags & KS_F_HAS_LISTENERS) != 0) {
386*aca3beaaSApple OSS Distributions 		for (i = 0; i < KAUTH_SCOPE_MAX_LISTENERS; i++) {
387*aca3beaaSApple OSS Distributions 			/* XXX - kauth_todo - there is a race here if listener is removed - we will fix this post Tiger.
388*aca3beaaSApple OSS Distributions 			 * Until the race is fixed our kext clients are responsible for all active requests that may
389*aca3beaaSApple OSS Distributions 			 * be in their callbacks or on the way to their callbacks before they free kl_callback or kl_idata.
390*aca3beaaSApple OSS Distributions 			 * We keep copies of these in our kauth_local_listener in an attempt to limit our expose to
391*aca3beaaSApple OSS Distributions 			 * unlisten race.
392*aca3beaaSApple OSS Distributions 			 */
393*aca3beaaSApple OSS Distributions 			if (scope->ks_listeners[i].kll_listenerp == NULL ||
394*aca3beaaSApple OSS Distributions 			    scope->ks_listeners[i].kll_callback == NULL) {
395*aca3beaaSApple OSS Distributions 				continue;
396*aca3beaaSApple OSS Distributions 			}
397*aca3beaaSApple OSS Distributions 
398*aca3beaaSApple OSS Distributions 			ret = scope->ks_listeners[i].kll_callback(
399*aca3beaaSApple OSS Distributions 				credential, scope->ks_listeners[i].kll_idata,
400*aca3beaaSApple OSS Distributions 				action, arg0, arg1, arg2, arg3);
401*aca3beaaSApple OSS Distributions 			if ((ret == KAUTH_RESULT_DENY) ||
402*aca3beaaSApple OSS Distributions 			    (result == KAUTH_RESULT_DEFER)) {
403*aca3beaaSApple OSS Distributions 				result = ret;
404*aca3beaaSApple OSS Distributions 			}
405*aca3beaaSApple OSS Distributions 		}
406*aca3beaaSApple OSS Distributions 	}
407*aca3beaaSApple OSS Distributions 
408*aca3beaaSApple OSS Distributions 	/* we need an explicit allow, or the auth fails */
409*aca3beaaSApple OSS Distributions 	/* XXX need a mechanism for auth failure to be signalled vs. denial */
410*aca3beaaSApple OSS Distributions 	return result == KAUTH_RESULT_ALLOW ? 0 : EPERM;
411*aca3beaaSApple OSS Distributions }
412*aca3beaaSApple OSS Distributions 
413*aca3beaaSApple OSS Distributions /*
414*aca3beaaSApple OSS Distributions  * Default authorization handlers.
415*aca3beaaSApple OSS Distributions  */
416*aca3beaaSApple OSS Distributions int
kauth_authorize_allow(__unused kauth_cred_t credential,__unused void * idata,__unused kauth_action_t action,__unused uintptr_t arg0,__unused uintptr_t arg1,__unused uintptr_t arg2,__unused uintptr_t arg3)417*aca3beaaSApple OSS Distributions kauth_authorize_allow(__unused kauth_cred_t credential, __unused void *idata, __unused kauth_action_t action,
418*aca3beaaSApple OSS Distributions     __unused uintptr_t arg0, __unused uintptr_t arg1, __unused uintptr_t arg2, __unused uintptr_t arg3)
419*aca3beaaSApple OSS Distributions {
420*aca3beaaSApple OSS Distributions 	return KAUTH_RESULT_ALLOW;
421*aca3beaaSApple OSS Distributions }
422*aca3beaaSApple OSS Distributions 
423*aca3beaaSApple OSS Distributions #if 0
424*aca3beaaSApple OSS Distributions /*
425*aca3beaaSApple OSS Distributions  * Debugging support.
426*aca3beaaSApple OSS Distributions  */
427*aca3beaaSApple OSS Distributions static int
428*aca3beaaSApple OSS Distributions kauth_scope_valid(kauth_scope_t scope)
429*aca3beaaSApple OSS Distributions {
430*aca3beaaSApple OSS Distributions 	kauth_scope_t   sp;
431*aca3beaaSApple OSS Distributions 
432*aca3beaaSApple OSS Distributions 	KAUTH_SCOPELOCK();
433*aca3beaaSApple OSS Distributions 	TAILQ_FOREACH(sp, &kauth_scopes, ks_link) {
434*aca3beaaSApple OSS Distributions 		if (sp == scope) {
435*aca3beaaSApple OSS Distributions 			break;
436*aca3beaaSApple OSS Distributions 		}
437*aca3beaaSApple OSS Distributions 	}
438*aca3beaaSApple OSS Distributions 	KAUTH_SCOPEUNLOCK();
439*aca3beaaSApple OSS Distributions 	return (sp == NULL) ? 0 : 1;
440*aca3beaaSApple OSS Distributions }
441*aca3beaaSApple OSS Distributions #endif
442*aca3beaaSApple OSS Distributions 
443*aca3beaaSApple OSS Distributions /*
444*aca3beaaSApple OSS Distributions  * Process authorization scope.
445*aca3beaaSApple OSS Distributions  */
446*aca3beaaSApple OSS Distributions 
447*aca3beaaSApple OSS Distributions int
kauth_authorize_process(kauth_cred_t credential,kauth_action_t action,struct proc * process,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3)448*aca3beaaSApple OSS Distributions kauth_authorize_process(kauth_cred_t credential, kauth_action_t action, struct proc *process, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
449*aca3beaaSApple OSS Distributions {
450*aca3beaaSApple OSS Distributions 	return kauth_authorize_action(kauth_scope_process, credential, action, (uintptr_t)process, arg1, arg2, arg3);
451*aca3beaaSApple OSS Distributions }
452*aca3beaaSApple OSS Distributions 
453*aca3beaaSApple OSS Distributions static int
kauth_authorize_process_callback(kauth_cred_t credential,__unused void * idata,kauth_action_t action,uintptr_t arg0,uintptr_t arg1,__unused uintptr_t arg2,__unused uintptr_t arg3)454*aca3beaaSApple OSS Distributions kauth_authorize_process_callback(kauth_cred_t credential, __unused void *idata, kauth_action_t action,
455*aca3beaaSApple OSS Distributions     uintptr_t arg0, uintptr_t arg1, __unused uintptr_t arg2, __unused uintptr_t arg3)
456*aca3beaaSApple OSS Distributions {
457*aca3beaaSApple OSS Distributions 	switch (action) {
458*aca3beaaSApple OSS Distributions 	case KAUTH_PROCESS_CANSIGNAL:
459*aca3beaaSApple OSS Distributions 		panic("KAUTH_PROCESS_CANSIGNAL not implemented");
460*aca3beaaSApple OSS Distributions 		/* XXX credential wrong here */
461*aca3beaaSApple OSS Distributions 		/* arg0 - process to signal
462*aca3beaaSApple OSS Distributions 		 * arg1 - signal to send the process
463*aca3beaaSApple OSS Distributions 		 */
464*aca3beaaSApple OSS Distributions 		if (cansignal(current_proc(), credential, (struct proc *)arg0, (int)arg1)) {
465*aca3beaaSApple OSS Distributions 			return KAUTH_RESULT_ALLOW;
466*aca3beaaSApple OSS Distributions 		}
467*aca3beaaSApple OSS Distributions 		break;
468*aca3beaaSApple OSS Distributions 	case KAUTH_PROCESS_CANTRACE:
469*aca3beaaSApple OSS Distributions 		/* current_proc() - process that will do the tracing
470*aca3beaaSApple OSS Distributions 		 * arg0 - process to be traced
471*aca3beaaSApple OSS Distributions 		 * arg1 - pointer to int - reason (errno) for denial
472*aca3beaaSApple OSS Distributions 		 */
473*aca3beaaSApple OSS Distributions 		if (cantrace(current_proc(), credential, (proc_t)arg0, (int *)arg1)) {
474*aca3beaaSApple OSS Distributions 			return KAUTH_RESULT_ALLOW;
475*aca3beaaSApple OSS Distributions 		}
476*aca3beaaSApple OSS Distributions 		break;
477*aca3beaaSApple OSS Distributions 	}
478*aca3beaaSApple OSS Distributions 
479*aca3beaaSApple OSS Distributions 	/* no explicit result, so defer to others in the chain */
480*aca3beaaSApple OSS Distributions 	return KAUTH_RESULT_DEFER;
481*aca3beaaSApple OSS Distributions }
482*aca3beaaSApple OSS Distributions 
483*aca3beaaSApple OSS Distributions /*
484*aca3beaaSApple OSS Distributions  * File system operation authorization scope.  This is really only a notification
485*aca3beaaSApple OSS Distributions  * of the file system operation, not an authorization check.  Thus the result is
486*aca3beaaSApple OSS Distributions  * not relevant.
487*aca3beaaSApple OSS Distributions  * arguments passed to KAUTH_FILEOP_OPEN listeners
488*aca3beaaSApple OSS Distributions  *		arg0 is pointer to vnode (vnode *) for given user path.
489*aca3beaaSApple OSS Distributions  *		arg1 is pointer to path (char *) passed in to open.
490*aca3beaaSApple OSS Distributions  * arguments passed to KAUTH_FILEOP_CLOSE listeners
491*aca3beaaSApple OSS Distributions  *		arg0 is pointer to vnode (vnode *) for file to be closed.
492*aca3beaaSApple OSS Distributions  *		arg1 is pointer to path (char *) of file to be closed.
493*aca3beaaSApple OSS Distributions  *		arg2 is close flags.
494*aca3beaaSApple OSS Distributions  * arguments passed to KAUTH_FILEOP_WILL_RENAME listeners
495*aca3beaaSApple OSS Distributions  *		arg0 is pointer to vnode (vnode *) of the file being renamed
496*aca3beaaSApple OSS Distributions  *		arg1 is pointer to the "from" path (char *)
497*aca3beaaSApple OSS Distributions  *		arg2 is pointer to the "to" path (char *)
498*aca3beaaSApple OSS Distributions  * arguments passed to KAUTH_FILEOP_RENAME listeners
499*aca3beaaSApple OSS Distributions  *		arg0 is pointer to "from" path (char *).
500*aca3beaaSApple OSS Distributions  *		arg1 is pointer to "to" path (char *).
501*aca3beaaSApple OSS Distributions  * arguments passed to KAUTH_FILEOP_EXCHANGE listeners
502*aca3beaaSApple OSS Distributions  *		arg0 is pointer to file 1 path (char *).
503*aca3beaaSApple OSS Distributions  *		arg1 is pointer to file 2 path (char *).
504*aca3beaaSApple OSS Distributions  * arguments passed to KAUTH_FILEOP_EXEC listeners
505*aca3beaaSApple OSS Distributions  *		arg0 is pointer to vnode (vnode *) for executable.
506*aca3beaaSApple OSS Distributions  *		arg1 is pointer to path (char *) to executable.
507*aca3beaaSApple OSS Distributions  */
508*aca3beaaSApple OSS Distributions 
509*aca3beaaSApple OSS Distributions int
kauth_authorize_fileop_has_listeners(void)510*aca3beaaSApple OSS Distributions kauth_authorize_fileop_has_listeners(void)
511*aca3beaaSApple OSS Distributions {
512*aca3beaaSApple OSS Distributions 	/*
513*aca3beaaSApple OSS Distributions 	 * return 1 if we have any listeners for the fileop scope
514*aca3beaaSApple OSS Distributions 	 * otherwize return 0
515*aca3beaaSApple OSS Distributions 	 */
516*aca3beaaSApple OSS Distributions 	if ((kauth_scope_fileop->ks_flags & KS_F_HAS_LISTENERS) != 0) {
517*aca3beaaSApple OSS Distributions 		return 1;
518*aca3beaaSApple OSS Distributions 	}
519*aca3beaaSApple OSS Distributions 	return 0;
520*aca3beaaSApple OSS Distributions }
521*aca3beaaSApple OSS Distributions 
522*aca3beaaSApple OSS Distributions int
kauth_authorize_fileop(kauth_cred_t credential,kauth_action_t action,uintptr_t arg0,uintptr_t arg1)523*aca3beaaSApple OSS Distributions kauth_authorize_fileop(kauth_cred_t credential, kauth_action_t action, uintptr_t arg0, uintptr_t arg1)
524*aca3beaaSApple OSS Distributions {
525*aca3beaaSApple OSS Distributions 	char            *namep = NULL;
526*aca3beaaSApple OSS Distributions 	int                     name_len;
527*aca3beaaSApple OSS Distributions 	uintptr_t       arg2 = 0;
528*aca3beaaSApple OSS Distributions 
529*aca3beaaSApple OSS Distributions 	/* we do not have a primary handler for the fileop scope so bail out if
530*aca3beaaSApple OSS Distributions 	 * there are no listeners.
531*aca3beaaSApple OSS Distributions 	 */
532*aca3beaaSApple OSS Distributions 	if ((kauth_scope_fileop->ks_flags & KS_F_HAS_LISTENERS) == 0) {
533*aca3beaaSApple OSS Distributions 		return 0;
534*aca3beaaSApple OSS Distributions 	}
535*aca3beaaSApple OSS Distributions 
536*aca3beaaSApple OSS Distributions 	if (action == KAUTH_FILEOP_OPEN ||
537*aca3beaaSApple OSS Distributions 	    action == KAUTH_FILEOP_CLOSE ||
538*aca3beaaSApple OSS Distributions 	    action == KAUTH_FILEOP_EXEC ||
539*aca3beaaSApple OSS Distributions 	    action == KAUTH_FILEOP_WILL_RENAME) {
540*aca3beaaSApple OSS Distributions 		/* get path to the given vnode as a convenience to our listeners.
541*aca3beaaSApple OSS Distributions 		 */
542*aca3beaaSApple OSS Distributions 		namep = get_pathbuff();
543*aca3beaaSApple OSS Distributions 		name_len = MAXPATHLEN;
544*aca3beaaSApple OSS Distributions 		if (vn_getpath((vnode_t)arg0, namep, &name_len) != 0) {
545*aca3beaaSApple OSS Distributions 			release_pathbuff(namep);
546*aca3beaaSApple OSS Distributions 			return 0;
547*aca3beaaSApple OSS Distributions 		}
548*aca3beaaSApple OSS Distributions 		if (action == KAUTH_FILEOP_CLOSE ||
549*aca3beaaSApple OSS Distributions 		    action == KAUTH_FILEOP_WILL_RENAME) {
550*aca3beaaSApple OSS Distributions 			/*
551*aca3beaaSApple OSS Distributions 			 * - Close has some flags that come in via arg1.
552*aca3beaaSApple OSS Distributions 			 * - Will-rename wants to pass the vnode and
553*aca3beaaSApple OSS Distributions 			 *   both paths to the listeners ("to" path
554*aca3beaaSApple OSS Distributions 			 *   starts in arg1, moves to arg2).
555*aca3beaaSApple OSS Distributions 			 */
556*aca3beaaSApple OSS Distributions 			arg2 = arg1;
557*aca3beaaSApple OSS Distributions 		}
558*aca3beaaSApple OSS Distributions 		arg1 = (uintptr_t)namep;
559*aca3beaaSApple OSS Distributions 	}
560*aca3beaaSApple OSS Distributions 	kauth_authorize_action(kauth_scope_fileop, credential, action, arg0, arg1, arg2, 0);
561*aca3beaaSApple OSS Distributions 
562*aca3beaaSApple OSS Distributions 	if (namep != NULL) {
563*aca3beaaSApple OSS Distributions 		release_pathbuff(namep);
564*aca3beaaSApple OSS Distributions 	}
565*aca3beaaSApple OSS Distributions 
566*aca3beaaSApple OSS Distributions 	return 0;
567*aca3beaaSApple OSS Distributions }
568*aca3beaaSApple OSS Distributions 
569*aca3beaaSApple OSS Distributions /*
570*aca3beaaSApple OSS Distributions  * Generic authorization scope.
571*aca3beaaSApple OSS Distributions  */
572*aca3beaaSApple OSS Distributions 
573*aca3beaaSApple OSS Distributions int
kauth_authorize_generic(kauth_cred_t credential,kauth_action_t action)574*aca3beaaSApple OSS Distributions kauth_authorize_generic(kauth_cred_t credential, kauth_action_t action)
575*aca3beaaSApple OSS Distributions {
576*aca3beaaSApple OSS Distributions 	if (credential == NULL) {
577*aca3beaaSApple OSS Distributions 		panic("auth against NULL credential");
578*aca3beaaSApple OSS Distributions 	}
579*aca3beaaSApple OSS Distributions 
580*aca3beaaSApple OSS Distributions 	return kauth_authorize_action(kauth_scope_generic, credential, action, 0, 0, 0, 0);
581*aca3beaaSApple OSS Distributions }
582*aca3beaaSApple OSS Distributions 
583*aca3beaaSApple OSS Distributions static int
kauth_authorize_generic_callback(kauth_cred_t credential,__unused void * idata,kauth_action_t action,__unused uintptr_t arg0,__unused uintptr_t arg1,__unused uintptr_t arg2,__unused uintptr_t arg3)584*aca3beaaSApple OSS Distributions kauth_authorize_generic_callback(kauth_cred_t credential, __unused void *idata, kauth_action_t action,
585*aca3beaaSApple OSS Distributions     __unused uintptr_t arg0, __unused uintptr_t arg1, __unused uintptr_t arg2, __unused uintptr_t arg3)
586*aca3beaaSApple OSS Distributions {
587*aca3beaaSApple OSS Distributions 	switch (action) {
588*aca3beaaSApple OSS Distributions 	case KAUTH_GENERIC_ISSUSER:
589*aca3beaaSApple OSS Distributions 		/* XXX == 0 ? */
590*aca3beaaSApple OSS Distributions 		return (kauth_cred_getuid(credential) == 0) ?
591*aca3beaaSApple OSS Distributions 		       KAUTH_RESULT_ALLOW : KAUTH_RESULT_DENY;
592*aca3beaaSApple OSS Distributions 	}
593*aca3beaaSApple OSS Distributions 
594*aca3beaaSApple OSS Distributions 	/* no explicit result, so defer to others in the chain */
595*aca3beaaSApple OSS Distributions 	return KAUTH_RESULT_DEFER;
596*aca3beaaSApple OSS Distributions }
597*aca3beaaSApple OSS Distributions 
598*aca3beaaSApple OSS Distributions /*
599*aca3beaaSApple OSS Distributions  * ACL evaluator.
600*aca3beaaSApple OSS Distributions  *
601*aca3beaaSApple OSS Distributions  * Determines whether the credential has the requested rights for an object secured by the supplied
602*aca3beaaSApple OSS Distributions  * ACL.
603*aca3beaaSApple OSS Distributions  *
604*aca3beaaSApple OSS Distributions  * Evaluation proceeds from the top down, with access denied if any ACE denies any of the requested
605*aca3beaaSApple OSS Distributions  * rights, or granted if all of the requested rights are satisfied by the ACEs so far.
606*aca3beaaSApple OSS Distributions  */
607*aca3beaaSApple OSS Distributions int
kauth_acl_evaluate(kauth_cred_t cred,kauth_acl_eval_t eval)608*aca3beaaSApple OSS Distributions kauth_acl_evaluate(kauth_cred_t cred, kauth_acl_eval_t eval)
609*aca3beaaSApple OSS Distributions {
610*aca3beaaSApple OSS Distributions 	int applies, error, i, gotguid;
611*aca3beaaSApple OSS Distributions 	kauth_ace_t ace;
612*aca3beaaSApple OSS Distributions 	guid_t guid;
613*aca3beaaSApple OSS Distributions 	uint32_t rights;
614*aca3beaaSApple OSS Distributions 	int wkguid;
615*aca3beaaSApple OSS Distributions 
616*aca3beaaSApple OSS Distributions 	if (cred == NULL) {
617*aca3beaaSApple OSS Distributions 		KAUTH_DEBUG("    ACL - got NULL credential");
618*aca3beaaSApple OSS Distributions 		return EINVAL;
619*aca3beaaSApple OSS Distributions 	}
620*aca3beaaSApple OSS Distributions 
621*aca3beaaSApple OSS Distributions 	if (eval == NULL) {
622*aca3beaaSApple OSS Distributions 		KAUTH_DEBUG("    ACL - got NULL ACL evaluator");
623*aca3beaaSApple OSS Distributions 		return EINVAL;
624*aca3beaaSApple OSS Distributions 	}
625*aca3beaaSApple OSS Distributions 
626*aca3beaaSApple OSS Distributions 	/* always allowed to do nothing */
627*aca3beaaSApple OSS Distributions 	if (eval->ae_requested == 0) {
628*aca3beaaSApple OSS Distributions 		eval->ae_result = KAUTH_RESULT_ALLOW;
629*aca3beaaSApple OSS Distributions 		return 0;
630*aca3beaaSApple OSS Distributions 	}
631*aca3beaaSApple OSS Distributions 
632*aca3beaaSApple OSS Distributions 	eval->ae_residual = eval->ae_requested;
633*aca3beaaSApple OSS Distributions 	eval->ae_found_deny = FALSE;
634*aca3beaaSApple OSS Distributions 
635*aca3beaaSApple OSS Distributions 	/*
636*aca3beaaSApple OSS Distributions 	 * Get our guid for comparison purposes.
637*aca3beaaSApple OSS Distributions 	 */
638*aca3beaaSApple OSS Distributions 	if ((error = kauth_cred_getguid(cred, &guid)) != 0) {
639*aca3beaaSApple OSS Distributions 		KAUTH_DEBUG("    ACL - can't get credential GUID (%d)", error);
640*aca3beaaSApple OSS Distributions 		error = 0;
641*aca3beaaSApple OSS Distributions 		gotguid = 0;
642*aca3beaaSApple OSS Distributions 	} else {
643*aca3beaaSApple OSS Distributions 		gotguid = 1;
644*aca3beaaSApple OSS Distributions 	}
645*aca3beaaSApple OSS Distributions 
646*aca3beaaSApple OSS Distributions 	KAUTH_DEBUG("    ACL - %d entries, initial residual %x", eval->ae_count, eval->ae_residual);
647*aca3beaaSApple OSS Distributions 	for (i = 0, ace = eval->ae_acl; i < eval->ae_count; i++, ace++) {
648*aca3beaaSApple OSS Distributions 		/*
649*aca3beaaSApple OSS Distributions 		 * Skip inherit-only entries.
650*aca3beaaSApple OSS Distributions 		 */
651*aca3beaaSApple OSS Distributions 		if (ace->ace_flags & KAUTH_ACE_ONLY_INHERIT) {
652*aca3beaaSApple OSS Distributions 			continue;
653*aca3beaaSApple OSS Distributions 		}
654*aca3beaaSApple OSS Distributions 
655*aca3beaaSApple OSS Distributions 		/*
656*aca3beaaSApple OSS Distributions 		 * Expand generic rights, if appropriate.
657*aca3beaaSApple OSS Distributions 		 */
658*aca3beaaSApple OSS Distributions 		rights = ace->ace_rights;
659*aca3beaaSApple OSS Distributions 		if (rights & KAUTH_ACE_GENERIC_ALL) {
660*aca3beaaSApple OSS Distributions 			rights |= eval->ae_exp_gall;
661*aca3beaaSApple OSS Distributions 		}
662*aca3beaaSApple OSS Distributions 		if (rights & KAUTH_ACE_GENERIC_READ) {
663*aca3beaaSApple OSS Distributions 			rights |= eval->ae_exp_gread;
664*aca3beaaSApple OSS Distributions 		}
665*aca3beaaSApple OSS Distributions 		if (rights & KAUTH_ACE_GENERIC_WRITE) {
666*aca3beaaSApple OSS Distributions 			rights |= eval->ae_exp_gwrite;
667*aca3beaaSApple OSS Distributions 		}
668*aca3beaaSApple OSS Distributions 		if (rights & KAUTH_ACE_GENERIC_EXECUTE) {
669*aca3beaaSApple OSS Distributions 			rights |= eval->ae_exp_gexec;
670*aca3beaaSApple OSS Distributions 		}
671*aca3beaaSApple OSS Distributions 
672*aca3beaaSApple OSS Distributions 		/*
673*aca3beaaSApple OSS Distributions 		 * Determine whether this entry applies to the current request.  This
674*aca3beaaSApple OSS Distributions 		 * saves us checking the GUID if the entry has nothing to do with what
675*aca3beaaSApple OSS Distributions 		 * we're currently doing.
676*aca3beaaSApple OSS Distributions 		 */
677*aca3beaaSApple OSS Distributions 		switch (ace->ace_flags & KAUTH_ACE_KINDMASK) {
678*aca3beaaSApple OSS Distributions 		case KAUTH_ACE_PERMIT:
679*aca3beaaSApple OSS Distributions 			if (!(eval->ae_residual & rights)) {
680*aca3beaaSApple OSS Distributions 				continue;
681*aca3beaaSApple OSS Distributions 			}
682*aca3beaaSApple OSS Distributions 			break;
683*aca3beaaSApple OSS Distributions 		case KAUTH_ACE_DENY:
684*aca3beaaSApple OSS Distributions 			if (!(eval->ae_requested & rights)) {
685*aca3beaaSApple OSS Distributions 				continue;
686*aca3beaaSApple OSS Distributions 			}
687*aca3beaaSApple OSS Distributions 			eval->ae_found_deny = TRUE;
688*aca3beaaSApple OSS Distributions 			break;
689*aca3beaaSApple OSS Distributions 		default:
690*aca3beaaSApple OSS Distributions 			/* we don't recognise this ACE, skip it */
691*aca3beaaSApple OSS Distributions 			continue;
692*aca3beaaSApple OSS Distributions 		}
693*aca3beaaSApple OSS Distributions 
694*aca3beaaSApple OSS Distributions 		/*
695*aca3beaaSApple OSS Distributions 		 * Verify whether this entry applies to the credential.
696*aca3beaaSApple OSS Distributions 		 */
697*aca3beaaSApple OSS Distributions 		wkguid = kauth_wellknown_guid(&ace->ace_applicable);
698*aca3beaaSApple OSS Distributions 		switch (wkguid) {
699*aca3beaaSApple OSS Distributions 		case KAUTH_WKG_OWNER:
700*aca3beaaSApple OSS Distributions 			applies = eval->ae_options & KAUTH_AEVAL_IS_OWNER;
701*aca3beaaSApple OSS Distributions 			break;
702*aca3beaaSApple OSS Distributions 		case KAUTH_WKG_GROUP:
703*aca3beaaSApple OSS Distributions 			if (!gotguid || (eval->ae_options & KAUTH_AEVAL_IN_GROUP_UNKNOWN)) {
704*aca3beaaSApple OSS Distributions 				applies = ((ace->ace_flags & KAUTH_ACE_KINDMASK) == KAUTH_ACE_DENY);
705*aca3beaaSApple OSS Distributions 			} else {
706*aca3beaaSApple OSS Distributions 				applies = eval->ae_options & KAUTH_AEVAL_IN_GROUP;
707*aca3beaaSApple OSS Distributions 			}
708*aca3beaaSApple OSS Distributions 			break;
709*aca3beaaSApple OSS Distributions 		/* we short-circuit these here rather than wasting time calling the group membership code */
710*aca3beaaSApple OSS Distributions 		case KAUTH_WKG_EVERYBODY:
711*aca3beaaSApple OSS Distributions 			applies = 1;
712*aca3beaaSApple OSS Distributions 			break;
713*aca3beaaSApple OSS Distributions 		case KAUTH_WKG_NOBODY:
714*aca3beaaSApple OSS Distributions 			applies = 0;
715*aca3beaaSApple OSS Distributions 			break;
716*aca3beaaSApple OSS Distributions 
717*aca3beaaSApple OSS Distributions 		default:
718*aca3beaaSApple OSS Distributions 			/* check to see whether it's exactly us, or a group we are a member of */
719*aca3beaaSApple OSS Distributions 			applies = !gotguid ? 0 : kauth_guid_equal(&guid, &ace->ace_applicable);
720*aca3beaaSApple OSS Distributions 			KAUTH_DEBUG("    ACL - ACE applicable " K_UUID_FMT " caller " K_UUID_FMT " %smatched",
721*aca3beaaSApple OSS Distributions 			    K_UUID_ARG(ace->ace_applicable), K_UUID_ARG(guid), applies ? "" : "not ");
722*aca3beaaSApple OSS Distributions 
723*aca3beaaSApple OSS Distributions 			if (!applies) {
724*aca3beaaSApple OSS Distributions 				error = !gotguid ? ENOENT : kauth_cred_ismember_guid(cred, &ace->ace_applicable, &applies);
725*aca3beaaSApple OSS Distributions 				/*
726*aca3beaaSApple OSS Distributions 				 * If we can't resolve group membership, we have to limit misbehaviour.
727*aca3beaaSApple OSS Distributions 				 * If the ACE is an 'allow' ACE, assume the cred is not a member (avoid
728*aca3beaaSApple OSS Distributions 				 * granting excess access).  If the ACE is a 'deny' ACE, assume the cred
729*aca3beaaSApple OSS Distributions 				 * is a member (avoid failing to deny).
730*aca3beaaSApple OSS Distributions 				 */
731*aca3beaaSApple OSS Distributions 				if (error != 0) {
732*aca3beaaSApple OSS Distributions 					KAUTH_DEBUG("    ACL[%d] - can't get membership, making pessimistic assumption", i);
733*aca3beaaSApple OSS Distributions 					switch (ace->ace_flags & KAUTH_ACE_KINDMASK) {
734*aca3beaaSApple OSS Distributions 					case KAUTH_ACE_PERMIT:
735*aca3beaaSApple OSS Distributions 						applies = 0;
736*aca3beaaSApple OSS Distributions 						break;
737*aca3beaaSApple OSS Distributions 					case KAUTH_ACE_DENY:
738*aca3beaaSApple OSS Distributions 						applies = 1;
739*aca3beaaSApple OSS Distributions 						break;
740*aca3beaaSApple OSS Distributions 					}
741*aca3beaaSApple OSS Distributions 				} else {
742*aca3beaaSApple OSS Distributions 					KAUTH_DEBUG("    ACL - %s group member", applies ? "is" : "not");
743*aca3beaaSApple OSS Distributions 				}
744*aca3beaaSApple OSS Distributions 			} else {
745*aca3beaaSApple OSS Distributions 				KAUTH_DEBUG("    ACL - entry matches caller");
746*aca3beaaSApple OSS Distributions 			}
747*aca3beaaSApple OSS Distributions 		}
748*aca3beaaSApple OSS Distributions 		if (!applies) {
749*aca3beaaSApple OSS Distributions 			continue;
750*aca3beaaSApple OSS Distributions 		}
751*aca3beaaSApple OSS Distributions 
752*aca3beaaSApple OSS Distributions 		/*
753*aca3beaaSApple OSS Distributions 		 * Apply ACE to outstanding rights.
754*aca3beaaSApple OSS Distributions 		 */
755*aca3beaaSApple OSS Distributions 		switch (ace->ace_flags & KAUTH_ACE_KINDMASK) {
756*aca3beaaSApple OSS Distributions 		case KAUTH_ACE_PERMIT:
757*aca3beaaSApple OSS Distributions 			/* satisfy any rights that this ACE grants */
758*aca3beaaSApple OSS Distributions 			eval->ae_residual = eval->ae_residual & ~rights;
759*aca3beaaSApple OSS Distributions 			KAUTH_DEBUG("    ACL[%d] - rights %x leave residual %x", i, rights, eval->ae_residual);
760*aca3beaaSApple OSS Distributions 			/* all rights satisfied? */
761*aca3beaaSApple OSS Distributions 			if (eval->ae_residual == 0) {
762*aca3beaaSApple OSS Distributions 				eval->ae_result = KAUTH_RESULT_ALLOW;
763*aca3beaaSApple OSS Distributions 				return 0;
764*aca3beaaSApple OSS Distributions 			}
765*aca3beaaSApple OSS Distributions 			break;
766*aca3beaaSApple OSS Distributions 		case KAUTH_ACE_DENY:
767*aca3beaaSApple OSS Distributions 			/* deny the request if any of the requested rights is denied */
768*aca3beaaSApple OSS Distributions 			if (eval->ae_requested & rights) {
769*aca3beaaSApple OSS Distributions 				KAUTH_DEBUG("    ACL[%d] - denying based on %x", i, rights);
770*aca3beaaSApple OSS Distributions 				eval->ae_result = KAUTH_RESULT_DENY;
771*aca3beaaSApple OSS Distributions 				return 0;
772*aca3beaaSApple OSS Distributions 			}
773*aca3beaaSApple OSS Distributions 			break;
774*aca3beaaSApple OSS Distributions 		default:
775*aca3beaaSApple OSS Distributions 			KAUTH_DEBUG("    ACL - unknown entry kind %d", ace->ace_flags & KAUTH_ACE_KINDMASK);
776*aca3beaaSApple OSS Distributions 			break;
777*aca3beaaSApple OSS Distributions 		}
778*aca3beaaSApple OSS Distributions 	}
779*aca3beaaSApple OSS Distributions 	/* if not permitted, defer to other modes of authorisation */
780*aca3beaaSApple OSS Distributions 	eval->ae_result = KAUTH_RESULT_DEFER;
781*aca3beaaSApple OSS Distributions 	return 0;
782*aca3beaaSApple OSS Distributions }
783*aca3beaaSApple OSS Distributions 
784*aca3beaaSApple OSS Distributions /*
785*aca3beaaSApple OSS Distributions  * Perform ACL inheritance and umask-ACL handling.
786*aca3beaaSApple OSS Distributions  *
787*aca3beaaSApple OSS Distributions  * Entries are inherited from the ACL on dvp.  A caller-supplied
788*aca3beaaSApple OSS Distributions  * ACL is in initial, and the result is output into product.
789*aca3beaaSApple OSS Distributions  * If the process has a umask ACL and one is not supplied, we use
790*aca3beaaSApple OSS Distributions  * the umask ACL.
791*aca3beaaSApple OSS Distributions  * If isdir is set, the resultant ACL is for a directory, otherwise it is for a file.
792*aca3beaaSApple OSS Distributions  */
793*aca3beaaSApple OSS Distributions int
kauth_acl_inherit(vnode_t dvp,kauth_acl_t initial,kauth_acl_t * product,int isdir,vfs_context_t ctx)794*aca3beaaSApple OSS Distributions kauth_acl_inherit(vnode_t dvp, kauth_acl_t initial, kauth_acl_t *product, int isdir, vfs_context_t ctx)
795*aca3beaaSApple OSS Distributions {
796*aca3beaaSApple OSS Distributions 	int     entries, error, index;
797*aca3beaaSApple OSS Distributions 	unsigned int i;
798*aca3beaaSApple OSS Distributions 	struct vnode_attr dva;
799*aca3beaaSApple OSS Distributions 	kauth_acl_t inherit, result;
800*aca3beaaSApple OSS Distributions 
801*aca3beaaSApple OSS Distributions 	/*
802*aca3beaaSApple OSS Distributions 	 * Fetch the ACL from the directory.  This should never fail.
803*aca3beaaSApple OSS Distributions 	 * Note that we don't manage inheritance when the remote server is
804*aca3beaaSApple OSS Distributions 	 * doing authorization, since this means server enforcement of
805*aca3beaaSApple OSS Distributions 	 * inheritance semantics; we just want to compose the initial
806*aca3beaaSApple OSS Distributions 	 * ACL and any inherited ACE entries from the container object.
807*aca3beaaSApple OSS Distributions 	 *
808*aca3beaaSApple OSS Distributions 	 * XXX TODO: <rdar://3634665> wants a "umask ACL" from the process.
809*aca3beaaSApple OSS Distributions 	 */
810*aca3beaaSApple OSS Distributions 	inherit = NULL;
811*aca3beaaSApple OSS Distributions 	/*
812*aca3beaaSApple OSS Distributions 	 * If there is no initial ACL, or there is, and the initial ACLs
813*aca3beaaSApple OSS Distributions 	 * flags do not request "no inheritance", then we inherit.  This allows
814*aca3beaaSApple OSS Distributions 	 * initial object creation via open_extended() and mkdir_extended()
815*aca3beaaSApple OSS Distributions 	 * to reject inheritance for themselves and for inferior nodes by
816*aca3beaaSApple OSS Distributions 	 * specifying a non-NULL inital ACL which has the KAUTH_ACL_NO_INHERIT
817*aca3beaaSApple OSS Distributions 	 * flag set in the flags field.
818*aca3beaaSApple OSS Distributions 	 */
819*aca3beaaSApple OSS Distributions 	if ((initial == NULL || !(initial->acl_flags & KAUTH_ACL_NO_INHERIT)) &&
820*aca3beaaSApple OSS Distributions 	    (dvp != NULL) && !vfs_authopaque(vnode_mount(dvp))) {
821*aca3beaaSApple OSS Distributions 		VATTR_INIT(&dva);
822*aca3beaaSApple OSS Distributions 		VATTR_WANTED(&dva, va_acl);
823*aca3beaaSApple OSS Distributions 		if ((error = vnode_getattr(dvp, &dva, ctx)) != 0) {
824*aca3beaaSApple OSS Distributions 			KAUTH_DEBUG("    ERROR - could not get parent directory ACL for inheritance");
825*aca3beaaSApple OSS Distributions 			return error;
826*aca3beaaSApple OSS Distributions 		}
827*aca3beaaSApple OSS Distributions 		if (VATTR_IS_SUPPORTED(&dva, va_acl)) {
828*aca3beaaSApple OSS Distributions 			inherit = dva.va_acl;
829*aca3beaaSApple OSS Distributions 		}
830*aca3beaaSApple OSS Distributions 	}
831*aca3beaaSApple OSS Distributions 
832*aca3beaaSApple OSS Distributions 	/*
833*aca3beaaSApple OSS Distributions 	 * Compute the number of entries in the result ACL by scanning the
834*aca3beaaSApple OSS Distributions 	 * input lists.
835*aca3beaaSApple OSS Distributions 	 */
836*aca3beaaSApple OSS Distributions 	entries = 0;
837*aca3beaaSApple OSS Distributions 	if (inherit != NULL) {
838*aca3beaaSApple OSS Distributions 		for (i = 0; i < inherit->acl_entrycount; i++) {
839*aca3beaaSApple OSS Distributions 			if (inherit->acl_ace[i].ace_flags & (isdir ? KAUTH_ACE_DIRECTORY_INHERIT : KAUTH_ACE_FILE_INHERIT)) {
840*aca3beaaSApple OSS Distributions 				entries++;
841*aca3beaaSApple OSS Distributions 			}
842*aca3beaaSApple OSS Distributions 		}
843*aca3beaaSApple OSS Distributions 	}
844*aca3beaaSApple OSS Distributions 
845*aca3beaaSApple OSS Distributions 	if (initial == NULL) {
846*aca3beaaSApple OSS Distributions 		/*
847*aca3beaaSApple OSS Distributions 		 * XXX 3634665 TODO: if the initial ACL is not specfied by
848*aca3beaaSApple OSS Distributions 		 * XXX the caller, fetch the umask ACL from the process,
849*aca3beaaSApple OSS Distributions 		 * and use it in place of "initial".
850*aca3beaaSApple OSS Distributions 		 */
851*aca3beaaSApple OSS Distributions 	}
852*aca3beaaSApple OSS Distributions 
853*aca3beaaSApple OSS Distributions 	if (initial != NULL) {
854*aca3beaaSApple OSS Distributions 		if (initial->acl_entrycount != KAUTH_FILESEC_NOACL) {
855*aca3beaaSApple OSS Distributions 			entries += initial->acl_entrycount;
856*aca3beaaSApple OSS Distributions 		} else {
857*aca3beaaSApple OSS Distributions 			initial = NULL;
858*aca3beaaSApple OSS Distributions 		}
859*aca3beaaSApple OSS Distributions 	}
860*aca3beaaSApple OSS Distributions 
861*aca3beaaSApple OSS Distributions 	/*
862*aca3beaaSApple OSS Distributions 	 * If there is no initial ACL, and no inheritable entries, the
863*aca3beaaSApple OSS Distributions 	 * object should be created with no ACL at all.
864*aca3beaaSApple OSS Distributions 	 * Note that this differs from the case where the initial ACL
865*aca3beaaSApple OSS Distributions 	 * is empty, in which case the object must also have an empty ACL.
866*aca3beaaSApple OSS Distributions 	 */
867*aca3beaaSApple OSS Distributions 	if ((entries == 0) && (initial == NULL)) {
868*aca3beaaSApple OSS Distributions 		*product = NULL;
869*aca3beaaSApple OSS Distributions 		error = 0;
870*aca3beaaSApple OSS Distributions 		goto out;
871*aca3beaaSApple OSS Distributions 	}
872*aca3beaaSApple OSS Distributions 
873*aca3beaaSApple OSS Distributions 	/*
874*aca3beaaSApple OSS Distributions 	 * Allocate the result buffer.
875*aca3beaaSApple OSS Distributions 	 */
876*aca3beaaSApple OSS Distributions 	if ((result = kauth_acl_alloc(entries)) == NULL) {
877*aca3beaaSApple OSS Distributions 		KAUTH_DEBUG("    ERROR - could not allocate %d-entry result buffer for inherited ACL", entries);
878*aca3beaaSApple OSS Distributions 		error = ENOMEM;
879*aca3beaaSApple OSS Distributions 		goto out;
880*aca3beaaSApple OSS Distributions 	}
881*aca3beaaSApple OSS Distributions 
882*aca3beaaSApple OSS Distributions 	/*
883*aca3beaaSApple OSS Distributions 	 * Composition is simply:
884*aca3beaaSApple OSS Distributions 	 *  - initial direct ACEs
885*aca3beaaSApple OSS Distributions 	 *  - inherited ACEs from new parent
886*aca3beaaSApple OSS Distributions 	 */
887*aca3beaaSApple OSS Distributions 	index = 0;
888*aca3beaaSApple OSS Distributions 	if (initial != NULL) {
889*aca3beaaSApple OSS Distributions 		for (i = 0; i < initial->acl_entrycount; i++) {
890*aca3beaaSApple OSS Distributions 			if (!(initial->acl_ace[i].ace_flags & KAUTH_ACE_INHERITED)) {
891*aca3beaaSApple OSS Distributions 				result->acl_ace[index++] = initial->acl_ace[i];
892*aca3beaaSApple OSS Distributions 			}
893*aca3beaaSApple OSS Distributions 		}
894*aca3beaaSApple OSS Distributions 		KAUTH_DEBUG("    INHERIT - applied %d of %d initial entries", index, initial->acl_entrycount);
895*aca3beaaSApple OSS Distributions 	}
896*aca3beaaSApple OSS Distributions 	if (inherit != NULL) {
897*aca3beaaSApple OSS Distributions 		for (i = 0; i < inherit->acl_entrycount; i++) {
898*aca3beaaSApple OSS Distributions 			/*
899*aca3beaaSApple OSS Distributions 			 * Inherit onto this object?  We inherit only if
900*aca3beaaSApple OSS Distributions 			 * the target object is a container object and the
901*aca3beaaSApple OSS Distributions 			 * KAUTH_ACE_DIRECTORY_INHERIT bit is set, OR if
902*aca3beaaSApple OSS Distributions 			 * if the target object is not a container, and
903*aca3beaaSApple OSS Distributions 			 * the KAUTH_ACE_FILE_INHERIT bit is set.
904*aca3beaaSApple OSS Distributions 			 */
905*aca3beaaSApple OSS Distributions 			if (inherit->acl_ace[i].ace_flags & (isdir ? KAUTH_ACE_DIRECTORY_INHERIT : KAUTH_ACE_FILE_INHERIT)) {
906*aca3beaaSApple OSS Distributions 				result->acl_ace[index] = inherit->acl_ace[i];
907*aca3beaaSApple OSS Distributions 				result->acl_ace[index].ace_flags |= KAUTH_ACE_INHERITED;
908*aca3beaaSApple OSS Distributions 				result->acl_ace[index].ace_flags &= ~KAUTH_ACE_ONLY_INHERIT;
909*aca3beaaSApple OSS Distributions 				/*
910*aca3beaaSApple OSS Distributions 				 * We do not re-inherit inheritance flags
911*aca3beaaSApple OSS Distributions 				 * if the ACE from the container has a
912*aca3beaaSApple OSS Distributions 				 * KAUTH_ACE_LIMIT_INHERIT, OR if the new
913*aca3beaaSApple OSS Distributions 				 * object is not itself a container (since
914*aca3beaaSApple OSS Distributions 				 * inheritance is always container-based).
915*aca3beaaSApple OSS Distributions 				 */
916*aca3beaaSApple OSS Distributions 				if ((result->acl_ace[index].ace_flags & KAUTH_ACE_LIMIT_INHERIT) || !isdir) {
917*aca3beaaSApple OSS Distributions 					result->acl_ace[index].ace_flags &=
918*aca3beaaSApple OSS Distributions 					    ~(KAUTH_ACE_INHERIT_CONTROL_FLAGS);
919*aca3beaaSApple OSS Distributions 				}
920*aca3beaaSApple OSS Distributions 				index++;
921*aca3beaaSApple OSS Distributions 			}
922*aca3beaaSApple OSS Distributions 		}
923*aca3beaaSApple OSS Distributions 	}
924*aca3beaaSApple OSS Distributions 	result->acl_entrycount = index;
925*aca3beaaSApple OSS Distributions 	*product = result;
926*aca3beaaSApple OSS Distributions 	KAUTH_DEBUG("    INHERIT - product ACL has %d entries", index);
927*aca3beaaSApple OSS Distributions 	error = 0;
928*aca3beaaSApple OSS Distributions out:
929*aca3beaaSApple OSS Distributions 	if (inherit != NULL) {
930*aca3beaaSApple OSS Distributions 		kauth_acl_free(inherit);
931*aca3beaaSApple OSS Distributions 	}
932*aca3beaaSApple OSS Distributions 	return error;
933*aca3beaaSApple OSS Distributions }
934*aca3beaaSApple OSS Distributions 
935*aca3beaaSApple OSS Distributions /*
936*aca3beaaSApple OSS Distributions  * Optimistically copy in a kauth_filesec structure
937*aca3beaaSApple OSS Distributions  *
938*aca3beaaSApple OSS Distributions  * Parameters:	xsecurity		user space kauth_filesec_t
939*aca3beaaSApple OSS Distributions  *		xsecdstpp		pointer to kauth_filesec_t to be
940*aca3beaaSApple OSS Distributions  *					modified to contain the contain a
941*aca3beaaSApple OSS Distributions  *					pointer to an allocated copy of the
942*aca3beaaSApple OSS Distributions  *					user space argument
943*aca3beaaSApple OSS Distributions  *
944*aca3beaaSApple OSS Distributions  * Returns:	0			Success
945*aca3beaaSApple OSS Distributions  *		ENOMEM			Insufficient memory for the copy.
946*aca3beaaSApple OSS Distributions  *		EINVAL			The user space data was invalid, or
947*aca3beaaSApple OSS Distributions  *					there were too many ACE entries.
948*aca3beaaSApple OSS Distributions  *		EFAULT			The user space address was invalid;
949*aca3beaaSApple OSS Distributions  *					this may mean 'fsec_entrycount' in
950*aca3beaaSApple OSS Distributions  *					the user copy is corrupt/incorrect.
951*aca3beaaSApple OSS Distributions  *
952*aca3beaaSApple OSS Distributions  * Implicit returns: xsecdestpp, modified (only if successful!)
953*aca3beaaSApple OSS Distributions  *
954*aca3beaaSApple OSS Distributions  * Notes:	The returned kauth_filesec_t is in host byte order
955*aca3beaaSApple OSS Distributions  *
956*aca3beaaSApple OSS Distributions  *		The caller is responsible for freeing the returned
957*aca3beaaSApple OSS Distributions  *		kauth_filesec_t in the success case using the function
958*aca3beaaSApple OSS Distributions  *		kauth_filesec_free()
959*aca3beaaSApple OSS Distributions  *
960*aca3beaaSApple OSS Distributions  *		Our largest initial guess is 32; this needs to move to
961*aca3beaaSApple OSS Distributions  *		a manifest constant in <sys/kauth.h>.
962*aca3beaaSApple OSS Distributions  */
963*aca3beaaSApple OSS Distributions int
kauth_copyinfilesec(user_addr_t xsecurity,kauth_filesec_t * xsecdestpp)964*aca3beaaSApple OSS Distributions kauth_copyinfilesec(user_addr_t xsecurity, kauth_filesec_t *xsecdestpp)
965*aca3beaaSApple OSS Distributions {
966*aca3beaaSApple OSS Distributions 	int error;
967*aca3beaaSApple OSS Distributions 	kauth_filesec_t fsec;
968*aca3beaaSApple OSS Distributions 	size_t count;
969*aca3beaaSApple OSS Distributions 	size_t copysize;
970*aca3beaaSApple OSS Distributions 
971*aca3beaaSApple OSS Distributions 	error = 0;
972*aca3beaaSApple OSS Distributions 	fsec = NULL;
973*aca3beaaSApple OSS Distributions 
974*aca3beaaSApple OSS Distributions 	/*
975*aca3beaaSApple OSS Distributions 	 * Make a guess at the size of the filesec.  We start with the base
976*aca3beaaSApple OSS Distributions 	 * pointer, and look at how much room is left on the page, clipped
977*aca3beaaSApple OSS Distributions 	 * to a sensible upper bound.  If it turns out this isn't enough,
978*aca3beaaSApple OSS Distributions 	 * we'll size based on the actual ACL contents and come back again.
979*aca3beaaSApple OSS Distributions 	 *
980*aca3beaaSApple OSS Distributions 	 * The upper bound must be less than KAUTH_ACL_MAX_ENTRIES.  The
981*aca3beaaSApple OSS Distributions 	 * value here is fairly arbitrary.  It's ok to have a zero count.
982*aca3beaaSApple OSS Distributions 	 *
983*aca3beaaSApple OSS Distributions 	 * Because we're just using these values to make a guess about the
984*aca3beaaSApple OSS Distributions 	 * number of entries, the actual address doesn't matter, only their
985*aca3beaaSApple OSS Distributions 	 * relative offsets into the page.  We take advantage of this to
986*aca3beaaSApple OSS Distributions 	 * avoid an overflow in the rounding step (this is a user-provided
987*aca3beaaSApple OSS Distributions 	 * parameter, so caution pays off).
988*aca3beaaSApple OSS Distributions 	 */
989*aca3beaaSApple OSS Distributions 	{
990*aca3beaaSApple OSS Distributions 		user_addr_t known_bound = (xsecurity & PAGE_MASK) + KAUTH_FILESEC_SIZE(0);
991*aca3beaaSApple OSS Distributions 		user_addr_t uaddr = (user_addr_t)mach_vm_round_page(known_bound);
992*aca3beaaSApple OSS Distributions 		count = (uaddr - known_bound) / sizeof(struct kauth_ace);
993*aca3beaaSApple OSS Distributions 	}
994*aca3beaaSApple OSS Distributions 	if (count > 32) {
995*aca3beaaSApple OSS Distributions 		count = 32;
996*aca3beaaSApple OSS Distributions 	}
997*aca3beaaSApple OSS Distributions restart:
998*aca3beaaSApple OSS Distributions 	if ((fsec = kauth_filesec_alloc((int)count)) == NULL) {
999*aca3beaaSApple OSS Distributions 		error = ENOMEM;
1000*aca3beaaSApple OSS Distributions 		goto out;
1001*aca3beaaSApple OSS Distributions 	}
1002*aca3beaaSApple OSS Distributions 	copysize = KAUTH_FILESEC_SIZE(count);
1003*aca3beaaSApple OSS Distributions 	if ((error = copyin(xsecurity, (caddr_t)fsec, copysize)) != 0) {
1004*aca3beaaSApple OSS Distributions 		goto out;
1005*aca3beaaSApple OSS Distributions 	}
1006*aca3beaaSApple OSS Distributions 
1007*aca3beaaSApple OSS Distributions 	/* validate the filesec header */
1008*aca3beaaSApple OSS Distributions 	if (fsec->fsec_magic != KAUTH_FILESEC_MAGIC) {
1009*aca3beaaSApple OSS Distributions 		error = EINVAL;
1010*aca3beaaSApple OSS Distributions 		goto out;
1011*aca3beaaSApple OSS Distributions 	}
1012*aca3beaaSApple OSS Distributions 
1013*aca3beaaSApple OSS Distributions 	/*
1014*aca3beaaSApple OSS Distributions 	 * Is there an ACL payload, and is it too big?
1015*aca3beaaSApple OSS Distributions 	 */
1016*aca3beaaSApple OSS Distributions 	if ((fsec->fsec_entrycount != KAUTH_FILESEC_NOACL) &&
1017*aca3beaaSApple OSS Distributions 	    (fsec->fsec_entrycount > count)) {
1018*aca3beaaSApple OSS Distributions 		if (fsec->fsec_entrycount > KAUTH_ACL_MAX_ENTRIES) {
1019*aca3beaaSApple OSS Distributions 			/* XXX This should be E2BIG */
1020*aca3beaaSApple OSS Distributions 			error = EINVAL;
1021*aca3beaaSApple OSS Distributions 			goto out;
1022*aca3beaaSApple OSS Distributions 		}
1023*aca3beaaSApple OSS Distributions 		count = fsec->fsec_entrycount;
1024*aca3beaaSApple OSS Distributions 		kauth_filesec_free(fsec);
1025*aca3beaaSApple OSS Distributions 		goto restart;
1026*aca3beaaSApple OSS Distributions 	}
1027*aca3beaaSApple OSS Distributions 
1028*aca3beaaSApple OSS Distributions out:
1029*aca3beaaSApple OSS Distributions 	if (error) {
1030*aca3beaaSApple OSS Distributions 		if (fsec) {
1031*aca3beaaSApple OSS Distributions 			kauth_filesec_free(fsec);
1032*aca3beaaSApple OSS Distributions 		}
1033*aca3beaaSApple OSS Distributions 	} else {
1034*aca3beaaSApple OSS Distributions 		*xsecdestpp = fsec;
1035*aca3beaaSApple OSS Distributions 		AUDIT_ARG(opaque, fsec, copysize);
1036*aca3beaaSApple OSS Distributions 	}
1037*aca3beaaSApple OSS Distributions 	return error;
1038*aca3beaaSApple OSS Distributions }
1039*aca3beaaSApple OSS Distributions 
1040*aca3beaaSApple OSS Distributions /*
1041*aca3beaaSApple OSS Distributions  * Allocate a block of memory containing a filesec structure, immediately
1042*aca3beaaSApple OSS Distributions  * followed by 'count' kauth_ace structures.
1043*aca3beaaSApple OSS Distributions  *
1044*aca3beaaSApple OSS Distributions  * Parameters:	count			Number of kauth_ace structures needed
1045*aca3beaaSApple OSS Distributions  *
1046*aca3beaaSApple OSS Distributions  * Returns:	!NULL			A pointer to the allocated block
1047*aca3beaaSApple OSS Distributions  *		NULL			Invalid 'count' or insufficient memory
1048*aca3beaaSApple OSS Distributions  *
1049*aca3beaaSApple OSS Distributions  * Notes:	Returned memory area assumes that the structures are packed
1050*aca3beaaSApple OSS Distributions  *		densely, so this function may only be used by code that also
1051*aca3beaaSApple OSS Distributions  *		assumes no padding following structures.
1052*aca3beaaSApple OSS Distributions  *
1053*aca3beaaSApple OSS Distributions  *		The returned structure must be freed by the caller using the
1054*aca3beaaSApple OSS Distributions  *		function kauth_filesec_free(), in case we decide to use an
1055*aca3beaaSApple OSS Distributions  *		allocation mechanism that is aware of the object size at some
1056*aca3beaaSApple OSS Distributions  *		point, since the object size is only available by introspecting
1057*aca3beaaSApple OSS Distributions  *		the object itself.
1058*aca3beaaSApple OSS Distributions  */
1059*aca3beaaSApple OSS Distributions kauth_filesec_t
kauth_filesec_alloc(int count)1060*aca3beaaSApple OSS Distributions kauth_filesec_alloc(int count)
1061*aca3beaaSApple OSS Distributions {
1062*aca3beaaSApple OSS Distributions 	kauth_filesec_t fsp;
1063*aca3beaaSApple OSS Distributions 
1064*aca3beaaSApple OSS Distributions 	/* if the caller hasn't given us a valid size hint, assume the worst */
1065*aca3beaaSApple OSS Distributions 	if ((count < 0) || (count > KAUTH_ACL_MAX_ENTRIES)) {
1066*aca3beaaSApple OSS Distributions 		return NULL;
1067*aca3beaaSApple OSS Distributions 	}
1068*aca3beaaSApple OSS Distributions 
1069*aca3beaaSApple OSS Distributions 	fsp = kalloc_data(KAUTH_FILESEC_SIZE(count), Z_WAITOK);
1070*aca3beaaSApple OSS Distributions 	if (fsp != NULL) {
1071*aca3beaaSApple OSS Distributions 		fsp->fsec_magic = KAUTH_FILESEC_MAGIC;
1072*aca3beaaSApple OSS Distributions 		fsp->fsec_owner = kauth_null_guid;
1073*aca3beaaSApple OSS Distributions 		fsp->fsec_group = kauth_null_guid;
1074*aca3beaaSApple OSS Distributions 		fsp->fsec_entrycount = KAUTH_FILESEC_NOACL;
1075*aca3beaaSApple OSS Distributions 		fsp->fsec_flags = 0;
1076*aca3beaaSApple OSS Distributions 	}
1077*aca3beaaSApple OSS Distributions 	return fsp;
1078*aca3beaaSApple OSS Distributions }
1079*aca3beaaSApple OSS Distributions 
1080*aca3beaaSApple OSS Distributions /*
1081*aca3beaaSApple OSS Distributions  * Free a kauth_filesec_t that was previous allocated, either by a direct
1082*aca3beaaSApple OSS Distributions  * call to kauth_filesec_alloc() or by calling a function that calls it.
1083*aca3beaaSApple OSS Distributions  *
1084*aca3beaaSApple OSS Distributions  * Parameters:	fsp			kauth_filesec_t to free
1085*aca3beaaSApple OSS Distributions  *
1086*aca3beaaSApple OSS Distributions  * Returns:	(void)
1087*aca3beaaSApple OSS Distributions  *
1088*aca3beaaSApple OSS Distributions  * Notes:	The kauth_filesec_t to be freed is assumed to be in host
1089*aca3beaaSApple OSS Distributions  *		byte order so that this function can introspect it in the
1090*aca3beaaSApple OSS Distributions  *		future to determine its size, if necesssary.
1091*aca3beaaSApple OSS Distributions  */
1092*aca3beaaSApple OSS Distributions void
kauth_filesec_free(kauth_filesec_t fsp)1093*aca3beaaSApple OSS Distributions kauth_filesec_free(kauth_filesec_t fsp)
1094*aca3beaaSApple OSS Distributions {
1095*aca3beaaSApple OSS Distributions #ifdef KAUTH_DEBUG_ENABLE
1096*aca3beaaSApple OSS Distributions 	if (fsp == KAUTH_FILESEC_NONE) {
1097*aca3beaaSApple OSS Distributions 		panic("freeing KAUTH_FILESEC_NONE");
1098*aca3beaaSApple OSS Distributions 	}
1099*aca3beaaSApple OSS Distributions 	if (fsp == KAUTH_FILESEC_WANTED) {
1100*aca3beaaSApple OSS Distributions 		panic("freeing KAUTH_FILESEC_WANTED");
1101*aca3beaaSApple OSS Distributions 	}
1102*aca3beaaSApple OSS Distributions #endif
1103*aca3beaaSApple OSS Distributions 	kfree_data_addr(fsp);
1104*aca3beaaSApple OSS Distributions }
1105*aca3beaaSApple OSS Distributions 
1106*aca3beaaSApple OSS Distributions /*
1107*aca3beaaSApple OSS Distributions  * Set the endianness of a filesec and an ACL; if 'acl' is NULL, use the
1108*aca3beaaSApple OSS Distributions  * ACL interior to 'fsec' instead.  If the endianness doesn't change, then
1109*aca3beaaSApple OSS Distributions  * this function will have no effect.
1110*aca3beaaSApple OSS Distributions  *
1111*aca3beaaSApple OSS Distributions  * Parameters:	kendian			The endianness to set; this is either
1112*aca3beaaSApple OSS Distributions  *					KAUTH_ENDIAN_HOST or KAUTH_ENDIAN_DISK.
1113*aca3beaaSApple OSS Distributions  *		fsec			The filesec to convert.
1114*aca3beaaSApple OSS Distributions  *		acl			The ACL to convert (optional)
1115*aca3beaaSApple OSS Distributions  *
1116*aca3beaaSApple OSS Distributions  * Returns:	(void)
1117*aca3beaaSApple OSS Distributions  *
1118*aca3beaaSApple OSS Distributions  * Notes:	We use ntohl() because it has a transitive property on Intel
1119*aca3beaaSApple OSS Distributions  *		machines and no effect on PPC mancines.  This guarantees us
1120*aca3beaaSApple OSS Distributions  *		that the swapping only occurs if the endiannes is wrong.
1121*aca3beaaSApple OSS Distributions  */
1122*aca3beaaSApple OSS Distributions void
kauth_filesec_acl_setendian(int kendian,kauth_filesec_t fsec,kauth_acl_t acl)1123*aca3beaaSApple OSS Distributions kauth_filesec_acl_setendian(int kendian, kauth_filesec_t fsec, kauth_acl_t acl)
1124*aca3beaaSApple OSS Distributions {
1125*aca3beaaSApple OSS Distributions 	uint32_t        compare_magic = KAUTH_FILESEC_MAGIC;
1126*aca3beaaSApple OSS Distributions 	uint32_t        invert_magic = ntohl(KAUTH_FILESEC_MAGIC);
1127*aca3beaaSApple OSS Distributions 	uint32_t        compare_acl_entrycount;
1128*aca3beaaSApple OSS Distributions 	uint32_t        i;
1129*aca3beaaSApple OSS Distributions 
1130*aca3beaaSApple OSS Distributions 	if (compare_magic == invert_magic) {
1131*aca3beaaSApple OSS Distributions 		return;
1132*aca3beaaSApple OSS Distributions 	}
1133*aca3beaaSApple OSS Distributions 
1134*aca3beaaSApple OSS Distributions 	/* If no ACL, use ACL interior to 'fsec' instead */
1135*aca3beaaSApple OSS Distributions 	if (acl == NULL) {
1136*aca3beaaSApple OSS Distributions 		acl = &fsec->fsec_acl;
1137*aca3beaaSApple OSS Distributions 	}
1138*aca3beaaSApple OSS Distributions 
1139*aca3beaaSApple OSS Distributions 	compare_acl_entrycount = acl->acl_entrycount;
1140*aca3beaaSApple OSS Distributions 
1141*aca3beaaSApple OSS Distributions 	/*
1142*aca3beaaSApple OSS Distributions 	 * Only convert what needs to be converted, and only if the arguments
1143*aca3beaaSApple OSS Distributions 	 * are valid.  The following switch and tests effectively reject
1144*aca3beaaSApple OSS Distributions 	 * conversions on invalid magic numbers as a desirable side effect.
1145*aca3beaaSApple OSS Distributions 	 */
1146*aca3beaaSApple OSS Distributions 	switch (kendian) {
1147*aca3beaaSApple OSS Distributions 	case KAUTH_ENDIAN_HOST:         /* not in host, convert to host */
1148*aca3beaaSApple OSS Distributions 		if (fsec->fsec_magic != invert_magic) {
1149*aca3beaaSApple OSS Distributions 			return;
1150*aca3beaaSApple OSS Distributions 		}
1151*aca3beaaSApple OSS Distributions 		/* acl_entrycount is byteswapped */
1152*aca3beaaSApple OSS Distributions 		compare_acl_entrycount = ntohl(acl->acl_entrycount);
1153*aca3beaaSApple OSS Distributions 		break;
1154*aca3beaaSApple OSS Distributions 	case KAUTH_ENDIAN_DISK:         /* not in disk, convert to disk */
1155*aca3beaaSApple OSS Distributions 		if (fsec->fsec_magic != compare_magic) {
1156*aca3beaaSApple OSS Distributions 			return;
1157*aca3beaaSApple OSS Distributions 		}
1158*aca3beaaSApple OSS Distributions 		break;
1159*aca3beaaSApple OSS Distributions 	default:                        /* bad argument */
1160*aca3beaaSApple OSS Distributions 		return;
1161*aca3beaaSApple OSS Distributions 	}
1162*aca3beaaSApple OSS Distributions 
1163*aca3beaaSApple OSS Distributions 	/* We are go for conversion */
1164*aca3beaaSApple OSS Distributions 	fsec->fsec_magic = ntohl(fsec->fsec_magic);
1165*aca3beaaSApple OSS Distributions 	acl->acl_entrycount = ntohl(acl->acl_entrycount);
1166*aca3beaaSApple OSS Distributions 	if (compare_acl_entrycount != KAUTH_FILESEC_NOACL) {
1167*aca3beaaSApple OSS Distributions 		acl->acl_flags = ntohl(acl->acl_flags);
1168*aca3beaaSApple OSS Distributions 
1169*aca3beaaSApple OSS Distributions 		/* swap ACE rights and flags */
1170*aca3beaaSApple OSS Distributions 		for (i = 0; i < compare_acl_entrycount; i++) {
1171*aca3beaaSApple OSS Distributions 			acl->acl_ace[i].ace_flags = ntohl(acl->acl_ace[i].ace_flags);
1172*aca3beaaSApple OSS Distributions 			acl->acl_ace[i].ace_rights = ntohl(acl->acl_ace[i].ace_rights);
1173*aca3beaaSApple OSS Distributions 		}
1174*aca3beaaSApple OSS Distributions 	}
1175*aca3beaaSApple OSS Distributions }
1176*aca3beaaSApple OSS Distributions 
1177*aca3beaaSApple OSS Distributions /*
1178*aca3beaaSApple OSS Distributions  * Allocate an ACL buffer.
1179*aca3beaaSApple OSS Distributions  */
1180*aca3beaaSApple OSS Distributions kauth_acl_t
kauth_acl_alloc(int count)1181*aca3beaaSApple OSS Distributions kauth_acl_alloc(int count)
1182*aca3beaaSApple OSS Distributions {
1183*aca3beaaSApple OSS Distributions 	/* if the caller hasn't given us a valid size hint, assume the worst */
1184*aca3beaaSApple OSS Distributions 	if ((count < 0) || (count > KAUTH_ACL_MAX_ENTRIES)) {
1185*aca3beaaSApple OSS Distributions 		return NULL;
1186*aca3beaaSApple OSS Distributions 	}
1187*aca3beaaSApple OSS Distributions 
1188*aca3beaaSApple OSS Distributions 	return kalloc_data(KAUTH_ACL_SIZE(count), Z_WAITOK | Z_ZERO);
1189*aca3beaaSApple OSS Distributions }
1190*aca3beaaSApple OSS Distributions 
1191*aca3beaaSApple OSS Distributions void
kauth_acl_free(kauth_acl_t aclp)1192*aca3beaaSApple OSS Distributions kauth_acl_free(kauth_acl_t aclp)
1193*aca3beaaSApple OSS Distributions {
1194*aca3beaaSApple OSS Distributions 	kfree_data_addr(aclp);
1195*aca3beaaSApple OSS Distributions }
1196*aca3beaaSApple OSS Distributions 
1197*aca3beaaSApple OSS Distributions 
1198*aca3beaaSApple OSS Distributions /*
1199*aca3beaaSApple OSS Distributions  * WARNING - caller must hold KAUTH_SCOPELOCK
1200*aca3beaaSApple OSS Distributions  */
1201*aca3beaaSApple OSS Distributions static int
kauth_add_callback_to_scope(kauth_scope_t sp,kauth_listener_t klp)1202*aca3beaaSApple OSS Distributions kauth_add_callback_to_scope(kauth_scope_t sp, kauth_listener_t klp)
1203*aca3beaaSApple OSS Distributions {
1204*aca3beaaSApple OSS Distributions 	int             i;
1205*aca3beaaSApple OSS Distributions 
1206*aca3beaaSApple OSS Distributions 	for (i = 0; i < KAUTH_SCOPE_MAX_LISTENERS; i++) {
1207*aca3beaaSApple OSS Distributions 		if (sp->ks_listeners[i].kll_listenerp == NULL) {
1208*aca3beaaSApple OSS Distributions 			sp->ks_listeners[i].kll_callback = klp->kl_callback;
1209*aca3beaaSApple OSS Distributions 			sp->ks_listeners[i].kll_idata = klp->kl_idata;
1210*aca3beaaSApple OSS Distributions 			sp->ks_listeners[i].kll_listenerp = klp;
1211*aca3beaaSApple OSS Distributions 			sp->ks_flags |= KS_F_HAS_LISTENERS;
1212*aca3beaaSApple OSS Distributions 			return 0;
1213*aca3beaaSApple OSS Distributions 		}
1214*aca3beaaSApple OSS Distributions 	}
1215*aca3beaaSApple OSS Distributions 	return ENOSPC;
1216*aca3beaaSApple OSS Distributions }
1217