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