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