xref: /titanic_51/usr/src/uts/common/syscall/rctlsys.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/rctl.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/rctl_impl.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/syslog.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/policy.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/proc.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/task.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate /*
45*7c478bd9Sstevel@tonic-gate  * setrctl(2), getrctl(2), and private rctlsys(2*) system calls
46*7c478bd9Sstevel@tonic-gate  *
47*7c478bd9Sstevel@tonic-gate  * Resource control block (rctlblk_ptr_t, rctl_opaque_t)
48*7c478bd9Sstevel@tonic-gate  *   The resource control system call interfaces present the resource control
49*7c478bd9Sstevel@tonic-gate  *   values and flags via the resource control block abstraction, made manifest
50*7c478bd9Sstevel@tonic-gate  *   via an opaque data type with strict type definitions.  Keeping the formal
51*7c478bd9Sstevel@tonic-gate  *   definitions in the rcontrol block allows us to be clever in the kernel,
52*7c478bd9Sstevel@tonic-gate  *   combining attributes where appropriate in the current implementation while
53*7c478bd9Sstevel@tonic-gate  *   preserving binary compatibility in the face of implementation changes.
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate #define	RBX_TO_BLK	0x1
57*7c478bd9Sstevel@tonic-gate #define	RBX_FROM_BLK	0x2
58*7c478bd9Sstevel@tonic-gate #define	RBX_VAL		0x4
59*7c478bd9Sstevel@tonic-gate #define	RBX_CTL		0x8
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate static void
62*7c478bd9Sstevel@tonic-gate rctlsys_rblk_xfrm(rctl_opaque_t *blk, rctl_dict_entry_t *rde,
63*7c478bd9Sstevel@tonic-gate     rctl_val_t *val, int flags)
64*7c478bd9Sstevel@tonic-gate {
65*7c478bd9Sstevel@tonic-gate 	if (flags & RBX_FROM_BLK) {
66*7c478bd9Sstevel@tonic-gate 		if (flags & RBX_VAL) {
67*7c478bd9Sstevel@tonic-gate 			/*
68*7c478bd9Sstevel@tonic-gate 			 * Firing time cannot be set.
69*7c478bd9Sstevel@tonic-gate 			 */
70*7c478bd9Sstevel@tonic-gate 			val->rcv_privilege = blk->rcq_privilege;
71*7c478bd9Sstevel@tonic-gate 			val->rcv_value = blk->rcq_value;
72*7c478bd9Sstevel@tonic-gate 			val->rcv_flagaction = blk->rcq_local_flagaction;
73*7c478bd9Sstevel@tonic-gate 			val->rcv_action_signal = blk->rcq_local_signal;
74*7c478bd9Sstevel@tonic-gate 			val->rcv_action_recip_pid =
75*7c478bd9Sstevel@tonic-gate 			    blk->rcq_local_recipient_pid;
76*7c478bd9Sstevel@tonic-gate 		}
77*7c478bd9Sstevel@tonic-gate 		if (flags & RBX_CTL) {
78*7c478bd9Sstevel@tonic-gate 			rde->rcd_flagaction = blk->rcq_global_flagaction;
79*7c478bd9Sstevel@tonic-gate 			rde->rcd_syslog_level = blk->rcq_global_syslog_level;
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 			/*
82*7c478bd9Sstevel@tonic-gate 			 * Because the strlog() interface supports fewer options
83*7c478bd9Sstevel@tonic-gate 			 * than are made available via the syslog() interface to
84*7c478bd9Sstevel@tonic-gate 			 * userland, we map the syslog level down to a smaller
85*7c478bd9Sstevel@tonic-gate 			 * set of distinct logging behaviours.
86*7c478bd9Sstevel@tonic-gate 			 */
87*7c478bd9Sstevel@tonic-gate 			rde->rcd_strlog_flags = 0;
88*7c478bd9Sstevel@tonic-gate 			switch (blk->rcq_global_syslog_level) {
89*7c478bd9Sstevel@tonic-gate 				case LOG_EMERG:
90*7c478bd9Sstevel@tonic-gate 				case LOG_ALERT:
91*7c478bd9Sstevel@tonic-gate 				case LOG_CRIT:
92*7c478bd9Sstevel@tonic-gate 					rde->rcd_strlog_flags |= SL_CONSOLE;
93*7c478bd9Sstevel@tonic-gate 					/*FALLTHROUGH*/
94*7c478bd9Sstevel@tonic-gate 				case LOG_ERR:
95*7c478bd9Sstevel@tonic-gate 					rde->rcd_strlog_flags |= SL_ERROR;
96*7c478bd9Sstevel@tonic-gate 					/*FALLTHROUGH*/
97*7c478bd9Sstevel@tonic-gate 				case LOG_WARNING:
98*7c478bd9Sstevel@tonic-gate 					rde->rcd_strlog_flags |= SL_WARN;
99*7c478bd9Sstevel@tonic-gate 					break;
100*7c478bd9Sstevel@tonic-gate 				case LOG_NOTICE:
101*7c478bd9Sstevel@tonic-gate 					rde->rcd_strlog_flags |= SL_CONSOLE;
102*7c478bd9Sstevel@tonic-gate 					/*FALLTHROUGH*/
103*7c478bd9Sstevel@tonic-gate 				case LOG_INFO:	/* informational */
104*7c478bd9Sstevel@tonic-gate 				case LOG_DEBUG:	/* debug-level messages */
105*7c478bd9Sstevel@tonic-gate 				default:
106*7c478bd9Sstevel@tonic-gate 					rde->rcd_strlog_flags |= SL_NOTE;
107*7c478bd9Sstevel@tonic-gate 					break;
108*7c478bd9Sstevel@tonic-gate 			}
109*7c478bd9Sstevel@tonic-gate 		}
110*7c478bd9Sstevel@tonic-gate 	} else {
111*7c478bd9Sstevel@tonic-gate 		bzero(blk,  sizeof (rctl_opaque_t));
112*7c478bd9Sstevel@tonic-gate 		if (flags & RBX_VAL) {
113*7c478bd9Sstevel@tonic-gate 			blk->rcq_privilege = val->rcv_privilege;
114*7c478bd9Sstevel@tonic-gate 			blk->rcq_value = val->rcv_value;
115*7c478bd9Sstevel@tonic-gate 			blk->rcq_enforced_value = rctl_model_value(rde,
116*7c478bd9Sstevel@tonic-gate 			    curproc, val->rcv_value);
117*7c478bd9Sstevel@tonic-gate 			blk->rcq_local_flagaction = val->rcv_flagaction;
118*7c478bd9Sstevel@tonic-gate 			blk->rcq_local_signal = val->rcv_action_signal;
119*7c478bd9Sstevel@tonic-gate 			blk->rcq_firing_time = val->rcv_firing_time;
120*7c478bd9Sstevel@tonic-gate 			blk->rcq_local_recipient_pid =
121*7c478bd9Sstevel@tonic-gate 			    val->rcv_action_recip_pid;
122*7c478bd9Sstevel@tonic-gate 		}
123*7c478bd9Sstevel@tonic-gate 		if (flags & RBX_CTL) {
124*7c478bd9Sstevel@tonic-gate 			blk->rcq_global_flagaction = rde->rcd_flagaction;
125*7c478bd9Sstevel@tonic-gate 			blk->rcq_global_syslog_level = rde->rcd_syslog_level;
126*7c478bd9Sstevel@tonic-gate 		}
127*7c478bd9Sstevel@tonic-gate 	}
128*7c478bd9Sstevel@tonic-gate }
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate /*
131*7c478bd9Sstevel@tonic-gate  * int rctl_invalid_value(rctl_dict_entry_t *, rctl_val_t *)
132*7c478bd9Sstevel@tonic-gate  *
133*7c478bd9Sstevel@tonic-gate  * Overview
134*7c478bd9Sstevel@tonic-gate  *   Perform basic validation of proposed new resource control value against the
135*7c478bd9Sstevel@tonic-gate  *   global properties set on the control.  Any system call operation presented
136*7c478bd9Sstevel@tonic-gate  *   with an invalid resource control value should return -1 and set errno to
137*7c478bd9Sstevel@tonic-gate  *   EINVAL.
138*7c478bd9Sstevel@tonic-gate  *
139*7c478bd9Sstevel@tonic-gate  * Return values
140*7c478bd9Sstevel@tonic-gate  *   0 if valid, 1 if invalid.
141*7c478bd9Sstevel@tonic-gate  *
142*7c478bd9Sstevel@tonic-gate  * Caller's context
143*7c478bd9Sstevel@tonic-gate  *   No restriction on context.
144*7c478bd9Sstevel@tonic-gate  */
145*7c478bd9Sstevel@tonic-gate int
146*7c478bd9Sstevel@tonic-gate rctl_invalid_value(rctl_dict_entry_t *rde, rctl_val_t *rval)
147*7c478bd9Sstevel@tonic-gate {
148*7c478bd9Sstevel@tonic-gate 	rctl_val_t *sys_rval;
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	if (rval->rcv_privilege != RCPRIV_BASIC &&
151*7c478bd9Sstevel@tonic-gate 	    rval->rcv_privilege != RCPRIV_PRIVILEGED &&
152*7c478bd9Sstevel@tonic-gate 	    rval->rcv_privilege != RCPRIV_SYSTEM)
153*7c478bd9Sstevel@tonic-gate 		return (1);
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	if (rval->rcv_flagaction & ~RCTL_LOCAL_MASK)
156*7c478bd9Sstevel@tonic-gate 		return (1);
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	if (rval->rcv_privilege == RCPRIV_BASIC &&
159*7c478bd9Sstevel@tonic-gate 	    (rde->rcd_flagaction & RCTL_GLOBAL_NOBASIC) != 0)
160*7c478bd9Sstevel@tonic-gate 		return (1);
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	if ((rval->rcv_flagaction & RCTL_LOCAL_DENY) == 0 &&
163*7c478bd9Sstevel@tonic-gate 	    (rde->rcd_flagaction & RCTL_GLOBAL_DENY_ALWAYS) != 0)
164*7c478bd9Sstevel@tonic-gate 		return (1);
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 	if ((rval->rcv_flagaction & RCTL_LOCAL_DENY) &&
167*7c478bd9Sstevel@tonic-gate 	    (rde->rcd_flagaction & RCTL_GLOBAL_DENY_NEVER))
168*7c478bd9Sstevel@tonic-gate 		return (1);
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	if ((rval->rcv_flagaction & RCTL_LOCAL_SIGNAL) &&
171*7c478bd9Sstevel@tonic-gate 	    (rde->rcd_flagaction & RCTL_GLOBAL_SIGNAL_NEVER))
172*7c478bd9Sstevel@tonic-gate 		return (1);
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	if ((rval->rcv_flagaction & RCTL_LOCAL_SIGNAL) &&
175*7c478bd9Sstevel@tonic-gate 	    rval->rcv_action_signal == 0)
176*7c478bd9Sstevel@tonic-gate 		return (1);
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 	if (rval->rcv_action_signal == SIGXCPU &&
179*7c478bd9Sstevel@tonic-gate 	    (rde->rcd_flagaction & RCTL_GLOBAL_CPU_TIME) == 0)
180*7c478bd9Sstevel@tonic-gate 		return (1);
181*7c478bd9Sstevel@tonic-gate 	else if (rval->rcv_action_signal == SIGXFSZ &&
182*7c478bd9Sstevel@tonic-gate 	    (rde->rcd_flagaction & RCTL_GLOBAL_FILE_SIZE) == 0)
183*7c478bd9Sstevel@tonic-gate 		return (1);
184*7c478bd9Sstevel@tonic-gate 	else if (rval->rcv_action_signal != SIGHUP &&
185*7c478bd9Sstevel@tonic-gate 	    rval->rcv_action_signal != SIGABRT &&
186*7c478bd9Sstevel@tonic-gate 	    rval->rcv_action_signal != SIGKILL &&
187*7c478bd9Sstevel@tonic-gate 	    rval->rcv_action_signal != SIGTERM &&
188*7c478bd9Sstevel@tonic-gate 	    rval->rcv_action_signal != SIGSTOP &&
189*7c478bd9Sstevel@tonic-gate 	    rval->rcv_action_signal != SIGXCPU &&
190*7c478bd9Sstevel@tonic-gate 	    rval->rcv_action_signal != SIGXFSZ &&
191*7c478bd9Sstevel@tonic-gate 	    rval->rcv_action_signal != SIGXRES &&
192*7c478bd9Sstevel@tonic-gate 	    rval->rcv_action_signal != 0)	/* That is, no signal is ok. */
193*7c478bd9Sstevel@tonic-gate 		return (1);
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	sys_rval = rde->rcd_default_value;
196*7c478bd9Sstevel@tonic-gate 	while (sys_rval->rcv_privilege != RCPRIV_SYSTEM)
197*7c478bd9Sstevel@tonic-gate 		sys_rval = sys_rval->rcv_next;
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 	if (rval->rcv_value > sys_rval->rcv_value)
200*7c478bd9Sstevel@tonic-gate 		return (1);
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	return (0);
203*7c478bd9Sstevel@tonic-gate }
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate /*
206*7c478bd9Sstevel@tonic-gate  * static long rctlsys_get(char *name, rctl_opaque_t *old_rblk,
207*7c478bd9Sstevel@tonic-gate  *   rctl_opaque_t *new_rblk, int flags)
208*7c478bd9Sstevel@tonic-gate  *
209*7c478bd9Sstevel@tonic-gate  * Overview
210*7c478bd9Sstevel@tonic-gate  *   rctlsys_get() is the implementation of the core logic of getrctl(2), the
211*7c478bd9Sstevel@tonic-gate  *   public system call for fetching resource control values.  Two mutually
212*7c478bd9Sstevel@tonic-gate  *   exclusive flag values are supported:  RCTL_FIRST and RCTL_NEXT.  When
213*7c478bd9Sstevel@tonic-gate  *   RCTL_FIRST is presented, the value of old_rblk is ignored, and the first
214*7c478bd9Sstevel@tonic-gate  *   value in the resource control value sequence for the named control is
215*7c478bd9Sstevel@tonic-gate  *   transformed and placed in the user memory location at new_rblk.  In the
216*7c478bd9Sstevel@tonic-gate  *   RCTL_NEXT case, the value of old_rblk is examined, and the next value in
217*7c478bd9Sstevel@tonic-gate  *   the sequence is transformed and placed at new_rblk.
218*7c478bd9Sstevel@tonic-gate  */
219*7c478bd9Sstevel@tonic-gate static long
220*7c478bd9Sstevel@tonic-gate rctlsys_get(char *name, rctl_opaque_t *old_rblk, rctl_opaque_t *new_rblk,
221*7c478bd9Sstevel@tonic-gate     int flags)
222*7c478bd9Sstevel@tonic-gate {
223*7c478bd9Sstevel@tonic-gate 	rctl_val_t *nval;
224*7c478bd9Sstevel@tonic-gate 	rctl_opaque_t *nblk;
225*7c478bd9Sstevel@tonic-gate 	rctl_hndl_t hndl;
226*7c478bd9Sstevel@tonic-gate 	char *kname;
227*7c478bd9Sstevel@tonic-gate 	size_t klen;
228*7c478bd9Sstevel@tonic-gate 	rctl_dict_entry_t *krde;
229*7c478bd9Sstevel@tonic-gate 	int ret;
230*7c478bd9Sstevel@tonic-gate 	int action = flags & (~RCTLSYS_ACTION_MASK);
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	if (flags & (~RCTLSYS_MASK))
233*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	if (action != RCTL_FIRST && action != RCTL_NEXT &&
236*7c478bd9Sstevel@tonic-gate 	    action != RCTL_USAGE)
237*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	if (new_rblk == NULL || name == NULL)
240*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	kname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
243*7c478bd9Sstevel@tonic-gate 	krde = kmem_alloc(sizeof (rctl_dict_entry_t), KM_SLEEP);
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	if (copyinstr(name, kname, MAXPATHLEN, &klen) != 0) {
246*7c478bd9Sstevel@tonic-gate 		kmem_free(kname, MAXPATHLEN);
247*7c478bd9Sstevel@tonic-gate 		kmem_free(krde, sizeof (rctl_dict_entry_t));
248*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
249*7c478bd9Sstevel@tonic-gate 	}
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 	if ((hndl = rctl_hndl_lookup(kname)) == -1) {
252*7c478bd9Sstevel@tonic-gate 		kmem_free(kname, MAXPATHLEN);
253*7c478bd9Sstevel@tonic-gate 		kmem_free(krde, sizeof (rctl_dict_entry_t));
254*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
255*7c478bd9Sstevel@tonic-gate 	}
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	if (rctl_global_get(kname, krde) == -1) {
258*7c478bd9Sstevel@tonic-gate 		kmem_free(kname, MAXPATHLEN);
259*7c478bd9Sstevel@tonic-gate 		kmem_free(krde, sizeof (rctl_dict_entry_t));
260*7c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
261*7c478bd9Sstevel@tonic-gate 	}
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	kmem_free(kname, MAXPATHLEN);
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	nval = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	if (action == RCTL_USAGE) {
268*7c478bd9Sstevel@tonic-gate 		kmem_cache_free(rctl_val_cache, nval);
269*7c478bd9Sstevel@tonic-gate 		kmem_free(krde, sizeof (rctl_dict_entry_t));
270*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENOTSUP));
271*7c478bd9Sstevel@tonic-gate 	} else if (action == RCTL_FIRST) {
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 		mutex_enter(&curproc->p_lock);
274*7c478bd9Sstevel@tonic-gate 		if (ret = rctl_local_get(hndl, NULL, nval, curproc)) {
275*7c478bd9Sstevel@tonic-gate 			mutex_exit(&curproc->p_lock);
276*7c478bd9Sstevel@tonic-gate 			kmem_cache_free(rctl_val_cache, nval);
277*7c478bd9Sstevel@tonic-gate 			kmem_free(krde, sizeof (rctl_dict_entry_t));
278*7c478bd9Sstevel@tonic-gate 			return (set_errno(ret));
279*7c478bd9Sstevel@tonic-gate 		}
280*7c478bd9Sstevel@tonic-gate 		mutex_exit(&curproc->p_lock);
281*7c478bd9Sstevel@tonic-gate 	} else {
282*7c478bd9Sstevel@tonic-gate 		/*
283*7c478bd9Sstevel@tonic-gate 		 * RCTL_NEXT
284*7c478bd9Sstevel@tonic-gate 		 */
285*7c478bd9Sstevel@tonic-gate 		rctl_val_t *oval;
286*7c478bd9Sstevel@tonic-gate 		rctl_opaque_t *oblk;
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 		oblk = kmem_alloc(sizeof (rctl_opaque_t), KM_SLEEP);
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 		if (copyin(old_rblk, oblk, sizeof (rctl_opaque_t)) == -1) {
291*7c478bd9Sstevel@tonic-gate 			kmem_cache_free(rctl_val_cache, nval);
292*7c478bd9Sstevel@tonic-gate 			kmem_free(oblk, sizeof (rctl_opaque_t));
293*7c478bd9Sstevel@tonic-gate 			kmem_free(krde, sizeof (rctl_dict_entry_t));
294*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
295*7c478bd9Sstevel@tonic-gate 		}
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 		oval = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 		rctlsys_rblk_xfrm(oblk, NULL, oval, RBX_FROM_BLK | RBX_VAL);
300*7c478bd9Sstevel@tonic-gate 		mutex_enter(&curproc->p_lock);
301*7c478bd9Sstevel@tonic-gate 		ret = rctl_local_get(hndl, oval, nval, curproc);
302*7c478bd9Sstevel@tonic-gate 		mutex_exit(&curproc->p_lock);
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 		kmem_cache_free(rctl_val_cache, oval);
305*7c478bd9Sstevel@tonic-gate 		kmem_free(oblk, sizeof (rctl_opaque_t));
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 		if (ret != 0) {
308*7c478bd9Sstevel@tonic-gate 			kmem_cache_free(rctl_val_cache, nval);
309*7c478bd9Sstevel@tonic-gate 			kmem_free(krde, sizeof (rctl_dict_entry_t));
310*7c478bd9Sstevel@tonic-gate 			return (set_errno(ret));
311*7c478bd9Sstevel@tonic-gate 		}
312*7c478bd9Sstevel@tonic-gate 	}
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 	nblk = kmem_alloc(sizeof (rctl_opaque_t), KM_SLEEP);
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	rctlsys_rblk_xfrm(nblk, krde, nval, RBX_TO_BLK | RBX_VAL | RBX_CTL);
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	kmem_free(krde, sizeof (rctl_dict_entry_t));
319*7c478bd9Sstevel@tonic-gate 	kmem_cache_free(rctl_val_cache, nval);
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	if (copyout(nblk, new_rblk, sizeof (rctl_opaque_t)) == -1) {
322*7c478bd9Sstevel@tonic-gate 		kmem_free(nblk, sizeof (rctl_opaque_t));
323*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
324*7c478bd9Sstevel@tonic-gate 	}
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	kmem_free(nblk, sizeof (rctl_opaque_t));
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	return (0);
329*7c478bd9Sstevel@tonic-gate }
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate /*
332*7c478bd9Sstevel@tonic-gate  * static long rctlsys_set(char *name, rctl_opaque_t *old_rblk,
333*7c478bd9Sstevel@tonic-gate  *   rctl_opaque_t *new_rblk, int flags)
334*7c478bd9Sstevel@tonic-gate  *
335*7c478bd9Sstevel@tonic-gate  * Overview
336*7c478bd9Sstevel@tonic-gate  *   rctlsys_set() is the implementation of the core login of setrctl(2), which
337*7c478bd9Sstevel@tonic-gate  *   allows the establishment of resource control values.  Flags may take on any
338*7c478bd9Sstevel@tonic-gate  *   of three exclusive values:  RCTL_INSERT, RCTL_DELETE, and RCTL_REPLACE.
339*7c478bd9Sstevel@tonic-gate  *   RCTL_INSERT ignores old_rblk and inserts the value in the appropriate
340*7c478bd9Sstevel@tonic-gate  *   position in the ordered sequence of resource control values.  RCTL_DELETE
341*7c478bd9Sstevel@tonic-gate  *   ignores old_rblk and deletes the first resource control value matching
342*7c478bd9Sstevel@tonic-gate  *   (value, priority) in the given resource block.  If no matching value is
343*7c478bd9Sstevel@tonic-gate  *   found, -1 is returned and errno is set to ENOENT.  Finally, in the case of
344*7c478bd9Sstevel@tonic-gate  *   RCTL_REPLACE, old_rblk is used to match (value, priority); the matching
345*7c478bd9Sstevel@tonic-gate  *   resource control value in the sequence is replaced with the contents of
346*7c478bd9Sstevel@tonic-gate  *   new_rblk.  Again, if no match is found, -1 is returned and errno is set to
347*7c478bd9Sstevel@tonic-gate  *   ENOENT.
348*7c478bd9Sstevel@tonic-gate  *
349*7c478bd9Sstevel@tonic-gate  *   rctlsys_set() causes a cursor test, which can reactivate resource controls
350*7c478bd9Sstevel@tonic-gate  *   that have previously fired.
351*7c478bd9Sstevel@tonic-gate  */
352*7c478bd9Sstevel@tonic-gate static long
353*7c478bd9Sstevel@tonic-gate rctlsys_set(char *name, rctl_opaque_t *old_rblk, rctl_opaque_t *new_rblk,
354*7c478bd9Sstevel@tonic-gate     int flags)
355*7c478bd9Sstevel@tonic-gate {
356*7c478bd9Sstevel@tonic-gate 	rctl_val_t *nval;
357*7c478bd9Sstevel@tonic-gate 	rctl_dict_entry_t *rde;
358*7c478bd9Sstevel@tonic-gate 	rctl_opaque_t *nblk;
359*7c478bd9Sstevel@tonic-gate 	rctl_hndl_t hndl;
360*7c478bd9Sstevel@tonic-gate 	char *kname;
361*7c478bd9Sstevel@tonic-gate 	size_t klen;
362*7c478bd9Sstevel@tonic-gate 	long ret = 0;
363*7c478bd9Sstevel@tonic-gate 	proc_t *pp = NULL;
364*7c478bd9Sstevel@tonic-gate 	pid_t pid;
365*7c478bd9Sstevel@tonic-gate 	int action = flags & (~RCTLSYS_ACTION_MASK);
366*7c478bd9Sstevel@tonic-gate 	rctl_val_t *oval;
367*7c478bd9Sstevel@tonic-gate 	rctl_val_t *rval1;
368*7c478bd9Sstevel@tonic-gate 	rctl_val_t *rval2;
369*7c478bd9Sstevel@tonic-gate 	rctl_val_t *tval;
370*7c478bd9Sstevel@tonic-gate 	rctl_opaque_t *oblk;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	if (flags & (~RCTLSYS_MASK))
373*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	if (action != RCTL_INSERT &&
376*7c478bd9Sstevel@tonic-gate 	    action != RCTL_DELETE &&
377*7c478bd9Sstevel@tonic-gate 	    action != RCTL_REPLACE)
378*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	if (new_rblk == NULL || name == NULL)
381*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	kname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
384*7c478bd9Sstevel@tonic-gate 	if (copyinstr(name, kname, MAXPATHLEN, &klen) != 0) {
385*7c478bd9Sstevel@tonic-gate 		kmem_free(kname, MAXPATHLEN);
386*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
387*7c478bd9Sstevel@tonic-gate 	}
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	if ((hndl = rctl_hndl_lookup(kname)) == -1) {
390*7c478bd9Sstevel@tonic-gate 		kmem_free(kname, MAXPATHLEN);
391*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
392*7c478bd9Sstevel@tonic-gate 	}
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	kmem_free(kname, MAXPATHLEN);
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	rde = rctl_dict_lookup_hndl(hndl);
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 	nblk = kmem_alloc(sizeof (rctl_opaque_t), KM_SLEEP);
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	if (copyin(new_rblk, nblk, sizeof (rctl_opaque_t)) == -1) {
401*7c478bd9Sstevel@tonic-gate 		kmem_free(nblk, sizeof (rctl_opaque_t));
402*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
403*7c478bd9Sstevel@tonic-gate 	}
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	nval = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 	rctlsys_rblk_xfrm(nblk, NULL, nval, RBX_FROM_BLK | RBX_VAL);
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	if (rctl_invalid_value(rde, nval)) {
410*7c478bd9Sstevel@tonic-gate 		kmem_free(nblk, sizeof (rctl_opaque_t));
411*7c478bd9Sstevel@tonic-gate 		kmem_cache_free(rctl_val_cache, nval);
412*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
413*7c478bd9Sstevel@tonic-gate 	}
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	/* allocate what we might need before potentially grabbing p_lock */
416*7c478bd9Sstevel@tonic-gate 	oblk = kmem_alloc(sizeof (rctl_opaque_t), KM_SLEEP);
417*7c478bd9Sstevel@tonic-gate 	oval = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
418*7c478bd9Sstevel@tonic-gate 	rval1 = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
419*7c478bd9Sstevel@tonic-gate 	rval2 = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 	if (nval->rcv_privilege == RCPRIV_BASIC) {
422*7c478bd9Sstevel@tonic-gate 		if (flags & RCTL_USE_RECIPIENT_PID) {
423*7c478bd9Sstevel@tonic-gate 			pid = nval->rcv_action_recip_pid;
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 			/* case for manipulating rctl values on other procs */
426*7c478bd9Sstevel@tonic-gate 			if (pid != curproc->p_pid) {
427*7c478bd9Sstevel@tonic-gate 				/* cannot be other pid on process rctls */
428*7c478bd9Sstevel@tonic-gate 				if (rde->rcd_entity == RCENTITY_PROCESS) {
429*7c478bd9Sstevel@tonic-gate 					ret = set_errno(EINVAL);
430*7c478bd9Sstevel@tonic-gate 					goto rctlsys_out;
431*7c478bd9Sstevel@tonic-gate 				}
432*7c478bd9Sstevel@tonic-gate 				/*
433*7c478bd9Sstevel@tonic-gate 				 * must have privilege to manipulate controls
434*7c478bd9Sstevel@tonic-gate 				 * on other processes
435*7c478bd9Sstevel@tonic-gate 				 */
436*7c478bd9Sstevel@tonic-gate 				if (secpolicy_rctlsys(CRED(), B_FALSE) != 0) {
437*7c478bd9Sstevel@tonic-gate 					ret = set_errno(EACCES);
438*7c478bd9Sstevel@tonic-gate 					goto rctlsys_out;
439*7c478bd9Sstevel@tonic-gate 				}
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 				pid = nval->rcv_action_recip_pid;
442*7c478bd9Sstevel@tonic-gate 				mutex_enter(&pidlock);
443*7c478bd9Sstevel@tonic-gate 				pp = prfind(pid);
444*7c478bd9Sstevel@tonic-gate 				if (!pp) {
445*7c478bd9Sstevel@tonic-gate 					mutex_exit(&pidlock);
446*7c478bd9Sstevel@tonic-gate 					ret = set_errno(ESRCH);
447*7c478bd9Sstevel@tonic-gate 					goto rctlsys_out;
448*7c478bd9Sstevel@tonic-gate 				}
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 				/*
451*7c478bd9Sstevel@tonic-gate 				 * idle or zombie procs have either not yet
452*7c478bd9Sstevel@tonic-gate 				 * set up their rctls or have already done
453*7c478bd9Sstevel@tonic-gate 				 * their rctl_set_tearoff's.
454*7c478bd9Sstevel@tonic-gate 				 */
455*7c478bd9Sstevel@tonic-gate 				if (pp->p_stat == SZOMB ||
456*7c478bd9Sstevel@tonic-gate 				    pp->p_stat == SIDL) {
457*7c478bd9Sstevel@tonic-gate 					mutex_exit(&pidlock);
458*7c478bd9Sstevel@tonic-gate 					ret = set_errno(ESRCH);
459*7c478bd9Sstevel@tonic-gate 					goto rctlsys_out;
460*7c478bd9Sstevel@tonic-gate 				}
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 				/*
463*7c478bd9Sstevel@tonic-gate 				 * hold this pp's p_lock to ensure that
464*7c478bd9Sstevel@tonic-gate 				 * it does not do it's rctl_set_tearoff
465*7c478bd9Sstevel@tonic-gate 				 * If we did not do this, we could
466*7c478bd9Sstevel@tonic-gate 				 * potentially add rctls to the entity
467*7c478bd9Sstevel@tonic-gate 				 * with a recipient that is a process
468*7c478bd9Sstevel@tonic-gate 				 * that has exited.
469*7c478bd9Sstevel@tonic-gate 				 */
470*7c478bd9Sstevel@tonic-gate 				mutex_enter(&pp->p_lock);
471*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 				/*
474*7c478bd9Sstevel@tonic-gate 				 * We know that curproc's task, project,
475*7c478bd9Sstevel@tonic-gate 				 * and zone pointers will not change
476*7c478bd9Sstevel@tonic-gate 				 * because functions that change them
477*7c478bd9Sstevel@tonic-gate 				 * call holdlwps(SHOLDFORK1) first.
478*7c478bd9Sstevel@tonic-gate 				 */
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 				/*
481*7c478bd9Sstevel@tonic-gate 				 * verify that the found pp is in the
482*7c478bd9Sstevel@tonic-gate 				 * current task.  If it is, then it
483*7c478bd9Sstevel@tonic-gate 				 * is also within the current project
484*7c478bd9Sstevel@tonic-gate 				 * and zone.
485*7c478bd9Sstevel@tonic-gate 				 */
486*7c478bd9Sstevel@tonic-gate 				if (rde->rcd_entity == RCENTITY_TASK &&
487*7c478bd9Sstevel@tonic-gate 				    pp->p_task != curproc->p_task) {
488*7c478bd9Sstevel@tonic-gate 					ret = set_errno(ESRCH);
489*7c478bd9Sstevel@tonic-gate 					goto rctlsys_out;
490*7c478bd9Sstevel@tonic-gate 				}
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 				ASSERT(pp->p_task->tk_proj ==
493*7c478bd9Sstevel@tonic-gate 				    curproc->p_task->tk_proj);
494*7c478bd9Sstevel@tonic-gate 				ASSERT(pp->p_zone == curproc->p_zone);
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 				nval->rcv_action_recipient = pp;
498*7c478bd9Sstevel@tonic-gate 				nval->rcv_action_recip_pid = pid;
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 			} else {
501*7c478bd9Sstevel@tonic-gate 				/* for manipulating rctl values on this proc */
502*7c478bd9Sstevel@tonic-gate 				mutex_enter(&curproc->p_lock);
503*7c478bd9Sstevel@tonic-gate 				pp = curproc;
504*7c478bd9Sstevel@tonic-gate 				nval->rcv_action_recipient = curproc;
505*7c478bd9Sstevel@tonic-gate 				nval->rcv_action_recip_pid = curproc->p_pid;
506*7c478bd9Sstevel@tonic-gate 			}
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 		} else {
509*7c478bd9Sstevel@tonic-gate 			/* RCTL_USE_RECIPIENT_PID not set, use this proc */
510*7c478bd9Sstevel@tonic-gate 			mutex_enter(&curproc->p_lock);
511*7c478bd9Sstevel@tonic-gate 			pp = curproc;
512*7c478bd9Sstevel@tonic-gate 			nval->rcv_action_recipient = curproc;
513*7c478bd9Sstevel@tonic-gate 			nval->rcv_action_recip_pid = curproc->p_pid;
514*7c478bd9Sstevel@tonic-gate 		}
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 	} else {
517*7c478bd9Sstevel@tonic-gate 		/* privileged controls have no recipient pid */
518*7c478bd9Sstevel@tonic-gate 		mutex_enter(&curproc->p_lock);
519*7c478bd9Sstevel@tonic-gate 		pp = curproc;
520*7c478bd9Sstevel@tonic-gate 		nval->rcv_action_recipient = NULL;
521*7c478bd9Sstevel@tonic-gate 		nval->rcv_action_recip_pid = -1;
522*7c478bd9Sstevel@tonic-gate 	}
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	nval->rcv_firing_time = 0;
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 	if (action == RCTL_REPLACE) {
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 		if (copyin(old_rblk, oblk, sizeof (rctl_opaque_t)) == -1) {
529*7c478bd9Sstevel@tonic-gate 			ret = set_errno(EFAULT);
530*7c478bd9Sstevel@tonic-gate 			goto rctlsys_out;
531*7c478bd9Sstevel@tonic-gate 		}
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 		rctlsys_rblk_xfrm(oblk, NULL, oval, RBX_FROM_BLK | RBX_VAL);
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 		if (rctl_invalid_value(rde, oval)) {
536*7c478bd9Sstevel@tonic-gate 			ret = set_errno(EINVAL);
537*7c478bd9Sstevel@tonic-gate 			goto rctlsys_out;
538*7c478bd9Sstevel@tonic-gate 		}
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 		if (oval->rcv_privilege == RCPRIV_BASIC) {
541*7c478bd9Sstevel@tonic-gate 			if (!(flags & RCTL_USE_RECIPIENT_PID)) {
542*7c478bd9Sstevel@tonic-gate 				oval->rcv_action_recipient = curproc;
543*7c478bd9Sstevel@tonic-gate 				oval->rcv_action_recip_pid = curproc->p_pid;
544*7c478bd9Sstevel@tonic-gate 			}
545*7c478bd9Sstevel@tonic-gate 		} else {
546*7c478bd9Sstevel@tonic-gate 			oval->rcv_action_recipient = NULL;
547*7c478bd9Sstevel@tonic-gate 			oval->rcv_action_recip_pid = -1;
548*7c478bd9Sstevel@tonic-gate 		}
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 		/*
551*7c478bd9Sstevel@tonic-gate 		 * Find the real value we're attempting to replace on the
552*7c478bd9Sstevel@tonic-gate 		 * sequence, rather than trusting the one delivered from
553*7c478bd9Sstevel@tonic-gate 		 * userland.
554*7c478bd9Sstevel@tonic-gate 		 */
555*7c478bd9Sstevel@tonic-gate 		if (ret = rctl_local_get(hndl, NULL, rval1, pp)) {
556*7c478bd9Sstevel@tonic-gate 			(void) set_errno(ret);
557*7c478bd9Sstevel@tonic-gate 			goto rctlsys_out;
558*7c478bd9Sstevel@tonic-gate 		}
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 		do {
561*7c478bd9Sstevel@tonic-gate 			if (rval1->rcv_privilege == RCPRIV_SYSTEM ||
562*7c478bd9Sstevel@tonic-gate 			    rctl_val_cmp(oval, rval1, 0) == 0)
563*7c478bd9Sstevel@tonic-gate 				break;
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 			tval = rval1;
566*7c478bd9Sstevel@tonic-gate 			rval1 = rval2;
567*7c478bd9Sstevel@tonic-gate 			rval2 = tval;
568*7c478bd9Sstevel@tonic-gate 		} while (rctl_local_get(hndl, rval2, rval1, pp) == 0);
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 		if (rval1->rcv_privilege == RCPRIV_SYSTEM) {
571*7c478bd9Sstevel@tonic-gate 			if (rctl_val_cmp(oval, rval1, 1) == 0)
572*7c478bd9Sstevel@tonic-gate 				ret = set_errno(EPERM);
573*7c478bd9Sstevel@tonic-gate 			else
574*7c478bd9Sstevel@tonic-gate 				ret = set_errno(ESRCH);
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 			goto rctlsys_out;
577*7c478bd9Sstevel@tonic-gate 		}
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 		bcopy(rval1, oval, sizeof (rctl_val_t));
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 		/*
582*7c478bd9Sstevel@tonic-gate 		 * System controls are immutable.
583*7c478bd9Sstevel@tonic-gate 		 */
584*7c478bd9Sstevel@tonic-gate 		if (nval->rcv_privilege == RCPRIV_SYSTEM) {
585*7c478bd9Sstevel@tonic-gate 			ret = set_errno(EPERM);
586*7c478bd9Sstevel@tonic-gate 			goto rctlsys_out;
587*7c478bd9Sstevel@tonic-gate 		}
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 		/*
590*7c478bd9Sstevel@tonic-gate 		 * Only privileged processes in the global zone can modify
591*7c478bd9Sstevel@tonic-gate 		 * privileged rctls of type RCENTITY_ZONE; replacing privileged
592*7c478bd9Sstevel@tonic-gate 		 * controls with basic ones are not allowed either.  Lowering a
593*7c478bd9Sstevel@tonic-gate 		 * lowerable one might be OK for privileged processes in a
594*7c478bd9Sstevel@tonic-gate 		 * non-global zone, but lowerable rctls probably don't make
595*7c478bd9Sstevel@tonic-gate 		 * sense for zones (hence, not modifiable from within a zone).
596*7c478bd9Sstevel@tonic-gate 		 */
597*7c478bd9Sstevel@tonic-gate 		if (rde->rcd_entity == RCENTITY_ZONE &&
598*7c478bd9Sstevel@tonic-gate 		    (nval->rcv_privilege == RCPRIV_PRIVILEGED ||
599*7c478bd9Sstevel@tonic-gate 		    oval->rcv_privilege == RCPRIV_PRIVILEGED) &&
600*7c478bd9Sstevel@tonic-gate 		    secpolicy_rctlsys(CRED(), B_TRUE) != 0) {
601*7c478bd9Sstevel@tonic-gate 			ret = set_errno(EACCES);
602*7c478bd9Sstevel@tonic-gate 			goto rctlsys_out;
603*7c478bd9Sstevel@tonic-gate 		}
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 		/*
606*7c478bd9Sstevel@tonic-gate 		 * Must be privileged to replace a privileged control with
607*7c478bd9Sstevel@tonic-gate 		 * a basic one.
608*7c478bd9Sstevel@tonic-gate 		 */
609*7c478bd9Sstevel@tonic-gate 		if (oval->rcv_privilege == RCPRIV_PRIVILEGED &&
610*7c478bd9Sstevel@tonic-gate 		    nval->rcv_privilege != RCPRIV_PRIVILEGED &&
611*7c478bd9Sstevel@tonic-gate 		    secpolicy_rctlsys(CRED(), B_FALSE) != 0) {
612*7c478bd9Sstevel@tonic-gate 			ret = set_errno(EACCES);
613*7c478bd9Sstevel@tonic-gate 			goto rctlsys_out;
614*7c478bd9Sstevel@tonic-gate 		}
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 		/*
617*7c478bd9Sstevel@tonic-gate 		 * Must have lowerable global property for non-privileged
618*7c478bd9Sstevel@tonic-gate 		 * to lower the value of a privileged control; otherwise must
619*7c478bd9Sstevel@tonic-gate 		 * have sufficient privileges to modify privileged controls
620*7c478bd9Sstevel@tonic-gate 		 * at all.
621*7c478bd9Sstevel@tonic-gate 		 */
622*7c478bd9Sstevel@tonic-gate 		if (oval->rcv_privilege == RCPRIV_PRIVILEGED &&
623*7c478bd9Sstevel@tonic-gate 		    nval->rcv_privilege == RCPRIV_PRIVILEGED &&
624*7c478bd9Sstevel@tonic-gate 		    ((((rde->rcd_flagaction & RCTL_GLOBAL_LOWERABLE) == 0) ||
625*7c478bd9Sstevel@tonic-gate 		    oval->rcv_flagaction != nval->rcv_flagaction ||
626*7c478bd9Sstevel@tonic-gate 		    oval->rcv_action_signal != nval->rcv_action_signal ||
627*7c478bd9Sstevel@tonic-gate 		    oval->rcv_value < nval->rcv_value)) &&
628*7c478bd9Sstevel@tonic-gate 		    secpolicy_rctlsys(CRED(), B_FALSE) != 0) {
629*7c478bd9Sstevel@tonic-gate 			ret = set_errno(EACCES);
630*7c478bd9Sstevel@tonic-gate 			goto rctlsys_out;
631*7c478bd9Sstevel@tonic-gate 		}
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 		if (ret = rctl_local_replace(hndl, oval, nval, pp)) {
634*7c478bd9Sstevel@tonic-gate 			(void) set_errno(ret);
635*7c478bd9Sstevel@tonic-gate 			goto rctlsys_out;
636*7c478bd9Sstevel@tonic-gate 		}
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 		/* ensure that nval is not freed */
639*7c478bd9Sstevel@tonic-gate 		nval = NULL;
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 	} else if (action == RCTL_INSERT) {
642*7c478bd9Sstevel@tonic-gate 		/*
643*7c478bd9Sstevel@tonic-gate 		 * System controls are immutable.
644*7c478bd9Sstevel@tonic-gate 		 */
645*7c478bd9Sstevel@tonic-gate 		if (nval->rcv_privilege == RCPRIV_SYSTEM) {
646*7c478bd9Sstevel@tonic-gate 			ret = set_errno(EPERM);
647*7c478bd9Sstevel@tonic-gate 			goto rctlsys_out;
648*7c478bd9Sstevel@tonic-gate 		}
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate 		/*
651*7c478bd9Sstevel@tonic-gate 		 * Only privileged processes in the global zone may add
652*7c478bd9Sstevel@tonic-gate 		 * privileged zone.* rctls.  Only privileged processes
653*7c478bd9Sstevel@tonic-gate 		 * may add other privileged rctls.
654*7c478bd9Sstevel@tonic-gate 		 */
655*7c478bd9Sstevel@tonic-gate 		if (nval->rcv_privilege == RCPRIV_PRIVILEGED) {
656*7c478bd9Sstevel@tonic-gate 			if ((rde->rcd_entity == RCENTITY_ZONE &&
657*7c478bd9Sstevel@tonic-gate 			    secpolicy_rctlsys(CRED(), B_TRUE) != 0) ||
658*7c478bd9Sstevel@tonic-gate 			    (rde->rcd_entity != RCENTITY_ZONE &&
659*7c478bd9Sstevel@tonic-gate 			    secpolicy_rctlsys(CRED(), B_FALSE) != 0)) {
660*7c478bd9Sstevel@tonic-gate 				ret = set_errno(EACCES);
661*7c478bd9Sstevel@tonic-gate 				goto rctlsys_out;
662*7c478bd9Sstevel@tonic-gate 			}
663*7c478bd9Sstevel@tonic-gate 		}
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 		/*
666*7c478bd9Sstevel@tonic-gate 		 * Only one basic control is allowed per rctl.
667*7c478bd9Sstevel@tonic-gate 		 * If a basic control is being inserted, delete
668*7c478bd9Sstevel@tonic-gate 		 * any other basic control.
669*7c478bd9Sstevel@tonic-gate 		 */
670*7c478bd9Sstevel@tonic-gate 		if ((nval->rcv_privilege == RCPRIV_BASIC) &&
671*7c478bd9Sstevel@tonic-gate 		    (rctl_local_get(hndl, NULL, rval1, pp) == 0)) {
672*7c478bd9Sstevel@tonic-gate 			do {
673*7c478bd9Sstevel@tonic-gate 				if (rval1->rcv_privilege == RCPRIV_BASIC &&
674*7c478bd9Sstevel@tonic-gate 				    rval1->rcv_action_recipient == curproc) {
675*7c478bd9Sstevel@tonic-gate 					(void) rctl_local_delete(hndl, rval1,
676*7c478bd9Sstevel@tonic-gate 					    pp);
677*7c478bd9Sstevel@tonic-gate 					if (rctl_local_get(hndl, NULL, rval1,
678*7c478bd9Sstevel@tonic-gate 					    pp) != 0)
679*7c478bd9Sstevel@tonic-gate 						break;
680*7c478bd9Sstevel@tonic-gate 				}
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate 				tval = rval1;
683*7c478bd9Sstevel@tonic-gate 				rval1 = rval2;
684*7c478bd9Sstevel@tonic-gate 				rval2 = tval;
685*7c478bd9Sstevel@tonic-gate 			} while (rctl_local_get(hndl, rval2, rval1, pp)
686*7c478bd9Sstevel@tonic-gate 			    == 0);
687*7c478bd9Sstevel@tonic-gate 		}
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate 		if (ret = rctl_local_insert(hndl, nval, pp)) {
691*7c478bd9Sstevel@tonic-gate 			(void) set_errno(ret);
692*7c478bd9Sstevel@tonic-gate 			goto rctlsys_out;
693*7c478bd9Sstevel@tonic-gate 		}
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 		/* ensure that nval is not freed */
696*7c478bd9Sstevel@tonic-gate 		nval = NULL;
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	} else {
699*7c478bd9Sstevel@tonic-gate 		/*
700*7c478bd9Sstevel@tonic-gate 		 * RCTL_DELETE
701*7c478bd9Sstevel@tonic-gate 		 */
702*7c478bd9Sstevel@tonic-gate 		if (nval->rcv_privilege == RCPRIV_SYSTEM) {
703*7c478bd9Sstevel@tonic-gate 			ret = set_errno(EPERM);
704*7c478bd9Sstevel@tonic-gate 			goto rctlsys_out;
705*7c478bd9Sstevel@tonic-gate 		}
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate 		if (nval->rcv_privilege == RCPRIV_PRIVILEGED) {
708*7c478bd9Sstevel@tonic-gate 			if ((rde->rcd_entity == RCENTITY_ZONE &&
709*7c478bd9Sstevel@tonic-gate 			    secpolicy_rctlsys(CRED(), B_TRUE) != 0) ||
710*7c478bd9Sstevel@tonic-gate 			    (rde->rcd_entity != RCENTITY_ZONE &&
711*7c478bd9Sstevel@tonic-gate 			    secpolicy_rctlsys(CRED(), B_FALSE) != 0)) {
712*7c478bd9Sstevel@tonic-gate 				ret = set_errno(EACCES);
713*7c478bd9Sstevel@tonic-gate 				goto rctlsys_out;
714*7c478bd9Sstevel@tonic-gate 			}
715*7c478bd9Sstevel@tonic-gate 		}
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 		if (ret = rctl_local_delete(hndl, nval, pp)) {
718*7c478bd9Sstevel@tonic-gate 			(void) set_errno(ret);
719*7c478bd9Sstevel@tonic-gate 			goto rctlsys_out;
720*7c478bd9Sstevel@tonic-gate 		}
721*7c478bd9Sstevel@tonic-gate 	}
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate rctlsys_out:
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate 	if (pp)
726*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pp->p_lock);
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate 	kmem_free(nblk, sizeof (rctl_opaque_t));
729*7c478bd9Sstevel@tonic-gate 	kmem_free(oblk, sizeof (rctl_opaque_t));
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate 	/* only free nval if we did not rctl_local_insert it */
732*7c478bd9Sstevel@tonic-gate 	if (nval)
733*7c478bd9Sstevel@tonic-gate 		kmem_cache_free(rctl_val_cache, nval);
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate 	kmem_cache_free(rctl_val_cache, oval);
736*7c478bd9Sstevel@tonic-gate 	kmem_cache_free(rctl_val_cache, rval1);
737*7c478bd9Sstevel@tonic-gate 	kmem_cache_free(rctl_val_cache, rval2);
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 	return (ret);
740*7c478bd9Sstevel@tonic-gate }
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate static long
743*7c478bd9Sstevel@tonic-gate rctlsys_lst(char *ubuf, size_t ubufsz)
744*7c478bd9Sstevel@tonic-gate {
745*7c478bd9Sstevel@tonic-gate 	char *kbuf;
746*7c478bd9Sstevel@tonic-gate 	size_t kbufsz;
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 	kbufsz = rctl_build_name_buf(&kbuf);
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 	if (kbufsz <= ubufsz &&
751*7c478bd9Sstevel@tonic-gate 	    copyout(kbuf, ubuf, kbufsz) != 0) {
752*7c478bd9Sstevel@tonic-gate 		kmem_free(kbuf, kbufsz);
753*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
754*7c478bd9Sstevel@tonic-gate 	}
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 	kmem_free(kbuf, kbufsz);
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate 	return (kbufsz);
759*7c478bd9Sstevel@tonic-gate }
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate static long
762*7c478bd9Sstevel@tonic-gate rctlsys_ctl(char *name, rctl_opaque_t *rblk, int flags)
763*7c478bd9Sstevel@tonic-gate {
764*7c478bd9Sstevel@tonic-gate 	rctl_dict_entry_t *krde;
765*7c478bd9Sstevel@tonic-gate 	rctl_opaque_t *krblk;
766*7c478bd9Sstevel@tonic-gate 	char *kname;
767*7c478bd9Sstevel@tonic-gate 	size_t klen;
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 	kname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 	if (name == NULL || copyinstr(name, kname, MAXPATHLEN, &klen) != 0) {
772*7c478bd9Sstevel@tonic-gate 		kmem_free(kname, MAXPATHLEN);
773*7c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
774*7c478bd9Sstevel@tonic-gate 	}
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	switch (flags) {
777*7c478bd9Sstevel@tonic-gate 	case RCTLCTL_GET:
778*7c478bd9Sstevel@tonic-gate 		krde = kmem_alloc(sizeof (rctl_dict_entry_t), KM_SLEEP);
779*7c478bd9Sstevel@tonic-gate 		krblk = kmem_zalloc(sizeof (rctl_opaque_t), KM_SLEEP);
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 		if (rctl_global_get(kname, krde) == -1) {
782*7c478bd9Sstevel@tonic-gate 			kmem_free(krde, sizeof (rctl_dict_entry_t));
783*7c478bd9Sstevel@tonic-gate 			kmem_free(krblk, sizeof (rctl_opaque_t));
784*7c478bd9Sstevel@tonic-gate 			kmem_free(kname, MAXPATHLEN);
785*7c478bd9Sstevel@tonic-gate 			return (set_errno(ESRCH));
786*7c478bd9Sstevel@tonic-gate 		}
787*7c478bd9Sstevel@tonic-gate 
788*7c478bd9Sstevel@tonic-gate 		rctlsys_rblk_xfrm(krblk, krde, NULL, RBX_TO_BLK | RBX_CTL);
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 		if (copyout(krblk, rblk, sizeof (rctl_opaque_t)) != 0) {
791*7c478bd9Sstevel@tonic-gate 			kmem_free(krde, sizeof (rctl_dict_entry_t));
792*7c478bd9Sstevel@tonic-gate 			kmem_free(krblk, sizeof (rctl_opaque_t));
793*7c478bd9Sstevel@tonic-gate 			kmem_free(kname, MAXPATHLEN);
794*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
795*7c478bd9Sstevel@tonic-gate 		}
796*7c478bd9Sstevel@tonic-gate 
797*7c478bd9Sstevel@tonic-gate 		kmem_free(krde, sizeof (rctl_dict_entry_t));
798*7c478bd9Sstevel@tonic-gate 		kmem_free(krblk, sizeof (rctl_opaque_t));
799*7c478bd9Sstevel@tonic-gate 		kmem_free(kname, MAXPATHLEN);
800*7c478bd9Sstevel@tonic-gate 		break;
801*7c478bd9Sstevel@tonic-gate 	case RCTLCTL_SET:
802*7c478bd9Sstevel@tonic-gate 		if (secpolicy_rctlsys(CRED(), B_TRUE) != 0) {
803*7c478bd9Sstevel@tonic-gate 			kmem_free(kname, MAXPATHLEN);
804*7c478bd9Sstevel@tonic-gate 			return (set_errno(EPERM));
805*7c478bd9Sstevel@tonic-gate 		}
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate 		krde = kmem_alloc(sizeof (rctl_dict_entry_t), KM_SLEEP);
808*7c478bd9Sstevel@tonic-gate 		krblk = kmem_zalloc(sizeof (rctl_opaque_t), KM_SLEEP);
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 		if (rctl_global_get(kname, krde) == -1) {
811*7c478bd9Sstevel@tonic-gate 			kmem_free(krde, sizeof (rctl_dict_entry_t));
812*7c478bd9Sstevel@tonic-gate 			kmem_free(krblk, sizeof (rctl_opaque_t));
813*7c478bd9Sstevel@tonic-gate 			kmem_free(kname, MAXPATHLEN);
814*7c478bd9Sstevel@tonic-gate 			return (set_errno(ESRCH));
815*7c478bd9Sstevel@tonic-gate 		}
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 		if (copyin(rblk, krblk, sizeof (rctl_opaque_t)) != 0) {
818*7c478bd9Sstevel@tonic-gate 			kmem_free(krde, sizeof (rctl_dict_entry_t));
819*7c478bd9Sstevel@tonic-gate 			kmem_free(krblk, sizeof (rctl_opaque_t));
820*7c478bd9Sstevel@tonic-gate 			kmem_free(kname, MAXPATHLEN);
821*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
822*7c478bd9Sstevel@tonic-gate 		}
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 		rctlsys_rblk_xfrm(krblk, krde, NULL, RBX_FROM_BLK | RBX_CTL);
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate 		if (rctl_global_set(kname, krde) == -1) {
827*7c478bd9Sstevel@tonic-gate 			kmem_free(krde, sizeof (rctl_dict_entry_t));
828*7c478bd9Sstevel@tonic-gate 			kmem_free(krblk, sizeof (rctl_opaque_t));
829*7c478bd9Sstevel@tonic-gate 			kmem_free(kname, MAXPATHLEN);
830*7c478bd9Sstevel@tonic-gate 			return (set_errno(ESRCH));
831*7c478bd9Sstevel@tonic-gate 		}
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate 		kmem_free(krde, sizeof (rctl_dict_entry_t));
834*7c478bd9Sstevel@tonic-gate 		kmem_free(krblk, sizeof (rctl_opaque_t));
835*7c478bd9Sstevel@tonic-gate 		kmem_free(kname, MAXPATHLEN);
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate 		break;
838*7c478bd9Sstevel@tonic-gate 	default:
839*7c478bd9Sstevel@tonic-gate 		kmem_free(kname, MAXPATHLEN);
840*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
841*7c478bd9Sstevel@tonic-gate 	}
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 	return (0);
844*7c478bd9Sstevel@tonic-gate }
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate long
847*7c478bd9Sstevel@tonic-gate rctlsys(int code, char *name, void *obuf, void *nbuf, size_t obufsz, int flags)
848*7c478bd9Sstevel@tonic-gate {
849*7c478bd9Sstevel@tonic-gate 	switch (code) {
850*7c478bd9Sstevel@tonic-gate 	case 0:
851*7c478bd9Sstevel@tonic-gate 		return (rctlsys_get(name, obuf, nbuf, flags));
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 	case 1:
854*7c478bd9Sstevel@tonic-gate 		return (rctlsys_set(name, obuf, nbuf, flags));
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 	case 2:
857*7c478bd9Sstevel@tonic-gate 		/*
858*7c478bd9Sstevel@tonic-gate 		 * Private call for rctl_walk(3C).
859*7c478bd9Sstevel@tonic-gate 		 */
860*7c478bd9Sstevel@tonic-gate 		return (rctlsys_lst(obuf, obufsz));
861*7c478bd9Sstevel@tonic-gate 
862*7c478bd9Sstevel@tonic-gate 	case 3:
863*7c478bd9Sstevel@tonic-gate 		/*
864*7c478bd9Sstevel@tonic-gate 		 * Private code for rctladm(1M):  "rctlctl".
865*7c478bd9Sstevel@tonic-gate 		 */
866*7c478bd9Sstevel@tonic-gate 		return (rctlsys_ctl(name, obuf, flags));
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 	default:
869*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
870*7c478bd9Sstevel@tonic-gate 	}
871*7c478bd9Sstevel@tonic-gate }
872