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