xref: /titanic_50/usr/src/lib/libproject/common/setproject.c (revision 3268e8899028a80444b82ffd371de903ba1122d5)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50209230bSgjelinek  * Common Development and Distribution License (the "License").
60209230bSgjelinek  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*3268e889SRalph Turner - Sun UK - Contractor  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/task.h>
277c478bd9Sstevel@tonic-gate #include <sys/types.h>
287c478bd9Sstevel@tonic-gate #include <unistd.h>
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <ctype.h>
317c478bd9Sstevel@tonic-gate #include <project.h>
327c478bd9Sstevel@tonic-gate #include <rctl.h>
337c478bd9Sstevel@tonic-gate #include <secdb.h>
347c478bd9Sstevel@tonic-gate #include <signal.h>
357c478bd9Sstevel@tonic-gate #include <stdlib.h>
367c478bd9Sstevel@tonic-gate #include <string.h>
37532877c4Srd117015 #include <strings.h>
387c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
397c478bd9Sstevel@tonic-gate #include <pwd.h>
407c478bd9Sstevel@tonic-gate #include <pool.h>
417c478bd9Sstevel@tonic-gate #include <libproc.h>
427c478bd9Sstevel@tonic-gate #include <priv.h>
437c478bd9Sstevel@tonic-gate #include <priv_utils.h>
447c478bd9Sstevel@tonic-gate #include <zone.h>
457c478bd9Sstevel@tonic-gate #include <sys/pool.h>
467c478bd9Sstevel@tonic-gate #include <sys/pool_impl.h>
47532877c4Srd117015 #include <sys/rctl_impl.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate static void
507c478bd9Sstevel@tonic-gate xstrtolower(char *s)
517c478bd9Sstevel@tonic-gate {
527c478bd9Sstevel@tonic-gate 	for (; *s != '\0'; s++)
537c478bd9Sstevel@tonic-gate 		*s = tolower(*s);
547c478bd9Sstevel@tonic-gate }
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate static void
577c478bd9Sstevel@tonic-gate remove_spaces(char *s)
587c478bd9Sstevel@tonic-gate {
597c478bd9Sstevel@tonic-gate 	char *current;
607c478bd9Sstevel@tonic-gate 	char *next;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	current = next = s;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	while (*next != '\0') {
657c478bd9Sstevel@tonic-gate 		while (isspace(*next))
667c478bd9Sstevel@tonic-gate 			next++;
677c478bd9Sstevel@tonic-gate 		*current++ = *next++;
687c478bd9Sstevel@tonic-gate 	}
697c478bd9Sstevel@tonic-gate 	*current = '\0';
707c478bd9Sstevel@tonic-gate }
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate int
737c478bd9Sstevel@tonic-gate build_rctlblk(rctlblk_t *blk, int comp_num, char *component)
747c478bd9Sstevel@tonic-gate {
757c478bd9Sstevel@tonic-gate 	char *signam;
767c478bd9Sstevel@tonic-gate 	int sig = 0;
777c478bd9Sstevel@tonic-gate 	uint_t act = rctlblk_get_local_action(blk, &sig);
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	if (comp_num == 0) {
807c478bd9Sstevel@tonic-gate 		/*
817c478bd9Sstevel@tonic-gate 		 * Setting privilege level for resource control block.
827c478bd9Sstevel@tonic-gate 		 */
837c478bd9Sstevel@tonic-gate 		xstrtolower(component);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 		if (strcmp("basic", component) == 0) {
867c478bd9Sstevel@tonic-gate 			rctlblk_set_privilege(blk, RCPRIV_BASIC);
877c478bd9Sstevel@tonic-gate 			return (0);
887c478bd9Sstevel@tonic-gate 		}
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 		if (strcmp("priv", component) == 0 ||
917c478bd9Sstevel@tonic-gate 		    strcmp("privileged", component) == 0) {
927c478bd9Sstevel@tonic-gate 			rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
937c478bd9Sstevel@tonic-gate 			return (0);
947c478bd9Sstevel@tonic-gate 		}
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 		return (-1);
977c478bd9Sstevel@tonic-gate 	}
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	if (comp_num == 1) {
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 		/*
1027c478bd9Sstevel@tonic-gate 		 * Setting value for resource control block.
1037c478bd9Sstevel@tonic-gate 		 */
1047c478bd9Sstevel@tonic-gate 		unsigned long long val;
1057c478bd9Sstevel@tonic-gate 		char *t;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 		/* Negative numbers are not allowed */
1087c478bd9Sstevel@tonic-gate 		if (strchr(component, '-') != NULL)
1097c478bd9Sstevel@tonic-gate 			return (-1);
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 		errno = 0;
1127c478bd9Sstevel@tonic-gate 		val = strtoull(component, &t, 10);
1137c478bd9Sstevel@tonic-gate 		if (errno != 0 || t == component || *t != '\0')
1147c478bd9Sstevel@tonic-gate 			return (-1);
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 		rctlblk_set_value(blk, (rctl_qty_t)val);
1177c478bd9Sstevel@tonic-gate 		return (0);
1187c478bd9Sstevel@tonic-gate 	}
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	/*
1217c478bd9Sstevel@tonic-gate 	 * Setting one or more actions on this resource control block.
1227c478bd9Sstevel@tonic-gate 	 */
1237c478bd9Sstevel@tonic-gate 	if (comp_num >= 2) {
1247c478bd9Sstevel@tonic-gate 		if (strcmp("none", component) == 0) {
1257c478bd9Sstevel@tonic-gate 			rctlblk_set_local_action(blk, 0, 0);
1267c478bd9Sstevel@tonic-gate 			return (0);
1277c478bd9Sstevel@tonic-gate 		}
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 		if (strcmp("deny", component) == 0) {
1307c478bd9Sstevel@tonic-gate 			act |= RCTL_LOCAL_DENY;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 			rctlblk_set_local_action(blk, act, sig);
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 			return (0);
1357c478bd9Sstevel@tonic-gate 		}
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 		/*
1387c478bd9Sstevel@tonic-gate 		 * The last, and trickiest, form of action is the signal
1397c478bd9Sstevel@tonic-gate 		 * specification.
1407c478bd9Sstevel@tonic-gate 		 */
1417c478bd9Sstevel@tonic-gate 		if ((signam = strchr(component, '=')) == NULL)
1427c478bd9Sstevel@tonic-gate 			return (-1);
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 		*signam++ = '\0';
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 		if (strcmp("sig", component) == 0 ||
1477c478bd9Sstevel@tonic-gate 		    strcmp("signal", component) == 0) {
1487c478bd9Sstevel@tonic-gate 			if (strncmp("SIG", signam, 3) == 0)
1497c478bd9Sstevel@tonic-gate 				signam += 3;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 			if (str2sig(signam, &sig) == -1)
1527c478bd9Sstevel@tonic-gate 				return (-1);
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 			act |= RCTL_LOCAL_SIGNAL;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 			rctlblk_set_local_action(blk, act, sig);
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 			return (0);
1597c478bd9Sstevel@tonic-gate 		}
1607c478bd9Sstevel@tonic-gate 	}
1617c478bd9Sstevel@tonic-gate 	return (-1);
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate /*
1657c478bd9Sstevel@tonic-gate  * States:
1667c478bd9Sstevel@tonic-gate  */
1677c478bd9Sstevel@tonic-gate #define	INPAREN		0x1
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate  * Errors:
1717c478bd9Sstevel@tonic-gate  */
1727c478bd9Sstevel@tonic-gate #define	SETFAILED	(-1)
1737c478bd9Sstevel@tonic-gate #define	COMPLETE	1
1747c478bd9Sstevel@tonic-gate #define	NESTING		2
1757c478bd9Sstevel@tonic-gate #define	UNCLOSED	3
1767c478bd9Sstevel@tonic-gate #define	CLOSEBEFOREOPEN	4
1777c478bd9Sstevel@tonic-gate #define	BADSPEC		5
1787c478bd9Sstevel@tonic-gate 
179*3268e889SRalph Turner - Sun UK - Contractor static void
180*3268e889SRalph Turner - Sun UK - Contractor reinit_blk(rctlblk_t *blk, int local_action)
181*3268e889SRalph Turner - Sun UK - Contractor {
182*3268e889SRalph Turner - Sun UK - Contractor 	rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
183*3268e889SRalph Turner - Sun UK - Contractor 	rctlblk_set_value(blk, 0);
184*3268e889SRalph Turner - Sun UK - Contractor 	rctlblk_set_local_flags(blk, 0);
185*3268e889SRalph Turner - Sun UK - Contractor 	rctlblk_set_local_action(blk, local_action, 0);
186*3268e889SRalph Turner - Sun UK - Contractor }
187*3268e889SRalph Turner - Sun UK - Contractor 
1887c478bd9Sstevel@tonic-gate static int
189532877c4Srd117015 rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr, int flags)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate 	int error = 0;
1927c478bd9Sstevel@tonic-gate 	uint_t component = 0;
1937c478bd9Sstevel@tonic-gate 	int valuecount = 0;
1947c478bd9Sstevel@tonic-gate 	uint_t state = 0;
1957c478bd9Sstevel@tonic-gate 	char *component_head;
1967c478bd9Sstevel@tonic-gate 	rctlblk_t *blk;
197532877c4Srd117015 	rctlblk_t *ablk;
198532877c4Srd117015 	int project_entity = 0;
199532877c4Srd117015 	int count = 0;
200532877c4Srd117015 	char *tmp;
201*3268e889SRalph Turner - Sun UK - Contractor 	int local_act;
202*3268e889SRalph Turner - Sun UK - Contractor 	rctlblk_t *rlast;
203*3268e889SRalph Turner - Sun UK - Contractor 	rctlblk_t *rnext;
204*3268e889SRalph Turner - Sun UK - Contractor 	rctlblk_t *rtmp;
205*3268e889SRalph Turner - Sun UK - Contractor 	int teardown_basic = 0;
206*3268e889SRalph Turner - Sun UK - Contractor 	int teardown_priv = 0;
2077c478bd9Sstevel@tonic-gate 
208532877c4Srd117015 	/* We cannot modify a zone resource control */
209532877c4Srd117015 	if (strncmp(ctl_name, "zone.", strlen("zone.")) == 0) {
2107c478bd9Sstevel@tonic-gate 		return (SETFAILED);
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate 
213532877c4Srd117015 	remove_spaces(val);
214532877c4Srd117015 
215*3268e889SRalph Turner - Sun UK - Contractor 	if (strncmp(ctl_name, "project.", strlen("project.")) == 0) {
216*3268e889SRalph Turner - Sun UK - Contractor 		project_entity = 1;
217*3268e889SRalph Turner - Sun UK - Contractor 	} else if ((strncmp(ctl_name, "process.", strlen("process.")) != 0) &&
218*3268e889SRalph Turner - Sun UK - Contractor 	    (strncmp(ctl_name, "task.", strlen("task.")) != 0)) {
219532877c4Srd117015 		return (SETFAILED);
220532877c4Srd117015 	}
221532877c4Srd117015 
222532877c4Srd117015 	/* Determine how many attributes we'll be setting */
223532877c4Srd117015 	for (tmp = val; *tmp != '\0'; tmp++) {
224532877c4Srd117015 		if (*tmp == '(')
225532877c4Srd117015 			count++;
226532877c4Srd117015 	}
227532877c4Srd117015 	/* Allocate sufficient memory for rctl blocks */
228532877c4Srd117015 	if ((count == 0) || ((ablk =
229532877c4Srd117015 	    (rctlblk_t *)malloc(rctlblk_size() * count)) == NULL)) {
230532877c4Srd117015 		return (SETFAILED);
231532877c4Srd117015 	}
232532877c4Srd117015 	blk = ablk;
233532877c4Srd117015 
234532877c4Srd117015 	/*
235532877c4Srd117015 	 * In order to set the new rctl's local_action, we'll need the
236532877c4Srd117015 	 * current value of global_flags.  We obtain global_flags by
237532877c4Srd117015 	 * performing a pr_getrctl().
238532877c4Srd117015 	 *
239532877c4Srd117015 	 * The ctl_name has been verified as valid, so we have no reason
240532877c4Srd117015 	 * to suspect that pr_getrctl() will return an error.
241532877c4Srd117015 	 */
242532877c4Srd117015 	(void) pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST);
243532877c4Srd117015 
244532877c4Srd117015 
2457c478bd9Sstevel@tonic-gate 	/*
2467c478bd9Sstevel@tonic-gate 	 * Set initial local action based on global deny properties.
2477c478bd9Sstevel@tonic-gate 	 */
2487c478bd9Sstevel@tonic-gate 	rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
2497c478bd9Sstevel@tonic-gate 	rctlblk_set_value(blk, 0);
2507c478bd9Sstevel@tonic-gate 	rctlblk_set_local_flags(blk, 0);
2517c478bd9Sstevel@tonic-gate 
252532877c4Srd117015 	if (rctlblk_get_global_flags(blk) & RCTL_GLOBAL_DENY_ALWAYS)
253*3268e889SRalph Turner - Sun UK - Contractor 		local_act = RCTL_LOCAL_DENY;
254532877c4Srd117015 	else
255*3268e889SRalph Turner - Sun UK - Contractor 		local_act = RCTL_LOCAL_NOACTION;
256532877c4Srd117015 
257*3268e889SRalph Turner - Sun UK - Contractor 	rctlblk_set_local_action(blk, local_act, 0);
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	for (; ; val++) {
260*3268e889SRalph Turner - Sun UK - Contractor 
2617c478bd9Sstevel@tonic-gate 		switch (*val) {
2627c478bd9Sstevel@tonic-gate 			case '(':
2637c478bd9Sstevel@tonic-gate 				if (state & INPAREN) {
2647c478bd9Sstevel@tonic-gate 					error = NESTING;
2657c478bd9Sstevel@tonic-gate 					break;
2667c478bd9Sstevel@tonic-gate 				}
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 				state |= INPAREN;
2697c478bd9Sstevel@tonic-gate 				component_head = (char *)val + 1;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 				break;
2727c478bd9Sstevel@tonic-gate 			case ')':
2737c478bd9Sstevel@tonic-gate 				if (state & INPAREN) {
2747c478bd9Sstevel@tonic-gate 					*val = '\0';
2757c478bd9Sstevel@tonic-gate 					if (component < 2) {
2767c478bd9Sstevel@tonic-gate 						error = BADSPEC;
2777c478bd9Sstevel@tonic-gate 						break;
2787c478bd9Sstevel@tonic-gate 					}
2797c478bd9Sstevel@tonic-gate 					if (build_rctlblk(blk, component,
2807c478bd9Sstevel@tonic-gate 					    component_head) == -1) {
2817c478bd9Sstevel@tonic-gate 						error = BADSPEC;
2827c478bd9Sstevel@tonic-gate 						break;
2837c478bd9Sstevel@tonic-gate 					}
2847c478bd9Sstevel@tonic-gate 					state &= ~INPAREN;
2857c478bd9Sstevel@tonic-gate 					component = 0;
2867c478bd9Sstevel@tonic-gate 					valuecount++;
287532877c4Srd117015 
288532877c4Srd117015 					if (project_entity &&
289532877c4Srd117015 					    (rctlblk_get_privilege(blk) ==
290532877c4Srd117015 					    RCPRIV_BASIC)) {
2917c478bd9Sstevel@tonic-gate 						error = SETFAILED;
292*3268e889SRalph Turner - Sun UK - Contractor 					} else {
293*3268e889SRalph Turner - Sun UK - Contractor 						if (rctlblk_get_privilege(blk)
294*3268e889SRalph Turner - Sun UK - Contractor 						    == RCPRIV_BASIC)
295*3268e889SRalph Turner - Sun UK - Contractor 							teardown_basic = 1;
296532877c4Srd117015 
297*3268e889SRalph Turner - Sun UK - Contractor 						if (rctlblk_get_privilege(blk)
298*3268e889SRalph Turner - Sun UK - Contractor 						    == RCPRIV_PRIVILEGED)
299*3268e889SRalph Turner - Sun UK - Contractor 							teardown_priv = 1;
300*3268e889SRalph Turner - Sun UK - Contractor 
301*3268e889SRalph Turner - Sun UK - Contractor 						if (valuecount > count) {
302*3268e889SRalph Turner - Sun UK - Contractor 							free(ablk);
303*3268e889SRalph Turner - Sun UK - Contractor 							return (SETFAILED);
304*3268e889SRalph Turner - Sun UK - Contractor 						}
305*3268e889SRalph Turner - Sun UK - Contractor 
306*3268e889SRalph Turner - Sun UK - Contractor 						if (valuecount != count) {
307532877c4Srd117015 							blk = RCTLBLK_INC(ablk,
308532877c4Srd117015 							    valuecount);
309*3268e889SRalph Turner - Sun UK - Contractor 							/* re-initialize blk */
310*3268e889SRalph Turner - Sun UK - Contractor 							reinit_blk(blk,
311*3268e889SRalph Turner - Sun UK - Contractor 							    local_act);
312*3268e889SRalph Turner - Sun UK - Contractor 						}
313532877c4Srd117015 					}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 				} else {
3167c478bd9Sstevel@tonic-gate 					error = CLOSEBEFOREOPEN;
3177c478bd9Sstevel@tonic-gate 				}
3187c478bd9Sstevel@tonic-gate 				break;
3197c478bd9Sstevel@tonic-gate 			case ',':
3207c478bd9Sstevel@tonic-gate 				if (state & INPAREN) {
3217c478bd9Sstevel@tonic-gate 					*val = '\0';
3227c478bd9Sstevel@tonic-gate 					if (build_rctlblk(blk, component,
3237c478bd9Sstevel@tonic-gate 					    component_head) == -1)
3247c478bd9Sstevel@tonic-gate 						error = BADSPEC;
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 					component++;
3277c478bd9Sstevel@tonic-gate 					component_head = (char *)val + 1;
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 				}
3307c478bd9Sstevel@tonic-gate 				break;
3317c478bd9Sstevel@tonic-gate 			case '\0':
3327c478bd9Sstevel@tonic-gate 				if (valuecount == 0)
3337c478bd9Sstevel@tonic-gate 					error = BADSPEC;
3347c478bd9Sstevel@tonic-gate 				else if (state & INPAREN)
3357c478bd9Sstevel@tonic-gate 					error = UNCLOSED;
3367c478bd9Sstevel@tonic-gate 				else
3377c478bd9Sstevel@tonic-gate 					error = COMPLETE;
3387c478bd9Sstevel@tonic-gate 				break;
3397c478bd9Sstevel@tonic-gate 			default:
3407c478bd9Sstevel@tonic-gate 				if (!(state & INPAREN))
3417c478bd9Sstevel@tonic-gate 					error = BADSPEC;
3427c478bd9Sstevel@tonic-gate 				break;
3437c478bd9Sstevel@tonic-gate 		}
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 		if (error)
3467c478bd9Sstevel@tonic-gate 			break;
3477c478bd9Sstevel@tonic-gate 	}
348*3268e889SRalph Turner - Sun UK - Contractor 	/* ablk points to array of rctlblk_t */
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	if (valuecount == 0)
3517c478bd9Sstevel@tonic-gate 		error = BADSPEC;
3527c478bd9Sstevel@tonic-gate 
353*3268e889SRalph Turner - Sun UK - Contractor 	if (error != COMPLETE) {
354*3268e889SRalph Turner - Sun UK - Contractor 		free(ablk);
355*3268e889SRalph Turner - Sun UK - Contractor 		return (error);
356*3268e889SRalph Turner - Sun UK - Contractor 	}
357*3268e889SRalph Turner - Sun UK - Contractor 
358*3268e889SRalph Turner - Sun UK - Contractor 	/* teardown rctls if required */
359*3268e889SRalph Turner - Sun UK - Contractor 	if (!project_entity) {
360*3268e889SRalph Turner - Sun UK - Contractor 
361*3268e889SRalph Turner - Sun UK - Contractor 		if ((rlast = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
362*3268e889SRalph Turner - Sun UK - Contractor 			free(ablk);
363*3268e889SRalph Turner - Sun UK - Contractor 			return (SETFAILED);
364*3268e889SRalph Turner - Sun UK - Contractor 		}
365*3268e889SRalph Turner - Sun UK - Contractor 		if ((rnext = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
366*3268e889SRalph Turner - Sun UK - Contractor 			free(ablk);
367*3268e889SRalph Turner - Sun UK - Contractor 			free(rlast);
368*3268e889SRalph Turner - Sun UK - Contractor 			return (SETFAILED);
369*3268e889SRalph Turner - Sun UK - Contractor 		}
370*3268e889SRalph Turner - Sun UK - Contractor 
371*3268e889SRalph Turner - Sun UK - Contractor 		if (pr_getrctl(Pr, ctl_name, NULL, rnext, RCTL_FIRST) == 0) {
372*3268e889SRalph Turner - Sun UK - Contractor 
373*3268e889SRalph Turner - Sun UK - Contractor 			while (1) {
374*3268e889SRalph Turner - Sun UK - Contractor 				if ((rctlblk_get_privilege(rnext) ==
375*3268e889SRalph Turner - Sun UK - Contractor 				    RCPRIV_PRIVILEGED) &&
376*3268e889SRalph Turner - Sun UK - Contractor 				    (teardown_priv == 1)) {
377*3268e889SRalph Turner - Sun UK - Contractor 					(void) pr_setrctl(Pr, ctl_name, NULL,
378*3268e889SRalph Turner - Sun UK - Contractor 					    rnext, RCTL_DELETE);
379*3268e889SRalph Turner - Sun UK - Contractor 				}
380*3268e889SRalph Turner - Sun UK - Contractor 				if ((rctlblk_get_privilege(rnext) ==
381*3268e889SRalph Turner - Sun UK - Contractor 				    RCPRIV_BASIC) && (teardown_basic == 1)) {
382*3268e889SRalph Turner - Sun UK - Contractor 					(void) pr_setrctl(Pr, ctl_name, NULL,
383*3268e889SRalph Turner - Sun UK - Contractor 					    rnext, RCTL_DELETE);
384*3268e889SRalph Turner - Sun UK - Contractor 				}
385*3268e889SRalph Turner - Sun UK - Contractor 
386*3268e889SRalph Turner - Sun UK - Contractor 				rtmp = rnext;
387*3268e889SRalph Turner - Sun UK - Contractor 				rnext = rlast;
388*3268e889SRalph Turner - Sun UK - Contractor 				rlast = rtmp;
389*3268e889SRalph Turner - Sun UK - Contractor 				if (pr_getrctl(Pr, ctl_name, rlast, rnext,
390*3268e889SRalph Turner - Sun UK - Contractor 				    RCTL_NEXT) == -1)
391*3268e889SRalph Turner - Sun UK - Contractor 					break;
392*3268e889SRalph Turner - Sun UK - Contractor 			}
393*3268e889SRalph Turner - Sun UK - Contractor 
394*3268e889SRalph Turner - Sun UK - Contractor 		}
395*3268e889SRalph Turner - Sun UK - Contractor 
396*3268e889SRalph Turner - Sun UK - Contractor 		free(rnext);
397*3268e889SRalph Turner - Sun UK - Contractor 		free(rlast);
398*3268e889SRalph Turner - Sun UK - Contractor 
399*3268e889SRalph Turner - Sun UK - Contractor 	}
400*3268e889SRalph Turner - Sun UK - Contractor 
401*3268e889SRalph Turner - Sun UK - Contractor 	/* set rctls */
402*3268e889SRalph Turner - Sun UK - Contractor 
403*3268e889SRalph Turner - Sun UK - Contractor 	blk = ablk;
404*3268e889SRalph Turner - Sun UK - Contractor 
405*3268e889SRalph Turner - Sun UK - Contractor 	if (project_entity) {
406*3268e889SRalph Turner - Sun UK - Contractor 		if (pr_setprojrctl(Pr, ctl_name, blk, count, flags) == -1)
407*3268e889SRalph Turner - Sun UK - Contractor 			error = SETFAILED;
408*3268e889SRalph Turner - Sun UK - Contractor 	} else {
409*3268e889SRalph Turner - Sun UK - Contractor 		valuecount = 0;
410*3268e889SRalph Turner - Sun UK - Contractor 		while (valuecount < count) {
411*3268e889SRalph Turner - Sun UK - Contractor 			if (pr_setrctl(Pr, ctl_name,
412*3268e889SRalph Turner - Sun UK - Contractor 			    NULL, blk, RCTL_INSERT) == -1) {
413*3268e889SRalph Turner - Sun UK - Contractor 				error = SETFAILED;
414*3268e889SRalph Turner - Sun UK - Contractor 				break;
415*3268e889SRalph Turner - Sun UK - Contractor 				}
416*3268e889SRalph Turner - Sun UK - Contractor 			valuecount++;
417*3268e889SRalph Turner - Sun UK - Contractor 			blk = RCTLBLK_INC(ablk, valuecount);
418*3268e889SRalph Turner - Sun UK - Contractor 		}
419*3268e889SRalph Turner - Sun UK - Contractor 	}
420*3268e889SRalph Turner - Sun UK - Contractor 
421*3268e889SRalph Turner - Sun UK - Contractor 
422*3268e889SRalph Turner - Sun UK - Contractor 
423*3268e889SRalph Turner - Sun UK - Contractor 	free(ablk);
424*3268e889SRalph Turner - Sun UK - Contractor 
4257c478bd9Sstevel@tonic-gate 	if (error != COMPLETE)
4267c478bd9Sstevel@tonic-gate 		return (error);
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	return (0);
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate static int
4327c478bd9Sstevel@tonic-gate rctlwalkfunc(const char *name, void *data)
4337c478bd9Sstevel@tonic-gate {
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	if (strcmp(name, (char *)data) == 0)
4367c478bd9Sstevel@tonic-gate 		return (-1);
4377c478bd9Sstevel@tonic-gate 	else
4387c478bd9Sstevel@tonic-gate 		return (0);
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate /*
4437c478bd9Sstevel@tonic-gate  * This routine determines if /dev/pool device is present on the system and
4447c478bd9Sstevel@tonic-gate  * pools are currently enabled.  We want to do this directly from libproject
4457c478bd9Sstevel@tonic-gate  * without using libpool's pool_get_status() routine because pools could be
4467c478bd9Sstevel@tonic-gate  * completely removed from the system.  Return 1 if pools are enabled, or
4477c478bd9Sstevel@tonic-gate  * 0 otherwise.  When used inside local zones, always pretend that pools
4487c478bd9Sstevel@tonic-gate  * are disabled because binding is not allowed and we're already in the
4497c478bd9Sstevel@tonic-gate  * right pool.
4507c478bd9Sstevel@tonic-gate  */
4517c478bd9Sstevel@tonic-gate static int
4527c478bd9Sstevel@tonic-gate pools_enabled(void)
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate 	pool_status_t status;
4557c478bd9Sstevel@tonic-gate 	int fd;
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	if (getzoneid() != GLOBAL_ZONEID)
4587c478bd9Sstevel@tonic-gate 		return (0);
4597c478bd9Sstevel@tonic-gate 	if ((fd = open("/dev/pool", O_RDONLY)) < 0)
4607c478bd9Sstevel@tonic-gate 		return (0);
4617c478bd9Sstevel@tonic-gate 	if (ioctl(fd, POOL_STATUSQ, &status) < 0) {
4627c478bd9Sstevel@tonic-gate 		(void) close(fd);
4637c478bd9Sstevel@tonic-gate 		return (0);
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 	(void) close(fd);
4667c478bd9Sstevel@tonic-gate 	return (status.ps_io_state);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate /*
4707c478bd9Sstevel@tonic-gate  * A pool_name of NULL means to attempt to bind to the default pool.
4717c478bd9Sstevel@tonic-gate  * If the "force" flag is non-zero, the value of "system.bind-default" will be
4727c478bd9Sstevel@tonic-gate  * ignored, and the process will be bound to the default pool if one exists.
4737c478bd9Sstevel@tonic-gate  */
4747c478bd9Sstevel@tonic-gate static int
4757c478bd9Sstevel@tonic-gate bind_to_pool(const char *pool_name, pid_t pid, int force)
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate 	pool_value_t *pvals[] = { NULL, NULL };
4787c478bd9Sstevel@tonic-gate 	pool_t **pools;
4797c478bd9Sstevel@tonic-gate 	uint_t nelem;
4807c478bd9Sstevel@tonic-gate 	uchar_t bval;
4817c478bd9Sstevel@tonic-gate 	pool_conf_t *conf;
4827c478bd9Sstevel@tonic-gate 	const char *nm;
4837c478bd9Sstevel@tonic-gate 	int retval;
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	if ((conf = pool_conf_alloc()) == NULL)
4867c478bd9Sstevel@tonic-gate 		return (-1);
4877c478bd9Sstevel@tonic-gate 	if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) < 0) {
4887c478bd9Sstevel@tonic-gate 		/*
4897c478bd9Sstevel@tonic-gate 		 * Pools configuration file is corrupted; allow logins.
4907c478bd9Sstevel@tonic-gate 		 */
4917c478bd9Sstevel@tonic-gate 		pool_conf_free(conf);
4927c478bd9Sstevel@tonic-gate 		return (0);
4937c478bd9Sstevel@tonic-gate 	}
4947c478bd9Sstevel@tonic-gate 	if (pool_name != NULL && pool_get_pool(conf, pool_name) != NULL) {
4957c478bd9Sstevel@tonic-gate 		/*
4967c478bd9Sstevel@tonic-gate 		 * There was a project.pool entry, and the pool it refers to
4977c478bd9Sstevel@tonic-gate 		 * is a valid (active) pool.
4987c478bd9Sstevel@tonic-gate 		 */
4997c478bd9Sstevel@tonic-gate 		(void) pool_conf_close(conf);
5007c478bd9Sstevel@tonic-gate 		pool_conf_free(conf);
5017c478bd9Sstevel@tonic-gate 		if (pool_set_binding(pool_name, P_PID, pid) != PO_SUCCESS) {
5027c478bd9Sstevel@tonic-gate 			if (pool_error() != POE_SYSTEM)
5037c478bd9Sstevel@tonic-gate 				errno = EINVAL;
5047c478bd9Sstevel@tonic-gate 			return (-1);
5057c478bd9Sstevel@tonic-gate 		}
5067c478bd9Sstevel@tonic-gate 		return (0);
5077c478bd9Sstevel@tonic-gate 	}
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	/*
5107c478bd9Sstevel@tonic-gate 	 * Bind to the pool with 'pool.default' = 'true' if
5117c478bd9Sstevel@tonic-gate 	 * 'system.bind-default' = 'true'.
5127c478bd9Sstevel@tonic-gate 	 */
5137c478bd9Sstevel@tonic-gate 	if ((pvals[0] = pool_value_alloc()) == NULL) {
5147c478bd9Sstevel@tonic-gate 		pool_conf_close(conf);
5157c478bd9Sstevel@tonic-gate 		pool_conf_free(conf);
5167c478bd9Sstevel@tonic-gate 		return (-1);
5177c478bd9Sstevel@tonic-gate 	}
5187c478bd9Sstevel@tonic-gate 	if (!force && pool_get_property(conf, pool_conf_to_elem(conf),
5197c478bd9Sstevel@tonic-gate 	    "system.bind-default", pvals[0]) != POC_BOOL ||
5207c478bd9Sstevel@tonic-gate 	    pool_value_get_bool(pvals[0], &bval) != PO_SUCCESS ||
5217c478bd9Sstevel@tonic-gate 	    bval == PO_FALSE) {
5227c478bd9Sstevel@tonic-gate 		pool_value_free(pvals[0]);
5237c478bd9Sstevel@tonic-gate 		pool_conf_close(conf);
5247c478bd9Sstevel@tonic-gate 		pool_conf_free(conf);
5257c478bd9Sstevel@tonic-gate 		errno = pool_name == NULL ? EACCES : ESRCH;
5267c478bd9Sstevel@tonic-gate 		return (-1);
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 	(void) pool_value_set_name(pvals[0], "pool.default");
5297c478bd9Sstevel@tonic-gate 	pool_value_set_bool(pvals[0], PO_TRUE);
5307c478bd9Sstevel@tonic-gate 	if ((pools = pool_query_pools(conf, &nelem, pvals)) == NULL) {
5317c478bd9Sstevel@tonic-gate 		/*
5327c478bd9Sstevel@tonic-gate 		 * No default pools exist.
5337c478bd9Sstevel@tonic-gate 		 */
5347c478bd9Sstevel@tonic-gate 		pool_value_free(pvals[0]);
5357c478bd9Sstevel@tonic-gate 		pool_conf_close(conf);
5367c478bd9Sstevel@tonic-gate 		pool_conf_free(conf);
5377c478bd9Sstevel@tonic-gate 		errno = pool_name == NULL ? EACCES : ESRCH;
5387c478bd9Sstevel@tonic-gate 		return (-1);
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate 	if (nelem != 1 ||
5417c478bd9Sstevel@tonic-gate 	    pool_get_property(conf, pool_to_elem(conf, pools[0]), "pool.name",
5427c478bd9Sstevel@tonic-gate 	    pvals[0]) != POC_STRING) {
5437c478bd9Sstevel@tonic-gate 		/*
5447c478bd9Sstevel@tonic-gate 		 * Configuration is invalid.
5457c478bd9Sstevel@tonic-gate 		 */
5467c478bd9Sstevel@tonic-gate 		free(pools);
5477c478bd9Sstevel@tonic-gate 		pool_value_free(pvals[0]);
5487c478bd9Sstevel@tonic-gate 		(void) pool_conf_close(conf);
5497c478bd9Sstevel@tonic-gate 		pool_conf_free(conf);
5507c478bd9Sstevel@tonic-gate 		return (0);
5517c478bd9Sstevel@tonic-gate 	}
5527c478bd9Sstevel@tonic-gate 	free(pools);
5537c478bd9Sstevel@tonic-gate 	(void) pool_conf_close(conf);
5547c478bd9Sstevel@tonic-gate 	pool_conf_free(conf);
5557c478bd9Sstevel@tonic-gate 	(void) pool_value_get_string(pvals[0], &nm);
5567c478bd9Sstevel@tonic-gate 	if (pool_set_binding(nm, P_PID, pid) != PO_SUCCESS) {
5577c478bd9Sstevel@tonic-gate 		if (pool_error() != POE_SYSTEM)
5587c478bd9Sstevel@tonic-gate 			errno = EINVAL;
5597c478bd9Sstevel@tonic-gate 		retval = -1;
5607c478bd9Sstevel@tonic-gate 	} else {
5617c478bd9Sstevel@tonic-gate 		retval = 0;
5627c478bd9Sstevel@tonic-gate 	}
5637c478bd9Sstevel@tonic-gate 	pool_value_free(pvals[0]);
5647c478bd9Sstevel@tonic-gate 	return (retval);
5657c478bd9Sstevel@tonic-gate }
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate /*
5687c478bd9Sstevel@tonic-gate  * Changes the assigned project, task and resource pool of a stopped target
5697c478bd9Sstevel@tonic-gate  * process.
5707c478bd9Sstevel@tonic-gate  *
5717c478bd9Sstevel@tonic-gate  * We may not have access to the project table if our target process is in
5727c478bd9Sstevel@tonic-gate  * getprojbyname()'s execution path. Similarly, we may not be able to get user
5737c478bd9Sstevel@tonic-gate  * information if the target process is in getpwnam()'s execution path. Thus we
5747c478bd9Sstevel@tonic-gate  * give the caller the option of skipping these checks by providing a pointer to
5757c478bd9Sstevel@tonic-gate  * a pre-validated project structure in proj (whose name matches project_name)
5767c478bd9Sstevel@tonic-gate  * and taking responsibility for ensuring that the target process' owner is a
5777c478bd9Sstevel@tonic-gate  * member of the target project.
5787c478bd9Sstevel@tonic-gate  *
5797c478bd9Sstevel@tonic-gate  * Callers of this function should always provide a pre-validated project
5807c478bd9Sstevel@tonic-gate  * structure in proj unless they can be sure that the target process will never
5817c478bd9Sstevel@tonic-gate  * be in setproject_proc()'s execution path.
5827c478bd9Sstevel@tonic-gate  */
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate projid_t
5857c478bd9Sstevel@tonic-gate setproject_proc(const char *project_name, const char *user_name, int flags,
5867c478bd9Sstevel@tonic-gate     pid_t pid, struct ps_prochandle *Pr, struct project *proj)
5877c478bd9Sstevel@tonic-gate {
5887c478bd9Sstevel@tonic-gate 	char pwdbuf[NSS_BUFLEN_PASSWD];
5897c478bd9Sstevel@tonic-gate 	char prbuf[PROJECT_BUFSZ];
5907c478bd9Sstevel@tonic-gate 	projid_t projid;
5917c478bd9Sstevel@tonic-gate 	struct passwd pwd;
5927c478bd9Sstevel@tonic-gate 	int i;
5937c478bd9Sstevel@tonic-gate 	int unknown = 0;
5947c478bd9Sstevel@tonic-gate 	int ret = 0;
5957c478bd9Sstevel@tonic-gate 	kva_t *kv_array;
5967c478bd9Sstevel@tonic-gate 	struct project local_proj; /* space to store proj if not provided */
597532877c4Srd117015 	const char *pool_name = NULL;
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	if (project_name != NULL) {
6007c478bd9Sstevel@tonic-gate 		/*
6017c478bd9Sstevel@tonic-gate 		 * Sanity checks.
6027c478bd9Sstevel@tonic-gate 		 */
6037c478bd9Sstevel@tonic-gate 		if (strcmp(project_name, "") == 0 ||
6047c478bd9Sstevel@tonic-gate 		    user_name == NULL) {
6057c478bd9Sstevel@tonic-gate 			errno = EINVAL;
6067c478bd9Sstevel@tonic-gate 			return (SETPROJ_ERR_TASK);
6077c478bd9Sstevel@tonic-gate 		}
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 		/*
6107c478bd9Sstevel@tonic-gate 		 * If proj is NULL, acquire project information to ensure that
6117c478bd9Sstevel@tonic-gate 		 * project_name is a valid project, and confirm that user_name
6127c478bd9Sstevel@tonic-gate 		 * exists and is a member of the specified project.
6137c478bd9Sstevel@tonic-gate 		 */
6147c478bd9Sstevel@tonic-gate 		if (proj == NULL) {
6157c478bd9Sstevel@tonic-gate 			if ((proj = getprojbyname(project_name, &local_proj,
6167c478bd9Sstevel@tonic-gate 			    prbuf, PROJECT_BUFSZ)) == NULL) {
6177c478bd9Sstevel@tonic-gate 				errno = ESRCH;
6187c478bd9Sstevel@tonic-gate 				return (SETPROJ_ERR_TASK);
6197c478bd9Sstevel@tonic-gate 			}
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 			if (getpwnam_r(user_name, &pwd,
6227c478bd9Sstevel@tonic-gate 			    pwdbuf, NSS_BUFLEN_PASSWD) == NULL) {
6237c478bd9Sstevel@tonic-gate 				errno = ESRCH;
6247c478bd9Sstevel@tonic-gate 				return (SETPROJ_ERR_TASK);
6257c478bd9Sstevel@tonic-gate 			}
6267c478bd9Sstevel@tonic-gate 			/*
6277c478bd9Sstevel@tonic-gate 			 * Root can join any project.
6287c478bd9Sstevel@tonic-gate 			 */
6297c478bd9Sstevel@tonic-gate 			if (pwd.pw_uid != (uid_t)0 &&
6307c478bd9Sstevel@tonic-gate 			    !inproj(user_name, project_name, prbuf,
6317c478bd9Sstevel@tonic-gate 			    PROJECT_BUFSZ)) {
6327c478bd9Sstevel@tonic-gate 				errno = ESRCH;
6337c478bd9Sstevel@tonic-gate 				return (SETPROJ_ERR_TASK);
6347c478bd9Sstevel@tonic-gate 			}
6357c478bd9Sstevel@tonic-gate 		}
6367c478bd9Sstevel@tonic-gate 		projid = proj->pj_projid;
6377c478bd9Sstevel@tonic-gate 	} else {
6387c478bd9Sstevel@tonic-gate 		projid = getprojid();
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate 
641532877c4Srd117015 
6427c478bd9Sstevel@tonic-gate 	if ((kv_array = _str2kva(proj->pj_attr, KV_ASSIGN,
6437c478bd9Sstevel@tonic-gate 	    KV_DELIMITER)) != NULL) {
6447c478bd9Sstevel@tonic-gate 		for (i = 0; i < kv_array->length; i++) {
6457c478bd9Sstevel@tonic-gate 			if (strcmp(kv_array->data[i].key,
6467c478bd9Sstevel@tonic-gate 			    "project.pool") == 0) {
6477c478bd9Sstevel@tonic-gate 				pool_name = kv_array->data[i].value;
6487c478bd9Sstevel@tonic-gate 			}
649532877c4Srd117015 			if (strcmp(kv_array->data[i].key, "task.final") == 0) {
650532877c4Srd117015 				flags |= TASK_FINAL;
6517c478bd9Sstevel@tonic-gate 			}
6527c478bd9Sstevel@tonic-gate 		}
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 
6550209230bSgjelinek 	/*
656532877c4Srd117015 	 * Bind process to a pool only if pools are configured
6570209230bSgjelinek 	 */
658532877c4Srd117015 	if (pools_enabled() == 1) {
659532877c4Srd117015 		char *old_pool_name;
660532877c4Srd117015 		/*
661532877c4Srd117015 		 * Attempt to bind to pool before calling
662532877c4Srd117015 		 * settaskid().
663532877c4Srd117015 		 */
664532877c4Srd117015 		old_pool_name = pool_get_binding(pid);
665532877c4Srd117015 		if (bind_to_pool(pool_name, pid, 0) != 0) {
6667c478bd9Sstevel@tonic-gate 			if (old_pool_name)
6677c478bd9Sstevel@tonic-gate 				free(old_pool_name);
6687c478bd9Sstevel@tonic-gate 			_kva_free(kv_array);
6697c478bd9Sstevel@tonic-gate 			return (SETPROJ_ERR_POOL);
6707c478bd9Sstevel@tonic-gate 		}
671532877c4Srd117015 		if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) {
6727c478bd9Sstevel@tonic-gate 			int saved_errno = errno;
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 			/*
6757c478bd9Sstevel@tonic-gate 			 * Undo pool binding.
6767c478bd9Sstevel@tonic-gate 			 */
6777c478bd9Sstevel@tonic-gate 			(void) bind_to_pool(old_pool_name, pid, 1);
6787c478bd9Sstevel@tonic-gate 			if (old_pool_name)
6797c478bd9Sstevel@tonic-gate 				free(old_pool_name);
6807c478bd9Sstevel@tonic-gate 			_kva_free(kv_array);
6817c478bd9Sstevel@tonic-gate 			/*
6827c478bd9Sstevel@tonic-gate 			 * Restore errno
6837c478bd9Sstevel@tonic-gate 			 */
6847c478bd9Sstevel@tonic-gate 			errno = saved_errno;
6857c478bd9Sstevel@tonic-gate 			return (SETPROJ_ERR_TASK);
6867c478bd9Sstevel@tonic-gate 		}
6877c478bd9Sstevel@tonic-gate 		if (old_pool_name)
6887c478bd9Sstevel@tonic-gate 			free(old_pool_name);
6897c478bd9Sstevel@tonic-gate 	} else {
6907c478bd9Sstevel@tonic-gate 		/*
6917c478bd9Sstevel@tonic-gate 		 * Pools are not configured, so simply create new task.
6927c478bd9Sstevel@tonic-gate 		 */
693532877c4Srd117015 		if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) {
694532877c4Srd117015 			_kva_free(kv_array);
6957c478bd9Sstevel@tonic-gate 			return (SETPROJ_ERR_TASK);
696532877c4Srd117015 		}
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	if (project_name == NULL) {
7007c478bd9Sstevel@tonic-gate 		/*
7017c478bd9Sstevel@tonic-gate 		 * In the case that we are starting a new task in the
7027c478bd9Sstevel@tonic-gate 		 * current project, we are finished, since the current
7037c478bd9Sstevel@tonic-gate 		 * resource controls will still apply. (Implicit behaviour:
7047c478bd9Sstevel@tonic-gate 		 * a project must be entirely logged out before name
7057c478bd9Sstevel@tonic-gate 		 * service changes will take effect.)
7067c478bd9Sstevel@tonic-gate 		 */
7077c478bd9Sstevel@tonic-gate 		_kva_free(kv_array);
7087c478bd9Sstevel@tonic-gate 		return (projid);
7097c478bd9Sstevel@tonic-gate 	}
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	if (kv_array == NULL)
7127c478bd9Sstevel@tonic-gate 		return (0);
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	for (i = 0; i < kv_array->length; i++) {
7157c478bd9Sstevel@tonic-gate 		/*
7167c478bd9Sstevel@tonic-gate 		 * Providing a special, i.e. a non-resource control, key?  Then
7177c478bd9Sstevel@tonic-gate 		 * parse that key here and end with "continue;".
7187c478bd9Sstevel@tonic-gate 		 */
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 		/*
7217c478bd9Sstevel@tonic-gate 		 * For generic bindings, the kernel performs the binding, as
7227c478bd9Sstevel@tonic-gate 		 * these are resource controls advertised by kernel subsystems.
7237c478bd9Sstevel@tonic-gate 		 */
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 		/*
7267c478bd9Sstevel@tonic-gate 		 * Check for known attribute name.
7277c478bd9Sstevel@tonic-gate 		 */
7287c478bd9Sstevel@tonic-gate 		errno = 0;
7297c478bd9Sstevel@tonic-gate 		if (rctl_walk(rctlwalkfunc, (void *)kv_array->data[i].key)
7307c478bd9Sstevel@tonic-gate 		    == 0)
7317c478bd9Sstevel@tonic-gate 			continue;
7327c478bd9Sstevel@tonic-gate 		if (errno) {
7337c478bd9Sstevel@tonic-gate 			_kva_free(kv_array);
7347c478bd9Sstevel@tonic-gate 			return (SETPROJ_ERR_TASK);
7357c478bd9Sstevel@tonic-gate 		}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 		ret = rctl_set(kv_array->data[i].key,
738532877c4Srd117015 		    kv_array->data[i].value, Pr, flags & TASK_PROJ_MASK);
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 		if (ret && unknown == 0) {
7417c478bd9Sstevel@tonic-gate 			/*
7427c478bd9Sstevel@tonic-gate 			 * We only report the first failure.
7437c478bd9Sstevel@tonic-gate 			 */
7447c478bd9Sstevel@tonic-gate 			unknown = i + 1;
7457c478bd9Sstevel@tonic-gate 		}
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 		if (ret && ret != SETFAILED) {
7487c478bd9Sstevel@tonic-gate 			/*
7497c478bd9Sstevel@tonic-gate 			 * We abort if we couldn't set a component, but if
7507c478bd9Sstevel@tonic-gate 			 * it's merely that the system didn't recognize it, we
7517c478bd9Sstevel@tonic-gate 			 * continue, as this could be a third party attribute.
7527c478bd9Sstevel@tonic-gate 			 */
7537c478bd9Sstevel@tonic-gate 			break;
7547c478bd9Sstevel@tonic-gate 		}
7557c478bd9Sstevel@tonic-gate 	}
7567c478bd9Sstevel@tonic-gate 	_kva_free(kv_array);
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	return (unknown);
7597c478bd9Sstevel@tonic-gate }
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate projid_t
7627c478bd9Sstevel@tonic-gate setproject(const char *project_name, const char *user_name, int flags)
7637c478bd9Sstevel@tonic-gate {
7647c478bd9Sstevel@tonic-gate 	return (setproject_proc(project_name, user_name, flags, P_MYID, NULL,
7657c478bd9Sstevel@tonic-gate 	    NULL));
7667c478bd9Sstevel@tonic-gate }
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate priv_set_t *
7707c478bd9Sstevel@tonic-gate setproject_initpriv(void)
7717c478bd9Sstevel@tonic-gate {
7727c478bd9Sstevel@tonic-gate 	static priv_t taskpriv = PRIV_PROC_TASKID;
7737c478bd9Sstevel@tonic-gate 	static priv_t rctlpriv = PRIV_SYS_RESOURCE;
7747c478bd9Sstevel@tonic-gate 	static priv_t poolpriv = PRIV_SYS_RES_CONFIG;
7757c478bd9Sstevel@tonic-gate 	static priv_t schedpriv = PRIV_PROC_PRIOCNTL;
7767c478bd9Sstevel@tonic-gate 	int res;
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	priv_set_t *nset;
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	if (getzoneid() == GLOBAL_ZONEID) {
7817c478bd9Sstevel@tonic-gate 		res = __init_suid_priv(0, taskpriv, rctlpriv, poolpriv,
7827c478bd9Sstevel@tonic-gate 		    schedpriv, (char *)NULL);
7837c478bd9Sstevel@tonic-gate 	} else {
7847c478bd9Sstevel@tonic-gate 		res = __init_suid_priv(0, taskpriv, rctlpriv, (char *)NULL);
7857c478bd9Sstevel@tonic-gate 	}
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	if (res != 0)
7887c478bd9Sstevel@tonic-gate 		return (NULL);
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	nset = priv_allocset();
7917c478bd9Sstevel@tonic-gate 	if (nset != NULL) {
7927c478bd9Sstevel@tonic-gate 		priv_emptyset(nset);
7937c478bd9Sstevel@tonic-gate 		(void) priv_addset(nset, taskpriv);
7947c478bd9Sstevel@tonic-gate 		(void) priv_addset(nset, rctlpriv);
7957c478bd9Sstevel@tonic-gate 		/*
7967c478bd9Sstevel@tonic-gate 		 * Only need these if we need to change pools, which can
7977c478bd9Sstevel@tonic-gate 		 * only happen if the target is in the global zone.  Rather
7987c478bd9Sstevel@tonic-gate 		 * than checking the target's zone just check our own
7997c478bd9Sstevel@tonic-gate 		 * (since if we're in a non-global zone we won't be able
8007c478bd9Sstevel@tonic-gate 		 * to control processes in other zones).
8017c478bd9Sstevel@tonic-gate 		 */
8027c478bd9Sstevel@tonic-gate 		if (getzoneid() == GLOBAL_ZONEID) {
8037c478bd9Sstevel@tonic-gate 			(void) priv_addset(nset, poolpriv);
8047c478bd9Sstevel@tonic-gate 			(void) priv_addset(nset, schedpriv);
8057c478bd9Sstevel@tonic-gate 		}
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 	return (nset);
8087c478bd9Sstevel@tonic-gate }
809