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