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