1 /* $NetBSD: kern_auth.c,v 1.60 2008/04/28 20:24:02 martin 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.60 2008/04/28 20:24:02 martin 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 int 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 > sizeof(cred->cr_groups) / sizeof(cred->cr_groups[0])) 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 == 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, 667 sizeof(uc->cr_groups) / sizeof(uc->cr_groups[0])); 668 memcpy(uc->cr_groups, cred->cr_groups, 669 uc->cr_ngroups * sizeof(uc->cr_groups[0])); 670 } 671 672 /* 673 * Make a struct pcred out of a kauth_cred_t. For compatibility. 674 */ 675 void 676 kauth_cred_topcred(kauth_cred_t cred, struct ki_pcred *pc) 677 { 678 KASSERT(cred != NULL); 679 KASSERT(pc != NULL); 680 681 pc->p_pad = NULL; 682 pc->p_ruid = cred->cr_uid; 683 pc->p_svuid = cred->cr_svuid; 684 pc->p_rgid = cred->cr_gid; 685 pc->p_svgid = cred->cr_svgid; 686 pc->p_refcnt = cred->cr_refcnt; 687 } 688 689 /* 690 * Return kauth_cred_t for the current LWP. 691 */ 692 kauth_cred_t 693 kauth_cred_get(void) 694 { 695 return (curlwp->l_cred); 696 } 697 698 /* 699 * Returns a scope matching the provided id. 700 * Requires the scope list lock to be held by the caller. 701 */ 702 static kauth_scope_t 703 kauth_ifindscope(const char *id) 704 { 705 kauth_scope_t scope; 706 707 KASSERT(rw_lock_held(&kauth_lock)); 708 709 scope = NULL; 710 SIMPLEQ_FOREACH(scope, &scope_list, next_scope) { 711 if (strcmp(scope->id, id) == 0) 712 break; 713 } 714 715 return (scope); 716 } 717 718 /* 719 * Register a new scope. 720 * 721 * id - identifier for the scope 722 * callback - the scope's default listener 723 * cookie - cookie to be passed to the listener(s) 724 */ 725 kauth_scope_t 726 kauth_register_scope(const char *id, kauth_scope_callback_t callback, 727 void *cookie) 728 { 729 kauth_scope_t scope; 730 kauth_listener_t listener = NULL; /* XXX gcc */ 731 732 /* Sanitize input */ 733 if (id == NULL) 734 return (NULL); 735 736 /* Allocate space for a new scope and listener. */ 737 scope = kmem_alloc(sizeof(*scope), KM_SLEEP); 738 if (scope == NULL) 739 return NULL; 740 if (callback != NULL) { 741 listener = kmem_alloc(sizeof(*listener), KM_SLEEP); 742 if (listener == NULL) { 743 kmem_free(scope, sizeof(*scope)); 744 return (NULL); 745 } 746 } 747 748 /* 749 * Acquire scope list lock. 750 */ 751 rw_enter(&kauth_lock, RW_WRITER); 752 753 /* Check we don't already have a scope with the same id */ 754 if (kauth_ifindscope(id) != NULL) { 755 rw_exit(&kauth_lock); 756 757 kmem_free(scope, sizeof(*scope)); 758 if (callback != NULL) 759 kmem_free(listener, sizeof(*listener)); 760 761 return (NULL); 762 } 763 764 /* Initialize new scope with parameters */ 765 scope->id = id; 766 scope->cookie = cookie; 767 scope->nlisteners = 1; 768 769 SIMPLEQ_INIT(&scope->listenq); 770 771 /* Add default listener */ 772 if (callback != NULL) { 773 listener->func = callback; 774 listener->scope = scope; 775 listener->refcnt = 0; 776 SIMPLEQ_INSERT_HEAD(&scope->listenq, listener, listener_next); 777 } 778 779 /* Insert scope to scopes list */ 780 SIMPLEQ_INSERT_TAIL(&scope_list, scope, next_scope); 781 782 rw_exit(&kauth_lock); 783 784 return (scope); 785 } 786 787 /* 788 * Initialize the kernel authorization subsystem. 789 * 790 * Initialize the scopes list lock. 791 * Create specificdata domain. 792 * Register the credentials scope, used in kauth(9) internally. 793 * Register built-in scopes: generic, system, process, network, machdep, device. 794 */ 795 void 796 kauth_init(void) 797 { 798 rw_init(&kauth_lock); 799 800 kauth_cred_cache = pool_cache_init(sizeof(struct kauth_cred), 801 coherency_unit, 0, 0, "kcredpl", NULL, IPL_NONE, 802 NULL, NULL, NULL); 803 804 /* Create specificdata domain. */ 805 kauth_domain = specificdata_domain_create(); 806 807 /* Register credentials scope. */ 808 kauth_builtin_scope_cred = 809 kauth_register_scope(KAUTH_SCOPE_CRED, NULL, NULL); 810 811 /* Register generic scope. */ 812 kauth_builtin_scope_generic = kauth_register_scope(KAUTH_SCOPE_GENERIC, 813 NULL, NULL); 814 815 /* Register system scope. */ 816 kauth_builtin_scope_system = kauth_register_scope(KAUTH_SCOPE_SYSTEM, 817 NULL, NULL); 818 819 /* Register process scope. */ 820 kauth_builtin_scope_process = kauth_register_scope(KAUTH_SCOPE_PROCESS, 821 NULL, NULL); 822 823 /* Register network scope. */ 824 kauth_builtin_scope_network = kauth_register_scope(KAUTH_SCOPE_NETWORK, 825 NULL, NULL); 826 827 /* Register machdep scope. */ 828 kauth_builtin_scope_machdep = kauth_register_scope(KAUTH_SCOPE_MACHDEP, 829 NULL, NULL); 830 831 /* Register device scope. */ 832 kauth_builtin_scope_device = kauth_register_scope(KAUTH_SCOPE_DEVICE, 833 NULL, NULL); 834 } 835 836 /* 837 * Deregister a scope. 838 * Requires scope list lock to be held by the caller. 839 * 840 * scope - the scope to deregister 841 */ 842 void 843 kauth_deregister_scope(kauth_scope_t scope) 844 { 845 if (scope != NULL) { 846 /* Remove scope from list */ 847 SIMPLEQ_REMOVE(&scope_list, scope, kauth_scope, next_scope); 848 kmem_free(scope, sizeof(*scope)); 849 } 850 } 851 852 /* 853 * Register a listener. 854 * 855 * id - scope identifier. 856 * callback - the callback routine for the listener. 857 * cookie - cookie to pass unmoidfied to the callback. 858 */ 859 kauth_listener_t 860 kauth_listen_scope(const char *id, kauth_scope_callback_t callback, 861 void *cookie) 862 { 863 kauth_scope_t scope; 864 kauth_listener_t listener; 865 866 listener = kmem_alloc(sizeof(*listener), KM_SLEEP); 867 if (listener == NULL) 868 return (NULL); 869 870 rw_enter(&kauth_lock, RW_WRITER); 871 872 /* 873 * Find scope struct. 874 */ 875 scope = kauth_ifindscope(id); 876 if (scope == NULL) { 877 rw_exit(&kauth_lock); 878 kmem_free(listener, sizeof(*listener)); 879 return (NULL); 880 } 881 882 /* Allocate listener */ 883 884 /* Initialize listener with parameters */ 885 listener->func = callback; 886 listener->refcnt = 0; 887 888 /* Add listener to scope */ 889 SIMPLEQ_INSERT_TAIL(&scope->listenq, listener, listener_next); 890 891 /* Raise number of listeners on scope. */ 892 scope->nlisteners++; 893 listener->scope = scope; 894 895 rw_exit(&kauth_lock); 896 897 return (listener); 898 } 899 900 /* 901 * Deregister a listener. 902 * 903 * listener - listener reference as returned from kauth_listen_scope(). 904 */ 905 void 906 kauth_unlisten_scope(kauth_listener_t listener) 907 { 908 909 if (listener != NULL) { 910 rw_enter(&kauth_lock, RW_WRITER); 911 SIMPLEQ_REMOVE(&listener->scope->listenq, listener, 912 kauth_listener, listener_next); 913 listener->scope->nlisteners--; 914 rw_exit(&kauth_lock); 915 kmem_free(listener, sizeof(*listener)); 916 } 917 } 918 919 /* 920 * Authorize a request. 921 * 922 * scope - the scope of the request as defined by KAUTH_SCOPE_* or as 923 * returned from kauth_register_scope(). 924 * credential - credentials of the user ("actor") making the request. 925 * action - request identifier. 926 * arg[0-3] - passed unmodified to listener(s). 927 */ 928 int 929 kauth_authorize_action(kauth_scope_t scope, kauth_cred_t cred, 930 kauth_action_t action, void *arg0, void *arg1, 931 void *arg2, void *arg3) 932 { 933 kauth_listener_t listener; 934 int error, allow, fail; 935 936 KASSERT(cred != NULL); 937 KASSERT(action != 0); 938 939 /* Short-circuit requests coming from the kernel. */ 940 if (cred == NOCRED || cred == FSCRED) 941 return (0); 942 943 KASSERT(scope != NULL); 944 945 fail = 0; 946 allow = 0; 947 948 /* rw_enter(&kauth_lock, RW_READER); XXX not yet */ 949 SIMPLEQ_FOREACH(listener, &scope->listenq, listener_next) { 950 error = listener->func(cred, action, scope->cookie, arg0, 951 arg1, arg2, arg3); 952 953 if (error == KAUTH_RESULT_ALLOW) 954 allow = 1; 955 else if (error == KAUTH_RESULT_DENY) 956 fail = 1; 957 } 958 /* rw_exit(&kauth_lock); */ 959 960 if (fail) 961 return (EPERM); 962 963 if (allow) 964 return (0); 965 966 if (!nsecmodels) 967 return (0); 968 969 return (EPERM); 970 }; 971 972 /* 973 * Generic scope authorization wrapper. 974 */ 975 int 976 kauth_authorize_generic(kauth_cred_t cred, kauth_action_t action, void *arg0) 977 { 978 return (kauth_authorize_action(kauth_builtin_scope_generic, cred, 979 action, arg0, NULL, NULL, NULL)); 980 } 981 982 /* 983 * System scope authorization wrapper. 984 */ 985 int 986 kauth_authorize_system(kauth_cred_t cred, kauth_action_t action, 987 enum kauth_system_req req, void *arg1, void *arg2, void *arg3) 988 { 989 return (kauth_authorize_action(kauth_builtin_scope_system, cred, 990 action, (void *)req, arg1, arg2, arg3)); 991 } 992 993 /* 994 * Process scope authorization wrapper. 995 */ 996 int 997 kauth_authorize_process(kauth_cred_t cred, kauth_action_t action, 998 struct proc *p, void *arg1, void *arg2, void *arg3) 999 { 1000 return (kauth_authorize_action(kauth_builtin_scope_process, cred, 1001 action, p, arg1, arg2, arg3)); 1002 } 1003 1004 /* 1005 * Network scope authorization wrapper. 1006 */ 1007 int 1008 kauth_authorize_network(kauth_cred_t cred, kauth_action_t action, 1009 enum kauth_network_req req, void *arg1, void *arg2, void *arg3) 1010 { 1011 return (kauth_authorize_action(kauth_builtin_scope_network, cred, 1012 action, (void *)req, arg1, arg2, arg3)); 1013 } 1014 1015 int 1016 kauth_authorize_machdep(kauth_cred_t cred, kauth_action_t action, 1017 void *arg0, void *arg1, void *arg2, void *arg3) 1018 { 1019 return (kauth_authorize_action(kauth_builtin_scope_machdep, cred, 1020 action, arg0, arg1, arg2, arg3)); 1021 } 1022 1023 int 1024 kauth_authorize_device(kauth_cred_t cred, kauth_action_t action, 1025 void *arg0, void *arg1, void *arg2, void *arg3) 1026 { 1027 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1028 action, arg0, arg1, arg2, arg3)); 1029 } 1030 1031 int 1032 kauth_authorize_device_tty(kauth_cred_t cred, kauth_action_t action, 1033 struct tty *tty) 1034 { 1035 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1036 action, tty, NULL, NULL, NULL)); 1037 } 1038 1039 int 1040 kauth_authorize_device_spec(kauth_cred_t cred, enum kauth_device_req req, 1041 struct vnode *vp) 1042 { 1043 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1044 KAUTH_DEVICE_RAWIO_SPEC, (void *)req, vp, NULL, NULL)); 1045 } 1046 1047 int 1048 kauth_authorize_device_passthru(kauth_cred_t cred, dev_t dev, u_long bits, 1049 void *data) 1050 { 1051 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1052 KAUTH_DEVICE_RAWIO_PASSTHRU, (void *)bits, (void *)(u_long)dev, 1053 data, NULL)); 1054 } 1055 1056 static int 1057 kauth_cred_hook(kauth_cred_t cred, kauth_action_t action, void *arg0, 1058 void *arg1) 1059 { 1060 int r; 1061 1062 r = kauth_authorize_action(kauth_builtin_scope_cred, cred, action, 1063 arg0, arg1, NULL, NULL); 1064 1065 #ifdef DIAGNOSTIC 1066 if (!SIMPLEQ_EMPTY(&kauth_builtin_scope_cred->listenq)) 1067 KASSERT(r == 0); 1068 #endif /* DIAGNOSTIC */ 1069 1070 return (r); 1071 } 1072 1073 void 1074 secmodel_register(void) 1075 { 1076 KASSERT(nsecmodels + 1 != 0); 1077 1078 rw_enter(&kauth_lock, RW_WRITER); 1079 nsecmodels++; 1080 rw_exit(&kauth_lock); 1081 } 1082 1083 void 1084 secmodel_deregister(void) 1085 { 1086 KASSERT(nsecmodels != 0); 1087 1088 rw_enter(&kauth_lock, RW_WRITER); 1089 nsecmodels--; 1090 rw_exit(&kauth_lock); 1091 } 1092