1/*
2 * Copyright (c) 2004-2011 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#include <mach/host_security.h>
60
61#include <libkern/OSAtomic.h>
62
63#include <kern/task.h>
64#include <kern/lock.h>
65#ifdef MACH_ASSERT
66# undef MACH_ASSERT
67#endif
68#define MACH_ASSERT 1	/* XXX so bogus */
69#include <kern/assert.h>
70
71#if CONFIG_MACF
72#include <security/mac.h>
73#include <security/mac_framework.h>
74#include <security/_label.h>
75#endif
76
77void mach_kauth_cred_uthread_update( void );
78
79#define CRED_DIAGNOSTIC 0
80
81# define NULLCRED_CHECK(_c)	do {if (!IS_VALID_CRED(_c)) panic("%s: bad credential %p", __FUNCTION__,_c);} while(0)
82
83/*
84 * Credential debugging; we can track entry into a function that might
85 * change a credential, and we can track actual credential changes that
86 * result.
87 *
88 * Note:	Does *NOT* currently include per-thread credential changes
89 */
90
91#if DEBUG_CRED
92#define	DEBUG_CRED_ENTER		printf
93#define	DEBUG_CRED_CHANGE		printf
94extern void kauth_cred_print(kauth_cred_t cred);
95
96#include <libkern/OSDebug.h>	/* needed for get_backtrace( ) */
97
98int is_target_cred( kauth_cred_t the_cred );
99void get_backtrace( void );
100
101static int sysctl_dump_creds( __unused struct sysctl_oid *oidp, __unused void *arg1,
102							  __unused int arg2, struct sysctl_req *req );
103static int
104sysctl_dump_cred_backtraces( __unused struct sysctl_oid *oidp, __unused void *arg1,
105							 __unused int arg2, struct sysctl_req *req );
106
107#define MAX_STACK_DEPTH 8
108struct cred_backtrace {
109	int				depth;
110	void *			stack[ MAX_STACK_DEPTH ];
111};
112typedef struct cred_backtrace cred_backtrace;
113
114#define MAX_CRED_BUFFER_SLOTS 200
115struct cred_debug_buffer {
116	int				next_slot;
117	cred_backtrace	stack_buffer[ MAX_CRED_BUFFER_SLOTS ];
118};
119typedef struct cred_debug_buffer cred_debug_buffer;
120cred_debug_buffer * cred_debug_buf_p = NULL;
121
122#else	/* !DEBUG_CRED */
123
124#define	DEBUG_CRED_ENTER(fmt, ...)	do {} while (0)
125#define	DEBUG_CRED_CHANGE(fmt, ...)	do {} while (0)
126
127#endif	/* !DEBUG_CRED */
128
129#if CONFIG_EXT_RESOLVER
130/*
131 * Interface to external identity resolver.
132 *
133 * The architecture of the interface is simple; the external resolver calls
134 * in to get work, then calls back with completed work.  It also calls us
135 * to let us know that it's (re)started, so that we can resubmit work if it
136 * times out.
137 */
138
139static lck_mtx_t *kauth_resolver_mtx;
140#define KAUTH_RESOLVER_LOCK()	lck_mtx_lock(kauth_resolver_mtx);
141#define KAUTH_RESOLVER_UNLOCK()	lck_mtx_unlock(kauth_resolver_mtx);
142
143static volatile pid_t	kauth_resolver_identity;
144static int	kauth_resolver_registered;
145static uint32_t	kauth_resolver_sequence;
146static int	kauth_resolver_timeout = 30;	/* default: 30 seconds */
147
148struct kauth_resolver_work {
149	TAILQ_ENTRY(kauth_resolver_work) kr_link;
150	struct kauth_identity_extlookup kr_work;
151	uint64_t	kr_extend;
152	uint32_t	kr_seqno;
153	int		kr_refs;
154	int		kr_flags;
155#define KAUTH_REQUEST_UNSUBMITTED	(1<<0)
156#define KAUTH_REQUEST_SUBMITTED		(1<<1)
157#define KAUTH_REQUEST_DONE		(1<<2)
158	int		kr_result;
159};
160
161TAILQ_HEAD(kauth_resolver_unsubmitted_head, kauth_resolver_work) kauth_resolver_unsubmitted;
162TAILQ_HEAD(kauth_resolver_submitted_head, kauth_resolver_work)	kauth_resolver_submitted;
163TAILQ_HEAD(kauth_resolver_done_head, kauth_resolver_work)	kauth_resolver_done;
164
165/* Number of resolver timeouts between logged complaints */
166#define KAUTH_COMPLAINT_INTERVAL 1000
167int kauth_resolver_timeout_cnt = 0;
168
169static int	kauth_resolver_submit(struct kauth_identity_extlookup *lkp, uint64_t extend_data);
170static int	kauth_resolver_complete(user_addr_t message);
171static int	kauth_resolver_getwork(user_addr_t message);
172static int	kauth_resolver_getwork2(user_addr_t message);
173
174#define	KAUTH_CACHES_MAX_SIZE 10000 /* Max # entries for both groups and id caches */
175
176struct kauth_identity {
177	TAILQ_ENTRY(kauth_identity) ki_link;
178	int	ki_valid;
179	uid_t	ki_uid;
180	gid_t	ki_gid;
181	guid_t	ki_guid;
182	ntsid_t ki_ntsid;
183	const char	*ki_name;	/* string name from string cache */
184	/*
185	 * Expiry times are the earliest time at which we will disregard the
186	 * cached state and go to userland.  Before then if the valid bit is
187	 * set, we will return the cached value.  If it's not set, we will
188	 * not go to userland to resolve, just assume that there is no answer
189	 * available.
190	 */
191	time_t	ki_guid_expiry;
192	time_t	ki_ntsid_expiry;
193};
194
195static TAILQ_HEAD(kauth_identity_head, kauth_identity) kauth_identities;
196static lck_mtx_t *kauth_identity_mtx;
197#define KAUTH_IDENTITY_LOCK()	lck_mtx_lock(kauth_identity_mtx);
198#define KAUTH_IDENTITY_UNLOCK()	lck_mtx_unlock(kauth_identity_mtx);
199#define KAUTH_IDENTITY_CACHEMAX_DEFAULT 100	/* XXX default sizing? */
200static int kauth_identity_cachemax = KAUTH_IDENTITY_CACHEMAX_DEFAULT;
201static int kauth_identity_count;
202
203static struct kauth_identity *kauth_identity_alloc(uid_t uid, gid_t gid, guid_t *guidp, time_t guid_expiry,
204    ntsid_t *ntsidp, time_t ntsid_expiry, const char *name, int nametype);
205static void	kauth_identity_register_and_free(struct kauth_identity *kip);
206static void	kauth_identity_updatecache(struct kauth_identity_extlookup *elp, struct kauth_identity *kip, uint64_t extend_data);
207static void	kauth_identity_trimcache(int newsize);
208static void	kauth_identity_lru(struct kauth_identity *kip);
209static int	kauth_identity_guid_expired(struct kauth_identity *kip);
210static int	kauth_identity_ntsid_expired(struct kauth_identity *kip);
211static int	kauth_identity_find_uid(uid_t uid, struct kauth_identity *kir, char *getname);
212static int	kauth_identity_find_gid(gid_t gid, struct kauth_identity *kir, char *getname);
213static int	kauth_identity_find_guid(guid_t *guidp, struct kauth_identity *kir, char *getname);
214static int	kauth_identity_find_ntsid(ntsid_t *ntsid, struct kauth_identity *kir, char *getname);
215static int	kauth_identity_find_nam(char *name, int valid, struct kauth_identity *kir);
216
217struct 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
226TAILQ_HEAD(kauth_groups_head, kauth_group_membership) kauth_groups;
227static lck_mtx_t *kauth_groups_mtx;
228#define KAUTH_GROUPS_LOCK()	lck_mtx_lock(kauth_groups_mtx);
229#define KAUTH_GROUPS_UNLOCK()	lck_mtx_unlock(kauth_groups_mtx);
230#define KAUTH_GROUPS_CACHEMAX_DEFAULT 100	/* XXX default sizing? */
231static int kauth_groups_cachemax = KAUTH_GROUPS_CACHEMAX_DEFAULT;
232static int kauth_groups_count;
233
234static int	kauth_groups_expired(struct kauth_group_membership *gm);
235static void	kauth_groups_lru(struct kauth_group_membership *gm);
236static void	kauth_groups_updatecache(struct kauth_identity_extlookup *el);
237static void	kauth_groups_trimcache(int newsize);
238
239#endif	/* CONFIG_EXT_RESOLVER */
240
241static const int kauth_cred_primes[KAUTH_CRED_PRIMES_COUNT] = KAUTH_CRED_PRIMES;
242static int	kauth_cred_primes_index = 0;
243static int	kauth_cred_table_size = 0;
244
245TAILQ_HEAD(kauth_cred_entry_head, ucred);
246static struct kauth_cred_entry_head * kauth_cred_table_anchor = NULL;
247
248#define KAUTH_CRED_HASH_DEBUG	0
249
250static int kauth_cred_add(kauth_cred_t new_cred);
251static void kauth_cred_remove(kauth_cred_t cred);
252static inline u_long kauth_cred_hash(const uint8_t *datap, int data_len, u_long start_key);
253static u_long kauth_cred_get_hashkey(kauth_cred_t cred);
254static kauth_cred_t kauth_cred_update(kauth_cred_t old_cred, kauth_cred_t new_cred, boolean_t retain_auditinfo);
255static void kauth_cred_unref_hashlocked(kauth_cred_t *credp);
256
257#if KAUTH_CRED_HASH_DEBUG
258static int	kauth_cred_count = 0;
259static void kauth_cred_hash_print(void);
260static void kauth_cred_print(kauth_cred_t cred);
261#endif
262
263#if CONFIG_EXT_RESOLVER
264/*
265 * kauth_resolver_init
266 *
267 * Description:	Initialize the daemon side of the credential identity resolver
268 *
269 * Parameters:	(void)
270 *
271 * Returns:	(void)
272 *
273 * Notes:	Initialize the credential identity resolver for use; the
274 *		credential identity resolver is the KPI used by the user
275 *		space credential identity resolver daemon to communicate
276 *		with the kernel via the identitysvc() system call..
277 *
278 *		This is how membership in more than 16 groups (1 effective
279 *		and 15 supplementary) is supported, and also how UID's,
280 *		UUID's, and so on, are translated to/from POSIX credential
281 *		values.
282 *
283 *		The credential identity resolver operates by attempting to
284 *		determine identity first from the credential, then from
285 *		the kernel credential identity cache, and finally by
286 *		enqueueing a request to a user space daemon.
287 *
288 *		This function is called from kauth_init() in the file
289 *		kern_authorization.c.
290 */
291void
292kauth_resolver_init(void)
293{
294	TAILQ_INIT(&kauth_resolver_unsubmitted);
295	TAILQ_INIT(&kauth_resolver_submitted);
296	TAILQ_INIT(&kauth_resolver_done);
297	kauth_resolver_sequence = 31337;
298	kauth_resolver_mtx = lck_mtx_alloc_init(kauth_lck_grp, 0/*LCK_ATTR_NULL*/);
299}
300
301
302/*
303 * kauth_resolver_submit
304 *
305 * Description:	Submit an external credential identity resolution request to
306 *		the user space daemon.
307 *
308 * Parameters:	lkp				A pointer to an external
309 *						lookup request
310 *		extend_data			extended data for kr_extend
311 *
312 * Returns:	0				Success
313 *		EWOULDBLOCK			No resolver registered
314 *		EINTR				Operation interrupted (e.g. by
315 *						a signal)
316 *		ENOMEM				Could not allocate work item
317 *	copyinstr:EFAULT			Bad message from user space
318 *	workp->kr_result:???			An error from the user space
319 *						daemon (includes ENOENT!)
320 *
321 * Implicit returns:
322 *		*lkp				Modified
323 *
324 * Notes:	Allocate a work queue entry, submit the work and wait for
325 *		the operation to either complete or time out.  Outstanding
326 *		operations may also be cancelled.
327 *
328 *		Submission is by means of placing the item on a work queue
329 *		which is serviced by an external resolver thread calling
330 *		into the kernel.  The caller then sleeps until timeout,
331 *		cancellation, or an external resolver thread calls in with
332 *		a result message to kauth_resolver_complete().  All of these
333 *		events wake the caller back up.
334 *
335 *		This code is called from either kauth_cred_ismember_gid()
336 *		for a group membership request, or it is called from
337 *		kauth_cred_cache_lookup() when we get a cache miss.
338 */
339static int
340kauth_resolver_submit(struct kauth_identity_extlookup *lkp, uint64_t extend_data)
341{
342	struct kauth_resolver_work *workp, *killp;
343	struct timespec ts;
344	int	error, shouldfree;
345
346	/* no point actually blocking if the resolver isn't up yet */
347	if (kauth_resolver_identity == 0) {
348		/*
349		 * We've already waited an initial <kauth_resolver_timeout>
350		 * seconds with no result.
351		 *
352		 * Sleep on a stack address so no one wakes us before timeout;
353		 * we sleep a half a second in case we are a high priority
354		 * process, so that memberd doesn't starve while we are in a
355		 * tight loop between user and kernel, eating all the CPU.
356		 */
357		error = tsleep(&ts, PZERO | PCATCH, "kr_submit", hz/2);
358		if (kauth_resolver_identity == 0) {
359			/*
360			 * if things haven't changed while we were asleep,
361			 * tell the caller we couldn't get an authoritative
362			 * answer.
363			 */
364			return(EWOULDBLOCK);
365		}
366	}
367
368	MALLOC(workp, struct kauth_resolver_work *, sizeof(*workp), M_KAUTH, M_WAITOK);
369	if (workp == NULL)
370		return(ENOMEM);
371
372	workp->kr_work = *lkp;
373	workp->kr_extend = extend_data;
374	workp->kr_refs = 1;
375	workp->kr_flags = KAUTH_REQUEST_UNSUBMITTED;
376	workp->kr_result = 0;
377
378	/*
379	 * We insert the request onto the unsubmitted queue, the call in from
380	 * the resolver will it to the submitted thread when appropriate.
381	 */
382	KAUTH_RESOLVER_LOCK();
383	workp->kr_seqno = workp->kr_work.el_seqno = kauth_resolver_sequence++;
384	workp->kr_work.el_result = KAUTH_EXTLOOKUP_INPROG;
385
386	/*
387	 * XXX We *MUST NOT* attempt to coalesce identical work items due to
388	 * XXX the inability to ensure order of update of the request item
389	 * XXX extended data vs. the wakeup; instead, we let whoever is waiting
390	 * XXX for each item repeat the update when they wake up.
391	 */
392	TAILQ_INSERT_TAIL(&kauth_resolver_unsubmitted, workp, kr_link);
393
394	/*
395	 * Wake up an external resolver thread to deal with the new work; one
396	 * may not be available, and if not, then the request will be grabbed
397	 * when a resolver thread comes back into the kernel to request new
398	 * work.
399	 */
400	wakeup_one((caddr_t)&kauth_resolver_unsubmitted);
401	for (;;) {
402		/* we could compute a better timeout here */
403		ts.tv_sec = kauth_resolver_timeout;
404		ts.tv_nsec = 0;
405		error = msleep(workp, kauth_resolver_mtx, PCATCH, "kr_submit", &ts);
406		/* request has been completed? */
407		if ((error == 0) && (workp->kr_flags & KAUTH_REQUEST_DONE))
408			break;
409		/* woken because the resolver has died? */
410		if (kauth_resolver_identity == 0) {
411			error = EIO;
412			break;
413		}
414		/* an error? */
415		if (error != 0)
416			break;
417	}
418
419	/* if the request was processed, copy the result */
420	if (error == 0)
421		*lkp = workp->kr_work;
422
423	if (error == EWOULDBLOCK) {
424	        if ((kauth_resolver_timeout_cnt++ % KAUTH_COMPLAINT_INTERVAL) == 0) {
425                        printf("kauth external resolver timed out (%d timeout(s) of %d seconds).\n",
426                                kauth_resolver_timeout_cnt, kauth_resolver_timeout);
427                }
428
429	        if (workp->kr_flags & KAUTH_REQUEST_UNSUBMITTED) {
430	                /*
431                	 * If the request timed out and was never collected, the resolver
432                	 * is dead and probably not coming back anytime soon.  In this
433                	 * case we revert to no-resolver behaviour, and punt all the other
434                	 * sleeping requests to clear the backlog.
435                	 */
436                        KAUTH_DEBUG("RESOLVER - request timed out without being collected for processing, resolver dead");
437
438                        /*
439                        * Make the current resolver non-authoritative, and mark it as
440                        * no longer registered to prevent kauth_cred_ismember_gid()
441                        * enqueueing more work until a new one is registered.  This
442                        * mitigates the damage a crashing resolver may inflict.
443                        */
444                        kauth_resolver_identity = 0;
445                        kauth_resolver_registered = 0;
446
447                        /* kill all the other requestes that are waiting as well */
448                        TAILQ_FOREACH(killp, &kauth_resolver_submitted, kr_link)
449                                wakeup(killp);
450                        TAILQ_FOREACH(killp, &kauth_resolver_unsubmitted, kr_link)
451                                wakeup(killp);
452                        /* Cause all waiting-for-work threads to return EIO */
453                        wakeup((caddr_t)&kauth_resolver_unsubmitted);
454                }
455        }
456
457	/*
458	 * drop our reference on the work item, and note whether we should
459	 * free it or not
460	 */
461	if (--workp->kr_refs <= 0) {
462		/* work out which list we have to remove it from */
463		if (workp->kr_flags & KAUTH_REQUEST_DONE) {
464			TAILQ_REMOVE(&kauth_resolver_done, workp, kr_link);
465		} else if (workp->kr_flags & KAUTH_REQUEST_SUBMITTED) {
466			TAILQ_REMOVE(&kauth_resolver_submitted, workp, kr_link);
467		} else if (workp->kr_flags & KAUTH_REQUEST_UNSUBMITTED) {
468			TAILQ_REMOVE(&kauth_resolver_unsubmitted, workp, kr_link);
469		} else {
470			KAUTH_DEBUG("RESOLVER - completed request has no valid queue");
471		}
472		shouldfree = 1;
473	} else {
474		/* someone else still has a reference on this request */
475		shouldfree = 0;
476	}
477
478	/* collect request result */
479	if (error == 0) {
480		error = workp->kr_result;
481	}
482	KAUTH_RESOLVER_UNLOCK();
483
484	/*
485	 * If we dropped the last reference, free the request.
486	 */
487	if (shouldfree) {
488		FREE(workp, M_KAUTH);
489	}
490
491	KAUTH_DEBUG("RESOLVER - returning %d", error);
492	return(error);
493}
494
495
496/*
497 * identitysvc
498 *
499 * Description:	System call interface for the external identity resolver.
500 *
501 * Parameters:	uap->message			Message from daemon to kernel
502 *
503 * Returns:	0				Successfully became resolver
504 *		EPERM				Not the resolver process
505 *	kauth_authorize_generic:EPERM		Not root user
506 *	kauth_resolver_complete:EIO
507 *	kauth_resolver_complete:EFAULT
508 *	kauth_resolver_getwork:EINTR
509 *	kauth_resolver_getwork:EFAULT
510 *
511 * Notes:	This system call blocks until there is work enqueued, at
512 *		which time the kernel wakes it up, and a message from the
513 *		kernel is copied out to the identity resolution daemon, which
514 *		proceed to attempt to resolve it.  When the resolution has
515 *		completed (successfully or not), the daemon called back into
516 *		this system call to give the result to the kernel, and wait
517 *		for the next request.
518 */
519int
520identitysvc(__unused struct proc *p, struct identitysvc_args *uap, __unused int32_t *retval)
521{
522	int opcode = uap->opcode;
523	user_addr_t message = uap->message;
524	struct kauth_resolver_work *workp;
525	struct kauth_cache_sizes sz_arg;
526	int error;
527	pid_t new_id;
528
529	/*
530	 * New server registering itself.
531	 */
532	if (opcode == KAUTH_EXTLOOKUP_REGISTER) {
533		new_id = current_proc()->p_pid;
534		if ((error = kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER)) != 0) {
535			KAUTH_DEBUG("RESOLVER - pid %d refused permission to become identity resolver", new_id);
536			return(error);
537		}
538		KAUTH_RESOLVER_LOCK();
539		if (kauth_resolver_identity != new_id) {
540			KAUTH_DEBUG("RESOLVER - new resolver %d taking over from old %d", new_id, kauth_resolver_identity);
541			/*
542			 * We have a new server, so assume that all the old requests have been lost.
543			 */
544			while ((workp = TAILQ_LAST(&kauth_resolver_submitted, kauth_resolver_submitted_head)) != NULL) {
545				TAILQ_REMOVE(&kauth_resolver_submitted, workp, kr_link);
546				workp->kr_flags &= ~KAUTH_REQUEST_SUBMITTED;
547				workp->kr_flags |= KAUTH_REQUEST_UNSUBMITTED;
548				TAILQ_INSERT_HEAD(&kauth_resolver_unsubmitted, workp, kr_link);
549			}
550			/*
551			 * Allow user space resolver to override the
552			 * external resolution timeout
553			 */
554			if (message > 30 && message < 10000) {
555				kauth_resolver_timeout = message;
556				KAUTH_DEBUG("RESOLVER - new resolver changes timeout to %d seconds\n", (int)message);
557			}
558			kauth_resolver_identity = new_id;
559			kauth_resolver_registered = 1;
560			wakeup(&kauth_resolver_unsubmitted);
561		}
562		KAUTH_RESOLVER_UNLOCK();
563		return(0);
564	}
565
566	/*
567	 * Beyond this point, we must be the resolver process.
568	 */
569	if (current_proc()->p_pid != kauth_resolver_identity) {
570		KAUTH_DEBUG("RESOLVER - call from bogus resolver %d\n", current_proc()->p_pid);
571		return(EPERM);
572	}
573
574	if (opcode == KAUTH_GET_CACHE_SIZES) {
575		KAUTH_IDENTITY_LOCK();
576		sz_arg.kcs_id_size = kauth_identity_cachemax;
577		KAUTH_IDENTITY_UNLOCK();
578
579		KAUTH_GROUPS_LOCK();
580		sz_arg.kcs_group_size = kauth_groups_cachemax;
581		KAUTH_GROUPS_UNLOCK();
582
583		if ((error = copyout(&sz_arg, uap->message, sizeof (sz_arg))) != 0) {
584			return (error);
585		}
586
587		return (0);
588	} else if (opcode == KAUTH_SET_CACHE_SIZES) {
589		if ((error = copyin(uap->message, &sz_arg, sizeof (sz_arg))) != 0) {
590			return (error);
591		}
592
593		if ((sz_arg.kcs_group_size > KAUTH_CACHES_MAX_SIZE) ||
594		    (sz_arg.kcs_id_size > KAUTH_CACHES_MAX_SIZE)) {
595			return (EINVAL);
596		}
597
598		KAUTH_IDENTITY_LOCK();
599		kauth_identity_cachemax = sz_arg.kcs_id_size;
600		kauth_identity_trimcache(kauth_identity_cachemax);
601		KAUTH_IDENTITY_UNLOCK();
602
603		KAUTH_GROUPS_LOCK();
604		kauth_groups_cachemax = sz_arg.kcs_group_size;
605		kauth_groups_trimcache(kauth_groups_cachemax);
606		KAUTH_GROUPS_UNLOCK();
607
608		return (0);
609	} else if (opcode == KAUTH_CLEAR_CACHES) {
610		KAUTH_IDENTITY_LOCK();
611		kauth_identity_trimcache(0);
612		KAUTH_IDENTITY_UNLOCK();
613
614		KAUTH_GROUPS_LOCK();
615		kauth_groups_trimcache(0);
616		KAUTH_GROUPS_UNLOCK();
617	} else if (opcode == KAUTH_EXTLOOKUP_DEREGISTER) {
618		/*
619		 * Terminate outstanding requests; without an authoritative
620		 * resolver, we are now back on our own authority.
621		 */
622		struct kauth_resolver_work *killp;
623
624		KAUTH_RESOLVER_LOCK();
625
626		/*
627		 * Clear the identity, but also mark it as unregistered so
628		 * there is no explicit future expectation of us getting a
629		 * new resolver any time soon.
630		 */
631		kauth_resolver_identity = 0;
632		kauth_resolver_registered = 0;
633
634		TAILQ_FOREACH(killp, &kauth_resolver_submitted, kr_link)
635		    wakeup(killp);
636		TAILQ_FOREACH(killp, &kauth_resolver_unsubmitted, kr_link)
637		    wakeup(killp);
638		/* Cause all waiting-for-work threads to return EIO */
639		wakeup((caddr_t)&kauth_resolver_unsubmitted);
640		KAUTH_RESOLVER_UNLOCK();
641	}
642
643	/*
644	 * Got a result returning?
645	 */
646	if (opcode & KAUTH_EXTLOOKUP_RESULT) {
647		if ((error = kauth_resolver_complete(message)) != 0)
648			return(error);
649	}
650
651	/*
652	 * Caller wants to take more work?
653	 */
654	if (opcode & KAUTH_EXTLOOKUP_WORKER) {
655		if ((error = kauth_resolver_getwork(message)) != 0)
656			return(error);
657	}
658
659	return(0);
660}
661
662
663/*
664 * kauth_resolver_getwork_continue
665 *
666 * Description:	Continuation for kauth_resolver_getwork
667 *
668 * Parameters:	result				Error code or 0 for the sleep
669 *						that got us to this function
670 *
671 * Returns:	0				Success
672 *		EINTR				Interrupted (e.g. by signal)
673 *	kauth_resolver_getwork2:EFAULT
674 *
675 * Notes:	See kauth_resolver_getwork(0 and kauth_resolver_getwork2() for
676 *		more information.
677 */
678static int
679kauth_resolver_getwork_continue(int result)
680{
681	thread_t thread;
682	struct uthread *ut;
683	user_addr_t message;
684
685	if (result) {
686		KAUTH_RESOLVER_UNLOCK();
687		return(result);
688	}
689
690	/*
691	 * If we lost a race with another thread/memberd restarting, then we
692	 * need to go back to sleep to look for more work.  If it was memberd
693	 * restarting, then the msleep0() will error out here, as our thread
694	 * will already be "dead".
695	 */
696	if (TAILQ_FIRST(&kauth_resolver_unsubmitted) == NULL) {
697		int error;
698
699		error = msleep0(&kauth_resolver_unsubmitted, kauth_resolver_mtx, PCATCH, "GRGetWork", 0, kauth_resolver_getwork_continue);
700		/*
701		 * If this is a wakeup from another thread in the resolver
702		 * deregistering it, error out the request-for-work thread
703		 */
704		if (!kauth_resolver_identity)
705			error = EIO;
706		KAUTH_RESOLVER_UNLOCK();
707		return(error);
708	}
709
710	thread = current_thread();
711	ut = get_bsdthread_info(thread);
712	message = ut->uu_kauth.message;
713	return(kauth_resolver_getwork2(message));
714}
715
716
717/*
718 * kauth_resolver_getwork2
719 *
720 * Decription:	Common utility function to copy out a identity resolver work
721 *		item from the kernel to user space as part of the user space
722 *		identity resolver requesting work.
723 *
724 * Parameters:	message				message to user space
725 *
726 * Returns:	0				Success
727 *		EFAULT				Bad user space message address
728 *
729 * Notes:	This common function exists to permit the use of continuations
730 *		in the identity resolution process.  This frees up the stack
731 *		while we are waiting for the user space resolver to complete
732 *		a request.  This is specifically used so that our per thread
733 *		cost can be small, and we will therefore be willing to run a
734 *		larger number of threads in the user space identity resolver.
735 */
736static int
737kauth_resolver_getwork2(user_addr_t message)
738{
739	struct kauth_resolver_work *workp;
740	int		error;
741
742	/*
743	 * Note: We depend on the caller protecting us from a NULL work item
744	 * queue, since we must have the kauth resolver lock on entry to this
745	 * function.
746	 */
747	workp = TAILQ_FIRST(&kauth_resolver_unsubmitted);
748
749	/*
750	 * Copy out the external lookup structure for the request, not
751	 * including the el_extend field, which contains the address of the
752	 * external buffer provided by the external resolver into which we
753	 * copy the extension request information.
754	 */
755	/* BEFORE FIELD */
756	if ((error = copyout(&workp->kr_work, message, offsetof(struct kauth_identity_extlookup, el_extend))) != 0) {
757		KAUTH_DEBUG("RESOLVER - error submitting work to resolve");
758		goto out;
759	}
760	/* AFTER FIELD */
761	if ((error = copyout(&workp->kr_work.el_info_reserved_1,
762			message + offsetof(struct kauth_identity_extlookup, el_info_reserved_1),
763		sizeof(struct kauth_identity_extlookup) - offsetof(struct kauth_identity_extlookup, el_info_reserved_1))) != 0) {
764		KAUTH_DEBUG("RESOLVER - error submitting work to resolve");
765		goto out;
766	}
767
768	/*
769	 * Handle extended requests here; if we have a request of a type where
770	 * the kernel wants a translation of extended information, then we need
771	 * to copy it out into the extended buffer, assuming the buffer is
772	 * valid; we only attempt to get the buffer address if we have request
773	 * data to copy into it.
774	 */
775
776	/*
777	 * translate a user@domain string into a uid/gid/whatever
778	 */
779	if (workp->kr_work.el_flags & (KAUTH_EXTLOOKUP_VALID_PWNAM | KAUTH_EXTLOOKUP_VALID_GRNAM)) {
780		uint64_t uaddr;
781
782		error = copyin(message + offsetof(struct kauth_identity_extlookup, el_extend), &uaddr, sizeof(uaddr));
783		if (!error) {
784			size_t actual;	/* not used */
785			/*
786			 * Use copyoutstr() to reduce the copy size; we let
787			 * this catch a NULL uaddr because we shouldn't be
788			 * asking in that case anyway.
789			 */
790			error = copyoutstr(CAST_DOWN(void *,workp->kr_extend), uaddr, MAXPATHLEN, &actual);
791		}
792		if (error) {
793			KAUTH_DEBUG("RESOLVER - error submitting work to resolve");
794			goto out;
795		}
796	}
797	TAILQ_REMOVE(&kauth_resolver_unsubmitted, workp, kr_link);
798	workp->kr_flags &= ~KAUTH_REQUEST_UNSUBMITTED;
799	workp->kr_flags |= KAUTH_REQUEST_SUBMITTED;
800	TAILQ_INSERT_TAIL(&kauth_resolver_submitted, workp, kr_link);
801
802out:
803	KAUTH_RESOLVER_UNLOCK();
804	return(error);
805}
806
807
808/*
809 * kauth_resolver_getwork
810 *
811 * Description:	Get a work item from the enqueued requests from the kernel and
812 *		give it to the user space daemon.
813 *
814 * Parameters:	message				message to user space
815 *
816 * Returns:	0				Success
817 *		EINTR				Interrupted (e.g. by signal)
818 *	kauth_resolver_getwork2:EFAULT
819 *
820 * Notes:	This function blocks in a continuation if there are no work
821 *		items available for processing at the time the user space
822 *		identity resolution daemon makes a request for work.  This
823 *		permits a large number of threads to be used by the daemon,
824 *		without using a lot of wired kernel memory when there are no
825 *		actual request outstanding.
826 */
827static int
828kauth_resolver_getwork(user_addr_t message)
829{
830	struct kauth_resolver_work *workp;
831	int		error;
832
833	KAUTH_RESOLVER_LOCK();
834	error = 0;
835	while ((workp = TAILQ_FIRST(&kauth_resolver_unsubmitted)) == NULL) {
836		thread_t thread = current_thread();
837		struct uthread *ut = get_bsdthread_info(thread);
838
839		ut->uu_kauth.message = message;
840		error = msleep0(&kauth_resolver_unsubmitted, kauth_resolver_mtx, PCATCH, "GRGetWork", 0, kauth_resolver_getwork_continue);
841		KAUTH_RESOLVER_UNLOCK();
842		/*
843		 * If this is a wakeup from another thread in the resolver
844		 * deregistering it, error out the request-for-work thread
845		 */
846		if (!kauth_resolver_identity)
847			error = EIO;
848		return(error);
849	}
850	return kauth_resolver_getwork2(message);
851}
852
853
854/*
855 * kauth_resolver_complete
856 *
857 * Description:	Return a result from userspace.
858 *
859 * Parameters:	message				message from user space
860 *
861 * Returns:	0				Success
862 *		EIO				The resolver is dead
863 *	copyin:EFAULT				Bad message from user space
864 */
865static int
866kauth_resolver_complete(user_addr_t message)
867{
868	struct kauth_identity_extlookup	extl;
869	struct kauth_resolver_work *workp;
870	struct kauth_resolver_work *killp;
871	int error, result;
872
873	/*
874	 * Copy in the mesage, including the extension field, since we are
875	 * copying into a local variable.
876	 */
877	if ((error = copyin(message, &extl, sizeof(extl))) != 0) {
878		KAUTH_DEBUG("RESOLVER - error getting completed work\n");
879		return(error);
880	}
881
882	KAUTH_RESOLVER_LOCK();
883
884	error = 0;
885	result = 0;
886	switch (extl.el_result) {
887	case KAUTH_EXTLOOKUP_INPROG:
888	{
889		static int once = 0;
890
891		/* XXX this should go away once memberd is updated */
892		if (!once) {
893			printf("kauth_resolver: memberd is not setting valid result codes (assuming always successful)\n");
894			once = 1;
895		}
896	}
897	/* FALLTHROUGH */
898
899	case KAUTH_EXTLOOKUP_SUCCESS:
900		break;
901
902	case KAUTH_EXTLOOKUP_FATAL:
903		/* fatal error means the resolver is dead */
904		KAUTH_DEBUG("RESOLVER - resolver %d died, waiting for a new one", kauth_resolver_identity);
905		/*
906		 * Terminate outstanding requests; without an authoritative
907		 * resolver, we are now back on our own authority.  Tag the
908		 * resolver unregistered to prevent kauth_cred_ismember_gid()
909		 * enqueueing more work until a new one is registered.  This
910		 * mitigates the damage a crashing resolver may inflict.
911		 */
912		kauth_resolver_identity = 0;
913		kauth_resolver_registered = 0;
914
915		TAILQ_FOREACH(killp, &kauth_resolver_submitted, kr_link)
916		    wakeup(killp);
917		TAILQ_FOREACH(killp, &kauth_resolver_unsubmitted, kr_link)
918		    wakeup(killp);
919		/* Cause all waiting-for-work threads to return EIO */
920		wakeup((caddr_t)&kauth_resolver_unsubmitted);
921		/* and return EIO to the caller */
922		error = EIO;
923		break;
924
925	case KAUTH_EXTLOOKUP_BADRQ:
926		KAUTH_DEBUG("RESOLVER - resolver reported invalid request %d", extl.el_seqno);
927		result = EINVAL;
928		break;
929
930	case KAUTH_EXTLOOKUP_FAILURE:
931		KAUTH_DEBUG("RESOLVER - resolver reported transient failure for request %d", extl.el_seqno);
932		result = EIO;
933		break;
934
935	default:
936		KAUTH_DEBUG("RESOLVER - resolver returned unexpected status %d", extl.el_result);
937		result = EIO;
938		break;
939	}
940
941	/*
942	 * In the case of a fatal error, we assume that the resolver will
943	 * restart quickly and re-collect all of the outstanding requests.
944	 * Thus, we don't complete the request which returned the fatal
945	 * error status.
946	 */
947	if (extl.el_result != KAUTH_EXTLOOKUP_FATAL) {
948		/* scan our list for this request */
949		TAILQ_FOREACH(workp, &kauth_resolver_submitted, kr_link) {
950			/* found it? */
951			if (workp->kr_seqno == extl.el_seqno) {
952
953				/*
954				 * Get the request of the submitted queue so
955				 * that it is not cleaned up out from under
956				 * us by a timeout.
957				 */
958				TAILQ_REMOVE(&kauth_resolver_submitted, workp, kr_link);
959				workp->kr_flags &= ~KAUTH_REQUEST_SUBMITTED;
960				workp->kr_flags |= KAUTH_REQUEST_DONE;
961				workp->kr_result = result;
962
963				/* Copy the result message to the work item. */
964				memcpy(&workp->kr_work, &extl, sizeof(struct kauth_identity_extlookup));
965
966				/*
967				 * Check if we have a result in the extension
968				 * field; if we do, then we need to separately
969				 * copy the data from the message el_extend
970				 * into the request buffer that's in the work
971				 * item.  We have to do it here because we do
972				 * not want to wake up the waiter until the
973				 * data is in their buffer, and because the
974				 * actual request response may be destroyed
975				 * by the time the requester wakes up, and they
976				 * do not have access to the user space buffer
977				 * address.
978				 *
979				 * It is safe to drop and reacquire the lock
980				 * here because we've already removed the item
981				 * from the submission queue, but have not yet
982				 * moved it to the completion queue.  Note that
983				 * near simultaneous requests may result in
984				 * duplication of requests for items in this
985				 * window. This should not be a performance
986				 * issue and is easily detectable by comparing
987				 * time to live on last response vs. time of
988				 * next request in the resolver logs.
989				 */
990				if (extl.el_flags & (KAUTH_EXTLOOKUP_VALID_PWNAM|KAUTH_EXTLOOKUP_VALID_GRNAM)) {
991					size_t actual;	/* notused */
992
993					KAUTH_RESOLVER_UNLOCK();
994					error = copyinstr(extl.el_extend, CAST_DOWN(void *, workp->kr_extend), MAXPATHLEN, &actual);
995					KAUTH_RESOLVER_LOCK();
996				}
997
998				/*
999				 * Move the completed work item to the
1000				 * completion queue and wake up requester(s)
1001				 */
1002				TAILQ_INSERT_TAIL(&kauth_resolver_done, workp, kr_link);
1003				wakeup(workp);
1004				break;
1005			}
1006		}
1007	}
1008	/*
1009	 * Note that it's OK for us not to find anything; if the request has
1010	 * timed out the work record will be gone.
1011	 */
1012	KAUTH_RESOLVER_UNLOCK();
1013
1014	return(error);
1015}
1016#endif /* CONFIG_EXT_RESOLVER */
1017
1018
1019/*
1020 * Identity cache.
1021 */
1022
1023#define	KI_VALID_UID	(1<<0)		/* UID and GID are mutually exclusive */
1024#define KI_VALID_GID	(1<<1)
1025#define KI_VALID_GUID	(1<<2)
1026#define KI_VALID_NTSID	(1<<3)
1027#define KI_VALID_PWNAM	(1<<4)	/* Used for translation */
1028#define KI_VALID_GRNAM	(1<<5)	/* Used for translation */
1029
1030#if CONFIG_EXT_RESOLVER
1031/*
1032 * kauth_identity_init
1033 *
1034 * Description:	Initialize the kernel side of the credential identity resolver
1035 *
1036 * Parameters:	(void)
1037 *
1038 * Returns:	(void)
1039 *
1040 * Notes:	Initialize the credential identity resolver for use; the
1041 *		credential identity resolver is the KPI used to communicate
1042 *		with a user space credential identity resolver daemon.
1043 *
1044 *		This function is called from kauth_init() in the file
1045 *		kern_authorization.c.
1046 */
1047void
1048kauth_identity_init(void)
1049{
1050	TAILQ_INIT(&kauth_identities);
1051	kauth_identity_mtx = lck_mtx_alloc_init(kauth_lck_grp, 0/*LCK_ATTR_NULL*/);
1052}
1053
1054
1055/*
1056 * kauth_identity_alloc
1057 *
1058 * Description:	Allocate and fill out a kauth_identity structure for
1059 *		translation between {UID|GID}/GUID/NTSID
1060 *
1061 * Parameters:	uid
1062 *
1063 * Returns:	NULL				Insufficient memory to satisfy
1064 *						the request
1065 *		!NULL				A pointer to the allocated
1066 *						structure, filled in
1067 *
1068 * Notes:	It is illegal to translate between UID and GID; any given UUID
1069 *		or NTSID can only refer to an NTSID or UUID (respectively),
1070 *		and *either* a UID *or* a GID, but not both.
1071 */
1072static struct kauth_identity *
1073kauth_identity_alloc(uid_t uid, gid_t gid, guid_t *guidp, time_t guid_expiry, ntsid_t *ntsidp, time_t ntsid_expiry, const char *name, int nametype)
1074{
1075	struct kauth_identity *kip;
1076
1077	/* get and fill in a new identity */
1078	MALLOC(kip, struct kauth_identity *, sizeof(*kip), M_KAUTH, M_WAITOK | M_ZERO);
1079	if (kip != NULL) {
1080		if (gid != KAUTH_GID_NONE) {
1081			kip->ki_gid = gid;
1082			kip->ki_valid = KI_VALID_GID;
1083		}
1084		if (uid != KAUTH_UID_NONE) {
1085			if (kip->ki_valid & KI_VALID_GID)
1086				panic("can't allocate kauth identity with both uid and gid");
1087			kip->ki_uid = uid;
1088			kip->ki_valid = KI_VALID_UID;
1089		}
1090		if (guidp != NULL) {
1091			kip->ki_guid = *guidp;
1092			kip->ki_valid |= KI_VALID_GUID;
1093		}
1094		kip->ki_guid_expiry = guid_expiry;
1095		if (ntsidp != NULL) {
1096			kip->ki_ntsid = *ntsidp;
1097			kip->ki_valid |= KI_VALID_NTSID;
1098		}
1099		kip->ki_ntsid_expiry = ntsid_expiry;
1100		if (name != NULL) {
1101			kip->ki_name = name;
1102			kip->ki_valid |= nametype;
1103		}
1104	}
1105	return(kip);
1106}
1107
1108
1109/*
1110 * kauth_identity_register_and_free
1111 *
1112 * Description:	Register an association between identity tokens.  The passed
1113 *		'kip' is consumed by this function.
1114 *
1115 * Parameters:	kip				Pointer to kauth_identity
1116 *						structure to register
1117 *
1118 * Returns:	(void)
1119 *
1120 * Notes:	The memory pointer to by 'kip' is assumed to have been
1121 *		previously allocated via kauth_identity_alloc().
1122 */
1123static void
1124kauth_identity_register_and_free(struct kauth_identity *kip)
1125{
1126	struct kauth_identity *ip;
1127
1128	/*
1129	 * We search the cache for the UID listed in the incoming association.
1130	 * If we already have an entry, the new information is merged.
1131	 */
1132	ip = NULL;
1133	KAUTH_IDENTITY_LOCK();
1134	if (kip->ki_valid & KI_VALID_UID) {
1135		if (kip->ki_valid & KI_VALID_GID)
1136			panic("kauth_identity: can't insert record with both UID and GID as key");
1137		TAILQ_FOREACH(ip, &kauth_identities, ki_link)
1138		    if ((ip->ki_valid & KI_VALID_UID) && (ip->ki_uid == kip->ki_uid))
1139				break;
1140	} else if (kip->ki_valid & KI_VALID_GID) {
1141		TAILQ_FOREACH(ip, &kauth_identities, ki_link)
1142		    if ((ip->ki_valid & KI_VALID_GID) && (ip->ki_gid == kip->ki_gid))
1143				break;
1144	} else {
1145		panic("kauth_identity: can't insert record without UID or GID as key");
1146	}
1147
1148	if (ip != NULL) {
1149		/* we already have an entry, merge/overwrite */
1150		if (kip->ki_valid & KI_VALID_GUID) {
1151			ip->ki_guid = kip->ki_guid;
1152			ip->ki_valid |= KI_VALID_GUID;
1153		}
1154		ip->ki_guid_expiry = kip->ki_guid_expiry;
1155		if (kip->ki_valid & KI_VALID_NTSID) {
1156			ip->ki_ntsid = kip->ki_ntsid;
1157			ip->ki_valid |= KI_VALID_NTSID;
1158		}
1159		ip->ki_ntsid_expiry = kip->ki_ntsid_expiry;
1160		/* a valid ki_name field overwrites the previous name field */
1161		if (kip->ki_valid & (KI_VALID_PWNAM | KI_VALID_GRNAM)) {
1162			/* if there's an old one, discard it */
1163			const char *oname = NULL;
1164			if (ip->ki_valid & (KI_VALID_PWNAM | KI_VALID_GRNAM))
1165				oname = ip->ki_name;
1166			ip->ki_name = kip->ki_name;
1167			kip->ki_name = oname;
1168		}
1169		/* and discard the incoming entry */
1170		ip = kip;
1171	} else {
1172		/*
1173		 * if we don't have any information on this identity, add it;
1174		 * if it pushes us over our limit, discard the oldest one.
1175		 */
1176		TAILQ_INSERT_HEAD(&kauth_identities, kip, ki_link);
1177		if (++kauth_identity_count > kauth_identity_cachemax) {
1178			ip = TAILQ_LAST(&kauth_identities, kauth_identity_head);
1179			TAILQ_REMOVE(&kauth_identities, ip, ki_link);
1180			kauth_identity_count--;
1181		}
1182	}
1183	KAUTH_IDENTITY_UNLOCK();
1184	/* have to drop lock before freeing expired entry (it may be in use) */
1185	if (ip != NULL) {
1186		/* if the ki_name field is used, clear it first */
1187		if (ip->ki_valid & (KI_VALID_PWNAM | KI_VALID_GRNAM))
1188			vfs_removename(ip->ki_name);
1189		/* free the expired entry */
1190		FREE(ip, M_KAUTH);
1191	}
1192}
1193
1194
1195/*
1196 * kauth_identity_updatecache
1197 *
1198 * Description:	Given a lookup result, add any associations that we don't
1199 *		currently have; replace ones which have changed.
1200 *
1201 * Parameters:	elp				External lookup result from
1202 *						user space daemon to kernel
1203 *		rkip				pointer to returned kauth
1204 *						identity, or NULL
1205 *		extend_data			Extended data (can vary)
1206 *
1207 * Returns:	(void)
1208 *
1209 * Implicit returns:
1210 *		*rkip				Modified (if non-NULL)
1211 *
1212 * Notes:	For extended information requests, this code relies on the fact
1213 *		that elp->el_flags is never used as an rvalue, and is only
1214 *		ever bit-tested for valid lookup information we are willing
1215 *		to cache.
1216 *
1217 * XXX:		We may have to do the same in the case that extended data was
1218 *		passed out to user space to ensure that the request string
1219 *		gets cached; we may also be able to use the rkip as an
1220 *		input to avoid this.  The jury is still out.
1221 *
1222 * XXX:		This codes performance could be improved for multiple valid
1223 *		results by combining the loop iteration in a single loop.
1224 */
1225static void
1226kauth_identity_updatecache(struct kauth_identity_extlookup *elp, struct kauth_identity *rkip, uint64_t extend_data)
1227{
1228	struct timeval tv;
1229	struct kauth_identity *kip;
1230	const char *speculative_name = NULL;
1231
1232	microuptime(&tv);
1233
1234	/*
1235	 * If there is extended data, and that data represents a name rather
1236	 * than something else, speculatively create an entry for it in the
1237	 * string cache.  We do this to avoid holding the KAUTH_IDENTITY_LOCK
1238	 * over the allocation later.
1239	 */
1240	if (elp->el_flags & (KAUTH_EXTLOOKUP_VALID_PWNAM | KAUTH_EXTLOOKUP_VALID_GRNAM)) {
1241		const char *tmp = CAST_DOWN(const char *,extend_data);
1242		speculative_name = vfs_addname(tmp, strnlen(tmp, MAXPATHLEN - 1), 0, 0);
1243	}
1244
1245	/* user identity? */
1246	if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_UID) {
1247		KAUTH_IDENTITY_LOCK();
1248		TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
1249			/* matching record */
1250			if ((kip->ki_valid & KI_VALID_UID) && (kip->ki_uid == elp->el_uid)) {
1251				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_UGUID) {
1252					kip->ki_guid = elp->el_uguid;
1253					kip->ki_valid |= KI_VALID_GUID;
1254				}
1255				kip->ki_guid_expiry = (elp->el_uguid_valid) ? tv.tv_sec + elp->el_uguid_valid : 0;
1256				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_USID) {
1257					kip->ki_ntsid = elp->el_usid;
1258					kip->ki_valid |= KI_VALID_NTSID;
1259				}
1260				kip->ki_ntsid_expiry = (elp->el_usid_valid) ? tv.tv_sec + elp->el_usid_valid : 0;
1261				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_PWNAM) {
1262					const char *oname = kip->ki_name;
1263					kip->ki_name = speculative_name;
1264					speculative_name = NULL;
1265					kip->ki_valid |= KI_VALID_PWNAM;
1266					if (oname) {
1267						/*
1268						 * free oname (if any) outside
1269						 * the lock
1270						 */
1271						speculative_name = oname;
1272					}
1273				}
1274				kauth_identity_lru(kip);
1275				if (rkip != NULL)
1276					*rkip = *kip;
1277				KAUTH_DEBUG("CACHE - refreshed %d is " K_UUID_FMT, kip->ki_uid, K_UUID_ARG(kip->ki_guid));
1278				break;
1279			}
1280		}
1281		KAUTH_IDENTITY_UNLOCK();
1282		/* not found in cache, add new record */
1283		if (kip == NULL) {
1284			kip = kauth_identity_alloc(elp->el_uid, KAUTH_GID_NONE,
1285			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_UGUID) ? &elp->el_uguid : NULL,
1286			    (elp->el_uguid_valid) ? tv.tv_sec + elp->el_uguid_valid : 0,
1287			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_USID) ? &elp->el_usid : NULL,
1288			    (elp->el_usid_valid) ? tv.tv_sec + elp->el_usid_valid : 0,
1289			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_PWNAM) ? speculative_name : NULL,
1290			    KI_VALID_PWNAM);
1291			if (kip != NULL) {
1292				if (rkip != NULL)
1293					*rkip = *kip;
1294				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_PWNAM)
1295					speculative_name = NULL;
1296				KAUTH_DEBUG("CACHE - learned %d is " K_UUID_FMT, kip->ki_uid, K_UUID_ARG(kip->ki_guid));
1297				kauth_identity_register_and_free(kip);
1298			}
1299		}
1300	}
1301
1302	/* group identity? (ignore, if we already processed it as a user) */
1303	if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GID && !(elp->el_flags & KAUTH_EXTLOOKUP_VALID_UID)) {
1304		KAUTH_IDENTITY_LOCK();
1305		TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
1306			/* matching record */
1307			if ((kip->ki_valid & KI_VALID_GID) && (kip->ki_gid == elp->el_gid)) {
1308				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GGUID) {
1309					kip->ki_guid = elp->el_gguid;
1310					kip->ki_valid |= KI_VALID_GUID;
1311				}
1312				kip->ki_guid_expiry = (elp->el_gguid_valid) ? tv.tv_sec + elp->el_gguid_valid : 0;
1313				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GSID) {
1314					kip->ki_ntsid = elp->el_gsid;
1315					kip->ki_valid |= KI_VALID_NTSID;
1316				}
1317				kip->ki_ntsid_expiry = (elp->el_gsid_valid) ? tv.tv_sec + elp->el_gsid_valid : 0;
1318				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GRNAM) {
1319					const char *oname = kip->ki_name;
1320					kip->ki_name = speculative_name;
1321					speculative_name = NULL;
1322					kip->ki_valid |= KI_VALID_GRNAM;
1323					if (oname) {
1324						/*
1325						 * free oname (if any) outside
1326						 * the lock
1327						 */
1328						speculative_name = oname;
1329					}
1330				}
1331				kauth_identity_lru(kip);
1332				if (rkip != NULL)
1333					*rkip = *kip;
1334				KAUTH_DEBUG("CACHE - refreshed %d is " K_UUID_FMT, kip->ki_uid, K_UUID_ARG(kip->ki_guid));
1335				break;
1336			}
1337		}
1338		KAUTH_IDENTITY_UNLOCK();
1339		/* not found in cache, add new record */
1340		if (kip == NULL) {
1341			kip = kauth_identity_alloc(KAUTH_UID_NONE, elp->el_gid,
1342			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GGUID) ? &elp->el_gguid : NULL,
1343			    (elp->el_gguid_valid) ? tv.tv_sec + elp->el_gguid_valid : 0,
1344			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GSID) ? &elp->el_gsid : NULL,
1345			    (elp->el_gsid_valid) ? tv.tv_sec + elp->el_gsid_valid : 0,
1346			    (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GRNAM) ? speculative_name : NULL,
1347			    KI_VALID_GRNAM);
1348			if (kip != NULL) {
1349				if (rkip != NULL)
1350					*rkip = *kip;
1351				if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GRNAM)
1352					speculative_name = NULL;
1353				KAUTH_DEBUG("CACHE - learned %d is " K_UUID_FMT, kip->ki_uid, K_UUID_ARG(kip->ki_guid));
1354				kauth_identity_register_and_free(kip);
1355			}
1356		}
1357	}
1358
1359	/* If we have a name reference to drop, drop it here */
1360	if (speculative_name != NULL) {
1361		vfs_removename(speculative_name);
1362	}
1363}
1364
1365
1366/*
1367 * Trim older entries from the identity cache.
1368 *
1369 * Must be called with the identity cache lock held.
1370 */
1371static void
1372kauth_identity_trimcache(int newsize) {
1373	struct kauth_identity 		*kip;
1374
1375	lck_mtx_assert(kauth_identity_mtx, LCK_MTX_ASSERT_OWNED);
1376
1377	while (kauth_identity_count > newsize) {
1378		kip = TAILQ_LAST(&kauth_identities, kauth_identity_head);
1379		TAILQ_REMOVE(&kauth_identities, kip, ki_link);
1380		kauth_identity_count--;
1381		FREE(kip, M_KAUTH);
1382	}
1383}
1384
1385/*
1386 * kauth_identity_lru
1387 *
1388 * Description:	Promote the entry to the head of the LRU, assumes the cache
1389 *		is locked.
1390 *
1391 * Parameters:	kip				kauth identity to move to the
1392 *						head of the LRU list, if it's
1393 *						not already there
1394 *
1395 * Returns:	(void)
1396 *
1397 * Notes:	This is called even if the entry has expired; typically an
1398 *		expired entry that's been looked up is about to be revalidated,
1399 *		and having it closer to the head of the LRU means finding it
1400 *		quickly again when the revalidation comes through.
1401 */
1402static void
1403kauth_identity_lru(struct kauth_identity *kip)
1404{
1405	if (kip != TAILQ_FIRST(&kauth_identities)) {
1406		TAILQ_REMOVE(&kauth_identities, kip, ki_link);
1407		TAILQ_INSERT_HEAD(&kauth_identities, kip, ki_link);
1408	}
1409}
1410
1411
1412/*
1413 * kauth_identity_guid_expired
1414 *
1415 * Description:	Handle lazy expiration of GUID translations.
1416 *
1417 * Parameters:	kip				kauth identity to check for
1418 *						GUID expiration
1419 *
1420 * Returns:	1				Expired
1421 *		0				Not expired
1422 */
1423static int
1424kauth_identity_guid_expired(struct kauth_identity *kip)
1425{
1426	struct timeval tv;
1427
1428	/*
1429	 * Expiration time of 0 means this entry is persistent.
1430	 */
1431	if (kip->ki_guid_expiry == 0)
1432		return (0);
1433
1434	microuptime(&tv);
1435	KAUTH_DEBUG("CACHE - GUID expires @ %d now %d", kip->ki_guid_expiry, tv.tv_sec);
1436
1437	return((kip->ki_guid_expiry <= tv.tv_sec) ? 1 : 0);
1438}
1439
1440
1441/*
1442 * kauth_identity_ntsid_expired
1443 *
1444 * Description:	Handle lazy expiration of NTSID translations.
1445 *
1446 * Parameters:	kip				kauth identity to check for
1447 *						NTSID expiration
1448 *
1449 * Returns:	1				Expired
1450 *		0				Not expired
1451 */
1452static int
1453kauth_identity_ntsid_expired(struct kauth_identity *kip)
1454{
1455	struct timeval tv;
1456
1457	/*
1458	 * Expiration time of 0 means this entry is persistent.
1459	 */
1460	if (kip->ki_ntsid_expiry == 0)
1461		return (0);
1462
1463	microuptime(&tv);
1464	KAUTH_DEBUG("CACHE - NTSID expires @ %d now %d", kip->ki_ntsid_expiry, tv.tv_sec);
1465
1466	return((kip->ki_ntsid_expiry <= tv.tv_sec) ? 1 : 0);
1467}
1468
1469
1470/*
1471 * kauth_identity_find_uid
1472 *
1473 * Description: Search for an entry by UID
1474 *
1475 * Parameters:	uid				UID to find
1476 *		kir				Pointer to return area
1477 *		getname				Name buffer, if ki_name wanted
1478 *
1479 * Returns:	0				Found
1480 *		ENOENT				Not found
1481 *
1482 * Implicit returns:
1483 *		*klr				Modified, if found
1484 */
1485static int
1486kauth_identity_find_uid(uid_t uid, struct kauth_identity *kir, char *getname)
1487{
1488	struct kauth_identity *kip;
1489
1490	KAUTH_IDENTITY_LOCK();
1491	TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
1492		if ((kip->ki_valid & KI_VALID_UID) && (uid == kip->ki_uid)) {
1493			kauth_identity_lru(kip);
1494			/* Copy via structure assignment */
1495			*kir = *kip;
1496			/* If a name is wanted and one exists, copy it out */
1497			if (getname != NULL && (kip->ki_valid & (KI_VALID_PWNAM | KI_VALID_GRNAM)))
1498				strlcpy(getname, kip->ki_name, MAXPATHLEN);
1499			break;
1500		}
1501	}
1502	KAUTH_IDENTITY_UNLOCK();
1503	return((kip == NULL) ? ENOENT : 0);
1504}
1505
1506
1507/*
1508 * kauth_identity_find_gid
1509 *
1510 * Description: Search for an entry by GID
1511 *
1512 * Parameters:	gid				GID to find
1513 *		kir				Pointer to return area
1514 *		getname				Name buffer, if ki_name wanted
1515 *
1516 * Returns:	0				Found
1517 *		ENOENT				Not found
1518 *
1519 * Implicit returns:
1520 *		*klr				Modified, if found
1521 */
1522static int
1523kauth_identity_find_gid(uid_t gid, struct kauth_identity *kir, char *getname)
1524{
1525	struct kauth_identity *kip;
1526
1527	KAUTH_IDENTITY_LOCK();
1528	TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
1529		if ((kip->ki_valid & KI_VALID_GID) && (gid == kip->ki_gid)) {
1530			kauth_identity_lru(kip);
1531			/* Copy via structure assignment */
1532			*kir = *kip;
1533			/* If a name is wanted and one exists, copy it out */
1534			if (getname != NULL && (kip->ki_valid & (KI_VALID_PWNAM | KI_VALID_GRNAM)))
1535				strlcpy(getname, kip->ki_name, MAXPATHLEN);
1536			break;
1537		}
1538	}
1539	KAUTH_IDENTITY_UNLOCK();
1540	return((kip == NULL) ? ENOENT : 0);
1541}
1542
1543
1544/*
1545 * kauth_identity_find_guid
1546 *
1547 * Description: Search for an entry by GUID
1548 *
1549 * Parameters:	guidp				Pointer to GUID to find
1550 *		kir				Pointer to return area
1551 *		getname				Name buffer, if ki_name wanted
1552 *
1553 * Returns:	0				Found
1554 *		ENOENT				Not found
1555 *
1556 * Implicit returns:
1557 *		*klr				Modified, if found
1558 *
1559 * Note:	The association may be expired, in which case the caller
1560 *		may elect to call out to userland to revalidate.
1561 */
1562static int
1563kauth_identity_find_guid(guid_t *guidp, struct kauth_identity *kir, char *getname)
1564{
1565	struct kauth_identity *kip;
1566
1567	KAUTH_IDENTITY_LOCK();
1568	TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
1569		if ((kip->ki_valid & KI_VALID_GUID) && (kauth_guid_equal(guidp, &kip->ki_guid))) {
1570			kauth_identity_lru(kip);
1571			/* Copy via structure assignment */
1572			*kir = *kip;
1573			/* If a name is wanted and one exists, copy it out */
1574			if (getname != NULL && (kip->ki_valid & (KI_VALID_PWNAM | KI_VALID_GRNAM)))
1575				strlcpy(getname, kip->ki_name, MAXPATHLEN);
1576			break;
1577		}
1578	}
1579	KAUTH_IDENTITY_UNLOCK();
1580	return((kip == NULL) ? ENOENT : 0);
1581}
1582
1583/*
1584 * kauth_identity_find_nam
1585 *
1586 * Description:	Search for an entry by name
1587 *
1588 * Parameters:	name				Pointer to name to find
1589 *		valid				KI_VALID_PWNAM or KI_VALID_GRNAM
1590 *		kir				Pointer to return area
1591 *
1592 * Returns:	0				Found
1593 *		ENOENT				Not found
1594 *
1595 * Implicit returns:
1596 *		*klr				Modified, if found
1597 */
1598static int
1599kauth_identity_find_nam(char *name, int valid, struct kauth_identity *kir)
1600{
1601	struct kauth_identity *kip;
1602
1603	KAUTH_IDENTITY_LOCK();
1604	TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
1605		if ((kip->ki_valid & valid) && !strcmp(name, kip->ki_name)) {
1606			kauth_identity_lru(kip);
1607			/* Copy via structure assignment */
1608			*kir = *kip;
1609			break;
1610		}
1611	}
1612	KAUTH_IDENTITY_UNLOCK();
1613	return((kip == NULL) ? ENOENT : 0);
1614}
1615
1616
1617/*
1618 * kauth_identity_find_ntsid
1619 *
1620 * Description: Search for an entry by NTSID
1621 *
1622 * Parameters:	ntsid				Pointer to NTSID to find
1623 *		kir				Pointer to return area
1624 *		getname				Name buffer, if ki_name wanted
1625 *
1626 * Returns:	0				Found
1627 *		ENOENT				Not found
1628 *
1629 * Implicit returns:
1630 *		*klr				Modified, if found
1631 *
1632 * Note:	The association may be expired, in which case the caller
1633 *		may elect to call out to userland to revalidate.
1634 */
1635static int
1636kauth_identity_find_ntsid(ntsid_t *ntsid, struct kauth_identity *kir, char *getname)
1637{
1638	struct kauth_identity *kip;
1639
1640	KAUTH_IDENTITY_LOCK();
1641	TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
1642		if ((kip->ki_valid & KI_VALID_NTSID) && (kauth_ntsid_equal(ntsid, &kip->ki_ntsid))) {
1643			kauth_identity_lru(kip);
1644			/* Copy via structure assignment */
1645			*kir = *kip;
1646			/* If a name is wanted and one exists, copy it out */
1647			if (getname != NULL && (kip->ki_valid & (KI_VALID_PWNAM | KI_VALID_GRNAM)))
1648				strlcpy(getname, kip->ki_name, MAXPATHLEN);
1649			break;
1650		}
1651	}
1652	KAUTH_IDENTITY_UNLOCK();
1653	return((kip == NULL) ? ENOENT : 0);
1654}
1655#endif	/* CONFIG_EXT_RESOLVER */
1656
1657
1658/*
1659 * GUID handling.
1660 */
1661guid_t kauth_null_guid;
1662
1663
1664/*
1665 * kauth_guid_equal
1666 *
1667 * Description:	Determine the equality of two GUIDs
1668 *
1669 * Parameters:	guid1				Pointer to first GUID
1670 *		guid2				Pointer to second GUID
1671 *
1672 * Returns:	0				If GUIDs are unequal
1673 *		!0				If GUIDs are equal
1674 */
1675int
1676kauth_guid_equal(guid_t *guid1, guid_t *guid2)
1677{
1678	return(bcmp(guid1, guid2, sizeof(*guid1)) == 0);
1679}
1680
1681
1682/*
1683 * kauth_wellknown_guid
1684 *
1685 * Description:	Determine if a GUID is a well-known GUID
1686 *
1687 * Parameters:	guid				Pointer to GUID to check
1688 *
1689 * Returns:	KAUTH_WKG_NOT			Not a well known GUID
1690 *		KAUTH_WKG_EVERYBODY		"Everybody"
1691 *		KAUTH_WKG_NOBODY		"Nobody"
1692 *		KAUTH_WKG_OWNER			"Other"
1693 *		KAUTH_WKG_GROUP			"Group"
1694 */
1695int
1696kauth_wellknown_guid(guid_t *guid)
1697{
1698	static char	fingerprint[] = {0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef};
1699	uint32_t		code;
1700	/*
1701	 * All WKGs begin with the same 12 bytes.
1702	 */
1703	if (bcmp((void *)guid, fingerprint, 12) == 0) {
1704		/*
1705		 * The final 4 bytes are our code (in network byte order).
1706		 */
1707		code = OSSwapHostToBigInt32(*(uint32_t *)&guid->g_guid[12]);
1708		switch(code) {
1709		case 0x0000000c:
1710			return(KAUTH_WKG_EVERYBODY);
1711		case 0xfffffffe:
1712			return(KAUTH_WKG_NOBODY);
1713		case 0x0000000a:
1714			return(KAUTH_WKG_OWNER);
1715		case 0x00000010:
1716			return(KAUTH_WKG_GROUP);
1717		}
1718	}
1719	return(KAUTH_WKG_NOT);
1720}
1721
1722
1723/*
1724 * kauth_ntsid_equal
1725 *
1726 * Description:	Determine the equality of two NTSIDs (NT Security Identifiers)
1727 *
1728 * Parameters:	sid1				Pointer to first NTSID
1729 *		sid2				Pointer to second NTSID
1730 *
1731 * Returns:	0				If GUIDs are unequal
1732 *		!0				If GUIDs are equal
1733 */
1734int
1735kauth_ntsid_equal(ntsid_t *sid1, ntsid_t *sid2)
1736{
1737	/* check sizes for equality, also sanity-check size while we're at it */
1738	if ((KAUTH_NTSID_SIZE(sid1) == KAUTH_NTSID_SIZE(sid2)) &&
1739	    (KAUTH_NTSID_SIZE(sid1) <= sizeof(*sid1)) &&
1740	    bcmp(sid1, sid2, KAUTH_NTSID_SIZE(sid1)) == 0)
1741		return(1);
1742	return(0);
1743}
1744
1745
1746/*
1747 * Identity KPI
1748 *
1749 * We support four tokens representing identity:
1750 *  - Credential reference
1751 *  - UID
1752 *  - GUID
1753 *  - NT security identifier
1754 *
1755 * Of these, the UID is the ubiquitous identifier; cross-referencing should
1756 * be done using it.
1757 */
1758
1759
1760
1761/*
1762 * kauth_cred_change_egid
1763 *
1764 * Description:	Set EGID by changing the first element of cr_groups for the
1765 *		passed credential; if the new EGID exists in the list of
1766 *		groups already, then rotate the old EGID into its position,
1767 *		otherwise replace it
1768 *
1769 * Parameters:	cred			Pointer to the credential to modify
1770 *		new_egid		The new EGID to set
1771 *
1772 * Returns:	0			The egid did not displace a member of
1773 *					the supplementary group list
1774 *		1			The egid being set displaced a member
1775 *					of the supplementary groups list
1776 *
1777 * Note:	Utility function; internal use only because of locking.
1778 *
1779 *		This function operates on the credential passed; the caller
1780 *		must operate either on a newly allocated credential (one for
1781 *		which there is no hash cache reference and no externally
1782 *		visible pointer reference), or a template credential.
1783 */
1784static int
1785kauth_cred_change_egid(kauth_cred_t cred, gid_t new_egid)
1786{
1787	int	i;
1788	int	displaced = 1;
1789#if radar_4600026
1790	int	is_member;
1791#endif	/* radar_4600026 */
1792	gid_t	old_egid = kauth_cred_getgid(cred);
1793	posix_cred_t pcred = posix_cred_get(cred);
1794
1795	/* Ignoring the first entry, scan for a match for the new egid */
1796	for (i = 1; i < pcred->cr_ngroups; i++) {
1797		/*
1798		 * If we find a match, swap them so we don't lose overall
1799		 * group information
1800		 */
1801		if (pcred->cr_groups[i] == new_egid) {
1802			pcred->cr_groups[i] = old_egid;
1803			DEBUG_CRED_CHANGE("kauth_cred_change_egid: unset displaced\n");
1804			displaced = 0;
1805			break;
1806		}
1807	}
1808
1809#if radar_4600026
1810#error Fix radar 4600026 first!!!
1811
1812/*
1813This is correct for memberd behaviour, but incorrect for POSIX; to address
1814this, we would need to automatically opt-out any SUID/SGID binary, and force
1815it to use initgroups to opt back in.  We take the approach of considering it
1816opt'ed out in any group of 16 displacement instead, since it's a much more
1817conservative approach (i.e. less likely to cause things to break).
1818*/
1819
1820	/*
1821	 * If we displaced a member of the supplementary groups list of the
1822	 * credential, and we have not opted out of memberd, then if memberd
1823	 * says that the credential is a member of the group, then it has not
1824	 * actually been displaced.
1825	 *
1826	 * NB:	This is typically a cold code path.
1827	 */
1828	if (displaced && !(pcred->cr_flags & CRF_NOMEMBERD) &&
1829	    kauth_cred_ismember_gid(cred, new_egid, &is_member) == 0 &&
1830	    is_member) {
1831	    	displaced = 0;
1832		DEBUG_CRED_CHANGE("kauth_cred_change_egid: reset displaced\n");
1833	}
1834#endif	/* radar_4600026 */
1835
1836	/* set the new EGID into the old spot */
1837	pcred->cr_groups[0] = new_egid;
1838
1839	return (displaced);
1840}
1841
1842
1843/*
1844 * kauth_cred_getuid
1845 *
1846 * Description:	Fetch UID from credential
1847 *
1848 * Parameters:	cred				Credential to examine
1849 *
1850 * Returns:	(uid_t)				UID associated with credential
1851 */
1852uid_t
1853kauth_cred_getuid(kauth_cred_t cred)
1854{
1855	NULLCRED_CHECK(cred);
1856	return(posix_cred_get(cred)->cr_uid);
1857}
1858
1859
1860/*
1861 * kauth_cred_getruid
1862 *
1863 * Description:	Fetch RUID from credential
1864 *
1865 * Parameters:	cred				Credential to examine
1866 *
1867 * Returns:	(uid_t)				RUID associated with credential
1868 */
1869uid_t
1870kauth_cred_getruid(kauth_cred_t cred)
1871{
1872	NULLCRED_CHECK(cred);
1873	return(posix_cred_get(cred)->cr_ruid);
1874}
1875
1876
1877/*
1878 * kauth_cred_getsvuid
1879 *
1880 * Description:	Fetch SVUID from credential
1881 *
1882 * Parameters:	cred				Credential to examine
1883 *
1884 * Returns:	(uid_t)				SVUID associated with credential
1885 */
1886uid_t
1887kauth_cred_getsvuid(kauth_cred_t cred)
1888{
1889	NULLCRED_CHECK(cred);
1890	return(posix_cred_get(cred)->cr_svuid);
1891}
1892
1893
1894/*
1895 * kauth_cred_getgid
1896 *
1897 * Description:	Fetch GID from credential
1898 *
1899 * Parameters:	cred				Credential to examine
1900 *
1901 * Returns:	(gid_t)				GID associated with credential
1902 */
1903gid_t
1904kauth_cred_getgid(kauth_cred_t cred)
1905{
1906	NULLCRED_CHECK(cred);
1907	return(posix_cred_get(cred)->cr_gid);
1908}
1909
1910
1911/*
1912 * kauth_cred_getrgid
1913 *
1914 * Description:	Fetch RGID from credential
1915 *
1916 * Parameters:	cred				Credential to examine
1917 *
1918 * Returns:	(gid_t)				RGID associated with credential
1919 */
1920gid_t
1921kauth_cred_getrgid(kauth_cred_t cred)
1922{
1923	NULLCRED_CHECK(cred);
1924	return(posix_cred_get(cred)->cr_rgid);
1925}
1926
1927
1928/*
1929 * kauth_cred_getsvgid
1930 *
1931 * Description:	Fetch SVGID from credential
1932 *
1933 * Parameters:	cred				Credential to examine
1934 *
1935 * Returns:	(gid_t)				SVGID associated with credential
1936 */
1937gid_t
1938kauth_cred_getsvgid(kauth_cred_t cred)
1939{
1940	NULLCRED_CHECK(cred);
1941	return(posix_cred_get(cred)->cr_svgid);
1942}
1943
1944
1945static int	kauth_cred_cache_lookup(int from, int to, void *src, void *dst);
1946
1947#if CONFIG_EXT_RESOLVER == 0
1948/*
1949 * If there's no resolver, short-circuit the kauth_cred_x2y() lookups.
1950 */
1951static __inline int
1952kauth_cred_cache_lookup(__unused int from, __unused int to,
1953	__unused void *src, __unused void *dst)
1954{
1955	return (EWOULDBLOCK);
1956
1957}
1958#endif
1959
1960/*
1961 * kauth_cred_guid2pwnam
1962 *
1963 * Description:	Fetch PWNAM from GUID
1964 *
1965 * Parameters:	guidp				Pointer to GUID to examine
1966 *		pwnam				Pointer to user@domain buffer
1967 *
1968 * Returns:	0				Success
1969 *	kauth_cred_cache_lookup:EINVAL
1970 *
1971 * Implicit returns:
1972 *		*pwnam				Modified, if successful
1973 *
1974 * Notes:	pwnam is assumed to point to a buffer of MAXPATHLEN in size
1975 */
1976int
1977kauth_cred_guid2pwnam(guid_t *guidp, char *pwnam)
1978{
1979	return(kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_PWNAM, guidp, pwnam));
1980}
1981
1982
1983/*
1984 * kauth_cred_guid2grnam
1985 *
1986 * Description:	Fetch GRNAM from GUID
1987 *
1988 * Parameters:	guidp				Pointer to GUID to examine
1989 *		grnam				Pointer to group@domain buffer
1990 *
1991 * Returns:	0				Success
1992 *	kauth_cred_cache_lookup:EINVAL
1993 *
1994 * Implicit returns:
1995 *		*grnam				Modified, if successful
1996 *
1997 * Notes:	grnam is assumed to point to a buffer of MAXPATHLEN in size
1998 */
1999int
2000kauth_cred_guid2grnam(guid_t *guidp, char *grnam)
2001{
2002	return(kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_GRNAM, guidp, grnam));
2003}
2004
2005
2006/*
2007 * kauth_cred_pwnam2guid
2008 *
2009 * Description:	Fetch PWNAM from GUID
2010 *
2011 * Parameters:	pwnam				String containing user@domain
2012 *		guidp				Pointer to buffer for GUID
2013 *
2014 * Returns:	0				Success
2015 *	kauth_cred_cache_lookup:EINVAL
2016 *
2017 * Implicit returns:
2018 *		*guidp				Modified, if successful
2019 *
2020 * Notes:	pwnam should not point to a request larger than MAXPATHLEN
2021 *		bytes in size, including the NUL termination of the string.
2022 */
2023int
2024kauth_cred_pwnam2guid(char *pwnam, guid_t *guidp)
2025{
2026	return(kauth_cred_cache_lookup(KI_VALID_PWNAM, KI_VALID_GUID, pwnam, guidp));
2027}
2028
2029
2030/*
2031 * kauth_cred_grnam2guid
2032 *
2033 * Description:	Fetch GRNAM from GUID
2034 *
2035 * Parameters:	grnam				String containing group@domain
2036 *		guidp				Pointer to buffer for GUID
2037 *
2038 * Returns:	0				Success
2039 *	kauth_cred_cache_lookup:EINVAL
2040 *
2041 * Implicit returns:
2042 *		*guidp				Modified, if successful
2043 *
2044 * Notes:	grnam should not point to a request larger than MAXPATHLEN
2045 *		bytes in size, including the NUL termination of the string.
2046 */
2047int
2048kauth_cred_grnam2guid(char *grnam, guid_t *guidp)
2049{
2050	return(kauth_cred_cache_lookup(KI_VALID_GRNAM, KI_VALID_GUID, grnam, guidp));
2051}
2052
2053
2054/*
2055 * kauth_cred_guid2uid
2056 *
2057 * Description:	Fetch UID from GUID
2058 *
2059 * Parameters:	guidp				Pointer to GUID to examine
2060 *		uidp				Pointer to buffer for UID
2061 *
2062 * Returns:	0				Success
2063 *	kauth_cred_cache_lookup:EINVAL
2064 *
2065 * Implicit returns:
2066 *		*uidp				Modified, if successful
2067 */
2068int
2069kauth_cred_guid2uid(guid_t *guidp, uid_t *uidp)
2070{
2071	return(kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_UID, guidp, uidp));
2072}
2073
2074
2075/*
2076 * kauth_cred_guid2gid
2077 *
2078 * Description:	Fetch GID from GUID
2079 *
2080 * Parameters:	guidp				Pointer to GUID to examine
2081 *		gidp				Pointer to buffer for GID
2082 *
2083 * Returns:	0				Success
2084 *	kauth_cred_cache_lookup:EINVAL
2085 *
2086 * Implicit returns:
2087 *		*gidp				Modified, if successful
2088 */
2089int
2090kauth_cred_guid2gid(guid_t *guidp, gid_t *gidp)
2091{
2092	return(kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_GID, guidp, gidp));
2093}
2094
2095
2096/*
2097 * kauth_cred_ntsid2uid
2098 *
2099 * Description:	Fetch UID from NTSID
2100 *
2101 * Parameters:	sidp				Pointer to NTSID to examine
2102 *		uidp				Pointer to buffer for UID
2103 *
2104 * Returns:	0				Success
2105 *	kauth_cred_cache_lookup:EINVAL
2106 *
2107 * Implicit returns:
2108 *		*uidp				Modified, if successful
2109 */
2110int
2111kauth_cred_ntsid2uid(ntsid_t *sidp, uid_t *uidp)
2112{
2113	return(kauth_cred_cache_lookup(KI_VALID_NTSID, KI_VALID_UID, sidp, uidp));
2114}
2115
2116
2117/*
2118 * kauth_cred_ntsid2gid
2119 *
2120 * Description:	Fetch GID from NTSID
2121 *
2122 * Parameters:	sidp				Pointer to NTSID to examine
2123 *		gidp				Pointer to buffer for GID
2124 *
2125 * Returns:	0				Success
2126 *	kauth_cred_cache_lookup:EINVAL
2127 *
2128 * Implicit returns:
2129 *		*gidp				Modified, if successful
2130 */
2131int
2132kauth_cred_ntsid2gid(ntsid_t *sidp, gid_t *gidp)
2133{
2134	return(kauth_cred_cache_lookup(KI_VALID_NTSID, KI_VALID_GID, sidp, gidp));
2135}
2136
2137
2138/*
2139 * kauth_cred_ntsid2guid
2140 *
2141 * Description:	Fetch GUID from NTSID
2142 *
2143 * Parameters:	sidp				Pointer to NTSID to examine
2144 *		guidp				Pointer to buffer for GUID
2145 *
2146 * Returns:	0				Success
2147 *	kauth_cred_cache_lookup:EINVAL
2148 *
2149 * Implicit returns:
2150 *		*guidp				Modified, if successful
2151 */
2152int
2153kauth_cred_ntsid2guid(ntsid_t *sidp, guid_t *guidp)
2154{
2155	return(kauth_cred_cache_lookup(KI_VALID_NTSID, KI_VALID_GUID, sidp, guidp));
2156}
2157
2158
2159/*
2160 * kauth_cred_uid2guid
2161 *
2162 * Description:	Fetch GUID from UID
2163 *
2164 * Parameters:	uid				UID to examine
2165 *		guidp				Pointer to buffer for GUID
2166 *
2167 * Returns:	0				Success
2168 *	kauth_cred_cache_lookup:EINVAL
2169 *
2170 * Implicit returns:
2171 *		*guidp				Modified, if successful
2172 */
2173int
2174kauth_cred_uid2guid(uid_t uid, guid_t *guidp)
2175{
2176	return(kauth_cred_cache_lookup(KI_VALID_UID, KI_VALID_GUID, &uid, guidp));
2177}
2178
2179
2180/*
2181 * kauth_cred_getguid
2182 *
2183 * Description:	Fetch GUID from credential
2184 *
2185 * Parameters:	cred				Credential to examine
2186 *		guidp				Pointer to buffer for GUID
2187 *
2188 * Returns:	0				Success
2189 *	kauth_cred_cache_lookup:EINVAL
2190 *
2191 * Implicit returns:
2192 *		*guidp				Modified, if successful
2193 */
2194int
2195kauth_cred_getguid(kauth_cred_t cred, guid_t *guidp)
2196{
2197	NULLCRED_CHECK(cred);
2198	return(kauth_cred_uid2guid(kauth_cred_getuid(cred), guidp));
2199}
2200
2201
2202/*
2203 * kauth_cred_getguid
2204 *
2205 * Description:	Fetch GUID from GID
2206 *
2207 * Parameters:	gid				GID to examine
2208 *		guidp				Pointer to buffer for GUID
2209 *
2210 * Returns:	0				Success
2211 *	kauth_cred_cache_lookup:EINVAL
2212 *
2213 * Implicit returns:
2214 *		*guidp				Modified, if successful
2215 */
2216int
2217kauth_cred_gid2guid(gid_t gid, guid_t *guidp)
2218{
2219	return(kauth_cred_cache_lookup(KI_VALID_GID, KI_VALID_GUID, &gid, guidp));
2220}
2221
2222
2223/*
2224 * kauth_cred_uid2ntsid
2225 *
2226 * Description:	Fetch NTSID from UID
2227 *
2228 * Parameters:	uid				UID to examine
2229 *		sidp				Pointer to buffer for NTSID
2230 *
2231 * Returns:	0				Success
2232 *	kauth_cred_cache_lookup:EINVAL
2233 *
2234 * Implicit returns:
2235 *		*sidp				Modified, if successful
2236 */
2237int
2238kauth_cred_uid2ntsid(uid_t uid, ntsid_t *sidp)
2239{
2240	return(kauth_cred_cache_lookup(KI_VALID_UID, KI_VALID_NTSID, &uid, sidp));
2241}
2242
2243
2244/*
2245 * kauth_cred_getntsid
2246 *
2247 * Description:	Fetch NTSID from credential
2248 *
2249 * Parameters:	cred				Credential to examine
2250 *		sidp				Pointer to buffer for NTSID
2251 *
2252 * Returns:	0				Success
2253 *	kauth_cred_cache_lookup:EINVAL
2254 *
2255 * Implicit returns:
2256 *		*sidp				Modified, if successful
2257 */
2258int
2259kauth_cred_getntsid(kauth_cred_t cred, ntsid_t *sidp)
2260{
2261	NULLCRED_CHECK(cred);
2262	return(kauth_cred_uid2ntsid(kauth_cred_getuid(cred), sidp));
2263}
2264
2265
2266/*
2267 * kauth_cred_gid2ntsid
2268 *
2269 * Description:	Fetch NTSID from GID
2270 *
2271 * Parameters:	gid				GID to examine
2272 *		sidp				Pointer to buffer for NTSID
2273 *
2274 * Returns:	0				Success
2275 *	kauth_cred_cache_lookup:EINVAL
2276 *
2277 * Implicit returns:
2278 *		*sidp				Modified, if successful
2279 */
2280int
2281kauth_cred_gid2ntsid(gid_t gid, ntsid_t *sidp)
2282{
2283	return(kauth_cred_cache_lookup(KI_VALID_GID, KI_VALID_NTSID, &gid, sidp));
2284}
2285
2286
2287/*
2288 * kauth_cred_guid2ntsid
2289 *
2290 * Description:	Fetch NTSID from GUID
2291 *
2292 * Parameters:	guidp				Pointer to GUID to examine
2293 *		sidp				Pointer to buffer for NTSID
2294 *
2295 * Returns:	0				Success
2296 *	kauth_cred_cache_lookup:EINVAL
2297 *
2298 * Implicit returns:
2299 *		*sidp				Modified, if successful
2300 */
2301int
2302kauth_cred_guid2ntsid(guid_t *guidp, ntsid_t *sidp)
2303{
2304	return(kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_NTSID, guidp, sidp));
2305}
2306
2307
2308/*
2309 * kauth_cred_cache_lookup
2310 *
2311 * Description:	Lookup a translation in the cache; if one is not found, and
2312 *		the attempt was not fatal, submit the request to the resolver
2313 *		instead, and wait for it to complete or be aborted.
2314 *
2315 * Parameters:	from				Identity information we have
2316 *		to				Identity information we want
2317 *		src				Pointer to buffer containing
2318 *						the source identity
2319 *		dst				Pointer to buffer to receive
2320 *						the target identity
2321 *
2322 * Returns:	0				Success
2323 *		EINVAL				Unknown source identity type
2324 */
2325#if CONFIG_EXT_RESOLVER
2326static int
2327kauth_cred_cache_lookup(int from, int to, void *src, void *dst)
2328{
2329	struct kauth_identity ki;
2330	struct kauth_identity_extlookup el;
2331	int error;
2332	uint64_t extend_data = 0ULL;
2333	int (* expired)(struct kauth_identity *kip);
2334	char *namebuf = NULL;
2335
2336	KAUTH_DEBUG("CACHE - translate %d to %d", from, to);
2337
2338	/*
2339	 * Look for an existing cache entry for this association.
2340	 * If the entry has not expired, return the cached information.
2341	 * We do not cache user@domain translations here; they use too
2342	 * much memory to hold onto forever, and can not be updated
2343	 * atomically.
2344	 */
2345	if (to == KI_VALID_PWNAM || to == KI_VALID_GRNAM) {
2346		namebuf = dst;
2347	}
2348	ki.ki_valid = 0;
2349	switch(from) {
2350	case KI_VALID_UID:
2351		error = kauth_identity_find_uid(*(uid_t *)src, &ki, namebuf);
2352		break;
2353	case KI_VALID_GID:
2354		error = kauth_identity_find_gid(*(gid_t *)src, &ki, namebuf);
2355		break;
2356	case KI_VALID_GUID:
2357		error = kauth_identity_find_guid((guid_t *)src, &ki, namebuf);
2358		break;
2359	case KI_VALID_NTSID:
2360		error = kauth_identity_find_ntsid((ntsid_t *)src, &ki, namebuf);
2361		break;
2362	case KI_VALID_PWNAM:
2363	case KI_VALID_GRNAM:
2364		/* Names are unique in their 'from' space */
2365		error = kauth_identity_find_nam((char *)src, from, &ki);
2366		break;
2367	default:
2368		return(EINVAL);
2369	}
2370	/* lookup failure or error */
2371	if (error != 0) {
2372		/* any other error is fatal */
2373		if (error != ENOENT) {
2374			/* XXX bogus check - this is not possible */
2375			KAUTH_DEBUG("CACHE - cache search error %d", error);
2376			return(error);
2377		}
2378	} else {
2379		/* found a valid cached entry, check expiry */
2380		switch(to) {
2381		case KI_VALID_GUID:
2382			expired = kauth_identity_guid_expired;
2383			break;
2384		case KI_VALID_NTSID:
2385			expired = kauth_identity_ntsid_expired;
2386			break;
2387		default:
2388			switch(from) {
2389			case KI_VALID_GUID:
2390				expired = kauth_identity_guid_expired;
2391				break;
2392			case KI_VALID_NTSID:
2393				expired = kauth_identity_ntsid_expired;
2394				break;
2395			default:
2396				expired = NULL;
2397			}
2398		}
2399
2400		/*
2401		 * If no expiry function, or not expired, we have found
2402		 * a hit.
2403		 */
2404		if (expired) {
2405			if (!expired(&ki)) {
2406				KAUTH_DEBUG("CACHE - entry valid, unexpired");
2407				expired = NULL; /* must clear it is used as a flag */
2408			} else {
2409				/*
2410				 * We leave ki_valid set here; it contains a
2411				 * translation but the TTL has expired.  If we can't
2412				 * get a result from the resolver, we will use it as
2413				 * a better-than nothing alternative.
2414				 */
2415
2416				KAUTH_DEBUG("CACHE - expired entry found");
2417			}
2418		} else {
2419			KAUTH_DEBUG("CACHE - no expiry function");
2420		}
2421
2422		if (!expired) {
2423			/* do we have a translation? */
2424			if (ki.ki_valid & to) {
2425				KAUTH_DEBUG("CACHE - found matching entry with valid 0x%08x", ki.ki_valid);
2426				DTRACE_PROC4(kauth__identity__cache__hit, int, from, int, to, void *, src, void *, dst);
2427				goto found;
2428			} else {
2429				/*
2430				 * GUIDs and NTSIDs map to either a UID or a GID, but not both.
2431				 * If we went looking for a translation from GUID or NTSID and
2432				 * found a translation that wasn't for our desired type, then
2433				 * don't bother calling the resolver. We know that this
2434				 * GUID/NTSID can't translate to our desired type.
2435				 */
2436				switch(from) {
2437				case KI_VALID_GUID:
2438				case KI_VALID_NTSID:
2439					switch(to) {
2440					case KI_VALID_GID:
2441						if ((ki.ki_valid & KI_VALID_UID)) {
2442							KAUTH_DEBUG("CACHE - unexpected entry 0x%08x & %x", ki.ki_valid, KI_VALID_GID);
2443							return (ENOENT);
2444						}
2445						break;
2446					case KI_VALID_UID:
2447						if ((ki.ki_valid & KI_VALID_GID)) {
2448							KAUTH_DEBUG("CACHE - unexpected entry 0x%08x & %x", ki.ki_valid, KI_VALID_UID);
2449							return (ENOENT);
2450						}
2451						break;
2452					}
2453					break;
2454				}
2455			}
2456		}
2457	}
2458
2459	/*
2460	 * We failed to find a cache entry; call the resolver.
2461	 *
2462	 * Note:	We ask for as much non-extended data as we can get,
2463	 *		and only provide (or ask for) extended information if
2464	 *		we have a 'from' (or 'to') which requires it.  This
2465	 *		way we don't pay for the extra transfer overhead for
2466	 *		data we don't need.
2467	 */
2468	bzero(&el, sizeof(el));
2469	el.el_info_pid = current_proc()->p_pid;
2470	switch(from) {
2471	case KI_VALID_UID:
2472		el.el_flags = KAUTH_EXTLOOKUP_VALID_UID;
2473		el.el_uid = *(uid_t *)src;
2474		break;
2475	case KI_VALID_GID:
2476		el.el_flags = KAUTH_EXTLOOKUP_VALID_GID;
2477		el.el_gid = *(gid_t *)src;
2478		break;
2479	case KI_VALID_GUID:
2480		el.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID;
2481		el.el_uguid = *(guid_t *)src;
2482		el.el_gguid = *(guid_t *)src;
2483		break;
2484	case KI_VALID_NTSID:
2485		el.el_flags = KAUTH_EXTLOOKUP_VALID_USID | KAUTH_EXTLOOKUP_VALID_GSID;
2486		el.el_usid = *(ntsid_t *)src;
2487		el.el_gsid = *(ntsid_t *)src;
2488		break;
2489	case KI_VALID_PWNAM:
2490		/* extra overhead */
2491		el.el_flags = KAUTH_EXTLOOKUP_VALID_PWNAM;
2492		extend_data = CAST_USER_ADDR_T(src);
2493		break;
2494	case KI_VALID_GRNAM:
2495		/* extra overhead */
2496		el.el_flags = KAUTH_EXTLOOKUP_VALID_GRNAM;
2497		extend_data = CAST_USER_ADDR_T(src);
2498		break;
2499	default:
2500		return(EINVAL);
2501	}
2502	/*
2503	 * Here we ask for everything all at once, to avoid having to work
2504	 * out what we really want now, or might want soon.
2505	 *
2506	 * Asking for SID translations when we don't know we need them right
2507	 * now is going to cause excess work to be done if we're connected
2508	 * to a network that thinks it can translate them.  This list needs
2509	 * to get smaller/smarter.
2510	 */
2511	el.el_flags |= KAUTH_EXTLOOKUP_WANT_UID | KAUTH_EXTLOOKUP_WANT_GID |
2512	    KAUTH_EXTLOOKUP_WANT_UGUID | KAUTH_EXTLOOKUP_WANT_GGUID |
2513	    KAUTH_EXTLOOKUP_WANT_USID | KAUTH_EXTLOOKUP_WANT_GSID;
2514	if (to == KI_VALID_PWNAM) {
2515		/* extra overhead */
2516		el.el_flags |= KAUTH_EXTLOOKUP_WANT_PWNAM;
2517		extend_data = CAST_USER_ADDR_T(dst);
2518	}
2519	if (to == KI_VALID_GRNAM) {
2520		/* extra overhead */
2521		el.el_flags |= KAUTH_EXTLOOKUP_WANT_GRNAM;
2522		extend_data = CAST_USER_ADDR_T(dst);
2523	}
2524
2525	/* Call resolver */
2526	KAUTH_DEBUG("CACHE - calling resolver for %x", el.el_flags);
2527
2528	DTRACE_PROC3(kauth__id__resolver__submitted, int, from, int, to, uintptr_t, src);
2529
2530	error = kauth_resolver_submit(&el, extend_data);
2531
2532	KAUTH_DEBUG("CACHE - resolver returned %d", error);
2533
2534	/* was the external lookup successful? */
2535	if (error == 0) {
2536		/*
2537		 * Save the results from the lookup - we may have other
2538		 * information, even if we didn't get a guid or the
2539		 * extended data.
2540		 *
2541		 * If we came from a name, we know the extend_data is valid.
2542		 */
2543		if (from == KI_VALID_PWNAM)
2544			el.el_flags |= KAUTH_EXTLOOKUP_VALID_PWNAM;
2545		else if (from == KI_VALID_GRNAM)
2546			el.el_flags |= KAUTH_EXTLOOKUP_VALID_GRNAM;
2547
2548		kauth_identity_updatecache(&el, &ki, extend_data);
2549
2550		/*
2551		 * Check to see if we have a valid cache entry
2552		 * originating from the result.
2553		 */
2554		if (!(ki.ki_valid & to)) {
2555			error = ENOENT;
2556		}
2557	}
2558	if (error)
2559		return(error);
2560found:
2561	/*
2562	 * Copy from the appropriate struct kauth_identity cache entry
2563	 * structure into the destination buffer area.
2564	 */
2565	switch(to) {
2566	case KI_VALID_UID:
2567		*(uid_t *)dst = ki.ki_uid;
2568		break;
2569	case KI_VALID_GID:
2570		*(gid_t *)dst = ki.ki_gid;
2571		break;
2572	case KI_VALID_GUID:
2573		*(guid_t *)dst = ki.ki_guid;
2574		break;
2575	case KI_VALID_NTSID:
2576		*(ntsid_t *)dst = ki.ki_ntsid;
2577		break;
2578	case KI_VALID_PWNAM:
2579	case KI_VALID_GRNAM:
2580		/* handled in kauth_resolver_complete() */
2581		break;
2582	default:
2583		return(EINVAL);
2584	}
2585	KAUTH_DEBUG("CACHE - returned successfully");
2586	return(0);
2587}
2588
2589
2590/*
2591 * Group membership cache.
2592 *
2593 * XXX the linked-list implementation here needs to be optimized.
2594 */
2595
2596/*
2597 * kauth_groups_init
2598 *
2599 * Description:	Initialize the groups cache
2600 *
2601 * Parameters:	(void)
2602 *
2603 * Returns:	(void)
2604 *
2605 * Notes:	Initialize the groups cache for use; the group cache is used
2606 *		to avoid unnecessary calls out to user space.
2607 *
2608 *		This function is called from kauth_init() in the file
2609 *		kern_authorization.c.
2610 */
2611void
2612kauth_groups_init(void)
2613{
2614	TAILQ_INIT(&kauth_groups);
2615	kauth_groups_mtx = lck_mtx_alloc_init(kauth_lck_grp, 0/*LCK_ATTR_NULL*/);
2616}
2617
2618
2619/*
2620 * kauth_groups_expired
2621 *
2622 * Description:	Handle lazy expiration of group membership cache entries
2623 *
2624 * Parameters:	gm				group membership entry to
2625 *						check for expiration
2626 *
2627 * Returns:	1				Expired
2628 *		0				Not expired
2629 */
2630static int
2631kauth_groups_expired(struct kauth_group_membership *gm)
2632{
2633	struct timeval tv;
2634
2635	/*
2636	 * Expiration time of 0 means this entry is persistent.
2637	 */
2638	if (gm->gm_expiry == 0)
2639		return (0);
2640
2641	microuptime(&tv);
2642
2643	return((gm->gm_expiry <= tv.tv_sec) ? 1 : 0);
2644}
2645
2646
2647/*
2648 * kauth_groups_lru
2649 *
2650 * Description:	Promote the entry to the head of the LRU, assumes the cache
2651 *		is locked.
2652 *
2653 * Parameters:	kip				group membership entry to move
2654 *						to the head of the LRU list,
2655 *						if it's not already there
2656 *
2657 * Returns:	(void)
2658 *
2659 * Notes:	This is called even if the entry has expired; typically an
2660 *		expired entry that's been looked up is about to be revalidated,
2661 *		and having it closer to the head of the LRU means finding it
2662 *		quickly again when the revalidation comes through.
2663 */
2664static void
2665kauth_groups_lru(struct kauth_group_membership *gm)
2666{
2667	if (gm != TAILQ_FIRST(&kauth_groups)) {
2668		TAILQ_REMOVE(&kauth_groups, gm, gm_link);
2669		TAILQ_INSERT_HEAD(&kauth_groups, gm, gm_link);
2670	}
2671}
2672
2673
2674/*
2675 * kauth_groups_updatecache
2676 *
2677 * Description:	Given a lookup result, add any group cache associations that
2678 *		we don't currently have.
2679 *
2680 * Parameters:	elp				External lookup result from
2681 *						user space daemon to kernel
2682 *		rkip				pointer to returned kauth
2683 *						identity, or NULL
2684 *
2685 * Returns:	(void)
2686 */
2687static void
2688kauth_groups_updatecache(struct kauth_identity_extlookup *el)
2689{
2690	struct kauth_group_membership *gm;
2691	struct timeval tv;
2692
2693	/* need a valid response if we are to cache anything */
2694	if ((el->el_flags &
2695		(KAUTH_EXTLOOKUP_VALID_UID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_VALID_MEMBERSHIP)) !=
2696	    (KAUTH_EXTLOOKUP_VALID_UID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_VALID_MEMBERSHIP))
2697		return;
2698
2699	microuptime(&tv);
2700
2701	/*
2702	 * Search for an existing record for this association before inserting
2703	 * a new one; if we find one, update it instead of creating a new one
2704	 */
2705	KAUTH_GROUPS_LOCK();
2706	TAILQ_FOREACH(gm, &kauth_groups, gm_link) {
2707		if ((el->el_uid == gm->gm_uid) &&
2708		    (el->el_gid == gm->gm_gid)) {
2709			if (el->el_flags & KAUTH_EXTLOOKUP_ISMEMBER) {
2710				gm->gm_flags |= KAUTH_GROUP_ISMEMBER;
2711			} else {
2712				gm->gm_flags &= ~KAUTH_GROUP_ISMEMBER;
2713			}
2714			gm->gm_expiry = (el->el_member_valid) ? el->el_member_valid + tv.tv_sec : 0;
2715			kauth_groups_lru(gm);
2716			break;
2717		}
2718	}
2719	KAUTH_GROUPS_UNLOCK();
2720
2721	/* if we found an entry to update, stop here */
2722	if (gm != NULL)
2723		return;
2724
2725	/* allocate a new record */
2726	MALLOC(gm, struct kauth_group_membership *, sizeof(*gm), M_KAUTH, M_WAITOK);
2727	if (gm != NULL) {
2728		gm->gm_uid = el->el_uid;
2729		gm->gm_gid = el->el_gid;
2730		if (el->el_flags & KAUTH_EXTLOOKUP_ISMEMBER) {
2731			gm->gm_flags |= KAUTH_GROUP_ISMEMBER;
2732		} else {
2733			gm->gm_flags &= ~KAUTH_GROUP_ISMEMBER;
2734		}
2735		gm->gm_expiry = (el->el_member_valid) ? el->el_member_valid + tv.tv_sec : 0;
2736	}
2737
2738	/*
2739	 * Insert the new entry.  Note that it's possible to race ourselves
2740	 * here and end up with duplicate entries in the list.  Wasteful, but
2741	 * harmless since the first into the list will never be looked up,
2742	 * and thus will eventually just fall off the end.
2743	 */
2744	KAUTH_GROUPS_LOCK();
2745	TAILQ_INSERT_HEAD(&kauth_groups, gm, gm_link);
2746	if (++kauth_groups_count > kauth_groups_cachemax) {
2747		gm = TAILQ_LAST(&kauth_groups, kauth_groups_head);
2748		TAILQ_REMOVE(&kauth_groups, gm, gm_link);
2749		kauth_groups_count--;
2750	} else {
2751		gm = NULL;
2752	}
2753	KAUTH_GROUPS_UNLOCK();
2754
2755	/* free expired cache entry */
2756	if (gm != NULL)
2757		FREE(gm, M_KAUTH);
2758}
2759
2760/*
2761 * Trim older entries from the group membership cache.
2762 *
2763 * Must be called with the group cache lock held.
2764 */
2765static void
2766kauth_groups_trimcache(int new_size) {
2767        struct kauth_group_membership *gm;
2768
2769	lck_mtx_assert(kauth_groups_mtx, LCK_MTX_ASSERT_OWNED);
2770
2771	while (kauth_groups_count > new_size) {
2772		gm = TAILQ_LAST(&kauth_groups, kauth_groups_head);
2773		TAILQ_REMOVE(&kauth_groups, gm, gm_link);
2774		kauth_groups_count--;
2775		FREE(gm, M_KAUTH);
2776	}
2777}
2778#endif	/* CONFIG_EXT_RESOLVER */
2779
2780/*
2781 * Group membership KPI
2782 */
2783
2784/*
2785 * kauth_cred_ismember_gid
2786 *
2787 * Description:	Given a credential and a GID, determine if the GID is a member
2788 *		of one of the supplementary groups associated with the given
2789 *		credential
2790 *
2791 * Parameters:	cred				Credential to check in
2792 *		gid				GID to check for membership
2793 *		resultp				Pointer to int to contain the
2794 *						result of the call
2795 *
2796 * Returns:	0				Success
2797 *		ENOENT				Could not perform lookup
2798 *	kauth_resolver_submit:EWOULDBLOCK
2799 *	kauth_resolver_submit:EINTR
2800 *	kauth_resolver_submit:ENOMEM
2801 *	kauth_resolver_submit:ENOENT		User space daemon did not vend
2802 *						this credential.
2803 *	kauth_resolver_submit:???		Unlikely error from user space
2804 *
2805 * Implicit returns:
2806 *		*resultp (modified)	1	Is member
2807 *					0	Is not member
2808 *
2809 * Notes:	This function guarantees not to modify resultp when returning
2810 *		an error.
2811 *
2812 *		This function effectively checks the EGID as well, since the
2813 *		EGID is cr_groups[0] as an implementation detail.
2814 */
2815int
2816kauth_cred_ismember_gid(kauth_cred_t cred, gid_t gid, int *resultp)
2817{
2818	posix_cred_t pcred = posix_cred_get(cred);
2819	int i;
2820
2821	/*
2822	 * Check the per-credential list of override groups.
2823	 *
2824	 * We can conditionalise this on cred->cr_gmuid == KAUTH_UID_NONE since
2825	 * the cache should be used for that case.
2826	 */
2827	for (i = 0; i < pcred->cr_ngroups; i++) {
2828		if (gid == pcred->cr_groups[i]) {
2829			*resultp = 1;
2830			return(0);
2831		}
2832	}
2833
2834	/*
2835	 * If we don't have a UID for group membership checks, the in-cred list
2836	 * was authoritative and we can stop here.
2837	 */
2838	if (pcred->cr_gmuid == KAUTH_UID_NONE) {
2839		*resultp = 0;
2840		return(0);
2841	}
2842
2843#if CONFIG_EXT_RESOLVER
2844	struct kauth_group_membership *gm;
2845	struct kauth_identity_extlookup el;
2846	int error;
2847
2848	/*
2849	 * If the resolver hasn't checked in yet, we are early in the boot
2850	 * phase and the local group list is complete and authoritative.
2851	 */
2852	if (!kauth_resolver_registered) {
2853		*resultp = 0;
2854		return(0);
2855	}
2856
2857	/* TODO: */
2858	/* XXX check supplementary groups */
2859	/* XXX check whiteout groups */
2860	/* XXX nesting of supplementary/whiteout groups? */
2861
2862	/*
2863	 * Check the group cache.
2864	 */
2865	KAUTH_GROUPS_LOCK();
2866	TAILQ_FOREACH(gm, &kauth_groups, gm_link) {
2867		if ((gm->gm_uid == pcred->cr_gmuid) && (gm->gm_gid == gid) && !kauth_groups_expired(gm)) {
2868			kauth_groups_lru(gm);
2869			break;
2870		}
2871	}
2872
2873	/* did we find a membership entry? */
2874	if (gm != NULL)
2875		*resultp = (gm->gm_flags & KAUTH_GROUP_ISMEMBER) ? 1 : 0;
2876	KAUTH_GROUPS_UNLOCK();
2877
2878	/* if we did, we can return now */
2879	if (gm != NULL) {
2880		DTRACE_PROC2(kauth__group__cache__hit, int, pcred->cr_gmuid, int, gid);
2881		return(0);
2882	}
2883
2884	/* nothing in the cache, need to go to userland */
2885	bzero(&el, sizeof(el));
2886	el.el_info_pid = current_proc()->p_pid;
2887	el.el_flags = KAUTH_EXTLOOKUP_VALID_UID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP;
2888	el.el_uid = pcred->cr_gmuid;
2889	el.el_gid = gid;
2890	el.el_member_valid = 0;		/* XXX set by resolver? */
2891
2892	DTRACE_PROC2(kauth__group__resolver__submitted, int, el.el_uid, int, el.el_gid);
2893
2894	error = kauth_resolver_submit(&el, 0ULL);
2895
2896	DTRACE_PROC2(kauth__group__resolver__returned, int, error, int, el.el_flags);
2897
2898	if (error != 0)
2899		return(error);
2900	/* save the results from the lookup */
2901	kauth_groups_updatecache(&el);
2902
2903	/* if we successfully ascertained membership, report */
2904	if (el.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) {
2905		*resultp = (el.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) ? 1 : 0;
2906		return(0);
2907	}
2908
2909	return(ENOENT);
2910#else
2911	*resultp = 0;
2912	return(0);
2913#endif
2914}
2915
2916/*
2917 * kauth_cred_ismember_guid
2918 *
2919 * Description:	Determine whether the supplied credential is a member of the
2920 *		group nominated by GUID.
2921 *
2922 * Parameters:	cred				Credential to check in
2923 *		guidp				Pointer to GUID whose group
2924 *						we are testing for membership
2925 *		resultp				Pointer to int to contain the
2926 *						result of the call
2927 *
2928 * Returns:	0				Success
2929 *	kauth_cred_guid2gid:EINVAL
2930 *	kauth_cred_ismember_gid:ENOENT
2931 *	kauth_resolver_submit:ENOENT		User space daemon did not vend
2932 *						this credential.
2933 *	kauth_cred_ismember_gid:EWOULDBLOCK
2934 *	kauth_cred_ismember_gid:EINTR
2935 *	kauth_cred_ismember_gid:ENOMEM
2936 *	kauth_cred_ismember_gid:???		Unlikely error from user space
2937 *
2938 * Implicit returns:
2939 *		*resultp (modified)	1	Is member
2940 *					0	Is not member
2941 */
2942int
2943kauth_cred_ismember_guid(__unused kauth_cred_t cred, guid_t *guidp, int *resultp)
2944{
2945	int error = 0;
2946
2947	switch (kauth_wellknown_guid(guidp)) {
2948	case KAUTH_WKG_NOBODY:
2949		*resultp = 0;
2950		break;
2951	case KAUTH_WKG_EVERYBODY:
2952		*resultp = 1;
2953		break;
2954	default:
2955#if CONFIG_EXT_RESOLVER
2956	{
2957		struct kauth_identity ki;
2958		gid_t gid;
2959#if 6603280
2960		/*
2961		 * Grovel the identity cache looking for this GUID.
2962		 * If we find it, and it is for a user record, return
2963		 * false because it's not a group.
2964		 *
2965		 * This is necessary because we don't have -ve caching
2966		 * of group memberships, and we really want to avoid
2967		 * calling out to the resolver if at all possible.
2968		 *
2969		 * Because we're called by the ACL evaluator, and the
2970		 * ACL evaluator is likely to encounter ACEs for users,
2971		 * this is expected to be a common case.
2972		 */
2973		ki.ki_valid = 0;
2974		if ((error = kauth_identity_find_guid(guidp, &ki, NULL)) == 0 &&
2975		    !kauth_identity_guid_expired(&ki)) {
2976			if (ki.ki_valid & KI_VALID_GID) {
2977				/* It's a group after all... */
2978				gid = ki.ki_gid;
2979				goto do_check;
2980			}
2981			if (ki.ki_valid & KI_VALID_UID) {
2982				*resultp = 0;
2983				return (0);
2984			}
2985		}
2986#endif /* 6603280 */
2987		/*
2988		 * Attempt to translate the GUID to a GID.  Even if
2989		 * this fails, we will have primed the cache if it is
2990		 * a user record and we'll see it above the next time
2991		 * we're asked.
2992		 */
2993		if ((error = kauth_cred_guid2gid(guidp, &gid)) != 0) {
2994			/*
2995			 * If we have no guid -> gid translation, it's not a group and
2996			 * thus the cred can't be a member.
2997			 */
2998			if (error == ENOENT) {
2999				*resultp = 0;
3000				error = 0;
3001			}
3002		} else {
3003 do_check:
3004			error = kauth_cred_ismember_gid(cred, gid, resultp);
3005		}
3006	}
3007#else	/* CONFIG_EXT_RESOLVER */
3008		error = ENOENT;
3009#endif	/* CONFIG_EXT_RESOLVER */
3010		break;
3011	}
3012	return(error);
3013}
3014
3015/*
3016 * kauth_cred_gid_subset
3017 *
3018 * Description:	Given two credentials, determine if all GIDs associated with
3019 * 		the first are also associated with the second
3020 *
3021 * Parameters:	cred1				Credential to check for
3022 * 		cred2				Credential to check in
3023 *		resultp				Pointer to int to contain the
3024 *						result of the call
3025 *
3026 * Returns:	0				Success
3027 *		non-zero			See kauth_cred_ismember_gid for
3028 *						error codes
3029 *
3030 * Implicit returns:
3031 *		*resultp (modified)	1	Is subset
3032 *					0	Is not subset
3033 *
3034 * Notes:	This function guarantees not to modify resultp when returning
3035 *		an error.
3036 */
3037int
3038kauth_cred_gid_subset(kauth_cred_t cred1, kauth_cred_t cred2, int *resultp)
3039{
3040	int i, err, res = 1;
3041	gid_t gid;
3042	posix_cred_t pcred1 = posix_cred_get(cred1);
3043	posix_cred_t pcred2 = posix_cred_get(cred2);
3044
3045	/* First, check the local list of groups */
3046	for (i = 0; i < pcred1->cr_ngroups; i++) {
3047		gid = pcred1->cr_groups[i];
3048		if ((err = kauth_cred_ismember_gid(cred2, gid, &res)) != 0) {
3049			return err;
3050		}
3051
3052		if (!res && gid != pcred2->cr_rgid && gid != pcred2->cr_svgid) {
3053			*resultp = 0;
3054			return 0;
3055		}
3056	}
3057
3058	/* Check real gid */
3059	if ((err = kauth_cred_ismember_gid(cred2, pcred1->cr_rgid, &res)) != 0) {
3060		return err;
3061	}
3062
3063	if (!res && pcred1->cr_rgid != pcred2->cr_rgid &&
3064			pcred1->cr_rgid != pcred2->cr_svgid) {
3065		*resultp = 0;
3066		return 0;
3067	}
3068
3069	/* Finally, check saved gid */
3070	if ((err = kauth_cred_ismember_gid(cred2, pcred1->cr_svgid, &res)) != 0){
3071		return err;
3072	}
3073
3074	if (!res && pcred1->cr_svgid != pcred2->cr_rgid &&
3075			pcred1->cr_svgid != pcred2->cr_svgid) {
3076		*resultp = 0;
3077		return 0;
3078	}
3079
3080	*resultp = 1;
3081	return 0;
3082}
3083
3084
3085/*
3086 * kauth_cred_issuser
3087 *
3088 * Description:	Fast replacement for issuser()
3089 *
3090 * Parameters:	cred				Credential to check for super
3091 *						user privileges
3092 *
3093 * Returns:	0				Not super user
3094 *		!0				Is super user
3095 *
3096 * Notes:	This function uses a magic number which is not a manifest
3097 *		constant; this is bad practice.
3098 */
3099int
3100kauth_cred_issuser(kauth_cred_t cred)
3101{
3102	return(kauth_cred_getuid(cred) == 0);
3103}
3104
3105
3106/*
3107 * Credential KPI
3108 */
3109
3110/* lock protecting credential hash table */
3111static lck_mtx_t *kauth_cred_hash_mtx;
3112#define KAUTH_CRED_HASH_LOCK()		lck_mtx_lock(kauth_cred_hash_mtx);
3113#define KAUTH_CRED_HASH_UNLOCK()	lck_mtx_unlock(kauth_cred_hash_mtx);
3114#if KAUTH_CRED_HASH_DEBUG
3115#define KAUTH_CRED_HASH_LOCK_ASSERT()	lck_mtx_assert(kauth_cred_hash_mtx, LCK_MTX_ASSERT_OWNED)
3116#else	/* !KAUTH_CRED_HASH_DEBUG */
3117#define KAUTH_CRED_HASH_LOCK_ASSERT()
3118#endif	/* !KAUTH_CRED_HASH_DEBUG */
3119
3120
3121/*
3122 * kauth_cred_init
3123 *
3124 * Description:	Initialize the credential hash cache
3125 *
3126 * Parameters:	(void)
3127 *
3128 * Returns:	(void)
3129 *
3130 * Notes:	Intialize the credential hash cache for use; the credential
3131 *		hash cache is used convert duplicate credentials into a
3132 *		single reference counted credential in order to save wired
3133 *		kernel memory.  In practice, this generally means a desktop
3134 *		system runs with a few tens of credentials, instead of one
3135 *		per process, one per thread, one per vnode cache entry, and
3136 *		so on.  This generally results in savings of 200K or more
3137 *		(potentially much more on server systems).
3138 *
3139 *		The hash cache internally has a reference on the credential
3140 *		for itself as a means of avoiding a reclaim race for a
3141 *		credential in the process of having it's last non-hash
3142 *		reference released.  This would otherwise result in the
3143 *		possibility of a freed credential that was still in uses due
3144 *		a race.  This use is protected by the KAUTH_CRED_HASH_LOCK.
3145 *
3146 *		On final release, the hash reference is droped, and the
3147 *		credential is freed back to the system.
3148 *
3149 *		This function is called from kauth_init() in the file
3150 *		kern_authorization.c.
3151 */
3152void
3153kauth_cred_init(void)
3154{
3155	int		i;
3156
3157	kauth_cred_hash_mtx = lck_mtx_alloc_init(kauth_lck_grp, 0/*LCK_ATTR_NULL*/);
3158	kauth_cred_table_size = kauth_cred_primes[kauth_cred_primes_index];
3159
3160	/*allocate credential hash table */
3161	MALLOC(kauth_cred_table_anchor, struct kauth_cred_entry_head *,
3162			(sizeof(struct kauth_cred_entry_head) * kauth_cred_table_size),
3163			M_KAUTH, M_WAITOK | M_ZERO);
3164	if (kauth_cred_table_anchor == NULL)
3165		panic("startup: kauth_cred_init");
3166	for (i = 0; i < kauth_cred_table_size; i++) {
3167		TAILQ_INIT(&kauth_cred_table_anchor[i]);
3168	}
3169}
3170
3171
3172/*
3173 * kauth_getuid
3174 *
3175 * Description:	Get the current thread's effective UID.
3176 *
3177 * Parameters:	(void)
3178 *
3179 * Returns:	(uid_t)				The effective UID of the
3180 *						current thread
3181 */
3182uid_t
3183kauth_getuid(void)
3184{
3185	return(kauth_cred_getuid(kauth_cred_get()));
3186}
3187
3188
3189/*
3190 * kauth_getruid
3191 *
3192 * Description:	Get the current thread's real UID.
3193 *
3194 * Parameters:	(void)
3195 *
3196 * Returns:	(uid_t)				The real UID of the current
3197 *						thread
3198 */
3199uid_t
3200kauth_getruid(void)
3201{
3202	return(kauth_cred_getruid(kauth_cred_get()));
3203}
3204
3205
3206/*
3207 * kauth_getgid
3208 *
3209 * Description:	Get the current thread's effective GID.
3210 *
3211 * Parameters:	(void)
3212 *
3213 * Returns:	(gid_t)				The effective GID of the
3214 *						current thread
3215 */
3216gid_t
3217kauth_getgid(void)
3218{
3219	return(kauth_cred_getgid(kauth_cred_get()));
3220}
3221
3222
3223/*
3224 * kauth_getgid
3225 *
3226 * Description:	Get the current thread's real GID.
3227 *
3228 * Parameters:	(void)
3229 *
3230 * Returns:	(gid_t)				The real GID of the current
3231 *						thread
3232 */
3233gid_t
3234kauth_getrgid(void)
3235{
3236	return(kauth_cred_getrgid(kauth_cred_get()));
3237}
3238
3239
3240/*
3241 * kauth_cred_get
3242 *
3243 * Description:	Returns a pointer to the current thread's credential
3244 *
3245 * Parameters:	(void)
3246 *
3247 * Returns:	(kauth_cred_t)			Pointer to the current thread's
3248 *						credential
3249 *
3250 * Notes:	This function does not take a reference; because of this, the
3251 *		caller MUST NOT do anything that would let the thread's
3252 *		credential change while using the returned value, without
3253 *		first explicitly taking their own reference.
3254 *
3255 *		If a caller intends to take a reference on the resulting
3256 *		credential pointer from calling this function, it is strongly
3257 *		recommended that the caller use kauth_cred_get_with_ref()
3258 *		instead, to protect against any future changes to the cred
3259 *		locking protocols; such changes could otherwise potentially
3260 *		introduce race windows in the callers code.
3261 */
3262kauth_cred_t
3263kauth_cred_get(void)
3264{
3265	struct proc *p;
3266	struct uthread *uthread;
3267
3268	uthread = get_bsdthread_info(current_thread());
3269	/* sanity */
3270	if (uthread == NULL)
3271		panic("thread wants credential but has no BSD thread info");
3272	/*
3273	 * We can lazy-bind credentials to threads, as long as their processes
3274	 * have them.
3275	 *
3276	 * XXX If we later inline this function, the code in this block
3277	 * XXX should probably be called out in a function.
3278	 */
3279	if (uthread->uu_ucred == NOCRED) {
3280		if ((p = (proc_t) get_bsdtask_info(get_threadtask(current_thread()))) == NULL)
3281			panic("thread wants credential but has no BSD process");
3282		uthread->uu_ucred = kauth_cred_proc_ref(p);
3283	}
3284	return(uthread->uu_ucred);
3285}
3286
3287void
3288mach_kauth_cred_uthread_update(void)
3289{
3290	uthread_t uthread;
3291	proc_t proc;
3292
3293	uthread = get_bsdthread_info(current_thread());
3294	proc = current_proc();
3295
3296	kauth_cred_uthread_update(uthread, proc);
3297}
3298
3299/*
3300 * kauth_cred_uthread_update
3301 *
3302 * Description:	Given a uthread, a proc, and whether or not the proc is locked,
3303 *		late-bind the uthread cred to the proc cred.
3304 *
3305 * Parameters:	uthread_t			The uthread to update
3306 *		proc_t				The process to update to
3307 *
3308 * Returns:	(void)
3309 *
3310 * Notes:	This code is common code called from system call or trap entry
3311 *		in the case that the process thread may have been changed
3312 *		since the last time the thread entered the kernel.  It is
3313 *		generally only called with the current uthread and process as
3314 *		parameters.
3315 */
3316void
3317kauth_cred_uthread_update(uthread_t uthread, proc_t proc)
3318{
3319	if (uthread->uu_ucred != proc->p_ucred &&
3320	    (uthread->uu_flag & UT_SETUID) == 0) {
3321		kauth_cred_t old = uthread->uu_ucred;
3322		uthread->uu_ucred = kauth_cred_proc_ref(proc);
3323		if (IS_VALID_CRED(old))
3324			kauth_cred_unref(&old);
3325	}
3326}
3327
3328
3329/*
3330 * kauth_cred_get_with_ref
3331 *
3332 * Description:	Takes a reference on the current thread's credential, and then
3333 *		returns a pointer to it to the caller.
3334 *
3335 * Parameters:	(void)
3336 *
3337 * Returns:	(kauth_cred_t)			Pointer to the current thread's
3338 *						newly referenced credential
3339 *
3340 * Notes:	This function takes a reference on the credential before
3341 *		returning it to the caller.
3342 *
3343 *		It is the responsibility of the calling code to release this
3344 *		reference when the credential is no longer in use.
3345 *
3346 *		Since the returned reference may be a persistent reference
3347 *		(e.g. one cached in another data structure with a lifetime
3348 *		longer than the calling function), this release may be delayed
3349 *		until such time as the persistent reference is to be destroyed.
3350 *		An example of this would be the per vnode credential cache used
3351 *		to accelerate lookup operations.
3352 */
3353kauth_cred_t
3354kauth_cred_get_with_ref(void)
3355{
3356	struct proc *procp;
3357	struct uthread *uthread;
3358
3359	uthread = get_bsdthread_info(current_thread());
3360	/* sanity checks */
3361	if (uthread == NULL)
3362		panic("%s - thread wants credential but has no BSD thread info", __FUNCTION__);
3363	if ((procp = (proc_t) get_bsdtask_info(get_threadtask(current_thread()))) == NULL)
3364		panic("%s - thread wants credential but has no BSD process", __FUNCTION__);
3365
3366	/*
3367	 * We can lazy-bind credentials to threads, as long as their processes
3368	 * have them.
3369	 *
3370	 * XXX If we later inline this function, the code in this block
3371	 * XXX should probably be called out in a function.
3372	 */
3373	if (uthread->uu_ucred == NOCRED) {
3374		/* take reference for new cred in thread */
3375		uthread->uu_ucred = kauth_cred_proc_ref(procp);
3376	}
3377	/* take a reference for our caller */
3378	kauth_cred_ref(uthread->uu_ucred);
3379	return(uthread->uu_ucred);
3380}
3381
3382
3383/*
3384 * kauth_cred_proc_ref
3385 *
3386 * Description:	Takes a reference on the current process's credential, and
3387 *		then returns a pointer to it to the caller.
3388 *
3389 * Parameters:	procp				Process whose credential we
3390 *						intend to take a reference on
3391 *
3392 * Returns:	(kauth_cred_t)			Pointer to the process's
3393 *						newly referenced credential
3394 *
3395 * Locks:	PROC_LOCK is held before taking the reference and released
3396 *		after the refeence is taken to protect the p_ucred field of
3397 *		the process referred to by procp.
3398 *
3399 * Notes:	This function takes a reference on the credential before
3400 *		returning it to the caller.
3401 *
3402 *		It is the responsibility of the calling code to release this
3403 *		reference when the credential is no longer in use.
3404 *
3405 *		Since the returned reference may be a persistent reference
3406 *		(e.g. one cached in another data structure with a lifetime
3407 *		longer than the calling function), this release may be delayed
3408 *		until such time as the persistent reference is to be destroyed.
3409 *		An example of this would be the per vnode credential cache used
3410 *		to accelerate lookup operations.
3411 */
3412kauth_cred_t
3413kauth_cred_proc_ref(proc_t procp)
3414{
3415	kauth_cred_t 	cred;
3416
3417	proc_lock(procp);
3418	cred = proc_ucred(procp);
3419	kauth_cred_ref(cred);
3420	proc_unlock(procp);
3421	return(cred);
3422}
3423
3424
3425/*
3426 * kauth_cred_alloc
3427 *
3428 * Description:	Allocate a new credential
3429 *
3430 * Parameters:	(void)
3431 *
3432 * Returns:	!NULL				Newly allocated credential
3433 *		NULL				Insufficient memory
3434 *
3435 * Notes:	The newly allocated credential is zero'ed as part of the
3436 *		allocation process, with the exception of the reference
3437 *		count, which is set to 1 to indicate a single reference
3438 *		held by the caller.
3439 *
3440 *		Since newly allocated credentials have no external pointers
3441 *		referencing them, prior to making them visible in an externally
3442 *		visible pointer (e.g. by adding them to the credential hash
3443 *		cache) is the only legal time in which an existing credential
3444 *		can be safely iinitialized or modified directly.
3445 *
3446 *		After initialization, the caller is expected to call the
3447 *		function kauth_cred_add() to add the credential to the hash
3448 *		cache, after which time it's frozen and becomes publically
3449 *		visible.
3450 *
3451 *		The release protocol depends on kauth_hash_add() being called
3452 *		before kauth_cred_rele() (there is a diagnostic panic which
3453 *		will trigger if this protocol is not observed).
3454 *
3455 * XXX:		This function really ought to be static, rather than being
3456 *		exported as KPI, since a failure of kauth_cred_add() can only
3457 *		be handled by an explicit free of the credential; such frees
3458 *		depend on knowlegdge of the allocation method used, which is
3459 *		permitted to change between kernel revisions.
3460 *
3461 * XXX:		In the insufficient resource case, this code panic's rather
3462 *		than returning a NULL pointer; the code that calls this
3463 *		function needs to be audited before this can be changed.
3464 */
3465kauth_cred_t
3466kauth_cred_alloc(void)
3467{
3468	kauth_cred_t newcred;
3469
3470	MALLOC_ZONE(newcred, kauth_cred_t, sizeof(*newcred), M_CRED, M_WAITOK);
3471	if (newcred != 0) {
3472		posix_cred_t newpcred = posix_cred_get(newcred);
3473		bzero(newcred, sizeof(*newcred));
3474		newcred->cr_ref = 1;
3475		newcred->cr_audit.as_aia_p = audit_default_aia_p;
3476		/* must do this, or cred has same group membership as uid 0 */
3477		newpcred->cr_gmuid = KAUTH_UID_NONE;
3478#if CRED_DIAGNOSTIC
3479	} else {
3480		panic("kauth_cred_alloc: couldn't allocate credential");
3481#endif
3482	}
3483
3484#if KAUTH_CRED_HASH_DEBUG
3485	kauth_cred_count++;
3486#endif
3487
3488#if CONFIG_MACF
3489	mac_cred_label_init(newcred);
3490#endif
3491
3492	return(newcred);
3493}
3494
3495
3496/*
3497 * kauth_cred_create
3498 *
3499 * Description:	Look to see if we already have a known credential in the hash
3500 *		cache; if one is found, bump the reference count and return
3501 *		it.  If there are no credentials that match the given
3502 *		credential, then allocate a new credential.
3503 *
3504 * Parameters:	cred				Template for credential to
3505 *						be created
3506 *
3507 * Returns:	(kauth_cred_t)			The credential that was found
3508 *						in the hash or created
3509 *		NULL				kauth_cred_add() failed, or
3510 *						there was not an egid specified
3511 *
3512 * Notes:	The gmuid is hard-defaulted to the UID specified.  Since we
3513 *		maintain this field, we can't expect callers to know how it
3514 *		needs to be set.  Callers should be prepared for this field
3515 *		to be overwritten.
3516 *
3517 * XXX:		This code will tight-loop if memory for a new credential is
3518 *		persistently unavailable; this is perhaps not the wisest way
3519 *		to handle this condition, but current callers do not expect
3520 *		a failure.
3521 */
3522kauth_cred_t
3523kauth_cred_create(kauth_cred_t cred)
3524{
3525	kauth_cred_t 	found_cred, new_cred = NULL;
3526	posix_cred_t	pcred = posix_cred_get(cred);
3527	int is_member = 0;
3528
3529	KAUTH_CRED_HASH_LOCK_ASSERT();
3530
3531	if (pcred->cr_flags & CRF_NOMEMBERD) {
3532		pcred->cr_gmuid = KAUTH_UID_NONE;
3533	} else {
3534		/*
3535		 * If the template credential is not opting out of external
3536		 * group membership resolution, then we need to check that
3537		 * the UID we will be using is resolvable by the external
3538		 * resolver.  If it's not, then we opt it out anyway, since
3539		 * all future external resolution requests will be failing
3540		 * anyway, and potentially taking a long time to do it.  We
3541		 * use gid 0 because we always know it will exist and not
3542		 * trigger additional lookups. This is OK, because we end up
3543		 * precatching the information here as a result.
3544		 */
3545		if (!kauth_cred_ismember_gid(cred, 0, &is_member)) {
3546			/*
3547			 * It's a recognized value; we don't really care about
3548			 * the answer, so long as it's something the external
3549			 * resolver could have vended.
3550			 */
3551			pcred->cr_gmuid = pcred->cr_uid;
3552		} else {
3553			/*
3554			 * It's not something the external resolver could
3555			 * have vended, so we don't want to ask it more
3556			 * questions about the credential in the future. This
3557			 * speeds up future lookups, as long as the caller
3558			 * caches results; otherwise, it the same recurring
3559			 * cost.  Since most credentials are used multiple
3560			 * times, we still get some performance win from this.
3561			 */
3562			pcred->cr_gmuid = KAUTH_UID_NONE;
3563			pcred->cr_flags |= CRF_NOMEMBERD;
3564		}
3565	}
3566
3567	/* Caller *must* specify at least the egid in cr_groups[0] */
3568	if (pcred->cr_ngroups < 1)
3569		return(NULL);
3570
3571	for (;;) {
3572		KAUTH_CRED_HASH_LOCK();
3573		found_cred = kauth_cred_find(cred);
3574		if (found_cred != NULL) {
3575			/*
3576			 * Found an existing credential so we'll bump
3577			 * reference count and return
3578			 */
3579			kauth_cred_ref(found_cred);
3580			KAUTH_CRED_HASH_UNLOCK();
3581			return(found_cred);
3582		}
3583		KAUTH_CRED_HASH_UNLOCK();
3584
3585		/*
3586		 * No existing credential found.  Create one and add it to
3587		 * our hash table.
3588		 */
3589		new_cred = kauth_cred_alloc();
3590		if (new_cred != NULL) {
3591			int		err;
3592			posix_cred_t	new_pcred = posix_cred_get(new_cred);
3593			new_pcred->cr_uid = pcred->cr_uid;
3594			new_pcred->cr_ruid = pcred->cr_ruid;
3595			new_pcred->cr_svuid = pcred->cr_svuid;
3596			new_pcred->cr_rgid = pcred->cr_rgid;
3597			new_pcred->cr_svgid = pcred->cr_svgid;
3598			new_pcred->cr_gmuid = pcred->cr_gmuid;
3599			new_pcred->cr_ngroups = pcred->cr_ngroups;
3600			bcopy(&pcred->cr_groups[0], &new_pcred->cr_groups[0], sizeof(new_pcred->cr_groups));
3601#if CONFIG_AUDIT
3602			bcopy(&cred->cr_audit, &new_cred->cr_audit,
3603			    sizeof(new_cred->cr_audit));
3604#endif
3605			new_pcred->cr_flags = pcred->cr_flags;
3606
3607			KAUTH_CRED_HASH_LOCK();
3608			err = kauth_cred_add(new_cred);
3609			KAUTH_CRED_HASH_UNLOCK();
3610
3611			/* Retry if kauth_cred_add returns non zero value */
3612			if (err == 0)
3613				break;
3614#if CONFIG_MACF
3615			mac_cred_label_destroy(new_cred);
3616#endif
3617			AUDIT_SESSION_UNREF(new_cred);
3618
3619			FREE_ZONE(new_cred, sizeof(*new_cred), M_CRED);
3620			new_cred = NULL;
3621		}
3622	}
3623
3624	return(new_cred);
3625}
3626
3627
3628/*
3629 * kauth_cred_setresuid
3630 *
3631 * Description:	Update the given credential using the UID arguments.  The given
3632 *		UIDs are used to set the effective UID, real UID, saved UID,
3633 *		and GMUID (used for group membership checking).
3634 *
3635 * Parameters:	cred				The original credential
3636 *		ruid				The new real UID
3637 *		euid				The new effective UID
3638 *		svuid				The new saved UID
3639 *		gmuid				KAUTH_UID_NONE -or- the new
3640 *						group membership UID
3641 *
3642 * Returns:	(kauth_cred_t)			The updated credential
3643 *
3644 * Note:	gmuid is different in that a KAUTH_UID_NONE is a valid
3645 *		setting, so if you don't want it to change, pass it the
3646 *		previous value, explicitly.
3647 *
3648 * IMPORTANT:	This function is implemented via kauth_cred_update(), which,
3649 *		if it returns a credential other than the one it is passed,
3650 *		will have dropped the reference on the passed credential.  All
3651 *		callers should be aware of this, and treat this function as an
3652 *		unref + ref, potentially on different credentials.
3653 *
3654 *		Because of this, the caller is expected to take its own
3655 *		reference on the credential passed as the first parameter,
3656 *		and be prepared to release the reference on the credential
3657 *		that is returned to them, if it is not intended to be a
3658 *		persistent reference.
3659 */
3660kauth_cred_t
3661kauth_cred_setresuid(kauth_cred_t cred, uid_t ruid, uid_t euid, uid_t svuid, uid_t gmuid)
3662{
3663	struct ucred temp_cred;
3664	posix_cred_t temp_pcred = posix_cred_get(&temp_cred);
3665	posix_cred_t pcred = posix_cred_get(cred);
3666
3667	NULLCRED_CHECK(cred);
3668
3669	/*
3670	 * We don't need to do anything if the UIDs we are changing are
3671	 * already the same as the UIDs passed in
3672	 */
3673	if ((euid == KAUTH_UID_NONE || pcred->cr_uid == euid) &&
3674	    (ruid == KAUTH_UID_NONE || pcred->cr_ruid == ruid) &&
3675	    (svuid == KAUTH_UID_NONE || pcred->cr_svuid == svuid) &&
3676	    (pcred->cr_gmuid == gmuid)) {
3677		/* no change needed */
3678		return(cred);
3679	}
3680
3681	/*
3682	 * Look up in cred hash table to see if we have a matching credential
3683	 * with the new values; this is done by calling kauth_cred_update().
3684	 */
3685	bcopy(cred, &temp_cred, sizeof(temp_cred));
3686	if (euid != KAUTH_UID_NONE) {
3687		temp_pcred->cr_uid = euid;
3688	}
3689	if (ruid != KAUTH_UID_NONE) {
3690		temp_pcred->cr_ruid = ruid;
3691	}
3692	if (svuid != KAUTH_UID_NONE) {
3693		temp_pcred->cr_svuid = svuid;
3694	}
3695
3696	/*
3697	 * If we are setting the gmuid to KAUTH_UID_NONE, then we want to
3698	 * opt out of participation in external group resolution, unless we
3699	 * unless we explicitly opt back in later.
3700	 */
3701	if ((temp_pcred->cr_gmuid = gmuid) == KAUTH_UID_NONE) {
3702		temp_pcred->cr_flags |= CRF_NOMEMBERD;
3703	}
3704
3705	return(kauth_cred_update(cred, &temp_cred, TRUE));
3706}
3707
3708
3709/*
3710 * kauth_cred_setresgid
3711 *
3712 * Description:	Update the given credential using the GID arguments.  The given
3713 *		GIDs are used to set the effective GID, real GID, and saved
3714 *		GID.
3715 *
3716 * Parameters:	cred				The original credential
3717 *		rgid				The new real GID
3718 *		egid				The new effective GID
3719 *		svgid				The new saved GID
3720 *
3721 * Returns:	(kauth_cred_t)			The updated credential
3722 *
3723 * IMPORTANT:	This function is implemented via kauth_cred_update(), which,
3724 *		if it returns a credential other than the one it is passed,
3725 *		will have dropped the reference on the passed credential.  All
3726 *		callers should be aware of this, and treat this function as an
3727 *		unref + ref, potentially on different credentials.
3728 *
3729 *		Because of this, the caller is expected to take its own
3730 *		reference on the credential passed as the first parameter,
3731 *		and be prepared to release the reference on the credential
3732 *		that is returned to them, if it is not intended to be a
3733 *		persistent reference.
3734 */
3735kauth_cred_t
3736kauth_cred_setresgid(kauth_cred_t cred, gid_t rgid, gid_t egid, gid_t svgid)
3737{
3738	struct ucred 	temp_cred;
3739	posix_cred_t temp_pcred = posix_cred_get(&temp_cred);
3740	posix_cred_t pcred = posix_cred_get(cred);
3741
3742	NULLCRED_CHECK(cred);
3743	DEBUG_CRED_ENTER("kauth_cred_setresgid %p %d %d %d\n", cred, rgid, egid, svgid);
3744
3745	/*
3746	 * We don't need to do anything if the given GID are already the
3747	 * same as the GIDs in the credential.
3748	 */
3749	if (pcred->cr_groups[0] == egid &&
3750	    pcred->cr_rgid == rgid &&
3751	    pcred->cr_svgid == svgid) {
3752		/* no change needed */
3753		return(cred);
3754	}
3755
3756	/*
3757	 * Look up in cred hash table to see if we have a matching credential
3758	 * with the new values; this is done by calling kauth_cred_update().
3759	 */
3760	bcopy(cred, &temp_cred, sizeof(temp_cred));
3761	if (egid != KAUTH_GID_NONE) {
3762		/* displacing a supplementary group opts us out of memberd */
3763		if (kauth_cred_change_egid(&temp_cred, egid)) {
3764			DEBUG_CRED_CHANGE("displaced!\n");
3765			temp_pcred->cr_flags |= CRF_NOMEMBERD;
3766			temp_pcred->cr_gmuid = KAUTH_UID_NONE;
3767		} else {
3768			DEBUG_CRED_CHANGE("not displaced\n");
3769		}
3770	}
3771	if (rgid != KAUTH_GID_NONE) {
3772		temp_pcred->cr_rgid = rgid;
3773	}
3774	if (svgid != KAUTH_GID_NONE) {
3775		temp_pcred->cr_svgid = svgid;
3776	}
3777
3778	return(kauth_cred_update(cred, &temp_cred, TRUE));
3779}
3780
3781
3782/*
3783 * Update the given credential with the given groups.  We only allocate a new
3784 *	credential when the given gid actually results in changes to the existing
3785 *	credential.
3786 *	The gmuid argument supplies a new uid (or KAUTH_UID_NONE to opt out)
3787 *	which will be used for group membership checking.
3788 */
3789/*
3790 * kauth_cred_setgroups
3791 *
3792 * Description:	Update the given credential using the provide supplementary
3793 *		group list and group membership UID
3794 *
3795 * Parameters:	cred				The original credential
3796 *		groups				Pointer to gid_t array which
3797 *						contains the new group list
3798 *		groupcount			The count of valid groups which
3799 *						are contained in 'groups'
3800 *		gmuid				KAUTH_UID_NONE -or- the new
3801 *						group membership UID
3802 *
3803 * Returns:	(kauth_cred_t)			The updated credential
3804 *
3805 * Note:	gmuid is different in that a KAUTH_UID_NONE is a valid
3806 *		setting, so if you don't want it to change, pass it the
3807 *		previous value, explicitly.
3808 *
3809 * IMPORTANT:	This function is implemented via kauth_cred_update(), which,
3810 *		if it returns a credential other than the one it is passed,
3811 *		will have dropped the reference on the passed credential.  All
3812 *		callers should be aware of this, and treat this function as an
3813 *		unref + ref, potentially on different credentials.
3814 *
3815 *		Because of this, the caller is expected to take its own
3816 *		reference on the credential passed as the first parameter,
3817 *		and be prepared to release the reference on the credential
3818 *		that is returned to them, if it is not intended to be a
3819 *		persistent reference.
3820 *
3821 * XXX:		Changes are determined in ordinal order - if the caller passes
3822 *		in the same groups list that is already present in the
3823 *		credential, but the members are in a different order, even if
3824 *		the EGID is not modified (i.e. cr_groups[0] is the same), it
3825 *		is considered a modification to the credential, and a new
3826 *		credential is created.
3827 *
3828 *		This should perhaps be better optimized, but it is considered
3829 *		to be the caller's problem.
3830 */
3831kauth_cred_t
3832kauth_cred_setgroups(kauth_cred_t cred, gid_t *groups, int groupcount, uid_t gmuid)
3833{
3834	int		i;
3835	struct ucred temp_cred;
3836	posix_cred_t temp_pcred = posix_cred_get(&temp_cred);
3837	posix_cred_t pcred;
3838
3839	NULLCRED_CHECK(cred);
3840
3841	pcred = posix_cred_get(cred);
3842
3843	/*
3844	 * We don't need to do anything if the given list of groups does not
3845	 * change.
3846	 */
3847	if ((pcred->cr_gmuid == gmuid) && (pcred->cr_ngroups == groupcount)) {
3848		for (i = 0; i < groupcount; i++) {
3849			if (pcred->cr_groups[i] != groups[i])
3850				break;
3851		}
3852		if (i == groupcount) {
3853			/* no change needed */
3854			return(cred);
3855		}
3856	}
3857
3858	/*
3859	 * Look up in cred hash table to see if we have a matching credential
3860	 * with new values.  If we are setting or clearing the gmuid, then
3861	 * update the cr_flags, since clearing it is sticky.  This permits an
3862	 * opt-out of memberd processing using setgroups(), and an opt-in
3863	 * using initgroups().  This is required for POSIX conformance.
3864	 */
3865	bcopy(cred, &temp_cred, sizeof(temp_cred));
3866	temp_pcred->cr_ngroups = groupcount;
3867	bcopy(groups, temp_pcred->cr_groups, sizeof(temp_pcred->cr_groups));
3868	temp_pcred->cr_gmuid = gmuid;
3869	if (gmuid == KAUTH_UID_NONE)
3870		temp_pcred->cr_flags |= CRF_NOMEMBERD;
3871	else
3872		temp_pcred->cr_flags &= ~CRF_NOMEMBERD;
3873
3874	return(kauth_cred_update(cred, &temp_cred, TRUE));
3875}
3876
3877/*
3878 * XXX temporary, for NFS support until we can come up with a better
3879 * XXX enumeration/comparison mechanism
3880 *
3881 * Notes:	The return value exists to account for the possibility of a
3882 *		kauth_cred_t without a POSIX label.  This will be the case in
3883 *		the future (see posix_cred_get() below, for more details).
3884 */
3885int
3886kauth_cred_getgroups(kauth_cred_t cred, gid_t *grouplist, int *countp)
3887{
3888	int limit = NGROUPS;
3889
3890	/*
3891	 * If they just want a copy of the groups list, they may not care
3892	 * about the actual count.  If they specify an input count, however,
3893	 * treat it as an indicator of the buffer size available in grouplist,
3894	 * and limit the returned list to that size.
3895	 */
3896	if (countp) {
3897		limit = MIN(*countp, cred->cr_posix.cr_ngroups);
3898		*countp = limit;
3899	}
3900
3901	memcpy(grouplist, cred->cr_posix.cr_groups, sizeof(gid_t) * limit);
3902
3903	return 0;
3904}
3905
3906
3907/*
3908 * kauth_cred_setuidgid
3909 *
3910 * Description:	Update the given credential using the UID and GID arguments.
3911 *		The given UID is used to set the effective UID, real UID, and
3912 *		saved UID.  The given GID is used to set the effective GID,
3913 *		real GID, and saved GID.
3914 *
3915 * Parameters:	cred				The original credential
3916 *		uid				The new UID to use
3917 *		gid				The new GID to use
3918 *
3919 * Returns:	(kauth_cred_t)			The updated credential
3920 *
3921 * Notes:	We set the gmuid to uid if the credential we are inheriting
3922 *		from has not opted out of memberd participation; otherwise
3923 *		we set it to KAUTH_UID_NONE
3924 *
3925 *		This code is only ever called from the per-thread credential
3926 *		code path in the "set per thread credential" case; and in
3927 *		posix_spawn() in the case that the POSIX_SPAWN_RESETIDS
3928 *		flag is set.
3929 *
3930 * IMPORTANT:	This function is implemented via kauth_cred_update(), which,
3931 *		if it returns a credential other than the one it is passed,
3932 *		will have dropped the reference on the passed credential.  All
3933 *		callers should be aware of this, and treat this function as an
3934 *		unref + ref, potentially on different credentials.
3935 *
3936 *		Because of this, the caller is expected to take its own
3937 *		reference on the credential passed as the first parameter,
3938 *		and be prepared to release the reference on the credential
3939 *		that is returned to them, if it is not intended to be a
3940 *		persistent reference.
3941 */
3942kauth_cred_t
3943kauth_cred_setuidgid(kauth_cred_t cred, uid_t uid, gid_t gid)
3944{
3945	struct ucred temp_cred;
3946	posix_cred_t temp_pcred = posix_cred_get(&temp_cred);
3947	posix_cred_t pcred;
3948
3949	NULLCRED_CHECK(cred);
3950
3951	pcred = posix_cred_get(cred);
3952
3953	/*
3954	 * We don't need to do anything if the effective, real and saved
3955	 * user IDs are already the same as the user ID passed into us.
3956	 */
3957	if (pcred->cr_uid == uid && pcred->cr_ruid == uid && pcred->cr_svuid == uid &&
3958		pcred->cr_gid == gid && pcred->cr_rgid == gid && pcred->cr_svgid == gid) {
3959		/* no change needed */
3960		return(cred);
3961	}
3962
3963	/*
3964	 * Look up in cred hash table to see if we have a matching credential
3965	 * with the new values.
3966	 */
3967	bzero(&temp_cred, sizeof(temp_cred));
3968	temp_pcred->cr_uid = uid;
3969	temp_pcred->cr_ruid = uid;
3970	temp_pcred->cr_svuid = uid;
3971	temp_pcred->cr_flags = pcred->cr_flags;
3972	/* inherit the opt-out of memberd */
3973	if (pcred->cr_flags & CRF_NOMEMBERD) {
3974		temp_pcred->cr_gmuid = KAUTH_UID_NONE;
3975		temp_pcred->cr_flags |= CRF_NOMEMBERD;
3976	} else {
3977		temp_pcred->cr_gmuid = uid;
3978		temp_pcred->cr_flags &= ~CRF_NOMEMBERD;
3979	}
3980	temp_pcred->cr_ngroups = 1;
3981	/* displacing a supplementary group opts us out of memberd */
3982	if (kauth_cred_change_egid(&temp_cred, gid)) {
3983		temp_pcred->cr_gmuid = KAUTH_UID_NONE;
3984		temp_pcred->cr_flags |= CRF_NOMEMBERD;
3985	}
3986	temp_pcred->cr_rgid = gid;
3987	temp_pcred->cr_svgid = gid;
3988#if CONFIG_MACF
3989	temp_cred.cr_label = cred->cr_label;
3990#endif
3991
3992	return(kauth_cred_update(cred, &temp_cred, TRUE));
3993}
3994
3995
3996/*
3997 * kauth_cred_setsvuidgid
3998 *
3999 * Description:	Function used by execve to set the saved uid and gid values
4000 *		for suid/sgid programs
4001 *
4002 * Parameters:	cred				The credential to update
4003 *		uid				The saved uid to set
4004 *		gid				The saved gid to set
4005 *
4006 * Returns:	(kauth_cred_t)			The updated credential
4007 *
4008 * IMPORTANT:	This function is implemented via kauth_cred_update(), which,
4009 *		if it returns a credential other than the one it is passed,
4010 *		will have dropped the reference on the passed credential.  All
4011 *		callers should be aware of this, and treat this function as an
4012 *		unref + ref, potentially on different credentials.
4013 *
4014 *		Because of this, the caller is expected to take its own
4015 *		reference on the credential passed as the first parameter,
4016 *		and be prepared to release the reference on the credential
4017 *		that is returned to them, if it is not intended to be a
4018 *		persistent reference.
4019 */
4020kauth_cred_t
4021kauth_cred_setsvuidgid(kauth_cred_t cred, uid_t uid, gid_t gid)
4022{
4023	struct ucred temp_cred;
4024	posix_cred_t temp_pcred = posix_cred_get(&temp_cred);
4025	posix_cred_t pcred;
4026
4027	NULLCRED_CHECK(cred);
4028
4029	pcred = posix_cred_get(cred);
4030
4031	DEBUG_CRED_ENTER("kauth_cred_setsvuidgid: %p u%d->%d g%d->%d\n", cred, cred->cr_svuid, uid, cred->cr_svgid, gid);
4032
4033	/*
4034	 * We don't need to do anything if the effective, real and saved
4035	 * uids are already the same as the uid provided.  This check is
4036	 * likely insufficient.
4037	 */
4038	if (pcred->cr_svuid == uid && pcred->cr_svgid == gid) {
4039		/* no change needed */
4040		return(cred);
4041	}
4042	DEBUG_CRED_CHANGE("kauth_cred_setsvuidgid: cred change\n");
4043
4044	/* look up in cred hash table to see if we have a matching credential
4045	 * with new values.
4046	 */
4047	bcopy(cred, &temp_cred, sizeof(temp_cred));
4048	temp_pcred->cr_svuid = uid;
4049	temp_pcred->cr_svgid = gid;
4050
4051	return(kauth_cred_update(cred, &temp_cred, TRUE));
4052}
4053
4054
4055/*
4056 * kauth_cred_setauditinfo
4057 *
4058 * Description:	Update the given credential using the given au_session_t.
4059 *
4060 * Parameters:	cred				The original credential
4061 *		auditinfo_p			Pointer to ne audit information
4062 *
4063 * Returns:	(kauth_cred_t)			The updated credential
4064 *
4065 * IMPORTANT:	This function is implemented via kauth_cred_update(), which,
4066 *		if it returns a credential other than the one it is passed,
4067 *		will have dropped the reference on the passed credential.  All
4068 *		callers should be aware of this, and treat this function as an
4069 *		unref + ref, potentially on different credentials.
4070 *
4071 *		Because of this, the caller is expected to take its own
4072 *		reference on the credential passed as the first parameter,
4073 *		and be prepared to release the reference on the credential
4074 *		that is returned to them, if it is not intended to be a
4075 *		persistent reference.
4076 */
4077kauth_cred_t
4078kauth_cred_setauditinfo(kauth_cred_t cred, au_session_t *auditinfo_p)
4079{
4080	struct ucred temp_cred;
4081
4082	NULLCRED_CHECK(cred);
4083
4084	/*
4085	 * We don't need to do anything if the audit info is already the
4086	 * same as the audit info in the credential provided.
4087	 */
4088	if (bcmp(&cred->cr_audit, auditinfo_p, sizeof(cred->cr_audit)) == 0) {
4089		/* no change needed */
4090		return(cred);
4091	}
4092
4093	bcopy(cred, &temp_cred, sizeof(temp_cred));
4094	bcopy(auditinfo_p, &temp_cred.cr_audit, sizeof(temp_cred.cr_audit));
4095
4096	return(kauth_cred_update(cred, &temp_cred, FALSE));
4097}
4098
4099#if CONFIG_MACF
4100/*
4101 * kauth_cred_label_update
4102 *
4103 * Description:	Update the MAC label associated with a credential
4104 *
4105 * Parameters:	cred				The original credential
4106 *		label				The MAC label to set
4107 *
4108 * Returns:	(kauth_cred_t)			The updated credential
4109 *
4110 * IMPORTANT:	This function is implemented via kauth_cred_update(), which,
4111 *		if it returns a credential other than the one it is passed,
4112 *		will have dropped the reference on the passed credential.  All
4113 *		callers should be aware of this, and treat this function as an
4114 *		unref + ref, potentially on different credentials.
4115 *
4116 *		Because of this, the caller is expected to take its own
4117 *		reference on the credential passed as the first parameter,
4118 *		and be prepared to release the reference on the credential
4119 *		that is returned to them, if it is not intended to be a
4120 *		persistent reference.
4121 */
4122kauth_cred_t
4123kauth_cred_label_update(kauth_cred_t cred, struct label *label)
4124{
4125	kauth_cred_t newcred;
4126	struct ucred temp_cred;
4127
4128	bcopy(cred, &temp_cred, sizeof(temp_cred));
4129
4130	mac_cred_label_init(&temp_cred);
4131	mac_cred_label_associate(cred, &temp_cred);
4132	mac_cred_label_update(&temp_cred, label);
4133
4134	newcred = kauth_cred_update(cred, &temp_cred, TRUE);
4135	mac_cred_label_destroy(&temp_cred);
4136	return (newcred);
4137}
4138
4139/*
4140 * kauth_cred_label_update_execve
4141 *
4142 * Description:	Update the MAC label associated with a credential as
4143 *		part of exec
4144 *
4145 * Parameters:	cred				The original credential
4146 *		vp				The exec vnode
4147 *		scriptl				The script MAC label
4148 *		execl				The executable MAC label
4149 *		disjointp			Pointer to flag to set if old
4150 *						and returned credentials are
4151 *						disjoint
4152 *
4153 * Returns:	(kauth_cred_t)			The updated credential
4154 *
4155 * Implicit returns:
4156 *		*disjointp			Set to 1 for disjoint creds
4157 *
4158 * IMPORTANT:	This function is implemented via kauth_cred_update(), which,
4159 *		if it returns a credential other than the one it is passed,
4160 *		will have dropped the reference on the passed credential.  All
4161 *		callers should be aware of this, and treat this function as an
4162 *		unref + ref, potentially on different credentials.
4163 *
4164 *		Because of this, the caller is expected to take its own
4165 *		reference on the credential passed as the first parameter,
4166 *		and be prepared to release the reference on the credential
4167 *		that is returned to them, if it is not intended to be a
4168 *		persistent reference.
4169 */
4170static
4171kauth_cred_t
4172kauth_cred_label_update_execve(kauth_cred_t cred, vfs_context_t ctx,
4173	struct vnode *vp, struct label *scriptl, struct label *execl,
4174	int *disjointp)
4175{
4176	kauth_cred_t newcred;
4177	struct ucred temp_cred;
4178
4179	bcopy(cred, &temp_cred, sizeof(temp_cred));
4180
4181	mac_cred_label_init(&temp_cred);
4182	mac_cred_label_associate(cred, &temp_cred);
4183	*disjointp = mac_cred_label_update_execve(ctx, &temp_cred,
4184						     vp, scriptl, execl);
4185
4186	newcred = kauth_cred_update(cred, &temp_cred, TRUE);
4187	mac_cred_label_destroy(&temp_cred);
4188	return (newcred);
4189}
4190
4191/*
4192 *  kauth_proc_label_update
4193 *
4194 * Description:  Update the label inside the credential associated with the process.
4195 *
4196 * Parameters:	p			The process to modify
4197 *				label		The label to place in the process credential
4198 *
4199 * Notes:		The credential associated with the process may change as a result
4200 *				of this call.  The caller should not assume the process reference to
4201 *				the old credential still exists.
4202 */
4203int kauth_proc_label_update(struct proc *p, struct label *label)
4204{
4205	kauth_cred_t my_cred, my_new_cred;
4206
4207	my_cred = kauth_cred_proc_ref(p);
4208
4209	DEBUG_CRED_ENTER("kauth_proc_label_update: %p\n", my_cred);
4210
4211	/* get current credential and take a reference while we muck with it */
4212	for (;;) {
4213
4214  		/*
4215		 * Set the credential with new info.  If there is no change,
4216		 * we get back the same credential we passed in; if there is
4217		 * a change, we drop the reference on the credential we
4218		 * passed in.  The subsequent compare is safe, because it is
4219		 * a pointer compare rather than a contents compare.
4220  		 */
4221		my_new_cred = kauth_cred_label_update(my_cred, label);
4222		if (my_cred != my_new_cred) {
4223
4224			DEBUG_CRED_CHANGE("kauth_proc_setlabel_unlocked CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
4225
4226			proc_lock(p);
4227			/*
4228			 * We need to protect for a race where another thread
4229			 * also changed the credential after we took our
4230			 * reference.  If p_ucred has changed then we should
4231			 * restart this again with the new cred.
4232			 */
4233			if (p->p_ucred != my_cred) {
4234				proc_unlock(p);
4235				kauth_cred_unref(&my_new_cred);
4236				my_cred = kauth_cred_proc_ref(p);
4237				/* try again */
4238				continue;
4239			}
4240			p->p_ucred = my_new_cred;
4241			/* update cred on proc */
4242			PROC_UPDATE_CREDS_ONPROC(p);
4243
4244			mac_proc_set_enforce(p, MAC_ALL_ENFORCE);
4245			proc_unlock(p);
4246		}
4247		break;
4248	}
4249	/* Drop old proc reference or our extra reference */
4250	kauth_cred_unref(&my_cred);
4251
4252	return (0);
4253}
4254
4255/*
4256 *  kauth_proc_label_update_execve
4257 *
4258 * Description: Update the label inside the credential associated with the
4259 *		process as part of a transitioning execve.  The label will
4260 *		be updated by the policies as part of this processing, not
4261 *		provided up front.
4262 *
4263 * Parameters:	p			The process to modify
4264 *		ctx			The context of the exec
4265 *		vp			The vnode being exec'ed
4266 *		scriptl			The script MAC label
4267 *		execl			The executable MAC label
4268 *
4269 * Returns:	0			Label update did not make credential
4270 *					disjoint
4271 *		1			Label update caused credential to be
4272 *					disjoint
4273 *
4274 * Notes:	The credential associated with the process WILL change as a
4275 *		result of this call.  The caller should not assume the process
4276 *		reference to the old credential still exists.
4277 */
4278int
4279kauth_proc_label_update_execve(struct proc *p, vfs_context_t ctx,
4280	struct vnode *vp, struct label *scriptl, struct label *execl)
4281{
4282	kauth_cred_t my_cred, my_new_cred;
4283	int disjoint = 0;
4284
4285	my_cred = kauth_cred_proc_ref(p);
4286
4287	DEBUG_CRED_ENTER("kauth_proc_label_update_execve: %p\n", my_cred);
4288
4289	/* get current credential and take a reference while we muck with it */
4290	for (;;) {
4291
4292  		/*
4293		 * Set the credential with new info.  If there is no change,
4294		 * we get back the same credential we passed in; if there is
4295		 * a change, we drop the reference on the credential we
4296		 * passed in.  The subsequent compare is safe, because it is
4297		 * a pointer compare rather than a contents compare.
4298  		 */
4299		my_new_cred = kauth_cred_label_update_execve(my_cred, ctx, vp, scriptl, execl, &disjoint);
4300		if (my_cred != my_new_cred) {
4301
4302			DEBUG_CRED_CHANGE("kauth_proc_label_update_execve_unlocked CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
4303
4304			proc_lock(p);
4305			/*
4306			 * We need to protect for a race where another thread
4307			 * also changed the credential after we took our
4308			 * reference.  If p_ucred has changed then we should
4309			 * restart this again with the new cred.
4310			 */
4311			if (p->p_ucred != my_cred) {
4312				proc_unlock(p);
4313				kauth_cred_unref(&my_new_cred);
4314				my_cred = kauth_cred_proc_ref(p);
4315				/* try again */
4316				continue;
4317			}
4318			p->p_ucred = my_new_cred;
4319			/* update cred on proc */
4320			PROC_UPDATE_CREDS_ONPROC(p);
4321			mac_proc_set_enforce(p, MAC_ALL_ENFORCE);
4322			proc_unlock(p);
4323		}
4324		break;
4325	}
4326	/* Drop old proc reference or our extra reference */
4327	kauth_cred_unref(&my_cred);
4328
4329	return (disjoint);
4330}
4331
4332#if 1
4333/*
4334 * for temporary binary compatibility
4335 */
4336kauth_cred_t	kauth_cred_setlabel(kauth_cred_t cred, struct label *label);
4337kauth_cred_t
4338kauth_cred_setlabel(kauth_cred_t cred, struct label *label)
4339{
4340	return kauth_cred_label_update(cred, label);
4341}
4342
4343int kauth_proc_setlabel(struct proc *p, struct label *label);
4344int
4345kauth_proc_setlabel(struct proc *p, struct label *label)
4346{
4347	return kauth_proc_label_update(p, label);
4348}
4349#endif
4350
4351#else
4352
4353/* this is a temp hack to cover us when MACF is not built in a kernel configuration.
4354 * Since we cannot build our export lists based on the kernel configuration we need
4355 * to define a stub.
4356 */
4357kauth_cred_t
4358kauth_cred_label_update(__unused kauth_cred_t cred, __unused void *label)
4359{
4360	return(NULL);
4361}
4362
4363int
4364kauth_proc_label_update(__unused struct proc *p, __unused void *label)
4365{
4366	return (0);
4367}
4368
4369#if 1
4370/*
4371 * for temporary binary compatibility
4372 */
4373kauth_cred_t	kauth_cred_setlabel(kauth_cred_t cred, void *label);
4374kauth_cred_t
4375kauth_cred_setlabel(__unused kauth_cred_t cred, __unused void *label)
4376{
4377	return NULL;
4378}
4379
4380int kauth_proc_setlabel(struct proc *p, void *label);
4381int
4382kauth_proc_setlabel(__unused struct proc *p, __unused void *label)
4383{
4384	return (0);
4385}
4386#endif
4387#endif
4388
4389/*
4390 * kauth_cred_ref
4391 *
4392 * Description:	Add a reference to the passed credential
4393 *
4394 * Parameters:	cred				The credential to reference
4395 *
4396 * Returns:	(void)
4397 *
4398 * Notes:	This function adds a reference to the provided credential;
4399 *		the existing reference on the credential is assumed to be
4400 *		held stable over this operation by taking the appropriate
4401 *		lock to protect the pointer from which it is being referenced,
4402 *		if necessary (e.g. the proc lock is held over the call if the
4403 *		credential being referenced is from p_ucred, the vnode lock
4404 *		if from the per vnode name cache cred cache, and so on).
4405 *
4406 *		This is safe from the kauth_cred_unref() path, since an atomic
4407 *		add is used, and the unref path specifically checks to see that
4408 *		the value has not been changed to add a reference between the
4409 *		time the credential is unreferenced by another pointer and the
4410 *		time it is unreferenced from the cred hash cache.
4411 */
4412void
4413kauth_cred_ref(kauth_cred_t cred)
4414{
4415	int		old_value;
4416
4417	NULLCRED_CHECK(cred);
4418
4419	old_value = OSAddAtomicLong(1, (long*)&cred->cr_ref);
4420
4421	if (old_value < 1)
4422		panic("kauth_cred_ref: trying to take a reference on a cred with no references");
4423
4424#if 0 // use this to watch a specific credential
4425	if ( is_target_cred( cred ) != 0 ) {
4426 		get_backtrace( );
4427	}
4428#endif
4429
4430	return;
4431}
4432
4433
4434/*
4435 * kauth_cred_unref_hashlocked
4436 *
4437 * Description:	release a credential reference; when the last reference is
4438 *		released, the credential will be freed.
4439 *
4440 * Parameters:	credp				Pointer to address containing
4441 *						credential to be freed
4442 *
4443 * Returns:	(void)
4444 *
4445 * Implicit returns:
4446 *		*credp				Set to NOCRED
4447 *
4448 * Notes:	This function assumes the credential hash lock is held.
4449 *
4450 *		This function is internal use only, since the hash lock is
4451 *		scoped to this compilation unit.
4452 *
4453 *		This function destroys the contents of the pointer passed by
4454 *		the caller to prevent the caller accidentally attempting to
4455 *		release a given reference twice in error.
4456 *
4457 *		The last reference is considered to be released when a release
4458 *		of a credential of a reference count of 2 occurs; this is an
4459 *		intended effect, to take into account the reference held by
4460 *		the credential hash, which is released at the same time.
4461 */
4462static void
4463kauth_cred_unref_hashlocked(kauth_cred_t *credp)
4464{
4465	int		old_value;
4466
4467	KAUTH_CRED_HASH_LOCK_ASSERT();
4468	NULLCRED_CHECK(*credp);
4469
4470	old_value = OSAddAtomicLong(-1, (long*)&(*credp)->cr_ref);
4471
4472#if DIAGNOSTIC
4473	if (old_value == 0)
4474		panic("%s:0x%08x kauth_cred_unref_hashlocked: dropping a reference on a cred with no references", current_proc()->p_comm, *credp);
4475	if (old_value == 1)
4476		panic("%s:0x%08x kauth_cred_unref_hashlocked: dropping a reference on a cred with no hash entry", current_proc()->p_comm, *credp);
4477#endif
4478
4479#if 0 // use this to watch a specific credential
4480	if ( is_target_cred( *credp ) != 0 ) {
4481		get_backtrace( );
4482	}
4483#endif
4484
4485	/*
4486	 * If the old_value is 2, then we have just released the last external
4487	 * reference to this credential
4488	 */
4489	if (old_value < 3) {
4490		/* The last absolute reference is our credential hash table */
4491		kauth_cred_remove(*credp);
4492	}
4493	*credp = NOCRED;
4494}
4495
4496
4497/*
4498 * kauth_cred_unref
4499 *
4500 * Description:	Release a credential reference while holding the credential
4501 *		hash lock; when the last reference is released, the credential
4502 *		will be freed.
4503 *
4504 * Parameters:	credp				Pointer to address containing
4505 *						credential to be freed
4506 *
4507 * Returns:	(void)
4508 *
4509 * Implicit returns:
4510 *		*credp				Set to NOCRED
4511 *
4512 * Notes:	See kauth_cred_unref_hashlocked() for more information.
4513 *
4514 */
4515void
4516kauth_cred_unref(kauth_cred_t *credp)
4517{
4518	KAUTH_CRED_HASH_LOCK();
4519	kauth_cred_unref_hashlocked(credp);
4520	KAUTH_CRED_HASH_UNLOCK();
4521}
4522
4523
4524#ifndef __LP64__
4525/*
4526 * kauth_cred_rele
4527 *
4528 * Description:	release a credential reference; when the last reference is
4529 *		released, the credential will be freed
4530 *
4531 * Parameters:	cred				Credential to release
4532 *
4533 * Returns:	(void)
4534 *
4535 * DEPRECATED:	This interface is obsolete due to a failure to clear out the
4536 *		clear the pointer in the caller to avoid multiple releases of
4537 *		the same credential.  The currently recommended interface is
4538 *		kauth_cred_unref().
4539 */
4540void
4541kauth_cred_rele(kauth_cred_t cred)
4542{
4543	kauth_cred_unref(&cred);
4544}
4545#endif /* !__LP64__ */
4546
4547
4548/*
4549 * kauth_cred_dup
4550 *
4551 * Description:	Duplicate a credential via alloc and copy; the new credential
4552 *		has only it's own
4553 *
4554 * Parameters:	cred				The credential to duplicate
4555 *
4556 * Returns:	(kauth_cred_t)			The duplicate credential
4557 *
4558 * Notes:	The typical value to calling this routine is if you are going
4559 *		to modify an existing credential, and expect to need a new one
4560 *		from the hash cache.
4561 *
4562 *		This should probably not be used in the majority of cases;
4563 *		if you are using it instead of kauth_cred_create(), you are
4564 *		likely making a mistake.
4565 *
4566 *		The newly allocated credential is copied as part of the
4567 *		allocation process, with the exception of the reference
4568 *		count, which is set to 1 to indicate a single reference
4569 *		held by the caller.
4570 *
4571 *		Since newly allocated credentials have no external pointers
4572 *		referencing them, prior to making them visible in an externally
4573 *		visible pointer (e.g. by adding them to the credential hash
4574 *		cache) is the only legal time in which an existing credential
4575 *		can be safely initialized or modified directly.
4576 *
4577 *		After initialization, the caller is expected to call the
4578 *		function kauth_cred_add() to add the credential to the hash
4579 *		cache, after which time it's frozen and becomes publicly
4580 *		visible.
4581 *
4582 *		The release protocol depends on kauth_hash_add() being called
4583 *		before kauth_cred_rele() (there is a diagnostic panic which
4584 *		will trigger if this protocol is not observed).
4585 *
4586 */
4587kauth_cred_t
4588kauth_cred_dup(kauth_cred_t cred)
4589{
4590	kauth_cred_t newcred;
4591#if CONFIG_MACF
4592	struct label *temp_label;
4593#endif
4594
4595#if CRED_DIAGNOSTIC
4596	if (cred == NOCRED || cred == FSCRED)
4597		panic("kauth_cred_dup: bad credential");
4598#endif
4599	newcred = kauth_cred_alloc();
4600	if (newcred != NULL) {
4601#if CONFIG_MACF
4602		temp_label = newcred->cr_label;
4603#endif
4604		bcopy(cred, newcred, sizeof(*newcred));
4605#if CONFIG_MACF
4606		newcred->cr_label = temp_label;
4607		mac_cred_label_associate(cred, newcred);
4608#endif
4609		AUDIT_SESSION_REF(cred);
4610		newcred->cr_ref = 1;
4611	}
4612	return(newcred);
4613}
4614
4615/*
4616 * kauth_cred_copy_real
4617 *
4618 * Description:	Returns a credential based on the passed credential but which
4619 *		reflects the real rather than effective UID and GID.
4620 *
4621 * Parameters:	cred				The credential from which to
4622 *						derive the new credential
4623 *
4624 * Returns:	(kauth_cred_t)			The copied credential
4625 *
4626 * IMPORTANT:	This function DOES NOT utilize kauth_cred_update(); as a
4627 *		result, the caller is responsible for dropping BOTH the
4628 *		additional reference on the passed cred (if any), and the
4629 *		credential returned by this function.  The drop should be
4630 *		via the kauth_cred_unref() KPI.
4631 */
4632kauth_cred_t
4633kauth_cred_copy_real(kauth_cred_t cred)
4634{
4635	kauth_cred_t newcred = NULL, found_cred;
4636	struct ucred temp_cred;
4637	posix_cred_t temp_pcred = posix_cred_get(&temp_cred);
4638	posix_cred_t pcred = posix_cred_get(cred);
4639
4640	/* if the credential is already 'real', just take a reference */
4641	if ((pcred->cr_ruid == pcred->cr_uid) &&
4642	    (pcred->cr_rgid == pcred->cr_gid)) {
4643		kauth_cred_ref(cred);
4644		return(cred);
4645	}
4646
4647	/*
4648	 * Look up in cred hash table to see if we have a matching credential
4649	 * with the new values.
4650	 */
4651	bcopy(cred, &temp_cred, sizeof(temp_cred));
4652	temp_pcred->cr_uid = pcred->cr_ruid;
4653	/* displacing a supplementary group opts us out of memberd */
4654	if (kauth_cred_change_egid(&temp_cred, pcred->cr_rgid)) {
4655		temp_pcred->cr_flags |= CRF_NOMEMBERD;
4656		temp_pcred->cr_gmuid = KAUTH_UID_NONE;
4657	}
4658	/*
4659	 * If the cred is not opted out, make sure we are using the r/euid
4660	 * for group checks
4661	 */
4662	if (temp_pcred->cr_gmuid != KAUTH_UID_NONE)
4663		temp_pcred->cr_gmuid = pcred->cr_ruid;
4664
4665	for (;;) {
4666		int		err;
4667
4668		KAUTH_CRED_HASH_LOCK();
4669		found_cred = kauth_cred_find(&temp_cred);
4670		if (found_cred == cred) {
4671			/* same cred so just bail */
4672			KAUTH_CRED_HASH_UNLOCK();
4673			return(cred);
4674		}
4675		if (found_cred != NULL) {
4676			/*
4677			 * Found a match so we bump reference count on new
4678			 * one.  We leave the old one alone.
4679			 */
4680			kauth_cred_ref(found_cred);
4681			KAUTH_CRED_HASH_UNLOCK();
4682			return(found_cred);
4683		}
4684
4685		/*
4686		 * Must allocate a new credential, copy in old credential
4687		 * data and update the real user and group IDs.
4688		 */
4689		newcred = kauth_cred_dup(&temp_cred);
4690		err = kauth_cred_add(newcred);
4691		KAUTH_CRED_HASH_UNLOCK();
4692
4693		/* Retry if kauth_cred_add() fails */
4694		if (err == 0)
4695			break;
4696#if CONFIG_MACF
4697		mac_cred_label_destroy(newcred);
4698#endif
4699		AUDIT_SESSION_UNREF(newcred);
4700
4701		FREE_ZONE(newcred, sizeof(*newcred), M_CRED);
4702		newcred = NULL;
4703	}
4704
4705	return(newcred);
4706}
4707
4708
4709/*
4710 * kauth_cred_update
4711 *
4712 * Description:	Common code to update a credential
4713 *
4714 * Parameters:	old_cred			Reference counted credential
4715 *						to update
4716 *		model_cred			Non-reference counted model
4717 *						credential to apply to the
4718 *						credential to be updated
4719 *		retain_auditinfo		Flag as to whether or not the
4720 *						audit information should be
4721 *						copied from the old_cred into
4722 *						the model_cred
4723 *
4724 * Returns:	(kauth_cred_t)			The updated credential
4725 *
4726 * IMPORTANT:	This function will potentially return a credential other than
4727 *		the one it is passed, and if so, it will have dropped the
4728 *		reference on the passed credential.  All callers should be
4729 *		aware of this, and treat this function as an unref + ref,
4730 *		potentially on different credentials.
4731 *
4732 *		Because of this, the caller is expected to take its own
4733 *		reference on the credential passed as the first parameter,
4734 *		and be prepared to release the reference on the credential
4735 *		that is returned to them, if it is not intended to be a
4736 *		persistent reference.
4737 */
4738static kauth_cred_t
4739kauth_cred_update(kauth_cred_t old_cred, kauth_cred_t model_cred,
4740	boolean_t retain_auditinfo)
4741{
4742	kauth_cred_t found_cred, new_cred = NULL;
4743
4744	/*
4745	 * Make sure we carry the auditinfo forward to the new credential
4746	 * unless we are actually updating the auditinfo.
4747	 */
4748	if (retain_auditinfo) {
4749		bcopy(&old_cred->cr_audit, &model_cred->cr_audit,
4750		    sizeof(model_cred->cr_audit));
4751	}
4752
4753	for (;;) {
4754		int		err;
4755
4756		KAUTH_CRED_HASH_LOCK();
4757		found_cred = kauth_cred_find(model_cred);
4758		if (found_cred == old_cred) {
4759			/* same cred so just bail */
4760			KAUTH_CRED_HASH_UNLOCK();
4761			return(old_cred);
4762		}
4763		if (found_cred != NULL) {
4764			DEBUG_CRED_CHANGE("kauth_cred_update(cache hit): %p -> %p\n", old_cred, found_cred);
4765			/*
4766			 * Found a match so we bump reference count on new
4767			 * one and decrement reference count on the old one.
4768			 */
4769			kauth_cred_ref(found_cred);
4770			kauth_cred_unref_hashlocked(&old_cred);
4771			KAUTH_CRED_HASH_UNLOCK();
4772			return(found_cred);
4773		}
4774
4775		/*
4776		 * Must allocate a new credential using the model.  also
4777		 * adds the new credential to the credential hash table.
4778		 */
4779		new_cred = kauth_cred_dup(model_cred);
4780		err = kauth_cred_add(new_cred);
4781		KAUTH_CRED_HASH_UNLOCK();
4782
4783		/* retry if kauth_cred_add returns non zero value */
4784		if (err == 0)
4785			break;
4786#if CONFIG_MACF
4787		mac_cred_label_destroy(new_cred);
4788#endif
4789		AUDIT_SESSION_UNREF(new_cred);
4790
4791		FREE_ZONE(new_cred, sizeof(*new_cred), M_CRED);
4792		new_cred = NULL;
4793	}
4794
4795	DEBUG_CRED_CHANGE("kauth_cred_update(cache miss): %p -> %p\n", old_cred, new_cred);
4796	kauth_cred_unref(&old_cred);
4797	return(new_cred);
4798}
4799
4800
4801/*
4802 * kauth_cred_add
4803 *
4804 * Description:	Add the given credential to our credential hash table and
4805 *		take an additional reference to account for our use of the
4806 *		credential in the hash table
4807 *
4808 * Parameters:	new_cred			Credential to insert into cred
4809 *						hash cache
4810 *
4811 * Returns:	0				Success
4812 *		-1				Hash insertion failed: caller
4813 *						should retry
4814 *
4815 * Locks:	Caller is expected to hold KAUTH_CRED_HASH_LOCK
4816 *
4817 * Notes:	The 'new_cred' MUST NOT already be in the cred hash cache
4818 */
4819static int
4820kauth_cred_add(kauth_cred_t new_cred)
4821{
4822	u_long			hash_key;
4823
4824	KAUTH_CRED_HASH_LOCK_ASSERT();
4825
4826	hash_key = kauth_cred_get_hashkey(new_cred);
4827	hash_key %= kauth_cred_table_size;
4828
4829	/* race fix - there is a window where another matching credential
4830	 * could have been inserted between the time this one was created and we
4831	 * got the hash lock.  If we find a match return an error and have the
4832	 * the caller retry.
4833	 */
4834	if (kauth_cred_find(new_cred) != NULL) {
4835		return(-1);
4836	}
4837
4838	/* take a reference for our use in credential hash table */
4839	kauth_cred_ref(new_cred);
4840
4841	/* insert the credential into the hash table */
4842	TAILQ_INSERT_HEAD(&kauth_cred_table_anchor[hash_key], new_cred, cr_link);
4843
4844	return(0);
4845}
4846
4847
4848/*
4849 * kauth_cred_remove
4850 *
4851 * Description:	Remove the given credential from our credential hash table
4852 *
4853 * Parameters:	cred				Credential to remove from cred
4854 *						hash cache
4855 *
4856 * Returns:	(void)
4857 *
4858 * Locks:	Caller is expected to hold KAUTH_CRED_HASH_LOCK
4859 *
4860 * Notes:	The check for the reference increment after entry is generally
4861 *		agree to be safe, since we use atomic operations, and the
4862 *		following code occurs with the hash lock held; in theory, this
4863 *		protects us from the 2->1 reference that gets us here.
4864 */
4865static void
4866kauth_cred_remove(kauth_cred_t cred)
4867{
4868	u_long			hash_key;
4869	kauth_cred_t	found_cred;
4870
4871	hash_key = kauth_cred_get_hashkey(cred);
4872	hash_key %= kauth_cred_table_size;
4873
4874	/* Avoid race */
4875	if (cred->cr_ref < 1)
4876		panic("cred reference underflow");
4877	if (cred->cr_ref > 1)
4878		return;		/* someone else got a ref */
4879
4880	/* Find cred in the credential hash table */
4881	TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[hash_key], cr_link) {
4882		if (found_cred == cred) {
4883			/* found a match, remove it from the hash table */
4884			TAILQ_REMOVE(&kauth_cred_table_anchor[hash_key], found_cred, cr_link);
4885#if CONFIG_MACF
4886			mac_cred_label_destroy(cred);
4887#endif
4888			AUDIT_SESSION_UNREF(cred);
4889
4890			cred->cr_ref = 0;
4891			FREE_ZONE(cred, sizeof(*cred), M_CRED);
4892#if KAUTH_CRED_HASH_DEBUG
4893			kauth_cred_count--;
4894#endif
4895			return;
4896		}
4897	}
4898
4899	/* Did not find a match... this should not happen! XXX Make panic? */
4900	printf("%s:%d - %s - %s - did not find a match for %p\n", __FILE__, __LINE__, __FUNCTION__, current_proc()->p_comm, cred);
4901	return;
4902}
4903
4904
4905/*
4906 * kauth_cred_find
4907 *
4908 * Description:	Using the given credential data, look for a match in our
4909 *		credential hash table
4910 *
4911 * Parameters:	cred				Credential to lookup in cred
4912 *						hash cache
4913 *
4914 * Returns:	NULL				Not found
4915 *		!NULL				Matching credential already in
4916 *						cred hash cache
4917 *
4918 * Locks:	Caller is expected to hold KAUTH_CRED_HASH_LOCK
4919 */
4920kauth_cred_t
4921kauth_cred_find(kauth_cred_t cred)
4922{
4923	u_long			hash_key;
4924	kauth_cred_t	found_cred;
4925	posix_cred_t pcred = posix_cred_get(cred);
4926
4927	KAUTH_CRED_HASH_LOCK_ASSERT();
4928
4929#if KAUTH_CRED_HASH_DEBUG
4930	static int		test_count = 0;
4931
4932	test_count++;
4933	if ((test_count % 200) == 0) {
4934		kauth_cred_hash_print();
4935	}
4936#endif
4937
4938	hash_key = kauth_cred_get_hashkey(cred);
4939	hash_key %= kauth_cred_table_size;
4940
4941	/* Find cred in the credential hash table */
4942	TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[hash_key], cr_link) {
4943		boolean_t match;
4944		posix_cred_t found_pcred = posix_cred_get(found_cred);
4945
4946		/*
4947		 * don't worry about the label unless the flags in
4948		 * either credential tell us to.
4949		 */
4950		match = (bcmp(found_pcred, pcred, sizeof (*pcred)) == 0) ? TRUE : FALSE;
4951		match = match && ((bcmp(&found_cred->cr_audit, &cred->cr_audit,
4952			sizeof(cred->cr_audit)) == 0) ? TRUE : FALSE);
4953		if (((found_pcred->cr_flags & CRF_MAC_ENFORCE) != 0) ||
4954		    ((pcred->cr_flags & CRF_MAC_ENFORCE) != 0)) {
4955			match = match && mac_cred_label_compare(found_cred->cr_label,
4956				cred->cr_label);
4957		}
4958
4959		if (match) {
4960			/* found a match */
4961			return(found_cred);
4962		}
4963	}
4964	/* No match found */
4965
4966	return(NULL);
4967}
4968
4969
4970/*
4971 * kauth_cred_hash
4972 *
4973 * Description:	Generates a hash key using data that makes up a credential;
4974 *		based on ElfHash
4975 *
4976 * Parameters:	datap				Pointer to data to hash
4977 *		data_len			Count of bytes to hash
4978 *		start_key			Start key value
4979 *
4980 * Returns:	(u_long)			Returned hash key
4981 */
4982static inline u_long
4983kauth_cred_hash(const uint8_t *datap, int data_len, u_long start_key)
4984{
4985	u_long	hash_key = start_key;
4986	u_long	temp;
4987
4988	while (data_len > 0) {
4989		hash_key = (hash_key << 4) + *datap++;
4990		temp = hash_key & 0xF0000000;
4991		if (temp) {
4992			hash_key ^= temp >> 24;
4993		}
4994		hash_key &= ~temp;
4995		data_len--;
4996	}
4997	return(hash_key);
4998}
4999
5000
5001/*
5002 * kauth_cred_get_hashkey
5003 *
5004 * Description:	Generate a hash key using data that makes up a credential;
5005 *		based on ElfHash.  We hash on the entire credential data,
5006 *		not including the ref count or the TAILQ, which are mutable;
5007 *		everything else isn't.
5008 *
5009 * Parameters:	cred				Credential for which hash is
5010 *						desired
5011 *
5012 * Returns:	(u_long)			Returned hash key
5013 *
5014 * Notes:	When actually moving the POSIX credential into a real label,
5015 *		remember to update this hash computation.
5016 */
5017static u_long
5018kauth_cred_get_hashkey(kauth_cred_t cred)
5019{
5020	posix_cred_t pcred = posix_cred_get(cred);
5021	u_long	hash_key = 0;
5022
5023	hash_key = kauth_cred_hash((uint8_t *)&cred->cr_posix,
5024							   sizeof (struct posix_cred),
5025							   hash_key);
5026	hash_key = kauth_cred_hash((uint8_t *)&cred->cr_audit,
5027							   sizeof(struct au_session),
5028							   hash_key);
5029
5030	if (pcred->cr_flags & CRF_MAC_ENFORCE) {
5031		hash_key = kauth_cred_hash((uint8_t *)cred->cr_label,
5032								   sizeof (struct label),
5033								   hash_key);
5034	}
5035	return(hash_key);
5036}
5037
5038
5039#if KAUTH_CRED_HASH_DEBUG
5040/*
5041 * kauth_cred_hash_print
5042 *
5043 * Description:	Print out cred hash cache table information for debugging
5044 *		purposes, including the credential contents
5045 *
5046 * Parameters:	(void)
5047 *
5048 * Returns:	(void)
5049 *
5050 * Implicit returns:	Results in console output
5051 */
5052static void
5053kauth_cred_hash_print(void)
5054{
5055	int 			i, j;
5056	kauth_cred_t	found_cred;
5057
5058	printf("\n\t kauth credential hash table statistics - current cred count %d \n", kauth_cred_count);
5059	/* count slot hits, misses, collisions, and max depth */
5060	for (i = 0; i < kauth_cred_table_size; i++) {
5061		printf("[%02d] ", i);
5062		j = 0;
5063		TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[i], cr_link) {
5064			if (j > 0) {
5065				printf("---- ");
5066			}
5067			j++;
5068			kauth_cred_print(found_cred);
5069			printf("\n");
5070		}
5071		if (j == 0) {
5072			printf("NOCRED \n");
5073		}
5074	}
5075}
5076#endif	/* KAUTH_CRED_HASH_DEBUG */
5077
5078
5079#if (defined(KAUTH_CRED_HASH_DEBUG) && (KAUTH_CRED_HASH_DEBUG != 0)) || defined(DEBUG_CRED)
5080/*
5081 * kauth_cred_print
5082 *
5083 * Description:	Print out an individual credential's contents for debugging
5084 *		purposes
5085 *
5086 * Parameters:	cred				The credential to print out
5087 *
5088 * Returns:	(void)
5089 *
5090 * Implicit returns:	Results in console output
5091 */
5092void
5093kauth_cred_print(kauth_cred_t cred)
5094{
5095	int 	i;
5096
5097	printf("%p - refs %lu flags 0x%08x uids e%d r%d sv%d gm%d ", cred, cred->cr_ref, cred->cr_flags, cred->cr_uid, cred->cr_ruid, cred->cr_svuid, cred->cr_gmuid);
5098	printf("group count %d gids ", cred->cr_ngroups);
5099	for (i = 0; i < NGROUPS; i++) {
5100		if (i == 0)
5101			printf("e");
5102		printf("%d ", cred->cr_groups[i]);
5103	}
5104	printf("r%d sv%d ", cred->cr_rgid, cred->cr_svgid);
5105	printf("auditinfo_addr %d %d %d %d %d %d\n",
5106		cred->cr_audit.s_aia_p->ai_auid,
5107		cred->cr_audit.as_mask.am_success,
5108		cred->cr_audit.as_mask.am_failure,
5109		cred->cr_audit.as_aia_p->ai_termid.at_port,
5110		cred->cr_audit.as_aia_p->ai_termid.at_addr[0],
5111		cred->cr_audit.as_aia_p->ai_asid);
5112}
5113
5114int is_target_cred( kauth_cred_t the_cred )
5115{
5116	if ( the_cred->cr_uid != 0 )
5117		return( 0 );
5118	if ( the_cred->cr_ruid != 0 )
5119		return( 0 );
5120	if ( the_cred->cr_svuid != 0 )
5121		return( 0 );
5122	if ( the_cred->cr_ngroups != 11 )
5123		return( 0 );
5124	if ( the_cred->cr_groups[0] != 11 )
5125		return( 0 );
5126	if ( the_cred->cr_groups[1] != 81 )
5127		return( 0 );
5128	if ( the_cred->cr_groups[2] != 63947 )
5129		return( 0 );
5130	if ( the_cred->cr_groups[3] != 80288 )
5131		return( 0 );
5132	if ( the_cred->cr_groups[4] != 89006 )
5133		return( 0 );
5134	if ( the_cred->cr_groups[5] != 52173 )
5135		return( 0 );
5136	if ( the_cred->cr_groups[6] != 84524 )
5137		return( 0 );
5138	if ( the_cred->cr_groups[7] != 79 )
5139		return( 0 );
5140	if ( the_cred->cr_groups[8] != 80292 )
5141		return( 0 );
5142	if ( the_cred->cr_groups[9] != 80 )
5143		return( 0 );
5144	if ( the_cred->cr_groups[10] != 90824 )
5145		return( 0 );
5146	if ( the_cred->cr_rgid != 11 )
5147		return( 0 );
5148	if ( the_cred->cr_svgid != 11 )
5149		return( 0 );
5150	if ( the_cred->cr_gmuid != 3475 )
5151		return( 0 );
5152	if ( the_cred->cr_audit.as_aia_p->ai_auid != 3475 )
5153		return( 0 );
5154/*
5155	if ( the_cred->cr_audit.as_mask.am_success != 0 )
5156		return( 0 );
5157	if ( the_cred->cr_audit.as_mask.am_failure != 0 )
5158		return( 0 );
5159	if ( the_cred->cr_audit.as_aia_p->ai_termid.at_port != 0 )
5160		return( 0 );
5161	if ( the_cred->cr_audit.as_aia_p->ai_termid.at_addr[0] != 0 )
5162		return( 0 );
5163	if ( the_cred->cr_audit.as_aia_p->ai_asid != 0 )
5164		return( 0 );
5165	if ( the_cred->cr_flags != 0 )
5166		return( 0 );
5167*/
5168	return( -1 ); // found target cred
5169}
5170
5171void get_backtrace( void )
5172{
5173	int				my_slot;
5174	void *			my_stack[ MAX_STACK_DEPTH ];
5175	int				i, my_depth;
5176
5177	if ( cred_debug_buf_p == NULL ) {
5178		MALLOC(cred_debug_buf_p, cred_debug_buffer *, sizeof(*cred_debug_buf_p), M_KAUTH, M_WAITOK);
5179		bzero(cred_debug_buf_p, sizeof(*cred_debug_buf_p));
5180	}
5181
5182	if ( cred_debug_buf_p->next_slot > (MAX_CRED_BUFFER_SLOTS - 1) ) {
5183		/* buffer is full */
5184		return;
5185	}
5186
5187	my_depth = OSBacktrace(&my_stack[0], MAX_STACK_DEPTH);
5188	if ( my_depth == 0 ) {
5189		printf("%s - OSBacktrace failed \n", __FUNCTION__);
5190		return;
5191	}
5192
5193	/* fill new backtrace */
5194	my_slot = cred_debug_buf_p->next_slot;
5195	cred_debug_buf_p->next_slot++;
5196	cred_debug_buf_p->stack_buffer[ my_slot ].depth = my_depth;
5197	for ( i = 0; i < my_depth; i++ ) {
5198		cred_debug_buf_p->stack_buffer[ my_slot ].stack[ i ] = my_stack[ i ];
5199	}
5200
5201	return;
5202}
5203
5204
5205/* subset of struct ucred for use in sysctl_dump_creds */
5206struct debug_ucred {
5207	void	*credp;
5208	u_long	cr_ref;				/* reference count */
5209	uid_t	cr_uid;				/* effective user id */
5210	uid_t	cr_ruid;			/* real user id */
5211	uid_t	cr_svuid;			/* saved user id */
5212	short	cr_ngroups;			/* number of groups in advisory list */
5213	gid_t	cr_groups[NGROUPS];	/* advisory group list */
5214	gid_t	cr_rgid;			/* real group id */
5215	gid_t	cr_svgid;			/* saved group id */
5216	uid_t	cr_gmuid;			/* UID for group membership purposes */
5217	struct auditinfo_addr cr_audit;	/* user auditing data. */
5218	void	*cr_label;			/* MACF label */
5219	int		cr_flags;			/* flags on credential */
5220};
5221typedef struct debug_ucred debug_ucred;
5222
5223SYSCTL_PROC(_kern, OID_AUTO, dump_creds, CTLFLAG_RD,
5224    NULL, 0, sysctl_dump_creds, "S,debug_ucred", "List of credentials in the cred hash");
5225
5226/*	accessed by:
5227 *	err = sysctlbyname( "kern.dump_creds", bufp, &len, NULL, 0 );
5228 */
5229
5230static int
5231sysctl_dump_creds( __unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req )
5232{
5233	int 			i, j, counter = 0;
5234	int				error;
5235	size_t			space;
5236	kauth_cred_t	found_cred;
5237	debug_ucred *	cred_listp;
5238	debug_ucred *	nextp;
5239
5240	/* This is a readonly node. */
5241	if (req->newptr != USER_ADDR_NULL)
5242		return (EPERM);
5243
5244	/* calculate space needed */
5245	for (i = 0; i < kauth_cred_table_size; i++) {
5246		TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[i], cr_link) {
5247			counter++;
5248		}
5249	}
5250
5251	/* they are querying us so just return the space required. */
5252	if (req->oldptr == USER_ADDR_NULL) {
5253		counter += 10; // add in some padding;
5254		req->oldidx = counter * sizeof(debug_ucred);
5255		return 0;
5256	}
5257
5258	MALLOC( cred_listp, debug_ucred *, req->oldlen, M_TEMP, M_WAITOK );
5259	if ( cred_listp == NULL ) {
5260		return (ENOMEM);
5261	}
5262
5263	/* fill in creds to send back */
5264	nextp = cred_listp;
5265	space = 0;
5266	for (i = 0; i < kauth_cred_table_size; i++) {
5267		TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[i], cr_link) {
5268			nextp->credp = found_cred;
5269			nextp->cr_ref = found_cred->cr_ref;
5270			nextp->cr_uid = found_cred->cr_uid;
5271			nextp->cr_ruid = found_cred->cr_ruid;
5272			nextp->cr_svuid = found_cred->cr_svuid;
5273			nextp->cr_ngroups = found_cred->cr_ngroups;
5274			for ( j = 0; j < nextp->cr_ngroups; j++ ) {
5275				nextp->cr_groups[ j ] = found_cred->cr_groups[ j ];
5276			}
5277			nextp->cr_rgid = found_cred->cr_rgid;
5278			nextp->cr_svgid = found_cred->cr_svgid;
5279			nextp->cr_gmuid = found_cred->cr_gmuid;
5280			nextp->cr_audit.ai_auid =
5281			    found_cred->cr_audit.as_aia_p->ai_auid;
5282			nextp->cr_audit.ai_mask.am_success =
5283			    found_cred->cr_audit.as_mask.am_success;
5284			nextp->cr_audit.ai_mask.am_failure =
5285			    found_cred->cr_audit.as_mask.am_failure;
5286			nextp->cr_audit.ai_termid.at_port =
5287			    found_cred->cr_audit.as_aia_p->ai_termid.at_port;
5288			nextp->cr_audit.ai_termid.at_type =
5289			    found_cred->cr_audit.as_aia_p->ai_termid.at_type;
5290			nextp->cr_audit.ai_termid.at_addr[0] =
5291			    found_cred->cr_audit.as_aia_p->ai_termid.at_addr[0];
5292			nextp->cr_audit.ai_termid.at_addr[1] =
5293			    found_cred->cr_audit.as_aia_p->ai_termid.at_addr[1];
5294			nextp->cr_audit.ai_termid.at_addr[2] =
5295			    found_cred->cr_audit.as_aia_p->ai_termid.at_addr[2];
5296			nextp->cr_audit.ai_termid.at_addr[3] =
5297			    found_cred->cr_audit.as_aia_p->ai_termid.at_addr[3];
5298			nextp->cr_audit.ai_asid =
5299			    found_cred->cr_audit.as_aia_p->ai_asid;
5300			nextp->cr_audit.ai_flags =
5301			    found_cred->cr_audit.as_aia_p->ai_flags;
5302			nextp->cr_label = found_cred->cr_label;
5303			nextp->cr_flags = found_cred->cr_flags;
5304			nextp++;
5305			space += sizeof(debug_ucred);
5306			if ( space > req->oldlen ) {
5307				FREE(cred_listp, M_TEMP);
5308				return (ENOMEM);
5309			}
5310		}
5311	}
5312	req->oldlen = space;
5313	error = SYSCTL_OUT(req, cred_listp, req->oldlen);
5314	FREE(cred_listp, M_TEMP);
5315	return (error);
5316}
5317
5318
5319SYSCTL_PROC(_kern, OID_AUTO, cred_bt, CTLFLAG_RD,
5320    NULL, 0, sysctl_dump_cred_backtraces, "S,cred_debug_buffer", "dump credential backtrace");
5321
5322/*	accessed by:
5323 *	err = sysctlbyname( "kern.cred_bt", bufp, &len, NULL, 0 );
5324 */
5325
5326static int
5327sysctl_dump_cred_backtraces( __unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req )
5328{
5329	int 			i, j;
5330	int				error;
5331	size_t			space;
5332	cred_debug_buffer *	bt_bufp;
5333	cred_backtrace *	nextp;
5334
5335	/* This is a readonly node. */
5336	if (req->newptr != USER_ADDR_NULL)
5337		return (EPERM);
5338
5339	if ( cred_debug_buf_p == NULL ) {
5340		return (EAGAIN);
5341	}
5342
5343	/* calculate space needed */
5344	space = sizeof( cred_debug_buf_p->next_slot );
5345	space += (sizeof( cred_backtrace ) * cred_debug_buf_p->next_slot);
5346
5347	/* they are querying us so just return the space required. */
5348	if (req->oldptr == USER_ADDR_NULL) {
5349		req->oldidx = space;
5350		return 0;
5351	}
5352
5353	if ( space > req->oldlen ) {
5354		return (ENOMEM);
5355	}
5356
5357	MALLOC( bt_bufp, cred_debug_buffer *, req->oldlen, M_TEMP, M_WAITOK );
5358	if ( bt_bufp == NULL ) {
5359		return (ENOMEM);
5360	}
5361
5362	/* fill in backtrace info to send back */
5363	bt_bufp->next_slot = cred_debug_buf_p->next_slot;
5364	space = sizeof(bt_bufp->next_slot);
5365
5366	nextp = &bt_bufp->stack_buffer[ 0 ];
5367	for (i = 0; i < cred_debug_buf_p->next_slot; i++) {
5368		nextp->depth = cred_debug_buf_p->stack_buffer[ i ].depth;
5369		for ( j = 0; j < nextp->depth; j++ ) {
5370			nextp->stack[ j ] = cred_debug_buf_p->stack_buffer[ i ].stack[ j ];
5371		}
5372		space += sizeof(*nextp);
5373		nextp++;
5374	}
5375	req->oldlen = space;
5376	error = SYSCTL_OUT(req, bt_bufp, req->oldlen);
5377	FREE(bt_bufp, M_TEMP);
5378	return (error);
5379}
5380
5381#endif	/* KAUTH_CRED_HASH_DEBUG || DEBUG_CRED */
5382
5383
5384/*
5385 **********************************************************************
5386 * The following routines will be moved to a policy_posix.c module at
5387 * some future point.
5388 **********************************************************************
5389 */
5390
5391/*
5392 * posix_cred_create
5393 *
5394 * Description:	Helper function to create a kauth_cred_t credential that is
5395 *		initally labelled with a specific POSIX credential label
5396 *
5397 * Parameters:	pcred			The posix_cred_t to use as the initial
5398 *					label value
5399 *
5400 * Returns:	(kauth_cred_t)		The credential that was found in the
5401 *					hash or creates
5402 *		NULL			kauth_cred_add() failed, or there was
5403 *					no egid specified, or we failed to
5404 *					attach a label to the new credential
5405 *
5406 * Notes:	This function currently wraps kauth_cred_create(), and is the
5407 *		only consumer of that ill-fated function, apart from bsd_init().
5408 *		It exists solely to support the NFS server code creation of
5409 *		credentials based on the over-the-wire RPC calls containing
5410 *		traditional POSIX credential information being tunneled to
5411 *		the server host from the client machine.
5412 *
5413 *		In the future, we hope this function goes away.
5414 *
5415 *		In the short term, it creates a temporary credential, puts
5416 *		the POSIX information from NFS into it, and then calls
5417 *		kauth_cred_create(), as an internal implementation detail.
5418 *
5419 *		If we have to keep it around in the medium term, it will
5420 *		create a new kauth_cred_t, then label it with a POSIX label
5421 *		corresponding to the contents of the kauth_cred_t.  If the
5422 *		policy_posix MACF module is not loaded, it will instead
5423 *		substitute a posix_cred_t which GRANTS all access (effectively
5424 *		a "root" credential) in order to not prevent NFS from working
5425 *		in the case that we are not supporting POSIX credentials.
5426 */
5427kauth_cred_t
5428posix_cred_create(posix_cred_t pcred)
5429{
5430	struct ucred temp_cred;
5431
5432	bzero(&temp_cred, sizeof(temp_cred));
5433	temp_cred.cr_posix = *pcred;
5434
5435	return kauth_cred_create(&temp_cred);
5436}
5437
5438
5439/*
5440 * posix_cred_get
5441 *
5442 * Description:	Given a kauth_cred_t, return the POSIX credential label, if
5443 *		any, which is associated with it.
5444 *
5445 * Parameters:	cred			The credential to obtain the label from
5446 *
5447 * Returns:	posix_cred_t		The POSIX credential label
5448 *
5449 * Notes:	In the event that the policy_posix MACF module IS NOT loaded,
5450 *		this function will return a pointer to a posix_cred_t which
5451 *		GRANTS all access (effectively, a "root" credential).  This is
5452 *		necessary to support legacy code which insists on tightly
5453 *		integrating POSIX credentials into its APIs, including, but
5454 *		not limited to, System V IPC mechanisms, POSIX IPC mechanisms,
5455 *		NFSv3, signals, dtrace, and a large number of kauth routines
5456 *		used to implement POSIX permissions related system calls.
5457 *
5458 *		In the event that the policy_posix MACF module IS loaded, and
5459 *		there is no POSIX label on the kauth_cred_t credential, this
5460 *		function will return a pointer to a posix_cred_t which DENIES
5461 *		all access (effectively, a "deny rights granted by POSIX"
5462 *		credential).  This is necessary to support the concept of a
5463 *		transiently loaded POSIX policy, or kauth_cred_t credentials
5464 *		which can not be used in conjunctions with POSIX permissions
5465 *		checks.
5466 *
5467 *		This function currently returns the address of the cr_posix
5468 *		field of the supplied kauth_cred_t credential, and as such
5469 *		currently can not fail.  In the future, this will not be the
5470 *		case.
5471 */
5472posix_cred_t
5473posix_cred_get(kauth_cred_t cred)
5474{
5475	return(&cred->cr_posix);
5476}
5477
5478
5479/*
5480 * posix_cred_label
5481 *
5482 * Description:	Label a kauth_cred_t with a POSIX credential label
5483 *
5484 * Parameters:	cred			The credential to label
5485 *		pcred			The POSIX credential t label it with
5486 *
5487 * Returns:	(void)
5488 *
5489 * Notes:	This function is currently void in order to permit it to fit
5490 *		in with the current MACF framework label methods which allow
5491 *		labeling to fail silently.  This is like acceptable for
5492 *		mandatory access controls, but not for POSIX, since those
5493 *		access controls are advisory.  We will need to consider a
5494 *		return value in a future version of the MACF API.
5495 *
5496 *		This operation currently cannot fail, as currently the POSIX
5497 *		credential is a subfield of the kauth_cred_t (ucred), which
5498 *		MUST be valid.  In the future, this will not be the case.
5499 */
5500void
5501posix_cred_label(kauth_cred_t cred, posix_cred_t pcred)
5502{
5503	cred->cr_posix = *pcred;	/* structure assign for now */
5504}
5505
5506
5507/*
5508 * posix_cred_access
5509 *
5510 * Description:	Perform a POSIX access check for a protected object
5511 *
5512 * Parameters:	cred			The credential to check
5513 *		object_uid		The POSIX UID of the protected object
5514 *		object_gid		The POSIX GID of the protected object
5515 *		object_mode		The POSIX mode of the protected object
5516 *		mode_req		The requested POSIX access rights
5517 *
5518 * Returns	0			Access is granted
5519 *		EACCES			Access is denied
5520 *
5521 * Notes:	This code optimizes the case where the world and group rights
5522 *		would both grant the requested rights to avoid making a group
5523 *		membership query.  This is a big performance win in the case
5524 *		where this is true.
5525 */
5526int
5527posix_cred_access(kauth_cred_t cred, id_t object_uid, id_t object_gid, mode_t object_mode, mode_t mode_req)
5528{
5529	int is_member;
5530	mode_t mode_owner = (object_mode & S_IRWXU);
5531	mode_t mode_group = (object_mode & S_IRWXG) << 3;
5532	mode_t mode_world = (object_mode & S_IRWXO) << 6;
5533
5534	/*
5535	 * Check first for owner rights
5536	 */
5537	if (kauth_cred_getuid(cred) == object_uid && (mode_req & mode_owner) == mode_req)
5538		return (0);
5539
5540	/*
5541	 * Combined group and world rights check, if we don't have owner rights
5542	 *
5543	 * OPTIMIZED: If group and world rights would grant the same bits, and
5544	 * they set of requested bits is in both, then we can simply check the
5545	 * world rights, avoiding a group membership check, which is expensive.
5546	 */
5547	if ((mode_req & mode_group & mode_world) == mode_req) {
5548		return (0);
5549	} else {
5550		/*
5551		 * NON-OPTIMIZED: requires group membership check.
5552		 */
5553		if ((mode_req & mode_group) != mode_req) {
5554			/*
5555			 * exclusion group : treat errors as "is a member"
5556			 *
5557			 * NON-OPTIMIZED: +group would deny; must check group
5558			 */
5559			if (!kauth_cred_ismember_gid(cred, object_gid, &is_member) && is_member) {
5560				/*
5561				 * DENY: +group denies
5562				 */
5563				return (EACCES);
5564			} else {
5565				if ((mode_req & mode_world) != mode_req) {
5566					/*
5567					 * DENY: both -group & world would deny
5568					 */
5569					return (EACCES);
5570				} else {
5571					/*
5572					 * ALLOW: allowed by -group and +world
5573					 */
5574					return (0);
5575				}
5576			}
5577		} else {
5578			/*
5579			 * inclusion group; treat errors as "not a member"
5580			 *
5581			 * NON-OPTIMIZED: +group allows, world denies; must
5582			 * check group
5583			 */
5584			if (!kauth_cred_ismember_gid(cred, object_gid, &is_member) && is_member) {
5585				/*
5586				 * ALLOW: allowed by +group
5587				 */
5588				return (0);
5589			} else {
5590				if ((mode_req & mode_world) != mode_req) {
5591					/*
5592					 * DENY: both -group & world would deny
5593					 */
5594					return (EACCES);
5595				} else {
5596					/*
5597					 * ALLOW: allowed by -group and +world
5598					 */
5599					return (0);
5600				}
5601			}
5602		}
5603	}
5604}
5605