1 /* $NetBSD: kern_auth.c,v 1.46 2007/02/24 20:41:33 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.46 2007/02/24 20:41:33 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> /* for pi_[p]cread */ 43 #include <sys/mutex.h> 44 #include <sys/specificdata.h> 45 46 /* 47 * Secmodel-specific credentials. 48 */ 49 struct kauth_key { 50 const char *ks_secmodel; /* secmodel */ 51 specificdata_key_t ks_key; /* key */ 52 }; 53 54 /* 55 * Credentials. 56 * 57 * A subset of this structure is used in kvm(3) (src/lib/libkvm/kvm_proc.c) 58 * and should be synchronized with this structure when the update is 59 * relevant. 60 */ 61 struct kauth_cred { 62 kmutex_t cr_lock; /* lock on cr_refcnt */ 63 u_int cr_refcnt; /* reference count */ 64 uid_t cr_uid; /* user id */ 65 uid_t cr_euid; /* effective user id */ 66 uid_t cr_svuid; /* saved effective user id */ 67 gid_t cr_gid; /* group id */ 68 gid_t cr_egid; /* effective group id */ 69 gid_t cr_svgid; /* saved effective group id */ 70 u_int cr_ngroups; /* number of groups */ 71 gid_t cr_groups[NGROUPS]; /* group memberships */ 72 specificdata_reference cr_sd; /* specific data */ 73 }; 74 75 /* 76 * Listener. 77 */ 78 struct kauth_listener { 79 kauth_scope_callback_t func; /* callback */ 80 kauth_scope_t scope; /* scope backpointer */ 81 u_int refcnt; /* reference count */ 82 SIMPLEQ_ENTRY(kauth_listener) listener_next; /* listener list */ 83 }; 84 85 /* 86 * Scope. 87 */ 88 struct kauth_scope { 89 const char *id; /* scope name */ 90 void *cookie; /* user cookie */ 91 u_int nlisteners; /* # of listeners */ 92 SIMPLEQ_HEAD(, kauth_listener) listenq; /* listener list */ 93 SIMPLEQ_ENTRY(kauth_scope) next_scope; /* scope list */ 94 }; 95 96 static int kauth_cred_hook(kauth_cred_t, kauth_action_t, void *, void *); 97 98 static POOL_INIT(kauth_cred_pool, sizeof(struct kauth_cred), 0, 0, 0, 99 "kauthcredpl", &pool_allocator_nointr); 100 101 /* List of scopes and its lock. */ 102 static SIMPLEQ_HEAD(, kauth_scope) scope_list; 103 104 /* Built-in scopes: generic, process. */ 105 static kauth_scope_t kauth_builtin_scope_generic; 106 static kauth_scope_t kauth_builtin_scope_system; 107 static kauth_scope_t kauth_builtin_scope_process; 108 static kauth_scope_t kauth_builtin_scope_network; 109 static kauth_scope_t kauth_builtin_scope_machdep; 110 static kauth_scope_t kauth_builtin_scope_device; 111 static kauth_scope_t kauth_builtin_scope_cred; 112 113 static unsigned int nsecmodels = 0; 114 115 static specificdata_domain_t kauth_domain; 116 krwlock_t kauth_lock; 117 118 /* Allocate new, empty kauth credentials. */ 119 kauth_cred_t 120 kauth_cred_alloc(void) 121 { 122 kauth_cred_t cred; 123 124 cred = pool_get(&kauth_cred_pool, PR_WAITOK); 125 memset(cred, 0, sizeof(*cred)); 126 mutex_init(&cred->cr_lock, MUTEX_DEFAULT, IPL_NONE); 127 cred->cr_refcnt = 1; 128 specificdata_init(kauth_domain, &cred->cr_sd); 129 kauth_cred_hook(cred, KAUTH_CRED_INIT, NULL, NULL); 130 131 return (cred); 132 } 133 134 /* Increment reference count to cred. */ 135 void 136 kauth_cred_hold(kauth_cred_t cred) 137 { 138 KASSERT(cred != NULL); 139 KASSERT(cred->cr_refcnt > 0); 140 141 mutex_enter(&cred->cr_lock); 142 cred->cr_refcnt++; 143 mutex_exit(&cred->cr_lock); 144 } 145 146 /* Decrease reference count to cred. If reached zero, free it. */ 147 void 148 kauth_cred_free(kauth_cred_t cred) 149 { 150 u_int refcnt; 151 152 KASSERT(cred != NULL); 153 KASSERT(cred->cr_refcnt > 0); 154 155 mutex_enter(&cred->cr_lock); 156 refcnt = --cred->cr_refcnt; 157 mutex_exit(&cred->cr_lock); 158 159 if (refcnt == 0) { 160 kauth_cred_hook(cred, KAUTH_CRED_FREE, NULL, NULL); 161 specificdata_fini(kauth_domain, &cred->cr_sd); 162 mutex_destroy(&cred->cr_lock); 163 pool_put(&kauth_cred_pool, cred); 164 } 165 } 166 167 void 168 kauth_cred_clone(kauth_cred_t from, kauth_cred_t to) 169 { 170 KASSERT(from != NULL); 171 KASSERT(to != NULL); 172 KASSERT(from->cr_refcnt > 0); 173 174 to->cr_uid = from->cr_uid; 175 to->cr_euid = from->cr_euid; 176 to->cr_svuid = from->cr_svuid; 177 to->cr_gid = from->cr_gid; 178 to->cr_egid = from->cr_egid; 179 to->cr_svgid = from->cr_svgid; 180 to->cr_ngroups = from->cr_ngroups; 181 memcpy(to->cr_groups, from->cr_groups, sizeof(to->cr_groups)); 182 183 kauth_cred_hook(from, KAUTH_CRED_COPY, to, NULL); 184 } 185 186 /* 187 * Duplicate cred and return a new kauth_cred_t. 188 */ 189 kauth_cred_t 190 kauth_cred_dup(kauth_cred_t cred) 191 { 192 kauth_cred_t new_cred; 193 194 KASSERT(cred != NULL); 195 KASSERT(cred->cr_refcnt > 0); 196 197 new_cred = kauth_cred_alloc(); 198 199 kauth_cred_clone(cred, new_cred); 200 201 return (new_cred); 202 } 203 204 /* 205 * Similar to crcopy(), only on a kauth_cred_t. 206 * XXX: Is this even needed? [kauth_cred_copy] 207 */ 208 kauth_cred_t 209 kauth_cred_copy(kauth_cred_t cred) 210 { 211 kauth_cred_t new_cred; 212 213 KASSERT(cred != NULL); 214 KASSERT(cred->cr_refcnt > 0); 215 216 /* If the provided credentials already have one reference, use them. */ 217 if (cred->cr_refcnt == 1) 218 return (cred); 219 220 new_cred = kauth_cred_alloc(); 221 222 kauth_cred_clone(cred, new_cred); 223 224 kauth_cred_free(cred); 225 226 return (new_cred); 227 } 228 229 void 230 kauth_proc_fork(struct proc *parent, struct proc *child) 231 { 232 233 mutex_enter(&parent->p_mutex); 234 kauth_cred_hold(parent->p_cred); 235 child->p_cred = parent->p_cred; 236 mutex_exit(&parent->p_mutex); 237 238 /* XXX: relies on parent process stalling during fork() */ 239 kauth_cred_hook(parent->p_cred, KAUTH_CRED_FORK, parent, 240 child); 241 } 242 243 uid_t 244 kauth_cred_getuid(kauth_cred_t cred) 245 { 246 KASSERT(cred != NULL); 247 248 return (cred->cr_uid); 249 } 250 251 uid_t 252 kauth_cred_geteuid(kauth_cred_t cred) 253 { 254 KASSERT(cred != NULL); 255 256 return (cred->cr_euid); 257 } 258 259 uid_t 260 kauth_cred_getsvuid(kauth_cred_t cred) 261 { 262 KASSERT(cred != NULL); 263 264 return (cred->cr_svuid); 265 } 266 267 gid_t 268 kauth_cred_getgid(kauth_cred_t cred) 269 { 270 KASSERT(cred != NULL); 271 272 return (cred->cr_gid); 273 } 274 275 gid_t 276 kauth_cred_getegid(kauth_cred_t cred) 277 { 278 KASSERT(cred != NULL); 279 280 return (cred->cr_egid); 281 } 282 283 gid_t 284 kauth_cred_getsvgid(kauth_cred_t cred) 285 { 286 KASSERT(cred != NULL); 287 288 return (cred->cr_svgid); 289 } 290 291 void 292 kauth_cred_setuid(kauth_cred_t cred, uid_t uid) 293 { 294 KASSERT(cred != NULL); 295 KASSERT(cred->cr_refcnt == 1); 296 297 cred->cr_uid = uid; 298 } 299 300 void 301 kauth_cred_seteuid(kauth_cred_t cred, uid_t uid) 302 { 303 KASSERT(cred != NULL); 304 KASSERT(cred->cr_refcnt == 1); 305 306 cred->cr_euid = uid; 307 } 308 309 void 310 kauth_cred_setsvuid(kauth_cred_t cred, uid_t uid) 311 { 312 KASSERT(cred != NULL); 313 KASSERT(cred->cr_refcnt == 1); 314 315 cred->cr_svuid = uid; 316 } 317 318 void 319 kauth_cred_setgid(kauth_cred_t cred, gid_t gid) 320 { 321 KASSERT(cred != NULL); 322 KASSERT(cred->cr_refcnt == 1); 323 324 cred->cr_gid = gid; 325 } 326 327 void 328 kauth_cred_setegid(kauth_cred_t cred, gid_t gid) 329 { 330 KASSERT(cred != NULL); 331 KASSERT(cred->cr_refcnt == 1); 332 333 cred->cr_egid = gid; 334 } 335 336 void 337 kauth_cred_setsvgid(kauth_cred_t cred, gid_t gid) 338 { 339 KASSERT(cred != NULL); 340 KASSERT(cred->cr_refcnt == 1); 341 342 cred->cr_svgid = gid; 343 } 344 345 /* Checks if gid is a member of the groups in cred. */ 346 int 347 kauth_cred_ismember_gid(kauth_cred_t cred, gid_t gid, int *resultp) 348 { 349 int i; 350 351 KASSERT(cred != NULL); 352 KASSERT(resultp != NULL); 353 354 *resultp = 0; 355 356 for (i = 0; i < cred->cr_ngroups; i++) 357 if (cred->cr_groups[i] == gid) { 358 *resultp = 1; 359 break; 360 } 361 362 return (0); 363 } 364 365 u_int 366 kauth_cred_ngroups(kauth_cred_t cred) 367 { 368 KASSERT(cred != NULL); 369 370 return (cred->cr_ngroups); 371 } 372 373 /* 374 * Return the group at index idx from the groups in cred. 375 */ 376 gid_t 377 kauth_cred_group(kauth_cred_t cred, u_int idx) 378 { 379 KASSERT(cred != NULL); 380 KASSERT(idx < cred->cr_ngroups); 381 382 return (cred->cr_groups[idx]); 383 } 384 385 /* XXX elad: gmuid is unused for now. */ 386 int 387 kauth_cred_setgroups(kauth_cred_t cred, gid_t *grbuf, size_t len, uid_t gmuid) 388 { 389 KASSERT(cred != NULL); 390 KASSERT(cred->cr_refcnt == 1); 391 KASSERT(len <= sizeof(cred->cr_groups) / sizeof(cred->cr_groups[0])); 392 393 if (len) 394 memcpy(cred->cr_groups, grbuf, len * sizeof(cred->cr_groups[0])); 395 memset(cred->cr_groups + len, 0xff, 396 sizeof(cred->cr_groups) - (len * sizeof(cred->cr_groups[0]))); 397 398 cred->cr_ngroups = len; 399 400 return (0); 401 } 402 403 int 404 kauth_cred_getgroups(kauth_cred_t cred, gid_t *grbuf, size_t len) 405 { 406 KASSERT(cred != NULL); 407 KASSERT(len <= cred->cr_ngroups); 408 409 memset(grbuf, 0xff, sizeof(*grbuf) * len); 410 memcpy(grbuf, cred->cr_groups, sizeof(*grbuf) * len); 411 412 return (0); 413 } 414 415 int 416 kauth_register_key(const char *secmodel, kauth_key_t *result) 417 { 418 kauth_key_t k; 419 specificdata_key_t key; 420 int error; 421 422 KASSERT(result != NULL); 423 424 error = specificdata_key_create(kauth_domain, &key, NULL); 425 if (error) 426 return (error); 427 428 k = kmem_alloc(sizeof(*k), KM_SLEEP); 429 k->ks_secmodel = secmodel; 430 k->ks_key = key; 431 432 *result = k; 433 434 return (0); 435 } 436 437 int 438 kauth_deregister_key(kauth_key_t key) 439 { 440 KASSERT(key != NULL); 441 442 specificdata_key_delete(kauth_domain, key->ks_key); 443 kmem_free(key, sizeof(*key)); 444 445 return (0); 446 } 447 448 void * 449 kauth_cred_getdata(kauth_cred_t cred, kauth_key_t key) 450 { 451 KASSERT(cred != NULL); 452 KASSERT(key != NULL); 453 454 return (specificdata_getspecific(kauth_domain, &cred->cr_sd, 455 key->ks_key)); 456 } 457 458 void 459 kauth_cred_setdata(kauth_cred_t cred, kauth_key_t key, void *data) 460 { 461 KASSERT(cred != NULL); 462 KASSERT(key != NULL); 463 464 specificdata_setspecific(kauth_domain, &cred->cr_sd, key->ks_key, data); 465 } 466 467 /* 468 * Match uids in two credentials. 469 */ 470 int 471 kauth_cred_uidmatch(kauth_cred_t cred1, kauth_cred_t cred2) 472 { 473 KASSERT(cred1 != NULL); 474 KASSERT(cred2 != NULL); 475 476 if (cred1->cr_uid == cred2->cr_uid || 477 cred1->cr_euid == cred2->cr_uid || 478 cred1->cr_uid == cred2->cr_euid || 479 cred1->cr_euid == cred2->cr_euid) 480 return (1); 481 482 return (0); 483 } 484 485 u_int 486 kauth_cred_getrefcnt(kauth_cred_t cred) 487 { 488 KASSERT(cred != NULL); 489 490 return (cred->cr_refcnt); 491 } 492 493 /* 494 * Convert userland credentials (struct uucred) to kauth_cred_t. 495 * XXX: For NFS & puffs 496 */ 497 void 498 kauth_uucred_to_cred(kauth_cred_t cred, const struct uucred *uuc) 499 { 500 KASSERT(cred != NULL); 501 KASSERT(uuc != NULL); 502 503 cred->cr_refcnt = 1; 504 cred->cr_uid = uuc->cr_uid; 505 cred->cr_euid = uuc->cr_uid; 506 cred->cr_svuid = uuc->cr_uid; 507 cred->cr_gid = uuc->cr_gid; 508 cred->cr_egid = uuc->cr_gid; 509 cred->cr_svgid = uuc->cr_gid; 510 cred->cr_ngroups = min(uuc->cr_ngroups, NGROUPS); 511 kauth_cred_setgroups(cred, __UNCONST(uuc->cr_groups), 512 cred->cr_ngroups, -1); 513 } 514 515 /* 516 * Convert kauth_cred_t to userland credentials (struct uucred). 517 * XXX: For NFS & puffs 518 */ 519 void 520 kauth_cred_to_uucred(struct uucred *uuc, const kauth_cred_t cred) 521 { 522 KASSERT(cred != NULL); 523 KASSERT(uuc != NULL); 524 int ng; 525 526 ng = min(cred->cr_ngroups, NGROUPS); 527 uuc->cr_uid = cred->cr_euid; 528 uuc->cr_gid = cred->cr_egid; 529 uuc->cr_ngroups = ng; 530 kauth_cred_getgroups(cred, uuc->cr_groups, ng); 531 } 532 533 /* 534 * Compare kauth_cred_t and uucred credentials. 535 * XXX: Modelled after crcmp() for NFS. 536 */ 537 int 538 kauth_cred_uucmp(kauth_cred_t cred, const struct uucred *uuc) 539 { 540 KASSERT(cred != NULL); 541 KASSERT(uuc != NULL); 542 543 if (cred->cr_euid == uuc->cr_uid && 544 cred->cr_egid == uuc->cr_gid && 545 cred->cr_ngroups == uuc->cr_ngroups) { 546 int i; 547 548 /* Check if all groups from uuc appear in cred. */ 549 for (i = 0; i < uuc->cr_ngroups; i++) { 550 int ismember; 551 552 ismember = 0; 553 if (kauth_cred_ismember_gid(cred, uuc->cr_groups[i], 554 &ismember) != 0 || !ismember) 555 return (1); 556 } 557 558 return (0); 559 } 560 561 return (1); 562 } 563 564 /* 565 * Make a struct ucred out of a kauth_cred_t. For compatibility. 566 */ 567 void 568 kauth_cred_toucred(kauth_cred_t cred, struct ki_ucred *uc) 569 { 570 KASSERT(cred != NULL); 571 KASSERT(uc != NULL); 572 573 uc->cr_ref = cred->cr_refcnt; 574 uc->cr_uid = cred->cr_euid; 575 uc->cr_gid = cred->cr_egid; 576 uc->cr_ngroups = min(cred->cr_ngroups, 577 sizeof(uc->cr_groups) / sizeof(uc->cr_groups[0])); 578 memcpy(uc->cr_groups, cred->cr_groups, 579 uc->cr_ngroups * sizeof(uc->cr_groups[0])); 580 } 581 582 /* 583 * Make a struct pcred out of a kauth_cred_t. For compatibility. 584 */ 585 void 586 kauth_cred_topcred(kauth_cred_t cred, struct ki_pcred *pc) 587 { 588 KASSERT(cred != NULL); 589 KASSERT(pc != NULL); 590 591 pc->p_pad = NULL; 592 pc->p_ruid = cred->cr_uid; 593 pc->p_svuid = cred->cr_svuid; 594 pc->p_rgid = cred->cr_gid; 595 pc->p_svgid = cred->cr_svgid; 596 pc->p_refcnt = cred->cr_refcnt; 597 } 598 599 /* 600 * Return kauth_cred_t for the current LWP. 601 */ 602 kauth_cred_t 603 kauth_cred_get(void) 604 { 605 return (curlwp->l_cred); 606 } 607 608 /* 609 * Returns a scope matching the provided id. 610 * Requires the scope list lock to be held by the caller. 611 */ 612 static kauth_scope_t 613 kauth_ifindscope(const char *id) 614 { 615 kauth_scope_t scope; 616 617 KASSERT(rw_lock_held(&kauth_lock)); 618 619 scope = NULL; 620 SIMPLEQ_FOREACH(scope, &scope_list, next_scope) { 621 if (strcmp(scope->id, id) == 0) 622 break; 623 } 624 625 return (scope); 626 } 627 628 /* 629 * Register a new scope. 630 * 631 * id - identifier for the scope 632 * callback - the scope's default listener 633 * cookie - cookie to be passed to the listener(s) 634 */ 635 kauth_scope_t 636 kauth_register_scope(const char *id, kauth_scope_callback_t callback, 637 void *cookie) 638 { 639 kauth_scope_t scope; 640 kauth_listener_t listener = NULL; /* XXX gcc */ 641 642 /* Sanitize input */ 643 if (id == NULL) 644 return (NULL); 645 646 /* Allocate space for a new scope and listener. */ 647 scope = kmem_alloc(sizeof(*scope), KM_SLEEP); 648 if (scope == NULL) 649 return NULL; 650 if (callback != NULL) { 651 listener = kmem_alloc(sizeof(*listener), KM_SLEEP); 652 if (listener == NULL) { 653 kmem_free(scope, sizeof(*scope)); 654 return (NULL); 655 } 656 } 657 658 /* 659 * Acquire scope list lock. 660 */ 661 rw_enter(&kauth_lock, RW_WRITER); 662 663 /* Check we don't already have a scope with the same id */ 664 if (kauth_ifindscope(id) != NULL) { 665 rw_exit(&kauth_lock); 666 667 kmem_free(scope, sizeof(*scope)); 668 if (callback != NULL) 669 kmem_free(listener, sizeof(*listener)); 670 671 return (NULL); 672 } 673 674 /* Initialize new scope with parameters */ 675 scope->id = id; 676 scope->cookie = cookie; 677 scope->nlisteners = 1; 678 679 SIMPLEQ_INIT(&scope->listenq); 680 681 /* Add default listener */ 682 if (callback != NULL) { 683 listener->func = callback; 684 listener->scope = scope; 685 listener->refcnt = 0; 686 SIMPLEQ_INSERT_HEAD(&scope->listenq, listener, listener_next); 687 } 688 689 /* Insert scope to scopes list */ 690 SIMPLEQ_INSERT_TAIL(&scope_list, scope, next_scope); 691 692 rw_exit(&kauth_lock); 693 694 return (scope); 695 } 696 697 /* 698 * Initialize the kernel authorization subsystem. 699 * 700 * Initialize the scopes list lock. 701 * Create specificdata domain. 702 * Register the credentials scope, used in kauth(9) internally. 703 * Register built-in scopes: generic, system, process, network, machdep, device. 704 */ 705 void 706 kauth_init(void) 707 { 708 SIMPLEQ_INIT(&scope_list); 709 rw_init(&kauth_lock); 710 711 /* Create specificdata domain. */ 712 kauth_domain = specificdata_domain_create(); 713 714 /* Register credentials scope. */ 715 kauth_builtin_scope_cred = 716 kauth_register_scope(KAUTH_SCOPE_CRED, NULL, NULL); 717 718 /* Register generic scope. */ 719 kauth_builtin_scope_generic = kauth_register_scope(KAUTH_SCOPE_GENERIC, 720 NULL, NULL); 721 722 /* Register system scope. */ 723 kauth_builtin_scope_system = kauth_register_scope(KAUTH_SCOPE_SYSTEM, 724 NULL, NULL); 725 726 /* Register process scope. */ 727 kauth_builtin_scope_process = kauth_register_scope(KAUTH_SCOPE_PROCESS, 728 NULL, NULL); 729 730 /* Register network scope. */ 731 kauth_builtin_scope_network = kauth_register_scope(KAUTH_SCOPE_NETWORK, 732 NULL, NULL); 733 734 /* Register machdep scope. */ 735 kauth_builtin_scope_machdep = kauth_register_scope(KAUTH_SCOPE_MACHDEP, 736 NULL, NULL); 737 738 /* Register device scope. */ 739 kauth_builtin_scope_device = kauth_register_scope(KAUTH_SCOPE_DEVICE, 740 NULL, NULL); 741 } 742 743 /* 744 * Deregister a scope. 745 * Requires scope list lock to be held by the caller. 746 * 747 * scope - the scope to deregister 748 */ 749 void 750 kauth_deregister_scope(kauth_scope_t scope) 751 { 752 if (scope != NULL) { 753 /* Remove scope from list */ 754 SIMPLEQ_REMOVE(&scope_list, scope, kauth_scope, next_scope); 755 kmem_free(scope, sizeof(*scope)); 756 } 757 } 758 759 /* 760 * Register a listener. 761 * 762 * id - scope identifier. 763 * callback - the callback routine for the listener. 764 * cookie - cookie to pass unmoidfied to the callback. 765 */ 766 kauth_listener_t 767 kauth_listen_scope(const char *id, kauth_scope_callback_t callback, 768 void *cookie) 769 { 770 kauth_scope_t scope; 771 kauth_listener_t listener; 772 773 listener = kmem_alloc(sizeof(*listener), KM_SLEEP); 774 if (listener == NULL) 775 return (NULL); 776 777 rw_enter(&kauth_lock, RW_WRITER); 778 779 /* 780 * Find scope struct. 781 */ 782 scope = kauth_ifindscope(id); 783 if (scope == NULL) { 784 rw_exit(&kauth_lock); 785 kmem_free(listener, sizeof(*listener)); 786 return (NULL); 787 } 788 789 /* Allocate listener */ 790 791 /* Initialize listener with parameters */ 792 listener->func = callback; 793 listener->refcnt = 0; 794 795 /* Add listener to scope */ 796 SIMPLEQ_INSERT_TAIL(&scope->listenq, listener, listener_next); 797 798 /* Raise number of listeners on scope. */ 799 scope->nlisteners++; 800 listener->scope = scope; 801 802 rw_exit(&kauth_lock); 803 804 return (listener); 805 } 806 807 /* 808 * Deregister a listener. 809 * 810 * listener - listener reference as returned from kauth_listen_scope(). 811 */ 812 void 813 kauth_unlisten_scope(kauth_listener_t listener) 814 { 815 816 if (listener != NULL) { 817 rw_enter(&kauth_lock, RW_WRITER); 818 SIMPLEQ_REMOVE(&listener->scope->listenq, listener, 819 kauth_listener, listener_next); 820 listener->scope->nlisteners--; 821 rw_exit(&kauth_lock); 822 kmem_free(listener, sizeof(*listener)); 823 } 824 } 825 826 /* 827 * Authorize a request. 828 * 829 * scope - the scope of the request as defined by KAUTH_SCOPE_* or as 830 * returned from kauth_register_scope(). 831 * credential - credentials of the user ("actor") making the request. 832 * action - request identifier. 833 * arg[0-3] - passed unmodified to listener(s). 834 */ 835 int 836 kauth_authorize_action(kauth_scope_t scope, kauth_cred_t cred, 837 kauth_action_t action, void *arg0, void *arg1, 838 void *arg2, void *arg3) 839 { 840 kauth_listener_t listener; 841 int error, allow, fail; 842 843 #if 0 /* defined(LOCKDEBUG) */ 844 spinlock_switchcheck(); 845 simple_lock_only_held(NULL, "kauth_authorize_action"); 846 #endif 847 848 KASSERT(cred != NULL); 849 KASSERT(action != 0); 850 851 /* Short-circuit requests coming from the kernel. */ 852 if (cred == NOCRED || cred == FSCRED) 853 return (0); 854 855 KASSERT(scope != NULL); 856 857 fail = 0; 858 allow = 0; 859 860 /* rw_enter(&kauth_lock, RW_READER); XXX not yet */ 861 SIMPLEQ_FOREACH(listener, &scope->listenq, listener_next) { 862 error = listener->func(cred, action, scope->cookie, arg0, 863 arg1, arg2, arg3); 864 865 if (error == KAUTH_RESULT_ALLOW) 866 allow = 1; 867 else if (error == KAUTH_RESULT_DENY) 868 fail = 1; 869 } 870 /* rw_exit(&kauth_lock); */ 871 872 if (fail) 873 return (EPERM); 874 875 if (allow) 876 return (0); 877 878 if (!nsecmodels) 879 return (0); 880 881 return (EPERM); 882 }; 883 884 /* 885 * Generic scope authorization wrapper. 886 */ 887 int 888 kauth_authorize_generic(kauth_cred_t cred, kauth_action_t action, void *arg0) 889 { 890 return (kauth_authorize_action(kauth_builtin_scope_generic, cred, 891 action, arg0, NULL, NULL, NULL)); 892 } 893 894 /* 895 * System scope authorization wrapper. 896 */ 897 int 898 kauth_authorize_system(kauth_cred_t cred, kauth_action_t action, 899 enum kauth_system_req req, void *arg1, void *arg2, void *arg3) 900 { 901 return (kauth_authorize_action(kauth_builtin_scope_system, cred, 902 action, (void *)req, arg1, arg2, arg3)); 903 } 904 905 /* 906 * Process scope authorization wrapper. 907 */ 908 int 909 kauth_authorize_process(kauth_cred_t cred, kauth_action_t action, 910 struct proc *p, void *arg1, void *arg2, void *arg3) 911 { 912 return (kauth_authorize_action(kauth_builtin_scope_process, cred, 913 action, p, arg1, arg2, arg3)); 914 } 915 916 /* 917 * Network scope authorization wrapper. 918 */ 919 int 920 kauth_authorize_network(kauth_cred_t cred, kauth_action_t action, 921 enum kauth_network_req req, void *arg1, void *arg2, void *arg3) 922 { 923 return (kauth_authorize_action(kauth_builtin_scope_network, cred, 924 action, (void *)req, arg1, arg2, arg3)); 925 } 926 927 int 928 kauth_authorize_machdep(kauth_cred_t cred, kauth_action_t action, 929 void *arg0, void *arg1, void *arg2, void *arg3) 930 { 931 return (kauth_authorize_action(kauth_builtin_scope_machdep, cred, 932 action, arg0, arg1, arg2, arg3)); 933 } 934 935 int 936 kauth_authorize_device(kauth_cred_t cred, kauth_action_t action, 937 void *arg0, void *arg1, void *arg2, void *arg3) 938 { 939 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 940 action, arg0, arg1, arg2, arg3)); 941 } 942 943 int 944 kauth_authorize_device_tty(kauth_cred_t cred, kauth_action_t action, 945 struct tty *tty) 946 { 947 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 948 action, tty, NULL, NULL, NULL)); 949 } 950 951 int 952 kauth_authorize_device_spec(kauth_cred_t cred, enum kauth_device_req req, 953 struct vnode *vp) 954 { 955 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 956 KAUTH_DEVICE_RAWIO_SPEC, (void *)req, vp, NULL, NULL)); 957 } 958 959 int 960 kauth_authorize_device_passthru(kauth_cred_t cred, dev_t dev, u_long bits, 961 void *data) 962 { 963 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 964 KAUTH_DEVICE_RAWIO_PASSTHRU, (void *)bits, (void *)(u_long)dev, 965 data, NULL)); 966 } 967 968 static int 969 kauth_cred_hook(kauth_cred_t cred, kauth_action_t action, void *arg0, 970 void *arg1) 971 { 972 int r; 973 974 r = kauth_authorize_action(kauth_builtin_scope_cred, cred, action, 975 arg0, arg1, NULL, NULL); 976 977 #ifdef DIAGNOSTIC 978 if (!SIMPLEQ_EMPTY(&kauth_builtin_scope_cred->listenq)) 979 KASSERT(r == 0); 980 #endif /* DIAGNOSTIC */ 981 982 return (r); 983 } 984 985 void 986 secmodel_register(void) 987 { 988 KASSERT(nsecmodels + 1 != 0); 989 990 rw_enter(&kauth_lock, RW_WRITER); 991 nsecmodels++; 992 rw_exit(&kauth_lock); 993 } 994 995 void 996 secmodel_deregister(void) 997 { 998 KASSERT(nsecmodels != 0); 999 1000 rw_enter(&kauth_lock, RW_WRITER); 1001 nsecmodels--; 1002 rw_exit(&kauth_lock); 1003 } 1004