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