10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51676Sjpk * Common Development and Distribution License (the "License").
61676Sjpk * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12273SCasper.Dik@Sun.COM * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
260Sstevel@tonic-gate /* All Rights Reserved */
270Sstevel@tonic-gate
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
300Sstevel@tonic-gate * The Regents of the University of California
310Sstevel@tonic-gate * All Rights Reserved
320Sstevel@tonic-gate *
330Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
340Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its
350Sstevel@tonic-gate * contributors.
360Sstevel@tonic-gate */
370Sstevel@tonic-gate
380Sstevel@tonic-gate #include <sys/types.h>
390Sstevel@tonic-gate #include <sys/sysmacros.h>
400Sstevel@tonic-gate #include <sys/param.h>
410Sstevel@tonic-gate #include <sys/systm.h>
420Sstevel@tonic-gate #include <sys/cred_impl.h>
430Sstevel@tonic-gate #include <sys/policy.h>
440Sstevel@tonic-gate #include <sys/vnode.h>
450Sstevel@tonic-gate #include <sys/errno.h>
460Sstevel@tonic-gate #include <sys/kmem.h>
470Sstevel@tonic-gate #include <sys/user.h>
480Sstevel@tonic-gate #include <sys/proc.h>
490Sstevel@tonic-gate #include <sys/syscall.h>
500Sstevel@tonic-gate #include <sys/debug.h>
510Sstevel@tonic-gate #include <sys/atomic.h>
520Sstevel@tonic-gate #include <sys/ucred.h>
530Sstevel@tonic-gate #include <sys/prsystm.h>
540Sstevel@tonic-gate #include <sys/modctl.h>
554321Scasper #include <sys/avl.h>
565331Samw #include <sys/door.h>
570Sstevel@tonic-gate #include <c2/audit.h>
580Sstevel@tonic-gate #include <sys/zone.h>
591676Sjpk #include <sys/tsol/label.h>
604321Scasper #include <sys/sid.h>
614520Snw141292 #include <sys/idmap.h>
626134Scasper #include <sys/klpd.h>
635331Samw #include <sys/varargs.h>
6411861SMarek.Pospisil@Sun.COM #include <sys/sysconf.h>
6511134SCasper.Dik@Sun.COM #include <util/qsort.h>
664321Scasper
675771Sjp151216
685771Sjp151216 /* Ephemeral IDs Zones specific data */
695771Sjp151216 typedef struct ephemeral_zsd {
705771Sjp151216 uid_t min_uid;
715771Sjp151216 uid_t last_uid;
725771Sjp151216 gid_t min_gid;
735771Sjp151216 gid_t last_gid;
744321Scasper kmutex_t eph_lock;
755771Sjp151216 cred_t *eph_nobody;
765771Sjp151216 } ephemeral_zsd_t;
775771Sjp151216
7811134SCasper.Dik@Sun.COM /* Supplemental groups list. */
7911134SCasper.Dik@Sun.COM typedef struct credgrp {
8011134SCasper.Dik@Sun.COM uint_t crg_ref;
8111134SCasper.Dik@Sun.COM uint_t crg_ngroups;
8211134SCasper.Dik@Sun.COM gid_t crg_groups[1];
8311134SCasper.Dik@Sun.COM } credgrp_t;
8411134SCasper.Dik@Sun.COM
8511134SCasper.Dik@Sun.COM static void crgrphold(credgrp_t *);
8611134SCasper.Dik@Sun.COM
8711134SCasper.Dik@Sun.COM #define CREDGRPSZ(ngrp) (sizeof (credgrp_t) + ((ngrp - 1) * sizeof (gid_t)))
885771Sjp151216
895771Sjp151216 static kmutex_t ephemeral_zone_mutex;
905771Sjp151216 static zone_key_t ephemeral_zone_key;
910Sstevel@tonic-gate
920Sstevel@tonic-gate static struct kmem_cache *cred_cache;
935771Sjp151216 static size_t crsize = 0;
945771Sjp151216 static int audoff = 0;
955771Sjp151216 uint32_t ucredsize;
965771Sjp151216 cred_t *kcred;
975771Sjp151216 static cred_t *dummycr;
980Sstevel@tonic-gate
990Sstevel@tonic-gate int rstlink; /* link(2) restricted to files owned by user? */
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate static int get_c2audit_load(void);
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate #define CR_AUINFO(c) (auditinfo_addr_t *)((audoff == 0) ? NULL : \
1040Sstevel@tonic-gate ((char *)(c)) + audoff)
1050Sstevel@tonic-gate
1061676Sjpk #define REMOTE_PEER_CRED(c) ((c)->cr_gid == -1)
1070Sstevel@tonic-gate
10811134SCasper.Dik@Sun.COM #define BIN_GROUP_SEARCH_CUTOFF 16
1094321Scasper
1104321Scasper static boolean_t hasephids = B_FALSE;
1114321Scasper
1125771Sjp151216 static ephemeral_zsd_t *
get_ephemeral_zsd(zone_t * zone)1135771Sjp151216 get_ephemeral_zsd(zone_t *zone)
1145771Sjp151216 {
1155771Sjp151216 ephemeral_zsd_t *eph_zsd;
1165771Sjp151216
1175771Sjp151216 eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
1185771Sjp151216 if (eph_zsd != NULL) {
1195771Sjp151216 return (eph_zsd);
1205771Sjp151216 }
1215771Sjp151216
1225771Sjp151216 mutex_enter(&ephemeral_zone_mutex);
1235771Sjp151216 eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
1245771Sjp151216 if (eph_zsd == NULL) {
1255771Sjp151216 eph_zsd = kmem_zalloc(sizeof (ephemeral_zsd_t), KM_SLEEP);
1265771Sjp151216 eph_zsd->min_uid = MAXUID;
1275771Sjp151216 eph_zsd->last_uid = IDMAP_WK__MAX_UID;
1285771Sjp151216 eph_zsd->min_gid = MAXUID;
1295771Sjp151216 eph_zsd->last_gid = IDMAP_WK__MAX_GID;
1305771Sjp151216 mutex_init(&eph_zsd->eph_lock, NULL, MUTEX_DEFAULT, NULL);
1315771Sjp151216
1325771Sjp151216 /*
1335771Sjp151216 * nobody is used to map SID containing CRs.
1345771Sjp151216 */
1355771Sjp151216 eph_zsd->eph_nobody = crdup(zone->zone_kcred);
1365771Sjp151216 (void) crsetugid(eph_zsd->eph_nobody, UID_NOBODY, GID_NOBODY);
1375771Sjp151216 CR_FLAGS(eph_zsd->eph_nobody) = 0;
1385771Sjp151216 eph_zsd->eph_nobody->cr_zone = zone;
1395771Sjp151216
1405771Sjp151216 (void) zone_setspecific(ephemeral_zone_key, zone, eph_zsd);
1415771Sjp151216 }
1425771Sjp151216 mutex_exit(&ephemeral_zone_mutex);
1435771Sjp151216 return (eph_zsd);
1445771Sjp151216 }
1455771Sjp151216
1469710SKen.Powell@Sun.COM static cred_t *crdup_flags(const cred_t *, int);
1476134Scasper static cred_t *cralloc_flags(int);
1486134Scasper
1495771Sjp151216 /*
1505771Sjp151216 * This function is called when a zone is destroyed
1515771Sjp151216 */
1525771Sjp151216 static void
1535771Sjp151216 /* ARGSUSED */
destroy_ephemeral_zsd(zoneid_t zone_id,void * arg)1545771Sjp151216 destroy_ephemeral_zsd(zoneid_t zone_id, void *arg)
1555771Sjp151216 {
1565771Sjp151216 ephemeral_zsd_t *eph_zsd = arg;
1575771Sjp151216 if (eph_zsd != NULL) {
1585771Sjp151216 mutex_destroy(&eph_zsd->eph_lock);
1595771Sjp151216 crfree(eph_zsd->eph_nobody);
1605771Sjp151216 kmem_free(eph_zsd, sizeof (ephemeral_zsd_t));
1615771Sjp151216 }
1625771Sjp151216 }
1635771Sjp151216
1645771Sjp151216
1655771Sjp151216
1664321Scasper /*
1670Sstevel@tonic-gate * Initialize credentials data structures.
1680Sstevel@tonic-gate */
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate void
cred_init(void)1710Sstevel@tonic-gate cred_init(void)
1720Sstevel@tonic-gate {
1730Sstevel@tonic-gate priv_init();
1740Sstevel@tonic-gate
17511134SCasper.Dik@Sun.COM crsize = sizeof (cred_t);
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate if (get_c2audit_load() > 0) {
1780Sstevel@tonic-gate #ifdef _LP64
1790Sstevel@tonic-gate /* assure audit context is 64-bit aligned */
1800Sstevel@tonic-gate audoff = (crsize +
1810Sstevel@tonic-gate sizeof (int64_t) - 1) & ~(sizeof (int64_t) - 1);
1820Sstevel@tonic-gate #else /* _LP64 */
1830Sstevel@tonic-gate audoff = crsize;
1840Sstevel@tonic-gate #endif /* _LP64 */
1850Sstevel@tonic-gate crsize = audoff + sizeof (auditinfo_addr_t);
1860Sstevel@tonic-gate crsize = (crsize + sizeof (int) - 1) & ~(sizeof (int) - 1);
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate cred_cache = kmem_cache_create("cred_cache", crsize, 0,
1904520Snw141292 NULL, NULL, NULL, NULL, NULL, 0);
1910Sstevel@tonic-gate
1920Sstevel@tonic-gate /*
1931676Sjpk * dummycr is used to copy initial state for creds.
1941676Sjpk */
1951676Sjpk dummycr = cralloc();
1961676Sjpk bzero(dummycr, crsize);
1971676Sjpk dummycr->cr_ref = 1;
1984321Scasper dummycr->cr_uid = (uid_t)-1;
1994321Scasper dummycr->cr_gid = (gid_t)-1;
2004321Scasper dummycr->cr_ruid = (uid_t)-1;
2014321Scasper dummycr->cr_rgid = (gid_t)-1;
2024321Scasper dummycr->cr_suid = (uid_t)-1;
2034321Scasper dummycr->cr_sgid = (gid_t)-1;
2044321Scasper
2051676Sjpk
2061676Sjpk /*
2070Sstevel@tonic-gate * kcred is used by anything that needs all privileges; it's
2080Sstevel@tonic-gate * also the template used for crget as it has all the compatible
2090Sstevel@tonic-gate * sets filled in.
2100Sstevel@tonic-gate */
2110Sstevel@tonic-gate kcred = cralloc();
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate bzero(kcred, crsize);
2140Sstevel@tonic-gate kcred->cr_ref = 1;
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate /* kcred is never freed, so we don't need zone_cred_hold here */
2170Sstevel@tonic-gate kcred->cr_zone = &zone0;
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate priv_fillset(&CR_LPRIV(kcred));
2200Sstevel@tonic-gate CR_IPRIV(kcred) = *priv_basic;
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate /* Not a basic privilege, if chown is not restricted add it to I0 */
2230Sstevel@tonic-gate if (!rstchown)
2240Sstevel@tonic-gate priv_addset(&CR_IPRIV(kcred), PRIV_FILE_CHOWN_SELF);
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate /* Basic privilege, if link is restricted remove it from I0 */
2270Sstevel@tonic-gate if (rstlink)
2280Sstevel@tonic-gate priv_delset(&CR_IPRIV(kcred), PRIV_FILE_LINK_ANY);
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate CR_EPRIV(kcred) = CR_PPRIV(kcred) = CR_IPRIV(kcred);
2311676Sjpk
2321676Sjpk CR_FLAGS(kcred) = NET_MAC_AWARE;
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate /*
2350Sstevel@tonic-gate * Set up credentials of p0.
2360Sstevel@tonic-gate */
2370Sstevel@tonic-gate ttoproc(curthread)->p_cred = kcred;
2380Sstevel@tonic-gate curthread->t_cred = kcred;
2390Sstevel@tonic-gate
2405771Sjp151216 ucredsize = UCRED_SIZE;
2414321Scasper
2425771Sjp151216 mutex_init(&ephemeral_zone_mutex, NULL, MUTEX_DEFAULT, NULL);
2435771Sjp151216 zone_key_create(&ephemeral_zone_key, NULL, NULL, destroy_ephemeral_zsd);
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate /*
2470Sstevel@tonic-gate * Allocate (nearly) uninitialized cred_t.
2480Sstevel@tonic-gate */
2496134Scasper static cred_t *
cralloc_flags(int flgs)2506134Scasper cralloc_flags(int flgs)
2510Sstevel@tonic-gate {
2526134Scasper cred_t *cr = kmem_cache_alloc(cred_cache, flgs);
2536134Scasper
2546134Scasper if (cr == NULL)
2556134Scasper return (NULL);
2566134Scasper
2570Sstevel@tonic-gate cr->cr_ref = 1; /* So we can crfree() */
2580Sstevel@tonic-gate cr->cr_zone = NULL;
2591676Sjpk cr->cr_label = NULL;
2604321Scasper cr->cr_ksid = NULL;
2616134Scasper cr->cr_klpd = NULL;
26211134SCasper.Dik@Sun.COM cr->cr_grps = NULL;
2634321Scasper return (cr);
2644321Scasper }
2654321Scasper
2666134Scasper cred_t *
cralloc(void)2676134Scasper cralloc(void)
2686134Scasper {
2696134Scasper return (cralloc_flags(KM_SLEEP));
2706134Scasper }
2716134Scasper
2724321Scasper /*
2734321Scasper * As cralloc but prepared for ksid change (if appropriate).
2744321Scasper */
2754321Scasper cred_t *
cralloc_ksid(void)2764321Scasper cralloc_ksid(void)
2774321Scasper {
2784321Scasper cred_t *cr = cralloc();
2794321Scasper if (hasephids)
2804321Scasper cr->cr_ksid = kcrsid_alloc();
2810Sstevel@tonic-gate return (cr);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate /*
2850Sstevel@tonic-gate * Allocate a initialized cred structure and crhold() it.
2860Sstevel@tonic-gate * Initialized means: all ids 0, group count 0, L=Full, E=P=I=I0
2870Sstevel@tonic-gate */
2880Sstevel@tonic-gate cred_t *
crget(void)2890Sstevel@tonic-gate crget(void)
2900Sstevel@tonic-gate {
2910Sstevel@tonic-gate cred_t *cr = kmem_cache_alloc(cred_cache, KM_SLEEP);
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate bcopy(kcred, cr, crsize);
2940Sstevel@tonic-gate cr->cr_ref = 1;
2950Sstevel@tonic-gate zone_cred_hold(cr->cr_zone);
2961676Sjpk if (cr->cr_label)
2971676Sjpk label_hold(cr->cr_label);
2986134Scasper ASSERT(cr->cr_klpd == NULL);
29911134SCasper.Dik@Sun.COM ASSERT(cr->cr_grps == NULL);
3000Sstevel@tonic-gate return (cr);
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate /*
3040Sstevel@tonic-gate * Broadcast the cred to all the threads in the process.
3050Sstevel@tonic-gate * The current thread's credentials can be set right away, but other
3060Sstevel@tonic-gate * threads must wait until the start of the next system call or trap.
3070Sstevel@tonic-gate * This avoids changing the cred in the middle of a system call.
3080Sstevel@tonic-gate *
3090Sstevel@tonic-gate * The cred has already been held for the process and the thread (2 holds),
3100Sstevel@tonic-gate * and p->p_cred set.
3110Sstevel@tonic-gate *
3120Sstevel@tonic-gate * p->p_crlock shouldn't be held here, since p_lock must be acquired.
3130Sstevel@tonic-gate */
3140Sstevel@tonic-gate void
crset(proc_t * p,cred_t * cr)3150Sstevel@tonic-gate crset(proc_t *p, cred_t *cr)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate kthread_id_t t;
3180Sstevel@tonic-gate kthread_id_t first;
3190Sstevel@tonic-gate cred_t *oldcr;
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate ASSERT(p == curproc); /* assumes p_lwpcnt can't change */
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate /*
3240Sstevel@tonic-gate * DTrace accesses t_cred in probe context. t_cred must always be
3250Sstevel@tonic-gate * either NULL, or point to a valid, allocated cred structure.
3260Sstevel@tonic-gate */
3270Sstevel@tonic-gate t = curthread;
3280Sstevel@tonic-gate oldcr = t->t_cred;
3290Sstevel@tonic-gate t->t_cred = cr; /* the cred is held by caller for this thread */
3300Sstevel@tonic-gate crfree(oldcr); /* free the old cred for the thread */
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate /*
3330Sstevel@tonic-gate * Broadcast to other threads, if any.
3340Sstevel@tonic-gate */
3350Sstevel@tonic-gate if (p->p_lwpcnt > 1) {
3360Sstevel@tonic-gate mutex_enter(&p->p_lock); /* to keep thread list safe */
3370Sstevel@tonic-gate first = curthread;
3380Sstevel@tonic-gate for (t = first->t_forw; t != first; t = t->t_forw)
3390Sstevel@tonic-gate t->t_pre_sys = 1; /* so syscall will get new cred */
3400Sstevel@tonic-gate mutex_exit(&p->p_lock);
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate /*
3450Sstevel@tonic-gate * Put a hold on a cred structure.
3460Sstevel@tonic-gate */
3470Sstevel@tonic-gate void
crhold(cred_t * cr)3480Sstevel@tonic-gate crhold(cred_t *cr)
3490Sstevel@tonic-gate {
350*12273SCasper.Dik@Sun.COM ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0);
3510Sstevel@tonic-gate atomic_add_32(&cr->cr_ref, 1);
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /*
3550Sstevel@tonic-gate * Release previous hold on a cred structure. Free it if refcnt == 0.
3561676Sjpk * If cred uses label different from zone label, free it.
3570Sstevel@tonic-gate */
3580Sstevel@tonic-gate void
crfree(cred_t * cr)3590Sstevel@tonic-gate crfree(cred_t *cr)
3600Sstevel@tonic-gate {
361*12273SCasper.Dik@Sun.COM ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0);
3620Sstevel@tonic-gate if (atomic_add_32_nv(&cr->cr_ref, -1) == 0) {
3630Sstevel@tonic-gate ASSERT(cr != kcred);
3641676Sjpk if (cr->cr_label)
3651676Sjpk label_rele(cr->cr_label);
3666134Scasper if (cr->cr_klpd)
3676134Scasper crklpd_rele(cr->cr_klpd);
3680Sstevel@tonic-gate if (cr->cr_zone)
3690Sstevel@tonic-gate zone_cred_rele(cr->cr_zone);
3704321Scasper if (cr->cr_ksid)
3714321Scasper kcrsid_rele(cr->cr_ksid);
37211134SCasper.Dik@Sun.COM if (cr->cr_grps)
37311134SCasper.Dik@Sun.COM crgrprele(cr->cr_grps);
37411134SCasper.Dik@Sun.COM
3750Sstevel@tonic-gate kmem_cache_free(cred_cache, cr);
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate /*
3800Sstevel@tonic-gate * Copy a cred structure to a new one and free the old one.
3810Sstevel@tonic-gate * The new cred will have two references. One for the calling process,
3820Sstevel@tonic-gate * and one for the thread.
3830Sstevel@tonic-gate */
3840Sstevel@tonic-gate cred_t *
crcopy(cred_t * cr)3850Sstevel@tonic-gate crcopy(cred_t *cr)
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate cred_t *newcr;
3880Sstevel@tonic-gate
3890Sstevel@tonic-gate newcr = cralloc();
3900Sstevel@tonic-gate bcopy(cr, newcr, crsize);
3910Sstevel@tonic-gate if (newcr->cr_zone)
3920Sstevel@tonic-gate zone_cred_hold(newcr->cr_zone);
3931676Sjpk if (newcr->cr_label)
3946134Scasper label_hold(newcr->cr_label);
3954321Scasper if (newcr->cr_ksid)
3966134Scasper kcrsid_hold(newcr->cr_ksid);
3976134Scasper if (newcr->cr_klpd)
3986134Scasper crklpd_hold(newcr->cr_klpd);
39911134SCasper.Dik@Sun.COM if (newcr->cr_grps)
40011134SCasper.Dik@Sun.COM crgrphold(newcr->cr_grps);
4010Sstevel@tonic-gate crfree(cr);
4020Sstevel@tonic-gate newcr->cr_ref = 2; /* caller gets two references */
4030Sstevel@tonic-gate return (newcr);
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate /*
4070Sstevel@tonic-gate * Copy a cred structure to a new one and free the old one.
4080Sstevel@tonic-gate * The new cred will have two references. One for the calling process,
4090Sstevel@tonic-gate * and one for the thread.
4100Sstevel@tonic-gate * This variation on crcopy uses a pre-allocated structure for the
4110Sstevel@tonic-gate * "new" cred.
4120Sstevel@tonic-gate */
4130Sstevel@tonic-gate void
crcopy_to(cred_t * oldcr,cred_t * newcr)4140Sstevel@tonic-gate crcopy_to(cred_t *oldcr, cred_t *newcr)
4150Sstevel@tonic-gate {
4164321Scasper credsid_t *nkcr = newcr->cr_ksid;
4174321Scasper
4180Sstevel@tonic-gate bcopy(oldcr, newcr, crsize);
4190Sstevel@tonic-gate if (newcr->cr_zone)
4200Sstevel@tonic-gate zone_cred_hold(newcr->cr_zone);
4211676Sjpk if (newcr->cr_label)
4221676Sjpk label_hold(newcr->cr_label);
4236134Scasper if (newcr->cr_klpd)
4246134Scasper crklpd_hold(newcr->cr_klpd);
42511134SCasper.Dik@Sun.COM if (newcr->cr_grps)
42611134SCasper.Dik@Sun.COM crgrphold(newcr->cr_grps);
4274321Scasper if (nkcr) {
4284321Scasper newcr->cr_ksid = nkcr;
4294321Scasper kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
4304321Scasper } else if (newcr->cr_ksid)
4314321Scasper kcrsid_hold(newcr->cr_ksid);
4320Sstevel@tonic-gate crfree(oldcr);
4330Sstevel@tonic-gate newcr->cr_ref = 2; /* caller gets two references */
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate
4360Sstevel@tonic-gate /*
4370Sstevel@tonic-gate * Dup a cred struct to a new held one.
4380Sstevel@tonic-gate * The old cred is not freed.
4390Sstevel@tonic-gate */
4406134Scasper static cred_t *
crdup_flags(const cred_t * cr,int flgs)4419710SKen.Powell@Sun.COM crdup_flags(const cred_t *cr, int flgs)
4420Sstevel@tonic-gate {
4430Sstevel@tonic-gate cred_t *newcr;
4440Sstevel@tonic-gate
4456134Scasper newcr = cralloc_flags(flgs);
4466134Scasper
4476134Scasper if (newcr == NULL)
4486134Scasper return (NULL);
4496134Scasper
4500Sstevel@tonic-gate bcopy(cr, newcr, crsize);
4510Sstevel@tonic-gate if (newcr->cr_zone)
4520Sstevel@tonic-gate zone_cred_hold(newcr->cr_zone);
4531676Sjpk if (newcr->cr_label)
4541676Sjpk label_hold(newcr->cr_label);
4556134Scasper if (newcr->cr_klpd)
4566134Scasper crklpd_hold(newcr->cr_klpd);
4574321Scasper if (newcr->cr_ksid)
4584321Scasper kcrsid_hold(newcr->cr_ksid);
45911134SCasper.Dik@Sun.COM if (newcr->cr_grps)
46011134SCasper.Dik@Sun.COM crgrphold(newcr->cr_grps);
4610Sstevel@tonic-gate newcr->cr_ref = 1;
4620Sstevel@tonic-gate return (newcr);
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate
4656134Scasper cred_t *
crdup(cred_t * cr)4666134Scasper crdup(cred_t *cr)
4676134Scasper {
4686134Scasper return (crdup_flags(cr, KM_SLEEP));
4696134Scasper }
4706134Scasper
4710Sstevel@tonic-gate /*
4720Sstevel@tonic-gate * Dup a cred struct to a new held one.
4730Sstevel@tonic-gate * The old cred is not freed.
4740Sstevel@tonic-gate * This variation on crdup uses a pre-allocated structure for the
4750Sstevel@tonic-gate * "new" cred.
4760Sstevel@tonic-gate */
4770Sstevel@tonic-gate void
crdup_to(cred_t * oldcr,cred_t * newcr)4780Sstevel@tonic-gate crdup_to(cred_t *oldcr, cred_t *newcr)
4790Sstevel@tonic-gate {
4804321Scasper credsid_t *nkcr = newcr->cr_ksid;
4814321Scasper
4820Sstevel@tonic-gate bcopy(oldcr, newcr, crsize);
4830Sstevel@tonic-gate if (newcr->cr_zone)
4840Sstevel@tonic-gate zone_cred_hold(newcr->cr_zone);
4851676Sjpk if (newcr->cr_label)
4861676Sjpk label_hold(newcr->cr_label);
4876134Scasper if (newcr->cr_klpd)
4886134Scasper crklpd_hold(newcr->cr_klpd);
48911134SCasper.Dik@Sun.COM if (newcr->cr_grps)
49011134SCasper.Dik@Sun.COM crgrphold(newcr->cr_grps);
4914321Scasper if (nkcr) {
4924321Scasper newcr->cr_ksid = nkcr;
4934321Scasper kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
4944321Scasper } else if (newcr->cr_ksid)
4954321Scasper kcrsid_hold(newcr->cr_ksid);
4960Sstevel@tonic-gate newcr->cr_ref = 1;
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate
4990Sstevel@tonic-gate /*
5000Sstevel@tonic-gate * Return the (held) credentials for the current running process.
5010Sstevel@tonic-gate */
5020Sstevel@tonic-gate cred_t *
crgetcred(void)5031676Sjpk crgetcred(void)
5040Sstevel@tonic-gate {
5050Sstevel@tonic-gate cred_t *cr;
5060Sstevel@tonic-gate proc_t *p;
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate p = ttoproc(curthread);
5090Sstevel@tonic-gate mutex_enter(&p->p_crlock);
5100Sstevel@tonic-gate crhold(cr = p->p_cred);
5110Sstevel@tonic-gate mutex_exit(&p->p_crlock);
5120Sstevel@tonic-gate return (cr);
5130Sstevel@tonic-gate }
5140Sstevel@tonic-gate
5150Sstevel@tonic-gate /*
5160Sstevel@tonic-gate * Backward compatibility check for suser().
5170Sstevel@tonic-gate * Accounting flag is now set in the policy functions; auditing is
5180Sstevel@tonic-gate * done through use of privilege in the audit trail.
5190Sstevel@tonic-gate */
5200Sstevel@tonic-gate int
suser(cred_t * cr)5210Sstevel@tonic-gate suser(cred_t *cr)
5220Sstevel@tonic-gate {
5230Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_SUSER_COMPAT, B_FALSE, EPERM, NULL)
5240Sstevel@tonic-gate == 0);
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate /*
5280Sstevel@tonic-gate * Determine whether the supplied group id is a member of the group
5290Sstevel@tonic-gate * described by the supplied credentials.
5300Sstevel@tonic-gate */
5310Sstevel@tonic-gate int
groupmember(gid_t gid,const cred_t * cr)5320Sstevel@tonic-gate groupmember(gid_t gid, const cred_t *cr)
5330Sstevel@tonic-gate {
5340Sstevel@tonic-gate if (gid == cr->cr_gid)
5350Sstevel@tonic-gate return (1);
5360Sstevel@tonic-gate return (supgroupmember(gid, cr));
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate /*
5400Sstevel@tonic-gate * As groupmember but only check against the supplemental groups.
5410Sstevel@tonic-gate */
5420Sstevel@tonic-gate int
supgroupmember(gid_t gid,const cred_t * cr)5430Sstevel@tonic-gate supgroupmember(gid_t gid, const cred_t *cr)
5440Sstevel@tonic-gate {
54511134SCasper.Dik@Sun.COM int hi, lo;
54611134SCasper.Dik@Sun.COM credgrp_t *grps = cr->cr_grps;
5470Sstevel@tonic-gate const gid_t *gp, *endgp;
5480Sstevel@tonic-gate
54911134SCasper.Dik@Sun.COM if (grps == NULL)
55011134SCasper.Dik@Sun.COM return (0);
55111134SCasper.Dik@Sun.COM
55211134SCasper.Dik@Sun.COM /* For a small number of groups, use sequentials search. */
55311134SCasper.Dik@Sun.COM if (grps->crg_ngroups <= BIN_GROUP_SEARCH_CUTOFF) {
55411134SCasper.Dik@Sun.COM endgp = &grps->crg_groups[grps->crg_ngroups];
55511134SCasper.Dik@Sun.COM for (gp = grps->crg_groups; gp < endgp; gp++)
55611134SCasper.Dik@Sun.COM if (*gp == gid)
55711134SCasper.Dik@Sun.COM return (1);
55811134SCasper.Dik@Sun.COM return (0);
55911134SCasper.Dik@Sun.COM }
56011134SCasper.Dik@Sun.COM
56111134SCasper.Dik@Sun.COM /* We use binary search when we have many groups. */
56211134SCasper.Dik@Sun.COM lo = 0;
56311134SCasper.Dik@Sun.COM hi = grps->crg_ngroups - 1;
56411134SCasper.Dik@Sun.COM gp = grps->crg_groups;
56511134SCasper.Dik@Sun.COM
56611134SCasper.Dik@Sun.COM do {
56711134SCasper.Dik@Sun.COM int m = (lo + hi) / 2;
56811134SCasper.Dik@Sun.COM
56911134SCasper.Dik@Sun.COM if (gid > gp[m])
57011134SCasper.Dik@Sun.COM lo = m + 1;
57111134SCasper.Dik@Sun.COM else if (gid < gp[m])
57211134SCasper.Dik@Sun.COM hi = m - 1;
57311134SCasper.Dik@Sun.COM else
5740Sstevel@tonic-gate return (1);
57511134SCasper.Dik@Sun.COM } while (lo <= hi);
57611134SCasper.Dik@Sun.COM
5770Sstevel@tonic-gate return (0);
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate /*
5810Sstevel@tonic-gate * This function is called to check whether the credentials set
5820Sstevel@tonic-gate * "scrp" has permission to act on credentials set "tcrp". It enforces the
5830Sstevel@tonic-gate * permission requirements needed to send a signal to a process.
5840Sstevel@tonic-gate * The same requirements are imposed by other system calls, however.
5850Sstevel@tonic-gate *
5860Sstevel@tonic-gate * The rules are:
5870Sstevel@tonic-gate * (1) if the credentials are the same, the check succeeds
5880Sstevel@tonic-gate * (2) if the zone ids don't match, and scrp is not in the global zone or
5890Sstevel@tonic-gate * does not have the PRIV_PROC_ZONE privilege, the check fails
5900Sstevel@tonic-gate * (3) if the real or effective user id of scrp matches the real or saved
5910Sstevel@tonic-gate * user id of tcrp or scrp has the PRIV_PROC_OWNER privilege, the check
5920Sstevel@tonic-gate * succeeds
5930Sstevel@tonic-gate * (4) otherwise, the check fails
5940Sstevel@tonic-gate */
5950Sstevel@tonic-gate int
hasprocperm(const cred_t * tcrp,const cred_t * scrp)5960Sstevel@tonic-gate hasprocperm(const cred_t *tcrp, const cred_t *scrp)
5970Sstevel@tonic-gate {
5980Sstevel@tonic-gate if (scrp == tcrp)
5990Sstevel@tonic-gate return (1);
6000Sstevel@tonic-gate if (scrp->cr_zone != tcrp->cr_zone &&
6010Sstevel@tonic-gate (scrp->cr_zone != global_zone ||
6020Sstevel@tonic-gate secpolicy_proc_zone(scrp) != 0))
6030Sstevel@tonic-gate return (0);
6040Sstevel@tonic-gate if (scrp->cr_uid == tcrp->cr_ruid ||
6050Sstevel@tonic-gate scrp->cr_ruid == tcrp->cr_ruid ||
6060Sstevel@tonic-gate scrp->cr_uid == tcrp->cr_suid ||
6070Sstevel@tonic-gate scrp->cr_ruid == tcrp->cr_suid ||
6080Sstevel@tonic-gate !PRIV_POLICY(scrp, PRIV_PROC_OWNER, B_FALSE, EPERM, "hasprocperm"))
6090Sstevel@tonic-gate return (1);
6100Sstevel@tonic-gate return (0);
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate /*
6140Sstevel@tonic-gate * This interface replaces hasprocperm; it works like hasprocperm but
6150Sstevel@tonic-gate * additionally returns success if the proc_t's match
6160Sstevel@tonic-gate * It is the preferred interface for most uses.
6176134Scasper * And it will acquire p_crlock itself, so it assert's that it shouldn't
6180Sstevel@tonic-gate * be held.
6190Sstevel@tonic-gate */
6200Sstevel@tonic-gate int
prochasprocperm(proc_t * tp,proc_t * sp,const cred_t * scrp)6210Sstevel@tonic-gate prochasprocperm(proc_t *tp, proc_t *sp, const cred_t *scrp)
6220Sstevel@tonic-gate {
6230Sstevel@tonic-gate int rets;
6240Sstevel@tonic-gate cred_t *tcrp;
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&tp->p_crlock));
6270Sstevel@tonic-gate
6280Sstevel@tonic-gate if (tp == sp)
6290Sstevel@tonic-gate return (1);
6300Sstevel@tonic-gate
6310Sstevel@tonic-gate if (tp->p_sessp != sp->p_sessp && secpolicy_basic_proc(scrp) != 0)
6320Sstevel@tonic-gate return (0);
6330Sstevel@tonic-gate
6340Sstevel@tonic-gate mutex_enter(&tp->p_crlock);
6356134Scasper crhold(tcrp = tp->p_cred);
6366134Scasper mutex_exit(&tp->p_crlock);
6370Sstevel@tonic-gate rets = hasprocperm(tcrp, scrp);
6386134Scasper crfree(tcrp);
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate return (rets);
6410Sstevel@tonic-gate }
6420Sstevel@tonic-gate
6430Sstevel@tonic-gate /*
6440Sstevel@tonic-gate * This routine is used to compare two credentials to determine if
6450Sstevel@tonic-gate * they refer to the same "user". If the pointers are equal, then
6460Sstevel@tonic-gate * they must refer to the same user. Otherwise, the contents of
6470Sstevel@tonic-gate * the credentials are compared to see whether they are equivalent.
6480Sstevel@tonic-gate *
6490Sstevel@tonic-gate * This routine returns 0 if the credentials refer to the same user,
6500Sstevel@tonic-gate * 1 if they do not.
6510Sstevel@tonic-gate */
6520Sstevel@tonic-gate int
crcmp(const cred_t * cr1,const cred_t * cr2)6530Sstevel@tonic-gate crcmp(const cred_t *cr1, const cred_t *cr2)
6540Sstevel@tonic-gate {
65511134SCasper.Dik@Sun.COM credgrp_t *grp1, *grp2;
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate if (cr1 == cr2)
6580Sstevel@tonic-gate return (0);
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate if (cr1->cr_uid == cr2->cr_uid &&
6610Sstevel@tonic-gate cr1->cr_gid == cr2->cr_gid &&
6620Sstevel@tonic-gate cr1->cr_ruid == cr2->cr_ruid &&
6630Sstevel@tonic-gate cr1->cr_rgid == cr2->cr_rgid &&
6640Sstevel@tonic-gate cr1->cr_zone == cr2->cr_zone &&
66511134SCasper.Dik@Sun.COM ((grp1 = cr1->cr_grps) == (grp2 = cr2->cr_grps) ||
66611134SCasper.Dik@Sun.COM (grp1 != NULL && grp2 != NULL &&
66711134SCasper.Dik@Sun.COM grp1->crg_ngroups == grp2->crg_ngroups &&
66811134SCasper.Dik@Sun.COM bcmp(grp1->crg_groups, grp2->crg_groups,
66911134SCasper.Dik@Sun.COM grp1->crg_ngroups * sizeof (gid_t)) == 0))) {
6700Sstevel@tonic-gate return (!priv_isequalset(&CR_OEPRIV(cr1), &CR_OEPRIV(cr2)));
6710Sstevel@tonic-gate }
6720Sstevel@tonic-gate return (1);
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate
6750Sstevel@tonic-gate /*
6760Sstevel@tonic-gate * Read access functions to cred_t.
6770Sstevel@tonic-gate */
6780Sstevel@tonic-gate uid_t
crgetuid(const cred_t * cr)6790Sstevel@tonic-gate crgetuid(const cred_t *cr)
6800Sstevel@tonic-gate {
6810Sstevel@tonic-gate return (cr->cr_uid);
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate uid_t
crgetruid(const cred_t * cr)6850Sstevel@tonic-gate crgetruid(const cred_t *cr)
6860Sstevel@tonic-gate {
6870Sstevel@tonic-gate return (cr->cr_ruid);
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate
6900Sstevel@tonic-gate uid_t
crgetsuid(const cred_t * cr)6910Sstevel@tonic-gate crgetsuid(const cred_t *cr)
6920Sstevel@tonic-gate {
6930Sstevel@tonic-gate return (cr->cr_suid);
6940Sstevel@tonic-gate }
6950Sstevel@tonic-gate
6960Sstevel@tonic-gate gid_t
crgetgid(const cred_t * cr)6970Sstevel@tonic-gate crgetgid(const cred_t *cr)
6980Sstevel@tonic-gate {
6990Sstevel@tonic-gate return (cr->cr_gid);
7000Sstevel@tonic-gate }
7010Sstevel@tonic-gate
7020Sstevel@tonic-gate gid_t
crgetrgid(const cred_t * cr)7030Sstevel@tonic-gate crgetrgid(const cred_t *cr)
7040Sstevel@tonic-gate {
7050Sstevel@tonic-gate return (cr->cr_rgid);
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate gid_t
crgetsgid(const cred_t * cr)7090Sstevel@tonic-gate crgetsgid(const cred_t *cr)
7100Sstevel@tonic-gate {
7110Sstevel@tonic-gate return (cr->cr_sgid);
7120Sstevel@tonic-gate }
7130Sstevel@tonic-gate
7140Sstevel@tonic-gate const auditinfo_addr_t *
crgetauinfo(const cred_t * cr)7150Sstevel@tonic-gate crgetauinfo(const cred_t *cr)
7160Sstevel@tonic-gate {
7170Sstevel@tonic-gate return ((const auditinfo_addr_t *)CR_AUINFO(cr));
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate auditinfo_addr_t *
crgetauinfo_modifiable(cred_t * cr)7210Sstevel@tonic-gate crgetauinfo_modifiable(cred_t *cr)
7220Sstevel@tonic-gate {
7230Sstevel@tonic-gate return (CR_AUINFO(cr));
7240Sstevel@tonic-gate }
7250Sstevel@tonic-gate
7260Sstevel@tonic-gate zoneid_t
crgetzoneid(const cred_t * cr)7270Sstevel@tonic-gate crgetzoneid(const cred_t *cr)
7280Sstevel@tonic-gate {
7291676Sjpk return (cr->cr_zone == NULL ?
7301676Sjpk (cr->cr_uid == -1 ? (zoneid_t)-1 : GLOBAL_ZONEID) :
7311676Sjpk cr->cr_zone->zone_id);
7320Sstevel@tonic-gate }
7330Sstevel@tonic-gate
7340Sstevel@tonic-gate projid_t
crgetprojid(const cred_t * cr)7350Sstevel@tonic-gate crgetprojid(const cred_t *cr)
7360Sstevel@tonic-gate {
7370Sstevel@tonic-gate return (cr->cr_projid);
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate
7401676Sjpk zone_t *
crgetzone(const cred_t * cr)7411676Sjpk crgetzone(const cred_t *cr)
7421676Sjpk {
7431676Sjpk return (cr->cr_zone);
7441676Sjpk }
7451676Sjpk
7461676Sjpk struct ts_label_s *
crgetlabel(const cred_t * cr)7471676Sjpk crgetlabel(const cred_t *cr)
7481676Sjpk {
7491676Sjpk return (cr->cr_label ?
7501676Sjpk cr->cr_label :
7511676Sjpk (cr->cr_zone ? cr->cr_zone->zone_slabel : NULL));
7521676Sjpk }
7531676Sjpk
7541676Sjpk boolean_t
crisremote(const cred_t * cr)7551676Sjpk crisremote(const cred_t *cr)
7561676Sjpk {
7571676Sjpk return (REMOTE_PEER_CRED(cr));
7581676Sjpk }
7591676Sjpk
7605771Sjp151216 #define BADUID(x, zn) ((x) != -1 && !VALID_UID((x), (zn)))
7615771Sjp151216 #define BADGID(x, zn) ((x) != -1 && !VALID_GID((x), (zn)))
7620Sstevel@tonic-gate
7630Sstevel@tonic-gate int
crsetresuid(cred_t * cr,uid_t r,uid_t e,uid_t s)7640Sstevel@tonic-gate crsetresuid(cred_t *cr, uid_t r, uid_t e, uid_t s)
7650Sstevel@tonic-gate {
7665771Sjp151216 zone_t *zone = crgetzone(cr);
7675771Sjp151216
7680Sstevel@tonic-gate ASSERT(cr->cr_ref <= 2);
7690Sstevel@tonic-gate
7705771Sjp151216 if (BADUID(r, zone) || BADUID(e, zone) || BADUID(s, zone))
7710Sstevel@tonic-gate return (-1);
7720Sstevel@tonic-gate
7730Sstevel@tonic-gate if (r != -1)
7740Sstevel@tonic-gate cr->cr_ruid = r;
7750Sstevel@tonic-gate if (e != -1)
7760Sstevel@tonic-gate cr->cr_uid = e;
7770Sstevel@tonic-gate if (s != -1)
7780Sstevel@tonic-gate cr->cr_suid = s;
7790Sstevel@tonic-gate
7800Sstevel@tonic-gate return (0);
7810Sstevel@tonic-gate }
7820Sstevel@tonic-gate
7830Sstevel@tonic-gate int
crsetresgid(cred_t * cr,gid_t r,gid_t e,gid_t s)7840Sstevel@tonic-gate crsetresgid(cred_t *cr, gid_t r, gid_t e, gid_t s)
7850Sstevel@tonic-gate {
7865771Sjp151216 zone_t *zone = crgetzone(cr);
7875771Sjp151216
7880Sstevel@tonic-gate ASSERT(cr->cr_ref <= 2);
7890Sstevel@tonic-gate
7905771Sjp151216 if (BADGID(r, zone) || BADGID(e, zone) || BADGID(s, zone))
7910Sstevel@tonic-gate return (-1);
7920Sstevel@tonic-gate
7930Sstevel@tonic-gate if (r != -1)
7940Sstevel@tonic-gate cr->cr_rgid = r;
7950Sstevel@tonic-gate if (e != -1)
7960Sstevel@tonic-gate cr->cr_gid = e;
7970Sstevel@tonic-gate if (s != -1)
7980Sstevel@tonic-gate cr->cr_sgid = s;
7990Sstevel@tonic-gate
8000Sstevel@tonic-gate return (0);
8010Sstevel@tonic-gate }
8020Sstevel@tonic-gate
8030Sstevel@tonic-gate int
crsetugid(cred_t * cr,uid_t uid,gid_t gid)8040Sstevel@tonic-gate crsetugid(cred_t *cr, uid_t uid, gid_t gid)
8050Sstevel@tonic-gate {
8065771Sjp151216 zone_t *zone = crgetzone(cr);
8075771Sjp151216
8080Sstevel@tonic-gate ASSERT(cr->cr_ref <= 2);
8090Sstevel@tonic-gate
8105771Sjp151216 if (!VALID_UID(uid, zone) || !VALID_GID(gid, zone))
8110Sstevel@tonic-gate return (-1);
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate cr->cr_uid = cr->cr_ruid = cr->cr_suid = uid;
8140Sstevel@tonic-gate cr->cr_gid = cr->cr_rgid = cr->cr_sgid = gid;
8150Sstevel@tonic-gate
8160Sstevel@tonic-gate return (0);
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate
81911134SCasper.Dik@Sun.COM static int
gidcmp(const void * v1,const void * v2)82011134SCasper.Dik@Sun.COM gidcmp(const void *v1, const void *v2)
82111134SCasper.Dik@Sun.COM {
82211134SCasper.Dik@Sun.COM gid_t g1 = *(gid_t *)v1;
82311134SCasper.Dik@Sun.COM gid_t g2 = *(gid_t *)v2;
82411134SCasper.Dik@Sun.COM
82511134SCasper.Dik@Sun.COM if (g1 < g2)
82611134SCasper.Dik@Sun.COM return (-1);
82711134SCasper.Dik@Sun.COM else if (g1 > g2)
82811134SCasper.Dik@Sun.COM return (1);
82911134SCasper.Dik@Sun.COM else
83011134SCasper.Dik@Sun.COM return (0);
83111134SCasper.Dik@Sun.COM }
83211134SCasper.Dik@Sun.COM
8330Sstevel@tonic-gate int
crsetgroups(cred_t * cr,int n,gid_t * grp)8340Sstevel@tonic-gate crsetgroups(cred_t *cr, int n, gid_t *grp)
8350Sstevel@tonic-gate {
8360Sstevel@tonic-gate ASSERT(cr->cr_ref <= 2);
8370Sstevel@tonic-gate
8380Sstevel@tonic-gate if (n > ngroups_max || n < 0)
8390Sstevel@tonic-gate return (-1);
8400Sstevel@tonic-gate
84111134SCasper.Dik@Sun.COM if (cr->cr_grps != NULL)
84211134SCasper.Dik@Sun.COM crgrprele(cr->cr_grps);
8430Sstevel@tonic-gate
84411134SCasper.Dik@Sun.COM if (n > 0) {
84511134SCasper.Dik@Sun.COM cr->cr_grps = kmem_alloc(CREDGRPSZ(n), KM_SLEEP);
84611134SCasper.Dik@Sun.COM bcopy(grp, cr->cr_grps->crg_groups, n * sizeof (gid_t));
84711134SCasper.Dik@Sun.COM cr->cr_grps->crg_ref = 1;
84811134SCasper.Dik@Sun.COM cr->cr_grps->crg_ngroups = n;
84911134SCasper.Dik@Sun.COM qsort(cr->cr_grps->crg_groups, n, sizeof (gid_t), gidcmp);
85011134SCasper.Dik@Sun.COM } else {
85111134SCasper.Dik@Sun.COM cr->cr_grps = NULL;
85211134SCasper.Dik@Sun.COM }
8530Sstevel@tonic-gate
8540Sstevel@tonic-gate return (0);
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate
8570Sstevel@tonic-gate void
crsetprojid(cred_t * cr,projid_t projid)8580Sstevel@tonic-gate crsetprojid(cred_t *cr, projid_t projid)
8590Sstevel@tonic-gate {
8600Sstevel@tonic-gate ASSERT(projid >= 0 && projid <= MAXPROJID);
8610Sstevel@tonic-gate cr->cr_projid = projid;
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate
8640Sstevel@tonic-gate /*
86511134SCasper.Dik@Sun.COM * This routine returns the pointer to the first element of the crg_groups
8660Sstevel@tonic-gate * array. It can move around in an implementation defined way.
86711134SCasper.Dik@Sun.COM * Note that when we have no grouplist, we return one element but the
86811134SCasper.Dik@Sun.COM * caller should never reference it.
8690Sstevel@tonic-gate */
8700Sstevel@tonic-gate const gid_t *
crgetgroups(const cred_t * cr)8710Sstevel@tonic-gate crgetgroups(const cred_t *cr)
8720Sstevel@tonic-gate {
87311134SCasper.Dik@Sun.COM return (cr->cr_grps == NULL ? &cr->cr_gid : cr->cr_grps->crg_groups);
8740Sstevel@tonic-gate }
8750Sstevel@tonic-gate
8760Sstevel@tonic-gate int
crgetngroups(const cred_t * cr)8770Sstevel@tonic-gate crgetngroups(const cred_t *cr)
8780Sstevel@tonic-gate {
87911134SCasper.Dik@Sun.COM return (cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups);
8800Sstevel@tonic-gate }
8810Sstevel@tonic-gate
8820Sstevel@tonic-gate void
cred2prcred(const cred_t * cr,prcred_t * pcrp)8830Sstevel@tonic-gate cred2prcred(const cred_t *cr, prcred_t *pcrp)
8840Sstevel@tonic-gate {
8850Sstevel@tonic-gate pcrp->pr_euid = cr->cr_uid;
8860Sstevel@tonic-gate pcrp->pr_ruid = cr->cr_ruid;
8870Sstevel@tonic-gate pcrp->pr_suid = cr->cr_suid;
8880Sstevel@tonic-gate pcrp->pr_egid = cr->cr_gid;
8890Sstevel@tonic-gate pcrp->pr_rgid = cr->cr_rgid;
8900Sstevel@tonic-gate pcrp->pr_sgid = cr->cr_sgid;
89111134SCasper.Dik@Sun.COM pcrp->pr_groups[0] = 0; /* in case ngroups == 0 */
89211134SCasper.Dik@Sun.COM pcrp->pr_ngroups = cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups;
8930Sstevel@tonic-gate
8940Sstevel@tonic-gate if (pcrp->pr_ngroups != 0)
89511134SCasper.Dik@Sun.COM bcopy(cr->cr_grps->crg_groups, pcrp->pr_groups,
89611134SCasper.Dik@Sun.COM sizeof (gid_t) * pcrp->pr_ngroups);
8970Sstevel@tonic-gate }
8980Sstevel@tonic-gate
8990Sstevel@tonic-gate static int
cred2ucaud(const cred_t * cr,auditinfo64_addr_t * ainfo,const cred_t * rcr)9001676Sjpk cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo, const cred_t *rcr)
9010Sstevel@tonic-gate {
9020Sstevel@tonic-gate auditinfo_addr_t *ai;
9030Sstevel@tonic-gate au_tid_addr_t tid;
9040Sstevel@tonic-gate
905*12273SCasper.Dik@Sun.COM if (secpolicy_audit_getattr(rcr, B_TRUE) != 0)
9060Sstevel@tonic-gate return (-1);
9070Sstevel@tonic-gate
9080Sstevel@tonic-gate ai = CR_AUINFO(cr); /* caller makes sure this is non-NULL */
9090Sstevel@tonic-gate tid = ai->ai_termid;
9100Sstevel@tonic-gate
9110Sstevel@tonic-gate ainfo->ai_auid = ai->ai_auid;
9120Sstevel@tonic-gate ainfo->ai_mask = ai->ai_mask;
9130Sstevel@tonic-gate ainfo->ai_asid = ai->ai_asid;
9140Sstevel@tonic-gate
9150Sstevel@tonic-gate ainfo->ai_termid.at_type = tid.at_type;
9160Sstevel@tonic-gate bcopy(&tid.at_addr, &ainfo->ai_termid.at_addr, 4 * sizeof (uint_t));
9170Sstevel@tonic-gate
9180Sstevel@tonic-gate ainfo->ai_termid.at_port.at_major = (uint32_t)getmajor(tid.at_port);
9190Sstevel@tonic-gate ainfo->ai_termid.at_port.at_minor = (uint32_t)getminor(tid.at_port);
9200Sstevel@tonic-gate
9210Sstevel@tonic-gate return (0);
9220Sstevel@tonic-gate }
9230Sstevel@tonic-gate
9241676Sjpk void
cred2uclabel(const cred_t * cr,bslabel_t * labelp)9251676Sjpk cred2uclabel(const cred_t *cr, bslabel_t *labelp)
9261676Sjpk {
9271676Sjpk ts_label_t *tslp;
9281676Sjpk
9291676Sjpk if ((tslp = crgetlabel(cr)) != NULL)
9301676Sjpk bcopy(&tslp->tsl_label, labelp, sizeof (bslabel_t));
9311676Sjpk }
9321676Sjpk
9330Sstevel@tonic-gate /*
9340Sstevel@tonic-gate * Convert a credential into a "ucred". Allow the caller to specify
9350Sstevel@tonic-gate * and aligned buffer, e.g., in an mblk, so we don't have to allocate
9360Sstevel@tonic-gate * memory and copy it twice.
9371676Sjpk *
9381676Sjpk * This function may call cred2ucaud(), which calls CRED(). Since this
9391676Sjpk * can be called from an interrupt thread, receiver's cred (rcr) is needed
9401676Sjpk * to determine whether audit info should be included.
9410Sstevel@tonic-gate */
9420Sstevel@tonic-gate struct ucred_s *
cred2ucred(const cred_t * cr,pid_t pid,void * buf,const cred_t * rcr)9431676Sjpk cred2ucred(const cred_t *cr, pid_t pid, void *buf, const cred_t *rcr)
9440Sstevel@tonic-gate {
9450Sstevel@tonic-gate struct ucred_s *uc;
94611134SCasper.Dik@Sun.COM uint32_t realsz = ucredminsize(cr);
94711134SCasper.Dik@Sun.COM ts_label_t *tslp = is_system_labeled() ? crgetlabel(cr) : NULL;
9480Sstevel@tonic-gate
9490Sstevel@tonic-gate /* The structure isn't always completely filled in, so zero it */
9500Sstevel@tonic-gate if (buf == NULL) {
95111134SCasper.Dik@Sun.COM uc = kmem_zalloc(realsz, KM_SLEEP);
9520Sstevel@tonic-gate } else {
95311134SCasper.Dik@Sun.COM bzero(buf, realsz);
9540Sstevel@tonic-gate uc = buf;
9550Sstevel@tonic-gate }
95611134SCasper.Dik@Sun.COM uc->uc_size = realsz;
9570Sstevel@tonic-gate uc->uc_pid = pid;
9580Sstevel@tonic-gate uc->uc_projid = cr->cr_projid;
9590Sstevel@tonic-gate uc->uc_zoneid = crgetzoneid(cr);
9600Sstevel@tonic-gate
9611676Sjpk if (REMOTE_PEER_CRED(cr)) {
9621676Sjpk /*
96311134SCasper.Dik@Sun.COM * Other than label, the rest of cred info about a
96411134SCasper.Dik@Sun.COM * remote peer isn't available. Copy the label directly
96511134SCasper.Dik@Sun.COM * after the header where we generally copy the prcred.
96611134SCasper.Dik@Sun.COM * That's why we use sizeof (struct ucred_s). The other
96711134SCasper.Dik@Sun.COM * offset fields are initialized to 0.
9681676Sjpk */
96911134SCasper.Dik@Sun.COM uc->uc_labeloff = tslp == NULL ? 0 : sizeof (struct ucred_s);
9701676Sjpk } else {
97111134SCasper.Dik@Sun.COM uc->uc_credoff = UCRED_CRED_OFF;
97211134SCasper.Dik@Sun.COM uc->uc_privoff = UCRED_PRIV_OFF;
97311134SCasper.Dik@Sun.COM uc->uc_audoff = UCRED_AUD_OFF;
97411134SCasper.Dik@Sun.COM uc->uc_labeloff = tslp == NULL ? 0 : UCRED_LABEL_OFF;
97511134SCasper.Dik@Sun.COM
9761676Sjpk cred2prcred(cr, UCCRED(uc));
9771676Sjpk cred2prpriv(cr, UCPRIV(uc));
97811134SCasper.Dik@Sun.COM
9791676Sjpk if (audoff == 0 || cred2ucaud(cr, UCAUD(uc), rcr) != 0)
9801676Sjpk uc->uc_audoff = 0;
98111134SCasper.Dik@Sun.COM }
98211134SCasper.Dik@Sun.COM if (tslp != NULL)
98311134SCasper.Dik@Sun.COM bcopy(&tslp->tsl_label, UCLABEL(uc), sizeof (bslabel_t));
98411134SCasper.Dik@Sun.COM
98511134SCasper.Dik@Sun.COM return (uc);
98611134SCasper.Dik@Sun.COM }
98711134SCasper.Dik@Sun.COM
98811134SCasper.Dik@Sun.COM /*
98911134SCasper.Dik@Sun.COM * Don't allocate the non-needed group entries. Note: this function
99011134SCasper.Dik@Sun.COM * must match the code in cred2ucred; they must agree about the
99111134SCasper.Dik@Sun.COM * minimal size of the ucred.
99211134SCasper.Dik@Sun.COM */
99311134SCasper.Dik@Sun.COM uint32_t
ucredminsize(const cred_t * cr)99411134SCasper.Dik@Sun.COM ucredminsize(const cred_t *cr)
99511134SCasper.Dik@Sun.COM {
99611134SCasper.Dik@Sun.COM int ndiff;
99711134SCasper.Dik@Sun.COM
99811134SCasper.Dik@Sun.COM if (cr == NULL)
99911134SCasper.Dik@Sun.COM return (ucredsize);
100011134SCasper.Dik@Sun.COM
100111134SCasper.Dik@Sun.COM if (REMOTE_PEER_CRED(cr)) {
100211134SCasper.Dik@Sun.COM if (is_system_labeled())
100311134SCasper.Dik@Sun.COM return (sizeof (struct ucred_s) + sizeof (bslabel_t));
100411134SCasper.Dik@Sun.COM else
100511134SCasper.Dik@Sun.COM return (sizeof (struct ucred_s));
10061676Sjpk }
10070Sstevel@tonic-gate
100811134SCasper.Dik@Sun.COM if (cr->cr_grps == NULL)
100911134SCasper.Dik@Sun.COM ndiff = ngroups_max - 1; /* Needs one for prcred_t */
101011134SCasper.Dik@Sun.COM else
101111134SCasper.Dik@Sun.COM ndiff = ngroups_max - cr->cr_grps->crg_ngroups;
101211134SCasper.Dik@Sun.COM
101311134SCasper.Dik@Sun.COM return (ucredsize - ndiff * sizeof (gid_t));
10140Sstevel@tonic-gate }
10150Sstevel@tonic-gate
10160Sstevel@tonic-gate /*
10170Sstevel@tonic-gate * Get the "ucred" of a process.
10180Sstevel@tonic-gate */
10190Sstevel@tonic-gate struct ucred_s *
pgetucred(proc_t * p)10200Sstevel@tonic-gate pgetucred(proc_t *p)
10210Sstevel@tonic-gate {
10220Sstevel@tonic-gate cred_t *cr;
10230Sstevel@tonic-gate struct ucred_s *uc;
10240Sstevel@tonic-gate
10250Sstevel@tonic-gate mutex_enter(&p->p_crlock);
10260Sstevel@tonic-gate cr = p->p_cred;
10270Sstevel@tonic-gate crhold(cr);
10280Sstevel@tonic-gate mutex_exit(&p->p_crlock);
10290Sstevel@tonic-gate
10301676Sjpk uc = cred2ucred(cr, p->p_pid, NULL, CRED());
10310Sstevel@tonic-gate crfree(cr);
10320Sstevel@tonic-gate
10330Sstevel@tonic-gate return (uc);
10340Sstevel@tonic-gate }
10350Sstevel@tonic-gate
10360Sstevel@tonic-gate /*
10370Sstevel@tonic-gate * If the reply status is NFSERR_EACCES, it may be because we are
10380Sstevel@tonic-gate * root (no root net access). Check the real uid, if it isn't root
10390Sstevel@tonic-gate * make that the uid instead and retry the call.
10400Sstevel@tonic-gate * Private interface for NFS.
10410Sstevel@tonic-gate */
10420Sstevel@tonic-gate cred_t *
crnetadjust(cred_t * cr)10430Sstevel@tonic-gate crnetadjust(cred_t *cr)
10440Sstevel@tonic-gate {
10450Sstevel@tonic-gate if (cr->cr_uid == 0 && cr->cr_ruid != 0) {
10460Sstevel@tonic-gate cr = crdup(cr);
10470Sstevel@tonic-gate cr->cr_uid = cr->cr_ruid;
10480Sstevel@tonic-gate return (cr);
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate return (NULL);
10510Sstevel@tonic-gate }
10520Sstevel@tonic-gate
10530Sstevel@tonic-gate /*
10540Sstevel@tonic-gate * The reference count is of interest when you want to check
10550Sstevel@tonic-gate * whether it is ok to modify the credential in place.
10560Sstevel@tonic-gate */
10570Sstevel@tonic-gate uint_t
crgetref(const cred_t * cr)10580Sstevel@tonic-gate crgetref(const cred_t *cr)
10590Sstevel@tonic-gate {
10600Sstevel@tonic-gate return (cr->cr_ref);
10610Sstevel@tonic-gate }
10620Sstevel@tonic-gate
10630Sstevel@tonic-gate static int
get_c2audit_load(void)10640Sstevel@tonic-gate get_c2audit_load(void)
10650Sstevel@tonic-gate {
10660Sstevel@tonic-gate static int gotit = 0;
10670Sstevel@tonic-gate static int c2audit_load;
10680Sstevel@tonic-gate
10690Sstevel@tonic-gate if (gotit)
10700Sstevel@tonic-gate return (c2audit_load);
107111861SMarek.Pospisil@Sun.COM c2audit_load = 1; /* set default value once */
107211861SMarek.Pospisil@Sun.COM if (mod_sysctl(SYS_CHECK_EXCLUDE, "c2audit") != 0)
107311861SMarek.Pospisil@Sun.COM c2audit_load = 0;
10740Sstevel@tonic-gate gotit++;
107511861SMarek.Pospisil@Sun.COM
10760Sstevel@tonic-gate return (c2audit_load);
10770Sstevel@tonic-gate }
10780Sstevel@tonic-gate
10790Sstevel@tonic-gate int
get_audit_ucrsize(void)10800Sstevel@tonic-gate get_audit_ucrsize(void)
10810Sstevel@tonic-gate {
10820Sstevel@tonic-gate return (get_c2audit_load() ? sizeof (auditinfo64_addr_t) : 0);
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate
10850Sstevel@tonic-gate /*
10860Sstevel@tonic-gate * Set zone pointer in credential to indicated value. First adds a
10870Sstevel@tonic-gate * hold for the new zone, then drops the hold on previous zone (if any).
10880Sstevel@tonic-gate * This is done in this order in case the old and new zones are the
10890Sstevel@tonic-gate * same.
10900Sstevel@tonic-gate */
10910Sstevel@tonic-gate void
crsetzone(cred_t * cr,zone_t * zptr)10920Sstevel@tonic-gate crsetzone(cred_t *cr, zone_t *zptr)
10930Sstevel@tonic-gate {
10940Sstevel@tonic-gate zone_t *oldzptr = cr->cr_zone;
10950Sstevel@tonic-gate
10960Sstevel@tonic-gate ASSERT(cr != kcred);
10970Sstevel@tonic-gate ASSERT(cr->cr_ref <= 2);
10980Sstevel@tonic-gate cr->cr_zone = zptr;
10990Sstevel@tonic-gate zone_cred_hold(zptr);
11000Sstevel@tonic-gate if (oldzptr)
11010Sstevel@tonic-gate zone_cred_rele(oldzptr);
11020Sstevel@tonic-gate }
11031676Sjpk
11041676Sjpk /*
11051676Sjpk * Create a new cred based on the supplied label
11061676Sjpk */
11071676Sjpk cred_t *
newcred_from_bslabel(bslabel_t * blabel,uint32_t doi,int flags)11081676Sjpk newcred_from_bslabel(bslabel_t *blabel, uint32_t doi, int flags)
11091676Sjpk {
11101676Sjpk ts_label_t *lbl = labelalloc(blabel, doi, flags);
11111676Sjpk cred_t *cr = NULL;
11121676Sjpk
11131676Sjpk if (lbl != NULL) {
11146134Scasper if ((cr = crdup_flags(dummycr, flags)) != NULL) {
11151676Sjpk cr->cr_label = lbl;
11161676Sjpk } else {
11171676Sjpk label_rele(lbl);
11181676Sjpk }
11191676Sjpk }
11201676Sjpk
11211676Sjpk return (cr);
11221676Sjpk }
11231676Sjpk
11241676Sjpk /*
11251676Sjpk * Derive a new cred from the existing cred, but with a different label.
11261676Sjpk * To be used when a cred is being shared, but the label needs to be changed
11271676Sjpk * by a caller without affecting other users
11281676Sjpk */
11291676Sjpk cred_t *
copycred_from_tslabel(const cred_t * cr,ts_label_t * label,int flags)11309710SKen.Powell@Sun.COM copycred_from_tslabel(const cred_t *cr, ts_label_t *label, int flags)
11319710SKen.Powell@Sun.COM {
11329710SKen.Powell@Sun.COM cred_t *newcr = NULL;
11339710SKen.Powell@Sun.COM
11349710SKen.Powell@Sun.COM if ((newcr = crdup_flags(cr, flags)) != NULL) {
11359710SKen.Powell@Sun.COM if (newcr->cr_label != NULL)
11369710SKen.Powell@Sun.COM label_rele(newcr->cr_label);
11379710SKen.Powell@Sun.COM label_hold(label);
11389710SKen.Powell@Sun.COM newcr->cr_label = label;
11399710SKen.Powell@Sun.COM }
11409710SKen.Powell@Sun.COM
11419710SKen.Powell@Sun.COM return (newcr);
11429710SKen.Powell@Sun.COM }
11439710SKen.Powell@Sun.COM
11449710SKen.Powell@Sun.COM /*
11459710SKen.Powell@Sun.COM * Derive a new cred from the existing cred, but with a different label.
11469710SKen.Powell@Sun.COM */
11479710SKen.Powell@Sun.COM cred_t *
copycred_from_bslabel(const cred_t * cr,bslabel_t * blabel,uint32_t doi,int flags)11489710SKen.Powell@Sun.COM copycred_from_bslabel(const cred_t *cr, bslabel_t *blabel,
11499710SKen.Powell@Sun.COM uint32_t doi, int flags)
11501676Sjpk {
11511676Sjpk ts_label_t *lbl = labelalloc(blabel, doi, flags);
11529710SKen.Powell@Sun.COM cred_t *newcr = NULL;
11531676Sjpk
11541676Sjpk if (lbl != NULL) {
11559710SKen.Powell@Sun.COM newcr = copycred_from_tslabel(cr, lbl, flags);
11569710SKen.Powell@Sun.COM label_rele(lbl);
11571676Sjpk }
11581676Sjpk
11591676Sjpk return (newcr);
11601676Sjpk }
11611676Sjpk
11621676Sjpk /*
11631676Sjpk * This function returns a pointer to the kcred-equivalent in the current zone.
11641676Sjpk */
11651676Sjpk cred_t *
zone_kcred(void)11661676Sjpk zone_kcred(void)
11671676Sjpk {
11681676Sjpk zone_t *zone;
11691676Sjpk
11701676Sjpk if ((zone = CRED()->cr_zone) != NULL)
11711676Sjpk return (zone->zone_kcred);
11721676Sjpk else
11731676Sjpk return (kcred);
11741676Sjpk }
11754321Scasper
11764321Scasper boolean_t
valid_ephemeral_uid(zone_t * zone,uid_t id)11775771Sjp151216 valid_ephemeral_uid(zone_t *zone, uid_t id)
11784321Scasper {
11795771Sjp151216 ephemeral_zsd_t *eph_zsd;
11805908Sjp151216 if (id <= IDMAP_WK__MAX_UID)
11815771Sjp151216 return (B_TRUE);
11825771Sjp151216
11835771Sjp151216 eph_zsd = get_ephemeral_zsd(zone);
11845771Sjp151216 ASSERT(eph_zsd != NULL);
11854321Scasper membar_consumer();
11865771Sjp151216 return (id > eph_zsd->min_uid && id <= eph_zsd->last_uid);
11874321Scasper }
11884321Scasper
11894321Scasper boolean_t
valid_ephemeral_gid(zone_t * zone,gid_t id)11905771Sjp151216 valid_ephemeral_gid(zone_t *zone, gid_t id)
11914321Scasper {
11925771Sjp151216 ephemeral_zsd_t *eph_zsd;
11935908Sjp151216 if (id <= IDMAP_WK__MAX_GID)
11945771Sjp151216 return (B_TRUE);
11955771Sjp151216
11965771Sjp151216 eph_zsd = get_ephemeral_zsd(zone);
11975771Sjp151216 ASSERT(eph_zsd != NULL);
11984321Scasper membar_consumer();
11995771Sjp151216 return (id > eph_zsd->min_gid && id <= eph_zsd->last_gid);
12004321Scasper }
12014321Scasper
12024321Scasper int
eph_uid_alloc(zone_t * zone,int flags,uid_t * start,int count)12035771Sjp151216 eph_uid_alloc(zone_t *zone, int flags, uid_t *start, int count)
12044321Scasper {
12055771Sjp151216 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12065771Sjp151216
12075771Sjp151216 ASSERT(eph_zsd != NULL);
12085771Sjp151216
12095771Sjp151216 mutex_enter(&eph_zsd->eph_lock);
12104321Scasper
12114321Scasper /* Test for unsigned integer wrap around */
12125771Sjp151216 if (eph_zsd->last_uid + count < eph_zsd->last_uid) {
12135771Sjp151216 mutex_exit(&eph_zsd->eph_lock);
12144321Scasper return (-1);
12154321Scasper }
12164321Scasper
12174321Scasper /* first call or idmap crashed and state corrupted */
12184321Scasper if (flags != 0)
12195771Sjp151216 eph_zsd->min_uid = eph_zsd->last_uid;
12204321Scasper
12214321Scasper hasephids = B_TRUE;
12225771Sjp151216 *start = eph_zsd->last_uid + 1;
12235771Sjp151216 atomic_add_32(&eph_zsd->last_uid, count);
12245771Sjp151216 mutex_exit(&eph_zsd->eph_lock);
12254321Scasper return (0);
12264321Scasper }
12274321Scasper
12284321Scasper int
eph_gid_alloc(zone_t * zone,int flags,gid_t * start,int count)12295771Sjp151216 eph_gid_alloc(zone_t *zone, int flags, gid_t *start, int count)
12304321Scasper {
12315771Sjp151216 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12325771Sjp151216
12335771Sjp151216 ASSERT(eph_zsd != NULL);
12345771Sjp151216
12355771Sjp151216 mutex_enter(&eph_zsd->eph_lock);
12364321Scasper
12374321Scasper /* Test for unsigned integer wrap around */
12385771Sjp151216 if (eph_zsd->last_gid + count < eph_zsd->last_gid) {
12395771Sjp151216 mutex_exit(&eph_zsd->eph_lock);
12404321Scasper return (-1);
12414321Scasper }
12424321Scasper
12434321Scasper /* first call or idmap crashed and state corrupted */
12444321Scasper if (flags != 0)
12455771Sjp151216 eph_zsd->min_gid = eph_zsd->last_gid;
12464321Scasper
12474321Scasper hasephids = B_TRUE;
12485771Sjp151216 *start = eph_zsd->last_gid + 1;
12495771Sjp151216 atomic_add_32(&eph_zsd->last_gid, count);
12505771Sjp151216 mutex_exit(&eph_zsd->eph_lock);
12514321Scasper return (0);
12524321Scasper }
12534321Scasper
12544321Scasper /*
12555771Sjp151216 * IMPORTANT.The two functions get_ephemeral_data() and set_ephemeral_data()
12565771Sjp151216 * are project private functions that are for use of the test system only and
12575771Sjp151216 * are not to be used for other purposes.
12585771Sjp151216 */
12595771Sjp151216
12605771Sjp151216 void
get_ephemeral_data(zone_t * zone,uid_t * min_uid,uid_t * last_uid,gid_t * min_gid,gid_t * last_gid)12615771Sjp151216 get_ephemeral_data(zone_t *zone, uid_t *min_uid, uid_t *last_uid,
12625771Sjp151216 gid_t *min_gid, gid_t *last_gid)
12635771Sjp151216 {
12645771Sjp151216 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12655771Sjp151216
12665771Sjp151216 ASSERT(eph_zsd != NULL);
12675771Sjp151216
12685771Sjp151216 mutex_enter(&eph_zsd->eph_lock);
12695771Sjp151216
12705771Sjp151216 *min_uid = eph_zsd->min_uid;
12715771Sjp151216 *last_uid = eph_zsd->last_uid;
12725771Sjp151216 *min_gid = eph_zsd->min_gid;
12735771Sjp151216 *last_gid = eph_zsd->last_gid;
12745771Sjp151216
12755771Sjp151216 mutex_exit(&eph_zsd->eph_lock);
12765771Sjp151216 }
12775771Sjp151216
12785771Sjp151216
12795771Sjp151216 void
set_ephemeral_data(zone_t * zone,uid_t min_uid,uid_t last_uid,gid_t min_gid,gid_t last_gid)12805771Sjp151216 set_ephemeral_data(zone_t *zone, uid_t min_uid, uid_t last_uid,
12815771Sjp151216 gid_t min_gid, gid_t last_gid)
12825771Sjp151216 {
12835771Sjp151216 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
12845771Sjp151216
12855771Sjp151216 ASSERT(eph_zsd != NULL);
12865771Sjp151216
12875771Sjp151216 mutex_enter(&eph_zsd->eph_lock);
12885771Sjp151216
12895771Sjp151216 if (min_uid != 0)
12905771Sjp151216 eph_zsd->min_uid = min_uid;
12915771Sjp151216 if (last_uid != 0)
12925771Sjp151216 eph_zsd->last_uid = last_uid;
12935771Sjp151216 if (min_gid != 0)
12945771Sjp151216 eph_zsd->min_gid = min_gid;
12955771Sjp151216 if (last_gid != 0)
12965771Sjp151216 eph_zsd->last_gid = last_gid;
12975771Sjp151216
12985771Sjp151216 mutex_exit(&eph_zsd->eph_lock);
12995771Sjp151216 }
13005771Sjp151216
13015771Sjp151216 /*
13025331Samw * If the credential user SID or group SID is mapped to an ephemeral
13035331Samw * ID, map the credential to nobody.
13044321Scasper */
13054321Scasper cred_t *
crgetmapped(const cred_t * cr)13064321Scasper crgetmapped(const cred_t *cr)
13074321Scasper {
13085771Sjp151216 ephemeral_zsd_t *eph_zsd;
13094406Scasper /*
13104406Scasper * Someone incorrectly passed a NULL cred to a vnode operation
13114406Scasper * either on purpose or by calling CRED() in interrupt context.
13124406Scasper */
13134406Scasper if (cr == NULL)
13144406Scasper return (NULL);
13154406Scasper
13164321Scasper if (cr->cr_ksid != NULL) {
13175771Sjp151216 if (cr->cr_ksid->kr_sidx[KSID_USER].ks_id > MAXUID) {
13185771Sjp151216 eph_zsd = get_ephemeral_zsd(crgetzone(cr));
13195771Sjp151216 return (eph_zsd->eph_nobody);
13205771Sjp151216 }
13214321Scasper
13225771Sjp151216 if (cr->cr_ksid->kr_sidx[KSID_GROUP].ks_id > MAXUID) {
13235771Sjp151216 eph_zsd = get_ephemeral_zsd(crgetzone(cr));
13245771Sjp151216 return (eph_zsd->eph_nobody);
13255771Sjp151216 }
13264321Scasper }
13274321Scasper
13284321Scasper return ((cred_t *)cr);
13294321Scasper }
13304321Scasper
13314321Scasper /* index should be in range for a ksidindex_t */
13324321Scasper void
crsetsid(cred_t * cr,ksid_t * ksp,int index)13334321Scasper crsetsid(cred_t *cr, ksid_t *ksp, int index)
13344321Scasper {
13354321Scasper ASSERT(cr->cr_ref <= 2);
13364321Scasper ASSERT(index >= 0 && index < KSID_COUNT);
13374321Scasper if (cr->cr_ksid == NULL && ksp == NULL)
13384321Scasper return;
13394321Scasper cr->cr_ksid = kcrsid_setsid(cr->cr_ksid, ksp, index);
13404321Scasper }
13414321Scasper
13424321Scasper void
crsetsidlist(cred_t * cr,ksidlist_t * ksl)13434321Scasper crsetsidlist(cred_t *cr, ksidlist_t *ksl)
13444321Scasper {
13454321Scasper ASSERT(cr->cr_ref <= 2);
13464321Scasper if (cr->cr_ksid == NULL && ksl == NULL)
13474321Scasper return;
13484321Scasper cr->cr_ksid = kcrsid_setsidlist(cr->cr_ksid, ksl);
13494321Scasper }
13504321Scasper
13514321Scasper ksid_t *
crgetsid(const cred_t * cr,int i)13524321Scasper crgetsid(const cred_t *cr, int i)
13534321Scasper {
13544321Scasper ASSERT(i >= 0 && i < KSID_COUNT);
13554321Scasper if (cr->cr_ksid != NULL && cr->cr_ksid->kr_sidx[i].ks_domain)
13564321Scasper return ((ksid_t *)&cr->cr_ksid->kr_sidx[i]);
13574321Scasper return (NULL);
13584321Scasper }
13594321Scasper
13604321Scasper ksidlist_t *
crgetsidlist(const cred_t * cr)13614321Scasper crgetsidlist(const cred_t *cr)
13624321Scasper {
13635331Samw if (cr->cr_ksid != NULL)
13644923Scasper return (cr->cr_ksid->kr_sidlist);
13654321Scasper return (NULL);
13664321Scasper }
13675331Samw
13685331Samw /*
13695331Samw * Interface to set the effective and permitted privileges for
13705331Samw * a credential; this interface does no security checks and is
13715331Samw * intended for kernel (file)servers creating credentials with
13725331Samw * specific privileges.
13735331Samw */
13745331Samw int
crsetpriv(cred_t * cr,...)13755331Samw crsetpriv(cred_t *cr, ...)
13765331Samw {
13775331Samw va_list ap;
13785331Samw const char *privnm;
13795331Samw
13805331Samw ASSERT(cr->cr_ref <= 2);
13815331Samw
13825331Samw priv_set_PA(cr);
13835331Samw
13845331Samw va_start(ap, cr);
13855331Samw
13865331Samw while ((privnm = va_arg(ap, const char *)) != NULL) {
13875331Samw int priv = priv_getbyname(privnm, 0);
13885331Samw if (priv < 0)
13895331Samw return (-1);
13905331Samw
13915331Samw priv_addset(&CR_PPRIV(cr), priv);
13925331Samw priv_addset(&CR_EPRIV(cr), priv);
13935331Samw }
13945331Samw priv_adjust_PA(cr);
13955331Samw va_end(ap);
13965331Samw return (0);
13975331Samw }
13986134Scasper
13999151SThomas.Haynes@Sun.COM /*
14009151SThomas.Haynes@Sun.COM * Interface to effectively set the PRIV_ALL for
14019151SThomas.Haynes@Sun.COM * a credential; this interface does no security checks and is
14029151SThomas.Haynes@Sun.COM * intended for kernel (file)servers to extend the user credentials
14039151SThomas.Haynes@Sun.COM * to be ALL, like either kcred or zcred.
14049151SThomas.Haynes@Sun.COM */
14059151SThomas.Haynes@Sun.COM void
crset_zone_privall(cred_t * cr)14069151SThomas.Haynes@Sun.COM crset_zone_privall(cred_t *cr)
14079151SThomas.Haynes@Sun.COM {
14089151SThomas.Haynes@Sun.COM zone_t *zone = crgetzone(cr);
14099151SThomas.Haynes@Sun.COM
14109151SThomas.Haynes@Sun.COM priv_fillset(&CR_LPRIV(cr));
14119151SThomas.Haynes@Sun.COM CR_EPRIV(cr) = CR_PPRIV(cr) = CR_IPRIV(cr) = CR_LPRIV(cr);
14129151SThomas.Haynes@Sun.COM priv_intersect(zone->zone_privset, &CR_LPRIV(cr));
14139151SThomas.Haynes@Sun.COM priv_intersect(zone->zone_privset, &CR_EPRIV(cr));
14149151SThomas.Haynes@Sun.COM priv_intersect(zone->zone_privset, &CR_IPRIV(cr));
14159151SThomas.Haynes@Sun.COM priv_intersect(zone->zone_privset, &CR_PPRIV(cr));
14169151SThomas.Haynes@Sun.COM }
14179151SThomas.Haynes@Sun.COM
14186134Scasper struct credklpd *
crgetcrklpd(const cred_t * cr)14196134Scasper crgetcrklpd(const cred_t *cr)
14206134Scasper {
14216134Scasper return (cr->cr_klpd);
14226134Scasper }
14236134Scasper
14246134Scasper void
crsetcrklpd(cred_t * cr,struct credklpd * crklpd)14256134Scasper crsetcrklpd(cred_t *cr, struct credklpd *crklpd)
14266134Scasper {
14276134Scasper ASSERT(cr->cr_ref <= 2);
14286134Scasper
14296134Scasper if (cr->cr_klpd != NULL)
14306134Scasper crklpd_rele(cr->cr_klpd);
14316134Scasper cr->cr_klpd = crklpd;
14326134Scasper }
143311134SCasper.Dik@Sun.COM
143411134SCasper.Dik@Sun.COM credgrp_t *
crgrpcopyin(int n,gid_t * gidset)143511134SCasper.Dik@Sun.COM crgrpcopyin(int n, gid_t *gidset)
143611134SCasper.Dik@Sun.COM {
143711134SCasper.Dik@Sun.COM credgrp_t *mem;
143811134SCasper.Dik@Sun.COM size_t sz = CREDGRPSZ(n);
143911134SCasper.Dik@Sun.COM
144011134SCasper.Dik@Sun.COM ASSERT(n > 0);
144111134SCasper.Dik@Sun.COM
144211134SCasper.Dik@Sun.COM mem = kmem_alloc(sz, KM_SLEEP);
144311134SCasper.Dik@Sun.COM
144411134SCasper.Dik@Sun.COM if (copyin(gidset, mem->crg_groups, sizeof (gid_t) * n)) {
144511134SCasper.Dik@Sun.COM kmem_free(mem, sz);
144611134SCasper.Dik@Sun.COM return (NULL);
144711134SCasper.Dik@Sun.COM }
144811134SCasper.Dik@Sun.COM mem->crg_ref = 1;
144911134SCasper.Dik@Sun.COM mem->crg_ngroups = n;
145011134SCasper.Dik@Sun.COM return (mem);
145111134SCasper.Dik@Sun.COM }
145211134SCasper.Dik@Sun.COM
145311134SCasper.Dik@Sun.COM const gid_t *
crgetggroups(const credgrp_t * grps)145411134SCasper.Dik@Sun.COM crgetggroups(const credgrp_t *grps)
145511134SCasper.Dik@Sun.COM {
145611134SCasper.Dik@Sun.COM return (grps->crg_groups);
145711134SCasper.Dik@Sun.COM }
145811134SCasper.Dik@Sun.COM
145911134SCasper.Dik@Sun.COM void
crsetcredgrp(cred_t * cr,credgrp_t * grps)146011134SCasper.Dik@Sun.COM crsetcredgrp(cred_t *cr, credgrp_t *grps)
146111134SCasper.Dik@Sun.COM {
146211134SCasper.Dik@Sun.COM ASSERT(cr->cr_ref <= 2);
146311134SCasper.Dik@Sun.COM
146411134SCasper.Dik@Sun.COM if (cr->cr_grps != NULL)
146511134SCasper.Dik@Sun.COM crgrprele(cr->cr_grps);
146611134SCasper.Dik@Sun.COM
146711134SCasper.Dik@Sun.COM cr->cr_grps = grps;
146811134SCasper.Dik@Sun.COM }
146911134SCasper.Dik@Sun.COM
147011134SCasper.Dik@Sun.COM void
crgrprele(credgrp_t * grps)147111134SCasper.Dik@Sun.COM crgrprele(credgrp_t *grps)
147211134SCasper.Dik@Sun.COM {
147311134SCasper.Dik@Sun.COM if (atomic_add_32_nv(&grps->crg_ref, -1) == 0)
147411134SCasper.Dik@Sun.COM kmem_free(grps, CREDGRPSZ(grps->crg_ngroups));
147511134SCasper.Dik@Sun.COM }
147611134SCasper.Dik@Sun.COM
147711134SCasper.Dik@Sun.COM static void
crgrphold(credgrp_t * grps)147811134SCasper.Dik@Sun.COM crgrphold(credgrp_t *grps)
147911134SCasper.Dik@Sun.COM {
148011134SCasper.Dik@Sun.COM atomic_add_32(&grps->crg_ref, 1);
148111134SCasper.Dik@Sun.COM }
1482