1 /* $NetBSD: kern_auth.c,v 1.75 2015/10/06 22:13:39 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2005, 2006 Elad Efrat <elad@NetBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __KERNEL_RCSID(0, "$NetBSD: kern_auth.c,v 1.75 2015/10/06 22:13:39 christos Exp $"); 32 33 #include <sys/types.h> 34 #include <sys/param.h> 35 #include <sys/queue.h> 36 #include <sys/proc.h> 37 #include <sys/ucred.h> 38 #include <sys/pool.h> 39 #define __KAUTH_PRIVATE 40 #include <sys/kauth.h> 41 #include <sys/kmem.h> 42 #include <sys/rwlock.h> 43 #include <sys/sysctl.h> 44 #include <sys/atomic.h> 45 #include <sys/specificdata.h> 46 #include <sys/vnode.h> 47 48 #include <secmodel/secmodel.h> 49 50 /* 51 * Secmodel-specific credentials. 52 */ 53 struct kauth_key { 54 secmodel_t ks_secmodel; /* secmodel */ 55 specificdata_key_t ks_key; /* key */ 56 }; 57 58 59 /* 60 * Listener. 61 */ 62 struct kauth_listener { 63 kauth_scope_callback_t func; /* callback */ 64 kauth_scope_t scope; /* scope backpointer */ 65 u_int refcnt; /* reference count */ 66 SIMPLEQ_ENTRY(kauth_listener) listener_next; /* listener list */ 67 }; 68 69 /* 70 * Scope. 71 */ 72 struct kauth_scope { 73 const char *id; /* scope name */ 74 void *cookie; /* user cookie */ 75 u_int nlisteners; /* # of listeners */ 76 SIMPLEQ_HEAD(, kauth_listener) listenq; /* listener list */ 77 SIMPLEQ_ENTRY(kauth_scope) next_scope; /* scope list */ 78 }; 79 80 static int kauth_cred_hook(kauth_cred_t, kauth_action_t, void *, void *); 81 82 /* List of scopes and its lock. */ 83 static SIMPLEQ_HEAD(, kauth_scope) scope_list = 84 SIMPLEQ_HEAD_INITIALIZER(scope_list); 85 86 /* Built-in scopes: generic, process. */ 87 static kauth_scope_t kauth_builtin_scope_generic; 88 static kauth_scope_t kauth_builtin_scope_system; 89 static kauth_scope_t kauth_builtin_scope_process; 90 static kauth_scope_t kauth_builtin_scope_network; 91 static kauth_scope_t kauth_builtin_scope_machdep; 92 static kauth_scope_t kauth_builtin_scope_device; 93 static kauth_scope_t kauth_builtin_scope_cred; 94 static kauth_scope_t kauth_builtin_scope_vnode; 95 96 static specificdata_domain_t kauth_domain; 97 static pool_cache_t kauth_cred_cache; 98 99 krwlock_t kauth_lock; 100 101 /* Allocate new, empty kauth credentials. */ 102 kauth_cred_t 103 kauth_cred_alloc(void) 104 { 105 kauth_cred_t cred; 106 107 cred = pool_cache_get(kauth_cred_cache, PR_WAITOK); 108 109 cred->cr_refcnt = 1; 110 cred->cr_uid = 0; 111 cred->cr_euid = 0; 112 cred->cr_svuid = 0; 113 cred->cr_gid = 0; 114 cred->cr_egid = 0; 115 cred->cr_svgid = 0; 116 cred->cr_ngroups = 0; 117 118 specificdata_init(kauth_domain, &cred->cr_sd); 119 kauth_cred_hook(cred, KAUTH_CRED_INIT, NULL, NULL); 120 121 return (cred); 122 } 123 124 /* Increment reference count to cred. */ 125 void 126 kauth_cred_hold(kauth_cred_t cred) 127 { 128 KASSERT(cred != NULL); 129 KASSERT(cred != NOCRED); 130 KASSERT(cred != FSCRED); 131 KASSERT(cred->cr_refcnt > 0); 132 133 atomic_inc_uint(&cred->cr_refcnt); 134 } 135 136 /* Decrease reference count to cred. If reached zero, free it. */ 137 void 138 kauth_cred_free(kauth_cred_t cred) 139 { 140 141 KASSERT(cred != NULL); 142 KASSERT(cred != NOCRED); 143 KASSERT(cred != FSCRED); 144 KASSERT(cred->cr_refcnt > 0); 145 ASSERT_SLEEPABLE(); 146 147 if (atomic_dec_uint_nv(&cred->cr_refcnt) > 0) 148 return; 149 150 kauth_cred_hook(cred, KAUTH_CRED_FREE, NULL, NULL); 151 specificdata_fini(kauth_domain, &cred->cr_sd); 152 pool_cache_put(kauth_cred_cache, cred); 153 } 154 155 static void 156 kauth_cred_clone1(kauth_cred_t from, kauth_cred_t to, bool copy_groups) 157 { 158 KASSERT(from != NULL); 159 KASSERT(from != NOCRED); 160 KASSERT(from != FSCRED); 161 KASSERT(to != NULL); 162 KASSERT(to != NOCRED); 163 KASSERT(to != FSCRED); 164 KASSERT(from->cr_refcnt > 0); 165 166 to->cr_uid = from->cr_uid; 167 to->cr_euid = from->cr_euid; 168 to->cr_svuid = from->cr_svuid; 169 to->cr_gid = from->cr_gid; 170 to->cr_egid = from->cr_egid; 171 to->cr_svgid = from->cr_svgid; 172 if (copy_groups) { 173 to->cr_ngroups = from->cr_ngroups; 174 memcpy(to->cr_groups, from->cr_groups, sizeof(to->cr_groups)); 175 } 176 177 kauth_cred_hook(from, KAUTH_CRED_COPY, to, NULL); 178 } 179 180 void 181 kauth_cred_clone(kauth_cred_t from, kauth_cred_t to) 182 { 183 kauth_cred_clone1(from, to, true); 184 } 185 186 /* 187 * Duplicate cred and return a new kauth_cred_t. 188 */ 189 kauth_cred_t 190 kauth_cred_dup(kauth_cred_t cred) 191 { 192 kauth_cred_t new_cred; 193 194 KASSERT(cred != NULL); 195 KASSERT(cred != NOCRED); 196 KASSERT(cred != FSCRED); 197 KASSERT(cred->cr_refcnt > 0); 198 199 new_cred = kauth_cred_alloc(); 200 201 kauth_cred_clone(cred, new_cred); 202 203 return (new_cred); 204 } 205 206 /* 207 * Similar to crcopy(), only on a kauth_cred_t. 208 * XXX: Is this even needed? [kauth_cred_copy] 209 */ 210 kauth_cred_t 211 kauth_cred_copy(kauth_cred_t cred) 212 { 213 kauth_cred_t new_cred; 214 215 KASSERT(cred != NULL); 216 KASSERT(cred != NOCRED); 217 KASSERT(cred != FSCRED); 218 KASSERT(cred->cr_refcnt > 0); 219 220 /* If the provided credentials already have one reference, use them. */ 221 if (cred->cr_refcnt == 1) 222 return (cred); 223 224 new_cred = kauth_cred_alloc(); 225 226 kauth_cred_clone(cred, new_cred); 227 228 kauth_cred_free(cred); 229 230 return (new_cred); 231 } 232 233 void 234 kauth_proc_fork(struct proc *parent, struct proc *child) 235 { 236 237 mutex_enter(parent->p_lock); 238 kauth_cred_hold(parent->p_cred); 239 child->p_cred = parent->p_cred; 240 mutex_exit(parent->p_lock); 241 242 /* XXX: relies on parent process stalling during fork() */ 243 kauth_cred_hook(parent->p_cred, KAUTH_CRED_FORK, parent, 244 child); 245 } 246 247 void 248 kauth_proc_chroot(kauth_cred_t cred, struct cwdinfo *cwdi) 249 { 250 kauth_cred_hook(cred, KAUTH_CRED_CHROOT, cwdi, NULL); 251 } 252 253 uid_t 254 kauth_cred_getuid(kauth_cred_t cred) 255 { 256 KASSERT(cred != NULL); 257 KASSERT(cred != NOCRED); 258 KASSERT(cred != FSCRED); 259 260 return (cred->cr_uid); 261 } 262 263 uid_t 264 kauth_cred_geteuid(kauth_cred_t cred) 265 { 266 KASSERT(cred != NULL); 267 KASSERT(cred != NOCRED); 268 KASSERT(cred != FSCRED); 269 270 return (cred->cr_euid); 271 } 272 273 uid_t 274 kauth_cred_getsvuid(kauth_cred_t cred) 275 { 276 KASSERT(cred != NULL); 277 KASSERT(cred != NOCRED); 278 KASSERT(cred != FSCRED); 279 280 return (cred->cr_svuid); 281 } 282 283 gid_t 284 kauth_cred_getgid(kauth_cred_t cred) 285 { 286 KASSERT(cred != NULL); 287 KASSERT(cred != NOCRED); 288 KASSERT(cred != FSCRED); 289 290 return (cred->cr_gid); 291 } 292 293 gid_t 294 kauth_cred_getegid(kauth_cred_t cred) 295 { 296 KASSERT(cred != NULL); 297 KASSERT(cred != NOCRED); 298 KASSERT(cred != FSCRED); 299 300 return (cred->cr_egid); 301 } 302 303 gid_t 304 kauth_cred_getsvgid(kauth_cred_t cred) 305 { 306 KASSERT(cred != NULL); 307 KASSERT(cred != NOCRED); 308 KASSERT(cred != FSCRED); 309 310 return (cred->cr_svgid); 311 } 312 313 void 314 kauth_cred_setuid(kauth_cred_t cred, uid_t uid) 315 { 316 KASSERT(cred != NULL); 317 KASSERT(cred != NOCRED); 318 KASSERT(cred != FSCRED); 319 KASSERT(cred->cr_refcnt == 1); 320 321 cred->cr_uid = uid; 322 } 323 324 void 325 kauth_cred_seteuid(kauth_cred_t cred, uid_t uid) 326 { 327 KASSERT(cred != NULL); 328 KASSERT(cred != NOCRED); 329 KASSERT(cred != FSCRED); 330 KASSERT(cred->cr_refcnt == 1); 331 332 cred->cr_euid = uid; 333 } 334 335 void 336 kauth_cred_setsvuid(kauth_cred_t cred, uid_t uid) 337 { 338 KASSERT(cred != NULL); 339 KASSERT(cred != NOCRED); 340 KASSERT(cred != FSCRED); 341 KASSERT(cred->cr_refcnt == 1); 342 343 cred->cr_svuid = uid; 344 } 345 346 void 347 kauth_cred_setgid(kauth_cred_t cred, gid_t gid) 348 { 349 KASSERT(cred != NULL); 350 KASSERT(cred != NOCRED); 351 KASSERT(cred != FSCRED); 352 KASSERT(cred->cr_refcnt == 1); 353 354 cred->cr_gid = gid; 355 } 356 357 void 358 kauth_cred_setegid(kauth_cred_t cred, gid_t gid) 359 { 360 KASSERT(cred != NULL); 361 KASSERT(cred != NOCRED); 362 KASSERT(cred != FSCRED); 363 KASSERT(cred->cr_refcnt == 1); 364 365 cred->cr_egid = gid; 366 } 367 368 void 369 kauth_cred_setsvgid(kauth_cred_t cred, gid_t gid) 370 { 371 KASSERT(cred != NULL); 372 KASSERT(cred != NOCRED); 373 KASSERT(cred != FSCRED); 374 KASSERT(cred->cr_refcnt == 1); 375 376 cred->cr_svgid = gid; 377 } 378 379 /* Checks if gid is a member of the groups in cred. */ 380 int 381 kauth_cred_ismember_gid(kauth_cred_t cred, gid_t gid, int *resultp) 382 { 383 uint32_t i; 384 385 KASSERT(cred != NULL); 386 KASSERT(cred != NOCRED); 387 KASSERT(cred != FSCRED); 388 KASSERT(resultp != NULL); 389 390 *resultp = 0; 391 392 for (i = 0; i < cred->cr_ngroups; i++) 393 if (cred->cr_groups[i] == gid) { 394 *resultp = 1; 395 break; 396 } 397 398 return (0); 399 } 400 401 u_int 402 kauth_cred_ngroups(kauth_cred_t cred) 403 { 404 KASSERT(cred != NULL); 405 KASSERT(cred != NOCRED); 406 KASSERT(cred != FSCRED); 407 408 return (cred->cr_ngroups); 409 } 410 411 /* 412 * Return the group at index idx from the groups in cred. 413 */ 414 gid_t 415 kauth_cred_group(kauth_cred_t cred, u_int idx) 416 { 417 KASSERT(cred != NULL); 418 KASSERT(cred != NOCRED); 419 KASSERT(cred != FSCRED); 420 KASSERT(idx < cred->cr_ngroups); 421 422 return (cred->cr_groups[idx]); 423 } 424 425 /* XXX elad: gmuid is unused for now. */ 426 int 427 kauth_cred_setgroups(kauth_cred_t cred, const gid_t *grbuf, size_t len, 428 uid_t gmuid, enum uio_seg seg) 429 { 430 int error = 0; 431 432 KASSERT(cred != NULL); 433 KASSERT(cred != NOCRED); 434 KASSERT(cred != FSCRED); 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(secmodel_t 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(cred != NOCRED); 543 KASSERT(cred != FSCRED); 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(cred != NOCRED); 555 KASSERT(cred != FSCRED); 556 KASSERT(key != NULL); 557 558 specificdata_setspecific(kauth_domain, &cred->cr_sd, key->ks_key, data); 559 } 560 561 /* 562 * Match uids in two credentials. 563 */ 564 int 565 kauth_cred_uidmatch(kauth_cred_t cred1, kauth_cred_t cred2) 566 { 567 KASSERT(cred1 != NULL); 568 KASSERT(cred1 != NOCRED); 569 KASSERT(cred1 != FSCRED); 570 KASSERT(cred2 != NULL); 571 KASSERT(cred2 != NOCRED); 572 KASSERT(cred2 != FSCRED); 573 574 if (cred1->cr_uid == cred2->cr_uid || 575 cred1->cr_euid == cred2->cr_uid || 576 cred1->cr_uid == cred2->cr_euid || 577 cred1->cr_euid == cred2->cr_euid) 578 return (1); 579 580 return (0); 581 } 582 583 u_int 584 kauth_cred_getrefcnt(kauth_cred_t cred) 585 { 586 KASSERT(cred != NULL); 587 KASSERT(cred != NOCRED); 588 KASSERT(cred != FSCRED); 589 590 return (cred->cr_refcnt); 591 } 592 593 /* 594 * Convert userland credentials (struct uucred) to kauth_cred_t. 595 * XXX: For NFS & puffs 596 */ 597 void 598 kauth_uucred_to_cred(kauth_cred_t cred, const struct uucred *uuc) 599 { 600 KASSERT(cred != NULL); 601 KASSERT(cred != NOCRED); 602 KASSERT(cred != FSCRED); 603 KASSERT(uuc != NULL); 604 605 cred->cr_refcnt = 1; 606 cred->cr_uid = uuc->cr_uid; 607 cred->cr_euid = uuc->cr_uid; 608 cred->cr_svuid = uuc->cr_uid; 609 cred->cr_gid = uuc->cr_gid; 610 cred->cr_egid = uuc->cr_gid; 611 cred->cr_svgid = uuc->cr_gid; 612 cred->cr_ngroups = min(uuc->cr_ngroups, NGROUPS); 613 kauth_cred_setgroups(cred, __UNCONST(uuc->cr_groups), 614 cred->cr_ngroups, -1, UIO_SYSSPACE); 615 } 616 617 /* 618 * Convert kauth_cred_t to userland credentials (struct uucred). 619 * XXX: For NFS & puffs 620 */ 621 void 622 kauth_cred_to_uucred(struct uucred *uuc, const kauth_cred_t cred) 623 { 624 KASSERT(cred != NULL); 625 KASSERT(cred != NOCRED); 626 KASSERT(cred != FSCRED); 627 KASSERT(uuc != NULL); 628 int ng; 629 630 ng = min(cred->cr_ngroups, NGROUPS); 631 uuc->cr_uid = cred->cr_euid; 632 uuc->cr_gid = cred->cr_egid; 633 uuc->cr_ngroups = ng; 634 kauth_cred_getgroups(cred, uuc->cr_groups, ng, UIO_SYSSPACE); 635 } 636 637 /* 638 * Compare kauth_cred_t and uucred credentials. 639 * XXX: Modelled after crcmp() for NFS. 640 */ 641 int 642 kauth_cred_uucmp(kauth_cred_t cred, const struct uucred *uuc) 643 { 644 KASSERT(cred != NULL); 645 KASSERT(cred != NOCRED); 646 KASSERT(cred != FSCRED); 647 KASSERT(uuc != NULL); 648 649 if (cred->cr_euid == uuc->cr_uid && 650 cred->cr_egid == uuc->cr_gid && 651 cred->cr_ngroups == (uint32_t)uuc->cr_ngroups) { 652 int i; 653 654 /* Check if all groups from uuc appear in cred. */ 655 for (i = 0; i < uuc->cr_ngroups; i++) { 656 int ismember; 657 658 ismember = 0; 659 if (kauth_cred_ismember_gid(cred, uuc->cr_groups[i], 660 &ismember) != 0 || !ismember) 661 return (1); 662 } 663 664 return (0); 665 } 666 667 return (1); 668 } 669 670 /* 671 * Make a struct ucred out of a kauth_cred_t. For compatibility. 672 */ 673 void 674 kauth_cred_toucred(kauth_cred_t cred, struct ki_ucred *uc) 675 { 676 KASSERT(cred != NULL); 677 KASSERT(cred != NOCRED); 678 KASSERT(cred != FSCRED); 679 KASSERT(uc != NULL); 680 681 uc->cr_ref = cred->cr_refcnt; 682 uc->cr_uid = cred->cr_euid; 683 uc->cr_gid = cred->cr_egid; 684 uc->cr_ngroups = min(cred->cr_ngroups, __arraycount(uc->cr_groups)); 685 memcpy(uc->cr_groups, cred->cr_groups, 686 uc->cr_ngroups * sizeof(uc->cr_groups[0])); 687 } 688 689 /* 690 * Make a struct pcred out of a kauth_cred_t. For compatibility. 691 */ 692 void 693 kauth_cred_topcred(kauth_cred_t cred, struct ki_pcred *pc) 694 { 695 KASSERT(cred != NULL); 696 KASSERT(cred != NOCRED); 697 KASSERT(cred != FSCRED); 698 KASSERT(pc != NULL); 699 700 pc->p_pad = NULL; 701 pc->p_ruid = cred->cr_uid; 702 pc->p_svuid = cred->cr_svuid; 703 pc->p_rgid = cred->cr_gid; 704 pc->p_svgid = cred->cr_svgid; 705 pc->p_refcnt = cred->cr_refcnt; 706 } 707 708 /* 709 * Return kauth_cred_t for the current LWP. 710 */ 711 kauth_cred_t 712 kauth_cred_get(void) 713 { 714 return (curlwp->l_cred); 715 } 716 717 /* 718 * Returns a scope matching the provided id. 719 * Requires the scope list lock to be held by the caller. 720 */ 721 static kauth_scope_t 722 kauth_ifindscope(const char *id) 723 { 724 kauth_scope_t scope; 725 726 KASSERT(rw_lock_held(&kauth_lock)); 727 728 scope = NULL; 729 SIMPLEQ_FOREACH(scope, &scope_list, next_scope) { 730 if (strcmp(scope->id, id) == 0) 731 break; 732 } 733 734 return (scope); 735 } 736 737 /* 738 * Register a new scope. 739 * 740 * id - identifier for the scope 741 * callback - the scope's default listener 742 * cookie - cookie to be passed to the listener(s) 743 */ 744 kauth_scope_t 745 kauth_register_scope(const char *id, kauth_scope_callback_t callback, 746 void *cookie) 747 { 748 kauth_scope_t scope; 749 kauth_listener_t listener = NULL; /* XXX gcc */ 750 751 /* Sanitize input */ 752 if (id == NULL) 753 return (NULL); 754 755 /* Allocate space for a new scope and listener. */ 756 scope = kmem_alloc(sizeof(*scope), KM_SLEEP); 757 if (scope == NULL) 758 return NULL; 759 if (callback != NULL) { 760 listener = kmem_alloc(sizeof(*listener), KM_SLEEP); 761 if (listener == NULL) { 762 kmem_free(scope, sizeof(*scope)); 763 return (NULL); 764 } 765 } 766 767 /* 768 * Acquire scope list lock. 769 */ 770 rw_enter(&kauth_lock, RW_WRITER); 771 772 /* Check we don't already have a scope with the same id */ 773 if (kauth_ifindscope(id) != NULL) { 774 rw_exit(&kauth_lock); 775 776 kmem_free(scope, sizeof(*scope)); 777 if (callback != NULL) 778 kmem_free(listener, sizeof(*listener)); 779 780 return (NULL); 781 } 782 783 /* Initialize new scope with parameters */ 784 scope->id = id; 785 scope->cookie = cookie; 786 scope->nlisteners = 1; 787 788 SIMPLEQ_INIT(&scope->listenq); 789 790 /* Add default listener */ 791 if (callback != NULL) { 792 listener->func = callback; 793 listener->scope = scope; 794 listener->refcnt = 0; 795 SIMPLEQ_INSERT_HEAD(&scope->listenq, listener, listener_next); 796 } 797 798 /* Insert scope to scopes list */ 799 SIMPLEQ_INSERT_TAIL(&scope_list, scope, next_scope); 800 801 rw_exit(&kauth_lock); 802 803 return (scope); 804 } 805 806 /* 807 * Initialize the kernel authorization subsystem. 808 * 809 * Initialize the scopes list lock. 810 * Create specificdata domain. 811 * Register the credentials scope, used in kauth(9) internally. 812 * Register built-in scopes: generic, system, process, network, machdep, device. 813 */ 814 void 815 kauth_init(void) 816 { 817 rw_init(&kauth_lock); 818 819 kauth_cred_cache = pool_cache_init(sizeof(struct kauth_cred), 820 coherency_unit, 0, 0, "kcredpl", NULL, IPL_NONE, 821 NULL, NULL, NULL); 822 823 /* Create specificdata domain. */ 824 kauth_domain = specificdata_domain_create(); 825 826 /* Register credentials scope. */ 827 kauth_builtin_scope_cred = 828 kauth_register_scope(KAUTH_SCOPE_CRED, NULL, NULL); 829 830 /* Register generic scope. */ 831 kauth_builtin_scope_generic = kauth_register_scope(KAUTH_SCOPE_GENERIC, 832 NULL, NULL); 833 834 /* Register system scope. */ 835 kauth_builtin_scope_system = kauth_register_scope(KAUTH_SCOPE_SYSTEM, 836 NULL, NULL); 837 838 /* Register process scope. */ 839 kauth_builtin_scope_process = kauth_register_scope(KAUTH_SCOPE_PROCESS, 840 NULL, NULL); 841 842 /* Register network scope. */ 843 kauth_builtin_scope_network = kauth_register_scope(KAUTH_SCOPE_NETWORK, 844 NULL, NULL); 845 846 /* Register machdep scope. */ 847 kauth_builtin_scope_machdep = kauth_register_scope(KAUTH_SCOPE_MACHDEP, 848 NULL, NULL); 849 850 /* Register device scope. */ 851 kauth_builtin_scope_device = kauth_register_scope(KAUTH_SCOPE_DEVICE, 852 NULL, NULL); 853 854 /* Register vnode scope. */ 855 kauth_builtin_scope_vnode = kauth_register_scope(KAUTH_SCOPE_VNODE, 856 NULL, NULL); 857 } 858 859 /* 860 * Deregister a scope. 861 * Requires scope list lock to be held by the caller. 862 * 863 * scope - the scope to deregister 864 */ 865 void 866 kauth_deregister_scope(kauth_scope_t scope) 867 { 868 if (scope != NULL) { 869 /* Remove scope from list */ 870 SIMPLEQ_REMOVE(&scope_list, scope, kauth_scope, next_scope); 871 kmem_free(scope, sizeof(*scope)); 872 } 873 } 874 875 /* 876 * Register a listener. 877 * 878 * id - scope identifier. 879 * callback - the callback routine for the listener. 880 * cookie - cookie to pass unmoidfied to the callback. 881 */ 882 kauth_listener_t 883 kauth_listen_scope(const char *id, kauth_scope_callback_t callback, 884 void *cookie) 885 { 886 kauth_scope_t scope; 887 kauth_listener_t listener; 888 889 listener = kmem_alloc(sizeof(*listener), KM_SLEEP); 890 if (listener == NULL) 891 return (NULL); 892 893 rw_enter(&kauth_lock, RW_WRITER); 894 895 /* 896 * Find scope struct. 897 */ 898 scope = kauth_ifindscope(id); 899 if (scope == NULL) { 900 rw_exit(&kauth_lock); 901 kmem_free(listener, sizeof(*listener)); 902 return (NULL); 903 } 904 905 /* Allocate listener */ 906 907 /* Initialize listener with parameters */ 908 listener->func = callback; 909 listener->refcnt = 0; 910 911 /* Add listener to scope */ 912 SIMPLEQ_INSERT_TAIL(&scope->listenq, listener, listener_next); 913 914 /* Raise number of listeners on scope. */ 915 scope->nlisteners++; 916 listener->scope = scope; 917 918 rw_exit(&kauth_lock); 919 920 return (listener); 921 } 922 923 /* 924 * Deregister a listener. 925 * 926 * listener - listener reference as returned from kauth_listen_scope(). 927 */ 928 void 929 kauth_unlisten_scope(kauth_listener_t listener) 930 { 931 932 if (listener != NULL) { 933 rw_enter(&kauth_lock, RW_WRITER); 934 SIMPLEQ_REMOVE(&listener->scope->listenq, listener, 935 kauth_listener, listener_next); 936 listener->scope->nlisteners--; 937 rw_exit(&kauth_lock); 938 kmem_free(listener, sizeof(*listener)); 939 } 940 } 941 942 /* 943 * Authorize a request. 944 * 945 * scope - the scope of the request as defined by KAUTH_SCOPE_* or as 946 * returned from kauth_register_scope(). 947 * credential - credentials of the user ("actor") making the request. 948 * action - request identifier. 949 * arg[0-3] - passed unmodified to listener(s). 950 * 951 * Returns the aggregated result: 952 * - KAUTH_RESULT_ALLOW if there is at least one KAUTH_RESULT_ALLOW and 953 * zero KAUTH_DESULT_DENY 954 * - KAUTH_RESULT_DENY if there is at least one KAUTH_RESULT_DENY 955 * - KAUTH_RESULT_DEFER if there is nothing but KAUTH_RESULT_DEFER 956 */ 957 static int 958 kauth_authorize_action_internal(kauth_scope_t scope, kauth_cred_t cred, 959 kauth_action_t action, void *arg0, void *arg1, void *arg2, void *arg3) 960 { 961 kauth_listener_t listener; 962 int error, allow, fail; 963 964 KASSERT(cred != NULL); 965 KASSERT(action != 0); 966 967 /* Short-circuit requests coming from the kernel. */ 968 if (cred == NOCRED || cred == FSCRED) 969 return KAUTH_RESULT_ALLOW; 970 971 KASSERT(scope != NULL); 972 973 fail = 0; 974 allow = 0; 975 976 /* rw_enter(&kauth_lock, RW_READER); XXX not yet */ 977 SIMPLEQ_FOREACH(listener, &scope->listenq, listener_next) { 978 error = listener->func(cred, action, scope->cookie, arg0, 979 arg1, arg2, arg3); 980 981 if (error == KAUTH_RESULT_ALLOW) 982 allow = 1; 983 else if (error == KAUTH_RESULT_DENY) 984 fail = 1; 985 } 986 /* rw_exit(&kauth_lock); */ 987 988 if (fail) 989 return (KAUTH_RESULT_DENY); 990 991 if (allow) 992 return (KAUTH_RESULT_ALLOW); 993 994 return (KAUTH_RESULT_DEFER); 995 }; 996 997 int 998 kauth_authorize_action(kauth_scope_t scope, kauth_cred_t cred, 999 kauth_action_t action, void *arg0, void *arg1, void *arg2, void *arg3) 1000 { 1001 int r; 1002 1003 r = kauth_authorize_action_internal(scope, cred, action, arg0, arg1, 1004 arg2, arg3); 1005 1006 if (r == KAUTH_RESULT_DENY) 1007 return (EPERM); 1008 1009 if (r == KAUTH_RESULT_ALLOW) 1010 return (0); 1011 1012 if (secmodel_nsecmodels() == 0) 1013 return (0); 1014 1015 return (EPERM); 1016 } 1017 1018 /* 1019 * Generic scope authorization wrapper. 1020 */ 1021 int 1022 kauth_authorize_generic(kauth_cred_t cred, kauth_action_t action, void *arg0) 1023 { 1024 return (kauth_authorize_action(kauth_builtin_scope_generic, cred, 1025 action, arg0, NULL, NULL, NULL)); 1026 } 1027 1028 /* 1029 * System scope authorization wrapper. 1030 */ 1031 int 1032 kauth_authorize_system(kauth_cred_t cred, kauth_action_t action, 1033 enum kauth_system_req req, void *arg1, void *arg2, void *arg3) 1034 { 1035 return (kauth_authorize_action(kauth_builtin_scope_system, cred, 1036 action, (void *)req, arg1, arg2, arg3)); 1037 } 1038 1039 /* 1040 * Process scope authorization wrapper. 1041 */ 1042 int 1043 kauth_authorize_process(kauth_cred_t cred, kauth_action_t action, 1044 struct proc *p, void *arg1, void *arg2, void *arg3) 1045 { 1046 return (kauth_authorize_action(kauth_builtin_scope_process, cred, 1047 action, p, arg1, arg2, arg3)); 1048 } 1049 1050 /* 1051 * Network scope authorization wrapper. 1052 */ 1053 int 1054 kauth_authorize_network(kauth_cred_t cred, kauth_action_t action, 1055 enum kauth_network_req req, void *arg1, void *arg2, void *arg3) 1056 { 1057 return (kauth_authorize_action(kauth_builtin_scope_network, cred, 1058 action, (void *)req, arg1, arg2, arg3)); 1059 } 1060 1061 int 1062 kauth_authorize_machdep(kauth_cred_t cred, kauth_action_t action, 1063 void *arg0, void *arg1, void *arg2, void *arg3) 1064 { 1065 return (kauth_authorize_action(kauth_builtin_scope_machdep, cred, 1066 action, arg0, arg1, arg2, arg3)); 1067 } 1068 1069 int 1070 kauth_authorize_device(kauth_cred_t cred, kauth_action_t action, 1071 void *arg0, void *arg1, void *arg2, void *arg3) 1072 { 1073 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1074 action, arg0, arg1, arg2, arg3)); 1075 } 1076 1077 int 1078 kauth_authorize_device_tty(kauth_cred_t cred, kauth_action_t action, 1079 struct tty *tty) 1080 { 1081 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1082 action, tty, NULL, NULL, NULL)); 1083 } 1084 1085 int 1086 kauth_authorize_device_spec(kauth_cred_t cred, enum kauth_device_req req, 1087 struct vnode *vp) 1088 { 1089 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1090 KAUTH_DEVICE_RAWIO_SPEC, (void *)req, vp, NULL, NULL)); 1091 } 1092 1093 int 1094 kauth_authorize_device_passthru(kauth_cred_t cred, dev_t dev, u_long bits, 1095 void *data) 1096 { 1097 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1098 KAUTH_DEVICE_RAWIO_PASSTHRU, (void *)bits, (void *)(u_long)dev, 1099 data, NULL)); 1100 } 1101 1102 kauth_action_t 1103 kauth_mode_to_action(mode_t mode) 1104 { 1105 kauth_action_t action = 0; 1106 1107 if (mode & VREAD) 1108 action |= KAUTH_VNODE_READ_DATA; 1109 if (mode & VWRITE) 1110 action |= KAUTH_VNODE_WRITE_DATA; 1111 if (mode & VEXEC) 1112 action |= KAUTH_VNODE_EXECUTE; 1113 1114 return action; 1115 } 1116 1117 kauth_action_t 1118 kauth_extattr_action(mode_t access_mode) 1119 { 1120 kauth_action_t action = 0; 1121 1122 if (access_mode & VREAD) 1123 action |= KAUTH_VNODE_READ_EXTATTRIBUTES; 1124 if (access_mode & VWRITE) 1125 action |= KAUTH_VNODE_WRITE_EXTATTRIBUTES; 1126 1127 return action; 1128 } 1129 1130 int 1131 kauth_authorize_vnode(kauth_cred_t cred, kauth_action_t action, 1132 struct vnode *vp, struct vnode *dvp, int fs_decision) 1133 { 1134 int error; 1135 1136 error = kauth_authorize_action_internal(kauth_builtin_scope_vnode, cred, 1137 action, vp, dvp, NULL, NULL); 1138 1139 if (error == KAUTH_RESULT_DENY) 1140 return (EACCES); 1141 1142 if (error == KAUTH_RESULT_ALLOW) 1143 return (0); 1144 1145 /* 1146 * If the file-system does not support decision-before-action, we can 1147 * only short-circuit the operation (deny). If we're here, it means no 1148 * listener denied it, so our only alternative is to supposedly-allow 1149 * it and let the file-system have the last word. 1150 */ 1151 if (fs_decision == KAUTH_VNODE_REMOTEFS) 1152 return (0); 1153 1154 return (fs_decision); 1155 } 1156 1157 static int 1158 kauth_cred_hook(kauth_cred_t cred, kauth_action_t action, void *arg0, 1159 void *arg1) 1160 { 1161 int r; 1162 1163 r = kauth_authorize_action(kauth_builtin_scope_cred, cred, action, 1164 arg0, arg1, NULL, NULL); 1165 1166 #ifdef DIAGNOSTIC 1167 if (!SIMPLEQ_EMPTY(&kauth_builtin_scope_cred->listenq)) 1168 KASSERT(r == 0); 1169 #endif /* DIAGNOSTIC */ 1170 1171 return (r); 1172 } 1173