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