2  * Copyright (c) 2004-2011 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   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. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  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. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  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, 
  36  * Kernel Authorization framework: Management of process/thread credentials 
  37  * and identity information. 
  40 #include <sys/param.h>  /* XXX trim includes */ 
  42 #include <sys/systm.h> 
  43 #include <sys/ucred.h> 
  44 #include <sys/proc_internal.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> 
  53 #include <security/audit/audit.h> 
  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> 
  61 #include <libkern/OSAtomic.h> 
  63 #include <kern/task.h> 
  64 #include <kern/locks.h> 
  68 #define MACH_ASSERT 1   /* XXX so bogus */ 
  69 #include <kern/assert.h> 
  72 #include <security/mac.h> 
  73 #include <security/mac_framework.h> 
  74 #include <security/_label.h> 
  77 #include <IOKit/IOBSD.h> 
  79 void mach_kauth_cred_uthread_update( void ); 
  81 #define CRED_DIAGNOSTIC 0 
  83 # define NULLCRED_CHECK(_c)     do {if (!IS_VALID_CRED(_c)) panic("%s: bad credential %p", __FUNCTION__,_c);} while(0) 
  85 /* Set to 1 to turn on KAUTH_DEBUG for kern_credential.c */ 
  99 # define K_UUID_FMT "%08x:%08x:%08x:%08x" 
 100 # define K_UUID_ARG(_u) *(int *)&_u.g_guid[0],*(int *)&_u.g_guid[4],*(int *)&_u.g_guid[8],*(int *)&_u.g_guid[12] 
 101 # define KAUTH_DEBUG(fmt, args...)      do { printf("%s:%d: " fmt "\n", __PRETTY_FUNCTION__, __LINE__ , ##args); } while (0) 
 105  * Credential debugging; we can track entry into a function that might 
 106  * change a credential, and we can track actual credential changes that 
 109  * Note:        Does *NOT* currently include per-thread credential changes 
 113 #define DEBUG_CRED_ENTER                printf 
 114 #define DEBUG_CRED_CHANGE               printf 
 115 extern void kauth_cred_print(kauth_cred_t cred
); 
 117 #include <libkern/OSDebug.h>    /* needed for get_backtrace( ) */ 
 119 int is_target_cred( kauth_cred_t the_cred 
); 
 120 void get_backtrace( void ); 
 122 static int sysctl_dump_creds( __unused 
struct sysctl_oid 
*oidp
, __unused 
void *arg1
,  
 123                                                           __unused 
int arg2
, struct sysctl_req 
*req 
); 
 125 sysctl_dump_cred_backtraces( __unused 
struct sysctl_oid 
*oidp
, __unused 
void *arg1
,  
 126                                                          __unused 
int arg2
, struct sysctl_req 
*req 
); 
 128 #define MAX_STACK_DEPTH 8 
 129 struct cred_backtrace 
{ 
 131         void *                  stack
[ MAX_STACK_DEPTH 
]; 
 133 typedef struct cred_backtrace cred_backtrace
; 
 135 #define MAX_CRED_BUFFER_SLOTS 200 
 136 struct cred_debug_buffer 
{ 
 138         cred_backtrace  stack_buffer
[ MAX_CRED_BUFFER_SLOTS 
];   
 140 typedef struct cred_debug_buffer cred_debug_buffer
; 
 141 cred_debug_buffer 
* cred_debug_buf_p 
= NULL
; 
 143 #else   /* !DEBUG_CRED */ 
 145 #define DEBUG_CRED_ENTER(fmt, ...)      do {} while (0) 
 146 #define DEBUG_CRED_CHANGE(fmt, ...)     do {} while (0) 
 148 #endif  /* !DEBUG_CRED */ 
 150 #if CONFIG_EXT_RESOLVER 
 152  * Interface to external identity resolver. 
 154  * The architecture of the interface is simple; the external resolver calls 
 155  * in to get work, then calls back with completed work.  It also calls us 
 156  * to let us know that it's (re)started, so that we can resubmit work if it 
 160 static lck_mtx_t 
*kauth_resolver_mtx
; 
 161 #define KAUTH_RESOLVER_LOCK()   lck_mtx_lock(kauth_resolver_mtx); 
 162 #define KAUTH_RESOLVER_UNLOCK() lck_mtx_unlock(kauth_resolver_mtx); 
 164 static volatile pid_t   kauth_resolver_identity
; 
 165 static int      kauth_identitysvc_has_registered
; 
 166 static int      kauth_resolver_registered
; 
 167 static uint32_t kauth_resolver_sequence
; 
 168 static int      kauth_resolver_timeout 
= 30;    /* default: 30 seconds */ 
 170 struct kauth_resolver_work 
{ 
 171         TAILQ_ENTRY(kauth_resolver_work
) kr_link
; 
 172         struct kauth_identity_extlookup kr_work
; 
 177 #define KAUTH_REQUEST_UNSUBMITTED       (1<<0) 
 178 #define KAUTH_REQUEST_SUBMITTED         (1<<1) 
 179 #define KAUTH_REQUEST_DONE              (1<<2) 
 183 TAILQ_HEAD(kauth_resolver_unsubmitted_head
, kauth_resolver_work
) kauth_resolver_unsubmitted
; 
 184 TAILQ_HEAD(kauth_resolver_submitted_head
, kauth_resolver_work
)  kauth_resolver_submitted
; 
 185 TAILQ_HEAD(kauth_resolver_done_head
, kauth_resolver_work
)       kauth_resolver_done
; 
 187 /* Number of resolver timeouts between logged complaints */ 
 188 #define KAUTH_COMPLAINT_INTERVAL 1000 
 189 int kauth_resolver_timeout_cnt 
= 0; 
 191 #if DEVELOPMENT || DEBUG 
 192 /* Internal builds get different (less ambiguous) breadcrumbs. */ 
 193 #define KAUTH_RESOLVER_FAILED_ERRCODE   EOWNERDEAD 
 195 /* But non-Internal builds get errors that are allowed by standards. */ 
 196 #define KAUTH_RESOLVER_FAILED_ERRCODE   EIO 
 197 #endif /* DEVELOPMENT || DEBUG */ 
 199 int kauth_resolver_failed_cnt 
= 0; 
 200 #define RESOLVER_FAILED_MESSAGE(fmt, args...)                           \ 
 202         if (!(kauth_resolver_failed_cnt++ % 100)) {                     \ 
 203                 printf("%s: " fmt "\n", __PRETTY_FUNCTION__, ##args);   \ 
 207 static int      kauth_resolver_submit(struct kauth_identity_extlookup 
*lkp
, uint64_t extend_data
); 
 208 static int      kauth_resolver_complete(user_addr_t message
); 
 209 static int      kauth_resolver_getwork(user_addr_t message
); 
 210 static int      kauth_resolver_getwork2(user_addr_t message
); 
 211 static __attribute__((noinline
)) int __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__( 
 212         struct kauth_resolver_work 
*);  
 214 #define KAUTH_CACHES_MAX_SIZE 10000 /* Max # entries for both groups and id caches */ 
 216 struct kauth_identity 
{ 
 217         TAILQ_ENTRY(kauth_identity
) ki_link
; 
 222         gid_t   ki_supgrps
[NGROUPS
]; 
 225         const char      *ki_name
;       /* string name from string cache */ 
 227          * Expiry times are the earliest time at which we will disregard the 
 228          * cached state and go to userland.  Before then if the valid bit is 
 229          * set, we will return the cached value.  If it's not set, we will 
 230          * not go to userland to resolve, just assume that there is no answer 
 233         time_t  ki_groups_expiry
; 
 234         time_t  ki_guid_expiry
; 
 235         time_t  ki_ntsid_expiry
; 
 238 static TAILQ_HEAD(kauth_identity_head
, kauth_identity
) kauth_identities
; 
 239 static lck_mtx_t 
*kauth_identity_mtx
; 
 240 #define KAUTH_IDENTITY_LOCK()   lck_mtx_lock(kauth_identity_mtx); 
 241 #define KAUTH_IDENTITY_UNLOCK() lck_mtx_unlock(kauth_identity_mtx); 
 242 #define KAUTH_IDENTITY_CACHEMAX_DEFAULT 100     /* XXX default sizing? */ 
 243 static int kauth_identity_cachemax 
= KAUTH_IDENTITY_CACHEMAX_DEFAULT
; 
 244 static int kauth_identity_count
; 
 246 static struct kauth_identity 
*kauth_identity_alloc(uid_t uid
, gid_t gid
, guid_t 
*guidp
, time_t guid_expiry
, 
 247         ntsid_t 
*ntsidp
, time_t ntsid_expiry
, int supgrpcnt
, gid_t 
*supgrps
, time_t groups_expiry
, 
 248         const char *name
, int nametype
); 
 249 static void     kauth_identity_register_and_free(struct kauth_identity 
*kip
); 
 250 static void     kauth_identity_updatecache(struct kauth_identity_extlookup 
*elp
, struct kauth_identity 
*kip
, uint64_t extend_data
); 
 251 static void     kauth_identity_trimcache(int newsize
); 
 252 static void     kauth_identity_lru(struct kauth_identity 
*kip
); 
 253 static int      kauth_identity_guid_expired(struct kauth_identity 
*kip
); 
 254 static int      kauth_identity_ntsid_expired(struct kauth_identity 
*kip
); 
 255 static int      kauth_identity_find_uid(uid_t uid
, struct kauth_identity 
*kir
, char *getname
); 
 256 static int      kauth_identity_find_gid(gid_t gid
, struct kauth_identity 
*kir
, char *getname
); 
 257 static int      kauth_identity_find_guid(guid_t 
*guidp
, struct kauth_identity 
*kir
, char *getname
); 
 258 static int      kauth_identity_find_ntsid(ntsid_t 
*ntsid
, struct kauth_identity 
*kir
, char *getname
); 
 259 static int      kauth_identity_find_nam(char *name
, int valid
, struct kauth_identity 
*kir
); 
 261 struct kauth_group_membership 
{ 
 262         TAILQ_ENTRY(kauth_group_membership
) gm_link
; 
 263         uid_t   gm_uid
;         /* the identity whose membership we're recording */ 
 264         gid_t   gm_gid
;         /* group of which they are a member */ 
 265         time_t  gm_expiry
;      /* TTL for the membership, or 0 for persistent entries */ 
 267 #define KAUTH_GROUP_ISMEMBER    (1<<0) 
 270 TAILQ_HEAD(kauth_groups_head
, kauth_group_membership
) kauth_groups
; 
 271 static lck_mtx_t 
*kauth_groups_mtx
; 
 272 #define KAUTH_GROUPS_LOCK()     lck_mtx_lock(kauth_groups_mtx); 
 273 #define KAUTH_GROUPS_UNLOCK()   lck_mtx_unlock(kauth_groups_mtx); 
 274 #define KAUTH_GROUPS_CACHEMAX_DEFAULT 100       /* XXX default sizing? */ 
 275 static int kauth_groups_cachemax 
= KAUTH_GROUPS_CACHEMAX_DEFAULT
; 
 276 static int kauth_groups_count
; 
 278 static int      kauth_groups_expired(struct kauth_group_membership 
*gm
); 
 279 static void     kauth_groups_lru(struct kauth_group_membership 
*gm
); 
 280 static void     kauth_groups_updatecache(struct kauth_identity_extlookup 
*el
); 
 281 static void     kauth_groups_trimcache(int newsize
); 
 283 #endif  /* CONFIG_EXT_RESOLVER */ 
 285 #define KAUTH_CRED_TABLE_SIZE 97 
 287 TAILQ_HEAD(kauth_cred_entry_head
, ucred
); 
 288 static struct kauth_cred_entry_head 
* kauth_cred_table_anchor 
= NULL
; 
 290 #define KAUTH_CRED_HASH_DEBUG   0 
 292 static int kauth_cred_add(kauth_cred_t new_cred
); 
 293 static boolean_t 
kauth_cred_remove(kauth_cred_t cred
); 
 294 static inline u_long 
kauth_cred_hash(const uint8_t *datap
, int data_len
, u_long start_key
); 
 295 static u_long 
kauth_cred_get_hashkey(kauth_cred_t cred
); 
 296 static kauth_cred_t 
kauth_cred_update(kauth_cred_t old_cred
, kauth_cred_t new_cred
, boolean_t retain_auditinfo
); 
 297 static boolean_t 
kauth_cred_unref_hashlocked(kauth_cred_t 
*credp
); 
 299 #if KAUTH_CRED_HASH_DEBUG 
 300 static int      kauth_cred_count 
= 0; 
 301 static void kauth_cred_hash_print(void); 
 302 static void kauth_cred_print(kauth_cred_t cred
); 
 305 #if CONFIG_EXT_RESOLVER 
 308  *  __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__ 
 310  * Description:  Waits for the user space daemon to respond to the request 
 311  *               we made. Function declared non inline to be visible in  
 312  *               stackshots and spindumps as well as debugging. 
 314  * Parameters:   workp                     Work queue entry. 
 316  * Returns:      0                         on Success. 
 317  *               EIO                       if Resolver is dead. 
 318  *               EINTR                     thread interrupted in msleep 
 319  *               EWOULDBLOCK               thread timed out in msleep 
 320  *               ERESTART                  returned by msleep. 
 323 static __attribute__((noinline
)) int  
 324 __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__( 
 325         struct kauth_resolver_work  
*workp
) 
 330                 /* we could compute a better timeout here */ 
 331                 ts
.tv_sec 
= kauth_resolver_timeout
; 
 333                 error 
= msleep(workp
, kauth_resolver_mtx
, PCATCH
, "kr_submit", &ts
); 
 334                 /* request has been completed? */ 
 335                 if ((error 
== 0) && (workp
->kr_flags 
& KAUTH_REQUEST_DONE
)) 
 337                 /* woken because the resolver has died? */ 
 338                 if (kauth_resolver_identity 
== 0) { 
 339                         RESOLVER_FAILED_MESSAGE("kauth external resolver died while while waiting for work to complete"); 
 340                         error 
= KAUTH_RESOLVER_FAILED_ERRCODE
; 
 352  * kauth_resolver_init 
 354  * Description: Initialize the daemon side of the credential identity resolver 
 360  * Notes:       Initialize the credential identity resolver for use; the 
 361  *              credential identity resolver is the KPI used by the user 
 362  *              space credential identity resolver daemon to communicate 
 363  *              with the kernel via the identitysvc() system call.. 
 365  *              This is how membership in more than 16 groups (1 effective 
 366  *              and 15 supplementary) is supported, and also how UID's, 
 367  *              UUID's, and so on, are translated to/from POSIX credential 
 370  *              The credential identity resolver operates by attempting to 
 371  *              determine identity first from the credential, then from 
 372  *              the kernel credential identity cache, and finally by 
 373  *              enqueueing a request to a user space daemon. 
 375  *              This function is called from kauth_init() in the file 
 376  *              kern_authorization.c. 
 379 kauth_resolver_init(void) 
 381         TAILQ_INIT(&kauth_resolver_unsubmitted
); 
 382         TAILQ_INIT(&kauth_resolver_submitted
); 
 383         TAILQ_INIT(&kauth_resolver_done
); 
 384         kauth_resolver_sequence 
= 31337; 
 385         kauth_resolver_mtx 
= lck_mtx_alloc_init(kauth_lck_grp
, 0/*LCK_ATTR_NULL*/); 
 390  * kauth_resolver_submit 
 392  * Description: Submit an external credential identity resolution request to 
 393  *              the user space daemon. 
 395  * Parameters:  lkp                             A pointer to an external 
 397  *              extend_data                     extended data for kr_extend 
 400  *              EWOULDBLOCK                     No resolver registered 
 401  *              EINTR                           Operation interrupted (e.g. by 
 403  *              ENOMEM                          Could not allocate work item 
 404  *      copyinstr:EFAULT                        Bad message from user space 
 405  *      workp->kr_result:???                    An error from the user space 
 406  *                                              daemon (includes ENOENT!) 
 411  * Notes:       Allocate a work queue entry, submit the work and wait for 
 412  *              the operation to either complete or time out.  Outstanding 
 413  *              operations may also be cancelled. 
 415  *              Submission is by means of placing the item on a work queue 
 416  *              which is serviced by an external resolver thread calling 
 417  *              into the kernel.  The caller then sleeps until timeout, 
 418  *              cancellation, or an external resolver thread calls in with 
 419  *              a result message to kauth_resolver_complete().  All of these 
 420  *              events wake the caller back up. 
 422  *              This code is called from either kauth_cred_ismember_gid() 
 423  *              for a group membership request, or it is called from 
 424  *              kauth_cred_cache_lookup() when we get a cache miss. 
 427 kauth_resolver_submit(struct kauth_identity_extlookup 
*lkp
, uint64_t extend_data
) 
 429         struct kauth_resolver_work 
*workp
, *killp
; 
 431         int     error
, shouldfree
; 
 433         /* no point actually blocking if the resolver isn't up yet */ 
 434         if (kauth_resolver_identity 
== 0) { 
 436                  * We've already waited an initial <kauth_resolver_timeout> 
 437                  * seconds with no result. 
 439                  * Sleep on a stack address so no one wakes us before timeout; 
 440                  * we sleep a half a second in case we are a high priority 
 441                  * process, so that memberd doesn't starve while we are in a 
 442                  * tight loop between user and kernel, eating all the CPU. 
 444                 error 
= tsleep(&ts
, PZERO 
| PCATCH
, "kr_submit", hz
/2); 
 445                 if (kauth_resolver_identity 
== 0) { 
 447                          * if things haven't changed while we were asleep, 
 448                          * tell the caller we couldn't get an authoritative 
 455         MALLOC(workp
, struct kauth_resolver_work 
*, sizeof(*workp
), M_KAUTH
, M_WAITOK
); 
 459         workp
->kr_work 
= *lkp
; 
 460         workp
->kr_extend 
= extend_data
; 
 462         workp
->kr_flags 
= KAUTH_REQUEST_UNSUBMITTED
; 
 463         workp
->kr_result 
= 0; 
 466          * We insert the request onto the unsubmitted queue, the call in from 
 467          * the resolver will it to the submitted thread when appropriate. 
 469         KAUTH_RESOLVER_LOCK(); 
 470         workp
->kr_seqno 
= workp
->kr_work
.el_seqno 
= kauth_resolver_sequence
++; 
 471         workp
->kr_work
.el_result 
= KAUTH_EXTLOOKUP_INPROG
; 
 474          * XXX We *MUST NOT* attempt to coalesce identical work items due to 
 475          * XXX the inability to ensure order of update of the request item 
 476          * XXX extended data vs. the wakeup; instead, we let whoever is waiting 
 477          * XXX for each item repeat the update when they wake up. 
 479         TAILQ_INSERT_TAIL(&kauth_resolver_unsubmitted
, workp
, kr_link
); 
 482          * Wake up an external resolver thread to deal with the new work; one 
 483          * may not be available, and if not, then the request will be grabbed 
 484          * when a resolver thread comes back into the kernel to request new 
 487         wakeup_one((caddr_t
)&kauth_resolver_unsubmitted
); 
 488         error 
= __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__(workp
); 
 490         /* if the request was processed, copy the result */ 
 492                 *lkp 
= workp
->kr_work
; 
 494         if (error 
== EWOULDBLOCK
) { 
 495                 if ((kauth_resolver_timeout_cnt
++ % KAUTH_COMPLAINT_INTERVAL
) == 0) { 
 496                         printf("kauth external resolver timed out (%d timeout(s) of %d seconds).\n", 
 497                                 kauth_resolver_timeout_cnt
, kauth_resolver_timeout
); 
 500                 if (workp
->kr_flags 
& KAUTH_REQUEST_UNSUBMITTED
) { 
 502                          * If the request timed out and was never collected, the resolver 
 503                          * is dead and probably not coming back anytime soon.  In this 
 504                          * case we revert to no-resolver behaviour, and punt all the other 
 505                          * sleeping requests to clear the backlog. 
 507                         KAUTH_DEBUG("RESOLVER - request timed out without being collected for processing, resolver dead"); 
 510                         * Make the current resolver non-authoritative, and mark it as 
 511                         * no longer registered to prevent kauth_cred_ismember_gid() 
 512                         * enqueueing more work until a new one is registered.  This 
 513                         * mitigates the damage a crashing resolver may inflict. 
 515                         kauth_resolver_identity 
= 0; 
 516                         kauth_resolver_registered 
= 0; 
 518                         /* kill all the other requestes that are waiting as well */ 
 519                         TAILQ_FOREACH(killp
, &kauth_resolver_submitted
, kr_link
) 
 521                         TAILQ_FOREACH(killp
, &kauth_resolver_unsubmitted
, kr_link
) 
 523                         /* Cause all waiting-for-work threads to return EIO */ 
 524                         wakeup((caddr_t
)&kauth_resolver_unsubmitted
); 
 529          * drop our reference on the work item, and note whether we should 
 532         if (--workp
->kr_refs 
<= 0) { 
 533                 /* work out which list we have to remove it from */ 
 534                 if (workp
->kr_flags 
& KAUTH_REQUEST_DONE
) { 
 535                         TAILQ_REMOVE(&kauth_resolver_done
, workp
, kr_link
); 
 536                 } else if (workp
->kr_flags 
& KAUTH_REQUEST_SUBMITTED
) { 
 537                         TAILQ_REMOVE(&kauth_resolver_submitted
, workp
, kr_link
); 
 538                 } else if (workp
->kr_flags 
& KAUTH_REQUEST_UNSUBMITTED
) { 
 539                         TAILQ_REMOVE(&kauth_resolver_unsubmitted
, workp
, kr_link
); 
 541                         KAUTH_DEBUG("RESOLVER - completed request has no valid queue"); 
 545                 /* someone else still has a reference on this request */ 
 549         /* collect request result */ 
 551                 error 
= workp
->kr_result
; 
 553         KAUTH_RESOLVER_UNLOCK(); 
 556          * If we dropped the last reference, free the request. 
 559                 FREE(workp
, M_KAUTH
); 
 562         KAUTH_DEBUG("RESOLVER - returning %d", error
); 
 570  * Description: System call interface for the external identity resolver. 
 572  * Parameters:  uap->message                    Message from daemon to kernel 
 574  * Returns:     0                               Successfully became resolver 
 575  *              EPERM                           Not the resolver process 
 576  *      kauth_authorize_generic:EPERM           Not root user 
 577  *      kauth_resolver_complete:EIO 
 578  *      kauth_resolver_complete:EFAULT 
 579  *      kauth_resolver_getwork:EINTR 
 580  *      kauth_resolver_getwork:EFAULT 
 582  * Notes:       This system call blocks until there is work enqueued, at 
 583  *              which time the kernel wakes it up, and a message from the 
 584  *              kernel is copied out to the identity resolution daemon, which 
 585  *              proceed to attempt to resolve it.  When the resolution has 
 586  *              completed (successfully or not), the daemon called back into 
 587  *              this system call to give the result to the kernel, and wait 
 588  *              for the next request. 
 591 identitysvc(__unused 
struct proc 
*p
, struct identitysvc_args 
*uap
, __unused 
int32_t *retval
) 
 593         int opcode 
= uap
->opcode
; 
 594         user_addr_t message 
= uap
->message
; 
 595         struct kauth_resolver_work 
*workp
; 
 596         struct kauth_cache_sizes sz_arg 
= {}; 
 600         if (!IOTaskHasEntitlement(current_task(), IDENTITYSVC_ENTITLEMENT
)) { 
 601                 KAUTH_DEBUG("RESOLVER - pid %d not entitled to call identitysvc", current_proc()->p_pid
); 
 606          * New server registering itself. 
 608         if (opcode 
== KAUTH_EXTLOOKUP_REGISTER
) { 
 609                 new_id 
= current_proc()->p_pid
; 
 610                 if ((error 
= kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER
)) != 0) { 
 611                         KAUTH_DEBUG("RESOLVER - pid %d refused permission to become identity resolver", new_id
); 
 614                 KAUTH_RESOLVER_LOCK(); 
 615                 if (kauth_resolver_identity 
!= new_id
) { 
 616                         KAUTH_DEBUG("RESOLVER - new resolver %d taking over from old %d", new_id
, kauth_resolver_identity
); 
 618                          * We have a new server, so assume that all the old requests have been lost. 
 620                         while ((workp 
= TAILQ_LAST(&kauth_resolver_submitted
, kauth_resolver_submitted_head
)) != NULL
) { 
 621                                 TAILQ_REMOVE(&kauth_resolver_submitted
, workp
, kr_link
); 
 622                                 workp
->kr_flags 
&= ~KAUTH_REQUEST_SUBMITTED
; 
 623                                 workp
->kr_flags 
|= KAUTH_REQUEST_UNSUBMITTED
; 
 624                                 TAILQ_INSERT_HEAD(&kauth_resolver_unsubmitted
, workp
, kr_link
); 
 627                          * Allow user space resolver to override the 
 628                          * external resolution timeout 
 630                         if (message 
> 30 && message 
< 10000) { 
 631                                 kauth_resolver_timeout 
= message
; 
 632                                 KAUTH_DEBUG("RESOLVER - new resolver changes timeout to %d seconds\n", (int)message
); 
 634                         kauth_resolver_identity 
= new_id
; 
 635                         kauth_resolver_registered 
= 1; 
 636                         kauth_identitysvc_has_registered 
= 1; 
 637                         wakeup(&kauth_resolver_unsubmitted
); 
 639                 KAUTH_RESOLVER_UNLOCK(); 
 644          * Beyond this point, we must be the resolver process. We verify this 
 645          * by confirming the resolver credential and pid. 
 647         if ((kauth_cred_getuid(kauth_cred_get()) != 0) || (current_proc()->p_pid 
!= kauth_resolver_identity
)) { 
 648                 KAUTH_DEBUG("RESOLVER - call from bogus resolver %d\n", current_proc()->p_pid
); 
 652         if (opcode 
== KAUTH_GET_CACHE_SIZES
) { 
 653                 KAUTH_IDENTITY_LOCK(); 
 654                 sz_arg
.kcs_id_size 
= kauth_identity_cachemax
; 
 655                 KAUTH_IDENTITY_UNLOCK(); 
 658                 sz_arg
.kcs_group_size 
= kauth_groups_cachemax
; 
 659                 KAUTH_GROUPS_UNLOCK(); 
 661                 if ((error 
= copyout(&sz_arg
, uap
->message
, sizeof (sz_arg
))) != 0) { 
 666         } else if (opcode 
== KAUTH_SET_CACHE_SIZES
) { 
 667                 if ((error 
= copyin(uap
->message
, &sz_arg
, sizeof (sz_arg
))) != 0) { 
 671                 if ((sz_arg
.kcs_group_size 
> KAUTH_CACHES_MAX_SIZE
) || 
 672                     (sz_arg
.kcs_id_size 
> KAUTH_CACHES_MAX_SIZE
)) { 
 676                 KAUTH_IDENTITY_LOCK(); 
 677                 kauth_identity_cachemax 
= sz_arg
.kcs_id_size
; 
 678                 kauth_identity_trimcache(kauth_identity_cachemax
); 
 679                 KAUTH_IDENTITY_UNLOCK(); 
 682                 kauth_groups_cachemax 
= sz_arg
.kcs_group_size
; 
 683                 kauth_groups_trimcache(kauth_groups_cachemax
); 
 684                 KAUTH_GROUPS_UNLOCK(); 
 687         } else if (opcode 
== KAUTH_CLEAR_CACHES
) { 
 688                 KAUTH_IDENTITY_LOCK(); 
 689                 kauth_identity_trimcache(0); 
 690                 KAUTH_IDENTITY_UNLOCK(); 
 693                 kauth_groups_trimcache(0); 
 694                 KAUTH_GROUPS_UNLOCK(); 
 695         } else if (opcode 
== KAUTH_EXTLOOKUP_DEREGISTER
) { 
 697                  * Terminate outstanding requests; without an authoritative 
 698                  * resolver, we are now back on our own authority. 
 700                 struct kauth_resolver_work 
*killp
; 
 702                 KAUTH_RESOLVER_LOCK(); 
 705                  * Clear the identity, but also mark it as unregistered so 
 706                  * there is no explicit future expectation of us getting a 
 707                  * new resolver any time soon. 
 709                 kauth_resolver_identity 
= 0; 
 710                 kauth_resolver_registered 
= 0; 
 712                 TAILQ_FOREACH(killp
, &kauth_resolver_submitted
, kr_link
) 
 714                 TAILQ_FOREACH(killp
, &kauth_resolver_unsubmitted
, kr_link
) 
 716                 /* Cause all waiting-for-work threads to return EIO */ 
 717                 wakeup((caddr_t
)&kauth_resolver_unsubmitted
); 
 718                 KAUTH_RESOLVER_UNLOCK(); 
 722          * Got a result returning? 
 724         if (opcode 
& KAUTH_EXTLOOKUP_RESULT
) { 
 725                 if ((error 
= kauth_resolver_complete(message
)) != 0) 
 730          * Caller wants to take more work? 
 732         if (opcode 
& KAUTH_EXTLOOKUP_WORKER
) { 
 733                 if ((error 
= kauth_resolver_getwork(message
)) != 0) 
 742  * kauth_resolver_getwork_continue 
 744  * Description: Continuation for kauth_resolver_getwork 
 746  * Parameters:  result                          Error code or 0 for the sleep 
 747  *                                              that got us to this function 
 750  *              EINTR                           Interrupted (e.g. by signal) 
 751  *      kauth_resolver_getwork2:EFAULT 
 753  * Notes:       See kauth_resolver_getwork(0 and kauth_resolver_getwork2() for 
 757 kauth_resolver_getwork_continue(int result
) 
 764                 KAUTH_RESOLVER_UNLOCK(); 
 769          * If we lost a race with another thread/memberd restarting, then we 
 770          * need to go back to sleep to look for more work.  If it was memberd 
 771          * restarting, then the msleep0() will error out here, as our thread 
 772          * will already be "dead". 
 774         if (TAILQ_FIRST(&kauth_resolver_unsubmitted
) == NULL
) { 
 777                 error 
= msleep0(&kauth_resolver_unsubmitted
, kauth_resolver_mtx
, PCATCH
, "GRGetWork", 0, kauth_resolver_getwork_continue
); 
 779                  * If this is a wakeup from another thread in the resolver 
 780                  * deregistering it, error out the request-for-work thread 
 782                 if (!kauth_resolver_identity
) { 
 783                         RESOLVER_FAILED_MESSAGE("external resolver died"); 
 784                         error 
= KAUTH_RESOLVER_FAILED_ERRCODE
; 
 786                 KAUTH_RESOLVER_UNLOCK(); 
 790         thread 
= current_thread(); 
 791         ut 
= get_bsdthread_info(thread
); 
 792         message 
= ut
->uu_save
.uus_kauth
.message
; 
 793         return(kauth_resolver_getwork2(message
)); 
 798  * kauth_resolver_getwork2 
 800  * Decription:  Common utility function to copy out a identity resolver work 
 801  *              item from the kernel to user space as part of the user space 
 802  *              identity resolver requesting work. 
 804  * Parameters:  message                         message to user space 
 807  *              EFAULT                          Bad user space message address 
 809  * Notes:       This common function exists to permit the use of continuations 
 810  *              in the identity resolution process.  This frees up the stack 
 811  *              while we are waiting for the user space resolver to complete 
 812  *              a request.  This is specifically used so that our per thread 
 813  *              cost can be small, and we will therefore be willing to run a 
 814  *              larger number of threads in the user space identity resolver. 
 817 kauth_resolver_getwork2(user_addr_t message
) 
 819         struct kauth_resolver_work 
*workp
; 
 823          * Note: We depend on the caller protecting us from a NULL work item 
 824          * queue, since we must have the kauth resolver lock on entry to this 
 827         workp 
= TAILQ_FIRST(&kauth_resolver_unsubmitted
); 
 830          * Copy out the external lookup structure for the request, not 
 831          * including the el_extend field, which contains the address of the 
 832          * external buffer provided by the external resolver into which we 
 833          * copy the extension request information. 
 836         if ((error 
= copyout(&workp
->kr_work
, message
, offsetof(struct kauth_identity_extlookup
, el_extend
))) != 0) { 
 837                 KAUTH_DEBUG("RESOLVER - error submitting work to resolve"); 
 841         if ((error 
= copyout(&workp
->kr_work
.el_info_reserved_1
, 
 842                         message 
+ offsetof(struct kauth_identity_extlookup
, el_info_reserved_1
), 
 843                 sizeof(struct kauth_identity_extlookup
) - offsetof(struct kauth_identity_extlookup
, el_info_reserved_1
))) != 0) { 
 844                 KAUTH_DEBUG("RESOLVER - error submitting work to resolve"); 
 849          * Handle extended requests here; if we have a request of a type where 
 850          * the kernel wants a translation of extended information, then we need 
 851          * to copy it out into the extended buffer, assuming the buffer is 
 852          * valid; we only attempt to get the buffer address if we have request 
 853          * data to copy into it. 
 857          * translate a user@domain string into a uid/gid/whatever 
 859         if (workp
->kr_work
.el_flags 
& (KAUTH_EXTLOOKUP_VALID_PWNAM 
| KAUTH_EXTLOOKUP_VALID_GRNAM
)) { 
 862                 error 
= copyin(message 
+ offsetof(struct kauth_identity_extlookup
, el_extend
), &uaddr
, sizeof(uaddr
)); 
 864                         size_t actual
;  /* not used */ 
 866                          * Use copyoutstr() to reduce the copy size; we let 
 867                          * this catch a NULL uaddr because we shouldn't be 
 868                          * asking in that case anyway. 
 870                         error 
= copyoutstr(CAST_DOWN(void *,workp
->kr_extend
), uaddr
, MAXPATHLEN
, &actual
); 
 873                         KAUTH_DEBUG("RESOLVER - error submitting work to resolve"); 
 877         TAILQ_REMOVE(&kauth_resolver_unsubmitted
, workp
, kr_link
); 
 878         workp
->kr_flags 
&= ~KAUTH_REQUEST_UNSUBMITTED
; 
 879         workp
->kr_flags 
|= KAUTH_REQUEST_SUBMITTED
; 
 880         TAILQ_INSERT_TAIL(&kauth_resolver_submitted
, workp
, kr_link
); 
 883         KAUTH_RESOLVER_UNLOCK(); 
 889  * kauth_resolver_getwork 
 891  * Description: Get a work item from the enqueued requests from the kernel and 
 892  *              give it to the user space daemon. 
 894  * Parameters:  message                         message to user space 
 897  *              EINTR                           Interrupted (e.g. by signal) 
 898  *      kauth_resolver_getwork2:EFAULT 
 900  * Notes:       This function blocks in a continuation if there are no work 
 901  *              items available for processing at the time the user space 
 902  *              identity resolution daemon makes a request for work.  This 
 903  *              permits a large number of threads to be used by the daemon, 
 904  *              without using a lot of wired kernel memory when there are no 
 905  *              actual request outstanding. 
 908 kauth_resolver_getwork(user_addr_t message
) 
 910         struct kauth_resolver_work 
*workp
; 
 913         KAUTH_RESOLVER_LOCK(); 
 915         while ((workp 
= TAILQ_FIRST(&kauth_resolver_unsubmitted
)) == NULL
) { 
 916                 thread_t thread 
= current_thread(); 
 917                 struct uthread 
*ut 
= get_bsdthread_info(thread
); 
 919                 ut
->uu_save
.uus_kauth
.message 
= message
; 
 920                 error 
= msleep0(&kauth_resolver_unsubmitted
, kauth_resolver_mtx
, PCATCH
, "GRGetWork", 0, kauth_resolver_getwork_continue
); 
 921                 KAUTH_RESOLVER_UNLOCK(); 
 923                  * If this is a wakeup from another thread in the resolver 
 924                  * deregistering it, error out the request-for-work thread 
 926                 if (!kauth_resolver_identity
) { 
 927                         printf("external resolver died"); 
 928                         error 
= KAUTH_RESOLVER_FAILED_ERRCODE
; 
 932         return kauth_resolver_getwork2(message
); 
 937  * kauth_resolver_complete 
 939  * Description: Return a result from userspace. 
 941  * Parameters:  message                         message from user space 
 944  *              EIO                             The resolver is dead 
 945  *      copyin:EFAULT                           Bad message from user space 
 948 kauth_resolver_complete(user_addr_t message
) 
 950         struct kauth_identity_extlookup extl
; 
 951         struct kauth_resolver_work 
*workp
; 
 952         struct kauth_resolver_work 
*killp
; 
 953         int error
, result
, want_extend_data
; 
 956          * Copy in the mesage, including the extension field, since we are 
 957          * copying into a local variable. 
 959         if ((error 
= copyin(message
, &extl
, sizeof(extl
))) != 0) { 
 960                 KAUTH_DEBUG("RESOLVER - error getting completed work\n"); 
 964         KAUTH_RESOLVER_LOCK(); 
 968         switch (extl
.el_result
) { 
 969         case KAUTH_EXTLOOKUP_INPROG
: 
 973                 /* XXX this should go away once memberd is updated */ 
 975                         printf("kauth_resolver: memberd is not setting valid result codes (assuming always successful)\n"); 
 981         case KAUTH_EXTLOOKUP_SUCCESS
: 
 984         case KAUTH_EXTLOOKUP_FATAL
: 
 985                 /* fatal error means the resolver is dead */ 
 986                 KAUTH_DEBUG("RESOLVER - resolver %d died, waiting for a new one", kauth_resolver_identity
); 
 987                 RESOLVER_FAILED_MESSAGE("resolver %d died, waiting for a new one", kauth_resolver_identity
); 
 989                  * Terminate outstanding requests; without an authoritative 
 990                  * resolver, we are now back on our own authority.  Tag the 
 991                  * resolver unregistered to prevent kauth_cred_ismember_gid() 
 992                  * enqueueing more work until a new one is registered.  This 
 993                  * mitigates the damage a crashing resolver may inflict. 
 995                 kauth_resolver_identity 
= 0; 
 996                 kauth_resolver_registered 
= 0; 
 998                 TAILQ_FOREACH(killp
, &kauth_resolver_submitted
, kr_link
) 
1000                 TAILQ_FOREACH(killp
, &kauth_resolver_unsubmitted
, kr_link
) 
1002                 /* Cause all waiting-for-work threads to return EIO */ 
1003                 wakeup((caddr_t
)&kauth_resolver_unsubmitted
); 
1004                 /* and return EIO to the caller */ 
1005                 error 
= KAUTH_RESOLVER_FAILED_ERRCODE
; 
1008         case KAUTH_EXTLOOKUP_BADRQ
: 
1009                 KAUTH_DEBUG("RESOLVER - resolver reported invalid request %d", extl
.el_seqno
); 
1013         case KAUTH_EXTLOOKUP_FAILURE
: 
1014                 KAUTH_DEBUG("RESOLVER - resolver reported transient failure for request %d", extl
.el_seqno
); 
1015                 RESOLVER_FAILED_MESSAGE("resolver reported transient failure for request %d", extl
.el_seqno
); 
1016                 result 
= KAUTH_RESOLVER_FAILED_ERRCODE
; 
1020                 KAUTH_DEBUG("RESOLVER - resolver returned unexpected status %d", extl
.el_result
); 
1021                 RESOLVER_FAILED_MESSAGE("resolver returned unexpected status %d", extl
.el_result
); 
1022                 result 
= KAUTH_RESOLVER_FAILED_ERRCODE
; 
1027          * In the case of a fatal error, we assume that the resolver will 
1028          * restart quickly and re-collect all of the outstanding requests. 
1029          * Thus, we don't complete the request which returned the fatal 
1032         if (extl
.el_result 
!= KAUTH_EXTLOOKUP_FATAL
) { 
1033                 /* scan our list for this request */ 
1034                 TAILQ_FOREACH(workp
, &kauth_resolver_submitted
, kr_link
) { 
1036                         if (workp
->kr_seqno 
== extl
.el_seqno
) { 
1038                                  * Do we want extend_data? 
1040                                 want_extend_data 
= (workp
->kr_work
.el_flags 
& (KAUTH_EXTLOOKUP_WANT_PWNAM
|KAUTH_EXTLOOKUP_WANT_GRNAM
)); 
1043                                  * Get the request of the submitted queue so 
1044                                  * that it is not cleaned up out from under 
1047                                 TAILQ_REMOVE(&kauth_resolver_submitted
, workp
, kr_link
); 
1048                                 workp
->kr_flags 
&= ~KAUTH_REQUEST_SUBMITTED
; 
1049                                 workp
->kr_flags 
|= KAUTH_REQUEST_DONE
; 
1050                                 workp
->kr_result 
= result
; 
1052                                 /* Copy the result message to the work item. */ 
1053                                 memcpy(&workp
->kr_work
, &extl
, sizeof(struct kauth_identity_extlookup
)); 
1056                                  * Check if we have a result in the extension 
1057                                  * field; if we do, then we need to separately 
1058                                  * copy the data from the message el_extend 
1059                                  * into the request buffer that's in the work 
1060                                  * item.  We have to do it here because we do 
1061                                  * not want to wake up the waiter until the 
1062                                  * data is in their buffer, and because the 
1063                                  * actual request response may be destroyed 
1064                                  * by the time the requester wakes up, and they 
1065                                  * do not have access to the user space buffer 
1068                                  * It is safe to drop and reacquire the lock 
1069                                  * here because we've already removed the item 
1070                                  * from the submission queue, but have not yet 
1071                                  * moved it to the completion queue.  Note that 
1072                                  * near simultaneous requests may result in 
1073                                  * duplication of requests for items in this 
1074                                  * window. This should not be a performance 
1075                                  * issue and is easily detectable by comparing 
1076                                  * time to live on last response vs. time of 
1077                                  * next request in the resolver logs. 
1079                                  * A malicious/faulty resolver could overwrite 
1080                                  * part of a user's address space if they return 
1081                                  * flags that mismatch the original request's flags. 
1083                                 if (want_extend_data 
&& (extl
.el_flags 
& (KAUTH_EXTLOOKUP_VALID_PWNAM
|KAUTH_EXTLOOKUP_VALID_GRNAM
))) { 
1084                                         size_t actual
;  /* notused */ 
1086                                         KAUTH_RESOLVER_UNLOCK(); 
1087                                         error 
= copyinstr(extl
.el_extend
, CAST_DOWN(void *, workp
->kr_extend
), MAXPATHLEN
, &actual
); 
1088                                         KAUTH_DEBUG("RESOLVER - resolver got name :%*s: len = %d\n", (int)actual
, 
1089                                                     actual 
? "null" : (char *)extl
.el_extend
, actual
); 
1090                                         KAUTH_RESOLVER_LOCK(); 
1091                                 } else if (extl
.el_flags 
&  (KAUTH_EXTLOOKUP_VALID_PWNAM
|KAUTH_EXTLOOKUP_VALID_GRNAM
)) { 
1093                                         KAUTH_DEBUG("RESOLVER - resolver returned mismatching extension flags (%d), request contained (%d)", 
1094                                                         extl
.el_flags
, request_flags
); 
1098                                  * Move the completed work item to the 
1099                                  * completion queue and wake up requester(s) 
1101                                 TAILQ_INSERT_TAIL(&kauth_resolver_done
, workp
, kr_link
); 
1108          * Note that it's OK for us not to find anything; if the request has 
1109          * timed out the work record will be gone. 
1111         KAUTH_RESOLVER_UNLOCK(); 
1115 #endif /* CONFIG_EXT_RESOLVER */ 
1122 #define KI_VALID_UID    (1<<0)          /* UID and GID are mutually exclusive */ 
1123 #define KI_VALID_GID    (1<<1) 
1124 #define KI_VALID_GUID   (1<<2) 
1125 #define KI_VALID_NTSID  (1<<3) 
1126 #define KI_VALID_PWNAM  (1<<4)  /* Used for translation */ 
1127 #define KI_VALID_GRNAM  (1<<5)  /* Used for translation */ 
1128 #define KI_VALID_GROUPS (1<<6) 
1130 #if CONFIG_EXT_RESOLVER 
1132  * kauth_identity_init 
1134  * Description: Initialize the kernel side of the credential identity resolver 
1136  * Parameters:  (void) 
1140  * Notes:       Initialize the credential identity resolver for use; the 
1141  *              credential identity resolver is the KPI used to communicate 
1142  *              with a user space credential identity resolver daemon. 
1144  *              This function is called from kauth_init() in the file 
1145  *              kern_authorization.c. 
1148 kauth_identity_init(void) 
1150         TAILQ_INIT(&kauth_identities
); 
1151         kauth_identity_mtx 
= lck_mtx_alloc_init(kauth_lck_grp
, 0/*LCK_ATTR_NULL*/); 
1156  * kauth_identity_alloc 
1158  * Description: Allocate and fill out a kauth_identity structure for 
1159  *              translation between {UID|GID}/GUID/NTSID 
1163  * Returns:     NULL                            Insufficient memory to satisfy 
1164  *                                              the request or bad parameters 
1165  *              !NULL                           A pointer to the allocated 
1166  *                                              structure, filled in 
1168  * Notes:       It is illegal to translate between UID and GID; any given UUID 
1169  *              or NTSID can only refer to an NTSID or UUID (respectively), 
1170  *              and *either* a UID *or* a GID, but not both. 
1172 static struct kauth_identity 
* 
1173 kauth_identity_alloc(uid_t uid
, gid_t gid
, guid_t 
*guidp
, time_t guid_expiry
, 
1174         ntsid_t 
*ntsidp
, time_t ntsid_expiry
, int supgrpcnt
, gid_t 
*supgrps
, time_t groups_expiry
, 
1175         const char *name
, int nametype
) 
1177         struct kauth_identity 
*kip
; 
1179         /* get and fill in a new identity */ 
1180         MALLOC(kip
, struct kauth_identity 
*, sizeof(*kip
), M_KAUTH
, M_WAITOK 
| M_ZERO
); 
1182                 if (gid 
!= KAUTH_GID_NONE
) { 
1184                         kip
->ki_valid 
= KI_VALID_GID
; 
1186                 if (uid 
!= KAUTH_UID_NONE
) { 
1187                         if (kip
->ki_valid 
& KI_VALID_GID
) 
1188                                 panic("can't allocate kauth identity with both uid and gid"); 
1190                         kip
->ki_valid 
= KI_VALID_UID
; 
1194                          * A malicious/faulty resolver could return bad values 
1196                         assert(supgrpcnt 
>= 0); 
1197                         assert(supgrpcnt 
<= NGROUPS
); 
1198                         assert(supgrps 
!= NULL
); 
1200                         if ((supgrpcnt 
< 0) || (supgrpcnt 
> NGROUPS
) || (supgrps 
== NULL
)) { 
1203                         if (kip
->ki_valid 
& KI_VALID_GID
) 
1204                                 panic("can't allocate kauth identity with both gid and supplementary groups"); 
1205                         kip
->ki_supgrpcnt 
= supgrpcnt
; 
1206                         memcpy(kip
->ki_supgrps
, supgrps
, sizeof(supgrps
[0]) * supgrpcnt
); 
1207                         kip
->ki_valid 
|= KI_VALID_GROUPS
; 
1209                 kip
->ki_groups_expiry 
= groups_expiry
; 
1210                 if (guidp 
!= NULL
) { 
1211                         kip
->ki_guid 
= *guidp
; 
1212                         kip
->ki_valid 
|= KI_VALID_GUID
; 
1214                 kip
->ki_guid_expiry 
= guid_expiry
; 
1215                 if (ntsidp 
!= NULL
) { 
1216                         kip
->ki_ntsid 
= *ntsidp
; 
1217                         kip
->ki_valid 
|= KI_VALID_NTSID
; 
1219                 kip
->ki_ntsid_expiry 
= ntsid_expiry
; 
1221                         kip
->ki_name 
= name
; 
1222                         kip
->ki_valid 
|= nametype
; 
1230  * kauth_identity_register_and_free 
1232  * Description: Register an association between identity tokens.  The passed 
1233  *              'kip' is consumed by this function. 
1235  * Parameters:  kip                             Pointer to kauth_identity 
1236  *                                              structure to register 
1240  * Notes:       The memory pointer to by 'kip' is assumed to have been 
1241  *              previously allocated via kauth_identity_alloc(). 
1244 kauth_identity_register_and_free(struct kauth_identity 
*kip
) 
1246         struct kauth_identity 
*ip
; 
1249          * We search the cache for the UID listed in the incoming association. 
1250          * If we already have an entry, the new information is merged. 
1253         KAUTH_IDENTITY_LOCK(); 
1254         if (kip
->ki_valid 
& KI_VALID_UID
) { 
1255                 if (kip
->ki_valid 
& KI_VALID_GID
) 
1256                         panic("kauth_identity: can't insert record with both UID and GID as key"); 
1257                 TAILQ_FOREACH(ip
, &kauth_identities
, ki_link
) 
1258                     if ((ip
->ki_valid 
& KI_VALID_UID
) && (ip
->ki_uid 
== kip
->ki_uid
)) 
1260         } else if (kip
->ki_valid 
& KI_VALID_GID
) { 
1261                 TAILQ_FOREACH(ip
, &kauth_identities
, ki_link
) 
1262                     if ((ip
->ki_valid 
& KI_VALID_GID
) && (ip
->ki_gid 
== kip
->ki_gid
)) 
1265                 panic("kauth_identity: can't insert record without UID or GID as key"); 
1269                 /* we already have an entry, merge/overwrite */ 
1270                 if (kip
->ki_valid 
& KI_VALID_GUID
) { 
1271                         ip
->ki_guid 
= kip
->ki_guid
; 
1272                         ip
->ki_valid 
|= KI_VALID_GUID
; 
1274                 ip
->ki_guid_expiry 
= kip
->ki_guid_expiry
; 
1275                 if (kip
->ki_valid 
& KI_VALID_NTSID
) { 
1276                         ip
->ki_ntsid 
= kip
->ki_ntsid
; 
1277                         ip
->ki_valid 
|= KI_VALID_NTSID
; 
1279                 ip
->ki_ntsid_expiry 
= kip
->ki_ntsid_expiry
; 
1280                 /* a valid ki_name field overwrites the previous name field */ 
1281                 if (kip
->ki_valid 
& (KI_VALID_PWNAM 
| KI_VALID_GRNAM
)) { 
1282                         /* if there's an old one, discard it */ 
1283                         const char *oname 
= NULL
; 
1284                         if (ip
->ki_valid 
& (KI_VALID_PWNAM 
| KI_VALID_GRNAM
)) 
1285                                 oname 
= ip
->ki_name
; 
1286                         ip
->ki_name 
= kip
->ki_name
; 
1287                         kip
->ki_name 
= oname
; 
1289                 /* and discard the incoming entry */ 
1293                  * if we don't have any information on this identity, add it; 
1294                  * if it pushes us over our limit, discard the oldest one. 
1296                 TAILQ_INSERT_HEAD(&kauth_identities
, kip
, ki_link
); 
1297                 if (++kauth_identity_count 
> kauth_identity_cachemax
) { 
1298                         ip 
= TAILQ_LAST(&kauth_identities
, kauth_identity_head
); 
1299                         TAILQ_REMOVE(&kauth_identities
, ip
, ki_link
); 
1300                         kauth_identity_count
--; 
1303         KAUTH_IDENTITY_UNLOCK(); 
1304         /* have to drop lock before freeing expired entry (it may be in use) */ 
1306                 /* if the ki_name field is used, clear it first */ 
1307                 if (ip
->ki_valid 
& (KI_VALID_PWNAM 
| KI_VALID_GRNAM
)) 
1308                         vfs_removename(ip
->ki_name
); 
1309                 /* free the expired entry */ 
1316  * kauth_identity_updatecache 
1318  * Description: Given a lookup result, add any associations that we don't 
1319  *              currently have; replace ones which have changed. 
1321  * Parameters:  elp                             External lookup result from 
1322  *                                              user space daemon to kernel 
1323  *              rkip                            pointer to returned kauth 
1325  *              extend_data                     Extended data (can vary) 
1330  *              *rkip                           Modified (if non-NULL) 
1332  * Notes:       For extended information requests, this code relies on the fact 
1333  *              that elp->el_flags is never used as an rvalue, and is only 
1334  *              ever bit-tested for valid lookup information we are willing 
1337  * XXX:         We may have to do the same in the case that extended data was 
1338  *              passed out to user space to ensure that the request string 
1339  *              gets cached; we may also be able to use the rkip as an 
1340  *              input to avoid this.  The jury is still out. 
1342  * XXX:         This codes performance could be improved for multiple valid 
1343  *              results by combining the loop iteration in a single loop. 
1346 kauth_identity_updatecache(struct kauth_identity_extlookup 
*elp
, struct kauth_identity 
*rkip
, uint64_t extend_data
) 
1349         struct kauth_identity 
*kip
; 
1350         const char *speculative_name 
= NULL
; 
1355          * If there is extended data, and that data represents a name rather 
1356          * than something else, speculatively create an entry for it in the 
1357          * string cache.  We do this to avoid holding the KAUTH_IDENTITY_LOCK 
1358          * over the allocation later. 
1360         if (elp
->el_flags 
& (KAUTH_EXTLOOKUP_VALID_PWNAM 
| KAUTH_EXTLOOKUP_VALID_GRNAM
)) { 
1361                 const char *tmp 
= CAST_DOWN(const char *,extend_data
); 
1362                 speculative_name 
= vfs_addname(tmp
, strnlen(tmp
, MAXPATHLEN 
- 1), 0, 0); 
1365         /* user identity? */ 
1366         if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_UID
) { 
1367                 KAUTH_IDENTITY_LOCK(); 
1368                 TAILQ_FOREACH(kip
, &kauth_identities
, ki_link
) { 
1369                         /* matching record */ 
1370                         if ((kip
->ki_valid 
& KI_VALID_UID
) && (kip
->ki_uid 
== elp
->el_uid
)) { 
1371                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_SUPGRPS
) { 
1372                                         assert(elp
->el_sup_grp_cnt 
<= NGROUPS
); 
1373                                         if (elp
->el_sup_grp_cnt 
> NGROUPS
) { 
1374                                                 KAUTH_DEBUG("CACHE - invalid sup_grp_cnt provided (%d), truncating to  %d", 
1375                                                            elp
->el_sup_grp_cnt
, NGROUPS
); 
1376                                                 elp
->el_sup_grp_cnt 
= NGROUPS
; 
1378                                         kip
->ki_supgrpcnt 
= elp
->el_sup_grp_cnt
; 
1379                                         memcpy(kip
->ki_supgrps
, elp
->el_sup_groups
, sizeof(elp
->el_sup_groups
[0]) * kip
->ki_supgrpcnt
); 
1380                                         kip
->ki_valid 
|= KI_VALID_GROUPS
; 
1381                                         kip
->ki_groups_expiry 
= (elp
->el_member_valid
) ? tv
.tv_sec 
+ elp
->el_member_valid 
: 0; 
1383                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_UGUID
) { 
1384                                         kip
->ki_guid 
= elp
->el_uguid
; 
1385                                         kip
->ki_valid 
|= KI_VALID_GUID
; 
1387                                 kip
->ki_guid_expiry 
= (elp
->el_uguid_valid
) ? tv
.tv_sec 
+ elp
->el_uguid_valid 
: 0; 
1388                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_USID
) { 
1389                                         kip
->ki_ntsid 
= elp
->el_usid
; 
1390                                         kip
->ki_valid 
|= KI_VALID_NTSID
; 
1392                                 kip
->ki_ntsid_expiry 
= (elp
->el_usid_valid
) ? tv
.tv_sec 
+ elp
->el_usid_valid 
: 0; 
1393                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_PWNAM
) { 
1394                                         const char *oname 
= kip
->ki_name
; 
1395                                         kip
->ki_name 
= speculative_name
; 
1396                                         speculative_name 
= NULL
; 
1397                                         kip
->ki_valid 
|= KI_VALID_PWNAM
; 
1400                                                  * free oname (if any) outside 
1403                                                 speculative_name 
= oname
; 
1406                                 kauth_identity_lru(kip
); 
1409                                 KAUTH_DEBUG("CACHE - refreshed %d is " K_UUID_FMT
, kip
->ki_uid
, K_UUID_ARG(kip
->ki_guid
)); 
1413                 KAUTH_IDENTITY_UNLOCK(); 
1414                 /* not found in cache, add new record */ 
1416                         kip 
= kauth_identity_alloc(elp
->el_uid
, KAUTH_GID_NONE
, 
1417                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_UGUID
) ? &elp
->el_uguid 
: NULL
, 
1418                             (elp
->el_uguid_valid
) ? tv
.tv_sec 
+ elp
->el_uguid_valid 
: 0, 
1419                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_USID
) ? &elp
->el_usid 
: NULL
, 
1420                             (elp
->el_usid_valid
) ? tv
.tv_sec 
+ elp
->el_usid_valid 
: 0, 
1421                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_SUPGRPS
) ? elp
->el_sup_grp_cnt 
: 0, 
1422                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_SUPGRPS
) ? elp
->el_sup_groups 
: NULL
, 
1423                             (elp
->el_member_valid
) ? tv
.tv_sec 
+ elp
->el_member_valid 
: 0, 
1424                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_PWNAM
) ? speculative_name 
: NULL
, 
1429                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_PWNAM
) 
1430                                         speculative_name 
= NULL
; 
1431                                 KAUTH_DEBUG("CACHE - learned %d is " K_UUID_FMT
, kip
->ki_uid
, K_UUID_ARG(kip
->ki_guid
)); 
1432                                 kauth_identity_register_and_free(kip
); 
1437         /* group identity? (ignore, if we already processed it as a user) */ 
1438         if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GID 
&& !(elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_UID
)) { 
1439                 KAUTH_IDENTITY_LOCK(); 
1440                 TAILQ_FOREACH(kip
, &kauth_identities
, ki_link
) { 
1441                         /* matching record */ 
1442                         if ((kip
->ki_valid 
& KI_VALID_GID
) && (kip
->ki_gid 
== elp
->el_gid
)) { 
1443                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GGUID
) { 
1444                                         kip
->ki_guid 
= elp
->el_gguid
; 
1445                                         kip
->ki_valid 
|= KI_VALID_GUID
; 
1447                                 kip
->ki_guid_expiry 
= (elp
->el_gguid_valid
) ? tv
.tv_sec 
+ elp
->el_gguid_valid 
: 0; 
1448                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GSID
) { 
1449                                         kip
->ki_ntsid 
= elp
->el_gsid
; 
1450                                         kip
->ki_valid 
|= KI_VALID_NTSID
; 
1452                                 kip
->ki_ntsid_expiry 
= (elp
->el_gsid_valid
) ? tv
.tv_sec 
+ elp
->el_gsid_valid 
: 0; 
1453                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GRNAM
) { 
1454                                         const char *oname 
= kip
->ki_name
; 
1455                                         kip
->ki_name 
= speculative_name
; 
1456                                         speculative_name 
= NULL
; 
1457                                         kip
->ki_valid 
|= KI_VALID_GRNAM
; 
1460                                                  * free oname (if any) outside 
1463                                                 speculative_name 
= oname
; 
1466                                 kauth_identity_lru(kip
); 
1469                                 KAUTH_DEBUG("CACHE - refreshed %d is " K_UUID_FMT
, kip
->ki_uid
, K_UUID_ARG(kip
->ki_guid
)); 
1473                 KAUTH_IDENTITY_UNLOCK(); 
1474                 /* not found in cache, add new record */ 
1476                         kip 
= kauth_identity_alloc(KAUTH_UID_NONE
, elp
->el_gid
, 
1477                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GGUID
) ? &elp
->el_gguid 
: NULL
, 
1478                             (elp
->el_gguid_valid
) ? tv
.tv_sec 
+ elp
->el_gguid_valid 
: 0, 
1479                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GSID
) ? &elp
->el_gsid 
: NULL
, 
1480                             (elp
->el_gsid_valid
) ? tv
.tv_sec 
+ elp
->el_gsid_valid 
: 0, 
1481                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_SUPGRPS
) ? elp
->el_sup_grp_cnt 
: 0, 
1482                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_SUPGRPS
) ? elp
->el_sup_groups 
: NULL
, 
1483                             (elp
->el_member_valid
) ? tv
.tv_sec 
+ elp
->el_member_valid 
: 0, 
1484                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GRNAM
) ? speculative_name 
: NULL
, 
1489                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GRNAM
) 
1490                                         speculative_name 
= NULL
; 
1491                                 KAUTH_DEBUG("CACHE - learned %d is " K_UUID_FMT
, kip
->ki_uid
, K_UUID_ARG(kip
->ki_guid
)); 
1492                                 kauth_identity_register_and_free(kip
); 
1497         /* If we have a name reference to drop, drop it here */ 
1498         if (speculative_name 
!= NULL
) { 
1499                 vfs_removename(speculative_name
); 
1505  * Trim older entries from the identity cache. 
1507  * Must be called with the identity cache lock held. 
1510 kauth_identity_trimcache(int newsize
) { 
1511         struct kauth_identity           
*kip
; 
1513         lck_mtx_assert(kauth_identity_mtx
, LCK_MTX_ASSERT_OWNED
); 
1515         while (kauth_identity_count 
> newsize
) { 
1516                 kip 
= TAILQ_LAST(&kauth_identities
, kauth_identity_head
); 
1517                 TAILQ_REMOVE(&kauth_identities
, kip
, ki_link
); 
1518                 kauth_identity_count
--; 
1524  * kauth_identity_lru 
1526  * Description: Promote the entry to the head of the LRU, assumes the cache 
1529  * Parameters:  kip                             kauth identity to move to the 
1530  *                                              head of the LRU list, if it's 
1535  * Notes:       This is called even if the entry has expired; typically an 
1536  *              expired entry that's been looked up is about to be revalidated, 
1537  *              and having it closer to the head of the LRU means finding it 
1538  *              quickly again when the revalidation comes through. 
1541 kauth_identity_lru(struct kauth_identity 
*kip
) 
1543         if (kip 
!= TAILQ_FIRST(&kauth_identities
)) { 
1544                 TAILQ_REMOVE(&kauth_identities
, kip
, ki_link
); 
1545                 TAILQ_INSERT_HEAD(&kauth_identities
, kip
, ki_link
); 
1551  * kauth_identity_guid_expired 
1553  * Description: Handle lazy expiration of GUID translations. 
1555  * Parameters:  kip                             kauth identity to check for 
1558  * Returns:     1                               Expired 
1562 kauth_identity_guid_expired(struct kauth_identity 
*kip
) 
1567          * Expiration time of 0 means this entry is persistent. 
1569         if (kip
->ki_guid_expiry 
== 0) 
1573         KAUTH_DEBUG("CACHE - GUID expires @ %ld now %ld", kip
->ki_guid_expiry
, tv
.tv_sec
); 
1575         return((kip
->ki_guid_expiry 
<= tv
.tv_sec
) ? 1 : 0); 
1580  * kauth_identity_ntsid_expired 
1582  * Description: Handle lazy expiration of NTSID translations. 
1584  * Parameters:  kip                             kauth identity to check for 
1587  * Returns:     1                               Expired 
1591 kauth_identity_ntsid_expired(struct kauth_identity 
*kip
) 
1596          * Expiration time of 0 means this entry is persistent. 
1598         if (kip
->ki_ntsid_expiry 
== 0) 
1602         KAUTH_DEBUG("CACHE - NTSID expires @ %ld now %ld", kip
->ki_ntsid_expiry
, tv
.tv_sec
); 
1604         return((kip
->ki_ntsid_expiry 
<= tv
.tv_sec
) ? 1 : 0); 
1608  * kauth_identity_groups_expired 
1610  * Description: Handle lazy expiration of supplemental group translations. 
1612  * Parameters:  kip                             kauth identity to check for 
1615  * Returns:     1                               Expired 
1619 kauth_identity_groups_expired(struct kauth_identity 
*kip
) 
1624          * Expiration time of 0 means this entry is persistent. 
1626         if (kip
->ki_groups_expiry 
== 0) 
1630         KAUTH_DEBUG("CACHE - GROUPS expires @ %ld now %ld\n", kip
->ki_groups_expiry
, tv
.tv_sec
); 
1632         return((kip
->ki_groups_expiry 
<= tv
.tv_sec
) ? 1 : 0); 
1636  * kauth_identity_find_uid 
1638  * Description: Search for an entry by UID 
1640  * Parameters:  uid                             UID to find 
1641  *              kir                             Pointer to return area 
1642  *              getname                         Name buffer, if ki_name wanted 
1648  *              *klr                            Modified, if found 
1651 kauth_identity_find_uid(uid_t uid
, struct kauth_identity 
*kir
, char *getname
) 
1653         struct kauth_identity 
*kip
; 
1655         KAUTH_IDENTITY_LOCK(); 
1656         TAILQ_FOREACH(kip
, &kauth_identities
, ki_link
) { 
1657                 if ((kip
->ki_valid 
& KI_VALID_UID
) && (uid 
== kip
->ki_uid
)) { 
1658                         kauth_identity_lru(kip
); 
1659                         /* Copy via structure assignment */ 
1661                         /* If a name is wanted and one exists, copy it out */ 
1662                         if (getname 
!= NULL 
&& (kip
->ki_valid 
& (KI_VALID_PWNAM 
| KI_VALID_GRNAM
))) 
1663                                 strlcpy(getname
, kip
->ki_name
, MAXPATHLEN
); 
1667         KAUTH_IDENTITY_UNLOCK(); 
1668         return((kip 
== NULL
) ? ENOENT 
: 0); 
1673  * kauth_identity_find_gid 
1675  * Description: Search for an entry by GID 
1677  * Parameters:  gid                             GID to find 
1678  *              kir                             Pointer to return area 
1679  *              getname                         Name buffer, if ki_name wanted 
1685  *              *klr                            Modified, if found 
1688 kauth_identity_find_gid(uid_t gid
, struct kauth_identity 
*kir
, char *getname
) 
1690         struct kauth_identity 
*kip
; 
1692         KAUTH_IDENTITY_LOCK(); 
1693         TAILQ_FOREACH(kip
, &kauth_identities
, ki_link
) { 
1694                 if ((kip
->ki_valid 
& KI_VALID_GID
) && (gid 
== kip
->ki_gid
)) { 
1695                         kauth_identity_lru(kip
); 
1696                         /* Copy via structure assignment */ 
1698                         /* If a name is wanted and one exists, copy it out */ 
1699                         if (getname 
!= NULL 
&& (kip
->ki_valid 
& (KI_VALID_PWNAM 
| KI_VALID_GRNAM
))) 
1700                                 strlcpy(getname
, kip
->ki_name
, MAXPATHLEN
); 
1704         KAUTH_IDENTITY_UNLOCK(); 
1705         return((kip 
== NULL
) ? ENOENT 
: 0); 
1710  * kauth_identity_find_guid 
1712  * Description: Search for an entry by GUID 
1714  * Parameters:  guidp                           Pointer to GUID to find 
1715  *              kir                             Pointer to return area 
1716  *              getname                         Name buffer, if ki_name wanted 
1722  *              *klr                            Modified, if found 
1724  * Note:        The association may be expired, in which case the caller 
1725  *              may elect to call out to userland to revalidate. 
1728 kauth_identity_find_guid(guid_t 
*guidp
, struct kauth_identity 
*kir
, char *getname
) 
1730         struct kauth_identity 
*kip
; 
1732         KAUTH_IDENTITY_LOCK(); 
1733         TAILQ_FOREACH(kip
, &kauth_identities
, ki_link
) { 
1734                 if ((kip
->ki_valid 
& KI_VALID_GUID
) && (kauth_guid_equal(guidp
, &kip
->ki_guid
))) { 
1735                         kauth_identity_lru(kip
); 
1736                         /* Copy via structure assignment */ 
1738                         /* If a name is wanted and one exists, copy it out */ 
1739                         if (getname 
!= NULL 
&& (kip
->ki_valid 
& (KI_VALID_PWNAM 
| KI_VALID_GRNAM
))) 
1740                                 strlcpy(getname
, kip
->ki_name
, MAXPATHLEN
); 
1744         KAUTH_IDENTITY_UNLOCK(); 
1745         return((kip 
== NULL
) ? ENOENT 
: 0); 
1749  * kauth_identity_find_nam 
1751  * Description: Search for an entry by name 
1753  * Parameters:  name                            Pointer to name to find 
1754  *              valid                           KI_VALID_PWNAM or KI_VALID_GRNAM 
1755  *              kir                             Pointer to return area 
1761  *              *klr                            Modified, if found 
1764 kauth_identity_find_nam(char *name
, int valid
, struct kauth_identity 
*kir
) 
1766         struct kauth_identity 
*kip
; 
1768         KAUTH_IDENTITY_LOCK(); 
1769         TAILQ_FOREACH(kip
, &kauth_identities
, ki_link
) { 
1770                 if ((kip
->ki_valid 
& valid
) && !strcmp(name
, kip
->ki_name
)) { 
1771                         kauth_identity_lru(kip
); 
1772                         /* Copy via structure assignment */ 
1777         KAUTH_IDENTITY_UNLOCK(); 
1778         return((kip 
== NULL
) ? ENOENT 
: 0); 
1783  * kauth_identity_find_ntsid 
1785  * Description: Search for an entry by NTSID 
1787  * Parameters:  ntsid                           Pointer to NTSID to find 
1788  *              kir                             Pointer to return area 
1789  *              getname                         Name buffer, if ki_name wanted 
1795  *              *klr                            Modified, if found 
1797  * Note:        The association may be expired, in which case the caller 
1798  *              may elect to call out to userland to revalidate. 
1801 kauth_identity_find_ntsid(ntsid_t 
*ntsid
, struct kauth_identity 
*kir
, char *getname
) 
1803         struct kauth_identity 
*kip
; 
1805         KAUTH_IDENTITY_LOCK(); 
1806         TAILQ_FOREACH(kip
, &kauth_identities
, ki_link
) { 
1807                 if ((kip
->ki_valid 
& KI_VALID_NTSID
) && (kauth_ntsid_equal(ntsid
, &kip
->ki_ntsid
))) { 
1808                         kauth_identity_lru(kip
); 
1809                         /* Copy via structure assignment */ 
1811                         /* If a name is wanted and one exists, copy it out */ 
1812                         if (getname 
!= NULL 
&& (kip
->ki_valid 
& (KI_VALID_PWNAM 
| KI_VALID_GRNAM
))) 
1813                                 strlcpy(getname
, kip
->ki_name
, MAXPATHLEN
); 
1817         KAUTH_IDENTITY_UNLOCK(); 
1818         return((kip 
== NULL
) ? ENOENT 
: 0); 
1820 #endif  /* CONFIG_EXT_RESOLVER */ 
1826 guid_t kauth_null_guid
; 
1832  * Description: Determine the equality of two GUIDs 
1834  * Parameters:  guid1                           Pointer to first GUID 
1835  *              guid2                           Pointer to second GUID 
1837  * Returns:     0                               If GUIDs are unequal 
1838  *              !0                              If GUIDs are equal 
1841 kauth_guid_equal(guid_t 
*guid1
, guid_t 
*guid2
) 
1843         return(bcmp(guid1
, guid2
, sizeof(*guid1
)) == 0); 
1848  * kauth_wellknown_guid 
1850  * Description: Determine if a GUID is a well-known GUID 
1852  * Parameters:  guid                            Pointer to GUID to check 
1854  * Returns:     KAUTH_WKG_NOT                   Not a well known GUID 
1855  *              KAUTH_WKG_EVERYBODY             "Everybody" 
1856  *              KAUTH_WKG_NOBODY                "Nobody" 
1857  *              KAUTH_WKG_OWNER                 "Other" 
1858  *              KAUTH_WKG_GROUP                 "Group" 
1861 kauth_wellknown_guid(guid_t 
*guid
) 
1863         static char     fingerprint
[] = {0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef}; 
1866          * All WKGs begin with the same 12 bytes. 
1868         if (bcmp((void *)guid
, fingerprint
, 12) == 0) { 
1870                  * The final 4 bytes are our code (in network byte order). 
1872                 code 
= OSSwapHostToBigInt32(*(uint32_t *)&guid
->g_guid
[12]); 
1875                         return(KAUTH_WKG_EVERYBODY
); 
1877                         return(KAUTH_WKG_NOBODY
); 
1879                         return(KAUTH_WKG_OWNER
); 
1881                         return(KAUTH_WKG_GROUP
); 
1884         return(KAUTH_WKG_NOT
); 
1891  * Description: Determine the equality of two NTSIDs (NT Security Identifiers)  
1893  * Parameters:  sid1                            Pointer to first NTSID 
1894  *              sid2                            Pointer to second NTSID 
1896  * Returns:     0                               If GUIDs are unequal 
1897  *              !0                              If GUIDs are equal 
1900 kauth_ntsid_equal(ntsid_t 
*sid1
, ntsid_t 
*sid2
) 
1902         /* check sizes for equality, also sanity-check size while we're at it */ 
1903         if ((KAUTH_NTSID_SIZE(sid1
) == KAUTH_NTSID_SIZE(sid2
)) && 
1904             (KAUTH_NTSID_SIZE(sid1
) <= sizeof(*sid1
)) && 
1905             bcmp(sid1
, sid2
, KAUTH_NTSID_SIZE(sid1
)) == 0) 
1914  * We support four tokens representing identity: 
1915  *  - Credential reference 
1918  *  - NT security identifier 
1920  * Of these, the UID is the ubiquitous identifier; cross-referencing should 
1927  * kauth_cred_change_egid 
1929  * Description: Set EGID by changing the first element of cr_groups for the 
1930  *              passed credential; if the new EGID exists in the list of 
1931  *              groups already, then rotate the old EGID into its position, 
1932  *              otherwise replace it 
1934  * Parameters:  cred                    Pointer to the credential to modify 
1935  *              new_egid                The new EGID to set 
1937  * Returns:     0                       The egid did not displace a member of 
1938  *                                      the supplementary group list 
1939  *              1                       The egid being set displaced a member 
1940  *                                      of the supplementary groups list 
1942  * Note:        Utility function; internal use only because of locking. 
1944  *              This function operates on the credential passed; the caller 
1945  *              must operate either on a newly allocated credential (one for 
1946  *              which there is no hash cache reference and no externally 
1947  *              visible pointer reference), or a template credential. 
1950 kauth_cred_change_egid(kauth_cred_t cred
, gid_t new_egid
) 
1956 #endif  /* radar_4600026 */ 
1957         gid_t   old_egid 
= kauth_cred_getgid(cred
); 
1958         posix_cred_t pcred 
= posix_cred_get(cred
); 
1960         /* Ignoring the first entry, scan for a match for the new egid */ 
1961         for (i 
= 1; i 
< pcred
->cr_ngroups
; i
++) { 
1963                  * If we find a match, swap them so we don't lose overall 
1966                 if (pcred
->cr_groups
[i
] == new_egid
) { 
1967                         pcred
->cr_groups
[i
] = old_egid
; 
1968                         DEBUG_CRED_CHANGE("kauth_cred_change_egid: unset displaced\n"); 
1975 #error Fix radar 4600026 first!!! 
1978 This is correct for memberd behaviour, but incorrect for POSIX; to address 
1979 this, we would need to automatically opt-out any SUID/SGID binary, and force 
1980 it to use initgroups to opt back in.  We take the approach of considering it 
1981 opt'ed out in any group of 16 displacement instead, since it's a much more 
1982 conservative approach (i.e. less likely to cause things to break). 
1986          * If we displaced a member of the supplementary groups list of the 
1987          * credential, and we have not opted out of memberd, then if memberd 
1988          * says that the credential is a member of the group, then it has not 
1989          * actually been displaced. 
1991          * NB:  This is typically a cold code path. 
1993         if (displaced 
&& !(pcred
->cr_flags 
& CRF_NOMEMBERD
) && 
1994             kauth_cred_ismember_gid(cred
, new_egid
, &is_member
) == 0 && 
1997                 DEBUG_CRED_CHANGE("kauth_cred_change_egid: reset displaced\n"); 
1999 #endif  /* radar_4600026 */ 
2001         /* set the new EGID into the old spot */ 
2002         pcred
->cr_groups
[0] = new_egid
; 
2011  * Description: Fetch UID from credential 
2013  * Parameters:  cred                            Credential to examine 
2015  * Returns:     (uid_t)                         UID associated with credential 
2018 kauth_cred_getuid(kauth_cred_t cred
) 
2020         NULLCRED_CHECK(cred
); 
2021         return(posix_cred_get(cred
)->cr_uid
); 
2026  * kauth_cred_getruid 
2028  * Description: Fetch RUID from credential 
2030  * Parameters:  cred                            Credential to examine 
2032  * Returns:     (uid_t)                         RUID associated with credential 
2035 kauth_cred_getruid(kauth_cred_t cred
) 
2037         NULLCRED_CHECK(cred
); 
2038         return(posix_cred_get(cred
)->cr_ruid
); 
2043  * kauth_cred_getsvuid 
2045  * Description: Fetch SVUID from credential 
2047  * Parameters:  cred                            Credential to examine 
2049  * Returns:     (uid_t)                         SVUID associated with credential 
2052 kauth_cred_getsvuid(kauth_cred_t cred
) 
2054         NULLCRED_CHECK(cred
); 
2055         return(posix_cred_get(cred
)->cr_svuid
); 
2062  * Description: Fetch GID from credential 
2064  * Parameters:  cred                            Credential to examine 
2066  * Returns:     (gid_t)                         GID associated with credential 
2069 kauth_cred_getgid(kauth_cred_t cred
) 
2071         NULLCRED_CHECK(cred
); 
2072         return(posix_cred_get(cred
)->cr_gid
); 
2077  * kauth_cred_getrgid 
2079  * Description: Fetch RGID from credential 
2081  * Parameters:  cred                            Credential to examine 
2083  * Returns:     (gid_t)                         RGID associated with credential 
2086 kauth_cred_getrgid(kauth_cred_t cred
) 
2088         NULLCRED_CHECK(cred
); 
2089         return(posix_cred_get(cred
)->cr_rgid
); 
2094  * kauth_cred_getsvgid 
2096  * Description: Fetch SVGID from credential 
2098  * Parameters:  cred                            Credential to examine 
2100  * Returns:     (gid_t)                         SVGID associated with credential 
2103 kauth_cred_getsvgid(kauth_cred_t cred
) 
2105         NULLCRED_CHECK(cred
); 
2106         return(posix_cred_get(cred
)->cr_svgid
); 
2110 static int      kauth_cred_cache_lookup(int from
, int to
, void *src
, void *dst
); 
2112 #if CONFIG_EXT_RESOLVER == 0 
2114  * If there's no resolver, only support a subset of the kauth_cred_x2y() lookups. 
2117 kauth_cred_cache_lookup(int from
, int to
, void *src
, void *dst
) 
2119         /* NB: These must match the definitions used by Libinfo's mbr_identifier_translate(). */ 
2120         static const uuid_t _user_compat_prefix 
= {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd, 0xcc, 0xcc, 0xbb, 0xbb, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00}; 
2121         static const uuid_t _group_compat_prefix 
= {0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0x00, 0x00, 0x00, 0x00}; 
2122 #define COMPAT_PREFIX_LEN       (sizeof(uuid_t) - sizeof(id_t)) 
2127         case KI_VALID_UID
: { 
2128                 id_t uid 
= htonl(*(id_t 
*)src
); 
2130                 if (to 
== KI_VALID_GUID
) { 
2132                         memcpy(uu
, _user_compat_prefix
, sizeof(_user_compat_prefix
)); 
2133                         memcpy(&uu
[COMPAT_PREFIX_LEN
], &uid
, sizeof(uid
)); 
2138         case KI_VALID_GID
: { 
2139                 id_t gid 
= htonl(*(id_t 
*)src
); 
2141                 if (to 
== KI_VALID_GUID
) { 
2143                         memcpy(uu
, _group_compat_prefix
, sizeof(_group_compat_prefix
)); 
2144                         memcpy(&uu
[COMPAT_PREFIX_LEN
], &gid
, sizeof(gid
)); 
2149         case KI_VALID_GUID
: { 
2150                 const uint8_t *uu 
= src
; 
2152                 if (to 
== KI_VALID_UID
) { 
2153                         if (memcmp(uu
, _user_compat_prefix
, COMPAT_PREFIX_LEN
) == 0) { 
2155                                 memcpy(&uid
, &uu
[COMPAT_PREFIX_LEN
], sizeof(uid
)); 
2156                                 *(id_t 
*)dst 
= ntohl(uid
); 
2159                 } else if (to 
== KI_VALID_GID
) { 
2160                         if (memcmp(uu
, _group_compat_prefix
, COMPAT_PREFIX_LEN
) == 0) { 
2162                                 memcpy(&gid
, &uu
[COMPAT_PREFIX_LEN
], sizeof(gid
)); 
2163                                 *(id_t 
*)dst 
= ntohl(gid
); 
2170                 /* NOT IMPLEMENTED */ 
2177 #if defined(CONFIG_EXT_RESOLVER) && (CONFIG_EXT_RESOLVER) 
2179  * Structure to hold supplemental groups. Used for impedance matching with  
2180  * kauth_cred_cache_lookup below. 
2188  * kauth_cred_uid2groups 
2190  * Description: Fetch supplemental GROUPS from UID 
2192  * Parameters:  uid                             UID to examine 
2193  *              groups                          pointer to an array of gid_ts 
2194  *              gcount                          pointer to the number of groups wanted/returned 
2196  * Returns:     0                               Success 
2197  *      kauth_cred_cache_lookup:EINVAL 
2200  *              *groups                         Modified, if successful 
2201  *              *gcount                         Modified, if successful 
2205 kauth_cred_uid2groups(uid_t 
*uid
, gid_t 
*groups
, int *gcount
) 
2209         struct supgroups supgroups
; 
2210         supgroups
.count 
= gcount
; 
2211         supgroups
.groups 
= groups
; 
2213         rv 
= kauth_cred_cache_lookup(KI_VALID_UID
, KI_VALID_GROUPS
, uid
, &supgroups
); 
2220  * kauth_cred_guid2pwnam 
2222  * Description: Fetch PWNAM from GUID 
2224  * Parameters:  guidp                           Pointer to GUID to examine 
2225  *              pwnam                           Pointer to user@domain buffer 
2227  * Returns:     0                               Success 
2228  *      kauth_cred_cache_lookup:EINVAL 
2231  *              *pwnam                          Modified, if successful 
2233  * Notes:       pwnam is assumed to point to a buffer of MAXPATHLEN in size 
2236 kauth_cred_guid2pwnam(guid_t 
*guidp
, char *pwnam
) 
2238         return(kauth_cred_cache_lookup(KI_VALID_GUID
, KI_VALID_PWNAM
, guidp
, pwnam
)); 
2243  * kauth_cred_guid2grnam 
2245  * Description: Fetch GRNAM from GUID 
2247  * Parameters:  guidp                           Pointer to GUID to examine 
2248  *              grnam                           Pointer to group@domain buffer 
2250  * Returns:     0                               Success 
2251  *      kauth_cred_cache_lookup:EINVAL 
2254  *              *grnam                          Modified, if successful 
2256  * Notes:       grnam is assumed to point to a buffer of MAXPATHLEN in size 
2259 kauth_cred_guid2grnam(guid_t 
*guidp
, char *grnam
) 
2261         return(kauth_cred_cache_lookup(KI_VALID_GUID
, KI_VALID_GRNAM
, guidp
, grnam
)); 
2266  * kauth_cred_pwnam2guid 
2268  * Description: Fetch PWNAM from GUID 
2270  * Parameters:  pwnam                           String containing user@domain 
2271  *              guidp                           Pointer to buffer for GUID 
2273  * Returns:     0                               Success 
2274  *      kauth_cred_cache_lookup:EINVAL 
2277  *              *guidp                          Modified, if successful 
2279  * Notes:       pwnam should not point to a request larger than MAXPATHLEN 
2280  *              bytes in size, including the NUL termination of the string. 
2283 kauth_cred_pwnam2guid(char *pwnam
, guid_t 
*guidp
) 
2285         return(kauth_cred_cache_lookup(KI_VALID_PWNAM
, KI_VALID_GUID
, pwnam
, guidp
)); 
2290  * kauth_cred_grnam2guid 
2292  * Description: Fetch GRNAM from GUID 
2294  * Parameters:  grnam                           String containing group@domain 
2295  *              guidp                           Pointer to buffer for GUID 
2297  * Returns:     0                               Success 
2298  *      kauth_cred_cache_lookup:EINVAL 
2301  *              *guidp                          Modified, if successful 
2303  * Notes:       grnam should not point to a request larger than MAXPATHLEN 
2304  *              bytes in size, including the NUL termination of the string. 
2307 kauth_cred_grnam2guid(char *grnam
, guid_t 
*guidp
) 
2309         return(kauth_cred_cache_lookup(KI_VALID_GRNAM
, KI_VALID_GUID
, grnam
, guidp
)); 
2314  * kauth_cred_guid2uid 
2316  * Description: Fetch UID from GUID 
2318  * Parameters:  guidp                           Pointer to GUID to examine 
2319  *              uidp                            Pointer to buffer for UID 
2321  * Returns:     0                               Success 
2322  *      kauth_cred_cache_lookup:EINVAL 
2325  *              *uidp                           Modified, if successful 
2328 kauth_cred_guid2uid(guid_t 
*guidp
, uid_t 
*uidp
) 
2330         return(kauth_cred_cache_lookup(KI_VALID_GUID
, KI_VALID_UID
, guidp
, uidp
)); 
2335  * kauth_cred_guid2gid 
2337  * Description: Fetch GID from GUID 
2339  * Parameters:  guidp                           Pointer to GUID to examine 
2340  *              gidp                            Pointer to buffer for GID 
2342  * Returns:     0                               Success 
2343  *      kauth_cred_cache_lookup:EINVAL 
2346  *              *gidp                           Modified, if successful 
2349 kauth_cred_guid2gid(guid_t 
*guidp
, gid_t 
*gidp
) 
2351         return(kauth_cred_cache_lookup(KI_VALID_GUID
, KI_VALID_GID
, guidp
, gidp
)); 
2355  * kauth_cred_nfs4domain2dsnode 
2357  * Description: Fetch dsnode from nfs4domain 
2359  * Parameters:  nfs4domain                      Pointer to a string nfs4 domain 
2360  *              dsnode                          Pointer to buffer for dsnode 
2362  * Returns:     0                               Success 
2363  *              ENOENT                          For now just a stub that always fails 
2366  *              *dsnode                         Modified, if successuful 
2369 kauth_cred_nfs4domain2dsnode(__unused 
char *nfs4domain
, __unused 
char *dsnode
) 
2375  * kauth_cred_dsnode2nfs4domain 
2377  * Description: Fetch nfs4domain from dsnode 
2379  * Parameters:  nfs4domain                      Pointer to  string dsnode 
2380  *              dsnode                          Pointer to buffer for nfs4domain 
2382  * Returns:     0                               Success 
2383  *              ENOENT                          For now just a stub that always fails 
2386  *              *nfs4domain                     Modified, if successuful 
2389 kauth_cred_dsnode2nfs4domain(__unused 
char *dsnode
, __unused 
char *nfs4domain
) 
2395  * kauth_cred_ntsid2uid 
2397  * Description: Fetch UID from NTSID 
2399  * Parameters:  sidp                            Pointer to NTSID to examine 
2400  *              uidp                            Pointer to buffer for UID 
2402  * Returns:     0                               Success 
2403  *      kauth_cred_cache_lookup:EINVAL 
2406  *              *uidp                           Modified, if successful 
2409 kauth_cred_ntsid2uid(ntsid_t 
*sidp
, uid_t 
*uidp
) 
2411         return(kauth_cred_cache_lookup(KI_VALID_NTSID
, KI_VALID_UID
, sidp
, uidp
)); 
2416  * kauth_cred_ntsid2gid 
2418  * Description: Fetch GID from NTSID 
2420  * Parameters:  sidp                            Pointer to NTSID to examine 
2421  *              gidp                            Pointer to buffer for GID 
2423  * Returns:     0                               Success 
2424  *      kauth_cred_cache_lookup:EINVAL 
2427  *              *gidp                           Modified, if successful 
2430 kauth_cred_ntsid2gid(ntsid_t 
*sidp
, gid_t 
*gidp
) 
2432         return(kauth_cred_cache_lookup(KI_VALID_NTSID
, KI_VALID_GID
, sidp
, gidp
)); 
2437  * kauth_cred_ntsid2guid 
2439  * Description: Fetch GUID from NTSID 
2441  * Parameters:  sidp                            Pointer to NTSID to examine 
2442  *              guidp                           Pointer to buffer for GUID 
2444  * Returns:     0                               Success 
2445  *      kauth_cred_cache_lookup:EINVAL 
2448  *              *guidp                          Modified, if successful 
2451 kauth_cred_ntsid2guid(ntsid_t 
*sidp
, guid_t 
*guidp
) 
2453         return(kauth_cred_cache_lookup(KI_VALID_NTSID
, KI_VALID_GUID
, sidp
, guidp
)); 
2458  * kauth_cred_uid2guid 
2460  * Description: Fetch GUID from UID 
2462  * Parameters:  uid                             UID to examine 
2463  *              guidp                           Pointer to buffer for GUID 
2465  * Returns:     0                               Success 
2466  *      kauth_cred_cache_lookup:EINVAL 
2469  *              *guidp                          Modified, if successful 
2472 kauth_cred_uid2guid(uid_t uid
, guid_t 
*guidp
) 
2474         return(kauth_cred_cache_lookup(KI_VALID_UID
, KI_VALID_GUID
, &uid
, guidp
)); 
2479  * kauth_cred_getguid 
2481  * Description: Fetch GUID from credential 
2483  * Parameters:  cred                            Credential to examine 
2484  *              guidp                           Pointer to buffer for GUID 
2486  * Returns:     0                               Success 
2487  *      kauth_cred_cache_lookup:EINVAL 
2490  *              *guidp                          Modified, if successful 
2493 kauth_cred_getguid(kauth_cred_t cred
, guid_t 
*guidp
) 
2495         NULLCRED_CHECK(cred
); 
2496         return(kauth_cred_uid2guid(kauth_cred_getuid(cred
), guidp
)); 
2501  * kauth_cred_getguid 
2503  * Description: Fetch GUID from GID 
2505  * Parameters:  gid                             GID to examine 
2506  *              guidp                           Pointer to buffer for GUID 
2508  * Returns:     0                               Success 
2509  *      kauth_cred_cache_lookup:EINVAL 
2512  *              *guidp                          Modified, if successful 
2515 kauth_cred_gid2guid(gid_t gid
, guid_t 
*guidp
) 
2517         return(kauth_cred_cache_lookup(KI_VALID_GID
, KI_VALID_GUID
, &gid
, guidp
)); 
2522  * kauth_cred_uid2ntsid 
2524  * Description: Fetch NTSID from UID 
2526  * Parameters:  uid                             UID to examine 
2527  *              sidp                            Pointer to buffer for NTSID 
2529  * Returns:     0                               Success 
2530  *      kauth_cred_cache_lookup:EINVAL 
2533  *              *sidp                           Modified, if successful 
2536 kauth_cred_uid2ntsid(uid_t uid
, ntsid_t 
*sidp
) 
2538         return(kauth_cred_cache_lookup(KI_VALID_UID
, KI_VALID_NTSID
, &uid
, sidp
)); 
2543  * kauth_cred_getntsid 
2545  * Description: Fetch NTSID from credential 
2547  * Parameters:  cred                            Credential to examine 
2548  *              sidp                            Pointer to buffer for NTSID 
2550  * Returns:     0                               Success 
2551  *      kauth_cred_cache_lookup:EINVAL 
2554  *              *sidp                           Modified, if successful 
2557 kauth_cred_getntsid(kauth_cred_t cred
, ntsid_t 
*sidp
) 
2559         NULLCRED_CHECK(cred
); 
2560         return(kauth_cred_uid2ntsid(kauth_cred_getuid(cred
), sidp
)); 
2565  * kauth_cred_gid2ntsid 
2567  * Description: Fetch NTSID from GID 
2569  * Parameters:  gid                             GID to examine 
2570  *              sidp                            Pointer to buffer for NTSID 
2572  * Returns:     0                               Success 
2573  *      kauth_cred_cache_lookup:EINVAL 
2576  *              *sidp                           Modified, if successful 
2579 kauth_cred_gid2ntsid(gid_t gid
, ntsid_t 
*sidp
) 
2581         return(kauth_cred_cache_lookup(KI_VALID_GID
, KI_VALID_NTSID
, &gid
, sidp
)); 
2586  * kauth_cred_guid2ntsid 
2588  * Description: Fetch NTSID from GUID 
2590  * Parameters:  guidp                           Pointer to GUID to examine 
2591  *              sidp                            Pointer to buffer for NTSID 
2593  * Returns:     0                               Success 
2594  *      kauth_cred_cache_lookup:EINVAL 
2597  *              *sidp                           Modified, if successful 
2600 kauth_cred_guid2ntsid(guid_t 
*guidp
, ntsid_t 
*sidp
) 
2602         return(kauth_cred_cache_lookup(KI_VALID_GUID
, KI_VALID_NTSID
, guidp
, sidp
)); 
2607  * kauth_cred_cache_lookup 
2609  * Description: Lookup a translation in the cache; if one is not found, and 
2610  *              the attempt was not fatal, submit the request to the resolver 
2611  *              instead, and wait for it to complete or be aborted. 
2613  * Parameters:  from                            Identity information we have 
2614  *              to                              Identity information we want 
2615  *              src                             Pointer to buffer containing 
2616  *                                              the source identity 
2617  *              dst                             Pointer to buffer to receive 
2618  *                                              the target identity 
2620  * Returns:     0                               Success 
2621  *              EINVAL                          Unknown source identity type 
2623 #if CONFIG_EXT_RESOLVER 
2625 kauth_cred_cache_lookup(int from
, int to
, void *src
, void *dst
) 
2627         struct kauth_identity ki
; 
2628         struct kauth_identity_extlookup el
; 
2630         uint64_t extend_data 
= 0ULL; 
2631         int (* expired
)(struct kauth_identity 
*kip
); 
2632         char *namebuf 
= NULL
; 
2634         KAUTH_DEBUG("CACHE - translate %d to %d", from
, to
); 
2637          * Look for an existing cache entry for this association. 
2638          * If the entry has not expired, return the cached information. 
2639          * We do not cache user@domain translations here; they use too 
2640          * much memory to hold onto forever, and can not be updated 
2643         if (to 
== KI_VALID_PWNAM 
|| to 
== KI_VALID_GRNAM
) { 
2652                 error 
= kauth_identity_find_uid(*(uid_t 
*)src
, &ki
, namebuf
); 
2655                 error 
= kauth_identity_find_gid(*(gid_t 
*)src
, &ki
, namebuf
); 
2658                 error 
= kauth_identity_find_guid((guid_t 
*)src
, &ki
, namebuf
); 
2660         case KI_VALID_NTSID
: 
2661                 error 
= kauth_identity_find_ntsid((ntsid_t 
*)src
, &ki
, namebuf
); 
2663         case KI_VALID_PWNAM
: 
2664         case KI_VALID_GRNAM
: 
2665                 /* Names are unique in their 'from' space */ 
2666                 error 
= kauth_identity_find_nam((char *)src
, from
, &ki
); 
2671         /* If we didn't get what we're asking for. Call the resolver */ 
2672         if (!error 
&& !(to 
& ki
.ki_valid
)) 
2674         /* lookup failure or error */ 
2676                 /* any other error is fatal */ 
2677                 if (error 
!= ENOENT
) { 
2678                         /* XXX bogus check - this is not possible */ 
2679                         KAUTH_DEBUG("CACHE - cache search error %d", error
); 
2683                 /* found a valid cached entry, check expiry */ 
2686                         expired 
= kauth_identity_guid_expired
; 
2688                 case KI_VALID_NTSID
: 
2689                         expired 
= kauth_identity_ntsid_expired
; 
2691                 case KI_VALID_GROUPS
: 
2692                         expired 
= kauth_identity_groups_expired
; 
2697                                 expired 
= kauth_identity_guid_expired
; 
2699                         case KI_VALID_NTSID
: 
2700                                 expired 
= kauth_identity_ntsid_expired
; 
2708                  * If no expiry function, or not expired, we have found 
2712                         if (!expired(&ki
)) { 
2713                                 KAUTH_DEBUG("CACHE - entry valid, unexpired"); 
2714                                 expired 
= NULL
; /* must clear it is used as a flag */ 
2717                                  * We leave ki_valid set here; it contains a 
2718                                  * translation but the TTL has expired.  If we can't 
2719                                  * get a result from the resolver, we will use it as 
2720                                  * a better-than nothing alternative. 
2723                                 KAUTH_DEBUG("CACHE - expired entry found"); 
2726                         KAUTH_DEBUG("CACHE - no expiry function"); 
2730                         /* do we have a translation? */ 
2731                         if (ki
.ki_valid 
& to
) { 
2732                                 KAUTH_DEBUG("CACHE - found matching entry with valid 0x%08x", ki
.ki_valid
); 
2733                                 DTRACE_PROC4(kauth__identity__cache__hit
, int, from
, int, to
, void *, src
, void *, dst
); 
2737                                  * GUIDs and NTSIDs map to either a UID or a GID, but not both.  
2738                                  * If we went looking for a translation from GUID or NTSID and  
2739                                  * found a translation that wasn't for our desired type, then  
2740                                  * don't bother calling the resolver. We know that this  
2741                                  * GUID/NTSID can't translate to our desired type. 
2745                                 case KI_VALID_NTSID
: 
2748                                                 if ((ki
.ki_valid 
& KI_VALID_UID
)) { 
2749                                                         KAUTH_DEBUG("CACHE - unexpected entry 0x%08x & %x", ki
.ki_valid
, KI_VALID_GID
); 
2754                                                 if ((ki
.ki_valid 
& KI_VALID_GID
)) { 
2755                                                         KAUTH_DEBUG("CACHE - unexpected entry 0x%08x & %x", ki
.ki_valid
, KI_VALID_UID
); 
2767          * We failed to find a cache entry; call the resolver. 
2769          * Note:        We ask for as much non-extended data as we can get, 
2770          *              and only provide (or ask for) extended information if 
2771          *              we have a 'from' (or 'to') which requires it.  This 
2772          *              way we don't pay for the extra transfer overhead for 
2773          *              data we don't need. 
2775         bzero(&el
, sizeof(el
)); 
2776         el
.el_info_pid 
= current_proc()->p_pid
; 
2779                 el
.el_flags 
= KAUTH_EXTLOOKUP_VALID_UID
; 
2780                 el
.el_uid 
= *(uid_t 
*)src
; 
2783                 el
.el_flags 
= KAUTH_EXTLOOKUP_VALID_GID
; 
2784                 el
.el_gid 
= *(gid_t 
*)src
; 
2787                 el
.el_flags 
= KAUTH_EXTLOOKUP_VALID_UGUID 
| KAUTH_EXTLOOKUP_VALID_GGUID
; 
2788                 el
.el_uguid 
= *(guid_t 
*)src
; 
2789                 el
.el_gguid 
= *(guid_t 
*)src
; 
2791         case KI_VALID_NTSID
: 
2792                 el
.el_flags 
= KAUTH_EXTLOOKUP_VALID_USID 
| KAUTH_EXTLOOKUP_VALID_GSID
; 
2793                 el
.el_usid 
= *(ntsid_t 
*)src
; 
2794                 el
.el_gsid 
= *(ntsid_t 
*)src
; 
2796         case KI_VALID_PWNAM
: 
2797                 /* extra overhead */ 
2798                 el
.el_flags 
= KAUTH_EXTLOOKUP_VALID_PWNAM
; 
2799                 extend_data 
= CAST_USER_ADDR_T(src
); 
2801         case KI_VALID_GRNAM
: 
2802                 /* extra overhead */ 
2803                 el
.el_flags 
= KAUTH_EXTLOOKUP_VALID_GRNAM
; 
2804                 extend_data 
= CAST_USER_ADDR_T(src
); 
2810          * Here we ask for everything all at once, to avoid having to work 
2811          * out what we really want now, or might want soon. 
2813          * Asking for SID translations when we don't know we need them right 
2814          * now is going to cause excess work to be done if we're connected 
2815          * to a network that thinks it can translate them.  This list needs 
2816          * to get smaller/smarter. 
2818         el
.el_flags 
|= KAUTH_EXTLOOKUP_WANT_UID 
| KAUTH_EXTLOOKUP_WANT_GID 
| 
2819             KAUTH_EXTLOOKUP_WANT_UGUID 
| KAUTH_EXTLOOKUP_WANT_GGUID 
| 
2820             KAUTH_EXTLOOKUP_WANT_USID 
| KAUTH_EXTLOOKUP_WANT_GSID
; 
2821         if (to 
== KI_VALID_PWNAM
) { 
2822                 /* extra overhead */ 
2823                 el
.el_flags 
|= KAUTH_EXTLOOKUP_WANT_PWNAM
; 
2824                 extend_data 
= CAST_USER_ADDR_T(dst
); 
2826         if (to 
== KI_VALID_GRNAM
) { 
2827                 /* extra overhead */ 
2828                 el
.el_flags 
|= KAUTH_EXTLOOKUP_WANT_GRNAM
; 
2829                 extend_data 
= CAST_USER_ADDR_T(dst
); 
2831         if (to 
== KI_VALID_GROUPS
) { 
2832                 /* Expensive and only useful for an NFS client not using kerberos */ 
2833                 el
.el_flags 
|= KAUTH_EXTLOOKUP_WANT_SUPGRPS
; 
2834                 if (ki
.ki_valid 
& KI_VALID_GROUPS
) { 
2836                          * Copy the current supplemental groups for the resolver.  
2837                          * The resolver should check these groups first and if 
2838                          * the user (uid) is still a member it should endeavor to  
2839                          * keep them in the list. Otherwise NFS clients could get 
2840                          * changing access to server file system objects on each 
2843                         if (ki
.ki_supgrpcnt 
> NGROUPS
) { 
2844                                 panic("kauth data structure corrupted. kauth identity 0x%p with %d groups, greater than max of %d", 
2845                                         &ki
, ki
.ki_supgrpcnt
, NGROUPS
); 
2848                         el
.el_sup_grp_cnt 
= ki
.ki_supgrpcnt
; 
2850                         memcpy(el
.el_sup_groups
, ki
.ki_supgrps
, sizeof (el
.el_sup_groups
[0]) * ki
.ki_supgrpcnt
); 
2851                         /* Let the resolver know these were the previous valid groups */ 
2852                         el
.el_flags 
|= KAUTH_EXTLOOKUP_VALID_SUPGRPS
; 
2853                         KAUTH_DEBUG("GROUPS: Sending previously valid GROUPS"); 
2855                         KAUTH_DEBUG("GROUPS: no valid groups to send"); 
2859         KAUTH_DEBUG("CACHE - calling resolver for %x", el
.el_flags
); 
2861         DTRACE_PROC3(kauth__id__resolver__submitted
, int, from
, int, to
, uintptr_t, src
); 
2863         error 
= kauth_resolver_submit(&el
, extend_data
); 
2865         DTRACE_PROC2(kauth__id__resolver__returned
, int, error
, struct kauth_identity_extlookup 
*, &el
) 
2867         KAUTH_DEBUG("CACHE - resolver returned %d", error
); 
2869         /* was the external lookup successful? */ 
2872                  * Save the results from the lookup - we may have other 
2873                  * information, even if we didn't get a guid or the 
2876                  * If we came from a name, we know the extend_data is valid. 
2878                 if (from 
== KI_VALID_PWNAM
) 
2879                         el
.el_flags 
|= KAUTH_EXTLOOKUP_VALID_PWNAM
; 
2880                 else if (from 
== KI_VALID_GRNAM
) 
2881                         el
.el_flags 
|= KAUTH_EXTLOOKUP_VALID_GRNAM
; 
2883                 kauth_identity_updatecache(&el
, &ki
, extend_data
); 
2886                  * Check to see if we have a valid cache entry 
2887                  * originating from the result. 
2889                 if (!(ki
.ki_valid 
& to
)) { 
2897          * Copy from the appropriate struct kauth_identity cache entry 
2898          * structure into the destination buffer area. 
2902                 *(uid_t 
*)dst 
= ki
.ki_uid
; 
2905                 *(gid_t 
*)dst 
= ki
.ki_gid
; 
2908                 *(guid_t 
*)dst 
= ki
.ki_guid
; 
2910         case KI_VALID_NTSID
: 
2911                 *(ntsid_t 
*)dst 
= ki
.ki_ntsid
; 
2913         case KI_VALID_GROUPS
: { 
2914                         struct supgroups 
*gp 
= (struct supgroups 
*)dst
; 
2915                         u_int32_t limit 
= ki
.ki_supgrpcnt
; 
2918                                 limit 
= MIN(ki
.ki_supgrpcnt
, *gp
->count
); 
2922                         memcpy(gp
->groups
, ki
.ki_supgrps
, sizeof(gid_t
) * limit
); 
2925         case KI_VALID_PWNAM
: 
2926         case KI_VALID_GRNAM
: 
2927                 /* handled in kauth_resolver_complete() */ 
2932         KAUTH_DEBUG("CACHE - returned successfully"); 
2938  * Group membership cache. 
2940  * XXX the linked-list implementation here needs to be optimized. 
2946  * Description: Initialize the groups cache 
2948  * Parameters:  (void) 
2952  * Notes:       Initialize the groups cache for use; the group cache is used 
2953  *              to avoid unnecessary calls out to user space. 
2955  *              This function is called from kauth_init() in the file 
2956  *              kern_authorization.c. 
2959 kauth_groups_init(void) 
2961         TAILQ_INIT(&kauth_groups
); 
2962         kauth_groups_mtx 
= lck_mtx_alloc_init(kauth_lck_grp
, 0/*LCK_ATTR_NULL*/); 
2967  * kauth_groups_expired 
2969  * Description: Handle lazy expiration of group membership cache entries 
2971  * Parameters:  gm                              group membership entry to 
2972  *                                              check for expiration 
2974  * Returns:     1                               Expired 
2978 kauth_groups_expired(struct kauth_group_membership 
*gm
) 
2983          * Expiration time of 0 means this entry is persistent. 
2985         if (gm
->gm_expiry 
== 0) 
2990         return((gm
->gm_expiry 
<= tv
.tv_sec
) ? 1 : 0); 
2997  * Description: Promote the entry to the head of the LRU, assumes the cache 
3000  * Parameters:  kip                             group membership entry to move 
3001  *                                              to the head of the LRU list, 
3002  *                                              if it's not already there 
3006  * Notes:       This is called even if the entry has expired; typically an 
3007  *              expired entry that's been looked up is about to be revalidated, 
3008  *              and having it closer to the head of the LRU means finding it 
3009  *              quickly again when the revalidation comes through. 
3012 kauth_groups_lru(struct kauth_group_membership 
*gm
) 
3014         if (gm 
!= TAILQ_FIRST(&kauth_groups
)) { 
3015                 TAILQ_REMOVE(&kauth_groups
, gm
, gm_link
); 
3016                 TAILQ_INSERT_HEAD(&kauth_groups
, gm
, gm_link
); 
3022  * kauth_groups_updatecache 
3024  * Description: Given a lookup result, add any group cache associations that 
3025  *              we don't currently have. 
3027  * Parameters:  elp                             External lookup result from 
3028  *                                              user space daemon to kernel 
3029  *              rkip                            pointer to returned kauth 
3035 kauth_groups_updatecache(struct kauth_identity_extlookup 
*el
) 
3037         struct kauth_group_membership 
*gm
; 
3040         /* need a valid response if we are to cache anything */ 
3042                 (KAUTH_EXTLOOKUP_VALID_UID 
| KAUTH_EXTLOOKUP_VALID_GID 
| KAUTH_EXTLOOKUP_VALID_MEMBERSHIP
)) != 
3043             (KAUTH_EXTLOOKUP_VALID_UID 
| KAUTH_EXTLOOKUP_VALID_GID 
| KAUTH_EXTLOOKUP_VALID_MEMBERSHIP
)) 
3049          * Search for an existing record for this association before inserting 
3050          * a new one; if we find one, update it instead of creating a new one 
3052         KAUTH_GROUPS_LOCK(); 
3053         TAILQ_FOREACH(gm
, &kauth_groups
, gm_link
) { 
3054                 if ((el
->el_uid 
== gm
->gm_uid
) && 
3055                     (el
->el_gid 
== gm
->gm_gid
)) { 
3056                         if (el
->el_flags 
& KAUTH_EXTLOOKUP_ISMEMBER
) { 
3057                                 gm
->gm_flags 
|= KAUTH_GROUP_ISMEMBER
; 
3059                                 gm
->gm_flags 
&= ~KAUTH_GROUP_ISMEMBER
; 
3061                         gm
->gm_expiry 
= (el
->el_member_valid
) ? el
->el_member_valid 
+ tv
.tv_sec 
: 0; 
3062                         kauth_groups_lru(gm
); 
3066         KAUTH_GROUPS_UNLOCK(); 
3068         /* if we found an entry to update, stop here */ 
3072         /* allocate a new record */ 
3073         MALLOC(gm
, struct kauth_group_membership 
*, sizeof(*gm
), M_KAUTH
, M_WAITOK
); 
3075                 gm
->gm_uid 
= el
->el_uid
; 
3076                 gm
->gm_gid 
= el
->el_gid
; 
3077                 if (el
->el_flags 
& KAUTH_EXTLOOKUP_ISMEMBER
) { 
3078                         gm
->gm_flags 
|= KAUTH_GROUP_ISMEMBER
; 
3080                         gm
->gm_flags 
&= ~KAUTH_GROUP_ISMEMBER
; 
3082                 gm
->gm_expiry 
= (el
->el_member_valid
) ? el
->el_member_valid 
+ tv
.tv_sec 
: 0; 
3086          * Insert the new entry.  Note that it's possible to race ourselves 
3087          * here and end up with duplicate entries in the list.  Wasteful, but 
3088          * harmless since the first into the list will never be looked up, 
3089          * and thus will eventually just fall off the end. 
3091         KAUTH_GROUPS_LOCK(); 
3092         TAILQ_INSERT_HEAD(&kauth_groups
, gm
, gm_link
); 
3093         if (++kauth_groups_count 
> kauth_groups_cachemax
) { 
3094                 gm 
= TAILQ_LAST(&kauth_groups
, kauth_groups_head
); 
3095                 TAILQ_REMOVE(&kauth_groups
, gm
, gm_link
); 
3096                 kauth_groups_count
--; 
3100         KAUTH_GROUPS_UNLOCK(); 
3102         /* free expired cache entry */ 
3108  * Trim older entries from the group membership cache. 
3110  * Must be called with the group cache lock held. 
3113 kauth_groups_trimcache(int new_size
) { 
3114         struct kauth_group_membership 
*gm
; 
3116         lck_mtx_assert(kauth_groups_mtx
, LCK_MTX_ASSERT_OWNED
); 
3118         while (kauth_groups_count 
> new_size
) { 
3119                 gm 
= TAILQ_LAST(&kauth_groups
, kauth_groups_head
); 
3120                 TAILQ_REMOVE(&kauth_groups
, gm
, gm_link
); 
3121                 kauth_groups_count
--; 
3125 #endif  /* CONFIG_EXT_RESOLVER */ 
3128  * Group membership KPI 
3132  * kauth_cred_ismember_gid 
3134  * Description: Given a credential and a GID, determine if the GID is a member 
3135  *              of one of the supplementary groups associated with the given 
3138  * Parameters:  cred                            Credential to check in 
3139  *              gid                             GID to check for membership 
3140  *              resultp                         Pointer to int to contain the 
3141  *                                              result of the call 
3143  * Returns:     0                               Success 
3144  *              ENOENT                          Could not perform lookup 
3145  *      kauth_resolver_submit:EWOULDBLOCK 
3146  *      kauth_resolver_submit:EINTR 
3147  *      kauth_resolver_submit:ENOMEM 
3148  *      kauth_resolver_submit:ENOENT            User space daemon did not vend 
3150  *      kauth_resolver_submit:???               Unlikely error from user space 
3153  *              *resultp (modified)     1       Is member 
3156  * Notes:       This function guarantees not to modify resultp when returning 
3159  *              This function effectively checks the EGID as well, since the 
3160  *              EGID is cr_groups[0] as an implementation detail. 
3163 kauth_cred_ismember_gid(kauth_cred_t cred
, gid_t gid
, int *resultp
) 
3165         posix_cred_t pcred 
= posix_cred_get(cred
); 
3169          * Check the per-credential list of override groups. 
3171          * We can conditionalise this on cred->cr_gmuid == KAUTH_UID_NONE since 
3172          * the cache should be used for that case. 
3174         for (i 
= 0; i 
< pcred
->cr_ngroups
; i
++) { 
3175                 if (gid 
== pcred
->cr_groups
[i
]) { 
3182          * If we don't have a UID for group membership checks, the in-cred list 
3183          * was authoritative and we can stop here. 
3185         if (pcred
->cr_gmuid 
== KAUTH_UID_NONE
) { 
3190 #if CONFIG_EXT_RESOLVER 
3191         struct kauth_group_membership 
*gm
; 
3192         struct kauth_identity_extlookup el
; 
3196          * If the resolver hasn't checked in yet, we are early in the boot 
3197          * phase and the local group list is complete and authoritative. 
3199         if (!kauth_resolver_registered
) { 
3205         /* XXX check supplementary groups */ 
3206         /* XXX check whiteout groups */ 
3207         /* XXX nesting of supplementary/whiteout groups? */ 
3210          * Check the group cache. 
3212         KAUTH_GROUPS_LOCK(); 
3213         TAILQ_FOREACH(gm
, &kauth_groups
, gm_link
) { 
3214                 if ((gm
->gm_uid 
== pcred
->cr_gmuid
) && (gm
->gm_gid 
== gid
) && !kauth_groups_expired(gm
)) { 
3215                         kauth_groups_lru(gm
); 
3220         /* did we find a membership entry? */ 
3222                 *resultp 
= (gm
->gm_flags 
& KAUTH_GROUP_ISMEMBER
) ? 1 : 0; 
3223         KAUTH_GROUPS_UNLOCK(); 
3225         /* if we did, we can return now */ 
3227                 DTRACE_PROC2(kauth__group__cache__hit
, int, pcred
->cr_gmuid
, int, gid
); 
3231         /* nothing in the cache, need to go to userland */ 
3232         bzero(&el
, sizeof(el
)); 
3233         el
.el_info_pid 
= current_proc()->p_pid
; 
3234         el
.el_flags 
= KAUTH_EXTLOOKUP_VALID_UID 
| KAUTH_EXTLOOKUP_VALID_GID 
| KAUTH_EXTLOOKUP_WANT_MEMBERSHIP
; 
3235         el
.el_uid 
= pcred
->cr_gmuid
; 
3237         el
.el_member_valid 
= 0;         /* XXX set by resolver? */ 
3239         DTRACE_PROC2(kauth__group__resolver__submitted
, int, el
.el_uid
, int, el
.el_gid
); 
3241         error 
= kauth_resolver_submit(&el
, 0ULL); 
3243         DTRACE_PROC2(kauth__group__resolver__returned
, int, error
, int, el
.el_flags
); 
3247         /* save the results from the lookup */ 
3248         kauth_groups_updatecache(&el
); 
3250         /* if we successfully ascertained membership, report */ 
3251         if (el
.el_flags 
& KAUTH_EXTLOOKUP_VALID_MEMBERSHIP
) { 
3252                 *resultp 
= (el
.el_flags 
& KAUTH_EXTLOOKUP_ISMEMBER
) ? 1 : 0; 
3264  * kauth_cred_ismember_guid 
3266  * Description: Determine whether the supplied credential is a member of the 
3267  *              group nominated by GUID. 
3269  * Parameters:  cred                            Credential to check in 
3270  *              guidp                           Pointer to GUID whose group 
3271  *                                              we are testing for membership 
3272  *              resultp                         Pointer to int to contain the 
3273  *                                              result of the call 
3275  * Returns:     0                               Success 
3276  *      kauth_cred_guid2gid:EINVAL 
3277  *      kauth_cred_ismember_gid:ENOENT 
3278  *      kauth_resolver_submit:ENOENT            User space daemon did not vend 
3280  *      kauth_cred_ismember_gid:EWOULDBLOCK 
3281  *      kauth_cred_ismember_gid:EINTR 
3282  *      kauth_cred_ismember_gid:ENOMEM 
3283  *      kauth_cred_ismember_gid:???             Unlikely error from user space 
3286  *              *resultp (modified)     1       Is member 
3290 kauth_cred_ismember_guid(__unused kauth_cred_t cred
, guid_t 
*guidp
, int *resultp
) 
3294         switch (kauth_wellknown_guid(guidp
)) { 
3295         case KAUTH_WKG_NOBODY
: 
3298         case KAUTH_WKG_EVERYBODY
: 
3304 #if CONFIG_EXT_RESOLVER 
3305                 struct kauth_identity ki
; 
3308                  * Grovel the identity cache looking for this GUID. 
3309                  * If we find it, and it is for a user record, return 
3310                  * false because it's not a group. 
3312                  * This is necessary because we don't have -ve caching 
3313                  * of group memberships, and we really want to avoid 
3314                  * calling out to the resolver if at all possible. 
3316                  * Because we're called by the ACL evaluator, and the 
3317                  * ACL evaluator is likely to encounter ACEs for users, 
3318                  * this is expected to be a common case. 
3321                 if ((error 
= kauth_identity_find_guid(guidp
, &ki
, NULL
)) == 0 && 
3322                     !kauth_identity_guid_expired(&ki
)) { 
3323                         if (ki
.ki_valid 
& KI_VALID_GID
) { 
3324                                 /* It's a group after all... */ 
3328                         if (ki
.ki_valid 
& KI_VALID_UID
) { 
3333 #endif /* CONFIG_EXT_RESOLVER */ 
3335                  * Attempt to translate the GUID to a GID.  Even if 
3336                  * this fails, we will have primed the cache if it is 
3337                  * a user record and we'll see it above the next time 
3340                 if ((error 
= kauth_cred_guid2gid(guidp
, &gid
)) != 0) { 
3342                          * If we have no guid -> gid translation, it's not a group and 
3343                          * thus the cred can't be a member. 
3345                         if (error 
== ENOENT
) { 
3350 #if CONFIG_EXT_RESOLVER 
3352 #endif /* CONFIG_EXT_RESOLVER */ 
3353                         error 
= kauth_cred_ismember_gid(cred
, gid
, resultp
); 
3362  * kauth_cred_gid_subset 
3364  * Description: Given two credentials, determine if all GIDs associated with  
3365  *              the first are also associated with the second 
3367  * Parameters:  cred1                           Credential to check for 
3368  *              cred2                           Credential to check in 
3369  *              resultp                         Pointer to int to contain the 
3370  *                                              result of the call 
3372  * Returns:     0                               Success 
3373  *              non-zero                        See kauth_cred_ismember_gid for 
3377  *              *resultp (modified)     1       Is subset 
3380  * Notes:       This function guarantees not to modify resultp when returning 
3384 kauth_cred_gid_subset(kauth_cred_t cred1
, kauth_cred_t cred2
, int *resultp
) 
3386         int i
, err
, res 
= 1; 
3388         posix_cred_t pcred1 
= posix_cred_get(cred1
); 
3389         posix_cred_t pcred2 
= posix_cred_get(cred2
); 
3391         /* First, check the local list of groups */ 
3392         for (i 
= 0; i 
< pcred1
->cr_ngroups
; i
++) { 
3393                 gid 
= pcred1
->cr_groups
[i
]; 
3394                 if ((err 
= kauth_cred_ismember_gid(cred2
, gid
, &res
)) != 0) { 
3398                 if (!res 
&& gid 
!= pcred2
->cr_rgid 
&& gid 
!= pcred2
->cr_svgid
) { 
3404         /* Check real gid */ 
3405         if ((err 
= kauth_cred_ismember_gid(cred2
, pcred1
->cr_rgid
, &res
)) != 0) { 
3409         if (!res 
&& pcred1
->cr_rgid 
!= pcred2
->cr_rgid 
&& 
3410                         pcred1
->cr_rgid 
!= pcred2
->cr_svgid
) { 
3415         /* Finally, check saved gid */ 
3416         if ((err 
= kauth_cred_ismember_gid(cred2
, pcred1
->cr_svgid
, &res
)) != 0){ 
3420         if (!res 
&& pcred1
->cr_svgid 
!= pcred2
->cr_rgid 
&& 
3421                         pcred1
->cr_svgid 
!= pcred2
->cr_svgid
) { 
3432  * kauth_cred_issuser 
3434  * Description: Fast replacement for issuser() 
3436  * Parameters:  cred                            Credential to check for super 
3439  * Returns:     0                               Not super user 
3442  * Notes:       This function uses a magic number which is not a manifest 
3443  *              constant; this is bad practice. 
3446 kauth_cred_issuser(kauth_cred_t cred
) 
3448         return(kauth_cred_getuid(cred
) == 0); 
3456 /* lock protecting credential hash table */ 
3457 static lck_mtx_t 
*kauth_cred_hash_mtx
; 
3458 #define KAUTH_CRED_HASH_LOCK()          lck_mtx_lock(kauth_cred_hash_mtx); 
3459 #define KAUTH_CRED_HASH_UNLOCK()        lck_mtx_unlock(kauth_cred_hash_mtx); 
3460 #if KAUTH_CRED_HASH_DEBUG 
3461 #define KAUTH_CRED_HASH_LOCK_ASSERT()   lck_mtx_assert(kauth_cred_hash_mtx, LCK_MTX_ASSERT_OWNED) 
3462 #else   /* !KAUTH_CRED_HASH_DEBUG */ 
3463 #define KAUTH_CRED_HASH_LOCK_ASSERT() 
3464 #endif  /* !KAUTH_CRED_HASH_DEBUG */ 
3470  * Description: Initialize the credential hash cache 
3472  * Parameters:  (void) 
3476  * Notes:       Intialize the credential hash cache for use; the credential 
3477  *              hash cache is used convert duplicate credentials into a 
3478  *              single reference counted credential in order to save wired 
3479  *              kernel memory.  In practice, this generally means a desktop 
3480  *              system runs with a few tens of credentials, instead of one 
3481  *              per process, one per thread, one per vnode cache entry, and 
3482  *              so on.  This generally results in savings of 200K or more 
3483  *              (potentially much more on server systems). 
3485  *              The hash cache internally has a reference on the credential 
3486  *              for itself as a means of avoiding a reclaim race for a 
3487  *              credential in the process of having it's last non-hash 
3488  *              reference released.  This would otherwise result in the 
3489  *              possibility of a freed credential that was still in uses due 
3490  *              a race.  This use is protected by the KAUTH_CRED_HASH_LOCK. 
3492  *              On final release, the hash reference is droped, and the 
3493  *              credential is freed back to the system. 
3495  *              This function is called from kauth_init() in the file 
3496  *              kern_authorization.c. 
3499 kauth_cred_init(void) 
3503         kauth_cred_hash_mtx 
= lck_mtx_alloc_init(kauth_lck_grp
, 0/*LCK_ATTR_NULL*/); 
3505         /*allocate credential hash table */ 
3506         MALLOC(kauth_cred_table_anchor
, struct kauth_cred_entry_head 
*,  
3507                         (sizeof(struct kauth_cred_entry_head
) * KAUTH_CRED_TABLE_SIZE
), 
3508                         M_KAUTH
, M_WAITOK 
| M_ZERO
); 
3509         if (kauth_cred_table_anchor 
== NULL
) 
3510                 panic("startup: kauth_cred_init"); 
3511         for (i 
= 0; i 
< KAUTH_CRED_TABLE_SIZE
; i
++) { 
3512                 TAILQ_INIT(&kauth_cred_table_anchor
[i
]); 
3520  * Description: Get the current thread's effective UID. 
3522  * Parameters:  (void) 
3524  * Returns:     (uid_t)                         The effective UID of the 
3530         return(kauth_cred_getuid(kauth_cred_get())); 
3537  * Description: Get the current thread's real UID. 
3539  * Parameters:  (void) 
3541  * Returns:     (uid_t)                         The real UID of the current 
3547         return(kauth_cred_getruid(kauth_cred_get())); 
3554  * Description: Get the current thread's effective GID. 
3556  * Parameters:  (void) 
3558  * Returns:     (gid_t)                         The effective GID of the 
3564         return(kauth_cred_getgid(kauth_cred_get())); 
3571  * Description: Get the current thread's real GID. 
3573  * Parameters:  (void) 
3575  * Returns:     (gid_t)                         The real GID of the current 
3581         return(kauth_cred_getrgid(kauth_cred_get())); 
3588  * Description: Returns a pointer to the current thread's credential 
3590  * Parameters:  (void) 
3592  * Returns:     (kauth_cred_t)                  Pointer to the current thread's 
3595  * Notes:       This function does not take a reference; because of this, the 
3596  *              caller MUST NOT do anything that would let the thread's 
3597  *              credential change while using the returned value, without 
3598  *              first explicitly taking their own reference. 
3600  *              If a caller intends to take a reference on the resulting 
3601  *              credential pointer from calling this function, it is strongly 
3602  *              recommended that the caller use kauth_cred_get_with_ref() 
3603  *              instead, to protect against any future changes to the cred 
3604  *              locking protocols; such changes could otherwise potentially 
3605  *              introduce race windows in the callers code. 
3608 kauth_cred_get(void) 
3611         struct uthread 
*uthread
; 
3613         uthread 
= get_bsdthread_info(current_thread()); 
3615         if (uthread 
== NULL
) 
3616                 panic("thread wants credential but has no BSD thread info"); 
3618          * We can lazy-bind credentials to threads, as long as their processes 
3621          * XXX If we later inline this function, the code in this block 
3622          * XXX should probably be called out in a function. 
3624         if (uthread
->uu_ucred 
== NOCRED
) { 
3625                 if ((p 
= (proc_t
) get_bsdtask_info(get_threadtask(current_thread()))) == NULL
) 
3626                         panic("thread wants credential but has no BSD process"); 
3627                 uthread
->uu_ucred 
= kauth_cred_proc_ref(p
); 
3629         return(uthread
->uu_ucred
); 
3633 mach_kauth_cred_uthread_update(void) 
3638         uthread 
= get_bsdthread_info(current_thread()); 
3639         proc 
= current_proc(); 
3641         kauth_cred_uthread_update(uthread
, proc
); 
3645  * kauth_cred_uthread_update 
3647  * Description: Given a uthread, a proc, and whether or not the proc is locked, 
3648  *              late-bind the uthread cred to the proc cred. 
3650  * Parameters:  uthread_t                       The uthread to update 
3651  *              proc_t                          The process to update to 
3655  * Notes:       This code is common code called from system call or trap entry 
3656  *              in the case that the process thread may have been changed 
3657  *              since the last time the thread entered the kernel.  It is 
3658  *              generally only called with the current uthread and process as 
3662 kauth_cred_uthread_update(uthread_t uthread
, proc_t proc
) 
3664         if (uthread
->uu_ucred 
!= proc
->p_ucred 
&& 
3665             (uthread
->uu_flag 
& UT_SETUID
) == 0) { 
3666                 kauth_cred_t old 
= uthread
->uu_ucred
; 
3667                 uthread
->uu_ucred 
= kauth_cred_proc_ref(proc
); 
3668                 if (IS_VALID_CRED(old
)) 
3669                         kauth_cred_unref(&old
); 
3675  * kauth_cred_get_with_ref 
3677  * Description: Takes a reference on the current thread's credential, and then 
3678  *              returns a pointer to it to the caller. 
3680  * Parameters:  (void) 
3682  * Returns:     (kauth_cred_t)                  Pointer to the current thread's 
3683  *                                              newly referenced credential 
3685  * Notes:       This function takes a reference on the credential before 
3686  *              returning it to the caller. 
3688  *              It is the responsibility of the calling code to release this 
3689  *              reference when the credential is no longer in use. 
3691  *              Since the returned reference may be a persistent reference 
3692  *              (e.g. one cached in another data structure with a lifetime 
3693  *              longer than the calling function), this release may be delayed 
3694  *              until such time as the persistent reference is to be destroyed. 
3695  *              An example of this would be the per vnode credential cache used 
3696  *              to accelerate lookup operations. 
3699 kauth_cred_get_with_ref(void) 
3702         struct uthread 
*uthread
; 
3704         uthread 
= get_bsdthread_info(current_thread()); 
3706         if (uthread 
== NULL
) 
3707                 panic("%s - thread wants credential but has no BSD thread info", __FUNCTION__
); 
3708         if ((procp 
= (proc_t
) get_bsdtask_info(get_threadtask(current_thread()))) == NULL
) 
3709                 panic("%s - thread wants credential but has no BSD process", __FUNCTION__
); 
3712          * We can lazy-bind credentials to threads, as long as their processes 
3715          * XXX If we later inline this function, the code in this block 
3716          * XXX should probably be called out in a function. 
3718         if (uthread
->uu_ucred 
== NOCRED
) { 
3719                 /* take reference for new cred in thread */ 
3720                 uthread
->uu_ucred 
= kauth_cred_proc_ref(procp
); 
3722         /* take a reference for our caller */ 
3723         kauth_cred_ref(uthread
->uu_ucred
); 
3724         return(uthread
->uu_ucred
); 
3729  * kauth_cred_proc_ref 
3731  * Description: Takes a reference on the current process's credential, and 
3732  *              then returns a pointer to it to the caller. 
3734  * Parameters:  procp                           Process whose credential we 
3735  *                                              intend to take a reference on 
3737  * Returns:     (kauth_cred_t)                  Pointer to the process's 
3738  *                                              newly referenced credential 
3740  * Locks:       PROC_UCRED_LOCK is held before taking the reference and released 
3741  *              after the refeence is taken to protect the p_ucred field of 
3742  *              the process referred to by procp. 
3744  * Notes:       This function takes a reference on the credential before 
3745  *              returning it to the caller. 
3747  *              It is the responsibility of the calling code to release this 
3748  *              reference when the credential is no longer in use. 
3750  *              Since the returned reference may be a persistent reference 
3751  *              (e.g. one cached in another data structure with a lifetime 
3752  *              longer than the calling function), this release may be delayed 
3753  *              until such time as the persistent reference is to be destroyed. 
3754  *              An example of this would be the per vnode credential cache used 
3755  *              to accelerate lookup operations. 
3758 kauth_cred_proc_ref(proc_t procp
) 
3762         proc_ucred_lock(procp
); 
3763         cred 
= proc_ucred(procp
); 
3764         kauth_cred_ref(cred
); 
3765         proc_ucred_unlock(procp
); 
3773  * Description: Allocate a new credential 
3775  * Parameters:  (void) 
3777  * Returns:     !NULL                           Newly allocated credential 
3778  *              NULL                            Insufficient memory 
3780  * Notes:       The newly allocated credential is zero'ed as part of the 
3781  *              allocation process, with the exception of the reference 
3782  *              count, which is set to 1 to indicate a single reference 
3783  *              held by the caller. 
3785  *              Since newly allocated credentials have no external pointers 
3786  *              referencing them, prior to making them visible in an externally 
3787  *              visible pointer (e.g. by adding them to the credential hash 
3788  *              cache) is the only legal time in which an existing credential 
3789  *              can be safely iinitialized or modified directly. 
3791  *              After initialization, the caller is expected to call the 
3792  *              function kauth_cred_add() to add the credential to the hash 
3793  *              cache, after which time it's frozen and becomes publically 
3796  *              The release protocol depends on kauth_hash_add() being called 
3797  *              before kauth_cred_rele() (there is a diagnostic panic which 
3798  *              will trigger if this protocol is not observed). 
3800  * XXX:         This function really ought to be static, rather than being 
3801  *              exported as KPI, since a failure of kauth_cred_add() can only 
3802  *              be handled by an explicit free of the credential; such frees 
3803  *              depend on knowlegdge of the allocation method used, which is 
3804  *              permitted to change between kernel revisions. 
3806  * XXX:         In the insufficient resource case, this code panic's rather 
3807  *              than returning a NULL pointer; the code that calls this 
3808  *              function needs to be audited before this can be changed. 
3811 kauth_cred_alloc(void) 
3813         kauth_cred_t newcred
; 
3815         MALLOC_ZONE(newcred
, kauth_cred_t
, sizeof(*newcred
), M_CRED
, M_WAITOK
); 
3817                 posix_cred_t newpcred 
= posix_cred_get(newcred
); 
3818                 bzero(newcred
, sizeof(*newcred
)); 
3819                 newcred
->cr_ref 
= 1; 
3820                 newcred
->cr_audit
.as_aia_p 
= audit_default_aia_p
; 
3821                 /* must do this, or cred has same group membership as uid 0 */ 
3822                 newpcred
->cr_gmuid 
= KAUTH_UID_NONE
; 
3825                 panic("kauth_cred_alloc: couldn't allocate credential"); 
3829 #if KAUTH_CRED_HASH_DEBUG 
3834         mac_cred_label_init(newcred
); 
3844  * Description: Look to see if we already have a known credential in the hash 
3845  *              cache; if one is found, bump the reference count and return 
3846  *              it.  If there are no credentials that match the given 
3847  *              credential, then allocate a new credential. 
3849  * Parameters:  cred                            Template for credential to 
3852  * Returns:     (kauth_cred_t)                  The credential that was found 
3853  *                                              in the hash or created 
3854  *              NULL                            kauth_cred_add() failed, or 
3855  *                                              there was not an egid specified 
3857  * Notes:       The gmuid is hard-defaulted to the UID specified.  Since we 
3858  *              maintain this field, we can't expect callers to know how it 
3859  *              needs to be set.  Callers should be prepared for this field 
3860  *              to be overwritten. 
3862  * XXX:         This code will tight-loop if memory for a new credential is 
3863  *              persistently unavailable; this is perhaps not the wisest way 
3864  *              to handle this condition, but current callers do not expect 
3868 kauth_cred_create(kauth_cred_t cred
) 
3870         kauth_cred_t    found_cred
, new_cred 
= NULL
; 
3871         posix_cred_t    pcred 
= posix_cred_get(cred
); 
3874         KAUTH_CRED_HASH_LOCK_ASSERT(); 
3876         if (pcred
->cr_flags 
& CRF_NOMEMBERD
) { 
3877                 pcred
->cr_gmuid 
= KAUTH_UID_NONE
; 
3880                  * If the template credential is not opting out of external 
3881                  * group membership resolution, then we need to check that 
3882                  * the UID we will be using is resolvable by the external 
3883                  * resolver.  If it's not, then we opt it out anyway, since 
3884                  * all future external resolution requests will be failing 
3885                  * anyway, and potentially taking a long time to do it.  We 
3886                  * use gid 0 because we always know it will exist and not 
3887                  * trigger additional lookups. This is OK, because we end up 
3888                  * precatching the information here as a result. 
3890                 if (!kauth_cred_ismember_gid(cred
, 0, &is_member
)) { 
3892                          * It's a recognized value; we don't really care about 
3893                          * the answer, so long as it's something the external 
3894                          * resolver could have vended. 
3896                         pcred
->cr_gmuid 
= pcred
->cr_uid
; 
3899                          * It's not something the external resolver could 
3900                          * have vended, so we don't want to ask it more 
3901                          * questions about the credential in the future. This 
3902                          * speeds up future lookups, as long as the caller 
3903                          * caches results; otherwise, it the same recurring 
3904                          * cost.  Since most credentials are used multiple 
3905                          * times, we still get some performance win from this. 
3907                         pcred
->cr_gmuid 
= KAUTH_UID_NONE
; 
3908                         pcred
->cr_flags 
|= CRF_NOMEMBERD
; 
3912         /* Caller *must* specify at least the egid in cr_groups[0] */ 
3913         if (pcred
->cr_ngroups 
< 1) 
3917                 KAUTH_CRED_HASH_LOCK(); 
3918                 found_cred 
= kauth_cred_find(cred
); 
3919                 if (found_cred 
!= NULL
) { 
3921                          * Found an existing credential so we'll bump 
3922                          * reference count and return 
3924                         kauth_cred_ref(found_cred
); 
3925                         KAUTH_CRED_HASH_UNLOCK(); 
3928                 KAUTH_CRED_HASH_UNLOCK(); 
3931                  * No existing credential found.  Create one and add it to 
3934                 new_cred 
= kauth_cred_alloc(); 
3935                 if (new_cred 
!= NULL
) { 
3937                         posix_cred_t    new_pcred 
= posix_cred_get(new_cred
); 
3938                         new_pcred
->cr_uid 
= pcred
->cr_uid
; 
3939                         new_pcred
->cr_ruid 
= pcred
->cr_ruid
; 
3940                         new_pcred
->cr_svuid 
= pcred
->cr_svuid
; 
3941                         new_pcred
->cr_rgid 
= pcred
->cr_rgid
; 
3942                         new_pcred
->cr_svgid 
= pcred
->cr_svgid
; 
3943                         new_pcred
->cr_gmuid 
= pcred
->cr_gmuid
; 
3944                         new_pcred
->cr_ngroups 
= pcred
->cr_ngroups
;       
3945                         bcopy(&pcred
->cr_groups
[0], &new_pcred
->cr_groups
[0], sizeof(new_pcred
->cr_groups
)); 
3947                         bcopy(&cred
->cr_audit
, &new_cred
->cr_audit
,  
3948                             sizeof(new_cred
->cr_audit
)); 
3950                         new_pcred
->cr_flags 
= pcred
->cr_flags
; 
3952                         KAUTH_CRED_HASH_LOCK(); 
3953                         err 
= kauth_cred_add(new_cred
); 
3954                         KAUTH_CRED_HASH_UNLOCK(); 
3956                         /* Retry if kauth_cred_add returns non zero value */ 
3960                         mac_cred_label_destroy(new_cred
); 
3962                         AUDIT_SESSION_UNREF(new_cred
); 
3964                         FREE_ZONE(new_cred
, sizeof(*new_cred
), M_CRED
); 
3974  * kauth_cred_setresuid 
3976  * Description: Update the given credential using the UID arguments.  The given 
3977  *              UIDs are used to set the effective UID, real UID, saved UID, 
3978  *              and GMUID (used for group membership checking). 
3980  * Parameters:  cred                            The original credential 
3981  *              ruid                            The new real UID 
3982  *              euid                            The new effective UID 
3983  *              svuid                           The new saved UID 
3984  *              gmuid                           KAUTH_UID_NONE -or- the new 
3985  *                                              group membership UID 
3987  * Returns:     (kauth_cred_t)                  The updated credential 
3989  * Note:        gmuid is different in that a KAUTH_UID_NONE is a valid 
3990  *              setting, so if you don't want it to change, pass it the 
3991  *              previous value, explicitly. 
3993  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
3994  *              if it returns a credential other than the one it is passed, 
3995  *              will have dropped the reference on the passed credential.  All 
3996  *              callers should be aware of this, and treat this function as an 
3997  *              unref + ref, potentially on different credentials. 
3999  *              Because of this, the caller is expected to take its own 
4000  *              reference on the credential passed as the first parameter, 
4001  *              and be prepared to release the reference on the credential 
4002  *              that is returned to them, if it is not intended to be a 
4003  *              persistent reference. 
4006 kauth_cred_setresuid(kauth_cred_t cred
, uid_t ruid
, uid_t euid
, uid_t svuid
, uid_t gmuid
) 
4008         struct ucred temp_cred
; 
4009         posix_cred_t temp_pcred 
= posix_cred_get(&temp_cred
); 
4010         posix_cred_t pcred 
= posix_cred_get(cred
); 
4012         NULLCRED_CHECK(cred
); 
4015          * We don't need to do anything if the UIDs we are changing are 
4016          * already the same as the UIDs passed in 
4018         if ((euid 
== KAUTH_UID_NONE 
|| pcred
->cr_uid 
== euid
) && 
4019             (ruid 
== KAUTH_UID_NONE 
|| pcred
->cr_ruid 
== ruid
) && 
4020             (svuid 
== KAUTH_UID_NONE 
|| pcred
->cr_svuid 
== svuid
) && 
4021             (pcred
->cr_gmuid 
== gmuid
)) { 
4022                 /* no change needed */ 
4027          * Look up in cred hash table to see if we have a matching credential 
4028          * with the new values; this is done by calling kauth_cred_update(). 
4030         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
4031         if (euid 
!= KAUTH_UID_NONE
) { 
4032                 temp_pcred
->cr_uid 
= euid
; 
4034         if (ruid 
!= KAUTH_UID_NONE
) { 
4035                 temp_pcred
->cr_ruid 
= ruid
; 
4037         if (svuid 
!= KAUTH_UID_NONE
) { 
4038                 temp_pcred
->cr_svuid 
= svuid
; 
4042          * If we are setting the gmuid to KAUTH_UID_NONE, then we want to 
4043          * opt out of participation in external group resolution, unless we 
4044          * unless we explicitly opt back in later. 
4046         if ((temp_pcred
->cr_gmuid 
= gmuid
) == KAUTH_UID_NONE
) { 
4047                 temp_pcred
->cr_flags 
|= CRF_NOMEMBERD
; 
4050         return(kauth_cred_update(cred
, &temp_cred
, TRUE
)); 
4055  * kauth_cred_setresgid 
4057  * Description: Update the given credential using the GID arguments.  The given 
4058  *              GIDs are used to set the effective GID, real GID, and saved 
4061  * Parameters:  cred                            The original credential 
4062  *              rgid                            The new real GID 
4063  *              egid                            The new effective GID 
4064  *              svgid                           The new saved GID 
4066  * Returns:     (kauth_cred_t)                  The updated credential 
4068  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
4069  *              if it returns a credential other than the one it is passed, 
4070  *              will have dropped the reference on the passed credential.  All 
4071  *              callers should be aware of this, and treat this function as an 
4072  *              unref + ref, potentially on different credentials. 
4074  *              Because of this, the caller is expected to take its own 
4075  *              reference on the credential passed as the first parameter, 
4076  *              and be prepared to release the reference on the credential 
4077  *              that is returned to them, if it is not intended to be a 
4078  *              persistent reference. 
4081 kauth_cred_setresgid(kauth_cred_t cred
, gid_t rgid
, gid_t egid
, gid_t svgid
) 
4083         struct ucred    temp_cred
; 
4084         posix_cred_t temp_pcred 
= posix_cred_get(&temp_cred
); 
4085         posix_cred_t pcred 
= posix_cred_get(cred
); 
4087         NULLCRED_CHECK(cred
); 
4088         DEBUG_CRED_ENTER("kauth_cred_setresgid %p %d %d %d\n", cred
, rgid
, egid
, svgid
); 
4091          * We don't need to do anything if the given GID are already the  
4092          * same as the GIDs in the credential. 
4094         if (pcred
->cr_groups
[0] == egid 
&& 
4095             pcred
->cr_rgid 
== rgid 
&& 
4096             pcred
->cr_svgid 
== svgid
) { 
4097                 /* no change needed */ 
4102          * Look up in cred hash table to see if we have a matching credential 
4103          * with the new values; this is done by calling kauth_cred_update(). 
4105         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
4106         if (egid 
!= KAUTH_GID_NONE
) { 
4107                 /* displacing a supplementary group opts us out of memberd */ 
4108                 if (kauth_cred_change_egid(&temp_cred
, egid
)) { 
4109                         DEBUG_CRED_CHANGE("displaced!\n"); 
4110                         temp_pcred
->cr_flags 
|= CRF_NOMEMBERD
; 
4111                         temp_pcred
->cr_gmuid 
= KAUTH_UID_NONE
; 
4113                         DEBUG_CRED_CHANGE("not displaced\n"); 
4116         if (rgid 
!= KAUTH_GID_NONE
) { 
4117                 temp_pcred
->cr_rgid 
= rgid
; 
4119         if (svgid 
!= KAUTH_GID_NONE
) { 
4120                 temp_pcred
->cr_svgid 
= svgid
; 
4123         return(kauth_cred_update(cred
, &temp_cred
, TRUE
)); 
4128  * Update the given credential with the given groups.  We only allocate a new  
4129  *      credential when the given gid actually results in changes to the existing  
4131  *      The gmuid argument supplies a new uid (or KAUTH_UID_NONE to opt out) 
4132  *      which will be used for group membership checking. 
4135  * kauth_cred_setgroups 
4137  * Description: Update the given credential using the provide supplementary 
4138  *              group list and group membership UID 
4140  * Parameters:  cred                            The original credential 
4141  *              groups                          Pointer to gid_t array which 
4142  *                                              contains the new group list 
4143  *              groupcount                      The count of valid groups which 
4144  *                                              are contained in 'groups' 
4145  *              gmuid                           KAUTH_UID_NONE -or- the new 
4146  *                                              group membership UID 
4148  * Returns:     (kauth_cred_t)                  The updated credential 
4150  * Note:        gmuid is different in that a KAUTH_UID_NONE is a valid 
4151  *              setting, so if you don't want it to change, pass it the 
4152  *              previous value, explicitly. 
4154  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
4155  *              if it returns a credential other than the one it is passed, 
4156  *              will have dropped the reference on the passed credential.  All 
4157  *              callers should be aware of this, and treat this function as an 
4158  *              unref + ref, potentially on different credentials. 
4160  *              Because of this, the caller is expected to take its own 
4161  *              reference on the credential passed as the first parameter, 
4162  *              and be prepared to release the reference on the credential 
4163  *              that is returned to them, if it is not intended to be a 
4164  *              persistent reference. 
4166  * XXX:         Changes are determined in ordinal order - if the caller passes 
4167  *              in the same groups list that is already present in the 
4168  *              credential, but the members are in a different order, even if 
4169  *              the EGID is not modified (i.e. cr_groups[0] is the same), it 
4170  *              is considered a modification to the credential, and a new 
4171  *              credential is created. 
4173  *              This should perhaps be better optimized, but it is considered 
4174  *              to be the caller's problem. 
4177 kauth_cred_setgroups(kauth_cred_t cred
, gid_t 
*groups
, int groupcount
, uid_t gmuid
) 
4180         struct ucred temp_cred
; 
4181         posix_cred_t temp_pcred 
= posix_cred_get(&temp_cred
); 
4184         NULLCRED_CHECK(cred
); 
4186         pcred 
= posix_cred_get(cred
); 
4189          * We don't need to do anything if the given list of groups does not 
4192         if ((pcred
->cr_gmuid 
== gmuid
) && (pcred
->cr_ngroups 
== groupcount
)) { 
4193                 for (i 
= 0; i 
< groupcount
; i
++) { 
4194                         if (pcred
->cr_groups
[i
] != groups
[i
]) 
4197                 if (i 
== groupcount
) { 
4198                         /* no change needed */ 
4204          * Look up in cred hash table to see if we have a matching credential 
4205          * with new values.  If we are setting or clearing the gmuid, then 
4206          * update the cr_flags, since clearing it is sticky.  This permits an 
4207          * opt-out of memberd processing using setgroups(), and an opt-in 
4208          * using initgroups().  This is required for POSIX conformance. 
4210         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
4211         temp_pcred
->cr_ngroups 
= groupcount
; 
4212         bcopy(groups
, temp_pcred
->cr_groups
, sizeof(temp_pcred
->cr_groups
)); 
4213         temp_pcred
->cr_gmuid 
= gmuid
; 
4214         if (gmuid 
== KAUTH_UID_NONE
) 
4215                 temp_pcred
->cr_flags 
|= CRF_NOMEMBERD
; 
4217                 temp_pcred
->cr_flags 
&= ~CRF_NOMEMBERD
; 
4219         return(kauth_cred_update(cred
, &temp_cred
, TRUE
)); 
4223  * Notes:       The return value exists to account for the possibility of a 
4224  *              kauth_cred_t without a POSIX label.  This will be the case in 
4225  *              the future (see posix_cred_get() below, for more details). 
4227 #if CONFIG_EXT_RESOLVER 
4228 int kauth_external_supplementary_groups_supported 
= 1; 
4230 SYSCTL_INT(_kern
, OID_AUTO
, ds_supgroups_supported
, CTLFLAG_RW 
| CTLFLAG_LOCKED
, &kauth_external_supplementary_groups_supported
, 0, ""); 
4234 kauth_cred_getgroups(kauth_cred_t cred
, gid_t 
*grouplist
, int *countp
) 
4236         int limit 
= NGROUPS
; 
4239         pcred 
= posix_cred_get(cred
); 
4241 #if CONFIG_EXT_RESOLVER   
4243          * If we've not opted out of using the resolver, then convert the cred to a list 
4244          * of supplemental groups. We do this only if there has been a resolver to talk to, 
4245          * since we may be too early in boot, or in an environment that isn't using DS. 
4247         if (kauth_identitysvc_has_registered 
&& kauth_external_supplementary_groups_supported 
&& (pcred
->cr_flags 
& CRF_NOMEMBERD
) == 0) {               
4248                 uid_t uid 
= kauth_cred_getuid(cred
); 
4251                 err 
= kauth_cred_uid2groups(&uid
, grouplist
, countp
); 
4255                 /* On error just fall through */ 
4256                 KAUTH_DEBUG("kauth_cred_getgroups failed %d\n", err
); 
4258 #endif /* CONFIG_EXT_RESOLVER */ 
4261          * If they just want a copy of the groups list, they may not care 
4262          * about the actual count.  If they specify an input count, however, 
4263          * treat it as an indicator of the buffer size available in grouplist, 
4264          * and limit the returned list to that size. 
4267                 limit 
= MIN(*countp
, pcred
->cr_ngroups
); 
4271         memcpy(grouplist
, pcred
->cr_groups
, sizeof(gid_t
) * limit
); 
4278  * kauth_cred_setuidgid 
4280  * Description: Update the given credential using the UID and GID arguments. 
4281  *              The given UID is used to set the effective UID, real UID, and 
4282  *              saved UID.  The given GID is used to set the effective GID, 
4283  *              real GID, and saved GID. 
4285  * Parameters:  cred                            The original credential 
4286  *              uid                             The new UID to use 
4287  *              gid                             The new GID to use 
4289  * Returns:     (kauth_cred_t)                  The updated credential 
4291  * Notes:       We set the gmuid to uid if the credential we are inheriting 
4292  *              from has not opted out of memberd participation; otherwise 
4293  *              we set it to KAUTH_UID_NONE 
4295  *              This code is only ever called from the per-thread credential 
4296  *              code path in the "set per thread credential" case; and in 
4297  *              posix_spawn() in the case that the POSIX_SPAWN_RESETIDS 
4300  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
4301  *              if it returns a credential other than the one it is passed, 
4302  *              will have dropped the reference on the passed credential.  All 
4303  *              callers should be aware of this, and treat this function as an 
4304  *              unref + ref, potentially on different credentials. 
4306  *              Because of this, the caller is expected to take its own 
4307  *              reference on the credential passed as the first parameter, 
4308  *              and be prepared to release the reference on the credential 
4309  *              that is returned to them, if it is not intended to be a 
4310  *              persistent reference. 
4313 kauth_cred_setuidgid(kauth_cred_t cred
, uid_t uid
, gid_t gid
) 
4315         struct ucred temp_cred
; 
4316         posix_cred_t temp_pcred 
= posix_cred_get(&temp_cred
); 
4319         NULLCRED_CHECK(cred
); 
4321         pcred 
= posix_cred_get(cred
); 
4324          * We don't need to do anything if the effective, real and saved 
4325          * user IDs are already the same as the user ID passed into us. 
4327         if (pcred
->cr_uid 
== uid 
&& pcred
->cr_ruid 
== uid 
&& pcred
->cr_svuid 
== uid 
&& 
4328                 pcred
->cr_gid 
== gid 
&& pcred
->cr_rgid 
== gid 
&& pcred
->cr_svgid 
== gid
) { 
4329                 /* no change needed */ 
4334          * Look up in cred hash table to see if we have a matching credential 
4335          * with the new values. 
4337         bzero(&temp_cred
, sizeof(temp_cred
)); 
4338         temp_pcred
->cr_uid 
= uid
; 
4339         temp_pcred
->cr_ruid 
= uid
; 
4340         temp_pcred
->cr_svuid 
= uid
; 
4341         temp_pcred
->cr_flags 
= pcred
->cr_flags
; 
4342         /* inherit the opt-out of memberd */ 
4343         if (pcred
->cr_flags 
& CRF_NOMEMBERD
) { 
4344                 temp_pcred
->cr_gmuid 
= KAUTH_UID_NONE
; 
4345                 temp_pcred
->cr_flags 
|= CRF_NOMEMBERD
; 
4347                 temp_pcred
->cr_gmuid 
= uid
; 
4348                 temp_pcred
->cr_flags 
&= ~CRF_NOMEMBERD
; 
4350         temp_pcred
->cr_ngroups 
= 1; 
4351         /* displacing a supplementary group opts us out of memberd */ 
4352         if (kauth_cred_change_egid(&temp_cred
, gid
)) { 
4353                 temp_pcred
->cr_gmuid 
= KAUTH_UID_NONE
; 
4354                 temp_pcred
->cr_flags 
|= CRF_NOMEMBERD
; 
4356         temp_pcred
->cr_rgid 
= gid
; 
4357         temp_pcred
->cr_svgid 
= gid
; 
4359         temp_cred
.cr_label 
= cred
->cr_label
; 
4362         return(kauth_cred_update(cred
, &temp_cred
, TRUE
)); 
4367  * kauth_cred_setsvuidgid 
4369  * Description: Function used by execve to set the saved uid and gid values 
4370  *              for suid/sgid programs 
4372  * Parameters:  cred                            The credential to update 
4373  *              uid                             The saved uid to set 
4374  *              gid                             The saved gid to set 
4376  * Returns:     (kauth_cred_t)                  The updated credential 
4378  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
4379  *              if it returns a credential other than the one it is passed, 
4380  *              will have dropped the reference on the passed credential.  All 
4381  *              callers should be aware of this, and treat this function as an 
4382  *              unref + ref, potentially on different credentials. 
4384  *              Because of this, the caller is expected to take its own 
4385  *              reference on the credential passed as the first parameter, 
4386  *              and be prepared to release the reference on the credential 
4387  *              that is returned to them, if it is not intended to be a 
4388  *              persistent reference. 
4391 kauth_cred_setsvuidgid(kauth_cred_t cred
, uid_t uid
, gid_t gid
) 
4393         struct ucred temp_cred
; 
4394         posix_cred_t temp_pcred 
= posix_cred_get(&temp_cred
); 
4397         NULLCRED_CHECK(cred
); 
4399         pcred 
= posix_cred_get(cred
); 
4401         DEBUG_CRED_ENTER("kauth_cred_setsvuidgid: %p u%d->%d g%d->%d\n", cred
, cred
->cr_svuid
, uid
, cred
->cr_svgid
, gid
); 
4404          * We don't need to do anything if the effective, real and saved 
4405          * uids are already the same as the uid provided.  This check is 
4406          * likely insufficient. 
4408         if (pcred
->cr_svuid 
== uid 
&& pcred
->cr_svgid 
== gid
) { 
4409                 /* no change needed */ 
4412         DEBUG_CRED_CHANGE("kauth_cred_setsvuidgid: cred change\n"); 
4414         /* look up in cred hash table to see if we have a matching credential 
4417         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
4418         temp_pcred
->cr_svuid 
= uid
; 
4419         temp_pcred
->cr_svgid 
= gid
; 
4421         return(kauth_cred_update(cred
, &temp_cred
, TRUE
)); 
4426  * kauth_cred_setauditinfo 
4428  * Description: Update the given credential using the given au_session_t. 
4430  * Parameters:  cred                            The original credential 
4431  *              auditinfo_p                     Pointer to ne audit information 
4433  * Returns:     (kauth_cred_t)                  The updated credential 
4435  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
4436  *              if it returns a credential other than the one it is passed, 
4437  *              will have dropped the reference on the passed credential.  All 
4438  *              callers should be aware of this, and treat this function as an 
4439  *              unref + ref, potentially on different credentials. 
4441  *              Because of this, the caller is expected to take its own 
4442  *              reference on the credential passed as the first parameter, 
4443  *              and be prepared to release the reference on the credential 
4444  *              that is returned to them, if it is not intended to be a 
4445  *              persistent reference. 
4448 kauth_cred_setauditinfo(kauth_cred_t cred
, au_session_t 
*auditinfo_p
) 
4450         struct ucred temp_cred
; 
4452         NULLCRED_CHECK(cred
); 
4455          * We don't need to do anything if the audit info is already the 
4456          * same as the audit info in the credential provided. 
4458         if (bcmp(&cred
->cr_audit
, auditinfo_p
, sizeof(cred
->cr_audit
)) == 0) { 
4459                 /* no change needed */ 
4463         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
4464         bcopy(auditinfo_p
, &temp_cred
.cr_audit
, sizeof(temp_cred
.cr_audit
)); 
4466         return(kauth_cred_update(cred
, &temp_cred
, FALSE
)); 
4471  * kauth_cred_label_update 
4473  * Description: Update the MAC label associated with a credential 
4475  * Parameters:  cred                            The original credential 
4476  *              label                           The MAC label to set 
4478  * Returns:     (kauth_cred_t)                  The updated credential 
4480  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
4481  *              if it returns a credential other than the one it is passed, 
4482  *              will have dropped the reference on the passed credential.  All 
4483  *              callers should be aware of this, and treat this function as an 
4484  *              unref + ref, potentially on different credentials. 
4486  *              Because of this, the caller is expected to take its own 
4487  *              reference on the credential passed as the first parameter, 
4488  *              and be prepared to release the reference on the credential 
4489  *              that is returned to them, if it is not intended to be a 
4490  *              persistent reference. 
4493 kauth_cred_label_update(kauth_cred_t cred
, struct label 
*label
) 
4495         kauth_cred_t newcred
; 
4496         struct ucred temp_cred
; 
4498         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
4500         mac_cred_label_init(&temp_cred
); 
4501         mac_cred_label_associate(cred
, &temp_cred
); 
4502         mac_cred_label_update(&temp_cred
, label
); 
4504         newcred 
= kauth_cred_update(cred
, &temp_cred
, TRUE
); 
4505         mac_cred_label_destroy(&temp_cred
); 
4510  * kauth_cred_label_update_execve 
4512  * Description: Update the MAC label associated with a credential as 
4515  * Parameters:  cred                            The original credential 
4517  *              scriptl                         The script MAC label 
4518  *              execl                           The executable MAC label 
4519  *              disjointp                       Pointer to flag to set if old 
4520  *                                              and returned credentials are 
4523  * Returns:     (kauth_cred_t)                  The updated credential 
4526  *              *disjointp                      Set to 1 for disjoint creds 
4528  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
4529  *              if it returns a credential other than the one it is passed, 
4530  *              will have dropped the reference on the passed credential.  All 
4531  *              callers should be aware of this, and treat this function as an 
4532  *              unref + ref, potentially on different credentials. 
4534  *              Because of this, the caller is expected to take its own 
4535  *              reference on the credential passed as the first parameter, 
4536  *              and be prepared to release the reference on the credential 
4537  *              that is returned to them, if it is not intended to be a 
4538  *              persistent reference. 
4543 kauth_cred_label_update_execve(kauth_cred_t cred
, vfs_context_t ctx
, 
4544         struct vnode 
*vp
, off_t offset
, struct vnode 
*scriptvp
, struct label 
*scriptl
, 
4545         struct label 
*execl
, unsigned int *csflags
, void *macextensions
, int *disjointp
, int *labelupdateerror
) 
4547         kauth_cred_t newcred
; 
4548         struct ucred temp_cred
; 
4550         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
4552         mac_cred_label_init(&temp_cred
); 
4553         mac_cred_label_associate(cred
, &temp_cred
); 
4554         mac_cred_label_update_execve(ctx
, &temp_cred
,  
4555                                                   vp
, offset
, scriptvp
, scriptl
, execl
, csflags
, 
4556                                                   macextensions
, disjointp
, labelupdateerror
); 
4558         newcred 
= kauth_cred_update(cred
, &temp_cred
, TRUE
); 
4559         mac_cred_label_destroy(&temp_cred
); 
4564  *  kauth_proc_label_update 
4566  * Description:  Update the label inside the credential associated with the process. 
4568  * Parameters:  p                       The process to modify 
4569  *                              label           The label to place in the process credential 
4571  * Notes:               The credential associated with the process may change as a result 
4572  *                              of this call.  The caller should not assume the process reference to 
4573  *                              the old credential still exists. 
4575 int kauth_proc_label_update(struct proc 
*p
, struct label 
*label
) 
4577         kauth_cred_t my_cred
, my_new_cred
; 
4579         my_cred 
= kauth_cred_proc_ref(p
); 
4581         DEBUG_CRED_ENTER("kauth_proc_label_update: %p\n", my_cred
); 
4583         /* get current credential and take a reference while we muck with it */ 
4587                  * Set the credential with new info.  If there is no change, 
4588                  * we get back the same credential we passed in; if there is 
4589                  * a change, we drop the reference on the credential we 
4590                  * passed in.  The subsequent compare is safe, because it is 
4591                  * a pointer compare rather than a contents compare. 
4593                 my_new_cred 
= kauth_cred_label_update(my_cred
, label
); 
4594                 if (my_cred 
!= my_new_cred
) { 
4596                         DEBUG_CRED_CHANGE("kauth_proc_setlabel_unlocked CH(%d): %p/0x%08x -> %p/0x%08x\n", p
->p_pid
, my_cred
, my_cred
->cr_flags
, my_new_cred
, my_new_cred
->cr_flags
); 
4600                          * We need to protect for a race where another thread 
4601                          * also changed the credential after we took our 
4602                          * reference.  If p_ucred has changed then we should 
4603                          * restart this again with the new cred. 
4605                         if (p
->p_ucred 
!= my_cred
) { 
4606                                 proc_ucred_unlock(p
); 
4607                                 kauth_cred_unref(&my_new_cred
); 
4608                                 my_cred 
= kauth_cred_proc_ref(p
); 
4612                         p
->p_ucred 
= my_new_cred
; 
4613                         /* update cred on proc */ 
4614                         PROC_UPDATE_CREDS_ONPROC(p
); 
4616                         proc_ucred_unlock(p
); 
4620         /* Drop old proc reference or our extra reference */ 
4621         kauth_cred_unref(&my_cred
); 
4627  *  kauth_proc_label_update_execve 
4629  * Description: Update the label inside the credential associated with the 
4630  *              process as part of a transitioning execve.  The label will 
4631  *              be updated by the policies as part of this processing, not 
4632  *              provided up front. 
4634  * Parameters:  p                       The process to modify 
4635  *              ctx                     The context of the exec 
4636  *              vp                      The vnode being exec'ed 
4637  *              scriptl                 The script MAC label 
4638  *              execl                   The executable MAC label 
4639  *              lupdateerror    The error place holder for MAC label authority  
4640  *                                              to update about possible termination 
4642  * Returns:     0                       Label update did not make credential 
4644  *              1                       Label update caused credential to be 
4647  * Notes:       The credential associated with the process WILL change as a 
4648  *              result of this call.  The caller should not assume the process 
4649  *              reference to the old credential still exists. 
4653 kauth_proc_label_update_execve(struct proc 
*p
, vfs_context_t ctx
, 
4654         struct vnode 
*vp
, off_t offset
, struct vnode 
*scriptvp
, struct label 
*scriptl
, 
4655         struct label 
*execl
, unsigned int *csflags
, void *macextensions
, int *disjoint
, int *update_return
) 
4657         kauth_cred_t my_cred
, my_new_cred
; 
4658         my_cred 
= kauth_cred_proc_ref(p
); 
4660         DEBUG_CRED_ENTER("kauth_proc_label_update_execve: %p\n", my_cred
); 
4662         /* get current credential and take a reference while we muck with it */ 
4666                  * Set the credential with new info.  If there is no change, 
4667                  * we get back the same credential we passed in; if there is 
4668                  * a change, we drop the reference on the credential we 
4669                  * passed in.  The subsequent compare is safe, because it is 
4670                  * a pointer compare rather than a contents compare. 
4672                 my_new_cred 
= kauth_cred_label_update_execve(my_cred
, ctx
, vp
, offset
, scriptvp
, scriptl
, execl
, csflags
, macextensions
, disjoint
, update_return
); 
4673                 if (my_cred 
!= my_new_cred
) { 
4675                         DEBUG_CRED_CHANGE("kauth_proc_label_update_execve_unlocked CH(%d): %p/0x%08x -> %p/0x%08x\n", p
->p_pid
, my_cred
, my_cred
->cr_flags
, my_new_cred
, my_new_cred
->cr_flags
); 
4679                          * We need to protect for a race where another thread 
4680                          * also changed the credential after we took our 
4681                          * reference.  If p_ucred has changed then we should 
4682                          * restart this again with the new cred. 
4684                         if (p
->p_ucred 
!= my_cred
) { 
4685                                 proc_ucred_unlock(p
); 
4686                                 kauth_cred_unref(&my_new_cred
); 
4687                                 my_cred 
= kauth_cred_proc_ref(p
); 
4691                         p
->p_ucred 
= my_new_cred
; 
4692                         /* update cred on proc */ 
4693                         PROC_UPDATE_CREDS_ONPROC(p
); 
4694                         proc_ucred_unlock(p
); 
4698         /* Drop old proc reference or our extra reference */ 
4699         kauth_cred_unref(&my_cred
); 
4704  * for temporary binary compatibility 
4706 kauth_cred_t    
kauth_cred_setlabel(kauth_cred_t cred
, struct label 
*label
); 
4708 kauth_cred_setlabel(kauth_cred_t cred
, struct label 
*label
) 
4710         return kauth_cred_label_update(cred
, label
); 
4713 int kauth_proc_setlabel(struct proc 
*p
, struct label 
*label
); 
4715 kauth_proc_setlabel(struct proc 
*p
, struct label 
*label
) 
4717         return kauth_proc_label_update(p
, label
); 
4723 /* this is a temp hack to cover us when MACF is not built in a kernel configuration.  
4724  * Since we cannot build our export lists based on the kernel configuration we need 
4728 kauth_cred_label_update(__unused kauth_cred_t cred
, __unused 
void *label
) 
4734 kauth_proc_label_update(__unused 
struct proc 
*p
, __unused 
void *label
) 
4741  * for temporary binary compatibility 
4743 kauth_cred_t    
kauth_cred_setlabel(kauth_cred_t cred
, void *label
); 
4745 kauth_cred_setlabel(__unused kauth_cred_t cred
, __unused 
void *label
) 
4750 int kauth_proc_setlabel(struct proc 
*p
, void *label
); 
4752 kauth_proc_setlabel(__unused 
struct proc 
*p
, __unused 
void *label
) 
4762  * Description: Add a reference to the passed credential 
4764  * Parameters:  cred                            The credential to reference 
4768  * Notes:       This function adds a reference to the provided credential; 
4769  *              the existing reference on the credential is assumed to be 
4770  *              held stable over this operation by taking the appropriate 
4771  *              lock to protect the pointer from which it is being referenced, 
4772  *              if necessary (e.g. the proc lock is held over the call if the 
4773  *              credential being referenced is from p_ucred, the vnode lock 
4774  *              if from the per vnode name cache cred cache, and so on). 
4776  *              This is safe from the kauth_cred_unref() path, since an atomic 
4777  *              add is used, and the unref path specifically checks to see that 
4778  *              the value has not been changed to add a reference between the 
4779  *              time the credential is unreferenced by another pointer and the 
4780  *              time it is unreferenced from the cred hash cache. 
4783 kauth_cred_ref(kauth_cred_t cred
) 
4787         NULLCRED_CHECK(cred
); 
4789         old_value 
= OSAddAtomicLong(1, (long*)&cred
->cr_ref
); 
4792                 panic("kauth_cred_ref: trying to take a reference on a cred with no references"); 
4794 #if 0 // use this to watch a specific credential 
4795         if ( is_target_cred( cred 
) != 0 ) { 
4805  * kauth_cred_unref_hashlocked 
4807  * Description: release a credential reference; when the last reference is 
4808  *              released, the credential will be freed. 
4810  * Parameters:  credp                           Pointer to address containing 
4811  *                                              credential to be freed 
4813  * Returns:     TRUE if the credential must be destroyed by the caller. 
4817  *              *credp                          Set to NOCRED 
4819  * Notes:       This function assumes the credential hash lock is held. 
4821  *              This function is internal use only, since the hash lock is 
4822  *              scoped to this compilation unit. 
4824  *              This function destroys the contents of the pointer passed by 
4825  *              the caller to prevent the caller accidentally attempting to 
4826  *              release a given reference twice in error. 
4828  *              The last reference is considered to be released when a release 
4829  *              of a credential of a reference count of 2 occurs; this is an 
4830  *              intended effect, to take into account the reference held by 
4831  *              the credential hash, which is released at the same time. 
4834 kauth_cred_unref_hashlocked(kauth_cred_t 
*credp
) 
4837         boolean_t       destroy_it 
= FALSE
; 
4839         KAUTH_CRED_HASH_LOCK_ASSERT(); 
4840         NULLCRED_CHECK(*credp
); 
4842         old_value 
= OSAddAtomicLong(-1, (long*)&(*credp
)->cr_ref
); 
4846                 panic("%s:0x%08x kauth_cred_unref_hashlocked: dropping a reference on a cred with no references", current_proc()->p_comm
, *credp
); 
4848                 panic("%s:0x%08x kauth_cred_unref_hashlocked: dropping a reference on a cred with no hash entry", current_proc()->p_comm
, *credp
); 
4851 #if 0 // use this to watch a specific credential 
4852         if ( is_target_cred( *credp 
) != 0 ) { 
4858          * If the old_value is 2, then we have just released the last external 
4859          * reference to this credential 
4861         if (old_value 
< 3) { 
4862                 /* The last absolute reference is our credential hash table */ 
4863                 destroy_it 
= kauth_cred_remove(*credp
); 
4866         if (destroy_it 
== FALSE
) { 
4870         return (destroy_it
); 
4877  * Description: Release a credential reference while holding the credential 
4878  *              hash lock; when the last reference is released, the credential 
4881  * Parameters:  credp                           Pointer to address containing 
4882  *                                              credential to be freed 
4887  *              *credp                          Set to NOCRED 
4889  * Notes:       See kauth_cred_unref_hashlocked() for more information. 
4893 kauth_cred_unref(kauth_cred_t 
*credp
) 
4895         boolean_t destroy_it
; 
4897         KAUTH_CRED_HASH_LOCK(); 
4898         destroy_it 
= kauth_cred_unref_hashlocked(credp
); 
4899         KAUTH_CRED_HASH_UNLOCK(); 
4901         if (destroy_it 
== TRUE
) { 
4902                 assert(*credp 
!= NOCRED
); 
4904                 mac_cred_label_destroy(*credp
); 
4906                 AUDIT_SESSION_UNREF(*credp
); 
4908                 (*credp
)->cr_ref 
= 0; 
4909                 FREE_ZONE(*credp
, sizeof(*(*credp
)), M_CRED
); 
4919  * Description: release a credential reference; when the last reference is 
4920  *              released, the credential will be freed 
4922  * Parameters:  cred                            Credential to release 
4926  * DEPRECATED:  This interface is obsolete due to a failure to clear out the 
4927  *              clear the pointer in the caller to avoid multiple releases of 
4928  *              the same credential.  The currently recommended interface is 
4929  *              kauth_cred_unref(). 
4932 kauth_cred_rele(kauth_cred_t cred
) 
4934         kauth_cred_unref(&cred
); 
4936 #endif /* !__LP64__ */ 
4942  * Description: Duplicate a credential via alloc and copy; the new credential 
4945  * Parameters:  cred                            The credential to duplicate 
4947  * Returns:     (kauth_cred_t)                  The duplicate credential 
4949  * Notes:       The typical value to calling this routine is if you are going 
4950  *              to modify an existing credential, and expect to need a new one 
4951  *              from the hash cache. 
4953  *              This should probably not be used in the majority of cases; 
4954  *              if you are using it instead of kauth_cred_create(), you are 
4955  *              likely making a mistake. 
4957  *              The newly allocated credential is copied as part of the 
4958  *              allocation process, with the exception of the reference 
4959  *              count, which is set to 1 to indicate a single reference 
4960  *              held by the caller. 
4962  *              Since newly allocated credentials have no external pointers 
4963  *              referencing them, prior to making them visible in an externally 
4964  *              visible pointer (e.g. by adding them to the credential hash 
4965  *              cache) is the only legal time in which an existing credential 
4966  *              can be safely initialized or modified directly. 
4968  *              After initialization, the caller is expected to call the 
4969  *              function kauth_cred_add() to add the credential to the hash 
4970  *              cache, after which time it's frozen and becomes publicly 
4973  *              The release protocol depends on kauth_hash_add() being called 
4974  *              before kauth_cred_rele() (there is a diagnostic panic which 
4975  *              will trigger if this protocol is not observed). 
4979 kauth_cred_dup(kauth_cred_t cred
) 
4981         kauth_cred_t newcred
; 
4983         struct label 
*temp_label
; 
4987         if (cred 
== NOCRED 
|| cred 
== FSCRED
) 
4988                 panic("kauth_cred_dup: bad credential"); 
4990         newcred 
= kauth_cred_alloc(); 
4991         if (newcred 
!= NULL
) { 
4993                 temp_label 
= newcred
->cr_label
; 
4995                 bcopy(cred
, newcred
, sizeof(*newcred
)); 
4997                 newcred
->cr_label 
= temp_label
; 
4998                 mac_cred_label_associate(cred
, newcred
); 
5000                 AUDIT_SESSION_REF(cred
); 
5001                 newcred
->cr_ref 
= 1; 
5007  * kauth_cred_copy_real 
5009  * Description: Returns a credential based on the passed credential but which 
5010  *              reflects the real rather than effective UID and GID. 
5012  * Parameters:  cred                            The credential from which to 
5013  *                                              derive the new credential 
5015  * Returns:     (kauth_cred_t)                  The copied credential 
5017  * IMPORTANT:   This function DOES NOT utilize kauth_cred_update(); as a 
5018  *              result, the caller is responsible for dropping BOTH the 
5019  *              additional reference on the passed cred (if any), and the 
5020  *              credential returned by this function.  The drop should be 
5021  *              via the kauth_cred_unref() KPI. 
5024 kauth_cred_copy_real(kauth_cred_t cred
) 
5026         kauth_cred_t newcred 
= NULL
, found_cred
; 
5027         struct ucred temp_cred
; 
5028         posix_cred_t temp_pcred 
= posix_cred_get(&temp_cred
); 
5029         posix_cred_t pcred 
= posix_cred_get(cred
); 
5031         /* if the credential is already 'real', just take a reference */ 
5032         if ((pcred
->cr_ruid 
== pcred
->cr_uid
) && 
5033             (pcred
->cr_rgid 
== pcred
->cr_gid
)) { 
5034                 kauth_cred_ref(cred
); 
5039          * Look up in cred hash table to see if we have a matching credential 
5040          * with the new values. 
5042         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
5043         temp_pcred
->cr_uid 
= pcred
->cr_ruid
; 
5044         /* displacing a supplementary group opts us out of memberd */ 
5045         if (kauth_cred_change_egid(&temp_cred
, pcred
->cr_rgid
)) { 
5046                 temp_pcred
->cr_flags 
|= CRF_NOMEMBERD
; 
5047                 temp_pcred
->cr_gmuid 
= KAUTH_UID_NONE
; 
5050          * If the cred is not opted out, make sure we are using the r/euid 
5053         if (temp_pcred
->cr_gmuid 
!= KAUTH_UID_NONE
) 
5054                 temp_pcred
->cr_gmuid 
= pcred
->cr_ruid
; 
5059                 KAUTH_CRED_HASH_LOCK(); 
5060                 found_cred 
= kauth_cred_find(&temp_cred
); 
5061                 if (found_cred 
== cred
) { 
5062                         /* same cred so just bail */ 
5063                         KAUTH_CRED_HASH_UNLOCK(); 
5066                 if (found_cred 
!= NULL
) { 
5068                          * Found a match so we bump reference count on new 
5069                          * one.  We leave the old one alone. 
5071                         kauth_cred_ref(found_cred
); 
5072                         KAUTH_CRED_HASH_UNLOCK(); 
5077                  * Must allocate a new credential, copy in old credential 
5078                  * data and update the real user and group IDs. 
5080                 newcred 
= kauth_cred_dup(&temp_cred
); 
5081                 err 
= kauth_cred_add(newcred
); 
5082                 KAUTH_CRED_HASH_UNLOCK(); 
5084                 /* Retry if kauth_cred_add() fails */ 
5088                 mac_cred_label_destroy(newcred
); 
5090                 AUDIT_SESSION_UNREF(newcred
); 
5092                 FREE_ZONE(newcred
, sizeof(*newcred
), M_CRED
); 
5103  * Description: Common code to update a credential 
5105  * Parameters:  old_cred                        Reference counted credential 
5107  *              model_cred                      Non-reference counted model 
5108  *                                              credential to apply to the 
5109  *                                              credential to be updated 
5110  *              retain_auditinfo                Flag as to whether or not the 
5111  *                                              audit information should be 
5112  *                                              copied from the old_cred into 
5115  * Returns:     (kauth_cred_t)                  The updated credential 
5117  * IMPORTANT:   This function will potentially return a credential other than 
5118  *              the one it is passed, and if so, it will have dropped the 
5119  *              reference on the passed credential.  All callers should be 
5120  *              aware of this, and treat this function as an unref + ref, 
5121  *              potentially on different credentials. 
5123  *              Because of this, the caller is expected to take its own 
5124  *              reference on the credential passed as the first parameter, 
5125  *              and be prepared to release the reference on the credential 
5126  *              that is returned to them, if it is not intended to be a 
5127  *              persistent reference. 
5130 kauth_cred_update(kauth_cred_t old_cred
, kauth_cred_t model_cred
, 
5131         boolean_t retain_auditinfo
) 
5133         kauth_cred_t found_cred
, new_cred 
= NULL
; 
5136          * Make sure we carry the auditinfo forward to the new credential 
5137          * unless we are actually updating the auditinfo. 
5139         if (retain_auditinfo
) { 
5140                 bcopy(&old_cred
->cr_audit
, &model_cred
->cr_audit
,  
5141                     sizeof(model_cred
->cr_audit
)); 
5147                 KAUTH_CRED_HASH_LOCK(); 
5148                 found_cred 
= kauth_cred_find(model_cred
); 
5149                 if (found_cred 
== old_cred
) { 
5150                         /* same cred so just bail */ 
5151                         KAUTH_CRED_HASH_UNLOCK(); 
5154                 if (found_cred 
!= NULL
) { 
5155                         boolean_t destroy_it
; 
5157                         DEBUG_CRED_CHANGE("kauth_cred_update(cache hit): %p -> %p\n", old_cred
, found_cred
); 
5159                          * Found a match so we bump reference count on new 
5160                          * one and decrement reference count on the old one. 
5162                         kauth_cred_ref(found_cred
); 
5163                         destroy_it 
= kauth_cred_unref_hashlocked(&old_cred
); 
5164                         KAUTH_CRED_HASH_UNLOCK(); 
5165                         if (destroy_it 
== TRUE
) { 
5166                                 assert(old_cred 
!= NOCRED
); 
5168                                 mac_cred_label_destroy(old_cred
); 
5170                                 AUDIT_SESSION_UNREF(old_cred
); 
5172                                 old_cred
->cr_ref 
= 0; 
5173                                 FREE_ZONE(old_cred
, sizeof(*old_cred
), M_CRED
); 
5181                  * Must allocate a new credential using the model.  also 
5182                  * adds the new credential to the credential hash table. 
5184                 new_cred 
= kauth_cred_dup(model_cred
); 
5185                 err 
= kauth_cred_add(new_cred
); 
5186                 KAUTH_CRED_HASH_UNLOCK(); 
5188                 /* retry if kauth_cred_add returns non zero value */ 
5192                 mac_cred_label_destroy(new_cred
); 
5194                 AUDIT_SESSION_UNREF(new_cred
); 
5196                 FREE_ZONE(new_cred
, sizeof(*new_cred
), M_CRED
); 
5200         DEBUG_CRED_CHANGE("kauth_cred_update(cache miss): %p -> %p\n", old_cred
, new_cred
); 
5201         kauth_cred_unref(&old_cred
); 
5209  * Description: Add the given credential to our credential hash table and 
5210  *              take an additional reference to account for our use of the 
5211  *              credential in the hash table 
5213  * Parameters:  new_cred                        Credential to insert into cred 
5216  * Returns:     0                               Success 
5217  *              -1                              Hash insertion failed: caller 
5220  * Locks:       Caller is expected to hold KAUTH_CRED_HASH_LOCK 
5222  * Notes:       The 'new_cred' MUST NOT already be in the cred hash cache 
5225 kauth_cred_add(kauth_cred_t new_cred
) 
5229         KAUTH_CRED_HASH_LOCK_ASSERT(); 
5231         hash_key 
= kauth_cred_get_hashkey(new_cred
); 
5232         hash_key 
%= KAUTH_CRED_TABLE_SIZE
; 
5234         /* race fix - there is a window where another matching credential  
5235          * could have been inserted between the time this one was created and we 
5236          * got the hash lock.  If we find a match return an error and have the  
5239         if (kauth_cred_find(new_cred
) != NULL
) { 
5243         /* take a reference for our use in credential hash table */  
5244         kauth_cred_ref(new_cred
); 
5246         /* insert the credential into the hash table */ 
5247         TAILQ_INSERT_HEAD(&kauth_cred_table_anchor
[hash_key
], new_cred
, cr_link
); 
5256  * Description: Remove the given credential from our credential hash table 
5258  * Parameters:  cred                            Credential to remove from cred 
5261  * Returns:     TRUE if the cred was found & removed from the hash; FALSE if not. 
5263  * Locks:       Caller is expected to hold KAUTH_CRED_HASH_LOCK 
5265  * Notes:       The check for the reference increment after entry is generally 
5266  *              agree to be safe, since we use atomic operations, and the 
5267  *              following code occurs with the hash lock held; in theory, this 
5268  *              protects us from the 2->1 reference that gets us here. 
5271 kauth_cred_remove(kauth_cred_t cred
) 
5274         kauth_cred_t    found_cred
; 
5276         hash_key 
= kauth_cred_get_hashkey(cred
); 
5277         hash_key 
%= KAUTH_CRED_TABLE_SIZE
; 
5280         if (cred
->cr_ref 
< 1) 
5281                 panic("cred reference underflow"); 
5282         if (cred
->cr_ref 
> 1) 
5283                 return (FALSE
);         /* someone else got a ref */ 
5285         /* Find cred in the credential hash table */ 
5286         TAILQ_FOREACH(found_cred
, &kauth_cred_table_anchor
[hash_key
], cr_link
) { 
5287                 if (found_cred 
== cred
) { 
5288                         /* found a match, remove it from the hash table */ 
5289                         TAILQ_REMOVE(&kauth_cred_table_anchor
[hash_key
], found_cred
, cr_link
); 
5290 #if KAUTH_CRED_HASH_DEBUG 
5297         /* Did not find a match... this should not happen! XXX Make panic? */ 
5298         printf("%s:%d - %s - %s - did not find a match for %p\n", __FILE__
, __LINE__
, __FUNCTION__
, current_proc()->p_comm
, cred
); 
5306  * Description: Using the given credential data, look for a match in our 
5307  *              credential hash table 
5309  * Parameters:  cred                            Credential to lookup in cred 
5312  * Returns:     NULL                            Not found 
5313  *              !NULL                           Matching credential already in 
5316  * Locks:       Caller is expected to hold KAUTH_CRED_HASH_LOCK 
5319 kauth_cred_find(kauth_cred_t cred
) 
5322         kauth_cred_t    found_cred
; 
5323         posix_cred_t pcred 
= posix_cred_get(cred
); 
5325         KAUTH_CRED_HASH_LOCK_ASSERT(); 
5327 #if KAUTH_CRED_HASH_DEBUG 
5328         static int              test_count 
= 0;  
5331         if ((test_count 
% 200) == 0) { 
5332                 kauth_cred_hash_print(); 
5336         hash_key 
= kauth_cred_get_hashkey(cred
); 
5337         hash_key 
%= KAUTH_CRED_TABLE_SIZE
; 
5339         /* Find cred in the credential hash table */ 
5340         TAILQ_FOREACH(found_cred
, &kauth_cred_table_anchor
[hash_key
], cr_link
) { 
5342                 posix_cred_t found_pcred 
= posix_cred_get(found_cred
); 
5345                  * don't worry about the label unless the flags in 
5346                  * either credential tell us to. 
5348                 match 
= (bcmp(found_pcred
, pcred
, sizeof (*pcred
)) == 0) ? TRUE 
: FALSE
; 
5349                 match 
= match 
&& ((bcmp(&found_cred
->cr_audit
, &cred
->cr_audit
, 
5350                         sizeof(cred
->cr_audit
)) == 0) ? TRUE 
: FALSE
); 
5352                 if (((found_pcred
->cr_flags 
& CRF_MAC_ENFORCE
) != 0) || 
5353                     ((pcred
->cr_flags 
& CRF_MAC_ENFORCE
) != 0)) { 
5354                         match 
= match 
&& mac_cred_label_compare(found_cred
->cr_label
, 
5363         /* No match found */ 
5372  * Description: Generates a hash key using data that makes up a credential; 
5375  * Parameters:  datap                           Pointer to data to hash 
5376  *              data_len                        Count of bytes to hash 
5377  *              start_key                       Start key value 
5379  * Returns:     (u_long)                        Returned hash key 
5381 static inline u_long
 
5382 kauth_cred_hash(const uint8_t *datap
, int data_len
, u_long start_key
) 
5384         u_long  hash_key 
= start_key
; 
5387         while (data_len 
> 0) { 
5388                 hash_key 
= (hash_key 
<< 4) + *datap
++; 
5389                 temp 
= hash_key 
& 0xF0000000; 
5391                         hash_key 
^= temp 
>> 24; 
5401  * kauth_cred_get_hashkey 
5403  * Description: Generate a hash key using data that makes up a credential; 
5404  *              based on ElfHash.  We hash on the entire credential data, 
5405  *              not including the ref count or the TAILQ, which are mutable; 
5406  *              everything else isn't. 
5408  * Parameters:  cred                            Credential for which hash is 
5411  * Returns:     (u_long)                        Returned hash key 
5413  * Notes:       When actually moving the POSIX credential into a real label, 
5414  *              remember to update this hash computation. 
5417 kauth_cred_get_hashkey(kauth_cred_t cred
) 
5420         posix_cred_t pcred 
= posix_cred_get(cred
); 
5422         u_long  hash_key 
= 0; 
5424         hash_key 
= kauth_cred_hash((uint8_t *)&cred
->cr_posix
,  
5425                                                            sizeof (struct posix_cred
), 
5427         hash_key 
= kauth_cred_hash((uint8_t *)&cred
->cr_audit
,  
5428                                                            sizeof(struct au_session
), 
5431         if (pcred
->cr_flags 
& CRF_MAC_ENFORCE
) { 
5432                 hash_key 
= kauth_cred_hash((uint8_t *)cred
->cr_label
,  
5433                                                                    sizeof (struct label
), 
5441 #if KAUTH_CRED_HASH_DEBUG 
5443  * kauth_cred_hash_print 
5445  * Description: Print out cred hash cache table information for debugging 
5446  *              purposes, including the credential contents 
5448  * Parameters:  (void) 
5452  * Implicit returns:    Results in console output 
5455 kauth_cred_hash_print(void)  
5458         kauth_cred_t    found_cred
; 
5460         printf("\n\t kauth credential hash table statistics - current cred count %d \n", kauth_cred_count
); 
5461         /* count slot hits, misses, collisions, and max depth */ 
5462         for (i 
= 0; i 
< KAUTH_CRED_TABLE_SIZE
; i
++) { 
5463                 printf("[%02d] ", i
); 
5465                 TAILQ_FOREACH(found_cred
, &kauth_cred_table_anchor
[i
], cr_link
) { 
5470                         kauth_cred_print(found_cred
); 
5474                         printf("NOCRED \n"); 
5478 #endif  /* KAUTH_CRED_HASH_DEBUG */ 
5481 #if (defined(KAUTH_CRED_HASH_DEBUG) && (KAUTH_CRED_HASH_DEBUG != 0)) || defined(DEBUG_CRED) 
5485  * Description: Print out an individual credential's contents for debugging 
5488  * Parameters:  cred                            The credential to print out 
5492  * Implicit returns:    Results in console output 
5495 kauth_cred_print(kauth_cred_t cred
)  
5499         printf("%p - refs %lu flags 0x%08x uids e%d r%d sv%d gm%d ", cred
, cred
->cr_ref
, cred
->cr_flags
, cred
->cr_uid
, cred
->cr_ruid
, cred
->cr_svuid
, cred
->cr_gmuid
); 
5500         printf("group count %d gids ", cred
->cr_ngroups
); 
5501         for (i 
= 0; i 
< NGROUPS
; i
++) { 
5504                 printf("%d ", cred
->cr_groups
[i
]); 
5506         printf("r%d sv%d ", cred
->cr_rgid
, cred
->cr_svgid
); 
5507         printf("auditinfo_addr %d %d %d %d %d %d\n",  
5508                 cred
->cr_audit
.s_aia_p
->ai_auid
, 
5509                 cred
->cr_audit
.as_mask
.am_success
, 
5510                 cred
->cr_audit
.as_mask
.am_failure
, 
5511                 cred
->cr_audit
.as_aia_p
->ai_termid
.at_port
, 
5512                 cred
->cr_audit
.as_aia_p
->ai_termid
.at_addr
[0], 
5513                 cred
->cr_audit
.as_aia_p
->ai_asid
); 
5516 int is_target_cred( kauth_cred_t the_cred 
) 
5518         if ( the_cred
->cr_uid 
!= 0 )  
5520         if ( the_cred
->cr_ruid 
!= 0 )  
5522         if ( the_cred
->cr_svuid 
!= 0 )  
5524         if ( the_cred
->cr_ngroups 
!= 11 )  
5526         if ( the_cred
->cr_groups
[0] != 11 )  
5528         if ( the_cred
->cr_groups
[1] != 81 )  
5530         if ( the_cred
->cr_groups
[2] != 63947 )  
5532         if ( the_cred
->cr_groups
[3] != 80288 )  
5534         if ( the_cred
->cr_groups
[4] != 89006 )  
5536         if ( the_cred
->cr_groups
[5] != 52173 )  
5538         if ( the_cred
->cr_groups
[6] != 84524 )  
5540         if ( the_cred
->cr_groups
[7] != 79 )  
5542         if ( the_cred
->cr_groups
[8] != 80292 )  
5544         if ( the_cred
->cr_groups
[9] != 80 )  
5546         if ( the_cred
->cr_groups
[10] != 90824 )  
5548         if ( the_cred
->cr_rgid 
!= 11 )  
5550         if ( the_cred
->cr_svgid 
!= 11 )  
5552         if ( the_cred
->cr_gmuid 
!= 3475 )  
5554         if ( the_cred
->cr_audit
.as_aia_p
->ai_auid 
!= 3475 )  
5557         if ( the_cred->cr_audit.as_mask.am_success != 0 )  
5559         if ( the_cred->cr_audit.as_mask.am_failure != 0 )  
5561         if ( the_cred->cr_audit.as_aia_p->ai_termid.at_port != 0 )  
5563         if ( the_cred->cr_audit.as_aia_p->ai_termid.at_addr[0] != 0 )  
5565         if ( the_cred->cr_audit.as_aia_p->ai_asid != 0 )  
5567         if ( the_cred->cr_flags != 0 )  
5570         return( -1 ); // found target cred 
5573 void get_backtrace( void ) 
5576         void *                  my_stack
[ MAX_STACK_DEPTH 
]; 
5579         if ( cred_debug_buf_p 
== NULL 
) { 
5580                 MALLOC(cred_debug_buf_p
, cred_debug_buffer 
*, sizeof(*cred_debug_buf_p
), M_KAUTH
, M_WAITOK
); 
5581                 bzero(cred_debug_buf_p
, sizeof(*cred_debug_buf_p
)); 
5584         if ( cred_debug_buf_p
->next_slot 
> (MAX_CRED_BUFFER_SLOTS 
- 1) ) { 
5585                 /* buffer is full */ 
5589         my_depth 
= OSBacktrace(&my_stack
[0], MAX_STACK_DEPTH
); 
5590         if ( my_depth 
== 0 ) { 
5591                 printf("%s - OSBacktrace failed \n", __FUNCTION__
); 
5595         /* fill new backtrace */ 
5596         my_slot 
= cred_debug_buf_p
->next_slot
; 
5597         cred_debug_buf_p
->next_slot
++; 
5598         cred_debug_buf_p
->stack_buffer
[ my_slot 
].depth 
= my_depth
; 
5599         for ( i 
= 0; i 
< my_depth
; i
++ ) { 
5600                 cred_debug_buf_p
->stack_buffer
[ my_slot 
].stack
[ i 
] = my_stack
[ i 
]; 
5607 /* subset of struct ucred for use in sysctl_dump_creds */ 
5608 struct debug_ucred 
{ 
5610         u_long  cr_ref
;                         /* reference count */ 
5611         uid_t   cr_uid
;                         /* effective user id */ 
5612         uid_t   cr_ruid
;                        /* real user id */ 
5613         uid_t   cr_svuid
;                       /* saved user id */ 
5614         short   cr_ngroups
;                     /* number of groups in advisory list */ 
5615         gid_t   cr_groups
[NGROUPS
];     /* advisory group list */ 
5616         gid_t   cr_rgid
;                        /* real group id */ 
5617         gid_t   cr_svgid
;                       /* saved group id */ 
5618         uid_t   cr_gmuid
;                       /* UID for group membership purposes */ 
5619         struct auditinfo_addr cr_audit
; /* user auditing data. */ 
5620         void    *cr_label
;                      /* MACF label */ 
5621         int             cr_flags
;                       /* flags on credential */ 
5623 typedef struct debug_ucred debug_ucred
; 
5625 SYSCTL_PROC(_kern
, OID_AUTO
, dump_creds
, CTLFLAG_RD
, 
5626     NULL
, 0, sysctl_dump_creds
, "S,debug_ucred", "List of credentials in the cred hash"); 
5629  *      err = sysctlbyname( "kern.dump_creds", bufp, &len, NULL, 0 ); 
5633 sysctl_dump_creds( __unused 
struct sysctl_oid 
*oidp
, __unused 
void *arg1
, __unused 
int arg2
, struct sysctl_req 
*req 
) 
5635         int                     i
, j
, counter 
= 0; 
5638         kauth_cred_t    found_cred
; 
5639         debug_ucred 
*   cred_listp
; 
5640         debug_ucred 
*   nextp
; 
5642         /* This is a readonly node. */ 
5643         if (req
->newptr 
!= USER_ADDR_NULL
) 
5646         /* calculate space needed */ 
5647         for (i 
= 0; i 
< KAUTH_CRED_TABLE_SIZE
; i
++) { 
5648                 TAILQ_FOREACH(found_cred
, &kauth_cred_table_anchor
[i
], cr_link
) { 
5653         /* they are querying us so just return the space required. */ 
5654         if (req
->oldptr 
== USER_ADDR_NULL
) { 
5655                 counter 
+= 10; // add in some padding; 
5656                 req
->oldidx 
= counter 
* sizeof(debug_ucred
); 
5660         MALLOC( cred_listp
, debug_ucred 
*, req
->oldlen
, M_TEMP
, M_WAITOK 
| M_ZERO
); 
5661         if ( cred_listp 
== NULL 
) { 
5665         /* fill in creds to send back */ 
5668         for (i 
= 0; i 
< KAUTH_CRED_TABLE_SIZE
; i
++) { 
5669                 TAILQ_FOREACH(found_cred
, &kauth_cred_table_anchor
[i
], cr_link
) { 
5670                         nextp
->credp 
= found_cred
; 
5671                         nextp
->cr_ref 
= found_cred
->cr_ref
; 
5672                         nextp
->cr_uid 
= found_cred
->cr_uid
; 
5673                         nextp
->cr_ruid 
= found_cred
->cr_ruid
; 
5674                         nextp
->cr_svuid 
= found_cred
->cr_svuid
; 
5675                         nextp
->cr_ngroups 
= found_cred
->cr_ngroups
; 
5676                         for ( j 
= 0; j 
< nextp
->cr_ngroups
; j
++ ) { 
5677                                 nextp
->cr_groups
[ j 
] = found_cred
->cr_groups
[ j 
]; 
5679                         nextp
->cr_rgid 
= found_cred
->cr_rgid
; 
5680                         nextp
->cr_svgid 
= found_cred
->cr_svgid
; 
5681                         nextp
->cr_gmuid 
= found_cred
->cr_gmuid
; 
5682                         nextp
->cr_audit
.ai_auid 
= 
5683                             found_cred
->cr_audit
.as_aia_p
->ai_auid
; 
5684                         nextp
->cr_audit
.ai_mask
.am_success 
= 
5685                             found_cred
->cr_audit
.as_mask
.am_success
; 
5686                         nextp
->cr_audit
.ai_mask
.am_failure 
= 
5687                             found_cred
->cr_audit
.as_mask
.am_failure
; 
5688                         nextp
->cr_audit
.ai_termid
.at_port 
= 
5689                             found_cred
->cr_audit
.as_aia_p
->ai_termid
.at_port
; 
5690                         nextp
->cr_audit
.ai_termid
.at_type 
= 
5691                             found_cred
->cr_audit
.as_aia_p
->ai_termid
.at_type
; 
5692                         nextp
->cr_audit
.ai_termid
.at_addr
[0] = 
5693                             found_cred
->cr_audit
.as_aia_p
->ai_termid
.at_addr
[0]; 
5694                         nextp
->cr_audit
.ai_termid
.at_addr
[1] = 
5695                             found_cred
->cr_audit
.as_aia_p
->ai_termid
.at_addr
[1]; 
5696                         nextp
->cr_audit
.ai_termid
.at_addr
[2] = 
5697                             found_cred
->cr_audit
.as_aia_p
->ai_termid
.at_addr
[2]; 
5698                         nextp
->cr_audit
.ai_termid
.at_addr
[3] = 
5699                             found_cred
->cr_audit
.as_aia_p
->ai_termid
.at_addr
[3]; 
5700                         nextp
->cr_audit
.ai_asid 
= 
5701                             found_cred
->cr_audit
.as_aia_p
->ai_asid
; 
5702                         nextp
->cr_audit
.ai_flags 
= 
5703                             found_cred
->cr_audit
.as_aia_p
->ai_flags
; 
5704                         nextp
->cr_label 
= found_cred
->cr_label
; 
5705                         nextp
->cr_flags 
= found_cred
->cr_flags
; 
5707                         space 
+= sizeof(debug_ucred
); 
5708                         if ( space 
> req
->oldlen 
) { 
5709                                 FREE(cred_listp
, M_TEMP
); 
5714         req
->oldlen 
= space
; 
5715         error 
= SYSCTL_OUT(req
, cred_listp
, req
->oldlen
); 
5716         FREE(cred_listp
, M_TEMP
); 
5721 SYSCTL_PROC(_kern
, OID_AUTO
, cred_bt
, CTLFLAG_RD
, 
5722     NULL
, 0, sysctl_dump_cred_backtraces
, "S,cred_debug_buffer", "dump credential backtrace"); 
5725  *      err = sysctlbyname( "kern.cred_bt", bufp, &len, NULL, 0 ); 
5729 sysctl_dump_cred_backtraces( __unused 
struct sysctl_oid 
*oidp
, __unused 
void *arg1
, __unused 
int arg2
, struct sysctl_req 
*req 
) 
5734         cred_debug_buffer 
*     bt_bufp
; 
5735         cred_backtrace 
*        nextp
; 
5737         /* This is a readonly node. */ 
5738         if (req
->newptr 
!= USER_ADDR_NULL
) 
5741         if ( cred_debug_buf_p 
== NULL 
) { 
5745         /* calculate space needed */ 
5746         space 
= sizeof( cred_debug_buf_p
->next_slot 
); 
5747         space 
+= (sizeof( cred_backtrace 
) * cred_debug_buf_p
->next_slot
); 
5749         /* they are querying us so just return the space required. */ 
5750         if (req
->oldptr 
== USER_ADDR_NULL
) { 
5751                 req
->oldidx 
= space
; 
5755         if ( space 
> req
->oldlen 
) { 
5759         MALLOC( bt_bufp
, cred_debug_buffer 
*, req
->oldlen
, M_TEMP
, M_WAITOK 
| M_ZERO
); 
5760         if ( bt_bufp 
== NULL 
) { 
5764         /* fill in backtrace info to send back */ 
5765         bt_bufp
->next_slot 
= cred_debug_buf_p
->next_slot
; 
5766         space 
= sizeof(bt_bufp
->next_slot
); 
5768         nextp 
= &bt_bufp
->stack_buffer
[ 0 ]; 
5769         for (i 
= 0; i 
< cred_debug_buf_p
->next_slot
; i
++) { 
5770                 nextp
->depth 
= cred_debug_buf_p
->stack_buffer
[ i 
].depth
; 
5771                 for ( j 
= 0; j 
< nextp
->depth
; j
++ ) { 
5772                         nextp
->stack
[ j 
] = cred_debug_buf_p
->stack_buffer
[ i 
].stack
[ j 
]; 
5774                 space 
+= sizeof(*nextp
); 
5777         req
->oldlen 
= space
; 
5778         error 
= SYSCTL_OUT(req
, bt_bufp
, req
->oldlen
); 
5779         FREE(bt_bufp
, M_TEMP
); 
5783 #endif  /* KAUTH_CRED_HASH_DEBUG || DEBUG_CRED */ 
5787  ********************************************************************** 
5788  * The following routines will be moved to a policy_posix.c module at 
5789  * some future point. 
5790  ********************************************************************** 
5796  * Description: Helper function to create a kauth_cred_t credential that is 
5797  *              initally labelled with a specific POSIX credential label 
5799  * Parameters:  pcred                   The posix_cred_t to use as the initial 
5802  * Returns:     (kauth_cred_t)          The credential that was found in the 
5804  *              NULL                    kauth_cred_add() failed, or there was 
5805  *                                      no egid specified, or we failed to 
5806  *                                      attach a label to the new credential 
5808  * Notes:       This function currently wraps kauth_cred_create(), and is the 
5809  *              only consumer of that ill-fated function, apart from bsd_init(). 
5810  *              It exists solely to support the NFS server code creation of 
5811  *              credentials based on the over-the-wire RPC calls containing 
5812  *              traditional POSIX credential information being tunneled to 
5813  *              the server host from the client machine. 
5815  *              In the future, we hope this function goes away. 
5817  *              In the short term, it creates a temporary credential, puts 
5818  *              the POSIX information from NFS into it, and then calls 
5819  *              kauth_cred_create(), as an internal implementation detail. 
5821  *              If we have to keep it around in the medium term, it will 
5822  *              create a new kauth_cred_t, then label it with a POSIX label 
5823  *              corresponding to the contents of the kauth_cred_t.  If the 
5824  *              policy_posix MACF module is not loaded, it will instead 
5825  *              substitute a posix_cred_t which GRANTS all access (effectively 
5826  *              a "root" credential) in order to not prevent NFS from working 
5827  *              in the case that we are not supporting POSIX credentials. 
5830 posix_cred_create(posix_cred_t pcred
) 
5832         struct ucred temp_cred
; 
5834         bzero(&temp_cred
, sizeof(temp_cred
)); 
5835         temp_cred
.cr_posix 
= *pcred
; 
5837         return kauth_cred_create(&temp_cred
); 
5844  * Description: Given a kauth_cred_t, return the POSIX credential label, if 
5845  *              any, which is associated with it. 
5847  * Parameters:  cred                    The credential to obtain the label from 
5849  * Returns:     posix_cred_t            The POSIX credential label 
5851  * Notes:       In the event that the policy_posix MACF module IS NOT loaded, 
5852  *              this function will return a pointer to a posix_cred_t which 
5853  *              GRANTS all access (effectively, a "root" credential).  This is 
5854  *              necessary to support legacy code which insists on tightly 
5855  *              integrating POSIX credentials into its APIs, including, but 
5856  *              not limited to, System V IPC mechanisms, POSIX IPC mechanisms, 
5857  *              NFSv3, signals, dtrace, and a large number of kauth routines 
5858  *              used to implement POSIX permissions related system calls. 
5860  *              In the event that the policy_posix MACF module IS loaded, and 
5861  *              there is no POSIX label on the kauth_cred_t credential, this 
5862  *              function will return a pointer to a posix_cred_t which DENIES 
5863  *              all access (effectively, a "deny rights granted by POSIX" 
5864  *              credential).  This is necessary to support the concept of a 
5865  *              transiently loaded POSIX policy, or kauth_cred_t credentials 
5866  *              which can not be used in conjunctions with POSIX permissions 
5869  *              This function currently returns the address of the cr_posix 
5870  *              field of the supplied kauth_cred_t credential, and as such 
5871  *              currently can not fail.  In the future, this will not be the 
5875 posix_cred_get(kauth_cred_t cred
) 
5877         return(&cred
->cr_posix
); 
5884  * Description: Label a kauth_cred_t with a POSIX credential label 
5886  * Parameters:  cred                    The credential to label 
5887  *              pcred                   The POSIX credential t label it with 
5891  * Notes:       This function is currently void in order to permit it to fit 
5892  *              in with the current MACF framework label methods which allow 
5893  *              labeling to fail silently.  This is like acceptable for 
5894  *              mandatory access controls, but not for POSIX, since those 
5895  *              access controls are advisory.  We will need to consider a 
5896  *              return value in a future version of the MACF API. 
5898  *              This operation currently cannot fail, as currently the POSIX 
5899  *              credential is a subfield of the kauth_cred_t (ucred), which 
5900  *              MUST be valid.  In the future, this will not be the case. 
5903 posix_cred_label(kauth_cred_t cred
, posix_cred_t pcred
) 
5905         cred
->cr_posix 
= *pcred
;        /* structure assign for now */ 
5912  * Description: Perform a POSIX access check for a protected object 
5914  * Parameters:  cred                    The credential to check 
5915  *              object_uid              The POSIX UID of the protected object 
5916  *              object_gid              The POSIX GID of the protected object 
5917  *              object_mode             The POSIX mode of the protected object 
5918  *              mode_req                The requested POSIX access rights 
5920  * Returns      0                       Access is granted 
5921  *              EACCES                  Access is denied 
5923  * Notes:       This code optimizes the case where the world and group rights 
5924  *              would both grant the requested rights to avoid making a group 
5925  *              membership query.  This is a big performance win in the case 
5926  *              where this is true. 
5929 posix_cred_access(kauth_cred_t cred
, id_t object_uid
, id_t object_gid
, mode_t object_mode
, mode_t mode_req
) 
5932         mode_t mode_owner 
= (object_mode 
& S_IRWXU
); 
5933         mode_t mode_group 
= (object_mode 
& S_IRWXG
) << 3; 
5934         mode_t mode_world 
= (object_mode 
& S_IRWXO
) << 6; 
5937          * Check first for owner rights 
5939         if (kauth_cred_getuid(cred
) == object_uid 
&& (mode_req 
& mode_owner
) == mode_req
) 
5943          * Combined group and world rights check, if we don't have owner rights 
5945          * OPTIMIZED: If group and world rights would grant the same bits, and 
5946          * they set of requested bits is in both, then we can simply check the 
5947          * world rights, avoiding a group membership check, which is expensive. 
5949         if ((mode_req 
& mode_group 
& mode_world
) == mode_req
) { 
5953                  * NON-OPTIMIZED: requires group membership check. 
5955                 if ((mode_req 
& mode_group
) != mode_req
) { 
5957                          * exclusion group : treat errors as "is a member" 
5959                          * NON-OPTIMIZED: +group would deny; must check group 
5961                         if (!kauth_cred_ismember_gid(cred
, object_gid
, &is_member
) && is_member
) { 
5963                                  * DENY: +group denies 
5967                                 if ((mode_req 
& mode_world
) != mode_req
) { 
5969                                          * DENY: both -group & world would deny 
5974                                          * ALLOW: allowed by -group and +world 
5981                          * inclusion group; treat errors as "not a member" 
5983                          * NON-OPTIMIZED: +group allows, world denies; must 
5986                         if (!kauth_cred_ismember_gid(cred
, object_gid
, &is_member
) && is_member
) { 
5988                                  * ALLOW: allowed by +group 
5992                                 if ((mode_req 
& mode_world
) != mode_req
) { 
5994                                          * DENY: both -group & world would deny 
5999                                          * ALLOW: allowed by -group and +world