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 77void 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 94extern void kauth_cred_print(kauth_cred_t cred); 95 96#include <libkern/OSDebug.h> /* needed for get_backtrace( ) */ 97 98int is_target_cred( kauth_cred_t the_cred ); 99void get_backtrace( void ); 100 101static int sysctl_dump_creds( __unused struct sysctl_oid *oidp, __unused void *arg1, 102 __unused int arg2, struct sysctl_req *req ); 103static int 104sysctl_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 108struct cred_backtrace { 109 int depth; 110 void * stack[ MAX_STACK_DEPTH ]; 111}; 112typedef struct cred_backtrace cred_backtrace; 113 114#define MAX_CRED_BUFFER_SLOTS 200 115struct cred_debug_buffer { 116 int next_slot; 117 cred_backtrace stack_buffer[ MAX_CRED_BUFFER_SLOTS ]; 118}; 119typedef struct cred_debug_buffer cred_debug_buffer; 120cred_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 139static 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 143static volatile pid_t kauth_resolver_identity; 144static int kauth_resolver_registered; 145static uint32_t kauth_resolver_sequence; 146static int kauth_resolver_timeout = 30; /* default: 30 seconds */ 147 148struct 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 161TAILQ_HEAD(kauth_resolver_unsubmitted_head, kauth_resolver_work) kauth_resolver_unsubmitted; 162TAILQ_HEAD(kauth_resolver_submitted_head, kauth_resolver_work) kauth_resolver_submitted; 163TAILQ_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 167int kauth_resolver_timeout_cnt = 0; 168 169static int kauth_resolver_submit(struct kauth_identity_extlookup *lkp, uint64_t extend_data); 170static int kauth_resolver_complete(user_addr_t message); 171static int kauth_resolver_getwork(user_addr_t message); 172static 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 176struct 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 195static TAILQ_HEAD(kauth_identity_head, kauth_identity) kauth_identities; 196static 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? */ 200static int kauth_identity_cachemax = KAUTH_IDENTITY_CACHEMAX_DEFAULT; 201static int kauth_identity_count; 202 203static 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); 205static void kauth_identity_register_and_free(struct kauth_identity *kip); 206static void kauth_identity_updatecache(struct kauth_identity_extlookup *elp, struct kauth_identity *kip, uint64_t extend_data); 207static void kauth_identity_trimcache(int newsize); 208static void kauth_identity_lru(struct kauth_identity *kip); 209static int kauth_identity_guid_expired(struct kauth_identity *kip); 210static int kauth_identity_ntsid_expired(struct kauth_identity *kip); 211static int kauth_identity_find_uid(uid_t uid, struct kauth_identity *kir, char *getname); 212static int kauth_identity_find_gid(gid_t gid, struct kauth_identity *kir, char *getname); 213static int kauth_identity_find_guid(guid_t *guidp, struct kauth_identity *kir, char *getname); 214static int kauth_identity_find_ntsid(ntsid_t *ntsid, struct kauth_identity *kir, char *getname); 215static int kauth_identity_find_nam(char *name, int valid, struct kauth_identity *kir); 216 217struct 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 226TAILQ_HEAD(kauth_groups_head, kauth_group_membership) kauth_groups; 227static 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? */ 231static int kauth_groups_cachemax = KAUTH_GROUPS_CACHEMAX_DEFAULT; 232static int kauth_groups_count; 233 234static int kauth_groups_expired(struct kauth_group_membership *gm); 235static void kauth_groups_lru(struct kauth_group_membership *gm); 236static void kauth_groups_updatecache(struct kauth_identity_extlookup *el); 237static void kauth_groups_trimcache(int newsize); 238 239#endif /* CONFIG_EXT_RESOLVER */ 240 241static const int kauth_cred_primes[KAUTH_CRED_PRIMES_COUNT] = KAUTH_CRED_PRIMES; 242static int kauth_cred_primes_index = 0; 243static int kauth_cred_table_size = 0; 244 245TAILQ_HEAD(kauth_cred_entry_head, ucred); 246static struct kauth_cred_entry_head * kauth_cred_table_anchor = NULL; 247 248#define KAUTH_CRED_HASH_DEBUG 0 249 250static int kauth_cred_add(kauth_cred_t new_cred); 251static void kauth_cred_remove(kauth_cred_t cred); 252static inline u_long kauth_cred_hash(const uint8_t *datap, int data_len, u_long start_key); 253static u_long kauth_cred_get_hashkey(kauth_cred_t cred); 254static kauth_cred_t kauth_cred_update(kauth_cred_t old_cred, kauth_cred_t new_cred, boolean_t retain_auditinfo); 255static void kauth_cred_unref_hashlocked(kauth_cred_t *credp); 256 257#if KAUTH_CRED_HASH_DEBUG 258static int kauth_cred_count = 0; 259static void kauth_cred_hash_print(void); 260static 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 */ 291void 292kauth_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 */ 339static int 340kauth_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 */ 519int 520identitysvc(__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 */ 678static int 679kauth_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 */ 736static int 737kauth_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 802out: 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 */ 827static int 828kauth_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 */ 865static int 866kauth_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 */ 1047void 1048kauth_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 */ 1072static struct kauth_identity * 1073kauth_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 */ 1123static void 1124kauth_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 */ 1225static void 1226kauth_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 */ 1371static void 1372kauth_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 */ 1402static void 1403kauth_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 */ 1423static int 1424kauth_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 */ 1452static int 1453kauth_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 */ 1485static int 1486kauth_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 */ 1522static int 1523kauth_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 */ 1562static int 1563kauth_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 */ 1598static int 1599kauth_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 */ 1635static int 1636kauth_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 */ 1661guid_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 */ 1675int 1676kauth_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 */ 1695int 1696kauth_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 */ 1734int 1735kauth_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 */ 1784static int 1785kauth_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/* 1813This is correct for memberd behaviour, but incorrect for POSIX; to address 1814this, we would need to automatically opt-out any SUID/SGID binary, and force 1815it to use initgroups to opt back in. We take the approach of considering it 1816opt'ed out in any group of 16 displacement instead, since it's a much more 1817conservative 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 */ 1852uid_t 1853kauth_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 */ 1869uid_t 1870kauth_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 */ 1886uid_t 1887kauth_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 */ 1903gid_t 1904kauth_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 */ 1920gid_t 1921kauth_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 */ 1937gid_t 1938kauth_cred_getsvgid(kauth_cred_t cred) 1939{ 1940 NULLCRED_CHECK(cred); 1941 return(posix_cred_get(cred)->cr_svgid); 1942} 1943 1944 1945static 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 */ 1951static __inline int 1952kauth_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 */ 1976int 1977kauth_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 */ 1999int 2000kauth_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 */ 2023int 2024kauth_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 */ 2047int 2048kauth_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 */ 2068int 2069kauth_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 */ 2089int 2090kauth_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 */ 2110int 2111kauth_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 */ 2131int 2132kauth_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 */ 2152int 2153kauth_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 */ 2173int 2174kauth_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 */ 2194int 2195kauth_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 */ 2216int 2217kauth_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 */ 2237int 2238kauth_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 */ 2258int 2259kauth_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 */ 2280int 2281kauth_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 */ 2301int 2302kauth_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 2326static int 2327kauth_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 KAUTH_DEBUG("CACHE - resolver returned %d", error); 2533 2534 /* was the external lookup successful? */ 2535 if (error == 0) { 2536 /* 2537 * Save the results from the lookup - we may have other 2538 * information, even if we didn't get a guid or the 2539 * extended data. 2540 * 2541 * If we came from a name, we know the extend_data is valid. 2542 */ 2543 if (from == KI_VALID_PWNAM) 2544 el.el_flags |= KAUTH_EXTLOOKUP_VALID_PWNAM; 2545 else if (from == KI_VALID_GRNAM) 2546 el.el_flags |= KAUTH_EXTLOOKUP_VALID_GRNAM; 2547 2548 kauth_identity_updatecache(&el, &ki, extend_data); 2549 2550 /* 2551 * Check to see if we have a valid cache entry 2552 * originating from the result. 2553 */ 2554 if (!(ki.ki_valid & to)) { 2555 error = ENOENT; 2556 } 2557 } 2558 if (error) 2559 return(error); 2560found: 2561 /* 2562 * Copy from the appropriate struct kauth_identity cache entry 2563 * structure into the destination buffer area. 2564 */ 2565 switch(to) { 2566 case KI_VALID_UID: 2567 *(uid_t *)dst = ki.ki_uid; 2568 break; 2569 case KI_VALID_GID: 2570 *(gid_t *)dst = ki.ki_gid; 2571 break; 2572 case KI_VALID_GUID: 2573 *(guid_t *)dst = ki.ki_guid; 2574 break; 2575 case KI_VALID_NTSID: 2576 *(ntsid_t *)dst = ki.ki_ntsid; 2577 break; 2578 case KI_VALID_PWNAM: 2579 case KI_VALID_GRNAM: 2580 /* handled in kauth_resolver_complete() */ 2581 break; 2582 default: 2583 return(EINVAL); 2584 } 2585 KAUTH_DEBUG("CACHE - returned successfully"); 2586 return(0); 2587} 2588 2589 2590/* 2591 * Group membership cache. 2592 * 2593 * XXX the linked-list implementation here needs to be optimized. 2594 */ 2595 2596/* 2597 * kauth_groups_init 2598 * 2599 * Description: Initialize the groups cache 2600 * 2601 * Parameters: (void) 2602 * 2603 * Returns: (void) 2604 * 2605 * Notes: Initialize the groups cache for use; the group cache is used 2606 * to avoid unnecessary calls out to user space. 2607 * 2608 * This function is called from kauth_init() in the file 2609 * kern_authorization.c. 2610 */ 2611void 2612kauth_groups_init(void) 2613{ 2614 TAILQ_INIT(&kauth_groups); 2615 kauth_groups_mtx = lck_mtx_alloc_init(kauth_lck_grp, 0/*LCK_ATTR_NULL*/); 2616} 2617 2618 2619/* 2620 * kauth_groups_expired 2621 * 2622 * Description: Handle lazy expiration of group membership cache entries 2623 * 2624 * Parameters: gm group membership entry to 2625 * check for expiration 2626 * 2627 * Returns: 1 Expired 2628 * 0 Not expired 2629 */ 2630static int 2631kauth_groups_expired(struct kauth_group_membership *gm) 2632{ 2633 struct timeval tv; 2634 2635 /* 2636 * Expiration time of 0 means this entry is persistent. 2637 */ 2638 if (gm->gm_expiry == 0) 2639 return (0); 2640 2641 microuptime(&tv); 2642 2643 return((gm->gm_expiry <= tv.tv_sec) ? 1 : 0); 2644} 2645 2646 2647/* 2648 * kauth_groups_lru 2649 * 2650 * Description: Promote the entry to the head of the LRU, assumes the cache 2651 * is locked. 2652 * 2653 * Parameters: kip group membership entry to move 2654 * to the head of the LRU list, 2655 * if it's not already there 2656 * 2657 * Returns: (void) 2658 * 2659 * Notes: This is called even if the entry has expired; typically an 2660 * expired entry that's been looked up is about to be revalidated, 2661 * and having it closer to the head of the LRU means finding it 2662 * quickly again when the revalidation comes through. 2663 */ 2664static void 2665kauth_groups_lru(struct kauth_group_membership *gm) 2666{ 2667 if (gm != TAILQ_FIRST(&kauth_groups)) { 2668 TAILQ_REMOVE(&kauth_groups, gm, gm_link); 2669 TAILQ_INSERT_HEAD(&kauth_groups, gm, gm_link); 2670 } 2671} 2672 2673 2674/* 2675 * kauth_groups_updatecache 2676 * 2677 * Description: Given a lookup result, add any group cache associations that 2678 * we don't currently have. 2679 * 2680 * Parameters: elp External lookup result from 2681 * user space daemon to kernel 2682 * rkip pointer to returned kauth 2683 * identity, or NULL 2684 * 2685 * Returns: (void) 2686 */ 2687static void 2688kauth_groups_updatecache(struct kauth_identity_extlookup *el) 2689{ 2690 struct kauth_group_membership *gm; 2691 struct timeval tv; 2692 2693 /* need a valid response if we are to cache anything */ 2694 if ((el->el_flags & 2695 (KAUTH_EXTLOOKUP_VALID_UID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_VALID_MEMBERSHIP)) != 2696 (KAUTH_EXTLOOKUP_VALID_UID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_VALID_MEMBERSHIP)) 2697 return; 2698 2699 microuptime(&tv); 2700 2701 /* 2702 * Search for an existing record for this association before inserting 2703 * a new one; if we find one, update it instead of creating a new one 2704 */ 2705 KAUTH_GROUPS_LOCK(); 2706 TAILQ_FOREACH(gm, &kauth_groups, gm_link) { 2707 if ((el->el_uid == gm->gm_uid) && 2708 (el->el_gid == gm->gm_gid)) { 2709 if (el->el_flags & KAUTH_EXTLOOKUP_ISMEMBER) { 2710 gm->gm_flags |= KAUTH_GROUP_ISMEMBER; 2711 } else { 2712 gm->gm_flags &= ~KAUTH_GROUP_ISMEMBER; 2713 } 2714 gm->gm_expiry = (el->el_member_valid) ? el->el_member_valid + tv.tv_sec : 0; 2715 kauth_groups_lru(gm); 2716 break; 2717 } 2718 } 2719 KAUTH_GROUPS_UNLOCK(); 2720 2721 /* if we found an entry to update, stop here */ 2722 if (gm != NULL) 2723 return; 2724 2725 /* allocate a new record */ 2726 MALLOC(gm, struct kauth_group_membership *, sizeof(*gm), M_KAUTH, M_WAITOK); 2727 if (gm != NULL) { 2728 gm->gm_uid = el->el_uid; 2729 gm->gm_gid = el->el_gid; 2730 if (el->el_flags & KAUTH_EXTLOOKUP_ISMEMBER) { 2731 gm->gm_flags |= KAUTH_GROUP_ISMEMBER; 2732 } else { 2733 gm->gm_flags &= ~KAUTH_GROUP_ISMEMBER; 2734 } 2735 gm->gm_expiry = (el->el_member_valid) ? el->el_member_valid + tv.tv_sec : 0; 2736 } 2737 2738 /* 2739 * Insert the new entry. Note that it's possible to race ourselves 2740 * here and end up with duplicate entries in the list. Wasteful, but 2741 * harmless since the first into the list will never be looked up, 2742 * and thus will eventually just fall off the end. 2743 */ 2744 KAUTH_GROUPS_LOCK(); 2745 TAILQ_INSERT_HEAD(&kauth_groups, gm, gm_link); 2746 if (++kauth_groups_count > kauth_groups_cachemax) { 2747 gm = TAILQ_LAST(&kauth_groups, kauth_groups_head); 2748 TAILQ_REMOVE(&kauth_groups, gm, gm_link); 2749 kauth_groups_count--; 2750 } else { 2751 gm = NULL; 2752 } 2753 KAUTH_GROUPS_UNLOCK(); 2754 2755 /* free expired cache entry */ 2756 if (gm != NULL) 2757 FREE(gm, M_KAUTH); 2758} 2759 2760/* 2761 * Trim older entries from the group membership cache. 2762 * 2763 * Must be called with the group cache lock held. 2764 */ 2765static void 2766kauth_groups_trimcache(int new_size) { 2767 struct kauth_group_membership *gm; 2768 2769 lck_mtx_assert(kauth_groups_mtx, LCK_MTX_ASSERT_OWNED); 2770 2771 while (kauth_groups_count > new_size) { 2772 gm = TAILQ_LAST(&kauth_groups, kauth_groups_head); 2773 TAILQ_REMOVE(&kauth_groups, gm, gm_link); 2774 kauth_groups_count--; 2775 FREE(gm, M_KAUTH); 2776 } 2777} 2778#endif /* CONFIG_EXT_RESOLVER */ 2779 2780/* 2781 * Group membership KPI 2782 */ 2783 2784/* 2785 * kauth_cred_ismember_gid 2786 * 2787 * Description: Given a credential and a GID, determine if the GID is a member 2788 * of one of the supplementary groups associated with the given 2789 * credential 2790 * 2791 * Parameters: cred Credential to check in 2792 * gid GID to check for membership 2793 * resultp Pointer to int to contain the 2794 * result of the call 2795 * 2796 * Returns: 0 Success 2797 * ENOENT Could not perform lookup 2798 * kauth_resolver_submit:EWOULDBLOCK 2799 * kauth_resolver_submit:EINTR 2800 * kauth_resolver_submit:ENOMEM 2801 * kauth_resolver_submit:ENOENT User space daemon did not vend 2802 * this credential. 2803 * kauth_resolver_submit:??? Unlikely error from user space 2804 * 2805 * Implicit returns: 2806 * *resultp (modified) 1 Is member 2807 * 0 Is not member 2808 * 2809 * Notes: This function guarantees not to modify resultp when returning 2810 * an error. 2811 * 2812 * This function effectively checks the EGID as well, since the 2813 * EGID is cr_groups[0] as an implementation detail. 2814 */ 2815int 2816kauth_cred_ismember_gid(kauth_cred_t cred, gid_t gid, int *resultp) 2817{ 2818 posix_cred_t pcred = posix_cred_get(cred); 2819 int i; 2820 2821 /* 2822 * Check the per-credential list of override groups. 2823 * 2824 * We can conditionalise this on cred->cr_gmuid == KAUTH_UID_NONE since 2825 * the cache should be used for that case. 2826 */ 2827 for (i = 0; i < pcred->cr_ngroups; i++) { 2828 if (gid == pcred->cr_groups[i]) { 2829 *resultp = 1; 2830 return(0); 2831 } 2832 } 2833 2834 /* 2835 * If we don't have a UID for group membership checks, the in-cred list 2836 * was authoritative and we can stop here. 2837 */ 2838 if (pcred->cr_gmuid == KAUTH_UID_NONE) { 2839 *resultp = 0; 2840 return(0); 2841 } 2842 2843#if CONFIG_EXT_RESOLVER 2844 struct kauth_group_membership *gm; 2845 struct kauth_identity_extlookup el; 2846 int error; 2847 2848 /* 2849 * If the resolver hasn't checked in yet, we are early in the boot 2850 * phase and the local group list is complete and authoritative. 2851 */ 2852 if (!kauth_resolver_registered) { 2853 *resultp = 0; 2854 return(0); 2855 } 2856 2857 /* TODO: */ 2858 /* XXX check supplementary groups */ 2859 /* XXX check whiteout groups */ 2860 /* XXX nesting of supplementary/whiteout groups? */ 2861 2862 /* 2863 * Check the group cache. 2864 */ 2865 KAUTH_GROUPS_LOCK(); 2866 TAILQ_FOREACH(gm, &kauth_groups, gm_link) { 2867 if ((gm->gm_uid == pcred->cr_gmuid) && (gm->gm_gid == gid) && !kauth_groups_expired(gm)) { 2868 kauth_groups_lru(gm); 2869 break; 2870 } 2871 } 2872 2873 /* did we find a membership entry? */ 2874 if (gm != NULL) 2875 *resultp = (gm->gm_flags & KAUTH_GROUP_ISMEMBER) ? 1 : 0; 2876 KAUTH_GROUPS_UNLOCK(); 2877 2878 /* if we did, we can return now */ 2879 if (gm != NULL) { 2880 DTRACE_PROC2(kauth__group__cache__hit, int, pcred->cr_gmuid, int, gid); 2881 return(0); 2882 } 2883 2884 /* nothing in the cache, need to go to userland */ 2885 bzero(&el, sizeof(el)); 2886 el.el_info_pid = current_proc()->p_pid; 2887 el.el_flags = KAUTH_EXTLOOKUP_VALID_UID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP; 2888 el.el_uid = pcred->cr_gmuid; 2889 el.el_gid = gid; 2890 el.el_member_valid = 0; /* XXX set by resolver? */ 2891 2892 DTRACE_PROC2(kauth__group__resolver__submitted, int, el.el_uid, int, el.el_gid); 2893 2894 error = kauth_resolver_submit(&el, 0ULL); 2895 2896 DTRACE_PROC2(kauth__group__resolver__returned, int, error, int, el.el_flags); 2897 2898 if (error != 0) 2899 return(error); 2900 /* save the results from the lookup */ 2901 kauth_groups_updatecache(&el); 2902 2903 /* if we successfully ascertained membership, report */ 2904 if (el.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) { 2905 *resultp = (el.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) ? 1 : 0; 2906 return(0); 2907 } 2908 2909 return(ENOENT); 2910#else 2911 *resultp = 0; 2912 return(0); 2913#endif 2914} 2915 2916/* 2917 * kauth_cred_ismember_guid 2918 * 2919 * Description: Determine whether the supplied credential is a member of the 2920 * group nominated by GUID. 2921 * 2922 * Parameters: cred Credential to check in 2923 * guidp Pointer to GUID whose group 2924 * we are testing for membership 2925 * resultp Pointer to int to contain the 2926 * result of the call 2927 * 2928 * Returns: 0 Success 2929 * kauth_cred_guid2gid:EINVAL 2930 * kauth_cred_ismember_gid:ENOENT 2931 * kauth_resolver_submit:ENOENT User space daemon did not vend 2932 * this credential. 2933 * kauth_cred_ismember_gid:EWOULDBLOCK 2934 * kauth_cred_ismember_gid:EINTR 2935 * kauth_cred_ismember_gid:ENOMEM 2936 * kauth_cred_ismember_gid:??? Unlikely error from user space 2937 * 2938 * Implicit returns: 2939 * *resultp (modified) 1 Is member 2940 * 0 Is not member 2941 */ 2942int 2943kauth_cred_ismember_guid(__unused kauth_cred_t cred, guid_t *guidp, int *resultp) 2944{ 2945 int error = 0; 2946 2947 switch (kauth_wellknown_guid(guidp)) { 2948 case KAUTH_WKG_NOBODY: 2949 *resultp = 0; 2950 break; 2951 case KAUTH_WKG_EVERYBODY: 2952 *resultp = 1; 2953 break; 2954 default: 2955#if CONFIG_EXT_RESOLVER 2956 { 2957 struct kauth_identity ki; 2958 gid_t gid; 2959#if 6603280 2960 /* 2961 * Grovel the identity cache looking for this GUID. 2962 * If we find it, and it is for a user record, return 2963 * false because it's not a group. 2964 * 2965 * This is necessary because we don't have -ve caching 2966 * of group memberships, and we really want to avoid 2967 * calling out to the resolver if at all possible. 2968 * 2969 * Because we're called by the ACL evaluator, and the 2970 * ACL evaluator is likely to encounter ACEs for users, 2971 * this is expected to be a common case. 2972 */ 2973 ki.ki_valid = 0; 2974 if ((error = kauth_identity_find_guid(guidp, &ki, NULL)) == 0 && 2975 !kauth_identity_guid_expired(&ki)) { 2976 if (ki.ki_valid & KI_VALID_GID) { 2977 /* It's a group after all... */ 2978 gid = ki.ki_gid; 2979 goto do_check; 2980 } 2981 if (ki.ki_valid & KI_VALID_UID) { 2982 *resultp = 0; 2983 return (0); 2984 } 2985 } 2986#endif /* 6603280 */ 2987 /* 2988 * Attempt to translate the GUID to a GID. Even if 2989 * this fails, we will have primed the cache if it is 2990 * a user record and we'll see it above the next time 2991 * we're asked. 2992 */ 2993 if ((error = kauth_cred_guid2gid(guidp, &gid)) != 0) { 2994 /* 2995 * If we have no guid -> gid translation, it's not a group and 2996 * thus the cred can't be a member. 2997 */ 2998 if (error == ENOENT) { 2999 *resultp = 0; 3000 error = 0; 3001 } 3002 } else { 3003 do_check: 3004 error = kauth_cred_ismember_gid(cred, gid, resultp); 3005 } 3006 } 3007#else /* CONFIG_EXT_RESOLVER */ 3008 error = ENOENT; 3009#endif /* CONFIG_EXT_RESOLVER */ 3010 break; 3011 } 3012 return(error); 3013} 3014 3015/* 3016 * kauth_cred_gid_subset 3017 * 3018 * Description: Given two credentials, determine if all GIDs associated with 3019 * the first are also associated with the second 3020 * 3021 * Parameters: cred1 Credential to check for 3022 * cred2 Credential to check in 3023 * resultp Pointer to int to contain the 3024 * result of the call 3025 * 3026 * Returns: 0 Success 3027 * non-zero See kauth_cred_ismember_gid for 3028 * error codes 3029 * 3030 * Implicit returns: 3031 * *resultp (modified) 1 Is subset 3032 * 0 Is not subset 3033 * 3034 * Notes: This function guarantees not to modify resultp when returning 3035 * an error. 3036 */ 3037int 3038kauth_cred_gid_subset(kauth_cred_t cred1, kauth_cred_t cred2, int *resultp) 3039{ 3040 int i, err, res = 1; 3041 gid_t gid; 3042 posix_cred_t pcred1 = posix_cred_get(cred1); 3043 posix_cred_t pcred2 = posix_cred_get(cred2); 3044 3045 /* First, check the local list of groups */ 3046 for (i = 0; i < pcred1->cr_ngroups; i++) { 3047 gid = pcred1->cr_groups[i]; 3048 if ((err = kauth_cred_ismember_gid(cred2, gid, &res)) != 0) { 3049 return err; 3050 } 3051 3052 if (!res && gid != pcred2->cr_rgid && gid != pcred2->cr_svgid) { 3053 *resultp = 0; 3054 return 0; 3055 } 3056 } 3057 3058 /* Check real gid */ 3059 if ((err = kauth_cred_ismember_gid(cred2, pcred1->cr_rgid, &res)) != 0) { 3060 return err; 3061 } 3062 3063 if (!res && pcred1->cr_rgid != pcred2->cr_rgid && 3064 pcred1->cr_rgid != pcred2->cr_svgid) { 3065 *resultp = 0; 3066 return 0; 3067 } 3068 3069 /* Finally, check saved gid */ 3070 if ((err = kauth_cred_ismember_gid(cred2, pcred1->cr_svgid, &res)) != 0){ 3071 return err; 3072 } 3073 3074 if (!res && pcred1->cr_svgid != pcred2->cr_rgid && 3075 pcred1->cr_svgid != pcred2->cr_svgid) { 3076 *resultp = 0; 3077 return 0; 3078 } 3079 3080 *resultp = 1; 3081 return 0; 3082} 3083 3084 3085/* 3086 * kauth_cred_issuser 3087 * 3088 * Description: Fast replacement for issuser() 3089 * 3090 * Parameters: cred Credential to check for super 3091 * user privileges 3092 * 3093 * Returns: 0 Not super user 3094 * !0 Is super user 3095 * 3096 * Notes: This function uses a magic number which is not a manifest 3097 * constant; this is bad practice. 3098 */ 3099int 3100kauth_cred_issuser(kauth_cred_t cred) 3101{ 3102 return(kauth_cred_getuid(cred) == 0); 3103} 3104 3105 3106/* 3107 * Credential KPI 3108 */ 3109 3110/* lock protecting credential hash table */ 3111static lck_mtx_t *kauth_cred_hash_mtx; 3112#define KAUTH_CRED_HASH_LOCK() lck_mtx_lock(kauth_cred_hash_mtx); 3113#define KAUTH_CRED_HASH_UNLOCK() lck_mtx_unlock(kauth_cred_hash_mtx); 3114#if KAUTH_CRED_HASH_DEBUG 3115#define KAUTH_CRED_HASH_LOCK_ASSERT() lck_mtx_assert(kauth_cred_hash_mtx, LCK_MTX_ASSERT_OWNED) 3116#else /* !KAUTH_CRED_HASH_DEBUG */ 3117#define KAUTH_CRED_HASH_LOCK_ASSERT() 3118#endif /* !KAUTH_CRED_HASH_DEBUG */ 3119 3120 3121/* 3122 * kauth_cred_init 3123 * 3124 * Description: Initialize the credential hash cache 3125 * 3126 * Parameters: (void) 3127 * 3128 * Returns: (void) 3129 * 3130 * Notes: Intialize the credential hash cache for use; the credential 3131 * hash cache is used convert duplicate credentials into a 3132 * single reference counted credential in order to save wired 3133 * kernel memory. In practice, this generally means a desktop 3134 * system runs with a few tens of credentials, instead of one 3135 * per process, one per thread, one per vnode cache entry, and 3136 * so on. This generally results in savings of 200K or more 3137 * (potentially much more on server systems). 3138 * 3139 * The hash cache internally has a reference on the credential 3140 * for itself as a means of avoiding a reclaim race for a 3141 * credential in the process of having it's last non-hash 3142 * reference released. This would otherwise result in the 3143 * possibility of a freed credential that was still in uses due 3144 * a race. This use is protected by the KAUTH_CRED_HASH_LOCK. 3145 * 3146 * On final release, the hash reference is droped, and the 3147 * credential is freed back to the system. 3148 * 3149 * This function is called from kauth_init() in the file 3150 * kern_authorization.c. 3151 */ 3152void 3153kauth_cred_init(void) 3154{ 3155 int i; 3156 3157 kauth_cred_hash_mtx = lck_mtx_alloc_init(kauth_lck_grp, 0/*LCK_ATTR_NULL*/); 3158 kauth_cred_table_size = kauth_cred_primes[kauth_cred_primes_index]; 3159 3160 /*allocate credential hash table */ 3161 MALLOC(kauth_cred_table_anchor, struct kauth_cred_entry_head *, 3162 (sizeof(struct kauth_cred_entry_head) * kauth_cred_table_size), 3163 M_KAUTH, M_WAITOK | M_ZERO); 3164 if (kauth_cred_table_anchor == NULL) 3165 panic("startup: kauth_cred_init"); 3166 for (i = 0; i < kauth_cred_table_size; i++) { 3167 TAILQ_INIT(&kauth_cred_table_anchor[i]); 3168 } 3169} 3170 3171 3172/* 3173 * kauth_getuid 3174 * 3175 * Description: Get the current thread's effective UID. 3176 * 3177 * Parameters: (void) 3178 * 3179 * Returns: (uid_t) The effective UID of the 3180 * current thread 3181 */ 3182uid_t 3183kauth_getuid(void) 3184{ 3185 return(kauth_cred_getuid(kauth_cred_get())); 3186} 3187 3188 3189/* 3190 * kauth_getruid 3191 * 3192 * Description: Get the current thread's real UID. 3193 * 3194 * Parameters: (void) 3195 * 3196 * Returns: (uid_t) The real UID of the current 3197 * thread 3198 */ 3199uid_t 3200kauth_getruid(void) 3201{ 3202 return(kauth_cred_getruid(kauth_cred_get())); 3203} 3204 3205 3206/* 3207 * kauth_getgid 3208 * 3209 * Description: Get the current thread's effective GID. 3210 * 3211 * Parameters: (void) 3212 * 3213 * Returns: (gid_t) The effective GID of the 3214 * current thread 3215 */ 3216gid_t 3217kauth_getgid(void) 3218{ 3219 return(kauth_cred_getgid(kauth_cred_get())); 3220} 3221 3222 3223/* 3224 * kauth_getgid 3225 * 3226 * Description: Get the current thread's real GID. 3227 * 3228 * Parameters: (void) 3229 * 3230 * Returns: (gid_t) The real GID of the current 3231 * thread 3232 */ 3233gid_t 3234kauth_getrgid(void) 3235{ 3236 return(kauth_cred_getrgid(kauth_cred_get())); 3237} 3238 3239 3240/* 3241 * kauth_cred_get 3242 * 3243 * Description: Returns a pointer to the current thread's credential 3244 * 3245 * Parameters: (void) 3246 * 3247 * Returns: (kauth_cred_t) Pointer to the current thread's 3248 * credential 3249 * 3250 * Notes: This function does not take a reference; because of this, the 3251 * caller MUST NOT do anything that would let the thread's 3252 * credential change while using the returned value, without 3253 * first explicitly taking their own reference. 3254 * 3255 * If a caller intends to take a reference on the resulting 3256 * credential pointer from calling this function, it is strongly 3257 * recommended that the caller use kauth_cred_get_with_ref() 3258 * instead, to protect against any future changes to the cred 3259 * locking protocols; such changes could otherwise potentially 3260 * introduce race windows in the callers code. 3261 */ 3262kauth_cred_t 3263kauth_cred_get(void) 3264{ 3265 struct proc *p; 3266 struct uthread *uthread; 3267 3268 uthread = get_bsdthread_info(current_thread()); 3269 /* sanity */ 3270 if (uthread == NULL) 3271 panic("thread wants credential but has no BSD thread info"); 3272 /* 3273 * We can lazy-bind credentials to threads, as long as their processes 3274 * have them. 3275 * 3276 * XXX If we later inline this function, the code in this block 3277 * XXX should probably be called out in a function. 3278 */ 3279 if (uthread->uu_ucred == NOCRED) { 3280 if ((p = (proc_t) get_bsdtask_info(get_threadtask(current_thread()))) == NULL) 3281 panic("thread wants credential but has no BSD process"); 3282 uthread->uu_ucred = kauth_cred_proc_ref(p); 3283 } 3284 return(uthread->uu_ucred); 3285} 3286 3287void 3288mach_kauth_cred_uthread_update(void) 3289{ 3290 uthread_t uthread; 3291 proc_t proc; 3292 3293 uthread = get_bsdthread_info(current_thread()); 3294 proc = current_proc(); 3295 3296 kauth_cred_uthread_update(uthread, proc); 3297} 3298 3299/* 3300 * kauth_cred_uthread_update 3301 * 3302 * Description: Given a uthread, a proc, and whether or not the proc is locked, 3303 * late-bind the uthread cred to the proc cred. 3304 * 3305 * Parameters: uthread_t The uthread to update 3306 * proc_t The process to update to 3307 * 3308 * Returns: (void) 3309 * 3310 * Notes: This code is common code called from system call or trap entry 3311 * in the case that the process thread may have been changed 3312 * since the last time the thread entered the kernel. It is 3313 * generally only called with the current uthread and process as 3314 * parameters. 3315 */ 3316void 3317kauth_cred_uthread_update(uthread_t uthread, proc_t proc) 3318{ 3319 if (uthread->uu_ucred != proc->p_ucred && 3320 (uthread->uu_flag & UT_SETUID) == 0) { 3321 kauth_cred_t old = uthread->uu_ucred; 3322 uthread->uu_ucred = kauth_cred_proc_ref(proc); 3323 if (IS_VALID_CRED(old)) 3324 kauth_cred_unref(&old); 3325 } 3326} 3327 3328 3329/* 3330 * kauth_cred_get_with_ref 3331 * 3332 * Description: Takes a reference on the current thread's credential, and then 3333 * returns a pointer to it to the caller. 3334 * 3335 * Parameters: (void) 3336 * 3337 * Returns: (kauth_cred_t) Pointer to the current thread's 3338 * newly referenced credential 3339 * 3340 * Notes: This function takes a reference on the credential before 3341 * returning it to the caller. 3342 * 3343 * It is the responsibility of the calling code to release this 3344 * reference when the credential is no longer in use. 3345 * 3346 * Since the returned reference may be a persistent reference 3347 * (e.g. one cached in another data structure with a lifetime 3348 * longer than the calling function), this release may be delayed 3349 * until such time as the persistent reference is to be destroyed. 3350 * An example of this would be the per vnode credential cache used 3351 * to accelerate lookup operations. 3352 */ 3353kauth_cred_t 3354kauth_cred_get_with_ref(void) 3355{ 3356 struct proc *procp; 3357 struct uthread *uthread; 3358 3359 uthread = get_bsdthread_info(current_thread()); 3360 /* sanity checks */ 3361 if (uthread == NULL) 3362 panic("%s - thread wants credential but has no BSD thread info", __FUNCTION__); 3363 if ((procp = (proc_t) get_bsdtask_info(get_threadtask(current_thread()))) == NULL) 3364 panic("%s - thread wants credential but has no BSD process", __FUNCTION__); 3365 3366 /* 3367 * We can lazy-bind credentials to threads, as long as their processes 3368 * have them. 3369 * 3370 * XXX If we later inline this function, the code in this block 3371 * XXX should probably be called out in a function. 3372 */ 3373 if (uthread->uu_ucred == NOCRED) { 3374 /* take reference for new cred in thread */ 3375 uthread->uu_ucred = kauth_cred_proc_ref(procp); 3376 } 3377 /* take a reference for our caller */ 3378 kauth_cred_ref(uthread->uu_ucred); 3379 return(uthread->uu_ucred); 3380} 3381 3382 3383/* 3384 * kauth_cred_proc_ref 3385 * 3386 * Description: Takes a reference on the current process's credential, and 3387 * then returns a pointer to it to the caller. 3388 * 3389 * Parameters: procp Process whose credential we 3390 * intend to take a reference on 3391 * 3392 * Returns: (kauth_cred_t) Pointer to the process's 3393 * newly referenced credential 3394 * 3395 * Locks: PROC_LOCK is held before taking the reference and released 3396 * after the refeence is taken to protect the p_ucred field of 3397 * the process referred to by procp. 3398 * 3399 * Notes: This function takes a reference on the credential before 3400 * returning it to the caller. 3401 * 3402 * It is the responsibility of the calling code to release this 3403 * reference when the credential is no longer in use. 3404 * 3405 * Since the returned reference may be a persistent reference 3406 * (e.g. one cached in another data structure with a lifetime 3407 * longer than the calling function), this release may be delayed 3408 * until such time as the persistent reference is to be destroyed. 3409 * An example of this would be the per vnode credential cache used 3410 * to accelerate lookup operations. 3411 */ 3412kauth_cred_t 3413kauth_cred_proc_ref(proc_t procp) 3414{ 3415 kauth_cred_t cred; 3416 3417 proc_lock(procp); 3418 cred = proc_ucred(procp); 3419 kauth_cred_ref(cred); 3420 proc_unlock(procp); 3421 return(cred); 3422} 3423 3424 3425/* 3426 * kauth_cred_alloc 3427 * 3428 * Description: Allocate a new credential 3429 * 3430 * Parameters: (void) 3431 * 3432 * Returns: !NULL Newly allocated credential 3433 * NULL Insufficient memory 3434 * 3435 * Notes: The newly allocated credential is zero'ed as part of the 3436 * allocation process, with the exception of the reference 3437 * count, which is set to 1 to indicate a single reference 3438 * held by the caller. 3439 * 3440 * Since newly allocated credentials have no external pointers 3441 * referencing them, prior to making them visible in an externally 3442 * visible pointer (e.g. by adding them to the credential hash 3443 * cache) is the only legal time in which an existing credential 3444 * can be safely iinitialized or modified directly. 3445 * 3446 * After initialization, the caller is expected to call the 3447 * function kauth_cred_add() to add the credential to the hash 3448 * cache, after which time it's frozen and becomes publically 3449 * visible. 3450 * 3451 * The release protocol depends on kauth_hash_add() being called 3452 * before kauth_cred_rele() (there is a diagnostic panic which 3453 * will trigger if this protocol is not observed). 3454 * 3455 * XXX: This function really ought to be static, rather than being 3456 * exported as KPI, since a failure of kauth_cred_add() can only 3457 * be handled by an explicit free of the credential; such frees 3458 * depend on knowlegdge of the allocation method used, which is 3459 * permitted to change between kernel revisions. 3460 * 3461 * XXX: In the insufficient resource case, this code panic's rather 3462 * than returning a NULL pointer; the code that calls this 3463 * function needs to be audited before this can be changed. 3464 */ 3465kauth_cred_t 3466kauth_cred_alloc(void) 3467{ 3468 kauth_cred_t newcred; 3469 3470 MALLOC_ZONE(newcred, kauth_cred_t, sizeof(*newcred), M_CRED, M_WAITOK); 3471 if (newcred != 0) { 3472 posix_cred_t newpcred = posix_cred_get(newcred); 3473 bzero(newcred, sizeof(*newcred)); 3474 newcred->cr_ref = 1; 3475 newcred->cr_audit.as_aia_p = audit_default_aia_p; 3476 /* must do this, or cred has same group membership as uid 0 */ 3477 newpcred->cr_gmuid = KAUTH_UID_NONE; 3478#if CRED_DIAGNOSTIC 3479 } else { 3480 panic("kauth_cred_alloc: couldn't allocate credential"); 3481#endif 3482 } 3483 3484#if KAUTH_CRED_HASH_DEBUG 3485 kauth_cred_count++; 3486#endif 3487 3488#if CONFIG_MACF 3489 mac_cred_label_init(newcred); 3490#endif 3491 3492 return(newcred); 3493} 3494 3495 3496/* 3497 * kauth_cred_create 3498 * 3499 * Description: Look to see if we already have a known credential in the hash 3500 * cache; if one is found, bump the reference count and return 3501 * it. If there are no credentials that match the given 3502 * credential, then allocate a new credential. 3503 * 3504 * Parameters: cred Template for credential to 3505 * be created 3506 * 3507 * Returns: (kauth_cred_t) The credential that was found 3508 * in the hash or created 3509 * NULL kauth_cred_add() failed, or 3510 * there was not an egid specified 3511 * 3512 * Notes: The gmuid is hard-defaulted to the UID specified. Since we 3513 * maintain this field, we can't expect callers to know how it 3514 * needs to be set. Callers should be prepared for this field 3515 * to be overwritten. 3516 * 3517 * XXX: This code will tight-loop if memory for a new credential is 3518 * persistently unavailable; this is perhaps not the wisest way 3519 * to handle this condition, but current callers do not expect 3520 * a failure. 3521 */ 3522kauth_cred_t 3523kauth_cred_create(kauth_cred_t cred) 3524{ 3525 kauth_cred_t found_cred, new_cred = NULL; 3526 posix_cred_t pcred = posix_cred_get(cred); 3527 int is_member = 0; 3528 3529 KAUTH_CRED_HASH_LOCK_ASSERT(); 3530 3531 if (pcred->cr_flags & CRF_NOMEMBERD) { 3532 pcred->cr_gmuid = KAUTH_UID_NONE; 3533 } else { 3534 /* 3535 * If the template credential is not opting out of external 3536 * group membership resolution, then we need to check that 3537 * the UID we will be using is resolvable by the external 3538 * resolver. If it's not, then we opt it out anyway, since 3539 * all future external resolution requests will be failing 3540 * anyway, and potentially taking a long time to do it. We 3541 * use gid 0 because we always know it will exist and not 3542 * trigger additional lookups. This is OK, because we end up 3543 * precatching the information here as a result. 3544 */ 3545 if (!kauth_cred_ismember_gid(cred, 0, &is_member)) { 3546 /* 3547 * It's a recognized value; we don't really care about 3548 * the answer, so long as it's something the external 3549 * resolver could have vended. 3550 */ 3551 pcred->cr_gmuid = pcred->cr_uid; 3552 } else { 3553 /* 3554 * It's not something the external resolver could 3555 * have vended, so we don't want to ask it more 3556 * questions about the credential in the future. This 3557 * speeds up future lookups, as long as the caller 3558 * caches results; otherwise, it the same recurring 3559 * cost. Since most credentials are used multiple 3560 * times, we still get some performance win from this. 3561 */ 3562 pcred->cr_gmuid = KAUTH_UID_NONE; 3563 pcred->cr_flags |= CRF_NOMEMBERD; 3564 } 3565 } 3566 3567 /* Caller *must* specify at least the egid in cr_groups[0] */ 3568 if (pcred->cr_ngroups < 1) 3569 return(NULL); 3570 3571 for (;;) { 3572 KAUTH_CRED_HASH_LOCK(); 3573 found_cred = kauth_cred_find(cred); 3574 if (found_cred != NULL) { 3575 /* 3576 * Found an existing credential so we'll bump 3577 * reference count and return 3578 */ 3579 kauth_cred_ref(found_cred); 3580 KAUTH_CRED_HASH_UNLOCK(); 3581 return(found_cred); 3582 } 3583 KAUTH_CRED_HASH_UNLOCK(); 3584 3585 /* 3586 * No existing credential found. Create one and add it to 3587 * our hash table. 3588 */ 3589 new_cred = kauth_cred_alloc(); 3590 if (new_cred != NULL) { 3591 int err; 3592 posix_cred_t new_pcred = posix_cred_get(new_cred); 3593 new_pcred->cr_uid = pcred->cr_uid; 3594 new_pcred->cr_ruid = pcred->cr_ruid; 3595 new_pcred->cr_svuid = pcred->cr_svuid; 3596 new_pcred->cr_rgid = pcred->cr_rgid; 3597 new_pcred->cr_svgid = pcred->cr_svgid; 3598 new_pcred->cr_gmuid = pcred->cr_gmuid; 3599 new_pcred->cr_ngroups = pcred->cr_ngroups; 3600 bcopy(&pcred->cr_groups[0], &new_pcred->cr_groups[0], sizeof(new_pcred->cr_groups)); 3601#if CONFIG_AUDIT 3602 bcopy(&cred->cr_audit, &new_cred->cr_audit, 3603 sizeof(new_cred->cr_audit)); 3604#endif 3605 new_pcred->cr_flags = pcred->cr_flags; 3606 3607 KAUTH_CRED_HASH_LOCK(); 3608 err = kauth_cred_add(new_cred); 3609 KAUTH_CRED_HASH_UNLOCK(); 3610 3611 /* Retry if kauth_cred_add returns non zero value */ 3612 if (err == 0) 3613 break; 3614#if CONFIG_MACF 3615 mac_cred_label_destroy(new_cred); 3616#endif 3617 AUDIT_SESSION_UNREF(new_cred); 3618 3619 FREE_ZONE(new_cred, sizeof(*new_cred), M_CRED); 3620 new_cred = NULL; 3621 } 3622 } 3623 3624 return(new_cred); 3625} 3626 3627 3628/* 3629 * kauth_cred_setresuid 3630 * 3631 * Description: Update the given credential using the UID arguments. The given 3632 * UIDs are used to set the effective UID, real UID, saved UID, 3633 * and GMUID (used for group membership checking). 3634 * 3635 * Parameters: cred The original credential 3636 * ruid The new real UID 3637 * euid The new effective UID 3638 * svuid The new saved UID 3639 * gmuid KAUTH_UID_NONE -or- the new 3640 * group membership UID 3641 * 3642 * Returns: (kauth_cred_t) The updated credential 3643 * 3644 * Note: gmuid is different in that a KAUTH_UID_NONE is a valid 3645 * setting, so if you don't want it to change, pass it the 3646 * previous value, explicitly. 3647 * 3648 * IMPORTANT: This function is implemented via kauth_cred_update(), which, 3649 * if it returns a credential other than the one it is passed, 3650 * will have dropped the reference on the passed credential. All 3651 * callers should be aware of this, and treat this function as an 3652 * unref + ref, potentially on different credentials. 3653 * 3654 * Because of this, the caller is expected to take its own 3655 * reference on the credential passed as the first parameter, 3656 * and be prepared to release the reference on the credential 3657 * that is returned to them, if it is not intended to be a 3658 * persistent reference. 3659 */ 3660kauth_cred_t 3661kauth_cred_setresuid(kauth_cred_t cred, uid_t ruid, uid_t euid, uid_t svuid, uid_t gmuid) 3662{ 3663 struct ucred temp_cred; 3664 posix_cred_t temp_pcred = posix_cred_get(&temp_cred); 3665 posix_cred_t pcred = posix_cred_get(cred); 3666 3667 NULLCRED_CHECK(cred); 3668 3669 /* 3670 * We don't need to do anything if the UIDs we are changing are 3671 * already the same as the UIDs passed in 3672 */ 3673 if ((euid == KAUTH_UID_NONE || pcred->cr_uid == euid) && 3674 (ruid == KAUTH_UID_NONE || pcred->cr_ruid == ruid) && 3675 (svuid == KAUTH_UID_NONE || pcred->cr_svuid == svuid) && 3676 (pcred->cr_gmuid == gmuid)) { 3677 /* no change needed */ 3678 return(cred); 3679 } 3680 3681 /* 3682 * Look up in cred hash table to see if we have a matching credential 3683 * with the new values; this is done by calling kauth_cred_update(). 3684 */ 3685 bcopy(cred, &temp_cred, sizeof(temp_cred)); 3686 if (euid != KAUTH_UID_NONE) { 3687 temp_pcred->cr_uid = euid; 3688 } 3689 if (ruid != KAUTH_UID_NONE) { 3690 temp_pcred->cr_ruid = ruid; 3691 } 3692 if (svuid != KAUTH_UID_NONE) { 3693 temp_pcred->cr_svuid = svuid; 3694 } 3695 3696 /* 3697 * If we are setting the gmuid to KAUTH_UID_NONE, then we want to 3698 * opt out of participation in external group resolution, unless we 3699 * unless we explicitly opt back in later. 3700 */ 3701 if ((temp_pcred->cr_gmuid = gmuid) == KAUTH_UID_NONE) { 3702 temp_pcred->cr_flags |= CRF_NOMEMBERD; 3703 } 3704 3705 return(kauth_cred_update(cred, &temp_cred, TRUE)); 3706} 3707 3708 3709/* 3710 * kauth_cred_setresgid 3711 * 3712 * Description: Update the given credential using the GID arguments. The given 3713 * GIDs are used to set the effective GID, real GID, and saved 3714 * GID. 3715 * 3716 * Parameters: cred The original credential 3717 * rgid The new real GID 3718 * egid The new effective GID 3719 * svgid The new saved GID 3720 * 3721 * Returns: (kauth_cred_t) The updated credential 3722 * 3723 * IMPORTANT: This function is implemented via kauth_cred_update(), which, 3724 * if it returns a credential other than the one it is passed, 3725 * will have dropped the reference on the passed credential. All 3726 * callers should be aware of this, and treat this function as an 3727 * unref + ref, potentially on different credentials. 3728 * 3729 * Because of this, the caller is expected to take its own 3730 * reference on the credential passed as the first parameter, 3731 * and be prepared to release the reference on the credential 3732 * that is returned to them, if it is not intended to be a 3733 * persistent reference. 3734 */ 3735kauth_cred_t 3736kauth_cred_setresgid(kauth_cred_t cred, gid_t rgid, gid_t egid, gid_t svgid) 3737{ 3738 struct ucred temp_cred; 3739 posix_cred_t temp_pcred = posix_cred_get(&temp_cred); 3740 posix_cred_t pcred = posix_cred_get(cred); 3741 3742 NULLCRED_CHECK(cred); 3743 DEBUG_CRED_ENTER("kauth_cred_setresgid %p %d %d %d\n", cred, rgid, egid, svgid); 3744 3745 /* 3746 * We don't need to do anything if the given GID are already the 3747 * same as the GIDs in the credential. 3748 */ 3749 if (pcred->cr_groups[0] == egid && 3750 pcred->cr_rgid == rgid && 3751 pcred->cr_svgid == svgid) { 3752 /* no change needed */ 3753 return(cred); 3754 } 3755 3756 /* 3757 * Look up in cred hash table to see if we have a matching credential 3758 * with the new values; this is done by calling kauth_cred_update(). 3759 */ 3760 bcopy(cred, &temp_cred, sizeof(temp_cred)); 3761 if (egid != KAUTH_GID_NONE) { 3762 /* displacing a supplementary group opts us out of memberd */ 3763 if (kauth_cred_change_egid(&temp_cred, egid)) { 3764 DEBUG_CRED_CHANGE("displaced!\n"); 3765 temp_pcred->cr_flags |= CRF_NOMEMBERD; 3766 temp_pcred->cr_gmuid = KAUTH_UID_NONE; 3767 } else { 3768 DEBUG_CRED_CHANGE("not displaced\n"); 3769 } 3770 } 3771 if (rgid != KAUTH_GID_NONE) { 3772 temp_pcred->cr_rgid = rgid; 3773 } 3774 if (svgid != KAUTH_GID_NONE) { 3775 temp_pcred->cr_svgid = svgid; 3776 } 3777 3778 return(kauth_cred_update(cred, &temp_cred, TRUE)); 3779} 3780 3781 3782/* 3783 * Update the given credential with the given groups. We only allocate a new 3784 * credential when the given gid actually results in changes to the existing 3785 * credential. 3786 * The gmuid argument supplies a new uid (or KAUTH_UID_NONE to opt out) 3787 * which will be used for group membership checking. 3788 */ 3789/* 3790 * kauth_cred_setgroups 3791 * 3792 * Description: Update the given credential using the provide supplementary 3793 * group list and group membership UID 3794 * 3795 * Parameters: cred The original credential 3796 * groups Pointer to gid_t array which 3797 * contains the new group list 3798 * groupcount The count of valid groups which 3799 * are contained in 'groups' 3800 * gmuid KAUTH_UID_NONE -or- the new 3801 * group membership UID 3802 * 3803 * Returns: (kauth_cred_t) The updated credential 3804 * 3805 * Note: gmuid is different in that a KAUTH_UID_NONE is a valid 3806 * setting, so if you don't want it to change, pass it the 3807 * previous value, explicitly. 3808 * 3809 * IMPORTANT: This function is implemented via kauth_cred_update(), which, 3810 * if it returns a credential other than the one it is passed, 3811 * will have dropped the reference on the passed credential. All 3812 * callers should be aware of this, and treat this function as an 3813 * unref + ref, potentially on different credentials. 3814 * 3815 * Because of this, the caller is expected to take its own 3816 * reference on the credential passed as the first parameter, 3817 * and be prepared to release the reference on the credential 3818 * that is returned to them, if it is not intended to be a 3819 * persistent reference. 3820 * 3821 * XXX: Changes are determined in ordinal order - if the caller passes 3822 * in the same groups list that is already present in the 3823 * credential, but the members are in a different order, even if 3824 * the EGID is not modified (i.e. cr_groups[0] is the same), it 3825 * is considered a modification to the credential, and a new 3826 * credential is created. 3827 * 3828 * This should perhaps be better optimized, but it is considered 3829 * to be the caller's problem. 3830 */ 3831kauth_cred_t 3832kauth_cred_setgroups(kauth_cred_t cred, gid_t *groups, int groupcount, uid_t gmuid) 3833{ 3834 int i; 3835 struct ucred temp_cred; 3836 posix_cred_t temp_pcred = posix_cred_get(&temp_cred); 3837 posix_cred_t pcred; 3838 3839 NULLCRED_CHECK(cred); 3840 3841 pcred = posix_cred_get(cred); 3842 3843 /* 3844 * We don't need to do anything if the given list of groups does not 3845 * change. 3846 */ 3847 if ((pcred->cr_gmuid == gmuid) && (pcred->cr_ngroups == groupcount)) { 3848 for (i = 0; i < groupcount; i++) { 3849 if (pcred->cr_groups[i] != groups[i]) 3850 break; 3851 } 3852 if (i == groupcount) { 3853 /* no change needed */ 3854 return(cred); 3855 } 3856 } 3857 3858 /* 3859 * Look up in cred hash table to see if we have a matching credential 3860 * with new values. If we are setting or clearing the gmuid, then 3861 * update the cr_flags, since clearing it is sticky. This permits an 3862 * opt-out of memberd processing using setgroups(), and an opt-in 3863 * using initgroups(). This is required for POSIX conformance. 3864 */ 3865 bcopy(cred, &temp_cred, sizeof(temp_cred)); 3866 temp_pcred->cr_ngroups = groupcount; 3867 bcopy(groups, temp_pcred->cr_groups, sizeof(temp_pcred->cr_groups)); 3868 temp_pcred->cr_gmuid = gmuid; 3869 if (gmuid == KAUTH_UID_NONE) 3870 temp_pcred->cr_flags |= CRF_NOMEMBERD; 3871 else 3872 temp_pcred->cr_flags &= ~CRF_NOMEMBERD; 3873 3874 return(kauth_cred_update(cred, &temp_cred, TRUE)); 3875} 3876 3877/* 3878 * XXX temporary, for NFS support until we can come up with a better 3879 * XXX enumeration/comparison mechanism 3880 * 3881 * Notes: The return value exists to account for the possibility of a 3882 * kauth_cred_t without a POSIX label. This will be the case in 3883 * the future (see posix_cred_get() below, for more details). 3884 */ 3885int 3886kauth_cred_getgroups(kauth_cred_t cred, gid_t *grouplist, int *countp) 3887{ 3888 int limit = NGROUPS; 3889 3890 /* 3891 * If they just want a copy of the groups list, they may not care 3892 * about the actual count. If they specify an input count, however, 3893 * treat it as an indicator of the buffer size available in grouplist, 3894 * and limit the returned list to that size. 3895 */ 3896 if (countp) { 3897 limit = MIN(*countp, cred->cr_posix.cr_ngroups); 3898 *countp = limit; 3899 } 3900 3901 memcpy(grouplist, cred->cr_posix.cr_groups, sizeof(gid_t) * limit); 3902 3903 return 0; 3904} 3905 3906 3907/* 3908 * kauth_cred_setuidgid 3909 * 3910 * Description: Update the given credential using the UID and GID arguments. 3911 * The given UID is used to set the effective UID, real UID, and 3912 * saved UID. The given GID is used to set the effective GID, 3913 * real GID, and saved GID. 3914 * 3915 * Parameters: cred The original credential 3916 * uid The new UID to use 3917 * gid The new GID to use 3918 * 3919 * Returns: (kauth_cred_t) The updated credential 3920 * 3921 * Notes: We set the gmuid to uid if the credential we are inheriting 3922 * from has not opted out of memberd participation; otherwise 3923 * we set it to KAUTH_UID_NONE 3924 * 3925 * This code is only ever called from the per-thread credential 3926 * code path in the "set per thread credential" case; and in 3927 * posix_spawn() in the case that the POSIX_SPAWN_RESETIDS 3928 * flag is set. 3929 * 3930 * IMPORTANT: This function is implemented via kauth_cred_update(), which, 3931 * if it returns a credential other than the one it is passed, 3932 * will have dropped the reference on the passed credential. All 3933 * callers should be aware of this, and treat this function as an 3934 * unref + ref, potentially on different credentials. 3935 * 3936 * Because of this, the caller is expected to take its own 3937 * reference on the credential passed as the first parameter, 3938 * and be prepared to release the reference on the credential 3939 * that is returned to them, if it is not intended to be a 3940 * persistent reference. 3941 */ 3942kauth_cred_t 3943kauth_cred_setuidgid(kauth_cred_t cred, uid_t uid, gid_t gid) 3944{ 3945 struct ucred temp_cred; 3946 posix_cred_t temp_pcred = posix_cred_get(&temp_cred); 3947 posix_cred_t pcred; 3948 3949 NULLCRED_CHECK(cred); 3950 3951 pcred = posix_cred_get(cred); 3952 3953 /* 3954 * We don't need to do anything if the effective, real and saved 3955 * user IDs are already the same as the user ID passed into us. 3956 */ 3957 if (pcred->cr_uid == uid && pcred->cr_ruid == uid && pcred->cr_svuid == uid && 3958 pcred->cr_gid == gid && pcred->cr_rgid == gid && pcred->cr_svgid == gid) { 3959 /* no change needed */ 3960 return(cred); 3961 } 3962 3963 /* 3964 * Look up in cred hash table to see if we have a matching credential 3965 * with the new values. 3966 */ 3967 bzero(&temp_cred, sizeof(temp_cred)); 3968 temp_pcred->cr_uid = uid; 3969 temp_pcred->cr_ruid = uid; 3970 temp_pcred->cr_svuid = uid; 3971 temp_pcred->cr_flags = pcred->cr_flags; 3972 /* inherit the opt-out of memberd */ 3973 if (pcred->cr_flags & CRF_NOMEMBERD) { 3974 temp_pcred->cr_gmuid = KAUTH_UID_NONE; 3975 temp_pcred->cr_flags |= CRF_NOMEMBERD; 3976 } else { 3977 temp_pcred->cr_gmuid = uid; 3978 temp_pcred->cr_flags &= ~CRF_NOMEMBERD; 3979 } 3980 temp_pcred->cr_ngroups = 1; 3981 /* displacing a supplementary group opts us out of memberd */ 3982 if (kauth_cred_change_egid(&temp_cred, gid)) { 3983 temp_pcred->cr_gmuid = KAUTH_UID_NONE; 3984 temp_pcred->cr_flags |= CRF_NOMEMBERD; 3985 } 3986 temp_pcred->cr_rgid = gid; 3987 temp_pcred->cr_svgid = gid; 3988#if CONFIG_MACF 3989 temp_cred.cr_label = cred->cr_label; 3990#endif 3991 3992 return(kauth_cred_update(cred, &temp_cred, TRUE)); 3993} 3994 3995 3996/* 3997 * kauth_cred_setsvuidgid 3998 * 3999 * Description: Function used by execve to set the saved uid and gid values 4000 * for suid/sgid programs 4001 * 4002 * Parameters: cred The credential to update 4003 * uid The saved uid to set 4004 * gid The saved gid to set 4005 * 4006 * Returns: (kauth_cred_t) The updated credential 4007 * 4008 * IMPORTANT: This function is implemented via kauth_cred_update(), which, 4009 * if it returns a credential other than the one it is passed, 4010 * will have dropped the reference on the passed credential. All 4011 * callers should be aware of this, and treat this function as an 4012 * unref + ref, potentially on different credentials. 4013 * 4014 * Because of this, the caller is expected to take its own 4015 * reference on the credential passed as the first parameter, 4016 * and be prepared to release the reference on the credential 4017 * that is returned to them, if it is not intended to be a 4018 * persistent reference. 4019 */ 4020kauth_cred_t 4021kauth_cred_setsvuidgid(kauth_cred_t cred, uid_t uid, gid_t gid) 4022{ 4023 struct ucred temp_cred; 4024 posix_cred_t temp_pcred = posix_cred_get(&temp_cred); 4025 posix_cred_t pcred; 4026 4027 NULLCRED_CHECK(cred); 4028 4029 pcred = posix_cred_get(cred); 4030 4031 DEBUG_CRED_ENTER("kauth_cred_setsvuidgid: %p u%d->%d g%d->%d\n", cred, cred->cr_svuid, uid, cred->cr_svgid, gid); 4032 4033 /* 4034 * We don't need to do anything if the effective, real and saved 4035 * uids are already the same as the uid provided. This check is 4036 * likely insufficient. 4037 */ 4038 if (pcred->cr_svuid == uid && pcred->cr_svgid == gid) { 4039 /* no change needed */ 4040 return(cred); 4041 } 4042 DEBUG_CRED_CHANGE("kauth_cred_setsvuidgid: cred change\n"); 4043 4044 /* look up in cred hash table to see if we have a matching credential 4045 * with new values. 4046 */ 4047 bcopy(cred, &temp_cred, sizeof(temp_cred)); 4048 temp_pcred->cr_svuid = uid; 4049 temp_pcred->cr_svgid = gid; 4050 4051 return(kauth_cred_update(cred, &temp_cred, TRUE)); 4052} 4053 4054 4055/* 4056 * kauth_cred_setauditinfo 4057 * 4058 * Description: Update the given credential using the given au_session_t. 4059 * 4060 * Parameters: cred The original credential 4061 * auditinfo_p Pointer to ne audit information 4062 * 4063 * Returns: (kauth_cred_t) The updated credential 4064 * 4065 * IMPORTANT: This function is implemented via kauth_cred_update(), which, 4066 * if it returns a credential other than the one it is passed, 4067 * will have dropped the reference on the passed credential. All 4068 * callers should be aware of this, and treat this function as an 4069 * unref + ref, potentially on different credentials. 4070 * 4071 * Because of this, the caller is expected to take its own 4072 * reference on the credential passed as the first parameter, 4073 * and be prepared to release the reference on the credential 4074 * that is returned to them, if it is not intended to be a 4075 * persistent reference. 4076 */ 4077kauth_cred_t 4078kauth_cred_setauditinfo(kauth_cred_t cred, au_session_t *auditinfo_p) 4079{ 4080 struct ucred temp_cred; 4081 4082 NULLCRED_CHECK(cred); 4083 4084 /* 4085 * We don't need to do anything if the audit info is already the 4086 * same as the audit info in the credential provided. 4087 */ 4088 if (bcmp(&cred->cr_audit, auditinfo_p, sizeof(cred->cr_audit)) == 0) { 4089 /* no change needed */ 4090 return(cred); 4091 } 4092 4093 bcopy(cred, &temp_cred, sizeof(temp_cred)); 4094 bcopy(auditinfo_p, &temp_cred.cr_audit, sizeof(temp_cred.cr_audit)); 4095 4096 return(kauth_cred_update(cred, &temp_cred, FALSE)); 4097} 4098 4099#if CONFIG_MACF 4100/* 4101 * kauth_cred_label_update 4102 * 4103 * Description: Update the MAC label associated with a credential 4104 * 4105 * Parameters: cred The original credential 4106 * label The MAC label to set 4107 * 4108 * Returns: (kauth_cred_t) The updated credential 4109 * 4110 * IMPORTANT: This function is implemented via kauth_cred_update(), which, 4111 * if it returns a credential other than the one it is passed, 4112 * will have dropped the reference on the passed credential. All 4113 * callers should be aware of this, and treat this function as an 4114 * unref + ref, potentially on different credentials. 4115 * 4116 * Because of this, the caller is expected to take its own 4117 * reference on the credential passed as the first parameter, 4118 * and be prepared to release the reference on the credential 4119 * that is returned to them, if it is not intended to be a 4120 * persistent reference. 4121 */ 4122kauth_cred_t 4123kauth_cred_label_update(kauth_cred_t cred, struct label *label) 4124{ 4125 kauth_cred_t newcred; 4126 struct ucred temp_cred; 4127 4128 bcopy(cred, &temp_cred, sizeof(temp_cred)); 4129 4130 mac_cred_label_init(&temp_cred); 4131 mac_cred_label_associate(cred, &temp_cred); 4132 mac_cred_label_update(&temp_cred, label); 4133 4134 newcred = kauth_cred_update(cred, &temp_cred, TRUE); 4135 mac_cred_label_destroy(&temp_cred); 4136 return (newcred); 4137} 4138 4139/* 4140 * kauth_cred_label_update_execve 4141 * 4142 * Description: Update the MAC label associated with a credential as 4143 * part of exec 4144 * 4145 * Parameters: cred The original credential 4146 * vp The exec vnode 4147 * scriptl The script MAC label 4148 * execl The executable MAC label 4149 * disjointp Pointer to flag to set if old 4150 * and returned credentials are 4151 * disjoint 4152 * 4153 * Returns: (kauth_cred_t) The updated credential 4154 * 4155 * Implicit returns: 4156 * *disjointp Set to 1 for disjoint creds 4157 * 4158 * IMPORTANT: This function is implemented via kauth_cred_update(), which, 4159 * if it returns a credential other than the one it is passed, 4160 * will have dropped the reference on the passed credential. All 4161 * callers should be aware of this, and treat this function as an 4162 * unref + ref, potentially on different credentials. 4163 * 4164 * Because of this, the caller is expected to take its own 4165 * reference on the credential passed as the first parameter, 4166 * and be prepared to release the reference on the credential 4167 * that is returned to them, if it is not intended to be a 4168 * persistent reference. 4169 */ 4170static 4171kauth_cred_t 4172kauth_cred_label_update_execve(kauth_cred_t cred, vfs_context_t ctx, 4173 struct vnode *vp, struct label *scriptl, struct label *execl, 4174 int *disjointp) 4175{ 4176 kauth_cred_t newcred; 4177 struct ucred temp_cred; 4178 4179 bcopy(cred, &temp_cred, sizeof(temp_cred)); 4180 4181 mac_cred_label_init(&temp_cred); 4182 mac_cred_label_associate(cred, &temp_cred); 4183 *disjointp = mac_cred_label_update_execve(ctx, &temp_cred, 4184 vp, scriptl, execl); 4185 4186 newcred = kauth_cred_update(cred, &temp_cred, TRUE); 4187 mac_cred_label_destroy(&temp_cred); 4188 return (newcred); 4189} 4190 4191/* 4192 * kauth_proc_label_update 4193 * 4194 * Description: Update the label inside the credential associated with the process. 4195 * 4196 * Parameters: p The process to modify 4197 * label The label to place in the process credential 4198 * 4199 * Notes: The credential associated with the process may change as a result 4200 * of this call. The caller should not assume the process reference to 4201 * the old credential still exists. 4202 */ 4203int kauth_proc_label_update(struct proc *p, struct label *label) 4204{ 4205 kauth_cred_t my_cred, my_new_cred; 4206 4207 my_cred = kauth_cred_proc_ref(p); 4208 4209 DEBUG_CRED_ENTER("kauth_proc_label_update: %p\n", my_cred); 4210 4211 /* get current credential and take a reference while we muck with it */ 4212 for (;;) { 4213 4214 /* 4215 * Set the credential with new info. If there is no change, 4216 * we get back the same credential we passed in; if there is 4217 * a change, we drop the reference on the credential we 4218 * passed in. The subsequent compare is safe, because it is 4219 * a pointer compare rather than a contents compare. 4220 */ 4221 my_new_cred = kauth_cred_label_update(my_cred, label); 4222 if (my_cred != my_new_cred) { 4223 4224 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); 4225 4226 proc_lock(p); 4227 /* 4228 * We need to protect for a race where another thread 4229 * also changed the credential after we took our 4230 * reference. If p_ucred has changed then we should 4231 * restart this again with the new cred. 4232 */ 4233 if (p->p_ucred != my_cred) { 4234 proc_unlock(p); 4235 kauth_cred_unref(&my_new_cred); 4236 my_cred = kauth_cred_proc_ref(p); 4237 /* try again */ 4238 continue; 4239 } 4240 p->p_ucred = my_new_cred; 4241 /* update cred on proc */ 4242 PROC_UPDATE_CREDS_ONPROC(p); 4243 4244 mac_proc_set_enforce(p, MAC_ALL_ENFORCE); 4245 proc_unlock(p); 4246 } 4247 break; 4248 } 4249 /* Drop old proc reference or our extra reference */ 4250 kauth_cred_unref(&my_cred); 4251 4252 return (0); 4253} 4254 4255/* 4256 * kauth_proc_label_update_execve 4257 * 4258 * Description: Update the label inside the credential associated with the 4259 * process as part of a transitioning execve. The label will 4260 * be updated by the policies as part of this processing, not 4261 * provided up front. 4262 * 4263 * Parameters: p The process to modify 4264 * ctx The context of the exec 4265 * vp The vnode being exec'ed 4266 * scriptl The script MAC label 4267 * execl The executable MAC label 4268 * 4269 * Returns: 0 Label update did not make credential 4270 * disjoint 4271 * 1 Label update caused credential to be 4272 * disjoint 4273 * 4274 * Notes: The credential associated with the process WILL change as a 4275 * result of this call. The caller should not assume the process 4276 * reference to the old credential still exists. 4277 */ 4278int 4279kauth_proc_label_update_execve(struct proc *p, vfs_context_t ctx, 4280 struct vnode *vp, struct label *scriptl, struct label *execl) 4281{ 4282 kauth_cred_t my_cred, my_new_cred; 4283 int disjoint = 0; 4284 4285 my_cred = kauth_cred_proc_ref(p); 4286 4287 DEBUG_CRED_ENTER("kauth_proc_label_update_execve: %p\n", my_cred); 4288 4289 /* get current credential and take a reference while we muck with it */ 4290 for (;;) { 4291 4292 /* 4293 * Set the credential with new info. If there is no change, 4294 * we get back the same credential we passed in; if there is 4295 * a change, we drop the reference on the credential we 4296 * passed in. The subsequent compare is safe, because it is 4297 * a pointer compare rather than a contents compare. 4298 */ 4299 my_new_cred = kauth_cred_label_update_execve(my_cred, ctx, vp, scriptl, execl, &disjoint); 4300 if (my_cred != my_new_cred) { 4301 4302 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); 4303 4304 proc_lock(p); 4305 /* 4306 * We need to protect for a race where another thread 4307 * also changed the credential after we took our 4308 * reference. If p_ucred has changed then we should 4309 * restart this again with the new cred. 4310 */ 4311 if (p->p_ucred != my_cred) { 4312 proc_unlock(p); 4313 kauth_cred_unref(&my_new_cred); 4314 my_cred = kauth_cred_proc_ref(p); 4315 /* try again */ 4316 continue; 4317 } 4318 p->p_ucred = my_new_cred; 4319 /* update cred on proc */ 4320 PROC_UPDATE_CREDS_ONPROC(p); 4321 mac_proc_set_enforce(p, MAC_ALL_ENFORCE); 4322 proc_unlock(p); 4323 } 4324 break; 4325 } 4326 /* Drop old proc reference or our extra reference */ 4327 kauth_cred_unref(&my_cred); 4328 4329 return (disjoint); 4330} 4331 4332#if 1 4333/* 4334 * for temporary binary compatibility 4335 */ 4336kauth_cred_t kauth_cred_setlabel(kauth_cred_t cred, struct label *label); 4337kauth_cred_t 4338kauth_cred_setlabel(kauth_cred_t cred, struct label *label) 4339{ 4340 return kauth_cred_label_update(cred, label); 4341} 4342 4343int kauth_proc_setlabel(struct proc *p, struct label *label); 4344int 4345kauth_proc_setlabel(struct proc *p, struct label *label) 4346{ 4347 return kauth_proc_label_update(p, label); 4348} 4349#endif 4350 4351#else 4352 4353/* this is a temp hack to cover us when MACF is not built in a kernel configuration. 4354 * Since we cannot build our export lists based on the kernel configuration we need 4355 * to define a stub. 4356 */ 4357kauth_cred_t 4358kauth_cred_label_update(__unused kauth_cred_t cred, __unused void *label) 4359{ 4360 return(NULL); 4361} 4362 4363int 4364kauth_proc_label_update(__unused struct proc *p, __unused void *label) 4365{ 4366 return (0); 4367} 4368 4369#if 1 4370/* 4371 * for temporary binary compatibility 4372 */ 4373kauth_cred_t kauth_cred_setlabel(kauth_cred_t cred, void *label); 4374kauth_cred_t 4375kauth_cred_setlabel(__unused kauth_cred_t cred, __unused void *label) 4376{ 4377 return NULL; 4378} 4379 4380int kauth_proc_setlabel(struct proc *p, void *label); 4381int 4382kauth_proc_setlabel(__unused struct proc *p, __unused void *label) 4383{ 4384 return (0); 4385} 4386#endif 4387#endif 4388 4389/* 4390 * kauth_cred_ref 4391 * 4392 * Description: Add a reference to the passed credential 4393 * 4394 * Parameters: cred The credential to reference 4395 * 4396 * Returns: (void) 4397 * 4398 * Notes: This function adds a reference to the provided credential; 4399 * the existing reference on the credential is assumed to be 4400 * held stable over this operation by taking the appropriate 4401 * lock to protect the pointer from which it is being referenced, 4402 * if necessary (e.g. the proc lock is held over the call if the 4403 * credential being referenced is from p_ucred, the vnode lock 4404 * if from the per vnode name cache cred cache, and so on). 4405 * 4406 * This is safe from the kauth_cred_unref() path, since an atomic 4407 * add is used, and the unref path specifically checks to see that 4408 * the value has not been changed to add a reference between the 4409 * time the credential is unreferenced by another pointer and the 4410 * time it is unreferenced from the cred hash cache. 4411 */ 4412void 4413kauth_cred_ref(kauth_cred_t cred) 4414{ 4415 int old_value; 4416 4417 NULLCRED_CHECK(cred); 4418 4419 old_value = OSAddAtomicLong(1, (long*)&cred->cr_ref); 4420 4421 if (old_value < 1) 4422 panic("kauth_cred_ref: trying to take a reference on a cred with no references"); 4423 4424#if 0 // use this to watch a specific credential 4425 if ( is_target_cred( cred ) != 0 ) { 4426 get_backtrace( ); 4427 } 4428#endif 4429 4430 return; 4431} 4432 4433 4434/* 4435 * kauth_cred_unref_hashlocked 4436 * 4437 * Description: release a credential reference; when the last reference is 4438 * released, the credential will be freed. 4439 * 4440 * Parameters: credp Pointer to address containing 4441 * credential to be freed 4442 * 4443 * Returns: (void) 4444 * 4445 * Implicit returns: 4446 * *credp Set to NOCRED 4447 * 4448 * Notes: This function assumes the credential hash lock is held. 4449 * 4450 * This function is internal use only, since the hash lock is 4451 * scoped to this compilation unit. 4452 * 4453 * This function destroys the contents of the pointer passed by 4454 * the caller to prevent the caller accidentally attempting to 4455 * release a given reference twice in error. 4456 * 4457 * The last reference is considered to be released when a release 4458 * of a credential of a reference count of 2 occurs; this is an 4459 * intended effect, to take into account the reference held by 4460 * the credential hash, which is released at the same time. 4461 */ 4462static void 4463kauth_cred_unref_hashlocked(kauth_cred_t *credp) 4464{ 4465 int old_value; 4466 4467 KAUTH_CRED_HASH_LOCK_ASSERT(); 4468 NULLCRED_CHECK(*credp); 4469 4470 old_value = OSAddAtomicLong(-1, (long*)&(*credp)->cr_ref); 4471 4472#if DIAGNOSTIC 4473 if (old_value == 0) 4474 panic("%s:0x%08x kauth_cred_unref_hashlocked: dropping a reference on a cred with no references", current_proc()->p_comm, *credp); 4475 if (old_value == 1) 4476 panic("%s:0x%08x kauth_cred_unref_hashlocked: dropping a reference on a cred with no hash entry", current_proc()->p_comm, *credp); 4477#endif 4478 4479#if 0 // use this to watch a specific credential 4480 if ( is_target_cred( *credp ) != 0 ) { 4481 get_backtrace( ); 4482 } 4483#endif 4484 4485 /* 4486 * If the old_value is 2, then we have just released the last external 4487 * reference to this credential 4488 */ 4489 if (old_value < 3) { 4490 /* The last absolute reference is our credential hash table */ 4491 kauth_cred_remove(*credp); 4492 } 4493 *credp = NOCRED; 4494} 4495 4496 4497/* 4498 * kauth_cred_unref 4499 * 4500 * Description: Release a credential reference while holding the credential 4501 * hash lock; when the last reference is released, the credential 4502 * will be freed. 4503 * 4504 * Parameters: credp Pointer to address containing 4505 * credential to be freed 4506 * 4507 * Returns: (void) 4508 * 4509 * Implicit returns: 4510 * *credp Set to NOCRED 4511 * 4512 * Notes: See kauth_cred_unref_hashlocked() for more information. 4513 * 4514 */ 4515void 4516kauth_cred_unref(kauth_cred_t *credp) 4517{ 4518 KAUTH_CRED_HASH_LOCK(); 4519 kauth_cred_unref_hashlocked(credp); 4520 KAUTH_CRED_HASH_UNLOCK(); 4521} 4522 4523 4524#ifndef __LP64__ 4525/* 4526 * kauth_cred_rele 4527 * 4528 * Description: release a credential reference; when the last reference is 4529 * released, the credential will be freed 4530 * 4531 * Parameters: cred Credential to release 4532 * 4533 * Returns: (void) 4534 * 4535 * DEPRECATED: This interface is obsolete due to a failure to clear out the 4536 * clear the pointer in the caller to avoid multiple releases of 4537 * the same credential. The currently recommended interface is 4538 * kauth_cred_unref(). 4539 */ 4540void 4541kauth_cred_rele(kauth_cred_t cred) 4542{ 4543 kauth_cred_unref(&cred); 4544} 4545#endif /* !__LP64__ */ 4546 4547 4548/* 4549 * kauth_cred_dup 4550 * 4551 * Description: Duplicate a credential via alloc and copy; the new credential 4552 * has only it's own 4553 * 4554 * Parameters: cred The credential to duplicate 4555 * 4556 * Returns: (kauth_cred_t) The duplicate credential 4557 * 4558 * Notes: The typical value to calling this routine is if you are going 4559 * to modify an existing credential, and expect to need a new one 4560 * from the hash cache. 4561 * 4562 * This should probably not be used in the majority of cases; 4563 * if you are using it instead of kauth_cred_create(), you are 4564 * likely making a mistake. 4565 * 4566 * The newly allocated credential is copied as part of the 4567 * allocation process, with the exception of the reference 4568 * count, which is set to 1 to indicate a single reference 4569 * held by the caller. 4570 * 4571 * Since newly allocated credentials have no external pointers 4572 * referencing them, prior to making them visible in an externally 4573 * visible pointer (e.g. by adding them to the credential hash 4574 * cache) is the only legal time in which an existing credential 4575 * can be safely initialized or modified directly. 4576 * 4577 * After initialization, the caller is expected to call the 4578 * function kauth_cred_add() to add the credential to the hash 4579 * cache, after which time it's frozen and becomes publicly 4580 * visible. 4581 * 4582 * The release protocol depends on kauth_hash_add() being called 4583 * before kauth_cred_rele() (there is a diagnostic panic which 4584 * will trigger if this protocol is not observed). 4585 * 4586 */ 4587kauth_cred_t 4588kauth_cred_dup(kauth_cred_t cred) 4589{ 4590 kauth_cred_t newcred; 4591#if CONFIG_MACF 4592 struct label *temp_label; 4593#endif 4594 4595#if CRED_DIAGNOSTIC 4596 if (cred == NOCRED || cred == FSCRED) 4597 panic("kauth_cred_dup: bad credential"); 4598#endif 4599 newcred = kauth_cred_alloc(); 4600 if (newcred != NULL) { 4601#if CONFIG_MACF 4602 temp_label = newcred->cr_label; 4603#endif 4604 bcopy(cred, newcred, sizeof(*newcred)); 4605#if CONFIG_MACF 4606 newcred->cr_label = temp_label; 4607 mac_cred_label_associate(cred, newcred); 4608#endif 4609 AUDIT_SESSION_REF(cred); 4610 newcred->cr_ref = 1; 4611 } 4612 return(newcred); 4613} 4614 4615/* 4616 * kauth_cred_copy_real 4617 * 4618 * Description: Returns a credential based on the passed credential but which 4619 * reflects the real rather than effective UID and GID. 4620 * 4621 * Parameters: cred The credential from which to 4622 * derive the new credential 4623 * 4624 * Returns: (kauth_cred_t) The copied credential 4625 * 4626 * IMPORTANT: This function DOES NOT utilize kauth_cred_update(); as a 4627 * result, the caller is responsible for dropping BOTH the 4628 * additional reference on the passed cred (if any), and the 4629 * credential returned by this function. The drop should be 4630 * via the kauth_cred_unref() KPI. 4631 */ 4632kauth_cred_t 4633kauth_cred_copy_real(kauth_cred_t cred) 4634{ 4635 kauth_cred_t newcred = NULL, found_cred; 4636 struct ucred temp_cred; 4637 posix_cred_t temp_pcred = posix_cred_get(&temp_cred); 4638 posix_cred_t pcred = posix_cred_get(cred); 4639 4640 /* if the credential is already 'real', just take a reference */ 4641 if ((pcred->cr_ruid == pcred->cr_uid) && 4642 (pcred->cr_rgid == pcred->cr_gid)) { 4643 kauth_cred_ref(cred); 4644 return(cred); 4645 } 4646 4647 /* 4648 * Look up in cred hash table to see if we have a matching credential 4649 * with the new values. 4650 */ 4651 bcopy(cred, &temp_cred, sizeof(temp_cred)); 4652 temp_pcred->cr_uid = pcred->cr_ruid; 4653 /* displacing a supplementary group opts us out of memberd */ 4654 if (kauth_cred_change_egid(&temp_cred, pcred->cr_rgid)) { 4655 temp_pcred->cr_flags |= CRF_NOMEMBERD; 4656 temp_pcred->cr_gmuid = KAUTH_UID_NONE; 4657 } 4658 /* 4659 * If the cred is not opted out, make sure we are using the r/euid 4660 * for group checks 4661 */ 4662 if (temp_pcred->cr_gmuid != KAUTH_UID_NONE) 4663 temp_pcred->cr_gmuid = pcred->cr_ruid; 4664 4665 for (;;) { 4666 int err; 4667 4668 KAUTH_CRED_HASH_LOCK(); 4669 found_cred = kauth_cred_find(&temp_cred); 4670 if (found_cred == cred) { 4671 /* same cred so just bail */ 4672 KAUTH_CRED_HASH_UNLOCK(); 4673 return(cred); 4674 } 4675 if (found_cred != NULL) { 4676 /* 4677 * Found a match so we bump reference count on new 4678 * one. We leave the old one alone. 4679 */ 4680 kauth_cred_ref(found_cred); 4681 KAUTH_CRED_HASH_UNLOCK(); 4682 return(found_cred); 4683 } 4684 4685 /* 4686 * Must allocate a new credential, copy in old credential 4687 * data and update the real user and group IDs. 4688 */ 4689 newcred = kauth_cred_dup(&temp_cred); 4690 err = kauth_cred_add(newcred); 4691 KAUTH_CRED_HASH_UNLOCK(); 4692 4693 /* Retry if kauth_cred_add() fails */ 4694 if (err == 0) 4695 break; 4696#if CONFIG_MACF 4697 mac_cred_label_destroy(newcred); 4698#endif 4699 AUDIT_SESSION_UNREF(newcred); 4700 4701 FREE_ZONE(newcred, sizeof(*newcred), M_CRED); 4702 newcred = NULL; 4703 } 4704 4705 return(newcred); 4706} 4707 4708 4709/* 4710 * kauth_cred_update 4711 * 4712 * Description: Common code to update a credential 4713 * 4714 * Parameters: old_cred Reference counted credential 4715 * to update 4716 * model_cred Non-reference counted model 4717 * credential to apply to the 4718 * credential to be updated 4719 * retain_auditinfo Flag as to whether or not the 4720 * audit information should be 4721 * copied from the old_cred into 4722 * the model_cred 4723 * 4724 * Returns: (kauth_cred_t) The updated credential 4725 * 4726 * IMPORTANT: This function will potentially return a credential other than 4727 * the one it is passed, and if so, it will have dropped the 4728 * reference on the passed credential. All callers should be 4729 * aware of this, and treat this function as an unref + ref, 4730 * potentially on different credentials. 4731 * 4732 * Because of this, the caller is expected to take its own 4733 * reference on the credential passed as the first parameter, 4734 * and be prepared to release the reference on the credential 4735 * that is returned to them, if it is not intended to be a 4736 * persistent reference. 4737 */ 4738static kauth_cred_t 4739kauth_cred_update(kauth_cred_t old_cred, kauth_cred_t model_cred, 4740 boolean_t retain_auditinfo) 4741{ 4742 kauth_cred_t found_cred, new_cred = NULL; 4743 4744 /* 4745 * Make sure we carry the auditinfo forward to the new credential 4746 * unless we are actually updating the auditinfo. 4747 */ 4748 if (retain_auditinfo) { 4749 bcopy(&old_cred->cr_audit, &model_cred->cr_audit, 4750 sizeof(model_cred->cr_audit)); 4751 } 4752 4753 for (;;) { 4754 int err; 4755 4756 KAUTH_CRED_HASH_LOCK(); 4757 found_cred = kauth_cred_find(model_cred); 4758 if (found_cred == old_cred) { 4759 /* same cred so just bail */ 4760 KAUTH_CRED_HASH_UNLOCK(); 4761 return(old_cred); 4762 } 4763 if (found_cred != NULL) { 4764 DEBUG_CRED_CHANGE("kauth_cred_update(cache hit): %p -> %p\n", old_cred, found_cred); 4765 /* 4766 * Found a match so we bump reference count on new 4767 * one and decrement reference count on the old one. 4768 */ 4769 kauth_cred_ref(found_cred); 4770 kauth_cred_unref_hashlocked(&old_cred); 4771 KAUTH_CRED_HASH_UNLOCK(); 4772 return(found_cred); 4773 } 4774 4775 /* 4776 * Must allocate a new credential using the model. also 4777 * adds the new credential to the credential hash table. 4778 */ 4779 new_cred = kauth_cred_dup(model_cred); 4780 err = kauth_cred_add(new_cred); 4781 KAUTH_CRED_HASH_UNLOCK(); 4782 4783 /* retry if kauth_cred_add returns non zero value */ 4784 if (err == 0) 4785 break; 4786#if CONFIG_MACF 4787 mac_cred_label_destroy(new_cred); 4788#endif 4789 AUDIT_SESSION_UNREF(new_cred); 4790 4791 FREE_ZONE(new_cred, sizeof(*new_cred), M_CRED); 4792 new_cred = NULL; 4793 } 4794 4795 DEBUG_CRED_CHANGE("kauth_cred_update(cache miss): %p -> %p\n", old_cred, new_cred); 4796 kauth_cred_unref(&old_cred); 4797 return(new_cred); 4798} 4799 4800 4801/* 4802 * kauth_cred_add 4803 * 4804 * Description: Add the given credential to our credential hash table and 4805 * take an additional reference to account for our use of the 4806 * credential in the hash table 4807 * 4808 * Parameters: new_cred Credential to insert into cred 4809 * hash cache 4810 * 4811 * Returns: 0 Success 4812 * -1 Hash insertion failed: caller 4813 * should retry 4814 * 4815 * Locks: Caller is expected to hold KAUTH_CRED_HASH_LOCK 4816 * 4817 * Notes: The 'new_cred' MUST NOT already be in the cred hash cache 4818 */ 4819static int 4820kauth_cred_add(kauth_cred_t new_cred) 4821{ 4822 u_long hash_key; 4823 4824 KAUTH_CRED_HASH_LOCK_ASSERT(); 4825 4826 hash_key = kauth_cred_get_hashkey(new_cred); 4827 hash_key %= kauth_cred_table_size; 4828 4829 /* race fix - there is a window where another matching credential 4830 * could have been inserted between the time this one was created and we 4831 * got the hash lock. If we find a match return an error and have the 4832 * the caller retry. 4833 */ 4834 if (kauth_cred_find(new_cred) != NULL) { 4835 return(-1); 4836 } 4837 4838 /* take a reference for our use in credential hash table */ 4839 kauth_cred_ref(new_cred); 4840 4841 /* insert the credential into the hash table */ 4842 TAILQ_INSERT_HEAD(&kauth_cred_table_anchor[hash_key], new_cred, cr_link); 4843 4844 return(0); 4845} 4846 4847 4848/* 4849 * kauth_cred_remove 4850 * 4851 * Description: Remove the given credential from our credential hash table 4852 * 4853 * Parameters: cred Credential to remove from cred 4854 * hash cache 4855 * 4856 * Returns: (void) 4857 * 4858 * Locks: Caller is expected to hold KAUTH_CRED_HASH_LOCK 4859 * 4860 * Notes: The check for the reference increment after entry is generally 4861 * agree to be safe, since we use atomic operations, and the 4862 * following code occurs with the hash lock held; in theory, this 4863 * protects us from the 2->1 reference that gets us here. 4864 */ 4865static void 4866kauth_cred_remove(kauth_cred_t cred) 4867{ 4868 u_long hash_key; 4869 kauth_cred_t found_cred; 4870 4871 hash_key = kauth_cred_get_hashkey(cred); 4872 hash_key %= kauth_cred_table_size; 4873 4874 /* Avoid race */ 4875 if (cred->cr_ref < 1) 4876 panic("cred reference underflow"); 4877 if (cred->cr_ref > 1) 4878 return; /* someone else got a ref */ 4879 4880 /* Find cred in the credential hash table */ 4881 TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[hash_key], cr_link) { 4882 if (found_cred == cred) { 4883 /* found a match, remove it from the hash table */ 4884 TAILQ_REMOVE(&kauth_cred_table_anchor[hash_key], found_cred, cr_link); 4885#if CONFIG_MACF 4886 mac_cred_label_destroy(cred); 4887#endif 4888 AUDIT_SESSION_UNREF(cred); 4889 4890 cred->cr_ref = 0; 4891 FREE_ZONE(cred, sizeof(*cred), M_CRED); 4892#if KAUTH_CRED_HASH_DEBUG 4893 kauth_cred_count--; 4894#endif 4895 return; 4896 } 4897 } 4898 4899 /* Did not find a match... this should not happen! XXX Make panic? */ 4900 printf("%s:%d - %s - %s - did not find a match for %p\n", __FILE__, __LINE__, __FUNCTION__, current_proc()->p_comm, cred); 4901 return; 4902} 4903 4904 4905/* 4906 * kauth_cred_find 4907 * 4908 * Description: Using the given credential data, look for a match in our 4909 * credential hash table 4910 * 4911 * Parameters: cred Credential to lookup in cred 4912 * hash cache 4913 * 4914 * Returns: NULL Not found 4915 * !NULL Matching credential already in 4916 * cred hash cache 4917 * 4918 * Locks: Caller is expected to hold KAUTH_CRED_HASH_LOCK 4919 */ 4920kauth_cred_t 4921kauth_cred_find(kauth_cred_t cred) 4922{ 4923 u_long hash_key; 4924 kauth_cred_t found_cred; 4925 posix_cred_t pcred = posix_cred_get(cred); 4926 4927 KAUTH_CRED_HASH_LOCK_ASSERT(); 4928 4929#if KAUTH_CRED_HASH_DEBUG 4930 static int test_count = 0; 4931 4932 test_count++; 4933 if ((test_count % 200) == 0) { 4934 kauth_cred_hash_print(); 4935 } 4936#endif 4937 4938 hash_key = kauth_cred_get_hashkey(cred); 4939 hash_key %= kauth_cred_table_size; 4940 4941 /* Find cred in the credential hash table */ 4942 TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[hash_key], cr_link) { 4943 boolean_t match; 4944 posix_cred_t found_pcred = posix_cred_get(found_cred); 4945 4946 /* 4947 * don't worry about the label unless the flags in 4948 * either credential tell us to. 4949 */ 4950 match = (bcmp(found_pcred, pcred, sizeof (*pcred)) == 0) ? TRUE : FALSE; 4951 match = match && ((bcmp(&found_cred->cr_audit, &cred->cr_audit, 4952 sizeof(cred->cr_audit)) == 0) ? TRUE : FALSE); 4953 if (((found_pcred->cr_flags & CRF_MAC_ENFORCE) != 0) || 4954 ((pcred->cr_flags & CRF_MAC_ENFORCE) != 0)) { 4955 match = match && mac_cred_label_compare(found_cred->cr_label, 4956 cred->cr_label); 4957 } 4958 4959 if (match) { 4960 /* found a match */ 4961 return(found_cred); 4962 } 4963 } 4964 /* No match found */ 4965 4966 return(NULL); 4967} 4968 4969 4970/* 4971 * kauth_cred_hash 4972 * 4973 * Description: Generates a hash key using data that makes up a credential; 4974 * based on ElfHash 4975 * 4976 * Parameters: datap Pointer to data to hash 4977 * data_len Count of bytes to hash 4978 * start_key Start key value 4979 * 4980 * Returns: (u_long) Returned hash key 4981 */ 4982static inline u_long 4983kauth_cred_hash(const uint8_t *datap, int data_len, u_long start_key) 4984{ 4985 u_long hash_key = start_key; 4986 u_long temp; 4987 4988 while (data_len > 0) { 4989 hash_key = (hash_key << 4) + *datap++; 4990 temp = hash_key & 0xF0000000; 4991 if (temp) { 4992 hash_key ^= temp >> 24; 4993 } 4994 hash_key &= ~temp; 4995 data_len--; 4996 } 4997 return(hash_key); 4998} 4999 5000 5001/* 5002 * kauth_cred_get_hashkey 5003 * 5004 * Description: Generate a hash key using data that makes up a credential; 5005 * based on ElfHash. We hash on the entire credential data, 5006 * not including the ref count or the TAILQ, which are mutable; 5007 * everything else isn't. 5008 * 5009 * Parameters: cred Credential for which hash is 5010 * desired 5011 * 5012 * Returns: (u_long) Returned hash key 5013 * 5014 * Notes: When actually moving the POSIX credential into a real label, 5015 * remember to update this hash computation. 5016 */ 5017static u_long 5018kauth_cred_get_hashkey(kauth_cred_t cred) 5019{ 5020 posix_cred_t pcred = posix_cred_get(cred); 5021 u_long hash_key = 0; 5022 5023 hash_key = kauth_cred_hash((uint8_t *)&cred->cr_posix, 5024 sizeof (struct posix_cred), 5025 hash_key); 5026 hash_key = kauth_cred_hash((uint8_t *)&cred->cr_audit, 5027 sizeof(struct au_session), 5028 hash_key); 5029 5030 if (pcred->cr_flags & CRF_MAC_ENFORCE) { 5031 hash_key = kauth_cred_hash((uint8_t *)cred->cr_label, 5032 sizeof (struct label), 5033 hash_key); 5034 } 5035 return(hash_key); 5036} 5037 5038 5039#if KAUTH_CRED_HASH_DEBUG 5040/* 5041 * kauth_cred_hash_print 5042 * 5043 * Description: Print out cred hash cache table information for debugging 5044 * purposes, including the credential contents 5045 * 5046 * Parameters: (void) 5047 * 5048 * Returns: (void) 5049 * 5050 * Implicit returns: Results in console output 5051 */ 5052static void 5053kauth_cred_hash_print(void) 5054{ 5055 int i, j; 5056 kauth_cred_t found_cred; 5057 5058 printf("\n\t kauth credential hash table statistics - current cred count %d \n", kauth_cred_count); 5059 /* count slot hits, misses, collisions, and max depth */ 5060 for (i = 0; i < kauth_cred_table_size; i++) { 5061 printf("[%02d] ", i); 5062 j = 0; 5063 TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[i], cr_link) { 5064 if (j > 0) { 5065 printf("---- "); 5066 } 5067 j++; 5068 kauth_cred_print(found_cred); 5069 printf("\n"); 5070 } 5071 if (j == 0) { 5072 printf("NOCRED \n"); 5073 } 5074 } 5075} 5076#endif /* KAUTH_CRED_HASH_DEBUG */ 5077 5078 5079#if (defined(KAUTH_CRED_HASH_DEBUG) && (KAUTH_CRED_HASH_DEBUG != 0)) || defined(DEBUG_CRED) 5080/* 5081 * kauth_cred_print 5082 * 5083 * Description: Print out an individual credential's contents for debugging 5084 * purposes 5085 * 5086 * Parameters: cred The credential to print out 5087 * 5088 * Returns: (void) 5089 * 5090 * Implicit returns: Results in console output 5091 */ 5092void 5093kauth_cred_print(kauth_cred_t cred) 5094{ 5095 int i; 5096 5097 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); 5098 printf("group count %d gids ", cred->cr_ngroups); 5099 for (i = 0; i < NGROUPS; i++) { 5100 if (i == 0) 5101 printf("e"); 5102 printf("%d ", cred->cr_groups[i]); 5103 } 5104 printf("r%d sv%d ", cred->cr_rgid, cred->cr_svgid); 5105 printf("auditinfo_addr %d %d %d %d %d %d\n", 5106 cred->cr_audit.s_aia_p->ai_auid, 5107 cred->cr_audit.as_mask.am_success, 5108 cred->cr_audit.as_mask.am_failure, 5109 cred->cr_audit.as_aia_p->ai_termid.at_port, 5110 cred->cr_audit.as_aia_p->ai_termid.at_addr[0], 5111 cred->cr_audit.as_aia_p->ai_asid); 5112} 5113 5114int is_target_cred( kauth_cred_t the_cred ) 5115{ 5116 if ( the_cred->cr_uid != 0 ) 5117 return( 0 ); 5118 if ( the_cred->cr_ruid != 0 ) 5119 return( 0 ); 5120 if ( the_cred->cr_svuid != 0 ) 5121 return( 0 ); 5122 if ( the_cred->cr_ngroups != 11 ) 5123 return( 0 ); 5124 if ( the_cred->cr_groups[0] != 11 ) 5125 return( 0 ); 5126 if ( the_cred->cr_groups[1] != 81 ) 5127 return( 0 ); 5128 if ( the_cred->cr_groups[2] != 63947 ) 5129 return( 0 ); 5130 if ( the_cred->cr_groups[3] != 80288 ) 5131 return( 0 ); 5132 if ( the_cred->cr_groups[4] != 89006 ) 5133 return( 0 ); 5134 if ( the_cred->cr_groups[5] != 52173 ) 5135 return( 0 ); 5136 if ( the_cred->cr_groups[6] != 84524 ) 5137 return( 0 ); 5138 if ( the_cred->cr_groups[7] != 79 ) 5139 return( 0 ); 5140 if ( the_cred->cr_groups[8] != 80292 ) 5141 return( 0 ); 5142 if ( the_cred->cr_groups[9] != 80 ) 5143 return( 0 ); 5144 if ( the_cred->cr_groups[10] != 90824 ) 5145 return( 0 ); 5146 if ( the_cred->cr_rgid != 11 ) 5147 return( 0 ); 5148 if ( the_cred->cr_svgid != 11 ) 5149 return( 0 ); 5150 if ( the_cred->cr_gmuid != 3475 ) 5151 return( 0 ); 5152 if ( the_cred->cr_audit.as_aia_p->ai_auid != 3475 ) 5153 return( 0 ); 5154/* 5155 if ( the_cred->cr_audit.as_mask.am_success != 0 ) 5156 return( 0 ); 5157 if ( the_cred->cr_audit.as_mask.am_failure != 0 ) 5158 return( 0 ); 5159 if ( the_cred->cr_audit.as_aia_p->ai_termid.at_port != 0 ) 5160 return( 0 ); 5161 if ( the_cred->cr_audit.as_aia_p->ai_termid.at_addr[0] != 0 ) 5162 return( 0 ); 5163 if ( the_cred->cr_audit.as_aia_p->ai_asid != 0 ) 5164 return( 0 ); 5165 if ( the_cred->cr_flags != 0 ) 5166 return( 0 ); 5167*/ 5168 return( -1 ); // found target cred 5169} 5170 5171void get_backtrace( void ) 5172{ 5173 int my_slot; 5174 void * my_stack[ MAX_STACK_DEPTH ]; 5175 int i, my_depth; 5176 5177 if ( cred_debug_buf_p == NULL ) { 5178 MALLOC(cred_debug_buf_p, cred_debug_buffer *, sizeof(*cred_debug_buf_p), M_KAUTH, M_WAITOK); 5179 bzero(cred_debug_buf_p, sizeof(*cred_debug_buf_p)); 5180 } 5181 5182 if ( cred_debug_buf_p->next_slot > (MAX_CRED_BUFFER_SLOTS - 1) ) { 5183 /* buffer is full */ 5184 return; 5185 } 5186 5187 my_depth = OSBacktrace(&my_stack[0], MAX_STACK_DEPTH); 5188 if ( my_depth == 0 ) { 5189 printf("%s - OSBacktrace failed \n", __FUNCTION__); 5190 return; 5191 } 5192 5193 /* fill new backtrace */ 5194 my_slot = cred_debug_buf_p->next_slot; 5195 cred_debug_buf_p->next_slot++; 5196 cred_debug_buf_p->stack_buffer[ my_slot ].depth = my_depth; 5197 for ( i = 0; i < my_depth; i++ ) { 5198 cred_debug_buf_p->stack_buffer[ my_slot ].stack[ i ] = my_stack[ i ]; 5199 } 5200 5201 return; 5202} 5203 5204 5205/* subset of struct ucred for use in sysctl_dump_creds */ 5206struct debug_ucred { 5207 void *credp; 5208 u_long cr_ref; /* reference count */ 5209 uid_t cr_uid; /* effective user id */ 5210 uid_t cr_ruid; /* real user id */ 5211 uid_t cr_svuid; /* saved user id */ 5212 short cr_ngroups; /* number of groups in advisory list */ 5213 gid_t cr_groups[NGROUPS]; /* advisory group list */ 5214 gid_t cr_rgid; /* real group id */ 5215 gid_t cr_svgid; /* saved group id */ 5216 uid_t cr_gmuid; /* UID for group membership purposes */ 5217 struct auditinfo_addr cr_audit; /* user auditing data. */ 5218 void *cr_label; /* MACF label */ 5219 int cr_flags; /* flags on credential */ 5220}; 5221typedef struct debug_ucred debug_ucred; 5222 5223SYSCTL_PROC(_kern, OID_AUTO, dump_creds, CTLFLAG_RD, 5224 NULL, 0, sysctl_dump_creds, "S,debug_ucred", "List of credentials in the cred hash"); 5225 5226/* accessed by: 5227 * err = sysctlbyname( "kern.dump_creds", bufp, &len, NULL, 0 ); 5228 */ 5229 5230static int 5231sysctl_dump_creds( __unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req ) 5232{ 5233 int i, j, counter = 0; 5234 int error; 5235 size_t space; 5236 kauth_cred_t found_cred; 5237 debug_ucred * cred_listp; 5238 debug_ucred * nextp; 5239 5240 /* This is a readonly node. */ 5241 if (req->newptr != USER_ADDR_NULL) 5242 return (EPERM); 5243 5244 /* calculate space needed */ 5245 for (i = 0; i < kauth_cred_table_size; i++) { 5246 TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[i], cr_link) { 5247 counter++; 5248 } 5249 } 5250 5251 /* they are querying us so just return the space required. */ 5252 if (req->oldptr == USER_ADDR_NULL) { 5253 counter += 10; // add in some padding; 5254 req->oldidx = counter * sizeof(debug_ucred); 5255 return 0; 5256 } 5257 5258 MALLOC( cred_listp, debug_ucred *, req->oldlen, M_TEMP, M_WAITOK ); 5259 if ( cred_listp == NULL ) { 5260 return (ENOMEM); 5261 } 5262 5263 /* fill in creds to send back */ 5264 nextp = cred_listp; 5265 space = 0; 5266 for (i = 0; i < kauth_cred_table_size; i++) { 5267 TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[i], cr_link) { 5268 nextp->credp = found_cred; 5269 nextp->cr_ref = found_cred->cr_ref; 5270 nextp->cr_uid = found_cred->cr_uid; 5271 nextp->cr_ruid = found_cred->cr_ruid; 5272 nextp->cr_svuid = found_cred->cr_svuid; 5273 nextp->cr_ngroups = found_cred->cr_ngroups; 5274 for ( j = 0; j < nextp->cr_ngroups; j++ ) { 5275 nextp->cr_groups[ j ] = found_cred->cr_groups[ j ]; 5276 } 5277 nextp->cr_rgid = found_cred->cr_rgid; 5278 nextp->cr_svgid = found_cred->cr_svgid; 5279 nextp->cr_gmuid = found_cred->cr_gmuid; 5280 nextp->cr_audit.ai_auid = 5281 found_cred->cr_audit.as_aia_p->ai_auid; 5282 nextp->cr_audit.ai_mask.am_success = 5283 found_cred->cr_audit.as_mask.am_success; 5284 nextp->cr_audit.ai_mask.am_failure = 5285 found_cred->cr_audit.as_mask.am_failure; 5286 nextp->cr_audit.ai_termid.at_port = 5287 found_cred->cr_audit.as_aia_p->ai_termid.at_port; 5288 nextp->cr_audit.ai_termid.at_type = 5289 found_cred->cr_audit.as_aia_p->ai_termid.at_type; 5290 nextp->cr_audit.ai_termid.at_addr[0] = 5291 found_cred->cr_audit.as_aia_p->ai_termid.at_addr[0]; 5292 nextp->cr_audit.ai_termid.at_addr[1] = 5293 found_cred->cr_audit.as_aia_p->ai_termid.at_addr[1]; 5294 nextp->cr_audit.ai_termid.at_addr[2] = 5295 found_cred->cr_audit.as_aia_p->ai_termid.at_addr[2]; 5296 nextp->cr_audit.ai_termid.at_addr[3] = 5297 found_cred->cr_audit.as_aia_p->ai_termid.at_addr[3]; 5298 nextp->cr_audit.ai_asid = 5299 found_cred->cr_audit.as_aia_p->ai_asid; 5300 nextp->cr_audit.ai_flags = 5301 found_cred->cr_audit.as_aia_p->ai_flags; 5302 nextp->cr_label = found_cred->cr_label; 5303 nextp->cr_flags = found_cred->cr_flags; 5304 nextp++; 5305 space += sizeof(debug_ucred); 5306 if ( space > req->oldlen ) { 5307 FREE(cred_listp, M_TEMP); 5308 return (ENOMEM); 5309 } 5310 } 5311 } 5312 req->oldlen = space; 5313 error = SYSCTL_OUT(req, cred_listp, req->oldlen); 5314 FREE(cred_listp, M_TEMP); 5315 return (error); 5316} 5317 5318 5319SYSCTL_PROC(_kern, OID_AUTO, cred_bt, CTLFLAG_RD, 5320 NULL, 0, sysctl_dump_cred_backtraces, "S,cred_debug_buffer", "dump credential backtrace"); 5321 5322/* accessed by: 5323 * err = sysctlbyname( "kern.cred_bt", bufp, &len, NULL, 0 ); 5324 */ 5325 5326static int 5327sysctl_dump_cred_backtraces( __unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req ) 5328{ 5329 int i, j; 5330 int error; 5331 size_t space; 5332 cred_debug_buffer * bt_bufp; 5333 cred_backtrace * nextp; 5334 5335 /* This is a readonly node. */ 5336 if (req->newptr != USER_ADDR_NULL) 5337 return (EPERM); 5338 5339 if ( cred_debug_buf_p == NULL ) { 5340 return (EAGAIN); 5341 } 5342 5343 /* calculate space needed */ 5344 space = sizeof( cred_debug_buf_p->next_slot ); 5345 space += (sizeof( cred_backtrace ) * cred_debug_buf_p->next_slot); 5346 5347 /* they are querying us so just return the space required. */ 5348 if (req->oldptr == USER_ADDR_NULL) { 5349 req->oldidx = space; 5350 return 0; 5351 } 5352 5353 if ( space > req->oldlen ) { 5354 return (ENOMEM); 5355 } 5356 5357 MALLOC( bt_bufp, cred_debug_buffer *, req->oldlen, M_TEMP, M_WAITOK ); 5358 if ( bt_bufp == NULL ) { 5359 return (ENOMEM); 5360 } 5361 5362 /* fill in backtrace info to send back */ 5363 bt_bufp->next_slot = cred_debug_buf_p->next_slot; 5364 space = sizeof(bt_bufp->next_slot); 5365 5366 nextp = &bt_bufp->stack_buffer[ 0 ]; 5367 for (i = 0; i < cred_debug_buf_p->next_slot; i++) { 5368 nextp->depth = cred_debug_buf_p->stack_buffer[ i ].depth; 5369 for ( j = 0; j < nextp->depth; j++ ) { 5370 nextp->stack[ j ] = cred_debug_buf_p->stack_buffer[ i ].stack[ j ]; 5371 } 5372 space += sizeof(*nextp); 5373 nextp++; 5374 } 5375 req->oldlen = space; 5376 error = SYSCTL_OUT(req, bt_bufp, req->oldlen); 5377 FREE(bt_bufp, M_TEMP); 5378 return (error); 5379} 5380 5381#endif /* KAUTH_CRED_HASH_DEBUG || DEBUG_CRED */ 5382 5383 5384/* 5385 ********************************************************************** 5386 * The following routines will be moved to a policy_posix.c module at 5387 * some future point. 5388 ********************************************************************** 5389 */ 5390 5391/* 5392 * posix_cred_create 5393 * 5394 * Description: Helper function to create a kauth_cred_t credential that is 5395 * initally labelled with a specific POSIX credential label 5396 * 5397 * Parameters: pcred The posix_cred_t to use as the initial 5398 * label value 5399 * 5400 * Returns: (kauth_cred_t) The credential that was found in the 5401 * hash or creates 5402 * NULL kauth_cred_add() failed, or there was 5403 * no egid specified, or we failed to 5404 * attach a label to the new credential 5405 * 5406 * Notes: This function currently wraps kauth_cred_create(), and is the 5407 * only consumer of that ill-fated function, apart from bsd_init(). 5408 * It exists solely to support the NFS server code creation of 5409 * credentials based on the over-the-wire RPC calls containing 5410 * traditional POSIX credential information being tunneled to 5411 * the server host from the client machine. 5412 * 5413 * In the future, we hope this function goes away. 5414 * 5415 * In the short term, it creates a temporary credential, puts 5416 * the POSIX information from NFS into it, and then calls 5417 * kauth_cred_create(), as an internal implementation detail. 5418 * 5419 * If we have to keep it around in the medium term, it will 5420 * create a new kauth_cred_t, then label it with a POSIX label 5421 * corresponding to the contents of the kauth_cred_t. If the 5422 * policy_posix MACF module is not loaded, it will instead 5423 * substitute a posix_cred_t which GRANTS all access (effectively 5424 * a "root" credential) in order to not prevent NFS from working 5425 * in the case that we are not supporting POSIX credentials. 5426 */ 5427kauth_cred_t 5428posix_cred_create(posix_cred_t pcred) 5429{ 5430 struct ucred temp_cred; 5431 5432 bzero(&temp_cred, sizeof(temp_cred)); 5433 temp_cred.cr_posix = *pcred; 5434 5435 return kauth_cred_create(&temp_cred); 5436} 5437 5438 5439/* 5440 * posix_cred_get 5441 * 5442 * Description: Given a kauth_cred_t, return the POSIX credential label, if 5443 * any, which is associated with it. 5444 * 5445 * Parameters: cred The credential to obtain the label from 5446 * 5447 * Returns: posix_cred_t The POSIX credential label 5448 * 5449 * Notes: In the event that the policy_posix MACF module IS NOT loaded, 5450 * this function will return a pointer to a posix_cred_t which 5451 * GRANTS all access (effectively, a "root" credential). This is 5452 * necessary to support legacy code which insists on tightly 5453 * integrating POSIX credentials into its APIs, including, but 5454 * not limited to, System V IPC mechanisms, POSIX IPC mechanisms, 5455 * NFSv3, signals, dtrace, and a large number of kauth routines 5456 * used to implement POSIX permissions related system calls. 5457 * 5458 * In the event that the policy_posix MACF module IS loaded, and 5459 * there is no POSIX label on the kauth_cred_t credential, this 5460 * function will return a pointer to a posix_cred_t which DENIES 5461 * all access (effectively, a "deny rights granted by POSIX" 5462 * credential). This is necessary to support the concept of a 5463 * transiently loaded POSIX policy, or kauth_cred_t credentials 5464 * which can not be used in conjunctions with POSIX permissions 5465 * checks. 5466 * 5467 * This function currently returns the address of the cr_posix 5468 * field of the supplied kauth_cred_t credential, and as such 5469 * currently can not fail. In the future, this will not be the 5470 * case. 5471 */ 5472posix_cred_t 5473posix_cred_get(kauth_cred_t cred) 5474{ 5475 return(&cred->cr_posix); 5476} 5477 5478 5479/* 5480 * posix_cred_label 5481 * 5482 * Description: Label a kauth_cred_t with a POSIX credential label 5483 * 5484 * Parameters: cred The credential to label 5485 * pcred The POSIX credential t label it with 5486 * 5487 * Returns: (void) 5488 * 5489 * Notes: This function is currently void in order to permit it to fit 5490 * in with the current MACF framework label methods which allow 5491 * labeling to fail silently. This is like acceptable for 5492 * mandatory access controls, but not for POSIX, since those 5493 * access controls are advisory. We will need to consider a 5494 * return value in a future version of the MACF API. 5495 * 5496 * This operation currently cannot fail, as currently the POSIX 5497 * credential is a subfield of the kauth_cred_t (ucred), which 5498 * MUST be valid. In the future, this will not be the case. 5499 */ 5500void 5501posix_cred_label(kauth_cred_t cred, posix_cred_t pcred) 5502{ 5503 cred->cr_posix = *pcred; /* structure assign for now */ 5504} 5505 5506 5507/* 5508 * posix_cred_access 5509 * 5510 * Description: Perform a POSIX access check for a protected object 5511 * 5512 * Parameters: cred The credential to check 5513 * object_uid The POSIX UID of the protected object 5514 * object_gid The POSIX GID of the protected object 5515 * object_mode The POSIX mode of the protected object 5516 * mode_req The requested POSIX access rights 5517 * 5518 * Returns 0 Access is granted 5519 * EACCES Access is denied 5520 * 5521 * Notes: This code optimizes the case where the world and group rights 5522 * would both grant the requested rights to avoid making a group 5523 * membership query. This is a big performance win in the case 5524 * where this is true. 5525 */ 5526int 5527posix_cred_access(kauth_cred_t cred, id_t object_uid, id_t object_gid, mode_t object_mode, mode_t mode_req) 5528{ 5529 int is_member; 5530 mode_t mode_owner = (object_mode & S_IRWXU); 5531 mode_t mode_group = (object_mode & S_IRWXG) << 3; 5532 mode_t mode_world = (object_mode & S_IRWXO) << 6; 5533 5534 /* 5535 * Check first for owner rights 5536 */ 5537 if (kauth_cred_getuid(cred) == object_uid && (mode_req & mode_owner) == mode_req) 5538 return (0); 5539 5540 /* 5541 * Combined group and world rights check, if we don't have owner rights 5542 * 5543 * OPTIMIZED: If group and world rights would grant the same bits, and 5544 * they set of requested bits is in both, then we can simply check the 5545 * world rights, avoiding a group membership check, which is expensive. 5546 */ 5547 if ((mode_req & mode_group & mode_world) == mode_req) { 5548 return (0); 5549 } else { 5550 /* 5551 * NON-OPTIMIZED: requires group membership check. 5552 */ 5553 if ((mode_req & mode_group) != mode_req) { 5554 /* 5555 * exclusion group : treat errors as "is a member" 5556 * 5557 * NON-OPTIMIZED: +group would deny; must check group 5558 */ 5559 if (!kauth_cred_ismember_gid(cred, object_gid, &is_member) && is_member) { 5560 /* 5561 * DENY: +group denies 5562 */ 5563 return (EACCES); 5564 } else { 5565 if ((mode_req & mode_world) != mode_req) { 5566 /* 5567 * DENY: both -group & world would deny 5568 */ 5569 return (EACCES); 5570 } else { 5571 /* 5572 * ALLOW: allowed by -group and +world 5573 */ 5574 return (0); 5575 } 5576 } 5577 } else { 5578 /* 5579 * inclusion group; treat errors as "not a member" 5580 * 5581 * NON-OPTIMIZED: +group allows, world denies; must 5582 * check group 5583 */ 5584 if (!kauth_cred_ismember_gid(cred, object_gid, &is_member) && is_member) { 5585 /* 5586 * ALLOW: allowed by +group 5587 */ 5588 return (0); 5589 } else { 5590 if ((mode_req & mode_world) != mode_req) { 5591 /* 5592 * DENY: both -group & world would deny 5593 */ 5594 return (EACCES); 5595 } else { 5596 /* 5597 * ALLOW: allowed by -group and +world 5598 */ 5599 return (0); 5600 } 5601 } 5602 } 5603 } 5604} 5605