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