]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_credential.c
c542382e52d69c9c18c8e4b8064b897b790b0572
[apple/xnu.git] / bsd / kern / kern_credential.c
1 /*
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30
31 /*
32 * Kernel Authorization framework: Management of process/thread credentials and identity information.
33 */
34
35
36 #include <sys/param.h> /* XXX trim includes */
37 #include <sys/acct.h>
38 #include <sys/systm.h>
39 #include <sys/ucred.h>
40 #include <sys/proc_internal.h>
41 #include <sys/user.h>
42 #include <sys/timeb.h>
43 #include <sys/times.h>
44 #include <sys/malloc.h>
45 #include <sys/kauth.h>
46 #include <sys/kernel.h>
47
48 #include <bsm/audit_kernel.h>
49
50 #include <sys/mount.h>
51 #include <sys/sysproto.h>
52 #include <mach/message.h>
53 #include <mach/host_security.h>
54
55 #include <libkern/OSAtomic.h>
56
57 #include <kern/task.h>
58 #include <kern/lock.h>
59 #ifdef MACH_ASSERT
60 # undef MACH_ASSERT
61 #endif
62 #define MACH_ASSERT 1 /* XXX so bogus */
63 #include <kern/assert.h>
64
65 #define CRED_DIAGNOSTIC 1
66
67 # define NULLCRED_CHECK(_c) do {if (((_c) == NOCRED) || ((_c) == FSCRED)) panic("bad credential %p", _c);} while(0)
68
69 /*
70 * Interface to external identity resolver.
71 *
72 * The architecture of the interface is simple; the external resolver calls in to
73 * get work, then calls back with completed work. It also calls us to let us know
74 * that it's (re)started, so that we can resubmit work if it times out.
75 */
76
77 static lck_mtx_t *kauth_resolver_mtx;
78 #define KAUTH_RESOLVER_LOCK() lck_mtx_lock(kauth_resolver_mtx);
79 #define KAUTH_RESOLVER_UNLOCK() lck_mtx_unlock(kauth_resolver_mtx);
80
81 static volatile pid_t kauth_resolver_identity;
82 static int kauth_resolver_registered;
83 static uint32_t kauth_resolver_sequence;
84
85 struct kauth_resolver_work {
86 TAILQ_ENTRY(kauth_resolver_work) kr_link;
87 struct kauth_identity_extlookup kr_work;
88 uint32_t kr_seqno;
89 int kr_refs;
90 int kr_flags;
91 #define KAUTH_REQUEST_UNSUBMITTED (1<<0)
92 #define KAUTH_REQUEST_SUBMITTED (1<<1)
93 #define KAUTH_REQUEST_DONE (1<<2)
94 int kr_result;
95 };
96
97 TAILQ_HEAD(kauth_resolver_unsubmitted_head, kauth_resolver_work) kauth_resolver_unsubmitted;
98 TAILQ_HEAD(kauth_resolver_submitted_head, kauth_resolver_work) kauth_resolver_submitted;
99 TAILQ_HEAD(kauth_resolver_done_head, kauth_resolver_work) kauth_resolver_done;
100
101 static int kauth_resolver_submit(struct kauth_identity_extlookup *lkp);
102 static int kauth_resolver_complete(user_addr_t message);
103 static int kauth_resolver_getwork(user_addr_t message);
104
105 #define KAUTH_CRED_PRIMES_COUNT 7
106 static const int kauth_cred_primes[KAUTH_CRED_PRIMES_COUNT] = {97, 241, 397, 743, 1499, 3989, 7499};
107 static int kauth_cred_primes_index = 0;
108 static int kauth_cred_table_size = 0;
109
110 TAILQ_HEAD(kauth_cred_entry_head, ucred);
111 static struct kauth_cred_entry_head * kauth_cred_table_anchor = NULL;
112
113 #define KAUTH_CRED_HASH_DEBUG 0
114
115 static int kauth_cred_add(kauth_cred_t new_cred);
116 static void kauth_cred_remove(kauth_cred_t cred);
117 static inline u_long kauth_cred_hash(const uint8_t *datap, int data_len, u_long start_key);
118 static u_long kauth_cred_get_hashkey(kauth_cred_t cred);
119 static kauth_cred_t kauth_cred_update(kauth_cred_t old_cred, kauth_cred_t new_cred, boolean_t retain_auditinfo);
120
121 #if KAUTH_CRED_HASH_DEBUG
122 static int kauth_cred_count = 0;
123 static void kauth_cred_hash_print(void);
124 static void kauth_cred_print(kauth_cred_t cred);
125 #endif
126
127 void
128 kauth_resolver_init(void)
129 {
130 TAILQ_INIT(&kauth_resolver_unsubmitted);
131 TAILQ_INIT(&kauth_resolver_submitted);
132 TAILQ_INIT(&kauth_resolver_done);
133 kauth_resolver_sequence = 31337;
134 kauth_resolver_mtx = lck_mtx_alloc_init(kauth_lck_grp, 0/*LCK_ATTR_NULL*/);
135 }
136
137 /*
138 * Allocate a work queue entry, submit the work and wait for completion.
139 *
140 * XXX do we want an 'interruptible' flag vs. always being interruptible?
141 */
142 static int
143 kauth_resolver_submit(struct kauth_identity_extlookup *lkp)
144 {
145 struct kauth_resolver_work *workp, *killp;
146 struct timespec ts;
147 int error, shouldfree;
148
149 /* no point actually blocking if the resolver isn't up yet */
150 if (kauth_resolver_identity == 0) {
151 /*
152 * We've already waited an initial 30 seconds with no result.
153 * Sleep on a stack address so no one wakes us before timeout;
154 * we sleep a half a second in case we are a high priority
155 * process, so that memberd doesn't starve while we are in a
156 * tight loop between user and kernel, eating all the CPU.
157 */
158 error = tsleep(&ts, PZERO | PCATCH, "kr_submit", hz/2);
159 if (kauth_resolver_identity == 0) {
160 /*
161 * if things haven't changed while we were asleep,
162 * tell the caller we couldn't get an authoritative
163 * answer.
164 */
165 return(EWOULDBLOCK);
166 }
167 }
168
169 MALLOC(workp, struct kauth_resolver_work *, sizeof(*workp), M_KAUTH, M_WAITOK);
170 if (workp == NULL)
171 return(ENOMEM);
172
173 workp->kr_work = *lkp;
174 workp->kr_refs = 1;
175 workp->kr_flags = KAUTH_REQUEST_UNSUBMITTED;
176 workp->kr_result = 0;
177
178 /*
179 * We insert the request onto the unsubmitted queue, the call in from the
180 * resolver will it to the submitted thread when appropriate.
181 */
182 KAUTH_RESOLVER_LOCK();
183 workp->kr_seqno = workp->kr_work.el_seqno = kauth_resolver_sequence++;
184 workp->kr_work.el_result = KAUTH_EXTLOOKUP_INPROG;
185
186 /* XXX as an optimisation, we could check the queue for identical items and coalesce */
187 TAILQ_INSERT_TAIL(&kauth_resolver_unsubmitted, workp, kr_link);
188
189 wakeup_one((caddr_t)&kauth_resolver_unsubmitted);
190 for (;;) {
191 /* we could compute a better timeout here */
192 ts.tv_sec = 30;
193 ts.tv_nsec = 0;
194 error = msleep(workp, kauth_resolver_mtx, PCATCH, "kr_submit", &ts);
195 /* request has been completed? */
196 if ((error == 0) && (workp->kr_flags & KAUTH_REQUEST_DONE))
197 break;
198 /* woken because the resolver has died? */
199 if (kauth_resolver_identity == 0) {
200 error = EIO;
201 break;
202 }
203 /* an error? */
204 if (error != 0)
205 break;
206 }
207 /* if the request was processed, copy the result */
208 if (error == 0)
209 *lkp = workp->kr_work;
210
211 /*
212 * If the request timed out and was never collected, the resolver is dead and
213 * probably not coming back anytime soon. In this case we revert to no-resolver
214 * behaviour, and punt all the other sleeping requests to clear the backlog.
215 */
216 if ((error == EWOULDBLOCK) && (workp->kr_flags & KAUTH_REQUEST_UNSUBMITTED)) {
217 KAUTH_DEBUG("RESOLVER - request timed out without being collected for processing, resolver dead");
218 kauth_resolver_identity = 0;
219 /* kill all the other requestes that are waiting as well */
220 TAILQ_FOREACH(killp, &kauth_resolver_submitted, kr_link)
221 wakeup(killp);
222 TAILQ_FOREACH(killp, &kauth_resolver_unsubmitted, kr_link)
223 wakeup(killp);
224 }
225
226 /* drop our reference on the work item, and note whether we should free it or not */
227 if (--workp->kr_refs <= 0) {
228 /* work out which list we have to remove it from */
229 if (workp->kr_flags & KAUTH_REQUEST_DONE) {
230 TAILQ_REMOVE(&kauth_resolver_done, workp, kr_link);
231 } else if (workp->kr_flags & KAUTH_REQUEST_SUBMITTED) {
232 TAILQ_REMOVE(&kauth_resolver_submitted, workp, kr_link);
233 } else if (workp->kr_flags & KAUTH_REQUEST_UNSUBMITTED) {
234 TAILQ_REMOVE(&kauth_resolver_unsubmitted, workp, kr_link);
235 } else {
236 KAUTH_DEBUG("RESOLVER - completed request has no valid queue");
237 }
238 shouldfree = 1;
239 } else {
240 /* someone else still has a reference on this request */
241 shouldfree = 0;
242 }
243 /* collect request result */
244 if (error == 0)
245 error = workp->kr_result;
246 KAUTH_RESOLVER_UNLOCK();
247 /*
248 * If we dropped the last reference, free the request.
249 */
250 if (shouldfree)
251 FREE(workp, M_KAUTH);
252
253 KAUTH_DEBUG("RESOLVER - returning %d", error);
254 return(error);
255 }
256
257 /*
258 * System call interface for the external identity resolver.
259 */
260 int
261 identitysvc(__unused struct proc *p, struct identitysvc_args *uap, __unused register_t *retval)
262 {
263 int opcode = uap->opcode;
264 user_addr_t message = uap->message;
265 struct kauth_resolver_work *workp;
266 int error;
267 pid_t new_id;
268
269 /*
270 * New server registering itself.
271 */
272 if (opcode == KAUTH_EXTLOOKUP_REGISTER) {
273 new_id = current_proc()->p_pid;
274 if ((error = kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER)) != 0) {
275 KAUTH_DEBUG("RESOLVER - pid %d refused permission to become identity resolver", new_id);
276 return(error);
277 }
278 KAUTH_RESOLVER_LOCK();
279 if (kauth_resolver_identity != new_id) {
280 KAUTH_DEBUG("RESOLVER - new resolver %d taking over from old %d", new_id, kauth_resolver_identity);
281 /*
282 * We have a new server, so assume that all the old requests have been lost.
283 */
284 while ((workp = TAILQ_LAST(&kauth_resolver_submitted, kauth_resolver_submitted_head)) != NULL) {
285 TAILQ_REMOVE(&kauth_resolver_submitted, workp, kr_link);
286 workp->kr_flags &= ~KAUTH_REQUEST_SUBMITTED;
287 workp->kr_flags |= KAUTH_REQUEST_UNSUBMITTED;
288 TAILQ_INSERT_HEAD(&kauth_resolver_unsubmitted, workp, kr_link);
289 }
290 kauth_resolver_identity = new_id;
291 kauth_resolver_registered = 1;
292 wakeup(&kauth_resolver_unsubmitted);
293 }
294 KAUTH_RESOLVER_UNLOCK();
295 return(0);
296 }
297
298 /*
299 * Beyond this point, we must be the resolver process.
300 */
301 if (current_proc()->p_pid != kauth_resolver_identity) {
302 KAUTH_DEBUG("RESOLVER - call from bogus resolver %d\n", current_proc()->p_pid);
303 return(EPERM);
304 }
305
306 /*
307 * Got a result returning?
308 */
309 if (opcode & KAUTH_EXTLOOKUP_RESULT) {
310 if ((error = kauth_resolver_complete(message)) != 0)
311 return(error);
312 }
313
314 /*
315 * Caller wants to take more work?
316 */
317 if (opcode & KAUTH_EXTLOOKUP_WORKER) {
318 if ((error = kauth_resolver_getwork(message)) != 0)
319 return(error);
320 }
321
322 return(0);
323 }
324
325 /*
326 * Get work for a caller.
327 */
328 static int
329 kauth_resolver_getwork(user_addr_t message)
330 {
331 struct kauth_resolver_work *workp;
332 int error;
333
334 KAUTH_RESOLVER_LOCK();
335 error = 0;
336 while ((workp = TAILQ_FIRST(&kauth_resolver_unsubmitted)) == NULL) {
337 error = msleep(&kauth_resolver_unsubmitted, kauth_resolver_mtx, PCATCH, "GRGetWork", 0);
338 if (error != 0)
339 break;
340 }
341 if (workp != NULL) {
342 if ((error = copyout(&workp->kr_work, message, sizeof(workp->kr_work))) != 0) {
343 KAUTH_DEBUG("RESOLVER - error submitting work to resolve");
344 goto out;
345 }
346 TAILQ_REMOVE(&kauth_resolver_unsubmitted, workp, kr_link);
347 workp->kr_flags &= ~KAUTH_REQUEST_UNSUBMITTED;
348 workp->kr_flags |= KAUTH_REQUEST_SUBMITTED;
349 TAILQ_INSERT_TAIL(&kauth_resolver_submitted, workp, kr_link);
350 }
351
352 out:
353 KAUTH_RESOLVER_UNLOCK();
354 return(error);
355 }
356
357 /*
358 * Return a result from userspace.
359 */
360 static int
361 kauth_resolver_complete(user_addr_t message)
362 {
363 struct kauth_identity_extlookup extl;
364 struct kauth_resolver_work *workp;
365 int error, result;
366
367 if ((error = copyin(message, &extl, sizeof(extl))) != 0) {
368 KAUTH_DEBUG("RESOLVER - error getting completed work\n");
369 return(error);
370 }
371
372 KAUTH_RESOLVER_LOCK();
373
374 error = 0;
375 result = 0;
376 switch (extl.el_result) {
377 case KAUTH_EXTLOOKUP_INPROG:
378 {
379 static int once = 0;
380
381 /* XXX this should go away once memberd is updated */
382 if (!once) {
383 printf("kauth_resolver: memberd is not setting valid result codes (assuming always successful)\n");
384 once = 1;
385 }
386 }
387 /* FALLTHROUGH */
388 case KAUTH_EXTLOOKUP_SUCCESS:
389 break;
390
391 case KAUTH_EXTLOOKUP_FATAL:
392 /* fatal error means the resolver is dead */
393 KAUTH_DEBUG("RESOLVER - resolver %d died, waiting for a new one", kauth_resolver_identity);
394 kauth_resolver_identity = 0;
395 /* XXX should we terminate all outstanding requests? */
396 error = EIO;
397 break;
398 case KAUTH_EXTLOOKUP_BADRQ:
399 KAUTH_DEBUG("RESOLVER - resolver reported invalid request %d", extl.el_seqno);
400 result = EINVAL;
401 break;
402 case KAUTH_EXTLOOKUP_FAILURE:
403 KAUTH_DEBUG("RESOLVER - resolver reported transient failure for request %d", extl.el_seqno);
404 result = EIO;
405 break;
406 default:
407 KAUTH_DEBUG("RESOLVER - resolver returned unexpected status %d", extl.el_result);
408 result = EIO;
409 break;
410 }
411
412 /*
413 * In the case of a fatal error, we assume that the resolver will restart
414 * quickly and re-collect all of the outstanding requests. Thus, we don't
415 * complete the request which returned the fatal error status.
416 */
417 if (extl.el_result != KAUTH_EXTLOOKUP_FATAL) {
418 /* scan our list for this request */
419 TAILQ_FOREACH(workp, &kauth_resolver_submitted, kr_link) {
420 /* found it? */
421 if (workp->kr_seqno == extl.el_seqno) {
422 /* copy result */
423 workp->kr_work = extl;
424 /* move onto completed list and wake up requester(s) */
425 TAILQ_REMOVE(&kauth_resolver_submitted, workp, kr_link);
426 workp->kr_flags &= ~KAUTH_REQUEST_SUBMITTED;
427 workp->kr_flags |= KAUTH_REQUEST_DONE;
428 workp->kr_result = result;
429 TAILQ_INSERT_TAIL(&kauth_resolver_done, workp, kr_link);
430 wakeup(workp);
431 break;
432 }
433 }
434 }
435 /*
436 * Note that it's OK for us not to find anything; if the request has
437 * timed out the work record will be gone.
438 */
439 KAUTH_RESOLVER_UNLOCK();
440
441 return(error);
442 }
443
444
445 /*
446 * Identity cache.
447 */
448
449 struct kauth_identity {
450 TAILQ_ENTRY(kauth_identity) ki_link;
451 int ki_valid;
452 #define KI_VALID_UID (1<<0) /* UID and GID are mutually exclusive */
453 #define KI_VALID_GID (1<<1)
454 #define KI_VALID_GUID (1<<2)
455 #define KI_VALID_NTSID (1<<3)
456 uid_t ki_uid;
457 gid_t ki_gid;
458 guid_t ki_guid;
459 ntsid_t ki_ntsid;
460 /*
461 * Expiry times are the earliest time at which we will disregard the cached state and go to
462 * userland. Before then if the valid bit is set, we will return the cached value. If it's
463 * not set, we will not go to userland to resolve, just assume that there is no answer
464 * available.
465 */
466 time_t ki_guid_expiry;
467 time_t ki_ntsid_expiry;
468 };
469
470 static TAILQ_HEAD(kauth_identity_head, kauth_identity) kauth_identities;
471 #define KAUTH_IDENTITY_CACHEMAX 100 /* XXX sizing? */
472 static int kauth_identity_count;
473
474 static lck_mtx_t *kauth_identity_mtx;
475 #define KAUTH_IDENTITY_LOCK() lck_mtx_lock(kauth_identity_mtx);
476 #define KAUTH_IDENTITY_UNLOCK() lck_mtx_unlock(kauth_identity_mtx);
477
478
479 static struct kauth_identity *kauth_identity_alloc(uid_t uid, gid_t gid, guid_t *guidp, time_t guid_expiry,
480 ntsid_t *ntsidp, time_t ntsid_expiry);
481 static void kauth_identity_register(struct kauth_identity *kip);
482 static void kauth_identity_updatecache(struct kauth_identity_extlookup *elp, struct kauth_identity *kip);
483 static void kauth_identity_lru(struct kauth_identity *kip);
484 static int kauth_identity_guid_expired(struct kauth_identity *kip);
485 static int kauth_identity_ntsid_expired(struct kauth_identity *kip);
486 static int kauth_identity_find_uid(uid_t uid, struct kauth_identity *kir);
487 static int kauth_identity_find_gid(gid_t gid, struct kauth_identity *kir);
488 static int kauth_identity_find_guid(guid_t *guidp, struct kauth_identity *kir);
489 static int kauth_identity_find_ntsid(ntsid_t *ntsid, struct kauth_identity *kir);
490
491 void
492 kauth_identity_init(void)
493 {
494 TAILQ_INIT(&kauth_identities);
495 kauth_identity_mtx = lck_mtx_alloc_init(kauth_lck_grp, 0/*LCK_ATTR_NULL*/);
496 }
497
498 static int
499 kauth_identity_resolve(__unused struct kauth_identity_extlookup *el)
500 {
501 return(kauth_resolver_submit(el));
502 }
503
504 static struct kauth_identity *
505 kauth_identity_alloc(uid_t uid, gid_t gid, guid_t *guidp, time_t guid_expiry, ntsid_t *ntsidp, time_t ntsid_expiry)
506 {
507 struct kauth_identity *kip;
508
509 /* get and fill in a new identity */
510 MALLOC(kip, struct kauth_identity *, sizeof(*kip), M_KAUTH, M_WAITOK | M_ZERO);
511 if (kip != NULL) {
512 if (gid != KAUTH_GID_NONE) {
513 kip->ki_gid = gid;
514 kip->ki_valid = KI_VALID_GID;
515 }
516 if (uid != KAUTH_UID_NONE) {
517 if (kip->ki_valid & KI_VALID_GID)
518 panic("can't allocate kauth identity with both uid and gid");
519 kip->ki_uid = uid;
520 kip->ki_valid = KI_VALID_UID;
521 }
522 if (guidp != NULL) {
523 kip->ki_guid = *guidp;
524 kip->ki_valid |= KI_VALID_GUID;
525 }
526 kip->ki_guid_expiry = guid_expiry;
527 if (ntsidp != NULL) {
528 kip->ki_ntsid = *ntsidp;
529 kip->ki_valid |= KI_VALID_NTSID;
530 }
531 kip->ki_ntsid_expiry = ntsid_expiry;
532 }
533 return(kip);
534 }
535
536 /*
537 * Register an association between identity tokens.
538 */
539 static void
540 kauth_identity_register(struct kauth_identity *kip)
541 {
542 struct kauth_identity *ip;
543
544 /*
545 * We search the cache for the UID listed in the incoming association. If we
546 * already have an entry, the new information is merged.
547 */
548 ip = NULL;
549 KAUTH_IDENTITY_LOCK();
550 if (kip->ki_valid & KI_VALID_UID) {
551 if (kip->ki_valid & KI_VALID_GID)
552 panic("kauth_identity: can't insert record with both UID and GID as key");
553 TAILQ_FOREACH(ip, &kauth_identities, ki_link)
554 if ((ip->ki_valid & KI_VALID_UID) && (ip->ki_uid == kip->ki_uid))
555 break;
556 } else if (kip->ki_valid & KI_VALID_GID) {
557 TAILQ_FOREACH(ip, &kauth_identities, ki_link)
558 if ((ip->ki_valid & KI_VALID_GID) && (ip->ki_gid == kip->ki_gid))
559 break;
560 } else {
561 panic("kauth_identity: can't insert record without UID or GID as key");
562 }
563
564 if (ip != NULL) {
565 /* we already have an entry, merge/overwrite */
566 if (kip->ki_valid & KI_VALID_GUID) {
567 ip->ki_guid = kip->ki_guid;
568 ip->ki_valid |= KI_VALID_GUID;
569 }
570 ip->ki_guid_expiry = kip->ki_guid_expiry;
571 if (kip->ki_valid & KI_VALID_NTSID) {
572 ip->ki_ntsid = kip->ki_ntsid;
573 ip->ki_valid |= KI_VALID_NTSID;
574 }
575 ip->ki_ntsid_expiry = kip->ki_ntsid_expiry;
576 /* and discard the incoming identity */
577 FREE(kip, M_KAUTH);
578 ip = NULL;
579 } else {
580 /* don't have any information on this identity, so just add it */
581 TAILQ_INSERT_HEAD(&kauth_identities, kip, ki_link);
582 if (++kauth_identity_count > KAUTH_IDENTITY_CACHEMAX) {
583 ip = TAILQ_LAST(&kauth_identities, kauth_identity_head);
584 TAILQ_REMOVE(&kauth_identities, ip, ki_link);
585 kauth_identity_count--;
586 }
587 }
588 KAUTH_IDENTITY_UNLOCK();
589 /* have to drop lock before freeing expired entry */
590 if (ip != NULL)
591 FREE(ip, M_KAUTH);
592 }
593
594 /*
595 * Given a lookup result, add any associations that we don't
596 * currently have.
597 */
598 static void
599 kauth_identity_updatecache(struct kauth_identity_extlookup *elp, struct kauth_identity *rkip)
600 {
601 struct timeval tv;
602 struct kauth_identity *kip;
603
604 microuptime(&tv);
605
606 /* user identity? */
607 if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_UID) {
608 KAUTH_IDENTITY_LOCK();
609 TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
610 /* matching record */
611 if ((kip->ki_valid & KI_VALID_UID) && (kip->ki_uid == elp->el_uid)) {
612 if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_UGUID) {
613 kip->ki_guid = elp->el_uguid;
614 kip->ki_valid |= KI_VALID_GUID;
615 }
616 kip->ki_guid_expiry = tv.tv_sec + elp->el_uguid_valid;
617 if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_USID) {
618 kip->ki_ntsid = elp->el_usid;
619 kip->ki_valid |= KI_VALID_NTSID;
620 }
621 kip->ki_ntsid_expiry = tv.tv_sec + elp->el_usid_valid;
622 kauth_identity_lru(kip);
623 if (rkip != NULL)
624 *rkip = *kip;
625 KAUTH_DEBUG("CACHE - refreshed %d is " K_UUID_FMT, kip->ki_uid, K_UUID_ARG(kip->ki_guid));
626 break;
627 }
628 }
629 KAUTH_IDENTITY_UNLOCK();
630 /* not found in cache, add new record */
631 if (kip == NULL) {
632 kip = kauth_identity_alloc(elp->el_uid, KAUTH_GID_NONE,
633 (elp->el_flags & KAUTH_EXTLOOKUP_VALID_UGUID) ? &elp->el_uguid : NULL,
634 tv.tv_sec + elp->el_uguid_valid,
635 (elp->el_flags & KAUTH_EXTLOOKUP_VALID_USID) ? &elp->el_usid : NULL,
636 tv.tv_sec + elp->el_usid_valid);
637 if (kip != NULL) {
638 if (rkip != NULL)
639 *rkip = *kip;
640 KAUTH_DEBUG("CACHE - learned %d is " K_UUID_FMT, kip->ki_uid, K_UUID_ARG(kip->ki_guid));
641 kauth_identity_register(kip);
642 }
643 }
644 }
645
646 /* group identity? */
647 if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GID) {
648 KAUTH_IDENTITY_LOCK();
649 TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
650 /* matching record */
651 if ((kip->ki_valid & KI_VALID_GID) && (kip->ki_gid == elp->el_gid)) {
652 if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GGUID) {
653 kip->ki_guid = elp->el_gguid;
654 kip->ki_valid |= KI_VALID_GUID;
655 }
656 kip->ki_guid_expiry = tv.tv_sec + elp->el_gguid_valid;
657 if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GSID) {
658 kip->ki_ntsid = elp->el_gsid;
659 kip->ki_valid |= KI_VALID_NTSID;
660 }
661 kip->ki_ntsid_expiry = tv.tv_sec + elp->el_gsid_valid;
662 kauth_identity_lru(kip);
663 if (rkip != NULL)
664 *rkip = *kip;
665 KAUTH_DEBUG("CACHE - refreshed %d is " K_UUID_FMT, kip->ki_uid, K_UUID_ARG(kip->ki_guid));
666 break;
667 }
668 }
669 KAUTH_IDENTITY_UNLOCK();
670 /* not found in cache, add new record */
671 if (kip == NULL) {
672 kip = kauth_identity_alloc(KAUTH_UID_NONE, elp->el_gid,
673 (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GGUID) ? &elp->el_gguid : NULL,
674 tv.tv_sec + elp->el_gguid_valid,
675 (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GSID) ? &elp->el_gsid : NULL,
676 tv.tv_sec + elp->el_gsid_valid);
677 if (kip != NULL) {
678 if (rkip != NULL)
679 *rkip = *kip;
680 KAUTH_DEBUG("CACHE - learned %d is " K_UUID_FMT, kip->ki_uid, K_UUID_ARG(kip->ki_guid));
681 kauth_identity_register(kip);
682 }
683 }
684 }
685
686 }
687
688 /*
689 * Promote the entry to the head of the LRU, assumes the cache is locked.
690 *
691 * This is called even if the entry has expired; typically an expired entry
692 * that's been looked up is about to be revalidated, and having it closer to
693 * the head of the LRU means finding it quickly again when the revalidation
694 * comes through.
695 */
696 static void
697 kauth_identity_lru(struct kauth_identity *kip)
698 {
699 if (kip != TAILQ_FIRST(&kauth_identities)) {
700 TAILQ_REMOVE(&kauth_identities, kip, ki_link);
701 TAILQ_INSERT_HEAD(&kauth_identities, kip, ki_link);
702 }
703 }
704
705 /*
706 * Handly lazy expiration of translations.
707 */
708 static int
709 kauth_identity_guid_expired(struct kauth_identity *kip)
710 {
711 struct timeval tv;
712
713 microuptime(&tv);
714 KAUTH_DEBUG("CACHE - GUID expires @ %d now %d", kip->ki_guid_expiry, tv.tv_sec);
715 return((kip->ki_guid_expiry <= tv.tv_sec) ? 1 : 0);
716 }
717
718 static int
719 kauth_identity_ntsid_expired(struct kauth_identity *kip)
720 {
721 struct timeval tv;
722
723 microuptime(&tv);
724 KAUTH_DEBUG("CACHE - NTSID expires @ %d now %d", kip->ki_ntsid_expiry, tv.tv_sec);
725 return((kip->ki_ntsid_expiry <= tv.tv_sec) ? 1 : 0);
726 }
727
728 /*
729 * Search for an entry by UID. Returns a copy of the entry, ENOENT if no valid
730 * association exists for the UID.
731 */
732 static int
733 kauth_identity_find_uid(uid_t uid, struct kauth_identity *kir)
734 {
735 struct kauth_identity *kip;
736
737 KAUTH_IDENTITY_LOCK();
738 TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
739 if ((kip->ki_valid & KI_VALID_UID) && (uid == kip->ki_uid)) {
740 kauth_identity_lru(kip);
741 *kir = *kip;
742 break;
743 }
744 }
745 KAUTH_IDENTITY_UNLOCK();
746 return((kip == NULL) ? ENOENT : 0);
747 }
748
749
750 /*
751 * Search for an entry by GID. Returns a copy of the entry, ENOENT if no valid
752 * association exists for the GID.
753 */
754 static int
755 kauth_identity_find_gid(uid_t gid, struct kauth_identity *kir)
756 {
757 struct kauth_identity *kip;
758
759 KAUTH_IDENTITY_LOCK();
760 TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
761 if ((kip->ki_valid & KI_VALID_GID) && (gid == kip->ki_gid)) {
762 kauth_identity_lru(kip);
763 *kir = *kip;
764 break;
765 }
766 }
767 KAUTH_IDENTITY_UNLOCK();
768 return((kip == NULL) ? ENOENT : 0);
769 }
770
771
772 /*
773 * Search for an entry by GUID. Returns a copy of the entry, ENOENT if no valid
774 * association exists for the GUID. Note that the association may be expired,
775 * in which case the caller may elect to call out to userland to revalidate.
776 */
777 static int
778 kauth_identity_find_guid(guid_t *guidp, struct kauth_identity *kir)
779 {
780 struct kauth_identity *kip;
781
782 KAUTH_IDENTITY_LOCK();
783 TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
784 if ((kip->ki_valid & KI_VALID_GUID) && (kauth_guid_equal(guidp, &kip->ki_guid))) {
785 kauth_identity_lru(kip);
786 *kir = *kip;
787 break;
788 }
789 }
790 KAUTH_IDENTITY_UNLOCK();
791 return((kip == NULL) ? ENOENT : 0);
792 }
793
794 /*
795 * Search for an entry by NT Security ID. Returns a copy of the entry, ENOENT if no valid
796 * association exists for the SID. Note that the association may be expired,
797 * in which case the caller may elect to call out to userland to revalidate.
798 */
799 static int
800 kauth_identity_find_ntsid(ntsid_t *ntsid, struct kauth_identity *kir)
801 {
802 struct kauth_identity *kip;
803
804 KAUTH_IDENTITY_LOCK();
805 TAILQ_FOREACH(kip, &kauth_identities, ki_link) {
806 if ((kip->ki_valid & KI_VALID_NTSID) && (kauth_ntsid_equal(ntsid, &kip->ki_ntsid))) {
807 kauth_identity_lru(kip);
808 *kir = *kip;
809 break;
810 }
811 }
812 KAUTH_IDENTITY_UNLOCK();
813 return((kip == NULL) ? ENOENT : 0);
814 }
815
816 /*
817 * GUID handling.
818 */
819 guid_t kauth_null_guid;
820
821 int
822 kauth_guid_equal(guid_t *guid1, guid_t *guid2)
823 {
824 return(!bcmp(guid1, guid2, sizeof(*guid1)));
825 }
826
827 /*
828 * Look for well-known GUIDs.
829 */
830 int
831 kauth_wellknown_guid(guid_t *guid)
832 {
833 static char fingerprint[] = {0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef};
834 int code;
835 /*
836 * All WKGs begin with the same 12 bytes.
837 */
838 if (!bcmp((void *)guid, fingerprint, 12)) {
839 /*
840 * The final 4 bytes are our code.
841 */
842 code = *(u_int32_t *)&guid->g_guid[12];
843 switch(code) {
844 case 0x0000000c:
845 return(KAUTH_WKG_EVERYBODY);
846 case 0xfffffffe:
847 return(KAUTH_WKG_NOBODY);
848 case 0x0000000a:
849 return(KAUTH_WKG_OWNER);
850 case 0x00000010:
851 return(KAUTH_WKG_GROUP);
852 }
853 }
854 return(KAUTH_WKG_NOT);
855 }
856
857
858 /*
859 * NT Security Identifier handling.
860 */
861 int
862 kauth_ntsid_equal(ntsid_t *sid1, ntsid_t *sid2)
863 {
864 /* check sizes for equality, also sanity-check size while we're at it */
865 if ((KAUTH_NTSID_SIZE(sid1) == KAUTH_NTSID_SIZE(sid2)) &&
866 (KAUTH_NTSID_SIZE(sid1) <= sizeof(*sid1)) &&
867 !bcmp(sid1, sid2, KAUTH_NTSID_SIZE(sid1)))
868 return(1);
869 return(0);
870 }
871
872 /*
873 * Identity KPI
874 *
875 * We support four tokens representing identity:
876 * - Credential reference
877 * - UID
878 * - GUID
879 * - NT security identifier
880 *
881 * Of these, the UID is the ubiquitous identifier; cross-referencing should
882 * be done using it.
883 */
884
885 static int kauth_cred_cache_lookup(int from, int to, void *src, void *dst);
886
887 /*
888 * Fetch UID from credential.
889 */
890 uid_t
891 kauth_cred_getuid(kauth_cred_t cred)
892 {
893 NULLCRED_CHECK(cred);
894 return(cred->cr_uid);
895 }
896
897 /*
898 * Fetch GID from credential.
899 */
900 uid_t
901 kauth_cred_getgid(kauth_cred_t cred)
902 {
903 NULLCRED_CHECK(cred);
904 return(cred->cr_gid);
905 }
906
907 /*
908 * Fetch UID from GUID.
909 */
910 int
911 kauth_cred_guid2uid(guid_t *guidp, uid_t *uidp)
912 {
913 return(kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_UID, guidp, uidp));
914 }
915
916 /*
917 * Fetch GID from GUID.
918 */
919 int
920 kauth_cred_guid2gid(guid_t *guidp, gid_t *gidp)
921 {
922 return(kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_GID, guidp, gidp));
923 }
924
925 /*
926 * Fetch UID from NT SID.
927 */
928 int
929 kauth_cred_ntsid2uid(ntsid_t *sidp, uid_t *uidp)
930 {
931 return(kauth_cred_cache_lookup(KI_VALID_NTSID, KI_VALID_UID, sidp, uidp));
932 }
933
934 /*
935 * Fetch GID from NT SID.
936 */
937 int
938 kauth_cred_ntsid2gid(ntsid_t *sidp, gid_t *gidp)
939 {
940 return(kauth_cred_cache_lookup(KI_VALID_NTSID, KI_VALID_GID, sidp, gidp));
941 }
942
943 /*
944 * Fetch GUID from NT SID.
945 */
946 int
947 kauth_cred_ntsid2guid(ntsid_t *sidp, guid_t *guidp)
948 {
949 return(kauth_cred_cache_lookup(KI_VALID_NTSID, KI_VALID_GUID, sidp, guidp));
950 }
951
952 /*
953 * Fetch GUID from UID.
954 */
955 int
956 kauth_cred_uid2guid(uid_t uid, guid_t *guidp)
957 {
958 return(kauth_cred_cache_lookup(KI_VALID_UID, KI_VALID_GUID, &uid, guidp));
959 }
960
961 /*
962 * Fetch user GUID from credential.
963 */
964 int
965 kauth_cred_getguid(kauth_cred_t cred, guid_t *guidp)
966 {
967 NULLCRED_CHECK(cred);
968 return(kauth_cred_uid2guid(kauth_cred_getuid(cred), guidp));
969 }
970
971 /*
972 * Fetch GUID from GID.
973 */
974 int
975 kauth_cred_gid2guid(gid_t gid, guid_t *guidp)
976 {
977 return(kauth_cred_cache_lookup(KI_VALID_GID, KI_VALID_GUID, &gid, guidp));
978 }
979
980 /*
981 * Fetch NT SID from UID.
982 */
983 int
984 kauth_cred_uid2ntsid(uid_t uid, ntsid_t *sidp)
985 {
986 return(kauth_cred_cache_lookup(KI_VALID_UID, KI_VALID_NTSID, &uid, sidp));
987 }
988
989 /*
990 * Fetch NT SID from credential.
991 */
992 int
993 kauth_cred_getntsid(kauth_cred_t cred, ntsid_t *sidp)
994 {
995 NULLCRED_CHECK(cred);
996 return(kauth_cred_uid2ntsid(kauth_cred_getuid(cred), sidp));
997 }
998
999 /*
1000 * Fetch NT SID from GID.
1001 */
1002 int
1003 kauth_cred_gid2ntsid(gid_t gid, ntsid_t *sidp)
1004 {
1005 return(kauth_cred_cache_lookup(KI_VALID_GID, KI_VALID_NTSID, &gid, sidp));
1006 }
1007
1008 /*
1009 * Fetch NT SID from GUID.
1010 */
1011 int
1012 kauth_cred_guid2ntsid(guid_t *guidp, ntsid_t *sidp)
1013 {
1014 return(kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_NTSID, guidp, sidp));
1015 }
1016
1017
1018
1019 /*
1020 * Lookup a translation in the cache.
1021 */
1022 static int
1023 kauth_cred_cache_lookup(int from, int to, void *src, void *dst)
1024 {
1025 struct kauth_identity ki;
1026 struct kauth_identity_extlookup el;
1027 int error;
1028 int (* expired)(struct kauth_identity *kip);
1029
1030 KAUTH_DEBUG("CACHE - translate %d to %d", from, to);
1031
1032 /*
1033 * Look for an existing cache entry for this association.
1034 * If the entry has not expired, return the cached information.
1035 */
1036 ki.ki_valid = 0;
1037 switch(from) {
1038 case KI_VALID_UID:
1039 error = kauth_identity_find_uid(*(uid_t *)src, &ki);
1040 break;
1041 case KI_VALID_GID:
1042 error = kauth_identity_find_gid(*(gid_t *)src, &ki);
1043 break;
1044 case KI_VALID_GUID:
1045 error = kauth_identity_find_guid((guid_t *)src, &ki);
1046 break;
1047 case KI_VALID_NTSID:
1048 error = kauth_identity_find_ntsid((ntsid_t *)src, &ki);
1049 break;
1050 default:
1051 return(EINVAL);
1052 }
1053 /* lookup failure or error */
1054 if (error != 0) {
1055 /* any other error is fatal */
1056 if (error != ENOENT) {
1057 KAUTH_DEBUG("CACHE - cache search error %d", error);
1058 return(error);
1059 }
1060 } else {
1061 /* do we have a translation? */
1062 if (ki.ki_valid & to) {
1063 /* found a valid cached entry, check expiry */
1064 switch(to) {
1065 case KI_VALID_GUID:
1066 expired = kauth_identity_guid_expired;
1067 break;
1068 case KI_VALID_NTSID:
1069 expired = kauth_identity_ntsid_expired;
1070 break;
1071 default:
1072 switch(from) {
1073 case KI_VALID_GUID:
1074 expired = kauth_identity_guid_expired;
1075 break;
1076 case KI_VALID_NTSID:
1077 expired = kauth_identity_ntsid_expired;
1078 break;
1079 default:
1080 expired = NULL;
1081 }
1082 }
1083 KAUTH_DEBUG("CACHE - found matching entry with valid %d", ki.ki_valid);
1084 /*
1085 * If no expiry function, or not expired, we have found
1086 * a hit.
1087 */
1088 if (!expired) {
1089 KAUTH_DEBUG("CACHE - no expiry function");
1090 goto found;
1091 }
1092 if (!expired(&ki)) {
1093 KAUTH_DEBUG("CACHE - entry valid, unexpired");
1094 goto found;
1095 }
1096 /*
1097 * We leave ki_valid set here; it contains a translation but the TTL has
1098 * expired. If we can't get a result from the resolver, we will
1099 * use it as a better-than nothing alternative.
1100 */
1101 KAUTH_DEBUG("CACHE - expired entry found");
1102 }
1103 }
1104
1105 /*
1106 * Call the resolver. We ask for as much data as we can get.
1107 */
1108 switch(from) {
1109 case KI_VALID_UID:
1110 el.el_flags = KAUTH_EXTLOOKUP_VALID_UID;
1111 el.el_uid = *(uid_t *)src;
1112 break;
1113 case KI_VALID_GID:
1114 el.el_flags = KAUTH_EXTLOOKUP_VALID_GID;
1115 el.el_gid = *(gid_t *)src;
1116 break;
1117 case KI_VALID_GUID:
1118 el.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID;
1119 el.el_uguid = *(guid_t *)src;
1120 el.el_gguid = *(guid_t *)src;
1121 break;
1122 case KI_VALID_NTSID:
1123 el.el_flags = KAUTH_EXTLOOKUP_VALID_USID | KAUTH_EXTLOOKUP_VALID_GSID;
1124 el.el_usid = *(ntsid_t *)src;
1125 el.el_gsid = *(ntsid_t *)src;
1126 break;
1127 default:
1128 return(EINVAL);
1129 }
1130 /*
1131 * Here we ask for everything all at once, to avoid having to work
1132 * out what we really want now, or might want soon.
1133 *
1134 * Asking for SID translations when we don't know we need them right
1135 * now is going to cause excess work to be done if we're connected
1136 * to a network that thinks it can translate them. This list needs
1137 * to get smaller/smarter.
1138 */
1139 el.el_flags |= KAUTH_EXTLOOKUP_WANT_UID | KAUTH_EXTLOOKUP_WANT_GID |
1140 KAUTH_EXTLOOKUP_WANT_UGUID | KAUTH_EXTLOOKUP_WANT_GGUID |
1141 KAUTH_EXTLOOKUP_WANT_USID | KAUTH_EXTLOOKUP_WANT_GSID;
1142 KAUTH_DEBUG("CACHE - calling resolver for %x", el.el_flags);
1143 error = kauth_identity_resolve(&el);
1144 KAUTH_DEBUG("CACHE - resolver returned %d", error);
1145 /* was the lookup successful? */
1146 if (error == 0) {
1147 /*
1148 * Save the results from the lookup - may have other information even if we didn't
1149 * get a guid.
1150 */
1151 kauth_identity_updatecache(&el, &ki);
1152 }
1153 /*
1154 * Check to see if we have a valid result.
1155 */
1156 if (!error && !(ki.ki_valid & to))
1157 error = ENOENT;
1158 if (error)
1159 return(error);
1160 found:
1161 switch(to) {
1162 case KI_VALID_UID:
1163 *(uid_t *)dst = ki.ki_uid;
1164 break;
1165 case KI_VALID_GID:
1166 *(gid_t *)dst = ki.ki_gid;
1167 break;
1168 case KI_VALID_GUID:
1169 *(guid_t *)dst = ki.ki_guid;
1170 break;
1171 case KI_VALID_NTSID:
1172 *(ntsid_t *)dst = ki.ki_ntsid;
1173 break;
1174 default:
1175 return(EINVAL);
1176 }
1177 KAUTH_DEBUG("CACHE - returned successfully");
1178 return(0);
1179 }
1180
1181
1182 /*
1183 * Group membership cache.
1184 *
1185 * XXX the linked-list implementation here needs to be optimized.
1186 */
1187
1188 struct kauth_group_membership {
1189 TAILQ_ENTRY(kauth_group_membership) gm_link;
1190 uid_t gm_uid; /* the identity whose membership we're recording */
1191 gid_t gm_gid; /* group of which they are a member */
1192 time_t gm_expiry; /* TTL for the membership */
1193 int gm_flags;
1194 #define KAUTH_GROUP_ISMEMBER (1<<0)
1195 };
1196
1197 TAILQ_HEAD(kauth_groups_head, kauth_group_membership) kauth_groups;
1198 #define KAUTH_GROUPS_CACHEMAX 100 /* XXX sizing? */
1199 static int kauth_groups_count;
1200
1201 static lck_mtx_t *kauth_groups_mtx;
1202 #define KAUTH_GROUPS_LOCK() lck_mtx_lock(kauth_groups_mtx);
1203 #define KAUTH_GROUPS_UNLOCK() lck_mtx_unlock(kauth_groups_mtx);
1204
1205 static int kauth_groups_expired(struct kauth_group_membership *gm);
1206 static void kauth_groups_lru(struct kauth_group_membership *gm);
1207 static void kauth_groups_updatecache(struct kauth_identity_extlookup *el);
1208
1209 void
1210 kauth_groups_init(void)
1211 {
1212 TAILQ_INIT(&kauth_groups);
1213 kauth_groups_mtx = lck_mtx_alloc_init(kauth_lck_grp, 0/*LCK_ATTR_NULL*/);
1214 }
1215
1216 static int
1217 kauth_groups_expired(struct kauth_group_membership *gm)
1218 {
1219 struct timeval tv;
1220
1221 microuptime(&tv);
1222 return((gm->gm_expiry <= tv.tv_sec) ? 1 : 0);
1223 }
1224
1225 static void
1226 kauth_groups_lru(struct kauth_group_membership *gm)
1227 {
1228 if (gm != TAILQ_FIRST(&kauth_groups)) {
1229 TAILQ_REMOVE(&kauth_groups, gm, gm_link);
1230 TAILQ_INSERT_HEAD(&kauth_groups, gm, gm_link);
1231 }
1232 }
1233
1234 static void
1235 kauth_groups_updatecache(struct kauth_identity_extlookup *el)
1236 {
1237 struct kauth_group_membership *gm;
1238 struct timeval tv;
1239
1240 /* need a valid response if we are to cache anything */
1241 if ((el->el_flags &
1242 (KAUTH_EXTLOOKUP_VALID_UID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_VALID_MEMBERSHIP)) !=
1243 (KAUTH_EXTLOOKUP_VALID_UID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_VALID_MEMBERSHIP))
1244 return;
1245
1246 microuptime(&tv);
1247
1248 /* search for an existing record for this association before inserting */
1249 KAUTH_GROUPS_LOCK();
1250 TAILQ_FOREACH(gm, &kauth_groups, gm_link) {
1251 if ((el->el_uid == gm->gm_uid) &&
1252 (el->el_gid == gm->gm_gid)) {
1253 if (el->el_flags & KAUTH_EXTLOOKUP_ISMEMBER) {
1254 gm->gm_flags |= KAUTH_GROUP_ISMEMBER;
1255 } else {
1256 gm->gm_flags &= ~KAUTH_GROUP_ISMEMBER;
1257 }
1258 gm->gm_expiry = el->el_member_valid + tv.tv_sec;
1259 kauth_groups_lru(gm);
1260 break;
1261 }
1262 }
1263 KAUTH_GROUPS_UNLOCK();
1264
1265 /* if we found an entry to update, stop here */
1266 if (gm != NULL)
1267 return;
1268
1269 /* allocate a new record */
1270 MALLOC(gm, struct kauth_group_membership *, sizeof(*gm), M_KAUTH, M_WAITOK);
1271 if (gm != NULL) {
1272 gm->gm_uid = el->el_uid;
1273 gm->gm_gid = el->el_gid;
1274 if (el->el_flags & KAUTH_EXTLOOKUP_ISMEMBER) {
1275 gm->gm_flags |= KAUTH_GROUP_ISMEMBER;
1276 } else {
1277 gm->gm_flags &= ~KAUTH_GROUP_ISMEMBER;
1278 }
1279 gm->gm_expiry = el->el_member_valid + tv.tv_sec;
1280 }
1281
1282 /*
1283 * Insert the new entry. Note that it's possible to race ourselves here
1284 * and end up with duplicate entries in the list. Wasteful, but harmless
1285 * since the first into the list will never be looked up, and thus will
1286 * eventually just fall off the end.
1287 */
1288 KAUTH_GROUPS_LOCK();
1289 TAILQ_INSERT_HEAD(&kauth_groups, gm, gm_link);
1290 if (kauth_groups_count++ > KAUTH_GROUPS_CACHEMAX) {
1291 gm = TAILQ_LAST(&kauth_groups, kauth_groups_head);
1292 TAILQ_REMOVE(&kauth_groups, gm, gm_link);
1293 kauth_groups_count--;
1294 } else {
1295 gm = NULL;
1296 }
1297 KAUTH_GROUPS_UNLOCK();
1298
1299 /* free expired cache entry */
1300 if (gm != NULL)
1301 FREE(gm, M_KAUTH);
1302 }
1303
1304 /*
1305 * Group membership KPI
1306 */
1307 /*
1308 * This function guarantees not to modify resultp when returning an error.
1309 */
1310 int
1311 kauth_cred_ismember_gid(kauth_cred_t cred, gid_t gid, int *resultp)
1312 {
1313 struct kauth_group_membership *gm;
1314 struct kauth_identity_extlookup el;
1315 int i, error;
1316
1317 /*
1318 * Check the per-credential list of override groups.
1319 *
1320 * We can conditionalise this on cred->cr_gmuid == KAUTH_UID_NONE since
1321 * the cache should be used for that case.
1322 */
1323 for (i = 0; i < cred->cr_ngroups; i++) {
1324 if (gid == cred->cr_groups[i]) {
1325 *resultp = 1;
1326 return(0);
1327 }
1328 }
1329
1330 /*
1331 * If we don't have a UID for group membership checks, the in-cred list
1332 * was authoritative and we can stop here.
1333 */
1334 if (cred->cr_gmuid == KAUTH_UID_NONE) {
1335 *resultp = 0;
1336 return(0);
1337 }
1338
1339
1340 /*
1341 * If the resolver hasn't checked in yet, we are early in the boot phase and
1342 * the local group list is complete and authoritative.
1343 */
1344 if (!kauth_resolver_registered) {
1345 *resultp = 0;
1346 return(0);
1347 }
1348
1349 /* TODO: */
1350 /* XXX check supplementary groups */
1351 /* XXX check whiteout groups */
1352 /* XXX nesting of supplementary/whiteout groups? */
1353
1354 /*
1355 * Check the group cache.
1356 */
1357 KAUTH_GROUPS_LOCK();
1358 TAILQ_FOREACH(gm, &kauth_groups, gm_link) {
1359 if ((gm->gm_uid == cred->cr_gmuid) && (gm->gm_gid == gid) && !kauth_groups_expired(gm)) {
1360 kauth_groups_lru(gm);
1361 break;
1362 }
1363 }
1364
1365 /* did we find a membership entry? */
1366 if (gm != NULL)
1367 *resultp = (gm->gm_flags & KAUTH_GROUP_ISMEMBER) ? 1 : 0;
1368 KAUTH_GROUPS_UNLOCK();
1369
1370 /* if we did, we can return now */
1371 if (gm != NULL)
1372 return(0);
1373
1374 /* nothing in the cache, need to go to userland */
1375 el.el_flags = KAUTH_EXTLOOKUP_VALID_UID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP;
1376 el.el_uid = cred->cr_gmuid;
1377 el.el_gid = gid;
1378 error = kauth_identity_resolve(&el);
1379 if (error != 0)
1380 return(error);
1381 /* save the results from the lookup */
1382 kauth_groups_updatecache(&el);
1383
1384 /* if we successfully ascertained membership, report */
1385 if (el.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) {
1386 *resultp = (el.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) ? 1 : 0;
1387 return(0);
1388 }
1389
1390 return(ENOENT);
1391 }
1392
1393 /*
1394 * Determine whether the supplied credential is a member of the
1395 * group nominated by GUID.
1396 */
1397 int
1398 kauth_cred_ismember_guid(kauth_cred_t cred, guid_t *guidp, int *resultp)
1399 {
1400 gid_t gid;
1401 int error, wkg;
1402
1403 error = 0;
1404 wkg = kauth_wellknown_guid(guidp);
1405 switch(wkg) {
1406 case KAUTH_WKG_NOBODY:
1407 *resultp = 0;
1408 break;
1409 case KAUTH_WKG_EVERYBODY:
1410 *resultp = 1;
1411 break;
1412 default:
1413 /* translate guid to gid */
1414 if ((error = kauth_cred_guid2gid(guidp, &gid)) != 0) {
1415 /*
1416 * If we have no guid -> gid translation, it's not a group and
1417 * thus the cred can't be a member.
1418 */
1419 if (error == ENOENT) {
1420 *resultp = 0;
1421 error = 0;
1422 }
1423 } else {
1424 error = kauth_cred_ismember_gid(cred, gid, resultp);
1425 }
1426 }
1427 return(error);
1428 }
1429
1430 /*
1431 * Fast replacement for issuser()
1432 */
1433 int
1434 kauth_cred_issuser(kauth_cred_t cred)
1435 {
1436 return(cred->cr_uid == 0);
1437 }
1438
1439 /*
1440 * Credential KPI
1441 */
1442
1443 /* lock protecting credential hash table */
1444 static lck_mtx_t *kauth_cred_hash_mtx;
1445 #define KAUTH_CRED_HASH_LOCK() lck_mtx_lock(kauth_cred_hash_mtx);
1446 #define KAUTH_CRED_HASH_UNLOCK() lck_mtx_unlock(kauth_cred_hash_mtx);
1447
1448 void
1449 kauth_cred_init(void)
1450 {
1451 int i;
1452
1453 kauth_cred_hash_mtx = lck_mtx_alloc_init(kauth_lck_grp, 0/*LCK_ATTR_NULL*/);
1454 kauth_cred_table_size = kauth_cred_primes[kauth_cred_primes_index];
1455
1456 /*allocate credential hash table */
1457 MALLOC(kauth_cred_table_anchor, struct kauth_cred_entry_head *,
1458 (sizeof(struct kauth_cred_entry_head) * kauth_cred_table_size),
1459 M_KAUTH, M_WAITOK | M_ZERO);
1460 for (i = 0; i < kauth_cred_table_size; i++) {
1461 TAILQ_INIT(&kauth_cred_table_anchor[i]);
1462 }
1463 }
1464
1465 /*
1466 * Return the current thread's effective UID.
1467 */
1468 uid_t
1469 kauth_getuid(void)
1470 {
1471 return(kauth_cred_get()->cr_uid);
1472 }
1473
1474 /*
1475 * Return the current thread's real UID.
1476 */
1477 uid_t
1478 kauth_getruid(void)
1479 {
1480 return(kauth_cred_get()->cr_ruid);
1481 }
1482
1483 /*
1484 * Return the current thread's effective GID.
1485 */
1486 gid_t
1487 kauth_getgid(void)
1488 {
1489 return(kauth_cred_get()->cr_groups[0]);
1490 }
1491
1492 /*
1493 * Return the current thread's real GID.
1494 */
1495 gid_t
1496 kauth_getrgid(void)
1497 {
1498 return(kauth_cred_get()->cr_rgid);
1499 }
1500
1501 /*
1502 * Returns a pointer to the current thread's credential, does not take a
1503 * reference (so the caller must not do anything that would let the thread's
1504 * credential change while using the returned value).
1505 */
1506 kauth_cred_t
1507 kauth_cred_get(void)
1508 {
1509 struct proc *p;
1510 struct uthread *uthread;
1511
1512 uthread = get_bsdthread_info(current_thread());
1513 /* sanity */
1514 if (uthread == NULL)
1515 panic("thread wants credential but has no BSD thread info");
1516 /*
1517 * We can lazy-bind credentials to threads, as long as their processes have them.
1518 * If we later inline this function, the code in this block should probably be
1519 * called out in a function.
1520 */
1521 if (uthread->uu_ucred == NOCRED) {
1522 if ((p = (proc_t) get_bsdtask_info(get_threadtask(current_thread()))) == NULL)
1523 panic("thread wants credential but has no BSD process");
1524 proc_lock(p);
1525 kauth_cred_ref(uthread->uu_ucred = p->p_ucred);
1526 proc_unlock(p);
1527 }
1528 return(uthread->uu_ucred);
1529 }
1530
1531 /*
1532 * Returns a pointer to the current thread's credential, takes a reference.
1533 */
1534 kauth_cred_t
1535 kauth_cred_get_with_ref(void)
1536 {
1537 struct proc *procp;
1538 struct uthread *uthread;
1539
1540 uthread = get_bsdthread_info(current_thread());
1541 /* sanity checks */
1542 if (uthread == NULL)
1543 panic("%s - thread wants credential but has no BSD thread info", __FUNCTION__);
1544 if ((procp = (proc_t) get_bsdtask_info(get_threadtask(current_thread()))) == NULL)
1545 panic("%s - thread wants credential but has no BSD process", __FUNCTION__);
1546
1547 /*
1548 * We can lazy-bind credentials to threads, as long as their processes have them.
1549 * If we later inline this function, the code in this block should probably be
1550 * called out in a function.
1551 */
1552 proc_lock(procp);
1553 if (uthread->uu_ucred == NOCRED) {
1554 /* take reference for new cred in thread */
1555 kauth_cred_ref(uthread->uu_ucred = proc_ucred(procp));
1556 }
1557 /* take a reference for our caller */
1558 kauth_cred_ref(uthread->uu_ucred);
1559 proc_unlock(procp);
1560 return(uthread->uu_ucred);
1561 }
1562
1563 /*
1564 * Returns a pointer to the given process's credential, takes a reference.
1565 */
1566 kauth_cred_t
1567 kauth_cred_proc_ref(proc_t procp)
1568 {
1569 kauth_cred_t cred;
1570
1571 proc_lock(procp);
1572 cred = proc_ucred(procp);
1573 kauth_cred_ref(cred);
1574 proc_unlock(procp);
1575 return(cred);
1576 }
1577
1578 /*
1579 * Allocates a new credential.
1580 */
1581 kauth_cred_t
1582 kauth_cred_alloc(void)
1583 {
1584 kauth_cred_t newcred;
1585
1586 MALLOC(newcred, kauth_cred_t, sizeof(*newcred), M_KAUTH, M_WAITOK | M_ZERO);
1587 if (newcred != 0) {
1588 newcred->cr_ref = 1;
1589 /* must do this, or cred has same group membership as uid 0 */
1590 newcred->cr_gmuid = KAUTH_UID_NONE;
1591 #if CRED_DIAGNOSTIC
1592 } else {
1593 panic("kauth_cred_alloc: couldn't allocate credential");
1594 #endif
1595 }
1596
1597 #if KAUTH_CRED_HASH_DEBUG
1598 kauth_cred_count++;
1599 #endif
1600
1601 return(newcred);
1602 }
1603
1604 /*
1605 * Looks to see if we already have a known credential and if found bumps the
1606 * reference count and returns it. If there are no credentials that match
1607 * the given credential then we allocate a new credential.
1608 *
1609 * Note that the gmuid is hard-defaulted to the UID specified. Since we maintain
1610 * this field, we can't expect callers to know how it needs to be set. Callers
1611 * should be prepared for this field to be overwritten.
1612 */
1613 kauth_cred_t
1614 kauth_cred_create(kauth_cred_t cred)
1615 {
1616 kauth_cred_t found_cred, new_cred = NULL;
1617
1618 cred->cr_gmuid = cred->cr_uid;
1619
1620 for (;;) {
1621 KAUTH_CRED_HASH_LOCK();
1622 found_cred = kauth_cred_find(cred);
1623 if (found_cred != NULL) {
1624 /* found an existing credential so we'll bump reference count and return */
1625 kauth_cred_ref(found_cred);
1626 KAUTH_CRED_HASH_UNLOCK();
1627 return(found_cred);
1628 }
1629 KAUTH_CRED_HASH_UNLOCK();
1630
1631 /* no existing credential found. create one and add it to our hash table */
1632 new_cred = kauth_cred_alloc();
1633 if (new_cred != NULL) {
1634 int err;
1635 new_cred->cr_uid = cred->cr_uid;
1636 new_cred->cr_ruid = cred->cr_ruid;
1637 new_cred->cr_svuid = cred->cr_svuid;
1638 new_cred->cr_rgid = cred->cr_rgid;
1639 new_cred->cr_svgid = cred->cr_svgid;
1640 new_cred->cr_gmuid = cred->cr_gmuid;
1641 new_cred->cr_ngroups = cred->cr_ngroups;
1642 bcopy(&cred->cr_groups[0], &new_cred->cr_groups[0], sizeof(new_cred->cr_groups));
1643 KAUTH_CRED_HASH_LOCK();
1644 err = kauth_cred_add(new_cred);
1645 KAUTH_CRED_HASH_UNLOCK();
1646
1647 /* retry if kauth_cred_add returns non zero value */
1648 if (err == 0)
1649 break;
1650 FREE(new_cred, M_KAUTH);
1651 new_cred = NULL;
1652 }
1653 }
1654
1655 return(new_cred);
1656 }
1657
1658 /*
1659 * Update the given credential using the uid argument. The given uid is used
1660 * set the effective user ID, real user ID, and saved user ID. We only
1661 * allocate a new credential when the given uid actually results in changes to
1662 * the existing credential.
1663 */
1664 kauth_cred_t
1665 kauth_cred_setuid(kauth_cred_t cred, uid_t uid)
1666 {
1667 struct ucred temp_cred;
1668
1669 NULLCRED_CHECK(cred);
1670
1671 /* don't need to do anything if the effective, real and saved user IDs are
1672 * already the same as the user ID passed in
1673 */
1674 if (cred->cr_uid == uid && cred->cr_ruid == uid && cred->cr_svuid == uid) {
1675 /* no change needed */
1676 return(cred);
1677 }
1678
1679 /* look up in cred hash table to see if we have a matching credential
1680 * with new values.
1681 */
1682 bcopy(cred, &temp_cred, sizeof(temp_cred));
1683 temp_cred.cr_uid = uid;
1684 temp_cred.cr_ruid = uid;
1685 temp_cred.cr_svuid = uid;
1686 temp_cred.cr_gmuid = uid;
1687
1688 return(kauth_cred_update(cred, &temp_cred, TRUE));
1689 }
1690
1691 /*
1692 * Update the given credential using the euid argument. The given uid is used
1693 * set the effective user ID. We only allocate a new credential when the given
1694 * uid actually results in changes to the existing credential.
1695 */
1696 kauth_cred_t
1697 kauth_cred_seteuid(kauth_cred_t cred, uid_t euid)
1698 {
1699 struct ucred temp_cred;
1700
1701 NULLCRED_CHECK(cred);
1702
1703 /* don't need to do anything if the given effective user ID is already the
1704 * same as the effective user ID in the credential.
1705 */
1706 if (cred->cr_uid == euid) {
1707 /* no change needed */
1708 return(cred);
1709 }
1710
1711 /* look up in cred hash table to see if we have a matching credential
1712 * with new values.
1713 */
1714 bcopy(cred, &temp_cred, sizeof(temp_cred));
1715 temp_cred.cr_uid = euid;
1716
1717 return(kauth_cred_update(cred, &temp_cred, TRUE));
1718 }
1719
1720 /*
1721 * Update the given credential using the gid argument. The given gid is used
1722 * set the effective group ID, real group ID, and saved group ID. We only
1723 * allocate a new credential when the given gid actually results in changes to
1724 * the existing credential.
1725 */
1726 kauth_cred_t
1727 kauth_cred_setgid(kauth_cred_t cred, gid_t gid)
1728 {
1729 struct ucred temp_cred;
1730
1731 NULLCRED_CHECK(cred);
1732
1733 /* don't need to do anything if the given group ID is already the
1734 * same as the group ID in the credential.
1735 */
1736 if (cred->cr_groups[0] == gid && cred->cr_rgid == gid && cred->cr_svgid == gid) {
1737 /* no change needed */
1738 return(cred);
1739 }
1740
1741 /* look up in cred hash table to see if we have a matching credential
1742 * with new values.
1743 */
1744 bcopy(cred, &temp_cred, sizeof(temp_cred));
1745 temp_cred.cr_groups[0] = gid;
1746 temp_cred.cr_rgid = gid;
1747 temp_cred.cr_svgid = gid;
1748
1749 return(kauth_cred_update(cred, &temp_cred, TRUE));
1750 }
1751
1752 /*
1753 * Update the given credential using the egid argument. The given gid is used
1754 * set the effective user ID. We only allocate a new credential when the given
1755 * gid actually results in changes to the existing credential.
1756 */
1757 kauth_cred_t
1758 kauth_cred_setegid(kauth_cred_t cred, gid_t egid)
1759 {
1760 struct ucred temp_cred;
1761
1762 NULLCRED_CHECK(cred);
1763
1764 /* don't need to do anything if the given group ID is already the
1765 * same as the group Id in the credential.
1766 */
1767 if (cred->cr_groups[0] == egid) {
1768 /* no change needed */
1769 return(cred);
1770 }
1771
1772 /* look up in cred hash table to see if we have a matching credential
1773 * with new values.
1774 */
1775 bcopy(cred, &temp_cred, sizeof(temp_cred));
1776 temp_cred.cr_groups[0] = egid;
1777
1778 return(kauth_cred_update(cred, &temp_cred, TRUE));
1779 }
1780
1781 /*
1782 * Update the given credential with the given groups. We only allocate a new
1783 * credential when the given gid actually results in changes to the existing
1784 * credential.
1785 * The gmuid argument supplies a new uid (or KAUTH_UID_NONE to opt out)
1786 * which will be used for group membership checking.
1787 */
1788 kauth_cred_t
1789 kauth_cred_setgroups(kauth_cred_t cred, gid_t *groups, int groupcount, uid_t gmuid)
1790 {
1791 int i;
1792 struct ucred temp_cred;
1793
1794 NULLCRED_CHECK(cred);
1795
1796 /* don't need to do anything if the given list of groups does not change.
1797 */
1798 if ((cred->cr_gmuid == gmuid) && (cred->cr_ngroups == groupcount)) {
1799 for (i = 0; i < groupcount; i++) {
1800 if (cred->cr_groups[i] != groups[i])
1801 break;
1802 }
1803 if (i == groupcount) {
1804 /* no change needed */
1805 return(cred);
1806 }
1807 }
1808
1809 /* look up in cred hash table to see if we have a matching credential
1810 * with new values.
1811 */
1812 bcopy(cred, &temp_cred, sizeof(temp_cred));
1813 temp_cred.cr_ngroups = groupcount;
1814 bcopy(groups, temp_cred.cr_groups, sizeof(temp_cred.cr_groups));
1815 temp_cred.cr_gmuid = gmuid;
1816
1817 return(kauth_cred_update(cred, &temp_cred, TRUE));
1818 }
1819
1820 /*
1821 * Update the given credential using the uid and gid arguments. The given uid
1822 * is used set the effective user ID, real user ID, and saved user ID.
1823 * The given gid is used set the effective group ID, real group ID, and saved
1824 * group ID.
1825 * We only allocate a new credential when the given uid and gid actually results
1826 * in changes to the existing credential.
1827 */
1828 kauth_cred_t
1829 kauth_cred_setuidgid(kauth_cred_t cred, uid_t uid, gid_t gid)
1830 {
1831 struct ucred temp_cred;
1832
1833 NULLCRED_CHECK(cred);
1834
1835 /* don't need to do anything if the effective, real and saved user IDs are
1836 * already the same as the user ID passed in
1837 */
1838 if (cred->cr_uid == uid && cred->cr_ruid == uid && cred->cr_svuid == uid &&
1839 cred->cr_groups[0] == gid && cred->cr_rgid == gid && cred->cr_svgid == gid) {
1840 /* no change needed */
1841 return(cred);
1842 }
1843
1844 /* look up in cred hash table to see if we have a matching credential
1845 * with new values.
1846 */
1847 bzero(&temp_cred, sizeof(temp_cred));
1848 temp_cred.cr_uid = uid;
1849 temp_cred.cr_ruid = uid;
1850 temp_cred.cr_svuid = uid;
1851 temp_cred.cr_gmuid = uid;
1852 temp_cred.cr_ngroups = 1;
1853 temp_cred.cr_groups[0] = gid;
1854 temp_cred.cr_rgid = gid;
1855 temp_cred.cr_svgid = gid;
1856
1857 return(kauth_cred_update(cred, &temp_cred, TRUE));
1858 }
1859
1860 /*
1861 * Update the given credential using the uid and gid arguments. The given uid
1862 * is used to set the saved user ID. The given gid is used to set the
1863 * saved group ID.
1864 * We only allocate a new credential when the given uid and gid actually results
1865 * in changes to the existing credential.
1866 */
1867 kauth_cred_t
1868 kauth_cred_setsvuidgid(kauth_cred_t cred, uid_t uid, gid_t gid)
1869 {
1870 struct ucred temp_cred;
1871
1872 NULLCRED_CHECK(cred);
1873
1874 /* don't need to do anything if the effective, real and saved user IDs are
1875 * already the same as the user ID passed in
1876 */
1877 if (cred->cr_svuid == uid && cred->cr_svgid == gid) {
1878 /* no change needed */
1879 return(cred);
1880 }
1881
1882 /* look up in cred hash table to see if we have a matching credential
1883 * with new values.
1884 */
1885 bcopy(cred, &temp_cred, sizeof(temp_cred));
1886 temp_cred.cr_svuid = uid;
1887 temp_cred.cr_svgid = gid;
1888
1889 return(kauth_cred_update(cred, &temp_cred, TRUE));
1890 }
1891
1892 /*
1893 * Update the given credential using the given auditinfo_t.
1894 * We only allocate a new credential when the given auditinfo_t actually results
1895 * in changes to the existing credential.
1896 */
1897 kauth_cred_t
1898 kauth_cred_setauditinfo(kauth_cred_t cred, auditinfo_t *auditinfo_p)
1899 {
1900 struct ucred temp_cred;
1901
1902 NULLCRED_CHECK(cred);
1903
1904 /* don't need to do anything if the audit info is already the same as the
1905 * audit info in the credential passed in
1906 */
1907 if (bcmp(&cred->cr_au, auditinfo_p, sizeof(cred->cr_au)) == 0) {
1908 /* no change needed */
1909 return(cred);
1910 }
1911
1912 /* look up in cred hash table to see if we have a matching credential
1913 * with new values.
1914 */
1915 bcopy(cred, &temp_cred, sizeof(temp_cred));
1916 bcopy(auditinfo_p, &temp_cred.cr_au, sizeof(temp_cred.cr_au));
1917
1918 return(kauth_cred_update(cred, &temp_cred, FALSE));
1919 }
1920
1921 /*
1922 * Add a reference to the passed credential.
1923 */
1924 void
1925 kauth_cred_ref(kauth_cred_t cred)
1926 {
1927 int old_value;
1928
1929 NULLCRED_CHECK(cred);
1930
1931 old_value = OSAddAtomic(1, &cred->cr_ref);
1932
1933 if (old_value < 1)
1934 panic("kauth_cred_ref: trying to take a reference on a cred with no references");
1935
1936 return;
1937 }
1938
1939 /*
1940 * Drop a reference from the passed credential, potentially destroying it.
1941 */
1942 void
1943 kauth_cred_rele(kauth_cred_t cred)
1944 {
1945 int old_value;
1946
1947 NULLCRED_CHECK(cred);
1948
1949 KAUTH_CRED_HASH_LOCK();
1950 old_value = OSAddAtomic(-1, &cred->cr_ref);
1951
1952 #if DIAGNOSTIC
1953 if (old_value == 0)
1954 panic("kauth_cred_rele: dropping a reference on a cred with no references");
1955 #endif
1956
1957 if (old_value < 3) {
1958 /* the last reference is our credential hash table */
1959 kauth_cred_remove(cred);
1960 }
1961 KAUTH_CRED_HASH_UNLOCK();
1962 }
1963
1964 /*
1965 * Duplicate a credential.
1966 * NOTE - caller should call kauth_cred_add after any credential changes are made.
1967 */
1968 kauth_cred_t
1969 kauth_cred_dup(kauth_cred_t cred)
1970 {
1971 kauth_cred_t newcred;
1972
1973 #if CRED_DIAGNOSTIC
1974 if (cred == NOCRED || cred == FSCRED)
1975 panic("kauth_cred_dup: bad credential");
1976 #endif
1977 newcred = kauth_cred_alloc();
1978 if (newcred != NULL) {
1979 bcopy(cred, newcred, sizeof(*newcred));
1980 newcred->cr_ref = 1;
1981 }
1982 return(newcred);
1983 }
1984
1985 /*
1986 * Returns a credential based on the passed credential but which
1987 * reflects the real rather than effective UID and GID.
1988 * NOTE - we do NOT decrement cred reference count on passed in credential
1989 */
1990 kauth_cred_t
1991 kauth_cred_copy_real(kauth_cred_t cred)
1992 {
1993 kauth_cred_t newcred = NULL, found_cred;
1994 struct ucred temp_cred;
1995
1996 /* if the credential is already 'real', just take a reference */
1997 if ((cred->cr_ruid == cred->cr_uid) &&
1998 (cred->cr_rgid == cred->cr_gid)) {
1999 kauth_cred_ref(cred);
2000 return(cred);
2001 }
2002
2003 /* look up in cred hash table to see if we have a matching credential
2004 * with new values.
2005 */
2006 bcopy(cred, &temp_cred, sizeof(temp_cred));
2007 temp_cred.cr_uid = cred->cr_ruid;
2008 temp_cred.cr_groups[0] = cred->cr_rgid;
2009 /* if the cred is not opted out, make sure we are using the r/euid for group checks */
2010 if (temp_cred.cr_gmuid != KAUTH_UID_NONE)
2011 temp_cred.cr_gmuid = cred->cr_ruid;
2012
2013 for (;;) {
2014 int err;
2015
2016 KAUTH_CRED_HASH_LOCK();
2017 found_cred = kauth_cred_find(&temp_cred);
2018 if (found_cred == cred) {
2019 /* same cred so just bail */
2020 KAUTH_CRED_HASH_UNLOCK();
2021 return(cred);
2022 }
2023 if (found_cred != NULL) {
2024 /* found a match so we bump reference count on new one and decrement
2025 * reference count on the old one.
2026 */
2027 kauth_cred_ref(found_cred);
2028 KAUTH_CRED_HASH_UNLOCK();
2029 return(found_cred);
2030 }
2031
2032 /* must allocate a new credential, copy in old credential data and update
2033 * with real user and group IDs.
2034 */
2035 newcred = kauth_cred_dup(&temp_cred);
2036 err = kauth_cred_add(newcred);
2037 KAUTH_CRED_HASH_UNLOCK();
2038
2039 /* retry if kauth_cred_add returns non zero value */
2040 if (err == 0)
2041 break;
2042 FREE(newcred, M_KAUTH);
2043 newcred = NULL;
2044 }
2045
2046 return(newcred);
2047 }
2048
2049 /*
2050 * common code to update a credential. model_cred is a temporary, non reference
2051 * counted credential used only for comparison and modeling purposes. old_cred
2052 * is a live reference counted credential that we intend to update using model_cred
2053 * as our model.
2054 */
2055 static kauth_cred_t kauth_cred_update(kauth_cred_t old_cred, kauth_cred_t model_cred, boolean_t retain_auditinfo)
2056 {
2057 kauth_cred_t found_cred, new_cred = NULL;
2058
2059 /* make sure we carry the auditinfo forward to the new credential unless
2060 * we are actually updating the auditinfo.
2061 */
2062 if (retain_auditinfo)
2063 bcopy(&old_cred->cr_au, &model_cred->cr_au, sizeof(model_cred->cr_au));
2064
2065 for (;;) {
2066 int err;
2067
2068 KAUTH_CRED_HASH_LOCK();
2069 found_cred = kauth_cred_find(model_cred);
2070 if (found_cred == old_cred) {
2071 /* same cred so just bail */
2072 KAUTH_CRED_HASH_UNLOCK();
2073 return(old_cred);
2074 }
2075 if (found_cred != NULL) {
2076 /* found a match so we bump reference count on new one and decrement
2077 * reference count on the old one.
2078 */
2079 kauth_cred_ref(found_cred);
2080 KAUTH_CRED_HASH_UNLOCK();
2081 kauth_cred_rele(old_cred);
2082 return(found_cred);
2083 }
2084
2085 /* must allocate a new credential using the model. also
2086 * adds the new credential to the credential hash table.
2087 */
2088 new_cred = kauth_cred_dup(model_cred);
2089 err = kauth_cred_add(new_cred);
2090 KAUTH_CRED_HASH_UNLOCK();
2091
2092 /* retry if kauth_cred_add returns non zero value */
2093 if (err == 0)
2094 break;
2095 FREE(new_cred, M_KAUTH);
2096 new_cred = NULL;
2097 }
2098
2099 kauth_cred_rele(old_cred);
2100 return(new_cred);
2101 }
2102
2103 /*
2104 * Add the given credential to our credential hash table and take an additional
2105 * reference to account for our use of the credential in the hash table.
2106 * NOTE - expects caller to hold KAUTH_CRED_HASH_LOCK!
2107 */
2108 static int kauth_cred_add(kauth_cred_t new_cred)
2109 {
2110 u_long hash_key;
2111
2112 hash_key = kauth_cred_get_hashkey(new_cred);
2113 hash_key %= kauth_cred_table_size;
2114
2115 /* race fix - there is a window where another matching credential
2116 * could have been inserted between the time this one was created and we
2117 * got the hash lock. If we find a match return an error and have the
2118 * the caller retry.
2119 */
2120 if (kauth_cred_find(new_cred) != NULL) {
2121 return(-1);
2122 }
2123
2124 /* take a reference for our use in credential hash table */
2125 kauth_cred_ref(new_cred);
2126
2127 /* insert the credential into the hash table */
2128 TAILQ_INSERT_HEAD(&kauth_cred_table_anchor[hash_key], new_cred, cr_link);
2129
2130 return(0);
2131 }
2132
2133 /*
2134 * Remove the given credential from our credential hash table.
2135 * NOTE - expects caller to hold KAUTH_CRED_HASH_LOCK!
2136 */
2137 static void kauth_cred_remove(kauth_cred_t cred)
2138 {
2139 u_long hash_key;
2140 kauth_cred_t found_cred;
2141
2142 hash_key = kauth_cred_get_hashkey(cred);
2143 hash_key %= kauth_cred_table_size;
2144
2145 /* avoid race */
2146 if (cred->cr_ref < 1)
2147 panic("cred reference underflow");
2148 if (cred->cr_ref > 1)
2149 return; /* someone else got a ref */
2150
2151 /* find cred in the credential hash table */
2152 TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[hash_key], cr_link) {
2153 if (found_cred == cred) {
2154 /* found a match, remove it from the hash table */
2155 TAILQ_REMOVE(&kauth_cred_table_anchor[hash_key], found_cred, cr_link);
2156 FREE(cred, M_KAUTH);
2157 #if KAUTH_CRED_HASH_DEBUG
2158 kauth_cred_count--;
2159 #endif
2160 return;
2161 }
2162 }
2163
2164 /* did not find a match. this should not happen! */
2165 printf("%s - %d - %s - did not find a match \n", __FILE__, __LINE__, __FUNCTION__);
2166 return;
2167 }
2168
2169 /*
2170 * Using the given credential data, look for a match in our credential hash
2171 * table.
2172 * NOTE - expects caller to hold KAUTH_CRED_HASH_LOCK!
2173 */
2174 kauth_cred_t kauth_cred_find(kauth_cred_t cred)
2175 {
2176 u_long hash_key;
2177 kauth_cred_t found_cred;
2178
2179 #if KAUTH_CRED_HASH_DEBUG
2180 static int test_count = 0;
2181
2182 test_count++;
2183 if ((test_count % 200) == 0) {
2184 kauth_cred_hash_print();
2185 }
2186 #endif
2187
2188 hash_key = kauth_cred_get_hashkey(cred);
2189 hash_key %= kauth_cred_table_size;
2190
2191 /* find cred in the credential hash table */
2192 TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[hash_key], cr_link) {
2193 if (bcmp(&found_cred->cr_uid, &cred->cr_uid, (sizeof(struct ucred) - offsetof(struct ucred, cr_uid))) == 0) {
2194 /* found a match */
2195 return(found_cred);
2196 }
2197 }
2198 /* no match found */
2199 return(NULL);
2200 }
2201
2202 /*
2203 * Generates a hash key using data that makes up a credential. Based on ElfHash.
2204 */
2205 static u_long kauth_cred_get_hashkey(kauth_cred_t cred)
2206 {
2207 u_long hash_key = 0;
2208
2209 hash_key = kauth_cred_hash((uint8_t *)&cred->cr_uid,
2210 (sizeof(struct ucred) - offsetof(struct ucred, cr_uid)),
2211 hash_key);
2212 return(hash_key);
2213 }
2214
2215 /*
2216 * Generates a hash key using data that makes up a credential. Based on ElfHash.
2217 */
2218 static inline u_long kauth_cred_hash(const uint8_t *datap, int data_len, u_long start_key)
2219 {
2220 u_long hash_key = start_key;
2221 u_long temp;
2222
2223 while (data_len > 0) {
2224 hash_key = (hash_key << 4) + *datap++;
2225 temp = hash_key & 0xF0000000;
2226 if (temp) {
2227 hash_key ^= temp >> 24;
2228 }
2229 hash_key &= ~temp;
2230 data_len--;
2231 }
2232 return(hash_key);
2233 }
2234
2235 #if KAUTH_CRED_HASH_DEBUG
2236 static void kauth_cred_hash_print(void)
2237 {
2238 int i, j;
2239 kauth_cred_t found_cred;
2240
2241 printf("\n\t kauth credential hash table statistics - current cred count %d \n", kauth_cred_count);
2242 /* count slot hits, misses, collisions, and max depth */
2243 for (i = 0; i < kauth_cred_table_size; i++) {
2244 printf("[%02d] ", i);
2245 j = 0;
2246 TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[i], cr_link) {
2247 if (j > 0) {
2248 printf("---- ");
2249 }
2250 j++;
2251 kauth_cred_print(found_cred);
2252 printf("\n");
2253 }
2254 if (j == 0) {
2255 printf("NOCRED \n");
2256 }
2257 }
2258 }
2259
2260
2261 static void kauth_cred_print(kauth_cred_t cred)
2262 {
2263 int i;
2264
2265 printf("0x%02X - refs %d uids %d %d %d ", cred, cred->cr_ref, cred->cr_uid, cred->cr_ruid, cred->cr_svuid);
2266 printf("group count %d gids ", cred->cr_ngroups);
2267 for (i = 0; i < NGROUPS; i++) {
2268 printf("%d ", cred->cr_groups[i]);
2269 }
2270 printf("%d %d %d ", cred->cr_rgid, cred->cr_svgid, cred->cr_gmuid);
2271 printf("auditinfo %d %d %d %d %d %d ",
2272 cred->cr_au.ai_auid, cred->cr_au.ai_mask.am_success, cred->cr_au.ai_mask.am_failure,
2273 cred->cr_au.ai_termid.port, cred->cr_au.ai_termid.machine, cred->cr_au.ai_asid);
2274
2275 }
2276 #endif