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