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