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