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