xref: /onnv-gate/usr/src/lib/libvscan/common/libvscan.c (revision 6407:71e85e2b3164)
15440Sjm199354 /*
25440Sjm199354  * CDDL HEADER START
35440Sjm199354  *
45440Sjm199354  * The contents of this file are subject to the terms of the
55440Sjm199354  * Common Development and Distribution License (the "License").
65440Sjm199354  * You may not use this file except in compliance with the License.
75440Sjm199354  *
85440Sjm199354  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95440Sjm199354  * or http://www.opensolaris.org/os/licensing.
105440Sjm199354  * See the License for the specific language governing permissions
115440Sjm199354  * and limitations under the License.
125440Sjm199354  *
135440Sjm199354  * When distributing Covered Code, include this CDDL HEADER in each
145440Sjm199354  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155440Sjm199354  * If applicable, add the following below this CDDL HEADER, with the
165440Sjm199354  * fields enclosed by brackets "[]" replaced with your own identifying
175440Sjm199354  * information: Portions Copyright [yyyy] [name of copyright owner]
185440Sjm199354  *
195440Sjm199354  * CDDL HEADER END
205440Sjm199354  */
215440Sjm199354 /*
22*6407Sjm199354  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235440Sjm199354  * Use is subject to license terms.
245440Sjm199354  */
255440Sjm199354 
265440Sjm199354 #pragma ident	"%Z%%M%	%I%	%E% SMI"
275440Sjm199354 
285440Sjm199354 #include <string.h>
295440Sjm199354 #include <stdio.h>
305440Sjm199354 #include <stdlib.h>
315440Sjm199354 #include <unistd.h>
325440Sjm199354 #include <ctype.h>
335440Sjm199354 #include <math.h>
345440Sjm199354 #include <limits.h>
355440Sjm199354 #include <libscf.h>
365440Sjm199354 #include <errno.h>
375440Sjm199354 #include <fcntl.h>
385440Sjm199354 #include <door.h>
395440Sjm199354 #include <pwd.h>
405440Sjm199354 #include <auth_attr.h>
415440Sjm199354 #include <secdb.h>
425440Sjm199354 #include <sys/socket.h>
435440Sjm199354 #include <arpa/inet.h>
445440Sjm199354 #include <libintl.h>
455440Sjm199354 #include <libvscan.h>
465440Sjm199354 
475440Sjm199354 #define	VS_INSTANCE_FMRI	"svc:/system/filesystem/vscan:icap"
485440Sjm199354 
495440Sjm199354 /* SMF property group and property names */
505440Sjm199354 #define	VS_PGNAME_GENERAL		"vs_general"
51*6407Sjm199354 #define	VS_PGNAME_ENGINE_PREFIX		"vs_engine_"
52*6407Sjm199354 #define	VS_PGNAME_ENGINE_LEN		VS_SE_NAME_LEN + 16
535440Sjm199354 
545440Sjm199354 #define	VS_PNAME_MAXSIZE		"maxsize"
555440Sjm199354 #define	VS_PNAME_MAXSIZE_ACTION		"maxsize_action"
565440Sjm199354 #define	VS_PNAME_TYPES			"types"
575440Sjm199354 #define	VS_PNAME_VLOG			"viruslog"
585440Sjm199354 
595440Sjm199354 #define	VS_PNAME_SE_ENABLE		"enable"
605440Sjm199354 #define	VS_PNAME_SE_HOST		"host"
615440Sjm199354 #define	VS_PNAME_SE_PORT		"port"
625440Sjm199354 #define	VS_PNAME_SE_MAXCONN		"max_connect"
635440Sjm199354 #define	VS_PNAME_VAUTH			"value_authorization"
645440Sjm199354 
655440Sjm199354 
665440Sjm199354 /* types string processing */
675440Sjm199354 #define	VS_TYPES_SEP		','
685440Sjm199354 #define	VS_TYPES_ESCAPE		'\\'
695440Sjm199354 #define	VS_TYPES_RULES		"+-"
705440Sjm199354 
715440Sjm199354 
725440Sjm199354 /*
735440Sjm199354  * The SCF context enapsulating the SCF objects used in the
745440Sjm199354  * repository load and store routines vs_scf_values_get()
755440Sjm199354  * and vs_scf_values_set().
765440Sjm199354  *
775440Sjm199354  * The context is always opened before a get or set, then
785440Sjm199354  * closed when finished (or on error); the open does an
795440Sjm199354  * initial setup, while inside the get and set functions,
805440Sjm199354  * additional objects within the context may be selectively
815440Sjm199354  * initialized for use, depending on the actions needed and
825440Sjm199354  * the properties being operated on.
835440Sjm199354  */
845440Sjm199354 typedef struct vs_scfctx {
855440Sjm199354 	scf_handle_t *vscf_handle;
865440Sjm199354 	scf_instance_t *vscf_inst;
875440Sjm199354 	scf_propertygroup_t *vscf_pgroup;
885440Sjm199354 	scf_transaction_t *vscf_tx;
895440Sjm199354 	scf_iter_t *vscf_iter;
905440Sjm199354 	scf_property_t *vscf_prop[VS_NUM_PROPIDS];
915440Sjm199354 	scf_transaction_entry_t *vscf_ent[VS_NUM_PROPIDS];
925440Sjm199354 	scf_value_t *vscf_val[VS_NUM_PROPIDS];
935440Sjm199354 } vs_scfctx_t;
945440Sjm199354 
955440Sjm199354 /*
965440Sjm199354  * The vscan property definition. Maps the property id with the name
975440Sjm199354  * and type used to store the property in the repository.
985440Sjm199354  * A table of these definitions is defined with a single entry per
995440Sjm199354  * property.
1005440Sjm199354  */
1015440Sjm199354 typedef struct {
1025440Sjm199354 	const char *vpd_name;
1035440Sjm199354 	uint64_t vpd_id;
1045440Sjm199354 	scf_type_t vpd_type;
1055440Sjm199354 } vs_propdef_t;
1065440Sjm199354 
1075440Sjm199354 typedef enum {
1085440Sjm199354 	VS_PTYPE_GEN,
1095440Sjm199354 	VS_PTYPE_SE
1105440Sjm199354 } vs_prop_type_t;
1115440Sjm199354 
1125440Sjm199354 typedef struct vs_prop_hd {
1135440Sjm199354 	vs_prop_type_t vp_type;
1145440Sjm199354 	uint64_t vp_ids;
1155440Sjm199354 	uint64_t vp_all;
1165440Sjm199354 	union {
1175440Sjm199354 		vs_props_t vp_gen;
1185440Sjm199354 		vs_props_se_t vp_se;
1195440Sjm199354 	} vp_props;
1205440Sjm199354 } vs_prop_hd_t;
1215440Sjm199354 
1225440Sjm199354 #define	vp_gen	vp_props.vp_gen
1235440Sjm199354 #define	vp_se	vp_props.vp_se
1245440Sjm199354 
1255440Sjm199354 /*
1265440Sjm199354  * Default values - these are used to return valid data
1275440Sjm199354  * to the caller in cases where invalid or unexpected values
1285440Sjm199354  * are found in the repository.
1295440Sjm199354  *
1305440Sjm199354  * Note: These values must be kept in sync with those defined
1315440Sjm199354  * in the service manifest.
1325440Sjm199354  */
1335440Sjm199354 static const boolean_t vs_dflt_allow = B_TRUE;
1345440Sjm199354 static const boolean_t vs_dflt_enable = B_TRUE;
1355440Sjm199354 static const char *vs_dflt_maxsize = "1GB";
1365440Sjm199354 static const char *vs_dflt_host = "";
1375440Sjm199354 static const uint16_t vs_dflt_port = 1344;
1385440Sjm199354 static const uint16_t vs_dflt_maxconn = 32L;
1395440Sjm199354 static const  char *vs_dflt_types = "+*";
1405440Sjm199354 static const char *vs_dflt_vlog = "";
1415440Sjm199354 
1425440Sjm199354 /* Property definition table */
1435440Sjm199354 static const vs_propdef_t vs_propdefs[] = {
1445440Sjm199354 	/* general properties */
1455440Sjm199354 	{ VS_PNAME_MAXSIZE, VS_PROPID_MAXSIZE, SCF_TYPE_ASTRING },
1465440Sjm199354 	{ VS_PNAME_MAXSIZE_ACTION, VS_PROPID_MAXSIZE_ACTION, SCF_TYPE_BOOLEAN },
1475440Sjm199354 	{ VS_PNAME_TYPES, VS_PROPID_TYPES, SCF_TYPE_ASTRING },
1485440Sjm199354 	{ VS_PNAME_VLOG, VS_PROPID_VLOG, SCF_TYPE_ASTRING },
1495440Sjm199354 	/* scan engine properties */
1505440Sjm199354 	{ VS_PNAME_SE_ENABLE, VS_PROPID_SE_ENABLE, SCF_TYPE_BOOLEAN },
1515440Sjm199354 	{ VS_PNAME_SE_HOST, VS_PROPID_SE_HOST, SCF_TYPE_HOST },
1525440Sjm199354 	{ VS_PNAME_SE_PORT, VS_PROPID_SE_PORT, SCF_TYPE_INTEGER },
1535440Sjm199354 	{ VS_PNAME_SE_MAXCONN, VS_PROPID_SE_MAXCONN, SCF_TYPE_INTEGER },
1545440Sjm199354 	{ VS_PNAME_VAUTH, VS_PROPID_VALUE_AUTH, SCF_TYPE_ASTRING }
1555440Sjm199354 };
1565440Sjm199354 
1575440Sjm199354 static const int vs_npropdefs = sizeof (vs_propdefs)/sizeof (vs_propdef_t);
1585440Sjm199354 
1595440Sjm199354 /* Local functions */
1605440Sjm199354 static const vs_propdef_t *vs_get_propdef(uint64_t);
1615440Sjm199354 static void vs_default_value(vs_prop_hd_t *, const uint64_t);
1625440Sjm199354 
1635440Sjm199354 static int vs_scf_values_get(const char *, vs_prop_hd_t *);
1645440Sjm199354 static int vs_scf_get(const vs_propdef_t *, vs_prop_hd_t *, vs_scfctx_t *, int);
1655440Sjm199354 
1665440Sjm199354 static int vs_scf_values_set(const char *, vs_prop_hd_t *);
1675440Sjm199354 static int vs_scf_set(const vs_propdef_t *, vs_prop_hd_t *, vs_scfctx_t *, int);
1685440Sjm199354 static int vs_scf_pg_create(const char *, vs_prop_hd_t *);
169*6407Sjm199354 static int vs_scf_pg_delete(const char *);
1705440Sjm199354 
1715440Sjm199354 static int vs_scf_ctx_open(vs_scfctx_t *);
1725440Sjm199354 static void vs_scf_ctx_close(vs_scfctx_t *);
1735440Sjm199354 
1745440Sjm199354 static int vs_validate(const vs_prop_hd_t *, uint64_t);
1755440Sjm199354 static int vs_is_valid_types(const char *);
1765440Sjm199354 static int vs_is_valid_host(const char *);
1775440Sjm199354 static int vs_checkauth(char *);
1785440Sjm199354 
179*6407Sjm199354 static int vs_props_get_engines(char *[], int *);
180*6407Sjm199354 static void vs_engid_to_pgname(const char *, char [VS_PGNAME_ENGINE_LEN]);
1815440Sjm199354 static int vs_scf_pg_count(void);
1825440Sjm199354 static int vs_strtoshift(const char *);
1835440Sjm199354 
1845440Sjm199354 
1855440Sjm199354 /*
1865440Sjm199354  * vs_props_get_all
1875440Sjm199354  *
1885440Sjm199354  * Retrieves the general service properties and all properties
1895440Sjm199354  * for all scan engines from the repository.
1905440Sjm199354  *
1915440Sjm199354  * If invalid property values are found, the values are corrected to
1925440Sjm199354  * the default value.
1935440Sjm199354  *
1945440Sjm199354  * Return codes:
1955440Sjm199354  *	VS_ERR_VS_ERR_NONE
1965440Sjm199354  *	VS_ERR_SCF
1975440Sjm199354  *	VS_ERR_SYS
1985440Sjm199354  */
1995440Sjm199354 int
2005440Sjm199354 vs_props_get_all(vs_props_all_t *va)
2015440Sjm199354 {
2025440Sjm199354 	int i, rc, n;
203*6407Sjm199354 	char *engids[VS_SE_MAX];
2045440Sjm199354 
2055440Sjm199354 	(void) memset(va, 0, sizeof (vs_props_all_t));
2065440Sjm199354 	if ((rc = vs_props_get(&va->va_props, VS_PROPID_GEN_ALL))
2075440Sjm199354 	    != VS_ERR_NONE)
2085440Sjm199354 		return (rc);
2095440Sjm199354 
2105440Sjm199354 	n = VS_SE_MAX;
2115440Sjm199354 	if ((rc = vs_props_get_engines(engids, &n)) != VS_ERR_NONE)
2125440Sjm199354 		return (rc);
2135440Sjm199354 
2145440Sjm199354 	for (i = 0; i < n; i++) {
215*6407Sjm199354 		if ((rc = vs_props_se_get(engids[i],
216*6407Sjm199354 		    &va->va_se[i], VS_PROPID_SE_ALL)) != VS_ERR_NONE)
217*6407Sjm199354 			break;
2185440Sjm199354 	}
2195440Sjm199354 
220*6407Sjm199354 	/* free engids allocated in vs_props_get_engines */
221*6407Sjm199354 	for (i = 0; i < VS_SE_MAX; i++)	{
222*6407Sjm199354 		if (engids[i] != NULL)
223*6407Sjm199354 			free(engids[i]);
224*6407Sjm199354 	}
225*6407Sjm199354 
226*6407Sjm199354 	return (rc);
2275440Sjm199354 }
2285440Sjm199354 
2295440Sjm199354 
2305440Sjm199354 /*
2315440Sjm199354  * vs_props_get
2325440Sjm199354  *
2335440Sjm199354  * Retrieves values for the specified general service properties from
2345440Sjm199354  * the repository.
2355440Sjm199354  *
2365440Sjm199354  * If invalid property values are found, the values are corrected to
2375440Sjm199354  * the default value.
2385440Sjm199354  *
2395440Sjm199354  * Return codes:
2405440Sjm199354  *	VS_ERR_VS_ERR_NONE
2415440Sjm199354  *	VS_ERR_INVALID_PROPERTY
2425440Sjm199354  *	VS_ERR_SCF
2435440Sjm199354  *	VS_ERR_SYS
2445440Sjm199354  */
2455440Sjm199354 int
2465440Sjm199354 vs_props_get(vs_props_t *vp, uint64_t propids)
2475440Sjm199354 {
2485440Sjm199354 	int  rc;
2495440Sjm199354 	vs_prop_hd_t prop_hd;
2505440Sjm199354 
2515440Sjm199354 	if ((propids & VS_PROPID_GEN_ALL) != propids)
2525440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
2535440Sjm199354 
2545440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
2555440Sjm199354 	prop_hd.vp_type = VS_PTYPE_GEN;
2565440Sjm199354 	prop_hd.vp_ids = propids;
2575440Sjm199354 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
2585440Sjm199354 
2595440Sjm199354 	rc = vs_scf_values_get(VS_PGNAME_GENERAL, &prop_hd);
2605440Sjm199354 
2615440Sjm199354 	*vp = prop_hd.vp_gen;
2625440Sjm199354 	return (rc);
2635440Sjm199354 }
2645440Sjm199354 
2655440Sjm199354 
2665440Sjm199354 /*
2675440Sjm199354  * vs_props_set
2685440Sjm199354  *
2695440Sjm199354  * Changes values for the specified general service properties
2705440Sjm199354  * in the repository.
2715440Sjm199354  *
2725440Sjm199354  * Return codes:
2735440Sjm199354  *	VS_ERR_VS_ERR_NONE
2745440Sjm199354  *	VS_ERR_INVALID_PROPERTY
2755440Sjm199354  *	VS_ERR_INVALID_VALUE
2765440Sjm199354  *	VS_ERR_SCF
2775440Sjm199354  *	VS_ERR_SYS
2785440Sjm199354  */
2795440Sjm199354 int
2805440Sjm199354 vs_props_set(const vs_props_t *vp, uint64_t propids)
2815440Sjm199354 {
2825440Sjm199354 	vs_prop_hd_t prop_hd;
2835440Sjm199354 
2845440Sjm199354 	if ((propids & VS_PROPID_GEN_ALL) != propids)
2855440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
2865440Sjm199354 
2875440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
2885440Sjm199354 	prop_hd.vp_type = VS_PTYPE_GEN;
2895440Sjm199354 	prop_hd.vp_ids = propids;
2905440Sjm199354 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
2915440Sjm199354 	prop_hd.vp_gen = *vp;
2925440Sjm199354 	return (vs_scf_values_set(VS_PGNAME_GENERAL, &prop_hd));
2935440Sjm199354 }
2945440Sjm199354 
2955440Sjm199354 
2965440Sjm199354 /*
2975440Sjm199354  * vs_props_se_get
2985440Sjm199354  *
2995440Sjm199354  * Retrieves values for the specified scan engine properties from the
3005440Sjm199354  * repository.
3015440Sjm199354  *
3025440Sjm199354  * If the enable property is set (true), the host property is
3035440Sjm199354  * checked for validity. If it is not valid, the requested values
3045440Sjm199354  * are returned with the enable propery set to off (false)
3055440Sjm199354  *
3065440Sjm199354  * Return codes:
3075440Sjm199354  *	VS_ERR_VS_ERR_NONE
3085440Sjm199354  *	VS_ERR_INVALID_PROPERTY
3095440Sjm199354  *	VS_ERR_SCF
3105440Sjm199354  *	VS_ERR_SYS
3115440Sjm199354  */
3125440Sjm199354 int
3135440Sjm199354 vs_props_se_get(char *engid, vs_props_se_t *sep, uint64_t propids)
3145440Sjm199354 {
3155440Sjm199354 	int rc;
316*6407Sjm199354 	char pgname[VS_PGNAME_ENGINE_LEN];
3175440Sjm199354 	vs_prop_hd_t prop_hd;
3185440Sjm199354 
3195440Sjm199354 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
3205440Sjm199354 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
3215440Sjm199354 		return (VS_ERR_INVALID_SE);
3225440Sjm199354 
3235440Sjm199354 	if ((propids & VS_PROPID_SE_ALL) != propids)
3245440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
3255440Sjm199354 
3265440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
3275440Sjm199354 	prop_hd.vp_type = VS_PTYPE_SE;
3285440Sjm199354 	prop_hd.vp_ids = propids;
3295440Sjm199354 	prop_hd.vp_all = VS_PROPID_SE_ALL;
3305440Sjm199354 	(void) strlcpy(prop_hd.vp_se.vep_engid, engid, VS_SE_NAME_LEN);
3315440Sjm199354 
3325440Sjm199354 	/* If getting enable, get the host property too */
3335440Sjm199354 	if ((propids & VS_PROPID_SE_ENABLE))
3345440Sjm199354 		prop_hd.vp_ids |= VS_PROPID_SE_HOST;
3355440Sjm199354 
3365440Sjm199354 	/* Load values from the repository */
337*6407Sjm199354 	vs_engid_to_pgname(engid, pgname);
338*6407Sjm199354 	rc = vs_scf_values_get(pgname, &prop_hd);
3395440Sjm199354 	if (rc != VS_ERR_NONE)
3405440Sjm199354 		return (rc);
3415440Sjm199354 
3425440Sjm199354 	/*
3435440Sjm199354 	 *  If the host is invalid and the enable property is on,
3445440Sjm199354 	 *  return enable property as off
3455440Sjm199354 	 */
3465440Sjm199354 	if ((prop_hd.vp_ids & VS_PROPID_SE_HOST) &&
3475440Sjm199354 	    (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)) {
3485440Sjm199354 		prop_hd.vp_se.vep_enable = B_FALSE;
3495440Sjm199354 	}
3505440Sjm199354 
3515440Sjm199354 	*sep = prop_hd.vp_se;
3525440Sjm199354 	return (rc);
3535440Sjm199354 }
3545440Sjm199354 
3555440Sjm199354 
3565440Sjm199354 
3575440Sjm199354 /*
3585440Sjm199354  * vs_props_se_set
3595440Sjm199354  *
3605440Sjm199354  * Changes the values for the specified scan engine properties in the
3615440Sjm199354  * repository.
3625440Sjm199354  *
3635440Sjm199354  * If the enable property is being changed to true in this operation,
3645440Sjm199354  * a host property must also be specified, or already exist in the
3655440Sjm199354  * repository.
3665440Sjm199354  *
3675440Sjm199354  * Return codes:
3685440Sjm199354  *	VS_ERR_NONE
3695440Sjm199354  *	VS_ERR_INVALID_PROPERTY
3705440Sjm199354  *	VS_ERR_INVALID_VALUE
3715440Sjm199354  *	VS_ERR_SCF
3725440Sjm199354  *	VS_ERR_SYS
3735440Sjm199354  */
3745440Sjm199354 int
3755440Sjm199354 vs_props_se_set(char *engid, const vs_props_se_t *sep, uint64_t propids)
3765440Sjm199354 {
3775440Sjm199354 	int rc;
378*6407Sjm199354 	char pgname[VS_PGNAME_ENGINE_LEN];
3795440Sjm199354 	vs_prop_hd_t prop_hd;
3805440Sjm199354 
3815440Sjm199354 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
3825440Sjm199354 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
3835440Sjm199354 		return (VS_ERR_INVALID_SE);
3845440Sjm199354 
3855440Sjm199354 	if ((propids & VS_PROPID_SE_ALL) != propids)
3865440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
3875440Sjm199354 
3885440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
3895440Sjm199354 	prop_hd.vp_type = VS_PTYPE_SE;
3905440Sjm199354 	prop_hd.vp_all = VS_PROPID_SE_ALL;
3915440Sjm199354 
392*6407Sjm199354 	vs_engid_to_pgname(engid, pgname);
393*6407Sjm199354 
3945440Sjm199354 	/*
3955440Sjm199354 	 * if enabling a scan engine, ensure that a valid host
3965440Sjm199354 	 * is also being set, or already exists in the repository
3975440Sjm199354 	 */
3985440Sjm199354 	if ((propids & VS_PROPID_SE_ENABLE) && (sep->vep_enable == B_TRUE) &&
3995440Sjm199354 	    !(propids & VS_PROPID_SE_HOST)) {
4005440Sjm199354 
4015440Sjm199354 		prop_hd.vp_ids = VS_PROPID_SE_HOST;
402*6407Sjm199354 		if ((rc = vs_scf_values_get(pgname, &prop_hd)) != VS_ERR_NONE)
4035440Sjm199354 			return (rc);
4045440Sjm199354 
4055440Sjm199354 		if (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)
4065440Sjm199354 			return (VS_ERR_INVALID_HOST);
4075440Sjm199354 	}
4085440Sjm199354 
4095440Sjm199354 	prop_hd.vp_ids = propids;
4105440Sjm199354 	prop_hd.vp_se = *sep;
4115440Sjm199354 
412*6407Sjm199354 	return (vs_scf_values_set(pgname, &prop_hd));
4135440Sjm199354 }
4145440Sjm199354 
4155440Sjm199354 
4165440Sjm199354 /*
4175440Sjm199354  * vs_props_se_create
4185440Sjm199354  */
4195440Sjm199354 int
4205440Sjm199354 vs_props_se_create(char *engid, const vs_props_se_t *sep, uint64_t propids)
4215440Sjm199354 {
4225440Sjm199354 	int n;
423*6407Sjm199354 	char pgname[VS_PGNAME_ENGINE_LEN];
4245440Sjm199354 	vs_prop_hd_t prop_hd;
4255440Sjm199354 
4265440Sjm199354 	if ((propids & VS_PROPID_SE_ALL) != propids)
4275440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
4285440Sjm199354 
4295440Sjm199354 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
4305440Sjm199354 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
4315440Sjm199354 		return (VS_ERR_INVALID_SE);
4325440Sjm199354 
4335440Sjm199354 	if ((n = vs_scf_pg_count()) == -1)
4345440Sjm199354 		return (VS_ERR_SCF);
4355440Sjm199354 
4365440Sjm199354 	if (n == VS_SE_MAX)
4375440Sjm199354 		return (VS_ERR_MAX_SE);
4385440Sjm199354 
439*6407Sjm199354 	vs_engid_to_pgname(engid, pgname);
440*6407Sjm199354 
4415440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
4425440Sjm199354 	prop_hd.vp_type = VS_PTYPE_SE;
4435440Sjm199354 	prop_hd.vp_all = VS_PROPID_SE_ALL;
4445440Sjm199354 	prop_hd.vp_ids = propids | VS_PROPID_VALUE_AUTH;
4455440Sjm199354 	prop_hd.vp_se = *sep;
4465440Sjm199354 
447*6407Sjm199354 	/* if hostname not specified, default it to engid */
448*6407Sjm199354 	if ((propids & VS_PROPID_SE_HOST) == 0) {
449*6407Sjm199354 		(void) strlcpy(prop_hd.vp_se.vep_host, engid, MAXHOSTNAMELEN);
450*6407Sjm199354 		prop_hd.vp_ids |= VS_PROPID_SE_HOST;
451*6407Sjm199354 	}
4525440Sjm199354 
453*6407Sjm199354 	return (vs_scf_pg_create(pgname, &prop_hd));
4545440Sjm199354 }
4555440Sjm199354 
4565440Sjm199354 
4575440Sjm199354 /*
4585440Sjm199354  * vs_props_se_delete
4595440Sjm199354  */
4605440Sjm199354 int
4615440Sjm199354 vs_props_se_delete(const char *engid)
4625440Sjm199354 {
463*6407Sjm199354 	char pgname[VS_PGNAME_ENGINE_LEN];
4645440Sjm199354 
4655440Sjm199354 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
4665440Sjm199354 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
4675440Sjm199354 		return (VS_ERR_INVALID_SE);
4685440Sjm199354 
469*6407Sjm199354 	vs_engid_to_pgname(engid, pgname);
4705440Sjm199354 
471*6407Sjm199354 	return (vs_scf_pg_delete(pgname));
4725440Sjm199354 }
4735440Sjm199354 
4745440Sjm199354 
4755440Sjm199354 /*
4765440Sjm199354  * vs_strerror
4775440Sjm199354  */
4785440Sjm199354 const char *
4795440Sjm199354 vs_strerror(int error)
4805440Sjm199354 {
4815440Sjm199354 	switch (error) {
4825440Sjm199354 	case VS_ERR_NONE:
4835440Sjm199354 		return (gettext("no error"));
4845440Sjm199354 	case VS_ERR_INVALID_PROPERTY:
4855440Sjm199354 		return (gettext("invalid property id"));
4865440Sjm199354 	case VS_ERR_INVALID_VALUE:
4875440Sjm199354 		return (gettext("invalid property value"));
4885440Sjm199354 	case VS_ERR_INVALID_HOST:
4895440Sjm199354 		return (gettext("invalid host"));
4905440Sjm199354 	case VS_ERR_INVALID_SE:
4915440Sjm199354 		return (gettext("invalid scan engine"));
4925440Sjm199354 	case VS_ERR_MAX_SE:
4935440Sjm199354 		return (gettext("max scan engines exceeded"));
4945440Sjm199354 	case VS_ERR_AUTH:
4955440Sjm199354 		return (gettext("insufficient privileges for action"));
4965440Sjm199354 	case VS_ERR_DAEMON_COMM:
4975440Sjm199354 		return (gettext("unable to contact vscand"));
4985440Sjm199354 	case VS_ERR_SCF:
4995440Sjm199354 		return (scf_strerror(scf_error()));
5005440Sjm199354 	case VS_ERR_SYS:
5015440Sjm199354 		return (strerror(errno));
5025440Sjm199354 	default:
5035440Sjm199354 		return (gettext("unknown error"));
5045440Sjm199354 	}
5055440Sjm199354 }
5065440Sjm199354 
5075440Sjm199354 
5085440Sjm199354 /*
5095440Sjm199354  * vs_get_propdef
5105440Sjm199354  *
5115440Sjm199354  * Finds and returns a property definition by property id.
5125440Sjm199354  */
5135440Sjm199354 static const vs_propdef_t *
5145440Sjm199354 vs_get_propdef(uint64_t propid)
5155440Sjm199354 {
5165440Sjm199354 	int i;
5175440Sjm199354 
5185440Sjm199354 	for (i = 0; i < vs_npropdefs; i++) {
5195440Sjm199354 		if (propid == vs_propdefs[i].vpd_id)
5205440Sjm199354 			return (&vs_propdefs[i]);
5215440Sjm199354 	}
5225440Sjm199354 
5235440Sjm199354 	return (NULL);
5245440Sjm199354 }
5255440Sjm199354 
5265440Sjm199354 
5275440Sjm199354 /*
5285440Sjm199354  * vs_default_value
5295440Sjm199354  *
5305440Sjm199354  * Sets a property value that contains invalid data to its default value.
5315440Sjm199354  *
5325440Sjm199354  * Note that this function does not alter any values in the repository
5335440Sjm199354  * This is only to enable the caller to get valid data.
5345440Sjm199354  */
5355440Sjm199354 static void
5365440Sjm199354 vs_default_value(vs_prop_hd_t *prop_hd, const uint64_t propid)
5375440Sjm199354 {
5385440Sjm199354 	vs_props_t *vp = &prop_hd->vp_gen;
5395440Sjm199354 	vs_props_se_t *vep = &prop_hd->vp_se;
5405440Sjm199354 
5415440Sjm199354 	switch (propid) {
5425440Sjm199354 	case VS_PROPID_MAXSIZE:
5435440Sjm199354 		(void) strlcpy(vp->vp_maxsize, vs_dflt_maxsize,
5445440Sjm199354 		    sizeof (vp->vp_maxsize));
5455440Sjm199354 		break;
5465440Sjm199354 	case VS_PROPID_MAXSIZE_ACTION:
5475440Sjm199354 		vp->vp_maxsize_action = vs_dflt_allow;
5485440Sjm199354 		break;
5495440Sjm199354 	case VS_PROPID_TYPES:
5505440Sjm199354 		(void) strlcpy(vp->vp_types, vs_dflt_types,
5515440Sjm199354 		    sizeof (vp->vp_types));
5525440Sjm199354 		break;
5535440Sjm199354 	case VS_PROPID_VLOG:
5545440Sjm199354 		(void) strlcpy(vp->vp_vlog, vs_dflt_vlog,
5555440Sjm199354 		    sizeof (vp->vp_vlog));
5565440Sjm199354 		break;
5575440Sjm199354 	case VS_PROPID_SE_ENABLE:
5585440Sjm199354 		vep->vep_enable = vs_dflt_enable;
5595440Sjm199354 		break;
5605440Sjm199354 	case VS_PROPID_SE_HOST:
5615440Sjm199354 		(void) strlcpy(vep->vep_host, vs_dflt_host,
5625440Sjm199354 		    sizeof (vep->vep_host));
5635440Sjm199354 		break;
5645440Sjm199354 	case VS_PROPID_SE_PORT:
5655440Sjm199354 		vep->vep_port = vs_dflt_port;
5665440Sjm199354 		break;
5675440Sjm199354 	case VS_PROPID_SE_MAXCONN:
5685440Sjm199354 		vep->vep_maxconn = vs_dflt_maxconn;
5695440Sjm199354 		break;
5705440Sjm199354 	default:
5715440Sjm199354 		break;
5725440Sjm199354 	}
5735440Sjm199354 }
5745440Sjm199354 
5755440Sjm199354 
5765440Sjm199354 /*
5775440Sjm199354  * vs_scf_values_get
5785440Sjm199354  *
5795440Sjm199354  * Gets property values for one or more properties from the repository.
5805440Sjm199354  * This is the single entry point for loading SMF values.
5815440Sjm199354  *
5825440Sjm199354  * While a transaction is not used for loading property values,
5835440Sjm199354  * the operation is parameterized by a property group. All properties
5845440Sjm199354  * retrieved in this function, then, must belong to the same property
5855440Sjm199354  * group.
5865440Sjm199354  */
5875440Sjm199354 int
5885440Sjm199354 vs_scf_values_get(const char *pgname, vs_prop_hd_t *prop_hd)
5895440Sjm199354 {
5905440Sjm199354 	vs_scfctx_t vsc;
5915440Sjm199354 	int rc, np;
5925440Sjm199354 	const vs_propdef_t *vpd;
5935440Sjm199354 	uint64_t propid;
5945440Sjm199354 
5955440Sjm199354 	if ((vs_scf_ctx_open(&vsc)) != 0) {
5965440Sjm199354 		vs_scf_ctx_close(&vsc);
5975440Sjm199354 		return (VS_ERR_SCF);
5985440Sjm199354 	}
5995440Sjm199354 
6005440Sjm199354 	if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
6015440Sjm199354 		vs_scf_ctx_close(&vsc);
6025440Sjm199354 		if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) {
6035440Sjm199354 			rc = scf_error();
6045440Sjm199354 			if ((rc == SCF_ERROR_NOT_FOUND) ||
6055440Sjm199354 			    (rc == SCF_ERROR_INVALID_ARGUMENT))
6065440Sjm199354 				return (VS_ERR_INVALID_SE);
6075440Sjm199354 		}
6085440Sjm199354 		return (VS_ERR_SCF);
6095440Sjm199354 	}
6105440Sjm199354 
6115440Sjm199354 	rc = VS_ERR_NONE;
6125440Sjm199354 	np = 0;
6135440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
6145440Sjm199354 		if ((prop_hd->vp_ids & propid) == 0)
6155440Sjm199354 			continue;
6165440Sjm199354 
6175440Sjm199354 		if ((vpd = vs_get_propdef(propid)) == NULL) {
6185440Sjm199354 			rc = VS_ERR_INVALID_PROPERTY;
6195440Sjm199354 			break;
6205440Sjm199354 		}
6215440Sjm199354 
6225440Sjm199354 		vsc.vscf_prop[np] = scf_property_create(vsc.vscf_handle);
6235440Sjm199354 		vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
6245440Sjm199354 
6255440Sjm199354 		if (vsc.vscf_prop[np] == NULL || vsc.vscf_val[np] == NULL) {
6265440Sjm199354 			rc = VS_ERR_SCF;
6275440Sjm199354 			break;
6285440Sjm199354 		}
6295440Sjm199354 
6305440Sjm199354 		if (scf_pg_get_property(vsc.vscf_pgroup, vpd->vpd_name,
6315440Sjm199354 		    vsc.vscf_prop[np]) == -1) {
6325440Sjm199354 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
6335440Sjm199354 				vs_default_value(prop_hd, vpd->vpd_id);
6345440Sjm199354 				continue;
6355440Sjm199354 			}
6365440Sjm199354 			rc = VS_ERR_SCF;
6375440Sjm199354 			break;
6385440Sjm199354 		}
6395440Sjm199354 
6405440Sjm199354 		if ((rc = vs_scf_get(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
6415440Sjm199354 			break;
6425440Sjm199354 
6435440Sjm199354 		++np;
6445440Sjm199354 	}
6455440Sjm199354 
6465440Sjm199354 
6475440Sjm199354 	vs_scf_ctx_close(&vsc);
6485440Sjm199354 
6495440Sjm199354 	return (rc);
6505440Sjm199354 }
6515440Sjm199354 
6525440Sjm199354 
6535440Sjm199354 /*
6545440Sjm199354  * vs_scf_get
6555440Sjm199354  *
6565440Sjm199354  * Loads a single values from the repository into the appropriate vscan
6575440Sjm199354  * property structure member.
6585440Sjm199354  */
6595440Sjm199354 static int
6605440Sjm199354 vs_scf_get(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
6615440Sjm199354 	vs_scfctx_t *vsc, int idx)
6625440Sjm199354 {
6635440Sjm199354 	int rc;
6645440Sjm199354 	int64_t port;
6655440Sjm199354 	uint8_t valbool;
6665440Sjm199354 	vs_props_t *vp = &prop_hd->vp_gen;
6675440Sjm199354 	vs_props_se_t *vep = &prop_hd->vp_se;
6685440Sjm199354 
6695440Sjm199354 	if ((rc = scf_property_get_value(vsc->vscf_prop[idx],
6705440Sjm199354 	    vsc->vscf_val[idx])) == -1) {
6715440Sjm199354 		if (rc == SCF_ERROR_CONSTRAINT_VIOLATED ||
6725440Sjm199354 		    rc == SCF_ERROR_NOT_FOUND) {
6735440Sjm199354 			vs_default_value(prop_hd, vpd->vpd_id);
6745440Sjm199354 			return (VS_ERR_NONE);
6755440Sjm199354 		}
6765440Sjm199354 		return (VS_ERR_SCF);
6775440Sjm199354 	}
6785440Sjm199354 
6795440Sjm199354 	rc = VS_ERR_NONE;
6805440Sjm199354 	switch (vpd->vpd_id) {
6815440Sjm199354 	case VS_PROPID_MAXSIZE:
6825440Sjm199354 		if ((scf_value_get_astring(vsc->vscf_val[idx],
6835440Sjm199354 		    vp->vp_maxsize, sizeof (vp->vp_maxsize))) == -1) {
6845440Sjm199354 			return (VS_ERR_SCF);
6855440Sjm199354 		}
6865440Sjm199354 		break;
6875440Sjm199354 	case VS_PROPID_MAXSIZE_ACTION:
6885440Sjm199354 		if ((scf_value_get_boolean(vsc->vscf_val[idx],
6895440Sjm199354 		    &valbool)) == -1) {
6905440Sjm199354 			return (VS_ERR_SCF);
6915440Sjm199354 		}
6925440Sjm199354 		vp->vp_maxsize_action = (valbool == 0) ? B_FALSE : B_TRUE;
6935440Sjm199354 		break;
6945440Sjm199354 	case VS_PROPID_TYPES:
6955440Sjm199354 		if ((scf_value_get_astring(vsc->vscf_val[idx],
6965440Sjm199354 		    vp->vp_types, sizeof (vp->vp_types))) == -1) {
6975440Sjm199354 			return (VS_ERR_SCF);
6985440Sjm199354 		}
6995440Sjm199354 		break;
7005440Sjm199354 	case VS_PROPID_VLOG:
7015440Sjm199354 		if ((scf_value_get_astring(vsc->vscf_val[idx],
7025440Sjm199354 		    vp->vp_vlog, sizeof (vp->vp_vlog))) == -1) {
7035440Sjm199354 			return (VS_ERR_SCF);
7045440Sjm199354 		}
7055440Sjm199354 		break;
7065440Sjm199354 	case VS_PROPID_SE_ENABLE:
7075440Sjm199354 		if ((scf_value_get_boolean(vsc->vscf_val[idx],
7085440Sjm199354 		    &valbool)) == -1) {
7095440Sjm199354 			return (VS_ERR_SCF);
7105440Sjm199354 		}
7115440Sjm199354 		vep->vep_enable = (valbool == 0) ? B_FALSE : B_TRUE;
7125440Sjm199354 		break;
7135440Sjm199354 	case VS_PROPID_SE_HOST:
7145440Sjm199354 		(void) scf_value_get_as_string_typed(vsc->vscf_val[idx],
7155440Sjm199354 		    vpd->vpd_type, vep->vep_host, sizeof (vep->vep_host));
7165440Sjm199354 		break;
7175440Sjm199354 	case VS_PROPID_SE_PORT:
7185440Sjm199354 		if ((scf_value_get_integer(vsc->vscf_val[idx], &port)) == -1)
7195440Sjm199354 			return (VS_ERR_SCF);
7205440Sjm199354 		if (port <= 0 || port >= UINT16_MAX)
7215440Sjm199354 			rc = VS_ERR_INVALID_VALUE;
7225440Sjm199354 		else
7235440Sjm199354 			vep->vep_port = (uint16_t)port;
7245440Sjm199354 		break;
7255440Sjm199354 	case VS_PROPID_SE_MAXCONN:
7265440Sjm199354 		if ((scf_value_get_integer(vsc->vscf_val[idx],
7275440Sjm199354 		    (int64_t *)&vep->vep_maxconn)) == -1) {
7285440Sjm199354 			return (VS_ERR_SCF);
7295440Sjm199354 		}
7305440Sjm199354 		break;
7315440Sjm199354 	default:
7325440Sjm199354 		break;
7335440Sjm199354 	}
7345440Sjm199354 
7355440Sjm199354 	if ((rc != VS_ERR_NONE) ||
7365440Sjm199354 	    (vs_validate(prop_hd, vpd->vpd_id) != VS_ERR_NONE)) {
7375440Sjm199354 		vs_default_value(prop_hd, vpd->vpd_id);
7385440Sjm199354 	}
7395440Sjm199354 
7405440Sjm199354 	return (VS_ERR_NONE);
7415440Sjm199354 }
7425440Sjm199354 
7435440Sjm199354 
7445440Sjm199354 /*
7455440Sjm199354  * vs_scf_pg_create
7465440Sjm199354  */
7475440Sjm199354 static int
7485440Sjm199354 vs_scf_pg_create(const char *pgname, vs_prop_hd_t *prop_hd)
7495440Sjm199354 {
7505440Sjm199354 	int rc;
7515440Sjm199354 	uint64_t propid;
7525440Sjm199354 	vs_scfctx_t vsc;
7535440Sjm199354 
7545440Sjm199354 	/* ensure that caller has authorization to refresh service */
7555440Sjm199354 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
7565440Sjm199354 		return (rc);
7575440Sjm199354 
7585440Sjm199354 	if (vs_scf_ctx_open(&vsc) != 0) {
7595440Sjm199354 		vs_scf_ctx_close(&vsc);
7605440Sjm199354 		return (VS_ERR_SCF);
7615440Sjm199354 	}
7625440Sjm199354 
7635440Sjm199354 	if (scf_instance_add_pg(vsc.vscf_inst, pgname,
7645440Sjm199354 	    SCF_GROUP_APPLICATION, 0, vsc.vscf_pgroup) == -1) {
7655440Sjm199354 		vs_scf_ctx_close(&vsc);
7665440Sjm199354 		if (scf_error() == SCF_ERROR_INVALID_ARGUMENT)
7675440Sjm199354 			return (VS_ERR_INVALID_SE);
7685440Sjm199354 		return (VS_ERR_SCF);
7695440Sjm199354 	}
7705440Sjm199354 	vs_scf_ctx_close(&vsc);
7715440Sjm199354 
7725440Sjm199354 	/* set default values for those not specified */
7735440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
7745440Sjm199354 		if ((propid & prop_hd->vp_all) && !(propid & prop_hd->vp_ids))
7755440Sjm199354 			vs_default_value(prop_hd, propid);
7765440Sjm199354 	}
777*6407Sjm199354 
7785440Sjm199354 	prop_hd->vp_ids = prop_hd->vp_all;
7795440Sjm199354 	prop_hd->vp_ids |= VS_PROPID_VALUE_AUTH;
7805440Sjm199354 
7815440Sjm199354 	rc = vs_scf_values_set(pgname, prop_hd);
7825440Sjm199354 	if (rc != VS_ERR_NONE)
783*6407Sjm199354 		(void) vs_scf_pg_delete(pgname);
7845440Sjm199354 
7855440Sjm199354 	return (rc);
7865440Sjm199354 }
7875440Sjm199354 
7885440Sjm199354 
7895440Sjm199354 /*
790*6407Sjm199354  * vs_scf_pg_delete
791*6407Sjm199354  */
792*6407Sjm199354 static int
793*6407Sjm199354 vs_scf_pg_delete(const char *pgname)
794*6407Sjm199354 {
795*6407Sjm199354 	int rc;
796*6407Sjm199354 	vs_scfctx_t vsc;
797*6407Sjm199354 
798*6407Sjm199354 	/* ensure that caller has authorization to refresh service */
799*6407Sjm199354 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
800*6407Sjm199354 		return (rc);
801*6407Sjm199354 
802*6407Sjm199354 	if (vs_scf_ctx_open(&vsc) != 0) {
803*6407Sjm199354 		vs_scf_ctx_close(&vsc);
804*6407Sjm199354 		return (VS_ERR_SCF);
805*6407Sjm199354 	}
806*6407Sjm199354 
807*6407Sjm199354 	if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
808*6407Sjm199354 		vs_scf_ctx_close(&vsc);
809*6407Sjm199354 		rc = scf_error();
810*6407Sjm199354 		if ((rc == SCF_ERROR_NOT_FOUND) ||
811*6407Sjm199354 		    (rc == SCF_ERROR_INVALID_ARGUMENT))
812*6407Sjm199354 			return (VS_ERR_INVALID_SE);
813*6407Sjm199354 		else
814*6407Sjm199354 			return (VS_ERR_SCF);
815*6407Sjm199354 	}
816*6407Sjm199354 
817*6407Sjm199354 	if (scf_pg_delete(vsc.vscf_pgroup) == -1) {
818*6407Sjm199354 		vs_scf_ctx_close(&vsc);
819*6407Sjm199354 		rc = scf_error();
820*6407Sjm199354 		if ((rc == SCF_ERROR_NOT_FOUND) ||
821*6407Sjm199354 		    (rc == SCF_ERROR_INVALID_ARGUMENT))
822*6407Sjm199354 			return (VS_ERR_INVALID_SE);
823*6407Sjm199354 
824*6407Sjm199354 		return (VS_ERR_SCF);
825*6407Sjm199354 	}
826*6407Sjm199354 
827*6407Sjm199354 	vs_scf_ctx_close(&vsc);
828*6407Sjm199354 
829*6407Sjm199354 	/* Notify the daemon that things have changed */
830*6407Sjm199354 	if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1) {
831*6407Sjm199354 		return (VS_ERR_SCF);
832*6407Sjm199354 	}
833*6407Sjm199354 
834*6407Sjm199354 	return (VS_ERR_NONE);
835*6407Sjm199354 }
836*6407Sjm199354 
837*6407Sjm199354 
838*6407Sjm199354 /*
8395440Sjm199354  * vs_scf_values_set
8405440Sjm199354  *
8415440Sjm199354  * Sets property values in the repository.  This is the single
8425440Sjm199354  * entry point for storing SMF values.
8435440Sjm199354  *
8445440Sjm199354  * Like loading values, this is an operation based on a single property
8455440Sjm199354  * group, so all property values changed in this function must belong
8465440Sjm199354  * to the same property group. Additionally, this operation is done in
8475440Sjm199354  * the context of a repository transaction; on any fatal error, the
8485440Sjm199354  * SCF context will be closed, destroying all SCF objects and aborting
8495440Sjm199354  * the transaction.
8505440Sjm199354  */
8515440Sjm199354 static int
8525440Sjm199354 vs_scf_values_set(const char *pgname, vs_prop_hd_t *prop_hd)
8535440Sjm199354 {
8545440Sjm199354 	int rc, np;
8555440Sjm199354 	const vs_propdef_t *vpd;
8565440Sjm199354 	uint64_t propid;
8575440Sjm199354 	vs_scfctx_t vsc;
8585440Sjm199354 
8595440Sjm199354 	/* ensure that caller has authorization to refresh service */
8605440Sjm199354 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
8615440Sjm199354 		return (rc);
8625440Sjm199354 
8635440Sjm199354 	if (vs_scf_ctx_open(&vsc) != 0) {
8645440Sjm199354 		vs_scf_ctx_close(&vsc);
8655440Sjm199354 		return (VS_ERR_SCF);
8665440Sjm199354 	}
8675440Sjm199354 
8685440Sjm199354 	if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
8695440Sjm199354 		vs_scf_ctx_close(&vsc);
8705440Sjm199354 		rc = scf_error();
8715440Sjm199354 		if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) {
8725440Sjm199354 			if ((rc == SCF_ERROR_NOT_FOUND) ||
8735440Sjm199354 			    (rc == SCF_ERROR_INVALID_ARGUMENT))
8745440Sjm199354 				return (VS_ERR_INVALID_SE);
8755440Sjm199354 		}
8765440Sjm199354 		return (VS_ERR_SCF);
8775440Sjm199354 	}
8785440Sjm199354 
8795440Sjm199354 	if (((vsc.vscf_tx = scf_transaction_create(vsc.vscf_handle)) == NULL) ||
8805440Sjm199354 	    (scf_transaction_start(vsc.vscf_tx, vsc.vscf_pgroup) == -1)) {
8815440Sjm199354 		vs_scf_ctx_close(&vsc);
8825440Sjm199354 		return (VS_ERR_SCF);
8835440Sjm199354 	}
8845440Sjm199354 
8855440Sjm199354 	/* Process the value change for each specified property */
8865440Sjm199354 	rc = 0;
8875440Sjm199354 	np = 0;
8885440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
8895440Sjm199354 		if ((prop_hd->vp_ids & propid) == 0)
8905440Sjm199354 			continue;
8915440Sjm199354 
8925440Sjm199354 		if ((vpd = vs_get_propdef(propid)) == NULL) {
8935440Sjm199354 			rc = VS_ERR_INVALID_PROPERTY;
8945440Sjm199354 			break;
8955440Sjm199354 		}
8965440Sjm199354 
8975440Sjm199354 		vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
8985440Sjm199354 		vsc.vscf_ent[np] = scf_entry_create(vsc.vscf_handle);
8995440Sjm199354 
9005440Sjm199354 		if (vsc.vscf_val[np] == NULL || vsc.vscf_ent[np] == NULL) {
9015440Sjm199354 			rc = VS_ERR_SCF;
9025440Sjm199354 			break;
9035440Sjm199354 		}
9045440Sjm199354 
9055440Sjm199354 		if ((rc = scf_transaction_property_change(vsc.vscf_tx,
9065440Sjm199354 		    vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type)) == -1) {
9075440Sjm199354 			rc = scf_transaction_property_new(vsc.vscf_tx,
9085440Sjm199354 			    vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type);
9095440Sjm199354 		}
9105440Sjm199354 		if (rc == -1) {
9115440Sjm199354 			rc = VS_ERR_SCF;
9125440Sjm199354 			break;
9135440Sjm199354 		}
9145440Sjm199354 
9155440Sjm199354 		if ((rc = vs_scf_set(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
9165440Sjm199354 			break;
9175440Sjm199354 
9185440Sjm199354 		++np;
9195440Sjm199354 	}
9205440Sjm199354 
9215440Sjm199354 	if (rc != VS_ERR_NONE) {
9225440Sjm199354 		vs_scf_ctx_close(&vsc);
9235440Sjm199354 		return (rc);
9245440Sjm199354 	}
9255440Sjm199354 
9265440Sjm199354 	/* Commit the transaction */
9275440Sjm199354 	if (scf_transaction_commit(vsc.vscf_tx) == -1) {
9285440Sjm199354 		vs_scf_ctx_close(&vsc);
9295440Sjm199354 		return (VS_ERR_SCF);
9305440Sjm199354 	}
9315440Sjm199354 	vs_scf_ctx_close(&vsc);
9325440Sjm199354 
9335440Sjm199354 	/* Notify the daemon that things have changed */
9345440Sjm199354 	if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1)
9355440Sjm199354 		return (VS_ERR_SCF);
9365440Sjm199354 
9375440Sjm199354 	return (VS_ERR_NONE);
9385440Sjm199354 }
9395440Sjm199354 
9405440Sjm199354 
9415440Sjm199354 /*
9425440Sjm199354  * vs_scf_set
9435440Sjm199354  *
9445440Sjm199354  * Stores a single value from the appropriate vscan property structure
9455440Sjm199354  * member into the repository.
9465440Sjm199354  *
9475440Sjm199354  * Values are set in the SCF value object, then the value object
9485440Sjm199354  * is added to the SCF property object.
9495440Sjm199354  */
9505440Sjm199354 static int
9515440Sjm199354 vs_scf_set(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
9525440Sjm199354     vs_scfctx_t *vsc, int idx)
9535440Sjm199354 {
9545440Sjm199354 	int rc;
9555440Sjm199354 	vs_props_t *vp = &prop_hd->vp_gen;
9565440Sjm199354 	vs_props_se_t *vep = &prop_hd->vp_se;
9575440Sjm199354 
9585440Sjm199354 	if ((rc = vs_validate(prop_hd, vpd->vpd_id)) != VS_ERR_NONE)
9595440Sjm199354 		return (rc);
9605440Sjm199354 
9615440Sjm199354 	rc = VS_ERR_NONE;
9625440Sjm199354 	switch (vpd->vpd_id) {
9635440Sjm199354 	case VS_PROPID_MAXSIZE:
9645440Sjm199354 		if ((scf_value_set_astring(vsc->vscf_val[idx],
9655440Sjm199354 		    vp->vp_maxsize)) == -1) {
9665440Sjm199354 			rc = VS_ERR_SCF;
9675440Sjm199354 		}
9685440Sjm199354 		break;
9695440Sjm199354 	case VS_PROPID_MAXSIZE_ACTION:
9705440Sjm199354 		scf_value_set_boolean(vsc->vscf_val[idx],
9715440Sjm199354 		    (uint8_t)vp->vp_maxsize_action);
9725440Sjm199354 		break;
9735440Sjm199354 	case VS_PROPID_TYPES:
9745440Sjm199354 		if ((scf_value_set_astring(vsc->vscf_val[idx],
9755440Sjm199354 		    vp->vp_types)) == -1) {
9765440Sjm199354 			return (VS_ERR_SCF);
9775440Sjm199354 		}
9785440Sjm199354 		break;
9795440Sjm199354 	case VS_PROPID_SE_ENABLE:
9805440Sjm199354 		scf_value_set_boolean(vsc->vscf_val[idx],
9815440Sjm199354 		    (uint8_t)vep->vep_enable);
9825440Sjm199354 		break;
9835440Sjm199354 	case VS_PROPID_SE_HOST:
9845440Sjm199354 		if ((scf_value_set_from_string(vsc->vscf_val[idx],
9855440Sjm199354 		    vpd->vpd_type, vep->vep_host)) == -1) {
9865440Sjm199354 			rc = VS_ERR_SCF;
9875440Sjm199354 		}
9885440Sjm199354 		break;
9895440Sjm199354 	case VS_PROPID_SE_PORT:
9905440Sjm199354 		scf_value_set_integer(vsc->vscf_val[idx], vep->vep_port);
9915440Sjm199354 		break;
9925440Sjm199354 	case VS_PROPID_SE_MAXCONN:
9935440Sjm199354 		scf_value_set_integer(vsc->vscf_val[idx],
9945440Sjm199354 		    vep->vep_maxconn);
9955440Sjm199354 		break;
9965440Sjm199354 	case VS_PROPID_VALUE_AUTH:
9975440Sjm199354 		if ((scf_value_set_astring(vsc->vscf_val[idx],
9985440Sjm199354 		    VS_VALUE_AUTH)) == -1) {
9995440Sjm199354 			return (VS_ERR_SCF);
10005440Sjm199354 		}
10015440Sjm199354 		break;
10025440Sjm199354 	default:
10035440Sjm199354 		break;
10045440Sjm199354 	}
10055440Sjm199354 
10065440Sjm199354 	if ((scf_entry_add_value(vsc->vscf_ent[idx],
10075440Sjm199354 	    vsc->vscf_val[idx])) == -1) {
10085440Sjm199354 		return (VS_ERR_SCF);
10095440Sjm199354 	}
10105440Sjm199354 
10115440Sjm199354 	return (rc);
10125440Sjm199354 }
10135440Sjm199354 
10145440Sjm199354 
10155440Sjm199354 /*
10165440Sjm199354  * vs_scf_ctx_open
10175440Sjm199354  *
10185440Sjm199354  * Opens an SCF context; creates the minumum SCF objects
10195440Sjm199354  * for use in loading/storing from the SMF repository (meaning
10205440Sjm199354  * vscf_property group data).
10215440Sjm199354  *
10225440Sjm199354  * Other SCF objects in the context may be initialized elsewher
10235440Sjm199354  * subsequent to open, but all initialized structures are destroyed
10245440Sjm199354  * in vs_scf_ctx_close().
10255440Sjm199354  */
10265440Sjm199354 static int
10275440Sjm199354 vs_scf_ctx_open(vs_scfctx_t *vsc)
10285440Sjm199354 {
10295440Sjm199354 	(void) memset(vsc, 0, sizeof (vs_scfctx_t));
10305440Sjm199354 
10315440Sjm199354 	if ((vsc->vscf_handle = scf_handle_create(SCF_VERSION)) == NULL)
10325440Sjm199354 		return (VS_ERR_SCF);
10335440Sjm199354 
10345440Sjm199354 	if (scf_handle_bind(vsc->vscf_handle) == -1)
10355440Sjm199354 		return (VS_ERR_SCF);
10365440Sjm199354 
10375440Sjm199354 	if ((vsc->vscf_inst = scf_instance_create(vsc->vscf_handle)) == NULL)
10385440Sjm199354 		return (VS_ERR_SCF);
10395440Sjm199354 
10405440Sjm199354 	if (scf_handle_decode_fmri(vsc->vscf_handle, VS_INSTANCE_FMRI,
10415440Sjm199354 	    NULL, NULL, vsc->vscf_inst, NULL, NULL,
10425440Sjm199354 	    SCF_DECODE_FMRI_EXACT) == -1) {
10435440Sjm199354 		return (VS_ERR_SCF);
10445440Sjm199354 	}
10455440Sjm199354 
10465440Sjm199354 	if ((vsc->vscf_pgroup = scf_pg_create(vsc->vscf_handle)) == NULL)
10475440Sjm199354 		return (VS_ERR_SCF);
10485440Sjm199354 
10495440Sjm199354 	return (VS_ERR_NONE);
10505440Sjm199354 }
10515440Sjm199354 
10525440Sjm199354 
10535440Sjm199354 /*
10545440Sjm199354  * vs_scf_ctx_close
10555440Sjm199354  *
10565440Sjm199354  * Closes an SCF context; destroys all initialized SCF objects.
10575440Sjm199354  */
10585440Sjm199354 static void
10595440Sjm199354 vs_scf_ctx_close(vs_scfctx_t *vsc)
10605440Sjm199354 {
10615440Sjm199354 	int i;
10625440Sjm199354 
10635440Sjm199354 	for (i = 0; i < VS_NUM_PROPIDS; i++) {
10645440Sjm199354 		if (vsc->vscf_val[i])
10655440Sjm199354 			scf_value_destroy(vsc->vscf_val[i]);
10665440Sjm199354 		if (vsc->vscf_ent[i])
10675440Sjm199354 			scf_entry_destroy(vsc->vscf_ent[i]);
10685440Sjm199354 		if (vsc->vscf_prop[i])
10695440Sjm199354 			scf_property_destroy(vsc->vscf_prop[i]);
10705440Sjm199354 	}
10715440Sjm199354 
10725440Sjm199354 	if (vsc->vscf_iter)
10735440Sjm199354 		scf_iter_destroy(vsc->vscf_iter);
10745440Sjm199354 	if (vsc->vscf_tx)
10755440Sjm199354 		scf_transaction_destroy(vsc->vscf_tx);
10765440Sjm199354 	if (vsc->vscf_pgroup)
10775440Sjm199354 		scf_pg_destroy(vsc->vscf_pgroup);
10785440Sjm199354 	if (vsc->vscf_inst)
10795440Sjm199354 		scf_instance_destroy(vsc->vscf_inst);
10805440Sjm199354 	if (vsc->vscf_handle)
10815440Sjm199354 		scf_handle_destroy(vsc->vscf_handle);
10825440Sjm199354 }
10835440Sjm199354 
10845440Sjm199354 
10855440Sjm199354 /*
10865440Sjm199354  * vs_validate
10875440Sjm199354  *
10885440Sjm199354  * Validate property identified in propid.
10895440Sjm199354  *
10905440Sjm199354  * Returns: VS_ERR_NONE
10915440Sjm199354  *          VS_ERR_INVALID_VALUE
10925440Sjm199354  *          VS_ERR_INVALID_PROPERTY
10935440Sjm199354  */
10945440Sjm199354 static int
10955440Sjm199354 vs_validate(const vs_prop_hd_t *prop_hd, uint64_t propid)
10965440Sjm199354 {
10975440Sjm199354 	uint64_t num;
10985440Sjm199354 	const vs_props_t *vp = &prop_hd->vp_gen;
10995440Sjm199354 	const vs_props_se_t *vep = &prop_hd->vp_se;
11005440Sjm199354 
11015440Sjm199354 	switch (propid) {
11025440Sjm199354 	case VS_PROPID_MAXSIZE:
11035440Sjm199354 		if ((vs_strtonum(vp->vp_maxsize, &num) != 0) || (num == 0))
11045440Sjm199354 			return (VS_ERR_INVALID_VALUE);
11055440Sjm199354 		break;
11065440Sjm199354 	case VS_PROPID_MAXSIZE_ACTION:
11075440Sjm199354 		break;
11085440Sjm199354 	case VS_PROPID_TYPES:
11095440Sjm199354 		if (!vs_is_valid_types(vp->vp_types))
11105440Sjm199354 			return (VS_ERR_INVALID_VALUE);
11115440Sjm199354 		break;
11125440Sjm199354 	case VS_PROPID_SE_ENABLE:
11135440Sjm199354 		break;
11145440Sjm199354 	case VS_PROPID_SE_PORT:
11155440Sjm199354 		if (vep->vep_port == 0)
11165440Sjm199354 			return (VS_ERR_INVALID_VALUE);
11175440Sjm199354 		break;
11185440Sjm199354 	case VS_PROPID_SE_HOST:
11195440Sjm199354 		if (!vs_is_valid_host(vep->vep_host))
11205440Sjm199354 			return (VS_ERR_INVALID_VALUE);
11215440Sjm199354 		break;
11225440Sjm199354 	case VS_PROPID_SE_MAXCONN:
11235440Sjm199354 		if (vep->vep_maxconn < VS_VAL_SE_MAXCONN_MIN ||
11245440Sjm199354 		    vep->vep_maxconn > VS_VAL_SE_MAXCONN_MAX)
11255440Sjm199354 			return (VS_ERR_INVALID_VALUE);
11265440Sjm199354 		break;
11275440Sjm199354 	case VS_PROPID_VALUE_AUTH:
11285440Sjm199354 	case VS_PROPID_VLOG:
11295440Sjm199354 		break;
11305440Sjm199354 	default:
11315440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
11325440Sjm199354 	}
11335440Sjm199354 
11345440Sjm199354 	return (VS_ERR_NONE);
11355440Sjm199354 }
11365440Sjm199354 
11375440Sjm199354 
11385440Sjm199354 /*
11395440Sjm199354  * vs_props_validate
11405440Sjm199354  *
11415440Sjm199354  * Validate  properties identified in propids.
11425440Sjm199354  *
11435440Sjm199354  * Returns: VS_ERR_NONE
11445440Sjm199354  *          VS_ERR_INVALID_VALUE
11455440Sjm199354  *          VS_ERR_INVALID_PROPERTY
11465440Sjm199354  */
11475440Sjm199354 int
11485440Sjm199354 vs_props_validate(const vs_props_t *props, uint64_t propids)
11495440Sjm199354 {
11505440Sjm199354 	uint64_t propid;
11515440Sjm199354 	vs_prop_hd_t prop_hd;
11525440Sjm199354 
11535440Sjm199354 	if ((propids & VS_PROPID_GEN_ALL) != propids)
11545440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
11555440Sjm199354 
11565440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
11575440Sjm199354 	prop_hd.vp_gen = *props;
11585440Sjm199354 	prop_hd.vp_type = VS_PTYPE_GEN;
11595440Sjm199354 	prop_hd.vp_ids = propids;
11605440Sjm199354 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
11615440Sjm199354 
11625440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
11635440Sjm199354 		if ((propids & propid) == 0)
11645440Sjm199354 			continue;
11655440Sjm199354 
11665440Sjm199354 		if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
11675440Sjm199354 			return (VS_ERR_INVALID_VALUE);
11685440Sjm199354 	}
11695440Sjm199354 
11705440Sjm199354 	return (VS_ERR_NONE);
11715440Sjm199354 }
11725440Sjm199354 
11735440Sjm199354 
11745440Sjm199354 /*
11755440Sjm199354  * vs_props_se_validate
11765440Sjm199354  *
11775440Sjm199354  * Validate properties identified in propids.
11785440Sjm199354  *
11795440Sjm199354  * Returns: VS_ERR_NONE
11805440Sjm199354  *          VS_ERR_INVALID_VALUE
11815440Sjm199354  *          VS_ERR_INVALID_PROPERTY
11825440Sjm199354  */
11835440Sjm199354 int
11845440Sjm199354 vs_props_se_validate(const vs_props_se_t *se_props, uint64_t propids)
11855440Sjm199354 {
11865440Sjm199354 	uint64_t propid;
11875440Sjm199354 	vs_prop_hd_t prop_hd;
11885440Sjm199354 
11895440Sjm199354 	if ((propids & VS_PROPID_SE_ALL) != propids)
11905440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
11915440Sjm199354 
11925440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
11935440Sjm199354 	prop_hd.vp_se = *se_props;
11945440Sjm199354 	prop_hd.vp_type = VS_PTYPE_SE;
11955440Sjm199354 	prop_hd.vp_ids = propids;
11965440Sjm199354 	prop_hd.vp_all = VS_PROPID_SE_ALL;
11975440Sjm199354 
11985440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
11995440Sjm199354 		if ((propids & propid) == 0)
12005440Sjm199354 			continue;
12015440Sjm199354 
12025440Sjm199354 		if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
12035440Sjm199354 			return (VS_ERR_INVALID_VALUE);
12045440Sjm199354 	}
12055440Sjm199354 
12065440Sjm199354 	return (VS_ERR_NONE);
12075440Sjm199354 }
12085440Sjm199354 
12095440Sjm199354 
12105440Sjm199354 /*
12115440Sjm199354  * vs_is_valid_types
12125440Sjm199354  *
12135440Sjm199354  * Checks that types property is a valid format:
12145440Sjm199354  * - doesn't exceed VS_VAL_TYPES_MAX
12155440Sjm199354  * - doesn't contain VS_VAL_TYPES_INVALID_CHARS
12165440Sjm199354  * - is correctly formatted - passes the parsing tests
12175440Sjm199354  *
12185440Sjm199354  * Returns 1 on success, 0 on failure
12195440Sjm199354  */
12205440Sjm199354 static int
12215440Sjm199354 vs_is_valid_types(const char *types)
12225440Sjm199354 {
12235440Sjm199354 	char buf[VS_VAL_TYPES_LEN];
12245440Sjm199354 	uint32_t len = VS_VAL_TYPES_LEN;
12255440Sjm199354 
12265440Sjm199354 	if (strlen(types) > VS_VAL_TYPES_LEN)
12275440Sjm199354 		return (0);
12285440Sjm199354 
12295440Sjm199354 	if (strpbrk(types, VS_VAL_TYPES_INVALID_CHARS) != NULL)
12305440Sjm199354 		return (0);
12315440Sjm199354 
12325440Sjm199354 	if (vs_parse_types(types, buf, &len) != 0)
12335440Sjm199354 		return (0);
12345440Sjm199354 
12355440Sjm199354 	return (1);
12365440Sjm199354 }
12375440Sjm199354 
12385440Sjm199354 
12395440Sjm199354 /*
12405440Sjm199354  * vs_is_valid_host
12415440Sjm199354  *
12425440Sjm199354  * Returns 1 on success, 0 on failure
12435440Sjm199354  */
12445440Sjm199354 static int
12455440Sjm199354 vs_is_valid_host(const char *host)
12465440Sjm199354 {
12475440Sjm199354 	long naddr;
12485440Sjm199354 	const char *p;
12495440Sjm199354 
12505440Sjm199354 	if (!host || *host == '\0')
12515440Sjm199354 		return (0);
12525440Sjm199354 
12535440Sjm199354 	if ('0' <= host[0] && host[0] <= '9') {
12545440Sjm199354 		/* ip address */
12555440Sjm199354 		if ((inet_pton(AF_INET, host, &naddr)) == 0)
12565440Sjm199354 			return (0);
12575440Sjm199354 		if ((naddr & IN_CLASSA_NET) == 0)
12585440Sjm199354 			return (0);
12595440Sjm199354 		if ((naddr & IN_CLASSC_HOST) == 0)
12605440Sjm199354 			return (0);
12615440Sjm199354 	} else {
12625440Sjm199354 		/* hostname */
12635440Sjm199354 		p = host;
12645440Sjm199354 		while (*p != '\0') {
12655440Sjm199354 			if (!isascii(*p))
12665440Sjm199354 				return (0);
12675440Sjm199354 
12685440Sjm199354 			if (isalnum(*p) ||
12695440Sjm199354 			    (*p == '.') || (*p == '-') || (*p == '_')) {
12705440Sjm199354 				++p;
12715440Sjm199354 			} else {
12725440Sjm199354 				return (0);
12735440Sjm199354 			}
12745440Sjm199354 		}
12755440Sjm199354 	}
12765440Sjm199354 
12775440Sjm199354 	return (1);
12785440Sjm199354 }
12795440Sjm199354 
12805440Sjm199354 
12815440Sjm199354 /*
12825440Sjm199354  * vs_parse_types
12835440Sjm199354  *
12845440Sjm199354  * Replace comma separators with '\0'.
12855440Sjm199354  *
12865440Sjm199354  * Types contains comma separated rules each beginning with +|-
12875440Sjm199354  *   - embedded commas are escaped by backslash
12885440Sjm199354  *   - backslash is escaped by backslash
12895440Sjm199354  *   - a single backslash not followed by comma is illegal
12905440Sjm199354  *
12915440Sjm199354  * On entry to the function len must contain the length of
12925440Sjm199354  * the buffer. On sucecssful exit len will contain the length
12935440Sjm199354  * of the parsed data within the buffer.
12945440Sjm199354  *
12955440Sjm199354  * Returns 0 on success, -1 on failure
12965440Sjm199354  */
12975440Sjm199354 int
12985440Sjm199354 vs_parse_types(const char *types, char *buf, uint32_t *len)
12995440Sjm199354 {
13005440Sjm199354 	char *p = (char *)types;
13015440Sjm199354 	char *b = buf;
13025440Sjm199354 
13035440Sjm199354 	if (strlen(types) > *len)
13045440Sjm199354 		return (-1);
13055440Sjm199354 
13065440Sjm199354 	if (strchr(VS_TYPES_RULES, *p) == NULL)
13075440Sjm199354 		return (-1);
13085440Sjm199354 
13095440Sjm199354 	(void) memset(buf, 0, *len);
13105440Sjm199354 
13115440Sjm199354 	while (*p) {
13125440Sjm199354 		switch (*p) {
13135440Sjm199354 		case VS_TYPES_SEP:
13145440Sjm199354 			if (*(p + 1) &&
13155440Sjm199354 			    (strchr(VS_TYPES_RULES, *(p + 1))) == NULL)
13165440Sjm199354 				return (-1);
13175440Sjm199354 			*b = '\0';
13185440Sjm199354 			break;
13195440Sjm199354 		case VS_TYPES_ESCAPE:
13205440Sjm199354 			++p;
13215440Sjm199354 			if (*p == VS_TYPES_ESCAPE || *p == VS_TYPES_SEP)
13225440Sjm199354 				*b = *p;
13235440Sjm199354 			else
13245440Sjm199354 				return (-1);
13255440Sjm199354 			break;
13265440Sjm199354 		default:
13275440Sjm199354 			*b = *p;
13285440Sjm199354 		}
13295440Sjm199354 		++p;
13305440Sjm199354 		++b;
13315440Sjm199354 	}
13325440Sjm199354 
13335440Sjm199354 	*len = (b - buf) + 1;
13345440Sjm199354 
13355440Sjm199354 	return (0);
13365440Sjm199354 }
13375440Sjm199354 
13385440Sjm199354 
13395440Sjm199354 /*
13405440Sjm199354  * vs_statistics
13415440Sjm199354  */
13425440Sjm199354 int
13435440Sjm199354 vs_statistics(vs_stats_t *stats)
13445440Sjm199354 {
13455440Sjm199354 	int door_fd, rc = VS_ERR_NONE;
13465440Sjm199354 	vs_stats_req_t *req;
1347*6407Sjm199354 	vs_stats_rsp_t *rsp;
13485440Sjm199354 	door_arg_t arg;
13495440Sjm199354 
13505440Sjm199354 	if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
13515440Sjm199354 		return (VS_ERR_SYS);
13525440Sjm199354 
1353*6407Sjm199354 	if ((rsp = calloc(1, sizeof (vs_stats_rsp_t))) == NULL) {
13545440Sjm199354 		free(req);
13555440Sjm199354 		return (VS_ERR_SYS);
13565440Sjm199354 	}
13575440Sjm199354 
13585440Sjm199354 	if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
13595440Sjm199354 		free(req);
1360*6407Sjm199354 		free(rsp);
13615440Sjm199354 		return (VS_ERR_DAEMON_COMM);
13625440Sjm199354 	}
13635440Sjm199354 
1364*6407Sjm199354 	req->vsr_magic = VS_STATS_DOOR_MAGIC;
1365*6407Sjm199354 	req->vsr_id = VS_STATS_GET;
13665440Sjm199354 
13675440Sjm199354 	arg.data_ptr = (char *)req;
13685440Sjm199354 	arg.data_size = sizeof (vs_stats_req_t);
13695440Sjm199354 	arg.desc_ptr = NULL;
13705440Sjm199354 	arg.desc_num = 0;
1371*6407Sjm199354 	arg.rbuf = (char *)rsp;
1372*6407Sjm199354 	arg.rsize = sizeof (vs_stats_rsp_t);
13735440Sjm199354 
1374*6407Sjm199354 	if ((door_call(door_fd, &arg) < 0) ||
1375*6407Sjm199354 	    (rsp->vsr_magic != VS_STATS_DOOR_MAGIC)) {
13765440Sjm199354 		rc = VS_ERR_DAEMON_COMM;
1377*6407Sjm199354 	} else {
1378*6407Sjm199354 		*stats = rsp->vsr_stats;
1379*6407Sjm199354 	}
13805440Sjm199354 
13815440Sjm199354 	(void) close(door_fd);
13825440Sjm199354 
13835440Sjm199354 	free(req);
1384*6407Sjm199354 	free(rsp);
13855440Sjm199354 	return (rc);
13865440Sjm199354 }
13875440Sjm199354 
13885440Sjm199354 
13895440Sjm199354 /*
13905440Sjm199354  * vs_statistics_reset
13915440Sjm199354  */
13925440Sjm199354 int
13935440Sjm199354 vs_statistics_reset()
13945440Sjm199354 {
13955440Sjm199354 	int door_fd, rc;
13965440Sjm199354 	vs_stats_req_t *req;
13975440Sjm199354 	door_arg_t arg;
13985440Sjm199354 
13995440Sjm199354 	/* ensure that caller has authorization to reset stats */
14005440Sjm199354 	if ((rc = vs_checkauth(VS_VALUE_AUTH)) != VS_ERR_NONE)
14015440Sjm199354 		return (rc);
14025440Sjm199354 
14035440Sjm199354 	if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
14045440Sjm199354 		return (VS_ERR_SYS);
14055440Sjm199354 
14065440Sjm199354 	if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
14075440Sjm199354 		free(req);
14085440Sjm199354 		return (VS_ERR_DAEMON_COMM);
14095440Sjm199354 	}
14105440Sjm199354 
1411*6407Sjm199354 	req->vsr_magic = VS_STATS_DOOR_MAGIC;
1412*6407Sjm199354 	req->vsr_id = VS_STATS_RESET;
14135440Sjm199354 
14145440Sjm199354 	arg.data_ptr = (char *)req;
14155440Sjm199354 	arg.data_size = sizeof (vs_stats_req_t);
14165440Sjm199354 	arg.desc_ptr = NULL;
14175440Sjm199354 	arg.desc_num = 0;
14185440Sjm199354 	arg.rbuf = NULL;
14195440Sjm199354 	arg.rsize = 0;
14205440Sjm199354 
14215440Sjm199354 	if (door_call(door_fd, &arg) < 0)
14225440Sjm199354 		rc = VS_ERR_DAEMON_COMM;
14235440Sjm199354 	else
14245440Sjm199354 		rc = VS_ERR_NONE;
14255440Sjm199354 
14265440Sjm199354 	(void) close(door_fd);
14275440Sjm199354 	free(req);
14285440Sjm199354 	return (rc);
14295440Sjm199354 }
14305440Sjm199354 
14315440Sjm199354 
14325440Sjm199354 /*
14335440Sjm199354  * vs_checkauth
14345440Sjm199354  */
14355440Sjm199354 static int
14365440Sjm199354 vs_checkauth(char *auth)
14375440Sjm199354 {
14385440Sjm199354 	struct passwd *pw;
14395440Sjm199354 	uid_t uid;
14405440Sjm199354 
14415440Sjm199354 	uid = getuid();
14425440Sjm199354 
14435440Sjm199354 	if ((pw = getpwuid(uid)) == NULL)
14445440Sjm199354 		return (VS_ERR_SYS);
14455440Sjm199354 
14465440Sjm199354 	if (chkauthattr(auth, pw->pw_name) != 1) {
14475440Sjm199354 		return (VS_ERR_AUTH);
14485440Sjm199354 	}
14495440Sjm199354 
14505440Sjm199354 	return (VS_ERR_NONE);
14515440Sjm199354 }
14525440Sjm199354 
14535440Sjm199354 
14545440Sjm199354 /*
14555440Sjm199354  * vs_props_get_engines
1456*6407Sjm199354  *
14575440Sjm199354  * On input, count specifies the maximum number of engine ids to
14585440Sjm199354  * return. engids must be an array with count entries.
14595440Sjm199354  * On return, count specifies the number of engine ids being
14605440Sjm199354  * returned in engids.
1461*6407Sjm199354  *
1462*6407Sjm199354  * Caller is responsible for free'ing the engids allocated herein.
14635440Sjm199354  */
14645440Sjm199354 static int
1465*6407Sjm199354 vs_props_get_engines(char *engids[], int *count)
14665440Sjm199354 {
1467*6407Sjm199354 	int i, prefix_len;
1468*6407Sjm199354 	char pgname[VS_PGNAME_ENGINE_LEN];
14695440Sjm199354 	vs_scfctx_t vsc;
14705440Sjm199354 
14715440Sjm199354 
14725440Sjm199354 	if (((vs_scf_ctx_open(&vsc)) != 0) ||
14735440Sjm199354 	    ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) ||
14745440Sjm199354 	    (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst,
14755440Sjm199354 	    SCF_GROUP_APPLICATION) != 0)) {
14765440Sjm199354 		vs_scf_ctx_close(&vsc);
14775440Sjm199354 		return (VS_ERR_SCF);
14785440Sjm199354 	}
14795440Sjm199354 
1480*6407Sjm199354 	for (i = 0; i < *count; i++)
1481*6407Sjm199354 		engids[i] = NULL;
1482*6407Sjm199354 
1483*6407Sjm199354 	i = 0;
1484*6407Sjm199354 	prefix_len = sizeof (VS_PGNAME_ENGINE_PREFIX) - 1;
1485*6407Sjm199354 
14865440Sjm199354 	while ((i < VS_SE_MAX) &&
14875440Sjm199354 	    (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)) {
1488*6407Sjm199354 		if (scf_pg_get_name(vsc.vscf_pgroup, pgname,
1489*6407Sjm199354 		    VS_PGNAME_ENGINE_LEN) < 0) {
14905440Sjm199354 			vs_scf_ctx_close(&vsc);
14915440Sjm199354 			return (VS_ERR_SCF);
14925440Sjm199354 		}
14935440Sjm199354 
1494*6407Sjm199354 		if (strncmp(pgname, VS_PGNAME_ENGINE_PREFIX, prefix_len) == 0) {
1495*6407Sjm199354 			if ((engids[i] = strdup(pgname + prefix_len)) != NULL) {
1496*6407Sjm199354 				if (++i == *count)
1497*6407Sjm199354 					break;
1498*6407Sjm199354 			}
1499*6407Sjm199354 		}
15005440Sjm199354 	}
15015440Sjm199354 	vs_scf_ctx_close(&vsc);
15025440Sjm199354 
15035440Sjm199354 	*count = i;
15045440Sjm199354 	return (VS_ERR_NONE);
15055440Sjm199354 }
15065440Sjm199354 
15075440Sjm199354 
15085440Sjm199354 /*
15095440Sjm199354  * vs_scf_pg_count
15105440Sjm199354  */
15115440Sjm199354 static int
15125440Sjm199354 vs_scf_pg_count(void)
15135440Sjm199354 {
15145440Sjm199354 	int count = 0;
15155440Sjm199354 	vs_scfctx_t vsc;
15165440Sjm199354 
15175440Sjm199354 	if ((vs_scf_ctx_open(&vsc) != 0) ||
15185440Sjm199354 	    ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) ||
15195440Sjm199354 	    (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst,
15205440Sjm199354 	    SCF_GROUP_APPLICATION) != 0)) {
15215440Sjm199354 		vs_scf_ctx_close(&vsc);
15225440Sjm199354 		return (-1);
15235440Sjm199354 	}
15245440Sjm199354 
15255440Sjm199354 	while (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)
15265440Sjm199354 		++count;
15275440Sjm199354 
15285440Sjm199354 	vs_scf_ctx_close(&vsc);
15295440Sjm199354 
15305440Sjm199354 	return (count);
15315440Sjm199354 }
15325440Sjm199354 
15335440Sjm199354 
15345440Sjm199354 /*
1535*6407Sjm199354  * vs_engid_to_pgname
1536*6407Sjm199354  *
1537*6407Sjm199354  * To convert an engine id (engid) to a property group name (pgname),
1538*6407Sjm199354  * the engine id is prefixed with VS_PGNAME_ENGINE_PREFIX.
1539*6407Sjm199354  */
1540*6407Sjm199354 static void
1541*6407Sjm199354 vs_engid_to_pgname(const char *engid, char pgname[VS_PGNAME_ENGINE_LEN])
1542*6407Sjm199354 {
1543*6407Sjm199354 	(void) snprintf(pgname, VS_PGNAME_ENGINE_LEN, "%s%s",
1544*6407Sjm199354 	    VS_PGNAME_ENGINE_PREFIX, engid);
1545*6407Sjm199354 }
1546*6407Sjm199354 
1547*6407Sjm199354 
1548*6407Sjm199354 /*
15495440Sjm199354  *  vs_strtonum
15505440Sjm199354  *
15515440Sjm199354  *  Converts a size string in the format into an integer.
15525440Sjm199354  *
15535440Sjm199354  *  A size string is a numeric value followed by an optional unit
15545440Sjm199354  *  specifier which is used as a multiplier to calculate a raw
15555440Sjm199354  *  number.
15565440Sjm199354  *  The size string format is:  N[.N][KMGTP][B]
15575440Sjm199354  *
15585440Sjm199354  *  The numeric value can contain a decimal portion. Unit specifiers
15595440Sjm199354  *  are either a one-character or two-character string; i.e. "K" or
15605440Sjm199354  *  "KB" for kilobytes. Unit specifiers must follow the numeric portion
15615440Sjm199354  *  immediately, and are not case-sensitive.
15625440Sjm199354  *
15635440Sjm199354  *  If either "B" is specified, or there is no unit specifier portion
15645440Sjm199354  *  in the string, the numeric value is calculated with no multiplier
15655440Sjm199354  *  (assumes a basic unit of "bytes").
15665440Sjm199354  *
15675440Sjm199354  *  Returns:
15685440Sjm199354  *	-1:	Failure; errno set to specify the error.
15695440Sjm199354  *	 0:	Success.
15705440Sjm199354  */
15715440Sjm199354 int
15725440Sjm199354 vs_strtonum(const char *value, uint64_t *num)
15735440Sjm199354 {
15745440Sjm199354 	char *end;
15755440Sjm199354 	int shift;
15765440Sjm199354 	double fval;
15775440Sjm199354 
15785440Sjm199354 	*num = 0;
15795440Sjm199354 
15805440Sjm199354 	/* Check to see if this looks like a number.  */
15815440Sjm199354 	if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
15825440Sjm199354 		errno = EINVAL;
15835440Sjm199354 		return (-1);
15845440Sjm199354 	}
15855440Sjm199354 
15865440Sjm199354 	/* Rely on stroll() to process the numeric portion.  */
15875440Sjm199354 	errno = 0;
15885440Sjm199354 	*num = strtoll(value, &end, 10);
15895440Sjm199354 
15905440Sjm199354 	/*
15915440Sjm199354 	 * Check for ERANGE, which indicates that the value is too large to
15925440Sjm199354 	 * fit in a 64-bit value.
15935440Sjm199354 	 */
15945440Sjm199354 	if (errno != 0)
15955440Sjm199354 		return (-1);
15965440Sjm199354 
15975440Sjm199354 	/*
15985440Sjm199354 	 * If we have a decimal value, then do the computation with floating
15995440Sjm199354 	 * point arithmetic.  Otherwise, use standard arithmetic.
16005440Sjm199354 	 */
16015440Sjm199354 	if (*end == '.') {
16025440Sjm199354 		fval = strtod(value, &end);
16035440Sjm199354 
16045440Sjm199354 		if ((shift = vs_strtoshift(end)) == -1)
16055440Sjm199354 			return (-1); /* errno set */
16065440Sjm199354 
16075440Sjm199354 		fval *= pow(2, shift);
16085440Sjm199354 		if (fval > UINT64_MAX) {
16095440Sjm199354 			errno = ERANGE;
16105440Sjm199354 			return (-1);
16115440Sjm199354 		}
16125440Sjm199354 
16135440Sjm199354 		*num = (uint64_t)fval;
16145440Sjm199354 	} else {
16155440Sjm199354 		if ((shift = vs_strtoshift(end)) == -1)
16165440Sjm199354 			return (-1); /* errno set */
16175440Sjm199354 
16185440Sjm199354 		/* Check for overflow */
16195440Sjm199354 		if (shift >= 64 || (*num << shift) >> shift != *num) {
16205440Sjm199354 			errno = ERANGE;
16215440Sjm199354 			return (-1);
16225440Sjm199354 		}
16235440Sjm199354 
16245440Sjm199354 		*num <<= shift;
16255440Sjm199354 	}
16265440Sjm199354 
16275440Sjm199354 	return (0);
16285440Sjm199354 }
16295440Sjm199354 
16305440Sjm199354 
16315440Sjm199354 /*
16325440Sjm199354  *  vs_strtoshift
16335440Sjm199354  *
16345440Sjm199354  *  Converts a unit specifier string into a number of bits that
16355440Sjm199354  *  a numeric value must be shifted.
16365440Sjm199354  *
16375440Sjm199354  *  Returns:
16385440Sjm199354  *	-1:	Failure; errno set to specify the error.
16395440Sjm199354  *	>-1:	Success; the shift count.
16405440Sjm199354  *
16415440Sjm199354  */
16425440Sjm199354 static int
16435440Sjm199354 vs_strtoshift(const char *buf)
16445440Sjm199354 {
16455440Sjm199354 	const char *ends = "BKMGTPEZ";
16465440Sjm199354 	int i;
16475440Sjm199354 
16485440Sjm199354 	if (buf[0] == '\0')
16495440Sjm199354 		return (0);
16505440Sjm199354 	for (i = 0; i < strlen(ends); i++) {
16515440Sjm199354 		if (toupper(buf[0]) == ends[i])
16525440Sjm199354 			break;
16535440Sjm199354 	}
16545440Sjm199354 	if (i == strlen(ends)) {
16555440Sjm199354 		errno = EINVAL;
16565440Sjm199354 		return (-1);
16575440Sjm199354 	}
16585440Sjm199354 
16595440Sjm199354 	/* Allow trailing 'b' characters except in the case of 'BB'. */
16605440Sjm199354 	if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' &&
16615440Sjm199354 	    toupper(buf[0]) != 'B')) {
16625440Sjm199354 		return (10 * i);
16635440Sjm199354 	}
16645440Sjm199354 
16655440Sjm199354 	errno = EINVAL;
16665440Sjm199354 	return (-1);
16675440Sjm199354 }
1668