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 void mach_kauth_cred_uthread_update( void ); 
  79 #define CRED_DIAGNOSTIC 0 
  81 # define NULLCRED_CHECK(_c)     do {if (!IS_VALID_CRED(_c)) panic("%s: bad credential %p", __FUNCTION__,_c);} while(0) 
  83 /* Set to 1 to turn on KAUTH_DEBUG for kern_credential.c */ 
  97 # define K_UUID_FMT "%08x:%08x:%08x:%08x" 
  98 # 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] 
  99 # define KAUTH_DEBUG(fmt, args...)      do { printf("%s:%d: " fmt "\n", __PRETTY_FUNCTION__, __LINE__ , ##args); } while (0) 
 103  * Credential debugging; we can track entry into a function that might 
 104  * change a credential, and we can track actual credential changes that 
 107  * Note:        Does *NOT* currently include per-thread credential changes 
 111 #define DEBUG_CRED_ENTER                printf 
 112 #define DEBUG_CRED_CHANGE               printf 
 113 extern void kauth_cred_print(kauth_cred_t cred
); 
 115 #include <libkern/OSDebug.h>    /* needed for get_backtrace( ) */ 
 117 int is_target_cred( kauth_cred_t the_cred 
); 
 118 void get_backtrace( void ); 
 120 static int sysctl_dump_creds( __unused 
struct sysctl_oid 
*oidp
, __unused 
void *arg1
,  
 121                                                           __unused 
int arg2
, struct sysctl_req 
*req 
); 
 123 sysctl_dump_cred_backtraces( __unused 
struct sysctl_oid 
*oidp
, __unused 
void *arg1
,  
 124                                                          __unused 
int arg2
, struct sysctl_req 
*req 
); 
 126 #define MAX_STACK_DEPTH 8 
 127 struct cred_backtrace 
{ 
 129         void *                  stack
[ MAX_STACK_DEPTH 
]; 
 131 typedef struct cred_backtrace cred_backtrace
; 
 133 #define MAX_CRED_BUFFER_SLOTS 200 
 134 struct cred_debug_buffer 
{ 
 136         cred_backtrace  stack_buffer
[ MAX_CRED_BUFFER_SLOTS 
];   
 138 typedef struct cred_debug_buffer cred_debug_buffer
; 
 139 cred_debug_buffer 
* cred_debug_buf_p 
= NULL
; 
 141 #else   /* !DEBUG_CRED */ 
 143 #define DEBUG_CRED_ENTER(fmt, ...)      do {} while (0) 
 144 #define DEBUG_CRED_CHANGE(fmt, ...)     do {} while (0) 
 146 #endif  /* !DEBUG_CRED */ 
 148 #if CONFIG_EXT_RESOLVER 
 150  * Interface to external identity resolver. 
 152  * The architecture of the interface is simple; the external resolver calls 
 153  * in to get work, then calls back with completed work.  It also calls us 
 154  * to let us know that it's (re)started, so that we can resubmit work if it 
 158 static lck_mtx_t 
*kauth_resolver_mtx
; 
 159 #define KAUTH_RESOLVER_LOCK()   lck_mtx_lock(kauth_resolver_mtx); 
 160 #define KAUTH_RESOLVER_UNLOCK() lck_mtx_unlock(kauth_resolver_mtx); 
 162 static volatile pid_t   kauth_resolver_identity
; 
 163 static int      kauth_identitysvc_has_registered
; 
 164 static int      kauth_resolver_registered
; 
 165 static uint32_t kauth_resolver_sequence
; 
 166 static int      kauth_resolver_timeout 
= 30;    /* default: 30 seconds */ 
 168 struct kauth_resolver_work 
{ 
 169         TAILQ_ENTRY(kauth_resolver_work
) kr_link
; 
 170         struct kauth_identity_extlookup kr_work
; 
 175 #define KAUTH_REQUEST_UNSUBMITTED       (1<<0) 
 176 #define KAUTH_REQUEST_SUBMITTED         (1<<1) 
 177 #define KAUTH_REQUEST_DONE              (1<<2) 
 181 TAILQ_HEAD(kauth_resolver_unsubmitted_head
, kauth_resolver_work
) kauth_resolver_unsubmitted
; 
 182 TAILQ_HEAD(kauth_resolver_submitted_head
, kauth_resolver_work
)  kauth_resolver_submitted
; 
 183 TAILQ_HEAD(kauth_resolver_done_head
, kauth_resolver_work
)       kauth_resolver_done
; 
 185 /* Number of resolver timeouts between logged complaints */ 
 186 #define KAUTH_COMPLAINT_INTERVAL 1000 
 187 int kauth_resolver_timeout_cnt 
= 0; 
 189 static int      kauth_resolver_submit(struct kauth_identity_extlookup 
*lkp
, uint64_t extend_data
); 
 190 static int      kauth_resolver_complete(user_addr_t message
); 
 191 static int      kauth_resolver_getwork(user_addr_t message
); 
 192 static int      kauth_resolver_getwork2(user_addr_t message
); 
 193 static __attribute__((noinline
)) int __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__( 
 194         struct kauth_resolver_work 
*);  
 196 #define KAUTH_CACHES_MAX_SIZE 10000 /* Max # entries for both groups and id caches */ 
 198 struct kauth_identity 
{ 
 199         TAILQ_ENTRY(kauth_identity
) ki_link
; 
 204         gid_t   ki_supgrps
[NGROUPS
]; 
 207         const char      *ki_name
;       /* string name from string cache */ 
 209          * Expiry times are the earliest time at which we will disregard the 
 210          * cached state and go to userland.  Before then if the valid bit is 
 211          * set, we will return the cached value.  If it's not set, we will 
 212          * not go to userland to resolve, just assume that there is no answer 
 215         time_t  ki_groups_expiry
; 
 216         time_t  ki_guid_expiry
; 
 217         time_t  ki_ntsid_expiry
; 
 220 static TAILQ_HEAD(kauth_identity_head
, kauth_identity
) kauth_identities
; 
 221 static lck_mtx_t 
*kauth_identity_mtx
; 
 222 #define KAUTH_IDENTITY_LOCK()   lck_mtx_lock(kauth_identity_mtx); 
 223 #define KAUTH_IDENTITY_UNLOCK() lck_mtx_unlock(kauth_identity_mtx); 
 224 #define KAUTH_IDENTITY_CACHEMAX_DEFAULT 100     /* XXX default sizing? */ 
 225 static int kauth_identity_cachemax 
= KAUTH_IDENTITY_CACHEMAX_DEFAULT
; 
 226 static int kauth_identity_count
; 
 228 static struct kauth_identity 
*kauth_identity_alloc(uid_t uid
, gid_t gid
, guid_t 
*guidp
, time_t guid_expiry
, 
 229         ntsid_t 
*ntsidp
, time_t ntsid_expiry
, int supgrpcnt
, gid_t 
*supgrps
, time_t groups_expiry
, 
 230         const char *name
, int nametype
); 
 231 static void     kauth_identity_register_and_free(struct kauth_identity 
*kip
); 
 232 static void     kauth_identity_updatecache(struct kauth_identity_extlookup 
*elp
, struct kauth_identity 
*kip
, uint64_t extend_data
); 
 233 static void     kauth_identity_trimcache(int newsize
); 
 234 static void     kauth_identity_lru(struct kauth_identity 
*kip
); 
 235 static int      kauth_identity_guid_expired(struct kauth_identity 
*kip
); 
 236 static int      kauth_identity_ntsid_expired(struct kauth_identity 
*kip
); 
 237 static int      kauth_identity_find_uid(uid_t uid
, struct kauth_identity 
*kir
, char *getname
); 
 238 static int      kauth_identity_find_gid(gid_t gid
, struct kauth_identity 
*kir
, char *getname
); 
 239 static int      kauth_identity_find_guid(guid_t 
*guidp
, struct kauth_identity 
*kir
, char *getname
); 
 240 static int      kauth_identity_find_ntsid(ntsid_t 
*ntsid
, struct kauth_identity 
*kir
, char *getname
); 
 241 static int      kauth_identity_find_nam(char *name
, int valid
, struct kauth_identity 
*kir
); 
 243 struct kauth_group_membership 
{ 
 244         TAILQ_ENTRY(kauth_group_membership
) gm_link
; 
 245         uid_t   gm_uid
;         /* the identity whose membership we're recording */ 
 246         gid_t   gm_gid
;         /* group of which they are a member */ 
 247         time_t  gm_expiry
;      /* TTL for the membership, or 0 for persistent entries */ 
 249 #define KAUTH_GROUP_ISMEMBER    (1<<0) 
 252 TAILQ_HEAD(kauth_groups_head
, kauth_group_membership
) kauth_groups
; 
 253 static lck_mtx_t 
*kauth_groups_mtx
; 
 254 #define KAUTH_GROUPS_LOCK()     lck_mtx_lock(kauth_groups_mtx); 
 255 #define KAUTH_GROUPS_UNLOCK()   lck_mtx_unlock(kauth_groups_mtx); 
 256 #define KAUTH_GROUPS_CACHEMAX_DEFAULT 100       /* XXX default sizing? */ 
 257 static int kauth_groups_cachemax 
= KAUTH_GROUPS_CACHEMAX_DEFAULT
; 
 258 static int kauth_groups_count
; 
 260 static int      kauth_groups_expired(struct kauth_group_membership 
*gm
); 
 261 static void     kauth_groups_lru(struct kauth_group_membership 
*gm
); 
 262 static void     kauth_groups_updatecache(struct kauth_identity_extlookup 
*el
); 
 263 static void     kauth_groups_trimcache(int newsize
); 
 265 #endif  /* CONFIG_EXT_RESOLVER */ 
 267 #define KAUTH_CRED_TABLE_SIZE 97 
 269 TAILQ_HEAD(kauth_cred_entry_head
, ucred
); 
 270 static struct kauth_cred_entry_head 
* kauth_cred_table_anchor 
= NULL
; 
 272 #define KAUTH_CRED_HASH_DEBUG   0 
 274 static int kauth_cred_add(kauth_cred_t new_cred
); 
 275 static boolean_t 
kauth_cred_remove(kauth_cred_t cred
); 
 276 static inline u_long 
kauth_cred_hash(const uint8_t *datap
, int data_len
, u_long start_key
); 
 277 static u_long 
kauth_cred_get_hashkey(kauth_cred_t cred
); 
 278 static kauth_cred_t 
kauth_cred_update(kauth_cred_t old_cred
, kauth_cred_t new_cred
, boolean_t retain_auditinfo
); 
 279 static boolean_t 
kauth_cred_unref_hashlocked(kauth_cred_t 
*credp
); 
 281 #if KAUTH_CRED_HASH_DEBUG 
 282 static int      kauth_cred_count 
= 0; 
 283 static void kauth_cred_hash_print(void); 
 284 static void kauth_cred_print(kauth_cred_t cred
); 
 287 #if CONFIG_EXT_RESOLVER 
 290  *  __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__ 
 292  * Description:  Waits for the user space daemon to respond to the request 
 293  *               we made. Function declared non inline to be visible in  
 294  *               stackshots and spindumps as well as debugging. 
 296  * Parameters:   workp                     Work queue entry. 
 298  * Returns:      0                         on Success. 
 299  *               EIO                       if Resolver is dead. 
 300  *               EINTR                     thread interrupted in msleep 
 301  *               EWOULDBLOCK               thread timed out in msleep 
 302  *               ERESTART                  returned by msleep. 
 305 static __attribute__((noinline
)) int  
 306 __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__( 
 307         struct kauth_resolver_work  
*workp
) 
 312                 /* we could compute a better timeout here */ 
 313                 ts
.tv_sec 
= kauth_resolver_timeout
; 
 315                 error 
= msleep(workp
, kauth_resolver_mtx
, PCATCH
, "kr_submit", &ts
); 
 316                 /* request has been completed? */ 
 317                 if ((error 
== 0) && (workp
->kr_flags 
& KAUTH_REQUEST_DONE
)) 
 319                 /* woken because the resolver has died? */ 
 320                 if (kauth_resolver_identity 
== 0) { 
 333  * kauth_resolver_init 
 335  * Description: Initialize the daemon side of the credential identity resolver 
 341  * Notes:       Initialize the credential identity resolver for use; the 
 342  *              credential identity resolver is the KPI used by the user 
 343  *              space credential identity resolver daemon to communicate 
 344  *              with the kernel via the identitysvc() system call.. 
 346  *              This is how membership in more than 16 groups (1 effective 
 347  *              and 15 supplementary) is supported, and also how UID's, 
 348  *              UUID's, and so on, are translated to/from POSIX credential 
 351  *              The credential identity resolver operates by attempting to 
 352  *              determine identity first from the credential, then from 
 353  *              the kernel credential identity cache, and finally by 
 354  *              enqueueing a request to a user space daemon. 
 356  *              This function is called from kauth_init() in the file 
 357  *              kern_authorization.c. 
 360 kauth_resolver_init(void) 
 362         TAILQ_INIT(&kauth_resolver_unsubmitted
); 
 363         TAILQ_INIT(&kauth_resolver_submitted
); 
 364         TAILQ_INIT(&kauth_resolver_done
); 
 365         kauth_resolver_sequence 
= 31337; 
 366         kauth_resolver_mtx 
= lck_mtx_alloc_init(kauth_lck_grp
, 0/*LCK_ATTR_NULL*/); 
 371  * kauth_resolver_submit 
 373  * Description: Submit an external credential identity resolution request to 
 374  *              the user space daemon. 
 376  * Parameters:  lkp                             A pointer to an external 
 378  *              extend_data                     extended data for kr_extend 
 381  *              EWOULDBLOCK                     No resolver registered 
 382  *              EINTR                           Operation interrupted (e.g. by 
 384  *              ENOMEM                          Could not allocate work item 
 385  *      copyinstr:EFAULT                        Bad message from user space 
 386  *      workp->kr_result:???                    An error from the user space 
 387  *                                              daemon (includes ENOENT!) 
 392  * Notes:       Allocate a work queue entry, submit the work and wait for 
 393  *              the operation to either complete or time out.  Outstanding 
 394  *              operations may also be cancelled. 
 396  *              Submission is by means of placing the item on a work queue 
 397  *              which is serviced by an external resolver thread calling 
 398  *              into the kernel.  The caller then sleeps until timeout, 
 399  *              cancellation, or an external resolver thread calls in with 
 400  *              a result message to kauth_resolver_complete().  All of these 
 401  *              events wake the caller back up. 
 403  *              This code is called from either kauth_cred_ismember_gid() 
 404  *              for a group membership request, or it is called from 
 405  *              kauth_cred_cache_lookup() when we get a cache miss. 
 408 kauth_resolver_submit(struct kauth_identity_extlookup 
*lkp
, uint64_t extend_data
) 
 410         struct kauth_resolver_work 
*workp
, *killp
; 
 412         int     error
, shouldfree
; 
 414         /* no point actually blocking if the resolver isn't up yet */ 
 415         if (kauth_resolver_identity 
== 0) { 
 417                  * We've already waited an initial <kauth_resolver_timeout> 
 418                  * seconds with no result. 
 420                  * Sleep on a stack address so no one wakes us before timeout; 
 421                  * we sleep a half a second in case we are a high priority 
 422                  * process, so that memberd doesn't starve while we are in a 
 423                  * tight loop between user and kernel, eating all the CPU. 
 425                 error 
= tsleep(&ts
, PZERO 
| PCATCH
, "kr_submit", hz
/2); 
 426                 if (kauth_resolver_identity 
== 0) { 
 428                          * if things haven't changed while we were asleep, 
 429                          * tell the caller we couldn't get an authoritative 
 436         MALLOC(workp
, struct kauth_resolver_work 
*, sizeof(*workp
), M_KAUTH
, M_WAITOK
); 
 440         workp
->kr_work 
= *lkp
; 
 441         workp
->kr_extend 
= extend_data
; 
 443         workp
->kr_flags 
= KAUTH_REQUEST_UNSUBMITTED
; 
 444         workp
->kr_result 
= 0; 
 447          * We insert the request onto the unsubmitted queue, the call in from 
 448          * the resolver will it to the submitted thread when appropriate. 
 450         KAUTH_RESOLVER_LOCK(); 
 451         workp
->kr_seqno 
= workp
->kr_work
.el_seqno 
= kauth_resolver_sequence
++; 
 452         workp
->kr_work
.el_result 
= KAUTH_EXTLOOKUP_INPROG
; 
 455          * XXX We *MUST NOT* attempt to coalesce identical work items due to 
 456          * XXX the inability to ensure order of update of the request item 
 457          * XXX extended data vs. the wakeup; instead, we let whoever is waiting 
 458          * XXX for each item repeat the update when they wake up. 
 460         TAILQ_INSERT_TAIL(&kauth_resolver_unsubmitted
, workp
, kr_link
); 
 463          * Wake up an external resolver thread to deal with the new work; one 
 464          * may not be available, and if not, then the request will be grabbed 
 465          * when a resolver thread comes back into the kernel to request new 
 468         wakeup_one((caddr_t
)&kauth_resolver_unsubmitted
); 
 469         error 
= __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__(workp
); 
 471         /* if the request was processed, copy the result */ 
 473                 *lkp 
= workp
->kr_work
; 
 475         if (error 
== EWOULDBLOCK
) { 
 476                 if ((kauth_resolver_timeout_cnt
++ % KAUTH_COMPLAINT_INTERVAL
) == 0) { 
 477                         printf("kauth external resolver timed out (%d timeout(s) of %d seconds).\n", 
 478                                 kauth_resolver_timeout_cnt
, kauth_resolver_timeout
); 
 481                 if (workp
->kr_flags 
& KAUTH_REQUEST_UNSUBMITTED
) { 
 483                          * If the request timed out and was never collected, the resolver 
 484                          * is dead and probably not coming back anytime soon.  In this 
 485                          * case we revert to no-resolver behaviour, and punt all the other 
 486                          * sleeping requests to clear the backlog. 
 488                         KAUTH_DEBUG("RESOLVER - request timed out without being collected for processing, resolver dead"); 
 491                         * Make the current resolver non-authoritative, and mark it as 
 492                         * no longer registered to prevent kauth_cred_ismember_gid() 
 493                         * enqueueing more work until a new one is registered.  This 
 494                         * mitigates the damage a crashing resolver may inflict. 
 496                         kauth_resolver_identity 
= 0; 
 497                         kauth_resolver_registered 
= 0; 
 499                         /* kill all the other requestes that are waiting as well */ 
 500                         TAILQ_FOREACH(killp
, &kauth_resolver_submitted
, kr_link
) 
 502                         TAILQ_FOREACH(killp
, &kauth_resolver_unsubmitted
, kr_link
) 
 504                         /* Cause all waiting-for-work threads to return EIO */ 
 505                         wakeup((caddr_t
)&kauth_resolver_unsubmitted
); 
 510          * drop our reference on the work item, and note whether we should 
 513         if (--workp
->kr_refs 
<= 0) { 
 514                 /* work out which list we have to remove it from */ 
 515                 if (workp
->kr_flags 
& KAUTH_REQUEST_DONE
) { 
 516                         TAILQ_REMOVE(&kauth_resolver_done
, workp
, kr_link
); 
 517                 } else if (workp
->kr_flags 
& KAUTH_REQUEST_SUBMITTED
) { 
 518                         TAILQ_REMOVE(&kauth_resolver_submitted
, workp
, kr_link
); 
 519                 } else if (workp
->kr_flags 
& KAUTH_REQUEST_UNSUBMITTED
) { 
 520                         TAILQ_REMOVE(&kauth_resolver_unsubmitted
, workp
, kr_link
); 
 522                         KAUTH_DEBUG("RESOLVER - completed request has no valid queue"); 
 526                 /* someone else still has a reference on this request */ 
 530         /* collect request result */ 
 532                 error 
= workp
->kr_result
; 
 534         KAUTH_RESOLVER_UNLOCK(); 
 537          * If we dropped the last reference, free the request. 
 540                 FREE(workp
, M_KAUTH
); 
 543         KAUTH_DEBUG("RESOLVER - returning %d", error
); 
 551  * Description: System call interface for the external identity resolver. 
 553  * Parameters:  uap->message                    Message from daemon to kernel 
 555  * Returns:     0                               Successfully became resolver 
 556  *              EPERM                           Not the resolver process 
 557  *      kauth_authorize_generic:EPERM           Not root user 
 558  *      kauth_resolver_complete:EIO 
 559  *      kauth_resolver_complete:EFAULT 
 560  *      kauth_resolver_getwork:EINTR 
 561  *      kauth_resolver_getwork:EFAULT 
 563  * Notes:       This system call blocks until there is work enqueued, at 
 564  *              which time the kernel wakes it up, and a message from the 
 565  *              kernel is copied out to the identity resolution daemon, which 
 566  *              proceed to attempt to resolve it.  When the resolution has 
 567  *              completed (successfully or not), the daemon called back into 
 568  *              this system call to give the result to the kernel, and wait 
 569  *              for the next request. 
 572 identitysvc(__unused 
struct proc 
*p
, struct identitysvc_args 
*uap
, __unused 
int32_t *retval
) 
 574         int opcode 
= uap
->opcode
; 
 575         user_addr_t message 
= uap
->message
; 
 576         struct kauth_resolver_work 
*workp
; 
 577         struct kauth_cache_sizes sz_arg
; 
 582          * New server registering itself. 
 584         if (opcode 
== KAUTH_EXTLOOKUP_REGISTER
) { 
 585                 new_id 
= current_proc()->p_pid
; 
 586                 if ((error 
= kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER
)) != 0) { 
 587                         KAUTH_DEBUG("RESOLVER - pid %d refused permission to become identity resolver", new_id
); 
 590                 KAUTH_RESOLVER_LOCK(); 
 591                 if (kauth_resolver_identity 
!= new_id
) { 
 592                         KAUTH_DEBUG("RESOLVER - new resolver %d taking over from old %d", new_id
, kauth_resolver_identity
); 
 594                          * We have a new server, so assume that all the old requests have been lost. 
 596                         while ((workp 
= TAILQ_LAST(&kauth_resolver_submitted
, kauth_resolver_submitted_head
)) != NULL
) { 
 597                                 TAILQ_REMOVE(&kauth_resolver_submitted
, workp
, kr_link
); 
 598                                 workp
->kr_flags 
&= ~KAUTH_REQUEST_SUBMITTED
; 
 599                                 workp
->kr_flags 
|= KAUTH_REQUEST_UNSUBMITTED
; 
 600                                 TAILQ_INSERT_HEAD(&kauth_resolver_unsubmitted
, workp
, kr_link
); 
 603                          * Allow user space resolver to override the 
 604                          * external resolution timeout 
 606                         if (message 
> 30 && message 
< 10000) { 
 607                                 kauth_resolver_timeout 
= message
; 
 608                                 KAUTH_DEBUG("RESOLVER - new resolver changes timeout to %d seconds\n", (int)message
); 
 610                         kauth_resolver_identity 
= new_id
; 
 611                         kauth_resolver_registered 
= 1; 
 612                         kauth_identitysvc_has_registered 
= 1; 
 613                         wakeup(&kauth_resolver_unsubmitted
); 
 615                 KAUTH_RESOLVER_UNLOCK(); 
 620          * Beyond this point, we must be the resolver process. We verify this 
 621          * by confirming the resolver credential and pid. 
 623         if ((kauth_cred_getuid(kauth_cred_get()) != 0) || (current_proc()->p_pid 
!= kauth_resolver_identity
)) { 
 624                 KAUTH_DEBUG("RESOLVER - call from bogus resolver %d\n", current_proc()->p_pid
); 
 628         if (opcode 
== KAUTH_GET_CACHE_SIZES
) { 
 629                 KAUTH_IDENTITY_LOCK(); 
 630                 sz_arg
.kcs_id_size 
= kauth_identity_cachemax
; 
 631                 KAUTH_IDENTITY_UNLOCK(); 
 634                 sz_arg
.kcs_group_size 
= kauth_groups_cachemax
; 
 635                 KAUTH_GROUPS_UNLOCK(); 
 637                 if ((error 
= copyout(&sz_arg
, uap
->message
, sizeof (sz_arg
))) != 0) { 
 642         } else if (opcode 
== KAUTH_SET_CACHE_SIZES
) { 
 643                 if ((error 
= copyin(uap
->message
, &sz_arg
, sizeof (sz_arg
))) != 0) { 
 647                 if ((sz_arg
.kcs_group_size 
> KAUTH_CACHES_MAX_SIZE
) || 
 648                     (sz_arg
.kcs_id_size 
> KAUTH_CACHES_MAX_SIZE
)) { 
 652                 KAUTH_IDENTITY_LOCK(); 
 653                 kauth_identity_cachemax 
= sz_arg
.kcs_id_size
; 
 654                 kauth_identity_trimcache(kauth_identity_cachemax
); 
 655                 KAUTH_IDENTITY_UNLOCK(); 
 658                 kauth_groups_cachemax 
= sz_arg
.kcs_group_size
; 
 659                 kauth_groups_trimcache(kauth_groups_cachemax
); 
 660                 KAUTH_GROUPS_UNLOCK(); 
 663         } else if (opcode 
== KAUTH_CLEAR_CACHES
) { 
 664                 KAUTH_IDENTITY_LOCK(); 
 665                 kauth_identity_trimcache(0); 
 666                 KAUTH_IDENTITY_UNLOCK(); 
 669                 kauth_groups_trimcache(0); 
 670                 KAUTH_GROUPS_UNLOCK(); 
 671         } else if (opcode 
== KAUTH_EXTLOOKUP_DEREGISTER
) { 
 673                  * Terminate outstanding requests; without an authoritative 
 674                  * resolver, we are now back on our own authority. 
 676                 struct kauth_resolver_work 
*killp
; 
 678                 KAUTH_RESOLVER_LOCK(); 
 681                  * Clear the identity, but also mark it as unregistered so 
 682                  * there is no explicit future expectation of us getting a 
 683                  * new resolver any time soon. 
 685                 kauth_resolver_identity 
= 0; 
 686                 kauth_resolver_registered 
= 0; 
 688                 TAILQ_FOREACH(killp
, &kauth_resolver_submitted
, kr_link
) 
 690                 TAILQ_FOREACH(killp
, &kauth_resolver_unsubmitted
, kr_link
) 
 692                 /* Cause all waiting-for-work threads to return EIO */ 
 693                 wakeup((caddr_t
)&kauth_resolver_unsubmitted
); 
 694                 KAUTH_RESOLVER_UNLOCK(); 
 698          * Got a result returning? 
 700         if (opcode 
& KAUTH_EXTLOOKUP_RESULT
) { 
 701                 if ((error 
= kauth_resolver_complete(message
)) != 0) 
 706          * Caller wants to take more work? 
 708         if (opcode 
& KAUTH_EXTLOOKUP_WORKER
) { 
 709                 if ((error 
= kauth_resolver_getwork(message
)) != 0) 
 718  * kauth_resolver_getwork_continue 
 720  * Description: Continuation for kauth_resolver_getwork 
 722  * Parameters:  result                          Error code or 0 for the sleep 
 723  *                                              that got us to this function 
 726  *              EINTR                           Interrupted (e.g. by signal) 
 727  *      kauth_resolver_getwork2:EFAULT 
 729  * Notes:       See kauth_resolver_getwork(0 and kauth_resolver_getwork2() for 
 733 kauth_resolver_getwork_continue(int result
) 
 740                 KAUTH_RESOLVER_UNLOCK(); 
 745          * If we lost a race with another thread/memberd restarting, then we 
 746          * need to go back to sleep to look for more work.  If it was memberd 
 747          * restarting, then the msleep0() will error out here, as our thread 
 748          * will already be "dead". 
 750         if (TAILQ_FIRST(&kauth_resolver_unsubmitted
) == NULL
) { 
 753                 error 
= msleep0(&kauth_resolver_unsubmitted
, kauth_resolver_mtx
, PCATCH
, "GRGetWork", 0, kauth_resolver_getwork_continue
); 
 755                  * If this is a wakeup from another thread in the resolver 
 756                  * deregistering it, error out the request-for-work thread 
 758                 if (!kauth_resolver_identity
) 
 760                 KAUTH_RESOLVER_UNLOCK(); 
 764         thread 
= current_thread(); 
 765         ut 
= get_bsdthread_info(thread
); 
 766         message 
= ut
->uu_kevent
.uu_kauth
.message
; 
 767         return(kauth_resolver_getwork2(message
)); 
 772  * kauth_resolver_getwork2 
 774  * Decription:  Common utility function to copy out a identity resolver work 
 775  *              item from the kernel to user space as part of the user space 
 776  *              identity resolver requesting work. 
 778  * Parameters:  message                         message to user space 
 781  *              EFAULT                          Bad user space message address 
 783  * Notes:       This common function exists to permit the use of continuations 
 784  *              in the identity resolution process.  This frees up the stack 
 785  *              while we are waiting for the user space resolver to complete 
 786  *              a request.  This is specifically used so that our per thread 
 787  *              cost can be small, and we will therefore be willing to run a 
 788  *              larger number of threads in the user space identity resolver. 
 791 kauth_resolver_getwork2(user_addr_t message
) 
 793         struct kauth_resolver_work 
*workp
; 
 797          * Note: We depend on the caller protecting us from a NULL work item 
 798          * queue, since we must have the kauth resolver lock on entry to this 
 801         workp 
= TAILQ_FIRST(&kauth_resolver_unsubmitted
); 
 804          * Copy out the external lookup structure for the request, not 
 805          * including the el_extend field, which contains the address of the 
 806          * external buffer provided by the external resolver into which we 
 807          * copy the extension request information. 
 810         if ((error 
= copyout(&workp
->kr_work
, message
, offsetof(struct kauth_identity_extlookup
, el_extend
))) != 0) { 
 811                 KAUTH_DEBUG("RESOLVER - error submitting work to resolve"); 
 815         if ((error 
= copyout(&workp
->kr_work
.el_info_reserved_1
, 
 816                         message 
+ offsetof(struct kauth_identity_extlookup
, el_info_reserved_1
), 
 817                 sizeof(struct kauth_identity_extlookup
) - offsetof(struct kauth_identity_extlookup
, el_info_reserved_1
))) != 0) { 
 818                 KAUTH_DEBUG("RESOLVER - error submitting work to resolve"); 
 823          * Handle extended requests here; if we have a request of a type where 
 824          * the kernel wants a translation of extended information, then we need 
 825          * to copy it out into the extended buffer, assuming the buffer is 
 826          * valid; we only attempt to get the buffer address if we have request 
 827          * data to copy into it. 
 831          * translate a user@domain string into a uid/gid/whatever 
 833         if (workp
->kr_work
.el_flags 
& (KAUTH_EXTLOOKUP_VALID_PWNAM 
| KAUTH_EXTLOOKUP_VALID_GRNAM
)) { 
 836                 error 
= copyin(message 
+ offsetof(struct kauth_identity_extlookup
, el_extend
), &uaddr
, sizeof(uaddr
)); 
 838                         size_t actual
;  /* not used */ 
 840                          * Use copyoutstr() to reduce the copy size; we let 
 841                          * this catch a NULL uaddr because we shouldn't be 
 842                          * asking in that case anyway. 
 844                         error 
= copyoutstr(CAST_DOWN(void *,workp
->kr_extend
), uaddr
, MAXPATHLEN
, &actual
); 
 847                         KAUTH_DEBUG("RESOLVER - error submitting work to resolve"); 
 851         TAILQ_REMOVE(&kauth_resolver_unsubmitted
, workp
, kr_link
); 
 852         workp
->kr_flags 
&= ~KAUTH_REQUEST_UNSUBMITTED
; 
 853         workp
->kr_flags 
|= KAUTH_REQUEST_SUBMITTED
; 
 854         TAILQ_INSERT_TAIL(&kauth_resolver_submitted
, workp
, kr_link
); 
 857         KAUTH_RESOLVER_UNLOCK(); 
 863  * kauth_resolver_getwork 
 865  * Description: Get a work item from the enqueued requests from the kernel and 
 866  *              give it to the user space daemon. 
 868  * Parameters:  message                         message to user space 
 871  *              EINTR                           Interrupted (e.g. by signal) 
 872  *      kauth_resolver_getwork2:EFAULT 
 874  * Notes:       This function blocks in a continuation if there are no work 
 875  *              items available for processing at the time the user space 
 876  *              identity resolution daemon makes a request for work.  This 
 877  *              permits a large number of threads to be used by the daemon, 
 878  *              without using a lot of wired kernel memory when there are no 
 879  *              actual request outstanding. 
 882 kauth_resolver_getwork(user_addr_t message
) 
 884         struct kauth_resolver_work 
*workp
; 
 887         KAUTH_RESOLVER_LOCK(); 
 889         while ((workp 
= TAILQ_FIRST(&kauth_resolver_unsubmitted
)) == NULL
) { 
 890                 thread_t thread 
= current_thread(); 
 891                 struct uthread 
*ut 
= get_bsdthread_info(thread
); 
 893                 ut
->uu_kevent
.uu_kauth
.message 
= message
; 
 894                 error 
= msleep0(&kauth_resolver_unsubmitted
, kauth_resolver_mtx
, PCATCH
, "GRGetWork", 0, kauth_resolver_getwork_continue
); 
 895                 KAUTH_RESOLVER_UNLOCK(); 
 897                  * If this is a wakeup from another thread in the resolver 
 898                  * deregistering it, error out the request-for-work thread 
 900                 if (!kauth_resolver_identity
) 
 904         return kauth_resolver_getwork2(message
); 
 909  * kauth_resolver_complete 
 911  * Description: Return a result from userspace. 
 913  * Parameters:  message                         message from user space 
 916  *              EIO                             The resolver is dead 
 917  *      copyin:EFAULT                           Bad message from user space 
 920 kauth_resolver_complete(user_addr_t message
) 
 922         struct kauth_identity_extlookup extl
; 
 923         struct kauth_resolver_work 
*workp
; 
 924         struct kauth_resolver_work 
*killp
; 
 925         int error
, result
, request_flags
; 
 928          * Copy in the mesage, including the extension field, since we are 
 929          * copying into a local variable. 
 931         if ((error 
= copyin(message
, &extl
, sizeof(extl
))) != 0) { 
 932                 KAUTH_DEBUG("RESOLVER - error getting completed work\n"); 
 936         KAUTH_RESOLVER_LOCK(); 
 940         switch (extl
.el_result
) { 
 941         case KAUTH_EXTLOOKUP_INPROG
: 
 945                 /* XXX this should go away once memberd is updated */ 
 947                         printf("kauth_resolver: memberd is not setting valid result codes (assuming always successful)\n"); 
 953         case KAUTH_EXTLOOKUP_SUCCESS
: 
 956         case KAUTH_EXTLOOKUP_FATAL
: 
 957                 /* fatal error means the resolver is dead */ 
 958                 KAUTH_DEBUG("RESOLVER - resolver %d died, waiting for a new one", kauth_resolver_identity
); 
 960                  * Terminate outstanding requests; without an authoritative 
 961                  * resolver, we are now back on our own authority.  Tag the 
 962                  * resolver unregistered to prevent kauth_cred_ismember_gid() 
 963                  * enqueueing more work until a new one is registered.  This 
 964                  * mitigates the damage a crashing resolver may inflict. 
 966                 kauth_resolver_identity 
= 0; 
 967                 kauth_resolver_registered 
= 0; 
 969                 TAILQ_FOREACH(killp
, &kauth_resolver_submitted
, kr_link
) 
 971                 TAILQ_FOREACH(killp
, &kauth_resolver_unsubmitted
, kr_link
) 
 973                 /* Cause all waiting-for-work threads to return EIO */ 
 974                 wakeup((caddr_t
)&kauth_resolver_unsubmitted
); 
 975                 /* and return EIO to the caller */ 
 979         case KAUTH_EXTLOOKUP_BADRQ
: 
 980                 KAUTH_DEBUG("RESOLVER - resolver reported invalid request %d", extl
.el_seqno
); 
 984         case KAUTH_EXTLOOKUP_FAILURE
: 
 985                 KAUTH_DEBUG("RESOLVER - resolver reported transient failure for request %d", extl
.el_seqno
); 
 990                 KAUTH_DEBUG("RESOLVER - resolver returned unexpected status %d", extl
.el_result
); 
 996          * In the case of a fatal error, we assume that the resolver will 
 997          * restart quickly and re-collect all of the outstanding requests. 
 998          * Thus, we don't complete the request which returned the fatal 
1001         if (extl
.el_result 
!= KAUTH_EXTLOOKUP_FATAL
) { 
1002                 /* scan our list for this request */ 
1003                 TAILQ_FOREACH(workp
, &kauth_resolver_submitted
, kr_link
) { 
1005                         if (workp
->kr_seqno 
== extl
.el_seqno
) { 
1007                                  * Take a snapshot of the original request flags. 
1009                                 request_flags 
= workp
->kr_work
.el_flags
; 
1012                                  * Get the request of the submitted queue so 
1013                                  * that it is not cleaned up out from under 
1016                                 TAILQ_REMOVE(&kauth_resolver_submitted
, workp
, kr_link
); 
1017                                 workp
->kr_flags 
&= ~KAUTH_REQUEST_SUBMITTED
; 
1018                                 workp
->kr_flags 
|= KAUTH_REQUEST_DONE
; 
1019                                 workp
->kr_result 
= result
; 
1021                                 /* Copy the result message to the work item. */ 
1022                                 memcpy(&workp
->kr_work
, &extl
, sizeof(struct kauth_identity_extlookup
)); 
1025                                  * Check if we have a result in the extension 
1026                                  * field; if we do, then we need to separately 
1027                                  * copy the data from the message el_extend 
1028                                  * into the request buffer that's in the work 
1029                                  * item.  We have to do it here because we do 
1030                                  * not want to wake up the waiter until the 
1031                                  * data is in their buffer, and because the 
1032                                  * actual request response may be destroyed 
1033                                  * by the time the requester wakes up, and they 
1034                                  * do not have access to the user space buffer 
1037                                  * It is safe to drop and reacquire the lock 
1038                                  * here because we've already removed the item 
1039                                  * from the submission queue, but have not yet 
1040                                  * moved it to the completion queue.  Note that 
1041                                  * near simultaneous requests may result in 
1042                                  * duplication of requests for items in this 
1043                                  * window. This should not be a performance 
1044                                  * issue and is easily detectable by comparing 
1045                                  * time to live on last response vs. time of 
1046                                  * next request in the resolver logs. 
1048                                  * A malicious/faulty resolver could overwrite 
1049                                  * part of a user's address space if they return 
1050                                  * flags that mismatch the original request's flags. 
1052                                 if ((extl
.el_flags 
& request_flags
) & (KAUTH_EXTLOOKUP_VALID_PWNAM
|KAUTH_EXTLOOKUP_VALID_GRNAM
)) { 
1053                                         size_t actual
;  /* notused */ 
1055                                         KAUTH_RESOLVER_UNLOCK(); 
1056                                         error 
= copyinstr(extl
.el_extend
, CAST_DOWN(void *, workp
->kr_extend
), MAXPATHLEN
, &actual
); 
1057                                         KAUTH_RESOLVER_LOCK(); 
1058                                 } else if (extl
.el_flags 
&  (KAUTH_EXTLOOKUP_VALID_PWNAM
|KAUTH_EXTLOOKUP_VALID_GRNAM
)) { 
1060                                         KAUTH_DEBUG("RESOLVER - resolver returned mismatching extension flags (%d), request contained (%d)", 
1061                                                         extl
.el_flags
, request_flags
); 
1065                                  * Move the completed work item to the 
1066                                  * completion queue and wake up requester(s) 
1068                                 TAILQ_INSERT_TAIL(&kauth_resolver_done
, workp
, kr_link
); 
1075          * Note that it's OK for us not to find anything; if the request has 
1076          * timed out the work record will be gone. 
1078         KAUTH_RESOLVER_UNLOCK(); 
1082 #endif /* CONFIG_EXT_RESOLVER */ 
1089 #define KI_VALID_UID    (1<<0)          /* UID and GID are mutually exclusive */ 
1090 #define KI_VALID_GID    (1<<1) 
1091 #define KI_VALID_GUID   (1<<2) 
1092 #define KI_VALID_NTSID  (1<<3) 
1093 #define KI_VALID_PWNAM  (1<<4)  /* Used for translation */ 
1094 #define KI_VALID_GRNAM  (1<<5)  /* Used for translation */ 
1095 #define KI_VALID_GROUPS (1<<6) 
1097 #if CONFIG_EXT_RESOLVER 
1099  * kauth_identity_init 
1101  * Description: Initialize the kernel side of the credential identity resolver 
1103  * Parameters:  (void) 
1107  * Notes:       Initialize the credential identity resolver for use; the 
1108  *              credential identity resolver is the KPI used to communicate 
1109  *              with a user space credential identity resolver daemon. 
1111  *              This function is called from kauth_init() in the file 
1112  *              kern_authorization.c. 
1115 kauth_identity_init(void) 
1117         TAILQ_INIT(&kauth_identities
); 
1118         kauth_identity_mtx 
= lck_mtx_alloc_init(kauth_lck_grp
, 0/*LCK_ATTR_NULL*/); 
1123  * kauth_identity_alloc 
1125  * Description: Allocate and fill out a kauth_identity structure for 
1126  *              translation between {UID|GID}/GUID/NTSID 
1130  * Returns:     NULL                            Insufficient memory to satisfy 
1131  *                                              the request or bad parameters 
1132  *              !NULL                           A pointer to the allocated 
1133  *                                              structure, filled in 
1135  * Notes:       It is illegal to translate between UID and GID; any given UUID 
1136  *              or NTSID can only refer to an NTSID or UUID (respectively), 
1137  *              and *either* a UID *or* a GID, but not both. 
1139 static struct kauth_identity 
* 
1140 kauth_identity_alloc(uid_t uid
, gid_t gid
, guid_t 
*guidp
, time_t guid_expiry
, 
1141         ntsid_t 
*ntsidp
, time_t ntsid_expiry
, int supgrpcnt
, gid_t 
*supgrps
, time_t groups_expiry
, 
1142         const char *name
, int nametype
) 
1144         struct kauth_identity 
*kip
; 
1146         /* get and fill in a new identity */ 
1147         MALLOC(kip
, struct kauth_identity 
*, sizeof(*kip
), M_KAUTH
, M_WAITOK 
| M_ZERO
); 
1149                 if (gid 
!= KAUTH_GID_NONE
) { 
1151                         kip
->ki_valid 
= KI_VALID_GID
; 
1153                 if (uid 
!= KAUTH_UID_NONE
) { 
1154                         if (kip
->ki_valid 
& KI_VALID_GID
) 
1155                                 panic("can't allocate kauth identity with both uid and gid"); 
1157                         kip
->ki_valid 
= KI_VALID_UID
; 
1161                          * A malicious/faulty resolver could return bad values 
1163                         assert(supgrpcnt 
>= 0); 
1164                         assert(supgrpcnt 
<= NGROUPS
); 
1165                         assert(supgrps 
!= NULL
); 
1167                         if ((supgrpcnt 
< 0) || (supgrpcnt 
> NGROUPS
) || (supgrps 
== NULL
)) { 
1170                         if (kip
->ki_valid 
& KI_VALID_GID
) 
1171                                 panic("can't allocate kauth identity with both gid and supplementary groups"); 
1172                         kip
->ki_supgrpcnt 
= supgrpcnt
; 
1173                         memcpy(kip
->ki_supgrps
, supgrps
, sizeof(supgrps
[0]) * supgrpcnt
); 
1174                         kip
->ki_valid 
|= KI_VALID_GROUPS
; 
1176                 kip
->ki_groups_expiry 
= groups_expiry
; 
1177                 if (guidp 
!= NULL
) { 
1178                         kip
->ki_guid 
= *guidp
; 
1179                         kip
->ki_valid 
|= KI_VALID_GUID
; 
1181                 kip
->ki_guid_expiry 
= guid_expiry
; 
1182                 if (ntsidp 
!= NULL
) { 
1183                         kip
->ki_ntsid 
= *ntsidp
; 
1184                         kip
->ki_valid 
|= KI_VALID_NTSID
; 
1186                 kip
->ki_ntsid_expiry 
= ntsid_expiry
; 
1188                         kip
->ki_name 
= name
; 
1189                         kip
->ki_valid 
|= nametype
; 
1197  * kauth_identity_register_and_free 
1199  * Description: Register an association between identity tokens.  The passed 
1200  *              'kip' is consumed by this function. 
1202  * Parameters:  kip                             Pointer to kauth_identity 
1203  *                                              structure to register 
1207  * Notes:       The memory pointer to by 'kip' is assumed to have been 
1208  *              previously allocated via kauth_identity_alloc(). 
1211 kauth_identity_register_and_free(struct kauth_identity 
*kip
) 
1213         struct kauth_identity 
*ip
; 
1216          * We search the cache for the UID listed in the incoming association. 
1217          * If we already have an entry, the new information is merged. 
1220         KAUTH_IDENTITY_LOCK(); 
1221         if (kip
->ki_valid 
& KI_VALID_UID
) { 
1222                 if (kip
->ki_valid 
& KI_VALID_GID
) 
1223                         panic("kauth_identity: can't insert record with both UID and GID as key"); 
1224                 TAILQ_FOREACH(ip
, &kauth_identities
, ki_link
) 
1225                     if ((ip
->ki_valid 
& KI_VALID_UID
) && (ip
->ki_uid 
== kip
->ki_uid
)) 
1227         } else if (kip
->ki_valid 
& KI_VALID_GID
) { 
1228                 TAILQ_FOREACH(ip
, &kauth_identities
, ki_link
) 
1229                     if ((ip
->ki_valid 
& KI_VALID_GID
) && (ip
->ki_gid 
== kip
->ki_gid
)) 
1232                 panic("kauth_identity: can't insert record without UID or GID as key"); 
1236                 /* we already have an entry, merge/overwrite */ 
1237                 if (kip
->ki_valid 
& KI_VALID_GUID
) { 
1238                         ip
->ki_guid 
= kip
->ki_guid
; 
1239                         ip
->ki_valid 
|= KI_VALID_GUID
; 
1241                 ip
->ki_guid_expiry 
= kip
->ki_guid_expiry
; 
1242                 if (kip
->ki_valid 
& KI_VALID_NTSID
) { 
1243                         ip
->ki_ntsid 
= kip
->ki_ntsid
; 
1244                         ip
->ki_valid 
|= KI_VALID_NTSID
; 
1246                 ip
->ki_ntsid_expiry 
= kip
->ki_ntsid_expiry
; 
1247                 /* a valid ki_name field overwrites the previous name field */ 
1248                 if (kip
->ki_valid 
& (KI_VALID_PWNAM 
| KI_VALID_GRNAM
)) { 
1249                         /* if there's an old one, discard it */ 
1250                         const char *oname 
= NULL
; 
1251                         if (ip
->ki_valid 
& (KI_VALID_PWNAM 
| KI_VALID_GRNAM
)) 
1252                                 oname 
= ip
->ki_name
; 
1253                         ip
->ki_name 
= kip
->ki_name
; 
1254                         kip
->ki_name 
= oname
; 
1256                 /* and discard the incoming entry */ 
1260                  * if we don't have any information on this identity, add it; 
1261                  * if it pushes us over our limit, discard the oldest one. 
1263                 TAILQ_INSERT_HEAD(&kauth_identities
, kip
, ki_link
); 
1264                 if (++kauth_identity_count 
> kauth_identity_cachemax
) { 
1265                         ip 
= TAILQ_LAST(&kauth_identities
, kauth_identity_head
); 
1266                         TAILQ_REMOVE(&kauth_identities
, ip
, ki_link
); 
1267                         kauth_identity_count
--; 
1270         KAUTH_IDENTITY_UNLOCK(); 
1271         /* have to drop lock before freeing expired entry (it may be in use) */ 
1273                 /* if the ki_name field is used, clear it first */ 
1274                 if (ip
->ki_valid 
& (KI_VALID_PWNAM 
| KI_VALID_GRNAM
)) 
1275                         vfs_removename(ip
->ki_name
); 
1276                 /* free the expired entry */ 
1283  * kauth_identity_updatecache 
1285  * Description: Given a lookup result, add any associations that we don't 
1286  *              currently have; replace ones which have changed. 
1288  * Parameters:  elp                             External lookup result from 
1289  *                                              user space daemon to kernel 
1290  *              rkip                            pointer to returned kauth 
1292  *              extend_data                     Extended data (can vary) 
1297  *              *rkip                           Modified (if non-NULL) 
1299  * Notes:       For extended information requests, this code relies on the fact 
1300  *              that elp->el_flags is never used as an rvalue, and is only 
1301  *              ever bit-tested for valid lookup information we are willing 
1304  * XXX:         We may have to do the same in the case that extended data was 
1305  *              passed out to user space to ensure that the request string 
1306  *              gets cached; we may also be able to use the rkip as an 
1307  *              input to avoid this.  The jury is still out. 
1309  * XXX:         This codes performance could be improved for multiple valid 
1310  *              results by combining the loop iteration in a single loop. 
1313 kauth_identity_updatecache(struct kauth_identity_extlookup 
*elp
, struct kauth_identity 
*rkip
, uint64_t extend_data
) 
1316         struct kauth_identity 
*kip
; 
1317         const char *speculative_name 
= NULL
; 
1322          * If there is extended data, and that data represents a name rather 
1323          * than something else, speculatively create an entry for it in the 
1324          * string cache.  We do this to avoid holding the KAUTH_IDENTITY_LOCK 
1325          * over the allocation later. 
1327         if (elp
->el_flags 
& (KAUTH_EXTLOOKUP_VALID_PWNAM 
| KAUTH_EXTLOOKUP_VALID_GRNAM
)) { 
1328                 const char *tmp 
= CAST_DOWN(const char *,extend_data
); 
1329                 speculative_name 
= vfs_addname(tmp
, strnlen(tmp
, MAXPATHLEN 
- 1), 0, 0); 
1332         /* user identity? */ 
1333         if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_UID
) { 
1334                 KAUTH_IDENTITY_LOCK(); 
1335                 TAILQ_FOREACH(kip
, &kauth_identities
, ki_link
) { 
1336                         /* matching record */ 
1337                         if ((kip
->ki_valid 
& KI_VALID_UID
) && (kip
->ki_uid 
== elp
->el_uid
)) { 
1338                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_SUPGRPS
) { 
1339                                         assert(elp
->el_sup_grp_cnt 
<= NGROUPS
); 
1340                                         if (elp
->el_sup_grp_cnt 
> NGROUPS
) { 
1341                                                 KAUTH_DEBUG("CACHE - invalid sup_grp_cnt provided (%d), truncating to  %d", 
1342                                                            elp
->el_sup_grp_cnt
, NGROUPS
); 
1343                                                 elp
->el_sup_grp_cnt 
= NGROUPS
; 
1345                                         kip
->ki_supgrpcnt 
= elp
->el_sup_grp_cnt
; 
1346                                         memcpy(kip
->ki_supgrps
, elp
->el_sup_groups
, sizeof(elp
->el_sup_groups
[0]) * kip
->ki_supgrpcnt
); 
1347                                         kip
->ki_valid 
|= KI_VALID_GROUPS
; 
1348                                         kip
->ki_groups_expiry 
= (elp
->el_member_valid
) ? tv
.tv_sec 
+ elp
->el_member_valid 
: 0; 
1350                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_UGUID
) { 
1351                                         kip
->ki_guid 
= elp
->el_uguid
; 
1352                                         kip
->ki_valid 
|= KI_VALID_GUID
; 
1354                                 kip
->ki_guid_expiry 
= (elp
->el_uguid_valid
) ? tv
.tv_sec 
+ elp
->el_uguid_valid 
: 0; 
1355                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_USID
) { 
1356                                         kip
->ki_ntsid 
= elp
->el_usid
; 
1357                                         kip
->ki_valid 
|= KI_VALID_NTSID
; 
1359                                 kip
->ki_ntsid_expiry 
= (elp
->el_usid_valid
) ? tv
.tv_sec 
+ elp
->el_usid_valid 
: 0; 
1360                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_PWNAM
) { 
1361                                         const char *oname 
= kip
->ki_name
; 
1362                                         kip
->ki_name 
= speculative_name
; 
1363                                         speculative_name 
= NULL
; 
1364                                         kip
->ki_valid 
|= KI_VALID_PWNAM
; 
1367                                                  * free oname (if any) outside 
1370                                                 speculative_name 
= oname
; 
1373                                 kauth_identity_lru(kip
); 
1376                                 KAUTH_DEBUG("CACHE - refreshed %d is " K_UUID_FMT
, kip
->ki_uid
, K_UUID_ARG(kip
->ki_guid
)); 
1380                 KAUTH_IDENTITY_UNLOCK(); 
1381                 /* not found in cache, add new record */ 
1383                         kip 
= kauth_identity_alloc(elp
->el_uid
, KAUTH_GID_NONE
, 
1384                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_UGUID
) ? &elp
->el_uguid 
: NULL
, 
1385                             (elp
->el_uguid_valid
) ? tv
.tv_sec 
+ elp
->el_uguid_valid 
: 0, 
1386                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_USID
) ? &elp
->el_usid 
: NULL
, 
1387                             (elp
->el_usid_valid
) ? tv
.tv_sec 
+ elp
->el_usid_valid 
: 0, 
1388                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_SUPGRPS
) ? elp
->el_sup_grp_cnt 
: 0, 
1389                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_SUPGRPS
) ? elp
->el_sup_groups 
: NULL
, 
1390                             (elp
->el_member_valid
) ? tv
.tv_sec 
+ elp
->el_member_valid 
: 0, 
1391                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_PWNAM
) ? speculative_name 
: NULL
, 
1396                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_PWNAM
) 
1397                                         speculative_name 
= NULL
; 
1398                                 KAUTH_DEBUG("CACHE - learned %d is " K_UUID_FMT
, kip
->ki_uid
, K_UUID_ARG(kip
->ki_guid
)); 
1399                                 kauth_identity_register_and_free(kip
); 
1404         /* group identity? (ignore, if we already processed it as a user) */ 
1405         if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GID 
&& !(elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_UID
)) { 
1406                 KAUTH_IDENTITY_LOCK(); 
1407                 TAILQ_FOREACH(kip
, &kauth_identities
, ki_link
) { 
1408                         /* matching record */ 
1409                         if ((kip
->ki_valid 
& KI_VALID_GID
) && (kip
->ki_gid 
== elp
->el_gid
)) { 
1410                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GGUID
) { 
1411                                         kip
->ki_guid 
= elp
->el_gguid
; 
1412                                         kip
->ki_valid 
|= KI_VALID_GUID
; 
1414                                 kip
->ki_guid_expiry 
= (elp
->el_gguid_valid
) ? tv
.tv_sec 
+ elp
->el_gguid_valid 
: 0; 
1415                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GSID
) { 
1416                                         kip
->ki_ntsid 
= elp
->el_gsid
; 
1417                                         kip
->ki_valid 
|= KI_VALID_NTSID
; 
1419                                 kip
->ki_ntsid_expiry 
= (elp
->el_gsid_valid
) ? tv
.tv_sec 
+ elp
->el_gsid_valid 
: 0; 
1420                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GRNAM
) { 
1421                                         const char *oname 
= kip
->ki_name
; 
1422                                         kip
->ki_name 
= speculative_name
; 
1423                                         speculative_name 
= NULL
; 
1424                                         kip
->ki_valid 
|= KI_VALID_GRNAM
; 
1427                                                  * free oname (if any) outside 
1430                                                 speculative_name 
= oname
; 
1433                                 kauth_identity_lru(kip
); 
1436                                 KAUTH_DEBUG("CACHE - refreshed %d is " K_UUID_FMT
, kip
->ki_uid
, K_UUID_ARG(kip
->ki_guid
)); 
1440                 KAUTH_IDENTITY_UNLOCK(); 
1441                 /* not found in cache, add new record */ 
1443                         kip 
= kauth_identity_alloc(KAUTH_UID_NONE
, elp
->el_gid
, 
1444                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GGUID
) ? &elp
->el_gguid 
: NULL
, 
1445                             (elp
->el_gguid_valid
) ? tv
.tv_sec 
+ elp
->el_gguid_valid 
: 0, 
1446                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GSID
) ? &elp
->el_gsid 
: NULL
, 
1447                             (elp
->el_gsid_valid
) ? tv
.tv_sec 
+ elp
->el_gsid_valid 
: 0, 
1448                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_SUPGRPS
) ? elp
->el_sup_grp_cnt 
: 0, 
1449                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_SUPGRPS
) ? elp
->el_sup_groups 
: NULL
, 
1450                             (elp
->el_member_valid
) ? tv
.tv_sec 
+ elp
->el_member_valid 
: 0, 
1451                             (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GRNAM
) ? speculative_name 
: NULL
, 
1456                                 if (elp
->el_flags 
& KAUTH_EXTLOOKUP_VALID_GRNAM
) 
1457                                         speculative_name 
= NULL
; 
1458                                 KAUTH_DEBUG("CACHE - learned %d is " K_UUID_FMT
, kip
->ki_uid
, K_UUID_ARG(kip
->ki_guid
)); 
1459                                 kauth_identity_register_and_free(kip
); 
1464         /* If we have a name reference to drop, drop it here */ 
1465         if (speculative_name 
!= NULL
) { 
1466                 vfs_removename(speculative_name
); 
1472  * Trim older entries from the identity cache. 
1474  * Must be called with the identity cache lock held. 
1477 kauth_identity_trimcache(int newsize
) { 
1478         struct kauth_identity           
*kip
; 
1480         lck_mtx_assert(kauth_identity_mtx
, LCK_MTX_ASSERT_OWNED
); 
1482         while (kauth_identity_count 
> newsize
) { 
1483                 kip 
= TAILQ_LAST(&kauth_identities
, kauth_identity_head
); 
1484                 TAILQ_REMOVE(&kauth_identities
, kip
, ki_link
); 
1485                 kauth_identity_count
--; 
1491  * kauth_identity_lru 
1493  * Description: Promote the entry to the head of the LRU, assumes the cache 
1496  * Parameters:  kip                             kauth identity to move to the 
1497  *                                              head of the LRU list, if it's 
1502  * Notes:       This is called even if the entry has expired; typically an 
1503  *              expired entry that's been looked up is about to be revalidated, 
1504  *              and having it closer to the head of the LRU means finding it 
1505  *              quickly again when the revalidation comes through. 
1508 kauth_identity_lru(struct kauth_identity 
*kip
) 
1510         if (kip 
!= TAILQ_FIRST(&kauth_identities
)) { 
1511                 TAILQ_REMOVE(&kauth_identities
, kip
, ki_link
); 
1512                 TAILQ_INSERT_HEAD(&kauth_identities
, kip
, ki_link
); 
1518  * kauth_identity_guid_expired 
1520  * Description: Handle lazy expiration of GUID translations. 
1522  * Parameters:  kip                             kauth identity to check for 
1525  * Returns:     1                               Expired 
1529 kauth_identity_guid_expired(struct kauth_identity 
*kip
) 
1534          * Expiration time of 0 means this entry is persistent. 
1536         if (kip
->ki_guid_expiry 
== 0) 
1540         KAUTH_DEBUG("CACHE - GUID expires @ %ld now %ld", kip
->ki_guid_expiry
, tv
.tv_sec
); 
1542         return((kip
->ki_guid_expiry 
<= tv
.tv_sec
) ? 1 : 0); 
1547  * kauth_identity_ntsid_expired 
1549  * Description: Handle lazy expiration of NTSID translations. 
1551  * Parameters:  kip                             kauth identity to check for 
1554  * Returns:     1                               Expired 
1558 kauth_identity_ntsid_expired(struct kauth_identity 
*kip
) 
1563          * Expiration time of 0 means this entry is persistent. 
1565         if (kip
->ki_ntsid_expiry 
== 0) 
1569         KAUTH_DEBUG("CACHE - NTSID expires @ %ld now %ld", kip
->ki_ntsid_expiry
, tv
.tv_sec
); 
1571         return((kip
->ki_ntsid_expiry 
<= tv
.tv_sec
) ? 1 : 0); 
1575  * kauth_identity_groups_expired 
1577  * Description: Handle lazy expiration of supplemental group translations. 
1579  * Parameters:  kip                             kauth identity to check for 
1582  * Returns:     1                               Expired 
1586 kauth_identity_groups_expired(struct kauth_identity 
*kip
) 
1591          * Expiration time of 0 means this entry is persistent. 
1593         if (kip
->ki_groups_expiry 
== 0) 
1597         KAUTH_DEBUG("CACHE - GROUPS expires @ %ld now %ld\n", kip
->ki_groups_expiry
, tv
.tv_sec
); 
1599         return((kip
->ki_groups_expiry 
<= tv
.tv_sec
) ? 1 : 0); 
1603  * kauth_identity_find_uid 
1605  * Description: Search for an entry by UID 
1607  * Parameters:  uid                             UID to find 
1608  *              kir                             Pointer to return area 
1609  *              getname                         Name buffer, if ki_name wanted 
1615  *              *klr                            Modified, if found 
1618 kauth_identity_find_uid(uid_t uid
, struct kauth_identity 
*kir
, char *getname
) 
1620         struct kauth_identity 
*kip
; 
1622         KAUTH_IDENTITY_LOCK(); 
1623         TAILQ_FOREACH(kip
, &kauth_identities
, ki_link
) { 
1624                 if ((kip
->ki_valid 
& KI_VALID_UID
) && (uid 
== kip
->ki_uid
)) { 
1625                         kauth_identity_lru(kip
); 
1626                         /* Copy via structure assignment */ 
1628                         /* If a name is wanted and one exists, copy it out */ 
1629                         if (getname 
!= NULL 
&& (kip
->ki_valid 
& (KI_VALID_PWNAM 
| KI_VALID_GRNAM
))) 
1630                                 strlcpy(getname
, kip
->ki_name
, MAXPATHLEN
); 
1634         KAUTH_IDENTITY_UNLOCK(); 
1635         return((kip 
== NULL
) ? ENOENT 
: 0); 
1640  * kauth_identity_find_gid 
1642  * Description: Search for an entry by GID 
1644  * Parameters:  gid                             GID to find 
1645  *              kir                             Pointer to return area 
1646  *              getname                         Name buffer, if ki_name wanted 
1652  *              *klr                            Modified, if found 
1655 kauth_identity_find_gid(uid_t gid
, struct kauth_identity 
*kir
, char *getname
) 
1657         struct kauth_identity 
*kip
; 
1659         KAUTH_IDENTITY_LOCK(); 
1660         TAILQ_FOREACH(kip
, &kauth_identities
, ki_link
) { 
1661                 if ((kip
->ki_valid 
& KI_VALID_GID
) && (gid 
== kip
->ki_gid
)) { 
1662                         kauth_identity_lru(kip
); 
1663                         /* Copy via structure assignment */ 
1665                         /* If a name is wanted and one exists, copy it out */ 
1666                         if (getname 
!= NULL 
&& (kip
->ki_valid 
& (KI_VALID_PWNAM 
| KI_VALID_GRNAM
))) 
1667                                 strlcpy(getname
, kip
->ki_name
, MAXPATHLEN
); 
1671         KAUTH_IDENTITY_UNLOCK(); 
1672         return((kip 
== NULL
) ? ENOENT 
: 0); 
1677  * kauth_identity_find_guid 
1679  * Description: Search for an entry by GUID 
1681  * Parameters:  guidp                           Pointer to GUID to find 
1682  *              kir                             Pointer to return area 
1683  *              getname                         Name buffer, if ki_name wanted 
1689  *              *klr                            Modified, if found 
1691  * Note:        The association may be expired, in which case the caller 
1692  *              may elect to call out to userland to revalidate. 
1695 kauth_identity_find_guid(guid_t 
*guidp
, struct kauth_identity 
*kir
, char *getname
) 
1697         struct kauth_identity 
*kip
; 
1699         KAUTH_IDENTITY_LOCK(); 
1700         TAILQ_FOREACH(kip
, &kauth_identities
, ki_link
) { 
1701                 if ((kip
->ki_valid 
& KI_VALID_GUID
) && (kauth_guid_equal(guidp
, &kip
->ki_guid
))) { 
1702                         kauth_identity_lru(kip
); 
1703                         /* Copy via structure assignment */ 
1705                         /* If a name is wanted and one exists, copy it out */ 
1706                         if (getname 
!= NULL 
&& (kip
->ki_valid 
& (KI_VALID_PWNAM 
| KI_VALID_GRNAM
))) 
1707                                 strlcpy(getname
, kip
->ki_name
, MAXPATHLEN
); 
1711         KAUTH_IDENTITY_UNLOCK(); 
1712         return((kip 
== NULL
) ? ENOENT 
: 0); 
1716  * kauth_identity_find_nam 
1718  * Description: Search for an entry by name 
1720  * Parameters:  name                            Pointer to name to find 
1721  *              valid                           KI_VALID_PWNAM or KI_VALID_GRNAM 
1722  *              kir                             Pointer to return area 
1728  *              *klr                            Modified, if found 
1731 kauth_identity_find_nam(char *name
, int valid
, struct kauth_identity 
*kir
) 
1733         struct kauth_identity 
*kip
; 
1735         KAUTH_IDENTITY_LOCK(); 
1736         TAILQ_FOREACH(kip
, &kauth_identities
, ki_link
) { 
1737                 if ((kip
->ki_valid 
& valid
) && !strcmp(name
, kip
->ki_name
)) { 
1738                         kauth_identity_lru(kip
); 
1739                         /* Copy via structure assignment */ 
1744         KAUTH_IDENTITY_UNLOCK(); 
1745         return((kip 
== NULL
) ? ENOENT 
: 0); 
1750  * kauth_identity_find_ntsid 
1752  * Description: Search for an entry by NTSID 
1754  * Parameters:  ntsid                           Pointer to NTSID to find 
1755  *              kir                             Pointer to return area 
1756  *              getname                         Name buffer, if ki_name wanted 
1762  *              *klr                            Modified, if found 
1764  * Note:        The association may be expired, in which case the caller 
1765  *              may elect to call out to userland to revalidate. 
1768 kauth_identity_find_ntsid(ntsid_t 
*ntsid
, struct kauth_identity 
*kir
, char *getname
) 
1770         struct kauth_identity 
*kip
; 
1772         KAUTH_IDENTITY_LOCK(); 
1773         TAILQ_FOREACH(kip
, &kauth_identities
, ki_link
) { 
1774                 if ((kip
->ki_valid 
& KI_VALID_NTSID
) && (kauth_ntsid_equal(ntsid
, &kip
->ki_ntsid
))) { 
1775                         kauth_identity_lru(kip
); 
1776                         /* Copy via structure assignment */ 
1778                         /* If a name is wanted and one exists, copy it out */ 
1779                         if (getname 
!= NULL 
&& (kip
->ki_valid 
& (KI_VALID_PWNAM 
| KI_VALID_GRNAM
))) 
1780                                 strlcpy(getname
, kip
->ki_name
, MAXPATHLEN
); 
1784         KAUTH_IDENTITY_UNLOCK(); 
1785         return((kip 
== NULL
) ? ENOENT 
: 0); 
1787 #endif  /* CONFIG_EXT_RESOLVER */ 
1793 guid_t kauth_null_guid
; 
1799  * Description: Determine the equality of two GUIDs 
1801  * Parameters:  guid1                           Pointer to first GUID 
1802  *              guid2                           Pointer to second GUID 
1804  * Returns:     0                               If GUIDs are unequal 
1805  *              !0                              If GUIDs are equal 
1808 kauth_guid_equal(guid_t 
*guid1
, guid_t 
*guid2
) 
1810         return(bcmp(guid1
, guid2
, sizeof(*guid1
)) == 0); 
1815  * kauth_wellknown_guid 
1817  * Description: Determine if a GUID is a well-known GUID 
1819  * Parameters:  guid                            Pointer to GUID to check 
1821  * Returns:     KAUTH_WKG_NOT                   Not a well known GUID 
1822  *              KAUTH_WKG_EVERYBODY             "Everybody" 
1823  *              KAUTH_WKG_NOBODY                "Nobody" 
1824  *              KAUTH_WKG_OWNER                 "Other" 
1825  *              KAUTH_WKG_GROUP                 "Group" 
1828 kauth_wellknown_guid(guid_t 
*guid
) 
1830         static char     fingerprint
[] = {0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef}; 
1833          * All WKGs begin with the same 12 bytes. 
1835         if (bcmp((void *)guid
, fingerprint
, 12) == 0) { 
1837                  * The final 4 bytes are our code (in network byte order). 
1839                 code 
= OSSwapHostToBigInt32(*(uint32_t *)&guid
->g_guid
[12]); 
1842                         return(KAUTH_WKG_EVERYBODY
); 
1844                         return(KAUTH_WKG_NOBODY
); 
1846                         return(KAUTH_WKG_OWNER
); 
1848                         return(KAUTH_WKG_GROUP
); 
1851         return(KAUTH_WKG_NOT
); 
1858  * Description: Determine the equality of two NTSIDs (NT Security Identifiers)  
1860  * Parameters:  sid1                            Pointer to first NTSID 
1861  *              sid2                            Pointer to second NTSID 
1863  * Returns:     0                               If GUIDs are unequal 
1864  *              !0                              If GUIDs are equal 
1867 kauth_ntsid_equal(ntsid_t 
*sid1
, ntsid_t 
*sid2
) 
1869         /* check sizes for equality, also sanity-check size while we're at it */ 
1870         if ((KAUTH_NTSID_SIZE(sid1
) == KAUTH_NTSID_SIZE(sid2
)) && 
1871             (KAUTH_NTSID_SIZE(sid1
) <= sizeof(*sid1
)) && 
1872             bcmp(sid1
, sid2
, KAUTH_NTSID_SIZE(sid1
)) == 0) 
1881  * We support four tokens representing identity: 
1882  *  - Credential reference 
1885  *  - NT security identifier 
1887  * Of these, the UID is the ubiquitous identifier; cross-referencing should 
1894  * kauth_cred_change_egid 
1896  * Description: Set EGID by changing the first element of cr_groups for the 
1897  *              passed credential; if the new EGID exists in the list of 
1898  *              groups already, then rotate the old EGID into its position, 
1899  *              otherwise replace it 
1901  * Parameters:  cred                    Pointer to the credential to modify 
1902  *              new_egid                The new EGID to set 
1904  * Returns:     0                       The egid did not displace a member of 
1905  *                                      the supplementary group list 
1906  *              1                       The egid being set displaced a member 
1907  *                                      of the supplementary groups list 
1909  * Note:        Utility function; internal use only because of locking. 
1911  *              This function operates on the credential passed; the caller 
1912  *              must operate either on a newly allocated credential (one for 
1913  *              which there is no hash cache reference and no externally 
1914  *              visible pointer reference), or a template credential. 
1917 kauth_cred_change_egid(kauth_cred_t cred
, gid_t new_egid
) 
1923 #endif  /* radar_4600026 */ 
1924         gid_t   old_egid 
= kauth_cred_getgid(cred
); 
1925         posix_cred_t pcred 
= posix_cred_get(cred
); 
1927         /* Ignoring the first entry, scan for a match for the new egid */ 
1928         for (i 
= 1; i 
< pcred
->cr_ngroups
; i
++) { 
1930                  * If we find a match, swap them so we don't lose overall 
1933                 if (pcred
->cr_groups
[i
] == new_egid
) { 
1934                         pcred
->cr_groups
[i
] = old_egid
; 
1935                         DEBUG_CRED_CHANGE("kauth_cred_change_egid: unset displaced\n"); 
1942 #error Fix radar 4600026 first!!! 
1945 This is correct for memberd behaviour, but incorrect for POSIX; to address 
1946 this, we would need to automatically opt-out any SUID/SGID binary, and force 
1947 it to use initgroups to opt back in.  We take the approach of considering it 
1948 opt'ed out in any group of 16 displacement instead, since it's a much more 
1949 conservative approach (i.e. less likely to cause things to break). 
1953          * If we displaced a member of the supplementary groups list of the 
1954          * credential, and we have not opted out of memberd, then if memberd 
1955          * says that the credential is a member of the group, then it has not 
1956          * actually been displaced. 
1958          * NB:  This is typically a cold code path. 
1960         if (displaced 
&& !(pcred
->cr_flags 
& CRF_NOMEMBERD
) && 
1961             kauth_cred_ismember_gid(cred
, new_egid
, &is_member
) == 0 && 
1964                 DEBUG_CRED_CHANGE("kauth_cred_change_egid: reset displaced\n"); 
1966 #endif  /* radar_4600026 */ 
1968         /* set the new EGID into the old spot */ 
1969         pcred
->cr_groups
[0] = new_egid
; 
1978  * Description: Fetch UID from credential 
1980  * Parameters:  cred                            Credential to examine 
1982  * Returns:     (uid_t)                         UID associated with credential 
1985 kauth_cred_getuid(kauth_cred_t cred
) 
1987         NULLCRED_CHECK(cred
); 
1988         return(posix_cred_get(cred
)->cr_uid
); 
1993  * kauth_cred_getruid 
1995  * Description: Fetch RUID from credential 
1997  * Parameters:  cred                            Credential to examine 
1999  * Returns:     (uid_t)                         RUID associated with credential 
2002 kauth_cred_getruid(kauth_cred_t cred
) 
2004         NULLCRED_CHECK(cred
); 
2005         return(posix_cred_get(cred
)->cr_ruid
); 
2010  * kauth_cred_getsvuid 
2012  * Description: Fetch SVUID from credential 
2014  * Parameters:  cred                            Credential to examine 
2016  * Returns:     (uid_t)                         SVUID associated with credential 
2019 kauth_cred_getsvuid(kauth_cred_t cred
) 
2021         NULLCRED_CHECK(cred
); 
2022         return(posix_cred_get(cred
)->cr_svuid
); 
2029  * Description: Fetch GID from credential 
2031  * Parameters:  cred                            Credential to examine 
2033  * Returns:     (gid_t)                         GID associated with credential 
2036 kauth_cred_getgid(kauth_cred_t cred
) 
2038         NULLCRED_CHECK(cred
); 
2039         return(posix_cred_get(cred
)->cr_gid
); 
2044  * kauth_cred_getrgid 
2046  * Description: Fetch RGID from credential 
2048  * Parameters:  cred                            Credential to examine 
2050  * Returns:     (gid_t)                         RGID associated with credential 
2053 kauth_cred_getrgid(kauth_cred_t cred
) 
2055         NULLCRED_CHECK(cred
); 
2056         return(posix_cred_get(cred
)->cr_rgid
); 
2061  * kauth_cred_getsvgid 
2063  * Description: Fetch SVGID from credential 
2065  * Parameters:  cred                            Credential to examine 
2067  * Returns:     (gid_t)                         SVGID associated with credential 
2070 kauth_cred_getsvgid(kauth_cred_t cred
) 
2072         NULLCRED_CHECK(cred
); 
2073         return(posix_cred_get(cred
)->cr_svgid
); 
2077 static int      kauth_cred_cache_lookup(int from
, int to
, void *src
, void *dst
); 
2079 #if CONFIG_EXT_RESOLVER == 0 
2081  * If there's no resolver, only support a subset of the kauth_cred_x2y() lookups. 
2084 kauth_cred_cache_lookup(int from
, int to
, void *src
, void *dst
) 
2086         /* NB: These must match the definitions used by Libinfo's mbr_identifier_translate(). */ 
2087         static const uuid_t _user_compat_prefix 
= {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd, 0xcc, 0xcc, 0xbb, 0xbb, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00}; 
2088         static const uuid_t _group_compat_prefix 
= {0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0x00, 0x00, 0x00, 0x00}; 
2089 #define COMPAT_PREFIX_LEN       (sizeof(uuid_t) - sizeof(id_t)) 
2094         case KI_VALID_UID
: { 
2095                 id_t uid 
= htonl(*(id_t 
*)src
); 
2097                 if (to 
== KI_VALID_GUID
) { 
2099                         memcpy(uu
, _user_compat_prefix
, sizeof(_user_compat_prefix
)); 
2100                         memcpy(&uu
[COMPAT_PREFIX_LEN
], &uid
, sizeof(uid
)); 
2105         case KI_VALID_GID
: { 
2106                 id_t gid 
= htonl(*(id_t 
*)src
); 
2108                 if (to 
== KI_VALID_GUID
) { 
2110                         memcpy(uu
, _group_compat_prefix
, sizeof(_group_compat_prefix
)); 
2111                         memcpy(&uu
[COMPAT_PREFIX_LEN
], &gid
, sizeof(gid
)); 
2116         case KI_VALID_GUID
: { 
2117                 const uint8_t *uu 
= src
; 
2119                 if (to 
== KI_VALID_UID
) { 
2120                         if (memcmp(uu
, _user_compat_prefix
, COMPAT_PREFIX_LEN
) == 0) { 
2122                                 memcpy(&uid
, &uu
[COMPAT_PREFIX_LEN
], sizeof(uid
)); 
2123                                 *(id_t 
*)dst 
= ntohl(uid
); 
2126                 } else if (to 
== KI_VALID_GID
) { 
2127                         if (memcmp(uu
, _group_compat_prefix
, COMPAT_PREFIX_LEN
) == 0) { 
2129                                 memcpy(&gid
, &uu
[COMPAT_PREFIX_LEN
], sizeof(gid
)); 
2130                                 *(id_t 
*)dst 
= ntohl(gid
); 
2137                 /* NOT IMPLEMENTED */ 
2144 #if defined(CONFIG_EXT_RESOLVER) && (CONFIG_EXT_RESOLVER) 
2146  * Structure to hold supplemental groups. Used for impedance matching with  
2147  * kauth_cred_cache_lookup below. 
2155  * kauth_cred_uid2groups 
2157  * Description: Fetch supplemental GROUPS from UID 
2159  * Parameters:  uid                             UID to examine 
2160  *              groups                          pointer to an array of gid_ts 
2161  *              gcount                          pointer to the number of groups wanted/returned 
2163  * Returns:     0                               Success 
2164  *      kauth_cred_cache_lookup:EINVAL 
2167  *              *groups                         Modified, if successful 
2168  *              *gcount                         Modified, if successful 
2172 kauth_cred_uid2groups(uid_t 
*uid
, gid_t 
*groups
, int *gcount
) 
2176         struct supgroups supgroups
; 
2177         supgroups
.count 
= gcount
; 
2178         supgroups
.groups 
= groups
; 
2180         rv 
= kauth_cred_cache_lookup(KI_VALID_UID
, KI_VALID_GROUPS
, uid
, &supgroups
); 
2187  * kauth_cred_guid2pwnam 
2189  * Description: Fetch PWNAM from GUID 
2191  * Parameters:  guidp                           Pointer to GUID to examine 
2192  *              pwnam                           Pointer to user@domain buffer 
2194  * Returns:     0                               Success 
2195  *      kauth_cred_cache_lookup:EINVAL 
2198  *              *pwnam                          Modified, if successful 
2200  * Notes:       pwnam is assumed to point to a buffer of MAXPATHLEN in size 
2203 kauth_cred_guid2pwnam(guid_t 
*guidp
, char *pwnam
) 
2205         return(kauth_cred_cache_lookup(KI_VALID_GUID
, KI_VALID_PWNAM
, guidp
, pwnam
)); 
2210  * kauth_cred_guid2grnam 
2212  * Description: Fetch GRNAM from GUID 
2214  * Parameters:  guidp                           Pointer to GUID to examine 
2215  *              grnam                           Pointer to group@domain buffer 
2217  * Returns:     0                               Success 
2218  *      kauth_cred_cache_lookup:EINVAL 
2221  *              *grnam                          Modified, if successful 
2223  * Notes:       grnam is assumed to point to a buffer of MAXPATHLEN in size 
2226 kauth_cred_guid2grnam(guid_t 
*guidp
, char *grnam
) 
2228         return(kauth_cred_cache_lookup(KI_VALID_GUID
, KI_VALID_GRNAM
, guidp
, grnam
)); 
2233  * kauth_cred_pwnam2guid 
2235  * Description: Fetch PWNAM from GUID 
2237  * Parameters:  pwnam                           String containing user@domain 
2238  *              guidp                           Pointer to buffer for GUID 
2240  * Returns:     0                               Success 
2241  *      kauth_cred_cache_lookup:EINVAL 
2244  *              *guidp                          Modified, if successful 
2246  * Notes:       pwnam should not point to a request larger than MAXPATHLEN 
2247  *              bytes in size, including the NUL termination of the string. 
2250 kauth_cred_pwnam2guid(char *pwnam
, guid_t 
*guidp
) 
2252         return(kauth_cred_cache_lookup(KI_VALID_PWNAM
, KI_VALID_GUID
, pwnam
, guidp
)); 
2257  * kauth_cred_grnam2guid 
2259  * Description: Fetch GRNAM from GUID 
2261  * Parameters:  grnam                           String containing group@domain 
2262  *              guidp                           Pointer to buffer for GUID 
2264  * Returns:     0                               Success 
2265  *      kauth_cred_cache_lookup:EINVAL 
2268  *              *guidp                          Modified, if successful 
2270  * Notes:       grnam should not point to a request larger than MAXPATHLEN 
2271  *              bytes in size, including the NUL termination of the string. 
2274 kauth_cred_grnam2guid(char *grnam
, guid_t 
*guidp
) 
2276         return(kauth_cred_cache_lookup(KI_VALID_GRNAM
, KI_VALID_GUID
, grnam
, guidp
)); 
2281  * kauth_cred_guid2uid 
2283  * Description: Fetch UID from GUID 
2285  * Parameters:  guidp                           Pointer to GUID to examine 
2286  *              uidp                            Pointer to buffer for UID 
2288  * Returns:     0                               Success 
2289  *      kauth_cred_cache_lookup:EINVAL 
2292  *              *uidp                           Modified, if successful 
2295 kauth_cred_guid2uid(guid_t 
*guidp
, uid_t 
*uidp
) 
2297         return(kauth_cred_cache_lookup(KI_VALID_GUID
, KI_VALID_UID
, guidp
, uidp
)); 
2302  * kauth_cred_guid2gid 
2304  * Description: Fetch GID from GUID 
2306  * Parameters:  guidp                           Pointer to GUID to examine 
2307  *              gidp                            Pointer to buffer for GID 
2309  * Returns:     0                               Success 
2310  *      kauth_cred_cache_lookup:EINVAL 
2313  *              *gidp                           Modified, if successful 
2316 kauth_cred_guid2gid(guid_t 
*guidp
, gid_t 
*gidp
) 
2318         return(kauth_cred_cache_lookup(KI_VALID_GUID
, KI_VALID_GID
, guidp
, gidp
)); 
2322  * kauth_cred_nfs4domain2dsnode 
2324  * Description: Fetch dsnode from nfs4domain 
2326  * Parameters:  nfs4domain                      Pointer to a string nfs4 domain 
2327  *              dsnode                          Pointer to buffer for dsnode 
2329  * Returns:     0                               Success 
2330  *              ENOENT                          For now just a stub that always fails 
2333  *              *dsnode                         Modified, if successuful 
2336 kauth_cred_nfs4domain2dsnode(__unused 
char *nfs4domain
, __unused 
char *dsnode
) 
2342  * kauth_cred_dsnode2nfs4domain 
2344  * Description: Fetch nfs4domain from dsnode 
2346  * Parameters:  nfs4domain                      Pointer to  string dsnode 
2347  *              dsnode                          Pointer to buffer for nfs4domain 
2349  * Returns:     0                               Success 
2350  *              ENOENT                          For now just a stub that always fails 
2353  *              *nfs4domain                     Modified, if successuful 
2356 kauth_cred_dsnode2nfs4domain(__unused 
char *dsnode
, __unused 
char *nfs4domain
) 
2362  * kauth_cred_ntsid2uid 
2364  * Description: Fetch UID from NTSID 
2366  * Parameters:  sidp                            Pointer to NTSID to examine 
2367  *              uidp                            Pointer to buffer for UID 
2369  * Returns:     0                               Success 
2370  *      kauth_cred_cache_lookup:EINVAL 
2373  *              *uidp                           Modified, if successful 
2376 kauth_cred_ntsid2uid(ntsid_t 
*sidp
, uid_t 
*uidp
) 
2378         return(kauth_cred_cache_lookup(KI_VALID_NTSID
, KI_VALID_UID
, sidp
, uidp
)); 
2383  * kauth_cred_ntsid2gid 
2385  * Description: Fetch GID from NTSID 
2387  * Parameters:  sidp                            Pointer to NTSID to examine 
2388  *              gidp                            Pointer to buffer for GID 
2390  * Returns:     0                               Success 
2391  *      kauth_cred_cache_lookup:EINVAL 
2394  *              *gidp                           Modified, if successful 
2397 kauth_cred_ntsid2gid(ntsid_t 
*sidp
, gid_t 
*gidp
) 
2399         return(kauth_cred_cache_lookup(KI_VALID_NTSID
, KI_VALID_GID
, sidp
, gidp
)); 
2404  * kauth_cred_ntsid2guid 
2406  * Description: Fetch GUID from NTSID 
2408  * Parameters:  sidp                            Pointer to NTSID to examine 
2409  *              guidp                           Pointer to buffer for GUID 
2411  * Returns:     0                               Success 
2412  *      kauth_cred_cache_lookup:EINVAL 
2415  *              *guidp                          Modified, if successful 
2418 kauth_cred_ntsid2guid(ntsid_t 
*sidp
, guid_t 
*guidp
) 
2420         return(kauth_cred_cache_lookup(KI_VALID_NTSID
, KI_VALID_GUID
, sidp
, guidp
)); 
2425  * kauth_cred_uid2guid 
2427  * Description: Fetch GUID from UID 
2429  * Parameters:  uid                             UID to examine 
2430  *              guidp                           Pointer to buffer for GUID 
2432  * Returns:     0                               Success 
2433  *      kauth_cred_cache_lookup:EINVAL 
2436  *              *guidp                          Modified, if successful 
2439 kauth_cred_uid2guid(uid_t uid
, guid_t 
*guidp
) 
2441         return(kauth_cred_cache_lookup(KI_VALID_UID
, KI_VALID_GUID
, &uid
, guidp
)); 
2446  * kauth_cred_getguid 
2448  * Description: Fetch GUID from credential 
2450  * Parameters:  cred                            Credential to examine 
2451  *              guidp                           Pointer to buffer for GUID 
2453  * Returns:     0                               Success 
2454  *      kauth_cred_cache_lookup:EINVAL 
2457  *              *guidp                          Modified, if successful 
2460 kauth_cred_getguid(kauth_cred_t cred
, guid_t 
*guidp
) 
2462         NULLCRED_CHECK(cred
); 
2463         return(kauth_cred_uid2guid(kauth_cred_getuid(cred
), guidp
)); 
2468  * kauth_cred_getguid 
2470  * Description: Fetch GUID from GID 
2472  * Parameters:  gid                             GID to examine 
2473  *              guidp                           Pointer to buffer for GUID 
2475  * Returns:     0                               Success 
2476  *      kauth_cred_cache_lookup:EINVAL 
2479  *              *guidp                          Modified, if successful 
2482 kauth_cred_gid2guid(gid_t gid
, guid_t 
*guidp
) 
2484         return(kauth_cred_cache_lookup(KI_VALID_GID
, KI_VALID_GUID
, &gid
, guidp
)); 
2489  * kauth_cred_uid2ntsid 
2491  * Description: Fetch NTSID from UID 
2493  * Parameters:  uid                             UID to examine 
2494  *              sidp                            Pointer to buffer for NTSID 
2496  * Returns:     0                               Success 
2497  *      kauth_cred_cache_lookup:EINVAL 
2500  *              *sidp                           Modified, if successful 
2503 kauth_cred_uid2ntsid(uid_t uid
, ntsid_t 
*sidp
) 
2505         return(kauth_cred_cache_lookup(KI_VALID_UID
, KI_VALID_NTSID
, &uid
, sidp
)); 
2510  * kauth_cred_getntsid 
2512  * Description: Fetch NTSID from credential 
2514  * Parameters:  cred                            Credential to examine 
2515  *              sidp                            Pointer to buffer for NTSID 
2517  * Returns:     0                               Success 
2518  *      kauth_cred_cache_lookup:EINVAL 
2521  *              *sidp                           Modified, if successful 
2524 kauth_cred_getntsid(kauth_cred_t cred
, ntsid_t 
*sidp
) 
2526         NULLCRED_CHECK(cred
); 
2527         return(kauth_cred_uid2ntsid(kauth_cred_getuid(cred
), sidp
)); 
2532  * kauth_cred_gid2ntsid 
2534  * Description: Fetch NTSID from GID 
2536  * Parameters:  gid                             GID to examine 
2537  *              sidp                            Pointer to buffer for NTSID 
2539  * Returns:     0                               Success 
2540  *      kauth_cred_cache_lookup:EINVAL 
2543  *              *sidp                           Modified, if successful 
2546 kauth_cred_gid2ntsid(gid_t gid
, ntsid_t 
*sidp
) 
2548         return(kauth_cred_cache_lookup(KI_VALID_GID
, KI_VALID_NTSID
, &gid
, sidp
)); 
2553  * kauth_cred_guid2ntsid 
2555  * Description: Fetch NTSID from GUID 
2557  * Parameters:  guidp                           Pointer to GUID to examine 
2558  *              sidp                            Pointer to buffer for NTSID 
2560  * Returns:     0                               Success 
2561  *      kauth_cred_cache_lookup:EINVAL 
2564  *              *sidp                           Modified, if successful 
2567 kauth_cred_guid2ntsid(guid_t 
*guidp
, ntsid_t 
*sidp
) 
2569         return(kauth_cred_cache_lookup(KI_VALID_GUID
, KI_VALID_NTSID
, guidp
, sidp
)); 
2574  * kauth_cred_cache_lookup 
2576  * Description: Lookup a translation in the cache; if one is not found, and 
2577  *              the attempt was not fatal, submit the request to the resolver 
2578  *              instead, and wait for it to complete or be aborted. 
2580  * Parameters:  from                            Identity information we have 
2581  *              to                              Identity information we want 
2582  *              src                             Pointer to buffer containing 
2583  *                                              the source identity 
2584  *              dst                             Pointer to buffer to receive 
2585  *                                              the target identity 
2587  * Returns:     0                               Success 
2588  *              EINVAL                          Unknown source identity type 
2590 #if CONFIG_EXT_RESOLVER 
2592 kauth_cred_cache_lookup(int from
, int to
, void *src
, void *dst
) 
2594         struct kauth_identity ki
; 
2595         struct kauth_identity_extlookup el
; 
2597         uint64_t extend_data 
= 0ULL; 
2598         int (* expired
)(struct kauth_identity 
*kip
); 
2599         char *namebuf 
= NULL
; 
2601         KAUTH_DEBUG("CACHE - translate %d to %d", from
, to
); 
2604          * Look for an existing cache entry for this association. 
2605          * If the entry has not expired, return the cached information. 
2606          * We do not cache user@domain translations here; they use too 
2607          * much memory to hold onto forever, and can not be updated 
2610         if (to 
== KI_VALID_PWNAM 
|| to 
== KI_VALID_GRNAM
) { 
2616                 error 
= kauth_identity_find_uid(*(uid_t 
*)src
, &ki
, namebuf
); 
2619                 error 
= kauth_identity_find_gid(*(gid_t 
*)src
, &ki
, namebuf
); 
2622                 error 
= kauth_identity_find_guid((guid_t 
*)src
, &ki
, namebuf
); 
2624         case KI_VALID_NTSID
: 
2625                 error 
= kauth_identity_find_ntsid((ntsid_t 
*)src
, &ki
, namebuf
); 
2627         case KI_VALID_PWNAM
: 
2628         case KI_VALID_GRNAM
: 
2629                 /* Names are unique in their 'from' space */ 
2630                 error 
= kauth_identity_find_nam((char *)src
, from
, &ki
); 
2635         /* lookup failure or error */ 
2637                 /* any other error is fatal */ 
2638                 if (error 
!= ENOENT
) { 
2639                         /* XXX bogus check - this is not possible */ 
2640                         KAUTH_DEBUG("CACHE - cache search error %d", error
); 
2644                 /* found a valid cached entry, check expiry */ 
2647                         expired 
= kauth_identity_guid_expired
; 
2649                 case KI_VALID_NTSID
: 
2650                         expired 
= kauth_identity_ntsid_expired
; 
2652                 case KI_VALID_GROUPS
: 
2653                         expired 
= kauth_identity_groups_expired
; 
2658                                 expired 
= kauth_identity_guid_expired
; 
2660                         case KI_VALID_NTSID
: 
2661                                 expired 
= kauth_identity_ntsid_expired
; 
2669                  * If no expiry function, or not expired, we have found 
2673                         if (!expired(&ki
)) { 
2674                                 KAUTH_DEBUG("CACHE - entry valid, unexpired"); 
2675                                 expired 
= NULL
; /* must clear it is used as a flag */ 
2678                                  * We leave ki_valid set here; it contains a 
2679                                  * translation but the TTL has expired.  If we can't 
2680                                  * get a result from the resolver, we will use it as 
2681                                  * a better-than nothing alternative. 
2684                                 KAUTH_DEBUG("CACHE - expired entry found"); 
2687                         KAUTH_DEBUG("CACHE - no expiry function"); 
2691                         /* do we have a translation? */ 
2692                         if (ki
.ki_valid 
& to
) { 
2693                                 KAUTH_DEBUG("CACHE - found matching entry with valid 0x%08x", ki
.ki_valid
); 
2694                                 DTRACE_PROC4(kauth__identity__cache__hit
, int, from
, int, to
, void *, src
, void *, dst
); 
2698                                  * GUIDs and NTSIDs map to either a UID or a GID, but not both.  
2699                                  * If we went looking for a translation from GUID or NTSID and  
2700                                  * found a translation that wasn't for our desired type, then  
2701                                  * don't bother calling the resolver. We know that this  
2702                                  * GUID/NTSID can't translate to our desired type. 
2706                                 case KI_VALID_NTSID
: 
2709                                                 if ((ki
.ki_valid 
& KI_VALID_UID
)) { 
2710                                                         KAUTH_DEBUG("CACHE - unexpected entry 0x%08x & %x", ki
.ki_valid
, KI_VALID_GID
); 
2715                                                 if ((ki
.ki_valid 
& KI_VALID_GID
)) { 
2716                                                         KAUTH_DEBUG("CACHE - unexpected entry 0x%08x & %x", ki
.ki_valid
, KI_VALID_UID
); 
2728          * We failed to find a cache entry; call the resolver. 
2730          * Note:        We ask for as much non-extended data as we can get, 
2731          *              and only provide (or ask for) extended information if 
2732          *              we have a 'from' (or 'to') which requires it.  This 
2733          *              way we don't pay for the extra transfer overhead for 
2734          *              data we don't need. 
2736         bzero(&el
, sizeof(el
)); 
2737         el
.el_info_pid 
= current_proc()->p_pid
; 
2740                 el
.el_flags 
= KAUTH_EXTLOOKUP_VALID_UID
; 
2741                 el
.el_uid 
= *(uid_t 
*)src
; 
2744                 el
.el_flags 
= KAUTH_EXTLOOKUP_VALID_GID
; 
2745                 el
.el_gid 
= *(gid_t 
*)src
; 
2748                 el
.el_flags 
= KAUTH_EXTLOOKUP_VALID_UGUID 
| KAUTH_EXTLOOKUP_VALID_GGUID
; 
2749                 el
.el_uguid 
= *(guid_t 
*)src
; 
2750                 el
.el_gguid 
= *(guid_t 
*)src
; 
2752         case KI_VALID_NTSID
: 
2753                 el
.el_flags 
= KAUTH_EXTLOOKUP_VALID_USID 
| KAUTH_EXTLOOKUP_VALID_GSID
; 
2754                 el
.el_usid 
= *(ntsid_t 
*)src
; 
2755                 el
.el_gsid 
= *(ntsid_t 
*)src
; 
2757         case KI_VALID_PWNAM
: 
2758                 /* extra overhead */ 
2759                 el
.el_flags 
= KAUTH_EXTLOOKUP_VALID_PWNAM
; 
2760                 extend_data 
= CAST_USER_ADDR_T(src
); 
2762         case KI_VALID_GRNAM
: 
2763                 /* extra overhead */ 
2764                 el
.el_flags 
= KAUTH_EXTLOOKUP_VALID_GRNAM
; 
2765                 extend_data 
= CAST_USER_ADDR_T(src
); 
2771          * Here we ask for everything all at once, to avoid having to work 
2772          * out what we really want now, or might want soon. 
2774          * Asking for SID translations when we don't know we need them right 
2775          * now is going to cause excess work to be done if we're connected 
2776          * to a network that thinks it can translate them.  This list needs 
2777          * to get smaller/smarter. 
2779         el
.el_flags 
|= KAUTH_EXTLOOKUP_WANT_UID 
| KAUTH_EXTLOOKUP_WANT_GID 
| 
2780             KAUTH_EXTLOOKUP_WANT_UGUID 
| KAUTH_EXTLOOKUP_WANT_GGUID 
| 
2781             KAUTH_EXTLOOKUP_WANT_USID 
| KAUTH_EXTLOOKUP_WANT_GSID
; 
2782         if (to 
== KI_VALID_PWNAM
) { 
2783                 /* extra overhead */ 
2784                 el
.el_flags 
|= KAUTH_EXTLOOKUP_WANT_PWNAM
; 
2785                 extend_data 
= CAST_USER_ADDR_T(dst
); 
2787         if (to 
== KI_VALID_GRNAM
) { 
2788                 /* extra overhead */ 
2789                 el
.el_flags 
|= KAUTH_EXTLOOKUP_WANT_GRNAM
; 
2790                 extend_data 
= CAST_USER_ADDR_T(dst
); 
2792         if (to 
== KI_VALID_GROUPS
) { 
2793                 /* Expensive and only useful for an NFS client not using kerberos */ 
2794                 el
.el_flags 
|= KAUTH_EXTLOOKUP_WANT_SUPGRPS
; 
2795                 if (ki
.ki_valid 
& KI_VALID_GROUPS
) { 
2797                          * Copy the current supplemental groups for the resolver.  
2798                          * The resolver should check these groups first and if 
2799                          * the user (uid) is still a member it should endeavor to  
2800                          * keep them in the list. Otherwise NFS clients could get 
2801                          * changing access to server file system objects on each 
2804                         if (ki
.ki_supgrpcnt 
> NGROUPS
) { 
2805                                 panic("kauth data structure corrupted. kauth identity 0x%p with %d groups, greater than max of %d", 
2806                                         &ki
, ki
.ki_supgrpcnt
, NGROUPS
); 
2809                         el
.el_sup_grp_cnt 
= ki
.ki_supgrpcnt
; 
2811                         memcpy(el
.el_sup_groups
, ki
.ki_supgrps
, sizeof (el
.el_sup_groups
[0]) * ki
.ki_supgrpcnt
); 
2812                         /* Let the resolver know these were the previous valid groups */ 
2813                         el
.el_flags 
|= KAUTH_EXTLOOKUP_VALID_SUPGRPS
; 
2814                         KAUTH_DEBUG("GROUPS: Sending previously valid GROUPS"); 
2816                         KAUTH_DEBUG("GROUPS: no valid groups to send"); 
2820         KAUTH_DEBUG("CACHE - calling resolver for %x", el
.el_flags
); 
2822         DTRACE_PROC3(kauth__id__resolver__submitted
, int, from
, int, to
, uintptr_t, src
); 
2824         error 
= kauth_resolver_submit(&el
, extend_data
); 
2826         DTRACE_PROC2(kauth__id__resolver__returned
, int, error
, struct kauth_identity_extlookup 
*, &el
) 
2828         KAUTH_DEBUG("CACHE - resolver returned %d", error
); 
2830         /* was the external lookup successful? */ 
2833                  * Save the results from the lookup - we may have other 
2834                  * information, even if we didn't get a guid or the 
2837                  * If we came from a name, we know the extend_data is valid. 
2839                 if (from 
== KI_VALID_PWNAM
) 
2840                         el
.el_flags 
|= KAUTH_EXTLOOKUP_VALID_PWNAM
; 
2841                 else if (from 
== KI_VALID_GRNAM
) 
2842                         el
.el_flags 
|= KAUTH_EXTLOOKUP_VALID_GRNAM
; 
2844                 kauth_identity_updatecache(&el
, &ki
, extend_data
); 
2847                  * Check to see if we have a valid cache entry 
2848                  * originating from the result. 
2850                 if (!(ki
.ki_valid 
& to
)) { 
2858          * Copy from the appropriate struct kauth_identity cache entry 
2859          * structure into the destination buffer area. 
2863                 *(uid_t 
*)dst 
= ki
.ki_uid
; 
2866                 *(gid_t 
*)dst 
= ki
.ki_gid
; 
2869                 *(guid_t 
*)dst 
= ki
.ki_guid
; 
2871         case KI_VALID_NTSID
: 
2872                 *(ntsid_t 
*)dst 
= ki
.ki_ntsid
; 
2874         case KI_VALID_GROUPS
: { 
2875                         struct supgroups 
*gp 
= (struct supgroups 
*)dst
; 
2876                         u_int32_t limit 
= ki
.ki_supgrpcnt
; 
2879                                 limit 
= MIN(ki
.ki_supgrpcnt
, *gp
->count
); 
2883                         memcpy(gp
->groups
, ki
.ki_supgrps
, sizeof(gid_t
) * limit
); 
2886         case KI_VALID_PWNAM
: 
2887         case KI_VALID_GRNAM
: 
2888                 /* handled in kauth_resolver_complete() */ 
2893         KAUTH_DEBUG("CACHE - returned successfully"); 
2899  * Group membership cache. 
2901  * XXX the linked-list implementation here needs to be optimized. 
2907  * Description: Initialize the groups cache 
2909  * Parameters:  (void) 
2913  * Notes:       Initialize the groups cache for use; the group cache is used 
2914  *              to avoid unnecessary calls out to user space. 
2916  *              This function is called from kauth_init() in the file 
2917  *              kern_authorization.c. 
2920 kauth_groups_init(void) 
2922         TAILQ_INIT(&kauth_groups
); 
2923         kauth_groups_mtx 
= lck_mtx_alloc_init(kauth_lck_grp
, 0/*LCK_ATTR_NULL*/); 
2928  * kauth_groups_expired 
2930  * Description: Handle lazy expiration of group membership cache entries 
2932  * Parameters:  gm                              group membership entry to 
2933  *                                              check for expiration 
2935  * Returns:     1                               Expired 
2939 kauth_groups_expired(struct kauth_group_membership 
*gm
) 
2944          * Expiration time of 0 means this entry is persistent. 
2946         if (gm
->gm_expiry 
== 0) 
2951         return((gm
->gm_expiry 
<= tv
.tv_sec
) ? 1 : 0); 
2958  * Description: Promote the entry to the head of the LRU, assumes the cache 
2961  * Parameters:  kip                             group membership entry to move 
2962  *                                              to the head of the LRU list, 
2963  *                                              if it's not already there 
2967  * Notes:       This is called even if the entry has expired; typically an 
2968  *              expired entry that's been looked up is about to be revalidated, 
2969  *              and having it closer to the head of the LRU means finding it 
2970  *              quickly again when the revalidation comes through. 
2973 kauth_groups_lru(struct kauth_group_membership 
*gm
) 
2975         if (gm 
!= TAILQ_FIRST(&kauth_groups
)) { 
2976                 TAILQ_REMOVE(&kauth_groups
, gm
, gm_link
); 
2977                 TAILQ_INSERT_HEAD(&kauth_groups
, gm
, gm_link
); 
2983  * kauth_groups_updatecache 
2985  * Description: Given a lookup result, add any group cache associations that 
2986  *              we don't currently have. 
2988  * Parameters:  elp                             External lookup result from 
2989  *                                              user space daemon to kernel 
2990  *              rkip                            pointer to returned kauth 
2996 kauth_groups_updatecache(struct kauth_identity_extlookup 
*el
) 
2998         struct kauth_group_membership 
*gm
; 
3001         /* need a valid response if we are to cache anything */ 
3003                 (KAUTH_EXTLOOKUP_VALID_UID 
| KAUTH_EXTLOOKUP_VALID_GID 
| KAUTH_EXTLOOKUP_VALID_MEMBERSHIP
)) != 
3004             (KAUTH_EXTLOOKUP_VALID_UID 
| KAUTH_EXTLOOKUP_VALID_GID 
| KAUTH_EXTLOOKUP_VALID_MEMBERSHIP
)) 
3010          * Search for an existing record for this association before inserting 
3011          * a new one; if we find one, update it instead of creating a new one 
3013         KAUTH_GROUPS_LOCK(); 
3014         TAILQ_FOREACH(gm
, &kauth_groups
, gm_link
) { 
3015                 if ((el
->el_uid 
== gm
->gm_uid
) && 
3016                     (el
->el_gid 
== gm
->gm_gid
)) { 
3017                         if (el
->el_flags 
& KAUTH_EXTLOOKUP_ISMEMBER
) { 
3018                                 gm
->gm_flags 
|= KAUTH_GROUP_ISMEMBER
; 
3020                                 gm
->gm_flags 
&= ~KAUTH_GROUP_ISMEMBER
; 
3022                         gm
->gm_expiry 
= (el
->el_member_valid
) ? el
->el_member_valid 
+ tv
.tv_sec 
: 0; 
3023                         kauth_groups_lru(gm
); 
3027         KAUTH_GROUPS_UNLOCK(); 
3029         /* if we found an entry to update, stop here */ 
3033         /* allocate a new record */ 
3034         MALLOC(gm
, struct kauth_group_membership 
*, sizeof(*gm
), M_KAUTH
, M_WAITOK
); 
3036                 gm
->gm_uid 
= el
->el_uid
; 
3037                 gm
->gm_gid 
= el
->el_gid
; 
3038                 if (el
->el_flags 
& KAUTH_EXTLOOKUP_ISMEMBER
) { 
3039                         gm
->gm_flags 
|= KAUTH_GROUP_ISMEMBER
; 
3041                         gm
->gm_flags 
&= ~KAUTH_GROUP_ISMEMBER
; 
3043                 gm
->gm_expiry 
= (el
->el_member_valid
) ? el
->el_member_valid 
+ tv
.tv_sec 
: 0; 
3047          * Insert the new entry.  Note that it's possible to race ourselves 
3048          * here and end up with duplicate entries in the list.  Wasteful, but 
3049          * harmless since the first into the list will never be looked up, 
3050          * and thus will eventually just fall off the end. 
3052         KAUTH_GROUPS_LOCK(); 
3053         TAILQ_INSERT_HEAD(&kauth_groups
, gm
, gm_link
); 
3054         if (++kauth_groups_count 
> kauth_groups_cachemax
) { 
3055                 gm 
= TAILQ_LAST(&kauth_groups
, kauth_groups_head
); 
3056                 TAILQ_REMOVE(&kauth_groups
, gm
, gm_link
); 
3057                 kauth_groups_count
--; 
3061         KAUTH_GROUPS_UNLOCK(); 
3063         /* free expired cache entry */ 
3069  * Trim older entries from the group membership cache. 
3071  * Must be called with the group cache lock held. 
3074 kauth_groups_trimcache(int new_size
) { 
3075         struct kauth_group_membership 
*gm
; 
3077         lck_mtx_assert(kauth_groups_mtx
, LCK_MTX_ASSERT_OWNED
); 
3079         while (kauth_groups_count 
> new_size
) { 
3080                 gm 
= TAILQ_LAST(&kauth_groups
, kauth_groups_head
); 
3081                 TAILQ_REMOVE(&kauth_groups
, gm
, gm_link
); 
3082                 kauth_groups_count
--; 
3086 #endif  /* CONFIG_EXT_RESOLVER */ 
3089  * Group membership KPI 
3093  * kauth_cred_ismember_gid 
3095  * Description: Given a credential and a GID, determine if the GID is a member 
3096  *              of one of the supplementary groups associated with the given 
3099  * Parameters:  cred                            Credential to check in 
3100  *              gid                             GID to check for membership 
3101  *              resultp                         Pointer to int to contain the 
3102  *                                              result of the call 
3104  * Returns:     0                               Success 
3105  *              ENOENT                          Could not perform lookup 
3106  *      kauth_resolver_submit:EWOULDBLOCK 
3107  *      kauth_resolver_submit:EINTR 
3108  *      kauth_resolver_submit:ENOMEM 
3109  *      kauth_resolver_submit:ENOENT            User space daemon did not vend 
3111  *      kauth_resolver_submit:???               Unlikely error from user space 
3114  *              *resultp (modified)     1       Is member 
3117  * Notes:       This function guarantees not to modify resultp when returning 
3120  *              This function effectively checks the EGID as well, since the 
3121  *              EGID is cr_groups[0] as an implementation detail. 
3124 kauth_cred_ismember_gid(kauth_cred_t cred
, gid_t gid
, int *resultp
) 
3126         posix_cred_t pcred 
= posix_cred_get(cred
); 
3130          * Check the per-credential list of override groups. 
3132          * We can conditionalise this on cred->cr_gmuid == KAUTH_UID_NONE since 
3133          * the cache should be used for that case. 
3135         for (i 
= 0; i 
< pcred
->cr_ngroups
; i
++) { 
3136                 if (gid 
== pcred
->cr_groups
[i
]) { 
3143          * If we don't have a UID for group membership checks, the in-cred list 
3144          * was authoritative and we can stop here. 
3146         if (pcred
->cr_gmuid 
== KAUTH_UID_NONE
) { 
3151 #if CONFIG_EXT_RESOLVER 
3152         struct kauth_group_membership 
*gm
; 
3153         struct kauth_identity_extlookup el
; 
3157          * If the resolver hasn't checked in yet, we are early in the boot 
3158          * phase and the local group list is complete and authoritative. 
3160         if (!kauth_resolver_registered
) { 
3166         /* XXX check supplementary groups */ 
3167         /* XXX check whiteout groups */ 
3168         /* XXX nesting of supplementary/whiteout groups? */ 
3171          * Check the group cache. 
3173         KAUTH_GROUPS_LOCK(); 
3174         TAILQ_FOREACH(gm
, &kauth_groups
, gm_link
) { 
3175                 if ((gm
->gm_uid 
== pcred
->cr_gmuid
) && (gm
->gm_gid 
== gid
) && !kauth_groups_expired(gm
)) { 
3176                         kauth_groups_lru(gm
); 
3181         /* did we find a membership entry? */ 
3183                 *resultp 
= (gm
->gm_flags 
& KAUTH_GROUP_ISMEMBER
) ? 1 : 0; 
3184         KAUTH_GROUPS_UNLOCK(); 
3186         /* if we did, we can return now */ 
3188                 DTRACE_PROC2(kauth__group__cache__hit
, int, pcred
->cr_gmuid
, int, gid
); 
3192         /* nothing in the cache, need to go to userland */ 
3193         bzero(&el
, sizeof(el
)); 
3194         el
.el_info_pid 
= current_proc()->p_pid
; 
3195         el
.el_flags 
= KAUTH_EXTLOOKUP_VALID_UID 
| KAUTH_EXTLOOKUP_VALID_GID 
| KAUTH_EXTLOOKUP_WANT_MEMBERSHIP
; 
3196         el
.el_uid 
= pcred
->cr_gmuid
; 
3198         el
.el_member_valid 
= 0;         /* XXX set by resolver? */ 
3200         DTRACE_PROC2(kauth__group__resolver__submitted
, int, el
.el_uid
, int, el
.el_gid
); 
3202         error 
= kauth_resolver_submit(&el
, 0ULL); 
3204         DTRACE_PROC2(kauth__group__resolver__returned
, int, error
, int, el
.el_flags
); 
3208         /* save the results from the lookup */ 
3209         kauth_groups_updatecache(&el
); 
3211         /* if we successfully ascertained membership, report */ 
3212         if (el
.el_flags 
& KAUTH_EXTLOOKUP_VALID_MEMBERSHIP
) { 
3213                 *resultp 
= (el
.el_flags 
& KAUTH_EXTLOOKUP_ISMEMBER
) ? 1 : 0; 
3225  * kauth_cred_ismember_guid 
3227  * Description: Determine whether the supplied credential is a member of the 
3228  *              group nominated by GUID. 
3230  * Parameters:  cred                            Credential to check in 
3231  *              guidp                           Pointer to GUID whose group 
3232  *                                              we are testing for membership 
3233  *              resultp                         Pointer to int to contain the 
3234  *                                              result of the call 
3236  * Returns:     0                               Success 
3237  *      kauth_cred_guid2gid:EINVAL 
3238  *      kauth_cred_ismember_gid:ENOENT 
3239  *      kauth_resolver_submit:ENOENT            User space daemon did not vend 
3241  *      kauth_cred_ismember_gid:EWOULDBLOCK 
3242  *      kauth_cred_ismember_gid:EINTR 
3243  *      kauth_cred_ismember_gid:ENOMEM 
3244  *      kauth_cred_ismember_gid:???             Unlikely error from user space 
3247  *              *resultp (modified)     1       Is member 
3251 kauth_cred_ismember_guid(__unused kauth_cred_t cred
, guid_t 
*guidp
, int *resultp
) 
3255         switch (kauth_wellknown_guid(guidp
)) { 
3256         case KAUTH_WKG_NOBODY
: 
3259         case KAUTH_WKG_EVERYBODY
: 
3265 #if CONFIG_EXT_RESOLVER 
3266                 struct kauth_identity ki
; 
3269                  * Grovel the identity cache looking for this GUID. 
3270                  * If we find it, and it is for a user record, return 
3271                  * false because it's not a group. 
3273                  * This is necessary because we don't have -ve caching 
3274                  * of group memberships, and we really want to avoid 
3275                  * calling out to the resolver if at all possible. 
3277                  * Because we're called by the ACL evaluator, and the 
3278                  * ACL evaluator is likely to encounter ACEs for users, 
3279                  * this is expected to be a common case. 
3282                 if ((error 
= kauth_identity_find_guid(guidp
, &ki
, NULL
)) == 0 && 
3283                     !kauth_identity_guid_expired(&ki
)) { 
3284                         if (ki
.ki_valid 
& KI_VALID_GID
) { 
3285                                 /* It's a group after all... */ 
3289                         if (ki
.ki_valid 
& KI_VALID_UID
) { 
3294 #endif /* CONFIG_EXT_RESOLVER */ 
3296                  * Attempt to translate the GUID to a GID.  Even if 
3297                  * this fails, we will have primed the cache if it is 
3298                  * a user record and we'll see it above the next time 
3301                 if ((error 
= kauth_cred_guid2gid(guidp
, &gid
)) != 0) { 
3303                          * If we have no guid -> gid translation, it's not a group and 
3304                          * thus the cred can't be a member. 
3306                         if (error 
== ENOENT
) { 
3311 #if CONFIG_EXT_RESOLVER 
3313 #endif /* CONFIG_EXT_RESOLVER */ 
3314                         error 
= kauth_cred_ismember_gid(cred
, gid
, resultp
); 
3323  * kauth_cred_gid_subset 
3325  * Description: Given two credentials, determine if all GIDs associated with  
3326  *              the first are also associated with the second 
3328  * Parameters:  cred1                           Credential to check for 
3329  *              cred2                           Credential to check in 
3330  *              resultp                         Pointer to int to contain the 
3331  *                                              result of the call 
3333  * Returns:     0                               Success 
3334  *              non-zero                        See kauth_cred_ismember_gid for 
3338  *              *resultp (modified)     1       Is subset 
3341  * Notes:       This function guarantees not to modify resultp when returning 
3345 kauth_cred_gid_subset(kauth_cred_t cred1
, kauth_cred_t cred2
, int *resultp
) 
3347         int i
, err
, res 
= 1; 
3349         posix_cred_t pcred1 
= posix_cred_get(cred1
); 
3350         posix_cred_t pcred2 
= posix_cred_get(cred2
); 
3352         /* First, check the local list of groups */ 
3353         for (i 
= 0; i 
< pcred1
->cr_ngroups
; i
++) { 
3354                 gid 
= pcred1
->cr_groups
[i
]; 
3355                 if ((err 
= kauth_cred_ismember_gid(cred2
, gid
, &res
)) != 0) { 
3359                 if (!res 
&& gid 
!= pcred2
->cr_rgid 
&& gid 
!= pcred2
->cr_svgid
) { 
3365         /* Check real gid */ 
3366         if ((err 
= kauth_cred_ismember_gid(cred2
, pcred1
->cr_rgid
, &res
)) != 0) { 
3370         if (!res 
&& pcred1
->cr_rgid 
!= pcred2
->cr_rgid 
&& 
3371                         pcred1
->cr_rgid 
!= pcred2
->cr_svgid
) { 
3376         /* Finally, check saved gid */ 
3377         if ((err 
= kauth_cred_ismember_gid(cred2
, pcred1
->cr_svgid
, &res
)) != 0){ 
3381         if (!res 
&& pcred1
->cr_svgid 
!= pcred2
->cr_rgid 
&& 
3382                         pcred1
->cr_svgid 
!= pcred2
->cr_svgid
) { 
3393  * kauth_cred_issuser 
3395  * Description: Fast replacement for issuser() 
3397  * Parameters:  cred                            Credential to check for super 
3400  * Returns:     0                               Not super user 
3403  * Notes:       This function uses a magic number which is not a manifest 
3404  *              constant; this is bad practice. 
3407 kauth_cred_issuser(kauth_cred_t cred
) 
3409         return(kauth_cred_getuid(cred
) == 0); 
3417 /* lock protecting credential hash table */ 
3418 static lck_mtx_t 
*kauth_cred_hash_mtx
; 
3419 #define KAUTH_CRED_HASH_LOCK()          lck_mtx_lock(kauth_cred_hash_mtx); 
3420 #define KAUTH_CRED_HASH_UNLOCK()        lck_mtx_unlock(kauth_cred_hash_mtx); 
3421 #if KAUTH_CRED_HASH_DEBUG 
3422 #define KAUTH_CRED_HASH_LOCK_ASSERT()   lck_mtx_assert(kauth_cred_hash_mtx, LCK_MTX_ASSERT_OWNED) 
3423 #else   /* !KAUTH_CRED_HASH_DEBUG */ 
3424 #define KAUTH_CRED_HASH_LOCK_ASSERT() 
3425 #endif  /* !KAUTH_CRED_HASH_DEBUG */ 
3431  * Description: Initialize the credential hash cache 
3433  * Parameters:  (void) 
3437  * Notes:       Intialize the credential hash cache for use; the credential 
3438  *              hash cache is used convert duplicate credentials into a 
3439  *              single reference counted credential in order to save wired 
3440  *              kernel memory.  In practice, this generally means a desktop 
3441  *              system runs with a few tens of credentials, instead of one 
3442  *              per process, one per thread, one per vnode cache entry, and 
3443  *              so on.  This generally results in savings of 200K or more 
3444  *              (potentially much more on server systems). 
3446  *              The hash cache internally has a reference on the credential 
3447  *              for itself as a means of avoiding a reclaim race for a 
3448  *              credential in the process of having it's last non-hash 
3449  *              reference released.  This would otherwise result in the 
3450  *              possibility of a freed credential that was still in uses due 
3451  *              a race.  This use is protected by the KAUTH_CRED_HASH_LOCK. 
3453  *              On final release, the hash reference is droped, and the 
3454  *              credential is freed back to the system. 
3456  *              This function is called from kauth_init() in the file 
3457  *              kern_authorization.c. 
3460 kauth_cred_init(void) 
3464         kauth_cred_hash_mtx 
= lck_mtx_alloc_init(kauth_lck_grp
, 0/*LCK_ATTR_NULL*/); 
3466         /*allocate credential hash table */ 
3467         MALLOC(kauth_cred_table_anchor
, struct kauth_cred_entry_head 
*,  
3468                         (sizeof(struct kauth_cred_entry_head
) * KAUTH_CRED_TABLE_SIZE
), 
3469                         M_KAUTH
, M_WAITOK 
| M_ZERO
); 
3470         if (kauth_cred_table_anchor 
== NULL
) 
3471                 panic("startup: kauth_cred_init"); 
3472         for (i 
= 0; i 
< KAUTH_CRED_TABLE_SIZE
; i
++) { 
3473                 TAILQ_INIT(&kauth_cred_table_anchor
[i
]); 
3481  * Description: Get the current thread's effective UID. 
3483  * Parameters:  (void) 
3485  * Returns:     (uid_t)                         The effective UID of the 
3491         return(kauth_cred_getuid(kauth_cred_get())); 
3498  * Description: Get the current thread's real UID. 
3500  * Parameters:  (void) 
3502  * Returns:     (uid_t)                         The real UID of the current 
3508         return(kauth_cred_getruid(kauth_cred_get())); 
3515  * Description: Get the current thread's effective GID. 
3517  * Parameters:  (void) 
3519  * Returns:     (gid_t)                         The effective GID of the 
3525         return(kauth_cred_getgid(kauth_cred_get())); 
3532  * Description: Get the current thread's real GID. 
3534  * Parameters:  (void) 
3536  * Returns:     (gid_t)                         The real GID of the current 
3542         return(kauth_cred_getrgid(kauth_cred_get())); 
3549  * Description: Returns a pointer to the current thread's credential 
3551  * Parameters:  (void) 
3553  * Returns:     (kauth_cred_t)                  Pointer to the current thread's 
3556  * Notes:       This function does not take a reference; because of this, the 
3557  *              caller MUST NOT do anything that would let the thread's 
3558  *              credential change while using the returned value, without 
3559  *              first explicitly taking their own reference. 
3561  *              If a caller intends to take a reference on the resulting 
3562  *              credential pointer from calling this function, it is strongly 
3563  *              recommended that the caller use kauth_cred_get_with_ref() 
3564  *              instead, to protect against any future changes to the cred 
3565  *              locking protocols; such changes could otherwise potentially 
3566  *              introduce race windows in the callers code. 
3569 kauth_cred_get(void) 
3572         struct uthread 
*uthread
; 
3574         uthread 
= get_bsdthread_info(current_thread()); 
3576         if (uthread 
== NULL
) 
3577                 panic("thread wants credential but has no BSD thread info"); 
3579          * We can lazy-bind credentials to threads, as long as their processes 
3582          * XXX If we later inline this function, the code in this block 
3583          * XXX should probably be called out in a function. 
3585         if (uthread
->uu_ucred 
== NOCRED
) { 
3586                 if ((p 
= (proc_t
) get_bsdtask_info(get_threadtask(current_thread()))) == NULL
) 
3587                         panic("thread wants credential but has no BSD process"); 
3588                 uthread
->uu_ucred 
= kauth_cred_proc_ref(p
); 
3590         return(uthread
->uu_ucred
); 
3594 mach_kauth_cred_uthread_update(void) 
3599         uthread 
= get_bsdthread_info(current_thread()); 
3600         proc 
= current_proc(); 
3602         kauth_cred_uthread_update(uthread
, proc
); 
3606  * kauth_cred_uthread_update 
3608  * Description: Given a uthread, a proc, and whether or not the proc is locked, 
3609  *              late-bind the uthread cred to the proc cred. 
3611  * Parameters:  uthread_t                       The uthread to update 
3612  *              proc_t                          The process to update to 
3616  * Notes:       This code is common code called from system call or trap entry 
3617  *              in the case that the process thread may have been changed 
3618  *              since the last time the thread entered the kernel.  It is 
3619  *              generally only called with the current uthread and process as 
3623 kauth_cred_uthread_update(uthread_t uthread
, proc_t proc
) 
3625         if (uthread
->uu_ucred 
!= proc
->p_ucred 
&& 
3626             (uthread
->uu_flag 
& UT_SETUID
) == 0) { 
3627                 kauth_cred_t old 
= uthread
->uu_ucred
; 
3628                 uthread
->uu_ucred 
= kauth_cred_proc_ref(proc
); 
3629                 if (IS_VALID_CRED(old
)) 
3630                         kauth_cred_unref(&old
); 
3636  * kauth_cred_get_with_ref 
3638  * Description: Takes a reference on the current thread's credential, and then 
3639  *              returns a pointer to it to the caller. 
3641  * Parameters:  (void) 
3643  * Returns:     (kauth_cred_t)                  Pointer to the current thread's 
3644  *                                              newly referenced credential 
3646  * Notes:       This function takes a reference on the credential before 
3647  *              returning it to the caller. 
3649  *              It is the responsibility of the calling code to release this 
3650  *              reference when the credential is no longer in use. 
3652  *              Since the returned reference may be a persistent reference 
3653  *              (e.g. one cached in another data structure with a lifetime 
3654  *              longer than the calling function), this release may be delayed 
3655  *              until such time as the persistent reference is to be destroyed. 
3656  *              An example of this would be the per vnode credential cache used 
3657  *              to accelerate lookup operations. 
3660 kauth_cred_get_with_ref(void) 
3663         struct uthread 
*uthread
; 
3665         uthread 
= get_bsdthread_info(current_thread()); 
3667         if (uthread 
== NULL
) 
3668                 panic("%s - thread wants credential but has no BSD thread info", __FUNCTION__
); 
3669         if ((procp 
= (proc_t
) get_bsdtask_info(get_threadtask(current_thread()))) == NULL
) 
3670                 panic("%s - thread wants credential but has no BSD process", __FUNCTION__
); 
3673          * We can lazy-bind credentials to threads, as long as their processes 
3676          * XXX If we later inline this function, the code in this block 
3677          * XXX should probably be called out in a function. 
3679         if (uthread
->uu_ucred 
== NOCRED
) { 
3680                 /* take reference for new cred in thread */ 
3681                 uthread
->uu_ucred 
= kauth_cred_proc_ref(procp
); 
3683         /* take a reference for our caller */ 
3684         kauth_cred_ref(uthread
->uu_ucred
); 
3685         return(uthread
->uu_ucred
); 
3690  * kauth_cred_proc_ref 
3692  * Description: Takes a reference on the current process's credential, and 
3693  *              then returns a pointer to it to the caller. 
3695  * Parameters:  procp                           Process whose credential we 
3696  *                                              intend to take a reference on 
3698  * Returns:     (kauth_cred_t)                  Pointer to the process's 
3699  *                                              newly referenced credential 
3701  * Locks:       PROC_UCRED_LOCK is held before taking the reference and released 
3702  *              after the refeence is taken to protect the p_ucred field of 
3703  *              the process referred to by procp. 
3705  * Notes:       This function takes a reference on the credential before 
3706  *              returning it to the caller. 
3708  *              It is the responsibility of the calling code to release this 
3709  *              reference when the credential is no longer in use. 
3711  *              Since the returned reference may be a persistent reference 
3712  *              (e.g. one cached in another data structure with a lifetime 
3713  *              longer than the calling function), this release may be delayed 
3714  *              until such time as the persistent reference is to be destroyed. 
3715  *              An example of this would be the per vnode credential cache used 
3716  *              to accelerate lookup operations. 
3719 kauth_cred_proc_ref(proc_t procp
) 
3723         proc_ucred_lock(procp
); 
3724         cred 
= proc_ucred(procp
); 
3725         kauth_cred_ref(cred
); 
3726         proc_ucred_unlock(procp
); 
3734  * Description: Allocate a new credential 
3736  * Parameters:  (void) 
3738  * Returns:     !NULL                           Newly allocated credential 
3739  *              NULL                            Insufficient memory 
3741  * Notes:       The newly allocated credential is zero'ed as part of the 
3742  *              allocation process, with the exception of the reference 
3743  *              count, which is set to 1 to indicate a single reference 
3744  *              held by the caller. 
3746  *              Since newly allocated credentials have no external pointers 
3747  *              referencing them, prior to making them visible in an externally 
3748  *              visible pointer (e.g. by adding them to the credential hash 
3749  *              cache) is the only legal time in which an existing credential 
3750  *              can be safely iinitialized or modified directly. 
3752  *              After initialization, the caller is expected to call the 
3753  *              function kauth_cred_add() to add the credential to the hash 
3754  *              cache, after which time it's frozen and becomes publically 
3757  *              The release protocol depends on kauth_hash_add() being called 
3758  *              before kauth_cred_rele() (there is a diagnostic panic which 
3759  *              will trigger if this protocol is not observed). 
3761  * XXX:         This function really ought to be static, rather than being 
3762  *              exported as KPI, since a failure of kauth_cred_add() can only 
3763  *              be handled by an explicit free of the credential; such frees 
3764  *              depend on knowlegdge of the allocation method used, which is 
3765  *              permitted to change between kernel revisions. 
3767  * XXX:         In the insufficient resource case, this code panic's rather 
3768  *              than returning a NULL pointer; the code that calls this 
3769  *              function needs to be audited before this can be changed. 
3772 kauth_cred_alloc(void) 
3774         kauth_cred_t newcred
; 
3776         MALLOC_ZONE(newcred
, kauth_cred_t
, sizeof(*newcred
), M_CRED
, M_WAITOK
); 
3778                 posix_cred_t newpcred 
= posix_cred_get(newcred
); 
3779                 bzero(newcred
, sizeof(*newcred
)); 
3780                 newcred
->cr_ref 
= 1; 
3781                 newcred
->cr_audit
.as_aia_p 
= audit_default_aia_p
; 
3782                 /* must do this, or cred has same group membership as uid 0 */ 
3783                 newpcred
->cr_gmuid 
= KAUTH_UID_NONE
; 
3786                 panic("kauth_cred_alloc: couldn't allocate credential"); 
3790 #if KAUTH_CRED_HASH_DEBUG 
3795         mac_cred_label_init(newcred
); 
3805  * Description: Look to see if we already have a known credential in the hash 
3806  *              cache; if one is found, bump the reference count and return 
3807  *              it.  If there are no credentials that match the given 
3808  *              credential, then allocate a new credential. 
3810  * Parameters:  cred                            Template for credential to 
3813  * Returns:     (kauth_cred_t)                  The credential that was found 
3814  *                                              in the hash or created 
3815  *              NULL                            kauth_cred_add() failed, or 
3816  *                                              there was not an egid specified 
3818  * Notes:       The gmuid is hard-defaulted to the UID specified.  Since we 
3819  *              maintain this field, we can't expect callers to know how it 
3820  *              needs to be set.  Callers should be prepared for this field 
3821  *              to be overwritten. 
3823  * XXX:         This code will tight-loop if memory for a new credential is 
3824  *              persistently unavailable; this is perhaps not the wisest way 
3825  *              to handle this condition, but current callers do not expect 
3829 kauth_cred_create(kauth_cred_t cred
) 
3831         kauth_cred_t    found_cred
, new_cred 
= NULL
; 
3832         posix_cred_t    pcred 
= posix_cred_get(cred
); 
3835         KAUTH_CRED_HASH_LOCK_ASSERT(); 
3837         if (pcred
->cr_flags 
& CRF_NOMEMBERD
) { 
3838                 pcred
->cr_gmuid 
= KAUTH_UID_NONE
; 
3841                  * If the template credential is not opting out of external 
3842                  * group membership resolution, then we need to check that 
3843                  * the UID we will be using is resolvable by the external 
3844                  * resolver.  If it's not, then we opt it out anyway, since 
3845                  * all future external resolution requests will be failing 
3846                  * anyway, and potentially taking a long time to do it.  We 
3847                  * use gid 0 because we always know it will exist and not 
3848                  * trigger additional lookups. This is OK, because we end up 
3849                  * precatching the information here as a result. 
3851                 if (!kauth_cred_ismember_gid(cred
, 0, &is_member
)) { 
3853                          * It's a recognized value; we don't really care about 
3854                          * the answer, so long as it's something the external 
3855                          * resolver could have vended. 
3857                         pcred
->cr_gmuid 
= pcred
->cr_uid
; 
3860                          * It's not something the external resolver could 
3861                          * have vended, so we don't want to ask it more 
3862                          * questions about the credential in the future. This 
3863                          * speeds up future lookups, as long as the caller 
3864                          * caches results; otherwise, it the same recurring 
3865                          * cost.  Since most credentials are used multiple 
3866                          * times, we still get some performance win from this. 
3868                         pcred
->cr_gmuid 
= KAUTH_UID_NONE
; 
3869                         pcred
->cr_flags 
|= CRF_NOMEMBERD
; 
3873         /* Caller *must* specify at least the egid in cr_groups[0] */ 
3874         if (pcred
->cr_ngroups 
< 1) 
3878                 KAUTH_CRED_HASH_LOCK(); 
3879                 found_cred 
= kauth_cred_find(cred
); 
3880                 if (found_cred 
!= NULL
) { 
3882                          * Found an existing credential so we'll bump 
3883                          * reference count and return 
3885                         kauth_cred_ref(found_cred
); 
3886                         KAUTH_CRED_HASH_UNLOCK(); 
3889                 KAUTH_CRED_HASH_UNLOCK(); 
3892                  * No existing credential found.  Create one and add it to 
3895                 new_cred 
= kauth_cred_alloc(); 
3896                 if (new_cred 
!= NULL
) { 
3898                         posix_cred_t    new_pcred 
= posix_cred_get(new_cred
); 
3899                         new_pcred
->cr_uid 
= pcred
->cr_uid
; 
3900                         new_pcred
->cr_ruid 
= pcred
->cr_ruid
; 
3901                         new_pcred
->cr_svuid 
= pcred
->cr_svuid
; 
3902                         new_pcred
->cr_rgid 
= pcred
->cr_rgid
; 
3903                         new_pcred
->cr_svgid 
= pcred
->cr_svgid
; 
3904                         new_pcred
->cr_gmuid 
= pcred
->cr_gmuid
; 
3905                         new_pcred
->cr_ngroups 
= pcred
->cr_ngroups
;       
3906                         bcopy(&pcred
->cr_groups
[0], &new_pcred
->cr_groups
[0], sizeof(new_pcred
->cr_groups
)); 
3908                         bcopy(&cred
->cr_audit
, &new_cred
->cr_audit
,  
3909                             sizeof(new_cred
->cr_audit
)); 
3911                         new_pcred
->cr_flags 
= pcred
->cr_flags
; 
3913                         KAUTH_CRED_HASH_LOCK(); 
3914                         err 
= kauth_cred_add(new_cred
); 
3915                         KAUTH_CRED_HASH_UNLOCK(); 
3917                         /* Retry if kauth_cred_add returns non zero value */ 
3921                         mac_cred_label_destroy(new_cred
); 
3923                         AUDIT_SESSION_UNREF(new_cred
); 
3925                         FREE_ZONE(new_cred
, sizeof(*new_cred
), M_CRED
); 
3935  * kauth_cred_setresuid 
3937  * Description: Update the given credential using the UID arguments.  The given 
3938  *              UIDs are used to set the effective UID, real UID, saved UID, 
3939  *              and GMUID (used for group membership checking). 
3941  * Parameters:  cred                            The original credential 
3942  *              ruid                            The new real UID 
3943  *              euid                            The new effective UID 
3944  *              svuid                           The new saved UID 
3945  *              gmuid                           KAUTH_UID_NONE -or- the new 
3946  *                                              group membership UID 
3948  * Returns:     (kauth_cred_t)                  The updated credential 
3950  * Note:        gmuid is different in that a KAUTH_UID_NONE is a valid 
3951  *              setting, so if you don't want it to change, pass it the 
3952  *              previous value, explicitly. 
3954  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
3955  *              if it returns a credential other than the one it is passed, 
3956  *              will have dropped the reference on the passed credential.  All 
3957  *              callers should be aware of this, and treat this function as an 
3958  *              unref + ref, potentially on different credentials. 
3960  *              Because of this, the caller is expected to take its own 
3961  *              reference on the credential passed as the first parameter, 
3962  *              and be prepared to release the reference on the credential 
3963  *              that is returned to them, if it is not intended to be a 
3964  *              persistent reference. 
3967 kauth_cred_setresuid(kauth_cred_t cred
, uid_t ruid
, uid_t euid
, uid_t svuid
, uid_t gmuid
) 
3969         struct ucred temp_cred
; 
3970         posix_cred_t temp_pcred 
= posix_cred_get(&temp_cred
); 
3971         posix_cred_t pcred 
= posix_cred_get(cred
); 
3973         NULLCRED_CHECK(cred
); 
3976          * We don't need to do anything if the UIDs we are changing are 
3977          * already the same as the UIDs passed in 
3979         if ((euid 
== KAUTH_UID_NONE 
|| pcred
->cr_uid 
== euid
) && 
3980             (ruid 
== KAUTH_UID_NONE 
|| pcred
->cr_ruid 
== ruid
) && 
3981             (svuid 
== KAUTH_UID_NONE 
|| pcred
->cr_svuid 
== svuid
) && 
3982             (pcred
->cr_gmuid 
== gmuid
)) { 
3983                 /* no change needed */ 
3988          * Look up in cred hash table to see if we have a matching credential 
3989          * with the new values; this is done by calling kauth_cred_update(). 
3991         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
3992         if (euid 
!= KAUTH_UID_NONE
) { 
3993                 temp_pcred
->cr_uid 
= euid
; 
3995         if (ruid 
!= KAUTH_UID_NONE
) { 
3996                 temp_pcred
->cr_ruid 
= ruid
; 
3998         if (svuid 
!= KAUTH_UID_NONE
) { 
3999                 temp_pcred
->cr_svuid 
= svuid
; 
4003          * If we are setting the gmuid to KAUTH_UID_NONE, then we want to 
4004          * opt out of participation in external group resolution, unless we 
4005          * unless we explicitly opt back in later. 
4007         if ((temp_pcred
->cr_gmuid 
= gmuid
) == KAUTH_UID_NONE
) { 
4008                 temp_pcred
->cr_flags 
|= CRF_NOMEMBERD
; 
4011         return(kauth_cred_update(cred
, &temp_cred
, TRUE
)); 
4016  * kauth_cred_setresgid 
4018  * Description: Update the given credential using the GID arguments.  The given 
4019  *              GIDs are used to set the effective GID, real GID, and saved 
4022  * Parameters:  cred                            The original credential 
4023  *              rgid                            The new real GID 
4024  *              egid                            The new effective GID 
4025  *              svgid                           The new saved GID 
4027  * Returns:     (kauth_cred_t)                  The updated credential 
4029  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
4030  *              if it returns a credential other than the one it is passed, 
4031  *              will have dropped the reference on the passed credential.  All 
4032  *              callers should be aware of this, and treat this function as an 
4033  *              unref + ref, potentially on different credentials. 
4035  *              Because of this, the caller is expected to take its own 
4036  *              reference on the credential passed as the first parameter, 
4037  *              and be prepared to release the reference on the credential 
4038  *              that is returned to them, if it is not intended to be a 
4039  *              persistent reference. 
4042 kauth_cred_setresgid(kauth_cred_t cred
, gid_t rgid
, gid_t egid
, gid_t svgid
) 
4044         struct ucred    temp_cred
; 
4045         posix_cred_t temp_pcred 
= posix_cred_get(&temp_cred
); 
4046         posix_cred_t pcred 
= posix_cred_get(cred
); 
4048         NULLCRED_CHECK(cred
); 
4049         DEBUG_CRED_ENTER("kauth_cred_setresgid %p %d %d %d\n", cred
, rgid
, egid
, svgid
); 
4052          * We don't need to do anything if the given GID are already the  
4053          * same as the GIDs in the credential. 
4055         if (pcred
->cr_groups
[0] == egid 
&& 
4056             pcred
->cr_rgid 
== rgid 
&& 
4057             pcred
->cr_svgid 
== svgid
) { 
4058                 /* no change needed */ 
4063          * Look up in cred hash table to see if we have a matching credential 
4064          * with the new values; this is done by calling kauth_cred_update(). 
4066         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
4067         if (egid 
!= KAUTH_GID_NONE
) { 
4068                 /* displacing a supplementary group opts us out of memberd */ 
4069                 if (kauth_cred_change_egid(&temp_cred
, egid
)) { 
4070                         DEBUG_CRED_CHANGE("displaced!\n"); 
4071                         temp_pcred
->cr_flags 
|= CRF_NOMEMBERD
; 
4072                         temp_pcred
->cr_gmuid 
= KAUTH_UID_NONE
; 
4074                         DEBUG_CRED_CHANGE("not displaced\n"); 
4077         if (rgid 
!= KAUTH_GID_NONE
) { 
4078                 temp_pcred
->cr_rgid 
= rgid
; 
4080         if (svgid 
!= KAUTH_GID_NONE
) { 
4081                 temp_pcred
->cr_svgid 
= svgid
; 
4084         return(kauth_cred_update(cred
, &temp_cred
, TRUE
)); 
4089  * Update the given credential with the given groups.  We only allocate a new  
4090  *      credential when the given gid actually results in changes to the existing  
4092  *      The gmuid argument supplies a new uid (or KAUTH_UID_NONE to opt out) 
4093  *      which will be used for group membership checking. 
4096  * kauth_cred_setgroups 
4098  * Description: Update the given credential using the provide supplementary 
4099  *              group list and group membership UID 
4101  * Parameters:  cred                            The original credential 
4102  *              groups                          Pointer to gid_t array which 
4103  *                                              contains the new group list 
4104  *              groupcount                      The count of valid groups which 
4105  *                                              are contained in 'groups' 
4106  *              gmuid                           KAUTH_UID_NONE -or- the new 
4107  *                                              group membership UID 
4109  * Returns:     (kauth_cred_t)                  The updated credential 
4111  * Note:        gmuid is different in that a KAUTH_UID_NONE is a valid 
4112  *              setting, so if you don't want it to change, pass it the 
4113  *              previous value, explicitly. 
4115  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
4116  *              if it returns a credential other than the one it is passed, 
4117  *              will have dropped the reference on the passed credential.  All 
4118  *              callers should be aware of this, and treat this function as an 
4119  *              unref + ref, potentially on different credentials. 
4121  *              Because of this, the caller is expected to take its own 
4122  *              reference on the credential passed as the first parameter, 
4123  *              and be prepared to release the reference on the credential 
4124  *              that is returned to them, if it is not intended to be a 
4125  *              persistent reference. 
4127  * XXX:         Changes are determined in ordinal order - if the caller passes 
4128  *              in the same groups list that is already present in the 
4129  *              credential, but the members are in a different order, even if 
4130  *              the EGID is not modified (i.e. cr_groups[0] is the same), it 
4131  *              is considered a modification to the credential, and a new 
4132  *              credential is created. 
4134  *              This should perhaps be better optimized, but it is considered 
4135  *              to be the caller's problem. 
4138 kauth_cred_setgroups(kauth_cred_t cred
, gid_t 
*groups
, int groupcount
, uid_t gmuid
) 
4141         struct ucred temp_cred
; 
4142         posix_cred_t temp_pcred 
= posix_cred_get(&temp_cred
); 
4145         NULLCRED_CHECK(cred
); 
4147         pcred 
= posix_cred_get(cred
); 
4150          * We don't need to do anything if the given list of groups does not 
4153         if ((pcred
->cr_gmuid 
== gmuid
) && (pcred
->cr_ngroups 
== groupcount
)) { 
4154                 for (i 
= 0; i 
< groupcount
; i
++) { 
4155                         if (pcred
->cr_groups
[i
] != groups
[i
]) 
4158                 if (i 
== groupcount
) { 
4159                         /* no change needed */ 
4165          * Look up in cred hash table to see if we have a matching credential 
4166          * with new values.  If we are setting or clearing the gmuid, then 
4167          * update the cr_flags, since clearing it is sticky.  This permits an 
4168          * opt-out of memberd processing using setgroups(), and an opt-in 
4169          * using initgroups().  This is required for POSIX conformance. 
4171         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
4172         temp_pcred
->cr_ngroups 
= groupcount
; 
4173         bcopy(groups
, temp_pcred
->cr_groups
, sizeof(temp_pcred
->cr_groups
)); 
4174         temp_pcred
->cr_gmuid 
= gmuid
; 
4175         if (gmuid 
== KAUTH_UID_NONE
) 
4176                 temp_pcred
->cr_flags 
|= CRF_NOMEMBERD
; 
4178                 temp_pcred
->cr_flags 
&= ~CRF_NOMEMBERD
; 
4180         return(kauth_cred_update(cred
, &temp_cred
, TRUE
)); 
4184  * Notes:       The return value exists to account for the possibility of a 
4185  *              kauth_cred_t without a POSIX label.  This will be the case in 
4186  *              the future (see posix_cred_get() below, for more details). 
4188 #if CONFIG_EXT_RESOLVER 
4189 int kauth_external_supplementary_groups_supported 
= 1; 
4191 SYSCTL_INT(_kern
, OID_AUTO
, ds_supgroups_supported
, CTLFLAG_RW 
| CTLFLAG_LOCKED
, &kauth_external_supplementary_groups_supported
, 0, ""); 
4195 kauth_cred_getgroups(kauth_cred_t cred
, gid_t 
*grouplist
, int *countp
) 
4197         int limit 
= NGROUPS
; 
4200         pcred 
= posix_cred_get(cred
); 
4202 #if CONFIG_EXT_RESOLVER   
4204          * If we've not opted out of using the resolver, then convert the cred to a list 
4205          * of supplemental groups. We do this only if there has been a resolver to talk to, 
4206          * since we may be too early in boot, or in an environment that isn't using DS. 
4208         if (kauth_identitysvc_has_registered 
&& kauth_external_supplementary_groups_supported 
&& (pcred
->cr_flags 
& CRF_NOMEMBERD
) == 0) {               
4209                 uid_t uid 
= kauth_cred_getuid(cred
); 
4212                 err 
= kauth_cred_uid2groups(&uid
, grouplist
, countp
); 
4216                 /* On error just fall through */ 
4217                 KAUTH_DEBUG("kauth_cred_getgroups failed %d\n", err
); 
4219 #endif /* CONFIG_EXT_RESOLVER */ 
4222          * If they just want a copy of the groups list, they may not care 
4223          * about the actual count.  If they specify an input count, however, 
4224          * treat it as an indicator of the buffer size available in grouplist, 
4225          * and limit the returned list to that size. 
4228                 limit 
= MIN(*countp
, pcred
->cr_ngroups
); 
4232         memcpy(grouplist
, pcred
->cr_groups
, sizeof(gid_t
) * limit
); 
4239  * kauth_cred_setuidgid 
4241  * Description: Update the given credential using the UID and GID arguments. 
4242  *              The given UID is used to set the effective UID, real UID, and 
4243  *              saved UID.  The given GID is used to set the effective GID, 
4244  *              real GID, and saved GID. 
4246  * Parameters:  cred                            The original credential 
4247  *              uid                             The new UID to use 
4248  *              gid                             The new GID to use 
4250  * Returns:     (kauth_cred_t)                  The updated credential 
4252  * Notes:       We set the gmuid to uid if the credential we are inheriting 
4253  *              from has not opted out of memberd participation; otherwise 
4254  *              we set it to KAUTH_UID_NONE 
4256  *              This code is only ever called from the per-thread credential 
4257  *              code path in the "set per thread credential" case; and in 
4258  *              posix_spawn() in the case that the POSIX_SPAWN_RESETIDS 
4261  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
4262  *              if it returns a credential other than the one it is passed, 
4263  *              will have dropped the reference on the passed credential.  All 
4264  *              callers should be aware of this, and treat this function as an 
4265  *              unref + ref, potentially on different credentials. 
4267  *              Because of this, the caller is expected to take its own 
4268  *              reference on the credential passed as the first parameter, 
4269  *              and be prepared to release the reference on the credential 
4270  *              that is returned to them, if it is not intended to be a 
4271  *              persistent reference. 
4274 kauth_cred_setuidgid(kauth_cred_t cred
, uid_t uid
, gid_t gid
) 
4276         struct ucred temp_cred
; 
4277         posix_cred_t temp_pcred 
= posix_cred_get(&temp_cred
); 
4280         NULLCRED_CHECK(cred
); 
4282         pcred 
= posix_cred_get(cred
); 
4285          * We don't need to do anything if the effective, real and saved 
4286          * user IDs are already the same as the user ID passed into us. 
4288         if (pcred
->cr_uid 
== uid 
&& pcred
->cr_ruid 
== uid 
&& pcred
->cr_svuid 
== uid 
&& 
4289                 pcred
->cr_gid 
== gid 
&& pcred
->cr_rgid 
== gid 
&& pcred
->cr_svgid 
== gid
) { 
4290                 /* no change needed */ 
4295          * Look up in cred hash table to see if we have a matching credential 
4296          * with the new values. 
4298         bzero(&temp_cred
, sizeof(temp_cred
)); 
4299         temp_pcred
->cr_uid 
= uid
; 
4300         temp_pcred
->cr_ruid 
= uid
; 
4301         temp_pcred
->cr_svuid 
= uid
; 
4302         temp_pcred
->cr_flags 
= pcred
->cr_flags
; 
4303         /* inherit the opt-out of memberd */ 
4304         if (pcred
->cr_flags 
& CRF_NOMEMBERD
) { 
4305                 temp_pcred
->cr_gmuid 
= KAUTH_UID_NONE
; 
4306                 temp_pcred
->cr_flags 
|= CRF_NOMEMBERD
; 
4308                 temp_pcred
->cr_gmuid 
= uid
; 
4309                 temp_pcred
->cr_flags 
&= ~CRF_NOMEMBERD
; 
4311         temp_pcred
->cr_ngroups 
= 1; 
4312         /* displacing a supplementary group opts us out of memberd */ 
4313         if (kauth_cred_change_egid(&temp_cred
, gid
)) { 
4314                 temp_pcred
->cr_gmuid 
= KAUTH_UID_NONE
; 
4315                 temp_pcred
->cr_flags 
|= CRF_NOMEMBERD
; 
4317         temp_pcred
->cr_rgid 
= gid
; 
4318         temp_pcred
->cr_svgid 
= gid
; 
4320         temp_cred
.cr_label 
= cred
->cr_label
; 
4323         return(kauth_cred_update(cred
, &temp_cred
, TRUE
)); 
4328  * kauth_cred_setsvuidgid 
4330  * Description: Function used by execve to set the saved uid and gid values 
4331  *              for suid/sgid programs 
4333  * Parameters:  cred                            The credential to update 
4334  *              uid                             The saved uid to set 
4335  *              gid                             The saved gid to set 
4337  * Returns:     (kauth_cred_t)                  The updated credential 
4339  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
4340  *              if it returns a credential other than the one it is passed, 
4341  *              will have dropped the reference on the passed credential.  All 
4342  *              callers should be aware of this, and treat this function as an 
4343  *              unref + ref, potentially on different credentials. 
4345  *              Because of this, the caller is expected to take its own 
4346  *              reference on the credential passed as the first parameter, 
4347  *              and be prepared to release the reference on the credential 
4348  *              that is returned to them, if it is not intended to be a 
4349  *              persistent reference. 
4352 kauth_cred_setsvuidgid(kauth_cred_t cred
, uid_t uid
, gid_t gid
) 
4354         struct ucred temp_cred
; 
4355         posix_cred_t temp_pcred 
= posix_cred_get(&temp_cred
); 
4358         NULLCRED_CHECK(cred
); 
4360         pcred 
= posix_cred_get(cred
); 
4362         DEBUG_CRED_ENTER("kauth_cred_setsvuidgid: %p u%d->%d g%d->%d\n", cred
, cred
->cr_svuid
, uid
, cred
->cr_svgid
, gid
); 
4365          * We don't need to do anything if the effective, real and saved 
4366          * uids are already the same as the uid provided.  This check is 
4367          * likely insufficient. 
4369         if (pcred
->cr_svuid 
== uid 
&& pcred
->cr_svgid 
== gid
) { 
4370                 /* no change needed */ 
4373         DEBUG_CRED_CHANGE("kauth_cred_setsvuidgid: cred change\n"); 
4375         /* look up in cred hash table to see if we have a matching credential 
4378         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
4379         temp_pcred
->cr_svuid 
= uid
; 
4380         temp_pcred
->cr_svgid 
= gid
; 
4382         return(kauth_cred_update(cred
, &temp_cred
, TRUE
)); 
4387  * kauth_cred_setauditinfo 
4389  * Description: Update the given credential using the given au_session_t. 
4391  * Parameters:  cred                            The original credential 
4392  *              auditinfo_p                     Pointer to ne audit information 
4394  * Returns:     (kauth_cred_t)                  The updated credential 
4396  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
4397  *              if it returns a credential other than the one it is passed, 
4398  *              will have dropped the reference on the passed credential.  All 
4399  *              callers should be aware of this, and treat this function as an 
4400  *              unref + ref, potentially on different credentials. 
4402  *              Because of this, the caller is expected to take its own 
4403  *              reference on the credential passed as the first parameter, 
4404  *              and be prepared to release the reference on the credential 
4405  *              that is returned to them, if it is not intended to be a 
4406  *              persistent reference. 
4409 kauth_cred_setauditinfo(kauth_cred_t cred
, au_session_t 
*auditinfo_p
) 
4411         struct ucred temp_cred
; 
4413         NULLCRED_CHECK(cred
); 
4416          * We don't need to do anything if the audit info is already the 
4417          * same as the audit info in the credential provided. 
4419         if (bcmp(&cred
->cr_audit
, auditinfo_p
, sizeof(cred
->cr_audit
)) == 0) { 
4420                 /* no change needed */ 
4424         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
4425         bcopy(auditinfo_p
, &temp_cred
.cr_audit
, sizeof(temp_cred
.cr_audit
)); 
4427         return(kauth_cred_update(cred
, &temp_cred
, FALSE
)); 
4432  * kauth_cred_label_update 
4434  * Description: Update the MAC label associated with a credential 
4436  * Parameters:  cred                            The original credential 
4437  *              label                           The MAC label to set 
4439  * Returns:     (kauth_cred_t)                  The updated credential 
4441  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
4442  *              if it returns a credential other than the one it is passed, 
4443  *              will have dropped the reference on the passed credential.  All 
4444  *              callers should be aware of this, and treat this function as an 
4445  *              unref + ref, potentially on different credentials. 
4447  *              Because of this, the caller is expected to take its own 
4448  *              reference on the credential passed as the first parameter, 
4449  *              and be prepared to release the reference on the credential 
4450  *              that is returned to them, if it is not intended to be a 
4451  *              persistent reference. 
4454 kauth_cred_label_update(kauth_cred_t cred
, struct label 
*label
) 
4456         kauth_cred_t newcred
; 
4457         struct ucred temp_cred
; 
4459         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
4461         mac_cred_label_init(&temp_cred
); 
4462         mac_cred_label_associate(cred
, &temp_cred
); 
4463         mac_cred_label_update(&temp_cred
, label
); 
4465         newcred 
= kauth_cred_update(cred
, &temp_cred
, TRUE
); 
4466         mac_cred_label_destroy(&temp_cred
); 
4471  * kauth_cred_label_update_execve 
4473  * Description: Update the MAC label associated with a credential as 
4476  * Parameters:  cred                            The original credential 
4478  *              scriptl                         The script MAC label 
4479  *              execl                           The executable MAC label 
4480  *              disjointp                       Pointer to flag to set if old 
4481  *                                              and returned credentials are 
4484  * Returns:     (kauth_cred_t)                  The updated credential 
4487  *              *disjointp                      Set to 1 for disjoint creds 
4489  * IMPORTANT:   This function is implemented via kauth_cred_update(), which, 
4490  *              if it returns a credential other than the one it is passed, 
4491  *              will have dropped the reference on the passed credential.  All 
4492  *              callers should be aware of this, and treat this function as an 
4493  *              unref + ref, potentially on different credentials. 
4495  *              Because of this, the caller is expected to take its own 
4496  *              reference on the credential passed as the first parameter, 
4497  *              and be prepared to release the reference on the credential 
4498  *              that is returned to them, if it is not intended to be a 
4499  *              persistent reference. 
4504 kauth_cred_label_update_execve(kauth_cred_t cred
, vfs_context_t ctx
, 
4505         struct vnode 
*vp
, off_t offset
, struct vnode 
*scriptvp
, struct label 
*scriptl
, 
4506         struct label 
*execl
, unsigned int *csflags
, void *macextensions
, int *disjointp
, int *labelupdateerror
) 
4508         kauth_cred_t newcred
; 
4509         struct ucred temp_cred
; 
4511         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
4513         mac_cred_label_init(&temp_cred
); 
4514         mac_cred_label_associate(cred
, &temp_cred
); 
4515         mac_cred_label_update_execve(ctx
, &temp_cred
,  
4516                                                   vp
, offset
, scriptvp
, scriptl
, execl
, csflags
, 
4517                                                   macextensions
, disjointp
, labelupdateerror
); 
4519         newcred 
= kauth_cred_update(cred
, &temp_cred
, TRUE
); 
4520         mac_cred_label_destroy(&temp_cred
); 
4525  *  kauth_proc_label_update 
4527  * Description:  Update the label inside the credential associated with the process. 
4529  * Parameters:  p                       The process to modify 
4530  *                              label           The label to place in the process credential 
4532  * Notes:               The credential associated with the process may change as a result 
4533  *                              of this call.  The caller should not assume the process reference to 
4534  *                              the old credential still exists. 
4536 int kauth_proc_label_update(struct proc 
*p
, struct label 
*label
) 
4538         kauth_cred_t my_cred
, my_new_cred
; 
4540         my_cred 
= kauth_cred_proc_ref(p
); 
4542         DEBUG_CRED_ENTER("kauth_proc_label_update: %p\n", my_cred
); 
4544         /* get current credential and take a reference while we muck with it */ 
4548                  * Set the credential with new info.  If there is no change, 
4549                  * we get back the same credential we passed in; if there is 
4550                  * a change, we drop the reference on the credential we 
4551                  * passed in.  The subsequent compare is safe, because it is 
4552                  * a pointer compare rather than a contents compare. 
4554                 my_new_cred 
= kauth_cred_label_update(my_cred
, label
); 
4555                 if (my_cred 
!= my_new_cred
) { 
4557                         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
); 
4561                          * We need to protect for a race where another thread 
4562                          * also changed the credential after we took our 
4563                          * reference.  If p_ucred has changed then we should 
4564                          * restart this again with the new cred. 
4566                         if (p
->p_ucred 
!= my_cred
) { 
4567                                 proc_ucred_unlock(p
); 
4568                                 kauth_cred_unref(&my_new_cred
); 
4569                                 my_cred 
= kauth_cred_proc_ref(p
); 
4573                         p
->p_ucred 
= my_new_cred
; 
4574                         /* update cred on proc */ 
4575                         PROC_UPDATE_CREDS_ONPROC(p
); 
4577                         mac_proc_set_enforce(p
, MAC_ALL_ENFORCE
); 
4578                         proc_ucred_unlock(p
); 
4582         /* Drop old proc reference or our extra reference */ 
4583         kauth_cred_unref(&my_cred
); 
4589  *  kauth_proc_label_update_execve 
4591  * Description: Update the label inside the credential associated with the 
4592  *              process as part of a transitioning execve.  The label will 
4593  *              be updated by the policies as part of this processing, not 
4594  *              provided up front. 
4596  * Parameters:  p                       The process to modify 
4597  *              ctx                     The context of the exec 
4598  *              vp                      The vnode being exec'ed 
4599  *              scriptl                 The script MAC label 
4600  *              execl                   The executable MAC label 
4601  *              lupdateerror    The error place holder for MAC label authority  
4602  *                                              to update about possible termination 
4604  * Returns:     0                       Label update did not make credential 
4606  *              1                       Label update caused credential to be 
4609  * Notes:       The credential associated with the process WILL change as a 
4610  *              result of this call.  The caller should not assume the process 
4611  *              reference to the old credential still exists. 
4615 kauth_proc_label_update_execve(struct proc 
*p
, vfs_context_t ctx
, 
4616         struct vnode 
*vp
, off_t offset
, struct vnode 
*scriptvp
, struct label 
*scriptl
, 
4617         struct label 
*execl
, unsigned int *csflags
, void *macextensions
, int *disjoint
, int *update_return
) 
4619         kauth_cred_t my_cred
, my_new_cred
; 
4620         my_cred 
= kauth_cred_proc_ref(p
); 
4622         DEBUG_CRED_ENTER("kauth_proc_label_update_execve: %p\n", my_cred
); 
4624         /* get current credential and take a reference while we muck with it */ 
4628                  * Set the credential with new info.  If there is no change, 
4629                  * we get back the same credential we passed in; if there is 
4630                  * a change, we drop the reference on the credential we 
4631                  * passed in.  The subsequent compare is safe, because it is 
4632                  * a pointer compare rather than a contents compare. 
4634                 my_new_cred 
= kauth_cred_label_update_execve(my_cred
, ctx
, vp
, offset
, scriptvp
, scriptl
, execl
, csflags
, macextensions
, disjoint
, update_return
); 
4635                 if (my_cred 
!= my_new_cred
) { 
4637                         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
); 
4641                          * We need to protect for a race where another thread 
4642                          * also changed the credential after we took our 
4643                          * reference.  If p_ucred has changed then we should 
4644                          * restart this again with the new cred. 
4646                         if (p
->p_ucred 
!= my_cred
) { 
4647                                 proc_ucred_unlock(p
); 
4648                                 kauth_cred_unref(&my_new_cred
); 
4649                                 my_cred 
= kauth_cred_proc_ref(p
); 
4653                         p
->p_ucred 
= my_new_cred
; 
4654                         /* update cred on proc */ 
4655                         PROC_UPDATE_CREDS_ONPROC(p
); 
4656                         mac_proc_set_enforce(p
, MAC_ALL_ENFORCE
); 
4657                         proc_ucred_unlock(p
); 
4661         /* Drop old proc reference or our extra reference */ 
4662         kauth_cred_unref(&my_cred
); 
4667  * for temporary binary compatibility 
4669 kauth_cred_t    
kauth_cred_setlabel(kauth_cred_t cred
, struct label 
*label
); 
4671 kauth_cred_setlabel(kauth_cred_t cred
, struct label 
*label
) 
4673         return kauth_cred_label_update(cred
, label
); 
4676 int kauth_proc_setlabel(struct proc 
*p
, struct label 
*label
); 
4678 kauth_proc_setlabel(struct proc 
*p
, struct label 
*label
) 
4680         return kauth_proc_label_update(p
, label
); 
4686 /* this is a temp hack to cover us when MACF is not built in a kernel configuration.  
4687  * Since we cannot build our export lists based on the kernel configuration we need 
4691 kauth_cred_label_update(__unused kauth_cred_t cred
, __unused 
void *label
) 
4697 kauth_proc_label_update(__unused 
struct proc 
*p
, __unused 
void *label
) 
4704  * for temporary binary compatibility 
4706 kauth_cred_t    
kauth_cred_setlabel(kauth_cred_t cred
, void *label
); 
4708 kauth_cred_setlabel(__unused kauth_cred_t cred
, __unused 
void *label
) 
4713 int kauth_proc_setlabel(struct proc 
*p
, void *label
); 
4715 kauth_proc_setlabel(__unused 
struct proc 
*p
, __unused 
void *label
) 
4725  * Description: Add a reference to the passed credential 
4727  * Parameters:  cred                            The credential to reference 
4731  * Notes:       This function adds a reference to the provided credential; 
4732  *              the existing reference on the credential is assumed to be 
4733  *              held stable over this operation by taking the appropriate 
4734  *              lock to protect the pointer from which it is being referenced, 
4735  *              if necessary (e.g. the proc lock is held over the call if the 
4736  *              credential being referenced is from p_ucred, the vnode lock 
4737  *              if from the per vnode name cache cred cache, and so on). 
4739  *              This is safe from the kauth_cred_unref() path, since an atomic 
4740  *              add is used, and the unref path specifically checks to see that 
4741  *              the value has not been changed to add a reference between the 
4742  *              time the credential is unreferenced by another pointer and the 
4743  *              time it is unreferenced from the cred hash cache. 
4746 kauth_cred_ref(kauth_cred_t cred
) 
4750         NULLCRED_CHECK(cred
); 
4752         old_value 
= OSAddAtomicLong(1, (long*)&cred
->cr_ref
); 
4755                 panic("kauth_cred_ref: trying to take a reference on a cred with no references"); 
4757 #if 0 // use this to watch a specific credential 
4758         if ( is_target_cred( cred 
) != 0 ) { 
4768  * kauth_cred_unref_hashlocked 
4770  * Description: release a credential reference; when the last reference is 
4771  *              released, the credential will be freed. 
4773  * Parameters:  credp                           Pointer to address containing 
4774  *                                              credential to be freed 
4776  * Returns:     TRUE if the credential must be destroyed by the caller. 
4780  *              *credp                          Set to NOCRED 
4782  * Notes:       This function assumes the credential hash lock is held. 
4784  *              This function is internal use only, since the hash lock is 
4785  *              scoped to this compilation unit. 
4787  *              This function destroys the contents of the pointer passed by 
4788  *              the caller to prevent the caller accidentally attempting to 
4789  *              release a given reference twice in error. 
4791  *              The last reference is considered to be released when a release 
4792  *              of a credential of a reference count of 2 occurs; this is an 
4793  *              intended effect, to take into account the reference held by 
4794  *              the credential hash, which is released at the same time. 
4797 kauth_cred_unref_hashlocked(kauth_cred_t 
*credp
) 
4800         boolean_t       destroy_it 
= FALSE
; 
4802         KAUTH_CRED_HASH_LOCK_ASSERT(); 
4803         NULLCRED_CHECK(*credp
); 
4805         old_value 
= OSAddAtomicLong(-1, (long*)&(*credp
)->cr_ref
); 
4809                 panic("%s:0x%08x kauth_cred_unref_hashlocked: dropping a reference on a cred with no references", current_proc()->p_comm
, *credp
); 
4811                 panic("%s:0x%08x kauth_cred_unref_hashlocked: dropping a reference on a cred with no hash entry", current_proc()->p_comm
, *credp
); 
4814 #if 0 // use this to watch a specific credential 
4815         if ( is_target_cred( *credp 
) != 0 ) { 
4821          * If the old_value is 2, then we have just released the last external 
4822          * reference to this credential 
4824         if (old_value 
< 3) { 
4825                 /* The last absolute reference is our credential hash table */ 
4826                 destroy_it 
= kauth_cred_remove(*credp
); 
4829         if (destroy_it 
== FALSE
) { 
4833         return (destroy_it
); 
4840  * Description: Release a credential reference while holding the credential 
4841  *              hash lock; when the last reference is released, the credential 
4844  * Parameters:  credp                           Pointer to address containing 
4845  *                                              credential to be freed 
4850  *              *credp                          Set to NOCRED 
4852  * Notes:       See kauth_cred_unref_hashlocked() for more information. 
4856 kauth_cred_unref(kauth_cred_t 
*credp
) 
4858         boolean_t destroy_it
; 
4860         KAUTH_CRED_HASH_LOCK(); 
4861         destroy_it 
= kauth_cred_unref_hashlocked(credp
); 
4862         KAUTH_CRED_HASH_UNLOCK(); 
4864         if (destroy_it 
== TRUE
) { 
4865                 assert(*credp 
!= NOCRED
); 
4867                 mac_cred_label_destroy(*credp
); 
4869                 AUDIT_SESSION_UNREF(*credp
); 
4871                 (*credp
)->cr_ref 
= 0; 
4872                 FREE_ZONE(*credp
, sizeof(*(*credp
)), M_CRED
); 
4882  * Description: release a credential reference; when the last reference is 
4883  *              released, the credential will be freed 
4885  * Parameters:  cred                            Credential to release 
4889  * DEPRECATED:  This interface is obsolete due to a failure to clear out the 
4890  *              clear the pointer in the caller to avoid multiple releases of 
4891  *              the same credential.  The currently recommended interface is 
4892  *              kauth_cred_unref(). 
4895 kauth_cred_rele(kauth_cred_t cred
) 
4897         kauth_cred_unref(&cred
); 
4899 #endif /* !__LP64__ */ 
4905  * Description: Duplicate a credential via alloc and copy; the new credential 
4908  * Parameters:  cred                            The credential to duplicate 
4910  * Returns:     (kauth_cred_t)                  The duplicate credential 
4912  * Notes:       The typical value to calling this routine is if you are going 
4913  *              to modify an existing credential, and expect to need a new one 
4914  *              from the hash cache. 
4916  *              This should probably not be used in the majority of cases; 
4917  *              if you are using it instead of kauth_cred_create(), you are 
4918  *              likely making a mistake. 
4920  *              The newly allocated credential is copied as part of the 
4921  *              allocation process, with the exception of the reference 
4922  *              count, which is set to 1 to indicate a single reference 
4923  *              held by the caller. 
4925  *              Since newly allocated credentials have no external pointers 
4926  *              referencing them, prior to making them visible in an externally 
4927  *              visible pointer (e.g. by adding them to the credential hash 
4928  *              cache) is the only legal time in which an existing credential 
4929  *              can be safely initialized or modified directly. 
4931  *              After initialization, the caller is expected to call the 
4932  *              function kauth_cred_add() to add the credential to the hash 
4933  *              cache, after which time it's frozen and becomes publicly 
4936  *              The release protocol depends on kauth_hash_add() being called 
4937  *              before kauth_cred_rele() (there is a diagnostic panic which 
4938  *              will trigger if this protocol is not observed). 
4942 kauth_cred_dup(kauth_cred_t cred
) 
4944         kauth_cred_t newcred
; 
4946         struct label 
*temp_label
; 
4950         if (cred 
== NOCRED 
|| cred 
== FSCRED
) 
4951                 panic("kauth_cred_dup: bad credential"); 
4953         newcred 
= kauth_cred_alloc(); 
4954         if (newcred 
!= NULL
) { 
4956                 temp_label 
= newcred
->cr_label
; 
4958                 bcopy(cred
, newcred
, sizeof(*newcred
)); 
4960                 newcred
->cr_label 
= temp_label
; 
4961                 mac_cred_label_associate(cred
, newcred
); 
4963                 AUDIT_SESSION_REF(cred
); 
4964                 newcred
->cr_ref 
= 1; 
4970  * kauth_cred_copy_real 
4972  * Description: Returns a credential based on the passed credential but which 
4973  *              reflects the real rather than effective UID and GID. 
4975  * Parameters:  cred                            The credential from which to 
4976  *                                              derive the new credential 
4978  * Returns:     (kauth_cred_t)                  The copied credential 
4980  * IMPORTANT:   This function DOES NOT utilize kauth_cred_update(); as a 
4981  *              result, the caller is responsible for dropping BOTH the 
4982  *              additional reference on the passed cred (if any), and the 
4983  *              credential returned by this function.  The drop should be 
4984  *              via the kauth_cred_unref() KPI. 
4987 kauth_cred_copy_real(kauth_cred_t cred
) 
4989         kauth_cred_t newcred 
= NULL
, found_cred
; 
4990         struct ucred temp_cred
; 
4991         posix_cred_t temp_pcred 
= posix_cred_get(&temp_cred
); 
4992         posix_cred_t pcred 
= posix_cred_get(cred
); 
4994         /* if the credential is already 'real', just take a reference */ 
4995         if ((pcred
->cr_ruid 
== pcred
->cr_uid
) && 
4996             (pcred
->cr_rgid 
== pcred
->cr_gid
)) { 
4997                 kauth_cred_ref(cred
); 
5002          * Look up in cred hash table to see if we have a matching credential 
5003          * with the new values. 
5005         bcopy(cred
, &temp_cred
, sizeof(temp_cred
)); 
5006         temp_pcred
->cr_uid 
= pcred
->cr_ruid
; 
5007         /* displacing a supplementary group opts us out of memberd */ 
5008         if (kauth_cred_change_egid(&temp_cred
, pcred
->cr_rgid
)) { 
5009                 temp_pcred
->cr_flags 
|= CRF_NOMEMBERD
; 
5010                 temp_pcred
->cr_gmuid 
= KAUTH_UID_NONE
; 
5013          * If the cred is not opted out, make sure we are using the r/euid 
5016         if (temp_pcred
->cr_gmuid 
!= KAUTH_UID_NONE
) 
5017                 temp_pcred
->cr_gmuid 
= pcred
->cr_ruid
; 
5022                 KAUTH_CRED_HASH_LOCK(); 
5023                 found_cred 
= kauth_cred_find(&temp_cred
); 
5024                 if (found_cred 
== cred
) { 
5025                         /* same cred so just bail */ 
5026                         KAUTH_CRED_HASH_UNLOCK(); 
5029                 if (found_cred 
!= NULL
) { 
5031                          * Found a match so we bump reference count on new 
5032                          * one.  We leave the old one alone. 
5034                         kauth_cred_ref(found_cred
); 
5035                         KAUTH_CRED_HASH_UNLOCK(); 
5040                  * Must allocate a new credential, copy in old credential 
5041                  * data and update the real user and group IDs. 
5043                 newcred 
= kauth_cred_dup(&temp_cred
); 
5044                 err 
= kauth_cred_add(newcred
); 
5045                 KAUTH_CRED_HASH_UNLOCK(); 
5047                 /* Retry if kauth_cred_add() fails */ 
5051                 mac_cred_label_destroy(newcred
); 
5053                 AUDIT_SESSION_UNREF(newcred
); 
5055                 FREE_ZONE(newcred
, sizeof(*newcred
), M_CRED
); 
5066  * Description: Common code to update a credential 
5068  * Parameters:  old_cred                        Reference counted credential 
5070  *              model_cred                      Non-reference counted model 
5071  *                                              credential to apply to the 
5072  *                                              credential to be updated 
5073  *              retain_auditinfo                Flag as to whether or not the 
5074  *                                              audit information should be 
5075  *                                              copied from the old_cred into 
5078  * Returns:     (kauth_cred_t)                  The updated credential 
5080  * IMPORTANT:   This function will potentially return a credential other than 
5081  *              the one it is passed, and if so, it will have dropped the 
5082  *              reference on the passed credential.  All callers should be 
5083  *              aware of this, and treat this function as an unref + ref, 
5084  *              potentially on different credentials. 
5086  *              Because of this, the caller is expected to take its own 
5087  *              reference on the credential passed as the first parameter, 
5088  *              and be prepared to release the reference on the credential 
5089  *              that is returned to them, if it is not intended to be a 
5090  *              persistent reference. 
5093 kauth_cred_update(kauth_cred_t old_cred
, kauth_cred_t model_cred
, 
5094         boolean_t retain_auditinfo
) 
5096         kauth_cred_t found_cred
, new_cred 
= NULL
; 
5099          * Make sure we carry the auditinfo forward to the new credential 
5100          * unless we are actually updating the auditinfo. 
5102         if (retain_auditinfo
) { 
5103                 bcopy(&old_cred
->cr_audit
, &model_cred
->cr_audit
,  
5104                     sizeof(model_cred
->cr_audit
)); 
5110                 KAUTH_CRED_HASH_LOCK(); 
5111                 found_cred 
= kauth_cred_find(model_cred
); 
5112                 if (found_cred 
== old_cred
) { 
5113                         /* same cred so just bail */ 
5114                         KAUTH_CRED_HASH_UNLOCK(); 
5117                 if (found_cred 
!= NULL
) { 
5118                         boolean_t destroy_it
; 
5120                         DEBUG_CRED_CHANGE("kauth_cred_update(cache hit): %p -> %p\n", old_cred
, found_cred
); 
5122                          * Found a match so we bump reference count on new 
5123                          * one and decrement reference count on the old one. 
5125                         kauth_cred_ref(found_cred
); 
5126                         destroy_it 
= kauth_cred_unref_hashlocked(&old_cred
); 
5127                         KAUTH_CRED_HASH_UNLOCK(); 
5128                         if (destroy_it 
== TRUE
) { 
5129                                 assert(old_cred 
!= NOCRED
); 
5131                                 mac_cred_label_destroy(old_cred
); 
5133                                 AUDIT_SESSION_UNREF(old_cred
); 
5135                                 old_cred
->cr_ref 
= 0; 
5136                                 FREE_ZONE(old_cred
, sizeof(*old_cred
), M_CRED
); 
5144                  * Must allocate a new credential using the model.  also 
5145                  * adds the new credential to the credential hash table. 
5147                 new_cred 
= kauth_cred_dup(model_cred
); 
5148                 err 
= kauth_cred_add(new_cred
); 
5149                 KAUTH_CRED_HASH_UNLOCK(); 
5151                 /* retry if kauth_cred_add returns non zero value */ 
5155                 mac_cred_label_destroy(new_cred
); 
5157                 AUDIT_SESSION_UNREF(new_cred
); 
5159                 FREE_ZONE(new_cred
, sizeof(*new_cred
), M_CRED
); 
5163         DEBUG_CRED_CHANGE("kauth_cred_update(cache miss): %p -> %p\n", old_cred
, new_cred
); 
5164         kauth_cred_unref(&old_cred
); 
5172  * Description: Add the given credential to our credential hash table and 
5173  *              take an additional reference to account for our use of the 
5174  *              credential in the hash table 
5176  * Parameters:  new_cred                        Credential to insert into cred 
5179  * Returns:     0                               Success 
5180  *              -1                              Hash insertion failed: caller 
5183  * Locks:       Caller is expected to hold KAUTH_CRED_HASH_LOCK 
5185  * Notes:       The 'new_cred' MUST NOT already be in the cred hash cache 
5188 kauth_cred_add(kauth_cred_t new_cred
) 
5192         KAUTH_CRED_HASH_LOCK_ASSERT(); 
5194         hash_key 
= kauth_cred_get_hashkey(new_cred
); 
5195         hash_key 
%= KAUTH_CRED_TABLE_SIZE
; 
5197         /* race fix - there is a window where another matching credential  
5198          * could have been inserted between the time this one was created and we 
5199          * got the hash lock.  If we find a match return an error and have the  
5202         if (kauth_cred_find(new_cred
) != NULL
) { 
5206         /* take a reference for our use in credential hash table */  
5207         kauth_cred_ref(new_cred
); 
5209         /* insert the credential into the hash table */ 
5210         TAILQ_INSERT_HEAD(&kauth_cred_table_anchor
[hash_key
], new_cred
, cr_link
); 
5219  * Description: Remove the given credential from our credential hash table 
5221  * Parameters:  cred                            Credential to remove from cred 
5224  * Returns:     TRUE if the cred was found & removed from the hash; FALSE if not. 
5226  * Locks:       Caller is expected to hold KAUTH_CRED_HASH_LOCK 
5228  * Notes:       The check for the reference increment after entry is generally 
5229  *              agree to be safe, since we use atomic operations, and the 
5230  *              following code occurs with the hash lock held; in theory, this 
5231  *              protects us from the 2->1 reference that gets us here. 
5234 kauth_cred_remove(kauth_cred_t cred
) 
5237         kauth_cred_t    found_cred
; 
5239         hash_key 
= kauth_cred_get_hashkey(cred
); 
5240         hash_key 
%= KAUTH_CRED_TABLE_SIZE
; 
5243         if (cred
->cr_ref 
< 1) 
5244                 panic("cred reference underflow"); 
5245         if (cred
->cr_ref 
> 1) 
5246                 return (FALSE
);         /* someone else got a ref */ 
5248         /* Find cred in the credential hash table */ 
5249         TAILQ_FOREACH(found_cred
, &kauth_cred_table_anchor
[hash_key
], cr_link
) { 
5250                 if (found_cred 
== cred
) { 
5251                         /* found a match, remove it from the hash table */ 
5252                         TAILQ_REMOVE(&kauth_cred_table_anchor
[hash_key
], found_cred
, cr_link
); 
5253 #if KAUTH_CRED_HASH_DEBUG 
5260         /* Did not find a match... this should not happen! XXX Make panic? */ 
5261         printf("%s:%d - %s - %s - did not find a match for %p\n", __FILE__
, __LINE__
, __FUNCTION__
, current_proc()->p_comm
, cred
); 
5269  * Description: Using the given credential data, look for a match in our 
5270  *              credential hash table 
5272  * Parameters:  cred                            Credential to lookup in cred 
5275  * Returns:     NULL                            Not found 
5276  *              !NULL                           Matching credential already in 
5279  * Locks:       Caller is expected to hold KAUTH_CRED_HASH_LOCK 
5282 kauth_cred_find(kauth_cred_t cred
) 
5285         kauth_cred_t    found_cred
; 
5286         posix_cred_t pcred 
= posix_cred_get(cred
); 
5288         KAUTH_CRED_HASH_LOCK_ASSERT(); 
5290 #if KAUTH_CRED_HASH_DEBUG 
5291         static int              test_count 
= 0;  
5294         if ((test_count 
% 200) == 0) { 
5295                 kauth_cred_hash_print(); 
5299         hash_key 
= kauth_cred_get_hashkey(cred
); 
5300         hash_key 
%= KAUTH_CRED_TABLE_SIZE
; 
5302         /* Find cred in the credential hash table */ 
5303         TAILQ_FOREACH(found_cred
, &kauth_cred_table_anchor
[hash_key
], cr_link
) { 
5305                 posix_cred_t found_pcred 
= posix_cred_get(found_cred
); 
5308                  * don't worry about the label unless the flags in 
5309                  * either credential tell us to. 
5311                 match 
= (bcmp(found_pcred
, pcred
, sizeof (*pcred
)) == 0) ? TRUE 
: FALSE
; 
5312                 match 
= match 
&& ((bcmp(&found_cred
->cr_audit
, &cred
->cr_audit
, 
5313                         sizeof(cred
->cr_audit
)) == 0) ? TRUE 
: FALSE
); 
5315                 if (((found_pcred
->cr_flags 
& CRF_MAC_ENFORCE
) != 0) || 
5316                     ((pcred
->cr_flags 
& CRF_MAC_ENFORCE
) != 0)) { 
5317                         match 
= match 
&& mac_cred_label_compare(found_cred
->cr_label
, 
5326         /* No match found */ 
5335  * Description: Generates a hash key using data that makes up a credential; 
5338  * Parameters:  datap                           Pointer to data to hash 
5339  *              data_len                        Count of bytes to hash 
5340  *              start_key                       Start key value 
5342  * Returns:     (u_long)                        Returned hash key 
5344 static inline u_long
 
5345 kauth_cred_hash(const uint8_t *datap
, int data_len
, u_long start_key
) 
5347         u_long  hash_key 
= start_key
; 
5350         while (data_len 
> 0) { 
5351                 hash_key 
= (hash_key 
<< 4) + *datap
++; 
5352                 temp 
= hash_key 
& 0xF0000000; 
5354                         hash_key 
^= temp 
>> 24; 
5364  * kauth_cred_get_hashkey 
5366  * Description: Generate a hash key using data that makes up a credential; 
5367  *              based on ElfHash.  We hash on the entire credential data, 
5368  *              not including the ref count or the TAILQ, which are mutable; 
5369  *              everything else isn't. 
5371  * Parameters:  cred                            Credential for which hash is 
5374  * Returns:     (u_long)                        Returned hash key 
5376  * Notes:       When actually moving the POSIX credential into a real label, 
5377  *              remember to update this hash computation. 
5380 kauth_cred_get_hashkey(kauth_cred_t cred
) 
5383         posix_cred_t pcred 
= posix_cred_get(cred
); 
5385         u_long  hash_key 
= 0; 
5387         hash_key 
= kauth_cred_hash((uint8_t *)&cred
->cr_posix
,  
5388                                                            sizeof (struct posix_cred
), 
5390         hash_key 
= kauth_cred_hash((uint8_t *)&cred
->cr_audit
,  
5391                                                            sizeof(struct au_session
), 
5394         if (pcred
->cr_flags 
& CRF_MAC_ENFORCE
) { 
5395                 hash_key 
= kauth_cred_hash((uint8_t *)cred
->cr_label
,  
5396                                                                    sizeof (struct label
), 
5404 #if KAUTH_CRED_HASH_DEBUG 
5406  * kauth_cred_hash_print 
5408  * Description: Print out cred hash cache table information for debugging 
5409  *              purposes, including the credential contents 
5411  * Parameters:  (void) 
5415  * Implicit returns:    Results in console output 
5418 kauth_cred_hash_print(void)  
5421         kauth_cred_t    found_cred
; 
5423         printf("\n\t kauth credential hash table statistics - current cred count %d \n", kauth_cred_count
); 
5424         /* count slot hits, misses, collisions, and max depth */ 
5425         for (i 
= 0; i 
< KAUTH_CRED_TABLE_SIZE
; i
++) { 
5426                 printf("[%02d] ", i
); 
5428                 TAILQ_FOREACH(found_cred
, &kauth_cred_table_anchor
[i
], cr_link
) { 
5433                         kauth_cred_print(found_cred
); 
5437                         printf("NOCRED \n"); 
5441 #endif  /* KAUTH_CRED_HASH_DEBUG */ 
5444 #if (defined(KAUTH_CRED_HASH_DEBUG) && (KAUTH_CRED_HASH_DEBUG != 0)) || defined(DEBUG_CRED) 
5448  * Description: Print out an individual credential's contents for debugging 
5451  * Parameters:  cred                            The credential to print out 
5455  * Implicit returns:    Results in console output 
5458 kauth_cred_print(kauth_cred_t cred
)  
5462         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
); 
5463         printf("group count %d gids ", cred
->cr_ngroups
); 
5464         for (i 
= 0; i 
< NGROUPS
; i
++) { 
5467                 printf("%d ", cred
->cr_groups
[i
]); 
5469         printf("r%d sv%d ", cred
->cr_rgid
, cred
->cr_svgid
); 
5470         printf("auditinfo_addr %d %d %d %d %d %d\n",  
5471                 cred
->cr_audit
.s_aia_p
->ai_auid
, 
5472                 cred
->cr_audit
.as_mask
.am_success
, 
5473                 cred
->cr_audit
.as_mask
.am_failure
, 
5474                 cred
->cr_audit
.as_aia_p
->ai_termid
.at_port
, 
5475                 cred
->cr_audit
.as_aia_p
->ai_termid
.at_addr
[0], 
5476                 cred
->cr_audit
.as_aia_p
->ai_asid
); 
5479 int is_target_cred( kauth_cred_t the_cred 
) 
5481         if ( the_cred
->cr_uid 
!= 0 )  
5483         if ( the_cred
->cr_ruid 
!= 0 )  
5485         if ( the_cred
->cr_svuid 
!= 0 )  
5487         if ( the_cred
->cr_ngroups 
!= 11 )  
5489         if ( the_cred
->cr_groups
[0] != 11 )  
5491         if ( the_cred
->cr_groups
[1] != 81 )  
5493         if ( the_cred
->cr_groups
[2] != 63947 )  
5495         if ( the_cred
->cr_groups
[3] != 80288 )  
5497         if ( the_cred
->cr_groups
[4] != 89006 )  
5499         if ( the_cred
->cr_groups
[5] != 52173 )  
5501         if ( the_cred
->cr_groups
[6] != 84524 )  
5503         if ( the_cred
->cr_groups
[7] != 79 )  
5505         if ( the_cred
->cr_groups
[8] != 80292 )  
5507         if ( the_cred
->cr_groups
[9] != 80 )  
5509         if ( the_cred
->cr_groups
[10] != 90824 )  
5511         if ( the_cred
->cr_rgid 
!= 11 )  
5513         if ( the_cred
->cr_svgid 
!= 11 )  
5515         if ( the_cred
->cr_gmuid 
!= 3475 )  
5517         if ( the_cred
->cr_audit
.as_aia_p
->ai_auid 
!= 3475 )  
5520         if ( the_cred->cr_audit.as_mask.am_success != 0 )  
5522         if ( the_cred->cr_audit.as_mask.am_failure != 0 )  
5524         if ( the_cred->cr_audit.as_aia_p->ai_termid.at_port != 0 )  
5526         if ( the_cred->cr_audit.as_aia_p->ai_termid.at_addr[0] != 0 )  
5528         if ( the_cred->cr_audit.as_aia_p->ai_asid != 0 )  
5530         if ( the_cred->cr_flags != 0 )  
5533         return( -1 ); // found target cred 
5536 void get_backtrace( void ) 
5539         void *                  my_stack
[ MAX_STACK_DEPTH 
]; 
5542         if ( cred_debug_buf_p 
== NULL 
) { 
5543                 MALLOC(cred_debug_buf_p
, cred_debug_buffer 
*, sizeof(*cred_debug_buf_p
), M_KAUTH
, M_WAITOK
); 
5544                 bzero(cred_debug_buf_p
, sizeof(*cred_debug_buf_p
)); 
5547         if ( cred_debug_buf_p
->next_slot 
> (MAX_CRED_BUFFER_SLOTS 
- 1) ) { 
5548                 /* buffer is full */ 
5552         my_depth 
= OSBacktrace(&my_stack
[0], MAX_STACK_DEPTH
); 
5553         if ( my_depth 
== 0 ) { 
5554                 printf("%s - OSBacktrace failed \n", __FUNCTION__
); 
5558         /* fill new backtrace */ 
5559         my_slot 
= cred_debug_buf_p
->next_slot
; 
5560         cred_debug_buf_p
->next_slot
++; 
5561         cred_debug_buf_p
->stack_buffer
[ my_slot 
].depth 
= my_depth
; 
5562         for ( i 
= 0; i 
< my_depth
; i
++ ) { 
5563                 cred_debug_buf_p
->stack_buffer
[ my_slot 
].stack
[ i 
] = my_stack
[ i 
]; 
5570 /* subset of struct ucred for use in sysctl_dump_creds */ 
5571 struct debug_ucred 
{ 
5573         u_long  cr_ref
;                         /* reference count */ 
5574         uid_t   cr_uid
;                         /* effective user id */ 
5575         uid_t   cr_ruid
;                        /* real user id */ 
5576         uid_t   cr_svuid
;                       /* saved user id */ 
5577         short   cr_ngroups
;                     /* number of groups in advisory list */ 
5578         gid_t   cr_groups
[NGROUPS
];     /* advisory group list */ 
5579         gid_t   cr_rgid
;                        /* real group id */ 
5580         gid_t   cr_svgid
;                       /* saved group id */ 
5581         uid_t   cr_gmuid
;                       /* UID for group membership purposes */ 
5582         struct auditinfo_addr cr_audit
; /* user auditing data. */ 
5583         void    *cr_label
;                      /* MACF label */ 
5584         int             cr_flags
;                       /* flags on credential */ 
5586 typedef struct debug_ucred debug_ucred
; 
5588 SYSCTL_PROC(_kern
, OID_AUTO
, dump_creds
, CTLFLAG_RD
, 
5589     NULL
, 0, sysctl_dump_creds
, "S,debug_ucred", "List of credentials in the cred hash"); 
5592  *      err = sysctlbyname( "kern.dump_creds", bufp, &len, NULL, 0 ); 
5596 sysctl_dump_creds( __unused 
struct sysctl_oid 
*oidp
, __unused 
void *arg1
, __unused 
int arg2
, struct sysctl_req 
*req 
) 
5598         int                     i
, j
, counter 
= 0; 
5601         kauth_cred_t    found_cred
; 
5602         debug_ucred 
*   cred_listp
; 
5603         debug_ucred 
*   nextp
; 
5605         /* This is a readonly node. */ 
5606         if (req
->newptr 
!= USER_ADDR_NULL
) 
5609         /* calculate space needed */ 
5610         for (i 
= 0; i 
< KAUTH_CRED_TABLE_SIZE
; i
++) { 
5611                 TAILQ_FOREACH(found_cred
, &kauth_cred_table_anchor
[i
], cr_link
) { 
5616         /* they are querying us so just return the space required. */ 
5617         if (req
->oldptr 
== USER_ADDR_NULL
) { 
5618                 counter 
+= 10; // add in some padding; 
5619                 req
->oldidx 
= counter 
* sizeof(debug_ucred
); 
5623         MALLOC( cred_listp
, debug_ucred 
*, req
->oldlen
, M_TEMP
, M_WAITOK 
); 
5624         if ( cred_listp 
== NULL 
) { 
5628         /* fill in creds to send back */ 
5631         for (i 
= 0; i 
< KAUTH_CRED_TABLE_SIZE
; i
++) { 
5632                 TAILQ_FOREACH(found_cred
, &kauth_cred_table_anchor
[i
], cr_link
) { 
5633                         nextp
->credp 
= found_cred
; 
5634                         nextp
->cr_ref 
= found_cred
->cr_ref
; 
5635                         nextp
->cr_uid 
= found_cred
->cr_uid
; 
5636                         nextp
->cr_ruid 
= found_cred
->cr_ruid
; 
5637                         nextp
->cr_svuid 
= found_cred
->cr_svuid
; 
5638                         nextp
->cr_ngroups 
= found_cred
->cr_ngroups
; 
5639                         for ( j 
= 0; j 
< nextp
->cr_ngroups
; j
++ ) { 
5640                                 nextp
->cr_groups
[ j 
] = found_cred
->cr_groups
[ j 
]; 
5642                         nextp
->cr_rgid 
= found_cred
->cr_rgid
; 
5643                         nextp
->cr_svgid 
= found_cred
->cr_svgid
; 
5644                         nextp
->cr_gmuid 
= found_cred
->cr_gmuid
; 
5645                         nextp
->cr_audit
.ai_auid 
= 
5646                             found_cred
->cr_audit
.as_aia_p
->ai_auid
; 
5647                         nextp
->cr_audit
.ai_mask
.am_success 
= 
5648                             found_cred
->cr_audit
.as_mask
.am_success
; 
5649                         nextp
->cr_audit
.ai_mask
.am_failure 
= 
5650                             found_cred
->cr_audit
.as_mask
.am_failure
; 
5651                         nextp
->cr_audit
.ai_termid
.at_port 
= 
5652                             found_cred
->cr_audit
.as_aia_p
->ai_termid
.at_port
; 
5653                         nextp
->cr_audit
.ai_termid
.at_type 
= 
5654                             found_cred
->cr_audit
.as_aia_p
->ai_termid
.at_type
; 
5655                         nextp
->cr_audit
.ai_termid
.at_addr
[0] = 
5656                             found_cred
->cr_audit
.as_aia_p
->ai_termid
.at_addr
[0]; 
5657                         nextp
->cr_audit
.ai_termid
.at_addr
[1] = 
5658                             found_cred
->cr_audit
.as_aia_p
->ai_termid
.at_addr
[1]; 
5659                         nextp
->cr_audit
.ai_termid
.at_addr
[2] = 
5660                             found_cred
->cr_audit
.as_aia_p
->ai_termid
.at_addr
[2]; 
5661                         nextp
->cr_audit
.ai_termid
.at_addr
[3] = 
5662                             found_cred
->cr_audit
.as_aia_p
->ai_termid
.at_addr
[3]; 
5663                         nextp
->cr_audit
.ai_asid 
= 
5664                             found_cred
->cr_audit
.as_aia_p
->ai_asid
; 
5665                         nextp
->cr_audit
.ai_flags 
= 
5666                             found_cred
->cr_audit
.as_aia_p
->ai_flags
; 
5667                         nextp
->cr_label 
= found_cred
->cr_label
; 
5668                         nextp
->cr_flags 
= found_cred
->cr_flags
; 
5670                         space 
+= sizeof(debug_ucred
); 
5671                         if ( space 
> req
->oldlen 
) { 
5672                                 FREE(cred_listp
, M_TEMP
); 
5677         req
->oldlen 
= space
; 
5678         error 
= SYSCTL_OUT(req
, cred_listp
, req
->oldlen
); 
5679         FREE(cred_listp
, M_TEMP
); 
5684 SYSCTL_PROC(_kern
, OID_AUTO
, cred_bt
, CTLFLAG_RD
, 
5685     NULL
, 0, sysctl_dump_cred_backtraces
, "S,cred_debug_buffer", "dump credential backtrace"); 
5688  *      err = sysctlbyname( "kern.cred_bt", bufp, &len, NULL, 0 ); 
5692 sysctl_dump_cred_backtraces( __unused 
struct sysctl_oid 
*oidp
, __unused 
void *arg1
, __unused 
int arg2
, struct sysctl_req 
*req 
) 
5697         cred_debug_buffer 
*     bt_bufp
; 
5698         cred_backtrace 
*        nextp
; 
5700         /* This is a readonly node. */ 
5701         if (req
->newptr 
!= USER_ADDR_NULL
) 
5704         if ( cred_debug_buf_p 
== NULL 
) { 
5708         /* calculate space needed */ 
5709         space 
= sizeof( cred_debug_buf_p
->next_slot 
); 
5710         space 
+= (sizeof( cred_backtrace 
) * cred_debug_buf_p
->next_slot
); 
5712         /* they are querying us so just return the space required. */ 
5713         if (req
->oldptr 
== USER_ADDR_NULL
) { 
5714                 req
->oldidx 
= space
; 
5718         if ( space 
> req
->oldlen 
) { 
5722         MALLOC( bt_bufp
, cred_debug_buffer 
*, req
->oldlen
, M_TEMP
, M_WAITOK 
); 
5723         if ( bt_bufp 
== NULL 
) { 
5727         /* fill in backtrace info to send back */ 
5728         bt_bufp
->next_slot 
= cred_debug_buf_p
->next_slot
; 
5729         space 
= sizeof(bt_bufp
->next_slot
); 
5731         nextp 
= &bt_bufp
->stack_buffer
[ 0 ]; 
5732         for (i 
= 0; i 
< cred_debug_buf_p
->next_slot
; i
++) { 
5733                 nextp
->depth 
= cred_debug_buf_p
->stack_buffer
[ i 
].depth
; 
5734                 for ( j 
= 0; j 
< nextp
->depth
; j
++ ) { 
5735                         nextp
->stack
[ j 
] = cred_debug_buf_p
->stack_buffer
[ i 
].stack
[ j 
]; 
5737                 space 
+= sizeof(*nextp
); 
5740         req
->oldlen 
= space
; 
5741         error 
= SYSCTL_OUT(req
, bt_bufp
, req
->oldlen
); 
5742         FREE(bt_bufp
, M_TEMP
); 
5746 #endif  /* KAUTH_CRED_HASH_DEBUG || DEBUG_CRED */ 
5750  ********************************************************************** 
5751  * The following routines will be moved to a policy_posix.c module at 
5752  * some future point. 
5753  ********************************************************************** 
5759  * Description: Helper function to create a kauth_cred_t credential that is 
5760  *              initally labelled with a specific POSIX credential label 
5762  * Parameters:  pcred                   The posix_cred_t to use as the initial 
5765  * Returns:     (kauth_cred_t)          The credential that was found in the 
5767  *              NULL                    kauth_cred_add() failed, or there was 
5768  *                                      no egid specified, or we failed to 
5769  *                                      attach a label to the new credential 
5771  * Notes:       This function currently wraps kauth_cred_create(), and is the 
5772  *              only consumer of that ill-fated function, apart from bsd_init(). 
5773  *              It exists solely to support the NFS server code creation of 
5774  *              credentials based on the over-the-wire RPC calls containing 
5775  *              traditional POSIX credential information being tunneled to 
5776  *              the server host from the client machine. 
5778  *              In the future, we hope this function goes away. 
5780  *              In the short term, it creates a temporary credential, puts 
5781  *              the POSIX information from NFS into it, and then calls 
5782  *              kauth_cred_create(), as an internal implementation detail. 
5784  *              If we have to keep it around in the medium term, it will 
5785  *              create a new kauth_cred_t, then label it with a POSIX label 
5786  *              corresponding to the contents of the kauth_cred_t.  If the 
5787  *              policy_posix MACF module is not loaded, it will instead 
5788  *              substitute a posix_cred_t which GRANTS all access (effectively 
5789  *              a "root" credential) in order to not prevent NFS from working 
5790  *              in the case that we are not supporting POSIX credentials. 
5793 posix_cred_create(posix_cred_t pcred
) 
5795         struct ucred temp_cred
; 
5797         bzero(&temp_cred
, sizeof(temp_cred
)); 
5798         temp_cred
.cr_posix 
= *pcred
; 
5800         return kauth_cred_create(&temp_cred
); 
5807  * Description: Given a kauth_cred_t, return the POSIX credential label, if 
5808  *              any, which is associated with it. 
5810  * Parameters:  cred                    The credential to obtain the label from 
5812  * Returns:     posix_cred_t            The POSIX credential label 
5814  * Notes:       In the event that the policy_posix MACF module IS NOT loaded, 
5815  *              this function will return a pointer to a posix_cred_t which 
5816  *              GRANTS all access (effectively, a "root" credential).  This is 
5817  *              necessary to support legacy code which insists on tightly 
5818  *              integrating POSIX credentials into its APIs, including, but 
5819  *              not limited to, System V IPC mechanisms, POSIX IPC mechanisms, 
5820  *              NFSv3, signals, dtrace, and a large number of kauth routines 
5821  *              used to implement POSIX permissions related system calls. 
5823  *              In the event that the policy_posix MACF module IS loaded, and 
5824  *              there is no POSIX label on the kauth_cred_t credential, this 
5825  *              function will return a pointer to a posix_cred_t which DENIES 
5826  *              all access (effectively, a "deny rights granted by POSIX" 
5827  *              credential).  This is necessary to support the concept of a 
5828  *              transiently loaded POSIX policy, or kauth_cred_t credentials 
5829  *              which can not be used in conjunctions with POSIX permissions 
5832  *              This function currently returns the address of the cr_posix 
5833  *              field of the supplied kauth_cred_t credential, and as such 
5834  *              currently can not fail.  In the future, this will not be the 
5838 posix_cred_get(kauth_cred_t cred
) 
5840         return(&cred
->cr_posix
); 
5847  * Description: Label a kauth_cred_t with a POSIX credential label 
5849  * Parameters:  cred                    The credential to label 
5850  *              pcred                   The POSIX credential t label it with 
5854  * Notes:       This function is currently void in order to permit it to fit 
5855  *              in with the current MACF framework label methods which allow 
5856  *              labeling to fail silently.  This is like acceptable for 
5857  *              mandatory access controls, but not for POSIX, since those 
5858  *              access controls are advisory.  We will need to consider a 
5859  *              return value in a future version of the MACF API. 
5861  *              This operation currently cannot fail, as currently the POSIX 
5862  *              credential is a subfield of the kauth_cred_t (ucred), which 
5863  *              MUST be valid.  In the future, this will not be the case. 
5866 posix_cred_label(kauth_cred_t cred
, posix_cred_t pcred
) 
5868         cred
->cr_posix 
= *pcred
;        /* structure assign for now */ 
5875  * Description: Perform a POSIX access check for a protected object 
5877  * Parameters:  cred                    The credential to check 
5878  *              object_uid              The POSIX UID of the protected object 
5879  *              object_gid              The POSIX GID of the protected object 
5880  *              object_mode             The POSIX mode of the protected object 
5881  *              mode_req                The requested POSIX access rights 
5883  * Returns      0                       Access is granted 
5884  *              EACCES                  Access is denied 
5886  * Notes:       This code optimizes the case where the world and group rights 
5887  *              would both grant the requested rights to avoid making a group 
5888  *              membership query.  This is a big performance win in the case 
5889  *              where this is true. 
5892 posix_cred_access(kauth_cred_t cred
, id_t object_uid
, id_t object_gid
, mode_t object_mode
, mode_t mode_req
) 
5895         mode_t mode_owner 
= (object_mode 
& S_IRWXU
); 
5896         mode_t mode_group 
= (object_mode 
& S_IRWXG
) << 3; 
5897         mode_t mode_world 
= (object_mode 
& S_IRWXO
) << 6; 
5900          * Check first for owner rights 
5902         if (kauth_cred_getuid(cred
) == object_uid 
&& (mode_req 
& mode_owner
) == mode_req
) 
5906          * Combined group and world rights check, if we don't have owner rights 
5908          * OPTIMIZED: If group and world rights would grant the same bits, and 
5909          * they set of requested bits is in both, then we can simply check the 
5910          * world rights, avoiding a group membership check, which is expensive. 
5912         if ((mode_req 
& mode_group 
& mode_world
) == mode_req
) { 
5916                  * NON-OPTIMIZED: requires group membership check. 
5918                 if ((mode_req 
& mode_group
) != mode_req
) { 
5920                          * exclusion group : treat errors as "is a member" 
5922                          * NON-OPTIMIZED: +group would deny; must check group 
5924                         if (!kauth_cred_ismember_gid(cred
, object_gid
, &is_member
) && is_member
) { 
5926                                  * DENY: +group denies 
5930                                 if ((mode_req 
& mode_world
) != mode_req
) { 
5932                                          * DENY: both -group & world would deny 
5937                                          * ALLOW: allowed by -group and +world 
5944                          * inclusion group; treat errors as "not a member" 
5946                          * NON-OPTIMIZED: +group allows, world denies; must 
5949                         if (!kauth_cred_ismember_gid(cred
, object_gid
, &is_member
) && is_member
) { 
5951                                  * ALLOW: allowed by +group 
5955                                 if ((mode_req 
& mode_world
) != mode_req
) { 
5957                                          * DENY: both -group & world would deny 
5962                                          * ALLOW: allowed by -group and +world