xref: /onnv-gate/usr/src/lib/libvscan/common/libvscan.c (revision 5440:f84b7f8d106d)
1*5440Sjm199354 /*
2*5440Sjm199354  * CDDL HEADER START
3*5440Sjm199354  *
4*5440Sjm199354  * The contents of this file are subject to the terms of the
5*5440Sjm199354  * Common Development and Distribution License (the "License").
6*5440Sjm199354  * You may not use this file except in compliance with the License.
7*5440Sjm199354  *
8*5440Sjm199354  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5440Sjm199354  * or http://www.opensolaris.org/os/licensing.
10*5440Sjm199354  * See the License for the specific language governing permissions
11*5440Sjm199354  * and limitations under the License.
12*5440Sjm199354  *
13*5440Sjm199354  * When distributing Covered Code, include this CDDL HEADER in each
14*5440Sjm199354  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5440Sjm199354  * If applicable, add the following below this CDDL HEADER, with the
16*5440Sjm199354  * fields enclosed by brackets "[]" replaced with your own identifying
17*5440Sjm199354  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5440Sjm199354  *
19*5440Sjm199354  * CDDL HEADER END
20*5440Sjm199354  */
21*5440Sjm199354 /*
22*5440Sjm199354  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*5440Sjm199354  * Use is subject to license terms.
24*5440Sjm199354  */
25*5440Sjm199354 
26*5440Sjm199354 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*5440Sjm199354 
28*5440Sjm199354 #include <string.h>
29*5440Sjm199354 #include <stdio.h>
30*5440Sjm199354 #include <stdlib.h>
31*5440Sjm199354 #include <unistd.h>
32*5440Sjm199354 #include <ctype.h>
33*5440Sjm199354 #include <math.h>
34*5440Sjm199354 #include <limits.h>
35*5440Sjm199354 #include <libscf.h>
36*5440Sjm199354 #include <errno.h>
37*5440Sjm199354 #include <fcntl.h>
38*5440Sjm199354 #include <door.h>
39*5440Sjm199354 #include <pwd.h>
40*5440Sjm199354 #include <auth_attr.h>
41*5440Sjm199354 #include <secdb.h>
42*5440Sjm199354 #include <sys/socket.h>
43*5440Sjm199354 #include <arpa/inet.h>
44*5440Sjm199354 #include <libintl.h>
45*5440Sjm199354 #include <libvscan.h>
46*5440Sjm199354 
47*5440Sjm199354 #define	VS_INSTANCE_FMRI	"svc:/system/filesystem/vscan:icap"
48*5440Sjm199354 
49*5440Sjm199354 /* SMF property group and property names */
50*5440Sjm199354 #define	VS_PGNAME_GENERAL		"vs_general"
51*5440Sjm199354 #define	VS_PGNAME_ENGINE		"vs_engine_%d"
52*5440Sjm199354 #define	VS_PGNAME_ENGINE_LEN		16
53*5440Sjm199354 
54*5440Sjm199354 #define	VS_PNAME_MAXSIZE		"maxsize"
55*5440Sjm199354 #define	VS_PNAME_MAXSIZE_ACTION		"maxsize_action"
56*5440Sjm199354 #define	VS_PNAME_TYPES			"types"
57*5440Sjm199354 #define	VS_PNAME_VLOG			"viruslog"
58*5440Sjm199354 
59*5440Sjm199354 #define	VS_PNAME_SE_ENABLE		"enable"
60*5440Sjm199354 #define	VS_PNAME_SE_HOST		"host"
61*5440Sjm199354 #define	VS_PNAME_SE_PORT		"port"
62*5440Sjm199354 #define	VS_PNAME_SE_MAXCONN		"max_connect"
63*5440Sjm199354 #define	VS_PNAME_VAUTH			"value_authorization"
64*5440Sjm199354 
65*5440Sjm199354 
66*5440Sjm199354 /* types string processing */
67*5440Sjm199354 #define	VS_TYPES_SEP		','
68*5440Sjm199354 #define	VS_TYPES_ESCAPE		'\\'
69*5440Sjm199354 #define	VS_TYPES_RULES		"+-"
70*5440Sjm199354 
71*5440Sjm199354 
72*5440Sjm199354 /*
73*5440Sjm199354  * The SCF context enapsulating the SCF objects used in the
74*5440Sjm199354  * repository load and store routines vs_scf_values_get()
75*5440Sjm199354  * and vs_scf_values_set().
76*5440Sjm199354  *
77*5440Sjm199354  * The context is always opened before a get or set, then
78*5440Sjm199354  * closed when finished (or on error); the open does an
79*5440Sjm199354  * initial setup, while inside the get and set functions,
80*5440Sjm199354  * additional objects within the context may be selectively
81*5440Sjm199354  * initialized for use, depending on the actions needed and
82*5440Sjm199354  * the properties being operated on.
83*5440Sjm199354  */
84*5440Sjm199354 typedef struct vs_scfctx {
85*5440Sjm199354 	scf_handle_t *vscf_handle;
86*5440Sjm199354 	scf_instance_t *vscf_inst;
87*5440Sjm199354 	scf_propertygroup_t *vscf_pgroup;
88*5440Sjm199354 	scf_transaction_t *vscf_tx;
89*5440Sjm199354 	scf_iter_t *vscf_iter;
90*5440Sjm199354 	scf_property_t *vscf_prop[VS_NUM_PROPIDS];
91*5440Sjm199354 	scf_transaction_entry_t *vscf_ent[VS_NUM_PROPIDS];
92*5440Sjm199354 	scf_value_t *vscf_val[VS_NUM_PROPIDS];
93*5440Sjm199354 } vs_scfctx_t;
94*5440Sjm199354 
95*5440Sjm199354 /*
96*5440Sjm199354  * The vscan property definition. Maps the property id with the name
97*5440Sjm199354  * and type used to store the property in the repository.
98*5440Sjm199354  * A table of these definitions is defined with a single entry per
99*5440Sjm199354  * property.
100*5440Sjm199354  */
101*5440Sjm199354 typedef struct {
102*5440Sjm199354 	const char *vpd_name;
103*5440Sjm199354 	uint64_t vpd_id;
104*5440Sjm199354 	scf_type_t vpd_type;
105*5440Sjm199354 } vs_propdef_t;
106*5440Sjm199354 
107*5440Sjm199354 typedef enum {
108*5440Sjm199354 	VS_PTYPE_GEN,
109*5440Sjm199354 	VS_PTYPE_SE
110*5440Sjm199354 } vs_prop_type_t;
111*5440Sjm199354 
112*5440Sjm199354 typedef struct vs_prop_hd {
113*5440Sjm199354 	vs_prop_type_t vp_type;
114*5440Sjm199354 	uint64_t vp_ids;
115*5440Sjm199354 	uint64_t vp_all;
116*5440Sjm199354 	union {
117*5440Sjm199354 		vs_props_t vp_gen;
118*5440Sjm199354 		vs_props_se_t vp_se;
119*5440Sjm199354 	} vp_props;
120*5440Sjm199354 } vs_prop_hd_t;
121*5440Sjm199354 
122*5440Sjm199354 #define	vp_gen	vp_props.vp_gen
123*5440Sjm199354 #define	vp_se	vp_props.vp_se
124*5440Sjm199354 
125*5440Sjm199354 /*
126*5440Sjm199354  * Default values - these are used to return valid data
127*5440Sjm199354  * to the caller in cases where invalid or unexpected values
128*5440Sjm199354  * are found in the repository.
129*5440Sjm199354  *
130*5440Sjm199354  * Note: These values must be kept in sync with those defined
131*5440Sjm199354  * in the service manifest.
132*5440Sjm199354  */
133*5440Sjm199354 static const boolean_t vs_dflt_allow = B_TRUE;
134*5440Sjm199354 static const boolean_t vs_dflt_enable = B_TRUE;
135*5440Sjm199354 static const char *vs_dflt_maxsize = "1GB";
136*5440Sjm199354 static const char *vs_dflt_host = "";
137*5440Sjm199354 static const uint16_t vs_dflt_port = 1344;
138*5440Sjm199354 static const uint16_t vs_dflt_maxconn = 32L;
139*5440Sjm199354 static const  char *vs_dflt_types = "+*";
140*5440Sjm199354 static const char *vs_dflt_vlog = "";
141*5440Sjm199354 
142*5440Sjm199354 /* Property definition table */
143*5440Sjm199354 static const vs_propdef_t vs_propdefs[] = {
144*5440Sjm199354 	/* general properties */
145*5440Sjm199354 	{ VS_PNAME_MAXSIZE, VS_PROPID_MAXSIZE, SCF_TYPE_ASTRING },
146*5440Sjm199354 	{ VS_PNAME_MAXSIZE_ACTION, VS_PROPID_MAXSIZE_ACTION, SCF_TYPE_BOOLEAN },
147*5440Sjm199354 	{ VS_PNAME_TYPES, VS_PROPID_TYPES, SCF_TYPE_ASTRING },
148*5440Sjm199354 	{ VS_PNAME_VLOG, VS_PROPID_VLOG, SCF_TYPE_ASTRING },
149*5440Sjm199354 	/* scan engine properties */
150*5440Sjm199354 	{ VS_PNAME_SE_ENABLE, VS_PROPID_SE_ENABLE, SCF_TYPE_BOOLEAN },
151*5440Sjm199354 	{ VS_PNAME_SE_HOST, VS_PROPID_SE_HOST, SCF_TYPE_HOST },
152*5440Sjm199354 	{ VS_PNAME_SE_PORT, VS_PROPID_SE_PORT, SCF_TYPE_INTEGER },
153*5440Sjm199354 	{ VS_PNAME_SE_MAXCONN, VS_PROPID_SE_MAXCONN, SCF_TYPE_INTEGER },
154*5440Sjm199354 	{ VS_PNAME_VAUTH, VS_PROPID_VALUE_AUTH, SCF_TYPE_ASTRING }
155*5440Sjm199354 };
156*5440Sjm199354 
157*5440Sjm199354 static const int vs_npropdefs = sizeof (vs_propdefs)/sizeof (vs_propdef_t);
158*5440Sjm199354 
159*5440Sjm199354 /* Local functions */
160*5440Sjm199354 static const vs_propdef_t *vs_get_propdef(uint64_t);
161*5440Sjm199354 static void vs_default_value(vs_prop_hd_t *, const uint64_t);
162*5440Sjm199354 
163*5440Sjm199354 static int vs_scf_values_get(const char *, vs_prop_hd_t *);
164*5440Sjm199354 static int vs_scf_get(const vs_propdef_t *, vs_prop_hd_t *, vs_scfctx_t *, int);
165*5440Sjm199354 
166*5440Sjm199354 static int vs_scf_values_set(const char *, vs_prop_hd_t *);
167*5440Sjm199354 static int vs_scf_set(const vs_propdef_t *, vs_prop_hd_t *, vs_scfctx_t *, int);
168*5440Sjm199354 static int vs_scf_pg_create(const char *, vs_prop_hd_t *);
169*5440Sjm199354 
170*5440Sjm199354 static int vs_scf_ctx_open(vs_scfctx_t *);
171*5440Sjm199354 static void vs_scf_ctx_close(vs_scfctx_t *);
172*5440Sjm199354 
173*5440Sjm199354 static int vs_validate(const vs_prop_hd_t *, uint64_t);
174*5440Sjm199354 static int vs_is_valid_types(const char *);
175*5440Sjm199354 static int vs_is_valid_host(const char *);
176*5440Sjm199354 static int vs_checkauth(char *);
177*5440Sjm199354 
178*5440Sjm199354 typedef char vs_engid_t[VS_SE_NAME_LEN];
179*5440Sjm199354 static int vs_props_get_engines(vs_engid_t *engids, int *count);
180*5440Sjm199354 static int vs_scf_pg_count(void);
181*5440Sjm199354 static int vs_strtoshift(const char *);
182*5440Sjm199354 
183*5440Sjm199354 
184*5440Sjm199354 /*
185*5440Sjm199354  * vs_props_get_all
186*5440Sjm199354  *
187*5440Sjm199354  * Retrieves the general service properties and all properties
188*5440Sjm199354  * for all scan engines from the repository.
189*5440Sjm199354  *
190*5440Sjm199354  * If invalid property values are found, the values are corrected to
191*5440Sjm199354  * the default value.
192*5440Sjm199354  *
193*5440Sjm199354  * Return codes:
194*5440Sjm199354  *	VS_ERR_VS_ERR_NONE
195*5440Sjm199354  *	VS_ERR_SCF
196*5440Sjm199354  *	VS_ERR_SYS
197*5440Sjm199354  */
198*5440Sjm199354 int
199*5440Sjm199354 vs_props_get_all(vs_props_all_t *va)
200*5440Sjm199354 {
201*5440Sjm199354 	int i, rc, n;
202*5440Sjm199354 	char *engid;
203*5440Sjm199354 	vs_engid_t engids[VS_SE_MAX];
204*5440Sjm199354 
205*5440Sjm199354 	(void) memset(va, 0, sizeof (vs_props_all_t));
206*5440Sjm199354 	if ((rc = vs_props_get(&va->va_props, VS_PROPID_GEN_ALL))
207*5440Sjm199354 	    != VS_ERR_NONE)
208*5440Sjm199354 		return (rc);
209*5440Sjm199354 
210*5440Sjm199354 	n = VS_SE_MAX;
211*5440Sjm199354 	if ((rc = vs_props_get_engines(engids, &n)) != VS_ERR_NONE)
212*5440Sjm199354 		return (rc);
213*5440Sjm199354 
214*5440Sjm199354 	if (n > VS_SE_MAX)
215*5440Sjm199354 		n = VS_SE_MAX;
216*5440Sjm199354 
217*5440Sjm199354 	for (i = 0; i < n; i++) {
218*5440Sjm199354 		engid = engids[i];
219*5440Sjm199354 		rc = vs_props_se_get(engid, &va->va_se[i], VS_PROPID_SE_ALL);
220*5440Sjm199354 		if (rc != VS_ERR_NONE)
221*5440Sjm199354 			return (rc);
222*5440Sjm199354 	}
223*5440Sjm199354 
224*5440Sjm199354 	return (VS_ERR_NONE);
225*5440Sjm199354 }
226*5440Sjm199354 
227*5440Sjm199354 
228*5440Sjm199354 /*
229*5440Sjm199354  * vs_props_get
230*5440Sjm199354  *
231*5440Sjm199354  * Retrieves values for the specified general service properties from
232*5440Sjm199354  * the repository.
233*5440Sjm199354  *
234*5440Sjm199354  * If invalid property values are found, the values are corrected to
235*5440Sjm199354  * the default value.
236*5440Sjm199354  *
237*5440Sjm199354  * Return codes:
238*5440Sjm199354  *	VS_ERR_VS_ERR_NONE
239*5440Sjm199354  *	VS_ERR_INVALID_PROPERTY
240*5440Sjm199354  *	VS_ERR_SCF
241*5440Sjm199354  *	VS_ERR_SYS
242*5440Sjm199354  */
243*5440Sjm199354 int
244*5440Sjm199354 vs_props_get(vs_props_t *vp, uint64_t propids)
245*5440Sjm199354 {
246*5440Sjm199354 	int  rc;
247*5440Sjm199354 	vs_prop_hd_t prop_hd;
248*5440Sjm199354 
249*5440Sjm199354 	if ((propids & VS_PROPID_GEN_ALL) != propids)
250*5440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
251*5440Sjm199354 
252*5440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
253*5440Sjm199354 	prop_hd.vp_type = VS_PTYPE_GEN;
254*5440Sjm199354 	prop_hd.vp_ids = propids;
255*5440Sjm199354 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
256*5440Sjm199354 
257*5440Sjm199354 	rc = vs_scf_values_get(VS_PGNAME_GENERAL, &prop_hd);
258*5440Sjm199354 
259*5440Sjm199354 	*vp = prop_hd.vp_gen;
260*5440Sjm199354 	return (rc);
261*5440Sjm199354 }
262*5440Sjm199354 
263*5440Sjm199354 
264*5440Sjm199354 /*
265*5440Sjm199354  * vs_props_set
266*5440Sjm199354  *
267*5440Sjm199354  * Changes values for the specified general service properties
268*5440Sjm199354  * in the repository.
269*5440Sjm199354  *
270*5440Sjm199354  * Return codes:
271*5440Sjm199354  *	VS_ERR_VS_ERR_NONE
272*5440Sjm199354  *	VS_ERR_INVALID_PROPERTY
273*5440Sjm199354  *	VS_ERR_INVALID_VALUE
274*5440Sjm199354  *	VS_ERR_SCF
275*5440Sjm199354  *	VS_ERR_SYS
276*5440Sjm199354  */
277*5440Sjm199354 int
278*5440Sjm199354 vs_props_set(const vs_props_t *vp, uint64_t propids)
279*5440Sjm199354 {
280*5440Sjm199354 	vs_prop_hd_t prop_hd;
281*5440Sjm199354 
282*5440Sjm199354 	if ((propids & VS_PROPID_GEN_ALL) != propids)
283*5440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
284*5440Sjm199354 
285*5440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
286*5440Sjm199354 	prop_hd.vp_type = VS_PTYPE_GEN;
287*5440Sjm199354 	prop_hd.vp_ids = propids;
288*5440Sjm199354 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
289*5440Sjm199354 	prop_hd.vp_gen = *vp;
290*5440Sjm199354 	return (vs_scf_values_set(VS_PGNAME_GENERAL, &prop_hd));
291*5440Sjm199354 }
292*5440Sjm199354 
293*5440Sjm199354 
294*5440Sjm199354 /*
295*5440Sjm199354  * vs_props_se_get
296*5440Sjm199354  *
297*5440Sjm199354  * Retrieves values for the specified scan engine properties from the
298*5440Sjm199354  * repository.
299*5440Sjm199354  *
300*5440Sjm199354  * If the enable property is set (true), the host property is
301*5440Sjm199354  * checked for validity. If it is not valid, the requested values
302*5440Sjm199354  * are returned with the enable propery set to off (false)
303*5440Sjm199354  *
304*5440Sjm199354  * Return codes:
305*5440Sjm199354  *	VS_ERR_VS_ERR_NONE
306*5440Sjm199354  *	VS_ERR_INVALID_PROPERTY
307*5440Sjm199354  *	VS_ERR_SCF
308*5440Sjm199354  *	VS_ERR_SYS
309*5440Sjm199354  */
310*5440Sjm199354 int
311*5440Sjm199354 vs_props_se_get(char *engid, vs_props_se_t *sep, uint64_t propids)
312*5440Sjm199354 {
313*5440Sjm199354 	int rc;
314*5440Sjm199354 	vs_prop_hd_t prop_hd;
315*5440Sjm199354 
316*5440Sjm199354 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
317*5440Sjm199354 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
318*5440Sjm199354 		return (VS_ERR_INVALID_SE);
319*5440Sjm199354 
320*5440Sjm199354 	if ((propids & VS_PROPID_SE_ALL) != propids)
321*5440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
322*5440Sjm199354 
323*5440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
324*5440Sjm199354 	prop_hd.vp_type = VS_PTYPE_SE;
325*5440Sjm199354 	prop_hd.vp_ids = propids;
326*5440Sjm199354 	prop_hd.vp_all = VS_PROPID_SE_ALL;
327*5440Sjm199354 	(void) strlcpy(prop_hd.vp_se.vep_engid, engid, VS_SE_NAME_LEN);
328*5440Sjm199354 
329*5440Sjm199354 	/* If getting enable, get the host property too */
330*5440Sjm199354 	if ((propids & VS_PROPID_SE_ENABLE))
331*5440Sjm199354 		prop_hd.vp_ids |= VS_PROPID_SE_HOST;
332*5440Sjm199354 
333*5440Sjm199354 	/* Load values from the repository */
334*5440Sjm199354 	rc = vs_scf_values_get(engid, &prop_hd);
335*5440Sjm199354 	if (rc != VS_ERR_NONE)
336*5440Sjm199354 		return (rc);
337*5440Sjm199354 
338*5440Sjm199354 	/*
339*5440Sjm199354 	 *  If the host is invalid and the enable property is on,
340*5440Sjm199354 	 *  return enable property as off
341*5440Sjm199354 	 */
342*5440Sjm199354 	if ((prop_hd.vp_ids & VS_PROPID_SE_HOST) &&
343*5440Sjm199354 	    (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)) {
344*5440Sjm199354 		prop_hd.vp_se.vep_enable = B_FALSE;
345*5440Sjm199354 	}
346*5440Sjm199354 
347*5440Sjm199354 	*sep = prop_hd.vp_se;
348*5440Sjm199354 	return (rc);
349*5440Sjm199354 }
350*5440Sjm199354 
351*5440Sjm199354 
352*5440Sjm199354 
353*5440Sjm199354 /*
354*5440Sjm199354  * vs_props_se_set
355*5440Sjm199354  *
356*5440Sjm199354  * Changes the values for the specified scan engine properties in the
357*5440Sjm199354  * repository.
358*5440Sjm199354  *
359*5440Sjm199354  * If the enable property is being changed to true in this operation,
360*5440Sjm199354  * a host property must also be specified, or already exist in the
361*5440Sjm199354  * repository.
362*5440Sjm199354  *
363*5440Sjm199354  * Return codes:
364*5440Sjm199354  *	VS_ERR_NONE
365*5440Sjm199354  *	VS_ERR_INVALID_PROPERTY
366*5440Sjm199354  *	VS_ERR_INVALID_VALUE
367*5440Sjm199354  *	VS_ERR_SCF
368*5440Sjm199354  *	VS_ERR_SYS
369*5440Sjm199354  */
370*5440Sjm199354 int
371*5440Sjm199354 vs_props_se_set(char *engid, const vs_props_se_t *sep, uint64_t propids)
372*5440Sjm199354 {
373*5440Sjm199354 	int rc;
374*5440Sjm199354 	vs_prop_hd_t prop_hd;
375*5440Sjm199354 
376*5440Sjm199354 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
377*5440Sjm199354 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
378*5440Sjm199354 		return (VS_ERR_INVALID_SE);
379*5440Sjm199354 
380*5440Sjm199354 	if ((propids & VS_PROPID_SE_ALL) != propids)
381*5440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
382*5440Sjm199354 
383*5440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
384*5440Sjm199354 	prop_hd.vp_type = VS_PTYPE_SE;
385*5440Sjm199354 	prop_hd.vp_all = VS_PROPID_SE_ALL;
386*5440Sjm199354 
387*5440Sjm199354 	/*
388*5440Sjm199354 	 * if enabling a scan engine, ensure that a valid host
389*5440Sjm199354 	 * is also being set, or already exists in the repository
390*5440Sjm199354 	 */
391*5440Sjm199354 	if ((propids & VS_PROPID_SE_ENABLE) && (sep->vep_enable == B_TRUE) &&
392*5440Sjm199354 	    !(propids & VS_PROPID_SE_HOST)) {
393*5440Sjm199354 
394*5440Sjm199354 		prop_hd.vp_ids = VS_PROPID_SE_HOST;
395*5440Sjm199354 		if ((rc = vs_scf_values_get(engid, &prop_hd)) != VS_ERR_NONE)
396*5440Sjm199354 			return (rc);
397*5440Sjm199354 
398*5440Sjm199354 		if (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)
399*5440Sjm199354 			return (VS_ERR_INVALID_HOST);
400*5440Sjm199354 	}
401*5440Sjm199354 
402*5440Sjm199354 	prop_hd.vp_ids = propids;
403*5440Sjm199354 	prop_hd.vp_se = *sep;
404*5440Sjm199354 
405*5440Sjm199354 	return (vs_scf_values_set(engid, &prop_hd));
406*5440Sjm199354 }
407*5440Sjm199354 
408*5440Sjm199354 
409*5440Sjm199354 /*
410*5440Sjm199354  * vs_props_se_create
411*5440Sjm199354  */
412*5440Sjm199354 int
413*5440Sjm199354 vs_props_se_create(char *engid, const vs_props_se_t *sep, uint64_t propids)
414*5440Sjm199354 {
415*5440Sjm199354 	int n;
416*5440Sjm199354 	vs_prop_hd_t prop_hd;
417*5440Sjm199354 
418*5440Sjm199354 	if ((propids & VS_PROPID_SE_ALL) != propids)
419*5440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
420*5440Sjm199354 
421*5440Sjm199354 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
422*5440Sjm199354 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
423*5440Sjm199354 		return (VS_ERR_INVALID_SE);
424*5440Sjm199354 
425*5440Sjm199354 	if ((n = vs_scf_pg_count()) == -1)
426*5440Sjm199354 		return (VS_ERR_SCF);
427*5440Sjm199354 
428*5440Sjm199354 	if (n == VS_SE_MAX)
429*5440Sjm199354 		return (VS_ERR_MAX_SE);
430*5440Sjm199354 
431*5440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
432*5440Sjm199354 	prop_hd.vp_type = VS_PTYPE_SE;
433*5440Sjm199354 	prop_hd.vp_all = VS_PROPID_SE_ALL;
434*5440Sjm199354 	prop_hd.vp_ids = propids | VS_PROPID_VALUE_AUTH;
435*5440Sjm199354 	prop_hd.vp_se = *sep;
436*5440Sjm199354 
437*5440Sjm199354 	return (vs_scf_pg_create(engid, &prop_hd));
438*5440Sjm199354 
439*5440Sjm199354 }
440*5440Sjm199354 
441*5440Sjm199354 
442*5440Sjm199354 /*
443*5440Sjm199354  * vs_props_se_delete
444*5440Sjm199354  */
445*5440Sjm199354 int
446*5440Sjm199354 vs_props_se_delete(const char *engid)
447*5440Sjm199354 {
448*5440Sjm199354 	int rc;
449*5440Sjm199354 	vs_scfctx_t vsc;
450*5440Sjm199354 
451*5440Sjm199354 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
452*5440Sjm199354 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
453*5440Sjm199354 		return (VS_ERR_INVALID_SE);
454*5440Sjm199354 
455*5440Sjm199354 	/* ensure that caller has authorization to refresh service */
456*5440Sjm199354 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
457*5440Sjm199354 		return (rc);
458*5440Sjm199354 
459*5440Sjm199354 	if (vs_scf_ctx_open(&vsc) != 0) {
460*5440Sjm199354 		vs_scf_ctx_close(&vsc);
461*5440Sjm199354 		return (VS_ERR_SCF);
462*5440Sjm199354 	}
463*5440Sjm199354 
464*5440Sjm199354 	if (scf_instance_get_pg(vsc.vscf_inst, engid, vsc.vscf_pgroup) == -1) {
465*5440Sjm199354 		vs_scf_ctx_close(&vsc);
466*5440Sjm199354 		rc = scf_error();
467*5440Sjm199354 		if ((rc == SCF_ERROR_NOT_FOUND) ||
468*5440Sjm199354 		    (rc == SCF_ERROR_INVALID_ARGUMENT))
469*5440Sjm199354 			return (VS_ERR_INVALID_SE);
470*5440Sjm199354 		else
471*5440Sjm199354 			return (VS_ERR_SCF);
472*5440Sjm199354 	}
473*5440Sjm199354 
474*5440Sjm199354 	if (scf_pg_delete(vsc.vscf_pgroup) == -1) {
475*5440Sjm199354 		vs_scf_ctx_close(&vsc);
476*5440Sjm199354 		rc = scf_error();
477*5440Sjm199354 		if ((rc == SCF_ERROR_NOT_FOUND) ||
478*5440Sjm199354 		    (rc == SCF_ERROR_INVALID_ARGUMENT))
479*5440Sjm199354 			return (VS_ERR_INVALID_SE);
480*5440Sjm199354 
481*5440Sjm199354 		return (VS_ERR_SCF);
482*5440Sjm199354 	}
483*5440Sjm199354 
484*5440Sjm199354 	vs_scf_ctx_close(&vsc);
485*5440Sjm199354 
486*5440Sjm199354 	/* Notify the daemon that things have changed */
487*5440Sjm199354 	if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1) {
488*5440Sjm199354 		return (VS_ERR_SCF);
489*5440Sjm199354 	}
490*5440Sjm199354 
491*5440Sjm199354 	return (VS_ERR_NONE);
492*5440Sjm199354 }
493*5440Sjm199354 
494*5440Sjm199354 
495*5440Sjm199354 /*
496*5440Sjm199354  * vs_strerror
497*5440Sjm199354  */
498*5440Sjm199354 const char *
499*5440Sjm199354 vs_strerror(int error)
500*5440Sjm199354 {
501*5440Sjm199354 	switch (error) {
502*5440Sjm199354 	case VS_ERR_NONE:
503*5440Sjm199354 		return (gettext("no error"));
504*5440Sjm199354 	case VS_ERR_INVALID_PROPERTY:
505*5440Sjm199354 		return (gettext("invalid property id"));
506*5440Sjm199354 	case VS_ERR_INVALID_VALUE:
507*5440Sjm199354 		return (gettext("invalid property value"));
508*5440Sjm199354 	case VS_ERR_INVALID_HOST:
509*5440Sjm199354 		return (gettext("invalid host"));
510*5440Sjm199354 	case VS_ERR_INVALID_SE:
511*5440Sjm199354 		return (gettext("invalid scan engine"));
512*5440Sjm199354 	case VS_ERR_MAX_SE:
513*5440Sjm199354 		return (gettext("max scan engines exceeded"));
514*5440Sjm199354 	case VS_ERR_AUTH:
515*5440Sjm199354 		return (gettext("insufficient privileges for action"));
516*5440Sjm199354 	case VS_ERR_DAEMON_COMM:
517*5440Sjm199354 		return (gettext("unable to contact vscand"));
518*5440Sjm199354 	case VS_ERR_SCF:
519*5440Sjm199354 		return (scf_strerror(scf_error()));
520*5440Sjm199354 	case VS_ERR_SYS:
521*5440Sjm199354 		return (strerror(errno));
522*5440Sjm199354 	default:
523*5440Sjm199354 		return (gettext("unknown error"));
524*5440Sjm199354 	}
525*5440Sjm199354 }
526*5440Sjm199354 
527*5440Sjm199354 
528*5440Sjm199354 /*
529*5440Sjm199354  * vs_get_propdef
530*5440Sjm199354  *
531*5440Sjm199354  * Finds and returns a property definition by property id.
532*5440Sjm199354  */
533*5440Sjm199354 static const vs_propdef_t *
534*5440Sjm199354 vs_get_propdef(uint64_t propid)
535*5440Sjm199354 {
536*5440Sjm199354 	int i;
537*5440Sjm199354 
538*5440Sjm199354 	for (i = 0; i < vs_npropdefs; i++) {
539*5440Sjm199354 		if (propid == vs_propdefs[i].vpd_id)
540*5440Sjm199354 			return (&vs_propdefs[i]);
541*5440Sjm199354 	}
542*5440Sjm199354 
543*5440Sjm199354 	return (NULL);
544*5440Sjm199354 }
545*5440Sjm199354 
546*5440Sjm199354 
547*5440Sjm199354 /*
548*5440Sjm199354  * vs_default_value
549*5440Sjm199354  *
550*5440Sjm199354  * Sets a property value that contains invalid data to its default value.
551*5440Sjm199354  *
552*5440Sjm199354  * Note that this function does not alter any values in the repository
553*5440Sjm199354  * This is only to enable the caller to get valid data.
554*5440Sjm199354  */
555*5440Sjm199354 static void
556*5440Sjm199354 vs_default_value(vs_prop_hd_t *prop_hd, const uint64_t propid)
557*5440Sjm199354 {
558*5440Sjm199354 	vs_props_t *vp = &prop_hd->vp_gen;
559*5440Sjm199354 	vs_props_se_t *vep = &prop_hd->vp_se;
560*5440Sjm199354 
561*5440Sjm199354 	switch (propid) {
562*5440Sjm199354 	case VS_PROPID_MAXSIZE:
563*5440Sjm199354 		(void) strlcpy(vp->vp_maxsize, vs_dflt_maxsize,
564*5440Sjm199354 		    sizeof (vp->vp_maxsize));
565*5440Sjm199354 		break;
566*5440Sjm199354 	case VS_PROPID_MAXSIZE_ACTION:
567*5440Sjm199354 		vp->vp_maxsize_action = vs_dflt_allow;
568*5440Sjm199354 		break;
569*5440Sjm199354 	case VS_PROPID_TYPES:
570*5440Sjm199354 		(void) strlcpy(vp->vp_types, vs_dflt_types,
571*5440Sjm199354 		    sizeof (vp->vp_types));
572*5440Sjm199354 		break;
573*5440Sjm199354 	case VS_PROPID_VLOG:
574*5440Sjm199354 		(void) strlcpy(vp->vp_vlog, vs_dflt_vlog,
575*5440Sjm199354 		    sizeof (vp->vp_vlog));
576*5440Sjm199354 		break;
577*5440Sjm199354 	case VS_PROPID_SE_ENABLE:
578*5440Sjm199354 		vep->vep_enable = vs_dflt_enable;
579*5440Sjm199354 		break;
580*5440Sjm199354 	case VS_PROPID_SE_HOST:
581*5440Sjm199354 		(void) strlcpy(vep->vep_host, vs_dflt_host,
582*5440Sjm199354 		    sizeof (vep->vep_host));
583*5440Sjm199354 		break;
584*5440Sjm199354 	case VS_PROPID_SE_PORT:
585*5440Sjm199354 		vep->vep_port = vs_dflt_port;
586*5440Sjm199354 		break;
587*5440Sjm199354 	case VS_PROPID_SE_MAXCONN:
588*5440Sjm199354 		vep->vep_maxconn = vs_dflt_maxconn;
589*5440Sjm199354 		break;
590*5440Sjm199354 	default:
591*5440Sjm199354 		break;
592*5440Sjm199354 	}
593*5440Sjm199354 }
594*5440Sjm199354 
595*5440Sjm199354 
596*5440Sjm199354 /*
597*5440Sjm199354  * vs_scf_values_get
598*5440Sjm199354  *
599*5440Sjm199354  * Gets property values for one or more properties from the repository.
600*5440Sjm199354  * This is the single entry point for loading SMF values.
601*5440Sjm199354  *
602*5440Sjm199354  * While a transaction is not used for loading property values,
603*5440Sjm199354  * the operation is parameterized by a property group. All properties
604*5440Sjm199354  * retrieved in this function, then, must belong to the same property
605*5440Sjm199354  * group.
606*5440Sjm199354  */
607*5440Sjm199354 int
608*5440Sjm199354 vs_scf_values_get(const char *pgname, vs_prop_hd_t *prop_hd)
609*5440Sjm199354 {
610*5440Sjm199354 	vs_scfctx_t vsc;
611*5440Sjm199354 	int rc, np;
612*5440Sjm199354 	const vs_propdef_t *vpd;
613*5440Sjm199354 	uint64_t propid;
614*5440Sjm199354 
615*5440Sjm199354 	if ((vs_scf_ctx_open(&vsc)) != 0) {
616*5440Sjm199354 		vs_scf_ctx_close(&vsc);
617*5440Sjm199354 		return (VS_ERR_SCF);
618*5440Sjm199354 	}
619*5440Sjm199354 
620*5440Sjm199354 	if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
621*5440Sjm199354 		vs_scf_ctx_close(&vsc);
622*5440Sjm199354 		if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) {
623*5440Sjm199354 			rc = scf_error();
624*5440Sjm199354 			if ((rc == SCF_ERROR_NOT_FOUND) ||
625*5440Sjm199354 			    (rc == SCF_ERROR_INVALID_ARGUMENT))
626*5440Sjm199354 				return (VS_ERR_INVALID_SE);
627*5440Sjm199354 		}
628*5440Sjm199354 		return (VS_ERR_SCF);
629*5440Sjm199354 	}
630*5440Sjm199354 
631*5440Sjm199354 	rc = VS_ERR_NONE;
632*5440Sjm199354 	np = 0;
633*5440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
634*5440Sjm199354 		if ((prop_hd->vp_ids & propid) == 0)
635*5440Sjm199354 			continue;
636*5440Sjm199354 
637*5440Sjm199354 		if ((vpd = vs_get_propdef(propid)) == NULL) {
638*5440Sjm199354 			rc = VS_ERR_INVALID_PROPERTY;
639*5440Sjm199354 			break;
640*5440Sjm199354 		}
641*5440Sjm199354 
642*5440Sjm199354 		vsc.vscf_prop[np] = scf_property_create(vsc.vscf_handle);
643*5440Sjm199354 		vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
644*5440Sjm199354 
645*5440Sjm199354 		if (vsc.vscf_prop[np] == NULL || vsc.vscf_val[np] == NULL) {
646*5440Sjm199354 			rc = VS_ERR_SCF;
647*5440Sjm199354 			break;
648*5440Sjm199354 		}
649*5440Sjm199354 
650*5440Sjm199354 		if (scf_pg_get_property(vsc.vscf_pgroup, vpd->vpd_name,
651*5440Sjm199354 		    vsc.vscf_prop[np]) == -1) {
652*5440Sjm199354 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
653*5440Sjm199354 				vs_default_value(prop_hd, vpd->vpd_id);
654*5440Sjm199354 				continue;
655*5440Sjm199354 			}
656*5440Sjm199354 			rc = VS_ERR_SCF;
657*5440Sjm199354 			break;
658*5440Sjm199354 		}
659*5440Sjm199354 
660*5440Sjm199354 		if ((rc = vs_scf_get(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
661*5440Sjm199354 			break;
662*5440Sjm199354 
663*5440Sjm199354 		++np;
664*5440Sjm199354 	}
665*5440Sjm199354 
666*5440Sjm199354 
667*5440Sjm199354 	vs_scf_ctx_close(&vsc);
668*5440Sjm199354 
669*5440Sjm199354 	return (rc);
670*5440Sjm199354 }
671*5440Sjm199354 
672*5440Sjm199354 
673*5440Sjm199354 /*
674*5440Sjm199354  * vs_scf_get
675*5440Sjm199354  *
676*5440Sjm199354  * Loads a single values from the repository into the appropriate vscan
677*5440Sjm199354  * property structure member.
678*5440Sjm199354  */
679*5440Sjm199354 static int
680*5440Sjm199354 vs_scf_get(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
681*5440Sjm199354 	vs_scfctx_t *vsc, int idx)
682*5440Sjm199354 {
683*5440Sjm199354 	int rc;
684*5440Sjm199354 	int64_t port;
685*5440Sjm199354 	uint8_t valbool;
686*5440Sjm199354 	vs_props_t *vp = &prop_hd->vp_gen;
687*5440Sjm199354 	vs_props_se_t *vep = &prop_hd->vp_se;
688*5440Sjm199354 
689*5440Sjm199354 	if ((rc = scf_property_get_value(vsc->vscf_prop[idx],
690*5440Sjm199354 	    vsc->vscf_val[idx])) == -1) {
691*5440Sjm199354 		if (rc == SCF_ERROR_CONSTRAINT_VIOLATED ||
692*5440Sjm199354 		    rc == SCF_ERROR_NOT_FOUND) {
693*5440Sjm199354 			vs_default_value(prop_hd, vpd->vpd_id);
694*5440Sjm199354 			return (VS_ERR_NONE);
695*5440Sjm199354 		}
696*5440Sjm199354 		return (VS_ERR_SCF);
697*5440Sjm199354 	}
698*5440Sjm199354 
699*5440Sjm199354 	rc = VS_ERR_NONE;
700*5440Sjm199354 	switch (vpd->vpd_id) {
701*5440Sjm199354 	case VS_PROPID_MAXSIZE:
702*5440Sjm199354 		if ((scf_value_get_astring(vsc->vscf_val[idx],
703*5440Sjm199354 		    vp->vp_maxsize, sizeof (vp->vp_maxsize))) == -1) {
704*5440Sjm199354 			return (VS_ERR_SCF);
705*5440Sjm199354 		}
706*5440Sjm199354 		break;
707*5440Sjm199354 	case VS_PROPID_MAXSIZE_ACTION:
708*5440Sjm199354 		if ((scf_value_get_boolean(vsc->vscf_val[idx],
709*5440Sjm199354 		    &valbool)) == -1) {
710*5440Sjm199354 			return (VS_ERR_SCF);
711*5440Sjm199354 		}
712*5440Sjm199354 		vp->vp_maxsize_action = (valbool == 0) ? B_FALSE : B_TRUE;
713*5440Sjm199354 		break;
714*5440Sjm199354 	case VS_PROPID_TYPES:
715*5440Sjm199354 		if ((scf_value_get_astring(vsc->vscf_val[idx],
716*5440Sjm199354 		    vp->vp_types, sizeof (vp->vp_types))) == -1) {
717*5440Sjm199354 			return (VS_ERR_SCF);
718*5440Sjm199354 		}
719*5440Sjm199354 		break;
720*5440Sjm199354 	case VS_PROPID_VLOG:
721*5440Sjm199354 		if ((scf_value_get_astring(vsc->vscf_val[idx],
722*5440Sjm199354 		    vp->vp_vlog, sizeof (vp->vp_vlog))) == -1) {
723*5440Sjm199354 			return (VS_ERR_SCF);
724*5440Sjm199354 		}
725*5440Sjm199354 		break;
726*5440Sjm199354 	case VS_PROPID_SE_ENABLE:
727*5440Sjm199354 		if ((scf_value_get_boolean(vsc->vscf_val[idx],
728*5440Sjm199354 		    &valbool)) == -1) {
729*5440Sjm199354 			return (VS_ERR_SCF);
730*5440Sjm199354 		}
731*5440Sjm199354 		vep->vep_enable = (valbool == 0) ? B_FALSE : B_TRUE;
732*5440Sjm199354 		break;
733*5440Sjm199354 	case VS_PROPID_SE_HOST:
734*5440Sjm199354 		(void) scf_value_get_as_string_typed(vsc->vscf_val[idx],
735*5440Sjm199354 		    vpd->vpd_type, vep->vep_host, sizeof (vep->vep_host));
736*5440Sjm199354 		break;
737*5440Sjm199354 	case VS_PROPID_SE_PORT:
738*5440Sjm199354 		if ((scf_value_get_integer(vsc->vscf_val[idx], &port)) == -1)
739*5440Sjm199354 			return (VS_ERR_SCF);
740*5440Sjm199354 		if (port <= 0 || port >= UINT16_MAX)
741*5440Sjm199354 			rc = VS_ERR_INVALID_VALUE;
742*5440Sjm199354 		else
743*5440Sjm199354 			vep->vep_port = (uint16_t)port;
744*5440Sjm199354 		break;
745*5440Sjm199354 	case VS_PROPID_SE_MAXCONN:
746*5440Sjm199354 		if ((scf_value_get_integer(vsc->vscf_val[idx],
747*5440Sjm199354 		    (int64_t *)&vep->vep_maxconn)) == -1) {
748*5440Sjm199354 			return (VS_ERR_SCF);
749*5440Sjm199354 		}
750*5440Sjm199354 		break;
751*5440Sjm199354 	default:
752*5440Sjm199354 		break;
753*5440Sjm199354 	}
754*5440Sjm199354 
755*5440Sjm199354 	if ((rc != VS_ERR_NONE) ||
756*5440Sjm199354 	    (vs_validate(prop_hd, vpd->vpd_id) != VS_ERR_NONE)) {
757*5440Sjm199354 		vs_default_value(prop_hd, vpd->vpd_id);
758*5440Sjm199354 	}
759*5440Sjm199354 
760*5440Sjm199354 	return (VS_ERR_NONE);
761*5440Sjm199354 }
762*5440Sjm199354 
763*5440Sjm199354 
764*5440Sjm199354 /*
765*5440Sjm199354  * vs_scf_pg_create
766*5440Sjm199354  */
767*5440Sjm199354 static int
768*5440Sjm199354 vs_scf_pg_create(const char *pgname, vs_prop_hd_t *prop_hd)
769*5440Sjm199354 {
770*5440Sjm199354 	int rc;
771*5440Sjm199354 	uint64_t propid;
772*5440Sjm199354 	uint64_t propids = prop_hd->vp_ids;
773*5440Sjm199354 	vs_scfctx_t vsc;
774*5440Sjm199354 
775*5440Sjm199354 	/* ensure that caller has authorization to refresh service */
776*5440Sjm199354 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
777*5440Sjm199354 		return (rc);
778*5440Sjm199354 
779*5440Sjm199354 	if (vs_scf_ctx_open(&vsc) != 0) {
780*5440Sjm199354 		vs_scf_ctx_close(&vsc);
781*5440Sjm199354 		return (VS_ERR_SCF);
782*5440Sjm199354 	}
783*5440Sjm199354 
784*5440Sjm199354 	if (scf_instance_add_pg(vsc.vscf_inst, pgname,
785*5440Sjm199354 	    SCF_GROUP_APPLICATION, 0, vsc.vscf_pgroup) == -1) {
786*5440Sjm199354 		vs_scf_ctx_close(&vsc);
787*5440Sjm199354 		if (scf_error() == SCF_ERROR_INVALID_ARGUMENT)
788*5440Sjm199354 			return (VS_ERR_INVALID_SE);
789*5440Sjm199354 		return (VS_ERR_SCF);
790*5440Sjm199354 	}
791*5440Sjm199354 	vs_scf_ctx_close(&vsc);
792*5440Sjm199354 
793*5440Sjm199354 	/* set default values for those not specified */
794*5440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
795*5440Sjm199354 		if ((propid & prop_hd->vp_all) && !(propid & prop_hd->vp_ids))
796*5440Sjm199354 			vs_default_value(prop_hd, propid);
797*5440Sjm199354 	}
798*5440Sjm199354 	prop_hd->vp_ids = prop_hd->vp_all;
799*5440Sjm199354 
800*5440Sjm199354 
801*5440Sjm199354 	if ((propids & VS_PROPID_SE_HOST) == 0)
802*5440Sjm199354 		(void) strlcpy(prop_hd->vp_se.vep_host, pgname, MAXHOSTNAMELEN);
803*5440Sjm199354 
804*5440Sjm199354 	prop_hd->vp_ids |= VS_PROPID_VALUE_AUTH;
805*5440Sjm199354 
806*5440Sjm199354 	rc = vs_scf_values_set(pgname, prop_hd);
807*5440Sjm199354 	if (rc != VS_ERR_NONE)
808*5440Sjm199354 		(void) vs_props_se_delete(pgname);
809*5440Sjm199354 
810*5440Sjm199354 	return (rc);
811*5440Sjm199354 }
812*5440Sjm199354 
813*5440Sjm199354 
814*5440Sjm199354 /*
815*5440Sjm199354  * vs_scf_values_set
816*5440Sjm199354  *
817*5440Sjm199354  * Sets property values in the repository.  This is the single
818*5440Sjm199354  * entry point for storing SMF values.
819*5440Sjm199354  *
820*5440Sjm199354  * Like loading values, this is an operation based on a single property
821*5440Sjm199354  * group, so all property values changed in this function must belong
822*5440Sjm199354  * to the same property group. Additionally, this operation is done in
823*5440Sjm199354  * the context of a repository transaction; on any fatal error, the
824*5440Sjm199354  * SCF context will be closed, destroying all SCF objects and aborting
825*5440Sjm199354  * the transaction.
826*5440Sjm199354  */
827*5440Sjm199354 static int
828*5440Sjm199354 vs_scf_values_set(const char *pgname, vs_prop_hd_t *prop_hd)
829*5440Sjm199354 {
830*5440Sjm199354 	int rc, np;
831*5440Sjm199354 	const vs_propdef_t *vpd;
832*5440Sjm199354 	uint64_t propid;
833*5440Sjm199354 	vs_scfctx_t vsc;
834*5440Sjm199354 
835*5440Sjm199354 
836*5440Sjm199354 	/* ensure that caller has authorization to refresh service */
837*5440Sjm199354 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
838*5440Sjm199354 		return (rc);
839*5440Sjm199354 
840*5440Sjm199354 	if (vs_scf_ctx_open(&vsc) != 0) {
841*5440Sjm199354 		vs_scf_ctx_close(&vsc);
842*5440Sjm199354 		return (VS_ERR_SCF);
843*5440Sjm199354 	}
844*5440Sjm199354 
845*5440Sjm199354 	if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
846*5440Sjm199354 		vs_scf_ctx_close(&vsc);
847*5440Sjm199354 		rc = scf_error();
848*5440Sjm199354 		if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) {
849*5440Sjm199354 			if ((rc == SCF_ERROR_NOT_FOUND) ||
850*5440Sjm199354 			    (rc == SCF_ERROR_INVALID_ARGUMENT))
851*5440Sjm199354 				return (VS_ERR_INVALID_SE);
852*5440Sjm199354 		}
853*5440Sjm199354 		return (VS_ERR_SCF);
854*5440Sjm199354 	}
855*5440Sjm199354 
856*5440Sjm199354 	if (((vsc.vscf_tx = scf_transaction_create(vsc.vscf_handle)) == NULL) ||
857*5440Sjm199354 	    (scf_transaction_start(vsc.vscf_tx, vsc.vscf_pgroup) == -1)) {
858*5440Sjm199354 		vs_scf_ctx_close(&vsc);
859*5440Sjm199354 		return (VS_ERR_SCF);
860*5440Sjm199354 	}
861*5440Sjm199354 
862*5440Sjm199354 	/* Process the value change for each specified property */
863*5440Sjm199354 	rc = 0;
864*5440Sjm199354 	np = 0;
865*5440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
866*5440Sjm199354 		if ((prop_hd->vp_ids & propid) == 0)
867*5440Sjm199354 			continue;
868*5440Sjm199354 
869*5440Sjm199354 		if ((vpd = vs_get_propdef(propid)) == NULL) {
870*5440Sjm199354 			rc = VS_ERR_INVALID_PROPERTY;
871*5440Sjm199354 			break;
872*5440Sjm199354 		}
873*5440Sjm199354 
874*5440Sjm199354 		vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
875*5440Sjm199354 		vsc.vscf_ent[np] = scf_entry_create(vsc.vscf_handle);
876*5440Sjm199354 
877*5440Sjm199354 		if (vsc.vscf_val[np] == NULL || vsc.vscf_ent[np] == NULL) {
878*5440Sjm199354 			rc = VS_ERR_SCF;
879*5440Sjm199354 			break;
880*5440Sjm199354 		}
881*5440Sjm199354 
882*5440Sjm199354 		if ((rc = scf_transaction_property_change(vsc.vscf_tx,
883*5440Sjm199354 		    vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type)) == -1) {
884*5440Sjm199354 			rc = scf_transaction_property_new(vsc.vscf_tx,
885*5440Sjm199354 			    vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type);
886*5440Sjm199354 		}
887*5440Sjm199354 		if (rc == -1) {
888*5440Sjm199354 			rc = VS_ERR_SCF;
889*5440Sjm199354 			break;
890*5440Sjm199354 		}
891*5440Sjm199354 
892*5440Sjm199354 		if ((rc = vs_scf_set(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
893*5440Sjm199354 			break;
894*5440Sjm199354 
895*5440Sjm199354 		++np;
896*5440Sjm199354 	}
897*5440Sjm199354 
898*5440Sjm199354 	if (rc != VS_ERR_NONE) {
899*5440Sjm199354 		vs_scf_ctx_close(&vsc);
900*5440Sjm199354 		return (rc);
901*5440Sjm199354 	}
902*5440Sjm199354 
903*5440Sjm199354 	/* Commit the transaction */
904*5440Sjm199354 	if (scf_transaction_commit(vsc.vscf_tx) == -1) {
905*5440Sjm199354 		vs_scf_ctx_close(&vsc);
906*5440Sjm199354 		return (VS_ERR_SCF);
907*5440Sjm199354 	}
908*5440Sjm199354 	vs_scf_ctx_close(&vsc);
909*5440Sjm199354 
910*5440Sjm199354 	/* Notify the daemon that things have changed */
911*5440Sjm199354 	if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1)
912*5440Sjm199354 		return (VS_ERR_SCF);
913*5440Sjm199354 
914*5440Sjm199354 	return (VS_ERR_NONE);
915*5440Sjm199354 }
916*5440Sjm199354 
917*5440Sjm199354 
918*5440Sjm199354 /*
919*5440Sjm199354  * vs_scf_set
920*5440Sjm199354  *
921*5440Sjm199354  * Stores a single value from the appropriate vscan property structure
922*5440Sjm199354  * member into the repository.
923*5440Sjm199354  *
924*5440Sjm199354  * Values are set in the SCF value object, then the value object
925*5440Sjm199354  * is added to the SCF property object.
926*5440Sjm199354  */
927*5440Sjm199354 static int
928*5440Sjm199354 vs_scf_set(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
929*5440Sjm199354     vs_scfctx_t *vsc, int idx)
930*5440Sjm199354 {
931*5440Sjm199354 	int rc;
932*5440Sjm199354 	vs_props_t *vp = &prop_hd->vp_gen;
933*5440Sjm199354 	vs_props_se_t *vep = &prop_hd->vp_se;
934*5440Sjm199354 
935*5440Sjm199354 	if ((rc = vs_validate(prop_hd, vpd->vpd_id)) != VS_ERR_NONE)
936*5440Sjm199354 		return (rc);
937*5440Sjm199354 
938*5440Sjm199354 	rc = VS_ERR_NONE;
939*5440Sjm199354 	switch (vpd->vpd_id) {
940*5440Sjm199354 	case VS_PROPID_MAXSIZE:
941*5440Sjm199354 		if ((scf_value_set_astring(vsc->vscf_val[idx],
942*5440Sjm199354 		    vp->vp_maxsize)) == -1) {
943*5440Sjm199354 			rc = VS_ERR_SCF;
944*5440Sjm199354 		}
945*5440Sjm199354 		break;
946*5440Sjm199354 	case VS_PROPID_MAXSIZE_ACTION:
947*5440Sjm199354 		scf_value_set_boolean(vsc->vscf_val[idx],
948*5440Sjm199354 		    (uint8_t)vp->vp_maxsize_action);
949*5440Sjm199354 		break;
950*5440Sjm199354 	case VS_PROPID_TYPES:
951*5440Sjm199354 		if ((scf_value_set_astring(vsc->vscf_val[idx],
952*5440Sjm199354 		    vp->vp_types)) == -1) {
953*5440Sjm199354 			return (VS_ERR_SCF);
954*5440Sjm199354 		}
955*5440Sjm199354 		break;
956*5440Sjm199354 	case VS_PROPID_SE_ENABLE:
957*5440Sjm199354 		scf_value_set_boolean(vsc->vscf_val[idx],
958*5440Sjm199354 		    (uint8_t)vep->vep_enable);
959*5440Sjm199354 		break;
960*5440Sjm199354 	case VS_PROPID_SE_HOST:
961*5440Sjm199354 		if ((scf_value_set_from_string(vsc->vscf_val[idx],
962*5440Sjm199354 		    vpd->vpd_type, vep->vep_host)) == -1) {
963*5440Sjm199354 			rc = VS_ERR_SCF;
964*5440Sjm199354 		}
965*5440Sjm199354 		break;
966*5440Sjm199354 	case VS_PROPID_SE_PORT:
967*5440Sjm199354 		scf_value_set_integer(vsc->vscf_val[idx], vep->vep_port);
968*5440Sjm199354 		break;
969*5440Sjm199354 	case VS_PROPID_SE_MAXCONN:
970*5440Sjm199354 		scf_value_set_integer(vsc->vscf_val[idx],
971*5440Sjm199354 		    vep->vep_maxconn);
972*5440Sjm199354 		break;
973*5440Sjm199354 	case VS_PROPID_VALUE_AUTH:
974*5440Sjm199354 		if ((scf_value_set_astring(vsc->vscf_val[idx],
975*5440Sjm199354 		    VS_VALUE_AUTH)) == -1) {
976*5440Sjm199354 			return (VS_ERR_SCF);
977*5440Sjm199354 		}
978*5440Sjm199354 		break;
979*5440Sjm199354 	default:
980*5440Sjm199354 		break;
981*5440Sjm199354 	}
982*5440Sjm199354 
983*5440Sjm199354 	if ((scf_entry_add_value(vsc->vscf_ent[idx],
984*5440Sjm199354 	    vsc->vscf_val[idx])) == -1) {
985*5440Sjm199354 		return (VS_ERR_SCF);
986*5440Sjm199354 	}
987*5440Sjm199354 
988*5440Sjm199354 	return (rc);
989*5440Sjm199354 }
990*5440Sjm199354 
991*5440Sjm199354 
992*5440Sjm199354 /*
993*5440Sjm199354  * vs_scf_ctx_open
994*5440Sjm199354  *
995*5440Sjm199354  * Opens an SCF context; creates the minumum SCF objects
996*5440Sjm199354  * for use in loading/storing from the SMF repository (meaning
997*5440Sjm199354  * vscf_property group data).
998*5440Sjm199354  *
999*5440Sjm199354  * Other SCF objects in the context may be initialized elsewher
1000*5440Sjm199354  * subsequent to open, but all initialized structures are destroyed
1001*5440Sjm199354  * in vs_scf_ctx_close().
1002*5440Sjm199354  */
1003*5440Sjm199354 static int
1004*5440Sjm199354 vs_scf_ctx_open(vs_scfctx_t *vsc)
1005*5440Sjm199354 {
1006*5440Sjm199354 	(void) memset(vsc, 0, sizeof (vs_scfctx_t));
1007*5440Sjm199354 
1008*5440Sjm199354 	if ((vsc->vscf_handle = scf_handle_create(SCF_VERSION)) == NULL)
1009*5440Sjm199354 		return (VS_ERR_SCF);
1010*5440Sjm199354 
1011*5440Sjm199354 	if (scf_handle_bind(vsc->vscf_handle) == -1)
1012*5440Sjm199354 		return (VS_ERR_SCF);
1013*5440Sjm199354 
1014*5440Sjm199354 	if ((vsc->vscf_inst = scf_instance_create(vsc->vscf_handle)) == NULL)
1015*5440Sjm199354 		return (VS_ERR_SCF);
1016*5440Sjm199354 
1017*5440Sjm199354 	if (scf_handle_decode_fmri(vsc->vscf_handle, VS_INSTANCE_FMRI,
1018*5440Sjm199354 	    NULL, NULL, vsc->vscf_inst, NULL, NULL,
1019*5440Sjm199354 	    SCF_DECODE_FMRI_EXACT) == -1) {
1020*5440Sjm199354 		return (VS_ERR_SCF);
1021*5440Sjm199354 	}
1022*5440Sjm199354 
1023*5440Sjm199354 	if ((vsc->vscf_pgroup = scf_pg_create(vsc->vscf_handle)) == NULL)
1024*5440Sjm199354 		return (VS_ERR_SCF);
1025*5440Sjm199354 
1026*5440Sjm199354 	return (VS_ERR_NONE);
1027*5440Sjm199354 }
1028*5440Sjm199354 
1029*5440Sjm199354 
1030*5440Sjm199354 /*
1031*5440Sjm199354  * vs_scf_ctx_close
1032*5440Sjm199354  *
1033*5440Sjm199354  * Closes an SCF context; destroys all initialized SCF objects.
1034*5440Sjm199354  */
1035*5440Sjm199354 static void
1036*5440Sjm199354 vs_scf_ctx_close(vs_scfctx_t *vsc)
1037*5440Sjm199354 {
1038*5440Sjm199354 	int i;
1039*5440Sjm199354 
1040*5440Sjm199354 	for (i = 0; i < VS_NUM_PROPIDS; i++) {
1041*5440Sjm199354 		if (vsc->vscf_val[i])
1042*5440Sjm199354 			scf_value_destroy(vsc->vscf_val[i]);
1043*5440Sjm199354 		if (vsc->vscf_ent[i])
1044*5440Sjm199354 			scf_entry_destroy(vsc->vscf_ent[i]);
1045*5440Sjm199354 		if (vsc->vscf_prop[i])
1046*5440Sjm199354 			scf_property_destroy(vsc->vscf_prop[i]);
1047*5440Sjm199354 	}
1048*5440Sjm199354 
1049*5440Sjm199354 	if (vsc->vscf_iter)
1050*5440Sjm199354 		scf_iter_destroy(vsc->vscf_iter);
1051*5440Sjm199354 	if (vsc->vscf_tx)
1052*5440Sjm199354 		scf_transaction_destroy(vsc->vscf_tx);
1053*5440Sjm199354 	if (vsc->vscf_pgroup)
1054*5440Sjm199354 		scf_pg_destroy(vsc->vscf_pgroup);
1055*5440Sjm199354 	if (vsc->vscf_inst)
1056*5440Sjm199354 		scf_instance_destroy(vsc->vscf_inst);
1057*5440Sjm199354 	if (vsc->vscf_handle)
1058*5440Sjm199354 		scf_handle_destroy(vsc->vscf_handle);
1059*5440Sjm199354 }
1060*5440Sjm199354 
1061*5440Sjm199354 
1062*5440Sjm199354 /*
1063*5440Sjm199354  * vs_validate
1064*5440Sjm199354  *
1065*5440Sjm199354  * Validate property identified in propid.
1066*5440Sjm199354  *
1067*5440Sjm199354  * Returns: VS_ERR_NONE
1068*5440Sjm199354  *          VS_ERR_INVALID_VALUE
1069*5440Sjm199354  *          VS_ERR_INVALID_PROPERTY
1070*5440Sjm199354  */
1071*5440Sjm199354 static int
1072*5440Sjm199354 vs_validate(const vs_prop_hd_t *prop_hd, uint64_t propid)
1073*5440Sjm199354 {
1074*5440Sjm199354 	uint64_t num;
1075*5440Sjm199354 	const vs_props_t *vp = &prop_hd->vp_gen;
1076*5440Sjm199354 	const vs_props_se_t *vep = &prop_hd->vp_se;
1077*5440Sjm199354 
1078*5440Sjm199354 	switch (propid) {
1079*5440Sjm199354 	case VS_PROPID_MAXSIZE:
1080*5440Sjm199354 		if ((vs_strtonum(vp->vp_maxsize, &num) != 0) || (num == 0))
1081*5440Sjm199354 			return (VS_ERR_INVALID_VALUE);
1082*5440Sjm199354 		break;
1083*5440Sjm199354 	case VS_PROPID_MAXSIZE_ACTION:
1084*5440Sjm199354 		break;
1085*5440Sjm199354 	case VS_PROPID_TYPES:
1086*5440Sjm199354 		if (!vs_is_valid_types(vp->vp_types))
1087*5440Sjm199354 			return (VS_ERR_INVALID_VALUE);
1088*5440Sjm199354 		break;
1089*5440Sjm199354 	case VS_PROPID_SE_ENABLE:
1090*5440Sjm199354 		break;
1091*5440Sjm199354 	case VS_PROPID_SE_PORT:
1092*5440Sjm199354 		if (vep->vep_port == 0)
1093*5440Sjm199354 			return (VS_ERR_INVALID_VALUE);
1094*5440Sjm199354 		break;
1095*5440Sjm199354 	case VS_PROPID_SE_HOST:
1096*5440Sjm199354 		if (!vs_is_valid_host(vep->vep_host))
1097*5440Sjm199354 			return (VS_ERR_INVALID_VALUE);
1098*5440Sjm199354 		break;
1099*5440Sjm199354 	case VS_PROPID_SE_MAXCONN:
1100*5440Sjm199354 		if (vep->vep_maxconn < VS_VAL_SE_MAXCONN_MIN ||
1101*5440Sjm199354 		    vep->vep_maxconn > VS_VAL_SE_MAXCONN_MAX)
1102*5440Sjm199354 			return (VS_ERR_INVALID_VALUE);
1103*5440Sjm199354 		break;
1104*5440Sjm199354 	case VS_PROPID_VALUE_AUTH:
1105*5440Sjm199354 	case VS_PROPID_VLOG:
1106*5440Sjm199354 		break;
1107*5440Sjm199354 	default:
1108*5440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
1109*5440Sjm199354 	}
1110*5440Sjm199354 
1111*5440Sjm199354 	return (VS_ERR_NONE);
1112*5440Sjm199354 }
1113*5440Sjm199354 
1114*5440Sjm199354 
1115*5440Sjm199354 /*
1116*5440Sjm199354  * vs_props_validate
1117*5440Sjm199354  *
1118*5440Sjm199354  * Validate  properties identified in propids.
1119*5440Sjm199354  *
1120*5440Sjm199354  * Returns: VS_ERR_NONE
1121*5440Sjm199354  *          VS_ERR_INVALID_VALUE
1122*5440Sjm199354  *          VS_ERR_INVALID_PROPERTY
1123*5440Sjm199354  */
1124*5440Sjm199354 int
1125*5440Sjm199354 vs_props_validate(const vs_props_t *props, uint64_t propids)
1126*5440Sjm199354 {
1127*5440Sjm199354 	uint64_t propid;
1128*5440Sjm199354 	vs_prop_hd_t prop_hd;
1129*5440Sjm199354 
1130*5440Sjm199354 	if ((propids & VS_PROPID_GEN_ALL) != propids)
1131*5440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
1132*5440Sjm199354 
1133*5440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
1134*5440Sjm199354 	prop_hd.vp_gen = *props;
1135*5440Sjm199354 	prop_hd.vp_type = VS_PTYPE_GEN;
1136*5440Sjm199354 	prop_hd.vp_ids = propids;
1137*5440Sjm199354 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
1138*5440Sjm199354 
1139*5440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
1140*5440Sjm199354 		if ((propids & propid) == 0)
1141*5440Sjm199354 			continue;
1142*5440Sjm199354 
1143*5440Sjm199354 		if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
1144*5440Sjm199354 			return (VS_ERR_INVALID_VALUE);
1145*5440Sjm199354 	}
1146*5440Sjm199354 
1147*5440Sjm199354 	return (VS_ERR_NONE);
1148*5440Sjm199354 }
1149*5440Sjm199354 
1150*5440Sjm199354 
1151*5440Sjm199354 /*
1152*5440Sjm199354  * vs_props_se_validate
1153*5440Sjm199354  *
1154*5440Sjm199354  * Validate properties identified in propids.
1155*5440Sjm199354  *
1156*5440Sjm199354  * Returns: VS_ERR_NONE
1157*5440Sjm199354  *          VS_ERR_INVALID_VALUE
1158*5440Sjm199354  *          VS_ERR_INVALID_PROPERTY
1159*5440Sjm199354  */
1160*5440Sjm199354 int
1161*5440Sjm199354 vs_props_se_validate(const vs_props_se_t *se_props, uint64_t propids)
1162*5440Sjm199354 {
1163*5440Sjm199354 	uint64_t propid;
1164*5440Sjm199354 	vs_prop_hd_t prop_hd;
1165*5440Sjm199354 
1166*5440Sjm199354 	if ((propids & VS_PROPID_SE_ALL) != propids)
1167*5440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
1168*5440Sjm199354 
1169*5440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
1170*5440Sjm199354 	prop_hd.vp_se = *se_props;
1171*5440Sjm199354 	prop_hd.vp_type = VS_PTYPE_SE;
1172*5440Sjm199354 	prop_hd.vp_ids = propids;
1173*5440Sjm199354 	prop_hd.vp_all = VS_PROPID_SE_ALL;
1174*5440Sjm199354 
1175*5440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
1176*5440Sjm199354 		if ((propids & propid) == 0)
1177*5440Sjm199354 			continue;
1178*5440Sjm199354 
1179*5440Sjm199354 		if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
1180*5440Sjm199354 			return (VS_ERR_INVALID_VALUE);
1181*5440Sjm199354 	}
1182*5440Sjm199354 
1183*5440Sjm199354 	return (VS_ERR_NONE);
1184*5440Sjm199354 }
1185*5440Sjm199354 
1186*5440Sjm199354 
1187*5440Sjm199354 /*
1188*5440Sjm199354  * vs_is_valid_types
1189*5440Sjm199354  *
1190*5440Sjm199354  * Checks that types property is a valid format:
1191*5440Sjm199354  * - doesn't exceed VS_VAL_TYPES_MAX
1192*5440Sjm199354  * - doesn't contain VS_VAL_TYPES_INVALID_CHARS
1193*5440Sjm199354  * - is correctly formatted - passes the parsing tests
1194*5440Sjm199354  *
1195*5440Sjm199354  * Returns 1 on success, 0 on failure
1196*5440Sjm199354  */
1197*5440Sjm199354 static int
1198*5440Sjm199354 vs_is_valid_types(const char *types)
1199*5440Sjm199354 {
1200*5440Sjm199354 	char buf[VS_VAL_TYPES_LEN];
1201*5440Sjm199354 	uint32_t len = VS_VAL_TYPES_LEN;
1202*5440Sjm199354 
1203*5440Sjm199354 	if (strlen(types) > VS_VAL_TYPES_LEN)
1204*5440Sjm199354 		return (0);
1205*5440Sjm199354 
1206*5440Sjm199354 	if (strpbrk(types, VS_VAL_TYPES_INVALID_CHARS) != NULL)
1207*5440Sjm199354 		return (0);
1208*5440Sjm199354 
1209*5440Sjm199354 	if (vs_parse_types(types, buf, &len) != 0)
1210*5440Sjm199354 		return (0);
1211*5440Sjm199354 
1212*5440Sjm199354 	return (1);
1213*5440Sjm199354 }
1214*5440Sjm199354 
1215*5440Sjm199354 
1216*5440Sjm199354 /*
1217*5440Sjm199354  * vs_is_valid_host
1218*5440Sjm199354  *
1219*5440Sjm199354  * Returns 1 on success, 0 on failure
1220*5440Sjm199354  */
1221*5440Sjm199354 static int
1222*5440Sjm199354 vs_is_valid_host(const char *host)
1223*5440Sjm199354 {
1224*5440Sjm199354 	long naddr;
1225*5440Sjm199354 	const char *p;
1226*5440Sjm199354 
1227*5440Sjm199354 	if (!host || *host == '\0')
1228*5440Sjm199354 		return (0);
1229*5440Sjm199354 
1230*5440Sjm199354 	if ('0' <= host[0] && host[0] <= '9') {
1231*5440Sjm199354 		/* ip address */
1232*5440Sjm199354 		if ((inet_pton(AF_INET, host, &naddr)) == 0)
1233*5440Sjm199354 			return (0);
1234*5440Sjm199354 		if ((naddr & IN_CLASSA_NET) == 0)
1235*5440Sjm199354 			return (0);
1236*5440Sjm199354 		if ((naddr & IN_CLASSC_HOST) == 0)
1237*5440Sjm199354 			return (0);
1238*5440Sjm199354 	} else {
1239*5440Sjm199354 		/* hostname */
1240*5440Sjm199354 		p = host;
1241*5440Sjm199354 		while (*p != '\0') {
1242*5440Sjm199354 			if (!isascii(*p))
1243*5440Sjm199354 				return (0);
1244*5440Sjm199354 
1245*5440Sjm199354 			if (isalnum(*p) ||
1246*5440Sjm199354 			    (*p == '.') || (*p == '-') || (*p == '_')) {
1247*5440Sjm199354 				++p;
1248*5440Sjm199354 			} else {
1249*5440Sjm199354 				return (0);
1250*5440Sjm199354 			}
1251*5440Sjm199354 		}
1252*5440Sjm199354 	}
1253*5440Sjm199354 
1254*5440Sjm199354 	return (1);
1255*5440Sjm199354 }
1256*5440Sjm199354 
1257*5440Sjm199354 
1258*5440Sjm199354 /*
1259*5440Sjm199354  * vs_parse_types
1260*5440Sjm199354  *
1261*5440Sjm199354  * Replace comma separators with '\0'.
1262*5440Sjm199354  *
1263*5440Sjm199354  * Types contains comma separated rules each beginning with +|-
1264*5440Sjm199354  *   - embedded commas are escaped by backslash
1265*5440Sjm199354  *   - backslash is escaped by backslash
1266*5440Sjm199354  *   - a single backslash not followed by comma is illegal
1267*5440Sjm199354  *
1268*5440Sjm199354  * On entry to the function len must contain the length of
1269*5440Sjm199354  * the buffer. On sucecssful exit len will contain the length
1270*5440Sjm199354  * of the parsed data within the buffer.
1271*5440Sjm199354  *
1272*5440Sjm199354  * Returns 0 on success, -1 on failure
1273*5440Sjm199354  */
1274*5440Sjm199354 int
1275*5440Sjm199354 vs_parse_types(const char *types, char *buf, uint32_t *len)
1276*5440Sjm199354 {
1277*5440Sjm199354 	char *p = (char *)types;
1278*5440Sjm199354 	char *b = buf;
1279*5440Sjm199354 
1280*5440Sjm199354 	if (strlen(types) > *len)
1281*5440Sjm199354 		return (-1);
1282*5440Sjm199354 
1283*5440Sjm199354 	if (strchr(VS_TYPES_RULES, *p) == NULL)
1284*5440Sjm199354 		return (-1);
1285*5440Sjm199354 
1286*5440Sjm199354 	(void) memset(buf, 0, *len);
1287*5440Sjm199354 
1288*5440Sjm199354 	while (*p) {
1289*5440Sjm199354 		switch (*p) {
1290*5440Sjm199354 		case VS_TYPES_SEP:
1291*5440Sjm199354 			if (*(p + 1) &&
1292*5440Sjm199354 			    (strchr(VS_TYPES_RULES, *(p + 1))) == NULL)
1293*5440Sjm199354 				return (-1);
1294*5440Sjm199354 			*b = '\0';
1295*5440Sjm199354 			break;
1296*5440Sjm199354 		case VS_TYPES_ESCAPE:
1297*5440Sjm199354 			++p;
1298*5440Sjm199354 			if (*p == VS_TYPES_ESCAPE || *p == VS_TYPES_SEP)
1299*5440Sjm199354 				*b = *p;
1300*5440Sjm199354 			else
1301*5440Sjm199354 				return (-1);
1302*5440Sjm199354 			break;
1303*5440Sjm199354 		default:
1304*5440Sjm199354 			*b = *p;
1305*5440Sjm199354 		}
1306*5440Sjm199354 		++p;
1307*5440Sjm199354 		++b;
1308*5440Sjm199354 	}
1309*5440Sjm199354 
1310*5440Sjm199354 	*len = (b - buf) + 1;
1311*5440Sjm199354 
1312*5440Sjm199354 	return (0);
1313*5440Sjm199354 }
1314*5440Sjm199354 
1315*5440Sjm199354 
1316*5440Sjm199354 /*
1317*5440Sjm199354  * vs_statistics
1318*5440Sjm199354  */
1319*5440Sjm199354 int
1320*5440Sjm199354 vs_statistics(vs_stats_t *stats)
1321*5440Sjm199354 {
1322*5440Sjm199354 	int door_fd, rc = VS_ERR_NONE;
1323*5440Sjm199354 	vs_stats_req_t *req;
1324*5440Sjm199354 	vs_stats_t *buf;
1325*5440Sjm199354 	door_arg_t arg;
1326*5440Sjm199354 
1327*5440Sjm199354 	if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
1328*5440Sjm199354 		return (VS_ERR_SYS);
1329*5440Sjm199354 
1330*5440Sjm199354 	if ((buf = calloc(1, sizeof (vs_stats_t))) == NULL) {
1331*5440Sjm199354 		free(req);
1332*5440Sjm199354 		return (VS_ERR_SYS);
1333*5440Sjm199354 	}
1334*5440Sjm199354 
1335*5440Sjm199354 	if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
1336*5440Sjm199354 		free(req);
1337*5440Sjm199354 		free(buf);
1338*5440Sjm199354 		return (VS_ERR_DAEMON_COMM);
1339*5440Sjm199354 	}
1340*5440Sjm199354 
1341*5440Sjm199354 	*req = VS_STATS_GET;
1342*5440Sjm199354 
1343*5440Sjm199354 	arg.data_ptr = (char *)req;
1344*5440Sjm199354 	arg.data_size = sizeof (vs_stats_req_t);
1345*5440Sjm199354 	arg.desc_ptr = NULL;
1346*5440Sjm199354 	arg.desc_num = 0;
1347*5440Sjm199354 	arg.rbuf = (char *)buf;
1348*5440Sjm199354 	arg.rsize = sizeof (vs_stats_t);
1349*5440Sjm199354 
1350*5440Sjm199354 	if (door_call(door_fd, &arg) < 0)
1351*5440Sjm199354 		rc = VS_ERR_DAEMON_COMM;
1352*5440Sjm199354 	else
1353*5440Sjm199354 		*stats = *buf;
1354*5440Sjm199354 
1355*5440Sjm199354 	(void) close(door_fd);
1356*5440Sjm199354 
1357*5440Sjm199354 	free(req);
1358*5440Sjm199354 	free(buf);
1359*5440Sjm199354 	return (rc);
1360*5440Sjm199354 }
1361*5440Sjm199354 
1362*5440Sjm199354 
1363*5440Sjm199354 /*
1364*5440Sjm199354  * vs_statistics_reset
1365*5440Sjm199354  */
1366*5440Sjm199354 int
1367*5440Sjm199354 vs_statistics_reset()
1368*5440Sjm199354 {
1369*5440Sjm199354 	int door_fd, rc;
1370*5440Sjm199354 	vs_stats_req_t *req;
1371*5440Sjm199354 	door_arg_t arg;
1372*5440Sjm199354 
1373*5440Sjm199354 	/* ensure that caller has authorization to reset stats */
1374*5440Sjm199354 	if ((rc = vs_checkauth(VS_VALUE_AUTH)) != VS_ERR_NONE)
1375*5440Sjm199354 		return (rc);
1376*5440Sjm199354 
1377*5440Sjm199354 	if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
1378*5440Sjm199354 		return (VS_ERR_SYS);
1379*5440Sjm199354 
1380*5440Sjm199354 	if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
1381*5440Sjm199354 		free(req);
1382*5440Sjm199354 		return (VS_ERR_DAEMON_COMM);
1383*5440Sjm199354 	}
1384*5440Sjm199354 
1385*5440Sjm199354 	*req = VS_STATS_RESET;
1386*5440Sjm199354 
1387*5440Sjm199354 	arg.data_ptr = (char *)req;
1388*5440Sjm199354 	arg.data_size = sizeof (vs_stats_req_t);
1389*5440Sjm199354 	arg.desc_ptr = NULL;
1390*5440Sjm199354 	arg.desc_num = 0;
1391*5440Sjm199354 	arg.rbuf = NULL;
1392*5440Sjm199354 	arg.rsize = 0;
1393*5440Sjm199354 
1394*5440Sjm199354 	if (door_call(door_fd, &arg) < 0)
1395*5440Sjm199354 		rc = VS_ERR_DAEMON_COMM;
1396*5440Sjm199354 	else
1397*5440Sjm199354 		rc = VS_ERR_NONE;
1398*5440Sjm199354 
1399*5440Sjm199354 	(void) close(door_fd);
1400*5440Sjm199354 	free(req);
1401*5440Sjm199354 	return (rc);
1402*5440Sjm199354 }
1403*5440Sjm199354 
1404*5440Sjm199354 
1405*5440Sjm199354 /*
1406*5440Sjm199354  * vs_checkauth
1407*5440Sjm199354  */
1408*5440Sjm199354 static int
1409*5440Sjm199354 vs_checkauth(char *auth)
1410*5440Sjm199354 {
1411*5440Sjm199354 	struct passwd *pw;
1412*5440Sjm199354 	uid_t uid;
1413*5440Sjm199354 
1414*5440Sjm199354 	uid = getuid();
1415*5440Sjm199354 
1416*5440Sjm199354 	if ((pw = getpwuid(uid)) == NULL)
1417*5440Sjm199354 		return (VS_ERR_SYS);
1418*5440Sjm199354 
1419*5440Sjm199354 	if (chkauthattr(auth, pw->pw_name) != 1) {
1420*5440Sjm199354 		return (VS_ERR_AUTH);
1421*5440Sjm199354 	}
1422*5440Sjm199354 
1423*5440Sjm199354 	return (VS_ERR_NONE);
1424*5440Sjm199354 }
1425*5440Sjm199354 
1426*5440Sjm199354 
1427*5440Sjm199354 /*
1428*5440Sjm199354  * vs_props_get_engines
1429*5440Sjm199354  * On input, count specifies the maximum number of engine ids to
1430*5440Sjm199354  * return. engids must be an array with count entries.
1431*5440Sjm199354  * On return, count specifies the number of engine ids being
1432*5440Sjm199354  * returned in engids.
1433*5440Sjm199354  */
1434*5440Sjm199354 static int
1435*5440Sjm199354 vs_props_get_engines(vs_engid_t *engids, int *count)
1436*5440Sjm199354 {
1437*5440Sjm199354 	int i = 0;
1438*5440Sjm199354 	vs_scfctx_t vsc;
1439*5440Sjm199354 
1440*5440Sjm199354 
1441*5440Sjm199354 	if (((vs_scf_ctx_open(&vsc)) != 0) ||
1442*5440Sjm199354 	    ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) ||
1443*5440Sjm199354 	    (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst,
1444*5440Sjm199354 	    SCF_GROUP_APPLICATION) != 0)) {
1445*5440Sjm199354 		vs_scf_ctx_close(&vsc);
1446*5440Sjm199354 		return (VS_ERR_SCF);
1447*5440Sjm199354 	}
1448*5440Sjm199354 
1449*5440Sjm199354 	while ((i < VS_SE_MAX) &&
1450*5440Sjm199354 	    (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)) {
1451*5440Sjm199354 		if (scf_pg_get_name(vsc.vscf_pgroup, engids[i],
1452*5440Sjm199354 		    VS_SE_NAME_LEN) < 0) {
1453*5440Sjm199354 			vs_scf_ctx_close(&vsc);
1454*5440Sjm199354 			return (VS_ERR_SCF);
1455*5440Sjm199354 		}
1456*5440Sjm199354 
1457*5440Sjm199354 		if (strcmp(engids[i], VS_PGNAME_GENERAL) == 0)
1458*5440Sjm199354 			*engids[i] = 0;
1459*5440Sjm199354 		else
1460*5440Sjm199354 			if (++i == *count)
1461*5440Sjm199354 			break;
1462*5440Sjm199354 	}
1463*5440Sjm199354 	vs_scf_ctx_close(&vsc);
1464*5440Sjm199354 
1465*5440Sjm199354 	*count = i;
1466*5440Sjm199354 	return (VS_ERR_NONE);
1467*5440Sjm199354 }
1468*5440Sjm199354 
1469*5440Sjm199354 
1470*5440Sjm199354 /*
1471*5440Sjm199354  * vs_scf_pg_count
1472*5440Sjm199354  */
1473*5440Sjm199354 static int
1474*5440Sjm199354 vs_scf_pg_count(void)
1475*5440Sjm199354 {
1476*5440Sjm199354 	int count = 0;
1477*5440Sjm199354 	vs_scfctx_t vsc;
1478*5440Sjm199354 
1479*5440Sjm199354 	if ((vs_scf_ctx_open(&vsc) != 0) ||
1480*5440Sjm199354 	    ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) ||
1481*5440Sjm199354 	    (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst,
1482*5440Sjm199354 	    SCF_GROUP_APPLICATION) != 0)) {
1483*5440Sjm199354 		vs_scf_ctx_close(&vsc);
1484*5440Sjm199354 		return (-1);
1485*5440Sjm199354 	}
1486*5440Sjm199354 
1487*5440Sjm199354 	while (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)
1488*5440Sjm199354 		++count;
1489*5440Sjm199354 
1490*5440Sjm199354 	vs_scf_ctx_close(&vsc);
1491*5440Sjm199354 
1492*5440Sjm199354 	return (count);
1493*5440Sjm199354 }
1494*5440Sjm199354 
1495*5440Sjm199354 
1496*5440Sjm199354 /*
1497*5440Sjm199354  *  vs_strtonum
1498*5440Sjm199354  *
1499*5440Sjm199354  *  Converts a size string in the format into an integer.
1500*5440Sjm199354  *
1501*5440Sjm199354  *  A size string is a numeric value followed by an optional unit
1502*5440Sjm199354  *  specifier which is used as a multiplier to calculate a raw
1503*5440Sjm199354  *  number.
1504*5440Sjm199354  *  The size string format is:  N[.N][KMGTP][B]
1505*5440Sjm199354  *
1506*5440Sjm199354  *  The numeric value can contain a decimal portion. Unit specifiers
1507*5440Sjm199354  *  are either a one-character or two-character string; i.e. "K" or
1508*5440Sjm199354  *  "KB" for kilobytes. Unit specifiers must follow the numeric portion
1509*5440Sjm199354  *  immediately, and are not case-sensitive.
1510*5440Sjm199354  *
1511*5440Sjm199354  *  If either "B" is specified, or there is no unit specifier portion
1512*5440Sjm199354  *  in the string, the numeric value is calculated with no multiplier
1513*5440Sjm199354  *  (assumes a basic unit of "bytes").
1514*5440Sjm199354  *
1515*5440Sjm199354  *  Returns:
1516*5440Sjm199354  *	-1:	Failure; errno set to specify the error.
1517*5440Sjm199354  *	 0:	Success.
1518*5440Sjm199354  */
1519*5440Sjm199354 int
1520*5440Sjm199354 vs_strtonum(const char *value, uint64_t *num)
1521*5440Sjm199354 {
1522*5440Sjm199354 	char *end;
1523*5440Sjm199354 	int shift;
1524*5440Sjm199354 	double fval;
1525*5440Sjm199354 
1526*5440Sjm199354 	*num = 0;
1527*5440Sjm199354 
1528*5440Sjm199354 	/* Check to see if this looks like a number.  */
1529*5440Sjm199354 	if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
1530*5440Sjm199354 		errno = EINVAL;
1531*5440Sjm199354 		return (-1);
1532*5440Sjm199354 	}
1533*5440Sjm199354 
1534*5440Sjm199354 	/* Rely on stroll() to process the numeric portion.  */
1535*5440Sjm199354 	errno = 0;
1536*5440Sjm199354 	*num = strtoll(value, &end, 10);
1537*5440Sjm199354 
1538*5440Sjm199354 	/*
1539*5440Sjm199354 	 * Check for ERANGE, which indicates that the value is too large to
1540*5440Sjm199354 	 * fit in a 64-bit value.
1541*5440Sjm199354 	 */
1542*5440Sjm199354 	if (errno != 0)
1543*5440Sjm199354 		return (-1);
1544*5440Sjm199354 
1545*5440Sjm199354 	/*
1546*5440Sjm199354 	 * If we have a decimal value, then do the computation with floating
1547*5440Sjm199354 	 * point arithmetic.  Otherwise, use standard arithmetic.
1548*5440Sjm199354 	 */
1549*5440Sjm199354 	if (*end == '.') {
1550*5440Sjm199354 		fval = strtod(value, &end);
1551*5440Sjm199354 
1552*5440Sjm199354 		if ((shift = vs_strtoshift(end)) == -1)
1553*5440Sjm199354 			return (-1); /* errno set */
1554*5440Sjm199354 
1555*5440Sjm199354 		fval *= pow(2, shift);
1556*5440Sjm199354 		if (fval > UINT64_MAX) {
1557*5440Sjm199354 			errno = ERANGE;
1558*5440Sjm199354 			return (-1);
1559*5440Sjm199354 		}
1560*5440Sjm199354 
1561*5440Sjm199354 		*num = (uint64_t)fval;
1562*5440Sjm199354 	} else {
1563*5440Sjm199354 		if ((shift = vs_strtoshift(end)) == -1)
1564*5440Sjm199354 			return (-1); /* errno set */
1565*5440Sjm199354 
1566*5440Sjm199354 		/* Check for overflow */
1567*5440Sjm199354 		if (shift >= 64 || (*num << shift) >> shift != *num) {
1568*5440Sjm199354 			errno = ERANGE;
1569*5440Sjm199354 			return (-1);
1570*5440Sjm199354 		}
1571*5440Sjm199354 
1572*5440Sjm199354 		*num <<= shift;
1573*5440Sjm199354 	}
1574*5440Sjm199354 
1575*5440Sjm199354 	return (0);
1576*5440Sjm199354 }
1577*5440Sjm199354 
1578*5440Sjm199354 
1579*5440Sjm199354 /*
1580*5440Sjm199354  *  vs_strtoshift
1581*5440Sjm199354  *
1582*5440Sjm199354  *  Converts a unit specifier string into a number of bits that
1583*5440Sjm199354  *  a numeric value must be shifted.
1584*5440Sjm199354  *
1585*5440Sjm199354  *  Returns:
1586*5440Sjm199354  *	-1:	Failure; errno set to specify the error.
1587*5440Sjm199354  *	>-1:	Success; the shift count.
1588*5440Sjm199354  *
1589*5440Sjm199354  */
1590*5440Sjm199354 static int
1591*5440Sjm199354 vs_strtoshift(const char *buf)
1592*5440Sjm199354 {
1593*5440Sjm199354 	const char *ends = "BKMGTPEZ";
1594*5440Sjm199354 	int i;
1595*5440Sjm199354 
1596*5440Sjm199354 	if (buf[0] == '\0')
1597*5440Sjm199354 		return (0);
1598*5440Sjm199354 	for (i = 0; i < strlen(ends); i++) {
1599*5440Sjm199354 		if (toupper(buf[0]) == ends[i])
1600*5440Sjm199354 			break;
1601*5440Sjm199354 	}
1602*5440Sjm199354 	if (i == strlen(ends)) {
1603*5440Sjm199354 		errno = EINVAL;
1604*5440Sjm199354 		return (-1);
1605*5440Sjm199354 	}
1606*5440Sjm199354 
1607*5440Sjm199354 	/* Allow trailing 'b' characters except in the case of 'BB'. */
1608*5440Sjm199354 	if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' &&
1609*5440Sjm199354 	    toupper(buf[0]) != 'B')) {
1610*5440Sjm199354 		return (10 * i);
1611*5440Sjm199354 	}
1612*5440Sjm199354 
1613*5440Sjm199354 	errno = EINVAL;
1614*5440Sjm199354 	return (-1);
1615*5440Sjm199354 }
1616