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