1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/task.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 31*7c478bd9Sstevel@tonic-gate #include <unistd.h> 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include <ctype.h> 34*7c478bd9Sstevel@tonic-gate #include <project.h> 35*7c478bd9Sstevel@tonic-gate #include <rctl.h> 36*7c478bd9Sstevel@tonic-gate #include <secdb.h> 37*7c478bd9Sstevel@tonic-gate #include <signal.h> 38*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 39*7c478bd9Sstevel@tonic-gate #include <string.h> 40*7c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h> 41*7c478bd9Sstevel@tonic-gate #include <pwd.h> 42*7c478bd9Sstevel@tonic-gate #include <pool.h> 43*7c478bd9Sstevel@tonic-gate #include <libproc.h> 44*7c478bd9Sstevel@tonic-gate #include <priv.h> 45*7c478bd9Sstevel@tonic-gate #include <priv_utils.h> 46*7c478bd9Sstevel@tonic-gate #include <zone.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/pool.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/pool_impl.h> 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate static void 51*7c478bd9Sstevel@tonic-gate xstrtolower(char *s) 52*7c478bd9Sstevel@tonic-gate { 53*7c478bd9Sstevel@tonic-gate for (; *s != '\0'; s++) 54*7c478bd9Sstevel@tonic-gate *s = tolower(*s); 55*7c478bd9Sstevel@tonic-gate } 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate static void 58*7c478bd9Sstevel@tonic-gate remove_spaces(char *s) 59*7c478bd9Sstevel@tonic-gate { 60*7c478bd9Sstevel@tonic-gate char *current; 61*7c478bd9Sstevel@tonic-gate char *next; 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate current = next = s; 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate while (*next != '\0') { 66*7c478bd9Sstevel@tonic-gate while (isspace(*next)) 67*7c478bd9Sstevel@tonic-gate next++; 68*7c478bd9Sstevel@tonic-gate *current++ = *next++; 69*7c478bd9Sstevel@tonic-gate } 70*7c478bd9Sstevel@tonic-gate *current = '\0'; 71*7c478bd9Sstevel@tonic-gate } 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate int 74*7c478bd9Sstevel@tonic-gate build_rctlblk(rctlblk_t *blk, int comp_num, char *component) 75*7c478bd9Sstevel@tonic-gate { 76*7c478bd9Sstevel@tonic-gate char *signam; 77*7c478bd9Sstevel@tonic-gate int sig = 0; 78*7c478bd9Sstevel@tonic-gate uint_t act = rctlblk_get_local_action(blk, &sig); 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate if (comp_num == 0) { 81*7c478bd9Sstevel@tonic-gate /* 82*7c478bd9Sstevel@tonic-gate * Setting privilege level for resource control block. 83*7c478bd9Sstevel@tonic-gate */ 84*7c478bd9Sstevel@tonic-gate xstrtolower(component); 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate if (strcmp("basic", component) == 0) { 87*7c478bd9Sstevel@tonic-gate rctlblk_set_privilege(blk, RCPRIV_BASIC); 88*7c478bd9Sstevel@tonic-gate return (0); 89*7c478bd9Sstevel@tonic-gate } 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate if (strcmp("priv", component) == 0 || 92*7c478bd9Sstevel@tonic-gate strcmp("privileged", component) == 0) { 93*7c478bd9Sstevel@tonic-gate rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED); 94*7c478bd9Sstevel@tonic-gate return (0); 95*7c478bd9Sstevel@tonic-gate } 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate return (-1); 98*7c478bd9Sstevel@tonic-gate } 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate if (comp_num == 1) { 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate /* 103*7c478bd9Sstevel@tonic-gate * Setting value for resource control block. 104*7c478bd9Sstevel@tonic-gate */ 105*7c478bd9Sstevel@tonic-gate unsigned long long val; 106*7c478bd9Sstevel@tonic-gate char *t; 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate /* Negative numbers are not allowed */ 109*7c478bd9Sstevel@tonic-gate if (strchr(component, '-') != NULL) 110*7c478bd9Sstevel@tonic-gate return (-1); 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate errno = 0; 113*7c478bd9Sstevel@tonic-gate val = strtoull(component, &t, 10); 114*7c478bd9Sstevel@tonic-gate if (errno != 0 || t == component || *t != '\0') 115*7c478bd9Sstevel@tonic-gate return (-1); 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate rctlblk_set_value(blk, (rctl_qty_t)val); 118*7c478bd9Sstevel@tonic-gate return (0); 119*7c478bd9Sstevel@tonic-gate } 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate /* 122*7c478bd9Sstevel@tonic-gate * Setting one or more actions on this resource control block. 123*7c478bd9Sstevel@tonic-gate */ 124*7c478bd9Sstevel@tonic-gate if (comp_num >= 2) { 125*7c478bd9Sstevel@tonic-gate if (strcmp("none", component) == 0) { 126*7c478bd9Sstevel@tonic-gate rctlblk_set_local_action(blk, 0, 0); 127*7c478bd9Sstevel@tonic-gate return (0); 128*7c478bd9Sstevel@tonic-gate } 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate if (strcmp("deny", component) == 0) { 131*7c478bd9Sstevel@tonic-gate act |= RCTL_LOCAL_DENY; 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate rctlblk_set_local_action(blk, act, sig); 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate return (0); 136*7c478bd9Sstevel@tonic-gate } 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate /* 139*7c478bd9Sstevel@tonic-gate * The last, and trickiest, form of action is the signal 140*7c478bd9Sstevel@tonic-gate * specification. 141*7c478bd9Sstevel@tonic-gate */ 142*7c478bd9Sstevel@tonic-gate if ((signam = strchr(component, '=')) == NULL) 143*7c478bd9Sstevel@tonic-gate return (-1); 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate *signam++ = '\0'; 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate if (strcmp("sig", component) == 0 || 148*7c478bd9Sstevel@tonic-gate strcmp("signal", component) == 0) { 149*7c478bd9Sstevel@tonic-gate if (strncmp("SIG", signam, 3) == 0) 150*7c478bd9Sstevel@tonic-gate signam += 3; 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate if (str2sig(signam, &sig) == -1) 153*7c478bd9Sstevel@tonic-gate return (-1); 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate act |= RCTL_LOCAL_SIGNAL; 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate rctlblk_set_local_action(blk, act, sig); 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate return (0); 160*7c478bd9Sstevel@tonic-gate } 161*7c478bd9Sstevel@tonic-gate } 162*7c478bd9Sstevel@tonic-gate return (-1); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate /* 166*7c478bd9Sstevel@tonic-gate * States: 167*7c478bd9Sstevel@tonic-gate */ 168*7c478bd9Sstevel@tonic-gate #define INPAREN 0x1 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate /* 171*7c478bd9Sstevel@tonic-gate * Errors: 172*7c478bd9Sstevel@tonic-gate */ 173*7c478bd9Sstevel@tonic-gate #define SETFAILED (-1) 174*7c478bd9Sstevel@tonic-gate #define COMPLETE 1 175*7c478bd9Sstevel@tonic-gate #define NESTING 2 176*7c478bd9Sstevel@tonic-gate #define UNCLOSED 3 177*7c478bd9Sstevel@tonic-gate #define CLOSEBEFOREOPEN 4 178*7c478bd9Sstevel@tonic-gate #define BADSPEC 5 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate static int 181*7c478bd9Sstevel@tonic-gate rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr) 182*7c478bd9Sstevel@tonic-gate { 183*7c478bd9Sstevel@tonic-gate int error = 0; 184*7c478bd9Sstevel@tonic-gate uint_t component = 0; 185*7c478bd9Sstevel@tonic-gate int valuecount = 0; 186*7c478bd9Sstevel@tonic-gate uint_t state = 0; 187*7c478bd9Sstevel@tonic-gate char *component_head; 188*7c478bd9Sstevel@tonic-gate rctlblk_t *blk; 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate remove_spaces(val); 191*7c478bd9Sstevel@tonic-gate if ((blk = malloc(rctlblk_size())) == NULL) { 192*7c478bd9Sstevel@tonic-gate return (SETFAILED); 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate /* 196*7c478bd9Sstevel@tonic-gate * Tear down everything with this ctl name. 197*7c478bd9Sstevel@tonic-gate */ 198*7c478bd9Sstevel@tonic-gate while (pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST) != -1 && 199*7c478bd9Sstevel@tonic-gate rctlblk_get_privilege(blk) != RCPRIV_SYSTEM) { 200*7c478bd9Sstevel@tonic-gate (void) pr_setrctl(Pr, ctl_name, NULL, blk, RCTL_DELETE); 201*7c478bd9Sstevel@tonic-gate } 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate /* 204*7c478bd9Sstevel@tonic-gate * Set initial local action based on global deny properties. 205*7c478bd9Sstevel@tonic-gate */ 206*7c478bd9Sstevel@tonic-gate rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED); 207*7c478bd9Sstevel@tonic-gate rctlblk_set_value(blk, 0); 208*7c478bd9Sstevel@tonic-gate rctlblk_set_local_flags(blk, 0); 209*7c478bd9Sstevel@tonic-gate if (rctlblk_get_global_flags(blk) & RCTL_GLOBAL_DENY_ALWAYS) 210*7c478bd9Sstevel@tonic-gate rctlblk_set_local_action(blk, RCTL_LOCAL_DENY, 0); 211*7c478bd9Sstevel@tonic-gate else 212*7c478bd9Sstevel@tonic-gate rctlblk_set_local_action(blk, RCTL_LOCAL_NOACTION, 0); 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate for (; ; val++) { 216*7c478bd9Sstevel@tonic-gate switch (*val) { 217*7c478bd9Sstevel@tonic-gate case '(': 218*7c478bd9Sstevel@tonic-gate if (state & INPAREN) { 219*7c478bd9Sstevel@tonic-gate error = NESTING; 220*7c478bd9Sstevel@tonic-gate break; 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate state |= INPAREN; 224*7c478bd9Sstevel@tonic-gate component_head = (char *)val + 1; 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate break; 227*7c478bd9Sstevel@tonic-gate case ')': 228*7c478bd9Sstevel@tonic-gate if (state & INPAREN) { 229*7c478bd9Sstevel@tonic-gate *val = '\0'; 230*7c478bd9Sstevel@tonic-gate if (component < 2) { 231*7c478bd9Sstevel@tonic-gate error = BADSPEC; 232*7c478bd9Sstevel@tonic-gate break; 233*7c478bd9Sstevel@tonic-gate } 234*7c478bd9Sstevel@tonic-gate if (build_rctlblk(blk, component, 235*7c478bd9Sstevel@tonic-gate component_head) == -1) { 236*7c478bd9Sstevel@tonic-gate error = BADSPEC; 237*7c478bd9Sstevel@tonic-gate break; 238*7c478bd9Sstevel@tonic-gate } 239*7c478bd9Sstevel@tonic-gate state &= ~INPAREN; 240*7c478bd9Sstevel@tonic-gate component = 0; 241*7c478bd9Sstevel@tonic-gate valuecount++; 242*7c478bd9Sstevel@tonic-gate if (pr_setrctl(Pr, ctl_name, NULL, blk, 243*7c478bd9Sstevel@tonic-gate RCTL_INSERT) == -1) 244*7c478bd9Sstevel@tonic-gate error = SETFAILED; 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate /* re-initialize block */ 247*7c478bd9Sstevel@tonic-gate rctlblk_set_privilege(blk, 248*7c478bd9Sstevel@tonic-gate RCPRIV_PRIVILEGED); 249*7c478bd9Sstevel@tonic-gate rctlblk_set_value(blk, 0); 250*7c478bd9Sstevel@tonic-gate rctlblk_set_local_flags(blk, 0); 251*7c478bd9Sstevel@tonic-gate if (rctlblk_get_global_flags(blk) & 252*7c478bd9Sstevel@tonic-gate RCTL_GLOBAL_DENY_ALWAYS) 253*7c478bd9Sstevel@tonic-gate rctlblk_set_local_action(blk, 254*7c478bd9Sstevel@tonic-gate RCTL_LOCAL_DENY, 0); 255*7c478bd9Sstevel@tonic-gate else 256*7c478bd9Sstevel@tonic-gate rctlblk_set_local_action(blk, 257*7c478bd9Sstevel@tonic-gate RCTL_LOCAL_NOACTION, 0); 258*7c478bd9Sstevel@tonic-gate } else { 259*7c478bd9Sstevel@tonic-gate error = CLOSEBEFOREOPEN; 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate break; 262*7c478bd9Sstevel@tonic-gate case ',': 263*7c478bd9Sstevel@tonic-gate if (state & INPAREN) { 264*7c478bd9Sstevel@tonic-gate *val = '\0'; 265*7c478bd9Sstevel@tonic-gate if (build_rctlblk(blk, component, 266*7c478bd9Sstevel@tonic-gate component_head) == -1) 267*7c478bd9Sstevel@tonic-gate error = BADSPEC; 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate component++; 270*7c478bd9Sstevel@tonic-gate component_head = (char *)val + 1; 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate break; 274*7c478bd9Sstevel@tonic-gate case '\0': 275*7c478bd9Sstevel@tonic-gate if (valuecount == 0) 276*7c478bd9Sstevel@tonic-gate error = BADSPEC; 277*7c478bd9Sstevel@tonic-gate else if (state & INPAREN) 278*7c478bd9Sstevel@tonic-gate error = UNCLOSED; 279*7c478bd9Sstevel@tonic-gate else 280*7c478bd9Sstevel@tonic-gate error = COMPLETE; 281*7c478bd9Sstevel@tonic-gate break; 282*7c478bd9Sstevel@tonic-gate default: 283*7c478bd9Sstevel@tonic-gate if (!(state & INPAREN)) 284*7c478bd9Sstevel@tonic-gate error = BADSPEC; 285*7c478bd9Sstevel@tonic-gate break; 286*7c478bd9Sstevel@tonic-gate } 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate if (error) 289*7c478bd9Sstevel@tonic-gate break; 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate free(blk); 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate if (valuecount == 0) 295*7c478bd9Sstevel@tonic-gate error = BADSPEC; 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate if (error != COMPLETE) 298*7c478bd9Sstevel@tonic-gate return (error); 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate return (0); 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate static int 304*7c478bd9Sstevel@tonic-gate rctlwalkfunc(const char *name, void *data) 305*7c478bd9Sstevel@tonic-gate { 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate if (strcmp(name, (char *)data) == 0) 308*7c478bd9Sstevel@tonic-gate return (-1); 309*7c478bd9Sstevel@tonic-gate else 310*7c478bd9Sstevel@tonic-gate return (0); 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate } 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate /* 315*7c478bd9Sstevel@tonic-gate * This routine determines if /dev/pool device is present on the system and 316*7c478bd9Sstevel@tonic-gate * pools are currently enabled. We want to do this directly from libproject 317*7c478bd9Sstevel@tonic-gate * without using libpool's pool_get_status() routine because pools could be 318*7c478bd9Sstevel@tonic-gate * completely removed from the system. Return 1 if pools are enabled, or 319*7c478bd9Sstevel@tonic-gate * 0 otherwise. When used inside local zones, always pretend that pools 320*7c478bd9Sstevel@tonic-gate * are disabled because binding is not allowed and we're already in the 321*7c478bd9Sstevel@tonic-gate * right pool. 322*7c478bd9Sstevel@tonic-gate */ 323*7c478bd9Sstevel@tonic-gate static int 324*7c478bd9Sstevel@tonic-gate pools_enabled(void) 325*7c478bd9Sstevel@tonic-gate { 326*7c478bd9Sstevel@tonic-gate pool_status_t status; 327*7c478bd9Sstevel@tonic-gate int fd; 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate if (getzoneid() != GLOBAL_ZONEID) 330*7c478bd9Sstevel@tonic-gate return (0); 331*7c478bd9Sstevel@tonic-gate if ((fd = open("/dev/pool", O_RDONLY)) < 0) 332*7c478bd9Sstevel@tonic-gate return (0); 333*7c478bd9Sstevel@tonic-gate if (ioctl(fd, POOL_STATUSQ, &status) < 0) { 334*7c478bd9Sstevel@tonic-gate (void) close(fd); 335*7c478bd9Sstevel@tonic-gate return (0); 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate (void) close(fd); 338*7c478bd9Sstevel@tonic-gate return (status.ps_io_state); 339*7c478bd9Sstevel@tonic-gate } 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate /* 342*7c478bd9Sstevel@tonic-gate * A pool_name of NULL means to attempt to bind to the default pool. 343*7c478bd9Sstevel@tonic-gate * If the "force" flag is non-zero, the value of "system.bind-default" will be 344*7c478bd9Sstevel@tonic-gate * ignored, and the process will be bound to the default pool if one exists. 345*7c478bd9Sstevel@tonic-gate */ 346*7c478bd9Sstevel@tonic-gate static int 347*7c478bd9Sstevel@tonic-gate bind_to_pool(const char *pool_name, pid_t pid, int force) 348*7c478bd9Sstevel@tonic-gate { 349*7c478bd9Sstevel@tonic-gate pool_value_t *pvals[] = { NULL, NULL }; 350*7c478bd9Sstevel@tonic-gate pool_t **pools; 351*7c478bd9Sstevel@tonic-gate uint_t nelem; 352*7c478bd9Sstevel@tonic-gate uchar_t bval; 353*7c478bd9Sstevel@tonic-gate pool_conf_t *conf; 354*7c478bd9Sstevel@tonic-gate const char *nm; 355*7c478bd9Sstevel@tonic-gate int retval; 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate if ((conf = pool_conf_alloc()) == NULL) 358*7c478bd9Sstevel@tonic-gate return (-1); 359*7c478bd9Sstevel@tonic-gate if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) < 0) { 360*7c478bd9Sstevel@tonic-gate /* 361*7c478bd9Sstevel@tonic-gate * Pools configuration file is corrupted; allow logins. 362*7c478bd9Sstevel@tonic-gate */ 363*7c478bd9Sstevel@tonic-gate pool_conf_free(conf); 364*7c478bd9Sstevel@tonic-gate return (0); 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate if (pool_name != NULL && pool_get_pool(conf, pool_name) != NULL) { 367*7c478bd9Sstevel@tonic-gate /* 368*7c478bd9Sstevel@tonic-gate * There was a project.pool entry, and the pool it refers to 369*7c478bd9Sstevel@tonic-gate * is a valid (active) pool. 370*7c478bd9Sstevel@tonic-gate */ 371*7c478bd9Sstevel@tonic-gate (void) pool_conf_close(conf); 372*7c478bd9Sstevel@tonic-gate pool_conf_free(conf); 373*7c478bd9Sstevel@tonic-gate if (pool_set_binding(pool_name, P_PID, pid) != PO_SUCCESS) { 374*7c478bd9Sstevel@tonic-gate if (pool_error() != POE_SYSTEM) 375*7c478bd9Sstevel@tonic-gate errno = EINVAL; 376*7c478bd9Sstevel@tonic-gate return (-1); 377*7c478bd9Sstevel@tonic-gate } 378*7c478bd9Sstevel@tonic-gate return (0); 379*7c478bd9Sstevel@tonic-gate } 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate /* 382*7c478bd9Sstevel@tonic-gate * Bind to the pool with 'pool.default' = 'true' if 383*7c478bd9Sstevel@tonic-gate * 'system.bind-default' = 'true'. 384*7c478bd9Sstevel@tonic-gate */ 385*7c478bd9Sstevel@tonic-gate if ((pvals[0] = pool_value_alloc()) == NULL) { 386*7c478bd9Sstevel@tonic-gate pool_conf_close(conf); 387*7c478bd9Sstevel@tonic-gate pool_conf_free(conf); 388*7c478bd9Sstevel@tonic-gate return (-1); 389*7c478bd9Sstevel@tonic-gate } 390*7c478bd9Sstevel@tonic-gate if (!force && pool_get_property(conf, pool_conf_to_elem(conf), 391*7c478bd9Sstevel@tonic-gate "system.bind-default", pvals[0]) != POC_BOOL || 392*7c478bd9Sstevel@tonic-gate pool_value_get_bool(pvals[0], &bval) != PO_SUCCESS || 393*7c478bd9Sstevel@tonic-gate bval == PO_FALSE) { 394*7c478bd9Sstevel@tonic-gate pool_value_free(pvals[0]); 395*7c478bd9Sstevel@tonic-gate pool_conf_close(conf); 396*7c478bd9Sstevel@tonic-gate pool_conf_free(conf); 397*7c478bd9Sstevel@tonic-gate errno = pool_name == NULL ? EACCES : ESRCH; 398*7c478bd9Sstevel@tonic-gate return (-1); 399*7c478bd9Sstevel@tonic-gate } 400*7c478bd9Sstevel@tonic-gate (void) pool_value_set_name(pvals[0], "pool.default"); 401*7c478bd9Sstevel@tonic-gate pool_value_set_bool(pvals[0], PO_TRUE); 402*7c478bd9Sstevel@tonic-gate if ((pools = pool_query_pools(conf, &nelem, pvals)) == NULL) { 403*7c478bd9Sstevel@tonic-gate /* 404*7c478bd9Sstevel@tonic-gate * No default pools exist. 405*7c478bd9Sstevel@tonic-gate */ 406*7c478bd9Sstevel@tonic-gate pool_value_free(pvals[0]); 407*7c478bd9Sstevel@tonic-gate pool_conf_close(conf); 408*7c478bd9Sstevel@tonic-gate pool_conf_free(conf); 409*7c478bd9Sstevel@tonic-gate errno = pool_name == NULL ? EACCES : ESRCH; 410*7c478bd9Sstevel@tonic-gate return (-1); 411*7c478bd9Sstevel@tonic-gate } 412*7c478bd9Sstevel@tonic-gate if (nelem != 1 || 413*7c478bd9Sstevel@tonic-gate pool_get_property(conf, pool_to_elem(conf, pools[0]), "pool.name", 414*7c478bd9Sstevel@tonic-gate pvals[0]) != POC_STRING) { 415*7c478bd9Sstevel@tonic-gate /* 416*7c478bd9Sstevel@tonic-gate * Configuration is invalid. 417*7c478bd9Sstevel@tonic-gate */ 418*7c478bd9Sstevel@tonic-gate free(pools); 419*7c478bd9Sstevel@tonic-gate pool_value_free(pvals[0]); 420*7c478bd9Sstevel@tonic-gate (void) pool_conf_close(conf); 421*7c478bd9Sstevel@tonic-gate pool_conf_free(conf); 422*7c478bd9Sstevel@tonic-gate return (0); 423*7c478bd9Sstevel@tonic-gate } 424*7c478bd9Sstevel@tonic-gate free(pools); 425*7c478bd9Sstevel@tonic-gate (void) pool_conf_close(conf); 426*7c478bd9Sstevel@tonic-gate pool_conf_free(conf); 427*7c478bd9Sstevel@tonic-gate (void) pool_value_get_string(pvals[0], &nm); 428*7c478bd9Sstevel@tonic-gate if (pool_set_binding(nm, P_PID, pid) != PO_SUCCESS) { 429*7c478bd9Sstevel@tonic-gate if (pool_error() != POE_SYSTEM) 430*7c478bd9Sstevel@tonic-gate errno = EINVAL; 431*7c478bd9Sstevel@tonic-gate retval = -1; 432*7c478bd9Sstevel@tonic-gate } else { 433*7c478bd9Sstevel@tonic-gate retval = 0; 434*7c478bd9Sstevel@tonic-gate } 435*7c478bd9Sstevel@tonic-gate pool_value_free(pvals[0]); 436*7c478bd9Sstevel@tonic-gate return (retval); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate /* 440*7c478bd9Sstevel@tonic-gate * Changes the assigned project, task and resource pool of a stopped target 441*7c478bd9Sstevel@tonic-gate * process. 442*7c478bd9Sstevel@tonic-gate * 443*7c478bd9Sstevel@tonic-gate * We may not have access to the project table if our target process is in 444*7c478bd9Sstevel@tonic-gate * getprojbyname()'s execution path. Similarly, we may not be able to get user 445*7c478bd9Sstevel@tonic-gate * information if the target process is in getpwnam()'s execution path. Thus we 446*7c478bd9Sstevel@tonic-gate * give the caller the option of skipping these checks by providing a pointer to 447*7c478bd9Sstevel@tonic-gate * a pre-validated project structure in proj (whose name matches project_name) 448*7c478bd9Sstevel@tonic-gate * and taking responsibility for ensuring that the target process' owner is a 449*7c478bd9Sstevel@tonic-gate * member of the target project. 450*7c478bd9Sstevel@tonic-gate * 451*7c478bd9Sstevel@tonic-gate * Callers of this function should always provide a pre-validated project 452*7c478bd9Sstevel@tonic-gate * structure in proj unless they can be sure that the target process will never 453*7c478bd9Sstevel@tonic-gate * be in setproject_proc()'s execution path. 454*7c478bd9Sstevel@tonic-gate */ 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate projid_t 457*7c478bd9Sstevel@tonic-gate setproject_proc(const char *project_name, const char *user_name, int flags, 458*7c478bd9Sstevel@tonic-gate pid_t pid, struct ps_prochandle *Pr, struct project *proj) 459*7c478bd9Sstevel@tonic-gate { 460*7c478bd9Sstevel@tonic-gate char pwdbuf[NSS_BUFLEN_PASSWD]; 461*7c478bd9Sstevel@tonic-gate char prbuf[PROJECT_BUFSZ]; 462*7c478bd9Sstevel@tonic-gate projid_t projid; 463*7c478bd9Sstevel@tonic-gate struct passwd pwd; 464*7c478bd9Sstevel@tonic-gate int i; 465*7c478bd9Sstevel@tonic-gate int unknown = 0; 466*7c478bd9Sstevel@tonic-gate int ret = 0; 467*7c478bd9Sstevel@tonic-gate kva_t *kv_array; 468*7c478bd9Sstevel@tonic-gate struct project local_proj; /* space to store proj if not provided */ 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate if (project_name != NULL) { 471*7c478bd9Sstevel@tonic-gate /* 472*7c478bd9Sstevel@tonic-gate * Sanity checks. 473*7c478bd9Sstevel@tonic-gate */ 474*7c478bd9Sstevel@tonic-gate if (strcmp(project_name, "") == 0 || 475*7c478bd9Sstevel@tonic-gate user_name == NULL) { 476*7c478bd9Sstevel@tonic-gate errno = EINVAL; 477*7c478bd9Sstevel@tonic-gate return (SETPROJ_ERR_TASK); 478*7c478bd9Sstevel@tonic-gate } 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate /* 481*7c478bd9Sstevel@tonic-gate * If proj is NULL, acquire project information to ensure that 482*7c478bd9Sstevel@tonic-gate * project_name is a valid project, and confirm that user_name 483*7c478bd9Sstevel@tonic-gate * exists and is a member of the specified project. 484*7c478bd9Sstevel@tonic-gate */ 485*7c478bd9Sstevel@tonic-gate if (proj == NULL) { 486*7c478bd9Sstevel@tonic-gate if ((proj = getprojbyname(project_name, &local_proj, 487*7c478bd9Sstevel@tonic-gate prbuf, PROJECT_BUFSZ)) == NULL) { 488*7c478bd9Sstevel@tonic-gate errno = ESRCH; 489*7c478bd9Sstevel@tonic-gate return (SETPROJ_ERR_TASK); 490*7c478bd9Sstevel@tonic-gate } 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate if (getpwnam_r(user_name, &pwd, 493*7c478bd9Sstevel@tonic-gate pwdbuf, NSS_BUFLEN_PASSWD) == NULL) { 494*7c478bd9Sstevel@tonic-gate errno = ESRCH; 495*7c478bd9Sstevel@tonic-gate return (SETPROJ_ERR_TASK); 496*7c478bd9Sstevel@tonic-gate } 497*7c478bd9Sstevel@tonic-gate /* 498*7c478bd9Sstevel@tonic-gate * Root can join any project. 499*7c478bd9Sstevel@tonic-gate */ 500*7c478bd9Sstevel@tonic-gate if (pwd.pw_uid != (uid_t)0 && 501*7c478bd9Sstevel@tonic-gate !inproj(user_name, project_name, prbuf, 502*7c478bd9Sstevel@tonic-gate PROJECT_BUFSZ)) { 503*7c478bd9Sstevel@tonic-gate errno = ESRCH; 504*7c478bd9Sstevel@tonic-gate return (SETPROJ_ERR_TASK); 505*7c478bd9Sstevel@tonic-gate } 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate projid = proj->pj_projid; 508*7c478bd9Sstevel@tonic-gate } else { 509*7c478bd9Sstevel@tonic-gate projid = getprojid(); 510*7c478bd9Sstevel@tonic-gate } 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate /* 513*7c478bd9Sstevel@tonic-gate * Only bind to a pool if pools are configured. 514*7c478bd9Sstevel@tonic-gate */ 515*7c478bd9Sstevel@tonic-gate if (pools_enabled() == 1) { 516*7c478bd9Sstevel@tonic-gate const char *pool_name = NULL; 517*7c478bd9Sstevel@tonic-gate char *old_pool_name; 518*7c478bd9Sstevel@tonic-gate int taskflags = flags; 519*7c478bd9Sstevel@tonic-gate /* 520*7c478bd9Sstevel@tonic-gate * Attempt to bind to pool before calling 521*7c478bd9Sstevel@tonic-gate * settaskid(). 522*7c478bd9Sstevel@tonic-gate */ 523*7c478bd9Sstevel@tonic-gate if ((kv_array = _str2kva(proj->pj_attr, KV_ASSIGN, 524*7c478bd9Sstevel@tonic-gate KV_DELIMITER)) != NULL) { 525*7c478bd9Sstevel@tonic-gate for (i = 0; i < kv_array->length; i++) { 526*7c478bd9Sstevel@tonic-gate if (strcmp(kv_array->data[i].key, 527*7c478bd9Sstevel@tonic-gate "project.pool") == 0) { 528*7c478bd9Sstevel@tonic-gate pool_name = kv_array->data[i].value; 529*7c478bd9Sstevel@tonic-gate break; 530*7c478bd9Sstevel@tonic-gate } 531*7c478bd9Sstevel@tonic-gate if (strcmp(kv_array->data[i].key, 532*7c478bd9Sstevel@tonic-gate "task.final") == 0) { 533*7c478bd9Sstevel@tonic-gate taskflags |= TASK_FINAL; 534*7c478bd9Sstevel@tonic-gate } 535*7c478bd9Sstevel@tonic-gate } 536*7c478bd9Sstevel@tonic-gate } 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate old_pool_name = pool_get_binding(pid); 539*7c478bd9Sstevel@tonic-gate if (bind_to_pool(pool_name, pid, 0) != 0) { 540*7c478bd9Sstevel@tonic-gate if (old_pool_name) 541*7c478bd9Sstevel@tonic-gate free(old_pool_name); 542*7c478bd9Sstevel@tonic-gate _kva_free(kv_array); 543*7c478bd9Sstevel@tonic-gate return (SETPROJ_ERR_POOL); 544*7c478bd9Sstevel@tonic-gate } 545*7c478bd9Sstevel@tonic-gate if (pr_settaskid(Pr, projid, taskflags) == -1) { 546*7c478bd9Sstevel@tonic-gate int saved_errno = errno; 547*7c478bd9Sstevel@tonic-gate 548*7c478bd9Sstevel@tonic-gate /* 549*7c478bd9Sstevel@tonic-gate * Undo pool binding. 550*7c478bd9Sstevel@tonic-gate */ 551*7c478bd9Sstevel@tonic-gate (void) bind_to_pool(old_pool_name, pid, 1); 552*7c478bd9Sstevel@tonic-gate if (old_pool_name) 553*7c478bd9Sstevel@tonic-gate free(old_pool_name); 554*7c478bd9Sstevel@tonic-gate _kva_free(kv_array); 555*7c478bd9Sstevel@tonic-gate /* 556*7c478bd9Sstevel@tonic-gate * Restore errno 557*7c478bd9Sstevel@tonic-gate */ 558*7c478bd9Sstevel@tonic-gate errno = saved_errno; 559*7c478bd9Sstevel@tonic-gate return (SETPROJ_ERR_TASK); 560*7c478bd9Sstevel@tonic-gate } 561*7c478bd9Sstevel@tonic-gate if (old_pool_name) 562*7c478bd9Sstevel@tonic-gate free(old_pool_name); 563*7c478bd9Sstevel@tonic-gate } else { 564*7c478bd9Sstevel@tonic-gate /* 565*7c478bd9Sstevel@tonic-gate * Pools are not configured, so simply create new task. 566*7c478bd9Sstevel@tonic-gate */ 567*7c478bd9Sstevel@tonic-gate if (pr_settaskid(Pr, projid, flags) == -1) 568*7c478bd9Sstevel@tonic-gate return (SETPROJ_ERR_TASK); 569*7c478bd9Sstevel@tonic-gate kv_array = _str2kva(proj->pj_attr, KV_ASSIGN, KV_DELIMITER); 570*7c478bd9Sstevel@tonic-gate } 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate if (project_name == NULL) { 573*7c478bd9Sstevel@tonic-gate /* 574*7c478bd9Sstevel@tonic-gate * In the case that we are starting a new task in the 575*7c478bd9Sstevel@tonic-gate * current project, we are finished, since the current 576*7c478bd9Sstevel@tonic-gate * resource controls will still apply. (Implicit behaviour: 577*7c478bd9Sstevel@tonic-gate * a project must be entirely logged out before name 578*7c478bd9Sstevel@tonic-gate * service changes will take effect.) 579*7c478bd9Sstevel@tonic-gate */ 580*7c478bd9Sstevel@tonic-gate _kva_free(kv_array); 581*7c478bd9Sstevel@tonic-gate return (projid); 582*7c478bd9Sstevel@tonic-gate } 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate if (kv_array == NULL) 585*7c478bd9Sstevel@tonic-gate return (0); 586*7c478bd9Sstevel@tonic-gate 587*7c478bd9Sstevel@tonic-gate for (i = 0; i < kv_array->length; i++) { 588*7c478bd9Sstevel@tonic-gate /* 589*7c478bd9Sstevel@tonic-gate * Providing a special, i.e. a non-resource control, key? Then 590*7c478bd9Sstevel@tonic-gate * parse that key here and end with "continue;". 591*7c478bd9Sstevel@tonic-gate */ 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate /* 594*7c478bd9Sstevel@tonic-gate * For generic bindings, the kernel performs the binding, as 595*7c478bd9Sstevel@tonic-gate * these are resource controls advertised by kernel subsystems. 596*7c478bd9Sstevel@tonic-gate */ 597*7c478bd9Sstevel@tonic-gate 598*7c478bd9Sstevel@tonic-gate /* 599*7c478bd9Sstevel@tonic-gate * Check for known attribute name. 600*7c478bd9Sstevel@tonic-gate */ 601*7c478bd9Sstevel@tonic-gate errno = 0; 602*7c478bd9Sstevel@tonic-gate if (rctl_walk(rctlwalkfunc, (void *)kv_array->data[i].key) 603*7c478bd9Sstevel@tonic-gate == 0) 604*7c478bd9Sstevel@tonic-gate continue; 605*7c478bd9Sstevel@tonic-gate if (errno) { 606*7c478bd9Sstevel@tonic-gate _kva_free(kv_array); 607*7c478bd9Sstevel@tonic-gate return (SETPROJ_ERR_TASK); 608*7c478bd9Sstevel@tonic-gate } 609*7c478bd9Sstevel@tonic-gate 610*7c478bd9Sstevel@tonic-gate ret = rctl_set(kv_array->data[i].key, 611*7c478bd9Sstevel@tonic-gate kv_array->data[i].value, Pr); 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate if (ret && unknown == 0) { 614*7c478bd9Sstevel@tonic-gate /* 615*7c478bd9Sstevel@tonic-gate * We only report the first failure. 616*7c478bd9Sstevel@tonic-gate */ 617*7c478bd9Sstevel@tonic-gate unknown = i + 1; 618*7c478bd9Sstevel@tonic-gate } 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate if (ret && ret != SETFAILED) { 621*7c478bd9Sstevel@tonic-gate /* 622*7c478bd9Sstevel@tonic-gate * We abort if we couldn't set a component, but if 623*7c478bd9Sstevel@tonic-gate * it's merely that the system didn't recognize it, we 624*7c478bd9Sstevel@tonic-gate * continue, as this could be a third party attribute. 625*7c478bd9Sstevel@tonic-gate */ 626*7c478bd9Sstevel@tonic-gate break; 627*7c478bd9Sstevel@tonic-gate } 628*7c478bd9Sstevel@tonic-gate } 629*7c478bd9Sstevel@tonic-gate _kva_free(kv_array); 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate return (unknown); 632*7c478bd9Sstevel@tonic-gate } 633*7c478bd9Sstevel@tonic-gate 634*7c478bd9Sstevel@tonic-gate projid_t 635*7c478bd9Sstevel@tonic-gate setproject(const char *project_name, const char *user_name, int flags) 636*7c478bd9Sstevel@tonic-gate { 637*7c478bd9Sstevel@tonic-gate return (setproject_proc(project_name, user_name, flags, P_MYID, NULL, 638*7c478bd9Sstevel@tonic-gate NULL)); 639*7c478bd9Sstevel@tonic-gate } 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate priv_set_t * 643*7c478bd9Sstevel@tonic-gate setproject_initpriv(void) 644*7c478bd9Sstevel@tonic-gate { 645*7c478bd9Sstevel@tonic-gate static priv_t taskpriv = PRIV_PROC_TASKID; 646*7c478bd9Sstevel@tonic-gate static priv_t rctlpriv = PRIV_SYS_RESOURCE; 647*7c478bd9Sstevel@tonic-gate static priv_t poolpriv = PRIV_SYS_RES_CONFIG; 648*7c478bd9Sstevel@tonic-gate static priv_t schedpriv = PRIV_PROC_PRIOCNTL; 649*7c478bd9Sstevel@tonic-gate int res; 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate priv_set_t *nset; 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate if (getzoneid() == GLOBAL_ZONEID) { 654*7c478bd9Sstevel@tonic-gate res = __init_suid_priv(0, taskpriv, rctlpriv, poolpriv, 655*7c478bd9Sstevel@tonic-gate schedpriv, (char *)NULL); 656*7c478bd9Sstevel@tonic-gate } else { 657*7c478bd9Sstevel@tonic-gate res = __init_suid_priv(0, taskpriv, rctlpriv, (char *)NULL); 658*7c478bd9Sstevel@tonic-gate } 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate if (res != 0) 661*7c478bd9Sstevel@tonic-gate return (NULL); 662*7c478bd9Sstevel@tonic-gate 663*7c478bd9Sstevel@tonic-gate nset = priv_allocset(); 664*7c478bd9Sstevel@tonic-gate if (nset != NULL) { 665*7c478bd9Sstevel@tonic-gate priv_emptyset(nset); 666*7c478bd9Sstevel@tonic-gate (void) priv_addset(nset, taskpriv); 667*7c478bd9Sstevel@tonic-gate (void) priv_addset(nset, rctlpriv); 668*7c478bd9Sstevel@tonic-gate /* 669*7c478bd9Sstevel@tonic-gate * Only need these if we need to change pools, which can 670*7c478bd9Sstevel@tonic-gate * only happen if the target is in the global zone. Rather 671*7c478bd9Sstevel@tonic-gate * than checking the target's zone just check our own 672*7c478bd9Sstevel@tonic-gate * (since if we're in a non-global zone we won't be able 673*7c478bd9Sstevel@tonic-gate * to control processes in other zones). 674*7c478bd9Sstevel@tonic-gate */ 675*7c478bd9Sstevel@tonic-gate if (getzoneid() == GLOBAL_ZONEID) { 676*7c478bd9Sstevel@tonic-gate (void) priv_addset(nset, poolpriv); 677*7c478bd9Sstevel@tonic-gate (void) priv_addset(nset, schedpriv); 678*7c478bd9Sstevel@tonic-gate } 679*7c478bd9Sstevel@tonic-gate } 680*7c478bd9Sstevel@tonic-gate return (nset); 681*7c478bd9Sstevel@tonic-gate } 682