xref: /titanic_52/usr/src/lib/libproject/common/setproject.c (revision 96ab4d5390a62b7e1743ec1fad5c0eef9682b961)
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 /*
223268e889SRalph Turner - Sun UK - Contractor  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
23*96ab4d53SJerry Jelinek  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <sys/task.h>
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <unistd.h>
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <ctype.h>
327c478bd9Sstevel@tonic-gate #include <project.h>
337c478bd9Sstevel@tonic-gate #include <rctl.h>
347c478bd9Sstevel@tonic-gate #include <secdb.h>
357c478bd9Sstevel@tonic-gate #include <signal.h>
367c478bd9Sstevel@tonic-gate #include <stdlib.h>
377c478bd9Sstevel@tonic-gate #include <string.h>
38532877c4Srd117015 #include <strings.h>
397c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
407c478bd9Sstevel@tonic-gate #include <pwd.h>
417c478bd9Sstevel@tonic-gate #include <pool.h>
427c478bd9Sstevel@tonic-gate #include <libproc.h>
437c478bd9Sstevel@tonic-gate #include <priv.h>
447c478bd9Sstevel@tonic-gate #include <priv_utils.h>
457c478bd9Sstevel@tonic-gate #include <zone.h>
467c478bd9Sstevel@tonic-gate #include <sys/pool.h>
477c478bd9Sstevel@tonic-gate #include <sys/pool_impl.h>
48532877c4Srd117015 #include <sys/rctl_impl.h>
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static void
517c478bd9Sstevel@tonic-gate xstrtolower(char *s)
527c478bd9Sstevel@tonic-gate {
537c478bd9Sstevel@tonic-gate 	for (; *s != '\0'; s++)
547c478bd9Sstevel@tonic-gate 		*s = tolower(*s);
557c478bd9Sstevel@tonic-gate }
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate static void
587c478bd9Sstevel@tonic-gate remove_spaces(char *s)
597c478bd9Sstevel@tonic-gate {
607c478bd9Sstevel@tonic-gate 	char *current;
617c478bd9Sstevel@tonic-gate 	char *next;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 	current = next = s;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate 	while (*next != '\0') {
667c478bd9Sstevel@tonic-gate 		while (isspace(*next))
677c478bd9Sstevel@tonic-gate 			next++;
687c478bd9Sstevel@tonic-gate 		*current++ = *next++;
697c478bd9Sstevel@tonic-gate 	}
707c478bd9Sstevel@tonic-gate 	*current = '\0';
717c478bd9Sstevel@tonic-gate }
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate int
747c478bd9Sstevel@tonic-gate build_rctlblk(rctlblk_t *blk, int comp_num, char *component)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate 	char *signam;
777c478bd9Sstevel@tonic-gate 	int sig = 0;
787c478bd9Sstevel@tonic-gate 	uint_t act = rctlblk_get_local_action(blk, &sig);
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	if (comp_num == 0) {
817c478bd9Sstevel@tonic-gate 		/*
827c478bd9Sstevel@tonic-gate 		 * Setting privilege level for resource control block.
837c478bd9Sstevel@tonic-gate 		 */
847c478bd9Sstevel@tonic-gate 		xstrtolower(component);
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 		if (strcmp("basic", component) == 0) {
877c478bd9Sstevel@tonic-gate 			rctlblk_set_privilege(blk, RCPRIV_BASIC);
887c478bd9Sstevel@tonic-gate 			return (0);
897c478bd9Sstevel@tonic-gate 		}
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 		if (strcmp("priv", component) == 0 ||
927c478bd9Sstevel@tonic-gate 		    strcmp("privileged", component) == 0) {
937c478bd9Sstevel@tonic-gate 			rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
947c478bd9Sstevel@tonic-gate 			return (0);
957c478bd9Sstevel@tonic-gate 		}
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 		return (-1);
987c478bd9Sstevel@tonic-gate 	}
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	if (comp_num == 1) {
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 		/*
1037c478bd9Sstevel@tonic-gate 		 * Setting value for resource control block.
1047c478bd9Sstevel@tonic-gate 		 */
1057c478bd9Sstevel@tonic-gate 		unsigned long long val;
1067c478bd9Sstevel@tonic-gate 		char *t;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 		/* Negative numbers are not allowed */
1097c478bd9Sstevel@tonic-gate 		if (strchr(component, '-') != NULL)
1107c478bd9Sstevel@tonic-gate 			return (-1);
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 		errno = 0;
1137c478bd9Sstevel@tonic-gate 		val = strtoull(component, &t, 10);
1147c478bd9Sstevel@tonic-gate 		if (errno != 0 || t == component || *t != '\0')
1157c478bd9Sstevel@tonic-gate 			return (-1);
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 		rctlblk_set_value(blk, (rctl_qty_t)val);
1187c478bd9Sstevel@tonic-gate 		return (0);
1197c478bd9Sstevel@tonic-gate 	}
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	/*
1227c478bd9Sstevel@tonic-gate 	 * Setting one or more actions on this resource control block.
1237c478bd9Sstevel@tonic-gate 	 */
1247c478bd9Sstevel@tonic-gate 	if (comp_num >= 2) {
1257c478bd9Sstevel@tonic-gate 		if (strcmp("none", component) == 0) {
1267c478bd9Sstevel@tonic-gate 			rctlblk_set_local_action(blk, 0, 0);
1277c478bd9Sstevel@tonic-gate 			return (0);
1287c478bd9Sstevel@tonic-gate 		}
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 		if (strcmp("deny", component) == 0) {
1317c478bd9Sstevel@tonic-gate 			act |= RCTL_LOCAL_DENY;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 			rctlblk_set_local_action(blk, act, sig);
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 			return (0);
1367c478bd9Sstevel@tonic-gate 		}
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 		/*
1397c478bd9Sstevel@tonic-gate 		 * The last, and trickiest, form of action is the signal
1407c478bd9Sstevel@tonic-gate 		 * specification.
1417c478bd9Sstevel@tonic-gate 		 */
1427c478bd9Sstevel@tonic-gate 		if ((signam = strchr(component, '=')) == NULL)
1437c478bd9Sstevel@tonic-gate 			return (-1);
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 		*signam++ = '\0';
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 		if (strcmp("sig", component) == 0 ||
1487c478bd9Sstevel@tonic-gate 		    strcmp("signal", component) == 0) {
1497c478bd9Sstevel@tonic-gate 			if (strncmp("SIG", signam, 3) == 0)
1507c478bd9Sstevel@tonic-gate 				signam += 3;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 			if (str2sig(signam, &sig) == -1)
1537c478bd9Sstevel@tonic-gate 				return (-1);
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 			act |= RCTL_LOCAL_SIGNAL;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 			rctlblk_set_local_action(blk, act, sig);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 			return (0);
1607c478bd9Sstevel@tonic-gate 		}
1617c478bd9Sstevel@tonic-gate 	}
1627c478bd9Sstevel@tonic-gate 	return (-1);
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate  * States:
1677c478bd9Sstevel@tonic-gate  */
1687c478bd9Sstevel@tonic-gate #define	INPAREN		0x1
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate /*
1717c478bd9Sstevel@tonic-gate  * Errors:
1727c478bd9Sstevel@tonic-gate  */
1737c478bd9Sstevel@tonic-gate #define	SETFAILED	(-1)
1747c478bd9Sstevel@tonic-gate #define	COMPLETE	1
1757c478bd9Sstevel@tonic-gate #define	NESTING		2
1767c478bd9Sstevel@tonic-gate #define	UNCLOSED	3
1777c478bd9Sstevel@tonic-gate #define	CLOSEBEFOREOPEN	4
1787c478bd9Sstevel@tonic-gate #define	BADSPEC		5
1797c478bd9Sstevel@tonic-gate 
1803268e889SRalph Turner - Sun UK - Contractor static void
1813268e889SRalph Turner - Sun UK - Contractor reinit_blk(rctlblk_t *blk, int local_action)
1823268e889SRalph Turner - Sun UK - Contractor {
1833268e889SRalph Turner - Sun UK - Contractor 	rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
1843268e889SRalph Turner - Sun UK - Contractor 	rctlblk_set_value(blk, 0);
1853268e889SRalph Turner - Sun UK - Contractor 	rctlblk_set_local_flags(blk, 0);
1863268e889SRalph Turner - Sun UK - Contractor 	rctlblk_set_local_action(blk, local_action, 0);
1873268e889SRalph Turner - Sun UK - Contractor }
1883268e889SRalph Turner - Sun UK - Contractor 
1897c478bd9Sstevel@tonic-gate static int
190532877c4Srd117015 rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr, int flags)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate 	int error = 0;
1937c478bd9Sstevel@tonic-gate 	uint_t component = 0;
1947c478bd9Sstevel@tonic-gate 	int valuecount = 0;
1957c478bd9Sstevel@tonic-gate 	uint_t state = 0;
1967c478bd9Sstevel@tonic-gate 	char *component_head;
1977c478bd9Sstevel@tonic-gate 	rctlblk_t *blk;
198532877c4Srd117015 	rctlblk_t *ablk;
199532877c4Srd117015 	int project_entity = 0;
200532877c4Srd117015 	int count = 0;
201532877c4Srd117015 	char *tmp;
2023268e889SRalph Turner - Sun UK - Contractor 	int local_act;
2033268e889SRalph Turner - Sun UK - Contractor 	rctlblk_t *rnext;
2043268e889SRalph Turner - Sun UK - Contractor 	int teardown_basic = 0;
2053268e889SRalph Turner - Sun UK - Contractor 	int teardown_priv = 0;
2067c478bd9Sstevel@tonic-gate 
207532877c4Srd117015 	/* We cannot modify a zone resource control */
208532877c4Srd117015 	if (strncmp(ctl_name, "zone.", strlen("zone.")) == 0) {
2097c478bd9Sstevel@tonic-gate 		return (SETFAILED);
2107c478bd9Sstevel@tonic-gate 	}
2117c478bd9Sstevel@tonic-gate 
212532877c4Srd117015 	remove_spaces(val);
213532877c4Srd117015 
2143268e889SRalph Turner - Sun UK - Contractor 	if (strncmp(ctl_name, "project.", strlen("project.")) == 0) {
2153268e889SRalph Turner - Sun UK - Contractor 		project_entity = 1;
2163268e889SRalph Turner - Sun UK - Contractor 	} else if ((strncmp(ctl_name, "process.", strlen("process.")) != 0) &&
2173268e889SRalph Turner - Sun UK - Contractor 	    (strncmp(ctl_name, "task.", strlen("task.")) != 0)) {
218532877c4Srd117015 		return (SETFAILED);
219532877c4Srd117015 	}
220532877c4Srd117015 
221532877c4Srd117015 	/* Determine how many attributes we'll be setting */
222532877c4Srd117015 	for (tmp = val; *tmp != '\0'; tmp++) {
223532877c4Srd117015 		if (*tmp == '(')
224532877c4Srd117015 			count++;
225532877c4Srd117015 	}
226532877c4Srd117015 	/* Allocate sufficient memory for rctl blocks */
227532877c4Srd117015 	if ((count == 0) || ((ablk =
228532877c4Srd117015 	    (rctlblk_t *)malloc(rctlblk_size() * count)) == NULL)) {
229532877c4Srd117015 		return (SETFAILED);
230532877c4Srd117015 	}
231532877c4Srd117015 	blk = ablk;
232532877c4Srd117015 
233532877c4Srd117015 	/*
234532877c4Srd117015 	 * In order to set the new rctl's local_action, we'll need the
235532877c4Srd117015 	 * current value of global_flags.  We obtain global_flags by
236532877c4Srd117015 	 * performing a pr_getrctl().
237532877c4Srd117015 	 *
238532877c4Srd117015 	 * The ctl_name has been verified as valid, so we have no reason
239532877c4Srd117015 	 * to suspect that pr_getrctl() will return an error.
240532877c4Srd117015 	 */
241532877c4Srd117015 	(void) pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST);
242532877c4Srd117015 
243532877c4Srd117015 
2447c478bd9Sstevel@tonic-gate 	/*
2457c478bd9Sstevel@tonic-gate 	 * Set initial local action based on global deny properties.
2467c478bd9Sstevel@tonic-gate 	 */
2477c478bd9Sstevel@tonic-gate 	rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
2487c478bd9Sstevel@tonic-gate 	rctlblk_set_value(blk, 0);
2497c478bd9Sstevel@tonic-gate 	rctlblk_set_local_flags(blk, 0);
2507c478bd9Sstevel@tonic-gate 
251532877c4Srd117015 	if (rctlblk_get_global_flags(blk) & RCTL_GLOBAL_DENY_ALWAYS)
2523268e889SRalph Turner - Sun UK - Contractor 		local_act = RCTL_LOCAL_DENY;
253532877c4Srd117015 	else
2543268e889SRalph Turner - Sun UK - Contractor 		local_act = RCTL_LOCAL_NOACTION;
255532877c4Srd117015 
2563268e889SRalph Turner - Sun UK - Contractor 	rctlblk_set_local_action(blk, local_act, 0);
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	for (; ; val++) {
2593268e889SRalph Turner - Sun UK - Contractor 
2607c478bd9Sstevel@tonic-gate 		switch (*val) {
2617c478bd9Sstevel@tonic-gate 			case '(':
2627c478bd9Sstevel@tonic-gate 				if (state & INPAREN) {
2637c478bd9Sstevel@tonic-gate 					error = NESTING;
2647c478bd9Sstevel@tonic-gate 					break;
2657c478bd9Sstevel@tonic-gate 				}
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 				state |= INPAREN;
2687c478bd9Sstevel@tonic-gate 				component_head = (char *)val + 1;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 				break;
2717c478bd9Sstevel@tonic-gate 			case ')':
2727c478bd9Sstevel@tonic-gate 				if (state & INPAREN) {
2737c478bd9Sstevel@tonic-gate 					*val = '\0';
2747c478bd9Sstevel@tonic-gate 					if (component < 2) {
2757c478bd9Sstevel@tonic-gate 						error = BADSPEC;
2767c478bd9Sstevel@tonic-gate 						break;
2777c478bd9Sstevel@tonic-gate 					}
2787c478bd9Sstevel@tonic-gate 					if (build_rctlblk(blk, component,
2797c478bd9Sstevel@tonic-gate 					    component_head) == -1) {
2807c478bd9Sstevel@tonic-gate 						error = BADSPEC;
2817c478bd9Sstevel@tonic-gate 						break;
2827c478bd9Sstevel@tonic-gate 					}
2837c478bd9Sstevel@tonic-gate 					state &= ~INPAREN;
2847c478bd9Sstevel@tonic-gate 					component = 0;
2857c478bd9Sstevel@tonic-gate 					valuecount++;
286532877c4Srd117015 
287532877c4Srd117015 					if (project_entity &&
288532877c4Srd117015 					    (rctlblk_get_privilege(blk) ==
289532877c4Srd117015 					    RCPRIV_BASIC)) {
2907c478bd9Sstevel@tonic-gate 						error = SETFAILED;
2913268e889SRalph Turner - Sun UK - Contractor 					} else {
2923268e889SRalph Turner - Sun UK - Contractor 						if (rctlblk_get_privilege(blk)
2933268e889SRalph Turner - Sun UK - Contractor 						    == RCPRIV_BASIC)
2943268e889SRalph Turner - Sun UK - Contractor 							teardown_basic = 1;
295532877c4Srd117015 
2963268e889SRalph Turner - Sun UK - Contractor 						if (rctlblk_get_privilege(blk)
2973268e889SRalph Turner - Sun UK - Contractor 						    == RCPRIV_PRIVILEGED)
2983268e889SRalph Turner - Sun UK - Contractor 							teardown_priv = 1;
2993268e889SRalph Turner - Sun UK - Contractor 
3003268e889SRalph Turner - Sun UK - Contractor 						if (valuecount > count) {
3013268e889SRalph Turner - Sun UK - Contractor 							free(ablk);
3023268e889SRalph Turner - Sun UK - Contractor 							return (SETFAILED);
3033268e889SRalph Turner - Sun UK - Contractor 						}
3043268e889SRalph Turner - Sun UK - Contractor 
3053268e889SRalph Turner - Sun UK - Contractor 						if (valuecount != count) {
306532877c4Srd117015 							blk = RCTLBLK_INC(ablk,
307532877c4Srd117015 							    valuecount);
3083268e889SRalph Turner - Sun UK - Contractor 							/* re-initialize blk */
3093268e889SRalph Turner - Sun UK - Contractor 							reinit_blk(blk,
3103268e889SRalph Turner - Sun UK - Contractor 							    local_act);
3113268e889SRalph Turner - Sun UK - Contractor 						}
312532877c4Srd117015 					}
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 				} else {
3157c478bd9Sstevel@tonic-gate 					error = CLOSEBEFOREOPEN;
3167c478bd9Sstevel@tonic-gate 				}
3177c478bd9Sstevel@tonic-gate 				break;
3187c478bd9Sstevel@tonic-gate 			case ',':
3197c478bd9Sstevel@tonic-gate 				if (state & INPAREN) {
3207c478bd9Sstevel@tonic-gate 					*val = '\0';
3217c478bd9Sstevel@tonic-gate 					if (build_rctlblk(blk, component,
3227c478bd9Sstevel@tonic-gate 					    component_head) == -1)
3237c478bd9Sstevel@tonic-gate 						error = BADSPEC;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 					component++;
3267c478bd9Sstevel@tonic-gate 					component_head = (char *)val + 1;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 				}
3297c478bd9Sstevel@tonic-gate 				break;
3307c478bd9Sstevel@tonic-gate 			case '\0':
3317c478bd9Sstevel@tonic-gate 				if (valuecount == 0)
3327c478bd9Sstevel@tonic-gate 					error = BADSPEC;
3337c478bd9Sstevel@tonic-gate 				else if (state & INPAREN)
3347c478bd9Sstevel@tonic-gate 					error = UNCLOSED;
3357c478bd9Sstevel@tonic-gate 				else
3367c478bd9Sstevel@tonic-gate 					error = COMPLETE;
3377c478bd9Sstevel@tonic-gate 				break;
3387c478bd9Sstevel@tonic-gate 			default:
3397c478bd9Sstevel@tonic-gate 				if (!(state & INPAREN))
3407c478bd9Sstevel@tonic-gate 					error = BADSPEC;
3417c478bd9Sstevel@tonic-gate 				break;
3427c478bd9Sstevel@tonic-gate 		}
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 		if (error)
3457c478bd9Sstevel@tonic-gate 			break;
3467c478bd9Sstevel@tonic-gate 	}
3473268e889SRalph Turner - Sun UK - Contractor 	/* ablk points to array of rctlblk_t */
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	if (valuecount == 0)
3507c478bd9Sstevel@tonic-gate 		error = BADSPEC;
3517c478bd9Sstevel@tonic-gate 
3523268e889SRalph Turner - Sun UK - Contractor 	if (error != COMPLETE) {
3533268e889SRalph Turner - Sun UK - Contractor 		free(ablk);
3543268e889SRalph Turner - Sun UK - Contractor 		return (error);
3553268e889SRalph Turner - Sun UK - Contractor 	}
3563268e889SRalph Turner - Sun UK - Contractor 
3573268e889SRalph Turner - Sun UK - Contractor 	/* teardown rctls if required */
3583268e889SRalph Turner - Sun UK - Contractor 	if (!project_entity) {
3593268e889SRalph Turner - Sun UK - Contractor 
3603268e889SRalph Turner - Sun UK - Contractor 		if ((rnext = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
3613268e889SRalph Turner - Sun UK - Contractor 			free(ablk);
3623268e889SRalph Turner - Sun UK - Contractor 			return (SETFAILED);
3633268e889SRalph Turner - Sun UK - Contractor 		}
3643268e889SRalph Turner - Sun UK - Contractor 
365*96ab4d53SJerry Jelinek restart:
3663268e889SRalph Turner - Sun UK - Contractor 		if (pr_getrctl(Pr, ctl_name, NULL, rnext, RCTL_FIRST) == 0) {
3673268e889SRalph Turner - Sun UK - Contractor 			while (1) {
3683268e889SRalph Turner - Sun UK - Contractor 				if ((rctlblk_get_privilege(rnext) ==
3693268e889SRalph Turner - Sun UK - Contractor 				    RCPRIV_PRIVILEGED) &&
3703268e889SRalph Turner - Sun UK - Contractor 				    (teardown_priv == 1)) {
3713268e889SRalph Turner - Sun UK - Contractor 					(void) pr_setrctl(Pr, ctl_name, NULL,
3723268e889SRalph Turner - Sun UK - Contractor 					    rnext, RCTL_DELETE);
373*96ab4d53SJerry Jelinek 					goto restart;
3743268e889SRalph Turner - Sun UK - Contractor 				}
3753268e889SRalph Turner - Sun UK - Contractor 				if ((rctlblk_get_privilege(rnext) ==
3763268e889SRalph Turner - Sun UK - Contractor 				    RCPRIV_BASIC) && (teardown_basic == 1)) {
3773268e889SRalph Turner - Sun UK - Contractor 					(void) pr_setrctl(Pr, ctl_name, NULL,
3783268e889SRalph Turner - Sun UK - Contractor 					    rnext, RCTL_DELETE);
379*96ab4d53SJerry Jelinek 					goto restart;
3803268e889SRalph Turner - Sun UK - Contractor 				}
3813268e889SRalph Turner - Sun UK - Contractor 
382*96ab4d53SJerry Jelinek 				if (pr_getrctl(Pr, ctl_name, rnext, rnext,
3833268e889SRalph Turner - Sun UK - Contractor 				    RCTL_NEXT) == -1)
3843268e889SRalph Turner - Sun UK - Contractor 					break;
3853268e889SRalph Turner - Sun UK - Contractor 			}
3863268e889SRalph Turner - Sun UK - Contractor 		}
3873268e889SRalph Turner - Sun UK - Contractor 
3883268e889SRalph Turner - Sun UK - Contractor 		free(rnext);
3893268e889SRalph Turner - Sun UK - Contractor 	}
3903268e889SRalph Turner - Sun UK - Contractor 
3913268e889SRalph Turner - Sun UK - Contractor 	/* set rctls */
3923268e889SRalph Turner - Sun UK - Contractor 
3933268e889SRalph Turner - Sun UK - Contractor 	blk = ablk;
3943268e889SRalph Turner - Sun UK - Contractor 
3953268e889SRalph Turner - Sun UK - Contractor 	if (project_entity) {
3963268e889SRalph Turner - Sun UK - Contractor 		if (pr_setprojrctl(Pr, ctl_name, blk, count, flags) == -1)
3973268e889SRalph Turner - Sun UK - Contractor 			error = SETFAILED;
3983268e889SRalph Turner - Sun UK - Contractor 	} else {
3993268e889SRalph Turner - Sun UK - Contractor 		valuecount = 0;
4003268e889SRalph Turner - Sun UK - Contractor 		while (valuecount < count) {
4013268e889SRalph Turner - Sun UK - Contractor 			if (pr_setrctl(Pr, ctl_name,
4023268e889SRalph Turner - Sun UK - Contractor 			    NULL, blk, RCTL_INSERT) == -1) {
4033268e889SRalph Turner - Sun UK - Contractor 				error = SETFAILED;
4043268e889SRalph Turner - Sun UK - Contractor 				break;
4053268e889SRalph Turner - Sun UK - Contractor 				}
4063268e889SRalph Turner - Sun UK - Contractor 			valuecount++;
4073268e889SRalph Turner - Sun UK - Contractor 			blk = RCTLBLK_INC(ablk, valuecount);
4083268e889SRalph Turner - Sun UK - Contractor 		}
4093268e889SRalph Turner - Sun UK - Contractor 	}
4103268e889SRalph Turner - Sun UK - Contractor 
4113268e889SRalph Turner - Sun UK - Contractor 
4123268e889SRalph Turner - Sun UK - Contractor 
4133268e889SRalph Turner - Sun UK - Contractor 	free(ablk);
4143268e889SRalph Turner - Sun UK - Contractor 
4157c478bd9Sstevel@tonic-gate 	if (error != COMPLETE)
4167c478bd9Sstevel@tonic-gate 		return (error);
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	return (0);
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate static int
4227c478bd9Sstevel@tonic-gate rctlwalkfunc(const char *name, void *data)
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	if (strcmp(name, (char *)data) == 0)
4267c478bd9Sstevel@tonic-gate 		return (-1);
4277c478bd9Sstevel@tonic-gate 	else
4287c478bd9Sstevel@tonic-gate 		return (0);
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate /*
4337c478bd9Sstevel@tonic-gate  * This routine determines if /dev/pool device is present on the system and
4347c478bd9Sstevel@tonic-gate  * pools are currently enabled.  We want to do this directly from libproject
4357c478bd9Sstevel@tonic-gate  * without using libpool's pool_get_status() routine because pools could be
4367c478bd9Sstevel@tonic-gate  * completely removed from the system.  Return 1 if pools are enabled, or
4377c478bd9Sstevel@tonic-gate  * 0 otherwise.  When used inside local zones, always pretend that pools
4387c478bd9Sstevel@tonic-gate  * are disabled because binding is not allowed and we're already in the
4397c478bd9Sstevel@tonic-gate  * right pool.
4407c478bd9Sstevel@tonic-gate  */
4417c478bd9Sstevel@tonic-gate static int
4427c478bd9Sstevel@tonic-gate pools_enabled(void)
4437c478bd9Sstevel@tonic-gate {
4447c478bd9Sstevel@tonic-gate 	pool_status_t status;
4457c478bd9Sstevel@tonic-gate 	int fd;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	if (getzoneid() != GLOBAL_ZONEID)
4487c478bd9Sstevel@tonic-gate 		return (0);
4497c478bd9Sstevel@tonic-gate 	if ((fd = open("/dev/pool", O_RDONLY)) < 0)
4507c478bd9Sstevel@tonic-gate 		return (0);
4517c478bd9Sstevel@tonic-gate 	if (ioctl(fd, POOL_STATUSQ, &status) < 0) {
4527c478bd9Sstevel@tonic-gate 		(void) close(fd);
4537c478bd9Sstevel@tonic-gate 		return (0);
4547c478bd9Sstevel@tonic-gate 	}
4557c478bd9Sstevel@tonic-gate 	(void) close(fd);
4567c478bd9Sstevel@tonic-gate 	return (status.ps_io_state);
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate /*
4607c478bd9Sstevel@tonic-gate  * A pool_name of NULL means to attempt to bind to the default pool.
4617c478bd9Sstevel@tonic-gate  * If the "force" flag is non-zero, the value of "system.bind-default" will be
4627c478bd9Sstevel@tonic-gate  * ignored, and the process will be bound to the default pool if one exists.
4637c478bd9Sstevel@tonic-gate  */
4647c478bd9Sstevel@tonic-gate static int
4657c478bd9Sstevel@tonic-gate bind_to_pool(const char *pool_name, pid_t pid, int force)
4667c478bd9Sstevel@tonic-gate {
4677c478bd9Sstevel@tonic-gate 	pool_value_t *pvals[] = { NULL, NULL };
4687c478bd9Sstevel@tonic-gate 	pool_t **pools;
4697c478bd9Sstevel@tonic-gate 	uint_t nelem;
4707c478bd9Sstevel@tonic-gate 	uchar_t bval;
4717c478bd9Sstevel@tonic-gate 	pool_conf_t *conf;
4727c478bd9Sstevel@tonic-gate 	const char *nm;
4737c478bd9Sstevel@tonic-gate 	int retval;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	if ((conf = pool_conf_alloc()) == NULL)
4767c478bd9Sstevel@tonic-gate 		return (-1);
4777c478bd9Sstevel@tonic-gate 	if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) < 0) {
4787c478bd9Sstevel@tonic-gate 		/*
4797c478bd9Sstevel@tonic-gate 		 * Pools configuration file is corrupted; allow logins.
4807c478bd9Sstevel@tonic-gate 		 */
4817c478bd9Sstevel@tonic-gate 		pool_conf_free(conf);
4827c478bd9Sstevel@tonic-gate 		return (0);
4837c478bd9Sstevel@tonic-gate 	}
4847c478bd9Sstevel@tonic-gate 	if (pool_name != NULL && pool_get_pool(conf, pool_name) != NULL) {
4857c478bd9Sstevel@tonic-gate 		/*
4867c478bd9Sstevel@tonic-gate 		 * There was a project.pool entry, and the pool it refers to
4877c478bd9Sstevel@tonic-gate 		 * is a valid (active) pool.
4887c478bd9Sstevel@tonic-gate 		 */
4897c478bd9Sstevel@tonic-gate 		(void) pool_conf_close(conf);
4907c478bd9Sstevel@tonic-gate 		pool_conf_free(conf);
4917c478bd9Sstevel@tonic-gate 		if (pool_set_binding(pool_name, P_PID, pid) != PO_SUCCESS) {
4927c478bd9Sstevel@tonic-gate 			if (pool_error() != POE_SYSTEM)
4937c478bd9Sstevel@tonic-gate 				errno = EINVAL;
4947c478bd9Sstevel@tonic-gate 			return (-1);
4957c478bd9Sstevel@tonic-gate 		}
4967c478bd9Sstevel@tonic-gate 		return (0);
4977c478bd9Sstevel@tonic-gate 	}
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	/*
5007c478bd9Sstevel@tonic-gate 	 * Bind to the pool with 'pool.default' = 'true' if
5017c478bd9Sstevel@tonic-gate 	 * 'system.bind-default' = 'true'.
5027c478bd9Sstevel@tonic-gate 	 */
5037c478bd9Sstevel@tonic-gate 	if ((pvals[0] = pool_value_alloc()) == NULL) {
5047c478bd9Sstevel@tonic-gate 		pool_conf_close(conf);
5057c478bd9Sstevel@tonic-gate 		pool_conf_free(conf);
5067c478bd9Sstevel@tonic-gate 		return (-1);
5077c478bd9Sstevel@tonic-gate 	}
5087c478bd9Sstevel@tonic-gate 	if (!force && pool_get_property(conf, pool_conf_to_elem(conf),
5097c478bd9Sstevel@tonic-gate 	    "system.bind-default", pvals[0]) != POC_BOOL ||
5107c478bd9Sstevel@tonic-gate 	    pool_value_get_bool(pvals[0], &bval) != PO_SUCCESS ||
5117c478bd9Sstevel@tonic-gate 	    bval == PO_FALSE) {
5127c478bd9Sstevel@tonic-gate 		pool_value_free(pvals[0]);
5137c478bd9Sstevel@tonic-gate 		pool_conf_close(conf);
5147c478bd9Sstevel@tonic-gate 		pool_conf_free(conf);
5157c478bd9Sstevel@tonic-gate 		errno = pool_name == NULL ? EACCES : ESRCH;
5167c478bd9Sstevel@tonic-gate 		return (-1);
5177c478bd9Sstevel@tonic-gate 	}
5187c478bd9Sstevel@tonic-gate 	(void) pool_value_set_name(pvals[0], "pool.default");
5197c478bd9Sstevel@tonic-gate 	pool_value_set_bool(pvals[0], PO_TRUE);
5207c478bd9Sstevel@tonic-gate 	if ((pools = pool_query_pools(conf, &nelem, pvals)) == NULL) {
5217c478bd9Sstevel@tonic-gate 		/*
5227c478bd9Sstevel@tonic-gate 		 * No default pools exist.
5237c478bd9Sstevel@tonic-gate 		 */
5247c478bd9Sstevel@tonic-gate 		pool_value_free(pvals[0]);
5257c478bd9Sstevel@tonic-gate 		pool_conf_close(conf);
5267c478bd9Sstevel@tonic-gate 		pool_conf_free(conf);
5277c478bd9Sstevel@tonic-gate 		errno = pool_name == NULL ? EACCES : ESRCH;
5287c478bd9Sstevel@tonic-gate 		return (-1);
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 	if (nelem != 1 ||
5317c478bd9Sstevel@tonic-gate 	    pool_get_property(conf, pool_to_elem(conf, pools[0]), "pool.name",
5327c478bd9Sstevel@tonic-gate 	    pvals[0]) != POC_STRING) {
5337c478bd9Sstevel@tonic-gate 		/*
5347c478bd9Sstevel@tonic-gate 		 * Configuration is invalid.
5357c478bd9Sstevel@tonic-gate 		 */
5367c478bd9Sstevel@tonic-gate 		free(pools);
5377c478bd9Sstevel@tonic-gate 		pool_value_free(pvals[0]);
5387c478bd9Sstevel@tonic-gate 		(void) pool_conf_close(conf);
5397c478bd9Sstevel@tonic-gate 		pool_conf_free(conf);
5407c478bd9Sstevel@tonic-gate 		return (0);
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate 	free(pools);
5437c478bd9Sstevel@tonic-gate 	(void) pool_conf_close(conf);
5447c478bd9Sstevel@tonic-gate 	pool_conf_free(conf);
5457c478bd9Sstevel@tonic-gate 	(void) pool_value_get_string(pvals[0], &nm);
5467c478bd9Sstevel@tonic-gate 	if (pool_set_binding(nm, P_PID, pid) != PO_SUCCESS) {
5477c478bd9Sstevel@tonic-gate 		if (pool_error() != POE_SYSTEM)
5487c478bd9Sstevel@tonic-gate 			errno = EINVAL;
5497c478bd9Sstevel@tonic-gate 		retval = -1;
5507c478bd9Sstevel@tonic-gate 	} else {
5517c478bd9Sstevel@tonic-gate 		retval = 0;
5527c478bd9Sstevel@tonic-gate 	}
5537c478bd9Sstevel@tonic-gate 	pool_value_free(pvals[0]);
5547c478bd9Sstevel@tonic-gate 	return (retval);
5557c478bd9Sstevel@tonic-gate }
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate /*
5587c478bd9Sstevel@tonic-gate  * Changes the assigned project, task and resource pool of a stopped target
5597c478bd9Sstevel@tonic-gate  * process.
5607c478bd9Sstevel@tonic-gate  *
5617c478bd9Sstevel@tonic-gate  * We may not have access to the project table if our target process is in
5627c478bd9Sstevel@tonic-gate  * getprojbyname()'s execution path. Similarly, we may not be able to get user
5637c478bd9Sstevel@tonic-gate  * information if the target process is in getpwnam()'s execution path. Thus we
5647c478bd9Sstevel@tonic-gate  * give the caller the option of skipping these checks by providing a pointer to
5657c478bd9Sstevel@tonic-gate  * a pre-validated project structure in proj (whose name matches project_name)
5667c478bd9Sstevel@tonic-gate  * and taking responsibility for ensuring that the target process' owner is a
5677c478bd9Sstevel@tonic-gate  * member of the target project.
5687c478bd9Sstevel@tonic-gate  *
5697c478bd9Sstevel@tonic-gate  * Callers of this function should always provide a pre-validated project
5707c478bd9Sstevel@tonic-gate  * structure in proj unless they can be sure that the target process will never
5717c478bd9Sstevel@tonic-gate  * be in setproject_proc()'s execution path.
5727c478bd9Sstevel@tonic-gate  */
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate projid_t
5757c478bd9Sstevel@tonic-gate setproject_proc(const char *project_name, const char *user_name, int flags,
5767c478bd9Sstevel@tonic-gate     pid_t pid, struct ps_prochandle *Pr, struct project *proj)
5777c478bd9Sstevel@tonic-gate {
5787c478bd9Sstevel@tonic-gate 	char pwdbuf[NSS_BUFLEN_PASSWD];
5797c478bd9Sstevel@tonic-gate 	char prbuf[PROJECT_BUFSZ];
5807c478bd9Sstevel@tonic-gate 	projid_t projid;
5817c478bd9Sstevel@tonic-gate 	struct passwd pwd;
5827c478bd9Sstevel@tonic-gate 	int i;
5837c478bd9Sstevel@tonic-gate 	int unknown = 0;
5847c478bd9Sstevel@tonic-gate 	int ret = 0;
5857c478bd9Sstevel@tonic-gate 	kva_t *kv_array;
5867c478bd9Sstevel@tonic-gate 	struct project local_proj; /* space to store proj if not provided */
587532877c4Srd117015 	const char *pool_name = NULL;
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	if (project_name != NULL) {
5907c478bd9Sstevel@tonic-gate 		/*
5917c478bd9Sstevel@tonic-gate 		 * Sanity checks.
5927c478bd9Sstevel@tonic-gate 		 */
5937c478bd9Sstevel@tonic-gate 		if (strcmp(project_name, "") == 0 ||
5947c478bd9Sstevel@tonic-gate 		    user_name == NULL) {
5957c478bd9Sstevel@tonic-gate 			errno = EINVAL;
5967c478bd9Sstevel@tonic-gate 			return (SETPROJ_ERR_TASK);
5977c478bd9Sstevel@tonic-gate 		}
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 		/*
6007c478bd9Sstevel@tonic-gate 		 * If proj is NULL, acquire project information to ensure that
6017c478bd9Sstevel@tonic-gate 		 * project_name is a valid project, and confirm that user_name
6027c478bd9Sstevel@tonic-gate 		 * exists and is a member of the specified project.
6037c478bd9Sstevel@tonic-gate 		 */
6047c478bd9Sstevel@tonic-gate 		if (proj == NULL) {
6057c478bd9Sstevel@tonic-gate 			if ((proj = getprojbyname(project_name, &local_proj,
6067c478bd9Sstevel@tonic-gate 			    prbuf, PROJECT_BUFSZ)) == NULL) {
6077c478bd9Sstevel@tonic-gate 				errno = ESRCH;
6087c478bd9Sstevel@tonic-gate 				return (SETPROJ_ERR_TASK);
6097c478bd9Sstevel@tonic-gate 			}
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 			if (getpwnam_r(user_name, &pwd,
6127c478bd9Sstevel@tonic-gate 			    pwdbuf, NSS_BUFLEN_PASSWD) == NULL) {
6137c478bd9Sstevel@tonic-gate 				errno = ESRCH;
6147c478bd9Sstevel@tonic-gate 				return (SETPROJ_ERR_TASK);
6157c478bd9Sstevel@tonic-gate 			}
6167c478bd9Sstevel@tonic-gate 			/*
6177c478bd9Sstevel@tonic-gate 			 * Root can join any project.
6187c478bd9Sstevel@tonic-gate 			 */
6197c478bd9Sstevel@tonic-gate 			if (pwd.pw_uid != (uid_t)0 &&
6207c478bd9Sstevel@tonic-gate 			    !inproj(user_name, project_name, prbuf,
6217c478bd9Sstevel@tonic-gate 			    PROJECT_BUFSZ)) {
6227c478bd9Sstevel@tonic-gate 				errno = ESRCH;
6237c478bd9Sstevel@tonic-gate 				return (SETPROJ_ERR_TASK);
6247c478bd9Sstevel@tonic-gate 			}
6257c478bd9Sstevel@tonic-gate 		}
6267c478bd9Sstevel@tonic-gate 		projid = proj->pj_projid;
6277c478bd9Sstevel@tonic-gate 	} else {
6287c478bd9Sstevel@tonic-gate 		projid = getprojid();
6297c478bd9Sstevel@tonic-gate 	}
6307c478bd9Sstevel@tonic-gate 
631532877c4Srd117015 
6327c478bd9Sstevel@tonic-gate 	if ((kv_array = _str2kva(proj->pj_attr, KV_ASSIGN,
6337c478bd9Sstevel@tonic-gate 	    KV_DELIMITER)) != NULL) {
6347c478bd9Sstevel@tonic-gate 		for (i = 0; i < kv_array->length; i++) {
6357c478bd9Sstevel@tonic-gate 			if (strcmp(kv_array->data[i].key,
6367c478bd9Sstevel@tonic-gate 			    "project.pool") == 0) {
6377c478bd9Sstevel@tonic-gate 				pool_name = kv_array->data[i].value;
6387c478bd9Sstevel@tonic-gate 			}
639532877c4Srd117015 			if (strcmp(kv_array->data[i].key, "task.final") == 0) {
640532877c4Srd117015 				flags |= TASK_FINAL;
6417c478bd9Sstevel@tonic-gate 			}
6427c478bd9Sstevel@tonic-gate 		}
6437c478bd9Sstevel@tonic-gate 	}
6447c478bd9Sstevel@tonic-gate 
6450209230bSgjelinek 	/*
646532877c4Srd117015 	 * Bind process to a pool only if pools are configured
6470209230bSgjelinek 	 */
648532877c4Srd117015 	if (pools_enabled() == 1) {
649532877c4Srd117015 		char *old_pool_name;
650532877c4Srd117015 		/*
651532877c4Srd117015 		 * Attempt to bind to pool before calling
652532877c4Srd117015 		 * settaskid().
653532877c4Srd117015 		 */
654532877c4Srd117015 		old_pool_name = pool_get_binding(pid);
655532877c4Srd117015 		if (bind_to_pool(pool_name, pid, 0) != 0) {
6567c478bd9Sstevel@tonic-gate 			if (old_pool_name)
6577c478bd9Sstevel@tonic-gate 				free(old_pool_name);
6587c478bd9Sstevel@tonic-gate 			_kva_free(kv_array);
6597c478bd9Sstevel@tonic-gate 			return (SETPROJ_ERR_POOL);
6607c478bd9Sstevel@tonic-gate 		}
661532877c4Srd117015 		if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) {
6627c478bd9Sstevel@tonic-gate 			int saved_errno = errno;
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 			/*
6657c478bd9Sstevel@tonic-gate 			 * Undo pool binding.
6667c478bd9Sstevel@tonic-gate 			 */
6677c478bd9Sstevel@tonic-gate 			(void) bind_to_pool(old_pool_name, pid, 1);
6687c478bd9Sstevel@tonic-gate 			if (old_pool_name)
6697c478bd9Sstevel@tonic-gate 				free(old_pool_name);
6707c478bd9Sstevel@tonic-gate 			_kva_free(kv_array);
6717c478bd9Sstevel@tonic-gate 			/*
6727c478bd9Sstevel@tonic-gate 			 * Restore errno
6737c478bd9Sstevel@tonic-gate 			 */
6747c478bd9Sstevel@tonic-gate 			errno = saved_errno;
6757c478bd9Sstevel@tonic-gate 			return (SETPROJ_ERR_TASK);
6767c478bd9Sstevel@tonic-gate 		}
6777c478bd9Sstevel@tonic-gate 		if (old_pool_name)
6787c478bd9Sstevel@tonic-gate 			free(old_pool_name);
6797c478bd9Sstevel@tonic-gate 	} else {
6807c478bd9Sstevel@tonic-gate 		/*
6817c478bd9Sstevel@tonic-gate 		 * Pools are not configured, so simply create new task.
6827c478bd9Sstevel@tonic-gate 		 */
683532877c4Srd117015 		if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) {
684532877c4Srd117015 			_kva_free(kv_array);
6857c478bd9Sstevel@tonic-gate 			return (SETPROJ_ERR_TASK);
686532877c4Srd117015 		}
6877c478bd9Sstevel@tonic-gate 	}
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	if (project_name == NULL) {
6907c478bd9Sstevel@tonic-gate 		/*
6917c478bd9Sstevel@tonic-gate 		 * In the case that we are starting a new task in the
6927c478bd9Sstevel@tonic-gate 		 * current project, we are finished, since the current
6937c478bd9Sstevel@tonic-gate 		 * resource controls will still apply. (Implicit behaviour:
6947c478bd9Sstevel@tonic-gate 		 * a project must be entirely logged out before name
6957c478bd9Sstevel@tonic-gate 		 * service changes will take effect.)
6967c478bd9Sstevel@tonic-gate 		 */
6977c478bd9Sstevel@tonic-gate 		_kva_free(kv_array);
6987c478bd9Sstevel@tonic-gate 		return (projid);
6997c478bd9Sstevel@tonic-gate 	}
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	if (kv_array == NULL)
7027c478bd9Sstevel@tonic-gate 		return (0);
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	for (i = 0; i < kv_array->length; i++) {
7057c478bd9Sstevel@tonic-gate 		/*
7067c478bd9Sstevel@tonic-gate 		 * Providing a special, i.e. a non-resource control, key?  Then
7077c478bd9Sstevel@tonic-gate 		 * parse that key here and end with "continue;".
7087c478bd9Sstevel@tonic-gate 		 */
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 		/*
7117c478bd9Sstevel@tonic-gate 		 * For generic bindings, the kernel performs the binding, as
7127c478bd9Sstevel@tonic-gate 		 * these are resource controls advertised by kernel subsystems.
7137c478bd9Sstevel@tonic-gate 		 */
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 		/*
7167c478bd9Sstevel@tonic-gate 		 * Check for known attribute name.
7177c478bd9Sstevel@tonic-gate 		 */
7187c478bd9Sstevel@tonic-gate 		errno = 0;
7197c478bd9Sstevel@tonic-gate 		if (rctl_walk(rctlwalkfunc, (void *)kv_array->data[i].key)
7207c478bd9Sstevel@tonic-gate 		    == 0)
7217c478bd9Sstevel@tonic-gate 			continue;
7227c478bd9Sstevel@tonic-gate 		if (errno) {
7237c478bd9Sstevel@tonic-gate 			_kva_free(kv_array);
7247c478bd9Sstevel@tonic-gate 			return (SETPROJ_ERR_TASK);
7257c478bd9Sstevel@tonic-gate 		}
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 		ret = rctl_set(kv_array->data[i].key,
728532877c4Srd117015 		    kv_array->data[i].value, Pr, flags & TASK_PROJ_MASK);
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 		if (ret && unknown == 0) {
7317c478bd9Sstevel@tonic-gate 			/*
7327c478bd9Sstevel@tonic-gate 			 * We only report the first failure.
7337c478bd9Sstevel@tonic-gate 			 */
7347c478bd9Sstevel@tonic-gate 			unknown = i + 1;
7357c478bd9Sstevel@tonic-gate 		}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 		if (ret && ret != SETFAILED) {
7387c478bd9Sstevel@tonic-gate 			/*
7397c478bd9Sstevel@tonic-gate 			 * We abort if we couldn't set a component, but if
7407c478bd9Sstevel@tonic-gate 			 * it's merely that the system didn't recognize it, we
7417c478bd9Sstevel@tonic-gate 			 * continue, as this could be a third party attribute.
7427c478bd9Sstevel@tonic-gate 			 */
7437c478bd9Sstevel@tonic-gate 			break;
7447c478bd9Sstevel@tonic-gate 		}
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 	_kva_free(kv_array);
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	return (unknown);
7497c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate projid_t
7527c478bd9Sstevel@tonic-gate setproject(const char *project_name, const char *user_name, int flags)
7537c478bd9Sstevel@tonic-gate {
7547c478bd9Sstevel@tonic-gate 	return (setproject_proc(project_name, user_name, flags, P_MYID, NULL,
7557c478bd9Sstevel@tonic-gate 	    NULL));
7567c478bd9Sstevel@tonic-gate }
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate priv_set_t *
7607c478bd9Sstevel@tonic-gate setproject_initpriv(void)
7617c478bd9Sstevel@tonic-gate {
7627c478bd9Sstevel@tonic-gate 	static priv_t taskpriv = PRIV_PROC_TASKID;
7637c478bd9Sstevel@tonic-gate 	static priv_t rctlpriv = PRIV_SYS_RESOURCE;
7647c478bd9Sstevel@tonic-gate 	static priv_t poolpriv = PRIV_SYS_RES_CONFIG;
7657c478bd9Sstevel@tonic-gate 	static priv_t schedpriv = PRIV_PROC_PRIOCNTL;
7667c478bd9Sstevel@tonic-gate 	int res;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	priv_set_t *nset;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	if (getzoneid() == GLOBAL_ZONEID) {
7717c478bd9Sstevel@tonic-gate 		res = __init_suid_priv(0, taskpriv, rctlpriv, poolpriv,
7727c478bd9Sstevel@tonic-gate 		    schedpriv, (char *)NULL);
7737c478bd9Sstevel@tonic-gate 	} else {
7747c478bd9Sstevel@tonic-gate 		res = __init_suid_priv(0, taskpriv, rctlpriv, (char *)NULL);
7757c478bd9Sstevel@tonic-gate 	}
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	if (res != 0)
7787c478bd9Sstevel@tonic-gate 		return (NULL);
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	nset = priv_allocset();
7817c478bd9Sstevel@tonic-gate 	if (nset != NULL) {
7827c478bd9Sstevel@tonic-gate 		priv_emptyset(nset);
7837c478bd9Sstevel@tonic-gate 		(void) priv_addset(nset, taskpriv);
7847c478bd9Sstevel@tonic-gate 		(void) priv_addset(nset, rctlpriv);
7857c478bd9Sstevel@tonic-gate 		/*
7867c478bd9Sstevel@tonic-gate 		 * Only need these if we need to change pools, which can
7877c478bd9Sstevel@tonic-gate 		 * only happen if the target is in the global zone.  Rather
7887c478bd9Sstevel@tonic-gate 		 * than checking the target's zone just check our own
7897c478bd9Sstevel@tonic-gate 		 * (since if we're in a non-global zone we won't be able
7907c478bd9Sstevel@tonic-gate 		 * to control processes in other zones).
7917c478bd9Sstevel@tonic-gate 		 */
7927c478bd9Sstevel@tonic-gate 		if (getzoneid() == GLOBAL_ZONEID) {
7937c478bd9Sstevel@tonic-gate 			(void) priv_addset(nset, poolpriv);
7947c478bd9Sstevel@tonic-gate 			(void) priv_addset(nset, schedpriv);
7957c478bd9Sstevel@tonic-gate 		}
7967c478bd9Sstevel@tonic-gate 	}
7977c478bd9Sstevel@tonic-gate 	return (nset);
7987c478bd9Sstevel@tonic-gate }
799