1 /* $NetBSD: kern_auth.c,v 1.68 2012/03/13 18:40:52 elad Exp $ */ 2 3 /*- 4 * Copyright (c) 2005, 2006 Elad Efrat <elad@NetBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __KERNEL_RCSID(0, "$NetBSD: kern_auth.c,v 1.68 2012/03/13 18:40:52 elad Exp $"); 32 33 #include <sys/types.h> 34 #include <sys/param.h> 35 #include <sys/queue.h> 36 #include <sys/proc.h> 37 #include <sys/ucred.h> 38 #include <sys/pool.h> 39 #include <sys/kauth.h> 40 #include <sys/kmem.h> 41 #include <sys/rwlock.h> 42 #include <sys/sysctl.h> 43 #include <sys/atomic.h> 44 #include <sys/specificdata.h> 45 #include <sys/vnode.h> 46 47 #include <secmodel/secmodel.h> 48 49 /* 50 * Secmodel-specific credentials. 51 */ 52 struct kauth_key { 53 secmodel_t ks_secmodel; /* secmodel */ 54 specificdata_key_t ks_key; /* key */ 55 }; 56 57 /* 58 * Credentials. 59 * 60 * A subset of this structure is used in kvm(3) (src/lib/libkvm/kvm_proc.c) 61 * and should be synchronized with this structure when the update is 62 * relevant. 63 */ 64 struct kauth_cred { 65 /* 66 * Ensure that the first part of the credential resides in its own 67 * cache line. Due to sharing there aren't many kauth_creds in a 68 * typical system, but the reference counts change very often. 69 * Keeping it seperate from the rest of the data prevents false 70 * sharing between CPUs. 71 */ 72 u_int cr_refcnt; /* reference count */ 73 #if COHERENCY_UNIT > 4 74 uint8_t cr_pad[COHERENCY_UNIT - 4]; 75 #endif 76 uid_t cr_uid; /* user id */ 77 uid_t cr_euid; /* effective user id */ 78 uid_t cr_svuid; /* saved effective user id */ 79 gid_t cr_gid; /* group id */ 80 gid_t cr_egid; /* effective group id */ 81 gid_t cr_svgid; /* saved effective group id */ 82 u_int cr_ngroups; /* number of groups */ 83 gid_t cr_groups[NGROUPS]; /* group memberships */ 84 specificdata_reference cr_sd; /* specific data */ 85 }; 86 87 /* 88 * Listener. 89 */ 90 struct kauth_listener { 91 kauth_scope_callback_t func; /* callback */ 92 kauth_scope_t scope; /* scope backpointer */ 93 u_int refcnt; /* reference count */ 94 SIMPLEQ_ENTRY(kauth_listener) listener_next; /* listener list */ 95 }; 96 97 /* 98 * Scope. 99 */ 100 struct kauth_scope { 101 const char *id; /* scope name */ 102 void *cookie; /* user cookie */ 103 u_int nlisteners; /* # of listeners */ 104 SIMPLEQ_HEAD(, kauth_listener) listenq; /* listener list */ 105 SIMPLEQ_ENTRY(kauth_scope) next_scope; /* scope list */ 106 }; 107 108 static int kauth_cred_hook(kauth_cred_t, kauth_action_t, void *, void *); 109 110 /* List of scopes and its lock. */ 111 static SIMPLEQ_HEAD(, kauth_scope) scope_list = 112 SIMPLEQ_HEAD_INITIALIZER(scope_list); 113 114 /* Built-in scopes: generic, process. */ 115 static kauth_scope_t kauth_builtin_scope_generic; 116 static kauth_scope_t kauth_builtin_scope_system; 117 static kauth_scope_t kauth_builtin_scope_process; 118 static kauth_scope_t kauth_builtin_scope_network; 119 static kauth_scope_t kauth_builtin_scope_machdep; 120 static kauth_scope_t kauth_builtin_scope_device; 121 static kauth_scope_t kauth_builtin_scope_cred; 122 static kauth_scope_t kauth_builtin_scope_vnode; 123 124 static specificdata_domain_t kauth_domain; 125 static pool_cache_t kauth_cred_cache; 126 127 krwlock_t kauth_lock; 128 129 /* Allocate new, empty kauth credentials. */ 130 kauth_cred_t 131 kauth_cred_alloc(void) 132 { 133 kauth_cred_t cred; 134 135 cred = pool_cache_get(kauth_cred_cache, PR_WAITOK); 136 137 cred->cr_refcnt = 1; 138 cred->cr_uid = 0; 139 cred->cr_euid = 0; 140 cred->cr_svuid = 0; 141 cred->cr_gid = 0; 142 cred->cr_egid = 0; 143 cred->cr_svgid = 0; 144 cred->cr_ngroups = 0; 145 146 specificdata_init(kauth_domain, &cred->cr_sd); 147 kauth_cred_hook(cred, KAUTH_CRED_INIT, NULL, NULL); 148 149 return (cred); 150 } 151 152 /* Increment reference count to cred. */ 153 void 154 kauth_cred_hold(kauth_cred_t cred) 155 { 156 KASSERT(cred != NULL); 157 KASSERT(cred->cr_refcnt > 0); 158 159 atomic_inc_uint(&cred->cr_refcnt); 160 } 161 162 /* Decrease reference count to cred. If reached zero, free it. */ 163 void 164 kauth_cred_free(kauth_cred_t cred) 165 { 166 167 KASSERT(cred != NULL); 168 KASSERT(cred->cr_refcnt > 0); 169 ASSERT_SLEEPABLE(); 170 171 if (atomic_dec_uint_nv(&cred->cr_refcnt) > 0) 172 return; 173 174 kauth_cred_hook(cred, KAUTH_CRED_FREE, NULL, NULL); 175 specificdata_fini(kauth_domain, &cred->cr_sd); 176 pool_cache_put(kauth_cred_cache, cred); 177 } 178 179 static void 180 kauth_cred_clone1(kauth_cred_t from, kauth_cred_t to, bool copy_groups) 181 { 182 KASSERT(from != NULL); 183 KASSERT(to != NULL); 184 KASSERT(from->cr_refcnt > 0); 185 186 to->cr_uid = from->cr_uid; 187 to->cr_euid = from->cr_euid; 188 to->cr_svuid = from->cr_svuid; 189 to->cr_gid = from->cr_gid; 190 to->cr_egid = from->cr_egid; 191 to->cr_svgid = from->cr_svgid; 192 if (copy_groups) { 193 to->cr_ngroups = from->cr_ngroups; 194 memcpy(to->cr_groups, from->cr_groups, sizeof(to->cr_groups)); 195 } 196 197 kauth_cred_hook(from, KAUTH_CRED_COPY, to, NULL); 198 } 199 200 void 201 kauth_cred_clone(kauth_cred_t from, kauth_cred_t to) 202 { 203 kauth_cred_clone1(from, to, true); 204 } 205 206 /* 207 * Duplicate cred and return a new kauth_cred_t. 208 */ 209 kauth_cred_t 210 kauth_cred_dup(kauth_cred_t cred) 211 { 212 kauth_cred_t new_cred; 213 214 KASSERT(cred != NULL); 215 KASSERT(cred->cr_refcnt > 0); 216 217 new_cred = kauth_cred_alloc(); 218 219 kauth_cred_clone(cred, new_cred); 220 221 return (new_cred); 222 } 223 224 /* 225 * Similar to crcopy(), only on a kauth_cred_t. 226 * XXX: Is this even needed? [kauth_cred_copy] 227 */ 228 kauth_cred_t 229 kauth_cred_copy(kauth_cred_t cred) 230 { 231 kauth_cred_t new_cred; 232 233 KASSERT(cred != NULL); 234 KASSERT(cred->cr_refcnt > 0); 235 236 /* If the provided credentials already have one reference, use them. */ 237 if (cred->cr_refcnt == 1) 238 return (cred); 239 240 new_cred = kauth_cred_alloc(); 241 242 kauth_cred_clone(cred, new_cred); 243 244 kauth_cred_free(cred); 245 246 return (new_cred); 247 } 248 249 void 250 kauth_proc_fork(struct proc *parent, struct proc *child) 251 { 252 253 mutex_enter(parent->p_lock); 254 kauth_cred_hold(parent->p_cred); 255 child->p_cred = parent->p_cred; 256 mutex_exit(parent->p_lock); 257 258 /* XXX: relies on parent process stalling during fork() */ 259 kauth_cred_hook(parent->p_cred, KAUTH_CRED_FORK, parent, 260 child); 261 } 262 263 uid_t 264 kauth_cred_getuid(kauth_cred_t cred) 265 { 266 KASSERT(cred != NULL); 267 268 return (cred->cr_uid); 269 } 270 271 uid_t 272 kauth_cred_geteuid(kauth_cred_t cred) 273 { 274 KASSERT(cred != NULL); 275 276 return (cred->cr_euid); 277 } 278 279 uid_t 280 kauth_cred_getsvuid(kauth_cred_t cred) 281 { 282 KASSERT(cred != NULL); 283 284 return (cred->cr_svuid); 285 } 286 287 gid_t 288 kauth_cred_getgid(kauth_cred_t cred) 289 { 290 KASSERT(cred != NULL); 291 292 return (cred->cr_gid); 293 } 294 295 gid_t 296 kauth_cred_getegid(kauth_cred_t cred) 297 { 298 KASSERT(cred != NULL); 299 300 return (cred->cr_egid); 301 } 302 303 gid_t 304 kauth_cred_getsvgid(kauth_cred_t cred) 305 { 306 KASSERT(cred != NULL); 307 308 return (cred->cr_svgid); 309 } 310 311 void 312 kauth_cred_setuid(kauth_cred_t cred, uid_t uid) 313 { 314 KASSERT(cred != NULL); 315 KASSERT(cred->cr_refcnt == 1); 316 317 cred->cr_uid = uid; 318 } 319 320 void 321 kauth_cred_seteuid(kauth_cred_t cred, uid_t uid) 322 { 323 KASSERT(cred != NULL); 324 KASSERT(cred->cr_refcnt == 1); 325 326 cred->cr_euid = uid; 327 } 328 329 void 330 kauth_cred_setsvuid(kauth_cred_t cred, uid_t uid) 331 { 332 KASSERT(cred != NULL); 333 KASSERT(cred->cr_refcnt == 1); 334 335 cred->cr_svuid = uid; 336 } 337 338 void 339 kauth_cred_setgid(kauth_cred_t cred, gid_t gid) 340 { 341 KASSERT(cred != NULL); 342 KASSERT(cred->cr_refcnt == 1); 343 344 cred->cr_gid = gid; 345 } 346 347 void 348 kauth_cred_setegid(kauth_cred_t cred, gid_t gid) 349 { 350 KASSERT(cred != NULL); 351 KASSERT(cred->cr_refcnt == 1); 352 353 cred->cr_egid = gid; 354 } 355 356 void 357 kauth_cred_setsvgid(kauth_cred_t cred, gid_t gid) 358 { 359 KASSERT(cred != NULL); 360 KASSERT(cred->cr_refcnt == 1); 361 362 cred->cr_svgid = gid; 363 } 364 365 /* Checks if gid is a member of the groups in cred. */ 366 int 367 kauth_cred_ismember_gid(kauth_cred_t cred, gid_t gid, int *resultp) 368 { 369 uint32_t i; 370 371 KASSERT(cred != NULL); 372 KASSERT(resultp != NULL); 373 374 *resultp = 0; 375 376 for (i = 0; i < cred->cr_ngroups; i++) 377 if (cred->cr_groups[i] == gid) { 378 *resultp = 1; 379 break; 380 } 381 382 return (0); 383 } 384 385 u_int 386 kauth_cred_ngroups(kauth_cred_t cred) 387 { 388 KASSERT(cred != NULL); 389 390 return (cred->cr_ngroups); 391 } 392 393 /* 394 * Return the group at index idx from the groups in cred. 395 */ 396 gid_t 397 kauth_cred_group(kauth_cred_t cred, u_int idx) 398 { 399 KASSERT(cred != NULL); 400 KASSERT(idx < cred->cr_ngroups); 401 402 return (cred->cr_groups[idx]); 403 } 404 405 /* XXX elad: gmuid is unused for now. */ 406 int 407 kauth_cred_setgroups(kauth_cred_t cred, const gid_t *grbuf, size_t len, 408 uid_t gmuid, enum uio_seg seg) 409 { 410 int error = 0; 411 412 KASSERT(cred != NULL); 413 KASSERT(cred->cr_refcnt == 1); 414 415 if (len > __arraycount(cred->cr_groups)) 416 return EINVAL; 417 418 if (len) { 419 if (seg == UIO_SYSSPACE) { 420 memcpy(cred->cr_groups, grbuf, 421 len * sizeof(cred->cr_groups[0])); 422 } else { 423 error = copyin(grbuf, cred->cr_groups, 424 len * sizeof(cred->cr_groups[0])); 425 if (error != 0) 426 len = 0; 427 } 428 } 429 memset(cred->cr_groups + len, 0xff, 430 sizeof(cred->cr_groups) - (len * sizeof(cred->cr_groups[0]))); 431 432 cred->cr_ngroups = len; 433 434 return error; 435 } 436 437 /* This supports sys_setgroups() */ 438 int 439 kauth_proc_setgroups(struct lwp *l, kauth_cred_t ncred) 440 { 441 kauth_cred_t cred; 442 int error; 443 444 /* 445 * At this point we could delete duplicate groups from ncred, 446 * and plausibly sort the list - but in general the later is 447 * a bad idea. 448 */ 449 proc_crmod_enter(); 450 /* Maybe we should use curproc here ? */ 451 cred = l->l_proc->p_cred; 452 453 kauth_cred_clone1(cred, ncred, false); 454 455 error = kauth_authorize_process(cred, KAUTH_PROCESS_SETID, 456 l->l_proc, NULL, NULL, NULL); 457 if (error != 0) { 458 proc_crmod_leave(cred, ncred, false); 459 return error; 460 } 461 462 /* Broadcast our credentials to the process and other LWPs. */ 463 proc_crmod_leave(ncred, cred, true); 464 return 0; 465 } 466 467 int 468 kauth_cred_getgroups(kauth_cred_t cred, gid_t *grbuf, size_t len, 469 enum uio_seg seg) 470 { 471 KASSERT(cred != NULL); 472 473 if (len > cred->cr_ngroups) 474 return EINVAL; 475 476 if (seg == UIO_USERSPACE) 477 return copyout(cred->cr_groups, grbuf, sizeof(*grbuf) * len); 478 memcpy(grbuf, cred->cr_groups, sizeof(*grbuf) * len); 479 480 return 0; 481 } 482 483 int 484 kauth_register_key(secmodel_t secmodel, kauth_key_t *result) 485 { 486 kauth_key_t k; 487 specificdata_key_t key; 488 int error; 489 490 KASSERT(result != NULL); 491 492 error = specificdata_key_create(kauth_domain, &key, NULL); 493 if (error) 494 return (error); 495 496 k = kmem_alloc(sizeof(*k), KM_SLEEP); 497 k->ks_secmodel = secmodel; 498 k->ks_key = key; 499 500 *result = k; 501 502 return (0); 503 } 504 505 int 506 kauth_deregister_key(kauth_key_t key) 507 { 508 KASSERT(key != NULL); 509 510 specificdata_key_delete(kauth_domain, key->ks_key); 511 kmem_free(key, sizeof(*key)); 512 513 return (0); 514 } 515 516 void * 517 kauth_cred_getdata(kauth_cred_t cred, kauth_key_t key) 518 { 519 KASSERT(cred != NULL); 520 KASSERT(key != NULL); 521 522 return (specificdata_getspecific(kauth_domain, &cred->cr_sd, 523 key->ks_key)); 524 } 525 526 void 527 kauth_cred_setdata(kauth_cred_t cred, kauth_key_t key, void *data) 528 { 529 KASSERT(cred != NULL); 530 KASSERT(key != NULL); 531 532 specificdata_setspecific(kauth_domain, &cred->cr_sd, key->ks_key, data); 533 } 534 535 /* 536 * Match uids in two credentials. 537 */ 538 int 539 kauth_cred_uidmatch(kauth_cred_t cred1, kauth_cred_t cred2) 540 { 541 KASSERT(cred1 != NULL); 542 KASSERT(cred2 != NULL); 543 544 if (cred1->cr_uid == cred2->cr_uid || 545 cred1->cr_euid == cred2->cr_uid || 546 cred1->cr_uid == cred2->cr_euid || 547 cred1->cr_euid == cred2->cr_euid) 548 return (1); 549 550 return (0); 551 } 552 553 u_int 554 kauth_cred_getrefcnt(kauth_cred_t cred) 555 { 556 KASSERT(cred != NULL); 557 558 return (cred->cr_refcnt); 559 } 560 561 /* 562 * Convert userland credentials (struct uucred) to kauth_cred_t. 563 * XXX: For NFS & puffs 564 */ 565 void 566 kauth_uucred_to_cred(kauth_cred_t cred, const struct uucred *uuc) 567 { 568 KASSERT(cred != NULL); 569 KASSERT(uuc != NULL); 570 571 cred->cr_refcnt = 1; 572 cred->cr_uid = uuc->cr_uid; 573 cred->cr_euid = uuc->cr_uid; 574 cred->cr_svuid = uuc->cr_uid; 575 cred->cr_gid = uuc->cr_gid; 576 cred->cr_egid = uuc->cr_gid; 577 cred->cr_svgid = uuc->cr_gid; 578 cred->cr_ngroups = min(uuc->cr_ngroups, NGROUPS); 579 kauth_cred_setgroups(cred, __UNCONST(uuc->cr_groups), 580 cred->cr_ngroups, -1, UIO_SYSSPACE); 581 } 582 583 /* 584 * Convert kauth_cred_t to userland credentials (struct uucred). 585 * XXX: For NFS & puffs 586 */ 587 void 588 kauth_cred_to_uucred(struct uucred *uuc, const kauth_cred_t cred) 589 { 590 KASSERT(cred != NULL); 591 KASSERT(uuc != NULL); 592 int ng; 593 594 ng = min(cred->cr_ngroups, NGROUPS); 595 uuc->cr_uid = cred->cr_euid; 596 uuc->cr_gid = cred->cr_egid; 597 uuc->cr_ngroups = ng; 598 kauth_cred_getgroups(cred, uuc->cr_groups, ng, UIO_SYSSPACE); 599 } 600 601 /* 602 * Compare kauth_cred_t and uucred credentials. 603 * XXX: Modelled after crcmp() for NFS. 604 */ 605 int 606 kauth_cred_uucmp(kauth_cred_t cred, const struct uucred *uuc) 607 { 608 KASSERT(cred != NULL); 609 KASSERT(uuc != NULL); 610 611 if (cred->cr_euid == uuc->cr_uid && 612 cred->cr_egid == uuc->cr_gid && 613 cred->cr_ngroups == (uint32_t)uuc->cr_ngroups) { 614 int i; 615 616 /* Check if all groups from uuc appear in cred. */ 617 for (i = 0; i < uuc->cr_ngroups; i++) { 618 int ismember; 619 620 ismember = 0; 621 if (kauth_cred_ismember_gid(cred, uuc->cr_groups[i], 622 &ismember) != 0 || !ismember) 623 return (1); 624 } 625 626 return (0); 627 } 628 629 return (1); 630 } 631 632 /* 633 * Make a struct ucred out of a kauth_cred_t. For compatibility. 634 */ 635 void 636 kauth_cred_toucred(kauth_cred_t cred, struct ki_ucred *uc) 637 { 638 KASSERT(cred != NULL); 639 KASSERT(uc != NULL); 640 641 uc->cr_ref = cred->cr_refcnt; 642 uc->cr_uid = cred->cr_euid; 643 uc->cr_gid = cred->cr_egid; 644 uc->cr_ngroups = min(cred->cr_ngroups, __arraycount(uc->cr_groups)); 645 memcpy(uc->cr_groups, cred->cr_groups, 646 uc->cr_ngroups * sizeof(uc->cr_groups[0])); 647 } 648 649 /* 650 * Make a struct pcred out of a kauth_cred_t. For compatibility. 651 */ 652 void 653 kauth_cred_topcred(kauth_cred_t cred, struct ki_pcred *pc) 654 { 655 KASSERT(cred != NULL); 656 KASSERT(pc != NULL); 657 658 pc->p_pad = NULL; 659 pc->p_ruid = cred->cr_uid; 660 pc->p_svuid = cred->cr_svuid; 661 pc->p_rgid = cred->cr_gid; 662 pc->p_svgid = cred->cr_svgid; 663 pc->p_refcnt = cred->cr_refcnt; 664 } 665 666 /* 667 * Return kauth_cred_t for the current LWP. 668 */ 669 kauth_cred_t 670 kauth_cred_get(void) 671 { 672 return (curlwp->l_cred); 673 } 674 675 /* 676 * Returns a scope matching the provided id. 677 * Requires the scope list lock to be held by the caller. 678 */ 679 static kauth_scope_t 680 kauth_ifindscope(const char *id) 681 { 682 kauth_scope_t scope; 683 684 KASSERT(rw_lock_held(&kauth_lock)); 685 686 scope = NULL; 687 SIMPLEQ_FOREACH(scope, &scope_list, next_scope) { 688 if (strcmp(scope->id, id) == 0) 689 break; 690 } 691 692 return (scope); 693 } 694 695 /* 696 * Register a new scope. 697 * 698 * id - identifier for the scope 699 * callback - the scope's default listener 700 * cookie - cookie to be passed to the listener(s) 701 */ 702 kauth_scope_t 703 kauth_register_scope(const char *id, kauth_scope_callback_t callback, 704 void *cookie) 705 { 706 kauth_scope_t scope; 707 kauth_listener_t listener = NULL; /* XXX gcc */ 708 709 /* Sanitize input */ 710 if (id == NULL) 711 return (NULL); 712 713 /* Allocate space for a new scope and listener. */ 714 scope = kmem_alloc(sizeof(*scope), KM_SLEEP); 715 if (scope == NULL) 716 return NULL; 717 if (callback != NULL) { 718 listener = kmem_alloc(sizeof(*listener), KM_SLEEP); 719 if (listener == NULL) { 720 kmem_free(scope, sizeof(*scope)); 721 return (NULL); 722 } 723 } 724 725 /* 726 * Acquire scope list lock. 727 */ 728 rw_enter(&kauth_lock, RW_WRITER); 729 730 /* Check we don't already have a scope with the same id */ 731 if (kauth_ifindscope(id) != NULL) { 732 rw_exit(&kauth_lock); 733 734 kmem_free(scope, sizeof(*scope)); 735 if (callback != NULL) 736 kmem_free(listener, sizeof(*listener)); 737 738 return (NULL); 739 } 740 741 /* Initialize new scope with parameters */ 742 scope->id = id; 743 scope->cookie = cookie; 744 scope->nlisteners = 1; 745 746 SIMPLEQ_INIT(&scope->listenq); 747 748 /* Add default listener */ 749 if (callback != NULL) { 750 listener->func = callback; 751 listener->scope = scope; 752 listener->refcnt = 0; 753 SIMPLEQ_INSERT_HEAD(&scope->listenq, listener, listener_next); 754 } 755 756 /* Insert scope to scopes list */ 757 SIMPLEQ_INSERT_TAIL(&scope_list, scope, next_scope); 758 759 rw_exit(&kauth_lock); 760 761 return (scope); 762 } 763 764 /* 765 * Initialize the kernel authorization subsystem. 766 * 767 * Initialize the scopes list lock. 768 * Create specificdata domain. 769 * Register the credentials scope, used in kauth(9) internally. 770 * Register built-in scopes: generic, system, process, network, machdep, device. 771 */ 772 void 773 kauth_init(void) 774 { 775 rw_init(&kauth_lock); 776 777 kauth_cred_cache = pool_cache_init(sizeof(struct kauth_cred), 778 coherency_unit, 0, 0, "kcredpl", NULL, IPL_NONE, 779 NULL, NULL, NULL); 780 781 /* Create specificdata domain. */ 782 kauth_domain = specificdata_domain_create(); 783 784 /* Register credentials scope. */ 785 kauth_builtin_scope_cred = 786 kauth_register_scope(KAUTH_SCOPE_CRED, NULL, NULL); 787 788 /* Register generic scope. */ 789 kauth_builtin_scope_generic = kauth_register_scope(KAUTH_SCOPE_GENERIC, 790 NULL, NULL); 791 792 /* Register system scope. */ 793 kauth_builtin_scope_system = kauth_register_scope(KAUTH_SCOPE_SYSTEM, 794 NULL, NULL); 795 796 /* Register process scope. */ 797 kauth_builtin_scope_process = kauth_register_scope(KAUTH_SCOPE_PROCESS, 798 NULL, NULL); 799 800 /* Register network scope. */ 801 kauth_builtin_scope_network = kauth_register_scope(KAUTH_SCOPE_NETWORK, 802 NULL, NULL); 803 804 /* Register machdep scope. */ 805 kauth_builtin_scope_machdep = kauth_register_scope(KAUTH_SCOPE_MACHDEP, 806 NULL, NULL); 807 808 /* Register device scope. */ 809 kauth_builtin_scope_device = kauth_register_scope(KAUTH_SCOPE_DEVICE, 810 NULL, NULL); 811 812 /* Register vnode scope. */ 813 kauth_builtin_scope_vnode = kauth_register_scope(KAUTH_SCOPE_VNODE, 814 NULL, NULL); 815 } 816 817 /* 818 * Deregister a scope. 819 * Requires scope list lock to be held by the caller. 820 * 821 * scope - the scope to deregister 822 */ 823 void 824 kauth_deregister_scope(kauth_scope_t scope) 825 { 826 if (scope != NULL) { 827 /* Remove scope from list */ 828 SIMPLEQ_REMOVE(&scope_list, scope, kauth_scope, next_scope); 829 kmem_free(scope, sizeof(*scope)); 830 } 831 } 832 833 /* 834 * Register a listener. 835 * 836 * id - scope identifier. 837 * callback - the callback routine for the listener. 838 * cookie - cookie to pass unmoidfied to the callback. 839 */ 840 kauth_listener_t 841 kauth_listen_scope(const char *id, kauth_scope_callback_t callback, 842 void *cookie) 843 { 844 kauth_scope_t scope; 845 kauth_listener_t listener; 846 847 listener = kmem_alloc(sizeof(*listener), KM_SLEEP); 848 if (listener == NULL) 849 return (NULL); 850 851 rw_enter(&kauth_lock, RW_WRITER); 852 853 /* 854 * Find scope struct. 855 */ 856 scope = kauth_ifindscope(id); 857 if (scope == NULL) { 858 rw_exit(&kauth_lock); 859 kmem_free(listener, sizeof(*listener)); 860 return (NULL); 861 } 862 863 /* Allocate listener */ 864 865 /* Initialize listener with parameters */ 866 listener->func = callback; 867 listener->refcnt = 0; 868 869 /* Add listener to scope */ 870 SIMPLEQ_INSERT_TAIL(&scope->listenq, listener, listener_next); 871 872 /* Raise number of listeners on scope. */ 873 scope->nlisteners++; 874 listener->scope = scope; 875 876 rw_exit(&kauth_lock); 877 878 return (listener); 879 } 880 881 /* 882 * Deregister a listener. 883 * 884 * listener - listener reference as returned from kauth_listen_scope(). 885 */ 886 void 887 kauth_unlisten_scope(kauth_listener_t listener) 888 { 889 890 if (listener != NULL) { 891 rw_enter(&kauth_lock, RW_WRITER); 892 SIMPLEQ_REMOVE(&listener->scope->listenq, listener, 893 kauth_listener, listener_next); 894 listener->scope->nlisteners--; 895 rw_exit(&kauth_lock); 896 kmem_free(listener, sizeof(*listener)); 897 } 898 } 899 900 /* 901 * Authorize a request. 902 * 903 * scope - the scope of the request as defined by KAUTH_SCOPE_* or as 904 * returned from kauth_register_scope(). 905 * credential - credentials of the user ("actor") making the request. 906 * action - request identifier. 907 * arg[0-3] - passed unmodified to listener(s). 908 * 909 * Returns the aggregated result: 910 * - KAUTH_RESULT_ALLOW if there is at least one KAUTH_RESULT_ALLOW and 911 * zero KAUTH_DESULT_DENY 912 * - KAUTH_RESULT_DENY if there is at least one KAUTH_RESULT_DENY 913 * - KAUTH_RESULT_DEFER if there is nothing but KAUTH_RESULT_DEFER 914 */ 915 static int 916 kauth_authorize_action_internal(kauth_scope_t scope, kauth_cred_t cred, 917 kauth_action_t action, void *arg0, void *arg1, void *arg2, void *arg3) 918 { 919 kauth_listener_t listener; 920 int error, allow, fail; 921 922 KASSERT(cred != NULL); 923 KASSERT(action != 0); 924 925 /* Short-circuit requests coming from the kernel. */ 926 if (cred == NOCRED || cred == FSCRED) 927 return (0); 928 929 KASSERT(scope != NULL); 930 931 fail = 0; 932 allow = 0; 933 934 /* rw_enter(&kauth_lock, RW_READER); XXX not yet */ 935 SIMPLEQ_FOREACH(listener, &scope->listenq, listener_next) { 936 error = listener->func(cred, action, scope->cookie, arg0, 937 arg1, arg2, arg3); 938 939 if (error == KAUTH_RESULT_ALLOW) 940 allow = 1; 941 else if (error == KAUTH_RESULT_DENY) 942 fail = 1; 943 } 944 /* rw_exit(&kauth_lock); */ 945 946 if (fail) 947 return (KAUTH_RESULT_DENY); 948 949 if (allow) 950 return (KAUTH_RESULT_ALLOW); 951 952 return (KAUTH_RESULT_DEFER); 953 }; 954 955 int 956 kauth_authorize_action(kauth_scope_t scope, kauth_cred_t cred, 957 kauth_action_t action, void *arg0, void *arg1, void *arg2, void *arg3) 958 { 959 int r; 960 961 r = kauth_authorize_action_internal(scope, cred, action, arg0, arg1, 962 arg2, arg3); 963 964 if (r == KAUTH_RESULT_DENY) 965 return (EPERM); 966 967 if (r == KAUTH_RESULT_ALLOW) 968 return (0); 969 970 if (secmodel_nsecmodels() == 0) 971 return (0); 972 973 return (EPERM); 974 } 975 976 /* 977 * Generic scope authorization wrapper. 978 */ 979 int 980 kauth_authorize_generic(kauth_cred_t cred, kauth_action_t action, void *arg0) 981 { 982 return (kauth_authorize_action(kauth_builtin_scope_generic, cred, 983 action, arg0, NULL, NULL, NULL)); 984 } 985 986 /* 987 * System scope authorization wrapper. 988 */ 989 int 990 kauth_authorize_system(kauth_cred_t cred, kauth_action_t action, 991 enum kauth_system_req req, void *arg1, void *arg2, void *arg3) 992 { 993 return (kauth_authorize_action(kauth_builtin_scope_system, cred, 994 action, (void *)req, arg1, arg2, arg3)); 995 } 996 997 /* 998 * Process scope authorization wrapper. 999 */ 1000 int 1001 kauth_authorize_process(kauth_cred_t cred, kauth_action_t action, 1002 struct proc *p, void *arg1, void *arg2, void *arg3) 1003 { 1004 return (kauth_authorize_action(kauth_builtin_scope_process, cred, 1005 action, p, arg1, arg2, arg3)); 1006 } 1007 1008 /* 1009 * Network scope authorization wrapper. 1010 */ 1011 int 1012 kauth_authorize_network(kauth_cred_t cred, kauth_action_t action, 1013 enum kauth_network_req req, void *arg1, void *arg2, void *arg3) 1014 { 1015 return (kauth_authorize_action(kauth_builtin_scope_network, cred, 1016 action, (void *)req, arg1, arg2, arg3)); 1017 } 1018 1019 int 1020 kauth_authorize_machdep(kauth_cred_t cred, kauth_action_t action, 1021 void *arg0, void *arg1, void *arg2, void *arg3) 1022 { 1023 return (kauth_authorize_action(kauth_builtin_scope_machdep, cred, 1024 action, arg0, arg1, arg2, arg3)); 1025 } 1026 1027 int 1028 kauth_authorize_device(kauth_cred_t cred, kauth_action_t action, 1029 void *arg0, void *arg1, void *arg2, void *arg3) 1030 { 1031 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1032 action, arg0, arg1, arg2, arg3)); 1033 } 1034 1035 int 1036 kauth_authorize_device_tty(kauth_cred_t cred, kauth_action_t action, 1037 struct tty *tty) 1038 { 1039 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1040 action, tty, NULL, NULL, NULL)); 1041 } 1042 1043 int 1044 kauth_authorize_device_spec(kauth_cred_t cred, enum kauth_device_req req, 1045 struct vnode *vp) 1046 { 1047 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1048 KAUTH_DEVICE_RAWIO_SPEC, (void *)req, vp, NULL, NULL)); 1049 } 1050 1051 int 1052 kauth_authorize_device_passthru(kauth_cred_t cred, dev_t dev, u_long bits, 1053 void *data) 1054 { 1055 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1056 KAUTH_DEVICE_RAWIO_PASSTHRU, (void *)bits, (void *)(u_long)dev, 1057 data, NULL)); 1058 } 1059 1060 kauth_action_t 1061 kauth_mode_to_action(mode_t mode) 1062 { 1063 kauth_action_t action = 0; 1064 1065 if (mode & VREAD) 1066 action |= KAUTH_VNODE_READ_DATA; 1067 if (mode & VWRITE) 1068 action |= KAUTH_VNODE_WRITE_DATA; 1069 if (mode & VEXEC) 1070 action |= KAUTH_VNODE_EXECUTE; 1071 1072 return action; 1073 } 1074 1075 kauth_action_t 1076 kauth_access_action(mode_t access_mode, enum vtype vn_type, mode_t file_mode) 1077 { 1078 kauth_action_t action = kauth_mode_to_action(access_mode); 1079 1080 if (FS_OBJECT_CAN_EXEC(vn_type, file_mode)) 1081 action |= KAUTH_VNODE_IS_EXEC; 1082 1083 return action; 1084 } 1085 1086 kauth_action_t 1087 kauth_extattr_action(mode_t access_mode) 1088 { 1089 kauth_action_t action = 0; 1090 1091 if (access_mode & VREAD) 1092 action |= KAUTH_VNODE_READ_EXTATTRIBUTES; 1093 if (access_mode & VWRITE) 1094 action |= KAUTH_VNODE_WRITE_EXTATTRIBUTES; 1095 1096 return action; 1097 } 1098 1099 int 1100 kauth_authorize_vnode(kauth_cred_t cred, kauth_action_t action, 1101 struct vnode *vp, struct vnode *dvp, int fs_decision) 1102 { 1103 int error; 1104 1105 error = kauth_authorize_action_internal(kauth_builtin_scope_vnode, cred, 1106 action, vp, dvp, NULL, NULL); 1107 1108 if (error == KAUTH_RESULT_DENY) 1109 return (EACCES); 1110 1111 if (error == KAUTH_RESULT_ALLOW) 1112 return (0); 1113 1114 /* 1115 * If the file-system does not support decision-before-action, we can 1116 * only short-circuit the operation (deny). If we're here, it means no 1117 * listener denied it, so our only alternative is to supposedly-allow 1118 * it and let the file-system have the last word. 1119 */ 1120 if (fs_decision == KAUTH_VNODE_REMOTEFS) 1121 return (0); 1122 1123 return (fs_decision); 1124 } 1125 1126 static int 1127 kauth_cred_hook(kauth_cred_t cred, kauth_action_t action, void *arg0, 1128 void *arg1) 1129 { 1130 int r; 1131 1132 r = kauth_authorize_action(kauth_builtin_scope_cred, cred, action, 1133 arg0, arg1, NULL, NULL); 1134 1135 #ifdef DIAGNOSTIC 1136 if (!SIMPLEQ_EMPTY(&kauth_builtin_scope_cred->listenq)) 1137 KASSERT(r == 0); 1138 #endif /* DIAGNOSTIC */ 1139 1140 return (r); 1141 } 1142