1 /* $NetBSD: kern_auth.c,v 1.77 2018/09/03 16:29:35 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.77 2018/09/03 16:29:35 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 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 = uimin(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 = uimin(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 = uimin(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 (callback != NULL) 758 listener = kmem_alloc(sizeof(*listener), KM_SLEEP); 759 760 /* 761 * Acquire scope list lock. 762 */ 763 rw_enter(&kauth_lock, RW_WRITER); 764 765 /* Check we don't already have a scope with the same id */ 766 if (kauth_ifindscope(id) != NULL) { 767 rw_exit(&kauth_lock); 768 769 kmem_free(scope, sizeof(*scope)); 770 if (callback != NULL) 771 kmem_free(listener, sizeof(*listener)); 772 773 return (NULL); 774 } 775 776 /* Initialize new scope with parameters */ 777 scope->id = id; 778 scope->cookie = cookie; 779 scope->nlisteners = 1; 780 781 SIMPLEQ_INIT(&scope->listenq); 782 783 /* Add default listener */ 784 if (callback != NULL) { 785 listener->func = callback; 786 listener->scope = scope; 787 listener->refcnt = 0; 788 SIMPLEQ_INSERT_HEAD(&scope->listenq, listener, listener_next); 789 } 790 791 /* Insert scope to scopes list */ 792 SIMPLEQ_INSERT_TAIL(&scope_list, scope, next_scope); 793 794 rw_exit(&kauth_lock); 795 796 return (scope); 797 } 798 799 /* 800 * Initialize the kernel authorization subsystem. 801 * 802 * Initialize the scopes list lock. 803 * Create specificdata domain. 804 * Register the credentials scope, used in kauth(9) internally. 805 * Register built-in scopes: generic, system, process, network, machdep, device. 806 */ 807 void 808 kauth_init(void) 809 { 810 rw_init(&kauth_lock); 811 812 kauth_cred_cache = pool_cache_init(sizeof(struct kauth_cred), 813 coherency_unit, 0, 0, "kcredpl", NULL, IPL_NONE, 814 NULL, NULL, NULL); 815 816 /* Create specificdata domain. */ 817 kauth_domain = specificdata_domain_create(); 818 819 /* Register credentials scope. */ 820 kauth_builtin_scope_cred = 821 kauth_register_scope(KAUTH_SCOPE_CRED, NULL, NULL); 822 823 /* Register generic scope. */ 824 kauth_builtin_scope_generic = kauth_register_scope(KAUTH_SCOPE_GENERIC, 825 NULL, NULL); 826 827 /* Register system scope. */ 828 kauth_builtin_scope_system = kauth_register_scope(KAUTH_SCOPE_SYSTEM, 829 NULL, NULL); 830 831 /* Register process scope. */ 832 kauth_builtin_scope_process = kauth_register_scope(KAUTH_SCOPE_PROCESS, 833 NULL, NULL); 834 835 /* Register network scope. */ 836 kauth_builtin_scope_network = kauth_register_scope(KAUTH_SCOPE_NETWORK, 837 NULL, NULL); 838 839 /* Register machdep scope. */ 840 kauth_builtin_scope_machdep = kauth_register_scope(KAUTH_SCOPE_MACHDEP, 841 NULL, NULL); 842 843 /* Register device scope. */ 844 kauth_builtin_scope_device = kauth_register_scope(KAUTH_SCOPE_DEVICE, 845 NULL, NULL); 846 847 /* Register vnode scope. */ 848 kauth_builtin_scope_vnode = kauth_register_scope(KAUTH_SCOPE_VNODE, 849 NULL, NULL); 850 } 851 852 /* 853 * Deregister a scope. 854 * Requires scope list lock to be held by the caller. 855 * 856 * scope - the scope to deregister 857 */ 858 void 859 kauth_deregister_scope(kauth_scope_t scope) 860 { 861 if (scope != NULL) { 862 /* Remove scope from list */ 863 SIMPLEQ_REMOVE(&scope_list, scope, kauth_scope, next_scope); 864 kmem_free(scope, sizeof(*scope)); 865 } 866 } 867 868 /* 869 * Register a listener. 870 * 871 * id - scope identifier. 872 * callback - the callback routine for the listener. 873 * cookie - cookie to pass unmoidfied to the callback. 874 */ 875 kauth_listener_t 876 kauth_listen_scope(const char *id, kauth_scope_callback_t callback, 877 void *cookie) 878 { 879 kauth_scope_t scope; 880 kauth_listener_t listener; 881 882 listener = kmem_alloc(sizeof(*listener), KM_SLEEP); 883 rw_enter(&kauth_lock, RW_WRITER); 884 885 /* 886 * Find scope struct. 887 */ 888 scope = kauth_ifindscope(id); 889 if (scope == NULL) { 890 rw_exit(&kauth_lock); 891 kmem_free(listener, sizeof(*listener)); 892 return (NULL); 893 } 894 895 /* Allocate listener */ 896 897 /* Initialize listener with parameters */ 898 listener->func = callback; 899 listener->refcnt = 0; 900 901 /* Add listener to scope */ 902 SIMPLEQ_INSERT_TAIL(&scope->listenq, listener, listener_next); 903 904 /* Raise number of listeners on scope. */ 905 scope->nlisteners++; 906 listener->scope = scope; 907 908 rw_exit(&kauth_lock); 909 910 return (listener); 911 } 912 913 /* 914 * Deregister a listener. 915 * 916 * listener - listener reference as returned from kauth_listen_scope(). 917 */ 918 void 919 kauth_unlisten_scope(kauth_listener_t listener) 920 { 921 922 if (listener != NULL) { 923 rw_enter(&kauth_lock, RW_WRITER); 924 SIMPLEQ_REMOVE(&listener->scope->listenq, listener, 925 kauth_listener, listener_next); 926 listener->scope->nlisteners--; 927 rw_exit(&kauth_lock); 928 kmem_free(listener, sizeof(*listener)); 929 } 930 } 931 932 /* 933 * Authorize a request. 934 * 935 * scope - the scope of the request as defined by KAUTH_SCOPE_* or as 936 * returned from kauth_register_scope(). 937 * credential - credentials of the user ("actor") making the request. 938 * action - request identifier. 939 * arg[0-3] - passed unmodified to listener(s). 940 * 941 * Returns the aggregated result: 942 * - KAUTH_RESULT_ALLOW if there is at least one KAUTH_RESULT_ALLOW and 943 * zero KAUTH_DESULT_DENY 944 * - KAUTH_RESULT_DENY if there is at least one KAUTH_RESULT_DENY 945 * - KAUTH_RESULT_DEFER if there is nothing but KAUTH_RESULT_DEFER 946 */ 947 static int 948 kauth_authorize_action_internal(kauth_scope_t scope, kauth_cred_t cred, 949 kauth_action_t action, void *arg0, void *arg1, void *arg2, void *arg3) 950 { 951 kauth_listener_t listener; 952 int error, allow, fail; 953 954 KASSERT(cred != NULL); 955 KASSERT(action != 0); 956 957 /* Short-circuit requests coming from the kernel. */ 958 if (cred == NOCRED || cred == FSCRED) 959 return KAUTH_RESULT_ALLOW; 960 961 KASSERT(scope != NULL); 962 963 fail = 0; 964 allow = 0; 965 966 /* rw_enter(&kauth_lock, RW_READER); XXX not yet */ 967 SIMPLEQ_FOREACH(listener, &scope->listenq, listener_next) { 968 error = listener->func(cred, action, scope->cookie, arg0, 969 arg1, arg2, arg3); 970 971 if (error == KAUTH_RESULT_ALLOW) 972 allow = 1; 973 else if (error == KAUTH_RESULT_DENY) 974 fail = 1; 975 } 976 /* rw_exit(&kauth_lock); */ 977 978 if (fail) 979 return (KAUTH_RESULT_DENY); 980 981 if (allow) 982 return (KAUTH_RESULT_ALLOW); 983 984 return (KAUTH_RESULT_DEFER); 985 }; 986 987 int 988 kauth_authorize_action(kauth_scope_t scope, kauth_cred_t cred, 989 kauth_action_t action, void *arg0, void *arg1, void *arg2, void *arg3) 990 { 991 int r; 992 993 r = kauth_authorize_action_internal(scope, cred, action, arg0, arg1, 994 arg2, arg3); 995 996 if (r == KAUTH_RESULT_DENY) 997 return (EPERM); 998 999 if (r == KAUTH_RESULT_ALLOW) 1000 return (0); 1001 1002 if (secmodel_nsecmodels() == 0) 1003 return (0); 1004 1005 return (EPERM); 1006 } 1007 1008 /* 1009 * Generic scope authorization wrapper. 1010 */ 1011 int 1012 kauth_authorize_generic(kauth_cred_t cred, kauth_action_t action, void *arg0) 1013 { 1014 return (kauth_authorize_action(kauth_builtin_scope_generic, cred, 1015 action, arg0, NULL, NULL, NULL)); 1016 } 1017 1018 /* 1019 * System scope authorization wrapper. 1020 */ 1021 int 1022 kauth_authorize_system(kauth_cred_t cred, kauth_action_t action, 1023 enum kauth_system_req req, void *arg1, void *arg2, void *arg3) 1024 { 1025 return (kauth_authorize_action(kauth_builtin_scope_system, cred, 1026 action, (void *)req, arg1, arg2, arg3)); 1027 } 1028 1029 /* 1030 * Process scope authorization wrapper. 1031 */ 1032 int 1033 kauth_authorize_process(kauth_cred_t cred, kauth_action_t action, 1034 struct proc *p, void *arg1, void *arg2, void *arg3) 1035 { 1036 return (kauth_authorize_action(kauth_builtin_scope_process, cred, 1037 action, p, arg1, arg2, arg3)); 1038 } 1039 1040 /* 1041 * Network scope authorization wrapper. 1042 */ 1043 int 1044 kauth_authorize_network(kauth_cred_t cred, kauth_action_t action, 1045 enum kauth_network_req req, void *arg1, void *arg2, void *arg3) 1046 { 1047 return (kauth_authorize_action(kauth_builtin_scope_network, cred, 1048 action, (void *)req, arg1, arg2, arg3)); 1049 } 1050 1051 int 1052 kauth_authorize_machdep(kauth_cred_t cred, kauth_action_t action, 1053 void *arg0, void *arg1, void *arg2, void *arg3) 1054 { 1055 return (kauth_authorize_action(kauth_builtin_scope_machdep, cred, 1056 action, arg0, arg1, arg2, arg3)); 1057 } 1058 1059 int 1060 kauth_authorize_device(kauth_cred_t cred, kauth_action_t action, 1061 void *arg0, void *arg1, void *arg2, void *arg3) 1062 { 1063 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1064 action, arg0, arg1, arg2, arg3)); 1065 } 1066 1067 int 1068 kauth_authorize_device_tty(kauth_cred_t cred, kauth_action_t action, 1069 struct tty *tty) 1070 { 1071 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1072 action, tty, NULL, NULL, NULL)); 1073 } 1074 1075 int 1076 kauth_authorize_device_spec(kauth_cred_t cred, enum kauth_device_req req, 1077 struct vnode *vp) 1078 { 1079 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1080 KAUTH_DEVICE_RAWIO_SPEC, (void *)req, vp, NULL, NULL)); 1081 } 1082 1083 int 1084 kauth_authorize_device_passthru(kauth_cred_t cred, dev_t dev, u_long bits, 1085 void *data) 1086 { 1087 return (kauth_authorize_action(kauth_builtin_scope_device, cred, 1088 KAUTH_DEVICE_RAWIO_PASSTHRU, (void *)bits, (void *)(u_long)dev, 1089 data, NULL)); 1090 } 1091 1092 kauth_action_t 1093 kauth_mode_to_action(mode_t mode) 1094 { 1095 kauth_action_t action = 0; 1096 1097 if (mode & VREAD) 1098 action |= KAUTH_VNODE_READ_DATA; 1099 if (mode & VWRITE) 1100 action |= KAUTH_VNODE_WRITE_DATA; 1101 if (mode & VEXEC) 1102 action |= KAUTH_VNODE_EXECUTE; 1103 1104 return action; 1105 } 1106 1107 kauth_action_t 1108 kauth_extattr_action(mode_t access_mode) 1109 { 1110 kauth_action_t action = 0; 1111 1112 if (access_mode & VREAD) 1113 action |= KAUTH_VNODE_READ_EXTATTRIBUTES; 1114 if (access_mode & VWRITE) 1115 action |= KAUTH_VNODE_WRITE_EXTATTRIBUTES; 1116 1117 return action; 1118 } 1119 1120 int 1121 kauth_authorize_vnode(kauth_cred_t cred, kauth_action_t action, 1122 struct vnode *vp, struct vnode *dvp, int fs_decision) 1123 { 1124 int error; 1125 1126 error = kauth_authorize_action_internal(kauth_builtin_scope_vnode, cred, 1127 action, vp, dvp, NULL, NULL); 1128 1129 if (error == KAUTH_RESULT_DENY) 1130 return (EACCES); 1131 1132 if (error == KAUTH_RESULT_ALLOW) 1133 return (0); 1134 1135 /* 1136 * If the file-system does not support decision-before-action, we can 1137 * only short-circuit the operation (deny). If we're here, it means no 1138 * listener denied it, so our only alternative is to supposedly-allow 1139 * it and let the file-system have the last word. 1140 */ 1141 if (fs_decision == KAUTH_VNODE_REMOTEFS) 1142 return (0); 1143 1144 return (fs_decision); 1145 } 1146 1147 static int 1148 kauth_cred_hook(kauth_cred_t cred, kauth_action_t action, void *arg0, 1149 void *arg1) 1150 { 1151 int r; 1152 1153 r = kauth_authorize_action(kauth_builtin_scope_cred, cred, action, 1154 arg0, arg1, NULL, NULL); 1155 1156 #ifdef DIAGNOSTIC 1157 if (!SIMPLEQ_EMPTY(&kauth_builtin_scope_cred->listenq)) 1158 KASSERT(r == 0); 1159 #endif /* DIAGNOSTIC */ 1160 1161 return (r); 1162 } 1163