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@ 
  30  * Centralized authorisation framework. 
  33 #include <sys/appleapiopts.h> 
  34 #include <sys/param.h>  /* XXX trim includes */ 
  36 #include <sys/systm.h> 
  37 #include <sys/ucred.h> 
  38 #include <sys/proc_internal.h> 
  39 #include <sys/timeb.h> 
  40 #include <sys/times.h> 
  41 #include <sys/malloc.h> 
  42 #include <sys/vnode_internal.h> 
  43 #include <sys/kauth.h> 
  46 #include <security/audit/audit.h> 
  48 #include <sys/mount.h> 
  49 #include <sys/sysproto.h> 
  50 #include <mach/message.h> 
  51 #include <mach/host_security.h> 
  53 #include <kern/locks.h> 
  57  * Authorization scopes. 
  60 lck_grp_t 
*kauth_lck_grp
; 
  61 static lck_mtx_t 
*kauth_scope_mtx
; 
  62 #define KAUTH_SCOPELOCK()       lck_mtx_lock(kauth_scope_mtx); 
  63 #define KAUTH_SCOPEUNLOCK()     lck_mtx_unlock(kauth_scope_mtx); 
  66  * We support listeners for scopes that have not been registered yet. 
  67  * If a listener comes in for a scope that is not active we hang the listener 
  68  * off our kauth_dangling_listeners list and once the scope becomes active we 
  69  * remove it from kauth_dangling_listeners and add it to the active scope. 
  71 struct kauth_listener 
{ 
  72         TAILQ_ENTRY(kauth_listener
)     kl_link
; 
  73         const char *                            kl_identifier
; 
  74         kauth_scope_callback_t          kl_callback
; 
  78 /* XXX - kauth_todo - there is a race if a scope listener is removed while we 
  79  * we are in the kauth_authorize_action code path.  We intentionally do not take 
  80  * a scope lock in order to get the best possible performance.  we will fix this  
  82  * Until the race is fixed our kext clients are responsible for all active  
  83  * requests that may be in their callback code or on the way to their callback 
  84  * code before they free kauth_listener.kl_callback or kauth_listener.kl_idata. 
  85  * We keep copies of these in our kauth_local_listener in an attempt to limit  
  86  * our expose to unlisten race.  
  88 struct kauth_local_listener 
{ 
  89         kauth_listener_t                        kll_listenerp
; 
  90         kauth_scope_callback_t          kll_callback
; 
  93 typedef struct kauth_local_listener 
*kauth_local_listener_t
; 
  95 static TAILQ_HEAD(,kauth_listener
) kauth_dangling_listeners
; 
  98  * Scope listeners need to be reworked to be dynamic. 
  99  * We intentionally used a static table to avoid locking issues with linked  
 100  * lists.  The listeners may be called quite often. 
 103 #define KAUTH_SCOPE_MAX_LISTENERS  15 
 106         TAILQ_ENTRY(kauth_scope
)        ks_link
; 
 107         volatile struct kauth_local_listener  ks_listeners
[KAUTH_SCOPE_MAX_LISTENERS
]; 
 108         const char *                            ks_identifier
; 
 109         kauth_scope_callback_t          ks_callback
; 
 114 /* values for kauth_scope.ks_flags */ 
 115 #define KS_F_HAS_LISTENERS              (1 << 0) 
 117 static TAILQ_HEAD(,kauth_scope
) kauth_scopes
; 
 119 static int kauth_add_callback_to_scope(kauth_scope_t sp
, kauth_listener_t klp
); 
 120 static void     kauth_scope_init(void); 
 121 static kauth_scope_t 
kauth_alloc_scope(const char *identifier
, kauth_scope_callback_t callback
, void *idata
); 
 122 static kauth_listener_t 
kauth_alloc_listener(const char *identifier
, kauth_scope_callback_t callback
, void *idata
); 
 124 static int      kauth_scope_valid(kauth_scope_t scope
); 
 127 kauth_scope_t   kauth_scope_process
; 
 128 static int      kauth_authorize_process_callback(kauth_cred_t _credential
, void *_idata
, kauth_action_t _action
, 
 129     uintptr_t arg0
, uintptr_t arg1
, __unused 
uintptr_t arg2
, __unused 
uintptr_t arg3
); 
 130 kauth_scope_t   kauth_scope_generic
; 
 131 static int      kauth_authorize_generic_callback(kauth_cred_t _credential
, void *_idata
, kauth_action_t _action
, 
 132     uintptr_t arg0
, uintptr_t arg1
, uintptr_t arg2
, uintptr_t arg3
); 
 133 kauth_scope_t   kauth_scope_fileop
; 
 135 extern int              cansignal(struct proc 
*, kauth_cred_t
, struct proc 
*, int, int); 
 136 extern char *   get_pathbuff(void); 
 137 extern void             release_pathbuff(char *path
); 
 145         lck_grp_attr_t  
*grp_attributes
; 
 147         TAILQ_INIT(&kauth_scopes
); 
 148         TAILQ_INIT(&kauth_dangling_listeners
); 
 150         /* set up our lock group */ 
 151         grp_attributes 
= lck_grp_attr_alloc_init(); 
 152         kauth_lck_grp 
= lck_grp_alloc_init("kauth", grp_attributes
); 
 153         lck_grp_attr_free(grp_attributes
); 
 155         /* bring up kauth subsystem components */ 
 157 #if CONFIG_EXT_RESOLVER 
 158         kauth_identity_init(); 
 162 #if CONFIG_EXT_RESOLVER 
 163         kauth_resolver_init(); 
 165         /* can't alloc locks after this */ 
 166         lck_grp_free(kauth_lck_grp
); 
 167         kauth_lck_grp 
= NULL
; 
 171 kauth_scope_init(void) 
 173         kauth_scope_mtx 
= lck_mtx_alloc_init(kauth_lck_grp
, 0 /*LCK_ATTR_NULL*/); 
 174         kauth_scope_process 
= kauth_register_scope(KAUTH_SCOPE_PROCESS
, kauth_authorize_process_callback
, NULL
); 
 175         kauth_scope_generic 
= kauth_register_scope(KAUTH_SCOPE_GENERIC
, kauth_authorize_generic_callback
, NULL
); 
 176         kauth_scope_fileop 
= kauth_register_scope(KAUTH_SCOPE_FILEOP
, NULL
, NULL
); 
 180  * Scope registration. 
 184 kauth_alloc_scope(const char *identifier
, kauth_scope_callback_t callback
, void *idata
) 
 189          * Allocate and populate the scope structure. 
 191         MALLOC(sp
, kauth_scope_t
, sizeof(*sp
), M_KAUTH
, M_WAITOK 
| M_ZERO
); 
 195         sp
->ks_identifier 
= identifier
; 
 196         sp
->ks_idata 
= idata
; 
 197         sp
->ks_callback 
= callback
; 
 201 static kauth_listener_t
 
 202 kauth_alloc_listener(const char *identifier
, kauth_scope_callback_t callback
, void *idata
) 
 204         kauth_listener_t lsp
; 
 207          * Allocate and populate the listener structure. 
 209         MALLOC(lsp
, kauth_listener_t
, sizeof(*lsp
), M_KAUTH
, M_WAITOK
); 
 212         lsp
->kl_identifier 
= identifier
; 
 213         lsp
->kl_idata 
= idata
; 
 214         lsp
->kl_callback 
= callback
; 
 219 kauth_register_scope(const char *identifier
, kauth_scope_callback_t callback
, void *idata
) 
 221         kauth_scope_t           sp
, tsp
; 
 222         kauth_listener_t        klp
; 
 224         if ((sp 
= kauth_alloc_scope(identifier
, callback
, idata
)) == NULL
) 
 228          * Lock the list and insert. 
 231         TAILQ_FOREACH(tsp
, &kauth_scopes
, ks_link
) { 
 233                 if (strncmp(tsp
->ks_identifier
, identifier
,  
 234                                         strlen(tsp
->ks_identifier
) + 1) == 0) { 
 240         TAILQ_INSERT_TAIL(&kauth_scopes
, sp
, ks_link
); 
 243          * Look for listeners waiting for this scope, move them to the active scope 
 245          * Note that we have to restart the scan every time we remove an entry 
 246          * from the list, since we can't remove the current item from the list. 
 249         TAILQ_FOREACH(klp
, &kauth_dangling_listeners
, kl_link
) { 
 250                 if (strncmp(klp
->kl_identifier
, sp
->ks_identifier
, 
 251                                         strlen(klp
->kl_identifier
) + 1) == 0) { 
 252                         /* found a match on the dangling listener list.  add it to the 
 255                         if (kauth_add_callback_to_scope(sp
, klp
) == 0) { 
 256                                 TAILQ_REMOVE(&kauth_dangling_listeners
, klp
, kl_link
); 
 260                                 printf("%s - failed to add listener to scope \"%s\" \n", __FUNCTION__
, sp
->ks_identifier
); 
 275 kauth_deregister_scope(kauth_scope_t scope
) 
 281         TAILQ_REMOVE(&kauth_scopes
, scope
, ks_link
); 
 283         /* relocate listeners back to the waiting list */ 
 284         for (i 
= 0; i 
< KAUTH_SCOPE_MAX_LISTENERS
; i
++) { 
 285                 if (scope
->ks_listeners
[i
].kll_listenerp 
!= NULL
) { 
 286                         TAILQ_INSERT_TAIL(&kauth_dangling_listeners
, scope
->ks_listeners
[i
].kll_listenerp
, kl_link
); 
 287                         scope
->ks_listeners
[i
].kll_listenerp 
= NULL
; 
 289                          * XXX - kauth_todo - WARNING, do not clear kll_callback or 
 290                          * kll_idata here.  they are part of our scope unlisten race hack 
 295         FREE(scope
, M_KAUTH
); 
 301 kauth_listen_scope(const char *identifier
, kauth_scope_callback_t callback
, void *idata
) 
 303         kauth_listener_t klp
; 
 306         if ((klp 
= kauth_alloc_listener(identifier
, callback
, idata
)) == NULL
) 
 310          * Lock the scope list and check to see whether this scope already exists. 
 313         TAILQ_FOREACH(sp
, &kauth_scopes
, ks_link
) { 
 314                 if (strncmp(sp
->ks_identifier
, identifier
, 
 315                                         strlen(sp
->ks_identifier
) + 1) == 0) { 
 316                         /* scope exists, add it to scope listener table */ 
 317                         if (kauth_add_callback_to_scope(sp
, klp
) == 0) { 
 321                         /* table already full */ 
 328         /* scope doesn't exist, put on waiting list. */ 
 329         TAILQ_INSERT_TAIL(&kauth_dangling_listeners
, klp
, kl_link
); 
 337 kauth_unlisten_scope(kauth_listener_t listener
) 
 340         kauth_listener_t        klp
; 
 341         int                                     i
, listener_count
, do_free
; 
 345         /* search the active scope for this listener */ 
 346         TAILQ_FOREACH(sp
, &kauth_scopes
, ks_link
) { 
 348                 if ((sp
->ks_flags 
& KS_F_HAS_LISTENERS
) != 0) { 
 350                         for (i 
= 0; i 
< KAUTH_SCOPE_MAX_LISTENERS
; i
++) { 
 351                                 if (sp
->ks_listeners
[i
].kll_listenerp 
== listener
) { 
 352                                         sp
->ks_listeners
[i
].kll_listenerp 
= NULL
; 
 355                                          * XXX - kauth_todo - WARNING, do not clear kll_callback or 
 356                                          * kll_idata here.  they are part of our scope unlisten race hack 
 359                                 else if (sp
->ks_listeners
[i
].kll_listenerp 
!= NULL
) { 
 364                                 if (listener_count 
== 0) { 
 365                                         sp
->ks_flags 
&= ~KS_F_HAS_LISTENERS
; 
 368                                 FREE(listener
, M_KAUTH
); 
 374         /* if not active, check the dangling list */ 
 375         TAILQ_FOREACH(klp
, &kauth_dangling_listeners
, kl_link
) { 
 376                 if (klp 
== listener
) { 
 377                         TAILQ_REMOVE(&kauth_dangling_listeners
, klp
, kl_link
); 
 379                         FREE(listener
, M_KAUTH
); 
 389  * Authorization requests. 
 392  *              EPERM                   Operation not permitted 
 394  * Imputed:     *arg3, modified         Callback return - depends on callback 
 395  *                                      modification of *arg3, if any 
 398 kauth_authorize_action(kauth_scope_t scope
, kauth_cred_t credential
, kauth_action_t action
, 
 399     uintptr_t arg0
, uintptr_t arg1
, uintptr_t arg2
, uintptr_t arg3
) 
 404         if (scope
->ks_callback 
!= NULL
) 
 405                 result 
= scope
->ks_callback(credential
, scope
->ks_idata
, action
, arg0
, arg1
, arg2
, arg3
); 
 407                 result 
= KAUTH_RESULT_DEFER
; 
 409         /* check with listeners */ 
 410         if ((scope
->ks_flags 
& KS_F_HAS_LISTENERS
) != 0) { 
 411                 for (i 
= 0; i 
< KAUTH_SCOPE_MAX_LISTENERS
; i
++) { 
 412                         /* XXX - kauth_todo - there is a race here if listener is removed - we will fix this post Tiger.  
 413                          * Until the race is fixed our kext clients are responsible for all active requests that may 
 414                          * be in their callbacks or on the way to their callbacks before they free kl_callback or kl_idata. 
 415                          * We keep copies of these in our kauth_local_listener in an attempt to limit our expose to  
 418                         if (scope
->ks_listeners
[i
].kll_listenerp 
== NULL 
||  
 419                                 scope
->ks_listeners
[i
].kll_callback 
== NULL
)  
 422                         ret 
= scope
->ks_listeners
[i
].kll_callback( 
 423                                         credential
, scope
->ks_listeners
[i
].kll_idata
,  
 424                                         action
, arg0
, arg1
, arg2
, arg3
); 
 425                         if ((ret 
== KAUTH_RESULT_DENY
) || 
 426                                 (result 
== KAUTH_RESULT_DEFER
)) 
 431         /* we need an explicit allow, or the auth fails */ 
 432         /* XXX need a mechanism for auth failure to be signalled vs. denial */ 
 433         return(result 
== KAUTH_RESULT_ALLOW 
? 0 : EPERM
); 
 437  * Default authorization handlers. 
 440 kauth_authorize_allow(__unused kauth_cred_t credential
, __unused 
void *idata
, __unused kauth_action_t action
, 
 441      __unused 
uintptr_t arg0
, __unused 
uintptr_t arg1
, __unused 
uintptr_t arg2
, __unused 
uintptr_t arg3
) 
 444         return(KAUTH_RESULT_ALLOW
); 
 452 kauth_scope_valid(kauth_scope_t scope
) 
 457         TAILQ_FOREACH(sp
, &kauth_scopes
, ks_link
) { 
 462         return((sp 
== NULL
) ? 0 : 1); 
 467  * Process authorization scope. 
 471 kauth_authorize_process(kauth_cred_t credential
, kauth_action_t action
, struct proc 
*process
, uintptr_t arg1
, uintptr_t arg2
, uintptr_t arg3
) 
 473         return(kauth_authorize_action(kauth_scope_process
, credential
, action
, (uintptr_t)process
, arg1
, arg2
, arg3
)); 
 477 kauth_authorize_process_callback(kauth_cred_t credential
, __unused 
void *idata
, kauth_action_t action
, 
 478     uintptr_t arg0
, uintptr_t arg1
, __unused 
uintptr_t arg2
, __unused 
uintptr_t arg3
) 
 481         case KAUTH_PROCESS_CANSIGNAL
: 
 482                 panic("KAUTH_PROCESS_CANSIGNAL not implemented"); 
 483                 /* XXX credential wrong here */ 
 484                 /* arg0 - process to signal 
 485                  * arg1 - signal to send the process 
 487                 if (cansignal(current_proc(), credential
, (struct proc 
*)arg0
, (int)arg1
, 0)) 
 488                         return(KAUTH_RESULT_ALLOW
); 
 490         case KAUTH_PROCESS_CANTRACE
: 
 491                 /* current_proc() - process that will do the tracing  
 492                  * arg0 - process to be traced  
 493                  * arg1 - pointer to int - reason (errno) for denial  
 495                 if (cantrace(current_proc(), credential
, (proc_t
)arg0
, (int *)arg1
)) 
 496                         return(KAUTH_RESULT_ALLOW
); 
 500         /* no explicit result, so defer to others in the chain */ 
 501         return(KAUTH_RESULT_DEFER
); 
 505  * File system operation authorization scope.  This is really only a notification 
 506  * of the file system operation, not an authorization check.  Thus the result is 
 508  * arguments passed to KAUTH_FILEOP_OPEN listeners 
 509  *              arg0 is pointer to vnode (vnode *) for given user path. 
 510  *              arg1 is pointer to path (char *) passed in to open. 
 511  * arguments passed to KAUTH_FILEOP_CLOSE listeners 
 512  *              arg0 is pointer to vnode (vnode *) for file to be closed. 
 513  *              arg1 is pointer to path (char *) of file to be closed. 
 514  *              arg2 is close flags. 
 515  * arguments passed to KAUTH_FILEOP_RENAME listeners 
 516  *              arg0 is pointer to "from" path (char *). 
 517  *              arg1 is pointer to "to" path (char *). 
 518  * arguments passed to KAUTH_FILEOP_EXCHANGE listeners 
 519  *              arg0 is pointer to file 1 path (char *). 
 520  *              arg1 is pointer to file 2 path (char *). 
 521  * arguments passed to KAUTH_FILEOP_EXEC listeners 
 522  *              arg0 is pointer to vnode (vnode *) for executable. 
 523  *              arg1 is pointer to path (char *) to executable. 
 527 kauth_authorize_fileop_has_listeners(void) 
 530          * return 1 if we have any listeners for the fileop scope 
 533         if ((kauth_scope_fileop
->ks_flags 
& KS_F_HAS_LISTENERS
) != 0) { 
 540 kauth_authorize_fileop(kauth_cred_t credential
, kauth_action_t action
, uintptr_t arg0
, uintptr_t arg1
) 
 546         /* we do not have a primary handler for the fileop scope so bail out if  
 547          * there are no listeners. 
 549         if ((kauth_scope_fileop
->ks_flags 
& KS_F_HAS_LISTENERS
) == 0) { 
 553         if (action 
== KAUTH_FILEOP_OPEN 
|| action 
== KAUTH_FILEOP_CLOSE 
|| action 
== KAUTH_FILEOP_EXEC
) { 
 554                 /* get path to the given vnode as a convenience to our listeners. 
 556                 namep 
= get_pathbuff(); 
 557                 name_len 
= MAXPATHLEN
; 
 558                 if (vn_getpath((vnode_t
)arg0
, namep
, &name_len
) != 0) { 
 559                         release_pathbuff(namep
); 
 562                 if (action 
== KAUTH_FILEOP_CLOSE
) { 
 563                         arg2 
= arg1
;  /* close has some flags that come in via arg1 */ 
 565                 arg1 
= (uintptr_t)namep
; 
 567         kauth_authorize_action(kauth_scope_fileop
, credential
, action
, arg0
, arg1
, arg2
, 0); 
 570                 release_pathbuff(namep
); 
 577  * Generic authorization scope. 
 581 kauth_authorize_generic(kauth_cred_t credential
, kauth_action_t action
) 
 583         if (credential 
== NULL
) 
 584                 panic("auth against NULL credential"); 
 586         return(kauth_authorize_action(kauth_scope_generic
, credential
, action
, 0, 0, 0, 0)); 
 591 kauth_authorize_generic_callback(kauth_cred_t credential
, __unused 
void *idata
, kauth_action_t action
, 
 592      __unused 
uintptr_t arg0
, __unused 
uintptr_t arg1
, __unused 
uintptr_t arg2
, __unused 
uintptr_t arg3
) 
 595         case KAUTH_GENERIC_ISSUSER
: 
 597                 return((kauth_cred_getuid(credential
) == 0) ? 
 598                     KAUTH_RESULT_ALLOW 
: KAUTH_RESULT_DENY
); 
 602         /* no explicit result, so defer to others in the chain */ 
 603         return(KAUTH_RESULT_DEFER
); 
 609  * Determines whether the credential has the requested rights for an object secured by the supplied 
 612  * Evaluation proceeds from the top down, with access denied if any ACE denies any of the requested 
 613  * rights, or granted if all of the requested rights are satisfied by the ACEs so far. 
 616 kauth_acl_evaluate(kauth_cred_t cred
, kauth_acl_eval_t eval
) 
 618         int applies
, error
, i
, gotguid
; 
 624         /* always allowed to do nothing */ 
 625         if (eval
->ae_requested 
== 0) { 
 626                 eval
->ae_result 
= KAUTH_RESULT_ALLOW
; 
 630         eval
->ae_residual 
= eval
->ae_requested
; 
 631         eval
->ae_found_deny 
= FALSE
; 
 634          * Get our guid for comparison purposes. 
 636         if ((error 
= kauth_cred_getguid(cred
, &guid
)) != 0) { 
 637                 KAUTH_DEBUG("    ACL - can't get credential GUID (%d)", error
); 
 644         KAUTH_DEBUG("    ACL - %d entries, initial residual %x", eval
->ae_count
, eval
->ae_residual
); 
 645         for (i 
= 0, ace 
= eval
->ae_acl
; i 
< eval
->ae_count
; i
++, ace
++) { 
 648                  * Skip inherit-only entries. 
 650                 if (ace
->ace_flags 
& KAUTH_ACE_ONLY_INHERIT
) 
 654                  * Expand generic rights, if appropriate. 
 656                 rights 
= ace
->ace_rights
; 
 657                 if (rights 
& KAUTH_ACE_GENERIC_ALL
) 
 658                         rights 
|= eval
->ae_exp_gall
; 
 659                 if (rights 
& KAUTH_ACE_GENERIC_READ
) 
 660                         rights 
|= eval
->ae_exp_gread
; 
 661                 if (rights 
& KAUTH_ACE_GENERIC_WRITE
) 
 662                         rights 
|= eval
->ae_exp_gwrite
; 
 663                 if (rights 
& KAUTH_ACE_GENERIC_EXECUTE
) 
 664                         rights 
|= eval
->ae_exp_gexec
; 
 667                  * Determine whether this entry applies to the current request.  This 
 668                  * saves us checking the GUID if the entry has nothing to do with what 
 669                  * we're currently doing. 
 671                 switch(ace
->ace_flags 
& KAUTH_ACE_KINDMASK
) { 
 672                 case KAUTH_ACE_PERMIT
: 
 673                         if (!(eval
->ae_residual 
& rights
)) 
 677                         if (!(eval
->ae_requested 
& rights
)) 
 679                         eval
->ae_found_deny 
= TRUE
; 
 682                         /* we don't recognise this ACE, skip it */ 
 687                  * Verify whether this entry applies to the credential. 
 689                 wkguid 
= kauth_wellknown_guid(&ace
->ace_applicable
); 
 691                 case KAUTH_WKG_OWNER
: 
 692                         applies 
= eval
->ae_options 
& KAUTH_AEVAL_IS_OWNER
; 
 694                 case KAUTH_WKG_GROUP
: 
 695                         if (!gotguid 
|| (eval
->ae_options 
& KAUTH_AEVAL_IN_GROUP_UNKNOWN
)) 
 696                                 applies 
= ((ace
->ace_flags 
& KAUTH_ACE_KINDMASK
) == KAUTH_ACE_DENY
); 
 698                                 applies 
= eval
->ae_options 
& KAUTH_AEVAL_IN_GROUP
; 
 700                 /* we short-circuit these here rather than wasting time calling the group membership code */ 
 701                 case KAUTH_WKG_EVERYBODY
: 
 704                 case KAUTH_WKG_NOBODY
: 
 709                         /* check to see whether it's exactly us, or a group we are a member of */ 
 710                         applies 
= !gotguid 
? 0 : kauth_guid_equal(&guid
, &ace
->ace_applicable
); 
 711                         KAUTH_DEBUG("    ACL - ACE applicable " K_UUID_FMT 
" caller " K_UUID_FMT 
" %smatched", 
 712                             K_UUID_ARG(ace
->ace_applicable
), K_UUID_ARG(guid
), applies 
? "" : "not "); 
 715                                 error 
= !gotguid 
? ENOENT 
: kauth_cred_ismember_guid(cred
, &ace
->ace_applicable
, &applies
); 
 717                                  * If we can't resolve group membership, we have to limit misbehaviour. 
 718                                  * If the ACE is an 'allow' ACE, assume the cred is not a member (avoid 
 719                                  * granting excess access).  If the ACE is a 'deny' ACE, assume the cred 
 720                                  * is a member (avoid failing to deny). 
 723                                         KAUTH_DEBUG("    ACL[%d] - can't get membership, making pessimistic assumption", i
); 
 724                                         switch(ace
->ace_flags 
& KAUTH_ACE_KINDMASK
) { 
 725                                         case KAUTH_ACE_PERMIT
: 
 733                                         KAUTH_DEBUG("    ACL - %s group member", applies 
? "is" : "not"); 
 736                                 KAUTH_DEBUG("    ACL - entry matches caller"); 
 743                  * Apply ACE to outstanding rights. 
 745                 switch(ace
->ace_flags 
& KAUTH_ACE_KINDMASK
) { 
 746                 case KAUTH_ACE_PERMIT
: 
 747                         /* satisfy any rights that this ACE grants */ 
 748                         eval
->ae_residual 
= eval
->ae_residual 
& ~rights
; 
 749                         KAUTH_DEBUG("    ACL[%d] - rights %x leave residual %x", i
, rights
, eval
->ae_residual
); 
 750                         /* all rights satisfied? */ 
 751                         if (eval
->ae_residual 
== 0) { 
 752                                 eval
->ae_result 
= KAUTH_RESULT_ALLOW
; 
 757                         /* deny the request if any of the requested rights is denied */ 
 758                         if (eval
->ae_requested 
& rights
) { 
 759                                 KAUTH_DEBUG("    ACL[%d] - denying based on %x", i
, rights
); 
 760                                 eval
->ae_result 
= KAUTH_RESULT_DENY
; 
 765                         KAUTH_DEBUG("    ACL - unknown entry kind %d", ace
->ace_flags 
& KAUTH_ACE_KINDMASK
); 
 769         /* if not permitted, defer to other modes of authorisation */ 
 770         eval
->ae_result 
= KAUTH_RESULT_DEFER
; 
 775  * Perform ACL inheritance and umask-ACL handling. 
 777  * Entries are inherited from the ACL on dvp.  A caller-supplied 
 778  * ACL is in initial, and the result is output into product. 
 779  * If the process has a umask ACL and one is not supplied, we use 
 781  * If isdir is set, the resultant ACL is for a directory, otherwise it is for a file. 
 784 kauth_acl_inherit(vnode_t dvp
, kauth_acl_t initial
, kauth_acl_t 
*product
, int isdir
, vfs_context_t ctx
) 
 786         int     entries
, error
, index
; 
 788         struct vnode_attr dva
; 
 789         kauth_acl_t inherit
, result
; 
 792          * Fetch the ACL from the directory.  This should never fail. 
 793          * Note that we don't manage inheritance when the remote server is 
 794          * doing authorization, since this means server enforcement of 
 795          * inheritance semantics; we just want to compose the initial 
 796          * ACL and any inherited ACE entries from the container object. 
 798          * XXX TODO: <rdar://3634665> wants a "umask ACL" from the process. 
 802          * If there is no initial ACL, or there is, and the initial ACLs 
 803          * flags do not request "no inheritance", then we inherit.  This allows 
 804          * initial object creation via open_extended() and mkdir_extended() 
 805          * to reject inheritance for themselves and for inferior nodes by 
 806          * specifying a non-NULL inital ACL which has the KAUTH_ACL_NO_INHERIT 
 807          * flag set in the flags field. 
 809         if ((initial 
== NULL 
|| !(initial
->acl_flags 
& KAUTH_ACL_NO_INHERIT
)) && 
 810             (dvp 
!= NULL
) && !vfs_authopaque(vnode_mount(dvp
))) { 
 812                 VATTR_WANTED(&dva
, va_acl
); 
 813                 if ((error 
= vnode_getattr(dvp
, &dva
, ctx
)) != 0) { 
 814                         KAUTH_DEBUG("    ERROR - could not get parent directory ACL for inheritance"); 
 817                 if (VATTR_IS_SUPPORTED(&dva
, va_acl
)) { 
 818                         inherit 
= dva
.va_acl
; 
 820                          * If there is an ACL on the parent directory, then 
 821                          * there are potentially inheritable ACE entries, but 
 822                          * if the flags on the directory ACL say not to 
 823                          * inherit, then we don't inherit.  This allows for 
 824                          * per directory rerooting of the inheritable ACL 
 827                         if (inherit 
!= NULL 
&& inherit
->acl_flags 
& KAUTH_ACL_NO_INHERIT
) { 
 828                                 kauth_acl_free(inherit
); 
 835          * Compute the number of entries in the result ACL by scanning the 
 839         if (inherit 
!= NULL
) { 
 840                 for (i 
= 0; i 
< inherit
->acl_entrycount
; i
++) { 
 841                         if (inherit
->acl_ace
[i
].ace_flags 
& (isdir 
? KAUTH_ACE_DIRECTORY_INHERIT 
: KAUTH_ACE_FILE_INHERIT
)) 
 846         if (initial 
== NULL
) { 
 848                  * XXX 3634665 TODO: if the initial ACL is not specfied by 
 849                  * XXX the caller, fetch the umask ACL from the process, 
 850                  * and use it in place of "initial". 
 854         if (initial 
!= NULL
) { 
 855                 if (initial
->acl_entrycount 
!= KAUTH_FILESEC_NOACL
) 
 856                         entries 
+= initial
->acl_entrycount
; 
 862          * If there is no initial ACL, and no inheritable entries, the 
 863          * object should be created with no ACL at all. 
 864          * Note that this differs from the case where the initial ACL 
 865          * is empty, in which case the object must also have an empty ACL. 
 867         if ((entries 
== 0) && (initial 
== NULL
)) { 
 874          * Allocate the result buffer. 
 876         if ((result 
= kauth_acl_alloc(entries
)) == NULL
) { 
 877                 KAUTH_DEBUG("    ERROR - could not allocate %d-entry result buffer for inherited ACL", entries
); 
 883          * Composition is simply: 
 884          *  - initial direct ACEs 
 885          *  - inherited ACEs from new parent 
 888         if (initial 
!= NULL
) { 
 889                 for (i 
= 0; i 
< initial
->acl_entrycount
; i
++) { 
 890                         if (!(initial
->acl_ace
[i
].ace_flags 
& KAUTH_ACE_INHERITED
)) { 
 891                                 result
->acl_ace
[index
++] = initial
->acl_ace
[i
]; 
 894                 KAUTH_DEBUG("    INHERIT - applied %d of %d initial entries", index
, initial
->acl_entrycount
); 
 896         if (inherit 
!= NULL
) { 
 897                 for (i 
= 0; i 
< inherit
->acl_entrycount
; i
++) { 
 899                          * Inherit onto this object?  We inherit only if 
 900                          * the target object is a container object and the 
 901                          * KAUTH_ACE_DIRECTORY_INHERIT bit is set, OR if 
 902                          * if the target object is not a container, and 
 903                          * the KAUTH_ACE_FILE_INHERIT bit is set. 
 905                         if (inherit
->acl_ace
[i
].ace_flags 
& (isdir 
? KAUTH_ACE_DIRECTORY_INHERIT 
: KAUTH_ACE_FILE_INHERIT
)) { 
 906                                 result
->acl_ace
[index
] = inherit
->acl_ace
[i
]; 
 907                                 result
->acl_ace
[index
].ace_flags 
|= KAUTH_ACE_INHERITED
; 
 908                                 result
->acl_ace
[index
].ace_flags 
&= ~KAUTH_ACE_ONLY_INHERIT
; 
 910                                  * We do not re-inherit inheritance flags 
 911                                  * if the ACE from the container has a 
 912                                  * KAUTH_ACE_LIMIT_INHERIT, OR if the new 
 913                                  * object is not itself a container (since 
 914                                  * inheritance is always container-based). 
 916                                 if ((result
->acl_ace
[index
].ace_flags 
& KAUTH_ACE_LIMIT_INHERIT
) || !isdir
) { 
 917                                         result
->acl_ace
[index
].ace_flags 
&= 
 918                                             ~(KAUTH_ACE_INHERIT_CONTROL_FLAGS
); 
 924         result
->acl_entrycount 
= index
; 
 926         KAUTH_DEBUG("    INHERIT - product ACL has %d entries", index
); 
 930                 kauth_acl_free(inherit
); 
 935  * Optimistically copy in a kauth_filesec structure 
 937  * Parameters:  xsecurity               user space kauth_filesec_t 
 938  *              xsecdstpp               pointer to kauth_filesec_t to be 
 939  *                                      modified to contain the contain a 
 940  *                                      pointer to an allocated copy of the 
 941  *                                      user space argument 
 944  *              ENOMEM                  Insufficient memory for the copy. 
 945  *              EINVAL                  The user space data was invalid, or 
 946  *                                      there were too many ACE entries. 
 947  *              EFAULT                  The user space address was invalid; 
 948  *                                      this may mean 'fsec_entrycount' in 
 949  *                                      the user copy is corrupt/incorrect. 
 951  * Implicit returns: xsecdestpp, modified (only if successful!) 
 953  * Notes:       The returned kauth_filesec_t is in host byte order 
 955  *              The caller is responsible for freeing the returned 
 956  *              kauth_filesec_t in the success case using the function 
 957  *              kauth_filesec_free() 
 959  *              Our largest initial guess is 32; this needs to move to 
 960  *              a manifest constant in <sys/kauth.h>. 
 963 kauth_copyinfilesec(user_addr_t xsecurity
, kauth_filesec_t 
*xsecdestpp
) 
 965         user_addr_t uaddr
, known_bound
; 
 967         kauth_filesec_t fsec
; 
 975          * Make a guess at the size of the filesec.  We start with the base 
 976          * pointer, and look at how much room is left on the page, clipped 
 977          * to a sensible upper bound.  If it turns out this isn't enough, 
 978          * we'll size based on the actual ACL contents and come back again. 
 980          * The upper bound must be less than KAUTH_ACL_MAX_ENTRIES.  The 
 981          * value here is fairly arbitrary.  It's ok to have a zero count. 
 983         known_bound 
= xsecurity 
+  KAUTH_FILESEC_SIZE(0); 
 984         uaddr 
= mach_vm_round_page(known_bound
); 
 985         count 
= (uaddr 
- known_bound
) / sizeof(struct kauth_ace
); 
 989         if ((fsec 
= kauth_filesec_alloc(count
)) == NULL
) { 
 993         copysize 
= KAUTH_FILESEC_SIZE(count
); 
 994         if ((error 
= copyin(xsecurity
, (caddr_t
)fsec
, copysize
)) != 0) 
 997         /* validate the filesec header */ 
 998         if (fsec
->fsec_magic 
!= KAUTH_FILESEC_MAGIC
) { 
1004          * Is there an ACL payload, and is it too big? 
1006         if ((fsec
->fsec_entrycount 
!= KAUTH_FILESEC_NOACL
) && 
1007             (fsec
->fsec_entrycount 
> count
)) { 
1008                 if (fsec
->fsec_entrycount 
> KAUTH_ACL_MAX_ENTRIES
) { 
1009                         /* XXX This should be E2BIG */ 
1013                 count 
= fsec
->fsec_entrycount
; 
1014                 kauth_filesec_free(fsec
); 
1021                         kauth_filesec_free(fsec
); 
1024                 AUDIT_ARG(opaque
, fsec
, copysize
); 
1030  * Allocate a block of memory containing a filesec structure, immediately 
1031  * followed by 'count' kauth_ace structures. 
1033  * Parameters:  count                   Number of kauth_ace structures needed 
1035  * Returns:     !NULL                   A pointer to the allocated block 
1036  *              NULL                    Invalid 'count' or insufficient memory 
1038  * Notes:       Returned memory area assumes that the structures are packed 
1039  *              densely, so this function may only be used by code that also 
1040  *              assumes no padding following structures. 
1042  *              The returned structure must be freed by the caller using the 
1043  *              function kauth_filesec_free(), in case we decide to use an 
1044  *              allocation mechanism that is aware of the object size at some 
1045  *              point, since the object size is only available by introspecting 
1046  *              the object itself. 
1049 kauth_filesec_alloc(int count
) 
1051         kauth_filesec_t fsp
; 
1053         /* if the caller hasn't given us a valid size hint, assume the worst */ 
1054         if ((count 
< 0) || (count 
> KAUTH_ACL_MAX_ENTRIES
)) 
1057         MALLOC(fsp
, kauth_filesec_t
, KAUTH_FILESEC_SIZE(count
), M_KAUTH
, M_WAITOK
); 
1059                 fsp
->fsec_magic 
= KAUTH_FILESEC_MAGIC
; 
1060                 fsp
->fsec_owner 
= kauth_null_guid
; 
1061                 fsp
->fsec_group 
= kauth_null_guid
; 
1062                 fsp
->fsec_entrycount 
= KAUTH_FILESEC_NOACL
; 
1063                 fsp
->fsec_flags 
= 0; 
1069  * Free a kauth_filesec_t that was previous allocated, either by a direct 
1070  * call to kauth_filesec_alloc() or by calling a function that calls it. 
1072  * Parameters:  fsp                     kauth_filesec_t to free 
1076  * Notes:       The kauth_filesec_t to be freed is assumed to be in host 
1077  *              byte order so that this function can introspect it in the 
1078  *              future to determine its size, if necesssary. 
1081 kauth_filesec_free(kauth_filesec_t fsp
) 
1083 #ifdef KAUTH_DEBUG_ENABLE 
1084         if (fsp 
== KAUTH_FILESEC_NONE
) 
1085                 panic("freeing KAUTH_FILESEC_NONE"); 
1086         if (fsp 
== KAUTH_FILESEC_WANTED
) 
1087                 panic("freeing KAUTH_FILESEC_WANTED"); 
1093  * Set the endianness of a filesec and an ACL; if 'acl' is NULL, use the  
1094  * ACL interior to 'fsec' instead.  If the endianness doesn't change, then 
1095  * this function will have no effect. 
1097  * Parameters:  kendian                 The endianness to set; this is either 
1098  *                                      KAUTH_ENDIAN_HOST or KAUTH_ENDIAN_DISK. 
1099  *              fsec                    The filesec to convert. 
1100  *              acl                     The ACL to convert (optional) 
1104  * Notes:       We use ntohl() because it has a transitive property on Intel 
1105  *              machines and no effect on PPC mancines.  This guarantees us 
1106  *              that the swapping only occurs if the endiannes is wrong. 
1109 kauth_filesec_acl_setendian(int kendian
, kauth_filesec_t fsec
, kauth_acl_t acl
) 
1111         uint32_t        compare_magic 
= KAUTH_FILESEC_MAGIC
; 
1112         uint32_t        invert_magic 
= ntohl(KAUTH_FILESEC_MAGIC
); 
1113         uint32_t        compare_acl_entrycount
; 
1116         if (compare_magic 
== invert_magic
) 
1119         /* If no ACL, use ACL interior to 'fsec' instead */ 
1121                 acl 
= &fsec
->fsec_acl
; 
1123         compare_acl_entrycount 
= acl
->acl_entrycount
; 
1126          * Only convert what needs to be converted, and only if the arguments 
1127          * are valid.  The following switch and tests effectively reject 
1128          * conversions on invalid magic numbers as a desirable side effect. 
1131         case KAUTH_ENDIAN_HOST
:         /* not in host, convert to host */ 
1132                 if (fsec
->fsec_magic 
!= invert_magic
) 
1134                 /* acl_entrycount is byteswapped */ 
1135                 compare_acl_entrycount 
= ntohl(acl
->acl_entrycount
); 
1137         case KAUTH_ENDIAN_DISK
:         /* not in disk, convert to disk */ 
1138                 if (fsec
->fsec_magic 
!= compare_magic
) 
1141         default:                        /* bad argument */ 
1145         /* We are go for conversion */ 
1146         fsec
->fsec_magic 
= ntohl(fsec
->fsec_magic
); 
1147         acl
->acl_entrycount 
= ntohl(acl
->acl_entrycount
); 
1148         if (compare_acl_entrycount 
!= KAUTH_FILESEC_NOACL
) { 
1149                 acl
->acl_flags 
= ntohl(acl
->acl_flags
); 
1151                 /* swap ACE rights and flags */ 
1152                 for (i 
= 0; i 
< compare_acl_entrycount
; i
++) { 
1153                         acl
->acl_ace
[i
].ace_flags 
= ntohl(acl
->acl_ace
[i
].ace_flags
); 
1154                         acl
->acl_ace
[i
].ace_rights 
= ntohl(acl
->acl_ace
[i
].ace_rights
); 
1161  * Allocate an ACL buffer. 
1164 kauth_acl_alloc(int count
) 
1168         /* if the caller hasn't given us a valid size hint, assume the worst */ 
1169         if ((count 
< 0) || (count 
> KAUTH_ACL_MAX_ENTRIES
)) 
1172         MALLOC(aclp
, kauth_acl_t
, KAUTH_ACL_SIZE(count
), M_KAUTH
, M_WAITOK
); 
1174                 aclp
->acl_entrycount 
= 0; 
1175                 aclp
->acl_flags 
= 0; 
1181 kauth_acl_free(kauth_acl_t aclp
) 
1183         FREE(aclp
, M_KAUTH
); 
1188  * WARNING - caller must hold KAUTH_SCOPELOCK 
1190 static int kauth_add_callback_to_scope(kauth_scope_t sp
, kauth_listener_t klp
) 
1194         for (i 
= 0; i 
< KAUTH_SCOPE_MAX_LISTENERS
; i
++) { 
1195                 if (sp
->ks_listeners
[i
].kll_listenerp 
== NULL
) { 
1196                         sp
->ks_listeners
[i
].kll_callback 
= klp
->kl_callback
; 
1197                         sp
->ks_listeners
[i
].kll_idata 
= klp
->kl_idata
; 
1198                         sp
->ks_listeners
[i
].kll_listenerp 
= klp
; 
1199                         sp
->ks_flags 
|= KS_F_HAS_LISTENERS
;