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