1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 28 /* 29 * University Copyright- Copyright (c) 1982, 1986, 1988 30 * The Regents of the University of California 31 * All Rights Reserved 32 * 33 * University Acknowledgment- Portions of this document are derived from 34 * software developed by the University of California, Berkeley, and its 35 * contributors. 36 */ 37 38 #include <sys/types.h> 39 #include <sys/sysmacros.h> 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/cred_impl.h> 43 #include <sys/policy.h> 44 #include <sys/vnode.h> 45 #include <sys/errno.h> 46 #include <sys/kmem.h> 47 #include <sys/user.h> 48 #include <sys/proc.h> 49 #include <sys/syscall.h> 50 #include <sys/debug.h> 51 #include <sys/atomic.h> 52 #include <sys/ucred.h> 53 #include <sys/prsystm.h> 54 #include <sys/modctl.h> 55 #include <sys/avl.h> 56 #include <sys/door.h> 57 #include <c2/audit.h> 58 #include <sys/zone.h> 59 #include <sys/tsol/label.h> 60 #include <sys/sid.h> 61 #include <sys/idmap.h> 62 #include <sys/klpd.h> 63 #include <sys/varargs.h> 64 #include <sys/sysconf.h> 65 #include <util/qsort.h> 66 67 68 /* Ephemeral IDs Zones specific data */ 69 typedef struct ephemeral_zsd { 70 uid_t min_uid; 71 uid_t last_uid; 72 gid_t min_gid; 73 gid_t last_gid; 74 kmutex_t eph_lock; 75 cred_t *eph_nobody; 76 } ephemeral_zsd_t; 77 78 /* Supplemental groups list. */ 79 typedef struct credgrp { 80 uint_t crg_ref; 81 uint_t crg_ngroups; 82 gid_t crg_groups[1]; 83 } credgrp_t; 84 85 static void crgrphold(credgrp_t *); 86 87 #define CREDGRPSZ(ngrp) (sizeof (credgrp_t) + ((ngrp - 1) * sizeof (gid_t))) 88 89 static kmutex_t ephemeral_zone_mutex; 90 static zone_key_t ephemeral_zone_key; 91 92 static struct kmem_cache *cred_cache; 93 static size_t crsize = 0; 94 static int audoff = 0; 95 uint32_t ucredsize; 96 cred_t *kcred; 97 static cred_t *dummycr; 98 99 int rstlink; /* link(2) restricted to files owned by user? */ 100 101 static int get_c2audit_load(void); 102 103 #define CR_AUINFO(c) (auditinfo_addr_t *)((audoff == 0) ? NULL : \ 104 ((char *)(c)) + audoff) 105 106 #define REMOTE_PEER_CRED(c) ((c)->cr_gid == -1) 107 108 #define BIN_GROUP_SEARCH_CUTOFF 16 109 110 static boolean_t hasephids = B_FALSE; 111 112 static ephemeral_zsd_t * 113 get_ephemeral_zsd(zone_t *zone) 114 { 115 ephemeral_zsd_t *eph_zsd; 116 117 eph_zsd = zone_getspecific(ephemeral_zone_key, zone); 118 if (eph_zsd != NULL) { 119 return (eph_zsd); 120 } 121 122 mutex_enter(&ephemeral_zone_mutex); 123 eph_zsd = zone_getspecific(ephemeral_zone_key, zone); 124 if (eph_zsd == NULL) { 125 eph_zsd = kmem_zalloc(sizeof (ephemeral_zsd_t), KM_SLEEP); 126 eph_zsd->min_uid = MAXUID; 127 eph_zsd->last_uid = IDMAP_WK__MAX_UID; 128 eph_zsd->min_gid = MAXUID; 129 eph_zsd->last_gid = IDMAP_WK__MAX_GID; 130 mutex_init(&eph_zsd->eph_lock, NULL, MUTEX_DEFAULT, NULL); 131 132 /* 133 * nobody is used to map SID containing CRs. 134 */ 135 eph_zsd->eph_nobody = crdup(zone->zone_kcred); 136 (void) crsetugid(eph_zsd->eph_nobody, UID_NOBODY, GID_NOBODY); 137 CR_FLAGS(eph_zsd->eph_nobody) = 0; 138 eph_zsd->eph_nobody->cr_zone = zone; 139 140 (void) zone_setspecific(ephemeral_zone_key, zone, eph_zsd); 141 } 142 mutex_exit(&ephemeral_zone_mutex); 143 return (eph_zsd); 144 } 145 146 static cred_t *crdup_flags(const cred_t *, int); 147 static cred_t *cralloc_flags(int); 148 149 /* 150 * This function is called when a zone is destroyed 151 */ 152 static void 153 /* ARGSUSED */ 154 destroy_ephemeral_zsd(zoneid_t zone_id, void *arg) 155 { 156 ephemeral_zsd_t *eph_zsd = arg; 157 if (eph_zsd != NULL) { 158 mutex_destroy(&eph_zsd->eph_lock); 159 crfree(eph_zsd->eph_nobody); 160 kmem_free(eph_zsd, sizeof (ephemeral_zsd_t)); 161 } 162 } 163 164 165 166 /* 167 * Initialize credentials data structures. 168 */ 169 170 void 171 cred_init(void) 172 { 173 priv_init(); 174 175 crsize = sizeof (cred_t); 176 177 if (get_c2audit_load() > 0) { 178 #ifdef _LP64 179 /* assure audit context is 64-bit aligned */ 180 audoff = (crsize + 181 sizeof (int64_t) - 1) & ~(sizeof (int64_t) - 1); 182 #else /* _LP64 */ 183 audoff = crsize; 184 #endif /* _LP64 */ 185 crsize = audoff + sizeof (auditinfo_addr_t); 186 crsize = (crsize + sizeof (int) - 1) & ~(sizeof (int) - 1); 187 } 188 189 cred_cache = kmem_cache_create("cred_cache", crsize, 0, 190 NULL, NULL, NULL, NULL, NULL, 0); 191 192 /* 193 * dummycr is used to copy initial state for creds. 194 */ 195 dummycr = cralloc(); 196 bzero(dummycr, crsize); 197 dummycr->cr_ref = 1; 198 dummycr->cr_uid = (uid_t)-1; 199 dummycr->cr_gid = (gid_t)-1; 200 dummycr->cr_ruid = (uid_t)-1; 201 dummycr->cr_rgid = (gid_t)-1; 202 dummycr->cr_suid = (uid_t)-1; 203 dummycr->cr_sgid = (gid_t)-1; 204 205 206 /* 207 * kcred is used by anything that needs all privileges; it's 208 * also the template used for crget as it has all the compatible 209 * sets filled in. 210 */ 211 kcred = cralloc(); 212 213 bzero(kcred, crsize); 214 kcred->cr_ref = 1; 215 216 /* kcred is never freed, so we don't need zone_cred_hold here */ 217 kcred->cr_zone = &zone0; 218 219 priv_fillset(&CR_LPRIV(kcred)); 220 CR_IPRIV(kcred) = *priv_basic; 221 222 /* Not a basic privilege, if chown is not restricted add it to I0 */ 223 if (!rstchown) 224 priv_addset(&CR_IPRIV(kcred), PRIV_FILE_CHOWN_SELF); 225 226 /* Basic privilege, if link is restricted remove it from I0 */ 227 if (rstlink) 228 priv_delset(&CR_IPRIV(kcred), PRIV_FILE_LINK_ANY); 229 230 CR_EPRIV(kcred) = CR_PPRIV(kcred) = CR_IPRIV(kcred); 231 232 CR_FLAGS(kcred) = NET_MAC_AWARE; 233 234 /* 235 * Set up credentials of p0. 236 */ 237 ttoproc(curthread)->p_cred = kcred; 238 curthread->t_cred = kcred; 239 240 ucredsize = UCRED_SIZE; 241 242 mutex_init(&ephemeral_zone_mutex, NULL, MUTEX_DEFAULT, NULL); 243 zone_key_create(&ephemeral_zone_key, NULL, NULL, destroy_ephemeral_zsd); 244 } 245 246 /* 247 * Allocate (nearly) uninitialized cred_t. 248 */ 249 static cred_t * 250 cralloc_flags(int flgs) 251 { 252 cred_t *cr = kmem_cache_alloc(cred_cache, flgs); 253 254 if (cr == NULL) 255 return (NULL); 256 257 cr->cr_ref = 1; /* So we can crfree() */ 258 cr->cr_zone = NULL; 259 cr->cr_label = NULL; 260 cr->cr_ksid = NULL; 261 cr->cr_klpd = NULL; 262 cr->cr_grps = NULL; 263 return (cr); 264 } 265 266 cred_t * 267 cralloc(void) 268 { 269 return (cralloc_flags(KM_SLEEP)); 270 } 271 272 /* 273 * As cralloc but prepared for ksid change (if appropriate). 274 */ 275 cred_t * 276 cralloc_ksid(void) 277 { 278 cred_t *cr = cralloc(); 279 if (hasephids) 280 cr->cr_ksid = kcrsid_alloc(); 281 return (cr); 282 } 283 284 /* 285 * Allocate a initialized cred structure and crhold() it. 286 * Initialized means: all ids 0, group count 0, L=Full, E=P=I=I0 287 */ 288 cred_t * 289 crget(void) 290 { 291 cred_t *cr = kmem_cache_alloc(cred_cache, KM_SLEEP); 292 293 bcopy(kcred, cr, crsize); 294 cr->cr_ref = 1; 295 zone_cred_hold(cr->cr_zone); 296 if (cr->cr_label) 297 label_hold(cr->cr_label); 298 ASSERT(cr->cr_klpd == NULL); 299 ASSERT(cr->cr_grps == NULL); 300 return (cr); 301 } 302 303 /* 304 * Broadcast the cred to all the threads in the process. 305 * The current thread's credentials can be set right away, but other 306 * threads must wait until the start of the next system call or trap. 307 * This avoids changing the cred in the middle of a system call. 308 * 309 * The cred has already been held for the process and the thread (2 holds), 310 * and p->p_cred set. 311 * 312 * p->p_crlock shouldn't be held here, since p_lock must be acquired. 313 */ 314 void 315 crset(proc_t *p, cred_t *cr) 316 { 317 kthread_id_t t; 318 kthread_id_t first; 319 cred_t *oldcr; 320 321 ASSERT(p == curproc); /* assumes p_lwpcnt can't change */ 322 323 /* 324 * DTrace accesses t_cred in probe context. t_cred must always be 325 * either NULL, or point to a valid, allocated cred structure. 326 */ 327 t = curthread; 328 oldcr = t->t_cred; 329 t->t_cred = cr; /* the cred is held by caller for this thread */ 330 crfree(oldcr); /* free the old cred for the thread */ 331 332 /* 333 * Broadcast to other threads, if any. 334 */ 335 if (p->p_lwpcnt > 1) { 336 mutex_enter(&p->p_lock); /* to keep thread list safe */ 337 first = curthread; 338 for (t = first->t_forw; t != first; t = t->t_forw) 339 t->t_pre_sys = 1; /* so syscall will get new cred */ 340 mutex_exit(&p->p_lock); 341 } 342 } 343 344 /* 345 * Put a hold on a cred structure. 346 */ 347 void 348 crhold(cred_t *cr) 349 { 350 ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0); 351 atomic_add_32(&cr->cr_ref, 1); 352 } 353 354 /* 355 * Release previous hold on a cred structure. Free it if refcnt == 0. 356 * If cred uses label different from zone label, free it. 357 */ 358 void 359 crfree(cred_t *cr) 360 { 361 ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0); 362 if (atomic_add_32_nv(&cr->cr_ref, -1) == 0) { 363 ASSERT(cr != kcred); 364 if (cr->cr_label) 365 label_rele(cr->cr_label); 366 if (cr->cr_klpd) 367 crklpd_rele(cr->cr_klpd); 368 if (cr->cr_zone) 369 zone_cred_rele(cr->cr_zone); 370 if (cr->cr_ksid) 371 kcrsid_rele(cr->cr_ksid); 372 if (cr->cr_grps) 373 crgrprele(cr->cr_grps); 374 375 kmem_cache_free(cred_cache, cr); 376 } 377 } 378 379 /* 380 * Copy a cred structure to a new one and free the old one. 381 * The new cred will have two references. One for the calling process, 382 * and one for the thread. 383 */ 384 cred_t * 385 crcopy(cred_t *cr) 386 { 387 cred_t *newcr; 388 389 newcr = cralloc(); 390 bcopy(cr, newcr, crsize); 391 if (newcr->cr_zone) 392 zone_cred_hold(newcr->cr_zone); 393 if (newcr->cr_label) 394 label_hold(newcr->cr_label); 395 if (newcr->cr_ksid) 396 kcrsid_hold(newcr->cr_ksid); 397 if (newcr->cr_klpd) 398 crklpd_hold(newcr->cr_klpd); 399 if (newcr->cr_grps) 400 crgrphold(newcr->cr_grps); 401 crfree(cr); 402 newcr->cr_ref = 2; /* caller gets two references */ 403 return (newcr); 404 } 405 406 /* 407 * Copy a cred structure to a new one and free the old one. 408 * The new cred will have two references. One for the calling process, 409 * and one for the thread. 410 * This variation on crcopy uses a pre-allocated structure for the 411 * "new" cred. 412 */ 413 void 414 crcopy_to(cred_t *oldcr, cred_t *newcr) 415 { 416 credsid_t *nkcr = newcr->cr_ksid; 417 418 bcopy(oldcr, newcr, crsize); 419 if (newcr->cr_zone) 420 zone_cred_hold(newcr->cr_zone); 421 if (newcr->cr_label) 422 label_hold(newcr->cr_label); 423 if (newcr->cr_klpd) 424 crklpd_hold(newcr->cr_klpd); 425 if (newcr->cr_grps) 426 crgrphold(newcr->cr_grps); 427 if (nkcr) { 428 newcr->cr_ksid = nkcr; 429 kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid); 430 } else if (newcr->cr_ksid) 431 kcrsid_hold(newcr->cr_ksid); 432 crfree(oldcr); 433 newcr->cr_ref = 2; /* caller gets two references */ 434 } 435 436 /* 437 * Dup a cred struct to a new held one. 438 * The old cred is not freed. 439 */ 440 static cred_t * 441 crdup_flags(const cred_t *cr, int flgs) 442 { 443 cred_t *newcr; 444 445 newcr = cralloc_flags(flgs); 446 447 if (newcr == NULL) 448 return (NULL); 449 450 bcopy(cr, newcr, crsize); 451 if (newcr->cr_zone) 452 zone_cred_hold(newcr->cr_zone); 453 if (newcr->cr_label) 454 label_hold(newcr->cr_label); 455 if (newcr->cr_klpd) 456 crklpd_hold(newcr->cr_klpd); 457 if (newcr->cr_ksid) 458 kcrsid_hold(newcr->cr_ksid); 459 if (newcr->cr_grps) 460 crgrphold(newcr->cr_grps); 461 newcr->cr_ref = 1; 462 return (newcr); 463 } 464 465 cred_t * 466 crdup(cred_t *cr) 467 { 468 return (crdup_flags(cr, KM_SLEEP)); 469 } 470 471 /* 472 * Dup a cred struct to a new held one. 473 * The old cred is not freed. 474 * This variation on crdup uses a pre-allocated structure for the 475 * "new" cred. 476 */ 477 void 478 crdup_to(cred_t *oldcr, cred_t *newcr) 479 { 480 credsid_t *nkcr = newcr->cr_ksid; 481 482 bcopy(oldcr, newcr, crsize); 483 if (newcr->cr_zone) 484 zone_cred_hold(newcr->cr_zone); 485 if (newcr->cr_label) 486 label_hold(newcr->cr_label); 487 if (newcr->cr_klpd) 488 crklpd_hold(newcr->cr_klpd); 489 if (newcr->cr_grps) 490 crgrphold(newcr->cr_grps); 491 if (nkcr) { 492 newcr->cr_ksid = nkcr; 493 kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid); 494 } else if (newcr->cr_ksid) 495 kcrsid_hold(newcr->cr_ksid); 496 newcr->cr_ref = 1; 497 } 498 499 /* 500 * Return the (held) credentials for the current running process. 501 */ 502 cred_t * 503 crgetcred(void) 504 { 505 cred_t *cr; 506 proc_t *p; 507 508 p = ttoproc(curthread); 509 mutex_enter(&p->p_crlock); 510 crhold(cr = p->p_cred); 511 mutex_exit(&p->p_crlock); 512 return (cr); 513 } 514 515 /* 516 * Backward compatibility check for suser(). 517 * Accounting flag is now set in the policy functions; auditing is 518 * done through use of privilege in the audit trail. 519 */ 520 int 521 suser(cred_t *cr) 522 { 523 return (PRIV_POLICY(cr, PRIV_SYS_SUSER_COMPAT, B_FALSE, EPERM, NULL) 524 == 0); 525 } 526 527 /* 528 * Determine whether the supplied group id is a member of the group 529 * described by the supplied credentials. 530 */ 531 int 532 groupmember(gid_t gid, const cred_t *cr) 533 { 534 if (gid == cr->cr_gid) 535 return (1); 536 return (supgroupmember(gid, cr)); 537 } 538 539 /* 540 * As groupmember but only check against the supplemental groups. 541 */ 542 int 543 supgroupmember(gid_t gid, const cred_t *cr) 544 { 545 int hi, lo; 546 credgrp_t *grps = cr->cr_grps; 547 const gid_t *gp, *endgp; 548 549 if (grps == NULL) 550 return (0); 551 552 /* For a small number of groups, use sequentials search. */ 553 if (grps->crg_ngroups <= BIN_GROUP_SEARCH_CUTOFF) { 554 endgp = &grps->crg_groups[grps->crg_ngroups]; 555 for (gp = grps->crg_groups; gp < endgp; gp++) 556 if (*gp == gid) 557 return (1); 558 return (0); 559 } 560 561 /* We use binary search when we have many groups. */ 562 lo = 0; 563 hi = grps->crg_ngroups - 1; 564 gp = grps->crg_groups; 565 566 do { 567 int m = (lo + hi) / 2; 568 569 if (gid > gp[m]) 570 lo = m + 1; 571 else if (gid < gp[m]) 572 hi = m - 1; 573 else 574 return (1); 575 } while (lo <= hi); 576 577 return (0); 578 } 579 580 /* 581 * This function is called to check whether the credentials set 582 * "scrp" has permission to act on credentials set "tcrp". It enforces the 583 * permission requirements needed to send a signal to a process. 584 * The same requirements are imposed by other system calls, however. 585 * 586 * The rules are: 587 * (1) if the credentials are the same, the check succeeds 588 * (2) if the zone ids don't match, and scrp is not in the global zone or 589 * does not have the PRIV_PROC_ZONE privilege, the check fails 590 * (3) if the real or effective user id of scrp matches the real or saved 591 * user id of tcrp or scrp has the PRIV_PROC_OWNER privilege, the check 592 * succeeds 593 * (4) otherwise, the check fails 594 */ 595 int 596 hasprocperm(const cred_t *tcrp, const cred_t *scrp) 597 { 598 if (scrp == tcrp) 599 return (1); 600 if (scrp->cr_zone != tcrp->cr_zone && 601 (scrp->cr_zone != global_zone || 602 secpolicy_proc_zone(scrp) != 0)) 603 return (0); 604 if (scrp->cr_uid == tcrp->cr_ruid || 605 scrp->cr_ruid == tcrp->cr_ruid || 606 scrp->cr_uid == tcrp->cr_suid || 607 scrp->cr_ruid == tcrp->cr_suid || 608 !PRIV_POLICY(scrp, PRIV_PROC_OWNER, B_FALSE, EPERM, "hasprocperm")) 609 return (1); 610 return (0); 611 } 612 613 /* 614 * This interface replaces hasprocperm; it works like hasprocperm but 615 * additionally returns success if the proc_t's match 616 * It is the preferred interface for most uses. 617 * And it will acquire p_crlock itself, so it assert's that it shouldn't 618 * be held. 619 */ 620 int 621 prochasprocperm(proc_t *tp, proc_t *sp, const cred_t *scrp) 622 { 623 int rets; 624 cred_t *tcrp; 625 626 ASSERT(MUTEX_NOT_HELD(&tp->p_crlock)); 627 628 if (tp == sp) 629 return (1); 630 631 if (tp->p_sessp != sp->p_sessp && secpolicy_basic_proc(scrp) != 0) 632 return (0); 633 634 mutex_enter(&tp->p_crlock); 635 crhold(tcrp = tp->p_cred); 636 mutex_exit(&tp->p_crlock); 637 rets = hasprocperm(tcrp, scrp); 638 crfree(tcrp); 639 640 return (rets); 641 } 642 643 /* 644 * This routine is used to compare two credentials to determine if 645 * they refer to the same "user". If the pointers are equal, then 646 * they must refer to the same user. Otherwise, the contents of 647 * the credentials are compared to see whether they are equivalent. 648 * 649 * This routine returns 0 if the credentials refer to the same user, 650 * 1 if they do not. 651 */ 652 int 653 crcmp(const cred_t *cr1, const cred_t *cr2) 654 { 655 credgrp_t *grp1, *grp2; 656 657 if (cr1 == cr2) 658 return (0); 659 660 if (cr1->cr_uid == cr2->cr_uid && 661 cr1->cr_gid == cr2->cr_gid && 662 cr1->cr_ruid == cr2->cr_ruid && 663 cr1->cr_rgid == cr2->cr_rgid && 664 cr1->cr_zone == cr2->cr_zone && 665 ((grp1 = cr1->cr_grps) == (grp2 = cr2->cr_grps) || 666 (grp1 != NULL && grp2 != NULL && 667 grp1->crg_ngroups == grp2->crg_ngroups && 668 bcmp(grp1->crg_groups, grp2->crg_groups, 669 grp1->crg_ngroups * sizeof (gid_t)) == 0))) { 670 return (!priv_isequalset(&CR_OEPRIV(cr1), &CR_OEPRIV(cr2))); 671 } 672 return (1); 673 } 674 675 /* 676 * Read access functions to cred_t. 677 */ 678 uid_t 679 crgetuid(const cred_t *cr) 680 { 681 return (cr->cr_uid); 682 } 683 684 uid_t 685 crgetruid(const cred_t *cr) 686 { 687 return (cr->cr_ruid); 688 } 689 690 uid_t 691 crgetsuid(const cred_t *cr) 692 { 693 return (cr->cr_suid); 694 } 695 696 gid_t 697 crgetgid(const cred_t *cr) 698 { 699 return (cr->cr_gid); 700 } 701 702 gid_t 703 crgetrgid(const cred_t *cr) 704 { 705 return (cr->cr_rgid); 706 } 707 708 gid_t 709 crgetsgid(const cred_t *cr) 710 { 711 return (cr->cr_sgid); 712 } 713 714 const auditinfo_addr_t * 715 crgetauinfo(const cred_t *cr) 716 { 717 return ((const auditinfo_addr_t *)CR_AUINFO(cr)); 718 } 719 720 auditinfo_addr_t * 721 crgetauinfo_modifiable(cred_t *cr) 722 { 723 return (CR_AUINFO(cr)); 724 } 725 726 zoneid_t 727 crgetzoneid(const cred_t *cr) 728 { 729 return (cr->cr_zone == NULL ? 730 (cr->cr_uid == -1 ? (zoneid_t)-1 : GLOBAL_ZONEID) : 731 cr->cr_zone->zone_id); 732 } 733 734 projid_t 735 crgetprojid(const cred_t *cr) 736 { 737 return (cr->cr_projid); 738 } 739 740 zone_t * 741 crgetzone(const cred_t *cr) 742 { 743 return (cr->cr_zone); 744 } 745 746 struct ts_label_s * 747 crgetlabel(const cred_t *cr) 748 { 749 return (cr->cr_label ? 750 cr->cr_label : 751 (cr->cr_zone ? cr->cr_zone->zone_slabel : NULL)); 752 } 753 754 boolean_t 755 crisremote(const cred_t *cr) 756 { 757 return (REMOTE_PEER_CRED(cr)); 758 } 759 760 #define BADUID(x, zn) ((x) != -1 && !VALID_UID((x), (zn))) 761 #define BADGID(x, zn) ((x) != -1 && !VALID_GID((x), (zn))) 762 763 int 764 crsetresuid(cred_t *cr, uid_t r, uid_t e, uid_t s) 765 { 766 zone_t *zone = crgetzone(cr); 767 768 ASSERT(cr->cr_ref <= 2); 769 770 if (BADUID(r, zone) || BADUID(e, zone) || BADUID(s, zone)) 771 return (-1); 772 773 if (r != -1) 774 cr->cr_ruid = r; 775 if (e != -1) 776 cr->cr_uid = e; 777 if (s != -1) 778 cr->cr_suid = s; 779 780 return (0); 781 } 782 783 int 784 crsetresgid(cred_t *cr, gid_t r, gid_t e, gid_t s) 785 { 786 zone_t *zone = crgetzone(cr); 787 788 ASSERT(cr->cr_ref <= 2); 789 790 if (BADGID(r, zone) || BADGID(e, zone) || BADGID(s, zone)) 791 return (-1); 792 793 if (r != -1) 794 cr->cr_rgid = r; 795 if (e != -1) 796 cr->cr_gid = e; 797 if (s != -1) 798 cr->cr_sgid = s; 799 800 return (0); 801 } 802 803 int 804 crsetugid(cred_t *cr, uid_t uid, gid_t gid) 805 { 806 zone_t *zone = crgetzone(cr); 807 808 ASSERT(cr->cr_ref <= 2); 809 810 if (!VALID_UID(uid, zone) || !VALID_GID(gid, zone)) 811 return (-1); 812 813 cr->cr_uid = cr->cr_ruid = cr->cr_suid = uid; 814 cr->cr_gid = cr->cr_rgid = cr->cr_sgid = gid; 815 816 return (0); 817 } 818 819 static int 820 gidcmp(const void *v1, const void *v2) 821 { 822 gid_t g1 = *(gid_t *)v1; 823 gid_t g2 = *(gid_t *)v2; 824 825 if (g1 < g2) 826 return (-1); 827 else if (g1 > g2) 828 return (1); 829 else 830 return (0); 831 } 832 833 int 834 crsetgroups(cred_t *cr, int n, gid_t *grp) 835 { 836 ASSERT(cr->cr_ref <= 2); 837 838 if (n > ngroups_max || n < 0) 839 return (-1); 840 841 if (cr->cr_grps != NULL) 842 crgrprele(cr->cr_grps); 843 844 if (n > 0) { 845 cr->cr_grps = kmem_alloc(CREDGRPSZ(n), KM_SLEEP); 846 bcopy(grp, cr->cr_grps->crg_groups, n * sizeof (gid_t)); 847 cr->cr_grps->crg_ref = 1; 848 cr->cr_grps->crg_ngroups = n; 849 qsort(cr->cr_grps->crg_groups, n, sizeof (gid_t), gidcmp); 850 } else { 851 cr->cr_grps = NULL; 852 } 853 854 return (0); 855 } 856 857 void 858 crsetprojid(cred_t *cr, projid_t projid) 859 { 860 ASSERT(projid >= 0 && projid <= MAXPROJID); 861 cr->cr_projid = projid; 862 } 863 864 /* 865 * This routine returns the pointer to the first element of the crg_groups 866 * array. It can move around in an implementation defined way. 867 * Note that when we have no grouplist, we return one element but the 868 * caller should never reference it. 869 */ 870 const gid_t * 871 crgetgroups(const cred_t *cr) 872 { 873 return (cr->cr_grps == NULL ? &cr->cr_gid : cr->cr_grps->crg_groups); 874 } 875 876 int 877 crgetngroups(const cred_t *cr) 878 { 879 return (cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups); 880 } 881 882 void 883 cred2prcred(const cred_t *cr, prcred_t *pcrp) 884 { 885 pcrp->pr_euid = cr->cr_uid; 886 pcrp->pr_ruid = cr->cr_ruid; 887 pcrp->pr_suid = cr->cr_suid; 888 pcrp->pr_egid = cr->cr_gid; 889 pcrp->pr_rgid = cr->cr_rgid; 890 pcrp->pr_sgid = cr->cr_sgid; 891 pcrp->pr_groups[0] = 0; /* in case ngroups == 0 */ 892 pcrp->pr_ngroups = cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups; 893 894 if (pcrp->pr_ngroups != 0) 895 bcopy(cr->cr_grps->crg_groups, pcrp->pr_groups, 896 sizeof (gid_t) * pcrp->pr_ngroups); 897 } 898 899 static int 900 cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo, const cred_t *rcr) 901 { 902 auditinfo_addr_t *ai; 903 au_tid_addr_t tid; 904 905 if (secpolicy_audit_getattr(rcr, B_TRUE) != 0) 906 return (-1); 907 908 ai = CR_AUINFO(cr); /* caller makes sure this is non-NULL */ 909 tid = ai->ai_termid; 910 911 ainfo->ai_auid = ai->ai_auid; 912 ainfo->ai_mask = ai->ai_mask; 913 ainfo->ai_asid = ai->ai_asid; 914 915 ainfo->ai_termid.at_type = tid.at_type; 916 bcopy(&tid.at_addr, &ainfo->ai_termid.at_addr, 4 * sizeof (uint_t)); 917 918 ainfo->ai_termid.at_port.at_major = (uint32_t)getmajor(tid.at_port); 919 ainfo->ai_termid.at_port.at_minor = (uint32_t)getminor(tid.at_port); 920 921 return (0); 922 } 923 924 void 925 cred2uclabel(const cred_t *cr, bslabel_t *labelp) 926 { 927 ts_label_t *tslp; 928 929 if ((tslp = crgetlabel(cr)) != NULL) 930 bcopy(&tslp->tsl_label, labelp, sizeof (bslabel_t)); 931 } 932 933 /* 934 * Convert a credential into a "ucred". Allow the caller to specify 935 * and aligned buffer, e.g., in an mblk, so we don't have to allocate 936 * memory and copy it twice. 937 * 938 * This function may call cred2ucaud(), which calls CRED(). Since this 939 * can be called from an interrupt thread, receiver's cred (rcr) is needed 940 * to determine whether audit info should be included. 941 */ 942 struct ucred_s * 943 cred2ucred(const cred_t *cr, pid_t pid, void *buf, const cred_t *rcr) 944 { 945 struct ucred_s *uc; 946 uint32_t realsz = ucredminsize(cr); 947 ts_label_t *tslp = is_system_labeled() ? crgetlabel(cr) : NULL; 948 949 /* The structure isn't always completely filled in, so zero it */ 950 if (buf == NULL) { 951 uc = kmem_zalloc(realsz, KM_SLEEP); 952 } else { 953 bzero(buf, realsz); 954 uc = buf; 955 } 956 uc->uc_size = realsz; 957 uc->uc_pid = pid; 958 uc->uc_projid = cr->cr_projid; 959 uc->uc_zoneid = crgetzoneid(cr); 960 961 if (REMOTE_PEER_CRED(cr)) { 962 /* 963 * Other than label, the rest of cred info about a 964 * remote peer isn't available. Copy the label directly 965 * after the header where we generally copy the prcred. 966 * That's why we use sizeof (struct ucred_s). The other 967 * offset fields are initialized to 0. 968 */ 969 uc->uc_labeloff = tslp == NULL ? 0 : sizeof (struct ucred_s); 970 } else { 971 uc->uc_credoff = UCRED_CRED_OFF; 972 uc->uc_privoff = UCRED_PRIV_OFF; 973 uc->uc_audoff = UCRED_AUD_OFF; 974 uc->uc_labeloff = tslp == NULL ? 0 : UCRED_LABEL_OFF; 975 976 cred2prcred(cr, UCCRED(uc)); 977 cred2prpriv(cr, UCPRIV(uc)); 978 979 if (audoff == 0 || cred2ucaud(cr, UCAUD(uc), rcr) != 0) 980 uc->uc_audoff = 0; 981 } 982 if (tslp != NULL) 983 bcopy(&tslp->tsl_label, UCLABEL(uc), sizeof (bslabel_t)); 984 985 return (uc); 986 } 987 988 /* 989 * Don't allocate the non-needed group entries. Note: this function 990 * must match the code in cred2ucred; they must agree about the 991 * minimal size of the ucred. 992 */ 993 uint32_t 994 ucredminsize(const cred_t *cr) 995 { 996 int ndiff; 997 998 if (cr == NULL) 999 return (ucredsize); 1000 1001 if (REMOTE_PEER_CRED(cr)) { 1002 if (is_system_labeled()) 1003 return (sizeof (struct ucred_s) + sizeof (bslabel_t)); 1004 else 1005 return (sizeof (struct ucred_s)); 1006 } 1007 1008 if (cr->cr_grps == NULL) 1009 ndiff = ngroups_max - 1; /* Needs one for prcred_t */ 1010 else 1011 ndiff = ngroups_max - cr->cr_grps->crg_ngroups; 1012 1013 return (ucredsize - ndiff * sizeof (gid_t)); 1014 } 1015 1016 /* 1017 * Get the "ucred" of a process. 1018 */ 1019 struct ucred_s * 1020 pgetucred(proc_t *p) 1021 { 1022 cred_t *cr; 1023 struct ucred_s *uc; 1024 1025 mutex_enter(&p->p_crlock); 1026 cr = p->p_cred; 1027 crhold(cr); 1028 mutex_exit(&p->p_crlock); 1029 1030 uc = cred2ucred(cr, p->p_pid, NULL, CRED()); 1031 crfree(cr); 1032 1033 return (uc); 1034 } 1035 1036 /* 1037 * If the reply status is NFSERR_EACCES, it may be because we are 1038 * root (no root net access). Check the real uid, if it isn't root 1039 * make that the uid instead and retry the call. 1040 * Private interface for NFS. 1041 */ 1042 cred_t * 1043 crnetadjust(cred_t *cr) 1044 { 1045 if (cr->cr_uid == 0 && cr->cr_ruid != 0) { 1046 cr = crdup(cr); 1047 cr->cr_uid = cr->cr_ruid; 1048 return (cr); 1049 } 1050 return (NULL); 1051 } 1052 1053 /* 1054 * The reference count is of interest when you want to check 1055 * whether it is ok to modify the credential in place. 1056 */ 1057 uint_t 1058 crgetref(const cred_t *cr) 1059 { 1060 return (cr->cr_ref); 1061 } 1062 1063 static int 1064 get_c2audit_load(void) 1065 { 1066 static int gotit = 0; 1067 static int c2audit_load; 1068 1069 if (gotit) 1070 return (c2audit_load); 1071 c2audit_load = 1; /* set default value once */ 1072 if (mod_sysctl(SYS_CHECK_EXCLUDE, "c2audit") != 0) 1073 c2audit_load = 0; 1074 gotit++; 1075 1076 return (c2audit_load); 1077 } 1078 1079 int 1080 get_audit_ucrsize(void) 1081 { 1082 return (get_c2audit_load() ? sizeof (auditinfo64_addr_t) : 0); 1083 } 1084 1085 /* 1086 * Set zone pointer in credential to indicated value. First adds a 1087 * hold for the new zone, then drops the hold on previous zone (if any). 1088 * This is done in this order in case the old and new zones are the 1089 * same. 1090 */ 1091 void 1092 crsetzone(cred_t *cr, zone_t *zptr) 1093 { 1094 zone_t *oldzptr = cr->cr_zone; 1095 1096 ASSERT(cr != kcred); 1097 ASSERT(cr->cr_ref <= 2); 1098 cr->cr_zone = zptr; 1099 zone_cred_hold(zptr); 1100 if (oldzptr) 1101 zone_cred_rele(oldzptr); 1102 } 1103 1104 /* 1105 * Create a new cred based on the supplied label 1106 */ 1107 cred_t * 1108 newcred_from_bslabel(bslabel_t *blabel, uint32_t doi, int flags) 1109 { 1110 ts_label_t *lbl = labelalloc(blabel, doi, flags); 1111 cred_t *cr = NULL; 1112 1113 if (lbl != NULL) { 1114 if ((cr = crdup_flags(dummycr, flags)) != NULL) { 1115 cr->cr_label = lbl; 1116 } else { 1117 label_rele(lbl); 1118 } 1119 } 1120 1121 return (cr); 1122 } 1123 1124 /* 1125 * Derive a new cred from the existing cred, but with a different label. 1126 * To be used when a cred is being shared, but the label needs to be changed 1127 * by a caller without affecting other users 1128 */ 1129 cred_t * 1130 copycred_from_tslabel(const cred_t *cr, ts_label_t *label, int flags) 1131 { 1132 cred_t *newcr = NULL; 1133 1134 if ((newcr = crdup_flags(cr, flags)) != NULL) { 1135 if (newcr->cr_label != NULL) 1136 label_rele(newcr->cr_label); 1137 label_hold(label); 1138 newcr->cr_label = label; 1139 } 1140 1141 return (newcr); 1142 } 1143 1144 /* 1145 * Derive a new cred from the existing cred, but with a different label. 1146 */ 1147 cred_t * 1148 copycred_from_bslabel(const cred_t *cr, bslabel_t *blabel, 1149 uint32_t doi, int flags) 1150 { 1151 ts_label_t *lbl = labelalloc(blabel, doi, flags); 1152 cred_t *newcr = NULL; 1153 1154 if (lbl != NULL) { 1155 newcr = copycred_from_tslabel(cr, lbl, flags); 1156 label_rele(lbl); 1157 } 1158 1159 return (newcr); 1160 } 1161 1162 /* 1163 * This function returns a pointer to the kcred-equivalent in the current zone. 1164 */ 1165 cred_t * 1166 zone_kcred(void) 1167 { 1168 zone_t *zone; 1169 1170 if ((zone = CRED()->cr_zone) != NULL) 1171 return (zone->zone_kcred); 1172 else 1173 return (kcred); 1174 } 1175 1176 boolean_t 1177 valid_ephemeral_uid(zone_t *zone, uid_t id) 1178 { 1179 ephemeral_zsd_t *eph_zsd; 1180 if (id <= IDMAP_WK__MAX_UID) 1181 return (B_TRUE); 1182 1183 eph_zsd = get_ephemeral_zsd(zone); 1184 ASSERT(eph_zsd != NULL); 1185 membar_consumer(); 1186 return (id > eph_zsd->min_uid && id <= eph_zsd->last_uid); 1187 } 1188 1189 boolean_t 1190 valid_ephemeral_gid(zone_t *zone, gid_t id) 1191 { 1192 ephemeral_zsd_t *eph_zsd; 1193 if (id <= IDMAP_WK__MAX_GID) 1194 return (B_TRUE); 1195 1196 eph_zsd = get_ephemeral_zsd(zone); 1197 ASSERT(eph_zsd != NULL); 1198 membar_consumer(); 1199 return (id > eph_zsd->min_gid && id <= eph_zsd->last_gid); 1200 } 1201 1202 int 1203 eph_uid_alloc(zone_t *zone, int flags, uid_t *start, int count) 1204 { 1205 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone); 1206 1207 ASSERT(eph_zsd != NULL); 1208 1209 mutex_enter(&eph_zsd->eph_lock); 1210 1211 /* Test for unsigned integer wrap around */ 1212 if (eph_zsd->last_uid + count < eph_zsd->last_uid) { 1213 mutex_exit(&eph_zsd->eph_lock); 1214 return (-1); 1215 } 1216 1217 /* first call or idmap crashed and state corrupted */ 1218 if (flags != 0) 1219 eph_zsd->min_uid = eph_zsd->last_uid; 1220 1221 hasephids = B_TRUE; 1222 *start = eph_zsd->last_uid + 1; 1223 atomic_add_32(&eph_zsd->last_uid, count); 1224 mutex_exit(&eph_zsd->eph_lock); 1225 return (0); 1226 } 1227 1228 int 1229 eph_gid_alloc(zone_t *zone, int flags, gid_t *start, int count) 1230 { 1231 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone); 1232 1233 ASSERT(eph_zsd != NULL); 1234 1235 mutex_enter(&eph_zsd->eph_lock); 1236 1237 /* Test for unsigned integer wrap around */ 1238 if (eph_zsd->last_gid + count < eph_zsd->last_gid) { 1239 mutex_exit(&eph_zsd->eph_lock); 1240 return (-1); 1241 } 1242 1243 /* first call or idmap crashed and state corrupted */ 1244 if (flags != 0) 1245 eph_zsd->min_gid = eph_zsd->last_gid; 1246 1247 hasephids = B_TRUE; 1248 *start = eph_zsd->last_gid + 1; 1249 atomic_add_32(&eph_zsd->last_gid, count); 1250 mutex_exit(&eph_zsd->eph_lock); 1251 return (0); 1252 } 1253 1254 /* 1255 * IMPORTANT.The two functions get_ephemeral_data() and set_ephemeral_data() 1256 * are project private functions that are for use of the test system only and 1257 * are not to be used for other purposes. 1258 */ 1259 1260 void 1261 get_ephemeral_data(zone_t *zone, uid_t *min_uid, uid_t *last_uid, 1262 gid_t *min_gid, gid_t *last_gid) 1263 { 1264 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone); 1265 1266 ASSERT(eph_zsd != NULL); 1267 1268 mutex_enter(&eph_zsd->eph_lock); 1269 1270 *min_uid = eph_zsd->min_uid; 1271 *last_uid = eph_zsd->last_uid; 1272 *min_gid = eph_zsd->min_gid; 1273 *last_gid = eph_zsd->last_gid; 1274 1275 mutex_exit(&eph_zsd->eph_lock); 1276 } 1277 1278 1279 void 1280 set_ephemeral_data(zone_t *zone, uid_t min_uid, uid_t last_uid, 1281 gid_t min_gid, gid_t last_gid) 1282 { 1283 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone); 1284 1285 ASSERT(eph_zsd != NULL); 1286 1287 mutex_enter(&eph_zsd->eph_lock); 1288 1289 if (min_uid != 0) 1290 eph_zsd->min_uid = min_uid; 1291 if (last_uid != 0) 1292 eph_zsd->last_uid = last_uid; 1293 if (min_gid != 0) 1294 eph_zsd->min_gid = min_gid; 1295 if (last_gid != 0) 1296 eph_zsd->last_gid = last_gid; 1297 1298 mutex_exit(&eph_zsd->eph_lock); 1299 } 1300 1301 /* 1302 * If the credential user SID or group SID is mapped to an ephemeral 1303 * ID, map the credential to nobody. 1304 */ 1305 cred_t * 1306 crgetmapped(const cred_t *cr) 1307 { 1308 ephemeral_zsd_t *eph_zsd; 1309 /* 1310 * Someone incorrectly passed a NULL cred to a vnode operation 1311 * either on purpose or by calling CRED() in interrupt context. 1312 */ 1313 if (cr == NULL) 1314 return (NULL); 1315 1316 if (cr->cr_ksid != NULL) { 1317 if (cr->cr_ksid->kr_sidx[KSID_USER].ks_id > MAXUID) { 1318 eph_zsd = get_ephemeral_zsd(crgetzone(cr)); 1319 return (eph_zsd->eph_nobody); 1320 } 1321 1322 if (cr->cr_ksid->kr_sidx[KSID_GROUP].ks_id > MAXUID) { 1323 eph_zsd = get_ephemeral_zsd(crgetzone(cr)); 1324 return (eph_zsd->eph_nobody); 1325 } 1326 } 1327 1328 return ((cred_t *)cr); 1329 } 1330 1331 /* index should be in range for a ksidindex_t */ 1332 void 1333 crsetsid(cred_t *cr, ksid_t *ksp, int index) 1334 { 1335 ASSERT(cr->cr_ref <= 2); 1336 ASSERT(index >= 0 && index < KSID_COUNT); 1337 if (cr->cr_ksid == NULL && ksp == NULL) 1338 return; 1339 cr->cr_ksid = kcrsid_setsid(cr->cr_ksid, ksp, index); 1340 } 1341 1342 void 1343 crsetsidlist(cred_t *cr, ksidlist_t *ksl) 1344 { 1345 ASSERT(cr->cr_ref <= 2); 1346 if (cr->cr_ksid == NULL && ksl == NULL) 1347 return; 1348 cr->cr_ksid = kcrsid_setsidlist(cr->cr_ksid, ksl); 1349 } 1350 1351 ksid_t * 1352 crgetsid(const cred_t *cr, int i) 1353 { 1354 ASSERT(i >= 0 && i < KSID_COUNT); 1355 if (cr->cr_ksid != NULL && cr->cr_ksid->kr_sidx[i].ks_domain) 1356 return ((ksid_t *)&cr->cr_ksid->kr_sidx[i]); 1357 return (NULL); 1358 } 1359 1360 ksidlist_t * 1361 crgetsidlist(const cred_t *cr) 1362 { 1363 if (cr->cr_ksid != NULL) 1364 return (cr->cr_ksid->kr_sidlist); 1365 return (NULL); 1366 } 1367 1368 /* 1369 * Interface to set the effective and permitted privileges for 1370 * a credential; this interface does no security checks and is 1371 * intended for kernel (file)servers creating credentials with 1372 * specific privileges. 1373 */ 1374 int 1375 crsetpriv(cred_t *cr, ...) 1376 { 1377 va_list ap; 1378 const char *privnm; 1379 1380 ASSERT(cr->cr_ref <= 2); 1381 1382 priv_set_PA(cr); 1383 1384 va_start(ap, cr); 1385 1386 while ((privnm = va_arg(ap, const char *)) != NULL) { 1387 int priv = priv_getbyname(privnm, 0); 1388 if (priv < 0) 1389 return (-1); 1390 1391 priv_addset(&CR_PPRIV(cr), priv); 1392 priv_addset(&CR_EPRIV(cr), priv); 1393 } 1394 priv_adjust_PA(cr); 1395 va_end(ap); 1396 return (0); 1397 } 1398 1399 /* 1400 * Interface to effectively set the PRIV_ALL for 1401 * a credential; this interface does no security checks and is 1402 * intended for kernel (file)servers to extend the user credentials 1403 * to be ALL, like either kcred or zcred. 1404 */ 1405 void 1406 crset_zone_privall(cred_t *cr) 1407 { 1408 zone_t *zone = crgetzone(cr); 1409 1410 priv_fillset(&CR_LPRIV(cr)); 1411 CR_EPRIV(cr) = CR_PPRIV(cr) = CR_IPRIV(cr) = CR_LPRIV(cr); 1412 priv_intersect(zone->zone_privset, &CR_LPRIV(cr)); 1413 priv_intersect(zone->zone_privset, &CR_EPRIV(cr)); 1414 priv_intersect(zone->zone_privset, &CR_IPRIV(cr)); 1415 priv_intersect(zone->zone_privset, &CR_PPRIV(cr)); 1416 } 1417 1418 struct credklpd * 1419 crgetcrklpd(const cred_t *cr) 1420 { 1421 return (cr->cr_klpd); 1422 } 1423 1424 void 1425 crsetcrklpd(cred_t *cr, struct credklpd *crklpd) 1426 { 1427 ASSERT(cr->cr_ref <= 2); 1428 1429 if (cr->cr_klpd != NULL) 1430 crklpd_rele(cr->cr_klpd); 1431 cr->cr_klpd = crklpd; 1432 } 1433 1434 credgrp_t * 1435 crgrpcopyin(int n, gid_t *gidset) 1436 { 1437 credgrp_t *mem; 1438 size_t sz = CREDGRPSZ(n); 1439 1440 ASSERT(n > 0); 1441 1442 mem = kmem_alloc(sz, KM_SLEEP); 1443 1444 if (copyin(gidset, mem->crg_groups, sizeof (gid_t) * n)) { 1445 kmem_free(mem, sz); 1446 return (NULL); 1447 } 1448 mem->crg_ref = 1; 1449 mem->crg_ngroups = n; 1450 return (mem); 1451 } 1452 1453 const gid_t * 1454 crgetggroups(const credgrp_t *grps) 1455 { 1456 return (grps->crg_groups); 1457 } 1458 1459 void 1460 crsetcredgrp(cred_t *cr, credgrp_t *grps) 1461 { 1462 ASSERT(cr->cr_ref <= 2); 1463 1464 if (cr->cr_grps != NULL) 1465 crgrprele(cr->cr_grps); 1466 1467 cr->cr_grps = grps; 1468 } 1469 1470 void 1471 crgrprele(credgrp_t *grps) 1472 { 1473 if (atomic_add_32_nv(&grps->crg_ref, -1) == 0) 1474 kmem_free(grps, CREDGRPSZ(grps->crg_ngroups)); 1475 } 1476 1477 static void 1478 crgrphold(credgrp_t *grps) 1479 { 1480 atomic_add_32(&grps->crg_ref, 1); 1481 } 1482