1 /* $NetBSD: kern_auth.c,v 1.72 2012/09/16 14:35:26 christos 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.72 2012/09/16 14:35:26 christos 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 separate 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 void 264 kauth_proc_chroot(kauth_cred_t cred, struct cwdinfo *cwdi) 265 { 266 kauth_cred_hook(cred, KAUTH_CRED_CHROOT, cwdi, NULL); 267 } 268 269 uid_t 270 kauth_cred_getuid(kauth_cred_t cred) 271 { 272 KASSERT(cred != NULL); 273 274 return (cred->cr_uid); 275 } 276 277 uid_t 278 kauth_cred_geteuid(kauth_cred_t cred) 279 { 280 KASSERT(cred != NULL); 281 282 return (cred->cr_euid); 283 } 284 285 uid_t 286 kauth_cred_getsvuid(kauth_cred_t cred) 287 { 288 KASSERT(cred != NULL); 289 290 return (cred->cr_svuid); 291 } 292 293 gid_t 294 kauth_cred_getgid(kauth_cred_t cred) 295 { 296 KASSERT(cred != NULL); 297 298 return (cred->cr_gid); 299 } 300 301 gid_t 302 kauth_cred_getegid(kauth_cred_t cred) 303 { 304 KASSERT(cred != NULL); 305 306 return (cred->cr_egid); 307 } 308 309 gid_t 310 kauth_cred_getsvgid(kauth_cred_t cred) 311 { 312 KASSERT(cred != NULL); 313 314 return (cred->cr_svgid); 315 } 316 317 void 318 kauth_cred_setuid(kauth_cred_t cred, uid_t uid) 319 { 320 KASSERT(cred != NULL); 321 KASSERT(cred->cr_refcnt == 1); 322 323 cred->cr_uid = uid; 324 } 325 326 void 327 kauth_cred_seteuid(kauth_cred_t cred, uid_t uid) 328 { 329 KASSERT(cred != NULL); 330 KASSERT(cred->cr_refcnt == 1); 331 332 cred->cr_euid = uid; 333 } 334 335 void 336 kauth_cred_setsvuid(kauth_cred_t cred, uid_t uid) 337 { 338 KASSERT(cred != NULL); 339 KASSERT(cred->cr_refcnt == 1); 340 341 cred->cr_svuid = uid; 342 } 343 344 void 345 kauth_cred_setgid(kauth_cred_t cred, gid_t gid) 346 { 347 KASSERT(cred != NULL); 348 KASSERT(cred->cr_refcnt == 1); 349 350 cred->cr_gid = gid; 351 } 352 353 void 354 kauth_cred_setegid(kauth_cred_t cred, gid_t gid) 355 { 356 KASSERT(cred != NULL); 357 KASSERT(cred->cr_refcnt == 1); 358 359 cred->cr_egid = gid; 360 } 361 362 void 363 kauth_cred_setsvgid(kauth_cred_t cred, gid_t gid) 364 { 365 KASSERT(cred != NULL); 366 KASSERT(cred->cr_refcnt == 1); 367 368 cred->cr_svgid = gid; 369 } 370 371 /* Checks if gid is a member of the groups in cred. */ 372 int 373 kauth_cred_ismember_gid(kauth_cred_t cred, gid_t gid, int *resultp) 374 { 375 uint32_t i; 376 377 KASSERT(cred != NULL); 378 KASSERT(resultp != NULL); 379 380 *resultp = 0; 381 382 for (i = 0; i < cred->cr_ngroups; i++) 383 if (cred->cr_groups[i] == gid) { 384 *resultp = 1; 385 break; 386 } 387 388 return (0); 389 } 390 391 u_int 392 kauth_cred_ngroups(kauth_cred_t cred) 393 { 394 KASSERT(cred != NULL); 395 396 return (cred->cr_ngroups); 397 } 398 399 /* 400 * Return the group at index idx from the groups in cred. 401 */ 402 gid_t 403 kauth_cred_group(kauth_cred_t cred, u_int idx) 404 { 405 KASSERT(cred != NULL); 406 KASSERT(idx < cred->cr_ngroups); 407 408 return (cred->cr_groups[idx]); 409 } 410 411 /* XXX elad: gmuid is unused for now. */ 412 int 413 kauth_cred_setgroups(kauth_cred_t cred, const gid_t *grbuf, size_t len, 414 uid_t gmuid, enum uio_seg seg) 415 { 416 int error = 0; 417 418 KASSERT(cred != NULL); 419 KASSERT(cred->cr_refcnt == 1); 420 421 if (len > __arraycount(cred->cr_groups)) 422 return EINVAL; 423 424 if (len) { 425 if (seg == UIO_SYSSPACE) { 426 memcpy(cred->cr_groups, grbuf, 427 len * sizeof(cred->cr_groups[0])); 428 } else { 429 error = copyin(grbuf, cred->cr_groups, 430 len * sizeof(cred->cr_groups[0])); 431 if (error != 0) 432 len = 0; 433 } 434 } 435 memset(cred->cr_groups + len, 0xff, 436 sizeof(cred->cr_groups) - (len * sizeof(cred->cr_groups[0]))); 437 438 cred->cr_ngroups = len; 439 440 return error; 441 } 442 443 /* This supports sys_setgroups() */ 444 int 445 kauth_proc_setgroups(struct lwp *l, kauth_cred_t ncred) 446 { 447 kauth_cred_t cred; 448 int error; 449 450 /* 451 * At this point we could delete duplicate groups from ncred, 452 * and plausibly sort the list - but in general the later is 453 * a bad idea. 454 */ 455 proc_crmod_enter(); 456 /* Maybe we should use curproc here ? */ 457 cred = l->l_proc->p_cred; 458 459 kauth_cred_clone1(cred, ncred, false); 460 461 error = kauth_authorize_process(cred, KAUTH_PROCESS_SETID, 462 l->l_proc, NULL, NULL, NULL); 463 if (error != 0) { 464 proc_crmod_leave(cred, ncred, false); 465 return error; 466 } 467 468 /* Broadcast our credentials to the process and other LWPs. */ 469 proc_crmod_leave(ncred, cred, true); 470 return 0; 471 } 472 473 int 474 kauth_cred_getgroups(kauth_cred_t cred, gid_t *grbuf, size_t len, 475 enum uio_seg seg) 476 { 477 KASSERT(cred != NULL); 478 479 if (len > cred->cr_ngroups) 480 return EINVAL; 481 482 if (seg == UIO_USERSPACE) 483 return copyout(cred->cr_groups, grbuf, sizeof(*grbuf) * len); 484 memcpy(grbuf, cred->cr_groups, sizeof(*grbuf) * len); 485 486 return 0; 487 } 488 489 int 490 kauth_register_key(secmodel_t secmodel, kauth_key_t *result) 491 { 492 kauth_key_t k; 493 specificdata_key_t key; 494 int error; 495 496 KASSERT(result != NULL); 497 498 error = specificdata_key_create(kauth_domain, &key, NULL); 499 if (error) 500 return (error); 501 502 k = kmem_alloc(sizeof(*k), KM_SLEEP); 503 k->ks_secmodel = secmodel; 504 k->ks_key = key; 505 506 *result = k; 507 508 return (0); 509 } 510 511 int 512 kauth_deregister_key(kauth_key_t key) 513 { 514 KASSERT(key != NULL); 515 516 specificdata_key_delete(kauth_domain, key->ks_key); 517 kmem_free(key, sizeof(*key)); 518 519 return (0); 520 } 521 522 void * 523 kauth_cred_getdata(kauth_cred_t cred, kauth_key_t key) 524 { 525 KASSERT(cred != NULL); 526 KASSERT(key != NULL); 527 528 return (specificdata_getspecific(kauth_domain, &cred->cr_sd, 529 key->ks_key)); 530 } 531 532 void 533 kauth_cred_setdata(kauth_cred_t cred, kauth_key_t key, void *data) 534 { 535 KASSERT(cred != NULL); 536 KASSERT(key != NULL); 537 538 specificdata_setspecific(kauth_domain, &cred->cr_sd, key->ks_key, data); 539 } 540 541 /* 542 * Match uids in two credentials. 543 */ 544 int 545 kauth_cred_uidmatch(kauth_cred_t cred1, kauth_cred_t cred2) 546 { 547 KASSERT(cred1 != NULL); 548 KASSERT(cred2 != NULL); 549 550 if (cred1->cr_uid == cred2->cr_uid || 551 cred1->cr_euid == cred2->cr_uid || 552 cred1->cr_uid == cred2->cr_euid || 553 cred1->cr_euid == cred2->cr_euid) 554 return (1); 555 556 return (0); 557 } 558 559 u_int 560 kauth_cred_getrefcnt(kauth_cred_t cred) 561 { 562 KASSERT(cred != NULL); 563 564 return (cred->cr_refcnt); 565 } 566 567 /* 568 * Convert userland credentials (struct uucred) to kauth_cred_t. 569 * XXX: For NFS & puffs 570 */ 571 void 572 kauth_uucred_to_cred(kauth_cred_t cred, const struct uucred *uuc) 573 { 574 KASSERT(cred != NULL); 575 KASSERT(uuc != NULL); 576 577 cred->cr_refcnt = 1; 578 cred->cr_uid = uuc->cr_uid; 579 cred->cr_euid = uuc->cr_uid; 580 cred->cr_svuid = uuc->cr_uid; 581 cred->cr_gid = uuc->cr_gid; 582 cred->cr_egid = uuc->cr_gid; 583 cred->cr_svgid = uuc->cr_gid; 584 cred->cr_ngroups = min(uuc->cr_ngroups, NGROUPS); 585 kauth_cred_setgroups(cred, __UNCONST(uuc->cr_groups), 586 cred->cr_ngroups, -1, UIO_SYSSPACE); 587 } 588 589 /* 590 * Convert kauth_cred_t to userland credentials (struct uucred). 591 * XXX: For NFS & puffs 592 */ 593 void 594 kauth_cred_to_uucred(struct uucred *uuc, const kauth_cred_t cred) 595 { 596 KASSERT(cred != NULL); 597 KASSERT(uuc != NULL); 598 int ng; 599 600 ng = min(cred->cr_ngroups, NGROUPS); 601 uuc->cr_uid = cred->cr_euid; 602 uuc->cr_gid = cred->cr_egid; 603 uuc->cr_ngroups = ng; 604 kauth_cred_getgroups(cred, uuc->cr_groups, ng, UIO_SYSSPACE); 605 } 606 607 /* 608 * Compare kauth_cred_t and uucred credentials. 609 * XXX: Modelled after crcmp() for NFS. 610 */ 611 int 612 kauth_cred_uucmp(kauth_cred_t cred, const struct uucred *uuc) 613 { 614 KASSERT(cred != NULL); 615 KASSERT(uuc != NULL); 616 617 if (cred->cr_euid == uuc->cr_uid && 618 cred->cr_egid == uuc->cr_gid && 619 cred->cr_ngroups == (uint32_t)uuc->cr_ngroups) { 620 int i; 621 622 /* Check if all groups from uuc appear in cred. */ 623 for (i = 0; i < uuc->cr_ngroups; i++) { 624 int ismember; 625 626 ismember = 0; 627 if (kauth_cred_ismember_gid(cred, uuc->cr_groups[i], 628 &ismember) != 0 || !ismember) 629 return (1); 630 } 631 632 return (0); 633 } 634 635 return (1); 636 } 637 638 /* 639 * Make a struct ucred out of a kauth_cred_t. For compatibility. 640 */ 641 void 642 kauth_cred_toucred(kauth_cred_t cred, struct ki_ucred *uc) 643 { 644 KASSERT(cred != NULL); 645 KASSERT(uc != NULL); 646 647 uc->cr_ref = cred->cr_refcnt; 648 uc->cr_uid = cred->cr_euid; 649 uc->cr_gid = cred->cr_egid; 650 uc->cr_ngroups = min(cred->cr_ngroups, __arraycount(uc->cr_groups)); 651 memcpy(uc->cr_groups, cred->cr_groups, 652 uc->cr_ngroups * sizeof(uc->cr_groups[0])); 653 } 654 655 /* 656 * Make a struct pcred out of a kauth_cred_t. For compatibility. 657 */ 658 void 659 kauth_cred_topcred(kauth_cred_t cred, struct ki_pcred *pc) 660 { 661 KASSERT(cred != NULL); 662 KASSERT(pc != NULL); 663 664 pc->p_pad = NULL; 665 pc->p_ruid = cred->cr_uid; 666 pc->p_svuid = cred->cr_svuid; 667 pc->p_rgid = cred->cr_gid; 668 pc->p_svgid = cred->cr_svgid; 669 pc->p_refcnt = cred->cr_refcnt; 670 } 671 672 /* 673 * Return kauth_cred_t for the current LWP. 674 */ 675 kauth_cred_t 676 kauth_cred_get(void) 677 { 678 return (curlwp->l_cred); 679 } 680 681 /* 682 * Returns a scope matching the provided id. 683 * Requires the scope list lock to be held by the caller. 684 */ 685 static kauth_scope_t 686 kauth_ifindscope(const char *id) 687 { 688 kauth_scope_t scope; 689 690 KASSERT(rw_lock_held(&kauth_lock)); 691 692 scope = NULL; 693 SIMPLEQ_FOREACH(scope, &scope_list, next_scope) { 694 if (strcmp(scope->id, id) == 0) 695 break; 696 } 697 698 return (scope); 699 } 700 701 /* 702 * Register a new scope. 703 * 704 * id - identifier for the scope 705 * callback - the scope's default listener 706 * cookie - cookie to be passed to the listener(s) 707 */ 708 kauth_scope_t 709 kauth_register_scope(const char *id, kauth_scope_callback_t callback, 710 void *cookie) 711 { 712 kauth_scope_t scope; 713 kauth_listener_t listener = NULL; /* XXX gcc */ 714 715 /* Sanitize input */ 716 if (id == NULL) 717 return (NULL); 718 719 /* Allocate space for a new scope and listener. */ 720 scope = kmem_alloc(sizeof(*scope), KM_SLEEP); 721 if (scope == NULL) 722 return NULL; 723 if (callback != NULL) { 724 listener = kmem_alloc(sizeof(*listener), KM_SLEEP); 725 if (listener == NULL) { 726 kmem_free(scope, sizeof(*scope)); 727 return (NULL); 728 } 729 } 730 731 /* 732 * Acquire scope list lock. 733 */ 734 rw_enter(&kauth_lock, RW_WRITER); 735 736 /* Check we don't already have a scope with the same id */ 737 if (kauth_ifindscope(id) != NULL) { 738 rw_exit(&kauth_lock); 739 740 kmem_free(scope, sizeof(*scope)); 741 if (callback != NULL) 742 kmem_free(listener, sizeof(*listener)); 743 744 return (NULL); 745 } 746 747 /* Initialize new scope with parameters */ 748 scope->id = id; 749 scope->cookie = cookie; 750 scope->nlisteners = 1; 751 752 SIMPLEQ_INIT(&scope->listenq); 753 754 /* Add default listener */ 755 if (callback != NULL) { 756 listener->func = callback; 757 listener->scope = scope; 758 listener->refcnt = 0; 759 SIMPLEQ_INSERT_HEAD(&scope->listenq, listener, listener_next); 760 } 761 762 /* Insert scope to scopes list */ 763 SIMPLEQ_INSERT_TAIL(&scope_list, scope, next_scope); 764 765 rw_exit(&kauth_lock); 766 767 return (scope); 768 } 769 770 /* 771 * Initialize the kernel authorization subsystem. 772 * 773 * Initialize the scopes list lock. 774 * Create specificdata domain. 775 * Register the credentials scope, used in kauth(9) internally. 776 * Register built-in scopes: generic, system, process, network, machdep, device. 777 */ 778 void 779 kauth_init(void) 780 { 781 rw_init(&kauth_lock); 782 783 kauth_cred_cache = pool_cache_init(sizeof(struct kauth_cred), 784 coherency_unit, 0, 0, "kcredpl", NULL, IPL_NONE, 785 NULL, NULL, NULL); 786 787 /* Create specificdata domain. */ 788 kauth_domain = specificdata_domain_create(); 789 790 /* Register credentials scope. */ 791 kauth_builtin_scope_cred = 792 kauth_register_scope(KAUTH_SCOPE_CRED, NULL, NULL); 793 794 /* Register generic scope. */ 795 kauth_builtin_scope_generic = kauth_register_scope(KAUTH_SCOPE_GENERIC, 796 NULL, NULL); 797 798 /* Register system scope. */ 799 kauth_builtin_scope_system = kauth_register_scope(KAUTH_SCOPE_SYSTEM, 800 NULL, NULL); 801 802 /* Register process scope. */ 803 kauth_builtin_scope_process = kauth_register_scope(KAUTH_SCOPE_PROCESS, 804 NULL, NULL); 805 806 /* Register network scope. */ 807 kauth_builtin_scope_network = kauth_register_scope(KAUTH_SCOPE_NETWORK, 808 NULL, NULL); 809 810 /* Register machdep scope. */ 811 kauth_builtin_scope_machdep = kauth_register_scope(KAUTH_SCOPE_MACHDEP, 812 NULL, NULL); 813 814 /* Register device scope. */ 815 kauth_builtin_scope_device = kauth_register_scope(KAUTH_SCOPE_DEVICE, 816 NULL, NULL); 817 818 /* Register vnode scope. */ 819 kauth_builtin_scope_vnode = kauth_register_scope(KAUTH_SCOPE_VNODE, 820 NULL, NULL); 821 } 822 823 /* 824 * Deregister a scope. 825 * Requires scope list lock to be held by the caller. 826 * 827 * scope - the scope to deregister 828 */ 829 void 830 kauth_deregister_scope(kauth_scope_t scope) 831 { 832 if (scope != NULL) { 833 /* Remove scope from list */ 834 SIMPLEQ_REMOVE(&scope_list, scope, kauth_scope, next_scope); 835 kmem_free(scope, sizeof(*scope)); 836 } 837 } 838 839 /* 840 * Register a listener. 841 * 842 * id - scope identifier. 843 * callback - the callback routine for the listener. 844 * cookie - cookie to pass unmoidfied to the callback. 845 */ 846 kauth_listener_t 847 kauth_listen_scope(const char *id, kauth_scope_callback_t callback, 848 void *cookie) 849 { 850 kauth_scope_t scope; 851 kauth_listener_t listener; 852 853 listener = kmem_alloc(sizeof(*listener), KM_SLEEP); 854 if (listener == NULL) 855 return (NULL); 856 857 rw_enter(&kauth_lock, RW_WRITER); 858 859 /* 860 * Find scope struct. 861 */ 862 scope = kauth_ifindscope(id); 863 if (scope == NULL) { 864 rw_exit(&kauth_lock); 865 kmem_free(listener, sizeof(*listener)); 866 return (NULL); 867 } 868 869 /* Allocate listener */ 870 871 /* Initialize listener with parameters */ 872 listener->func = callback; 873 listener->refcnt = 0; 874 875 /* Add listener to scope */ 876 SIMPLEQ_INSERT_TAIL(&scope->listenq, listener, listener_next); 877 878 /* Raise number of listeners on scope. */ 879 scope->nlisteners++; 880 listener->scope = scope; 881 882 rw_exit(&kauth_lock); 883 884 return (listener); 885 } 886 887 /* 888 * Deregister a listener. 889 * 890 * listener - listener reference as returned from kauth_listen_scope(). 891 */ 892 void 893 kauth_unlisten_scope(kauth_listener_t listener) 894 { 895 896 if (listener != NULL) { 897 rw_enter(&kauth_lock, RW_WRITER); 898 SIMPLEQ_REMOVE(&listener->scope->listenq, listener, 899 kauth_listener, listener_next); 900 listener->scope->nlisteners--; 901 rw_exit(&kauth_lock); 902 kmem_free(listener, sizeof(*listener)); 903 } 904 } 905 906 /* 907 * Authorize a request. 908 * 909 * scope - the scope of the request as defined by KAUTH_SCOPE_* or as 910 * returned from kauth_register_scope(). 911 * credential - credentials of the user ("actor") making the request. 912 * action - request identifier. 913 * arg[0-3] - passed unmodified to listener(s). 914 * 915 * Returns the aggregated result: 916 * - KAUTH_RESULT_ALLOW if there is at least one KAUTH_RESULT_ALLOW and 917 * zero KAUTH_DESULT_DENY 918 * - KAUTH_RESULT_DENY if there is at least one KAUTH_RESULT_DENY 919 * - KAUTH_RESULT_DEFER if there is nothing but KAUTH_RESULT_DEFER 920 */ 921 static int 922 kauth_authorize_action_internal(kauth_scope_t scope, kauth_cred_t cred, 923 kauth_action_t action, void *arg0, void *arg1, void *arg2, void *arg3) 924 { 925 kauth_listener_t listener; 926 int error, allow, fail; 927 928 KASSERT(cred != NULL); 929 KASSERT(action != 0); 930 931 /* Short-circuit requests coming from the kernel. */ 932 if (cred == NOCRED || cred == FSCRED) 933 return KAUTH_RESULT_ALLOW; 934 935 KASSERT(scope != NULL); 936 937 fail = 0; 938 allow = 0; 939 940 /* rw_enter(&kauth_lock, RW_READER); XXX not yet */ 941 SIMPLEQ_FOREACH(listener, &scope->listenq, listener_next) { 942 error = listener->func(cred, action, scope->cookie, arg0, 943 arg1, arg2, arg3); 944 945 if (error == KAUTH_RESULT_ALLOW) 946 allow = 1; 947 else if (error == KAUTH_RESULT_DENY) 948 fail = 1; 949 } 950 /* rw_exit(&kauth_lock); */ 951 952 if (fail) 953 return (KAUTH_RESULT_DENY); 954 955 if (allow) 956 return (KAUTH_RESULT_ALLOW); 957 958 return (KAUTH_RESULT_DEFER); 959 }; 960 961 int 962 kauth_authorize_action(kauth_scope_t scope, kauth_cred_t cred, 963 kauth_action_t action, void *arg0, void *arg1, void *arg2, void *arg3) 964 { 965 int r; 966 967 r = kauth_authorize_action_internal(scope, cred, action, arg0, arg1, 968 arg2, arg3); 969 970 if (r == KAUTH_RESULT_DENY) 971 return (EPERM); 972 973 if (r == KAUTH_RESULT_ALLOW) 974 return (0); 975 976 if (secmodel_nsecmodels() == 0) 977 return (0); 978 979 return (EPERM); 980 } 981 982 /* 983 * Generic scope authorization wrapper. 984 */ 985 int 986 kauth_authorize_generic(kauth_cred_t cred, kauth_action_t action, void *arg0) 987 { 988 return (kauth_authorize_action(kauth_builtin_scope_generic, cred, 989 action, arg0, NULL, NULL, NULL)); 990 } 991 992 /* 993 * System scope authorization wrapper. 994 */ 995 int 996 kauth_authorize_system(kauth_cred_t cred, kauth_action_t action, 997 enum kauth_system_req req, void *arg1, void *arg2, void *arg3) 998 { 999 return (kauth_authorize_action(kauth_builtin_scope_system, cred, 1000 action, (void *)req, arg1, arg2, arg3)); 1001 } 1002 1003 /* 1004 * Process scope authorization wrapper. 1005 */ 1006 int 1007 kauth_authorize_process(kauth_cred_t cred, kauth_action_t action, 1008 struct proc *p, void *arg1, void *arg2, void *arg3) 1009 { 1010 return (kauth_authorize_action(kauth_builtin_scope_process, cred, 1011 action, p, arg1, arg2, arg3)); 1012 } 1013 1014 /* 1015 * Network scope authorization wrapper. 1016 */ 1017 int 1018 kauth_authorize_network(kauth_cred_t cred, kauth_action_t action, 1019 enum kauth_network_req req, void *arg1, void *arg2, void *arg3) 1020 { 1021 return (kauth_authorize_action(kauth_builtin_scope_network, cred, 1022 action, (void *)req, arg1, arg2, arg3)); 1023 } 1024 1025 int 1026 kauth_authorize_machdep(kauth_cred_t cred, kauth_action_t action, 1027 void *arg0, void *arg1, void *arg2, void *arg3) 1028 { 1029 return (kauth_authorize_action(kauth_builtin_scope_machdep, cred, 1030 action, arg0, arg1, arg2, arg3)); 1031 } 1032 1033 int 1034 kauth_authorize_device(kauth_cred_t cred, kauth_action_t action, 1035 void *arg0, void *arg1, void *arg2, void *arg3) 1036 { 1037 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1038 action, arg0, arg1, arg2, arg3)); 1039 } 1040 1041 int 1042 kauth_authorize_device_tty(kauth_cred_t cred, kauth_action_t action, 1043 struct tty *tty) 1044 { 1045 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1046 action, tty, NULL, NULL, NULL)); 1047 } 1048 1049 int 1050 kauth_authorize_device_spec(kauth_cred_t cred, enum kauth_device_req req, 1051 struct vnode *vp) 1052 { 1053 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1054 KAUTH_DEVICE_RAWIO_SPEC, (void *)req, vp, NULL, NULL)); 1055 } 1056 1057 int 1058 kauth_authorize_device_passthru(kauth_cred_t cred, dev_t dev, u_long bits, 1059 void *data) 1060 { 1061 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1062 KAUTH_DEVICE_RAWIO_PASSTHRU, (void *)bits, (void *)(u_long)dev, 1063 data, NULL)); 1064 } 1065 1066 kauth_action_t 1067 kauth_mode_to_action(mode_t mode) 1068 { 1069 kauth_action_t action = 0; 1070 1071 if (mode & VREAD) 1072 action |= KAUTH_VNODE_READ_DATA; 1073 if (mode & VWRITE) 1074 action |= KAUTH_VNODE_WRITE_DATA; 1075 if (mode & VEXEC) 1076 action |= KAUTH_VNODE_EXECUTE; 1077 1078 return action; 1079 } 1080 1081 kauth_action_t 1082 kauth_access_action(mode_t access_mode, enum vtype vn_type, mode_t file_mode) 1083 { 1084 kauth_action_t action = kauth_mode_to_action(access_mode); 1085 1086 if (FS_OBJECT_CAN_EXEC(vn_type, file_mode)) 1087 action |= KAUTH_VNODE_IS_EXEC; 1088 1089 return action; 1090 } 1091 1092 kauth_action_t 1093 kauth_extattr_action(mode_t access_mode) 1094 { 1095 kauth_action_t action = 0; 1096 1097 if (access_mode & VREAD) 1098 action |= KAUTH_VNODE_READ_EXTATTRIBUTES; 1099 if (access_mode & VWRITE) 1100 action |= KAUTH_VNODE_WRITE_EXTATTRIBUTES; 1101 1102 return action; 1103 } 1104 1105 int 1106 kauth_authorize_vnode(kauth_cred_t cred, kauth_action_t action, 1107 struct vnode *vp, struct vnode *dvp, int fs_decision) 1108 { 1109 int error; 1110 1111 error = kauth_authorize_action_internal(kauth_builtin_scope_vnode, cred, 1112 action, vp, dvp, NULL, NULL); 1113 1114 if (error == KAUTH_RESULT_DENY) 1115 return (EACCES); 1116 1117 if (error == KAUTH_RESULT_ALLOW) 1118 return (0); 1119 1120 /* 1121 * If the file-system does not support decision-before-action, we can 1122 * only short-circuit the operation (deny). If we're here, it means no 1123 * listener denied it, so our only alternative is to supposedly-allow 1124 * it and let the file-system have the last word. 1125 */ 1126 if (fs_decision == KAUTH_VNODE_REMOTEFS) 1127 return (0); 1128 1129 return (fs_decision); 1130 } 1131 1132 static int 1133 kauth_cred_hook(kauth_cred_t cred, kauth_action_t action, void *arg0, 1134 void *arg1) 1135 { 1136 int r; 1137 1138 r = kauth_authorize_action(kauth_builtin_scope_cred, cred, action, 1139 arg0, arg1, NULL, NULL); 1140 1141 #ifdef DIAGNOSTIC 1142 if (!SIMPLEQ_EMPTY(&kauth_builtin_scope_cred->listenq)) 1143 KASSERT(r == 0); 1144 #endif /* DIAGNOSTIC */ 1145 1146 return (r); 1147 } 1148