xref: /xnu-10063.121.3/bsd/kern/kern_credential.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
1 /*
2  * Copyright (c) 2004-2020 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  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
30  * support for mandatory and extensible security protections.  This notice
31  * is included in support of clause 2.2 (b) of the Apple Public License,
32  * Version 2.0.
33  */
34 
35 /*
36  * Kernel Authorization framework: Management of process/thread credentials
37  * and identity information.
38  */
39 
40 #include <sys/param.h>  /* XXX trim includes */
41 #include <sys/acct.h>
42 #include <sys/systm.h>
43 #include <sys/ucred.h>
44 #include <sys/proc_internal.h>
45 #include <sys/user.h>
46 #include <sys/timeb.h>
47 #include <sys/times.h>
48 #include <sys/malloc.h>
49 #include <sys/kauth.h>
50 #include <sys/kernel.h>
51 #include <sys/sdt.h>
52 
53 #include <security/audit/audit.h>
54 
55 #include <sys/mount.h>
56 #include <sys/stat.h>   /* For manifest constants in posix_cred_access */
57 #include <sys/sysproto.h>
58 #include <mach/message.h>
59 
60 #include <machine/atomic.h>
61 #include <libkern/OSByteOrder.h>
62 
63 #include <kern/smr_hash.h>
64 #include <kern/task.h>
65 #include <kern/locks.h>
66 #ifdef MACH_ASSERT
67 # undef MACH_ASSERT
68 #endif
69 #define MACH_ASSERT 1   /* XXX so bogus */
70 #include <kern/assert.h>
71 
72 #if CONFIG_MACF
73 #include <security/mac.h>
74 #include <security/mac_policy.h>
75 #include <security/mac_framework.h>
76 #include <security/_label.h>
77 #endif
78 
79 #include <os/hash.h>
80 #include <IOKit/IOBSD.h>
81 
82 /* Set to 1 to turn on KAUTH_DEBUG for kern_credential.c */
83 #if 0
84 #ifdef KAUTH_DEBUG
85 #undef KAUTH_DEBUG
86 #endif
87 
88 #ifdef K_UUID_FMT
89 #undef K_UUID_FMT
90 #endif
91 
92 #ifdef K_UUID_ARG
93 #undef K_UUID_ARG
94 #endif
95 
96 # define K_UUID_FMT "%08x:%08x:%08x:%08x"
97 # define K_UUID_ARG(_u) &_u.g_guid_asint[0],&_u.g_guid_asint[1],&_u.g_guid_asint[2],&_u.g_guid_asint[3]
98 # define KAUTH_DEBUG(fmt, args...)      do { printf("%s:%d: " fmt "\n", __PRETTY_FUNCTION__, __LINE__ , ##args); } while (0)
99 #endif
100 
101 #if CONFIG_EXT_RESOLVER
102 /*
103  * Interface to external identity resolver.
104  *
105  * The architecture of the interface is simple; the external resolver calls
106  * in to get work, then calls back with completed work.  It also calls us
107  * to let us know that it's (re)started, so that we can resubmit work if it
108  * times out.
109  */
110 
111 static LCK_MTX_DECLARE(kauth_resolver_mtx, &kauth_lck_grp);
112 #define KAUTH_RESOLVER_LOCK()   lck_mtx_lock(&kauth_resolver_mtx);
113 #define KAUTH_RESOLVER_UNLOCK() lck_mtx_unlock(&kauth_resolver_mtx);
114 
115 static volatile pid_t   kauth_resolver_identity;
116 static int      kauth_identitysvc_has_registered;
117 static int      kauth_resolver_registered;
118 static uint32_t kauth_resolver_sequence = 31337;
119 static int      kauth_resolver_timeout = 30;    /* default: 30 seconds */
120 
121 struct kauth_resolver_work {
122 	TAILQ_ENTRY(kauth_resolver_work) kr_link;
123 	struct kauth_identity_extlookup kr_work;
124 	uint64_t        kr_extend;
125 	uint32_t        kr_seqno;
126 	int             kr_refs;
127 	int             kr_flags;
128 #define KAUTH_REQUEST_UNSUBMITTED       (1<<0)
129 #define KAUTH_REQUEST_SUBMITTED         (1<<1)
130 #define KAUTH_REQUEST_DONE              (1<<2)
131 	int             kr_result;
132 };
133 
134 TAILQ_HEAD(kauth_resolver_unsubmitted_head, kauth_resolver_work) kauth_resolver_unsubmitted =
135     TAILQ_HEAD_INITIALIZER(kauth_resolver_unsubmitted);
136 TAILQ_HEAD(kauth_resolver_submitted_head, kauth_resolver_work) kauth_resolver_submitted =
137     TAILQ_HEAD_INITIALIZER(kauth_resolver_submitted);
138 TAILQ_HEAD(kauth_resolver_done_head, kauth_resolver_work) kauth_resolver_done =
139     TAILQ_HEAD_INITIALIZER(kauth_resolver_done);
140 
141 /* Number of resolver timeouts between logged complaints */
142 #define KAUTH_COMPLAINT_INTERVAL 1000
143 int kauth_resolver_timeout_cnt = 0;
144 
145 #if DEVELOPMENT || DEBUG
146 /* Internal builds get different (less ambiguous) breadcrumbs. */
147 #define KAUTH_RESOLVER_FAILED_ERRCODE   EOWNERDEAD
148 #else
149 /* But non-Internal builds get errors that are allowed by standards. */
150 #define KAUTH_RESOLVER_FAILED_ERRCODE   EIO
151 #endif /* DEVELOPMENT || DEBUG */
152 
153 int kauth_resolver_failed_cnt = 0;
154 #define RESOLVER_FAILED_MESSAGE(fmt, args...)                           \
155 do {                                                                    \
156 	if (!(kauth_resolver_failed_cnt++ % 100)) {                     \
157 	        printf("%s: " fmt "\n", __PRETTY_FUNCTION__, ##args);   \
158 	}                                                               \
159 } while (0)
160 
161 static int      kauth_resolver_submit(struct kauth_identity_extlookup *lkp, uint64_t extend_data);
162 static int      kauth_resolver_complete(user_addr_t message);
163 static int      kauth_resolver_getwork(user_addr_t message);
164 static int      kauth_resolver_getwork2(user_addr_t message);
165 static __attribute__((noinline)) int __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__(
166 	struct kauth_resolver_work *);
167 
168 #define KAUTH_CACHES_MAX_SIZE 10000 /* Max # entries for both groups and id caches */
169 
170 struct kauth_identity {
171 	TAILQ_ENTRY(kauth_identity) ki_link;
172 	int     ki_valid;
173 	uid_t   ki_uid;
174 	gid_t   ki_gid;
175 	uint32_t         ki_supgrpcnt;
176 	gid_t   ki_supgrps[NGROUPS];
177 	guid_t  ki_guid;
178 	ntsid_t ki_ntsid;
179 	const char      *ki_name;       /* string name from string cache */
180 	/*
181 	 * Expiry times are the earliest time at which we will disregard the
182 	 * cached state and go to userland.  Before then if the valid bit is
183 	 * set, we will return the cached value.  If it's not set, we will
184 	 * not go to userland to resolve, just assume that there is no answer
185 	 * available.
186 	 */
187 	time_t  ki_groups_expiry;
188 	time_t  ki_guid_expiry;
189 	time_t  ki_ntsid_expiry;
190 };
191 
192 static TAILQ_HEAD(kauth_identity_head, kauth_identity) kauth_identities =
193     TAILQ_HEAD_INITIALIZER(kauth_identities);
194 static LCK_MTX_DECLARE(kauth_identity_mtx, &kauth_lck_grp);
195 #define KAUTH_IDENTITY_LOCK()   lck_mtx_lock(&kauth_identity_mtx);
196 #define KAUTH_IDENTITY_UNLOCK() lck_mtx_unlock(&kauth_identity_mtx);
197 #define KAUTH_IDENTITY_CACHEMAX_DEFAULT 100     /* XXX default sizing? */
198 static int kauth_identity_cachemax = KAUTH_IDENTITY_CACHEMAX_DEFAULT;
199 static int kauth_identity_count;
200 
201 static struct kauth_identity *kauth_identity_alloc(uid_t uid, gid_t gid, guid_t *guidp, time_t guid_expiry,
202     ntsid_t *ntsidp, time_t ntsid_expiry, size_t supgrpcnt, gid_t *supgrps, time_t groups_expiry,
203     const char *name, int nametype);
204 static void     kauth_identity_register_and_free(struct kauth_identity *kip);
205 static void     kauth_identity_updatecache(struct kauth_identity_extlookup *elp, struct kauth_identity *kip, uint64_t extend_data);
206 static void     kauth_identity_trimcache(int newsize);
207 static void     kauth_identity_lru(struct kauth_identity *kip);
208 static int      kauth_identity_guid_expired(struct kauth_identity *kip);
209 static int      kauth_identity_ntsid_expired(struct kauth_identity *kip);
210 static int      kauth_identity_find_uid(uid_t uid, struct kauth_identity *kir, char *getname);
211 static int      kauth_identity_find_gid(gid_t gid, struct kauth_identity *kir, char *getname);
212 static int      kauth_identity_find_guid(guid_t *guidp, struct kauth_identity *kir, char *getname);
213 static int      kauth_identity_find_ntsid(ntsid_t *ntsid, struct kauth_identity *kir, char *getname);
214 static int      kauth_identity_find_nam(char *name, int valid, struct kauth_identity *kir);
215 
216 struct kauth_group_membership {
217 	TAILQ_ENTRY(kauth_group_membership) gm_link;
218 	uid_t   gm_uid;         /* the identity whose membership we're recording */
219 	gid_t   gm_gid;         /* group of which they are a member */
220 	time_t  gm_expiry;      /* TTL for the membership, or 0 for persistent entries */
221 	int     gm_flags;
222 #define KAUTH_GROUP_ISMEMBER    (1<<0)
223 };
224 
225 TAILQ_HEAD(kauth_groups_head, kauth_group_membership) kauth_groups =
226     TAILQ_HEAD_INITIALIZER(kauth_groups);
227 static LCK_MTX_DECLARE(kauth_groups_mtx, &kauth_lck_grp);
228 #define KAUTH_GROUPS_LOCK()     lck_mtx_lock(&kauth_groups_mtx);
229 #define KAUTH_GROUPS_UNLOCK()   lck_mtx_unlock(&kauth_groups_mtx);
230 #define KAUTH_GROUPS_CACHEMAX_DEFAULT 100       /* XXX default sizing? */
231 static int kauth_groups_cachemax = KAUTH_GROUPS_CACHEMAX_DEFAULT;
232 static int kauth_groups_count;
233 
234 static int      kauth_groups_expired(struct kauth_group_membership *gm);
235 static void     kauth_groups_lru(struct kauth_group_membership *gm);
236 static void     kauth_groups_updatecache(struct kauth_identity_extlookup *el);
237 static void     kauth_groups_trimcache(int newsize);
238 
239 /*
240  *  __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__
241  *
242  * Description:  Waits for the user space daemon to respond to the request
243  *               we made. Function declared non inline to be visible in
244  *               stackshots and spindumps as well as debugging.
245  *
246  * Parameters:   workp                     Work queue entry.
247  *
248  * Returns:      0                         on Success.
249  *               EIO                       if Resolver is dead.
250  *               EINTR                     thread interrupted in msleep
251  *               EWOULDBLOCK               thread timed out in msleep
252  *               ERESTART                  returned by msleep.
253  *
254  */
255 static __attribute__((noinline)) int
__KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__(struct kauth_resolver_work * workp)256 __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__(
257 	struct kauth_resolver_work  *workp)
258 {
259 	int error = 0;
260 	struct timespec ts;
261 	for (;;) {
262 		/* we could compute a better timeout here */
263 		ts.tv_sec = kauth_resolver_timeout;
264 		ts.tv_nsec = 0;
265 		error = msleep(workp, &kauth_resolver_mtx, PCATCH, "kr_submit", &ts);
266 		/* request has been completed? */
267 		if ((error == 0) && (workp->kr_flags & KAUTH_REQUEST_DONE)) {
268 			break;
269 		}
270 		/* woken because the resolver has died? */
271 		if (kauth_resolver_identity == 0) {
272 			RESOLVER_FAILED_MESSAGE("kauth external resolver died while while waiting for work to complete");
273 			error = KAUTH_RESOLVER_FAILED_ERRCODE;
274 			break;
275 		}
276 		/* an error? */
277 		if (error != 0) {
278 			break;
279 		}
280 	}
281 	return error;
282 }
283 
284 
285 /*
286  * kauth_resolver_identity_reset
287  *
288  * Description: Reset the identity of the external resolver in certain
289  *              controlled circumstances.
290  *
291  * Parameters:  None.
292  *
293  * Returns:     Nothing.
294  */
295 void
kauth_resolver_identity_reset(void)296 kauth_resolver_identity_reset(void)
297 {
298 	KAUTH_RESOLVER_LOCK();
299 	if (kauth_resolver_identity != 0) {
300 		printf("kauth external resolver %d failed to de-register.\n",
301 		    kauth_resolver_identity);
302 		kauth_resolver_identity = 0;
303 		kauth_resolver_registered = 0;
304 	}
305 	KAUTH_RESOLVER_UNLOCK();
306 }
307 
308 /*
309  * kauth_resolver_submit
310  *
311  * Description:	Submit an external credential identity resolution request to
312  *		the user space daemon.
313  *
314  * Parameters:	lkp				A pointer to an external
315  *						lookup request
316  *		extend_data			extended data for kr_extend
317  *
318  * Returns:	0				Success
319  *		EWOULDBLOCK			No resolver registered
320  *		EINTR				Operation interrupted (e.g. by
321  *						a signal)
322  *		ENOMEM				Could not allocate work item
323  *	copyinstr:EFAULT			Bad message from user space
324  *	workp->kr_result:???			An error from the user space
325  *						daemon (includes ENOENT!)
326  *
327  * Implicit returns:
328  *		*lkp				Modified
329  *
330  * Notes:	Allocate a work queue entry, submit the work and wait for
331  *		the operation to either complete or time out.  Outstanding
332  *		operations may also be cancelled.
333  *
334  *		Submission is by means of placing the item on a work queue
335  *		which is serviced by an external resolver thread calling
336  *		into the kernel.  The caller then sleeps until timeout,
337  *		cancellation, or an external resolver thread calls in with
338  *		a result message to kauth_resolver_complete().  All of these
339  *		events wake the caller back up.
340  *
341  *		This code is called from either kauth_cred_ismember_gid()
342  *		for a group membership request, or it is called from
343  *		kauth_cred_cache_lookup() when we get a cache miss.
344  */
345 static int
kauth_resolver_submit(struct kauth_identity_extlookup * lkp,uint64_t extend_data)346 kauth_resolver_submit(struct kauth_identity_extlookup *lkp, uint64_t extend_data)
347 {
348 	struct kauth_resolver_work *workp, *killp;
349 	struct timespec ts;
350 	int     error, shouldfree;
351 
352 	/* no point actually blocking if the resolver isn't up yet */
353 	if (kauth_resolver_identity == 0) {
354 		/*
355 		 * We've already waited an initial <kauth_resolver_timeout>
356 		 * seconds with no result.
357 		 *
358 		 * Sleep on a stack address so no one wakes us before timeout;
359 		 * we sleep a half a second in case we are a high priority
360 		 * process, so that memberd doesn't starve while we are in a
361 		 * tight loop between user and kernel, eating all the CPU.
362 		 */
363 		error = tsleep(&ts, PZERO | PCATCH, "kr_submit", hz / 2);
364 		if (kauth_resolver_identity == 0) {
365 			/*
366 			 * if things haven't changed while we were asleep,
367 			 * tell the caller we couldn't get an authoritative
368 			 * answer.
369 			 */
370 			return EWOULDBLOCK;
371 		}
372 	}
373 
374 	workp = kalloc_type(struct kauth_resolver_work, Z_WAITOK | Z_NOFAIL);
375 
376 	workp->kr_work = *lkp;
377 	workp->kr_extend = extend_data;
378 	workp->kr_refs = 1;
379 	workp->kr_flags = KAUTH_REQUEST_UNSUBMITTED;
380 	workp->kr_result = 0;
381 
382 	/*
383 	 * We insert the request onto the unsubmitted queue, the call in from
384 	 * the resolver will it to the submitted thread when appropriate.
385 	 */
386 	KAUTH_RESOLVER_LOCK();
387 	workp->kr_seqno = workp->kr_work.el_seqno = kauth_resolver_sequence++;
388 	workp->kr_work.el_result = KAUTH_EXTLOOKUP_INPROG;
389 
390 	/*
391 	 * XXX We *MUST NOT* attempt to coalesce identical work items due to
392 	 * XXX the inability to ensure order of update of the request item
393 	 * XXX extended data vs. the wakeup; instead, we let whoever is waiting
394 	 * XXX for each item repeat the update when they wake up.
395 	 */
396 	TAILQ_INSERT_TAIL(&kauth_resolver_unsubmitted, workp, kr_link);
397 
398 	/*
399 	 * Wake up an external resolver thread to deal with the new work; one
400 	 * may not be available, and if not, then the request will be grabbed
401 	 * when a resolver thread comes back into the kernel to request new
402 	 * work.
403 	 */
404 	wakeup_one((caddr_t)&kauth_resolver_unsubmitted);
405 	error = __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__(workp);
406 
407 	/* if the request was processed, copy the result */
408 	if (error == 0) {
409 		*lkp = workp->kr_work;
410 	}
411 
412 	if (error == EWOULDBLOCK) {
413 		if ((kauth_resolver_timeout_cnt++ % KAUTH_COMPLAINT_INTERVAL) == 0) {
414 			printf("kauth external resolver timed out (%d timeout(s) of %d seconds).\n",
415 			    kauth_resolver_timeout_cnt, kauth_resolver_timeout);
416 		}
417 
418 		if (workp->kr_flags & KAUTH_REQUEST_UNSUBMITTED) {
419 			/*
420 			 * If the request timed out and was never collected, the resolver
421 			 * is dead and probably not coming back anytime soon.  In this
422 			 * case we revert to no-resolver behaviour, and punt all the other
423 			 * sleeping requests to clear the backlog.
424 			 */
425 			KAUTH_DEBUG("RESOLVER - request timed out without being collected for processing, resolver dead");
426 
427 			/*
428 			 * Make the current resolver non-authoritative, and mark it as
429 			 * no longer registered to prevent kauth_cred_ismember_gid()
430 			 * enqueueing more work until a new one is registered.  This
431 			 * mitigates the damage a crashing resolver may inflict.
432 			 */
433 			kauth_resolver_identity = 0;
434 			kauth_resolver_registered = 0;
435 
436 			/* kill all the other requestes that are waiting as well */
437 			TAILQ_FOREACH(killp, &kauth_resolver_submitted, kr_link)
438 			wakeup(killp);
439 			TAILQ_FOREACH(killp, &kauth_resolver_unsubmitted, kr_link)
440 			wakeup(killp);
441 			/* Cause all waiting-for-work threads to return EIO */
442 			wakeup((caddr_t)&kauth_resolver_unsubmitted);
443 		}
444 	}
445 
446 	/*
447 	 * drop our reference on the work item, and note whether we should
448 	 * free it or not
449 	 */
450 	if (--workp->kr_refs <= 0) {
451 		/* work out which list we have to remove it from */
452 		if (workp->kr_flags & KAUTH_REQUEST_DONE) {
453 			TAILQ_REMOVE(&kauth_resolver_done, workp, kr_link);
454 		} else if (workp->kr_flags & KAUTH_REQUEST_SUBMITTED) {
455 			TAILQ_REMOVE(&kauth_resolver_submitted, workp, kr_link);
456 		} else if (workp->kr_flags & KAUTH_REQUEST_UNSUBMITTED) {
457 			TAILQ_REMOVE(&kauth_resolver_unsubmitted, workp, kr_link);
458 		} else {
459 			KAUTH_DEBUG("RESOLVER - completed request has no valid queue");
460 		}
461 		shouldfree = 1;
462 	} else {
463 		/* someone else still has a reference on this request */
464 		shouldfree = 0;
465 	}
466 
467 	/* collect request result */
468 	if (error == 0) {
469 		error = workp->kr_result;
470 	}
471 	KAUTH_RESOLVER_UNLOCK();
472 
473 	/*
474 	 * If we dropped the last reference, free the request.
475 	 */
476 	if (shouldfree) {
477 		kfree_type(struct kauth_resolver_work, workp);
478 	}
479 
480 	KAUTH_DEBUG("RESOLVER - returning %d", error);
481 	return error;
482 }
483 
484 
485 /*
486  * identitysvc
487  *
488  * Description:	System call interface for the external identity resolver.
489  *
490  * Parameters:	uap->message			Message from daemon to kernel
491  *
492  * Returns:	0				Successfully became resolver
493  *		EPERM				Not the resolver process
494  *	kauth_authorize_generic:EPERM		Not root user
495  *	kauth_resolver_complete:EIO
496  *	kauth_resolver_complete:EFAULT
497  *	kauth_resolver_getwork:EINTR
498  *	kauth_resolver_getwork:EFAULT
499  *
500  * Notes:	This system call blocks until there is work enqueued, at
501  *		which time the kernel wakes it up, and a message from the
502  *		kernel is copied out to the identity resolution daemon, which
503  *		proceed to attempt to resolve it.  When the resolution has
504  *		completed (successfully or not), the daemon called back into
505  *		this system call to give the result to the kernel, and wait
506  *		for the next request.
507  */
508 int
identitysvc(__unused struct proc * p,struct identitysvc_args * uap,__unused int32_t * retval)509 identitysvc(__unused struct proc *p, struct identitysvc_args *uap, __unused int32_t *retval)
510 {
511 	int opcode = uap->opcode;
512 	user_addr_t message = uap->message;
513 	struct kauth_resolver_work *workp;
514 	struct kauth_cache_sizes sz_arg = {};
515 	int error;
516 	pid_t new_id;
517 
518 	if (!IOCurrentTaskHasEntitlement(IDENTITYSVC_ENTITLEMENT)) {
519 		KAUTH_DEBUG("RESOLVER - pid %d not entitled to call identitysvc", proc_getpid(current_proc()));
520 		return EPERM;
521 	}
522 
523 	/*
524 	 * New server registering itself.
525 	 */
526 	if (opcode == KAUTH_EXTLOOKUP_REGISTER) {
527 		new_id = proc_getpid(current_proc());
528 		if ((error = kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER)) != 0) {
529 			KAUTH_DEBUG("RESOLVER - pid %d refused permission to become identity resolver", new_id);
530 			return error;
531 		}
532 		KAUTH_RESOLVER_LOCK();
533 		if (kauth_resolver_identity != new_id) {
534 			KAUTH_DEBUG("RESOLVER - new resolver %d taking over from old %d", new_id, kauth_resolver_identity);
535 			/*
536 			 * We have a new server, so assume that all the old requests have been lost.
537 			 */
538 			while ((workp = TAILQ_LAST(&kauth_resolver_submitted, kauth_resolver_submitted_head)) != NULL) {
539 				TAILQ_REMOVE(&kauth_resolver_submitted, workp, kr_link);
540 				workp->kr_flags &= ~KAUTH_REQUEST_SUBMITTED;
541 				workp->kr_flags |= KAUTH_REQUEST_UNSUBMITTED;
542 				TAILQ_INSERT_HEAD(&kauth_resolver_unsubmitted, workp, kr_link);
543 			}
544 			/*
545 			 * Allow user space resolver to override the
546 			 * external resolution timeout
547 			 */
548 			if (message > 30 && message < 10000) {
549 				kauth_resolver_timeout = (int)message;
550 				KAUTH_DEBUG("RESOLVER - new resolver changes timeout to %d seconds\n", (int)message);
551 			}
552 			kauth_resolver_identity = new_id;
553 			kauth_resolver_registered = 1;
554 			kauth_identitysvc_has_registered = 1;
555 			wakeup(&kauth_resolver_unsubmitted);
556 		}
557 		KAUTH_RESOLVER_UNLOCK();
558 		return 0;
559 	}
560 
561 	/*
562 	 * Beyond this point, we must be the resolver process. We verify this
563 	 * by confirming the resolver credential and pid.
564 	 */
565 	if ((kauth_cred_getuid(kauth_cred_get()) != 0) || (proc_getpid(current_proc()) != kauth_resolver_identity)) {
566 		KAUTH_DEBUG("RESOLVER - call from bogus resolver %d\n", proc_getpid(current_proc()));
567 		return EPERM;
568 	}
569 
570 	if (opcode == KAUTH_GET_CACHE_SIZES) {
571 		KAUTH_IDENTITY_LOCK();
572 		sz_arg.kcs_id_size = kauth_identity_cachemax;
573 		KAUTH_IDENTITY_UNLOCK();
574 
575 		KAUTH_GROUPS_LOCK();
576 		sz_arg.kcs_group_size = kauth_groups_cachemax;
577 		KAUTH_GROUPS_UNLOCK();
578 
579 		if ((error = copyout(&sz_arg, uap->message, sizeof(sz_arg))) != 0) {
580 			return error;
581 		}
582 
583 		return 0;
584 	} else if (opcode == KAUTH_SET_CACHE_SIZES) {
585 		if ((error = copyin(uap->message, &sz_arg, sizeof(sz_arg))) != 0) {
586 			return error;
587 		}
588 
589 		if ((sz_arg.kcs_group_size > KAUTH_CACHES_MAX_SIZE) ||
590 		    (sz_arg.kcs_id_size > KAUTH_CACHES_MAX_SIZE)) {
591 			return EINVAL;
592 		}
593 
594 		KAUTH_IDENTITY_LOCK();
595 		kauth_identity_cachemax = sz_arg.kcs_id_size;
596 		kauth_identity_trimcache(kauth_identity_cachemax);
597 		KAUTH_IDENTITY_UNLOCK();
598 
599 		KAUTH_GROUPS_LOCK();
600 		kauth_groups_cachemax = sz_arg.kcs_group_size;
601 		kauth_groups_trimcache(kauth_groups_cachemax);
602 		KAUTH_GROUPS_UNLOCK();
603 
604 		return 0;
605 	} else if (opcode == KAUTH_CLEAR_CACHES) {
606 		KAUTH_IDENTITY_LOCK();
607 		kauth_identity_trimcache(0);
608 		KAUTH_IDENTITY_UNLOCK();
609 
610 		KAUTH_GROUPS_LOCK();
611 		kauth_groups_trimcache(0);
612 		KAUTH_GROUPS_UNLOCK();
613 	} else if (opcode == KAUTH_EXTLOOKUP_DEREGISTER) {
614 		/*
615 		 * Terminate outstanding requests; without an authoritative
616 		 * resolver, we are now back on our own authority.
617 		 */
618 		struct kauth_resolver_work *killp;
619 
620 		KAUTH_RESOLVER_LOCK();
621 
622 		/*
623 		 * Clear the identity, but also mark it as unregistered so
624 		 * there is no explicit future expectation of us getting a
625 		 * new resolver any time soon.
626 		 */
627 		kauth_resolver_identity = 0;
628 		kauth_resolver_registered = 0;
629 
630 		TAILQ_FOREACH(killp, &kauth_resolver_submitted, kr_link)
631 		wakeup(killp);
632 		TAILQ_FOREACH(killp, &kauth_resolver_unsubmitted, kr_link)
633 		wakeup(killp);
634 		/* Cause all waiting-for-work threads to return EIO */
635 		wakeup((caddr_t)&kauth_resolver_unsubmitted);
636 		KAUTH_RESOLVER_UNLOCK();
637 	}
638 
639 	/*
640 	 * Got a result returning?
641 	 */
642 	if (opcode & KAUTH_EXTLOOKUP_RESULT) {
643 		if ((error = kauth_resolver_complete(message)) != 0) {
644 			return error;
645 		}
646 	}
647 
648 	/*
649 	 * Caller wants to take more work?
650 	 */
651 	if (opcode & KAUTH_EXTLOOKUP_WORKER) {
652 		if ((error = kauth_resolver_getwork(message)) != 0) {
653 			return error;
654 		}
655 	}
656 
657 	return 0;
658 }
659 
660 
661 /*
662  * kauth_resolver_getwork_continue
663  *
664  * Description:	Continuation for kauth_resolver_getwork
665  *
666  * Parameters:	result				Error code or 0 for the sleep
667  *						that got us to this function
668  *
669  * Returns:	0				Success
670  *		EINTR				Interrupted (e.g. by signal)
671  *	kauth_resolver_getwork2:EFAULT
672  *
673  * Notes:	See kauth_resolver_getwork(0 and kauth_resolver_getwork2() for
674  *		more information.
675  */
676 static int
kauth_resolver_getwork_continue(int result)677 kauth_resolver_getwork_continue(int result)
678 {
679 	thread_t thread;
680 	struct uthread *ut;
681 	user_addr_t message;
682 
683 	if (result) {
684 		KAUTH_RESOLVER_UNLOCK();
685 		return result;
686 	}
687 
688 	/*
689 	 * If we lost a race with another thread/memberd restarting, then we
690 	 * need to go back to sleep to look for more work.  If it was memberd
691 	 * restarting, then the msleep0() will error out here, as our thread
692 	 * will already be "dead".
693 	 */
694 	if (TAILQ_FIRST(&kauth_resolver_unsubmitted) == NULL) {
695 		int error;
696 
697 		error = msleep0(&kauth_resolver_unsubmitted, &kauth_resolver_mtx, PCATCH, "GRGetWork", 0, kauth_resolver_getwork_continue);
698 		/*
699 		 * If this is a wakeup from another thread in the resolver
700 		 * deregistering it, error out the request-for-work thread
701 		 */
702 		if (!kauth_resolver_identity) {
703 			RESOLVER_FAILED_MESSAGE("external resolver died");
704 			error = KAUTH_RESOLVER_FAILED_ERRCODE;
705 		}
706 		KAUTH_RESOLVER_UNLOCK();
707 		return error;
708 	}
709 
710 	thread = current_thread();
711 	ut = get_bsdthread_info(thread);
712 	message = ut->uu_save.uus_kauth.message;
713 	return kauth_resolver_getwork2(message);
714 }
715 
716 
717 /*
718  * kauth_resolver_getwork2
719  *
720  * Decription:	Common utility function to copy out a identity resolver work
721  *		item from the kernel to user space as part of the user space
722  *		identity resolver requesting work.
723  *
724  * Parameters:	message				message to user space
725  *
726  * Returns:	0				Success
727  *		EFAULT				Bad user space message address
728  *
729  * Notes:	This common function exists to permit the use of continuations
730  *		in the identity resolution process.  This frees up the stack
731  *		while we are waiting for the user space resolver to complete
732  *		a request.  This is specifically used so that our per thread
733  *		cost can be small, and we will therefore be willing to run a
734  *		larger number of threads in the user space identity resolver.
735  */
736 static int
kauth_resolver_getwork2(user_addr_t message)737 kauth_resolver_getwork2(user_addr_t message)
738 {
739 	struct kauth_resolver_work *workp;
740 	int             error;
741 
742 	/*
743 	 * Note: We depend on the caller protecting us from a NULL work item
744 	 * queue, since we must have the kauth resolver lock on entry to this
745 	 * function.
746 	 */
747 	workp = TAILQ_FIRST(&kauth_resolver_unsubmitted);
748 
749 	/*
750 	 * Copy out the external lookup structure for the request, not
751 	 * including the el_extend field, which contains the address of the
752 	 * external buffer provided by the external resolver into which we
753 	 * copy the extension request information.
754 	 */
755 	/* BEFORE FIELD */
756 	if ((error = copyout(&workp->kr_work, message, offsetof(struct kauth_identity_extlookup, el_extend))) != 0) {
757 		KAUTH_DEBUG("RESOLVER - error submitting work to resolve");
758 		goto out;
759 	}
760 	/* AFTER FIELD */
761 	if ((error = copyout(&workp->kr_work.el_info_reserved_1,
762 	    message + offsetof(struct kauth_identity_extlookup, el_info_reserved_1),
763 	    sizeof(struct kauth_identity_extlookup) - offsetof(struct kauth_identity_extlookup, el_info_reserved_1))) != 0) {
764 		KAUTH_DEBUG("RESOLVER - error submitting work to resolve");
765 		goto out;
766 	}
767 
768 	/*
769 	 * Handle extended requests here; if we have a request of a type where
770 	 * the kernel wants a translation of extended information, then we need
771 	 * to copy it out into the extended buffer, assuming the buffer is
772 	 * valid; we only attempt to get the buffer address if we have request
773 	 * data to copy into it.
774 	 */
775 
776 	/*
777 	 * translate a user@domain string into a uid/gid/whatever
778 	 */
779 	if (workp->kr_work.el_flags & (KAUTH_EXTLOOKUP_VALID_PWNAM | KAUTH_EXTLOOKUP_VALID_GRNAM)) {
780 		uint64_t uaddr;
781 
782 		error = copyin(message + offsetof(struct kauth_identity_extlookup, el_extend), &uaddr, sizeof(uaddr));
783 		if (!error) {
784 			size_t actual;  /* not used */
785 			/*
786 			 * Use copyoutstr() to reduce the copy size; we let
787 			 * this catch a NULL uaddr because we shouldn't be
788 			 * asking in that case anyway.
789 			 */
790 			error = copyoutstr(CAST_DOWN(void *, workp->kr_extend), uaddr, MAXPATHLEN, &actual);
791 		}
792 		if (error) {
793 			KAUTH_DEBUG("RESOLVER - error submitting work to resolve");
794 			goto out;
795 		}
796 	}
797 	TAILQ_REMOVE(&kauth_resolver_unsubmitted, workp, kr_link);
798 	workp->kr_flags &= ~KAUTH_REQUEST_UNSUBMITTED;
799 	workp->kr_flags |= KAUTH_REQUEST_SUBMITTED;
800 	TAILQ_INSERT_TAIL(&kauth_resolver_submitted, workp, kr_link);
801 
802 out:
803 	KAUTH_RESOLVER_UNLOCK();
804 	return error;
805 }
806 
807 
808 /*
809  * kauth_resolver_getwork
810  *
811  * Description:	Get a work item from the enqueued requests from the kernel and
812  *		give it to the user space daemon.
813  *
814  * Parameters:	message				message to user space
815  *
816  * Returns:	0				Success
817  *		EINTR				Interrupted (e.g. by signal)
818  *	kauth_resolver_getwork2:EFAULT
819  *
820  * Notes:	This function blocks in a continuation if there are no work
821  *		items available for processing at the time the user space
822  *		identity resolution daemon makes a request for work.  This
823  *		permits a large number of threads to be used by the daemon,
824  *		without using a lot of wired kernel memory when there are no
825  *		actual request outstanding.
826  */
827 static int
kauth_resolver_getwork(user_addr_t message)828 kauth_resolver_getwork(user_addr_t message)
829 {
830 	struct kauth_resolver_work *workp;
831 	int             error;
832 
833 	KAUTH_RESOLVER_LOCK();
834 	error = 0;
835 	while ((workp = TAILQ_FIRST(&kauth_resolver_unsubmitted)) == NULL) {
836 		thread_t thread = current_thread();
837 		struct uthread *ut = get_bsdthread_info(thread);
838 
839 		ut->uu_save.uus_kauth.message = message;
840 		error = msleep0(&kauth_resolver_unsubmitted, &kauth_resolver_mtx, PCATCH, "GRGetWork", 0, kauth_resolver_getwork_continue);
841 		KAUTH_RESOLVER_UNLOCK();
842 		/*
843 		 * If this is a wakeup from another thread in the resolver
844 		 * deregistering it, error out the request-for-work thread
845 		 */
846 		if (!kauth_resolver_identity) {
847 			printf("external resolver died");
848 			error = KAUTH_RESOLVER_FAILED_ERRCODE;
849 		}
850 		return error;
851 	}
852 	return kauth_resolver_getwork2(message);
853 }
854 
855 
856 /*
857  * kauth_resolver_complete
858  *
859  * Description:	Return a result from userspace.
860  *
861  * Parameters:	message				message from user space
862  *
863  * Returns:	0				Success
864  *		EIO				The resolver is dead
865  *	copyin:EFAULT				Bad message from user space
866  */
867 static int
kauth_resolver_complete(user_addr_t message)868 kauth_resolver_complete(user_addr_t message)
869 {
870 	struct kauth_identity_extlookup extl;
871 	struct kauth_resolver_work *workp;
872 	struct kauth_resolver_work *killp;
873 	int error, result, want_extend_data;
874 
875 	/*
876 	 * Copy in the mesage, including the extension field, since we are
877 	 * copying into a local variable.
878 	 */
879 	if ((error = copyin(message, &extl, sizeof(extl))) != 0) {
880 		KAUTH_DEBUG("RESOLVER - error getting completed work\n");
881 		return error;
882 	}
883 
884 	KAUTH_RESOLVER_LOCK();
885 
886 	error = 0;
887 	result = 0;
888 	switch (extl.el_result) {
889 	case KAUTH_EXTLOOKUP_INPROG:
890 	{
891 		static int once = 0;
892 
893 		/* XXX this should go away once memberd is updated */
894 		if (!once) {
895 			printf("kauth_resolver: memberd is not setting valid result codes (assuming always successful)\n");
896 			once = 1;
897 		}
898 	}
899 		OS_FALLTHROUGH;
900 
901 	case KAUTH_EXTLOOKUP_SUCCESS:
902 		break;
903 
904 	case KAUTH_EXTLOOKUP_FATAL:
905 		/* fatal error means the resolver is dead */
906 		KAUTH_DEBUG("RESOLVER - resolver %d died, waiting for a new one", kauth_resolver_identity);
907 		RESOLVER_FAILED_MESSAGE("resolver %d died, waiting for a new one", kauth_resolver_identity);
908 		/*
909 		 * Terminate outstanding requests; without an authoritative
910 		 * resolver, we are now back on our own authority.  Tag the
911 		 * resolver unregistered to prevent kauth_cred_ismember_gid()
912 		 * enqueueing more work until a new one is registered.  This
913 		 * mitigates the damage a crashing resolver may inflict.
914 		 */
915 		kauth_resolver_identity = 0;
916 		kauth_resolver_registered = 0;
917 
918 		TAILQ_FOREACH(killp, &kauth_resolver_submitted, kr_link)
919 		wakeup(killp);
920 		TAILQ_FOREACH(killp, &kauth_resolver_unsubmitted, kr_link)
921 		wakeup(killp);
922 		/* Cause all waiting-for-work threads to return EIO */
923 		wakeup((caddr_t)&kauth_resolver_unsubmitted);
924 		/* and return EIO to the caller */
925 		error = KAUTH_RESOLVER_FAILED_ERRCODE;
926 		break;
927 
928 	case KAUTH_EXTLOOKUP_BADRQ:
929 		KAUTH_DEBUG("RESOLVER - resolver reported invalid request %d", extl.el_seqno);
930 		result = EINVAL;
931 		break;
932 
933 	case KAUTH_EXTLOOKUP_FAILURE:
934 		KAUTH_DEBUG("RESOLVER - resolver reported transient failure for request %d", extl.el_seqno);
935 		RESOLVER_FAILED_MESSAGE("resolver reported transient failure for request %d", extl.el_seqno);
936 		result = KAUTH_RESOLVER_FAILED_ERRCODE;
937 		break;
938 
939 	default:
940 		KAUTH_DEBUG("RESOLVER - resolver returned unexpected status %d", extl.el_result);
941 		RESOLVER_FAILED_MESSAGE("resolver returned unexpected status %d", extl.el_result);
942 		result = KAUTH_RESOLVER_FAILED_ERRCODE;
943 		break;
944 	}
945 
946 	/*
947 	 * In the case of a fatal error, we assume that the resolver will
948 	 * restart quickly and re-collect all of the outstanding requests.
949 	 * Thus, we don't complete the request which returned the fatal
950 	 * error status.
951 	 */
952 	if (extl.el_result != KAUTH_EXTLOOKUP_FATAL) {
953 		/* scan our list for this request */
954 		TAILQ_FOREACH(workp, &kauth_resolver_submitted, kr_link) {
955 			/* found it? */
956 			if (workp->kr_seqno == extl.el_seqno) {
957 				/*
958 				 * Do we want extend_data?
959 				 */
960 				want_extend_data = (workp->kr_work.el_flags & (KAUTH_EXTLOOKUP_WANT_PWNAM | KAUTH_EXTLOOKUP_WANT_GRNAM));
961 
962 				/*
963 				 * Get the request of the submitted queue so
964 				 * that it is not cleaned up out from under
965 				 * us by a timeout.
966 				 */
967 				TAILQ_REMOVE(&kauth_resolver_submitted, workp, kr_link);
968 				workp->kr_flags &= ~KAUTH_REQUEST_SUBMITTED;
969 				workp->kr_flags |= KAUTH_REQUEST_DONE;
970 				workp->kr_result = result;
971 
972 				/* Copy the result message to the work item. */
973 				memcpy(&workp->kr_work, &extl, sizeof(struct kauth_identity_extlookup));
974 
975 				/*
976 				 * Check if we have a result in the extension
977 				 * field; if we do, then we need to separately
978 				 * copy the data from the message el_extend
979 				 * into the request buffer that's in the work
980 				 * item.  We have to do it here because we do
981 				 * not want to wake up the waiter until the
982 				 * data is in their buffer, and because the
983 				 * actual request response may be destroyed
984 				 * by the time the requester wakes up, and they
985 				 * do not have access to the user space buffer
986 				 * address.
987 				 *
988 				 * It is safe to drop and reacquire the lock
989 				 * here because we've already removed the item
990 				 * from the submission queue, but have not yet
991 				 * moved it to the completion queue.  Note that
992 				 * near simultaneous requests may result in
993 				 * duplication of requests for items in this
994 				 * window. This should not be a performance
995 				 * issue and is easily detectable by comparing
996 				 * time to live on last response vs. time of
997 				 * next request in the resolver logs.
998 				 *
999 				 * A malicious/faulty resolver could overwrite
1000 				 * part of a user's address space if they return
1001 				 * flags that mismatch the original request's flags.
1002 				 */
1003 				if (want_extend_data && (extl.el_flags & (KAUTH_EXTLOOKUP_VALID_PWNAM | KAUTH_EXTLOOKUP_VALID_GRNAM))) {
1004 					size_t actual;  /* notused */
1005 
1006 					KAUTH_RESOLVER_UNLOCK();
1007 					error = copyinstr(extl.el_extend, CAST_DOWN(void *, workp->kr_extend), MAXPATHLEN, &actual);
1008 					KAUTH_DEBUG("RESOLVER - resolver got name :%*s: len = %d\n", (int)actual,
1009 					    actual ? "null" : (char *)extl.el_extend, actual);
1010 					KAUTH_RESOLVER_LOCK();
1011 				} else if (extl.el_flags &  (KAUTH_EXTLOOKUP_VALID_PWNAM | KAUTH_EXTLOOKUP_VALID_GRNAM)) {
1012 					error = EFAULT;
1013 					KAUTH_DEBUG("RESOLVER - resolver returned mismatching extension flags (%d), request contained (%d)",
1014 					    extl.el_flags, want_extend_data);
1015 				}
1016 
1017 				/*
1018 				 * Move the completed work item to the
1019 				 * completion queue and wake up requester(s)
1020 				 */
1021 				TAILQ_INSERT_TAIL(&kauth_resolver_done, workp, kr_link);
1022 				wakeup(workp);
1023 				break;
1024 			}
1025 		}
1026 	}
1027 	/*
1028 	 * Note that it's OK for us not to find anything; if the request has
1029 	 * timed out the work record will be gone.
1030 	 */
1031 	KAUTH_RESOLVER_UNLOCK();
1032 
1033 	return error;
1034 }
1035 #endif /* CONFIG_EXT_RESOLVER */
1036 
1037 
1038 /*
1039  * Identity cache.
1040  */
1041 
1042 #define KI_VALID_UID    (1<<0)          /* UID and GID are mutually exclusive */
1043 #define KI_VALID_GID    (1<<1)
1044 #define KI_VALID_GUID   (1<<2)
1045 #define KI_VALID_NTSID  (1<<3)
1046 #define KI_VALID_PWNAM  (1<<4)  /* Used for translation */
1047 #define KI_VALID_GRNAM  (1<<5)  /* Used for translation */
1048 #define KI_VALID_GROUPS (1<<6)
1049 
1050 #if CONFIG_EXT_RESOLVER
1051 /*
1052  * kauth_identity_alloc
1053  *
1054  * Description:	Allocate and fill out a kauth_identity structure for
1055  *		translation between {UID|GID}/GUID/NTSID
1056  *
1057  * Parameters:	uid
1058  *
1059  * Returns:	NULL				Insufficient memory to satisfy
1060  *						the request or bad parameters
1061  *		!NULL				A pointer to the allocated
1062  *						structure, filled in
1063  *
1064  * Notes:	It is illegal to translate between UID and GID; any given UUID
1065  *		or NTSID can only refer to an NTSID or UUID (respectively),
1066  *		and *either* a UID *or* a GID, but not both.
1067  */
1068 static struct kauth_identity *
kauth_identity_alloc(uid_t uid,gid_t gid,guid_t * guidp,time_t guid_expiry,ntsid_t * ntsidp,time_t ntsid_expiry,size_t supgrpcnt,gid_t * supgrps,time_t groups_expiry,const char * name,int nametype)1069 kauth_identity_alloc(uid_t uid, gid_t gid, guid_t *guidp, time_t guid_expiry,
1070     ntsid_t *ntsidp, time_t ntsid_expiry, size_t supgrpcnt, gid_t *supgrps, time_t groups_expiry,
1071     const char *name, int nametype)
1072 {
1073 	struct kauth_identity *kip;
1074 
1075 	/* get and fill in a new identity */
1076 	kip = kalloc_type(struct kauth_identity, Z_WAITOK | Z_ZERO | Z_NOFAIL);
1077 	if (gid != KAUTH_GID_NONE) {
1078 		kip->ki_gid = gid;
1079 		kip->ki_valid = KI_VALID_GID;
1080 	}
1081 	if (uid != KAUTH_UID_NONE) {
1082 		if (kip->ki_valid & KI_VALID_GID) {
1083 			panic("can't allocate kauth identity with both uid and gid");
1084 		}
1085 		kip->ki_uid = uid;
1086 		kip->ki_valid = KI_VALID_UID;
1087 	}
1088 	if (supgrpcnt) {
1089 		/*
1090 		 * A malicious/faulty resolver could return bad values
1091 		 */
1092 		assert(supgrpcnt <= NGROUPS);
1093 		assert(supgrps != NULL);
1094 
1095 		if ((supgrpcnt > NGROUPS) || (supgrps == NULL)) {
1096 			return NULL;
1097 		}
1098 		if (kip->ki_valid & KI_VALID_GID) {
1099 			panic("can't allocate kauth identity with both gid and supplementary groups");
1100 		}
1101 		kip->ki_supgrpcnt = (uint32_t)supgrpcnt;
1102 		memcpy(kip->ki_supgrps, supgrps, sizeof(supgrps[0]) * supgrpcnt);
1103 		kip->ki_valid |= KI_VALID_GROUPS;
1104 	}
1105 	kip->ki_groups_expiry = groups_expiry;
1106 	if (guidp != NULL) {
1107 		kip->ki_guid = *guidp;
1108 		kip->ki_valid |= KI_VALID_GUID;
1109 	}
1110 	kip->ki_guid_expiry = guid_expiry;
1111 	if (ntsidp != NULL) {
1112 		kip->ki_ntsid = *ntsidp;
1113 		kip->ki_valid |= KI_VALID_NTSID;
1114 	}
1115 	kip->ki_ntsid_expiry = ntsid_expiry;
1116 	if (name != NULL) {
1117 		kip->ki_name = name;
1118 		kip->ki_valid |= nametype;
1119 	}
1120 	return kip;
1121 }
1122 
1123 
1124 /*
1125  * kauth_identity_register_and_free
1126  *
1127  * Description:	Register an association between identity tokens.  The passed
1128  *		'kip' is consumed by this function.
1129  *
1130  * Parameters:	kip				Pointer to kauth_identity
1131  *						structure to register
1132  *
1133  * Returns:	(void)
1134  *
1135  * Notes:	The memory pointer to by 'kip' is assumed to have been
1136  *		previously allocated via kauth_identity_alloc().
1137  */
1138 static void
kauth_identity_register_and_free(struct kauth_identity * kip)1139 kauth_identity_register_and_free(struct kauth_identity *kip)
1140 {
1141 	struct kauth_identity *ip;
1142 
1143 	/*
1144 	 * We search the cache for the UID listed in the incoming association.
1145 	 * If we already have an entry, the new information is merged.
1146 	 */
1147 	ip = NULL;
1148 	KAUTH_IDENTITY_LOCK();
1149 	if (kip->ki_valid & KI_VALID_UID) {
1150 		if (kip->ki_valid & KI_VALID_GID) {
1151 			panic("kauth_identity: can't insert record with both UID and GID as key");
1152 		}
1153 		TAILQ_FOREACH(ip, &kauth_identities, ki_link)
1154 		if ((ip->ki_valid & KI_VALID_UID) && (ip->ki_uid == kip->ki_uid)) {
1155 			break;
1156 		}
1157 	} else if (kip->ki_valid & KI_VALID_GID) {
1158 		TAILQ_FOREACH(ip, &kauth_identities, ki_link)
1159 		if ((ip->ki_valid & KI_VALID_GID) && (ip->ki_gid == kip->ki_gid)) {
1160 			break;
1161 		}
1162 	} else {
1163 		panic("kauth_identity: can't insert record without UID or GID as key");
1164 	}
1165 
1166 	if (ip != NULL) {
1167 		/* we already have an entry, merge/overwrite */
1168 		if (kip->ki_valid & KI_VALID_GUID) {
1169 			ip->ki_guid = kip->ki_guid;
1170 			ip->ki_valid |= KI_VALID_GUID;
1171 		}
1172 		ip->ki_guid_expiry = kip->ki_guid_expiry;
1173 		if (kip->ki_valid & KI_VALID_NTSID) {
1174 			ip->ki_ntsid = kip->ki_ntsid;
1175 			ip->ki_valid |= KI_VALID_NTSID;
1176 		}
1177 		ip->ki_ntsid_expiry = kip->ki_ntsid_expiry;
1178 		/* a valid ki_name field overwrites the previous name field */
1179 		if (kip->ki_valid & (KI_VALID_PWNAM | KI_VALID_GRNAM)) {
1180 			/* if there's an old one, discard it */
1181 			const char *oname = NULL;
1182 			if (ip->ki_valid & (KI_VALID_PWNAM | KI_VALID_GRNAM)) {
1183 				oname = ip->ki_name;
1184 			}
1185 			ip->ki_name = kip->ki_name;
1186 			kip->ki_name = oname;
1187 		}
1188 		/* and discard the incoming entry */
1189 		ip = kip;
1190 	} else {
1191 		/*
1192 		 * if we don't have any information on this identity, add it;
1193 		 * if it pushes us over our limit, discard the oldest one.
1194 		 */
1195 		TAILQ_INSERT_HEAD(&kauth_identities, kip, ki_link);
1196 		if (++kauth_identity_count > kauth_identity_cachemax) {
1197 			ip = TAILQ_LAST(&kauth_identities, kauth_identity_head);
1198 			TAILQ_REMOVE(&kauth_identities, ip, ki_link);
1199 			kauth_identity_count--;
1200 		}
1201 	}
1202 	KAUTH_IDENTITY_UNLOCK();
1203 	/* have to drop lock before freeing expired entry (it may be in use) */
1204 	if (ip != NULL) {
1205 		/* if the ki_name field is used, clear it first */
1206 		if (ip->ki_valid & (KI_VALID_PWNAM | KI_VALID_GRNAM)) {
1207 			vfs_removename(ip->ki_name);
1208 		}
1209 		/* free the expired entry */
1210 		kfree_type(struct kauth_identity, ip);
1211 	}
1212 }
1213 
1214 
1215 /*
1216  * kauth_identity_updatecache
1217  *
1218  * Description:	Given a lookup result, add any associations that we don't
1219  *		currently have; replace ones which have changed.
1220  *
1221  * Parameters:	elp				External lookup result from
1222  *						user space daemon to kernel
1223  *		rkip				pointer to returned kauth
1224  *						identity, or NULL
1225  *		extend_data			Extended data (can vary)
1226  *
1227  * Returns:	(void)
1228  *
1229  * Implicit returns:
1230  *		*rkip				Modified (if non-NULL)
1231  *
1232  * Notes:	For extended information requests, this code relies on the fact
1233  *		that elp->el_flags is never used as an rvalue, and is only
1234  *		ever bit-tested for valid lookup information we are willing
1235  *		to cache.
1236  *
1237  * XXX:		We may have to do the same in the case that extended data was
1238  *		passed out to user space to ensure that the request string
1239  *		gets cached; we may also be able to use the rkip as an
1240  *		input to avoid this.  The jury is still out.
1241  *
1242  * XXX:		This codes performance could be improved for multiple valid
1243  *		results by combining the loop iteration in a single loop.
1244  */
1245 static void
kauth_identity_updatecache(struct kauth_identity_extlookup * elp,struct kauth_identity * rkip,uint64_t extend_data)1246 kauth_identity_updatecache(struct kauth_identity_extlookup *elp, struct kauth_identity *rkip, uint64_t extend_data)
1247 {
1248 	struct timeval tv;
1249 	struct kauth_identity *kip;
1250 	const char *speculative_name = NULL;
1251 
1252 	microuptime(&tv);
1253 
1254 	/*
1255 	 * If there is extended data, and that data represents a name rather
1256 	 * than something else, speculatively create an entry for it in the
1257 	 * string cache.  We do this to avoid holding the KAUTH_IDENTITY_LOCK
1258 	 * over the allocation later.
1259 	 */
1260 	if (elp->el_flags & (KAUTH_EXTLOOKUP_VALID_PWNAM | KAUTH_EXTLOOKUP_VALID_GRNAM)) {
1261 		const char *tmp = CAST_DOWN(const char *, extend_data);
1262 		speculative_name = vfs_addname(tmp, (uint32_t)strnlen(tmp, MAXPATHLEN - 1), 0, 0);
1263 	}
1264 
1265 	/* user identity? */
1266 	if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_UID) {
1267 		KAUTH_IDENTITY_LOCK();
1268 		TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
1269 			/* matching record */
1270 			if ((kip->ki_valid & KI_VALID_UID) && (kip->ki_uid == elp->el_uid)) {
1271 				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_SUPGRPS) {
1272 					assert(elp->el_sup_grp_cnt <= NGROUPS);
1273 					if (elp->el_sup_grp_cnt > NGROUPS) {
1274 						KAUTH_DEBUG("CACHE - invalid sup_grp_cnt provided (%d), truncating to  %d",
1275 						    elp->el_sup_grp_cnt, NGROUPS);
1276 						elp->el_sup_grp_cnt = NGROUPS;
1277 					}
1278 					kip->ki_supgrpcnt = elp->el_sup_grp_cnt;
1279 					memcpy(kip->ki_supgrps, elp->el_sup_groups, sizeof(elp->el_sup_groups[0]) * kip->ki_supgrpcnt);
1280 					kip->ki_valid |= KI_VALID_GROUPS;
1281 					kip->ki_groups_expiry = (elp->el_member_valid) ? tv.tv_sec + elp->el_member_valid : 0;
1282 				}
1283 				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_UGUID) {
1284 					kip->ki_guid = elp->el_uguid;
1285 					kip->ki_valid |= KI_VALID_GUID;
1286 				}
1287 				kip->ki_guid_expiry = (elp->el_uguid_valid) ? tv.tv_sec + elp->el_uguid_valid : 0;
1288 				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_USID) {
1289 					kip->ki_ntsid = elp->el_usid;
1290 					kip->ki_valid |= KI_VALID_NTSID;
1291 				}
1292 				kip->ki_ntsid_expiry = (elp->el_usid_valid) ? tv.tv_sec + elp->el_usid_valid : 0;
1293 				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_PWNAM) {
1294 					const char *oname = kip->ki_name;
1295 					kip->ki_name = speculative_name;
1296 					speculative_name = NULL;
1297 					kip->ki_valid |= KI_VALID_PWNAM;
1298 					if (oname) {
1299 						/*
1300 						 * free oname (if any) outside
1301 						 * the lock
1302 						 */
1303 						speculative_name = oname;
1304 					}
1305 				}
1306 				kauth_identity_lru(kip);
1307 				if (rkip != NULL) {
1308 					*rkip = *kip;
1309 				}
1310 				KAUTH_DEBUG("CACHE - refreshed %d is " K_UUID_FMT, kip->ki_uid, K_UUID_ARG(kip->ki_guid));
1311 				break;
1312 			}
1313 		}
1314 		KAUTH_IDENTITY_UNLOCK();
1315 		/* not found in cache, add new record */
1316 		if (kip == NULL) {
1317 			kip = kauth_identity_alloc(elp->el_uid, KAUTH_GID_NONE,
1318 			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_UGUID) ? &elp->el_uguid : NULL,
1319 			    (elp->el_uguid_valid) ? tv.tv_sec + elp->el_uguid_valid : 0,
1320 			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_USID) ? &elp->el_usid : NULL,
1321 			    (elp->el_usid_valid) ? tv.tv_sec + elp->el_usid_valid : 0,
1322 			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_SUPGRPS) ? elp->el_sup_grp_cnt : 0,
1323 			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_SUPGRPS) ? elp->el_sup_groups : NULL,
1324 			    (elp->el_member_valid) ? tv.tv_sec + elp->el_member_valid : 0,
1325 			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_PWNAM) ? speculative_name : NULL,
1326 			    KI_VALID_PWNAM);
1327 			if (kip != NULL) {
1328 				if (rkip != NULL) {
1329 					*rkip = *kip;
1330 				}
1331 				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_PWNAM) {
1332 					speculative_name = NULL;
1333 				}
1334 				KAUTH_DEBUG("CACHE - learned %d is " K_UUID_FMT, kip->ki_uid, K_UUID_ARG(kip->ki_guid));
1335 				kauth_identity_register_and_free(kip);
1336 			}
1337 		}
1338 	}
1339 
1340 	/* group identity? (ignore, if we already processed it as a user) */
1341 	if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GID && !(elp->el_flags & KAUTH_EXTLOOKUP_VALID_UID)) {
1342 		KAUTH_IDENTITY_LOCK();
1343 		TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
1344 			/* matching record */
1345 			if ((kip->ki_valid & KI_VALID_GID) && (kip->ki_gid == elp->el_gid)) {
1346 				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GGUID) {
1347 					kip->ki_guid = elp->el_gguid;
1348 					kip->ki_valid |= KI_VALID_GUID;
1349 				}
1350 				kip->ki_guid_expiry = (elp->el_gguid_valid) ? tv.tv_sec + elp->el_gguid_valid : 0;
1351 				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GSID) {
1352 					kip->ki_ntsid = elp->el_gsid;
1353 					kip->ki_valid |= KI_VALID_NTSID;
1354 				}
1355 				kip->ki_ntsid_expiry = (elp->el_gsid_valid) ? tv.tv_sec + elp->el_gsid_valid : 0;
1356 				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GRNAM) {
1357 					const char *oname = kip->ki_name;
1358 					kip->ki_name = speculative_name;
1359 					speculative_name = NULL;
1360 					kip->ki_valid |= KI_VALID_GRNAM;
1361 					if (oname) {
1362 						/*
1363 						 * free oname (if any) outside
1364 						 * the lock
1365 						 */
1366 						speculative_name = oname;
1367 					}
1368 				}
1369 				kauth_identity_lru(kip);
1370 				if (rkip != NULL) {
1371 					*rkip = *kip;
1372 				}
1373 				KAUTH_DEBUG("CACHE - refreshed %d is " K_UUID_FMT, kip->ki_uid, K_UUID_ARG(kip->ki_guid));
1374 				break;
1375 			}
1376 		}
1377 		KAUTH_IDENTITY_UNLOCK();
1378 		/* not found in cache, add new record */
1379 		if (kip == NULL) {
1380 			kip = kauth_identity_alloc(KAUTH_UID_NONE, elp->el_gid,
1381 			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GGUID) ? &elp->el_gguid : NULL,
1382 			    (elp->el_gguid_valid) ? tv.tv_sec + elp->el_gguid_valid : 0,
1383 			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GSID) ? &elp->el_gsid : NULL,
1384 			    (elp->el_gsid_valid) ? tv.tv_sec + elp->el_gsid_valid : 0,
1385 			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_SUPGRPS) ? elp->el_sup_grp_cnt : 0,
1386 			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_SUPGRPS) ? elp->el_sup_groups : NULL,
1387 			    (elp->el_member_valid) ? tv.tv_sec + elp->el_member_valid : 0,
1388 			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GRNAM) ? speculative_name : NULL,
1389 			    KI_VALID_GRNAM);
1390 			if (kip != NULL) {
1391 				if (rkip != NULL) {
1392 					*rkip = *kip;
1393 				}
1394 				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GRNAM) {
1395 					speculative_name = NULL;
1396 				}
1397 				KAUTH_DEBUG("CACHE - learned %d is " K_UUID_FMT, kip->ki_uid, K_UUID_ARG(kip->ki_guid));
1398 				kauth_identity_register_and_free(kip);
1399 			}
1400 		}
1401 	}
1402 
1403 	/* If we have a name reference to drop, drop it here */
1404 	if (speculative_name != NULL) {
1405 		vfs_removename(speculative_name);
1406 	}
1407 }
1408 
1409 
1410 /*
1411  * Trim older entries from the identity cache.
1412  *
1413  * Must be called with the identity cache lock held.
1414  */
1415 static void
kauth_identity_trimcache(int newsize)1416 kauth_identity_trimcache(int newsize)
1417 {
1418 	struct kauth_identity           *kip;
1419 
1420 	lck_mtx_assert(&kauth_identity_mtx, LCK_MTX_ASSERT_OWNED);
1421 
1422 	while (kauth_identity_count > newsize) {
1423 		kip = TAILQ_LAST(&kauth_identities, kauth_identity_head);
1424 		TAILQ_REMOVE(&kauth_identities, kip, ki_link);
1425 		kauth_identity_count--;
1426 		kfree_type(struct kauth_identity, kip);
1427 	}
1428 }
1429 
1430 /*
1431  * kauth_identity_lru
1432  *
1433  * Description:	Promote the entry to the head of the LRU, assumes the cache
1434  *		is locked.
1435  *
1436  * Parameters:	kip				kauth identity to move to the
1437  *						head of the LRU list, if it's
1438  *						not already there
1439  *
1440  * Returns:	(void)
1441  *
1442  * Notes:	This is called even if the entry has expired; typically an
1443  *		expired entry that's been looked up is about to be revalidated,
1444  *		and having it closer to the head of the LRU means finding it
1445  *		quickly again when the revalidation comes through.
1446  */
1447 static void
kauth_identity_lru(struct kauth_identity * kip)1448 kauth_identity_lru(struct kauth_identity *kip)
1449 {
1450 	if (kip != TAILQ_FIRST(&kauth_identities)) {
1451 		TAILQ_REMOVE(&kauth_identities, kip, ki_link);
1452 		TAILQ_INSERT_HEAD(&kauth_identities, kip, ki_link);
1453 	}
1454 }
1455 
1456 
1457 /*
1458  * kauth_identity_guid_expired
1459  *
1460  * Description:	Handle lazy expiration of GUID translations.
1461  *
1462  * Parameters:	kip				kauth identity to check for
1463  *						GUID expiration
1464  *
1465  * Returns:	1				Expired
1466  *		0				Not expired
1467  */
1468 static int
kauth_identity_guid_expired(struct kauth_identity * kip)1469 kauth_identity_guid_expired(struct kauth_identity *kip)
1470 {
1471 	struct timeval tv;
1472 
1473 	/*
1474 	 * Expiration time of 0 means this entry is persistent.
1475 	 */
1476 	if (kip->ki_guid_expiry == 0) {
1477 		return 0;
1478 	}
1479 
1480 	microuptime(&tv);
1481 	KAUTH_DEBUG("CACHE - GUID expires @ %ld now %ld", kip->ki_guid_expiry, tv.tv_sec);
1482 
1483 	return (kip->ki_guid_expiry <= tv.tv_sec) ? 1 : 0;
1484 }
1485 
1486 
1487 /*
1488  * kauth_identity_ntsid_expired
1489  *
1490  * Description:	Handle lazy expiration of NTSID translations.
1491  *
1492  * Parameters:	kip				kauth identity to check for
1493  *						NTSID expiration
1494  *
1495  * Returns:	1				Expired
1496  *		0				Not expired
1497  */
1498 static int
kauth_identity_ntsid_expired(struct kauth_identity * kip)1499 kauth_identity_ntsid_expired(struct kauth_identity *kip)
1500 {
1501 	struct timeval tv;
1502 
1503 	/*
1504 	 * Expiration time of 0 means this entry is persistent.
1505 	 */
1506 	if (kip->ki_ntsid_expiry == 0) {
1507 		return 0;
1508 	}
1509 
1510 	microuptime(&tv);
1511 	KAUTH_DEBUG("CACHE - NTSID expires @ %ld now %ld", kip->ki_ntsid_expiry, tv.tv_sec);
1512 
1513 	return (kip->ki_ntsid_expiry <= tv.tv_sec) ? 1 : 0;
1514 }
1515 
1516 /*
1517  * kauth_identity_groups_expired
1518  *
1519  * Description:	Handle lazy expiration of supplemental group translations.
1520  *
1521  * Parameters:	kip				kauth identity to check for
1522  *						groups expiration
1523  *
1524  * Returns:	1				Expired
1525  *		0				Not expired
1526  */
1527 static int
kauth_identity_groups_expired(struct kauth_identity * kip)1528 kauth_identity_groups_expired(struct kauth_identity *kip)
1529 {
1530 	struct timeval tv;
1531 
1532 	/*
1533 	 * Expiration time of 0 means this entry is persistent.
1534 	 */
1535 	if (kip->ki_groups_expiry == 0) {
1536 		return 0;
1537 	}
1538 
1539 	microuptime(&tv);
1540 	KAUTH_DEBUG("CACHE - GROUPS expires @ %ld now %ld\n", kip->ki_groups_expiry, tv.tv_sec);
1541 
1542 	return (kip->ki_groups_expiry <= tv.tv_sec) ? 1 : 0;
1543 }
1544 
1545 /*
1546  * kauth_identity_find_uid
1547  *
1548  * Description: Search for an entry by UID
1549  *
1550  * Parameters:	uid				UID to find
1551  *		kir				Pointer to return area
1552  *		getname				Name buffer, if ki_name wanted
1553  *
1554  * Returns:	0				Found
1555  *		ENOENT				Not found
1556  *
1557  * Implicit returns:
1558  *		*klr				Modified, if found
1559  */
1560 static int
kauth_identity_find_uid(uid_t uid,struct kauth_identity * kir,char * getname)1561 kauth_identity_find_uid(uid_t uid, struct kauth_identity *kir, char *getname)
1562 {
1563 	struct kauth_identity *kip;
1564 
1565 	KAUTH_IDENTITY_LOCK();
1566 	TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
1567 		if ((kip->ki_valid & KI_VALID_UID) && (uid == kip->ki_uid)) {
1568 			kauth_identity_lru(kip);
1569 			/* Copy via structure assignment */
1570 			*kir = *kip;
1571 			/* If a name is wanted and one exists, copy it out */
1572 			if (getname != NULL && (kip->ki_valid & (KI_VALID_PWNAM | KI_VALID_GRNAM))) {
1573 				strlcpy(getname, kip->ki_name, MAXPATHLEN);
1574 			}
1575 			break;
1576 		}
1577 	}
1578 	KAUTH_IDENTITY_UNLOCK();
1579 	return (kip == NULL) ? ENOENT : 0;
1580 }
1581 
1582 
1583 /*
1584  * kauth_identity_find_gid
1585  *
1586  * Description: Search for an entry by GID
1587  *
1588  * Parameters:	gid				GID to find
1589  *		kir				Pointer to return area
1590  *		getname				Name buffer, if ki_name wanted
1591  *
1592  * Returns:	0				Found
1593  *		ENOENT				Not found
1594  *
1595  * Implicit returns:
1596  *		*klr				Modified, if found
1597  */
1598 static int
kauth_identity_find_gid(uid_t gid,struct kauth_identity * kir,char * getname)1599 kauth_identity_find_gid(uid_t gid, struct kauth_identity *kir, char *getname)
1600 {
1601 	struct kauth_identity *kip;
1602 
1603 	KAUTH_IDENTITY_LOCK();
1604 	TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
1605 		if ((kip->ki_valid & KI_VALID_GID) && (gid == kip->ki_gid)) {
1606 			kauth_identity_lru(kip);
1607 			/* Copy via structure assignment */
1608 			*kir = *kip;
1609 			/* If a name is wanted and one exists, copy it out */
1610 			if (getname != NULL && (kip->ki_valid & (KI_VALID_PWNAM | KI_VALID_GRNAM))) {
1611 				strlcpy(getname, kip->ki_name, MAXPATHLEN);
1612 			}
1613 			break;
1614 		}
1615 	}
1616 	KAUTH_IDENTITY_UNLOCK();
1617 	return (kip == NULL) ? ENOENT : 0;
1618 }
1619 
1620 
1621 /*
1622  * kauth_identity_find_guid
1623  *
1624  * Description: Search for an entry by GUID
1625  *
1626  * Parameters:	guidp				Pointer to GUID to find
1627  *		kir				Pointer to return area
1628  *		getname				Name buffer, if ki_name wanted
1629  *
1630  * Returns:	0				Found
1631  *		ENOENT				Not found
1632  *
1633  * Implicit returns:
1634  *		*klr				Modified, if found
1635  *
1636  * Note:	The association may be expired, in which case the caller
1637  *		may elect to call out to userland to revalidate.
1638  */
1639 static int
kauth_identity_find_guid(guid_t * guidp,struct kauth_identity * kir,char * getname)1640 kauth_identity_find_guid(guid_t *guidp, struct kauth_identity *kir, char *getname)
1641 {
1642 	struct kauth_identity *kip;
1643 
1644 	KAUTH_IDENTITY_LOCK();
1645 	TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
1646 		if ((kip->ki_valid & KI_VALID_GUID) && (kauth_guid_equal(guidp, &kip->ki_guid))) {
1647 			kauth_identity_lru(kip);
1648 			/* Copy via structure assignment */
1649 			*kir = *kip;
1650 			/* If a name is wanted and one exists, copy it out */
1651 			if (getname != NULL && (kip->ki_valid & (KI_VALID_PWNAM | KI_VALID_GRNAM))) {
1652 				strlcpy(getname, kip->ki_name, MAXPATHLEN);
1653 			}
1654 			break;
1655 		}
1656 	}
1657 	KAUTH_IDENTITY_UNLOCK();
1658 	return (kip == NULL) ? ENOENT : 0;
1659 }
1660 
1661 /*
1662  * kauth_identity_find_nam
1663  *
1664  * Description:	Search for an entry by name
1665  *
1666  * Parameters:	name				Pointer to name to find
1667  *		valid				KI_VALID_PWNAM or KI_VALID_GRNAM
1668  *		kir				Pointer to return area
1669  *
1670  * Returns:	0				Found
1671  *		ENOENT				Not found
1672  *
1673  * Implicit returns:
1674  *		*klr				Modified, if found
1675  */
1676 static int
kauth_identity_find_nam(char * name,int valid,struct kauth_identity * kir)1677 kauth_identity_find_nam(char *name, int valid, struct kauth_identity *kir)
1678 {
1679 	struct kauth_identity *kip;
1680 
1681 	KAUTH_IDENTITY_LOCK();
1682 	TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
1683 		if ((kip->ki_valid & valid) && !strcmp(name, kip->ki_name)) {
1684 			kauth_identity_lru(kip);
1685 			/* Copy via structure assignment */
1686 			*kir = *kip;
1687 			break;
1688 		}
1689 	}
1690 	KAUTH_IDENTITY_UNLOCK();
1691 	return (kip == NULL) ? ENOENT : 0;
1692 }
1693 
1694 
1695 /*
1696  * kauth_identity_find_ntsid
1697  *
1698  * Description: Search for an entry by NTSID
1699  *
1700  * Parameters:	ntsid				Pointer to NTSID to find
1701  *		kir				Pointer to return area
1702  *		getname				Name buffer, if ki_name wanted
1703  *
1704  * Returns:	0				Found
1705  *		ENOENT				Not found
1706  *
1707  * Implicit returns:
1708  *		*klr				Modified, if found
1709  *
1710  * Note:	The association may be expired, in which case the caller
1711  *		may elect to call out to userland to revalidate.
1712  */
1713 static int
kauth_identity_find_ntsid(ntsid_t * ntsid,struct kauth_identity * kir,char * getname)1714 kauth_identity_find_ntsid(ntsid_t *ntsid, struct kauth_identity *kir, char *getname)
1715 {
1716 	struct kauth_identity *kip;
1717 
1718 	KAUTH_IDENTITY_LOCK();
1719 	TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
1720 		if ((kip->ki_valid & KI_VALID_NTSID) && (kauth_ntsid_equal(ntsid, &kip->ki_ntsid))) {
1721 			kauth_identity_lru(kip);
1722 			/* Copy via structure assignment */
1723 			*kir = *kip;
1724 			/* If a name is wanted and one exists, copy it out */
1725 			if (getname != NULL && (kip->ki_valid & (KI_VALID_PWNAM | KI_VALID_GRNAM))) {
1726 				strlcpy(getname, kip->ki_name, MAXPATHLEN);
1727 			}
1728 			break;
1729 		}
1730 	}
1731 	KAUTH_IDENTITY_UNLOCK();
1732 	return (kip == NULL) ? ENOENT : 0;
1733 }
1734 #endif  /* CONFIG_EXT_RESOLVER */
1735 
1736 
1737 /*
1738  * GUID handling.
1739  */
1740 guid_t kauth_null_guid;
1741 
1742 
1743 /*
1744  * kauth_guid_equal
1745  *
1746  * Description:	Determine the equality of two GUIDs
1747  *
1748  * Parameters:	guid1				Pointer to first GUID
1749  *		guid2				Pointer to second GUID
1750  *
1751  * Returns:	0				If GUIDs are unequal
1752  *		!0				If GUIDs are equal
1753  */
1754 int
kauth_guid_equal(guid_t * guid1,guid_t * guid2)1755 kauth_guid_equal(guid_t *guid1, guid_t *guid2)
1756 {
1757 	return bcmp(guid1, guid2, sizeof(*guid1)) == 0;
1758 }
1759 
1760 
1761 /*
1762  * kauth_wellknown_guid
1763  *
1764  * Description:	Determine if a GUID is a well-known GUID
1765  *
1766  * Parameters:	guid				Pointer to GUID to check
1767  *
1768  * Returns:	KAUTH_WKG_NOT			Not a well known GUID
1769  *		KAUTH_WKG_EVERYBODY		"Everybody"
1770  *		KAUTH_WKG_NOBODY		"Nobody"
1771  *		KAUTH_WKG_OWNER			"Other"
1772  *		KAUTH_WKG_GROUP			"Group"
1773  */
1774 int
kauth_wellknown_guid(guid_t * guid)1775 kauth_wellknown_guid(guid_t *guid)
1776 {
1777 	static char     fingerprint[] = {0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef};
1778 	uint32_t                code;
1779 	/*
1780 	 * All WKGs begin with the same 12 bytes.
1781 	 */
1782 	if (bcmp((void *)guid, fingerprint, 12) == 0) {
1783 		/*
1784 		 * The final 4 bytes are our code (in network byte order).
1785 		 */
1786 		code = OSSwapHostToBigInt32(*(uint32_t *)&guid->g_guid[12]);
1787 		switch (code) {
1788 		case 0x0000000c:
1789 			return KAUTH_WKG_EVERYBODY;
1790 		case 0xfffffffe:
1791 			return KAUTH_WKG_NOBODY;
1792 		case 0x0000000a:
1793 			return KAUTH_WKG_OWNER;
1794 		case 0x00000010:
1795 			return KAUTH_WKG_GROUP;
1796 		}
1797 	}
1798 	return KAUTH_WKG_NOT;
1799 }
1800 
1801 
1802 /*
1803  * kauth_ntsid_equal
1804  *
1805  * Description:	Determine the equality of two NTSIDs (NT Security Identifiers)
1806  *
1807  * Parameters:	sid1				Pointer to first NTSID
1808  *		sid2				Pointer to second NTSID
1809  *
1810  * Returns:	0				If GUIDs are unequal
1811  *		!0				If GUIDs are equal
1812  */
1813 int
kauth_ntsid_equal(ntsid_t * sid1,ntsid_t * sid2)1814 kauth_ntsid_equal(ntsid_t *sid1, ntsid_t *sid2)
1815 {
1816 	/* check sizes for equality, also sanity-check size while we're at it */
1817 	if ((KAUTH_NTSID_SIZE(sid1) == KAUTH_NTSID_SIZE(sid2)) &&
1818 	    (KAUTH_NTSID_SIZE(sid1) <= sizeof(*sid1)) &&
1819 	    bcmp(sid1, sid2, KAUTH_NTSID_SIZE(sid1)) == 0) {
1820 		return 1;
1821 	}
1822 	return 0;
1823 }
1824 
1825 
1826 /*
1827  * Identity KPI
1828  *
1829  * We support four tokens representing identity:
1830  *  - Credential reference
1831  *  - UID
1832  *  - GUID
1833  *  - NT security identifier
1834  *
1835  * Of these, the UID is the ubiquitous identifier; cross-referencing should
1836  * be done using it.
1837  */
1838 
1839 
1840 
1841 /*
1842  * kauth_cred_change_egid
1843  *
1844  * Description:	Set EGID by changing the first element of cr_groups for the
1845  *		passed credential; if the new EGID exists in the list of
1846  *		groups already, then rotate the old EGID into its position,
1847  *		otherwise replace it
1848  *
1849  * Parameters:	cred			Pointer to the credential to modify
1850  *		new_egid		The new EGID to set
1851  *
1852  * Returns:	0			The egid did not displace a member of
1853  *					the supplementary group list
1854  *		1			The egid being set displaced a member
1855  *					of the supplementary groups list
1856  *
1857  * Note:	Utility function; internal use only because of locking.
1858  *
1859  *		This function operates on the credential passed; the caller
1860  *		must operate either on a newly allocated credential (one for
1861  *		which there is no hash cache reference and no externally
1862  *		visible pointer reference), or a template credential.
1863  */
1864 static int
kauth_cred_change_egid(kauth_cred_t cred,gid_t new_egid)1865 kauth_cred_change_egid(kauth_cred_t cred, gid_t new_egid)
1866 {
1867 	int     i;
1868 	int     displaced = 1;
1869 #if radar_4600026
1870 	int     is_member;
1871 #endif  /* radar_4600026 */
1872 	gid_t   old_egid = kauth_cred_getgid(cred);
1873 	posix_cred_t pcred = posix_cred_get(cred);
1874 
1875 	/* Ignoring the first entry, scan for a match for the new egid */
1876 	for (i = 1; i < pcred->cr_ngroups; i++) {
1877 		/*
1878 		 * If we find a match, swap them so we don't lose overall
1879 		 * group information
1880 		 */
1881 		if (pcred->cr_groups[i] == new_egid) {
1882 			pcred->cr_groups[i] = old_egid;
1883 			displaced = 0;
1884 			break;
1885 		}
1886 	}
1887 
1888 #if radar_4600026
1889 #error Fix radar 4600026 first!!!
1890 
1891 /*
1892  *  This is correct for memberd behaviour, but incorrect for POSIX; to address
1893  *  this, we would need to automatically opt-out any SUID/SGID binary, and force
1894  *  it to use initgroups to opt back in.  We take the approach of considering it
1895  *  opt'ed out in any group of 16 displacement instead, since it's a much more
1896  *  conservative approach (i.e. less likely to cause things to break).
1897  */
1898 
1899 	/*
1900 	 * If we displaced a member of the supplementary groups list of the
1901 	 * credential, and we have not opted out of memberd, then if memberd
1902 	 * says that the credential is a member of the group, then it has not
1903 	 * actually been displaced.
1904 	 *
1905 	 * NB:	This is typically a cold code path.
1906 	 */
1907 	if (displaced && !(pcred->cr_flags & CRF_NOMEMBERD) &&
1908 	    kauth_cred_ismember_gid(cred, new_egid, &is_member) == 0 &&
1909 	    is_member) {
1910 		displaced = 0;
1911 	}
1912 #endif  /* radar_4600026 */
1913 
1914 	/* set the new EGID into the old spot */
1915 	pcred->cr_groups[0] = new_egid;
1916 
1917 	return displaced;
1918 }
1919 
1920 
1921 uid_t
kauth_cred_getuid(kauth_cred_t cred)1922 kauth_cred_getuid(kauth_cred_t cred)
1923 {
1924 	return posix_cred_get(cred)->cr_uid;
1925 }
1926 
1927 uid_t
kauth_cred_getruid(kauth_cred_t cred)1928 kauth_cred_getruid(kauth_cred_t cred)
1929 {
1930 	return posix_cred_get(cred)->cr_ruid;
1931 }
1932 
1933 uid_t
kauth_cred_getsvuid(kauth_cred_t cred)1934 kauth_cred_getsvuid(kauth_cred_t cred)
1935 {
1936 	return posix_cred_get(cred)->cr_svuid;
1937 }
1938 
1939 
1940 gid_t
kauth_cred_getgid(kauth_cred_t cred)1941 kauth_cred_getgid(kauth_cred_t cred)
1942 {
1943 	return posix_cred_get(cred)->cr_gid;
1944 }
1945 
1946 gid_t
kauth_cred_getrgid(kauth_cred_t cred)1947 kauth_cred_getrgid(kauth_cred_t cred)
1948 {
1949 	return posix_cred_get(cred)->cr_rgid;
1950 }
1951 
1952 gid_t
kauth_cred_getsvgid(kauth_cred_t cred)1953 kauth_cred_getsvgid(kauth_cred_t cred)
1954 {
1955 	return posix_cred_get(cred)->cr_svgid;
1956 }
1957 
1958 
1959 static int      kauth_cred_cache_lookup(int from, int to, void *src, void *dst);
1960 
1961 #if CONFIG_EXT_RESOLVER == 0
1962 /*
1963  * If there's no resolver, only support a subset of the kauth_cred_x2y() lookups.
1964  */
1965 static __inline int
kauth_cred_cache_lookup(int from,int to,void * src,void * dst)1966 kauth_cred_cache_lookup(int from, int to, void *src, void *dst)
1967 {
1968 	/* NB: These must match the definitions used by Libinfo's mbr_identifier_translate(). */
1969 	static const uuid_t _user_compat_prefix = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd, 0xcc, 0xcc, 0xbb, 0xbb, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00};
1970 	static const uuid_t _group_compat_prefix = {0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0x00, 0x00, 0x00, 0x00};
1971 #define COMPAT_PREFIX_LEN       (sizeof(uuid_t) - sizeof(id_t))
1972 
1973 	assert(from != to);
1974 
1975 	switch (from) {
1976 	case KI_VALID_UID: {
1977 		id_t uid = htonl(*(id_t *)src);
1978 
1979 		if (to == KI_VALID_GUID) {
1980 			uint8_t *uu = dst;
1981 			memcpy(uu, _user_compat_prefix, sizeof(_user_compat_prefix));
1982 			memcpy(&uu[COMPAT_PREFIX_LEN], &uid, sizeof(uid));
1983 			return 0;
1984 		}
1985 		break;
1986 	}
1987 	case KI_VALID_GID: {
1988 		id_t gid = htonl(*(id_t *)src);
1989 
1990 		if (to == KI_VALID_GUID) {
1991 			uint8_t *uu = dst;
1992 			memcpy(uu, _group_compat_prefix, sizeof(_group_compat_prefix));
1993 			memcpy(&uu[COMPAT_PREFIX_LEN], &gid, sizeof(gid));
1994 			return 0;
1995 		}
1996 		break;
1997 	}
1998 	case KI_VALID_GUID: {
1999 		const uint8_t *uu = src;
2000 
2001 		if (to == KI_VALID_UID) {
2002 			if (memcmp(uu, _user_compat_prefix, COMPAT_PREFIX_LEN) == 0) {
2003 				id_t uid;
2004 				memcpy(&uid, &uu[COMPAT_PREFIX_LEN], sizeof(uid));
2005 				*(id_t *)dst = ntohl(uid);
2006 				return 0;
2007 			}
2008 		} else if (to == KI_VALID_GID) {
2009 			if (memcmp(uu, _group_compat_prefix, COMPAT_PREFIX_LEN) == 0) {
2010 				id_t gid;
2011 				memcpy(&gid, &uu[COMPAT_PREFIX_LEN], sizeof(gid));
2012 				*(id_t *)dst = ntohl(gid);
2013 				return 0;
2014 			}
2015 		}
2016 		break;
2017 	}
2018 	default:
2019 		/* NOT IMPLEMENTED */
2020 		break;
2021 	}
2022 	return ENOENT;
2023 }
2024 #endif
2025 
2026 #if defined(CONFIG_EXT_RESOLVER) && (CONFIG_EXT_RESOLVER)
2027 /*
2028  * Structure to hold supplemental groups. Used for impedance matching with
2029  * kauth_cred_cache_lookup below.
2030  */
2031 struct supgroups {
2032 	size_t *count;
2033 	gid_t *groups;
2034 };
2035 
2036 /*
2037  * kauth_cred_uid2groups
2038  *
2039  * Description:	Fetch supplemental GROUPS from UID
2040  *
2041  * Parameters:	uid				UID to examine
2042  *		groups				pointer to an array of gid_ts
2043  *		gcount				pointer to the number of groups wanted/returned
2044  *
2045  * Returns:	0				Success
2046  *	kauth_cred_cache_lookup:EINVAL
2047  *
2048  * Implicit returns:
2049  *		*groups				Modified, if successful
2050  *		*gcount				Modified, if successful
2051  *
2052  */
2053 static int
kauth_cred_uid2groups(uid_t * uid,gid_t * groups,size_t * gcount)2054 kauth_cred_uid2groups(uid_t *uid, gid_t *groups, size_t *gcount)
2055 {
2056 	int rv;
2057 
2058 	struct supgroups supgroups;
2059 	supgroups.count = gcount;
2060 	supgroups.groups = groups;
2061 
2062 	rv = kauth_cred_cache_lookup(KI_VALID_UID, KI_VALID_GROUPS, uid, &supgroups);
2063 
2064 	return rv;
2065 }
2066 #endif
2067 
2068 /*
2069  * kauth_cred_guid2pwnam
2070  *
2071  * Description:	Fetch PWNAM from GUID
2072  *
2073  * Parameters:	guidp				Pointer to GUID to examine
2074  *		pwnam				Pointer to user@domain buffer
2075  *
2076  * Returns:	0				Success
2077  *	kauth_cred_cache_lookup:EINVAL
2078  *
2079  * Implicit returns:
2080  *		*pwnam				Modified, if successful
2081  *
2082  * Notes:	pwnam is assumed to point to a buffer of MAXPATHLEN in size
2083  */
2084 int
kauth_cred_guid2pwnam(guid_t * guidp,char * pwnam)2085 kauth_cred_guid2pwnam(guid_t *guidp, char *pwnam)
2086 {
2087 	return kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_PWNAM, guidp, pwnam);
2088 }
2089 
2090 
2091 /*
2092  * kauth_cred_guid2grnam
2093  *
2094  * Description:	Fetch GRNAM from GUID
2095  *
2096  * Parameters:	guidp				Pointer to GUID to examine
2097  *		grnam				Pointer to group@domain buffer
2098  *
2099  * Returns:	0				Success
2100  *	kauth_cred_cache_lookup:EINVAL
2101  *
2102  * Implicit returns:
2103  *		*grnam				Modified, if successful
2104  *
2105  * Notes:	grnam is assumed to point to a buffer of MAXPATHLEN in size
2106  */
2107 int
kauth_cred_guid2grnam(guid_t * guidp,char * grnam)2108 kauth_cred_guid2grnam(guid_t *guidp, char *grnam)
2109 {
2110 	return kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_GRNAM, guidp, grnam);
2111 }
2112 
2113 
2114 /*
2115  * kauth_cred_pwnam2guid
2116  *
2117  * Description:	Fetch PWNAM from GUID
2118  *
2119  * Parameters:	pwnam				String containing user@domain
2120  *		guidp				Pointer to buffer for GUID
2121  *
2122  * Returns:	0				Success
2123  *	kauth_cred_cache_lookup:EINVAL
2124  *
2125  * Implicit returns:
2126  *		*guidp				Modified, if successful
2127  *
2128  * Notes:	pwnam should not point to a request larger than MAXPATHLEN
2129  *		bytes in size, including the NUL termination of the string.
2130  */
2131 int
kauth_cred_pwnam2guid(char * pwnam,guid_t * guidp)2132 kauth_cred_pwnam2guid(char *pwnam, guid_t *guidp)
2133 {
2134 	return kauth_cred_cache_lookup(KI_VALID_PWNAM, KI_VALID_GUID, pwnam, guidp);
2135 }
2136 
2137 
2138 /*
2139  * kauth_cred_grnam2guid
2140  *
2141  * Description:	Fetch GRNAM from GUID
2142  *
2143  * Parameters:	grnam				String containing group@domain
2144  *		guidp				Pointer to buffer for GUID
2145  *
2146  * Returns:	0				Success
2147  *	kauth_cred_cache_lookup:EINVAL
2148  *
2149  * Implicit returns:
2150  *		*guidp				Modified, if successful
2151  *
2152  * Notes:	grnam should not point to a request larger than MAXPATHLEN
2153  *		bytes in size, including the NUL termination of the string.
2154  */
2155 int
kauth_cred_grnam2guid(char * grnam,guid_t * guidp)2156 kauth_cred_grnam2guid(char *grnam, guid_t *guidp)
2157 {
2158 	return kauth_cred_cache_lookup(KI_VALID_GRNAM, KI_VALID_GUID, grnam, guidp);
2159 }
2160 
2161 
2162 /*
2163  * kauth_cred_guid2uid
2164  *
2165  * Description:	Fetch UID from GUID
2166  *
2167  * Parameters:	guidp				Pointer to GUID to examine
2168  *		uidp				Pointer to buffer for UID
2169  *
2170  * Returns:	0				Success
2171  *	kauth_cred_cache_lookup:EINVAL
2172  *
2173  * Implicit returns:
2174  *		*uidp				Modified, if successful
2175  */
2176 int
kauth_cred_guid2uid(guid_t * guidp,uid_t * uidp)2177 kauth_cred_guid2uid(guid_t *guidp, uid_t *uidp)
2178 {
2179 	return kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_UID, guidp, uidp);
2180 }
2181 
2182 
2183 /*
2184  * kauth_cred_guid2gid
2185  *
2186  * Description:	Fetch GID from GUID
2187  *
2188  * Parameters:	guidp				Pointer to GUID to examine
2189  *		gidp				Pointer to buffer for GID
2190  *
2191  * Returns:	0				Success
2192  *	kauth_cred_cache_lookup:EINVAL
2193  *
2194  * Implicit returns:
2195  *		*gidp				Modified, if successful
2196  */
2197 int
kauth_cred_guid2gid(guid_t * guidp,gid_t * gidp)2198 kauth_cred_guid2gid(guid_t *guidp, gid_t *gidp)
2199 {
2200 	return kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_GID, guidp, gidp);
2201 }
2202 
2203 /*
2204  * kauth_cred_nfs4domain2dsnode
2205  *
2206  * Description: Fetch dsnode from nfs4domain
2207  *
2208  * Parameters:	nfs4domain			Pointer to a string nfs4 domain
2209  *		dsnode				Pointer to buffer for dsnode
2210  *
2211  * Returns:	0				Success
2212  *		ENOENT				For now just a stub that always fails
2213  *
2214  * Implicit returns:
2215  *		*dsnode				Modified, if successuful
2216  */
2217 int
kauth_cred_nfs4domain2dsnode(__unused char * nfs4domain,__unused char * dsnode)2218 kauth_cred_nfs4domain2dsnode(__unused char *nfs4domain, __unused char *dsnode)
2219 {
2220 	return ENOENT;
2221 }
2222 
2223 /*
2224  * kauth_cred_dsnode2nfs4domain
2225  *
2226  * Description: Fetch nfs4domain from dsnode
2227  *
2228  * Parameters:	nfs4domain			Pointer to  string dsnode
2229  *		dsnode				Pointer to buffer for nfs4domain
2230  *
2231  * Returns:	0				Success
2232  *		ENOENT				For now just a stub that always fails
2233  *
2234  * Implicit returns:
2235  *		*nfs4domain			Modified, if successuful
2236  */
2237 int
kauth_cred_dsnode2nfs4domain(__unused char * dsnode,__unused char * nfs4domain)2238 kauth_cred_dsnode2nfs4domain(__unused char *dsnode, __unused char *nfs4domain)
2239 {
2240 	return ENOENT;
2241 }
2242 
2243 /*
2244  * kauth_cred_ntsid2uid
2245  *
2246  * Description:	Fetch UID from NTSID
2247  *
2248  * Parameters:	sidp				Pointer to NTSID to examine
2249  *		uidp				Pointer to buffer for UID
2250  *
2251  * Returns:	0				Success
2252  *	kauth_cred_cache_lookup:EINVAL
2253  *
2254  * Implicit returns:
2255  *		*uidp				Modified, if successful
2256  */
2257 int
kauth_cred_ntsid2uid(ntsid_t * sidp,uid_t * uidp)2258 kauth_cred_ntsid2uid(ntsid_t *sidp, uid_t *uidp)
2259 {
2260 	return kauth_cred_cache_lookup(KI_VALID_NTSID, KI_VALID_UID, sidp, uidp);
2261 }
2262 
2263 
2264 /*
2265  * kauth_cred_ntsid2gid
2266  *
2267  * Description:	Fetch GID from NTSID
2268  *
2269  * Parameters:	sidp				Pointer to NTSID to examine
2270  *		gidp				Pointer to buffer for GID
2271  *
2272  * Returns:	0				Success
2273  *	kauth_cred_cache_lookup:EINVAL
2274  *
2275  * Implicit returns:
2276  *		*gidp				Modified, if successful
2277  */
2278 int
kauth_cred_ntsid2gid(ntsid_t * sidp,gid_t * gidp)2279 kauth_cred_ntsid2gid(ntsid_t *sidp, gid_t *gidp)
2280 {
2281 	return kauth_cred_cache_lookup(KI_VALID_NTSID, KI_VALID_GID, sidp, gidp);
2282 }
2283 
2284 
2285 /*
2286  * kauth_cred_ntsid2guid
2287  *
2288  * Description:	Fetch GUID from NTSID
2289  *
2290  * Parameters:	sidp				Pointer to NTSID to examine
2291  *		guidp				Pointer to buffer for GUID
2292  *
2293  * Returns:	0				Success
2294  *	kauth_cred_cache_lookup:EINVAL
2295  *
2296  * Implicit returns:
2297  *		*guidp				Modified, if successful
2298  */
2299 int
kauth_cred_ntsid2guid(ntsid_t * sidp,guid_t * guidp)2300 kauth_cred_ntsid2guid(ntsid_t *sidp, guid_t *guidp)
2301 {
2302 	return kauth_cred_cache_lookup(KI_VALID_NTSID, KI_VALID_GUID, sidp, guidp);
2303 }
2304 
2305 
2306 /*
2307  * kauth_cred_uid2guid
2308  *
2309  * Description:	Fetch GUID from UID
2310  *
2311  * Parameters:	uid				UID to examine
2312  *		guidp				Pointer to buffer for GUID
2313  *
2314  * Returns:	0				Success
2315  *	kauth_cred_cache_lookup:EINVAL
2316  *
2317  * Implicit returns:
2318  *		*guidp				Modified, if successful
2319  */
2320 int
kauth_cred_uid2guid(uid_t uid,guid_t * guidp)2321 kauth_cred_uid2guid(uid_t uid, guid_t *guidp)
2322 {
2323 	return kauth_cred_cache_lookup(KI_VALID_UID, KI_VALID_GUID, &uid, guidp);
2324 }
2325 
2326 
2327 /*
2328  * kauth_cred_getguid
2329  *
2330  * Description:	Fetch GUID from credential
2331  *
2332  * Parameters:	cred				Credential to examine
2333  *		guidp				Pointer to buffer for GUID
2334  *
2335  * Returns:	0				Success
2336  *	kauth_cred_cache_lookup:EINVAL
2337  *
2338  * Implicit returns:
2339  *		*guidp				Modified, if successful
2340  */
2341 int
kauth_cred_getguid(kauth_cred_t cred,guid_t * guidp)2342 kauth_cred_getguid(kauth_cred_t cred, guid_t *guidp)
2343 {
2344 	return kauth_cred_uid2guid(kauth_cred_getuid(cred), guidp);
2345 }
2346 
2347 
2348 /*
2349  * kauth_cred_getguid
2350  *
2351  * Description:	Fetch GUID from GID
2352  *
2353  * Parameters:	gid				GID to examine
2354  *		guidp				Pointer to buffer for GUID
2355  *
2356  * Returns:	0				Success
2357  *	kauth_cred_cache_lookup:EINVAL
2358  *
2359  * Implicit returns:
2360  *		*guidp				Modified, if successful
2361  */
2362 int
kauth_cred_gid2guid(gid_t gid,guid_t * guidp)2363 kauth_cred_gid2guid(gid_t gid, guid_t *guidp)
2364 {
2365 	return kauth_cred_cache_lookup(KI_VALID_GID, KI_VALID_GUID, &gid, guidp);
2366 }
2367 
2368 
2369 /*
2370  * kauth_cred_uid2ntsid
2371  *
2372  * Description:	Fetch NTSID from UID
2373  *
2374  * Parameters:	uid				UID to examine
2375  *		sidp				Pointer to buffer for NTSID
2376  *
2377  * Returns:	0				Success
2378  *	kauth_cred_cache_lookup:EINVAL
2379  *
2380  * Implicit returns:
2381  *		*sidp				Modified, if successful
2382  */
2383 int
kauth_cred_uid2ntsid(uid_t uid,ntsid_t * sidp)2384 kauth_cred_uid2ntsid(uid_t uid, ntsid_t *sidp)
2385 {
2386 	return kauth_cred_cache_lookup(KI_VALID_UID, KI_VALID_NTSID, &uid, sidp);
2387 }
2388 
2389 
2390 /*
2391  * kauth_cred_getntsid
2392  *
2393  * Description:	Fetch NTSID from credential
2394  *
2395  * Parameters:	cred				Credential to examine
2396  *		sidp				Pointer to buffer for NTSID
2397  *
2398  * Returns:	0				Success
2399  *	kauth_cred_cache_lookup:EINVAL
2400  *
2401  * Implicit returns:
2402  *		*sidp				Modified, if successful
2403  */
2404 int
kauth_cred_getntsid(kauth_cred_t cred,ntsid_t * sidp)2405 kauth_cred_getntsid(kauth_cred_t cred, ntsid_t *sidp)
2406 {
2407 	return kauth_cred_uid2ntsid(kauth_cred_getuid(cred), sidp);
2408 }
2409 
2410 
2411 /*
2412  * kauth_cred_gid2ntsid
2413  *
2414  * Description:	Fetch NTSID from GID
2415  *
2416  * Parameters:	gid				GID to examine
2417  *		sidp				Pointer to buffer for NTSID
2418  *
2419  * Returns:	0				Success
2420  *	kauth_cred_cache_lookup:EINVAL
2421  *
2422  * Implicit returns:
2423  *		*sidp				Modified, if successful
2424  */
2425 int
kauth_cred_gid2ntsid(gid_t gid,ntsid_t * sidp)2426 kauth_cred_gid2ntsid(gid_t gid, ntsid_t *sidp)
2427 {
2428 	return kauth_cred_cache_lookup(KI_VALID_GID, KI_VALID_NTSID, &gid, sidp);
2429 }
2430 
2431 
2432 /*
2433  * kauth_cred_guid2ntsid
2434  *
2435  * Description:	Fetch NTSID from GUID
2436  *
2437  * Parameters:	guidp				Pointer to GUID to examine
2438  *		sidp				Pointer to buffer for NTSID
2439  *
2440  * Returns:	0				Success
2441  *	kauth_cred_cache_lookup:EINVAL
2442  *
2443  * Implicit returns:
2444  *		*sidp				Modified, if successful
2445  */
2446 int
kauth_cred_guid2ntsid(guid_t * guidp,ntsid_t * sidp)2447 kauth_cred_guid2ntsid(guid_t *guidp, ntsid_t *sidp)
2448 {
2449 	return kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_NTSID, guidp, sidp);
2450 }
2451 
2452 
2453 /*
2454  * kauth_cred_cache_lookup
2455  *
2456  * Description:	Lookup a translation in the cache; if one is not found, and
2457  *		the attempt was not fatal, submit the request to the resolver
2458  *		instead, and wait for it to complete or be aborted.
2459  *
2460  * Parameters:	from				Identity information we have
2461  *		to				Identity information we want
2462  *		src				Pointer to buffer containing
2463  *						the source identity
2464  *		dst				Pointer to buffer to receive
2465  *						the target identity
2466  *
2467  * Returns:	0				Success
2468  *		EINVAL				Unknown source identity type
2469  */
2470 #if CONFIG_EXT_RESOLVER
2471 static int
kauth_cred_cache_lookup(int from,int to,void * src,void * dst)2472 kauth_cred_cache_lookup(int from, int to, void *src, void *dst)
2473 {
2474 	struct kauth_identity ki;
2475 	struct kauth_identity_extlookup el;
2476 	int error;
2477 	uint64_t extend_data = 0ULL;
2478 	int (* expired)(struct kauth_identity *kip);
2479 	char *namebuf = NULL;
2480 
2481 	KAUTH_DEBUG("CACHE - translate %d to %d", from, to);
2482 
2483 	/*
2484 	 * Look for an existing cache entry for this association.
2485 	 * If the entry has not expired, return the cached information.
2486 	 * We do not cache user@domain translations here; they use too
2487 	 * much memory to hold onto forever, and can not be updated
2488 	 * atomically.
2489 	 */
2490 	if (to == KI_VALID_PWNAM || to == KI_VALID_GRNAM) {
2491 		if (dst == NULL) {
2492 			return EINVAL;
2493 		}
2494 		namebuf = dst;
2495 		*namebuf = '\0';
2496 	}
2497 	ki.ki_valid = 0;
2498 	switch (from) {
2499 	case KI_VALID_UID:
2500 		error = kauth_identity_find_uid(*(uid_t *)src, &ki, namebuf);
2501 		break;
2502 	case KI_VALID_GID:
2503 		error = kauth_identity_find_gid(*(gid_t *)src, &ki, namebuf);
2504 		break;
2505 	case KI_VALID_GUID:
2506 		error = kauth_identity_find_guid((guid_t *)src, &ki, namebuf);
2507 		break;
2508 	case KI_VALID_NTSID:
2509 		error = kauth_identity_find_ntsid((ntsid_t *)src, &ki, namebuf);
2510 		break;
2511 	case KI_VALID_PWNAM:
2512 	case KI_VALID_GRNAM:
2513 		/* Names are unique in their 'from' space */
2514 		error = kauth_identity_find_nam((char *)src, from, &ki);
2515 		break;
2516 	default:
2517 		return EINVAL;
2518 	}
2519 	/* If we didn't get what we're asking for. Call the resolver */
2520 	if (!error && !(to & ki.ki_valid)) {
2521 		error = ENOENT;
2522 	}
2523 	/* lookup failure or error */
2524 	if (error != 0) {
2525 		/* any other error is fatal */
2526 		if (error != ENOENT) {
2527 			/* XXX bogus check - this is not possible */
2528 			KAUTH_DEBUG("CACHE - cache search error %d", error);
2529 			return error;
2530 		}
2531 	} else {
2532 		/* found a valid cached entry, check expiry */
2533 		switch (to) {
2534 		case KI_VALID_GUID:
2535 			expired = kauth_identity_guid_expired;
2536 			break;
2537 		case KI_VALID_NTSID:
2538 			expired = kauth_identity_ntsid_expired;
2539 			break;
2540 		case KI_VALID_GROUPS:
2541 			expired = kauth_identity_groups_expired;
2542 			break;
2543 		default:
2544 			switch (from) {
2545 			case KI_VALID_GUID:
2546 				expired = kauth_identity_guid_expired;
2547 				break;
2548 			case KI_VALID_NTSID:
2549 				expired = kauth_identity_ntsid_expired;
2550 				break;
2551 			default:
2552 				expired = NULL;
2553 			}
2554 		}
2555 
2556 		/*
2557 		 * If no expiry function, or not expired, we have found
2558 		 * a hit.
2559 		 */
2560 		if (expired) {
2561 			if (!expired(&ki)) {
2562 				KAUTH_DEBUG("CACHE - entry valid, unexpired");
2563 				expired = NULL; /* must clear it is used as a flag */
2564 			} else {
2565 				/*
2566 				 * We leave ki_valid set here; it contains a
2567 				 * translation but the TTL has expired.  If we can't
2568 				 * get a result from the resolver, we will use it as
2569 				 * a better-than nothing alternative.
2570 				 */
2571 
2572 				KAUTH_DEBUG("CACHE - expired entry found");
2573 			}
2574 		} else {
2575 			KAUTH_DEBUG("CACHE - no expiry function");
2576 		}
2577 
2578 		if (!expired) {
2579 			/* do we have a translation? */
2580 			if (ki.ki_valid & to) {
2581 				KAUTH_DEBUG("CACHE - found matching entry with valid 0x%08x", ki.ki_valid);
2582 				DTRACE_PROC4(kauth__identity__cache__hit, int, from, int, to, void *, src, void *, dst);
2583 				goto found;
2584 			} else {
2585 				/*
2586 				 * GUIDs and NTSIDs map to either a UID or a GID, but not both.
2587 				 * If we went looking for a translation from GUID or NTSID and
2588 				 * found a translation that wasn't for our desired type, then
2589 				 * don't bother calling the resolver. We know that this
2590 				 * GUID/NTSID can't translate to our desired type.
2591 				 */
2592 				switch (from) {
2593 				case KI_VALID_GUID:
2594 				case KI_VALID_NTSID:
2595 					switch (to) {
2596 					case KI_VALID_GID:
2597 						if ((ki.ki_valid & KI_VALID_UID)) {
2598 							KAUTH_DEBUG("CACHE - unexpected entry 0x%08x & %x", ki.ki_valid, KI_VALID_GID);
2599 							return ENOENT;
2600 						}
2601 						break;
2602 					case KI_VALID_UID:
2603 						if ((ki.ki_valid & KI_VALID_GID)) {
2604 							KAUTH_DEBUG("CACHE - unexpected entry 0x%08x & %x", ki.ki_valid, KI_VALID_UID);
2605 							return ENOENT;
2606 						}
2607 						break;
2608 					}
2609 					break;
2610 				}
2611 			}
2612 		}
2613 	}
2614 
2615 	/*
2616 	 * We failed to find a cache entry; call the resolver.
2617 	 *
2618 	 * Note:	We ask for as much non-extended data as we can get,
2619 	 *		and only provide (or ask for) extended information if
2620 	 *		we have a 'from' (or 'to') which requires it.  This
2621 	 *		way we don't pay for the extra transfer overhead for
2622 	 *		data we don't need.
2623 	 */
2624 	bzero(&el, sizeof(el));
2625 	el.el_info_pid = proc_getpid(current_proc());
2626 	switch (from) {
2627 	case KI_VALID_UID:
2628 		el.el_flags = KAUTH_EXTLOOKUP_VALID_UID;
2629 		el.el_uid = *(uid_t *)src;
2630 		break;
2631 	case KI_VALID_GID:
2632 		el.el_flags = KAUTH_EXTLOOKUP_VALID_GID;
2633 		el.el_gid = *(gid_t *)src;
2634 		break;
2635 	case KI_VALID_GUID:
2636 		el.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID;
2637 		el.el_uguid = *(guid_t *)src;
2638 		el.el_gguid = *(guid_t *)src;
2639 		break;
2640 	case KI_VALID_NTSID:
2641 		el.el_flags = KAUTH_EXTLOOKUP_VALID_USID | KAUTH_EXTLOOKUP_VALID_GSID;
2642 		el.el_usid = *(ntsid_t *)src;
2643 		el.el_gsid = *(ntsid_t *)src;
2644 		break;
2645 	case KI_VALID_PWNAM:
2646 		/* extra overhead */
2647 		el.el_flags = KAUTH_EXTLOOKUP_VALID_PWNAM;
2648 		extend_data = CAST_USER_ADDR_T(src);
2649 		break;
2650 	case KI_VALID_GRNAM:
2651 		/* extra overhead */
2652 		el.el_flags = KAUTH_EXTLOOKUP_VALID_GRNAM;
2653 		extend_data = CAST_USER_ADDR_T(src);
2654 		break;
2655 	default:
2656 		return EINVAL;
2657 	}
2658 	/*
2659 	 * Here we ask for everything all at once, to avoid having to work
2660 	 * out what we really want now, or might want soon.
2661 	 *
2662 	 * Asking for SID translations when we don't know we need them right
2663 	 * now is going to cause excess work to be done if we're connected
2664 	 * to a network that thinks it can translate them.  This list needs
2665 	 * to get smaller/smarter.
2666 	 */
2667 	el.el_flags |= KAUTH_EXTLOOKUP_WANT_UID | KAUTH_EXTLOOKUP_WANT_GID |
2668 	    KAUTH_EXTLOOKUP_WANT_UGUID | KAUTH_EXTLOOKUP_WANT_GGUID |
2669 	    KAUTH_EXTLOOKUP_WANT_USID | KAUTH_EXTLOOKUP_WANT_GSID;
2670 	if (to == KI_VALID_PWNAM) {
2671 		/* extra overhead */
2672 		el.el_flags |= KAUTH_EXTLOOKUP_WANT_PWNAM;
2673 		extend_data = CAST_USER_ADDR_T(dst);
2674 	}
2675 	if (to == KI_VALID_GRNAM) {
2676 		/* extra overhead */
2677 		el.el_flags |= KAUTH_EXTLOOKUP_WANT_GRNAM;
2678 		extend_data = CAST_USER_ADDR_T(dst);
2679 	}
2680 	if (to == KI_VALID_GROUPS) {
2681 		/* Expensive and only useful for an NFS client not using kerberos */
2682 		el.el_flags |= KAUTH_EXTLOOKUP_WANT_SUPGRPS;
2683 		if (ki.ki_valid & KI_VALID_GROUPS) {
2684 			/*
2685 			 * Copy the current supplemental groups for the resolver.
2686 			 * The resolver should check these groups first and if
2687 			 * the user (uid) is still a member it should endeavor to
2688 			 * keep them in the list. Otherwise NFS clients could get
2689 			 * changing access to server file system objects on each
2690 			 * expiration.
2691 			 */
2692 			if (ki.ki_supgrpcnt > NGROUPS) {
2693 				panic("kauth data structure corrupted. kauth identity 0x%p with %u groups, greater than max of %d",
2694 				    &ki, ki.ki_supgrpcnt, NGROUPS);
2695 			}
2696 
2697 			el.el_sup_grp_cnt = (uint32_t)ki.ki_supgrpcnt;
2698 
2699 			memcpy(el.el_sup_groups, ki.ki_supgrps, sizeof(el.el_sup_groups[0]) * ki.ki_supgrpcnt);
2700 			/* Let the resolver know these were the previous valid groups */
2701 			el.el_flags |= KAUTH_EXTLOOKUP_VALID_SUPGRPS;
2702 			KAUTH_DEBUG("GROUPS: Sending previously valid GROUPS");
2703 		} else {
2704 			KAUTH_DEBUG("GROUPS: no valid groups to send");
2705 		}
2706 	}
2707 
2708 	/* Call resolver */
2709 	KAUTH_DEBUG("CACHE - calling resolver for %x", el.el_flags);
2710 
2711 	DTRACE_PROC3(kauth__id__resolver__submitted, int, from, int, to, uintptr_t, src);
2712 
2713 	error = kauth_resolver_submit(&el, extend_data);
2714 
2715 	DTRACE_PROC2(kauth__id__resolver__returned, int, error, struct kauth_identity_extlookup *, &el)
2716 
2717 	KAUTH_DEBUG("CACHE - resolver returned %d", error);
2718 
2719 	/* was the external lookup successful? */
2720 	if (error == 0) {
2721 		/*
2722 		 * Save the results from the lookup - we may have other
2723 		 * information, even if we didn't get a guid or the
2724 		 * extended data.
2725 		 *
2726 		 * If we came from a name, we know the extend_data is valid.
2727 		 */
2728 		if (from == KI_VALID_PWNAM) {
2729 			el.el_flags |= KAUTH_EXTLOOKUP_VALID_PWNAM;
2730 		} else if (from == KI_VALID_GRNAM) {
2731 			el.el_flags |= KAUTH_EXTLOOKUP_VALID_GRNAM;
2732 		}
2733 
2734 		kauth_identity_updatecache(&el, &ki, extend_data);
2735 
2736 		/*
2737 		 * Check to see if we have a valid cache entry
2738 		 * originating from the result.
2739 		 */
2740 		if (!(ki.ki_valid & to)) {
2741 			error = ENOENT;
2742 		}
2743 	}
2744 	if (error) {
2745 		return error;
2746 	}
2747 found:
2748 	/*
2749 	 * Copy from the appropriate struct kauth_identity cache entry
2750 	 * structure into the destination buffer area.
2751 	 */
2752 	switch (to) {
2753 	case KI_VALID_UID:
2754 		*(uid_t *)dst = ki.ki_uid;
2755 		break;
2756 	case KI_VALID_GID:
2757 		*(gid_t *)dst = ki.ki_gid;
2758 		break;
2759 	case KI_VALID_GUID:
2760 		*(guid_t *)dst = ki.ki_guid;
2761 		break;
2762 	case KI_VALID_NTSID:
2763 		*(ntsid_t *)dst = ki.ki_ntsid;
2764 		break;
2765 	case KI_VALID_GROUPS: {
2766 		struct supgroups *gp = (struct supgroups *)dst;
2767 		size_t limit = ki.ki_supgrpcnt;
2768 
2769 		if (gp->count) {
2770 			limit = MIN(ki.ki_supgrpcnt, *gp->count);
2771 			*gp->count = limit;
2772 		}
2773 
2774 		memcpy(gp->groups, ki.ki_supgrps, sizeof(gid_t) * limit);
2775 	}
2776 	break;
2777 	case KI_VALID_PWNAM:
2778 	case KI_VALID_GRNAM:
2779 		/* handled in kauth_resolver_complete() */
2780 		break;
2781 	default:
2782 		return EINVAL;
2783 	}
2784 	KAUTH_DEBUG("CACHE - returned successfully");
2785 	return 0;
2786 }
2787 
2788 
2789 /*
2790  * Group membership cache.
2791  *
2792  * XXX the linked-list implementation here needs to be optimized.
2793  */
2794 
2795 /*
2796  * kauth_groups_expired
2797  *
2798  * Description:	Handle lazy expiration of group membership cache entries
2799  *
2800  * Parameters:	gm				group membership entry to
2801  *						check for expiration
2802  *
2803  * Returns:	1				Expired
2804  *		0				Not expired
2805  */
2806 static int
kauth_groups_expired(struct kauth_group_membership * gm)2807 kauth_groups_expired(struct kauth_group_membership *gm)
2808 {
2809 	struct timeval tv;
2810 
2811 	/*
2812 	 * Expiration time of 0 means this entry is persistent.
2813 	 */
2814 	if (gm->gm_expiry == 0) {
2815 		return 0;
2816 	}
2817 
2818 	microuptime(&tv);
2819 
2820 	return (gm->gm_expiry <= tv.tv_sec) ? 1 : 0;
2821 }
2822 
2823 
2824 /*
2825  * kauth_groups_lru
2826  *
2827  * Description:	Promote the entry to the head of the LRU, assumes the cache
2828  *		is locked.
2829  *
2830  * Parameters:	kip				group membership entry to move
2831  *						to the head of the LRU list,
2832  *						if it's not already there
2833  *
2834  * Returns:	(void)
2835  *
2836  * Notes:	This is called even if the entry has expired; typically an
2837  *		expired entry that's been looked up is about to be revalidated,
2838  *		and having it closer to the head of the LRU means finding it
2839  *		quickly again when the revalidation comes through.
2840  */
2841 static void
kauth_groups_lru(struct kauth_group_membership * gm)2842 kauth_groups_lru(struct kauth_group_membership *gm)
2843 {
2844 	if (gm != TAILQ_FIRST(&kauth_groups)) {
2845 		TAILQ_REMOVE(&kauth_groups, gm, gm_link);
2846 		TAILQ_INSERT_HEAD(&kauth_groups, gm, gm_link);
2847 	}
2848 }
2849 
2850 
2851 /*
2852  * kauth_groups_updatecache
2853  *
2854  * Description:	Given a lookup result, add any group cache associations that
2855  *		we don't currently have.
2856  *
2857  * Parameters:	elp				External lookup result from
2858  *						user space daemon to kernel
2859  *		rkip				pointer to returned kauth
2860  *						identity, or NULL
2861  *
2862  * Returns:	(void)
2863  */
2864 static void
kauth_groups_updatecache(struct kauth_identity_extlookup * el)2865 kauth_groups_updatecache(struct kauth_identity_extlookup *el)
2866 {
2867 	struct kauth_group_membership *gm;
2868 	struct timeval tv;
2869 
2870 	/* need a valid response if we are to cache anything */
2871 	if ((el->el_flags &
2872 	    (KAUTH_EXTLOOKUP_VALID_UID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_VALID_MEMBERSHIP)) !=
2873 	    (KAUTH_EXTLOOKUP_VALID_UID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_VALID_MEMBERSHIP)) {
2874 		return;
2875 	}
2876 
2877 	microuptime(&tv);
2878 
2879 	/*
2880 	 * Search for an existing record for this association before inserting
2881 	 * a new one; if we find one, update it instead of creating a new one
2882 	 */
2883 	KAUTH_GROUPS_LOCK();
2884 	TAILQ_FOREACH(gm, &kauth_groups, gm_link) {
2885 		if ((el->el_uid == gm->gm_uid) &&
2886 		    (el->el_gid == gm->gm_gid)) {
2887 			if (el->el_flags & KAUTH_EXTLOOKUP_ISMEMBER) {
2888 				gm->gm_flags |= KAUTH_GROUP_ISMEMBER;
2889 			} else {
2890 				gm->gm_flags &= ~KAUTH_GROUP_ISMEMBER;
2891 			}
2892 			gm->gm_expiry = (el->el_member_valid) ? el->el_member_valid + tv.tv_sec : 0;
2893 			kauth_groups_lru(gm);
2894 			break;
2895 		}
2896 	}
2897 	KAUTH_GROUPS_UNLOCK();
2898 
2899 	/* if we found an entry to update, stop here */
2900 	if (gm != NULL) {
2901 		return;
2902 	}
2903 
2904 	/* allocate a new record */
2905 	gm = kalloc_type(struct kauth_group_membership, Z_WAITOK | Z_NOFAIL);
2906 	gm->gm_uid = el->el_uid;
2907 	gm->gm_gid = el->el_gid;
2908 	if (el->el_flags & KAUTH_EXTLOOKUP_ISMEMBER) {
2909 		gm->gm_flags |= KAUTH_GROUP_ISMEMBER;
2910 	} else {
2911 		gm->gm_flags &= ~KAUTH_GROUP_ISMEMBER;
2912 	}
2913 	gm->gm_expiry = (el->el_member_valid) ? el->el_member_valid + tv.tv_sec : 0;
2914 
2915 	/*
2916 	 * Insert the new entry.  Note that it's possible to race ourselves
2917 	 * here and end up with duplicate entries in the list.  Wasteful, but
2918 	 * harmless since the first into the list will never be looked up,
2919 	 * and thus will eventually just fall off the end.
2920 	 */
2921 	KAUTH_GROUPS_LOCK();
2922 	TAILQ_INSERT_HEAD(&kauth_groups, gm, gm_link);
2923 	if (++kauth_groups_count > kauth_groups_cachemax) {
2924 		gm = TAILQ_LAST(&kauth_groups, kauth_groups_head);
2925 		TAILQ_REMOVE(&kauth_groups, gm, gm_link);
2926 		kauth_groups_count--;
2927 	} else {
2928 		gm = NULL;
2929 	}
2930 	KAUTH_GROUPS_UNLOCK();
2931 
2932 	/* free expired cache entry */
2933 	kfree_type(struct kauth_group_membership, gm);
2934 }
2935 
2936 /*
2937  * Trim older entries from the group membership cache.
2938  *
2939  * Must be called with the group cache lock held.
2940  */
2941 static void
kauth_groups_trimcache(int new_size)2942 kauth_groups_trimcache(int new_size)
2943 {
2944 	struct kauth_group_membership *gm;
2945 
2946 	lck_mtx_assert(&kauth_groups_mtx, LCK_MTX_ASSERT_OWNED);
2947 
2948 	while (kauth_groups_count > new_size) {
2949 		gm = TAILQ_LAST(&kauth_groups, kauth_groups_head);
2950 		TAILQ_REMOVE(&kauth_groups, gm, gm_link);
2951 		kauth_groups_count--;
2952 		kfree_type(struct kauth_group_membership, gm);
2953 	}
2954 }
2955 #endif  /* CONFIG_EXT_RESOLVER */
2956 
2957 /*
2958  * Group membership KPI
2959  */
2960 
2961 /*
2962  * kauth_cred_ismember_gid
2963  *
2964  * Description:	Given a credential and a GID, determine if the GID is a member
2965  *		of one of the supplementary groups associated with the given
2966  *		credential
2967  *
2968  * Parameters:	cred				Credential to check in
2969  *		gid				GID to check for membership
2970  *		resultp				Pointer to int to contain the
2971  *						result of the call
2972  *
2973  * Returns:	0				Success
2974  *		ENOENT				Could not perform lookup
2975  *	kauth_resolver_submit:EWOULDBLOCK
2976  *	kauth_resolver_submit:EINTR
2977  *	kauth_resolver_submit:ENOMEM
2978  *	kauth_resolver_submit:ENOENT		User space daemon did not vend
2979  *						this credential.
2980  *	kauth_resolver_submit:???		Unlikely error from user space
2981  *
2982  * Implicit returns:
2983  *		*resultp (modified)	1	Is member
2984  *					0	Is not member
2985  *
2986  * Notes:	This function guarantees not to modify resultp when returning
2987  *		an error.
2988  *
2989  *		This function effectively checks the EGID as well, since the
2990  *		EGID is cr_groups[0] as an implementation detail.
2991  */
2992 int
kauth_cred_ismember_gid(kauth_cred_t cred,gid_t gid,int * resultp)2993 kauth_cred_ismember_gid(kauth_cred_t cred, gid_t gid, int *resultp)
2994 {
2995 	posix_cred_t pcred = posix_cred_get(cred);
2996 	int i;
2997 
2998 	/*
2999 	 * Check the per-credential list of override groups.
3000 	 *
3001 	 * We can conditionalise this on cred->cr_gmuid == KAUTH_UID_NONE since
3002 	 * the cache should be used for that case.
3003 	 */
3004 	for (i = 0; i < pcred->cr_ngroups; i++) {
3005 		if (gid == pcred->cr_groups[i]) {
3006 			*resultp = 1;
3007 			return 0;
3008 		}
3009 	}
3010 
3011 	/*
3012 	 * If we don't have a UID for group membership checks, the in-cred list
3013 	 * was authoritative and we can stop here.
3014 	 */
3015 	if (pcred->cr_gmuid == KAUTH_UID_NONE) {
3016 		*resultp = 0;
3017 		return 0;
3018 	}
3019 
3020 #if CONFIG_EXT_RESOLVER
3021 	struct kauth_group_membership *gm;
3022 	struct kauth_identity_extlookup el;
3023 	int error;
3024 
3025 	/*
3026 	 * If the resolver hasn't checked in yet, we are early in the boot
3027 	 * phase and the local group list is complete and authoritative.
3028 	 */
3029 	if (!kauth_resolver_registered) {
3030 		*resultp = 0;
3031 		return 0;
3032 	}
3033 
3034 	/* TODO: */
3035 	/* XXX check supplementary groups */
3036 	/* XXX check whiteout groups */
3037 	/* XXX nesting of supplementary/whiteout groups? */
3038 
3039 	/*
3040 	 * Check the group cache.
3041 	 */
3042 	KAUTH_GROUPS_LOCK();
3043 	TAILQ_FOREACH(gm, &kauth_groups, gm_link) {
3044 		if ((gm->gm_uid == pcred->cr_gmuid) && (gm->gm_gid == gid) && !kauth_groups_expired(gm)) {
3045 			kauth_groups_lru(gm);
3046 			break;
3047 		}
3048 	}
3049 
3050 	/* did we find a membership entry? */
3051 	if (gm != NULL) {
3052 		*resultp = (gm->gm_flags & KAUTH_GROUP_ISMEMBER) ? 1 : 0;
3053 	}
3054 	KAUTH_GROUPS_UNLOCK();
3055 
3056 	/* if we did, we can return now */
3057 	if (gm != NULL) {
3058 		DTRACE_PROC2(kauth__group__cache__hit, int, pcred->cr_gmuid, int, gid);
3059 		return 0;
3060 	}
3061 
3062 	/* nothing in the cache, need to go to userland */
3063 	bzero(&el, sizeof(el));
3064 	el.el_info_pid = proc_getpid(current_proc());
3065 	el.el_flags = KAUTH_EXTLOOKUP_VALID_UID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP;
3066 	el.el_uid = pcred->cr_gmuid;
3067 	el.el_gid = gid;
3068 	el.el_member_valid = 0;         /* XXX set by resolver? */
3069 
3070 	DTRACE_PROC2(kauth__group__resolver__submitted, int, el.el_uid, int, el.el_gid);
3071 
3072 	error = kauth_resolver_submit(&el, 0ULL);
3073 
3074 	DTRACE_PROC2(kauth__group__resolver__returned, int, error, int, el.el_flags);
3075 
3076 	if (error != 0) {
3077 		return error;
3078 	}
3079 	/* save the results from the lookup */
3080 	kauth_groups_updatecache(&el);
3081 
3082 	/* if we successfully ascertained membership, report */
3083 	if (el.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) {
3084 		*resultp = (el.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) ? 1 : 0;
3085 		return 0;
3086 	}
3087 
3088 	return ENOENT;
3089 #else
3090 	*resultp = 0;
3091 	return 0;
3092 #endif
3093 }
3094 
3095 /*
3096  * kauth_cred_ismember_guid
3097  *
3098  * Description:	Determine whether the supplied credential is a member of the
3099  *		group nominated by GUID.
3100  *
3101  * Parameters:	cred				Credential to check in
3102  *		guidp				Pointer to GUID whose group
3103  *						we are testing for membership
3104  *		resultp				Pointer to int to contain the
3105  *						result of the call
3106  *
3107  * Returns:	0				Success
3108  *	kauth_cred_guid2gid:EINVAL
3109  *	kauth_cred_ismember_gid:ENOENT
3110  *	kauth_resolver_submit:ENOENT		User space daemon did not vend
3111  *						this credential.
3112  *	kauth_cred_ismember_gid:EWOULDBLOCK
3113  *	kauth_cred_ismember_gid:EINTR
3114  *	kauth_cred_ismember_gid:ENOMEM
3115  *	kauth_cred_ismember_gid:???		Unlikely error from user space
3116  *
3117  * Implicit returns:
3118  *		*resultp (modified)	1	Is member
3119  *					0	Is not member
3120  */
3121 int
kauth_cred_ismember_guid(__unused kauth_cred_t cred,guid_t * guidp,int * resultp)3122 kauth_cred_ismember_guid(__unused kauth_cred_t cred, guid_t *guidp, int *resultp)
3123 {
3124 	int error = 0;
3125 
3126 	switch (kauth_wellknown_guid(guidp)) {
3127 	case KAUTH_WKG_NOBODY:
3128 		*resultp = 0;
3129 		break;
3130 	case KAUTH_WKG_EVERYBODY:
3131 		*resultp = 1;
3132 		break;
3133 	default:
3134 	{
3135 		gid_t gid;
3136 #if CONFIG_EXT_RESOLVER
3137 		struct kauth_identity ki;
3138 
3139 		/*
3140 		 * Grovel the identity cache looking for this GUID.
3141 		 * If we find it, and it is for a user record, return
3142 		 * false because it's not a group.
3143 		 *
3144 		 * This is necessary because we don't have -ve caching
3145 		 * of group memberships, and we really want to avoid
3146 		 * calling out to the resolver if at all possible.
3147 		 *
3148 		 * Because we're called by the ACL evaluator, and the
3149 		 * ACL evaluator is likely to encounter ACEs for users,
3150 		 * this is expected to be a common case.
3151 		 */
3152 		ki.ki_valid = 0;
3153 		if ((error = kauth_identity_find_guid(guidp, &ki, NULL)) == 0 &&
3154 		    !kauth_identity_guid_expired(&ki)) {
3155 			if (ki.ki_valid & KI_VALID_GID) {
3156 				/* It's a group after all... */
3157 				gid = ki.ki_gid;
3158 				goto do_check;
3159 			}
3160 			if (ki.ki_valid & KI_VALID_UID) {
3161 				*resultp = 0;
3162 				return 0;
3163 			}
3164 		}
3165 #endif /* CONFIG_EXT_RESOLVER */
3166 		/*
3167 		 * Attempt to translate the GUID to a GID.  Even if
3168 		 * this fails, we will have primed the cache if it is
3169 		 * a user record and we'll see it above the next time
3170 		 * we're asked.
3171 		 */
3172 		if ((error = kauth_cred_guid2gid(guidp, &gid)) != 0) {
3173 			/*
3174 			 * If we have no guid -> gid translation, it's not a group and
3175 			 * thus the cred can't be a member.
3176 			 */
3177 			if (error == ENOENT) {
3178 				*resultp = 0;
3179 				error = 0;
3180 			}
3181 		} else {
3182 #if CONFIG_EXT_RESOLVER
3183 do_check:
3184 #endif /* CONFIG_EXT_RESOLVER */
3185 			error = kauth_cred_ismember_gid(cred, gid, resultp);
3186 		}
3187 	}
3188 	break;
3189 	}
3190 	return error;
3191 }
3192 
3193 /*
3194  * kauth_cred_gid_subset
3195  *
3196  * Description:	Given two credentials, determine if all GIDs associated with
3197  *              the first are also associated with the second
3198  *
3199  * Parameters:	cred1				Credential to check for
3200  *              cred2				Credential to check in
3201  *		resultp				Pointer to int to contain the
3202  *						result of the call
3203  *
3204  * Returns:	0				Success
3205  *		non-zero			See kauth_cred_ismember_gid for
3206  *						error codes
3207  *
3208  * Implicit returns:
3209  *		*resultp (modified)	1	Is subset
3210  *					0	Is not subset
3211  *
3212  * Notes:	This function guarantees not to modify resultp when returning
3213  *		an error.
3214  */
3215 int
kauth_cred_gid_subset(kauth_cred_t cred1,kauth_cred_t cred2,int * resultp)3216 kauth_cred_gid_subset(kauth_cred_t cred1, kauth_cred_t cred2, int *resultp)
3217 {
3218 	int i, err, res = 1;
3219 	gid_t gid;
3220 	posix_cred_t pcred1 = posix_cred_get(cred1);
3221 	posix_cred_t pcred2 = posix_cred_get(cred2);
3222 
3223 	/* First, check the local list of groups */
3224 	for (i = 0; i < pcred1->cr_ngroups; i++) {
3225 		gid = pcred1->cr_groups[i];
3226 		if ((err = kauth_cred_ismember_gid(cred2, gid, &res)) != 0) {
3227 			return err;
3228 		}
3229 
3230 		if (!res && gid != pcred2->cr_rgid && gid != pcred2->cr_svgid) {
3231 			*resultp = 0;
3232 			return 0;
3233 		}
3234 	}
3235 
3236 	/* Check real gid */
3237 	if ((err = kauth_cred_ismember_gid(cred2, pcred1->cr_rgid, &res)) != 0) {
3238 		return err;
3239 	}
3240 
3241 	if (!res && pcred1->cr_rgid != pcred2->cr_rgid &&
3242 	    pcred1->cr_rgid != pcred2->cr_svgid) {
3243 		*resultp = 0;
3244 		return 0;
3245 	}
3246 
3247 	/* Finally, check saved gid */
3248 	if ((err = kauth_cred_ismember_gid(cred2, pcred1->cr_svgid, &res)) != 0) {
3249 		return err;
3250 	}
3251 
3252 	if (!res && pcred1->cr_svgid != pcred2->cr_rgid &&
3253 	    pcred1->cr_svgid != pcred2->cr_svgid) {
3254 		*resultp = 0;
3255 		return 0;
3256 	}
3257 
3258 	*resultp = 1;
3259 	return 0;
3260 }
3261 
3262 
3263 /*
3264  * kauth_cred_issuser
3265  *
3266  * Description:	Fast replacement for issuser()
3267  *
3268  * Parameters:	cred				Credential to check for super
3269  *						user privileges
3270  *
3271  * Returns:	0				Not super user
3272  *		!0				Is super user
3273  *
3274  * Notes:	This function uses a magic number which is not a manifest
3275  *		constant; this is bad practice.
3276  */
3277 int
kauth_cred_issuser(kauth_cred_t cred)3278 kauth_cred_issuser(kauth_cred_t cred)
3279 {
3280 	return kauth_cred_getuid(cred) == 0;
3281 }
3282 
3283 
3284 /*
3285  * Credential KPI
3286  */
3287 
3288 static smrh_key_t   kauth_cred_key(kauth_cred_t cred);
3289 static uint32_t     kauth_cred_key_hash(smrh_key_t key, uint32_t seed);
3290 static bool         kauth_cred_key_equ(smrh_key_t k1, smrh_key_t k2);
3291 static uint32_t     kauth_cred_obj_hash(const struct smrq_slink *, uint32_t seed);
3292 static bool         kauth_cred_obj_equ(const struct smrq_slink *, smrh_key_t);
3293 static bool         kauth_cred_obj_try_get(void *);
3294 
3295 struct ucred_rw {
3296 	os_ref_atomic_t         crw_weak_ref;
3297 	struct ucred           *crw_cred;
3298 	struct smrq_slink       crw_link;
3299 	struct smr_node         crw_node;
3300 };
3301 
3302 #define KAUTH_CRED_REF_MAX 0x0ffffffful
3303 
3304 ZONE_DEFINE_ID(ZONE_ID_KAUTH_CRED, "cred", struct ucred, ZC_READONLY | ZC_ZFREE_CLEARMEM);
3305 static KALLOC_TYPE_DEFINE(ucred_rw_zone, struct ucred_rw, KT_DEFAULT);
3306 os_refgrp_decl(static, ucred_ref_grp, "ucred_rw", NULL);
3307 
3308 SMRH_TRAITS_DEFINE(kauth_cred_traits, struct ucred_rw, crw_link,
3309     .domain      = &smr_proc_task,
3310     .key_hash    = kauth_cred_key_hash,
3311     .key_equ     = kauth_cred_key_equ,
3312     .obj_hash    = kauth_cred_obj_hash,
3313     .obj_equ     = kauth_cred_obj_equ,
3314     .obj_try_get = kauth_cred_obj_try_get);
3315 
3316 static struct smr_shash kauth_cred_hash;
3317 
3318 static inline void
ucred_rw_ref(struct ucred_rw * rw)3319 ucred_rw_ref(struct ucred_rw *rw)
3320 {
3321 	os_ref_retain_raw(&rw->crw_weak_ref, &ucred_ref_grp);
3322 }
3323 
3324 static inline bool
ucred_rw_tryref(struct ucred_rw * rw)3325 ucred_rw_tryref(struct ucred_rw *rw)
3326 {
3327 	return os_ref_retain_try_raw(&rw->crw_weak_ref, &ucred_ref_grp);
3328 }
3329 
3330 static inline os_ref_count_t
ucred_rw_unref(struct ucred_rw * rw)3331 ucred_rw_unref(struct ucred_rw *rw)
3332 {
3333 	return os_ref_release_raw(&rw->crw_weak_ref, &ucred_ref_grp);
3334 }
3335 
3336 static inline void
ucred_rw_unref_live(struct ucred_rw * rw)3337 ucred_rw_unref_live(struct ucred_rw *rw)
3338 {
3339 	os_ref_release_live_raw(&rw->crw_weak_ref, &ucred_ref_grp);
3340 }
3341 
3342 __abortlike
3343 static void
kauth_cred_panic_over_released(kauth_cred_t cred)3344 kauth_cred_panic_over_released(kauth_cred_t cred)
3345 {
3346 	panic("kauth_cred_unref: cred %p over-released", cred);
3347 }
3348 
3349 __abortlike
3350 static void
kauth_cred_panic_over_retain(kauth_cred_t cred)3351 kauth_cred_panic_over_retain(kauth_cred_t cred)
3352 {
3353 	panic("kauth_cred_ref: cred %p over-retained", cred);
3354 }
3355 
3356 static void
kauth_cred_hold(kauth_cred_t cred)3357 kauth_cred_hold(kauth_cred_t cred)
3358 {
3359 	unsigned long ref;
3360 
3361 	ref = zalloc_ro_update_field_atomic(ZONE_ID_KAUTH_CRED,
3362 	    cred, cr_ref, ZRO_ATOMIC_ADD_LONG, 1);
3363 	if (ref >= KAUTH_CRED_REF_MAX) {
3364 		kauth_cred_panic_over_retain(cred);
3365 	}
3366 }
3367 
3368 static void
kauth_cred_drop(kauth_cred_t cred)3369 kauth_cred_drop(kauth_cred_t cred)
3370 {
3371 	unsigned long ref;
3372 
3373 	ref = zalloc_ro_update_field_atomic(ZONE_ID_KAUTH_CRED,
3374 	    cred, cr_ref, ZRO_ATOMIC_ADD_LONG, -1);
3375 	if (__improbable(ref == 0 || ref > KAUTH_CRED_REF_MAX)) {
3376 		kauth_cred_panic_over_released(cred);
3377 	}
3378 }
3379 
3380 /*
3381  * kauth_cred_init
3382  *
3383  * Description:	Initialize the credential hash cache
3384  *
3385  * Parameters:	(void)
3386  *
3387  * Returns:	(void)
3388  *
3389  * Notes:	Intialize the credential hash cache for use; the credential
3390  *		hash cache is used convert duplicate credentials into a
3391  *		single reference counted credential in order to save wired
3392  *		kernel memory.  In practice, this generally means a desktop
3393  *		system runs with a few tens of credentials, instead of one
3394  *		per process, one per thread, one per vnode cache entry, and
3395  *		so on.  This generally results in savings of 200K or more
3396  *		(potentially much more on server systems).
3397  *
3398  *		We also create the kernel and init creds before lockdown
3399  *		so that vfs_context0 and initcred pointers can be made constant.
3400  *
3401  *		We do this in the "ZALLOC" stage because we need
3402  *		the kauth_cred_hash_mtx to be initialized,
3403  *		and to allocate the kernel cred.
3404  */
3405 __startup_func
3406 static void
kauth_cred_init(void)3407 kauth_cred_init(void)
3408 {
3409 	struct posix_cred kernel_cred_template = {
3410 		.cr_ngroups = 1,
3411 		.cr_flags   = CRF_NOMEMBERD,
3412 	};
3413 
3414 	smr_shash_init(&kauth_cred_hash, SMRSH_BALANCED, maxproc / 4);
3415 	vfs_context0.vc_ucred = posix_cred_create(&kernel_cred_template);
3416 }
3417 STARTUP(ZALLOC, STARTUP_RANK_LAST, kauth_cred_init);
3418 
3419 uid_t
kauth_getuid(void)3420 kauth_getuid(void)
3421 {
3422 	return kauth_cred_getuid(kauth_cred_get());
3423 }
3424 
3425 uid_t
kauth_getruid(void)3426 kauth_getruid(void)
3427 {
3428 	return kauth_cred_getruid(kauth_cred_get());
3429 }
3430 
3431 gid_t
kauth_getgid(void)3432 kauth_getgid(void)
3433 {
3434 	return kauth_cred_getgid(kauth_cred_get());
3435 }
3436 
3437 gid_t
kauth_getrgid(void)3438 kauth_getrgid(void)
3439 {
3440 	return kauth_cred_getrgid(kauth_cred_get());
3441 }
3442 
3443 kauth_cred_t
kauth_cred_get(void)3444 kauth_cred_get(void)
3445 {
3446 	return current_thread_ro()->tro_cred;
3447 }
3448 
3449 intptr_t
current_thread_cred_label_get(int slot)3450 current_thread_cred_label_get(int slot)
3451 {
3452 #if CONFIG_MACF
3453 	return mac_label_get(kauth_cred_get()->cr_label, slot);
3454 #else
3455 	return 0;
3456 #endif
3457 }
3458 
3459 __abortlike
3460 static void
current_cached_proc_cred_panic(proc_t p)3461 current_cached_proc_cred_panic(proc_t p)
3462 {
3463 	panic("current_cached_proc_cred(%p) called but current_proc() is %p",
3464 	    p, current_proc());
3465 }
3466 
3467 kauth_cred_t
current_cached_proc_cred(proc_t p)3468 current_cached_proc_cred(proc_t p)
3469 {
3470 	thread_ro_t tro = current_thread_ro();
3471 
3472 	if (tro->tro_proc != p && p != PROC_NULL) {
3473 		current_cached_proc_cred_panic(p);
3474 	}
3475 	return tro->tro_realcred;
3476 }
3477 
3478 intptr_t
current_cached_proc_label_get(int slot)3479 current_cached_proc_label_get(int slot)
3480 {
3481 #if CONFIG_MACF
3482 	return mac_label_get(current_cached_proc_cred(PROC_NULL)->cr_label, slot);
3483 #else
3484 	return 0;
3485 #endif
3486 }
3487 
3488 kauth_cred_t
current_cached_proc_cred_ref(proc_t p)3489 current_cached_proc_cred_ref(proc_t p)
3490 {
3491 	kauth_cred_t cred = current_cached_proc_cred(p);
3492 
3493 	kauth_cred_ref(cred);
3494 	return cred;
3495 }
3496 
3497 __attribute__((noinline))
3498 static void
kauth_cred_thread_update_slow(thread_ro_t tro,proc_t proc)3499 kauth_cred_thread_update_slow(thread_ro_t tro, proc_t proc)
3500 {
3501 	struct ucred *cred = kauth_cred_proc_ref(proc);
3502 	struct thread_ro_creds my_creds = tro->tro_creds;
3503 
3504 	if (my_creds.tro_realcred != cred) {
3505 		if (my_creds.tro_realcred == my_creds.tro_cred) {
3506 			kauth_cred_set(&my_creds.tro_cred, cred);
3507 		}
3508 		kauth_cred_set(&my_creds.tro_realcred, cred);
3509 		zalloc_ro_update_field(ZONE_ID_THREAD_RO,
3510 		    tro, tro_creds, &my_creds);
3511 	}
3512 	kauth_cred_unref(&cred);
3513 }
3514 
3515 /*
3516  * current_cached_proc_cred_update
3517  *
3518  * Notes:	This code is common code called from system call or trap entry
3519  *		in the case that the process thread may have been changed
3520  *		since the last time the thread entered the kernel.
3521  */
3522 __attribute__((always_inline))
3523 void
current_cached_proc_cred_update(void)3524 current_cached_proc_cred_update(void)
3525 {
3526 	thread_ro_t tro  = current_thread_ro();
3527 	proc_t      proc = tro->tro_proc;
3528 
3529 	if (__improbable(tro->tro_task != kernel_task &&
3530 	    tro->tro_realcred != proc_ucred_unsafe(proc))) {
3531 		kauth_cred_thread_update_slow(tro, proc);
3532 	}
3533 }
3534 
3535 kauth_cred_t
kauth_cred_get_with_ref(void)3536 kauth_cred_get_with_ref(void)
3537 {
3538 	struct ucred *ucred = kauth_cred_get();
3539 	kauth_cred_ref(ucred);
3540 	return ucred;
3541 }
3542 
3543 __abortlike
3544 static void
kauth_cred_verify_panic(kauth_cred_t cred,struct ucred_rw * cred_rw)3545 kauth_cred_verify_panic(kauth_cred_t cred, struct ucred_rw *cred_rw)
3546 {
3547 	panic("kauth_cred_t backref mismatch: cred:%p cred->cr_rw:%p "
3548 	    "cred_rw:%p", cred, cred->cr_rw, cred_rw);
3549 }
3550 
3551 __pure2
3552 static struct ucred_rw *
kauth_cred_rw(kauth_cred_t cred)3553 kauth_cred_rw(kauth_cred_t cred)
3554 {
3555 	struct ucred_rw *rw = kauth_cred_require(cred)->cr_rw;
3556 
3557 	if (__improbable(rw->crw_cred != cred)) {
3558 		kauth_cred_verify_panic(cred, rw);
3559 	}
3560 
3561 	return rw;
3562 }
3563 
3564 
3565 kauth_cred_t
kauth_cred_proc_ref(proc_t procp)3566 kauth_cred_proc_ref(proc_t procp)
3567 {
3568 	kauth_cred_t cred;
3569 
3570 	smr_proc_task_enter();
3571 	cred = proc_ucred_smr(procp);
3572 	if (!ucred_rw_tryref(kauth_cred_rw(cred))) {
3573 		cred = NOCRED;
3574 	}
3575 	smr_proc_task_leave();
3576 
3577 	if (__improbable(cred == NOCRED)) {
3578 		proc_ucred_lock(procp);
3579 		cred = proc_ucred_locked(procp);
3580 		kauth_cred_ref(cred);
3581 		proc_ucred_unlock(procp);
3582 	}
3583 	return cred;
3584 }
3585 
3586 static kauth_cred_t
__kauth_cred_proc_ref_for_pidversion_slow(pid_t pid,uint32_t pidvers,bool dovers)3587 __kauth_cred_proc_ref_for_pidversion_slow(pid_t pid, uint32_t pidvers, bool dovers)
3588 {
3589 	kauth_cred_t cred = NOCRED;
3590 	proc_t procp;
3591 
3592 	procp = proc_find(pid);
3593 	if (procp == PROC_NULL) {
3594 		return NOCRED;
3595 	}
3596 
3597 	if (dovers && proc_get_ro(procp)->p_idversion != pidvers) {
3598 		proc_rele(procp);
3599 		return NOCRED;
3600 	}
3601 
3602 	cred = kauth_cred_proc_ref(procp);
3603 	proc_rele(procp);
3604 
3605 	return cred;
3606 }
3607 
3608 static inline kauth_cred_t
__kauth_cred_proc_ref_for_pidversion(pid_t pid,uint32_t pidvers,bool dovers)3609 __kauth_cred_proc_ref_for_pidversion(pid_t pid, uint32_t pidvers, bool dovers)
3610 {
3611 	kauth_cred_t cred = NOCRED;
3612 	struct proc_ro *pro;
3613 	proc_t procp;
3614 	int err;
3615 
3616 	smr_proc_task_enter();
3617 	procp = proc_find_noref_smr(pid);
3618 	if (procp == PROC_NULL) {
3619 		err = ESRCH;
3620 	} else {
3621 		pro = proc_get_ro(procp);
3622 		cred = proc_ucred_smr(procp);
3623 		if (dovers && pro->p_idversion != pidvers) {
3624 			err = ESRCH;
3625 		} else if (!ucred_rw_tryref(kauth_cred_rw(cred))) {
3626 			err = EAGAIN;
3627 		} else {
3628 			err = 0;
3629 		}
3630 	}
3631 	smr_proc_task_leave();
3632 
3633 	if (__probable(err == 0)) {
3634 		return cred;
3635 	}
3636 
3637 	if (err == EAGAIN) {
3638 		return __kauth_cred_proc_ref_for_pidversion_slow(pid, pidvers, dovers);
3639 	}
3640 
3641 	return NOCRED;
3642 }
3643 
3644 kauth_cred_t
kauth_cred_proc_ref_for_pid(pid_t pid)3645 kauth_cred_proc_ref_for_pid(pid_t pid)
3646 {
3647 	return __kauth_cred_proc_ref_for_pidversion(pid, 0, false);
3648 }
3649 
3650 kauth_cred_t
kauth_cred_proc_ref_for_pidversion(pid_t pid,uint32_t pidvers)3651 kauth_cred_proc_ref_for_pidversion(pid_t pid, uint32_t pidvers)
3652 {
3653 	return __kauth_cred_proc_ref_for_pidversion(pid, pidvers, true);
3654 }
3655 
3656 /*
3657  * kauth_cred_alloc
3658  *
3659  * Description: Create a deduplicated credential optionally derived
3660  *              from a parent credential, according to the specified template.
3661  *
3662  * Parameters:  parent_cred                     the parent cred the model is
3663  *                                              derived from (or NOCRED for
3664  *                                              a creation)
3665  *
3666  *              model_cred                      the (mutable) template of the
3667  *                                              cred to add to the hash table.
3668  *
3669  * Returns:     (kauth_thread_t)                The inserted cred, or the
3670  *                                              collision that was found.
3671  */
3672 static kauth_cred_t
kauth_cred_alloc(kauth_cred_t parent_cred,kauth_cred_t model_cred)3673 kauth_cred_alloc(kauth_cred_t parent_cred, kauth_cred_t model_cred)
3674 {
3675 	struct ucred_rw *found_rw;
3676 	struct ucred_rw *new_rw;
3677 	struct ucred *newcred;
3678 
3679 	/*
3680 	 * Step 1: find if there's a duplicate entry
3681 	 */
3682 
3683 	found_rw = smr_shash_get(&kauth_cred_hash, kauth_cred_key(model_cred),
3684 	    &kauth_cred_traits);
3685 
3686 	if (found_rw) {
3687 		/* found a duplicate, free the label if the model owned it */
3688 #if CONFIG_MACF
3689 		if (!parent_cred || model_cred->cr_label != parent_cred->cr_label) {
3690 			mac_cred_label_destroy(model_cred);
3691 		}
3692 #endif
3693 
3694 		/* smr_hash_get() already did a kauth_cred_ro() */
3695 		return found_rw->crw_cred;
3696 	}
3697 
3698 	/*
3699 	 * Step 2: create a fresh new kauth_cred.
3700 	 *
3701 	 *         give it ownership of the label and audit session,
3702 	 *         if it doesn't have it already.
3703 	 */
3704 #if CONFIG_MACF
3705 	if (parent_cred && model_cred->cr_label == parent_cred->cr_label) {
3706 		mac_cred_label_init(model_cred);
3707 		mac_cred_label_associate(parent_cred, model_cred);
3708 	}
3709 	mac_cred_label_seal(model_cred);
3710 #else
3711 	(void)parent_cred;
3712 #endif
3713 	AUDIT_SESSION_REF(model_cred);
3714 
3715 	new_rw = zalloc_flags(ucred_rw_zone, Z_WAITOK | Z_ZERO | Z_NOFAIL);
3716 	os_ref_init_raw(&new_rw->crw_weak_ref, &ucred_ref_grp);
3717 
3718 	model_cred->cr_rw     = new_rw;
3719 	model_cred->cr_unused = NULL;
3720 	model_cred->cr_ref    = 0;
3721 
3722 	newcred = zalloc_ro(ZONE_ID_KAUTH_CRED, Z_WAITOK | Z_ZERO | Z_NOFAIL);
3723 	new_rw->crw_cred = newcred;
3724 
3725 #if HAS_APPLE_PAC
3726 	{
3727 		void *naked_ptr = model_cred->cr_label;
3728 		void *signed_ptr;
3729 		signed_ptr = ptrauth_sign_unauthenticated(naked_ptr,
3730 		    ptrauth_key_process_independent_data,
3731 		    ptrauth_blend_discriminator(&newcred->cr_label,
3732 		    OS_PTRAUTH_DISCRIMINATOR("ucred.cr_label")));
3733 		memcpy((void *)&model_cred->cr_label, &signed_ptr, sizeof(void *));
3734 	}
3735 #endif
3736 
3737 	zalloc_ro_update_elem(ZONE_ID_KAUTH_CRED, newcred, model_cred);
3738 
3739 	/*
3740 	 * Step 3: try to insert in the hash table,
3741 	 *         and deal someone else racing us.
3742 	 */
3743 	found_rw = smr_shash_get_or_insert(&kauth_cred_hash,
3744 	    kauth_cred_key(newcred), &new_rw->crw_link, &kauth_cred_traits);
3745 	if (__probable(!found_rw)) {
3746 		return newcred;
3747 	}
3748 
3749 #if CONFIG_MACF
3750 	mac_cred_label_free(newcred->cr_label);
3751 #endif
3752 	AUDIT_SESSION_UNREF(newcred);
3753 	zfree(ucred_rw_zone, new_rw);
3754 	zfree_ro(ZONE_ID_KAUTH_CRED, newcred);
3755 
3756 	/* smr_shash_get_or_insert() already did a kauth_cred_ro() */
3757 	return found_rw->crw_cred;
3758 }
3759 
3760 kauth_cred_t
kauth_cred_require(kauth_cred_t cred)3761 kauth_cred_require(kauth_cred_t cred)
3762 {
3763 	zone_require_ro(ZONE_ID_KAUTH_CRED, sizeof(struct ucred), cred);
3764 	return cred;
3765 }
3766 
3767 __abortlike
3768 static void
kauth_cred_rw_verify_panic(const struct ucred_rw * cred_rw,kauth_cred_t cred)3769 kauth_cred_rw_verify_panic(const struct ucred_rw *cred_rw, kauth_cred_t cred)
3770 {
3771 	panic("ucred_rw backref mismatch: cred_rw:%p cred_rw->crw_cred:%p "
3772 	    "cred: %p", cred_rw, cred_rw->crw_cred, cred);
3773 }
3774 
3775 __pure2
3776 static kauth_cred_t
kauth_cred_ro(const struct ucred_rw * cred_rw)3777 kauth_cred_ro(const struct ucred_rw *cred_rw)
3778 {
3779 	kauth_cred_t cred = kauth_cred_require(cred_rw->crw_cred);
3780 
3781 	if (__improbable(cred->cr_rw != cred_rw)) {
3782 		kauth_cred_rw_verify_panic(cred_rw, cred);
3783 	}
3784 
3785 	return cred;
3786 }
3787 
3788 __attribute__((noinline))
3789 static void
kauth_cred_free(struct smr_node * node)3790 kauth_cred_free(struct smr_node *node)
3791 {
3792 	struct ucred_rw *rw = __container_of(node, struct ucred_rw, crw_node);
3793 	struct ucred *cred = kauth_cred_ro(rw);
3794 
3795 	if (cred == vfs_context0.vc_ucred) {
3796 		panic("Over-release of the kernel credentials");
3797 	}
3798 	if (os_atomic_load(&cred->cr_ref, relaxed) != 0) {
3799 		panic("%s: freeing credential with active long-term ref", __func__);
3800 	}
3801 
3802 #if CONFIG_MACF
3803 	mac_cred_label_free(cred->cr_label);
3804 #endif
3805 
3806 	zfree(ucred_rw_zone, rw);
3807 	zfree_ro(ZONE_ID_KAUTH_CRED, cred);
3808 }
3809 
3810 __attribute__((noinline))
3811 static void
kauth_cred_retire(struct ucred_rw * rw,struct ucred * cred __unused)3812 kauth_cred_retire(struct ucred_rw *rw, struct ucred *cred __unused)
3813 {
3814 	vm_size_t size = sizeof(struct ucred_rw) +
3815 #if CONFIG_MACF
3816 	    sizeof(struct label) +
3817 #endif
3818 	    sizeof(struct ucred);
3819 
3820 	smr_shash_remove(&kauth_cred_hash, &rw->crw_link, &kauth_cred_traits);
3821 	AUDIT_SESSION_UNREF(cred); /* uses SMR, safe to do immediately */
3822 	smr_call(&smr_proc_task, &rw->crw_node, size, kauth_cred_free);
3823 }
3824 
3825 static kauth_cred_t
posix_cred_create_internal(posix_cred_t pcred,struct au_session audit)3826 posix_cred_create_internal(posix_cred_t pcred, struct au_session audit)
3827 {
3828 	struct ucred model = {
3829 		.cr_posix = *pcred,
3830 		.cr_label = NULL,
3831 		.cr_audit = audit,
3832 	};
3833 	int is_member = 0;
3834 
3835 	if (pcred->cr_ngroups < 1) {
3836 		return NOCRED;
3837 	}
3838 
3839 	if (pcred->cr_flags & CRF_NOMEMBERD) {
3840 		pcred->cr_gmuid = KAUTH_UID_NONE;
3841 	} else {
3842 		/*
3843 		 * If the template credential is not opting out of external
3844 		 * group membership resolution, then we need to check that
3845 		 * the UID we will be using is resolvable by the external
3846 		 * resolver.  If it's not, then we opt it out anyway, since
3847 		 * all future external resolution requests will be failing
3848 		 * anyway, and potentially taking a long time to do it.  We
3849 		 * use gid 0 because we always know it will exist and not
3850 		 * trigger additional lookups. This is OK, because we end up
3851 		 * precatching the information here as a result.
3852 		 */
3853 		if (!kauth_cred_ismember_gid(&model, 0, &is_member)) {
3854 			/*
3855 			 * It's a recognized value; we don't really care about
3856 			 * the answer, so long as it's something the external
3857 			 * resolver could have vended.
3858 			 */
3859 			pcred->cr_gmuid = pcred->cr_uid;
3860 		} else {
3861 			/*
3862 			 * It's not something the external resolver could
3863 			 * have vended, so we don't want to ask it more
3864 			 * questions about the credential in the future. This
3865 			 * speeds up future lookups, as long as the caller
3866 			 * caches results; otherwise, it the same recurring
3867 			 * cost.  Since most credentials are used multiple
3868 			 * times, we still get some performance win from this.
3869 			 */
3870 			pcred->cr_gmuid = KAUTH_UID_NONE;
3871 			pcred->cr_flags |= CRF_NOMEMBERD;
3872 		}
3873 	}
3874 
3875 	mac_cred_label_init(&model);
3876 	return kauth_cred_alloc(NOCRED, &model);
3877 }
3878 
3879 /*
3880  * kauth_cred_create
3881  *
3882  * Description:	Obsolete function that is unfortunately exported,
3883  *              but that no one should use directly.
3884  *
3885  * Parameters:	cred				Template for credential to
3886  *						be created
3887  *
3888  * Returns:	(kauth_cred_t)			The credential that was found
3889  *						in the hash or created
3890  *		NULL				kauth_cred_add() failed, or
3891  *						there was not an egid specified
3892  *
3893  * Notes:	The gmuid is hard-defaulted to the UID specified.  Since we
3894  *		maintain this field, we can't expect callers to know how it
3895  *		needs to be set.  Callers should be prepared for this field
3896  *		to be overwritten.
3897  */
3898 kauth_cred_t
kauth_cred_create(kauth_cred_t cred)3899 kauth_cred_create(kauth_cred_t cred)
3900 {
3901 	return posix_cred_create_internal(&cred->cr_posix, cred->cr_audit);
3902 }
3903 
3904 kauth_cred_t
kauth_cred_derive(kauth_cred_t cred,kauth_cred_derive_t derive_fn)3905 kauth_cred_derive(kauth_cred_t cred, kauth_cred_derive_t derive_fn)
3906 {
3907 	struct ucred model = {
3908 		.cr_posix = cred->cr_posix,
3909 		.cr_label = cred->cr_label,
3910 		.cr_audit = cred->cr_audit,
3911 	};
3912 
3913 	if (derive_fn(cred, &model)) {
3914 		return kauth_cred_alloc(cred, &model);
3915 	}
3916 
3917 	kauth_cred_ref(cred);
3918 	return cred;
3919 }
3920 
3921 
3922 bool
kauth_cred_proc_update(proc_t p,proc_settoken_t action,kauth_cred_derive_t derive_fn)3923 kauth_cred_proc_update(
3924 	proc_t                  p,
3925 	proc_settoken_t         action,
3926 	kauth_cred_derive_t     derive_fn)
3927 {
3928 	kauth_cred_t cur_cred, free_cred, new_cred;
3929 
3930 	cur_cred = kauth_cred_proc_ref(p);
3931 
3932 	for (;;) {
3933 		new_cred = kauth_cred_derive(cur_cred, derive_fn);
3934 		if (new_cred == cur_cred) {
3935 			if (action == PROC_SETTOKEN_ALWAYS) {
3936 				set_security_token(p, cur_cred);
3937 			}
3938 			kauth_cred_unref(&new_cred);
3939 			kauth_cred_unref(&cur_cred);
3940 			return false;
3941 		}
3942 
3943 		proc_ucred_lock(p);
3944 		if (__probable(proc_ucred_locked(p) == cur_cred)) {
3945 			kauth_cred_ref(new_cred);
3946 			kauth_cred_hold(new_cred);
3947 
3948 			zalloc_ro_mut(ZONE_ID_PROC_RO, proc_get_ro(p),
3949 			    offsetof(struct proc_ro, p_ucred),
3950 			    &new_cred, sizeof(struct ucred *));
3951 
3952 			kauth_cred_drop(cur_cred);
3953 			ucred_rw_unref_live(cur_cred->cr_rw);
3954 
3955 			proc_update_creds_onproc(p, new_cred);
3956 			proc_ucred_unlock(p);
3957 
3958 			if (action == PROC_SETTOKEN_SETUGID) {
3959 				OSBitOrAtomic(P_SUGID, &p->p_flag);
3960 			}
3961 			if (action != PROC_SETTOKEN_NONE) {
3962 				set_security_token(p, new_cred);
3963 			}
3964 
3965 			kauth_cred_unref(&new_cred);
3966 			kauth_cred_unref(&cur_cred);
3967 			return true;
3968 		}
3969 
3970 		free_cred = cur_cred;
3971 		cur_cred = proc_ucred_locked(p);
3972 		kauth_cred_ref(cur_cred);
3973 		proc_ucred_unlock(p);
3974 
3975 		kauth_cred_unref(&free_cred);
3976 		kauth_cred_unref(&new_cred);
3977 	}
3978 }
3979 
3980 
3981 /*
3982  * kauth_cred_model_setresuid
3983  *
3984  * Description:	Update the given credential using the UID arguments.  The given
3985  *		UIDs are used to set the effective UID, real UID, saved UID,
3986  *		and GMUID (used for group membership checking).
3987  *
3988  * Parameters:	model				The model credential
3989  *		ruid				The new real UID
3990  *		euid				The new effective UID
3991  *		svuid				The new saved UID
3992  *		gmuid				KAUTH_UID_NONE -or- the new
3993  *						group membership UID
3994  *
3995  * Returns:	(kauth_cred_t)			The updated credential
3996  *
3997  * Note:	gmuid is different in that a KAUTH_UID_NONE is a valid
3998  *		setting, so if you don't want it to change, pass it the
3999  *		previous value, explicitly.
4000  */
4001 bool
kauth_cred_model_setresuid(kauth_cred_t model,uid_t ruid,uid_t euid,uid_t svuid,uid_t gmuid)4002 kauth_cred_model_setresuid(
4003 	kauth_cred_t            model,
4004 	uid_t                   ruid,
4005 	uid_t                   euid,
4006 	uid_t                   svuid,
4007 	uid_t                   gmuid)
4008 {
4009 	posix_cred_t pcred = posix_cred_get(model);
4010 	bool updated = false;
4011 
4012 	/*
4013 	 * We don't need to do anything if the UIDs we are changing are
4014 	 * already the same as the UIDs passed in
4015 	 */
4016 	if (euid != KAUTH_UID_NONE && pcred->cr_uid != euid) {
4017 		pcred->cr_uid = euid;
4018 		updated = true;
4019 	}
4020 
4021 	if (ruid != KAUTH_UID_NONE && pcred->cr_ruid != ruid) {
4022 		pcred->cr_ruid = ruid;
4023 		updated = true;
4024 	}
4025 
4026 	if (svuid != KAUTH_UID_NONE && pcred->cr_svuid != svuid) {
4027 		pcred->cr_svuid = svuid;
4028 		updated = true;
4029 	}
4030 
4031 	if (pcred->cr_gmuid != gmuid) {
4032 		/*
4033 		 * If we are setting the gmuid to KAUTH_UID_NONE, then we want
4034 		 * to opt out of participation in external group resolution,
4035 		 * unless we explicitly opt back in later.
4036 		 */
4037 		pcred->cr_gmuid = gmuid;
4038 		if (gmuid == KAUTH_UID_NONE) {
4039 			pcred->cr_flags |= CRF_NOMEMBERD;
4040 		}
4041 		updated = true;
4042 	}
4043 
4044 	return updated;
4045 }
4046 
4047 
4048 /*
4049  * kauth_cred_model_setresgid
4050  *
4051  * Description:	Update the given credential using the GID arguments.  The given
4052  *		GIDs are used to set the effective GID, real GID, and saved
4053  *		GID.
4054  *
4055  * Parameters:	model				The model credential
4056  *		rgid				The new real GID
4057  *		egid				The new effective GID
4058  *		svgid				The new saved GID
4059  *
4060  * Returns:	(kauth_cred_t)			The updated credential
4061  */
4062 bool
kauth_cred_model_setresgid(kauth_cred_t model,gid_t rgid,gid_t egid,gid_t svgid)4063 kauth_cred_model_setresgid(
4064 	kauth_cred_t            model,
4065 	gid_t                   rgid,
4066 	gid_t                   egid,
4067 	gid_t                   svgid)
4068 {
4069 	posix_cred_t pcred = posix_cred_get(model);
4070 	bool updated = false;
4071 
4072 	if (egid != KAUTH_GID_NONE && pcred->cr_gid != egid) {
4073 		if (kauth_cred_change_egid(model, egid)) {
4074 			pcred->cr_flags |= CRF_NOMEMBERD;
4075 			pcred->cr_gmuid = KAUTH_UID_NONE;
4076 		}
4077 		updated = true;
4078 	}
4079 
4080 	if (rgid != KAUTH_GID_NONE && pcred->cr_rgid != rgid) {
4081 		pcred->cr_rgid = rgid;
4082 		updated = true;
4083 	}
4084 	if (svgid != KAUTH_GID_NONE && pcred->cr_svgid != svgid) {
4085 		pcred->cr_svgid = svgid;
4086 		updated = true;
4087 	}
4088 
4089 	return updated;
4090 }
4091 
4092 
4093 /*
4094  * Update the given credential with the given groups.  We only allocate a new
4095  *	credential when the given gid actually results in changes to the existing
4096  *	credential.
4097  *	The gmuid argument supplies a new uid (or KAUTH_UID_NONE to opt out)
4098  *	which will be used for group membership checking.
4099  */
4100 /*
4101  * kauth_cred_model_setgroups
4102  *
4103  * Description:	Update the given credential using the provide supplementary
4104  *		group list and group membership UID
4105  *
4106  * Parameters:	cred				The model credential
4107  *		groups				Pointer to gid_t array which
4108  *						contains the new group list
4109  *		groupcount			The count of valid groups which
4110  *						are contained in 'groups'
4111  *		gmuid				KAUTH_UID_NONE -or- the new
4112  *						group membership UID
4113  *
4114  * Returns:	(kauth_cred_t)			The updated credential
4115  *
4116  * Note:	gmuid is different in that a KAUTH_UID_NONE is a valid
4117  *		setting, so if you don't want it to change, pass it the
4118  *		previous value, explicitly.
4119  *
4120  * XXX:		Changes are determined in ordinal order - if the caller passes
4121  *		in the same groups list that is already present in the
4122  *		credential, but the members are in a different order, even if
4123  *		the EGID is not modified (i.e. cr_groups[0] is the same), it
4124  *		is considered a modification to the credential, and a new
4125  *		credential is created.
4126  *
4127  *		This should perhaps be better optimized, but it is considered
4128  *		to be the caller's problem.
4129  */
4130 bool
kauth_cred_model_setgroups(kauth_cred_t model,gid_t * groups,size_t groupcount,uid_t gmuid)4131 kauth_cred_model_setgroups(
4132 	kauth_cred_t            model,
4133 	gid_t                  *groups,
4134 	size_t                  groupcount,
4135 	uid_t                   gmuid)
4136 {
4137 	posix_cred_t pcred = posix_cred_get(model);
4138 
4139 	assert(groupcount <= NGROUPS);
4140 	groupcount = MIN(groupcount, NGROUPS);
4141 
4142 	/*
4143 	 * We don't need to do anything if the given list of groups does not
4144 	 * change.
4145 	 */
4146 	if (pcred->cr_gmuid == gmuid &&
4147 	    pcred->cr_ngroups == groupcount &&
4148 	    memcmp(pcred->cr_groups, groups, groupcount * sizeof(gid_t)) == 0) {
4149 		return false;
4150 	}
4151 
4152 	pcred->cr_gmuid = gmuid;
4153 	pcred->cr_ngroups = (short)groupcount;
4154 	memcpy(pcred->cr_groups, groups, groupcount * sizeof(gid_t));
4155 	if (gmuid == KAUTH_UID_NONE) {
4156 		pcred->cr_flags |= CRF_NOMEMBERD;
4157 	} else {
4158 		pcred->cr_flags &= ~CRF_NOMEMBERD;
4159 	}
4160 	return true;
4161 }
4162 
4163 /*
4164  * Notes:	The return value exists to account for the possibility of a
4165  *		kauth_cred_t without a POSIX label.  This will be the case in
4166  *		the future (see posix_cred_get() below, for more details).
4167  */
4168 #if CONFIG_EXT_RESOLVER
4169 int kauth_external_supplementary_groups_supported = 1;
4170 
4171 SYSCTL_INT(_kern, OID_AUTO, ds_supgroups_supported, CTLFLAG_RW | CTLFLAG_LOCKED, &kauth_external_supplementary_groups_supported, 0, "");
4172 #endif
4173 
4174 int
kauth_cred_getgroups(kauth_cred_t cred,gid_t * grouplist,size_t * countp)4175 kauth_cred_getgroups(kauth_cred_t cred, gid_t *grouplist, size_t *countp)
4176 {
4177 	size_t limit = NGROUPS;
4178 	posix_cred_t pcred;
4179 
4180 	if (cred == NULL) {
4181 		KAUTH_DEBUG("kauth_cred_getgroups got NULL credential");
4182 		return EINVAL;
4183 	}
4184 
4185 	if (grouplist == NULL) {
4186 		KAUTH_DEBUG("kauth_cred_getgroups got NULL group list");
4187 		return EINVAL;
4188 	}
4189 
4190 	pcred = posix_cred_get(cred);
4191 
4192 #if CONFIG_EXT_RESOLVER
4193 	/*
4194 	 * If we've not opted out of using the resolver, then convert the cred to a list
4195 	 * of supplemental groups. We do this only if there has been a resolver to talk to,
4196 	 * since we may be too early in boot, or in an environment that isn't using DS.
4197 	 */
4198 	if (kauth_identitysvc_has_registered && kauth_external_supplementary_groups_supported && (pcred->cr_flags & CRF_NOMEMBERD) == 0) {
4199 		uid_t uid = kauth_cred_getuid(cred);
4200 		int err;
4201 
4202 		err = kauth_cred_uid2groups(&uid, grouplist, countp);
4203 		if (!err) {
4204 			return 0;
4205 		}
4206 
4207 		/* On error just fall through */
4208 		KAUTH_DEBUG("kauth_cred_getgroups failed %d\n", err);
4209 	}
4210 #endif /* CONFIG_EXT_RESOLVER */
4211 
4212 	/*
4213 	 * If they just want a copy of the groups list, they may not care
4214 	 * about the actual count.  If they specify an input count, however,
4215 	 * treat it as an indicator of the buffer size available in grouplist,
4216 	 * and limit the returned list to that size.
4217 	 */
4218 	if (countp) {
4219 		limit = MIN(*countp, pcred->cr_ngroups);
4220 		*countp = limit;
4221 	}
4222 
4223 	memcpy(grouplist, pcred->cr_groups, sizeof(gid_t) * limit);
4224 
4225 	return 0;
4226 }
4227 
4228 
4229 /*
4230  * kauth_cred_model_setuidgid
4231  *
4232  * Description:	Update the given credential using the UID and GID arguments.
4233  *		The given UID is used to set the effective UID, real UID, and
4234  *		saved UID.  The given GID is used to set the effective GID,
4235  *		real GID, and saved GID.
4236  *
4237  * Parameters:	model				The model credential
4238  *		uid				The new UID to use
4239  *		gid				The new GID to use
4240  *
4241  * Returns:	(kauth_cred_t)			The updated credential
4242  *
4243  * Notes:	We set the gmuid to uid if the credential we are inheriting
4244  *		from has not opted out of memberd participation; otherwise
4245  *		we set it to KAUTH_UID_NONE
4246  *
4247  *		This code is only ever called from the per-thread credential
4248  *		code path in the "set per thread credential" case; and in
4249  *		posix_spawn() in the case that the POSIX_SPAWN_RESETIDS
4250  *		flag is set.
4251  */
4252 bool
kauth_cred_model_setuidgid(kauth_cred_t model,uid_t uid,gid_t gid)4253 kauth_cred_model_setuidgid(kauth_cred_t model, uid_t uid, gid_t gid)
4254 {
4255 	struct posix_cred pcred = {
4256 		.cr_uid     = uid,
4257 		.cr_ruid    = uid,
4258 		.cr_svuid   = uid,
4259 
4260 		.cr_ngroups = 1,
4261 		.cr_gid     = gid,
4262 		.cr_rgid    = gid,
4263 		.cr_svgid   = gid,
4264 
4265 		.cr_flags   = model->cr_posix.cr_flags,
4266 	};
4267 
4268 	/* inherit the opt-out of memberd */
4269 	if (pcred.cr_flags & CRF_NOMEMBERD) {
4270 		pcred.cr_gmuid = KAUTH_UID_NONE;
4271 	} else {
4272 		pcred.cr_gmuid = uid;
4273 	}
4274 
4275 	if (memcmp(&model->cr_posix, &pcred, sizeof(struct posix_cred)) != 0) {
4276 		model->cr_posix = pcred;
4277 		return true;
4278 	}
4279 
4280 	return false;
4281 }
4282 
4283 
4284 /*
4285  * kauth_cred_model_setauditinfo
4286  *
4287  * Description:	Update the given credential using the given au_session_t.
4288  *
4289  * Parameters:	model				The model credential
4290  *		auditinfo_p			Pointer to ne audit information
4291  *
4292  * Returns:	(kauth_cred_t)			The updated credential
4293  */
4294 bool
kauth_cred_model_setauditinfo(kauth_cred_t model,au_session_t * auditinfo_p)4295 kauth_cred_model_setauditinfo(kauth_cred_t model, au_session_t *auditinfo_p)
4296 {
4297 	if (memcmp(&model->cr_audit, auditinfo_p, sizeof(model->cr_audit)) != 0) {
4298 		model->cr_audit = *auditinfo_p;
4299 		return true;
4300 	}
4301 
4302 
4303 	return false;
4304 }
4305 
4306 #if CONFIG_MACF
4307 kauth_cred_t
kauth_cred_label_update(kauth_cred_t cred,struct label * label)4308 kauth_cred_label_update(kauth_cred_t cred, struct label *label)
4309 {
4310 	kauth_cred_t new_cred;
4311 
4312 	new_cred = kauth_cred_derive(cred,
4313 	    ^bool (kauth_cred_t parent, kauth_cred_t model) {
4314 		mac_cred_label_init(model);
4315 		mac_cred_label_associate(parent, model);
4316 		mac_cred_label_update(model, label);
4317 		return true;
4318 	});
4319 
4320 	kauth_cred_unref(&cred);
4321 	return new_cred;
4322 }
4323 
4324 int
kauth_proc_label_update(struct proc * p,struct label * label)4325 kauth_proc_label_update(struct proc *p, struct label *label)
4326 {
4327 	kauth_cred_proc_update(p, PROC_SETTOKEN_NONE,
4328 	    ^bool (kauth_cred_t parent, kauth_cred_t model) {
4329 		mac_cred_label_init(model);
4330 		mac_cred_label_associate(parent, model);
4331 		mac_cred_label_update(model, label);
4332 		return true;
4333 	});
4334 	return 0;
4335 }
4336 
4337 /*
4338  *  kauth_proc_label_update_execve
4339  *
4340  * Description: Update the label inside the credential associated with the
4341  *		process as part of a transitioning execve.  The label will
4342  *		be updated by the policies as part of this processing, not
4343  *		provided up front.
4344  *
4345  * Parameters:	p			The process to modify
4346  *		ctx			The context of the exec
4347  *		vp			The vnode being exec'ed
4348  *		scriptl			The script MAC label
4349  *		execl			The executable MAC label
4350  *		lupdateerror	The error place holder for MAC label authority
4351  *						to update about possible termination
4352  *
4353  * Returns:	0			Label update did not make credential
4354  *					disjoint
4355  *		1			Label update caused credential to be
4356  *					disjoint
4357  *
4358  * Notes:	The credential associated with the process WILL change as a
4359  *		result of this call.  The caller should not assume the process
4360  *		reference to the old credential still exists.
4361  */
4362 
4363 void
kauth_proc_label_update_execve(struct proc * p,vfs_context_t ctx,struct vnode * vp,off_t offset,struct vnode * scriptvp,struct label * scriptl,struct label * execl,unsigned int * csflags,void * macextensions,int * disjoint,int * update_return)4364 kauth_proc_label_update_execve(struct proc *p, vfs_context_t ctx,
4365     struct vnode *vp, off_t offset, struct vnode *scriptvp, struct label *scriptl,
4366     struct label *execl, unsigned int *csflags, void *macextensions, int *disjoint, int *update_return)
4367 {
4368 	kauth_cred_proc_update(p, PROC_SETTOKEN_NONE,
4369 	    ^bool (kauth_cred_t parent, kauth_cred_t model) {
4370 		mac_cred_label_init(model);
4371 		mac_cred_label_associate(parent, model);
4372 		mac_cred_label_update_execve(ctx, model,
4373 		vp, offset, scriptvp, scriptl, execl, csflags,
4374 		macextensions, disjoint, update_return);
4375 		return true;
4376 	});
4377 }
4378 #else
4379 kauth_cred_t
kauth_cred_label_update(__unused kauth_cred_t cred,__unused struct label * label)4380 kauth_cred_label_update(__unused kauth_cred_t cred, __unused struct label *label)
4381 {
4382 	return NULL;
4383 }
4384 
4385 int
kauth_proc_label_update(__unused struct proc * p,__unused struct label * label)4386 kauth_proc_label_update(__unused struct proc *p, __unused struct label *label)
4387 {
4388 	return 0;
4389 }
4390 #endif
4391 
4392 
4393 void
kauth_cred_ref(kauth_cred_t cred)4394 kauth_cred_ref(kauth_cred_t cred)
4395 {
4396 	ucred_rw_ref(kauth_cred_rw(cred));
4397 }
4398 
4399 void
4400 (kauth_cred_unref)(kauth_cred_t * credp)
4401 {
4402 	struct ucred    *cred = *credp;
4403 	struct ucred_rw *rw   = kauth_cred_rw(cred);
4404 
4405 	*credp = NOCRED;
4406 
4407 	if (ucred_rw_unref(rw) == 0) {
4408 		kauth_cred_retire(rw, cred);
4409 	}
4410 }
4411 
4412 /*
4413  * kauth_cred_set
4414  *
4415  * Description:	Store a long-term credential reference to a credential pointer,
4416  *		dropping the long-term reference on any previous credential held
4417  *		at the address.
4418  *
4419  * Parameters:	credp				Pointer to the credential
4420  *						storage field.  If *credp points
4421  *						to a valid credential before
4422  *						this call, its long-term
4423  *						reference will be dropped.
4424  *		new_cred			The new credential to take a
4425  *						long-term reference to and
4426  *						assign to *credp.  May be
4427  *						NOCRED.
4428  *
4429  * Returns:	(void)
4430  *
4431  * Notes:	Taking/dropping a long-term reference is costly in terms of
4432  *		performance.
4433  */
4434 void
4435 (kauth_cred_set)(kauth_cred_t * credp, kauth_cred_t new_cred)
4436 {
4437 	kauth_cred_t old_cred = *credp;
4438 
4439 	if (old_cred != new_cred) {
4440 		if (IS_VALID_CRED(new_cred)) {
4441 			kauth_cred_ref(new_cred);
4442 			kauth_cred_hold(new_cred);
4443 		}
4444 
4445 		*credp = new_cred;
4446 
4447 		if (IS_VALID_CRED(old_cred)) {
4448 			kauth_cred_drop(old_cred);
4449 			kauth_cred_unref(&old_cred);
4450 		}
4451 	}
4452 }
4453 
4454 /*
4455  * kauth_cred_copy_real
4456  *
4457  * Description:	Returns a credential based on the passed credential but which
4458  *		reflects the real rather than effective UID and GID.
4459  *
4460  * Parameters:	cred				The credential from which to
4461  *						derive the new credential
4462  *
4463  * Returns:	(kauth_cred_t)			The copied credential
4464  *
4465  * IMPORTANT:	This function DOES NOT utilize kauth_cred_update(); as a
4466  *		result, the caller is responsible for dropping BOTH the
4467  *		additional reference on the passed cred (if any), and the
4468  *		credential returned by this function.  The drop should be
4469  *		via the kauth_cred_unref() KPI.
4470  */
4471 kauth_cred_t
kauth_cred_copy_real(kauth_cred_t cred)4472 kauth_cred_copy_real(kauth_cred_t cred)
4473 {
4474 	kauth_cred_derive_t fn = ^bool (kauth_cred_t parent __unused, kauth_cred_t model) {
4475 		posix_cred_t pcred = posix_cred_get(model);
4476 
4477 		/* if the credential is already 'real', just take a reference */
4478 		if ((pcred->cr_ruid == pcred->cr_uid) &&
4479 		    (pcred->cr_rgid == pcred->cr_gid)) {
4480 			return false;
4481 		}
4482 
4483 		pcred->cr_uid = pcred->cr_ruid;
4484 		/* displacing a supplementary group opts us out of memberd */
4485 		if (kauth_cred_change_egid(model, pcred->cr_rgid)) {
4486 			pcred->cr_flags |= CRF_NOMEMBERD;
4487 			pcred->cr_gmuid = KAUTH_UID_NONE;
4488 		}
4489 		/*
4490 		 * If the cred is not opted out, make sure we are using the r/euid
4491 		 * for group checks
4492 		 */
4493 		if (pcred->cr_gmuid != KAUTH_UID_NONE) {
4494 			pcred->cr_gmuid = pcred->cr_ruid;
4495 		}
4496 		return true;
4497 	};
4498 
4499 	return kauth_cred_derive(cred, fn);
4500 }
4501 
4502 /*
4503  * Hash table traits methods
4504  */
4505 static smrh_key_t
kauth_cred_key(kauth_cred_t cred)4506 kauth_cred_key(kauth_cred_t cred)
4507 {
4508 	return (smrh_key_t){ .smrk_opaque = cred };
4509 }
4510 
4511 static uint32_t
kauth_cred_ro_hash(const struct ucred * cred,uint32_t seed)4512 kauth_cred_ro_hash(const struct ucred *cred, uint32_t seed)
4513 {
4514 	uint32_t hash = seed;
4515 
4516 	hash = os_hash_jenkins_update(&cred->cr_posix,
4517 	    sizeof(struct posix_cred), hash);
4518 	hash = os_hash_jenkins_update(&cred->cr_audit,
4519 	    sizeof(struct au_session), hash);
4520 #if CONFIG_MACF
4521 	if (cred->cr_posix.cr_flags & CRF_MAC_ENFORCE) {
4522 		hash = mac_cred_label_hash_update(cred->cr_label, hash);
4523 	}
4524 #endif /* CONFIG_MACF */
4525 
4526 	return hash;
4527 }
4528 static uint32_t
kauth_cred_key_hash(smrh_key_t key,uint32_t seed)4529 kauth_cred_key_hash(smrh_key_t key, uint32_t seed)
4530 {
4531 	return kauth_cred_ro_hash(key.smrk_opaque, seed);
4532 }
4533 static uint32_t
kauth_cred_obj_hash(const struct smrq_slink * link,uint32_t seed)4534 kauth_cred_obj_hash(const struct smrq_slink *link, uint32_t seed)
4535 {
4536 	const struct ucred_rw *rw;
4537 
4538 	rw = __container_of(link, struct ucred_rw, crw_link);
4539 	/* this is used during rehash, re-auth the objects as we do */
4540 	return kauth_cred_ro_hash(kauth_cred_ro(rw), seed);
4541 }
4542 
4543 static bool
kauth_cred_key_equ(smrh_key_t k1,smrh_key_t k2)4544 kauth_cred_key_equ(smrh_key_t k1, smrh_key_t k2)
4545 {
4546 	const struct ucred *cred1 = k1.smrk_opaque;
4547 	const struct ucred *cred2 = k2.smrk_opaque;
4548 	const struct posix_cred *pcred1 = &cred1->cr_posix;
4549 	const struct posix_cred *pcred2 = &cred2->cr_posix;
4550 
4551 	/*
4552 	 * don't worry about the label unless the flags in
4553 	 * either credential tell us to.
4554 	 */
4555 	if (memcmp(pcred1, pcred2, sizeof(*pcred1))) {
4556 		return false;
4557 	}
4558 	if (memcmp(&cred1->cr_audit, &cred2->cr_audit, sizeof(cred1->cr_audit))) {
4559 		return false;
4560 	}
4561 #if CONFIG_MACF
4562 	/* Note: we know the flags are equal, so we only need to test one */
4563 	if (pcred1->cr_flags & CRF_MAC_ENFORCE) {
4564 		if (!mac_cred_label_is_equal(cred1->cr_label, cred2->cr_label)) {
4565 			return false;
4566 		}
4567 	}
4568 #endif
4569 	return true;
4570 }
4571 static bool
kauth_cred_obj_equ(const struct smrq_slink * link,smrh_key_t key)4572 kauth_cred_obj_equ(const struct smrq_slink *link, smrh_key_t key)
4573 {
4574 	const struct ucred_rw *rw;
4575 
4576 	rw = __container_of(link, struct ucred_rw, crw_link);
4577 	/* only do the kauth_cred_ro() check in try_get() */
4578 	return kauth_cred_key_equ(kauth_cred_key(rw->crw_cred), key);
4579 }
4580 
4581 static bool
kauth_cred_obj_try_get(void * obj)4582 kauth_cred_obj_try_get(void *obj)
4583 {
4584 	struct ucred_rw *rw = obj;
4585 	kauth_cred_t cred = kauth_cred_require(rw->crw_cred);
4586 
4587 	if (__improbable(cred->cr_rw != rw)) {
4588 		kauth_cred_rw_verify_panic(rw, cred);
4589 	}
4590 
4591 	return ucred_rw_tryref(rw);
4592 }
4593 
4594 /*
4595  **********************************************************************
4596  * The following routines will be moved to a policy_posix.c module at
4597  * some future point.
4598  **********************************************************************
4599  */
4600 
4601 /*
4602  * posix_cred_create
4603  *
4604  * Description:	Helper function to create a kauth_cred_t credential that is
4605  *		initally labelled with a specific POSIX credential label
4606  *
4607  * Parameters:	pcred			The posix_cred_t to use as the initial
4608  *					label value
4609  *
4610  * Returns:	(kauth_cred_t)		The credential that was found in the
4611  *					hash or creates
4612  *		NULL			kauth_cred_make() failed, or there was
4613  *		                        no egid specified, or we failed to
4614  *					attach a label to the new credential
4615  *
4616  * Notes:	The gmuid is hard-defaulted to the UID specified.  Since we
4617  *		maintain this field, we can't expect callers to know how it
4618  *		needs to be set.  Callers should be prepared for this field
4619  *		to be overwritten.
4620  */
4621 kauth_cred_t
posix_cred_create(posix_cred_t pcred)4622 posix_cred_create(posix_cred_t pcred)
4623 {
4624 	struct au_session audit = {
4625 		.as_aia_p = audit_default_aia_p,
4626 	};
4627 
4628 	return posix_cred_create_internal(pcred, audit);
4629 }
4630 
4631 
4632 /*
4633  * posix_cred_get
4634  *
4635  * Description:	Given a kauth_cred_t, return the POSIX credential label, if
4636  *		any, which is associated with it.
4637  *
4638  * Parameters:	cred			The credential to obtain the label from
4639  *
4640  * Returns:	posix_cred_t		The POSIX credential label
4641  *
4642  * Notes:	In the event that the policy_posix MACF module IS NOT loaded,
4643  *		this function will return a pointer to a posix_cred_t which
4644  *		GRANTS all access (effectively, a "root" credential).  This is
4645  *		necessary to support legacy code which insists on tightly
4646  *		integrating POSIX credentials into its APIs, including, but
4647  *		not limited to, System V IPC mechanisms, POSIX IPC mechanisms,
4648  *		NFSv3, signals, dtrace, and a large number of kauth routines
4649  *		used to implement POSIX permissions related system calls.
4650  *
4651  *		In the event that the policy_posix MACF module IS loaded, and
4652  *		there is no POSIX label on the kauth_cred_t credential, this
4653  *		function will return a pointer to a posix_cred_t which DENIES
4654  *		all access (effectively, a "deny rights granted by POSIX"
4655  *		credential).  This is necessary to support the concept of a
4656  *		transiently loaded POSIX policy, or kauth_cred_t credentials
4657  *		which can not be used in conjunctions with POSIX permissions
4658  *		checks.
4659  *
4660  *		This function currently returns the address of the cr_posix
4661  *		field of the supplied kauth_cred_t credential, and as such
4662  *		currently can not fail.  In the future, this will not be the
4663  *		case.
4664  */
4665 posix_cred_t
posix_cred_get(kauth_cred_t cred)4666 posix_cred_get(kauth_cred_t cred)
4667 {
4668 	return &cred->cr_posix;
4669 }
4670 
4671 
4672 /*
4673  * posix_cred_access
4674  *
4675  * Description:	Perform a POSIX access check for a protected object
4676  *
4677  * Parameters:	cred			The credential to check
4678  *		object_uid		The POSIX UID of the protected object
4679  *		object_gid		The POSIX GID of the protected object
4680  *		object_mode		The POSIX mode of the protected object
4681  *		mode_req		The requested POSIX access rights
4682  *
4683  * Returns	0			Access is granted
4684  *		EACCES			Access is denied
4685  *
4686  * Notes:	This code optimizes the case where the world and group rights
4687  *		would both grant the requested rights to avoid making a group
4688  *		membership query.  This is a big performance win in the case
4689  *		where this is true.
4690  */
4691 int
posix_cred_access(kauth_cred_t cred,id_t object_uid,id_t object_gid,mode_t object_mode,mode_t mode_req)4692 posix_cred_access(kauth_cred_t cred, id_t object_uid, id_t object_gid, mode_t object_mode, mode_t mode_req)
4693 {
4694 	int is_member;
4695 	mode_t mode_owner = (object_mode & S_IRWXU);
4696 	mode_t mode_group = (mode_t)((object_mode & S_IRWXG) << 3);
4697 	mode_t mode_world = (mode_t)((object_mode & S_IRWXO) << 6);
4698 
4699 	/*
4700 	 * Check first for owner rights
4701 	 */
4702 	if (kauth_cred_getuid(cred) == object_uid && (mode_req & mode_owner) == mode_req) {
4703 		return 0;
4704 	}
4705 
4706 	/*
4707 	 * Combined group and world rights check, if we don't have owner rights
4708 	 *
4709 	 * OPTIMIZED: If group and world rights would grant the same bits, and
4710 	 * they set of requested bits is in both, then we can simply check the
4711 	 * world rights, avoiding a group membership check, which is expensive.
4712 	 */
4713 	if ((mode_req & mode_group & mode_world) == mode_req) {
4714 		return 0;
4715 	} else {
4716 		/*
4717 		 * NON-OPTIMIZED: requires group membership check.
4718 		 */
4719 		if ((mode_req & mode_group) != mode_req) {
4720 			/*
4721 			 * exclusion group : treat errors as "is a member"
4722 			 *
4723 			 * NON-OPTIMIZED: +group would deny; must check group
4724 			 */
4725 			if (!kauth_cred_ismember_gid(cred, object_gid, &is_member) && is_member) {
4726 				/*
4727 				 * DENY: +group denies
4728 				 */
4729 				return EACCES;
4730 			} else {
4731 				if ((mode_req & mode_world) != mode_req) {
4732 					/*
4733 					 * DENY: both -group & world would deny
4734 					 */
4735 					return EACCES;
4736 				} else {
4737 					/*
4738 					 * ALLOW: allowed by -group and +world
4739 					 */
4740 					return 0;
4741 				}
4742 			}
4743 		} else {
4744 			/*
4745 			 * inclusion group; treat errors as "not a member"
4746 			 *
4747 			 * NON-OPTIMIZED: +group allows, world denies; must
4748 			 * check group
4749 			 */
4750 			if (!kauth_cred_ismember_gid(cred, object_gid, &is_member) && is_member) {
4751 				/*
4752 				 * ALLOW: allowed by +group
4753 				 */
4754 				return 0;
4755 			} else {
4756 				if ((mode_req & mode_world) != mode_req) {
4757 					/*
4758 					 * DENY: both -group & world would deny
4759 					 */
4760 					return EACCES;
4761 				} else {
4762 					/*
4763 					 * ALLOW: allowed by -group and +world
4764 					 */
4765 					return 0;
4766 				}
4767 			}
4768 		}
4769 	}
4770 }
4771