10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
53247Sgjelinek * Common Development and Distribution License (the "License").
63247Sgjelinek * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12932SRalph.Turner@Sun.COM * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <sys/task.h>
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <unistd.h>
290Sstevel@tonic-gate
300Sstevel@tonic-gate #include <ctype.h>
310Sstevel@tonic-gate #include <project.h>
320Sstevel@tonic-gate #include <rctl.h>
330Sstevel@tonic-gate #include <secdb.h>
340Sstevel@tonic-gate #include <signal.h>
350Sstevel@tonic-gate #include <stdlib.h>
360Sstevel@tonic-gate #include <string.h>
373684Srd117015 #include <strings.h>
380Sstevel@tonic-gate #include <nss_dbdefs.h>
390Sstevel@tonic-gate #include <pwd.h>
400Sstevel@tonic-gate #include <pool.h>
410Sstevel@tonic-gate #include <libproc.h>
420Sstevel@tonic-gate #include <priv.h>
430Sstevel@tonic-gate #include <priv_utils.h>
440Sstevel@tonic-gate #include <zone.h>
450Sstevel@tonic-gate #include <sys/pool.h>
460Sstevel@tonic-gate #include <sys/pool_impl.h>
473684Srd117015 #include <sys/rctl_impl.h>
480Sstevel@tonic-gate
490Sstevel@tonic-gate static void
xstrtolower(char * s)500Sstevel@tonic-gate xstrtolower(char *s)
510Sstevel@tonic-gate {
520Sstevel@tonic-gate for (; *s != '\0'; s++)
530Sstevel@tonic-gate *s = tolower(*s);
540Sstevel@tonic-gate }
550Sstevel@tonic-gate
560Sstevel@tonic-gate static void
remove_spaces(char * s)570Sstevel@tonic-gate remove_spaces(char *s)
580Sstevel@tonic-gate {
590Sstevel@tonic-gate char *current;
600Sstevel@tonic-gate char *next;
610Sstevel@tonic-gate
620Sstevel@tonic-gate current = next = s;
630Sstevel@tonic-gate
640Sstevel@tonic-gate while (*next != '\0') {
650Sstevel@tonic-gate while (isspace(*next))
66*12932SRalph.Turner@Sun.COM next++;
670Sstevel@tonic-gate *current++ = *next++;
680Sstevel@tonic-gate }
690Sstevel@tonic-gate *current = '\0';
700Sstevel@tonic-gate }
710Sstevel@tonic-gate
720Sstevel@tonic-gate int
build_rctlblk(rctlblk_t * blk,int comp_num,char * component)730Sstevel@tonic-gate build_rctlblk(rctlblk_t *blk, int comp_num, char *component)
740Sstevel@tonic-gate {
750Sstevel@tonic-gate char *signam;
760Sstevel@tonic-gate int sig = 0;
770Sstevel@tonic-gate uint_t act = rctlblk_get_local_action(blk, &sig);
780Sstevel@tonic-gate
790Sstevel@tonic-gate if (comp_num == 0) {
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate * Setting privilege level for resource control block.
820Sstevel@tonic-gate */
830Sstevel@tonic-gate xstrtolower(component);
840Sstevel@tonic-gate
850Sstevel@tonic-gate if (strcmp("basic", component) == 0) {
860Sstevel@tonic-gate rctlblk_set_privilege(blk, RCPRIV_BASIC);
870Sstevel@tonic-gate return (0);
880Sstevel@tonic-gate }
890Sstevel@tonic-gate
900Sstevel@tonic-gate if (strcmp("priv", component) == 0 ||
910Sstevel@tonic-gate strcmp("privileged", component) == 0) {
920Sstevel@tonic-gate rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
930Sstevel@tonic-gate return (0);
940Sstevel@tonic-gate }
950Sstevel@tonic-gate
960Sstevel@tonic-gate return (-1);
970Sstevel@tonic-gate }
980Sstevel@tonic-gate
990Sstevel@tonic-gate if (comp_num == 1) {
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate * Setting value for resource control block.
1030Sstevel@tonic-gate */
1040Sstevel@tonic-gate unsigned long long val;
1050Sstevel@tonic-gate char *t;
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate /* Negative numbers are not allowed */
1080Sstevel@tonic-gate if (strchr(component, '-') != NULL)
1090Sstevel@tonic-gate return (-1);
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate errno = 0;
1120Sstevel@tonic-gate val = strtoull(component, &t, 10);
1130Sstevel@tonic-gate if (errno != 0 || t == component || *t != '\0')
1140Sstevel@tonic-gate return (-1);
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate rctlblk_set_value(blk, (rctl_qty_t)val);
1170Sstevel@tonic-gate return (0);
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate /*
1210Sstevel@tonic-gate * Setting one or more actions on this resource control block.
1220Sstevel@tonic-gate */
1230Sstevel@tonic-gate if (comp_num >= 2) {
1240Sstevel@tonic-gate if (strcmp("none", component) == 0) {
1250Sstevel@tonic-gate rctlblk_set_local_action(blk, 0, 0);
1260Sstevel@tonic-gate return (0);
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate if (strcmp("deny", component) == 0) {
1300Sstevel@tonic-gate act |= RCTL_LOCAL_DENY;
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate rctlblk_set_local_action(blk, act, sig);
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate return (0);
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate /*
1380Sstevel@tonic-gate * The last, and trickiest, form of action is the signal
1390Sstevel@tonic-gate * specification.
1400Sstevel@tonic-gate */
1410Sstevel@tonic-gate if ((signam = strchr(component, '=')) == NULL)
1420Sstevel@tonic-gate return (-1);
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate *signam++ = '\0';
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate if (strcmp("sig", component) == 0 ||
1470Sstevel@tonic-gate strcmp("signal", component) == 0) {
1480Sstevel@tonic-gate if (strncmp("SIG", signam, 3) == 0)
1490Sstevel@tonic-gate signam += 3;
1500Sstevel@tonic-gate
1510Sstevel@tonic-gate if (str2sig(signam, &sig) == -1)
1520Sstevel@tonic-gate return (-1);
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate act |= RCTL_LOCAL_SIGNAL;
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate rctlblk_set_local_action(blk, act, sig);
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate return (0);
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate return (-1);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate /*
1650Sstevel@tonic-gate * States:
1660Sstevel@tonic-gate */
1670Sstevel@tonic-gate #define INPAREN 0x1
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate /*
1700Sstevel@tonic-gate * Errors:
1710Sstevel@tonic-gate */
1720Sstevel@tonic-gate #define SETFAILED (-1)
1730Sstevel@tonic-gate #define COMPLETE 1
1740Sstevel@tonic-gate #define NESTING 2
1750Sstevel@tonic-gate #define UNCLOSED 3
1760Sstevel@tonic-gate #define CLOSEBEFOREOPEN 4
1770Sstevel@tonic-gate #define BADSPEC 5
1780Sstevel@tonic-gate
179*12932SRalph.Turner@Sun.COM static void
reinit_blk(rctlblk_t * blk,int local_action)180*12932SRalph.Turner@Sun.COM reinit_blk(rctlblk_t *blk, int local_action)
181*12932SRalph.Turner@Sun.COM {
182*12932SRalph.Turner@Sun.COM rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
183*12932SRalph.Turner@Sun.COM rctlblk_set_value(blk, 0);
184*12932SRalph.Turner@Sun.COM rctlblk_set_local_flags(blk, 0);
185*12932SRalph.Turner@Sun.COM rctlblk_set_local_action(blk, local_action, 0);
186*12932SRalph.Turner@Sun.COM }
187*12932SRalph.Turner@Sun.COM
1880Sstevel@tonic-gate static int
rctl_set(char * ctl_name,char * val,struct ps_prochandle * Pr,int flags)1893684Srd117015 rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr, int flags)
1900Sstevel@tonic-gate {
1910Sstevel@tonic-gate int error = 0;
1920Sstevel@tonic-gate uint_t component = 0;
1930Sstevel@tonic-gate int valuecount = 0;
1940Sstevel@tonic-gate uint_t state = 0;
1950Sstevel@tonic-gate char *component_head;
1960Sstevel@tonic-gate rctlblk_t *blk;
1973684Srd117015 rctlblk_t *ablk;
1983684Srd117015 int project_entity = 0;
1993684Srd117015 int count = 0;
2003684Srd117015 char *tmp;
201*12932SRalph.Turner@Sun.COM int local_act;
202*12932SRalph.Turner@Sun.COM rctlblk_t *rlast;
203*12932SRalph.Turner@Sun.COM rctlblk_t *rnext;
204*12932SRalph.Turner@Sun.COM rctlblk_t *rtmp;
205*12932SRalph.Turner@Sun.COM int teardown_basic = 0;
206*12932SRalph.Turner@Sun.COM int teardown_priv = 0;
2070Sstevel@tonic-gate
2083684Srd117015 /* We cannot modify a zone resource control */
2093684Srd117015 if (strncmp(ctl_name, "zone.", strlen("zone.")) == 0) {
2100Sstevel@tonic-gate return (SETFAILED);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate
2133684Srd117015 remove_spaces(val);
2143684Srd117015
215*12932SRalph.Turner@Sun.COM if (strncmp(ctl_name, "project.", strlen("project.")) == 0) {
2163684Srd117015 project_entity = 1;
217*12932SRalph.Turner@Sun.COM } else if ((strncmp(ctl_name, "process.", strlen("process.")) != 0) &&
218*12932SRalph.Turner@Sun.COM (strncmp(ctl_name, "task.", strlen("task.")) != 0)) {
2193684Srd117015 return (SETFAILED);
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate
222*12932SRalph.Turner@Sun.COM /* Determine how many attributes we'll be setting */
223*12932SRalph.Turner@Sun.COM for (tmp = val; *tmp != '\0'; tmp++) {
224*12932SRalph.Turner@Sun.COM if (*tmp == '(')
225*12932SRalph.Turner@Sun.COM count++;
226*12932SRalph.Turner@Sun.COM }
227*12932SRalph.Turner@Sun.COM /* Allocate sufficient memory for rctl blocks */
228*12932SRalph.Turner@Sun.COM if ((count == 0) || ((ablk =
229*12932SRalph.Turner@Sun.COM (rctlblk_t *)malloc(rctlblk_size() * count)) == NULL)) {
230*12932SRalph.Turner@Sun.COM return (SETFAILED);
231*12932SRalph.Turner@Sun.COM }
232*12932SRalph.Turner@Sun.COM blk = ablk;
233*12932SRalph.Turner@Sun.COM
234*12932SRalph.Turner@Sun.COM /*
235*12932SRalph.Turner@Sun.COM * In order to set the new rctl's local_action, we'll need the
236*12932SRalph.Turner@Sun.COM * current value of global_flags. We obtain global_flags by
237*12932SRalph.Turner@Sun.COM * performing a pr_getrctl().
238*12932SRalph.Turner@Sun.COM *
239*12932SRalph.Turner@Sun.COM * The ctl_name has been verified as valid, so we have no reason
240*12932SRalph.Turner@Sun.COM * to suspect that pr_getrctl() will return an error.
241*12932SRalph.Turner@Sun.COM */
242*12932SRalph.Turner@Sun.COM (void) pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST);
243*12932SRalph.Turner@Sun.COM
244*12932SRalph.Turner@Sun.COM
2450Sstevel@tonic-gate /*
2460Sstevel@tonic-gate * Set initial local action based on global deny properties.
2470Sstevel@tonic-gate */
2480Sstevel@tonic-gate rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
2490Sstevel@tonic-gate rctlblk_set_value(blk, 0);
2500Sstevel@tonic-gate rctlblk_set_local_flags(blk, 0);
2513684Srd117015
2520Sstevel@tonic-gate if (rctlblk_get_global_flags(blk) & RCTL_GLOBAL_DENY_ALWAYS)
253*12932SRalph.Turner@Sun.COM local_act = RCTL_LOCAL_DENY;
2540Sstevel@tonic-gate else
255*12932SRalph.Turner@Sun.COM local_act = RCTL_LOCAL_NOACTION;
2560Sstevel@tonic-gate
257*12932SRalph.Turner@Sun.COM rctlblk_set_local_action(blk, local_act, 0);
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate for (; ; val++) {
260*12932SRalph.Turner@Sun.COM
2610Sstevel@tonic-gate switch (*val) {
2620Sstevel@tonic-gate case '(':
2630Sstevel@tonic-gate if (state & INPAREN) {
2640Sstevel@tonic-gate error = NESTING;
2650Sstevel@tonic-gate break;
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate state |= INPAREN;
2690Sstevel@tonic-gate component_head = (char *)val + 1;
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate break;
2720Sstevel@tonic-gate case ')':
2730Sstevel@tonic-gate if (state & INPAREN) {
2740Sstevel@tonic-gate *val = '\0';
2750Sstevel@tonic-gate if (component < 2) {
2760Sstevel@tonic-gate error = BADSPEC;
2770Sstevel@tonic-gate break;
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate if (build_rctlblk(blk, component,
2800Sstevel@tonic-gate component_head) == -1) {
2810Sstevel@tonic-gate error = BADSPEC;
2820Sstevel@tonic-gate break;
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate state &= ~INPAREN;
2850Sstevel@tonic-gate component = 0;
2860Sstevel@tonic-gate valuecount++;
2873684Srd117015
2883684Srd117015 if (project_entity &&
2893684Srd117015 (rctlblk_get_privilege(blk) ==
2903684Srd117015 RCPRIV_BASIC)) {
2910Sstevel@tonic-gate error = SETFAILED;
292*12932SRalph.Turner@Sun.COM } else {
293*12932SRalph.Turner@Sun.COM if (rctlblk_get_privilege(blk)
294*12932SRalph.Turner@Sun.COM == RCPRIV_BASIC)
295*12932SRalph.Turner@Sun.COM teardown_basic = 1;
296*12932SRalph.Turner@Sun.COM
297*12932SRalph.Turner@Sun.COM if (rctlblk_get_privilege(blk)
298*12932SRalph.Turner@Sun.COM == RCPRIV_PRIVILEGED)
299*12932SRalph.Turner@Sun.COM teardown_priv = 1;
300*12932SRalph.Turner@Sun.COM
301*12932SRalph.Turner@Sun.COM if (valuecount > count) {
302*12932SRalph.Turner@Sun.COM free(ablk);
3033684Srd117015 return (SETFAILED);
304*12932SRalph.Turner@Sun.COM }
3053684Srd117015
306*12932SRalph.Turner@Sun.COM if (valuecount != count) {
3073684Srd117015 blk = RCTLBLK_INC(ablk,
308*12932SRalph.Turner@Sun.COM valuecount);
309*12932SRalph.Turner@Sun.COM /* re-initialize blk */
310*12932SRalph.Turner@Sun.COM reinit_blk(blk,
311*12932SRalph.Turner@Sun.COM local_act);
312*12932SRalph.Turner@Sun.COM }
3133684Srd117015 }
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate } else {
3160Sstevel@tonic-gate error = CLOSEBEFOREOPEN;
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate break;
3190Sstevel@tonic-gate case ',':
3200Sstevel@tonic-gate if (state & INPAREN) {
3210Sstevel@tonic-gate *val = '\0';
3220Sstevel@tonic-gate if (build_rctlblk(blk, component,
3230Sstevel@tonic-gate component_head) == -1)
3240Sstevel@tonic-gate error = BADSPEC;
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate component++;
3270Sstevel@tonic-gate component_head = (char *)val + 1;
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate break;
3310Sstevel@tonic-gate case '\0':
3320Sstevel@tonic-gate if (valuecount == 0)
3330Sstevel@tonic-gate error = BADSPEC;
3340Sstevel@tonic-gate else if (state & INPAREN)
3350Sstevel@tonic-gate error = UNCLOSED;
3360Sstevel@tonic-gate else
3370Sstevel@tonic-gate error = COMPLETE;
3380Sstevel@tonic-gate break;
3390Sstevel@tonic-gate default:
3400Sstevel@tonic-gate if (!(state & INPAREN))
3410Sstevel@tonic-gate error = BADSPEC;
3420Sstevel@tonic-gate break;
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate if (error)
3460Sstevel@tonic-gate break;
3470Sstevel@tonic-gate }
348*12932SRalph.Turner@Sun.COM /* ablk points to array of rctlblk_t */
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate if (valuecount == 0)
3510Sstevel@tonic-gate error = BADSPEC;
3520Sstevel@tonic-gate
353*12932SRalph.Turner@Sun.COM if (error != COMPLETE) {
354*12932SRalph.Turner@Sun.COM free(ablk);
355*12932SRalph.Turner@Sun.COM return (error);
356*12932SRalph.Turner@Sun.COM }
357*12932SRalph.Turner@Sun.COM
358*12932SRalph.Turner@Sun.COM /* teardown rctls if required */
359*12932SRalph.Turner@Sun.COM if (!project_entity) {
360*12932SRalph.Turner@Sun.COM
361*12932SRalph.Turner@Sun.COM if ((rlast = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
362*12932SRalph.Turner@Sun.COM free(ablk);
363*12932SRalph.Turner@Sun.COM return (SETFAILED);
364*12932SRalph.Turner@Sun.COM }
365*12932SRalph.Turner@Sun.COM if ((rnext = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
366*12932SRalph.Turner@Sun.COM free(ablk);
367*12932SRalph.Turner@Sun.COM free(rlast);
368*12932SRalph.Turner@Sun.COM return (SETFAILED);
369*12932SRalph.Turner@Sun.COM }
370*12932SRalph.Turner@Sun.COM
371*12932SRalph.Turner@Sun.COM if (pr_getrctl(Pr, ctl_name, NULL, rnext, RCTL_FIRST) == 0) {
372*12932SRalph.Turner@Sun.COM
373*12932SRalph.Turner@Sun.COM while (1) {
374*12932SRalph.Turner@Sun.COM if ((rctlblk_get_privilege(rnext) ==
375*12932SRalph.Turner@Sun.COM RCPRIV_PRIVILEGED) &&
376*12932SRalph.Turner@Sun.COM (teardown_priv == 1)) {
377*12932SRalph.Turner@Sun.COM (void) pr_setrctl(Pr, ctl_name, NULL,
378*12932SRalph.Turner@Sun.COM rnext, RCTL_DELETE);
379*12932SRalph.Turner@Sun.COM }
380*12932SRalph.Turner@Sun.COM if ((rctlblk_get_privilege(rnext) ==
381*12932SRalph.Turner@Sun.COM RCPRIV_BASIC) && (teardown_basic == 1)) {
382*12932SRalph.Turner@Sun.COM (void) pr_setrctl(Pr, ctl_name, NULL,
383*12932SRalph.Turner@Sun.COM rnext, RCTL_DELETE);
384*12932SRalph.Turner@Sun.COM }
385*12932SRalph.Turner@Sun.COM
386*12932SRalph.Turner@Sun.COM rtmp = rnext;
387*12932SRalph.Turner@Sun.COM rnext = rlast;
388*12932SRalph.Turner@Sun.COM rlast = rtmp;
389*12932SRalph.Turner@Sun.COM if (pr_getrctl(Pr, ctl_name, rlast, rnext,
390*12932SRalph.Turner@Sun.COM RCTL_NEXT) == -1)
391*12932SRalph.Turner@Sun.COM break;
392*12932SRalph.Turner@Sun.COM }
393*12932SRalph.Turner@Sun.COM
394*12932SRalph.Turner@Sun.COM }
395*12932SRalph.Turner@Sun.COM
396*12932SRalph.Turner@Sun.COM free(rnext);
397*12932SRalph.Turner@Sun.COM free(rlast);
398*12932SRalph.Turner@Sun.COM
399*12932SRalph.Turner@Sun.COM }
400*12932SRalph.Turner@Sun.COM
401*12932SRalph.Turner@Sun.COM /* set rctls */
402*12932SRalph.Turner@Sun.COM
403*12932SRalph.Turner@Sun.COM blk = ablk;
404*12932SRalph.Turner@Sun.COM
405*12932SRalph.Turner@Sun.COM if (project_entity) {
406*12932SRalph.Turner@Sun.COM if (pr_setprojrctl(Pr, ctl_name, blk, count, flags) == -1)
407*12932SRalph.Turner@Sun.COM error = SETFAILED;
408*12932SRalph.Turner@Sun.COM } else {
409*12932SRalph.Turner@Sun.COM valuecount = 0;
410*12932SRalph.Turner@Sun.COM while (valuecount < count) {
411*12932SRalph.Turner@Sun.COM if (pr_setrctl(Pr, ctl_name,
412*12932SRalph.Turner@Sun.COM NULL, blk, RCTL_INSERT) == -1) {
413*12932SRalph.Turner@Sun.COM error = SETFAILED;
414*12932SRalph.Turner@Sun.COM break;
415*12932SRalph.Turner@Sun.COM }
416*12932SRalph.Turner@Sun.COM valuecount++;
417*12932SRalph.Turner@Sun.COM blk = RCTLBLK_INC(ablk, valuecount);
418*12932SRalph.Turner@Sun.COM }
419*12932SRalph.Turner@Sun.COM }
420*12932SRalph.Turner@Sun.COM
421*12932SRalph.Turner@Sun.COM
422*12932SRalph.Turner@Sun.COM
423*12932SRalph.Turner@Sun.COM free(ablk);
424*12932SRalph.Turner@Sun.COM
4250Sstevel@tonic-gate if (error != COMPLETE)
4260Sstevel@tonic-gate return (error);
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate return (0);
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate static int
rctlwalkfunc(const char * name,void * data)4320Sstevel@tonic-gate rctlwalkfunc(const char *name, void *data)
4330Sstevel@tonic-gate {
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate if (strcmp(name, (char *)data) == 0)
4360Sstevel@tonic-gate return (-1);
4370Sstevel@tonic-gate else
4380Sstevel@tonic-gate return (0);
4390Sstevel@tonic-gate
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate /*
4430Sstevel@tonic-gate * This routine determines if /dev/pool device is present on the system and
4440Sstevel@tonic-gate * pools are currently enabled. We want to do this directly from libproject
4450Sstevel@tonic-gate * without using libpool's pool_get_status() routine because pools could be
4460Sstevel@tonic-gate * completely removed from the system. Return 1 if pools are enabled, or
4470Sstevel@tonic-gate * 0 otherwise. When used inside local zones, always pretend that pools
4480Sstevel@tonic-gate * are disabled because binding is not allowed and we're already in the
4490Sstevel@tonic-gate * right pool.
4500Sstevel@tonic-gate */
4510Sstevel@tonic-gate static int
pools_enabled(void)4520Sstevel@tonic-gate pools_enabled(void)
4530Sstevel@tonic-gate {
4540Sstevel@tonic-gate pool_status_t status;
4550Sstevel@tonic-gate int fd;
4560Sstevel@tonic-gate
4570Sstevel@tonic-gate if (getzoneid() != GLOBAL_ZONEID)
4580Sstevel@tonic-gate return (0);
4590Sstevel@tonic-gate if ((fd = open("/dev/pool", O_RDONLY)) < 0)
4600Sstevel@tonic-gate return (0);
4610Sstevel@tonic-gate if (ioctl(fd, POOL_STATUSQ, &status) < 0) {
4620Sstevel@tonic-gate (void) close(fd);
4630Sstevel@tonic-gate return (0);
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate (void) close(fd);
4660Sstevel@tonic-gate return (status.ps_io_state);
4670Sstevel@tonic-gate }
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate /*
4700Sstevel@tonic-gate * A pool_name of NULL means to attempt to bind to the default pool.
4710Sstevel@tonic-gate * If the "force" flag is non-zero, the value of "system.bind-default" will be
4720Sstevel@tonic-gate * ignored, and the process will be bound to the default pool if one exists.
4730Sstevel@tonic-gate */
4740Sstevel@tonic-gate static int
bind_to_pool(const char * pool_name,pid_t pid,int force)4750Sstevel@tonic-gate bind_to_pool(const char *pool_name, pid_t pid, int force)
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate pool_value_t *pvals[] = { NULL, NULL };
4780Sstevel@tonic-gate pool_t **pools;
4790Sstevel@tonic-gate uint_t nelem;
4800Sstevel@tonic-gate uchar_t bval;
4810Sstevel@tonic-gate pool_conf_t *conf;
4820Sstevel@tonic-gate const char *nm;
4830Sstevel@tonic-gate int retval;
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate if ((conf = pool_conf_alloc()) == NULL)
4860Sstevel@tonic-gate return (-1);
4870Sstevel@tonic-gate if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) < 0) {
4880Sstevel@tonic-gate /*
4890Sstevel@tonic-gate * Pools configuration file is corrupted; allow logins.
4900Sstevel@tonic-gate */
4910Sstevel@tonic-gate pool_conf_free(conf);
4920Sstevel@tonic-gate return (0);
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate if (pool_name != NULL && pool_get_pool(conf, pool_name) != NULL) {
4950Sstevel@tonic-gate /*
4960Sstevel@tonic-gate * There was a project.pool entry, and the pool it refers to
4970Sstevel@tonic-gate * is a valid (active) pool.
4980Sstevel@tonic-gate */
4990Sstevel@tonic-gate (void) pool_conf_close(conf);
5000Sstevel@tonic-gate pool_conf_free(conf);
5010Sstevel@tonic-gate if (pool_set_binding(pool_name, P_PID, pid) != PO_SUCCESS) {
5020Sstevel@tonic-gate if (pool_error() != POE_SYSTEM)
5030Sstevel@tonic-gate errno = EINVAL;
5040Sstevel@tonic-gate return (-1);
5050Sstevel@tonic-gate }
5060Sstevel@tonic-gate return (0);
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate /*
5100Sstevel@tonic-gate * Bind to the pool with 'pool.default' = 'true' if
5110Sstevel@tonic-gate * 'system.bind-default' = 'true'.
5120Sstevel@tonic-gate */
5130Sstevel@tonic-gate if ((pvals[0] = pool_value_alloc()) == NULL) {
5140Sstevel@tonic-gate pool_conf_close(conf);
5150Sstevel@tonic-gate pool_conf_free(conf);
5160Sstevel@tonic-gate return (-1);
5170Sstevel@tonic-gate }
5180Sstevel@tonic-gate if (!force && pool_get_property(conf, pool_conf_to_elem(conf),
5190Sstevel@tonic-gate "system.bind-default", pvals[0]) != POC_BOOL ||
5200Sstevel@tonic-gate pool_value_get_bool(pvals[0], &bval) != PO_SUCCESS ||
5210Sstevel@tonic-gate bval == PO_FALSE) {
5220Sstevel@tonic-gate pool_value_free(pvals[0]);
5230Sstevel@tonic-gate pool_conf_close(conf);
5240Sstevel@tonic-gate pool_conf_free(conf);
5250Sstevel@tonic-gate errno = pool_name == NULL ? EACCES : ESRCH;
5260Sstevel@tonic-gate return (-1);
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate (void) pool_value_set_name(pvals[0], "pool.default");
5290Sstevel@tonic-gate pool_value_set_bool(pvals[0], PO_TRUE);
5300Sstevel@tonic-gate if ((pools = pool_query_pools(conf, &nelem, pvals)) == NULL) {
5310Sstevel@tonic-gate /*
5320Sstevel@tonic-gate * No default pools exist.
5330Sstevel@tonic-gate */
5340Sstevel@tonic-gate pool_value_free(pvals[0]);
5350Sstevel@tonic-gate pool_conf_close(conf);
5360Sstevel@tonic-gate pool_conf_free(conf);
5370Sstevel@tonic-gate errno = pool_name == NULL ? EACCES : ESRCH;
5380Sstevel@tonic-gate return (-1);
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate if (nelem != 1 ||
5410Sstevel@tonic-gate pool_get_property(conf, pool_to_elem(conf, pools[0]), "pool.name",
5420Sstevel@tonic-gate pvals[0]) != POC_STRING) {
5430Sstevel@tonic-gate /*
5440Sstevel@tonic-gate * Configuration is invalid.
5450Sstevel@tonic-gate */
5460Sstevel@tonic-gate free(pools);
5470Sstevel@tonic-gate pool_value_free(pvals[0]);
5480Sstevel@tonic-gate (void) pool_conf_close(conf);
5490Sstevel@tonic-gate pool_conf_free(conf);
5500Sstevel@tonic-gate return (0);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate free(pools);
5530Sstevel@tonic-gate (void) pool_conf_close(conf);
5540Sstevel@tonic-gate pool_conf_free(conf);
5550Sstevel@tonic-gate (void) pool_value_get_string(pvals[0], &nm);
5560Sstevel@tonic-gate if (pool_set_binding(nm, P_PID, pid) != PO_SUCCESS) {
5570Sstevel@tonic-gate if (pool_error() != POE_SYSTEM)
5580Sstevel@tonic-gate errno = EINVAL;
5590Sstevel@tonic-gate retval = -1;
5600Sstevel@tonic-gate } else {
5610Sstevel@tonic-gate retval = 0;
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate pool_value_free(pvals[0]);
5640Sstevel@tonic-gate return (retval);
5650Sstevel@tonic-gate }
5660Sstevel@tonic-gate
5670Sstevel@tonic-gate /*
5680Sstevel@tonic-gate * Changes the assigned project, task and resource pool of a stopped target
5690Sstevel@tonic-gate * process.
5700Sstevel@tonic-gate *
5710Sstevel@tonic-gate * We may not have access to the project table if our target process is in
5720Sstevel@tonic-gate * getprojbyname()'s execution path. Similarly, we may not be able to get user
5730Sstevel@tonic-gate * information if the target process is in getpwnam()'s execution path. Thus we
5740Sstevel@tonic-gate * give the caller the option of skipping these checks by providing a pointer to
5750Sstevel@tonic-gate * a pre-validated project structure in proj (whose name matches project_name)
5760Sstevel@tonic-gate * and taking responsibility for ensuring that the target process' owner is a
5770Sstevel@tonic-gate * member of the target project.
5780Sstevel@tonic-gate *
5790Sstevel@tonic-gate * Callers of this function should always provide a pre-validated project
5800Sstevel@tonic-gate * structure in proj unless they can be sure that the target process will never
5810Sstevel@tonic-gate * be in setproject_proc()'s execution path.
5820Sstevel@tonic-gate */
5830Sstevel@tonic-gate
5840Sstevel@tonic-gate projid_t
setproject_proc(const char * project_name,const char * user_name,int flags,pid_t pid,struct ps_prochandle * Pr,struct project * proj)5850Sstevel@tonic-gate setproject_proc(const char *project_name, const char *user_name, int flags,
5860Sstevel@tonic-gate pid_t pid, struct ps_prochandle *Pr, struct project *proj)
5870Sstevel@tonic-gate {
5880Sstevel@tonic-gate char pwdbuf[NSS_BUFLEN_PASSWD];
5890Sstevel@tonic-gate char prbuf[PROJECT_BUFSZ];
5900Sstevel@tonic-gate projid_t projid;
5910Sstevel@tonic-gate struct passwd pwd;
5920Sstevel@tonic-gate int i;
5930Sstevel@tonic-gate int unknown = 0;
5940Sstevel@tonic-gate int ret = 0;
5950Sstevel@tonic-gate kva_t *kv_array;
5960Sstevel@tonic-gate struct project local_proj; /* space to store proj if not provided */
5973684Srd117015 const char *pool_name = NULL;
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate if (project_name != NULL) {
6000Sstevel@tonic-gate /*
6010Sstevel@tonic-gate * Sanity checks.
6020Sstevel@tonic-gate */
6030Sstevel@tonic-gate if (strcmp(project_name, "") == 0 ||
6040Sstevel@tonic-gate user_name == NULL) {
6050Sstevel@tonic-gate errno = EINVAL;
6060Sstevel@tonic-gate return (SETPROJ_ERR_TASK);
6070Sstevel@tonic-gate }
6080Sstevel@tonic-gate
6090Sstevel@tonic-gate /*
6100Sstevel@tonic-gate * If proj is NULL, acquire project information to ensure that
6110Sstevel@tonic-gate * project_name is a valid project, and confirm that user_name
6120Sstevel@tonic-gate * exists and is a member of the specified project.
6130Sstevel@tonic-gate */
6140Sstevel@tonic-gate if (proj == NULL) {
6150Sstevel@tonic-gate if ((proj = getprojbyname(project_name, &local_proj,
6160Sstevel@tonic-gate prbuf, PROJECT_BUFSZ)) == NULL) {
6170Sstevel@tonic-gate errno = ESRCH;
6180Sstevel@tonic-gate return (SETPROJ_ERR_TASK);
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate
6210Sstevel@tonic-gate if (getpwnam_r(user_name, &pwd,
6220Sstevel@tonic-gate pwdbuf, NSS_BUFLEN_PASSWD) == NULL) {
6230Sstevel@tonic-gate errno = ESRCH;
6240Sstevel@tonic-gate return (SETPROJ_ERR_TASK);
6250Sstevel@tonic-gate }
6260Sstevel@tonic-gate /*
6270Sstevel@tonic-gate * Root can join any project.
6280Sstevel@tonic-gate */
6290Sstevel@tonic-gate if (pwd.pw_uid != (uid_t)0 &&
6300Sstevel@tonic-gate !inproj(user_name, project_name, prbuf,
6310Sstevel@tonic-gate PROJECT_BUFSZ)) {
6320Sstevel@tonic-gate errno = ESRCH;
6330Sstevel@tonic-gate return (SETPROJ_ERR_TASK);
6340Sstevel@tonic-gate }
6350Sstevel@tonic-gate }
6360Sstevel@tonic-gate projid = proj->pj_projid;
6370Sstevel@tonic-gate } else {
6380Sstevel@tonic-gate projid = getprojid();
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate
6413684Srd117015
6423684Srd117015 if ((kv_array = _str2kva(proj->pj_attr, KV_ASSIGN,
6433684Srd117015 KV_DELIMITER)) != NULL) {
6443684Srd117015 for (i = 0; i < kv_array->length; i++) {
6453684Srd117015 if (strcmp(kv_array->data[i].key,
6463684Srd117015 "project.pool") == 0) {
6473684Srd117015 pool_name = kv_array->data[i].value;
6483684Srd117015 }
6493684Srd117015 if (strcmp(kv_array->data[i].key, "task.final") == 0) {
6503684Srd117015 flags |= TASK_FINAL;
6513684Srd117015 }
6523684Srd117015 }
6533684Srd117015 }
6543684Srd117015
6550Sstevel@tonic-gate /*
6563684Srd117015 * Bind process to a pool only if pools are configured
6570Sstevel@tonic-gate */
6580Sstevel@tonic-gate if (pools_enabled() == 1) {
6590Sstevel@tonic-gate char *old_pool_name;
6600Sstevel@tonic-gate /*
6610Sstevel@tonic-gate * Attempt to bind to pool before calling
6620Sstevel@tonic-gate * settaskid().
6630Sstevel@tonic-gate */
6640Sstevel@tonic-gate old_pool_name = pool_get_binding(pid);
6653684Srd117015 if (bind_to_pool(pool_name, pid, 0) != 0) {
6660Sstevel@tonic-gate if (old_pool_name)
6670Sstevel@tonic-gate free(old_pool_name);
6680Sstevel@tonic-gate _kva_free(kv_array);
6690Sstevel@tonic-gate return (SETPROJ_ERR_POOL);
6700Sstevel@tonic-gate }
6713684Srd117015 if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) {
6720Sstevel@tonic-gate int saved_errno = errno;
6730Sstevel@tonic-gate
6740Sstevel@tonic-gate /*
6750Sstevel@tonic-gate * Undo pool binding.
6760Sstevel@tonic-gate */
6770Sstevel@tonic-gate (void) bind_to_pool(old_pool_name, pid, 1);
6780Sstevel@tonic-gate if (old_pool_name)
6790Sstevel@tonic-gate free(old_pool_name);
6800Sstevel@tonic-gate _kva_free(kv_array);
6810Sstevel@tonic-gate /*
6820Sstevel@tonic-gate * Restore errno
6830Sstevel@tonic-gate */
6840Sstevel@tonic-gate errno = saved_errno;
6850Sstevel@tonic-gate return (SETPROJ_ERR_TASK);
6860Sstevel@tonic-gate }
6870Sstevel@tonic-gate if (old_pool_name)
6880Sstevel@tonic-gate free(old_pool_name);
6890Sstevel@tonic-gate } else {
6900Sstevel@tonic-gate /*
6910Sstevel@tonic-gate * Pools are not configured, so simply create new task.
6920Sstevel@tonic-gate */
6933684Srd117015 if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) {
6943684Srd117015 _kva_free(kv_array);
6950Sstevel@tonic-gate return (SETPROJ_ERR_TASK);
6963684Srd117015 }
6970Sstevel@tonic-gate }
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate if (project_name == NULL) {
7000Sstevel@tonic-gate /*
7010Sstevel@tonic-gate * In the case that we are starting a new task in the
7020Sstevel@tonic-gate * current project, we are finished, since the current
7030Sstevel@tonic-gate * resource controls will still apply. (Implicit behaviour:
7040Sstevel@tonic-gate * a project must be entirely logged out before name
7050Sstevel@tonic-gate * service changes will take effect.)
7060Sstevel@tonic-gate */
7070Sstevel@tonic-gate _kva_free(kv_array);
7080Sstevel@tonic-gate return (projid);
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate
7110Sstevel@tonic-gate if (kv_array == NULL)
7120Sstevel@tonic-gate return (0);
7130Sstevel@tonic-gate
7140Sstevel@tonic-gate for (i = 0; i < kv_array->length; i++) {
7150Sstevel@tonic-gate /*
7160Sstevel@tonic-gate * Providing a special, i.e. a non-resource control, key? Then
7170Sstevel@tonic-gate * parse that key here and end with "continue;".
7180Sstevel@tonic-gate */
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate /*
7210Sstevel@tonic-gate * For generic bindings, the kernel performs the binding, as
7220Sstevel@tonic-gate * these are resource controls advertised by kernel subsystems.
7230Sstevel@tonic-gate */
7240Sstevel@tonic-gate
7250Sstevel@tonic-gate /*
7260Sstevel@tonic-gate * Check for known attribute name.
7270Sstevel@tonic-gate */
7280Sstevel@tonic-gate errno = 0;
7290Sstevel@tonic-gate if (rctl_walk(rctlwalkfunc, (void *)kv_array->data[i].key)
7300Sstevel@tonic-gate == 0)
7310Sstevel@tonic-gate continue;
7320Sstevel@tonic-gate if (errno) {
7330Sstevel@tonic-gate _kva_free(kv_array);
7340Sstevel@tonic-gate return (SETPROJ_ERR_TASK);
7350Sstevel@tonic-gate }
7360Sstevel@tonic-gate
7370Sstevel@tonic-gate ret = rctl_set(kv_array->data[i].key,
7383684Srd117015 kv_array->data[i].value, Pr, flags & TASK_PROJ_MASK);
7390Sstevel@tonic-gate
7400Sstevel@tonic-gate if (ret && unknown == 0) {
7410Sstevel@tonic-gate /*
7420Sstevel@tonic-gate * We only report the first failure.
7430Sstevel@tonic-gate */
7440Sstevel@tonic-gate unknown = i + 1;
7450Sstevel@tonic-gate }
7460Sstevel@tonic-gate
7470Sstevel@tonic-gate if (ret && ret != SETFAILED) {
7480Sstevel@tonic-gate /*
7490Sstevel@tonic-gate * We abort if we couldn't set a component, but if
7500Sstevel@tonic-gate * it's merely that the system didn't recognize it, we
7510Sstevel@tonic-gate * continue, as this could be a third party attribute.
7520Sstevel@tonic-gate */
7530Sstevel@tonic-gate break;
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate }
7560Sstevel@tonic-gate _kva_free(kv_array);
7570Sstevel@tonic-gate
7580Sstevel@tonic-gate return (unknown);
7590Sstevel@tonic-gate }
7600Sstevel@tonic-gate
7610Sstevel@tonic-gate projid_t
setproject(const char * project_name,const char * user_name,int flags)7620Sstevel@tonic-gate setproject(const char *project_name, const char *user_name, int flags)
7630Sstevel@tonic-gate {
7640Sstevel@tonic-gate return (setproject_proc(project_name, user_name, flags, P_MYID, NULL,
7650Sstevel@tonic-gate NULL));
7660Sstevel@tonic-gate }
7670Sstevel@tonic-gate
7680Sstevel@tonic-gate
7690Sstevel@tonic-gate priv_set_t *
setproject_initpriv(void)7700Sstevel@tonic-gate setproject_initpriv(void)
7710Sstevel@tonic-gate {
7720Sstevel@tonic-gate static priv_t taskpriv = PRIV_PROC_TASKID;
7730Sstevel@tonic-gate static priv_t rctlpriv = PRIV_SYS_RESOURCE;
7740Sstevel@tonic-gate static priv_t poolpriv = PRIV_SYS_RES_CONFIG;
7750Sstevel@tonic-gate static priv_t schedpriv = PRIV_PROC_PRIOCNTL;
7760Sstevel@tonic-gate int res;
7770Sstevel@tonic-gate
7780Sstevel@tonic-gate priv_set_t *nset;
7790Sstevel@tonic-gate
7800Sstevel@tonic-gate if (getzoneid() == GLOBAL_ZONEID) {
7810Sstevel@tonic-gate res = __init_suid_priv(0, taskpriv, rctlpriv, poolpriv,
7820Sstevel@tonic-gate schedpriv, (char *)NULL);
7830Sstevel@tonic-gate } else {
7840Sstevel@tonic-gate res = __init_suid_priv(0, taskpriv, rctlpriv, (char *)NULL);
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate
7870Sstevel@tonic-gate if (res != 0)
7880Sstevel@tonic-gate return (NULL);
7890Sstevel@tonic-gate
7900Sstevel@tonic-gate nset = priv_allocset();
7910Sstevel@tonic-gate if (nset != NULL) {
7920Sstevel@tonic-gate priv_emptyset(nset);
7930Sstevel@tonic-gate (void) priv_addset(nset, taskpriv);
7940Sstevel@tonic-gate (void) priv_addset(nset, rctlpriv);
7950Sstevel@tonic-gate /*
7960Sstevel@tonic-gate * Only need these if we need to change pools, which can
7970Sstevel@tonic-gate * only happen if the target is in the global zone. Rather
7980Sstevel@tonic-gate * than checking the target's zone just check our own
7990Sstevel@tonic-gate * (since if we're in a non-global zone we won't be able
8000Sstevel@tonic-gate * to control processes in other zones).
8010Sstevel@tonic-gate */
8020Sstevel@tonic-gate if (getzoneid() == GLOBAL_ZONEID) {
8030Sstevel@tonic-gate (void) priv_addset(nset, poolpriv);
8040Sstevel@tonic-gate (void) priv_addset(nset, schedpriv);
8050Sstevel@tonic-gate }
8060Sstevel@tonic-gate }
8070Sstevel@tonic-gate return (nset);
8080Sstevel@tonic-gate }
809