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