1911106dfSjm /*
2911106dfSjm  * CDDL HEADER START
3911106dfSjm  *
4911106dfSjm  * The contents of this file are subject to the terms of the
5911106dfSjm  * Common Development and Distribution License (the "License").
6911106dfSjm  * You may not use this file except in compliance with the License.
7911106dfSjm  *
8911106dfSjm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9911106dfSjm  * or http://www.opensolaris.org/os/licensing.
10911106dfSjm  * See the License for the specific language governing permissions
11911106dfSjm  * and limitations under the License.
12911106dfSjm  *
13911106dfSjm  * When distributing Covered Code, include this CDDL HEADER in each
14911106dfSjm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15911106dfSjm  * If applicable, add the following below this CDDL HEADER, with the
16911106dfSjm  * fields enclosed by brackets "[]" replaced with your own identifying
17911106dfSjm  * information: Portions Copyright [yyyy] [name of copyright owner]
18911106dfSjm  *
19911106dfSjm  * CDDL HEADER END
20911106dfSjm  */
21911106dfSjm /*
22*1bf43fcdSjoyce mcintosh  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23911106dfSjm  * Use is subject to license terms.
24911106dfSjm  */
25911106dfSjm 
26911106dfSjm #include <string.h>
27911106dfSjm #include <stdio.h>
28911106dfSjm #include <stdlib.h>
29911106dfSjm #include <unistd.h>
30911106dfSjm #include <ctype.h>
31911106dfSjm #include <math.h>
32911106dfSjm #include <limits.h>
33911106dfSjm #include <libscf.h>
34911106dfSjm #include <errno.h>
35911106dfSjm #include <fcntl.h>
36911106dfSjm #include <door.h>
37911106dfSjm #include <pwd.h>
38911106dfSjm #include <auth_attr.h>
39911106dfSjm #include <secdb.h>
40911106dfSjm #include <sys/socket.h>
41911106dfSjm #include <arpa/inet.h>
42911106dfSjm #include <libintl.h>
43911106dfSjm #include <libvscan.h>
44911106dfSjm 
451843d056SAlan Wright #define	VS_DOOR_CALL_RETRIES	3
461843d056SAlan Wright 
47911106dfSjm #define	VS_INSTANCE_FMRI	"svc:/system/filesystem/vscan:icap"
48911106dfSjm 
49911106dfSjm /* SMF property group and property names */
50911106dfSjm #define	VS_PGNAME_GENERAL		"vs_general"
51bfc848c6Sjm #define	VS_PGNAME_ENGINE_PREFIX		"vs_engine_"
52bfc848c6Sjm #define	VS_PGNAME_ENGINE_LEN		VS_SE_NAME_LEN + 16
53911106dfSjm 
54911106dfSjm #define	VS_PNAME_MAXSIZE		"maxsize"
55911106dfSjm #define	VS_PNAME_MAXSIZE_ACTION		"maxsize_action"
56911106dfSjm #define	VS_PNAME_TYPES			"types"
57911106dfSjm #define	VS_PNAME_VLOG			"viruslog"
58911106dfSjm 
59911106dfSjm #define	VS_PNAME_SE_ENABLE		"enable"
60911106dfSjm #define	VS_PNAME_SE_HOST		"host"
61911106dfSjm #define	VS_PNAME_SE_PORT		"port"
62911106dfSjm #define	VS_PNAME_SE_MAXCONN		"max_connect"
63911106dfSjm #define	VS_PNAME_VAUTH			"value_authorization"
64911106dfSjm 
65911106dfSjm 
66911106dfSjm /* types string processing */
67911106dfSjm #define	VS_TYPES_SEP		','
68911106dfSjm #define	VS_TYPES_ESCAPE		'\\'
69911106dfSjm #define	VS_TYPES_RULES		"+-"
70911106dfSjm 
71911106dfSjm 
72911106dfSjm /*
73911106dfSjm  * The SCF context enapsulating the SCF objects used in the
74911106dfSjm  * repository load and store routines vs_scf_values_get()
75911106dfSjm  * and vs_scf_values_set().
76911106dfSjm  *
77911106dfSjm  * The context is always opened before a get or set, then
78911106dfSjm  * closed when finished (or on error); the open does an
79911106dfSjm  * initial setup, while inside the get and set functions,
80911106dfSjm  * additional objects within the context may be selectively
81911106dfSjm  * initialized for use, depending on the actions needed and
82911106dfSjm  * the properties being operated on.
83911106dfSjm  */
84911106dfSjm typedef struct vs_scfctx {
85911106dfSjm 	scf_handle_t *vscf_handle;
86911106dfSjm 	scf_instance_t *vscf_inst;
87911106dfSjm 	scf_propertygroup_t *vscf_pgroup;
88911106dfSjm 	scf_transaction_t *vscf_tx;
89911106dfSjm 	scf_iter_t *vscf_iter;
90911106dfSjm 	scf_property_t *vscf_prop[VS_NUM_PROPIDS];
91911106dfSjm 	scf_transaction_entry_t *vscf_ent[VS_NUM_PROPIDS];
92911106dfSjm 	scf_value_t *vscf_val[VS_NUM_PROPIDS];
93911106dfSjm } vs_scfctx_t;
94911106dfSjm 
95911106dfSjm /*
96911106dfSjm  * The vscan property definition. Maps the property id with the name
97911106dfSjm  * and type used to store the property in the repository.
98911106dfSjm  * A table of these definitions is defined with a single entry per
99911106dfSjm  * property.
100911106dfSjm  */
101911106dfSjm typedef struct {
102911106dfSjm 	const char *vpd_name;
103911106dfSjm 	uint64_t vpd_id;
104911106dfSjm 	scf_type_t vpd_type;
105911106dfSjm } vs_propdef_t;
106911106dfSjm 
107911106dfSjm typedef enum {
108911106dfSjm 	VS_PTYPE_GEN,
109911106dfSjm 	VS_PTYPE_SE
110911106dfSjm } vs_prop_type_t;
111911106dfSjm 
112911106dfSjm typedef struct vs_prop_hd {
113911106dfSjm 	vs_prop_type_t vp_type;
114911106dfSjm 	uint64_t vp_ids;
115911106dfSjm 	uint64_t vp_all;
116911106dfSjm 	union {
117911106dfSjm 		vs_props_t vp_gen;
118911106dfSjm 		vs_props_se_t vp_se;
119911106dfSjm 	} vp_props;
120911106dfSjm } vs_prop_hd_t;
121911106dfSjm 
122911106dfSjm #define	vp_gen	vp_props.vp_gen
123911106dfSjm #define	vp_se	vp_props.vp_se
124911106dfSjm 
125911106dfSjm /*
126911106dfSjm  * Default values - these are used to return valid data
127911106dfSjm  * to the caller in cases where invalid or unexpected values
128911106dfSjm  * are found in the repository.
129911106dfSjm  *
130911106dfSjm  * Note: These values must be kept in sync with those defined
131911106dfSjm  * in the service manifest.
132911106dfSjm  */
133911106dfSjm static const boolean_t vs_dflt_allow = B_TRUE;
134911106dfSjm static const boolean_t vs_dflt_enable = B_TRUE;
135911106dfSjm static const char *vs_dflt_maxsize = "1GB";
136911106dfSjm static const char *vs_dflt_host = "";
137911106dfSjm static const uint16_t vs_dflt_port = 1344;
138*1bf43fcdSjoyce mcintosh static const uint16_t vs_dflt_maxconn = 8;
139911106dfSjm static const  char *vs_dflt_types = "+*";
140911106dfSjm static const char *vs_dflt_vlog = "";
141911106dfSjm 
142911106dfSjm /* Property definition table */
143911106dfSjm static const vs_propdef_t vs_propdefs[] = {
144911106dfSjm 	/* general properties */
145911106dfSjm 	{ VS_PNAME_MAXSIZE, VS_PROPID_MAXSIZE, SCF_TYPE_ASTRING },
146911106dfSjm 	{ VS_PNAME_MAXSIZE_ACTION, VS_PROPID_MAXSIZE_ACTION, SCF_TYPE_BOOLEAN },
147911106dfSjm 	{ VS_PNAME_TYPES, VS_PROPID_TYPES, SCF_TYPE_ASTRING },
148911106dfSjm 	{ VS_PNAME_VLOG, VS_PROPID_VLOG, SCF_TYPE_ASTRING },
149911106dfSjm 	/* scan engine properties */
150911106dfSjm 	{ VS_PNAME_SE_ENABLE, VS_PROPID_SE_ENABLE, SCF_TYPE_BOOLEAN },
151911106dfSjm 	{ VS_PNAME_SE_HOST, VS_PROPID_SE_HOST, SCF_TYPE_HOST },
152911106dfSjm 	{ VS_PNAME_SE_PORT, VS_PROPID_SE_PORT, SCF_TYPE_INTEGER },
153911106dfSjm 	{ VS_PNAME_SE_MAXCONN, VS_PROPID_SE_MAXCONN, SCF_TYPE_INTEGER },
154911106dfSjm 	{ VS_PNAME_VAUTH, VS_PROPID_VALUE_AUTH, SCF_TYPE_ASTRING }
155911106dfSjm };
156911106dfSjm 
157911106dfSjm static const int vs_npropdefs = sizeof (vs_propdefs)/sizeof (vs_propdef_t);
158911106dfSjm 
159911106dfSjm /* Local functions */
160911106dfSjm static const vs_propdef_t *vs_get_propdef(uint64_t);
161911106dfSjm static void vs_default_value(vs_prop_hd_t *, const uint64_t);
162911106dfSjm 
163911106dfSjm static int vs_scf_values_get(const char *, vs_prop_hd_t *);
164911106dfSjm static int vs_scf_get(const vs_propdef_t *, vs_prop_hd_t *, vs_scfctx_t *, int);
165911106dfSjm 
166911106dfSjm static int vs_scf_values_set(const char *, vs_prop_hd_t *);
167911106dfSjm static int vs_scf_set(const vs_propdef_t *, vs_prop_hd_t *, vs_scfctx_t *, int);
168911106dfSjm static int vs_scf_pg_create(const char *, vs_prop_hd_t *);
169bfc848c6Sjm static int vs_scf_pg_delete(const char *);
170911106dfSjm 
171911106dfSjm static int vs_scf_ctx_open(vs_scfctx_t *);
172911106dfSjm static void vs_scf_ctx_close(vs_scfctx_t *);
173911106dfSjm 
174911106dfSjm static int vs_validate(const vs_prop_hd_t *, uint64_t);
175911106dfSjm static int vs_is_valid_types(const char *);
176911106dfSjm static int vs_is_valid_host(const char *);
177911106dfSjm static int vs_checkauth(char *);
1781843d056SAlan Wright static int vs_door_call(int, door_arg_t *);
179911106dfSjm 
180bfc848c6Sjm static int vs_props_get_engines(char *[], int *);
181bfc848c6Sjm static void vs_engid_to_pgname(const char *, char [VS_PGNAME_ENGINE_LEN]);
182911106dfSjm static int vs_scf_pg_count(void);
183911106dfSjm static int vs_strtoshift(const char *);
184911106dfSjm 
185911106dfSjm 
186911106dfSjm /*
187911106dfSjm  * vs_props_get_all
188911106dfSjm  *
189911106dfSjm  * Retrieves the general service properties and all properties
190911106dfSjm  * for all scan engines from the repository.
191911106dfSjm  *
192911106dfSjm  * If invalid property values are found, the values are corrected to
193911106dfSjm  * the default value.
194911106dfSjm  *
195911106dfSjm  * Return codes:
196911106dfSjm  *	VS_ERR_VS_ERR_NONE
197911106dfSjm  *	VS_ERR_SCF
198911106dfSjm  *	VS_ERR_SYS
199911106dfSjm  */
200911106dfSjm int
vs_props_get_all(vs_props_all_t * va)201911106dfSjm vs_props_get_all(vs_props_all_t *va)
202911106dfSjm {
203911106dfSjm 	int i, rc, n;
204bfc848c6Sjm 	char *engids[VS_SE_MAX];
205911106dfSjm 
206911106dfSjm 	(void) memset(va, 0, sizeof (vs_props_all_t));
207911106dfSjm 	if ((rc = vs_props_get(&va->va_props, VS_PROPID_GEN_ALL))
208911106dfSjm 	    != VS_ERR_NONE)
209911106dfSjm 		return (rc);
210911106dfSjm 
211911106dfSjm 	n = VS_SE_MAX;
212911106dfSjm 	if ((rc = vs_props_get_engines(engids, &n)) != VS_ERR_NONE)
213911106dfSjm 		return (rc);
214911106dfSjm 
215911106dfSjm 	for (i = 0; i < n; i++) {
216bfc848c6Sjm 		if ((rc = vs_props_se_get(engids[i],
217bfc848c6Sjm 		    &va->va_se[i], VS_PROPID_SE_ALL)) != VS_ERR_NONE)
218bfc848c6Sjm 			break;
219911106dfSjm 	}
220911106dfSjm 
221bfc848c6Sjm 	/* free engids allocated in vs_props_get_engines */
222bfc848c6Sjm 	for (i = 0; i < VS_SE_MAX; i++)	{
223bfc848c6Sjm 		if (engids[i] != NULL)
224bfc848c6Sjm 			free(engids[i]);
225bfc848c6Sjm 	}
226bfc848c6Sjm 
227bfc848c6Sjm 	return (rc);
228911106dfSjm }
229911106dfSjm 
230911106dfSjm 
231911106dfSjm /*
232911106dfSjm  * vs_props_get
233911106dfSjm  *
234911106dfSjm  * Retrieves values for the specified general service properties from
235911106dfSjm  * the repository.
236911106dfSjm  *
237911106dfSjm  * If invalid property values are found, the values are corrected to
238911106dfSjm  * the default value.
239911106dfSjm  *
240911106dfSjm  * Return codes:
241911106dfSjm  *	VS_ERR_VS_ERR_NONE
242911106dfSjm  *	VS_ERR_INVALID_PROPERTY
243911106dfSjm  *	VS_ERR_SCF
244911106dfSjm  *	VS_ERR_SYS
245911106dfSjm  */
246911106dfSjm int
vs_props_get(vs_props_t * vp,uint64_t propids)247911106dfSjm vs_props_get(vs_props_t *vp, uint64_t propids)
248911106dfSjm {
249911106dfSjm 	int  rc;
250911106dfSjm 	vs_prop_hd_t prop_hd;
251911106dfSjm 
252911106dfSjm 	if ((propids & VS_PROPID_GEN_ALL) != propids)
253911106dfSjm 		return (VS_ERR_INVALID_PROPERTY);
254911106dfSjm 
255911106dfSjm 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
256911106dfSjm 	prop_hd.vp_type = VS_PTYPE_GEN;
257911106dfSjm 	prop_hd.vp_ids = propids;
258911106dfSjm 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
259911106dfSjm 
260911106dfSjm 	rc = vs_scf_values_get(VS_PGNAME_GENERAL, &prop_hd);
261911106dfSjm 
262911106dfSjm 	*vp = prop_hd.vp_gen;
263911106dfSjm 	return (rc);
264911106dfSjm }
265911106dfSjm 
266911106dfSjm 
267911106dfSjm /*
268911106dfSjm  * vs_props_set
269911106dfSjm  *
270911106dfSjm  * Changes values for the specified general service properties
271911106dfSjm  * in the repository.
272911106dfSjm  *
273911106dfSjm  * Return codes:
274911106dfSjm  *	VS_ERR_VS_ERR_NONE
275911106dfSjm  *	VS_ERR_INVALID_PROPERTY
276911106dfSjm  *	VS_ERR_INVALID_VALUE
277911106dfSjm  *	VS_ERR_SCF
278911106dfSjm  *	VS_ERR_SYS
279911106dfSjm  */
280911106dfSjm int
vs_props_set(const vs_props_t * vp,uint64_t propids)281911106dfSjm vs_props_set(const vs_props_t *vp, uint64_t propids)
282911106dfSjm {
283911106dfSjm 	vs_prop_hd_t prop_hd;
284911106dfSjm 
285911106dfSjm 	if ((propids & VS_PROPID_GEN_ALL) != propids)
286911106dfSjm 		return (VS_ERR_INVALID_PROPERTY);
287911106dfSjm 
288911106dfSjm 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
289911106dfSjm 	prop_hd.vp_type = VS_PTYPE_GEN;
290911106dfSjm 	prop_hd.vp_ids = propids;
291911106dfSjm 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
292911106dfSjm 	prop_hd.vp_gen = *vp;
293911106dfSjm 	return (vs_scf_values_set(VS_PGNAME_GENERAL, &prop_hd));
294911106dfSjm }
295911106dfSjm 
296911106dfSjm 
297911106dfSjm /*
298911106dfSjm  * vs_props_se_get
299911106dfSjm  *
300911106dfSjm  * Retrieves values for the specified scan engine properties from the
301911106dfSjm  * repository.
302911106dfSjm  *
303911106dfSjm  * If the enable property is set (true), the host property is
304911106dfSjm  * checked for validity. If it is not valid, the requested values
305911106dfSjm  * are returned with the enable propery set to off (false)
306911106dfSjm  *
307911106dfSjm  * Return codes:
308911106dfSjm  *	VS_ERR_VS_ERR_NONE
309911106dfSjm  *	VS_ERR_INVALID_PROPERTY
310911106dfSjm  *	VS_ERR_SCF
311911106dfSjm  *	VS_ERR_SYS
312911106dfSjm  */
313911106dfSjm int
vs_props_se_get(char * engid,vs_props_se_t * sep,uint64_t propids)314911106dfSjm vs_props_se_get(char *engid, vs_props_se_t *sep, uint64_t propids)
315911106dfSjm {
316911106dfSjm 	int rc;
317bfc848c6Sjm 	char pgname[VS_PGNAME_ENGINE_LEN];
318911106dfSjm 	vs_prop_hd_t prop_hd;
319911106dfSjm 
320911106dfSjm 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
321911106dfSjm 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
322911106dfSjm 		return (VS_ERR_INVALID_SE);
323911106dfSjm 
324911106dfSjm 	if ((propids & VS_PROPID_SE_ALL) != propids)
325911106dfSjm 		return (VS_ERR_INVALID_PROPERTY);
326911106dfSjm 
327911106dfSjm 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
328911106dfSjm 	prop_hd.vp_type = VS_PTYPE_SE;
329911106dfSjm 	prop_hd.vp_ids = propids;
330911106dfSjm 	prop_hd.vp_all = VS_PROPID_SE_ALL;
331911106dfSjm 	(void) strlcpy(prop_hd.vp_se.vep_engid, engid, VS_SE_NAME_LEN);
332911106dfSjm 
333911106dfSjm 	/* If getting enable, get the host property too */
334911106dfSjm 	if ((propids & VS_PROPID_SE_ENABLE))
335911106dfSjm 		prop_hd.vp_ids |= VS_PROPID_SE_HOST;
336911106dfSjm 
337911106dfSjm 	/* Load values from the repository */
338bfc848c6Sjm 	vs_engid_to_pgname(engid, pgname);
339bfc848c6Sjm 	rc = vs_scf_values_get(pgname, &prop_hd);
340911106dfSjm 	if (rc != VS_ERR_NONE)
341911106dfSjm 		return (rc);
342911106dfSjm 
343911106dfSjm 	/*
344911106dfSjm 	 *  If the host is invalid and the enable property is on,
345911106dfSjm 	 *  return enable property as off
346911106dfSjm 	 */
347911106dfSjm 	if ((prop_hd.vp_ids & VS_PROPID_SE_HOST) &&
348911106dfSjm 	    (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)) {
349911106dfSjm 		prop_hd.vp_se.vep_enable = B_FALSE;
350911106dfSjm 	}
351911106dfSjm 
352911106dfSjm 	*sep = prop_hd.vp_se;
353911106dfSjm 	return (rc);
354911106dfSjm }
355911106dfSjm 
356911106dfSjm 
357911106dfSjm 
358911106dfSjm /*
359911106dfSjm  * vs_props_se_set
360911106dfSjm  *
361911106dfSjm  * Changes the values for the specified scan engine properties in the
362911106dfSjm  * repository.
363911106dfSjm  *
364911106dfSjm  * If the enable property is being changed to true in this operation,
365911106dfSjm  * a host property must also be specified, or already exist in the
366911106dfSjm  * repository.
367911106dfSjm  *
368911106dfSjm  * Return codes:
369911106dfSjm  *	VS_ERR_NONE
370911106dfSjm  *	VS_ERR_INVALID_PROPERTY
371911106dfSjm  *	VS_ERR_INVALID_VALUE
372911106dfSjm  *	VS_ERR_SCF
373911106dfSjm  *	VS_ERR_SYS
374911106dfSjm  */
375911106dfSjm int
vs_props_se_set(char * engid,const vs_props_se_t * sep,uint64_t propids)376911106dfSjm vs_props_se_set(char *engid, const vs_props_se_t *sep, uint64_t propids)
377911106dfSjm {
378911106dfSjm 	int rc;
379bfc848c6Sjm 	char pgname[VS_PGNAME_ENGINE_LEN];
380911106dfSjm 	vs_prop_hd_t prop_hd;
381911106dfSjm 
382911106dfSjm 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
383911106dfSjm 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
384911106dfSjm 		return (VS_ERR_INVALID_SE);
385911106dfSjm 
386911106dfSjm 	if ((propids & VS_PROPID_SE_ALL) != propids)
387911106dfSjm 		return (VS_ERR_INVALID_PROPERTY);
388911106dfSjm 
389911106dfSjm 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
390911106dfSjm 	prop_hd.vp_type = VS_PTYPE_SE;
391911106dfSjm 	prop_hd.vp_all = VS_PROPID_SE_ALL;
392911106dfSjm 
393bfc848c6Sjm 	vs_engid_to_pgname(engid, pgname);
394bfc848c6Sjm 
395911106dfSjm 	/*
396911106dfSjm 	 * if enabling a scan engine, ensure that a valid host
397911106dfSjm 	 * is also being set, or already exists in the repository
398911106dfSjm 	 */
399911106dfSjm 	if ((propids & VS_PROPID_SE_ENABLE) && (sep->vep_enable == B_TRUE) &&
400911106dfSjm 	    !(propids & VS_PROPID_SE_HOST)) {
401911106dfSjm 
402911106dfSjm 		prop_hd.vp_ids = VS_PROPID_SE_HOST;
403bfc848c6Sjm 		if ((rc = vs_scf_values_get(pgname, &prop_hd)) != VS_ERR_NONE)
404911106dfSjm 			return (rc);
405911106dfSjm 
406911106dfSjm 		if (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)
407911106dfSjm 			return (VS_ERR_INVALID_HOST);
408911106dfSjm 	}
409911106dfSjm 
410911106dfSjm 	prop_hd.vp_ids = propids;
411911106dfSjm 	prop_hd.vp_se = *sep;
412911106dfSjm 
413bfc848c6Sjm 	return (vs_scf_values_set(pgname, &prop_hd));
414911106dfSjm }
415911106dfSjm 
416911106dfSjm 
417911106dfSjm /*
418911106dfSjm  * vs_props_se_create
419911106dfSjm  */
420911106dfSjm int
vs_props_se_create(char * engid,const vs_props_se_t * sep,uint64_t propids)421911106dfSjm vs_props_se_create(char *engid, const vs_props_se_t *sep, uint64_t propids)
422911106dfSjm {
423911106dfSjm 	int n;
424bfc848c6Sjm 	char pgname[VS_PGNAME_ENGINE_LEN];
425911106dfSjm 	vs_prop_hd_t prop_hd;
426911106dfSjm 
427911106dfSjm 	if ((propids & VS_PROPID_SE_ALL) != propids)
428911106dfSjm 		return (VS_ERR_INVALID_PROPERTY);
429911106dfSjm 
430911106dfSjm 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
431911106dfSjm 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
432911106dfSjm 		return (VS_ERR_INVALID_SE);
433911106dfSjm 
434911106dfSjm 	if ((n = vs_scf_pg_count()) == -1)
435911106dfSjm 		return (VS_ERR_SCF);
436911106dfSjm 
437911106dfSjm 	if (n == VS_SE_MAX)
438911106dfSjm 		return (VS_ERR_MAX_SE);
439911106dfSjm 
440bfc848c6Sjm 	vs_engid_to_pgname(engid, pgname);
441bfc848c6Sjm 
442911106dfSjm 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
443911106dfSjm 	prop_hd.vp_type = VS_PTYPE_SE;
444911106dfSjm 	prop_hd.vp_all = VS_PROPID_SE_ALL;
445911106dfSjm 	prop_hd.vp_ids = propids | VS_PROPID_VALUE_AUTH;
446911106dfSjm 	prop_hd.vp_se = *sep;
447911106dfSjm 
448bfc848c6Sjm 	/* if hostname not specified, default it to engid */
449bfc848c6Sjm 	if ((propids & VS_PROPID_SE_HOST) == 0) {
450bfc848c6Sjm 		(void) strlcpy(prop_hd.vp_se.vep_host, engid, MAXHOSTNAMELEN);
451bfc848c6Sjm 		prop_hd.vp_ids |= VS_PROPID_SE_HOST;
452bfc848c6Sjm 	}
453911106dfSjm 
454bfc848c6Sjm 	return (vs_scf_pg_create(pgname, &prop_hd));
455911106dfSjm }
456911106dfSjm 
457911106dfSjm 
458911106dfSjm /*
459911106dfSjm  * vs_props_se_delete
460911106dfSjm  */
461911106dfSjm int
vs_props_se_delete(const char * engid)462911106dfSjm vs_props_se_delete(const char *engid)
463911106dfSjm {
464bfc848c6Sjm 	char pgname[VS_PGNAME_ENGINE_LEN];
465911106dfSjm 
466911106dfSjm 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
467911106dfSjm 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
468911106dfSjm 		return (VS_ERR_INVALID_SE);
469911106dfSjm 
470bfc848c6Sjm 	vs_engid_to_pgname(engid, pgname);
471911106dfSjm 
472bfc848c6Sjm 	return (vs_scf_pg_delete(pgname));
473911106dfSjm }
474911106dfSjm 
475911106dfSjm 
476911106dfSjm /*
477911106dfSjm  * vs_strerror
478911106dfSjm  */
479911106dfSjm const char *
vs_strerror(int error)480911106dfSjm vs_strerror(int error)
481911106dfSjm {
482911106dfSjm 	switch (error) {
483911106dfSjm 	case VS_ERR_NONE:
484911106dfSjm 		return (gettext("no error"));
485911106dfSjm 	case VS_ERR_INVALID_PROPERTY:
486911106dfSjm 		return (gettext("invalid property id"));
487911106dfSjm 	case VS_ERR_INVALID_VALUE:
488911106dfSjm 		return (gettext("invalid property value"));
489911106dfSjm 	case VS_ERR_INVALID_HOST:
490911106dfSjm 		return (gettext("invalid host"));
491911106dfSjm 	case VS_ERR_INVALID_SE:
492911106dfSjm 		return (gettext("invalid scan engine"));
493911106dfSjm 	case VS_ERR_MAX_SE:
494911106dfSjm 		return (gettext("max scan engines exceeded"));
495911106dfSjm 	case VS_ERR_AUTH:
496911106dfSjm 		return (gettext("insufficient privileges for action"));
497911106dfSjm 	case VS_ERR_DAEMON_COMM:
498911106dfSjm 		return (gettext("unable to contact vscand"));
499911106dfSjm 	case VS_ERR_SCF:
500911106dfSjm 		return (scf_strerror(scf_error()));
501911106dfSjm 	case VS_ERR_SYS:
502911106dfSjm 		return (strerror(errno));
503911106dfSjm 	default:
504911106dfSjm 		return (gettext("unknown error"));
505911106dfSjm 	}
506911106dfSjm }
507911106dfSjm 
508911106dfSjm 
509911106dfSjm /*
510911106dfSjm  * vs_get_propdef
511911106dfSjm  *
512911106dfSjm  * Finds and returns a property definition by property id.
513911106dfSjm  */
514911106dfSjm static const vs_propdef_t *
vs_get_propdef(uint64_t propid)515911106dfSjm vs_get_propdef(uint64_t propid)
516911106dfSjm {
517911106dfSjm 	int i;
518911106dfSjm 
519911106dfSjm 	for (i = 0; i < vs_npropdefs; i++) {
520911106dfSjm 		if (propid == vs_propdefs[i].vpd_id)
521911106dfSjm 			return (&vs_propdefs[i]);
522911106dfSjm 	}
523911106dfSjm 
524911106dfSjm 	return (NULL);
525911106dfSjm }
526911106dfSjm 
527911106dfSjm 
528911106dfSjm /*
529911106dfSjm  * vs_default_value
530911106dfSjm  *
531911106dfSjm  * Sets a property value that contains invalid data to its default value.
532911106dfSjm  *
533911106dfSjm  * Note that this function does not alter any values in the repository
534911106dfSjm  * This is only to enable the caller to get valid data.
535911106dfSjm  */
536911106dfSjm static void
vs_default_value(vs_prop_hd_t * prop_hd,const uint64_t propid)537911106dfSjm vs_default_value(vs_prop_hd_t *prop_hd, const uint64_t propid)
538911106dfSjm {
539911106dfSjm 	vs_props_t *vp = &prop_hd->vp_gen;
540911106dfSjm 	vs_props_se_t *vep = &prop_hd->vp_se;
541911106dfSjm 
542911106dfSjm 	switch (propid) {
543911106dfSjm 	case VS_PROPID_MAXSIZE:
544911106dfSjm 		(void) strlcpy(vp->vp_maxsize, vs_dflt_maxsize,
545911106dfSjm 		    sizeof (vp->vp_maxsize));
546911106dfSjm 		break;
547911106dfSjm 	case VS_PROPID_MAXSIZE_ACTION:
548911106dfSjm 		vp->vp_maxsize_action = vs_dflt_allow;
549911106dfSjm 		break;
550911106dfSjm 	case VS_PROPID_TYPES:
551911106dfSjm 		(void) strlcpy(vp->vp_types, vs_dflt_types,
552911106dfSjm 		    sizeof (vp->vp_types));
553911106dfSjm 		break;
554911106dfSjm 	case VS_PROPID_VLOG:
555911106dfSjm 		(void) strlcpy(vp->vp_vlog, vs_dflt_vlog,
556911106dfSjm 		    sizeof (vp->vp_vlog));
557911106dfSjm 		break;
558911106dfSjm 	case VS_PROPID_SE_ENABLE:
559911106dfSjm 		vep->vep_enable = vs_dflt_enable;
560911106dfSjm 		break;
561911106dfSjm 	case VS_PROPID_SE_HOST:
562911106dfSjm 		(void) strlcpy(vep->vep_host, vs_dflt_host,
563911106dfSjm 		    sizeof (vep->vep_host));
564911106dfSjm 		break;
565911106dfSjm 	case VS_PROPID_SE_PORT:
566911106dfSjm 		vep->vep_port = vs_dflt_port;
567911106dfSjm 		break;
568911106dfSjm 	case VS_PROPID_SE_MAXCONN:
569911106dfSjm 		vep->vep_maxconn = vs_dflt_maxconn;
570911106dfSjm 		break;
571911106dfSjm 	default:
572911106dfSjm 		break;
573911106dfSjm 	}
574911106dfSjm }
575911106dfSjm 
576911106dfSjm 
577911106dfSjm /*
578911106dfSjm  * vs_scf_values_get
579911106dfSjm  *
580911106dfSjm  * Gets property values for one or more properties from the repository.
581911106dfSjm  * This is the single entry point for loading SMF values.
582911106dfSjm  *
583911106dfSjm  * While a transaction is not used for loading property values,
584911106dfSjm  * the operation is parameterized by a property group. All properties
585911106dfSjm  * retrieved in this function, then, must belong to the same property
586911106dfSjm  * group.
587911106dfSjm  */
588911106dfSjm int
vs_scf_values_get(const char * pgname,vs_prop_hd_t * prop_hd)589911106dfSjm vs_scf_values_get(const char *pgname, vs_prop_hd_t *prop_hd)
590911106dfSjm {
591911106dfSjm 	vs_scfctx_t vsc;
592911106dfSjm 	int rc, np;
593911106dfSjm 	const vs_propdef_t *vpd;
594911106dfSjm 	uint64_t propid;
595911106dfSjm 
596911106dfSjm 	if ((vs_scf_ctx_open(&vsc)) != 0) {
597911106dfSjm 		vs_scf_ctx_close(&vsc);
598911106dfSjm 		return (VS_ERR_SCF);
599911106dfSjm 	}
600911106dfSjm 
601911106dfSjm 	if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
602911106dfSjm 		vs_scf_ctx_close(&vsc);
603911106dfSjm 		if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) {
604911106dfSjm 			rc = scf_error();
605911106dfSjm 			if ((rc == SCF_ERROR_NOT_FOUND) ||
606911106dfSjm 			    (rc == SCF_ERROR_INVALID_ARGUMENT))
607911106dfSjm 				return (VS_ERR_INVALID_SE);
608911106dfSjm 		}
609911106dfSjm 		return (VS_ERR_SCF);
610911106dfSjm 	}
611911106dfSjm 
612911106dfSjm 	rc = VS_ERR_NONE;
613911106dfSjm 	np = 0;
614911106dfSjm 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
615911106dfSjm 		if ((prop_hd->vp_ids & propid) == 0)
616911106dfSjm 			continue;
617911106dfSjm 
618911106dfSjm 		if ((vpd = vs_get_propdef(propid)) == NULL) {
619911106dfSjm 			rc = VS_ERR_INVALID_PROPERTY;
620911106dfSjm 			break;
621911106dfSjm 		}
622911106dfSjm 
623911106dfSjm 		vsc.vscf_prop[np] = scf_property_create(vsc.vscf_handle);
624911106dfSjm 		vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
625911106dfSjm 
626911106dfSjm 		if (vsc.vscf_prop[np] == NULL || vsc.vscf_val[np] == NULL) {
627911106dfSjm 			rc = VS_ERR_SCF;
628911106dfSjm 			break;
629911106dfSjm 		}
630911106dfSjm 
631911106dfSjm 		if (scf_pg_get_property(vsc.vscf_pgroup, vpd->vpd_name,
632911106dfSjm 		    vsc.vscf_prop[np]) == -1) {
633911106dfSjm 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
634911106dfSjm 				vs_default_value(prop_hd, vpd->vpd_id);
635911106dfSjm 				continue;
636911106dfSjm 			}
637911106dfSjm 			rc = VS_ERR_SCF;
638911106dfSjm 			break;
639911106dfSjm 		}
640911106dfSjm 
641911106dfSjm 		if ((rc = vs_scf_get(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
642911106dfSjm 			break;
643911106dfSjm 
644911106dfSjm 		++np;
645911106dfSjm 	}
646911106dfSjm 
647911106dfSjm 
648911106dfSjm 	vs_scf_ctx_close(&vsc);
649911106dfSjm 
650911106dfSjm 	return (rc);
651911106dfSjm }
652911106dfSjm 
653911106dfSjm 
654911106dfSjm /*
655911106dfSjm  * vs_scf_get
656911106dfSjm  *
657911106dfSjm  * Loads a single values from the repository into the appropriate vscan
658911106dfSjm  * property structure member.
659911106dfSjm  */
660911106dfSjm static int
vs_scf_get(const vs_propdef_t * vpd,vs_prop_hd_t * prop_hd,vs_scfctx_t * vsc,int idx)661911106dfSjm vs_scf_get(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
662911106dfSjm 	vs_scfctx_t *vsc, int idx)
663911106dfSjm {
664911106dfSjm 	int rc;
665911106dfSjm 	int64_t port;
666911106dfSjm 	uint8_t valbool;
667911106dfSjm 	vs_props_t *vp = &prop_hd->vp_gen;
668911106dfSjm 	vs_props_se_t *vep = &prop_hd->vp_se;
669911106dfSjm 
670911106dfSjm 	if ((rc = scf_property_get_value(vsc->vscf_prop[idx],
671911106dfSjm 	    vsc->vscf_val[idx])) == -1) {
672911106dfSjm 		if (rc == SCF_ERROR_CONSTRAINT_VIOLATED ||
673911106dfSjm 		    rc == SCF_ERROR_NOT_FOUND) {
674911106dfSjm 			vs_default_value(prop_hd, vpd->vpd_id);
675911106dfSjm 			return (VS_ERR_NONE);
676911106dfSjm 		}
677911106dfSjm 		return (VS_ERR_SCF);
678911106dfSjm 	}
679911106dfSjm 
680911106dfSjm 	rc = VS_ERR_NONE;
681911106dfSjm 	switch (vpd->vpd_id) {
682911106dfSjm 	case VS_PROPID_MAXSIZE:
683911106dfSjm 		if ((scf_value_get_astring(vsc->vscf_val[idx],
684911106dfSjm 		    vp->vp_maxsize, sizeof (vp->vp_maxsize))) == -1) {
685911106dfSjm 			return (VS_ERR_SCF);
686911106dfSjm 		}
687911106dfSjm 		break;
688911106dfSjm 	case VS_PROPID_MAXSIZE_ACTION:
689911106dfSjm 		if ((scf_value_get_boolean(vsc->vscf_val[idx],
690911106dfSjm 		    &valbool)) == -1) {
691911106dfSjm 			return (VS_ERR_SCF);
692911106dfSjm 		}
693911106dfSjm 		vp->vp_maxsize_action = (valbool == 0) ? B_FALSE : B_TRUE;
694911106dfSjm 		break;
695911106dfSjm 	case VS_PROPID_TYPES:
696911106dfSjm 		if ((scf_value_get_astring(vsc->vscf_val[idx],
697911106dfSjm 		    vp->vp_types, sizeof (vp->vp_types))) == -1) {
698911106dfSjm 			return (VS_ERR_SCF);
699911106dfSjm 		}
700911106dfSjm 		break;
701911106dfSjm 	case VS_PROPID_VLOG:
702911106dfSjm 		if ((scf_value_get_astring(vsc->vscf_val[idx],
703911106dfSjm 		    vp->vp_vlog, sizeof (vp->vp_vlog))) == -1) {
704911106dfSjm 			return (VS_ERR_SCF);
705911106dfSjm 		}
706911106dfSjm 		break;
707911106dfSjm 	case VS_PROPID_SE_ENABLE:
708911106dfSjm 		if ((scf_value_get_boolean(vsc->vscf_val[idx],
709911106dfSjm 		    &valbool)) == -1) {
710911106dfSjm 			return (VS_ERR_SCF);
711911106dfSjm 		}
712911106dfSjm 		vep->vep_enable = (valbool == 0) ? B_FALSE : B_TRUE;
713911106dfSjm 		break;
714911106dfSjm 	case VS_PROPID_SE_HOST:
715911106dfSjm 		(void) scf_value_get_as_string_typed(vsc->vscf_val[idx],
716911106dfSjm 		    vpd->vpd_type, vep->vep_host, sizeof (vep->vep_host));
717911106dfSjm 		break;
718911106dfSjm 	case VS_PROPID_SE_PORT:
719911106dfSjm 		if ((scf_value_get_integer(vsc->vscf_val[idx], &port)) == -1)
720911106dfSjm 			return (VS_ERR_SCF);
721911106dfSjm 		if (port <= 0 || port >= UINT16_MAX)
722911106dfSjm 			rc = VS_ERR_INVALID_VALUE;
723911106dfSjm 		else
724911106dfSjm 			vep->vep_port = (uint16_t)port;
725911106dfSjm 		break;
726911106dfSjm 	case VS_PROPID_SE_MAXCONN:
727911106dfSjm 		if ((scf_value_get_integer(vsc->vscf_val[idx],
728911106dfSjm 		    (int64_t *)&vep->vep_maxconn)) == -1) {
729911106dfSjm 			return (VS_ERR_SCF);
730911106dfSjm 		}
731911106dfSjm 		break;
732911106dfSjm 	default:
733911106dfSjm 		break;
734911106dfSjm 	}
735911106dfSjm 
736911106dfSjm 	if ((rc != VS_ERR_NONE) ||
737911106dfSjm 	    (vs_validate(prop_hd, vpd->vpd_id) != VS_ERR_NONE)) {
738911106dfSjm 		vs_default_value(prop_hd, vpd->vpd_id);
739911106dfSjm 	}
740911106dfSjm 
741911106dfSjm 	return (VS_ERR_NONE);
742911106dfSjm }
743911106dfSjm 
744911106dfSjm 
745911106dfSjm /*
746911106dfSjm  * vs_scf_pg_create
747911106dfSjm  */
748911106dfSjm static int
vs_scf_pg_create(const char * pgname,vs_prop_hd_t * prop_hd)749911106dfSjm vs_scf_pg_create(const char *pgname, vs_prop_hd_t *prop_hd)
750911106dfSjm {
751911106dfSjm 	int rc;
752911106dfSjm 	uint64_t propid;
753911106dfSjm 	vs_scfctx_t vsc;
754911106dfSjm 
755911106dfSjm 	/* ensure that caller has authorization to refresh service */
756911106dfSjm 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
757911106dfSjm 		return (rc);
758911106dfSjm 
759911106dfSjm 	if (vs_scf_ctx_open(&vsc) != 0) {
760911106dfSjm 		vs_scf_ctx_close(&vsc);
761911106dfSjm 		return (VS_ERR_SCF);
762911106dfSjm 	}
763911106dfSjm 
764911106dfSjm 	if (scf_instance_add_pg(vsc.vscf_inst, pgname,
765911106dfSjm 	    SCF_GROUP_APPLICATION, 0, vsc.vscf_pgroup) == -1) {
766911106dfSjm 		vs_scf_ctx_close(&vsc);
767911106dfSjm 		if (scf_error() == SCF_ERROR_INVALID_ARGUMENT)
768911106dfSjm 			return (VS_ERR_INVALID_SE);
769911106dfSjm 		return (VS_ERR_SCF);
770911106dfSjm 	}
771911106dfSjm 	vs_scf_ctx_close(&vsc);
772911106dfSjm 
773911106dfSjm 	/* set default values for those not specified */
774911106dfSjm 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
775911106dfSjm 		if ((propid & prop_hd->vp_all) && !(propid & prop_hd->vp_ids))
776911106dfSjm 			vs_default_value(prop_hd, propid);
777911106dfSjm 	}
778911106dfSjm 
779bfc848c6Sjm 	prop_hd->vp_ids = prop_hd->vp_all;
780911106dfSjm 	prop_hd->vp_ids |= VS_PROPID_VALUE_AUTH;
781911106dfSjm 
782911106dfSjm 	rc = vs_scf_values_set(pgname, prop_hd);
783911106dfSjm 	if (rc != VS_ERR_NONE)
784bfc848c6Sjm 		(void) vs_scf_pg_delete(pgname);
785911106dfSjm 
786911106dfSjm 	return (rc);
787911106dfSjm }
788911106dfSjm 
789911106dfSjm 
790bfc848c6Sjm /*
791bfc848c6Sjm  * vs_scf_pg_delete
792bfc848c6Sjm  */
793bfc848c6Sjm static int
vs_scf_pg_delete(const char * pgname)794bfc848c6Sjm vs_scf_pg_delete(const char *pgname)
795bfc848c6Sjm {
796bfc848c6Sjm 	int rc;
797bfc848c6Sjm 	vs_scfctx_t vsc;
798bfc848c6Sjm 
799bfc848c6Sjm 	/* ensure that caller has authorization to refresh service */
800bfc848c6Sjm 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
801bfc848c6Sjm 		return (rc);
802bfc848c6Sjm 
803bfc848c6Sjm 	if (vs_scf_ctx_open(&vsc) != 0) {
804bfc848c6Sjm 		vs_scf_ctx_close(&vsc);
805bfc848c6Sjm 		return (VS_ERR_SCF);
806bfc848c6Sjm 	}
807bfc848c6Sjm 
808bfc848c6Sjm 	if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
809bfc848c6Sjm 		vs_scf_ctx_close(&vsc);
810bfc848c6Sjm 		rc = scf_error();
811bfc848c6Sjm 		if ((rc == SCF_ERROR_NOT_FOUND) ||
812bfc848c6Sjm 		    (rc == SCF_ERROR_INVALID_ARGUMENT))
813bfc848c6Sjm 			return (VS_ERR_INVALID_SE);
814bfc848c6Sjm 		else
815bfc848c6Sjm 			return (VS_ERR_SCF);
816bfc848c6Sjm 	}
817bfc848c6Sjm 
818bfc848c6Sjm 	if (scf_pg_delete(vsc.vscf_pgroup) == -1) {
819bfc848c6Sjm 		vs_scf_ctx_close(&vsc);
820bfc848c6Sjm 		rc = scf_error();
821bfc848c6Sjm 		if ((rc == SCF_ERROR_NOT_FOUND) ||
822bfc848c6Sjm 		    (rc == SCF_ERROR_INVALID_ARGUMENT))
823bfc848c6Sjm 			return (VS_ERR_INVALID_SE);
824bfc848c6Sjm 
825bfc848c6Sjm 		return (VS_ERR_SCF);
826bfc848c6Sjm 	}
827bfc848c6Sjm 
828bfc848c6Sjm 	vs_scf_ctx_close(&vsc);
829bfc848c6Sjm 
830bfc848c6Sjm 	/* Notify the daemon that things have changed */
831bfc848c6Sjm 	if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1) {
832bfc848c6Sjm 		return (VS_ERR_SCF);
833bfc848c6Sjm 	}
834bfc848c6Sjm 
835bfc848c6Sjm 	return (VS_ERR_NONE);
836bfc848c6Sjm }
837bfc848c6Sjm 
838bfc848c6Sjm 
839911106dfSjm /*
840911106dfSjm  * vs_scf_values_set
841911106dfSjm  *
842911106dfSjm  * Sets property values in the repository.  This is the single
843911106dfSjm  * entry point for storing SMF values.
844911106dfSjm  *
845911106dfSjm  * Like loading values, this is an operation based on a single property
846911106dfSjm  * group, so all property values changed in this function must belong
847911106dfSjm  * to the same property group. Additionally, this operation is done in
848911106dfSjm  * the context of a repository transaction; on any fatal error, the
849911106dfSjm  * SCF context will be closed, destroying all SCF objects and aborting
850911106dfSjm  * the transaction.
851911106dfSjm  */
852911106dfSjm static int
vs_scf_values_set(const char * pgname,vs_prop_hd_t * prop_hd)853911106dfSjm vs_scf_values_set(const char *pgname, vs_prop_hd_t *prop_hd)
854911106dfSjm {
855911106dfSjm 	int rc, np;
856911106dfSjm 	const vs_propdef_t *vpd;
857911106dfSjm 	uint64_t propid;
858911106dfSjm 	vs_scfctx_t vsc;
859911106dfSjm 
860911106dfSjm 	/* ensure that caller has authorization to refresh service */
861911106dfSjm 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
862911106dfSjm 		return (rc);
863911106dfSjm 
864911106dfSjm 	if (vs_scf_ctx_open(&vsc) != 0) {
865911106dfSjm 		vs_scf_ctx_close(&vsc);
866911106dfSjm 		return (VS_ERR_SCF);
867911106dfSjm 	}
868911106dfSjm 
869911106dfSjm 	if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
870911106dfSjm 		vs_scf_ctx_close(&vsc);
871911106dfSjm 		rc = scf_error();
872911106dfSjm 		if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) {
873911106dfSjm 			if ((rc == SCF_ERROR_NOT_FOUND) ||
874911106dfSjm 			    (rc == SCF_ERROR_INVALID_ARGUMENT))
875911106dfSjm 				return (VS_ERR_INVALID_SE);
876911106dfSjm 		}
877911106dfSjm 		return (VS_ERR_SCF);
878911106dfSjm 	}
879911106dfSjm 
880911106dfSjm 	if (((vsc.vscf_tx = scf_transaction_create(vsc.vscf_handle)) == NULL) ||
881911106dfSjm 	    (scf_transaction_start(vsc.vscf_tx, vsc.vscf_pgroup) == -1)) {
882911106dfSjm 		vs_scf_ctx_close(&vsc);
883911106dfSjm 		return (VS_ERR_SCF);
884911106dfSjm 	}
885911106dfSjm 
886911106dfSjm 	/* Process the value change for each specified property */
887911106dfSjm 	rc = 0;
888911106dfSjm 	np = 0;
889911106dfSjm 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
890911106dfSjm 		if ((prop_hd->vp_ids & propid) == 0)
891911106dfSjm 			continue;
892911106dfSjm 
893911106dfSjm 		if ((vpd = vs_get_propdef(propid)) == NULL) {
894911106dfSjm 			rc = VS_ERR_INVALID_PROPERTY;
895911106dfSjm 			break;
896911106dfSjm 		}
897911106dfSjm 
898911106dfSjm 		vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
899911106dfSjm 		vsc.vscf_ent[np] = scf_entry_create(vsc.vscf_handle);
900911106dfSjm 
901911106dfSjm 		if (vsc.vscf_val[np] == NULL || vsc.vscf_ent[np] == NULL) {
902911106dfSjm 			rc = VS_ERR_SCF;
903911106dfSjm 			break;
904911106dfSjm 		}
905911106dfSjm 
906911106dfSjm 		if ((rc = scf_transaction_property_change(vsc.vscf_tx,
907911106dfSjm 		    vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type)) == -1) {
908911106dfSjm 			rc = scf_transaction_property_new(vsc.vscf_tx,
909911106dfSjm 			    vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type);
910911106dfSjm 		}
911911106dfSjm 		if (rc == -1) {
912911106dfSjm 			rc = VS_ERR_SCF;
913911106dfSjm 			break;
914911106dfSjm 		}
915911106dfSjm 
916911106dfSjm 		if ((rc = vs_scf_set(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
917911106dfSjm 			break;
918911106dfSjm 
919911106dfSjm 		++np;
920911106dfSjm 	}
921911106dfSjm 
922911106dfSjm 	if (rc != VS_ERR_NONE) {
923911106dfSjm 		vs_scf_ctx_close(&vsc);
924911106dfSjm 		return (rc);
925911106dfSjm 	}
926911106dfSjm 
927911106dfSjm 	/* Commit the transaction */
928911106dfSjm 	if (scf_transaction_commit(vsc.vscf_tx) == -1) {
929911106dfSjm 		vs_scf_ctx_close(&vsc);
930911106dfSjm 		return (VS_ERR_SCF);
931911106dfSjm 	}
932911106dfSjm 	vs_scf_ctx_close(&vsc);
933911106dfSjm 
934911106dfSjm 	/* Notify the daemon that things have changed */
935911106dfSjm 	if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1)
936911106dfSjm 		return (VS_ERR_SCF);
937911106dfSjm 
938911106dfSjm 	return (VS_ERR_NONE);
939911106dfSjm }
940911106dfSjm 
941911106dfSjm 
942911106dfSjm /*
943911106dfSjm  * vs_scf_set
944911106dfSjm  *
945911106dfSjm  * Stores a single value from the appropriate vscan property structure
946911106dfSjm  * member into the repository.
947911106dfSjm  *
948911106dfSjm  * Values are set in the SCF value object, then the value object
949911106dfSjm  * is added to the SCF property object.
950911106dfSjm  */
951911106dfSjm static int
vs_scf_set(const vs_propdef_t * vpd,vs_prop_hd_t * prop_hd,vs_scfctx_t * vsc,int idx)952911106dfSjm vs_scf_set(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
953911106dfSjm     vs_scfctx_t *vsc, int idx)
954911106dfSjm {
955911106dfSjm 	int rc;
956911106dfSjm 	vs_props_t *vp = &prop_hd->vp_gen;
957911106dfSjm 	vs_props_se_t *vep = &prop_hd->vp_se;
958911106dfSjm 
959911106dfSjm 	if ((rc = vs_validate(prop_hd, vpd->vpd_id)) != VS_ERR_NONE)
960911106dfSjm 		return (rc);
961911106dfSjm 
962911106dfSjm 	rc = VS_ERR_NONE;
963911106dfSjm 	switch (vpd->vpd_id) {
964911106dfSjm 	case VS_PROPID_MAXSIZE:
965911106dfSjm 		if ((scf_value_set_astring(vsc->vscf_val[idx],
966911106dfSjm 		    vp->vp_maxsize)) == -1) {
967911106dfSjm 			rc = VS_ERR_SCF;
968911106dfSjm 		}
969911106dfSjm 		break;
970911106dfSjm 	case VS_PROPID_MAXSIZE_ACTION:
971911106dfSjm 		scf_value_set_boolean(vsc->vscf_val[idx],
972911106dfSjm 		    (uint8_t)vp->vp_maxsize_action);
973911106dfSjm 		break;
974911106dfSjm 	case VS_PROPID_TYPES:
975911106dfSjm 		if ((scf_value_set_astring(vsc->vscf_val[idx],
976911106dfSjm 		    vp->vp_types)) == -1) {
977911106dfSjm 			return (VS_ERR_SCF);
978911106dfSjm 		}
979911106dfSjm 		break;
980911106dfSjm 	case VS_PROPID_SE_ENABLE:
981911106dfSjm 		scf_value_set_boolean(vsc->vscf_val[idx],
982911106dfSjm 		    (uint8_t)vep->vep_enable);
983911106dfSjm 		break;
984911106dfSjm 	case VS_PROPID_SE_HOST:
985911106dfSjm 		if ((scf_value_set_from_string(vsc->vscf_val[idx],
986911106dfSjm 		    vpd->vpd_type, vep->vep_host)) == -1) {
987911106dfSjm 			rc = VS_ERR_SCF;
988911106dfSjm 		}
989911106dfSjm 		break;
990911106dfSjm 	case VS_PROPID_SE_PORT:
991911106dfSjm 		scf_value_set_integer(vsc->vscf_val[idx], vep->vep_port);
992911106dfSjm 		break;
993911106dfSjm 	case VS_PROPID_SE_MAXCONN:
994911106dfSjm 		scf_value_set_integer(vsc->vscf_val[idx],
995911106dfSjm 		    vep->vep_maxconn);
996911106dfSjm 		break;
997911106dfSjm 	case VS_PROPID_VALUE_AUTH:
998911106dfSjm 		if ((scf_value_set_astring(vsc->vscf_val[idx],
999911106dfSjm 		    VS_VALUE_AUTH)) == -1) {
1000911106dfSjm 			return (VS_ERR_SCF);
1001911106dfSjm 		}
1002911106dfSjm 		break;
1003911106dfSjm 	default:
1004911106dfSjm 		break;
1005911106dfSjm 	}
1006911106dfSjm 
1007911106dfSjm 	if ((scf_entry_add_value(vsc->vscf_ent[idx],
1008911106dfSjm 	    vsc->vscf_val[idx])) == -1) {
1009911106dfSjm 		return (VS_ERR_SCF);
1010911106dfSjm 	}
1011911106dfSjm 
1012911106dfSjm 	return (rc);
1013911106dfSjm }
1014911106dfSjm 
1015911106dfSjm 
1016911106dfSjm /*
1017911106dfSjm  * vs_scf_ctx_open
1018911106dfSjm  *
1019911106dfSjm  * Opens an SCF context; creates the minumum SCF objects
1020911106dfSjm  * for use in loading/storing from the SMF repository (meaning
1021911106dfSjm  * vscf_property group data).
1022911106dfSjm  *
1023911106dfSjm  * Other SCF objects in the context may be initialized elsewher
1024911106dfSjm  * subsequent to open, but all initialized structures are destroyed
1025911106dfSjm  * in vs_scf_ctx_close().
1026911106dfSjm  */
1027911106dfSjm static int
vs_scf_ctx_open(vs_scfctx_t * vsc)1028911106dfSjm vs_scf_ctx_open(vs_scfctx_t *vsc)
1029911106dfSjm {
1030911106dfSjm 	(void) memset(vsc, 0, sizeof (vs_scfctx_t));
1031911106dfSjm 
1032911106dfSjm 	if ((vsc->vscf_handle = scf_handle_create(SCF_VERSION)) == NULL)
1033911106dfSjm 		return (VS_ERR_SCF);
1034911106dfSjm 
1035911106dfSjm 	if (scf_handle_bind(vsc->vscf_handle) == -1)
1036911106dfSjm 		return (VS_ERR_SCF);
1037911106dfSjm 
1038911106dfSjm 	if ((vsc->vscf_inst = scf_instance_create(vsc->vscf_handle)) == NULL)
1039911106dfSjm 		return (VS_ERR_SCF);
1040911106dfSjm 
1041911106dfSjm 	if (scf_handle_decode_fmri(vsc->vscf_handle, VS_INSTANCE_FMRI,
1042911106dfSjm 	    NULL, NULL, vsc->vscf_inst, NULL, NULL,
1043911106dfSjm 	    SCF_DECODE_FMRI_EXACT) == -1) {
1044911106dfSjm 		return (VS_ERR_SCF);
1045911106dfSjm 	}
1046911106dfSjm 
1047911106dfSjm 	if ((vsc->vscf_pgroup = scf_pg_create(vsc->vscf_handle)) == NULL)
1048911106dfSjm 		return (VS_ERR_SCF);
1049911106dfSjm 
1050911106dfSjm 	return (VS_ERR_NONE);
1051911106dfSjm }
1052911106dfSjm 
1053911106dfSjm 
1054911106dfSjm /*
1055911106dfSjm  * vs_scf_ctx_close
1056911106dfSjm  *
1057911106dfSjm  * Closes an SCF context; destroys all initialized SCF objects.
1058911106dfSjm  */
1059911106dfSjm static void
vs_scf_ctx_close(vs_scfctx_t * vsc)1060911106dfSjm vs_scf_ctx_close(vs_scfctx_t *vsc)
1061911106dfSjm {
1062911106dfSjm 	int i;
1063911106dfSjm 
1064911106dfSjm 	for (i = 0; i < VS_NUM_PROPIDS; i++) {
1065911106dfSjm 		if (vsc->vscf_val[i])
1066911106dfSjm 			scf_value_destroy(vsc->vscf_val[i]);
1067911106dfSjm 		if (vsc->vscf_ent[i])
1068911106dfSjm 			scf_entry_destroy(vsc->vscf_ent[i]);
1069911106dfSjm 		if (vsc->vscf_prop[i])
1070911106dfSjm 			scf_property_destroy(vsc->vscf_prop[i]);
1071911106dfSjm 	}
1072911106dfSjm 
1073911106dfSjm 	if (vsc->vscf_iter)
1074911106dfSjm 		scf_iter_destroy(vsc->vscf_iter);
1075911106dfSjm 	if (vsc->vscf_tx)
1076911106dfSjm 		scf_transaction_destroy(vsc->vscf_tx);
1077911106dfSjm 	if (vsc->vscf_pgroup)
1078911106dfSjm 		scf_pg_destroy(vsc->vscf_pgroup);
1079911106dfSjm 	if (vsc->vscf_inst)
1080911106dfSjm 		scf_instance_destroy(vsc->vscf_inst);
1081911106dfSjm 	if (vsc->vscf_handle)
1082911106dfSjm 		scf_handle_destroy(vsc->vscf_handle);
1083911106dfSjm }
1084911106dfSjm 
1085911106dfSjm 
1086911106dfSjm /*
1087911106dfSjm  * vs_validate
1088911106dfSjm  *
1089911106dfSjm  * Validate property identified in propid.
1090911106dfSjm  *
1091911106dfSjm  * Returns: VS_ERR_NONE
1092911106dfSjm  *          VS_ERR_INVALID_VALUE
1093911106dfSjm  *          VS_ERR_INVALID_PROPERTY
1094911106dfSjm  */
1095911106dfSjm static int
vs_validate(const vs_prop_hd_t * prop_hd,uint64_t propid)1096911106dfSjm vs_validate(const vs_prop_hd_t *prop_hd, uint64_t propid)
1097911106dfSjm {
1098911106dfSjm 	uint64_t num;
1099911106dfSjm 	const vs_props_t *vp = &prop_hd->vp_gen;
1100911106dfSjm 	const vs_props_se_t *vep = &prop_hd->vp_se;
1101911106dfSjm 
1102911106dfSjm 	switch (propid) {
1103911106dfSjm 	case VS_PROPID_MAXSIZE:
1104911106dfSjm 		if ((vs_strtonum(vp->vp_maxsize, &num) != 0) || (num == 0))
1105911106dfSjm 			return (VS_ERR_INVALID_VALUE);
1106911106dfSjm 		break;
1107911106dfSjm 	case VS_PROPID_MAXSIZE_ACTION:
1108911106dfSjm 		break;
1109911106dfSjm 	case VS_PROPID_TYPES:
1110911106dfSjm 		if (!vs_is_valid_types(vp->vp_types))
1111911106dfSjm 			return (VS_ERR_INVALID_VALUE);
1112911106dfSjm 		break;
1113911106dfSjm 	case VS_PROPID_SE_ENABLE:
1114911106dfSjm 		break;
1115911106dfSjm 	case VS_PROPID_SE_PORT:
1116911106dfSjm 		if (vep->vep_port == 0)
1117911106dfSjm 			return (VS_ERR_INVALID_VALUE);
1118911106dfSjm 		break;
1119911106dfSjm 	case VS_PROPID_SE_HOST:
1120911106dfSjm 		if (!vs_is_valid_host(vep->vep_host))
1121911106dfSjm 			return (VS_ERR_INVALID_VALUE);
1122911106dfSjm 		break;
1123911106dfSjm 	case VS_PROPID_SE_MAXCONN:
1124911106dfSjm 		if (vep->vep_maxconn < VS_VAL_SE_MAXCONN_MIN ||
1125911106dfSjm 		    vep->vep_maxconn > VS_VAL_SE_MAXCONN_MAX)
1126911106dfSjm 			return (VS_ERR_INVALID_VALUE);
1127911106dfSjm 		break;
1128911106dfSjm 	case VS_PROPID_VALUE_AUTH:
1129911106dfSjm 	case VS_PROPID_VLOG:
1130911106dfSjm 		break;
1131911106dfSjm 	default:
1132911106dfSjm 		return (VS_ERR_INVALID_PROPERTY);
1133911106dfSjm 	}
1134911106dfSjm 
1135911106dfSjm 	return (VS_ERR_NONE);
1136911106dfSjm }
1137911106dfSjm 
1138911106dfSjm 
1139911106dfSjm /*
1140911106dfSjm  * vs_props_validate
1141911106dfSjm  *
1142911106dfSjm  * Validate  properties identified in propids.
1143911106dfSjm  *
1144911106dfSjm  * Returns: VS_ERR_NONE
1145911106dfSjm  *          VS_ERR_INVALID_VALUE
1146911106dfSjm  *          VS_ERR_INVALID_PROPERTY
1147911106dfSjm  */
1148911106dfSjm int
vs_props_validate(const vs_props_t * props,uint64_t propids)1149911106dfSjm vs_props_validate(const vs_props_t *props, uint64_t propids)
1150911106dfSjm {
1151911106dfSjm 	uint64_t propid;
1152911106dfSjm 	vs_prop_hd_t prop_hd;
1153911106dfSjm 
1154911106dfSjm 	if ((propids & VS_PROPID_GEN_ALL) != propids)
1155911106dfSjm 		return (VS_ERR_INVALID_PROPERTY);
1156911106dfSjm 
1157911106dfSjm 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
1158911106dfSjm 	prop_hd.vp_gen = *props;
1159911106dfSjm 	prop_hd.vp_type = VS_PTYPE_GEN;
1160911106dfSjm 	prop_hd.vp_ids = propids;
1161911106dfSjm 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
1162911106dfSjm 
1163911106dfSjm 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
1164911106dfSjm 		if ((propids & propid) == 0)
1165911106dfSjm 			continue;
1166911106dfSjm 
1167911106dfSjm 		if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
1168911106dfSjm 			return (VS_ERR_INVALID_VALUE);
1169911106dfSjm 	}
1170911106dfSjm 
1171911106dfSjm 	return (VS_ERR_NONE);
1172911106dfSjm }
1173911106dfSjm 
1174911106dfSjm 
1175911106dfSjm /*
1176911106dfSjm  * vs_props_se_validate
1177911106dfSjm  *
1178911106dfSjm  * Validate properties identified in propids.
1179911106dfSjm  *
1180911106dfSjm  * Returns: VS_ERR_NONE
1181911106dfSjm  *          VS_ERR_INVALID_VALUE
1182911106dfSjm  *          VS_ERR_INVALID_PROPERTY
1183911106dfSjm  */
1184911106dfSjm int
vs_props_se_validate(const vs_props_se_t * se_props,uint64_t propids)1185911106dfSjm vs_props_se_validate(const vs_props_se_t *se_props, uint64_t propids)
1186911106dfSjm {
1187911106dfSjm 	uint64_t propid;
1188911106dfSjm 	vs_prop_hd_t prop_hd;
1189911106dfSjm 
1190911106dfSjm 	if ((propids & VS_PROPID_SE_ALL) != propids)
1191911106dfSjm 		return (VS_ERR_INVALID_PROPERTY);
1192911106dfSjm 
1193911106dfSjm 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
1194911106dfSjm 	prop_hd.vp_se = *se_props;
1195911106dfSjm 	prop_hd.vp_type = VS_PTYPE_SE;
1196911106dfSjm 	prop_hd.vp_ids = propids;
1197911106dfSjm 	prop_hd.vp_all = VS_PROPID_SE_ALL;
1198911106dfSjm 
1199911106dfSjm 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
1200911106dfSjm 		if ((propids & propid) == 0)
1201911106dfSjm 			continue;
1202911106dfSjm 
1203911106dfSjm 		if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
1204911106dfSjm 			return (VS_ERR_INVALID_VALUE);
1205911106dfSjm 	}
1206911106dfSjm 
1207911106dfSjm 	return (VS_ERR_NONE);
1208911106dfSjm }
1209911106dfSjm 
1210911106dfSjm 
1211911106dfSjm /*
1212911106dfSjm  * vs_is_valid_types
1213911106dfSjm  *
1214911106dfSjm  * Checks that types property is a valid format:
1215911106dfSjm  * - doesn't exceed VS_VAL_TYPES_MAX
1216911106dfSjm  * - doesn't contain VS_VAL_TYPES_INVALID_CHARS
1217911106dfSjm  * - is correctly formatted - passes the parsing tests
1218911106dfSjm  *
1219911106dfSjm  * Returns 1 on success, 0 on failure
1220911106dfSjm  */
1221911106dfSjm static int
vs_is_valid_types(const char * types)1222911106dfSjm vs_is_valid_types(const char *types)
1223911106dfSjm {
1224911106dfSjm 	char buf[VS_VAL_TYPES_LEN];
1225911106dfSjm 	uint32_t len = VS_VAL_TYPES_LEN;
1226911106dfSjm 
1227911106dfSjm 	if (strlen(types) > VS_VAL_TYPES_LEN)
1228911106dfSjm 		return (0);
1229911106dfSjm 
1230911106dfSjm 	if (strpbrk(types, VS_VAL_TYPES_INVALID_CHARS) != NULL)
1231911106dfSjm 		return (0);
1232911106dfSjm 
1233911106dfSjm 	if (vs_parse_types(types, buf, &len) != 0)
1234911106dfSjm 		return (0);
1235911106dfSjm 
1236911106dfSjm 	return (1);
1237911106dfSjm }
1238911106dfSjm 
1239911106dfSjm 
1240911106dfSjm /*
1241911106dfSjm  * vs_is_valid_host
1242911106dfSjm  *
1243911106dfSjm  * Returns 1 on success, 0 on failure
1244911106dfSjm  */
1245911106dfSjm static int
vs_is_valid_host(const char * host)1246911106dfSjm vs_is_valid_host(const char *host)
1247911106dfSjm {
1248911106dfSjm 	long naddr;
1249911106dfSjm 	const char *p;
1250911106dfSjm 
1251911106dfSjm 	if (!host || *host == '\0')
1252911106dfSjm 		return (0);
1253911106dfSjm 
1254911106dfSjm 	if ('0' <= host[0] && host[0] <= '9') {
1255911106dfSjm 		/* ip address */
1256911106dfSjm 		if ((inet_pton(AF_INET, host, &naddr)) == 0)
1257911106dfSjm 			return (0);
1258911106dfSjm 		if ((naddr & IN_CLASSA_NET) == 0)
1259911106dfSjm 			return (0);
1260911106dfSjm 		if ((naddr & IN_CLASSC_HOST) == 0)
1261911106dfSjm 			return (0);
1262911106dfSjm 	} else {
1263911106dfSjm 		/* hostname */
1264911106dfSjm 		p = host;
1265911106dfSjm 		while (*p != '\0') {
1266911106dfSjm 			if (!isascii(*p))
1267911106dfSjm 				return (0);
1268911106dfSjm 
1269911106dfSjm 			if (isalnum(*p) ||
1270911106dfSjm 			    (*p == '.') || (*p == '-') || (*p == '_')) {
1271911106dfSjm 				++p;
1272911106dfSjm 			} else {
1273911106dfSjm 				return (0);
1274911106dfSjm 			}
1275911106dfSjm 		}
1276911106dfSjm 	}
1277911106dfSjm 
1278911106dfSjm 	return (1);
1279911106dfSjm }
1280911106dfSjm 
1281911106dfSjm 
1282911106dfSjm /*
1283911106dfSjm  * vs_parse_types
1284911106dfSjm  *
1285911106dfSjm  * Replace comma separators with '\0'.
1286911106dfSjm  *
1287911106dfSjm  * Types contains comma separated rules each beginning with +|-
1288911106dfSjm  *   - embedded commas are escaped by backslash
1289911106dfSjm  *   - backslash is escaped by backslash
1290911106dfSjm  *   - a single backslash not followed by comma is illegal
1291911106dfSjm  *
1292911106dfSjm  * On entry to the function len must contain the length of
1293911106dfSjm  * the buffer. On sucecssful exit len will contain the length
1294911106dfSjm  * of the parsed data within the buffer.
1295911106dfSjm  *
1296911106dfSjm  * Returns 0 on success, -1 on failure
1297911106dfSjm  */
1298911106dfSjm int
vs_parse_types(const char * types,char * buf,uint32_t * len)1299911106dfSjm vs_parse_types(const char *types, char *buf, uint32_t *len)
1300911106dfSjm {
1301911106dfSjm 	char *p = (char *)types;
1302911106dfSjm 	char *b = buf;
1303911106dfSjm 
1304911106dfSjm 	if (strlen(types) > *len)
1305911106dfSjm 		return (-1);
1306911106dfSjm 
1307911106dfSjm 	if (strchr(VS_TYPES_RULES, *p) == NULL)
1308911106dfSjm 		return (-1);
1309911106dfSjm 
1310911106dfSjm 	(void) memset(buf, 0, *len);
1311911106dfSjm 
1312911106dfSjm 	while (*p) {
1313911106dfSjm 		switch (*p) {
1314911106dfSjm 		case VS_TYPES_SEP:
1315911106dfSjm 			if (*(p + 1) &&
1316911106dfSjm 			    (strchr(VS_TYPES_RULES, *(p + 1))) == NULL)
1317911106dfSjm 				return (-1);
1318911106dfSjm 			*b = '\0';
1319911106dfSjm 			break;
1320911106dfSjm 		case VS_TYPES_ESCAPE:
1321911106dfSjm 			++p;
1322911106dfSjm 			if (*p == VS_TYPES_ESCAPE || *p == VS_TYPES_SEP)
1323911106dfSjm 				*b = *p;
1324911106dfSjm 			else
1325911106dfSjm 				return (-1);
1326911106dfSjm 			break;
1327911106dfSjm 		default:
1328911106dfSjm 			*b = *p;
1329911106dfSjm 		}
1330911106dfSjm 		++p;
1331911106dfSjm 		++b;
1332911106dfSjm 	}
1333911106dfSjm 
1334911106dfSjm 	*len = (b - buf) + 1;
1335911106dfSjm 
1336911106dfSjm 	return (0);
1337911106dfSjm }
1338911106dfSjm 
1339911106dfSjm 
1340911106dfSjm /*
1341911106dfSjm  * vs_statistics
1342911106dfSjm  */
1343911106dfSjm int
vs_statistics(vs_stats_t * stats)1344911106dfSjm vs_statistics(vs_stats_t *stats)
1345911106dfSjm {
1346911106dfSjm 	int door_fd, rc = VS_ERR_NONE;
1347911106dfSjm 	vs_stats_req_t *req;
1348bfc848c6Sjm 	vs_stats_rsp_t *rsp;
1349911106dfSjm 	door_arg_t arg;
1350911106dfSjm 
1351911106dfSjm 	if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
1352911106dfSjm 		return (VS_ERR_SYS);
1353911106dfSjm 
1354bfc848c6Sjm 	if ((rsp = calloc(1, sizeof (vs_stats_rsp_t))) == NULL) {
1355911106dfSjm 		free(req);
1356911106dfSjm 		return (VS_ERR_SYS);
1357911106dfSjm 	}
1358911106dfSjm 
1359911106dfSjm 	if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
1360911106dfSjm 		free(req);
1361bfc848c6Sjm 		free(rsp);
1362911106dfSjm 		return (VS_ERR_DAEMON_COMM);
1363911106dfSjm 	}
1364911106dfSjm 
1365bfc848c6Sjm 	req->vsr_magic = VS_STATS_DOOR_MAGIC;
1366bfc848c6Sjm 	req->vsr_id = VS_STATS_GET;
1367911106dfSjm 
1368911106dfSjm 	arg.data_ptr = (char *)req;
1369911106dfSjm 	arg.data_size = sizeof (vs_stats_req_t);
1370911106dfSjm 	arg.desc_ptr = NULL;
1371911106dfSjm 	arg.desc_num = 0;
1372bfc848c6Sjm 	arg.rbuf = (char *)rsp;
1373bfc848c6Sjm 	arg.rsize = sizeof (vs_stats_rsp_t);
1374911106dfSjm 
13751843d056SAlan Wright 	rc = vs_door_call(door_fd, &arg);
13761843d056SAlan Wright 
13771843d056SAlan Wright 	if ((rc == VS_ERR_NONE) && (rsp->vsr_magic == VS_STATS_DOOR_MAGIC))
1378bfc848c6Sjm 		*stats = rsp->vsr_stats;
13791843d056SAlan Wright 	else
13801843d056SAlan Wright 		rc = VS_ERR_DAEMON_COMM;
1381911106dfSjm 
1382911106dfSjm 	(void) close(door_fd);
1383911106dfSjm 
1384911106dfSjm 	free(req);
1385bfc848c6Sjm 	free(rsp);
1386911106dfSjm 	return (rc);
1387911106dfSjm }
1388911106dfSjm 
1389911106dfSjm 
1390911106dfSjm /*
1391911106dfSjm  * vs_statistics_reset
1392911106dfSjm  */
1393911106dfSjm int
vs_statistics_reset()1394911106dfSjm vs_statistics_reset()
1395911106dfSjm {
1396911106dfSjm 	int door_fd, rc;
1397911106dfSjm 	vs_stats_req_t *req;
1398911106dfSjm 	door_arg_t arg;
1399911106dfSjm 
1400911106dfSjm 	/* ensure that caller has authorization to reset stats */
1401911106dfSjm 	if ((rc = vs_checkauth(VS_VALUE_AUTH)) != VS_ERR_NONE)
1402911106dfSjm 		return (rc);
1403911106dfSjm 
1404911106dfSjm 	if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
1405911106dfSjm 		return (VS_ERR_SYS);
1406911106dfSjm 
1407911106dfSjm 	if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
1408911106dfSjm 		free(req);
1409911106dfSjm 		return (VS_ERR_DAEMON_COMM);
1410911106dfSjm 	}
1411911106dfSjm 
1412bfc848c6Sjm 	req->vsr_magic = VS_STATS_DOOR_MAGIC;
1413bfc848c6Sjm 	req->vsr_id = VS_STATS_RESET;
1414911106dfSjm 
1415911106dfSjm 	arg.data_ptr = (char *)req;
1416911106dfSjm 	arg.data_size = sizeof (vs_stats_req_t);
1417911106dfSjm 	arg.desc_ptr = NULL;
1418911106dfSjm 	arg.desc_num = 0;
1419911106dfSjm 	arg.rbuf = NULL;
1420911106dfSjm 	arg.rsize = 0;
1421911106dfSjm 
14221843d056SAlan Wright 	rc = vs_door_call(door_fd, &arg);
1423911106dfSjm 
1424911106dfSjm 	(void) close(door_fd);
1425911106dfSjm 	free(req);
1426911106dfSjm 	return (rc);
1427911106dfSjm }
1428911106dfSjm 
14291843d056SAlan Wright /*
14301843d056SAlan Wright  * Door call with retries.
14311843d056SAlan Wright  *
14321843d056SAlan Wright  * Returns VS_ERR_NONE on success, otherwise VS_ERR_DAEMON_COMM.
14331843d056SAlan Wright  */
14341843d056SAlan Wright static int
vs_door_call(int fd,door_arg_t * arg)14351843d056SAlan Wright vs_door_call(int fd, door_arg_t *arg)
14361843d056SAlan Wright {
14371843d056SAlan Wright 	int rc = -1;
14381843d056SAlan Wright 	int i;
14391843d056SAlan Wright 
14401843d056SAlan Wright 	for (i = 0; i < VS_DOOR_CALL_RETRIES; ++i) {
14411843d056SAlan Wright 		errno = 0;
14421843d056SAlan Wright 
14431843d056SAlan Wright 		if ((rc = door_call(fd, arg)) == 0)
14441843d056SAlan Wright 			break;
14451843d056SAlan Wright 
14461843d056SAlan Wright 		if (errno != EAGAIN && errno != EINTR)
14471843d056SAlan Wright 			break;
14481843d056SAlan Wright 	}
14491843d056SAlan Wright 
14501843d056SAlan Wright 	return ((rc == 0) ? VS_ERR_NONE : VS_ERR_DAEMON_COMM);
14511843d056SAlan Wright }
1452911106dfSjm 
1453911106dfSjm /*
1454911106dfSjm  * vs_checkauth
1455911106dfSjm  */
1456911106dfSjm static int
vs_checkauth(char * auth)1457911106dfSjm vs_checkauth(char *auth)
1458911106dfSjm {
1459911106dfSjm 	struct passwd *pw;
1460911106dfSjm 	uid_t uid;
1461911106dfSjm 
1462911106dfSjm 	uid = getuid();
1463911106dfSjm 
1464911106dfSjm 	if ((pw = getpwuid(uid)) == NULL)
1465911106dfSjm 		return (VS_ERR_SYS);
1466911106dfSjm 
1467911106dfSjm 	if (chkauthattr(auth, pw->pw_name) != 1) {
1468911106dfSjm 		return (VS_ERR_AUTH);
1469911106dfSjm 	}
1470911106dfSjm 
1471911106dfSjm 	return (VS_ERR_NONE);
1472911106dfSjm }
1473911106dfSjm 
1474911106dfSjm 
1475911106dfSjm /*
1476911106dfSjm  * vs_props_get_engines
1477bfc848c6Sjm  *
1478911106dfSjm  * On input, count specifies the maximum number of engine ids to
1479911106dfSjm  * return. engids must be an array with count entries.
1480911106dfSjm  * On return, count specifies the number of engine ids being
1481911106dfSjm  * returned in engids.
1482bfc848c6Sjm  *
1483bfc848c6Sjm  * Caller is responsible for free'ing the engids allocated herein.
1484911106dfSjm  */
1485911106dfSjm static int
vs_props_get_engines(char * engids[],int * count)1486bfc848c6Sjm vs_props_get_engines(char *engids[], int *count)
1487911106dfSjm {
1488bfc848c6Sjm 	int i, prefix_len;
1489bfc848c6Sjm 	char pgname[VS_PGNAME_ENGINE_LEN];
1490911106dfSjm 	vs_scfctx_t vsc;
1491911106dfSjm 
1492911106dfSjm 
1493911106dfSjm 	if (((vs_scf_ctx_open(&vsc)) != 0) ||
1494911106dfSjm 	    ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) ||
1495911106dfSjm 	    (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst,
1496911106dfSjm 	    SCF_GROUP_APPLICATION) != 0)) {
1497911106dfSjm 		vs_scf_ctx_close(&vsc);
1498911106dfSjm 		return (VS_ERR_SCF);
1499911106dfSjm 	}
1500911106dfSjm 
1501bfc848c6Sjm 	for (i = 0; i < *count; i++)
1502bfc848c6Sjm 		engids[i] = NULL;
1503bfc848c6Sjm 
1504bfc848c6Sjm 	i = 0;
1505bfc848c6Sjm 	prefix_len = sizeof (VS_PGNAME_ENGINE_PREFIX) - 1;
1506bfc848c6Sjm 
1507911106dfSjm 	while ((i < VS_SE_MAX) &&
1508911106dfSjm 	    (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)) {
1509bfc848c6Sjm 		if (scf_pg_get_name(vsc.vscf_pgroup, pgname,
1510bfc848c6Sjm 		    VS_PGNAME_ENGINE_LEN) < 0) {
1511911106dfSjm 			vs_scf_ctx_close(&vsc);
1512911106dfSjm 			return (VS_ERR_SCF);
1513911106dfSjm 		}
1514911106dfSjm 
1515bfc848c6Sjm 		if (strncmp(pgname, VS_PGNAME_ENGINE_PREFIX, prefix_len) == 0) {
1516bfc848c6Sjm 			if ((engids[i] = strdup(pgname + prefix_len)) != NULL) {
1517bfc848c6Sjm 				if (++i == *count)
1518bfc848c6Sjm 					break;
1519bfc848c6Sjm 			}
1520bfc848c6Sjm 		}
1521911106dfSjm 	}
1522911106dfSjm 	vs_scf_ctx_close(&vsc);
1523911106dfSjm 
1524911106dfSjm 	*count = i;
1525911106dfSjm 	return (VS_ERR_NONE);
1526911106dfSjm }
1527911106dfSjm 
1528911106dfSjm 
1529911106dfSjm /*
1530911106dfSjm  * vs_scf_pg_count
1531911106dfSjm  */
1532911106dfSjm static int
vs_scf_pg_count(void)1533911106dfSjm vs_scf_pg_count(void)
1534911106dfSjm {
1535911106dfSjm 	int count = 0;
1536911106dfSjm 	vs_scfctx_t vsc;
1537911106dfSjm 
1538911106dfSjm 	if ((vs_scf_ctx_open(&vsc) != 0) ||
1539911106dfSjm 	    ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) ||
1540911106dfSjm 	    (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst,
1541911106dfSjm 	    SCF_GROUP_APPLICATION) != 0)) {
1542911106dfSjm 		vs_scf_ctx_close(&vsc);
1543911106dfSjm 		return (-1);
1544911106dfSjm 	}
1545911106dfSjm 
1546911106dfSjm 	while (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)
1547911106dfSjm 		++count;
1548911106dfSjm 
1549911106dfSjm 	vs_scf_ctx_close(&vsc);
1550911106dfSjm 
1551911106dfSjm 	return (count);
1552911106dfSjm }
1553911106dfSjm 
1554911106dfSjm 
1555bfc848c6Sjm /*
1556bfc848c6Sjm  * vs_engid_to_pgname
1557bfc848c6Sjm  *
1558bfc848c6Sjm  * To convert an engine id (engid) to a property group name (pgname),
1559bfc848c6Sjm  * the engine id is prefixed with VS_PGNAME_ENGINE_PREFIX.
1560bfc848c6Sjm  */
1561bfc848c6Sjm static void
vs_engid_to_pgname(const char * engid,char pgname[VS_PGNAME_ENGINE_LEN])1562bfc848c6Sjm vs_engid_to_pgname(const char *engid, char pgname[VS_PGNAME_ENGINE_LEN])
1563bfc848c6Sjm {
1564bfc848c6Sjm 	(void) snprintf(pgname, VS_PGNAME_ENGINE_LEN, "%s%s",
1565bfc848c6Sjm 	    VS_PGNAME_ENGINE_PREFIX, engid);
1566bfc848c6Sjm }
1567bfc848c6Sjm 
1568bfc848c6Sjm 
1569911106dfSjm /*
1570911106dfSjm  *  vs_strtonum
1571911106dfSjm  *
1572911106dfSjm  *  Converts a size string in the format into an integer.
1573911106dfSjm  *
1574911106dfSjm  *  A size string is a numeric value followed by an optional unit
1575911106dfSjm  *  specifier which is used as a multiplier to calculate a raw
1576911106dfSjm  *  number.
1577911106dfSjm  *  The size string format is:  N[.N][KMGTP][B]
1578911106dfSjm  *
1579911106dfSjm  *  The numeric value can contain a decimal portion. Unit specifiers
1580911106dfSjm  *  are either a one-character or two-character string; i.e. "K" or
1581911106dfSjm  *  "KB" for kilobytes. Unit specifiers must follow the numeric portion
1582911106dfSjm  *  immediately, and are not case-sensitive.
1583911106dfSjm  *
1584911106dfSjm  *  If either "B" is specified, or there is no unit specifier portion
1585911106dfSjm  *  in the string, the numeric value is calculated with no multiplier
1586911106dfSjm  *  (assumes a basic unit of "bytes").
1587911106dfSjm  *
1588911106dfSjm  *  Returns:
1589911106dfSjm  *	-1:	Failure; errno set to specify the error.
1590911106dfSjm  *	 0:	Success.
1591911106dfSjm  */
1592911106dfSjm int
vs_strtonum(const char * value,uint64_t * num)1593911106dfSjm vs_strtonum(const char *value, uint64_t *num)
1594911106dfSjm {
1595911106dfSjm 	char *end;
1596911106dfSjm 	int shift;
1597911106dfSjm 	double fval;
1598911106dfSjm 
1599911106dfSjm 	*num = 0;
1600911106dfSjm 
1601911106dfSjm 	/* Check to see if this looks like a number.  */
1602911106dfSjm 	if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
1603911106dfSjm 		errno = EINVAL;
1604911106dfSjm 		return (-1);
1605911106dfSjm 	}
1606911106dfSjm 
1607911106dfSjm 	/* Rely on stroll() to process the numeric portion.  */
1608911106dfSjm 	errno = 0;
1609911106dfSjm 	*num = strtoll(value, &end, 10);
1610911106dfSjm 
1611911106dfSjm 	/*
1612911106dfSjm 	 * Check for ERANGE, which indicates that the value is too large to
1613911106dfSjm 	 * fit in a 64-bit value.
1614911106dfSjm 	 */
1615911106dfSjm 	if (errno != 0)
1616911106dfSjm 		return (-1);
1617911106dfSjm 
1618911106dfSjm 	/*
1619911106dfSjm 	 * If we have a decimal value, then do the computation with floating
1620911106dfSjm 	 * point arithmetic.  Otherwise, use standard arithmetic.
1621911106dfSjm 	 */
1622911106dfSjm 	if (*end == '.') {
1623911106dfSjm 		fval = strtod(value, &end);
1624911106dfSjm 
1625911106dfSjm 		if ((shift = vs_strtoshift(end)) == -1)
1626911106dfSjm 			return (-1); /* errno set */
1627911106dfSjm 
1628911106dfSjm 		fval *= pow(2, shift);
1629911106dfSjm 		if (fval > UINT64_MAX) {
1630911106dfSjm 			errno = ERANGE;
1631911106dfSjm 			return (-1);
1632911106dfSjm 		}
1633911106dfSjm 
1634911106dfSjm 		*num = (uint64_t)fval;
1635911106dfSjm 	} else {
1636911106dfSjm 		if ((shift = vs_strtoshift(end)) == -1)
1637911106dfSjm 			return (-1); /* errno set */
1638911106dfSjm 
1639911106dfSjm 		/* Check for overflow */
1640911106dfSjm 		if (shift >= 64 || (*num << shift) >> shift != *num) {
1641911106dfSjm 			errno = ERANGE;
1642911106dfSjm 			return (-1);
1643911106dfSjm 		}
1644911106dfSjm 
1645911106dfSjm 		*num <<= shift;
1646911106dfSjm 	}
1647911106dfSjm 
1648911106dfSjm 	return (0);
1649911106dfSjm }
1650911106dfSjm 
1651911106dfSjm 
1652911106dfSjm /*
1653911106dfSjm  *  vs_strtoshift
1654911106dfSjm  *
1655911106dfSjm  *  Converts a unit specifier string into a number of bits that
1656911106dfSjm  *  a numeric value must be shifted.
1657911106dfSjm  *
1658911106dfSjm  *  Returns:
1659911106dfSjm  *	-1:	Failure; errno set to specify the error.
1660911106dfSjm  *	>-1:	Success; the shift count.
1661911106dfSjm  *
1662911106dfSjm  */
1663911106dfSjm static int
vs_strtoshift(const char * buf)1664911106dfSjm vs_strtoshift(const char *buf)
1665911106dfSjm {
1666911106dfSjm 	const char *ends = "BKMGTPEZ";
1667911106dfSjm 	int i;
1668911106dfSjm 
1669911106dfSjm 	if (buf[0] == '\0')
1670911106dfSjm 		return (0);
1671911106dfSjm 	for (i = 0; i < strlen(ends); i++) {
1672911106dfSjm 		if (toupper(buf[0]) == ends[i])
1673911106dfSjm 			break;
1674911106dfSjm 	}
1675911106dfSjm 	if (i == strlen(ends)) {
1676911106dfSjm 		errno = EINVAL;
1677911106dfSjm 		return (-1);
1678911106dfSjm 	}
1679911106dfSjm 
1680911106dfSjm 	/* Allow trailing 'b' characters except in the case of 'BB'. */
1681911106dfSjm 	if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' &&
1682911106dfSjm 	    toupper(buf[0]) != 'B')) {
1683911106dfSjm 		return (10 * i);
1684911106dfSjm 	}
1685911106dfSjm 
1686911106dfSjm 	errno = EINVAL;
1687911106dfSjm 	return (-1);
1688911106dfSjm }
1689