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