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