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