1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*0Sstevel@tonic-gate /* All Rights Reserved */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate /* 31*0Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 32*0Sstevel@tonic-gate * The Regents of the University of California 33*0Sstevel@tonic-gate * All Rights Reserved 34*0Sstevel@tonic-gate * 35*0Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 36*0Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 37*0Sstevel@tonic-gate * contributors. 38*0Sstevel@tonic-gate */ 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate #include <sys/types.h> 43*0Sstevel@tonic-gate #include <sys/sysmacros.h> 44*0Sstevel@tonic-gate #include <sys/param.h> 45*0Sstevel@tonic-gate #include <sys/systm.h> 46*0Sstevel@tonic-gate #include <sys/cred_impl.h> 47*0Sstevel@tonic-gate #include <sys/policy.h> 48*0Sstevel@tonic-gate #include <sys/vnode.h> 49*0Sstevel@tonic-gate #include <sys/errno.h> 50*0Sstevel@tonic-gate #include <sys/kmem.h> 51*0Sstevel@tonic-gate #include <sys/user.h> 52*0Sstevel@tonic-gate #include <sys/proc.h> 53*0Sstevel@tonic-gate #include <sys/acct.h> 54*0Sstevel@tonic-gate #include <sys/syscall.h> 55*0Sstevel@tonic-gate #include <sys/cmn_err.h> 56*0Sstevel@tonic-gate #include <sys/debug.h> 57*0Sstevel@tonic-gate #include <sys/atomic.h> 58*0Sstevel@tonic-gate #include <sys/ucred.h> 59*0Sstevel@tonic-gate #include <sys/prsystm.h> 60*0Sstevel@tonic-gate #include <sys/modctl.h> 61*0Sstevel@tonic-gate #include <c2/audit.h> 62*0Sstevel@tonic-gate #include <sys/zone.h> 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate static struct kmem_cache *cred_cache; 65*0Sstevel@tonic-gate static size_t crsize = 0; 66*0Sstevel@tonic-gate static int audoff = 0; 67*0Sstevel@tonic-gate uint32_t ucredsize; 68*0Sstevel@tonic-gate cred_t *kcred; 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate int rstlink; /* link(2) restricted to files owned by user? */ 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate static int get_c2audit_load(void); 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate #define CR_AUINFO(c) (auditinfo_addr_t *)((audoff == 0) ? NULL : \ 75*0Sstevel@tonic-gate ((char *)(c)) + audoff) 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate /* 79*0Sstevel@tonic-gate * Initialize credentials data structures. 80*0Sstevel@tonic-gate */ 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate void 83*0Sstevel@tonic-gate cred_init(void) 84*0Sstevel@tonic-gate { 85*0Sstevel@tonic-gate priv_init(); 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate crsize = sizeof (cred_t) + sizeof (gid_t) * (ngroups_max - 1); 88*0Sstevel@tonic-gate /* 89*0Sstevel@tonic-gate * Make sure it's word-aligned. 90*0Sstevel@tonic-gate */ 91*0Sstevel@tonic-gate crsize = (crsize + sizeof (int) - 1) & ~(sizeof (int) - 1); 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate if (get_c2audit_load() > 0) { 94*0Sstevel@tonic-gate #ifdef _LP64 95*0Sstevel@tonic-gate /* assure audit context is 64-bit aligned */ 96*0Sstevel@tonic-gate audoff = (crsize + 97*0Sstevel@tonic-gate sizeof (int64_t) - 1) & ~(sizeof (int64_t) - 1); 98*0Sstevel@tonic-gate #else /* _LP64 */ 99*0Sstevel@tonic-gate audoff = crsize; 100*0Sstevel@tonic-gate #endif /* _LP64 */ 101*0Sstevel@tonic-gate crsize = audoff + sizeof (auditinfo_addr_t); 102*0Sstevel@tonic-gate crsize = (crsize + sizeof (int) - 1) & ~(sizeof (int) - 1); 103*0Sstevel@tonic-gate } 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate cred_cache = kmem_cache_create("cred_cache", crsize, 0, 106*0Sstevel@tonic-gate NULL, NULL, NULL, NULL, NULL, 0); 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate /* 109*0Sstevel@tonic-gate * kcred is used by anything that needs all privileges; it's 110*0Sstevel@tonic-gate * also the template used for crget as it has all the compatible 111*0Sstevel@tonic-gate * sets filled in. 112*0Sstevel@tonic-gate */ 113*0Sstevel@tonic-gate kcred = cralloc(); 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate bzero(kcred, crsize); 116*0Sstevel@tonic-gate kcred->cr_ref = 1; 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate /* kcred is never freed, so we don't need zone_cred_hold here */ 119*0Sstevel@tonic-gate kcred->cr_zone = &zone0; 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate priv_fillset(&CR_LPRIV(kcred)); 122*0Sstevel@tonic-gate CR_IPRIV(kcred) = *priv_basic; 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate /* Not a basic privilege, if chown is not restricted add it to I0 */ 125*0Sstevel@tonic-gate if (!rstchown) 126*0Sstevel@tonic-gate priv_addset(&CR_IPRIV(kcred), PRIV_FILE_CHOWN_SELF); 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate /* Basic privilege, if link is restricted remove it from I0 */ 129*0Sstevel@tonic-gate if (rstlink) 130*0Sstevel@tonic-gate priv_delset(&CR_IPRIV(kcred), PRIV_FILE_LINK_ANY); 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate CR_EPRIV(kcred) = CR_PPRIV(kcred) = CR_IPRIV(kcred); 133*0Sstevel@tonic-gate /* CR_FLAGS(kcred) == 0, courtesy of bzero() */ 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate /* 136*0Sstevel@tonic-gate * Set up credentials of p0. 137*0Sstevel@tonic-gate */ 138*0Sstevel@tonic-gate ttoproc(curthread)->p_cred = kcred; 139*0Sstevel@tonic-gate curthread->t_cred = kcred; 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate ucredsize = UCRED_SIZE; 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate /* 145*0Sstevel@tonic-gate * Allocate (nearly) uninitialized cred_t. 146*0Sstevel@tonic-gate */ 147*0Sstevel@tonic-gate cred_t * 148*0Sstevel@tonic-gate cralloc(void) 149*0Sstevel@tonic-gate { 150*0Sstevel@tonic-gate cred_t *cr = kmem_cache_alloc(cred_cache, KM_SLEEP); 151*0Sstevel@tonic-gate cr->cr_ref = 1; /* So we can crfree() */ 152*0Sstevel@tonic-gate cr->cr_zone = NULL; 153*0Sstevel@tonic-gate return (cr); 154*0Sstevel@tonic-gate } 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate /* 157*0Sstevel@tonic-gate * Allocate a initialized cred structure and crhold() it. 158*0Sstevel@tonic-gate * Initialized means: all ids 0, group count 0, L=Full, E=P=I=I0 159*0Sstevel@tonic-gate */ 160*0Sstevel@tonic-gate cred_t * 161*0Sstevel@tonic-gate crget(void) 162*0Sstevel@tonic-gate { 163*0Sstevel@tonic-gate cred_t *cr = kmem_cache_alloc(cred_cache, KM_SLEEP); 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate bcopy(kcred, cr, crsize); 166*0Sstevel@tonic-gate cr->cr_ref = 1; 167*0Sstevel@tonic-gate zone_cred_hold(cr->cr_zone); 168*0Sstevel@tonic-gate return (cr); 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate /* 172*0Sstevel@tonic-gate * Broadcast the cred to all the threads in the process. 173*0Sstevel@tonic-gate * The current thread's credentials can be set right away, but other 174*0Sstevel@tonic-gate * threads must wait until the start of the next system call or trap. 175*0Sstevel@tonic-gate * This avoids changing the cred in the middle of a system call. 176*0Sstevel@tonic-gate * 177*0Sstevel@tonic-gate * The cred has already been held for the process and the thread (2 holds), 178*0Sstevel@tonic-gate * and p->p_cred set. 179*0Sstevel@tonic-gate * 180*0Sstevel@tonic-gate * p->p_crlock shouldn't be held here, since p_lock must be acquired. 181*0Sstevel@tonic-gate */ 182*0Sstevel@tonic-gate void 183*0Sstevel@tonic-gate crset(proc_t *p, cred_t *cr) 184*0Sstevel@tonic-gate { 185*0Sstevel@tonic-gate kthread_id_t t; 186*0Sstevel@tonic-gate kthread_id_t first; 187*0Sstevel@tonic-gate cred_t *oldcr; 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate ASSERT(p == curproc); /* assumes p_lwpcnt can't change */ 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate /* 192*0Sstevel@tonic-gate * DTrace accesses t_cred in probe context. t_cred must always be 193*0Sstevel@tonic-gate * either NULL, or point to a valid, allocated cred structure. 194*0Sstevel@tonic-gate */ 195*0Sstevel@tonic-gate t = curthread; 196*0Sstevel@tonic-gate oldcr = t->t_cred; 197*0Sstevel@tonic-gate t->t_cred = cr; /* the cred is held by caller for this thread */ 198*0Sstevel@tonic-gate crfree(oldcr); /* free the old cred for the thread */ 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate /* 201*0Sstevel@tonic-gate * Broadcast to other threads, if any. 202*0Sstevel@tonic-gate */ 203*0Sstevel@tonic-gate if (p->p_lwpcnt > 1) { 204*0Sstevel@tonic-gate mutex_enter(&p->p_lock); /* to keep thread list safe */ 205*0Sstevel@tonic-gate first = curthread; 206*0Sstevel@tonic-gate for (t = first->t_forw; t != first; t = t->t_forw) 207*0Sstevel@tonic-gate t->t_pre_sys = 1; /* so syscall will get new cred */ 208*0Sstevel@tonic-gate mutex_exit(&p->p_lock); 209*0Sstevel@tonic-gate } 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate /* 213*0Sstevel@tonic-gate * Put a hold on a cred structure. 214*0Sstevel@tonic-gate */ 215*0Sstevel@tonic-gate void 216*0Sstevel@tonic-gate crhold(cred_t *cr) 217*0Sstevel@tonic-gate { 218*0Sstevel@tonic-gate atomic_add_32(&cr->cr_ref, 1); 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate /* 222*0Sstevel@tonic-gate * Release previous hold on a cred structure. Free it if refcnt == 0. 223*0Sstevel@tonic-gate */ 224*0Sstevel@tonic-gate void 225*0Sstevel@tonic-gate crfree(cred_t *cr) 226*0Sstevel@tonic-gate { 227*0Sstevel@tonic-gate if (atomic_add_32_nv(&cr->cr_ref, -1) == 0) { 228*0Sstevel@tonic-gate ASSERT(cr != kcred); 229*0Sstevel@tonic-gate if (cr->cr_zone) 230*0Sstevel@tonic-gate zone_cred_rele(cr->cr_zone); 231*0Sstevel@tonic-gate kmem_cache_free(cred_cache, cr); 232*0Sstevel@tonic-gate } 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate /* 236*0Sstevel@tonic-gate * Copy a cred structure to a new one and free the old one. 237*0Sstevel@tonic-gate * The new cred will have two references. One for the calling process, 238*0Sstevel@tonic-gate * and one for the thread. 239*0Sstevel@tonic-gate */ 240*0Sstevel@tonic-gate cred_t * 241*0Sstevel@tonic-gate crcopy(cred_t *cr) 242*0Sstevel@tonic-gate { 243*0Sstevel@tonic-gate cred_t *newcr; 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate newcr = cralloc(); 246*0Sstevel@tonic-gate bcopy(cr, newcr, crsize); 247*0Sstevel@tonic-gate if (newcr->cr_zone) 248*0Sstevel@tonic-gate zone_cred_hold(newcr->cr_zone); 249*0Sstevel@tonic-gate crfree(cr); 250*0Sstevel@tonic-gate newcr->cr_ref = 2; /* caller gets two references */ 251*0Sstevel@tonic-gate return (newcr); 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate /* 255*0Sstevel@tonic-gate * Copy a cred structure to a new one and free the old one. 256*0Sstevel@tonic-gate * The new cred will have two references. One for the calling process, 257*0Sstevel@tonic-gate * and one for the thread. 258*0Sstevel@tonic-gate * This variation on crcopy uses a pre-allocated structure for the 259*0Sstevel@tonic-gate * "new" cred. 260*0Sstevel@tonic-gate */ 261*0Sstevel@tonic-gate void 262*0Sstevel@tonic-gate crcopy_to(cred_t *oldcr, cred_t *newcr) 263*0Sstevel@tonic-gate { 264*0Sstevel@tonic-gate bcopy(oldcr, newcr, crsize); 265*0Sstevel@tonic-gate if (newcr->cr_zone) 266*0Sstevel@tonic-gate zone_cred_hold(newcr->cr_zone); 267*0Sstevel@tonic-gate crfree(oldcr); 268*0Sstevel@tonic-gate newcr->cr_ref = 2; /* caller gets two references */ 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate /* 272*0Sstevel@tonic-gate * Dup a cred struct to a new held one. 273*0Sstevel@tonic-gate * The old cred is not freed. 274*0Sstevel@tonic-gate */ 275*0Sstevel@tonic-gate cred_t * 276*0Sstevel@tonic-gate crdup(cred_t *cr) 277*0Sstevel@tonic-gate { 278*0Sstevel@tonic-gate cred_t *newcr; 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate newcr = cralloc(); 281*0Sstevel@tonic-gate bcopy(cr, newcr, crsize); 282*0Sstevel@tonic-gate if (newcr->cr_zone) 283*0Sstevel@tonic-gate zone_cred_hold(newcr->cr_zone); 284*0Sstevel@tonic-gate newcr->cr_ref = 1; 285*0Sstevel@tonic-gate return (newcr); 286*0Sstevel@tonic-gate } 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate /* 289*0Sstevel@tonic-gate * Dup a cred struct to a new held one. 290*0Sstevel@tonic-gate * The old cred is not freed. 291*0Sstevel@tonic-gate * This variation on crdup uses a pre-allocated structure for the 292*0Sstevel@tonic-gate * "new" cred. 293*0Sstevel@tonic-gate */ 294*0Sstevel@tonic-gate void 295*0Sstevel@tonic-gate crdup_to(cred_t *oldcr, cred_t *newcr) 296*0Sstevel@tonic-gate { 297*0Sstevel@tonic-gate bcopy(oldcr, newcr, crsize); 298*0Sstevel@tonic-gate if (newcr->cr_zone) 299*0Sstevel@tonic-gate zone_cred_hold(newcr->cr_zone); 300*0Sstevel@tonic-gate newcr->cr_ref = 1; 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate /* 304*0Sstevel@tonic-gate * Return the (held) credentials for the current running process. 305*0Sstevel@tonic-gate */ 306*0Sstevel@tonic-gate cred_t * 307*0Sstevel@tonic-gate crgetcred() 308*0Sstevel@tonic-gate { 309*0Sstevel@tonic-gate cred_t *cr; 310*0Sstevel@tonic-gate proc_t *p; 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate p = ttoproc(curthread); 313*0Sstevel@tonic-gate mutex_enter(&p->p_crlock); 314*0Sstevel@tonic-gate crhold(cr = p->p_cred); 315*0Sstevel@tonic-gate mutex_exit(&p->p_crlock); 316*0Sstevel@tonic-gate return (cr); 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate /* 320*0Sstevel@tonic-gate * Backward compatibility check for suser(). 321*0Sstevel@tonic-gate * Accounting flag is now set in the policy functions; auditing is 322*0Sstevel@tonic-gate * done through use of privilege in the audit trail. 323*0Sstevel@tonic-gate */ 324*0Sstevel@tonic-gate int 325*0Sstevel@tonic-gate suser(cred_t *cr) 326*0Sstevel@tonic-gate { 327*0Sstevel@tonic-gate return (PRIV_POLICY(cr, PRIV_SYS_SUSER_COMPAT, B_FALSE, EPERM, NULL) 328*0Sstevel@tonic-gate == 0); 329*0Sstevel@tonic-gate } 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate /* 332*0Sstevel@tonic-gate * Determine whether the supplied group id is a member of the group 333*0Sstevel@tonic-gate * described by the supplied credentials. 334*0Sstevel@tonic-gate */ 335*0Sstevel@tonic-gate int 336*0Sstevel@tonic-gate groupmember(gid_t gid, const cred_t *cr) 337*0Sstevel@tonic-gate { 338*0Sstevel@tonic-gate if (gid == cr->cr_gid) 339*0Sstevel@tonic-gate return (1); 340*0Sstevel@tonic-gate return (supgroupmember(gid, cr)); 341*0Sstevel@tonic-gate } 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate /* 344*0Sstevel@tonic-gate * As groupmember but only check against the supplemental groups. 345*0Sstevel@tonic-gate */ 346*0Sstevel@tonic-gate int 347*0Sstevel@tonic-gate supgroupmember(gid_t gid, const cred_t *cr) 348*0Sstevel@tonic-gate { 349*0Sstevel@tonic-gate const gid_t *gp, *endgp; 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate endgp = &cr->cr_groups[cr->cr_ngroups]; 352*0Sstevel@tonic-gate for (gp = cr->cr_groups; gp < endgp; gp++) 353*0Sstevel@tonic-gate if (*gp == gid) 354*0Sstevel@tonic-gate return (1); 355*0Sstevel@tonic-gate return (0); 356*0Sstevel@tonic-gate } 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate /* 359*0Sstevel@tonic-gate * This function is called to check whether the credentials set 360*0Sstevel@tonic-gate * "scrp" has permission to act on credentials set "tcrp". It enforces the 361*0Sstevel@tonic-gate * permission requirements needed to send a signal to a process. 362*0Sstevel@tonic-gate * The same requirements are imposed by other system calls, however. 363*0Sstevel@tonic-gate * 364*0Sstevel@tonic-gate * The rules are: 365*0Sstevel@tonic-gate * (1) if the credentials are the same, the check succeeds 366*0Sstevel@tonic-gate * (2) if the zone ids don't match, and scrp is not in the global zone or 367*0Sstevel@tonic-gate * does not have the PRIV_PROC_ZONE privilege, the check fails 368*0Sstevel@tonic-gate * (3) if the real or effective user id of scrp matches the real or saved 369*0Sstevel@tonic-gate * user id of tcrp or scrp has the PRIV_PROC_OWNER privilege, the check 370*0Sstevel@tonic-gate * succeeds 371*0Sstevel@tonic-gate * (4) otherwise, the check fails 372*0Sstevel@tonic-gate */ 373*0Sstevel@tonic-gate int 374*0Sstevel@tonic-gate hasprocperm(const cred_t *tcrp, const cred_t *scrp) 375*0Sstevel@tonic-gate { 376*0Sstevel@tonic-gate if (scrp == tcrp) 377*0Sstevel@tonic-gate return (1); 378*0Sstevel@tonic-gate if (scrp->cr_zone != tcrp->cr_zone && 379*0Sstevel@tonic-gate (scrp->cr_zone != global_zone || 380*0Sstevel@tonic-gate secpolicy_proc_zone(scrp) != 0)) 381*0Sstevel@tonic-gate return (0); 382*0Sstevel@tonic-gate if (scrp->cr_uid == tcrp->cr_ruid || 383*0Sstevel@tonic-gate scrp->cr_ruid == tcrp->cr_ruid || 384*0Sstevel@tonic-gate scrp->cr_uid == tcrp->cr_suid || 385*0Sstevel@tonic-gate scrp->cr_ruid == tcrp->cr_suid || 386*0Sstevel@tonic-gate !PRIV_POLICY(scrp, PRIV_PROC_OWNER, B_FALSE, EPERM, "hasprocperm")) 387*0Sstevel@tonic-gate return (1); 388*0Sstevel@tonic-gate return (0); 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate /* 392*0Sstevel@tonic-gate * This interface replaces hasprocperm; it works like hasprocperm but 393*0Sstevel@tonic-gate * additionally returns success if the proc_t's match 394*0Sstevel@tonic-gate * It is the preferred interface for most uses. 395*0Sstevel@tonic-gate * And it will acquire pcrlock itself, so it assert's that it shouldn't 396*0Sstevel@tonic-gate * be held. 397*0Sstevel@tonic-gate */ 398*0Sstevel@tonic-gate int 399*0Sstevel@tonic-gate prochasprocperm(proc_t *tp, proc_t *sp, const cred_t *scrp) 400*0Sstevel@tonic-gate { 401*0Sstevel@tonic-gate int rets; 402*0Sstevel@tonic-gate cred_t *tcrp; 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&tp->p_crlock)); 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate if (tp == sp) 407*0Sstevel@tonic-gate return (1); 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate if (tp->p_sessp != sp->p_sessp && secpolicy_basic_proc(scrp) != 0) 410*0Sstevel@tonic-gate return (0); 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate mutex_enter(&tp->p_crlock); 413*0Sstevel@tonic-gate tcrp = tp->p_cred; 414*0Sstevel@tonic-gate rets = hasprocperm(tcrp, scrp); 415*0Sstevel@tonic-gate mutex_exit(&tp->p_crlock); 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate return (rets); 418*0Sstevel@tonic-gate } 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate /* 421*0Sstevel@tonic-gate * This routine is used to compare two credentials to determine if 422*0Sstevel@tonic-gate * they refer to the same "user". If the pointers are equal, then 423*0Sstevel@tonic-gate * they must refer to the same user. Otherwise, the contents of 424*0Sstevel@tonic-gate * the credentials are compared to see whether they are equivalent. 425*0Sstevel@tonic-gate * 426*0Sstevel@tonic-gate * This routine returns 0 if the credentials refer to the same user, 427*0Sstevel@tonic-gate * 1 if they do not. 428*0Sstevel@tonic-gate */ 429*0Sstevel@tonic-gate int 430*0Sstevel@tonic-gate crcmp(const cred_t *cr1, const cred_t *cr2) 431*0Sstevel@tonic-gate { 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate if (cr1 == cr2) 434*0Sstevel@tonic-gate return (0); 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate if (cr1->cr_uid == cr2->cr_uid && 437*0Sstevel@tonic-gate cr1->cr_gid == cr2->cr_gid && 438*0Sstevel@tonic-gate cr1->cr_ruid == cr2->cr_ruid && 439*0Sstevel@tonic-gate cr1->cr_rgid == cr2->cr_rgid && 440*0Sstevel@tonic-gate cr1->cr_ngroups == cr2->cr_ngroups && 441*0Sstevel@tonic-gate cr1->cr_zone == cr2->cr_zone && 442*0Sstevel@tonic-gate bcmp(cr1->cr_groups, cr2->cr_groups, 443*0Sstevel@tonic-gate cr1->cr_ngroups * sizeof (gid_t)) == 0) { 444*0Sstevel@tonic-gate return (!priv_isequalset(&CR_OEPRIV(cr1), &CR_OEPRIV(cr2))); 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate return (1); 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate /* 450*0Sstevel@tonic-gate * Read access functions to cred_t. 451*0Sstevel@tonic-gate */ 452*0Sstevel@tonic-gate uid_t 453*0Sstevel@tonic-gate crgetuid(const cred_t *cr) 454*0Sstevel@tonic-gate { 455*0Sstevel@tonic-gate return (cr->cr_uid); 456*0Sstevel@tonic-gate } 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate uid_t 459*0Sstevel@tonic-gate crgetruid(const cred_t *cr) 460*0Sstevel@tonic-gate { 461*0Sstevel@tonic-gate return (cr->cr_ruid); 462*0Sstevel@tonic-gate } 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate uid_t 465*0Sstevel@tonic-gate crgetsuid(const cred_t *cr) 466*0Sstevel@tonic-gate { 467*0Sstevel@tonic-gate return (cr->cr_suid); 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate gid_t 471*0Sstevel@tonic-gate crgetgid(const cred_t *cr) 472*0Sstevel@tonic-gate { 473*0Sstevel@tonic-gate return (cr->cr_gid); 474*0Sstevel@tonic-gate } 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate gid_t 477*0Sstevel@tonic-gate crgetrgid(const cred_t *cr) 478*0Sstevel@tonic-gate { 479*0Sstevel@tonic-gate return (cr->cr_rgid); 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate gid_t 483*0Sstevel@tonic-gate crgetsgid(const cred_t *cr) 484*0Sstevel@tonic-gate { 485*0Sstevel@tonic-gate return (cr->cr_sgid); 486*0Sstevel@tonic-gate } 487*0Sstevel@tonic-gate 488*0Sstevel@tonic-gate const auditinfo_addr_t * 489*0Sstevel@tonic-gate crgetauinfo(const cred_t *cr) 490*0Sstevel@tonic-gate { 491*0Sstevel@tonic-gate return ((const auditinfo_addr_t *)CR_AUINFO(cr)); 492*0Sstevel@tonic-gate } 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate auditinfo_addr_t * 495*0Sstevel@tonic-gate crgetauinfo_modifiable(cred_t *cr) 496*0Sstevel@tonic-gate { 497*0Sstevel@tonic-gate return (CR_AUINFO(cr)); 498*0Sstevel@tonic-gate } 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate zoneid_t 501*0Sstevel@tonic-gate crgetzoneid(const cred_t *cr) 502*0Sstevel@tonic-gate { 503*0Sstevel@tonic-gate return (cr->cr_zone->zone_id); 504*0Sstevel@tonic-gate } 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate projid_t 507*0Sstevel@tonic-gate crgetprojid(const cred_t *cr) 508*0Sstevel@tonic-gate { 509*0Sstevel@tonic-gate return (cr->cr_projid); 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate #define BADID(x) ((x) != -1 && (unsigned int)(x) > MAXUID) 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate int 515*0Sstevel@tonic-gate crsetresuid(cred_t *cr, uid_t r, uid_t e, uid_t s) 516*0Sstevel@tonic-gate { 517*0Sstevel@tonic-gate ASSERT(cr->cr_ref <= 2); 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate if (BADID(r) || BADID(e) || BADID(s)) 520*0Sstevel@tonic-gate return (-1); 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate if (r != -1) 523*0Sstevel@tonic-gate cr->cr_ruid = r; 524*0Sstevel@tonic-gate if (e != -1) 525*0Sstevel@tonic-gate cr->cr_uid = e; 526*0Sstevel@tonic-gate if (s != -1) 527*0Sstevel@tonic-gate cr->cr_suid = s; 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate return (0); 530*0Sstevel@tonic-gate } 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate int 533*0Sstevel@tonic-gate crsetresgid(cred_t *cr, gid_t r, gid_t e, gid_t s) 534*0Sstevel@tonic-gate { 535*0Sstevel@tonic-gate ASSERT(cr->cr_ref <= 2); 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate if (BADID(r) || BADID(e) || BADID(s)) 538*0Sstevel@tonic-gate return (-1); 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate if (r != -1) 541*0Sstevel@tonic-gate cr->cr_rgid = r; 542*0Sstevel@tonic-gate if (e != -1) 543*0Sstevel@tonic-gate cr->cr_gid = e; 544*0Sstevel@tonic-gate if (s != -1) 545*0Sstevel@tonic-gate cr->cr_sgid = s; 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate return (0); 548*0Sstevel@tonic-gate } 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate int 551*0Sstevel@tonic-gate crsetugid(cred_t *cr, uid_t uid, gid_t gid) 552*0Sstevel@tonic-gate { 553*0Sstevel@tonic-gate ASSERT(cr->cr_ref <= 2); 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate if (uid < 0 || uid > MAXUID || gid < 0 || gid > MAXUID) 556*0Sstevel@tonic-gate return (-1); 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate cr->cr_uid = cr->cr_ruid = cr->cr_suid = uid; 559*0Sstevel@tonic-gate cr->cr_gid = cr->cr_rgid = cr->cr_sgid = gid; 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate return (0); 562*0Sstevel@tonic-gate } 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate int 565*0Sstevel@tonic-gate crsetgroups(cred_t *cr, int n, gid_t *grp) 566*0Sstevel@tonic-gate { 567*0Sstevel@tonic-gate ASSERT(cr->cr_ref <= 2); 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate if (n > ngroups_max || n < 0) 570*0Sstevel@tonic-gate return (-1); 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate cr->cr_ngroups = n; 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate if (n > 0) 575*0Sstevel@tonic-gate bcopy(grp, cr->cr_groups, n * sizeof (gid_t)); 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate return (0); 578*0Sstevel@tonic-gate } 579*0Sstevel@tonic-gate 580*0Sstevel@tonic-gate void 581*0Sstevel@tonic-gate crsetprojid(cred_t *cr, projid_t projid) 582*0Sstevel@tonic-gate { 583*0Sstevel@tonic-gate ASSERT(projid >= 0 && projid <= MAXPROJID); 584*0Sstevel@tonic-gate cr->cr_projid = projid; 585*0Sstevel@tonic-gate } 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate /* 588*0Sstevel@tonic-gate * This routine returns the pointer to the first element of the cr_groups 589*0Sstevel@tonic-gate * array. It can move around in an implementation defined way. 590*0Sstevel@tonic-gate */ 591*0Sstevel@tonic-gate const gid_t * 592*0Sstevel@tonic-gate crgetgroups(const cred_t *cr) 593*0Sstevel@tonic-gate { 594*0Sstevel@tonic-gate return (cr->cr_groups); 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate int 598*0Sstevel@tonic-gate crgetngroups(const cred_t *cr) 599*0Sstevel@tonic-gate { 600*0Sstevel@tonic-gate return (cr->cr_ngroups); 601*0Sstevel@tonic-gate } 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate void 604*0Sstevel@tonic-gate cred2prcred(const cred_t *cr, prcred_t *pcrp) 605*0Sstevel@tonic-gate { 606*0Sstevel@tonic-gate pcrp->pr_euid = cr->cr_uid; 607*0Sstevel@tonic-gate pcrp->pr_ruid = cr->cr_ruid; 608*0Sstevel@tonic-gate pcrp->pr_suid = cr->cr_suid; 609*0Sstevel@tonic-gate pcrp->pr_egid = cr->cr_gid; 610*0Sstevel@tonic-gate pcrp->pr_rgid = cr->cr_rgid; 611*0Sstevel@tonic-gate pcrp->pr_sgid = cr->cr_sgid; 612*0Sstevel@tonic-gate pcrp->pr_ngroups = MIN(cr->cr_ngroups, (uint_t)ngroups_max); 613*0Sstevel@tonic-gate pcrp->pr_groups[0] = 0; /* in case ngroups == 0 */ 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate if (pcrp->pr_ngroups != 0) 616*0Sstevel@tonic-gate bcopy(cr->cr_groups, pcrp->pr_groups, 617*0Sstevel@tonic-gate sizeof (gid_t) * cr->cr_ngroups); 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate static int 621*0Sstevel@tonic-gate cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo) 622*0Sstevel@tonic-gate { 623*0Sstevel@tonic-gate auditinfo_addr_t *ai; 624*0Sstevel@tonic-gate au_tid_addr_t tid; 625*0Sstevel@tonic-gate 626*0Sstevel@tonic-gate if (secpolicy_audit_getattr(CRED()) != 0) 627*0Sstevel@tonic-gate return (-1); 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate ai = CR_AUINFO(cr); /* caller makes sure this is non-NULL */ 630*0Sstevel@tonic-gate tid = ai->ai_termid; 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate ainfo->ai_auid = ai->ai_auid; 633*0Sstevel@tonic-gate ainfo->ai_mask = ai->ai_mask; 634*0Sstevel@tonic-gate ainfo->ai_asid = ai->ai_asid; 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate ainfo->ai_termid.at_type = tid.at_type; 637*0Sstevel@tonic-gate bcopy(&tid.at_addr, &ainfo->ai_termid.at_addr, 4 * sizeof (uint_t)); 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate ainfo->ai_termid.at_port.at_major = (uint32_t)getmajor(tid.at_port); 640*0Sstevel@tonic-gate ainfo->ai_termid.at_port.at_minor = (uint32_t)getminor(tid.at_port); 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate return (0); 643*0Sstevel@tonic-gate } 644*0Sstevel@tonic-gate 645*0Sstevel@tonic-gate /* 646*0Sstevel@tonic-gate * Convert a credential into a "ucred". Allow the caller to specify 647*0Sstevel@tonic-gate * and aligned buffer, e.g., in an mblk, so we don't have to allocate 648*0Sstevel@tonic-gate * memory and copy it twice. 649*0Sstevel@tonic-gate */ 650*0Sstevel@tonic-gate struct ucred_s * 651*0Sstevel@tonic-gate cred2ucred(const cred_t *cr, pid_t pid, void *buf) 652*0Sstevel@tonic-gate { 653*0Sstevel@tonic-gate struct ucred_s *uc; 654*0Sstevel@tonic-gate 655*0Sstevel@tonic-gate /* The structure isn't always completely filled in, so zero it */ 656*0Sstevel@tonic-gate if (buf == NULL) { 657*0Sstevel@tonic-gate uc = kmem_zalloc(ucredsize, KM_SLEEP); 658*0Sstevel@tonic-gate } else { 659*0Sstevel@tonic-gate bzero(buf, ucredsize); 660*0Sstevel@tonic-gate uc = buf; 661*0Sstevel@tonic-gate } 662*0Sstevel@tonic-gate uc->uc_size = ucredsize; 663*0Sstevel@tonic-gate uc->uc_credoff = UCRED_CRED_OFF; 664*0Sstevel@tonic-gate uc->uc_privoff = UCRED_PRIV_OFF; 665*0Sstevel@tonic-gate uc->uc_audoff = UCRED_AUD_OFF; 666*0Sstevel@tonic-gate uc->uc_pid = pid; 667*0Sstevel@tonic-gate uc->uc_projid = cr->cr_projid; 668*0Sstevel@tonic-gate uc->uc_zoneid = crgetzoneid(cr); 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gate cred2prcred(cr, UCCRED(uc)); 671*0Sstevel@tonic-gate cred2prpriv(cr, UCPRIV(uc)); 672*0Sstevel@tonic-gate if (audoff == 0 || cred2ucaud(cr, UCAUD(uc)) != 0) 673*0Sstevel@tonic-gate uc->uc_audoff = 0; 674*0Sstevel@tonic-gate 675*0Sstevel@tonic-gate return (uc); 676*0Sstevel@tonic-gate } 677*0Sstevel@tonic-gate 678*0Sstevel@tonic-gate /* 679*0Sstevel@tonic-gate * Get the "ucred" of a process. 680*0Sstevel@tonic-gate */ 681*0Sstevel@tonic-gate struct ucred_s * 682*0Sstevel@tonic-gate pgetucred(proc_t *p) 683*0Sstevel@tonic-gate { 684*0Sstevel@tonic-gate cred_t *cr; 685*0Sstevel@tonic-gate struct ucred_s *uc; 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate mutex_enter(&p->p_crlock); 688*0Sstevel@tonic-gate cr = p->p_cred; 689*0Sstevel@tonic-gate crhold(cr); 690*0Sstevel@tonic-gate mutex_exit(&p->p_crlock); 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate uc = cred2ucred(cr, p->p_pid, NULL); 693*0Sstevel@tonic-gate crfree(cr); 694*0Sstevel@tonic-gate 695*0Sstevel@tonic-gate return (uc); 696*0Sstevel@tonic-gate } 697*0Sstevel@tonic-gate 698*0Sstevel@tonic-gate /* 699*0Sstevel@tonic-gate * If the reply status is NFSERR_EACCES, it may be because we are 700*0Sstevel@tonic-gate * root (no root net access). Check the real uid, if it isn't root 701*0Sstevel@tonic-gate * make that the uid instead and retry the call. 702*0Sstevel@tonic-gate * Private interface for NFS. 703*0Sstevel@tonic-gate */ 704*0Sstevel@tonic-gate cred_t * 705*0Sstevel@tonic-gate crnetadjust(cred_t *cr) 706*0Sstevel@tonic-gate { 707*0Sstevel@tonic-gate if (cr->cr_uid == 0 && cr->cr_ruid != 0) { 708*0Sstevel@tonic-gate cr = crdup(cr); 709*0Sstevel@tonic-gate cr->cr_uid = cr->cr_ruid; 710*0Sstevel@tonic-gate return (cr); 711*0Sstevel@tonic-gate } 712*0Sstevel@tonic-gate return (NULL); 713*0Sstevel@tonic-gate } 714*0Sstevel@tonic-gate 715*0Sstevel@tonic-gate /* 716*0Sstevel@tonic-gate * The reference count is of interest when you want to check 717*0Sstevel@tonic-gate * whether it is ok to modify the credential in place. 718*0Sstevel@tonic-gate */ 719*0Sstevel@tonic-gate uint_t 720*0Sstevel@tonic-gate crgetref(const cred_t *cr) 721*0Sstevel@tonic-gate { 722*0Sstevel@tonic-gate return (cr->cr_ref); 723*0Sstevel@tonic-gate } 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate static int 726*0Sstevel@tonic-gate get_c2audit_load(void) 727*0Sstevel@tonic-gate { 728*0Sstevel@tonic-gate static int gotit = 0; 729*0Sstevel@tonic-gate static int c2audit_load; 730*0Sstevel@tonic-gate u_longlong_t audit_load_val; 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate if (gotit) 733*0Sstevel@tonic-gate return (c2audit_load); 734*0Sstevel@tonic-gate audit_load_val = 0; /* set default value once */ 735*0Sstevel@tonic-gate (void) mod_sysvar("c2audit", "audit_load", &audit_load_val); 736*0Sstevel@tonic-gate c2audit_load = (int)audit_load_val; 737*0Sstevel@tonic-gate gotit++; 738*0Sstevel@tonic-gate return (c2audit_load); 739*0Sstevel@tonic-gate } 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate int 742*0Sstevel@tonic-gate get_audit_ucrsize(void) 743*0Sstevel@tonic-gate { 744*0Sstevel@tonic-gate return (get_c2audit_load() ? sizeof (auditinfo64_addr_t) : 0); 745*0Sstevel@tonic-gate } 746*0Sstevel@tonic-gate 747*0Sstevel@tonic-gate /* 748*0Sstevel@tonic-gate * Set zone pointer in credential to indicated value. First adds a 749*0Sstevel@tonic-gate * hold for the new zone, then drops the hold on previous zone (if any). 750*0Sstevel@tonic-gate * This is done in this order in case the old and new zones are the 751*0Sstevel@tonic-gate * same. 752*0Sstevel@tonic-gate */ 753*0Sstevel@tonic-gate void 754*0Sstevel@tonic-gate crsetzone(cred_t *cr, zone_t *zptr) 755*0Sstevel@tonic-gate { 756*0Sstevel@tonic-gate zone_t *oldzptr = cr->cr_zone; 757*0Sstevel@tonic-gate 758*0Sstevel@tonic-gate ASSERT(cr != kcred); 759*0Sstevel@tonic-gate ASSERT(cr->cr_ref <= 2); 760*0Sstevel@tonic-gate cr->cr_zone = zptr; 761*0Sstevel@tonic-gate zone_cred_hold(zptr); 762*0Sstevel@tonic-gate if (oldzptr) 763*0Sstevel@tonic-gate zone_cred_rele(oldzptr); 764*0Sstevel@tonic-gate } 765