1/* 2 * Copyright (c) 2004-2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29/* 30 * Centralized authorisation framework. 31 */ 32 33#include <sys/appleapiopts.h> 34#include <sys/param.h> /* XXX trim includes */ 35#include <sys/acct.h> 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> 44#include <sys/stat.h> 45 46#include <security/audit/audit.h> 47 48#include <sys/mount.h> 49#include <sys/sysproto.h> 50#include <mach/message.h> 51#include <mach/host_security.h> 52 53#include <kern/locks.h> 54 55 56/* 57 * Authorization scopes. 58 */ 59 60lck_grp_t *kauth_lck_grp; 61static 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); 64 65/* 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. 70 */ 71struct kauth_listener { 72 TAILQ_ENTRY(kauth_listener) kl_link; 73 const char * kl_identifier; 74 kauth_scope_callback_t kl_callback; 75 void * kl_idata; 76}; 77 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 81 * post Tiger. 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. 87 */ 88struct kauth_local_listener { 89 kauth_listener_t kll_listenerp; 90 kauth_scope_callback_t kll_callback; 91 void * kll_idata; 92}; 93typedef struct kauth_local_listener *kauth_local_listener_t; 94 95static TAILQ_HEAD(,kauth_listener) kauth_dangling_listeners; 96 97/* 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. 101 * XXX - kauth_todo 102 */ 103#define KAUTH_SCOPE_MAX_LISTENERS 15 104 105struct kauth_scope { 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; 110 void * ks_idata; 111 u_int ks_flags; 112}; 113 114/* values for kauth_scope.ks_flags */ 115#define KS_F_HAS_LISTENERS (1 << 0) 116 117static TAILQ_HEAD(,kauth_scope) kauth_scopes; 118 119static int kauth_add_callback_to_scope(kauth_scope_t sp, kauth_listener_t klp); 120static void kauth_scope_init(void); 121static kauth_scope_t kauth_alloc_scope(const char *identifier, kauth_scope_callback_t callback, void *idata); 122static kauth_listener_t kauth_alloc_listener(const char *identifier, kauth_scope_callback_t callback, void *idata); 123#if 0 124static int kauth_scope_valid(kauth_scope_t scope); 125#endif 126 127kauth_scope_t kauth_scope_process; 128static 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); 130kauth_scope_t kauth_scope_generic; 131static 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); 133kauth_scope_t kauth_scope_fileop; 134 135extern int cansignal(struct proc *, kauth_cred_t, struct proc *, int, int); 136extern char * get_pathbuff(void); 137extern void release_pathbuff(char *path); 138 139/* 140 * Initialization. 141 */ 142void 143kauth_init(void) 144{ 145 lck_grp_attr_t *grp_attributes; 146 147 TAILQ_INIT(&kauth_scopes); 148 TAILQ_INIT(&kauth_dangling_listeners); 149 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); 154 155 /* bring up kauth subsystem components */ 156 kauth_cred_init(); 157#if CONFIG_EXT_RESOLVER 158 kauth_identity_init(); 159 kauth_groups_init(); 160#endif 161 kauth_scope_init(); 162#if CONFIG_EXT_RESOLVER 163 kauth_resolver_init(); 164#endif 165 /* can't alloc locks after this */ 166 lck_grp_free(kauth_lck_grp); 167 kauth_lck_grp = NULL; 168} 169 170static void 171kauth_scope_init(void) 172{ 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); 177} 178 179/* 180 * Scope registration. 181 */ 182 183static kauth_scope_t 184kauth_alloc_scope(const char *identifier, kauth_scope_callback_t callback, void *idata) 185{ 186 kauth_scope_t sp; 187 188 /* 189 * Allocate and populate the scope structure. 190 */ 191 MALLOC(sp, kauth_scope_t, sizeof(*sp), M_KAUTH, M_WAITOK | M_ZERO); 192 if (sp == NULL) 193 return(NULL); 194 sp->ks_flags = 0; 195 sp->ks_identifier = identifier; 196 sp->ks_idata = idata; 197 sp->ks_callback = callback; 198 return(sp); 199} 200 201static kauth_listener_t 202kauth_alloc_listener(const char *identifier, kauth_scope_callback_t callback, void *idata) 203{ 204 kauth_listener_t lsp; 205 206 /* 207 * Allocate and populate the listener structure. 208 */ 209 MALLOC(lsp, kauth_listener_t, sizeof(*lsp), M_KAUTH, M_WAITOK); 210 if (lsp == NULL) 211 return(NULL); 212 lsp->kl_identifier = identifier; 213 lsp->kl_idata = idata; 214 lsp->kl_callback = callback; 215 return(lsp); 216} 217 218kauth_scope_t 219kauth_register_scope(const char *identifier, kauth_scope_callback_t callback, void *idata) 220{ 221 kauth_scope_t sp, tsp; 222 kauth_listener_t klp; 223 224 if ((sp = kauth_alloc_scope(identifier, callback, idata)) == NULL) 225 return(NULL); 226 227 /* 228 * Lock the list and insert. 229 */ 230 KAUTH_SCOPELOCK(); 231 TAILQ_FOREACH(tsp, &kauth_scopes, ks_link) { 232 /* duplicate! */ 233 if (strncmp(tsp->ks_identifier, identifier, 234 strlen(tsp->ks_identifier) + 1) == 0) { 235 KAUTH_SCOPEUNLOCK(); 236 FREE(sp, M_KAUTH); 237 return(NULL); 238 } 239 } 240 TAILQ_INSERT_TAIL(&kauth_scopes, sp, ks_link); 241 242 /* 243 * Look for listeners waiting for this scope, move them to the active scope 244 * listener table. 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. 247 */ 248restart: 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 253 * the active scope. 254 */ 255 if (kauth_add_callback_to_scope(sp, klp) == 0) { 256 TAILQ_REMOVE(&kauth_dangling_listeners, klp, kl_link); 257 } 258 else { 259#if 0 260 printf("%s - failed to add listener to scope \"%s\" \n", __FUNCTION__, sp->ks_identifier); 261#endif 262 break; 263 } 264 goto restart; 265 } 266 } 267 268 KAUTH_SCOPEUNLOCK(); 269 return(sp); 270} 271 272 273 274void 275kauth_deregister_scope(kauth_scope_t scope) 276{ 277 int i; 278 279 KAUTH_SCOPELOCK(); 280 281 TAILQ_REMOVE(&kauth_scopes, scope, ks_link); 282 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; 288 /* 289 * XXX - kauth_todo - WARNING, do not clear kll_callback or 290 * kll_idata here. they are part of our scope unlisten race hack 291 */ 292 } 293 } 294 KAUTH_SCOPEUNLOCK(); 295 FREE(scope, M_KAUTH); 296 297 return; 298} 299 300kauth_listener_t 301kauth_listen_scope(const char *identifier, kauth_scope_callback_t callback, void *idata) 302{ 303 kauth_listener_t klp; 304 kauth_scope_t sp; 305 306 if ((klp = kauth_alloc_listener(identifier, callback, idata)) == NULL) 307 return(NULL); 308 309 /* 310 * Lock the scope list and check to see whether this scope already exists. 311 */ 312 KAUTH_SCOPELOCK(); 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) { 318 KAUTH_SCOPEUNLOCK(); 319 return(klp); 320 } 321 /* table already full */ 322 KAUTH_SCOPEUNLOCK(); 323 FREE(klp, M_KAUTH); 324 return(NULL); 325 } 326 } 327 328 /* scope doesn't exist, put on waiting list. */ 329 TAILQ_INSERT_TAIL(&kauth_dangling_listeners, klp, kl_link); 330 331 KAUTH_SCOPEUNLOCK(); 332 333 return(klp); 334} 335 336void 337kauth_unlisten_scope(kauth_listener_t listener) 338{ 339 kauth_scope_t sp; 340 kauth_listener_t klp; 341 int i, listener_count, do_free; 342 343 KAUTH_SCOPELOCK(); 344 345 /* search the active scope for this listener */ 346 TAILQ_FOREACH(sp, &kauth_scopes, ks_link) { 347 do_free = 0; 348 if ((sp->ks_flags & KS_F_HAS_LISTENERS) != 0) { 349 listener_count = 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; 353 do_free = 1; 354 /* 355 * XXX - kauth_todo - WARNING, do not clear kll_callback or 356 * kll_idata here. they are part of our scope unlisten race hack 357 */ 358 } 359 else if (sp->ks_listeners[i].kll_listenerp != NULL) { 360 listener_count++; 361 } 362 } 363 if (do_free) { 364 if (listener_count == 0) { 365 sp->ks_flags &= ~KS_F_HAS_LISTENERS; 366 } 367 KAUTH_SCOPEUNLOCK(); 368 FREE(listener, M_KAUTH); 369 return; 370 } 371 } 372 } 373 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); 378 KAUTH_SCOPEUNLOCK(); 379 FREE(listener, M_KAUTH); 380 return; 381 } 382 } 383 384 KAUTH_SCOPEUNLOCK(); 385 return; 386} 387 388/* 389 * Authorization requests. 390 * 391 * Returns: 0 Success 392 * EPERM Operation not permitted 393 * 394 * Imputed: *arg3, modified Callback return - depends on callback 395 * modification of *arg3, if any 396 */ 397int 398kauth_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) 400{ 401 int result, ret, i; 402 403 /* ask the scope */ 404 if (scope->ks_callback != NULL) 405 result = scope->ks_callback(credential, scope->ks_idata, action, arg0, arg1, arg2, arg3); 406 else 407 result = KAUTH_RESULT_DEFER; 408 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 416 * unlisten race. 417 */ 418 if (scope->ks_listeners[i].kll_listenerp == NULL || 419 scope->ks_listeners[i].kll_callback == NULL) 420 continue; 421 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)) 427 result = ret; 428 } 429 } 430 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); 434} 435 436/* 437 * Default authorization handlers. 438 */ 439int 440kauth_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) 442{ 443 444 return(KAUTH_RESULT_ALLOW); 445} 446 447#if 0 448/* 449 * Debugging support. 450 */ 451static int 452kauth_scope_valid(kauth_scope_t scope) 453{ 454 kauth_scope_t sp; 455 456 KAUTH_SCOPELOCK(); 457 TAILQ_FOREACH(sp, &kauth_scopes, ks_link) { 458 if (sp == scope) 459 break; 460 } 461 KAUTH_SCOPEUNLOCK(); 462 return((sp == NULL) ? 0 : 1); 463} 464#endif 465 466/* 467 * Process authorization scope. 468 */ 469 470int 471kauth_authorize_process(kauth_cred_t credential, kauth_action_t action, struct proc *process, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) 472{ 473 return(kauth_authorize_action(kauth_scope_process, credential, action, (uintptr_t)process, arg1, arg2, arg3)); 474} 475 476static int 477kauth_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) 479{ 480 switch(action) { 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 486 */ 487 if (cansignal(current_proc(), credential, (struct proc *)arg0, (int)arg1, 0)) 488 return(KAUTH_RESULT_ALLOW); 489 break; 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 494 */ 495 if (cantrace(current_proc(), credential, (proc_t)arg0, (int *)arg1)) 496 return(KAUTH_RESULT_ALLOW); 497 break; 498 } 499 500 /* no explicit result, so defer to others in the chain */ 501 return(KAUTH_RESULT_DEFER); 502} 503 504/* 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 507 * not relevant. 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. 524 */ 525 526int 527kauth_authorize_fileop_has_listeners(void) 528{ 529 /* 530 * return 1 if we have any listeners for the fileop scope 531 * otherwize return 0 532 */ 533 if ((kauth_scope_fileop->ks_flags & KS_F_HAS_LISTENERS) != 0) { 534 return(1); 535 } 536 return (0); 537} 538 539int 540kauth_authorize_fileop(kauth_cred_t credential, kauth_action_t action, uintptr_t arg0, uintptr_t arg1) 541{ 542 char *namep = NULL; 543 int name_len; 544 uintptr_t arg2 = 0; 545 546 /* we do not have a primary handler for the fileop scope so bail out if 547 * there are no listeners. 548 */ 549 if ((kauth_scope_fileop->ks_flags & KS_F_HAS_LISTENERS) == 0) { 550 return(0); 551 } 552 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. 555 */ 556 namep = get_pathbuff(); 557 name_len = MAXPATHLEN; 558 if (vn_getpath((vnode_t)arg0, namep, &name_len) != 0) { 559 release_pathbuff(namep); 560 return(0); 561 } 562 if (action == KAUTH_FILEOP_CLOSE) { 563 arg2 = arg1; /* close has some flags that come in via arg1 */ 564 } 565 arg1 = (uintptr_t)namep; 566 } 567 kauth_authorize_action(kauth_scope_fileop, credential, action, arg0, arg1, arg2, 0); 568 569 if (namep != NULL) { 570 release_pathbuff(namep); 571 } 572 573 return(0); 574} 575 576/* 577 * Generic authorization scope. 578 */ 579 580int 581kauth_authorize_generic(kauth_cred_t credential, kauth_action_t action) 582{ 583 if (credential == NULL) 584 panic("auth against NULL credential"); 585 586 return(kauth_authorize_action(kauth_scope_generic, credential, action, 0, 0, 0, 0)); 587 588} 589 590static int 591kauth_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) 593{ 594 switch(action) { 595 case KAUTH_GENERIC_ISSUSER: 596 /* XXX == 0 ? */ 597 return((kauth_cred_getuid(credential) == 0) ? 598 KAUTH_RESULT_ALLOW : KAUTH_RESULT_DENY); 599 break; 600 } 601 602 /* no explicit result, so defer to others in the chain */ 603 return(KAUTH_RESULT_DEFER); 604} 605 606/* 607 * ACL evaluator. 608 * 609 * Determines whether the credential has the requested rights for an object secured by the supplied 610 * ACL. 611 * 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. 614 */ 615int 616kauth_acl_evaluate(kauth_cred_t cred, kauth_acl_eval_t eval) 617{ 618 int applies, error, i, gotguid; 619 kauth_ace_t ace; 620 guid_t guid; 621 uint32_t rights; 622 int wkguid; 623 624 /* always allowed to do nothing */ 625 if (eval->ae_requested == 0) { 626 eval->ae_result = KAUTH_RESULT_ALLOW; 627 return(0); 628 } 629 630 eval->ae_residual = eval->ae_requested; 631 eval->ae_found_deny = FALSE; 632 633 /* 634 * Get our guid for comparison purposes. 635 */ 636 if ((error = kauth_cred_getguid(cred, &guid)) != 0) { 637 KAUTH_DEBUG(" ACL - can't get credential GUID (%d)", error); 638 error = 0; 639 gotguid = 0; 640 } else { 641 gotguid = 1; 642 } 643 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++) { 646 647 /* 648 * Skip inherit-only entries. 649 */ 650 if (ace->ace_flags & KAUTH_ACE_ONLY_INHERIT) 651 continue; 652 653 /* 654 * Expand generic rights, if appropriate. 655 */ 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; 665 666 /* 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. 670 */ 671 switch(ace->ace_flags & KAUTH_ACE_KINDMASK) { 672 case KAUTH_ACE_PERMIT: 673 if (!(eval->ae_residual & rights)) 674 continue; 675 break; 676 case KAUTH_ACE_DENY: 677 if (!(eval->ae_requested & rights)) 678 continue; 679 eval->ae_found_deny = TRUE; 680 break; 681 default: 682 /* we don't recognise this ACE, skip it */ 683 continue; 684 } 685 686 /* 687 * Verify whether this entry applies to the credential. 688 */ 689 wkguid = kauth_wellknown_guid(&ace->ace_applicable); 690 switch(wkguid) { 691 case KAUTH_WKG_OWNER: 692 applies = eval->ae_options & KAUTH_AEVAL_IS_OWNER; 693 break; 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); 697 else 698 applies = eval->ae_options & KAUTH_AEVAL_IN_GROUP; 699 break; 700 /* we short-circuit these here rather than wasting time calling the group membership code */ 701 case KAUTH_WKG_EVERYBODY: 702 applies = 1; 703 break; 704 case KAUTH_WKG_NOBODY: 705 applies = 0; 706 break; 707 708 default: 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 "); 713 714 if (!applies) { 715 error = !gotguid ? ENOENT : kauth_cred_ismember_guid(cred, &ace->ace_applicable, &applies); 716 /* 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). 721 */ 722 if (error != 0) { 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: 726 applies = 0; 727 break; 728 case KAUTH_ACE_DENY: 729 applies = 1; 730 break; 731 } 732 } else { 733 KAUTH_DEBUG(" ACL - %s group member", applies ? "is" : "not"); 734 } 735 } else { 736 KAUTH_DEBUG(" ACL - entry matches caller"); 737 } 738 } 739 if (!applies) 740 continue; 741 742 /* 743 * Apply ACE to outstanding rights. 744 */ 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; 753 return(0); 754 } 755 break; 756 case KAUTH_ACE_DENY: 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; 761 return(0); 762 } 763 break; 764 default: 765 KAUTH_DEBUG(" ACL - unknown entry kind %d", ace->ace_flags & KAUTH_ACE_KINDMASK); 766 break; 767 } 768 } 769 /* if not permitted, defer to other modes of authorisation */ 770 eval->ae_result = KAUTH_RESULT_DEFER; 771 return(0); 772} 773 774/* 775 * Perform ACL inheritance and umask-ACL handling. 776 * 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 780 * the umask ACL. 781 * If isdir is set, the resultant ACL is for a directory, otherwise it is for a file. 782 */ 783int 784kauth_acl_inherit(vnode_t dvp, kauth_acl_t initial, kauth_acl_t *product, int isdir, vfs_context_t ctx) 785{ 786 int entries, error, index; 787 unsigned int i; 788 struct vnode_attr dva; 789 kauth_acl_t inherit, result; 790 791 /* 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. 797 * 798 * XXX TODO: <rdar://3634665> wants a "umask ACL" from the process. 799 */ 800 inherit = NULL; 801 /* 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. 808 */ 809 if ((initial == NULL || !(initial->acl_flags & KAUTH_ACL_NO_INHERIT)) && 810 (dvp != NULL) && !vfs_authopaque(vnode_mount(dvp))) { 811 VATTR_INIT(&dva); 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"); 815 return(error); 816 } 817 if (VATTR_IS_SUPPORTED(&dva, va_acl)) { 818 inherit = dva.va_acl; 819 /* 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 825 * hierarchy. 826 */ 827 if (inherit != NULL && inherit->acl_flags & KAUTH_ACL_NO_INHERIT) { 828 kauth_acl_free(inherit); 829 inherit = NULL; 830 } 831 } 832 } 833 834 /* 835 * Compute the number of entries in the result ACL by scanning the 836 * input lists. 837 */ 838 entries = 0; 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)) 842 entries++; 843 } 844 } 845 846 if (initial == NULL) { 847 /* 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". 851 */ 852 } 853 854 if (initial != NULL) { 855 if (initial->acl_entrycount != KAUTH_FILESEC_NOACL) 856 entries += initial->acl_entrycount; 857 else 858 initial = NULL; 859 } 860 861 /* 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. 866 */ 867 if ((entries == 0) && (initial == NULL)) { 868 *product = NULL; 869 error = 0; 870 goto out; 871 } 872 873 /* 874 * Allocate the result buffer. 875 */ 876 if ((result = kauth_acl_alloc(entries)) == NULL) { 877 KAUTH_DEBUG(" ERROR - could not allocate %d-entry result buffer for inherited ACL", entries); 878 error = ENOMEM; 879 goto out; 880 } 881 882 /* 883 * Composition is simply: 884 * - initial direct ACEs 885 * - inherited ACEs from new parent 886 */ 887 index = 0; 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]; 892 } 893 } 894 KAUTH_DEBUG(" INHERIT - applied %d of %d initial entries", index, initial->acl_entrycount); 895 } 896 if (inherit != NULL) { 897 for (i = 0; i < inherit->acl_entrycount; i++) { 898 /* 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. 904 */ 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; 909 /* 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). 915 */ 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); 919 } 920 index++; 921 } 922 } 923 } 924 result->acl_entrycount = index; 925 *product = result; 926 KAUTH_DEBUG(" INHERIT - product ACL has %d entries", index); 927 error = 0; 928out: 929 if (inherit != NULL) 930 kauth_acl_free(inherit); 931 return(error); 932} 933 934/* 935 * Optimistically copy in a kauth_filesec structure 936 * 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 942 * 943 * Returns: 0 Success 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. 950 * 951 * Implicit returns: xsecdestpp, modified (only if successful!) 952 * 953 * Notes: The returned kauth_filesec_t is in host byte order 954 * 955 * The caller is responsible for freeing the returned 956 * kauth_filesec_t in the success case using the function 957 * kauth_filesec_free() 958 * 959 * Our largest initial guess is 32; this needs to move to 960 * a manifest constant in <sys/kauth.h>. 961 */ 962int 963kauth_copyinfilesec(user_addr_t xsecurity, kauth_filesec_t *xsecdestpp) 964{ 965 user_addr_t uaddr, known_bound; 966 int error; 967 kauth_filesec_t fsec; 968 u_int32_t count; 969 size_t copysize; 970 971 error = 0; 972 fsec = NULL; 973 974 /* 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. 979 * 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. 982 */ 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); 986 if (count > 32) 987 count = 32; 988restart: 989 if ((fsec = kauth_filesec_alloc(count)) == NULL) { 990 error = ENOMEM; 991 goto out; 992 } 993 copysize = KAUTH_FILESEC_SIZE(count); 994 if ((error = copyin(xsecurity, (caddr_t)fsec, copysize)) != 0) 995 goto out; 996 997 /* validate the filesec header */ 998 if (fsec->fsec_magic != KAUTH_FILESEC_MAGIC) { 999 error = EINVAL; 1000 goto out; 1001 } 1002 1003 /* 1004 * Is there an ACL payload, and is it too big? 1005 */ 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 */ 1010 error = EINVAL; 1011 goto out; 1012 } 1013 count = fsec->fsec_entrycount; 1014 kauth_filesec_free(fsec); 1015 goto restart; 1016 } 1017 1018out: 1019 if (error) { 1020 if (fsec) 1021 kauth_filesec_free(fsec); 1022 } else { 1023 *xsecdestpp = fsec; 1024 AUDIT_ARG(opaque, fsec, copysize); 1025 } 1026 return(error); 1027} 1028 1029/* 1030 * Allocate a block of memory containing a filesec structure, immediately 1031 * followed by 'count' kauth_ace structures. 1032 * 1033 * Parameters: count Number of kauth_ace structures needed 1034 * 1035 * Returns: !NULL A pointer to the allocated block 1036 * NULL Invalid 'count' or insufficient memory 1037 * 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. 1041 * 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. 1047 */ 1048kauth_filesec_t 1049kauth_filesec_alloc(int count) 1050{ 1051 kauth_filesec_t fsp; 1052 1053 /* if the caller hasn't given us a valid size hint, assume the worst */ 1054 if ((count < 0) || (count > KAUTH_ACL_MAX_ENTRIES)) 1055 return(NULL); 1056 1057 MALLOC(fsp, kauth_filesec_t, KAUTH_FILESEC_SIZE(count), M_KAUTH, M_WAITOK); 1058 if (fsp != NULL) { 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; 1064 } 1065 return(fsp); 1066} 1067 1068/* 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. 1071 * 1072 * Parameters: fsp kauth_filesec_t to free 1073 * 1074 * Returns: (void) 1075 * 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. 1079 */ 1080void 1081kauth_filesec_free(kauth_filesec_t fsp) 1082{ 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"); 1088#endif 1089 FREE(fsp, M_KAUTH); 1090} 1091 1092/* 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. 1096 * 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) 1101 * 1102 * Returns: (void) 1103 * 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. 1107 */ 1108void 1109kauth_filesec_acl_setendian(int kendian, kauth_filesec_t fsec, kauth_acl_t acl) 1110{ 1111 uint32_t compare_magic = KAUTH_FILESEC_MAGIC; 1112 uint32_t invert_magic = ntohl(KAUTH_FILESEC_MAGIC); 1113 uint32_t compare_acl_entrycount; 1114 uint32_t i; 1115 1116 if (compare_magic == invert_magic) 1117 return; 1118 1119 /* If no ACL, use ACL interior to 'fsec' instead */ 1120 if (acl == NULL) 1121 acl = &fsec->fsec_acl; 1122 1123 compare_acl_entrycount = acl->acl_entrycount; 1124 1125 /* 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. 1129 */ 1130 switch(kendian) { 1131 case KAUTH_ENDIAN_HOST: /* not in host, convert to host */ 1132 if (fsec->fsec_magic != invert_magic) 1133 return; 1134 /* acl_entrycount is byteswapped */ 1135 compare_acl_entrycount = ntohl(acl->acl_entrycount); 1136 break; 1137 case KAUTH_ENDIAN_DISK: /* not in disk, convert to disk */ 1138 if (fsec->fsec_magic != compare_magic) 1139 return; 1140 break; 1141 default: /* bad argument */ 1142 return; 1143 } 1144 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); 1150 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); 1155 } 1156 } 1157 } 1158 1159 1160/* 1161 * Allocate an ACL buffer. 1162 */ 1163kauth_acl_t 1164kauth_acl_alloc(int count) 1165{ 1166 kauth_acl_t aclp; 1167 1168 /* if the caller hasn't given us a valid size hint, assume the worst */ 1169 if ((count < 0) || (count > KAUTH_ACL_MAX_ENTRIES)) 1170 return(NULL); 1171 1172 MALLOC(aclp, kauth_acl_t, KAUTH_ACL_SIZE(count), M_KAUTH, M_WAITOK); 1173 if (aclp != NULL) { 1174 aclp->acl_entrycount = 0; 1175 aclp->acl_flags = 0; 1176 } 1177 return(aclp); 1178} 1179 1180void 1181kauth_acl_free(kauth_acl_t aclp) 1182{ 1183 FREE(aclp, M_KAUTH); 1184} 1185 1186 1187/* 1188 * WARNING - caller must hold KAUTH_SCOPELOCK 1189 */ 1190static int kauth_add_callback_to_scope(kauth_scope_t sp, kauth_listener_t klp) 1191{ 1192 int i; 1193 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; 1200 return(0); 1201 } 1202 } 1203 return(ENOSPC); 1204} 1205