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