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