xref: /onnv-gate/usr/src/lib/libvscan/common/libvscan.c (revision 10050:09746c0f5a44)
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*10050SJoyce.McIntosh@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235440Sjm199354  * Use is subject to license terms.
245440Sjm199354  */
255440Sjm199354 
265440Sjm199354 #include <string.h>
275440Sjm199354 #include <stdio.h>
285440Sjm199354 #include <stdlib.h>
295440Sjm199354 #include <unistd.h>
305440Sjm199354 #include <ctype.h>
315440Sjm199354 #include <math.h>
325440Sjm199354 #include <limits.h>
335440Sjm199354 #include <libscf.h>
345440Sjm199354 #include <errno.h>
355440Sjm199354 #include <fcntl.h>
365440Sjm199354 #include <door.h>
375440Sjm199354 #include <pwd.h>
385440Sjm199354 #include <auth_attr.h>
395440Sjm199354 #include <secdb.h>
405440Sjm199354 #include <sys/socket.h>
415440Sjm199354 #include <arpa/inet.h>
425440Sjm199354 #include <libintl.h>
435440Sjm199354 #include <libvscan.h>
445440Sjm199354 
457943Samw@Sun.COM #define	VS_DOOR_CALL_RETRIES	3
467943Samw@Sun.COM 
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"
516407Sjm199354 #define	VS_PGNAME_ENGINE_PREFIX		"vs_engine_"
526407Sjm199354 #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;
138*10050SJoyce.McIntosh@Sun.COM static const uint16_t vs_dflt_maxconn = 8;
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 *);
1696407Sjm199354 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 *);
1787943Samw@Sun.COM static int vs_door_call(int, door_arg_t *);
1795440Sjm199354 
1806407Sjm199354 static int vs_props_get_engines(char *[], int *);
1816407Sjm199354 static void vs_engid_to_pgname(const char *, char [VS_PGNAME_ENGINE_LEN]);
1825440Sjm199354 static int vs_scf_pg_count(void);
1835440Sjm199354 static int vs_strtoshift(const char *);
1845440Sjm199354 
1855440Sjm199354 
1865440Sjm199354 /*
1875440Sjm199354  * vs_props_get_all
1885440Sjm199354  *
1895440Sjm199354  * Retrieves the general service properties and all properties
1905440Sjm199354  * for all scan engines from the repository.
1915440Sjm199354  *
1925440Sjm199354  * If invalid property values are found, the values are corrected to
1935440Sjm199354  * the default value.
1945440Sjm199354  *
1955440Sjm199354  * Return codes:
1965440Sjm199354  *	VS_ERR_VS_ERR_NONE
1975440Sjm199354  *	VS_ERR_SCF
1985440Sjm199354  *	VS_ERR_SYS
1995440Sjm199354  */
2005440Sjm199354 int
vs_props_get_all(vs_props_all_t * va)2015440Sjm199354 vs_props_get_all(vs_props_all_t *va)
2025440Sjm199354 {
2035440Sjm199354 	int i, rc, n;
2046407Sjm199354 	char *engids[VS_SE_MAX];
2055440Sjm199354 
2065440Sjm199354 	(void) memset(va, 0, sizeof (vs_props_all_t));
2075440Sjm199354 	if ((rc = vs_props_get(&va->va_props, VS_PROPID_GEN_ALL))
2085440Sjm199354 	    != VS_ERR_NONE)
2095440Sjm199354 		return (rc);
2105440Sjm199354 
2115440Sjm199354 	n = VS_SE_MAX;
2125440Sjm199354 	if ((rc = vs_props_get_engines(engids, &n)) != VS_ERR_NONE)
2135440Sjm199354 		return (rc);
2145440Sjm199354 
2155440Sjm199354 	for (i = 0; i < n; i++) {
2166407Sjm199354 		if ((rc = vs_props_se_get(engids[i],
2176407Sjm199354 		    &va->va_se[i], VS_PROPID_SE_ALL)) != VS_ERR_NONE)
2186407Sjm199354 			break;
2195440Sjm199354 	}
2205440Sjm199354 
2216407Sjm199354 	/* free engids allocated in vs_props_get_engines */
2226407Sjm199354 	for (i = 0; i < VS_SE_MAX; i++)	{
2236407Sjm199354 		if (engids[i] != NULL)
2246407Sjm199354 			free(engids[i]);
2256407Sjm199354 	}
2266407Sjm199354 
2276407Sjm199354 	return (rc);
2285440Sjm199354 }
2295440Sjm199354 
2305440Sjm199354 
2315440Sjm199354 /*
2325440Sjm199354  * vs_props_get
2335440Sjm199354  *
2345440Sjm199354  * Retrieves values for the specified general service properties from
2355440Sjm199354  * the repository.
2365440Sjm199354  *
2375440Sjm199354  * If invalid property values are found, the values are corrected to
2385440Sjm199354  * the default value.
2395440Sjm199354  *
2405440Sjm199354  * Return codes:
2415440Sjm199354  *	VS_ERR_VS_ERR_NONE
2425440Sjm199354  *	VS_ERR_INVALID_PROPERTY
2435440Sjm199354  *	VS_ERR_SCF
2445440Sjm199354  *	VS_ERR_SYS
2455440Sjm199354  */
2465440Sjm199354 int
vs_props_get(vs_props_t * vp,uint64_t propids)2475440Sjm199354 vs_props_get(vs_props_t *vp, uint64_t propids)
2485440Sjm199354 {
2495440Sjm199354 	int  rc;
2505440Sjm199354 	vs_prop_hd_t prop_hd;
2515440Sjm199354 
2525440Sjm199354 	if ((propids & VS_PROPID_GEN_ALL) != propids)
2535440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
2545440Sjm199354 
2555440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
2565440Sjm199354 	prop_hd.vp_type = VS_PTYPE_GEN;
2575440Sjm199354 	prop_hd.vp_ids = propids;
2585440Sjm199354 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
2595440Sjm199354 
2605440Sjm199354 	rc = vs_scf_values_get(VS_PGNAME_GENERAL, &prop_hd);
2615440Sjm199354 
2625440Sjm199354 	*vp = prop_hd.vp_gen;
2635440Sjm199354 	return (rc);
2645440Sjm199354 }
2655440Sjm199354 
2665440Sjm199354 
2675440Sjm199354 /*
2685440Sjm199354  * vs_props_set
2695440Sjm199354  *
2705440Sjm199354  * Changes values for the specified general service properties
2715440Sjm199354  * in the repository.
2725440Sjm199354  *
2735440Sjm199354  * Return codes:
2745440Sjm199354  *	VS_ERR_VS_ERR_NONE
2755440Sjm199354  *	VS_ERR_INVALID_PROPERTY
2765440Sjm199354  *	VS_ERR_INVALID_VALUE
2775440Sjm199354  *	VS_ERR_SCF
2785440Sjm199354  *	VS_ERR_SYS
2795440Sjm199354  */
2805440Sjm199354 int
vs_props_set(const vs_props_t * vp,uint64_t propids)2815440Sjm199354 vs_props_set(const vs_props_t *vp, uint64_t propids)
2825440Sjm199354 {
2835440Sjm199354 	vs_prop_hd_t prop_hd;
2845440Sjm199354 
2855440Sjm199354 	if ((propids & VS_PROPID_GEN_ALL) != propids)
2865440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
2875440Sjm199354 
2885440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
2895440Sjm199354 	prop_hd.vp_type = VS_PTYPE_GEN;
2905440Sjm199354 	prop_hd.vp_ids = propids;
2915440Sjm199354 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
2925440Sjm199354 	prop_hd.vp_gen = *vp;
2935440Sjm199354 	return (vs_scf_values_set(VS_PGNAME_GENERAL, &prop_hd));
2945440Sjm199354 }
2955440Sjm199354 
2965440Sjm199354 
2975440Sjm199354 /*
2985440Sjm199354  * vs_props_se_get
2995440Sjm199354  *
3005440Sjm199354  * Retrieves values for the specified scan engine properties from the
3015440Sjm199354  * repository.
3025440Sjm199354  *
3035440Sjm199354  * If the enable property is set (true), the host property is
3045440Sjm199354  * checked for validity. If it is not valid, the requested values
3055440Sjm199354  * are returned with the enable propery set to off (false)
3065440Sjm199354  *
3075440Sjm199354  * Return codes:
3085440Sjm199354  *	VS_ERR_VS_ERR_NONE
3095440Sjm199354  *	VS_ERR_INVALID_PROPERTY
3105440Sjm199354  *	VS_ERR_SCF
3115440Sjm199354  *	VS_ERR_SYS
3125440Sjm199354  */
3135440Sjm199354 int
vs_props_se_get(char * engid,vs_props_se_t * sep,uint64_t propids)3145440Sjm199354 vs_props_se_get(char *engid, vs_props_se_t *sep, uint64_t propids)
3155440Sjm199354 {
3165440Sjm199354 	int rc;
3176407Sjm199354 	char pgname[VS_PGNAME_ENGINE_LEN];
3185440Sjm199354 	vs_prop_hd_t prop_hd;
3195440Sjm199354 
3205440Sjm199354 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
3215440Sjm199354 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
3225440Sjm199354 		return (VS_ERR_INVALID_SE);
3235440Sjm199354 
3245440Sjm199354 	if ((propids & VS_PROPID_SE_ALL) != propids)
3255440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
3265440Sjm199354 
3275440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
3285440Sjm199354 	prop_hd.vp_type = VS_PTYPE_SE;
3295440Sjm199354 	prop_hd.vp_ids = propids;
3305440Sjm199354 	prop_hd.vp_all = VS_PROPID_SE_ALL;
3315440Sjm199354 	(void) strlcpy(prop_hd.vp_se.vep_engid, engid, VS_SE_NAME_LEN);
3325440Sjm199354 
3335440Sjm199354 	/* If getting enable, get the host property too */
3345440Sjm199354 	if ((propids & VS_PROPID_SE_ENABLE))
3355440Sjm199354 		prop_hd.vp_ids |= VS_PROPID_SE_HOST;
3365440Sjm199354 
3375440Sjm199354 	/* Load values from the repository */
3386407Sjm199354 	vs_engid_to_pgname(engid, pgname);
3396407Sjm199354 	rc = vs_scf_values_get(pgname, &prop_hd);
3405440Sjm199354 	if (rc != VS_ERR_NONE)
3415440Sjm199354 		return (rc);
3425440Sjm199354 
3435440Sjm199354 	/*
3445440Sjm199354 	 *  If the host is invalid and the enable property is on,
3455440Sjm199354 	 *  return enable property as off
3465440Sjm199354 	 */
3475440Sjm199354 	if ((prop_hd.vp_ids & VS_PROPID_SE_HOST) &&
3485440Sjm199354 	    (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)) {
3495440Sjm199354 		prop_hd.vp_se.vep_enable = B_FALSE;
3505440Sjm199354 	}
3515440Sjm199354 
3525440Sjm199354 	*sep = prop_hd.vp_se;
3535440Sjm199354 	return (rc);
3545440Sjm199354 }
3555440Sjm199354 
3565440Sjm199354 
3575440Sjm199354 
3585440Sjm199354 /*
3595440Sjm199354  * vs_props_se_set
3605440Sjm199354  *
3615440Sjm199354  * Changes the values for the specified scan engine properties in the
3625440Sjm199354  * repository.
3635440Sjm199354  *
3645440Sjm199354  * If the enable property is being changed to true in this operation,
3655440Sjm199354  * a host property must also be specified, or already exist in the
3665440Sjm199354  * repository.
3675440Sjm199354  *
3685440Sjm199354  * Return codes:
3695440Sjm199354  *	VS_ERR_NONE
3705440Sjm199354  *	VS_ERR_INVALID_PROPERTY
3715440Sjm199354  *	VS_ERR_INVALID_VALUE
3725440Sjm199354  *	VS_ERR_SCF
3735440Sjm199354  *	VS_ERR_SYS
3745440Sjm199354  */
3755440Sjm199354 int
vs_props_se_set(char * engid,const vs_props_se_t * sep,uint64_t propids)3765440Sjm199354 vs_props_se_set(char *engid, const vs_props_se_t *sep, uint64_t propids)
3775440Sjm199354 {
3785440Sjm199354 	int rc;
3796407Sjm199354 	char pgname[VS_PGNAME_ENGINE_LEN];
3805440Sjm199354 	vs_prop_hd_t prop_hd;
3815440Sjm199354 
3825440Sjm199354 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
3835440Sjm199354 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
3845440Sjm199354 		return (VS_ERR_INVALID_SE);
3855440Sjm199354 
3865440Sjm199354 	if ((propids & VS_PROPID_SE_ALL) != propids)
3875440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
3885440Sjm199354 
3895440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
3905440Sjm199354 	prop_hd.vp_type = VS_PTYPE_SE;
3915440Sjm199354 	prop_hd.vp_all = VS_PROPID_SE_ALL;
3925440Sjm199354 
3936407Sjm199354 	vs_engid_to_pgname(engid, pgname);
3946407Sjm199354 
3955440Sjm199354 	/*
3965440Sjm199354 	 * if enabling a scan engine, ensure that a valid host
3975440Sjm199354 	 * is also being set, or already exists in the repository
3985440Sjm199354 	 */
3995440Sjm199354 	if ((propids & VS_PROPID_SE_ENABLE) && (sep->vep_enable == B_TRUE) &&
4005440Sjm199354 	    !(propids & VS_PROPID_SE_HOST)) {
4015440Sjm199354 
4025440Sjm199354 		prop_hd.vp_ids = VS_PROPID_SE_HOST;
4036407Sjm199354 		if ((rc = vs_scf_values_get(pgname, &prop_hd)) != VS_ERR_NONE)
4045440Sjm199354 			return (rc);
4055440Sjm199354 
4065440Sjm199354 		if (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)
4075440Sjm199354 			return (VS_ERR_INVALID_HOST);
4085440Sjm199354 	}
4095440Sjm199354 
4105440Sjm199354 	prop_hd.vp_ids = propids;
4115440Sjm199354 	prop_hd.vp_se = *sep;
4125440Sjm199354 
4136407Sjm199354 	return (vs_scf_values_set(pgname, &prop_hd));
4145440Sjm199354 }
4155440Sjm199354 
4165440Sjm199354 
4175440Sjm199354 /*
4185440Sjm199354  * vs_props_se_create
4195440Sjm199354  */
4205440Sjm199354 int
vs_props_se_create(char * engid,const vs_props_se_t * sep,uint64_t propids)4215440Sjm199354 vs_props_se_create(char *engid, const vs_props_se_t *sep, uint64_t propids)
4225440Sjm199354 {
4235440Sjm199354 	int n;
4246407Sjm199354 	char pgname[VS_PGNAME_ENGINE_LEN];
4255440Sjm199354 	vs_prop_hd_t prop_hd;
4265440Sjm199354 
4275440Sjm199354 	if ((propids & VS_PROPID_SE_ALL) != propids)
4285440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
4295440Sjm199354 
4305440Sjm199354 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
4315440Sjm199354 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
4325440Sjm199354 		return (VS_ERR_INVALID_SE);
4335440Sjm199354 
4345440Sjm199354 	if ((n = vs_scf_pg_count()) == -1)
4355440Sjm199354 		return (VS_ERR_SCF);
4365440Sjm199354 
4375440Sjm199354 	if (n == VS_SE_MAX)
4385440Sjm199354 		return (VS_ERR_MAX_SE);
4395440Sjm199354 
4406407Sjm199354 	vs_engid_to_pgname(engid, pgname);
4416407Sjm199354 
4425440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
4435440Sjm199354 	prop_hd.vp_type = VS_PTYPE_SE;
4445440Sjm199354 	prop_hd.vp_all = VS_PROPID_SE_ALL;
4455440Sjm199354 	prop_hd.vp_ids = propids | VS_PROPID_VALUE_AUTH;
4465440Sjm199354 	prop_hd.vp_se = *sep;
4475440Sjm199354 
4486407Sjm199354 	/* if hostname not specified, default it to engid */
4496407Sjm199354 	if ((propids & VS_PROPID_SE_HOST) == 0) {
4506407Sjm199354 		(void) strlcpy(prop_hd.vp_se.vep_host, engid, MAXHOSTNAMELEN);
4516407Sjm199354 		prop_hd.vp_ids |= VS_PROPID_SE_HOST;
4526407Sjm199354 	}
4535440Sjm199354 
4546407Sjm199354 	return (vs_scf_pg_create(pgname, &prop_hd));
4555440Sjm199354 }
4565440Sjm199354 
4575440Sjm199354 
4585440Sjm199354 /*
4595440Sjm199354  * vs_props_se_delete
4605440Sjm199354  */
4615440Sjm199354 int
vs_props_se_delete(const char * engid)4625440Sjm199354 vs_props_se_delete(const char *engid)
4635440Sjm199354 {
4646407Sjm199354 	char pgname[VS_PGNAME_ENGINE_LEN];
4655440Sjm199354 
4665440Sjm199354 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
4675440Sjm199354 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
4685440Sjm199354 		return (VS_ERR_INVALID_SE);
4695440Sjm199354 
4706407Sjm199354 	vs_engid_to_pgname(engid, pgname);
4715440Sjm199354 
4726407Sjm199354 	return (vs_scf_pg_delete(pgname));
4735440Sjm199354 }
4745440Sjm199354 
4755440Sjm199354 
4765440Sjm199354 /*
4775440Sjm199354  * vs_strerror
4785440Sjm199354  */
4795440Sjm199354 const char *
vs_strerror(int error)4805440Sjm199354 vs_strerror(int error)
4815440Sjm199354 {
4825440Sjm199354 	switch (error) {
4835440Sjm199354 	case VS_ERR_NONE:
4845440Sjm199354 		return (gettext("no error"));
4855440Sjm199354 	case VS_ERR_INVALID_PROPERTY:
4865440Sjm199354 		return (gettext("invalid property id"));
4875440Sjm199354 	case VS_ERR_INVALID_VALUE:
4885440Sjm199354 		return (gettext("invalid property value"));
4895440Sjm199354 	case VS_ERR_INVALID_HOST:
4905440Sjm199354 		return (gettext("invalid host"));
4915440Sjm199354 	case VS_ERR_INVALID_SE:
4925440Sjm199354 		return (gettext("invalid scan engine"));
4935440Sjm199354 	case VS_ERR_MAX_SE:
4945440Sjm199354 		return (gettext("max scan engines exceeded"));
4955440Sjm199354 	case VS_ERR_AUTH:
4965440Sjm199354 		return (gettext("insufficient privileges for action"));
4975440Sjm199354 	case VS_ERR_DAEMON_COMM:
4985440Sjm199354 		return (gettext("unable to contact vscand"));
4995440Sjm199354 	case VS_ERR_SCF:
5005440Sjm199354 		return (scf_strerror(scf_error()));
5015440Sjm199354 	case VS_ERR_SYS:
5025440Sjm199354 		return (strerror(errno));
5035440Sjm199354 	default:
5045440Sjm199354 		return (gettext("unknown error"));
5055440Sjm199354 	}
5065440Sjm199354 }
5075440Sjm199354 
5085440Sjm199354 
5095440Sjm199354 /*
5105440Sjm199354  * vs_get_propdef
5115440Sjm199354  *
5125440Sjm199354  * Finds and returns a property definition by property id.
5135440Sjm199354  */
5145440Sjm199354 static const vs_propdef_t *
vs_get_propdef(uint64_t propid)5155440Sjm199354 vs_get_propdef(uint64_t propid)
5165440Sjm199354 {
5175440Sjm199354 	int i;
5185440Sjm199354 
5195440Sjm199354 	for (i = 0; i < vs_npropdefs; i++) {
5205440Sjm199354 		if (propid == vs_propdefs[i].vpd_id)
5215440Sjm199354 			return (&vs_propdefs[i]);
5225440Sjm199354 	}
5235440Sjm199354 
5245440Sjm199354 	return (NULL);
5255440Sjm199354 }
5265440Sjm199354 
5275440Sjm199354 
5285440Sjm199354 /*
5295440Sjm199354  * vs_default_value
5305440Sjm199354  *
5315440Sjm199354  * Sets a property value that contains invalid data to its default value.
5325440Sjm199354  *
5335440Sjm199354  * Note that this function does not alter any values in the repository
5345440Sjm199354  * This is only to enable the caller to get valid data.
5355440Sjm199354  */
5365440Sjm199354 static void
vs_default_value(vs_prop_hd_t * prop_hd,const uint64_t propid)5375440Sjm199354 vs_default_value(vs_prop_hd_t *prop_hd, const uint64_t propid)
5385440Sjm199354 {
5395440Sjm199354 	vs_props_t *vp = &prop_hd->vp_gen;
5405440Sjm199354 	vs_props_se_t *vep = &prop_hd->vp_se;
5415440Sjm199354 
5425440Sjm199354 	switch (propid) {
5435440Sjm199354 	case VS_PROPID_MAXSIZE:
5445440Sjm199354 		(void) strlcpy(vp->vp_maxsize, vs_dflt_maxsize,
5455440Sjm199354 		    sizeof (vp->vp_maxsize));
5465440Sjm199354 		break;
5475440Sjm199354 	case VS_PROPID_MAXSIZE_ACTION:
5485440Sjm199354 		vp->vp_maxsize_action = vs_dflt_allow;
5495440Sjm199354 		break;
5505440Sjm199354 	case VS_PROPID_TYPES:
5515440Sjm199354 		(void) strlcpy(vp->vp_types, vs_dflt_types,
5525440Sjm199354 		    sizeof (vp->vp_types));
5535440Sjm199354 		break;
5545440Sjm199354 	case VS_PROPID_VLOG:
5555440Sjm199354 		(void) strlcpy(vp->vp_vlog, vs_dflt_vlog,
5565440Sjm199354 		    sizeof (vp->vp_vlog));
5575440Sjm199354 		break;
5585440Sjm199354 	case VS_PROPID_SE_ENABLE:
5595440Sjm199354 		vep->vep_enable = vs_dflt_enable;
5605440Sjm199354 		break;
5615440Sjm199354 	case VS_PROPID_SE_HOST:
5625440Sjm199354 		(void) strlcpy(vep->vep_host, vs_dflt_host,
5635440Sjm199354 		    sizeof (vep->vep_host));
5645440Sjm199354 		break;
5655440Sjm199354 	case VS_PROPID_SE_PORT:
5665440Sjm199354 		vep->vep_port = vs_dflt_port;
5675440Sjm199354 		break;
5685440Sjm199354 	case VS_PROPID_SE_MAXCONN:
5695440Sjm199354 		vep->vep_maxconn = vs_dflt_maxconn;
5705440Sjm199354 		break;
5715440Sjm199354 	default:
5725440Sjm199354 		break;
5735440Sjm199354 	}
5745440Sjm199354 }
5755440Sjm199354 
5765440Sjm199354 
5775440Sjm199354 /*
5785440Sjm199354  * vs_scf_values_get
5795440Sjm199354  *
5805440Sjm199354  * Gets property values for one or more properties from the repository.
5815440Sjm199354  * This is the single entry point for loading SMF values.
5825440Sjm199354  *
5835440Sjm199354  * While a transaction is not used for loading property values,
5845440Sjm199354  * the operation is parameterized by a property group. All properties
5855440Sjm199354  * retrieved in this function, then, must belong to the same property
5865440Sjm199354  * group.
5875440Sjm199354  */
5885440Sjm199354 int
vs_scf_values_get(const char * pgname,vs_prop_hd_t * prop_hd)5895440Sjm199354 vs_scf_values_get(const char *pgname, vs_prop_hd_t *prop_hd)
5905440Sjm199354 {
5915440Sjm199354 	vs_scfctx_t vsc;
5925440Sjm199354 	int rc, np;
5935440Sjm199354 	const vs_propdef_t *vpd;
5945440Sjm199354 	uint64_t propid;
5955440Sjm199354 
5965440Sjm199354 	if ((vs_scf_ctx_open(&vsc)) != 0) {
5975440Sjm199354 		vs_scf_ctx_close(&vsc);
5985440Sjm199354 		return (VS_ERR_SCF);
5995440Sjm199354 	}
6005440Sjm199354 
6015440Sjm199354 	if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
6025440Sjm199354 		vs_scf_ctx_close(&vsc);
6035440Sjm199354 		if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) {
6045440Sjm199354 			rc = scf_error();
6055440Sjm199354 			if ((rc == SCF_ERROR_NOT_FOUND) ||
6065440Sjm199354 			    (rc == SCF_ERROR_INVALID_ARGUMENT))
6075440Sjm199354 				return (VS_ERR_INVALID_SE);
6085440Sjm199354 		}
6095440Sjm199354 		return (VS_ERR_SCF);
6105440Sjm199354 	}
6115440Sjm199354 
6125440Sjm199354 	rc = VS_ERR_NONE;
6135440Sjm199354 	np = 0;
6145440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
6155440Sjm199354 		if ((prop_hd->vp_ids & propid) == 0)
6165440Sjm199354 			continue;
6175440Sjm199354 
6185440Sjm199354 		if ((vpd = vs_get_propdef(propid)) == NULL) {
6195440Sjm199354 			rc = VS_ERR_INVALID_PROPERTY;
6205440Sjm199354 			break;
6215440Sjm199354 		}
6225440Sjm199354 
6235440Sjm199354 		vsc.vscf_prop[np] = scf_property_create(vsc.vscf_handle);
6245440Sjm199354 		vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
6255440Sjm199354 
6265440Sjm199354 		if (vsc.vscf_prop[np] == NULL || vsc.vscf_val[np] == NULL) {
6275440Sjm199354 			rc = VS_ERR_SCF;
6285440Sjm199354 			break;
6295440Sjm199354 		}
6305440Sjm199354 
6315440Sjm199354 		if (scf_pg_get_property(vsc.vscf_pgroup, vpd->vpd_name,
6325440Sjm199354 		    vsc.vscf_prop[np]) == -1) {
6335440Sjm199354 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
6345440Sjm199354 				vs_default_value(prop_hd, vpd->vpd_id);
6355440Sjm199354 				continue;
6365440Sjm199354 			}
6375440Sjm199354 			rc = VS_ERR_SCF;
6385440Sjm199354 			break;
6395440Sjm199354 		}
6405440Sjm199354 
6415440Sjm199354 		if ((rc = vs_scf_get(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
6425440Sjm199354 			break;
6435440Sjm199354 
6445440Sjm199354 		++np;
6455440Sjm199354 	}
6465440Sjm199354 
6475440Sjm199354 
6485440Sjm199354 	vs_scf_ctx_close(&vsc);
6495440Sjm199354 
6505440Sjm199354 	return (rc);
6515440Sjm199354 }
6525440Sjm199354 
6535440Sjm199354 
6545440Sjm199354 /*
6555440Sjm199354  * vs_scf_get
6565440Sjm199354  *
6575440Sjm199354  * Loads a single values from the repository into the appropriate vscan
6585440Sjm199354  * property structure member.
6595440Sjm199354  */
6605440Sjm199354 static int
vs_scf_get(const vs_propdef_t * vpd,vs_prop_hd_t * prop_hd,vs_scfctx_t * vsc,int idx)6615440Sjm199354 vs_scf_get(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
6625440Sjm199354 	vs_scfctx_t *vsc, int idx)
6635440Sjm199354 {
6645440Sjm199354 	int rc;
6655440Sjm199354 	int64_t port;
6665440Sjm199354 	uint8_t valbool;
6675440Sjm199354 	vs_props_t *vp = &prop_hd->vp_gen;
6685440Sjm199354 	vs_props_se_t *vep = &prop_hd->vp_se;
6695440Sjm199354 
6705440Sjm199354 	if ((rc = scf_property_get_value(vsc->vscf_prop[idx],
6715440Sjm199354 	    vsc->vscf_val[idx])) == -1) {
6725440Sjm199354 		if (rc == SCF_ERROR_CONSTRAINT_VIOLATED ||
6735440Sjm199354 		    rc == SCF_ERROR_NOT_FOUND) {
6745440Sjm199354 			vs_default_value(prop_hd, vpd->vpd_id);
6755440Sjm199354 			return (VS_ERR_NONE);
6765440Sjm199354 		}
6775440Sjm199354 		return (VS_ERR_SCF);
6785440Sjm199354 	}
6795440Sjm199354 
6805440Sjm199354 	rc = VS_ERR_NONE;
6815440Sjm199354 	switch (vpd->vpd_id) {
6825440Sjm199354 	case VS_PROPID_MAXSIZE:
6835440Sjm199354 		if ((scf_value_get_astring(vsc->vscf_val[idx],
6845440Sjm199354 		    vp->vp_maxsize, sizeof (vp->vp_maxsize))) == -1) {
6855440Sjm199354 			return (VS_ERR_SCF);
6865440Sjm199354 		}
6875440Sjm199354 		break;
6885440Sjm199354 	case VS_PROPID_MAXSIZE_ACTION:
6895440Sjm199354 		if ((scf_value_get_boolean(vsc->vscf_val[idx],
6905440Sjm199354 		    &valbool)) == -1) {
6915440Sjm199354 			return (VS_ERR_SCF);
6925440Sjm199354 		}
6935440Sjm199354 		vp->vp_maxsize_action = (valbool == 0) ? B_FALSE : B_TRUE;
6945440Sjm199354 		break;
6955440Sjm199354 	case VS_PROPID_TYPES:
6965440Sjm199354 		if ((scf_value_get_astring(vsc->vscf_val[idx],
6975440Sjm199354 		    vp->vp_types, sizeof (vp->vp_types))) == -1) {
6985440Sjm199354 			return (VS_ERR_SCF);
6995440Sjm199354 		}
7005440Sjm199354 		break;
7015440Sjm199354 	case VS_PROPID_VLOG:
7025440Sjm199354 		if ((scf_value_get_astring(vsc->vscf_val[idx],
7035440Sjm199354 		    vp->vp_vlog, sizeof (vp->vp_vlog))) == -1) {
7045440Sjm199354 			return (VS_ERR_SCF);
7055440Sjm199354 		}
7065440Sjm199354 		break;
7075440Sjm199354 	case VS_PROPID_SE_ENABLE:
7085440Sjm199354 		if ((scf_value_get_boolean(vsc->vscf_val[idx],
7095440Sjm199354 		    &valbool)) == -1) {
7105440Sjm199354 			return (VS_ERR_SCF);
7115440Sjm199354 		}
7125440Sjm199354 		vep->vep_enable = (valbool == 0) ? B_FALSE : B_TRUE;
7135440Sjm199354 		break;
7145440Sjm199354 	case VS_PROPID_SE_HOST:
7155440Sjm199354 		(void) scf_value_get_as_string_typed(vsc->vscf_val[idx],
7165440Sjm199354 		    vpd->vpd_type, vep->vep_host, sizeof (vep->vep_host));
7175440Sjm199354 		break;
7185440Sjm199354 	case VS_PROPID_SE_PORT:
7195440Sjm199354 		if ((scf_value_get_integer(vsc->vscf_val[idx], &port)) == -1)
7205440Sjm199354 			return (VS_ERR_SCF);
7215440Sjm199354 		if (port <= 0 || port >= UINT16_MAX)
7225440Sjm199354 			rc = VS_ERR_INVALID_VALUE;
7235440Sjm199354 		else
7245440Sjm199354 			vep->vep_port = (uint16_t)port;
7255440Sjm199354 		break;
7265440Sjm199354 	case VS_PROPID_SE_MAXCONN:
7275440Sjm199354 		if ((scf_value_get_integer(vsc->vscf_val[idx],
7285440Sjm199354 		    (int64_t *)&vep->vep_maxconn)) == -1) {
7295440Sjm199354 			return (VS_ERR_SCF);
7305440Sjm199354 		}
7315440Sjm199354 		break;
7325440Sjm199354 	default:
7335440Sjm199354 		break;
7345440Sjm199354 	}
7355440Sjm199354 
7365440Sjm199354 	if ((rc != VS_ERR_NONE) ||
7375440Sjm199354 	    (vs_validate(prop_hd, vpd->vpd_id) != VS_ERR_NONE)) {
7385440Sjm199354 		vs_default_value(prop_hd, vpd->vpd_id);
7395440Sjm199354 	}
7405440Sjm199354 
7415440Sjm199354 	return (VS_ERR_NONE);
7425440Sjm199354 }
7435440Sjm199354 
7445440Sjm199354 
7455440Sjm199354 /*
7465440Sjm199354  * vs_scf_pg_create
7475440Sjm199354  */
7485440Sjm199354 static int
vs_scf_pg_create(const char * pgname,vs_prop_hd_t * prop_hd)7495440Sjm199354 vs_scf_pg_create(const char *pgname, vs_prop_hd_t *prop_hd)
7505440Sjm199354 {
7515440Sjm199354 	int rc;
7525440Sjm199354 	uint64_t propid;
7535440Sjm199354 	vs_scfctx_t vsc;
7545440Sjm199354 
7555440Sjm199354 	/* ensure that caller has authorization to refresh service */
7565440Sjm199354 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
7575440Sjm199354 		return (rc);
7585440Sjm199354 
7595440Sjm199354 	if (vs_scf_ctx_open(&vsc) != 0) {
7605440Sjm199354 		vs_scf_ctx_close(&vsc);
7615440Sjm199354 		return (VS_ERR_SCF);
7625440Sjm199354 	}
7635440Sjm199354 
7645440Sjm199354 	if (scf_instance_add_pg(vsc.vscf_inst, pgname,
7655440Sjm199354 	    SCF_GROUP_APPLICATION, 0, vsc.vscf_pgroup) == -1) {
7665440Sjm199354 		vs_scf_ctx_close(&vsc);
7675440Sjm199354 		if (scf_error() == SCF_ERROR_INVALID_ARGUMENT)
7685440Sjm199354 			return (VS_ERR_INVALID_SE);
7695440Sjm199354 		return (VS_ERR_SCF);
7705440Sjm199354 	}
7715440Sjm199354 	vs_scf_ctx_close(&vsc);
7725440Sjm199354 
7735440Sjm199354 	/* set default values for those not specified */
7745440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
7755440Sjm199354 		if ((propid & prop_hd->vp_all) && !(propid & prop_hd->vp_ids))
7765440Sjm199354 			vs_default_value(prop_hd, propid);
7775440Sjm199354 	}
7786407Sjm199354 
7795440Sjm199354 	prop_hd->vp_ids = prop_hd->vp_all;
7805440Sjm199354 	prop_hd->vp_ids |= VS_PROPID_VALUE_AUTH;
7815440Sjm199354 
7825440Sjm199354 	rc = vs_scf_values_set(pgname, prop_hd);
7835440Sjm199354 	if (rc != VS_ERR_NONE)
7846407Sjm199354 		(void) vs_scf_pg_delete(pgname);
7855440Sjm199354 
7865440Sjm199354 	return (rc);
7875440Sjm199354 }
7885440Sjm199354 
7895440Sjm199354 
7905440Sjm199354 /*
7916407Sjm199354  * vs_scf_pg_delete
7926407Sjm199354  */
7936407Sjm199354 static int
vs_scf_pg_delete(const char * pgname)7946407Sjm199354 vs_scf_pg_delete(const char *pgname)
7956407Sjm199354 {
7966407Sjm199354 	int rc;
7976407Sjm199354 	vs_scfctx_t vsc;
7986407Sjm199354 
7996407Sjm199354 	/* ensure that caller has authorization to refresh service */
8006407Sjm199354 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
8016407Sjm199354 		return (rc);
8026407Sjm199354 
8036407Sjm199354 	if (vs_scf_ctx_open(&vsc) != 0) {
8046407Sjm199354 		vs_scf_ctx_close(&vsc);
8056407Sjm199354 		return (VS_ERR_SCF);
8066407Sjm199354 	}
8076407Sjm199354 
8086407Sjm199354 	if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
8096407Sjm199354 		vs_scf_ctx_close(&vsc);
8106407Sjm199354 		rc = scf_error();
8116407Sjm199354 		if ((rc == SCF_ERROR_NOT_FOUND) ||
8126407Sjm199354 		    (rc == SCF_ERROR_INVALID_ARGUMENT))
8136407Sjm199354 			return (VS_ERR_INVALID_SE);
8146407Sjm199354 		else
8156407Sjm199354 			return (VS_ERR_SCF);
8166407Sjm199354 	}
8176407Sjm199354 
8186407Sjm199354 	if (scf_pg_delete(vsc.vscf_pgroup) == -1) {
8196407Sjm199354 		vs_scf_ctx_close(&vsc);
8206407Sjm199354 		rc = scf_error();
8216407Sjm199354 		if ((rc == SCF_ERROR_NOT_FOUND) ||
8226407Sjm199354 		    (rc == SCF_ERROR_INVALID_ARGUMENT))
8236407Sjm199354 			return (VS_ERR_INVALID_SE);
8246407Sjm199354 
8256407Sjm199354 		return (VS_ERR_SCF);
8266407Sjm199354 	}
8276407Sjm199354 
8286407Sjm199354 	vs_scf_ctx_close(&vsc);
8296407Sjm199354 
8306407Sjm199354 	/* Notify the daemon that things have changed */
8316407Sjm199354 	if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1) {
8326407Sjm199354 		return (VS_ERR_SCF);
8336407Sjm199354 	}
8346407Sjm199354 
8356407Sjm199354 	return (VS_ERR_NONE);
8366407Sjm199354 }
8376407Sjm199354 
8386407Sjm199354 
8396407Sjm199354 /*
8405440Sjm199354  * vs_scf_values_set
8415440Sjm199354  *
8425440Sjm199354  * Sets property values in the repository.  This is the single
8435440Sjm199354  * entry point for storing SMF values.
8445440Sjm199354  *
8455440Sjm199354  * Like loading values, this is an operation based on a single property
8465440Sjm199354  * group, so all property values changed in this function must belong
8475440Sjm199354  * to the same property group. Additionally, this operation is done in
8485440Sjm199354  * the context of a repository transaction; on any fatal error, the
8495440Sjm199354  * SCF context will be closed, destroying all SCF objects and aborting
8505440Sjm199354  * the transaction.
8515440Sjm199354  */
8525440Sjm199354 static int
vs_scf_values_set(const char * pgname,vs_prop_hd_t * prop_hd)8535440Sjm199354 vs_scf_values_set(const char *pgname, vs_prop_hd_t *prop_hd)
8545440Sjm199354 {
8555440Sjm199354 	int rc, np;
8565440Sjm199354 	const vs_propdef_t *vpd;
8575440Sjm199354 	uint64_t propid;
8585440Sjm199354 	vs_scfctx_t vsc;
8595440Sjm199354 
8605440Sjm199354 	/* ensure that caller has authorization to refresh service */
8615440Sjm199354 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
8625440Sjm199354 		return (rc);
8635440Sjm199354 
8645440Sjm199354 	if (vs_scf_ctx_open(&vsc) != 0) {
8655440Sjm199354 		vs_scf_ctx_close(&vsc);
8665440Sjm199354 		return (VS_ERR_SCF);
8675440Sjm199354 	}
8685440Sjm199354 
8695440Sjm199354 	if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
8705440Sjm199354 		vs_scf_ctx_close(&vsc);
8715440Sjm199354 		rc = scf_error();
8725440Sjm199354 		if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) {
8735440Sjm199354 			if ((rc == SCF_ERROR_NOT_FOUND) ||
8745440Sjm199354 			    (rc == SCF_ERROR_INVALID_ARGUMENT))
8755440Sjm199354 				return (VS_ERR_INVALID_SE);
8765440Sjm199354 		}
8775440Sjm199354 		return (VS_ERR_SCF);
8785440Sjm199354 	}
8795440Sjm199354 
8805440Sjm199354 	if (((vsc.vscf_tx = scf_transaction_create(vsc.vscf_handle)) == NULL) ||
8815440Sjm199354 	    (scf_transaction_start(vsc.vscf_tx, vsc.vscf_pgroup) == -1)) {
8825440Sjm199354 		vs_scf_ctx_close(&vsc);
8835440Sjm199354 		return (VS_ERR_SCF);
8845440Sjm199354 	}
8855440Sjm199354 
8865440Sjm199354 	/* Process the value change for each specified property */
8875440Sjm199354 	rc = 0;
8885440Sjm199354 	np = 0;
8895440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
8905440Sjm199354 		if ((prop_hd->vp_ids & propid) == 0)
8915440Sjm199354 			continue;
8925440Sjm199354 
8935440Sjm199354 		if ((vpd = vs_get_propdef(propid)) == NULL) {
8945440Sjm199354 			rc = VS_ERR_INVALID_PROPERTY;
8955440Sjm199354 			break;
8965440Sjm199354 		}
8975440Sjm199354 
8985440Sjm199354 		vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
8995440Sjm199354 		vsc.vscf_ent[np] = scf_entry_create(vsc.vscf_handle);
9005440Sjm199354 
9015440Sjm199354 		if (vsc.vscf_val[np] == NULL || vsc.vscf_ent[np] == NULL) {
9025440Sjm199354 			rc = VS_ERR_SCF;
9035440Sjm199354 			break;
9045440Sjm199354 		}
9055440Sjm199354 
9065440Sjm199354 		if ((rc = scf_transaction_property_change(vsc.vscf_tx,
9075440Sjm199354 		    vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type)) == -1) {
9085440Sjm199354 			rc = scf_transaction_property_new(vsc.vscf_tx,
9095440Sjm199354 			    vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type);
9105440Sjm199354 		}
9115440Sjm199354 		if (rc == -1) {
9125440Sjm199354 			rc = VS_ERR_SCF;
9135440Sjm199354 			break;
9145440Sjm199354 		}
9155440Sjm199354 
9165440Sjm199354 		if ((rc = vs_scf_set(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
9175440Sjm199354 			break;
9185440Sjm199354 
9195440Sjm199354 		++np;
9205440Sjm199354 	}
9215440Sjm199354 
9225440Sjm199354 	if (rc != VS_ERR_NONE) {
9235440Sjm199354 		vs_scf_ctx_close(&vsc);
9245440Sjm199354 		return (rc);
9255440Sjm199354 	}
9265440Sjm199354 
9275440Sjm199354 	/* Commit the transaction */
9285440Sjm199354 	if (scf_transaction_commit(vsc.vscf_tx) == -1) {
9295440Sjm199354 		vs_scf_ctx_close(&vsc);
9305440Sjm199354 		return (VS_ERR_SCF);
9315440Sjm199354 	}
9325440Sjm199354 	vs_scf_ctx_close(&vsc);
9335440Sjm199354 
9345440Sjm199354 	/* Notify the daemon that things have changed */
9355440Sjm199354 	if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1)
9365440Sjm199354 		return (VS_ERR_SCF);
9375440Sjm199354 
9385440Sjm199354 	return (VS_ERR_NONE);
9395440Sjm199354 }
9405440Sjm199354 
9415440Sjm199354 
9425440Sjm199354 /*
9435440Sjm199354  * vs_scf_set
9445440Sjm199354  *
9455440Sjm199354  * Stores a single value from the appropriate vscan property structure
9465440Sjm199354  * member into the repository.
9475440Sjm199354  *
9485440Sjm199354  * Values are set in the SCF value object, then the value object
9495440Sjm199354  * is added to the SCF property object.
9505440Sjm199354  */
9515440Sjm199354 static int
vs_scf_set(const vs_propdef_t * vpd,vs_prop_hd_t * prop_hd,vs_scfctx_t * vsc,int idx)9525440Sjm199354 vs_scf_set(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
9535440Sjm199354     vs_scfctx_t *vsc, int idx)
9545440Sjm199354 {
9555440Sjm199354 	int rc;
9565440Sjm199354 	vs_props_t *vp = &prop_hd->vp_gen;
9575440Sjm199354 	vs_props_se_t *vep = &prop_hd->vp_se;
9585440Sjm199354 
9595440Sjm199354 	if ((rc = vs_validate(prop_hd, vpd->vpd_id)) != VS_ERR_NONE)
9605440Sjm199354 		return (rc);
9615440Sjm199354 
9625440Sjm199354 	rc = VS_ERR_NONE;
9635440Sjm199354 	switch (vpd->vpd_id) {
9645440Sjm199354 	case VS_PROPID_MAXSIZE:
9655440Sjm199354 		if ((scf_value_set_astring(vsc->vscf_val[idx],
9665440Sjm199354 		    vp->vp_maxsize)) == -1) {
9675440Sjm199354 			rc = VS_ERR_SCF;
9685440Sjm199354 		}
9695440Sjm199354 		break;
9705440Sjm199354 	case VS_PROPID_MAXSIZE_ACTION:
9715440Sjm199354 		scf_value_set_boolean(vsc->vscf_val[idx],
9725440Sjm199354 		    (uint8_t)vp->vp_maxsize_action);
9735440Sjm199354 		break;
9745440Sjm199354 	case VS_PROPID_TYPES:
9755440Sjm199354 		if ((scf_value_set_astring(vsc->vscf_val[idx],
9765440Sjm199354 		    vp->vp_types)) == -1) {
9775440Sjm199354 			return (VS_ERR_SCF);
9785440Sjm199354 		}
9795440Sjm199354 		break;
9805440Sjm199354 	case VS_PROPID_SE_ENABLE:
9815440Sjm199354 		scf_value_set_boolean(vsc->vscf_val[idx],
9825440Sjm199354 		    (uint8_t)vep->vep_enable);
9835440Sjm199354 		break;
9845440Sjm199354 	case VS_PROPID_SE_HOST:
9855440Sjm199354 		if ((scf_value_set_from_string(vsc->vscf_val[idx],
9865440Sjm199354 		    vpd->vpd_type, vep->vep_host)) == -1) {
9875440Sjm199354 			rc = VS_ERR_SCF;
9885440Sjm199354 		}
9895440Sjm199354 		break;
9905440Sjm199354 	case VS_PROPID_SE_PORT:
9915440Sjm199354 		scf_value_set_integer(vsc->vscf_val[idx], vep->vep_port);
9925440Sjm199354 		break;
9935440Sjm199354 	case VS_PROPID_SE_MAXCONN:
9945440Sjm199354 		scf_value_set_integer(vsc->vscf_val[idx],
9955440Sjm199354 		    vep->vep_maxconn);
9965440Sjm199354 		break;
9975440Sjm199354 	case VS_PROPID_VALUE_AUTH:
9985440Sjm199354 		if ((scf_value_set_astring(vsc->vscf_val[idx],
9995440Sjm199354 		    VS_VALUE_AUTH)) == -1) {
10005440Sjm199354 			return (VS_ERR_SCF);
10015440Sjm199354 		}
10025440Sjm199354 		break;
10035440Sjm199354 	default:
10045440Sjm199354 		break;
10055440Sjm199354 	}
10065440Sjm199354 
10075440Sjm199354 	if ((scf_entry_add_value(vsc->vscf_ent[idx],
10085440Sjm199354 	    vsc->vscf_val[idx])) == -1) {
10095440Sjm199354 		return (VS_ERR_SCF);
10105440Sjm199354 	}
10115440Sjm199354 
10125440Sjm199354 	return (rc);
10135440Sjm199354 }
10145440Sjm199354 
10155440Sjm199354 
10165440Sjm199354 /*
10175440Sjm199354  * vs_scf_ctx_open
10185440Sjm199354  *
10195440Sjm199354  * Opens an SCF context; creates the minumum SCF objects
10205440Sjm199354  * for use in loading/storing from the SMF repository (meaning
10215440Sjm199354  * vscf_property group data).
10225440Sjm199354  *
10235440Sjm199354  * Other SCF objects in the context may be initialized elsewher
10245440Sjm199354  * subsequent to open, but all initialized structures are destroyed
10255440Sjm199354  * in vs_scf_ctx_close().
10265440Sjm199354  */
10275440Sjm199354 static int
vs_scf_ctx_open(vs_scfctx_t * vsc)10285440Sjm199354 vs_scf_ctx_open(vs_scfctx_t *vsc)
10295440Sjm199354 {
10305440Sjm199354 	(void) memset(vsc, 0, sizeof (vs_scfctx_t));
10315440Sjm199354 
10325440Sjm199354 	if ((vsc->vscf_handle = scf_handle_create(SCF_VERSION)) == NULL)
10335440Sjm199354 		return (VS_ERR_SCF);
10345440Sjm199354 
10355440Sjm199354 	if (scf_handle_bind(vsc->vscf_handle) == -1)
10365440Sjm199354 		return (VS_ERR_SCF);
10375440Sjm199354 
10385440Sjm199354 	if ((vsc->vscf_inst = scf_instance_create(vsc->vscf_handle)) == NULL)
10395440Sjm199354 		return (VS_ERR_SCF);
10405440Sjm199354 
10415440Sjm199354 	if (scf_handle_decode_fmri(vsc->vscf_handle, VS_INSTANCE_FMRI,
10425440Sjm199354 	    NULL, NULL, vsc->vscf_inst, NULL, NULL,
10435440Sjm199354 	    SCF_DECODE_FMRI_EXACT) == -1) {
10445440Sjm199354 		return (VS_ERR_SCF);
10455440Sjm199354 	}
10465440Sjm199354 
10475440Sjm199354 	if ((vsc->vscf_pgroup = scf_pg_create(vsc->vscf_handle)) == NULL)
10485440Sjm199354 		return (VS_ERR_SCF);
10495440Sjm199354 
10505440Sjm199354 	return (VS_ERR_NONE);
10515440Sjm199354 }
10525440Sjm199354 
10535440Sjm199354 
10545440Sjm199354 /*
10555440Sjm199354  * vs_scf_ctx_close
10565440Sjm199354  *
10575440Sjm199354  * Closes an SCF context; destroys all initialized SCF objects.
10585440Sjm199354  */
10595440Sjm199354 static void
vs_scf_ctx_close(vs_scfctx_t * vsc)10605440Sjm199354 vs_scf_ctx_close(vs_scfctx_t *vsc)
10615440Sjm199354 {
10625440Sjm199354 	int i;
10635440Sjm199354 
10645440Sjm199354 	for (i = 0; i < VS_NUM_PROPIDS; i++) {
10655440Sjm199354 		if (vsc->vscf_val[i])
10665440Sjm199354 			scf_value_destroy(vsc->vscf_val[i]);
10675440Sjm199354 		if (vsc->vscf_ent[i])
10685440Sjm199354 			scf_entry_destroy(vsc->vscf_ent[i]);
10695440Sjm199354 		if (vsc->vscf_prop[i])
10705440Sjm199354 			scf_property_destroy(vsc->vscf_prop[i]);
10715440Sjm199354 	}
10725440Sjm199354 
10735440Sjm199354 	if (vsc->vscf_iter)
10745440Sjm199354 		scf_iter_destroy(vsc->vscf_iter);
10755440Sjm199354 	if (vsc->vscf_tx)
10765440Sjm199354 		scf_transaction_destroy(vsc->vscf_tx);
10775440Sjm199354 	if (vsc->vscf_pgroup)
10785440Sjm199354 		scf_pg_destroy(vsc->vscf_pgroup);
10795440Sjm199354 	if (vsc->vscf_inst)
10805440Sjm199354 		scf_instance_destroy(vsc->vscf_inst);
10815440Sjm199354 	if (vsc->vscf_handle)
10825440Sjm199354 		scf_handle_destroy(vsc->vscf_handle);
10835440Sjm199354 }
10845440Sjm199354 
10855440Sjm199354 
10865440Sjm199354 /*
10875440Sjm199354  * vs_validate
10885440Sjm199354  *
10895440Sjm199354  * Validate property identified in propid.
10905440Sjm199354  *
10915440Sjm199354  * Returns: VS_ERR_NONE
10925440Sjm199354  *          VS_ERR_INVALID_VALUE
10935440Sjm199354  *          VS_ERR_INVALID_PROPERTY
10945440Sjm199354  */
10955440Sjm199354 static int
vs_validate(const vs_prop_hd_t * prop_hd,uint64_t propid)10965440Sjm199354 vs_validate(const vs_prop_hd_t *prop_hd, uint64_t propid)
10975440Sjm199354 {
10985440Sjm199354 	uint64_t num;
10995440Sjm199354 	const vs_props_t *vp = &prop_hd->vp_gen;
11005440Sjm199354 	const vs_props_se_t *vep = &prop_hd->vp_se;
11015440Sjm199354 
11025440Sjm199354 	switch (propid) {
11035440Sjm199354 	case VS_PROPID_MAXSIZE:
11045440Sjm199354 		if ((vs_strtonum(vp->vp_maxsize, &num) != 0) || (num == 0))
11055440Sjm199354 			return (VS_ERR_INVALID_VALUE);
11065440Sjm199354 		break;
11075440Sjm199354 	case VS_PROPID_MAXSIZE_ACTION:
11085440Sjm199354 		break;
11095440Sjm199354 	case VS_PROPID_TYPES:
11105440Sjm199354 		if (!vs_is_valid_types(vp->vp_types))
11115440Sjm199354 			return (VS_ERR_INVALID_VALUE);
11125440Sjm199354 		break;
11135440Sjm199354 	case VS_PROPID_SE_ENABLE:
11145440Sjm199354 		break;
11155440Sjm199354 	case VS_PROPID_SE_PORT:
11165440Sjm199354 		if (vep->vep_port == 0)
11175440Sjm199354 			return (VS_ERR_INVALID_VALUE);
11185440Sjm199354 		break;
11195440Sjm199354 	case VS_PROPID_SE_HOST:
11205440Sjm199354 		if (!vs_is_valid_host(vep->vep_host))
11215440Sjm199354 			return (VS_ERR_INVALID_VALUE);
11225440Sjm199354 		break;
11235440Sjm199354 	case VS_PROPID_SE_MAXCONN:
11245440Sjm199354 		if (vep->vep_maxconn < VS_VAL_SE_MAXCONN_MIN ||
11255440Sjm199354 		    vep->vep_maxconn > VS_VAL_SE_MAXCONN_MAX)
11265440Sjm199354 			return (VS_ERR_INVALID_VALUE);
11275440Sjm199354 		break;
11285440Sjm199354 	case VS_PROPID_VALUE_AUTH:
11295440Sjm199354 	case VS_PROPID_VLOG:
11305440Sjm199354 		break;
11315440Sjm199354 	default:
11325440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
11335440Sjm199354 	}
11345440Sjm199354 
11355440Sjm199354 	return (VS_ERR_NONE);
11365440Sjm199354 }
11375440Sjm199354 
11385440Sjm199354 
11395440Sjm199354 /*
11405440Sjm199354  * vs_props_validate
11415440Sjm199354  *
11425440Sjm199354  * Validate  properties identified in propids.
11435440Sjm199354  *
11445440Sjm199354  * Returns: VS_ERR_NONE
11455440Sjm199354  *          VS_ERR_INVALID_VALUE
11465440Sjm199354  *          VS_ERR_INVALID_PROPERTY
11475440Sjm199354  */
11485440Sjm199354 int
vs_props_validate(const vs_props_t * props,uint64_t propids)11495440Sjm199354 vs_props_validate(const vs_props_t *props, uint64_t propids)
11505440Sjm199354 {
11515440Sjm199354 	uint64_t propid;
11525440Sjm199354 	vs_prop_hd_t prop_hd;
11535440Sjm199354 
11545440Sjm199354 	if ((propids & VS_PROPID_GEN_ALL) != propids)
11555440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
11565440Sjm199354 
11575440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
11585440Sjm199354 	prop_hd.vp_gen = *props;
11595440Sjm199354 	prop_hd.vp_type = VS_PTYPE_GEN;
11605440Sjm199354 	prop_hd.vp_ids = propids;
11615440Sjm199354 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
11625440Sjm199354 
11635440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
11645440Sjm199354 		if ((propids & propid) == 0)
11655440Sjm199354 			continue;
11665440Sjm199354 
11675440Sjm199354 		if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
11685440Sjm199354 			return (VS_ERR_INVALID_VALUE);
11695440Sjm199354 	}
11705440Sjm199354 
11715440Sjm199354 	return (VS_ERR_NONE);
11725440Sjm199354 }
11735440Sjm199354 
11745440Sjm199354 
11755440Sjm199354 /*
11765440Sjm199354  * vs_props_se_validate
11775440Sjm199354  *
11785440Sjm199354  * Validate properties identified in propids.
11795440Sjm199354  *
11805440Sjm199354  * Returns: VS_ERR_NONE
11815440Sjm199354  *          VS_ERR_INVALID_VALUE
11825440Sjm199354  *          VS_ERR_INVALID_PROPERTY
11835440Sjm199354  */
11845440Sjm199354 int
vs_props_se_validate(const vs_props_se_t * se_props,uint64_t propids)11855440Sjm199354 vs_props_se_validate(const vs_props_se_t *se_props, uint64_t propids)
11865440Sjm199354 {
11875440Sjm199354 	uint64_t propid;
11885440Sjm199354 	vs_prop_hd_t prop_hd;
11895440Sjm199354 
11905440Sjm199354 	if ((propids & VS_PROPID_SE_ALL) != propids)
11915440Sjm199354 		return (VS_ERR_INVALID_PROPERTY);
11925440Sjm199354 
11935440Sjm199354 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
11945440Sjm199354 	prop_hd.vp_se = *se_props;
11955440Sjm199354 	prop_hd.vp_type = VS_PTYPE_SE;
11965440Sjm199354 	prop_hd.vp_ids = propids;
11975440Sjm199354 	prop_hd.vp_all = VS_PROPID_SE_ALL;
11985440Sjm199354 
11995440Sjm199354 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
12005440Sjm199354 		if ((propids & propid) == 0)
12015440Sjm199354 			continue;
12025440Sjm199354 
12035440Sjm199354 		if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
12045440Sjm199354 			return (VS_ERR_INVALID_VALUE);
12055440Sjm199354 	}
12065440Sjm199354 
12075440Sjm199354 	return (VS_ERR_NONE);
12085440Sjm199354 }
12095440Sjm199354 
12105440Sjm199354 
12115440Sjm199354 /*
12125440Sjm199354  * vs_is_valid_types
12135440Sjm199354  *
12145440Sjm199354  * Checks that types property is a valid format:
12155440Sjm199354  * - doesn't exceed VS_VAL_TYPES_MAX
12165440Sjm199354  * - doesn't contain VS_VAL_TYPES_INVALID_CHARS
12175440Sjm199354  * - is correctly formatted - passes the parsing tests
12185440Sjm199354  *
12195440Sjm199354  * Returns 1 on success, 0 on failure
12205440Sjm199354  */
12215440Sjm199354 static int
vs_is_valid_types(const char * types)12225440Sjm199354 vs_is_valid_types(const char *types)
12235440Sjm199354 {
12245440Sjm199354 	char buf[VS_VAL_TYPES_LEN];
12255440Sjm199354 	uint32_t len = VS_VAL_TYPES_LEN;
12265440Sjm199354 
12275440Sjm199354 	if (strlen(types) > VS_VAL_TYPES_LEN)
12285440Sjm199354 		return (0);
12295440Sjm199354 
12305440Sjm199354 	if (strpbrk(types, VS_VAL_TYPES_INVALID_CHARS) != NULL)
12315440Sjm199354 		return (0);
12325440Sjm199354 
12335440Sjm199354 	if (vs_parse_types(types, buf, &len) != 0)
12345440Sjm199354 		return (0);
12355440Sjm199354 
12365440Sjm199354 	return (1);
12375440Sjm199354 }
12385440Sjm199354 
12395440Sjm199354 
12405440Sjm199354 /*
12415440Sjm199354  * vs_is_valid_host
12425440Sjm199354  *
12435440Sjm199354  * Returns 1 on success, 0 on failure
12445440Sjm199354  */
12455440Sjm199354 static int
vs_is_valid_host(const char * host)12465440Sjm199354 vs_is_valid_host(const char *host)
12475440Sjm199354 {
12485440Sjm199354 	long naddr;
12495440Sjm199354 	const char *p;
12505440Sjm199354 
12515440Sjm199354 	if (!host || *host == '\0')
12525440Sjm199354 		return (0);
12535440Sjm199354 
12545440Sjm199354 	if ('0' <= host[0] && host[0] <= '9') {
12555440Sjm199354 		/* ip address */
12565440Sjm199354 		if ((inet_pton(AF_INET, host, &naddr)) == 0)
12575440Sjm199354 			return (0);
12585440Sjm199354 		if ((naddr & IN_CLASSA_NET) == 0)
12595440Sjm199354 			return (0);
12605440Sjm199354 		if ((naddr & IN_CLASSC_HOST) == 0)
12615440Sjm199354 			return (0);
12625440Sjm199354 	} else {
12635440Sjm199354 		/* hostname */
12645440Sjm199354 		p = host;
12655440Sjm199354 		while (*p != '\0') {
12665440Sjm199354 			if (!isascii(*p))
12675440Sjm199354 				return (0);
12685440Sjm199354 
12695440Sjm199354 			if (isalnum(*p) ||
12705440Sjm199354 			    (*p == '.') || (*p == '-') || (*p == '_')) {
12715440Sjm199354 				++p;
12725440Sjm199354 			} else {
12735440Sjm199354 				return (0);
12745440Sjm199354 			}
12755440Sjm199354 		}
12765440Sjm199354 	}
12775440Sjm199354 
12785440Sjm199354 	return (1);
12795440Sjm199354 }
12805440Sjm199354 
12815440Sjm199354 
12825440Sjm199354 /*
12835440Sjm199354  * vs_parse_types
12845440Sjm199354  *
12855440Sjm199354  * Replace comma separators with '\0'.
12865440Sjm199354  *
12875440Sjm199354  * Types contains comma separated rules each beginning with +|-
12885440Sjm199354  *   - embedded commas are escaped by backslash
12895440Sjm199354  *   - backslash is escaped by backslash
12905440Sjm199354  *   - a single backslash not followed by comma is illegal
12915440Sjm199354  *
12925440Sjm199354  * On entry to the function len must contain the length of
12935440Sjm199354  * the buffer. On sucecssful exit len will contain the length
12945440Sjm199354  * of the parsed data within the buffer.
12955440Sjm199354  *
12965440Sjm199354  * Returns 0 on success, -1 on failure
12975440Sjm199354  */
12985440Sjm199354 int
vs_parse_types(const char * types,char * buf,uint32_t * len)12995440Sjm199354 vs_parse_types(const char *types, char *buf, uint32_t *len)
13005440Sjm199354 {
13015440Sjm199354 	char *p = (char *)types;
13025440Sjm199354 	char *b = buf;
13035440Sjm199354 
13045440Sjm199354 	if (strlen(types) > *len)
13055440Sjm199354 		return (-1);
13065440Sjm199354 
13075440Sjm199354 	if (strchr(VS_TYPES_RULES, *p) == NULL)
13085440Sjm199354 		return (-1);
13095440Sjm199354 
13105440Sjm199354 	(void) memset(buf, 0, *len);
13115440Sjm199354 
13125440Sjm199354 	while (*p) {
13135440Sjm199354 		switch (*p) {
13145440Sjm199354 		case VS_TYPES_SEP:
13155440Sjm199354 			if (*(p + 1) &&
13165440Sjm199354 			    (strchr(VS_TYPES_RULES, *(p + 1))) == NULL)
13175440Sjm199354 				return (-1);
13185440Sjm199354 			*b = '\0';
13195440Sjm199354 			break;
13205440Sjm199354 		case VS_TYPES_ESCAPE:
13215440Sjm199354 			++p;
13225440Sjm199354 			if (*p == VS_TYPES_ESCAPE || *p == VS_TYPES_SEP)
13235440Sjm199354 				*b = *p;
13245440Sjm199354 			else
13255440Sjm199354 				return (-1);
13265440Sjm199354 			break;
13275440Sjm199354 		default:
13285440Sjm199354 			*b = *p;
13295440Sjm199354 		}
13305440Sjm199354 		++p;
13315440Sjm199354 		++b;
13325440Sjm199354 	}
13335440Sjm199354 
13345440Sjm199354 	*len = (b - buf) + 1;
13355440Sjm199354 
13365440Sjm199354 	return (0);
13375440Sjm199354 }
13385440Sjm199354 
13395440Sjm199354 
13405440Sjm199354 /*
13415440Sjm199354  * vs_statistics
13425440Sjm199354  */
13435440Sjm199354 int
vs_statistics(vs_stats_t * stats)13445440Sjm199354 vs_statistics(vs_stats_t *stats)
13455440Sjm199354 {
13465440Sjm199354 	int door_fd, rc = VS_ERR_NONE;
13475440Sjm199354 	vs_stats_req_t *req;
13486407Sjm199354 	vs_stats_rsp_t *rsp;
13495440Sjm199354 	door_arg_t arg;
13505440Sjm199354 
13515440Sjm199354 	if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
13525440Sjm199354 		return (VS_ERR_SYS);
13535440Sjm199354 
13546407Sjm199354 	if ((rsp = calloc(1, sizeof (vs_stats_rsp_t))) == NULL) {
13555440Sjm199354 		free(req);
13565440Sjm199354 		return (VS_ERR_SYS);
13575440Sjm199354 	}
13585440Sjm199354 
13595440Sjm199354 	if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
13605440Sjm199354 		free(req);
13616407Sjm199354 		free(rsp);
13625440Sjm199354 		return (VS_ERR_DAEMON_COMM);
13635440Sjm199354 	}
13645440Sjm199354 
13656407Sjm199354 	req->vsr_magic = VS_STATS_DOOR_MAGIC;
13666407Sjm199354 	req->vsr_id = VS_STATS_GET;
13675440Sjm199354 
13685440Sjm199354 	arg.data_ptr = (char *)req;
13695440Sjm199354 	arg.data_size = sizeof (vs_stats_req_t);
13705440Sjm199354 	arg.desc_ptr = NULL;
13715440Sjm199354 	arg.desc_num = 0;
13726407Sjm199354 	arg.rbuf = (char *)rsp;
13736407Sjm199354 	arg.rsize = sizeof (vs_stats_rsp_t);
13745440Sjm199354 
13757943Samw@Sun.COM 	rc = vs_door_call(door_fd, &arg);
13767943Samw@Sun.COM 
13777943Samw@Sun.COM 	if ((rc == VS_ERR_NONE) && (rsp->vsr_magic == VS_STATS_DOOR_MAGIC))
13787943Samw@Sun.COM 		*stats = rsp->vsr_stats;
13797943Samw@Sun.COM 	else
13805440Sjm199354 		rc = VS_ERR_DAEMON_COMM;
13815440Sjm199354 
13825440Sjm199354 	(void) close(door_fd);
13835440Sjm199354 
13845440Sjm199354 	free(req);
13856407Sjm199354 	free(rsp);
13865440Sjm199354 	return (rc);
13875440Sjm199354 }
13885440Sjm199354 
13895440Sjm199354 
13905440Sjm199354 /*
13915440Sjm199354  * vs_statistics_reset
13925440Sjm199354  */
13935440Sjm199354 int
vs_statistics_reset()13945440Sjm199354 vs_statistics_reset()
13955440Sjm199354 {
13965440Sjm199354 	int door_fd, rc;
13975440Sjm199354 	vs_stats_req_t *req;
13985440Sjm199354 	door_arg_t arg;
13995440Sjm199354 
14005440Sjm199354 	/* ensure that caller has authorization to reset stats */
14015440Sjm199354 	if ((rc = vs_checkauth(VS_VALUE_AUTH)) != VS_ERR_NONE)
14025440Sjm199354 		return (rc);
14035440Sjm199354 
14045440Sjm199354 	if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
14055440Sjm199354 		return (VS_ERR_SYS);
14065440Sjm199354 
14075440Sjm199354 	if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
14085440Sjm199354 		free(req);
14095440Sjm199354 		return (VS_ERR_DAEMON_COMM);
14105440Sjm199354 	}
14115440Sjm199354 
14126407Sjm199354 	req->vsr_magic = VS_STATS_DOOR_MAGIC;
14136407Sjm199354 	req->vsr_id = VS_STATS_RESET;
14145440Sjm199354 
14155440Sjm199354 	arg.data_ptr = (char *)req;
14165440Sjm199354 	arg.data_size = sizeof (vs_stats_req_t);
14175440Sjm199354 	arg.desc_ptr = NULL;
14185440Sjm199354 	arg.desc_num = 0;
14195440Sjm199354 	arg.rbuf = NULL;
14205440Sjm199354 	arg.rsize = 0;
14215440Sjm199354 
14227943Samw@Sun.COM 	rc = vs_door_call(door_fd, &arg);
14235440Sjm199354 
14245440Sjm199354 	(void) close(door_fd);
14255440Sjm199354 	free(req);
14265440Sjm199354 	return (rc);
14275440Sjm199354 }
14285440Sjm199354 
14297943Samw@Sun.COM /*
14307943Samw@Sun.COM  * Door call with retries.
14317943Samw@Sun.COM  *
14327943Samw@Sun.COM  * Returns VS_ERR_NONE on success, otherwise VS_ERR_DAEMON_COMM.
14337943Samw@Sun.COM  */
14347943Samw@Sun.COM static int
vs_door_call(int fd,door_arg_t * arg)14357943Samw@Sun.COM vs_door_call(int fd, door_arg_t *arg)
14367943Samw@Sun.COM {
14377943Samw@Sun.COM 	int rc = -1;
14387943Samw@Sun.COM 	int i;
14397943Samw@Sun.COM 
14407943Samw@Sun.COM 	for (i = 0; i < VS_DOOR_CALL_RETRIES; ++i) {
14417943Samw@Sun.COM 		errno = 0;
14427943Samw@Sun.COM 
14437943Samw@Sun.COM 		if ((rc = door_call(fd, arg)) == 0)
14447943Samw@Sun.COM 			break;
14457943Samw@Sun.COM 
14467943Samw@Sun.COM 		if (errno != EAGAIN && errno != EINTR)
14477943Samw@Sun.COM 			break;
14487943Samw@Sun.COM 	}
14497943Samw@Sun.COM 
14507943Samw@Sun.COM 	return ((rc == 0) ? VS_ERR_NONE : VS_ERR_DAEMON_COMM);
14517943Samw@Sun.COM }
14525440Sjm199354 
14535440Sjm199354 /*
14545440Sjm199354  * vs_checkauth
14555440Sjm199354  */
14565440Sjm199354 static int
vs_checkauth(char * auth)14575440Sjm199354 vs_checkauth(char *auth)
14585440Sjm199354 {
14595440Sjm199354 	struct passwd *pw;
14605440Sjm199354 	uid_t uid;
14615440Sjm199354 
14625440Sjm199354 	uid = getuid();
14635440Sjm199354 
14645440Sjm199354 	if ((pw = getpwuid(uid)) == NULL)
14655440Sjm199354 		return (VS_ERR_SYS);
14665440Sjm199354 
14675440Sjm199354 	if (chkauthattr(auth, pw->pw_name) != 1) {
14685440Sjm199354 		return (VS_ERR_AUTH);
14695440Sjm199354 	}
14705440Sjm199354 
14715440Sjm199354 	return (VS_ERR_NONE);
14725440Sjm199354 }
14735440Sjm199354 
14745440Sjm199354 
14755440Sjm199354 /*
14765440Sjm199354  * vs_props_get_engines
14776407Sjm199354  *
14785440Sjm199354  * On input, count specifies the maximum number of engine ids to
14795440Sjm199354  * return. engids must be an array with count entries.
14805440Sjm199354  * On return, count specifies the number of engine ids being
14815440Sjm199354  * returned in engids.
14826407Sjm199354  *
14836407Sjm199354  * Caller is responsible for free'ing the engids allocated herein.
14845440Sjm199354  */
14855440Sjm199354 static int
vs_props_get_engines(char * engids[],int * count)14866407Sjm199354 vs_props_get_engines(char *engids[], int *count)
14875440Sjm199354 {
14886407Sjm199354 	int i, prefix_len;
14896407Sjm199354 	char pgname[VS_PGNAME_ENGINE_LEN];
14905440Sjm199354 	vs_scfctx_t vsc;
14915440Sjm199354 
14925440Sjm199354 
14935440Sjm199354 	if (((vs_scf_ctx_open(&vsc)) != 0) ||
14945440Sjm199354 	    ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) ||
14955440Sjm199354 	    (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst,
14965440Sjm199354 	    SCF_GROUP_APPLICATION) != 0)) {
14975440Sjm199354 		vs_scf_ctx_close(&vsc);
14985440Sjm199354 		return (VS_ERR_SCF);
14995440Sjm199354 	}
15005440Sjm199354 
15016407Sjm199354 	for (i = 0; i < *count; i++)
15026407Sjm199354 		engids[i] = NULL;
15036407Sjm199354 
15046407Sjm199354 	i = 0;
15056407Sjm199354 	prefix_len = sizeof (VS_PGNAME_ENGINE_PREFIX) - 1;
15066407Sjm199354 
15075440Sjm199354 	while ((i < VS_SE_MAX) &&
15085440Sjm199354 	    (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)) {
15096407Sjm199354 		if (scf_pg_get_name(vsc.vscf_pgroup, pgname,
15106407Sjm199354 		    VS_PGNAME_ENGINE_LEN) < 0) {
15115440Sjm199354 			vs_scf_ctx_close(&vsc);
15125440Sjm199354 			return (VS_ERR_SCF);
15135440Sjm199354 		}
15145440Sjm199354 
15156407Sjm199354 		if (strncmp(pgname, VS_PGNAME_ENGINE_PREFIX, prefix_len) == 0) {
15166407Sjm199354 			if ((engids[i] = strdup(pgname + prefix_len)) != NULL) {
15176407Sjm199354 				if (++i == *count)
15186407Sjm199354 					break;
15196407Sjm199354 			}
15206407Sjm199354 		}
15215440Sjm199354 	}
15225440Sjm199354 	vs_scf_ctx_close(&vsc);
15235440Sjm199354 
15245440Sjm199354 	*count = i;
15255440Sjm199354 	return (VS_ERR_NONE);
15265440Sjm199354 }
15275440Sjm199354 
15285440Sjm199354 
15295440Sjm199354 /*
15305440Sjm199354  * vs_scf_pg_count
15315440Sjm199354  */
15325440Sjm199354 static int
vs_scf_pg_count(void)15335440Sjm199354 vs_scf_pg_count(void)
15345440Sjm199354 {
15355440Sjm199354 	int count = 0;
15365440Sjm199354 	vs_scfctx_t vsc;
15375440Sjm199354 
15385440Sjm199354 	if ((vs_scf_ctx_open(&vsc) != 0) ||
15395440Sjm199354 	    ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) ||
15405440Sjm199354 	    (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst,
15415440Sjm199354 	    SCF_GROUP_APPLICATION) != 0)) {
15425440Sjm199354 		vs_scf_ctx_close(&vsc);
15435440Sjm199354 		return (-1);
15445440Sjm199354 	}
15455440Sjm199354 
15465440Sjm199354 	while (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)
15475440Sjm199354 		++count;
15485440Sjm199354 
15495440Sjm199354 	vs_scf_ctx_close(&vsc);
15505440Sjm199354 
15515440Sjm199354 	return (count);
15525440Sjm199354 }
15535440Sjm199354 
15545440Sjm199354 
15555440Sjm199354 /*
15566407Sjm199354  * vs_engid_to_pgname
15576407Sjm199354  *
15586407Sjm199354  * To convert an engine id (engid) to a property group name (pgname),
15596407Sjm199354  * the engine id is prefixed with VS_PGNAME_ENGINE_PREFIX.
15606407Sjm199354  */
15616407Sjm199354 static void
vs_engid_to_pgname(const char * engid,char pgname[VS_PGNAME_ENGINE_LEN])15626407Sjm199354 vs_engid_to_pgname(const char *engid, char pgname[VS_PGNAME_ENGINE_LEN])
15636407Sjm199354 {
15646407Sjm199354 	(void) snprintf(pgname, VS_PGNAME_ENGINE_LEN, "%s%s",
15656407Sjm199354 	    VS_PGNAME_ENGINE_PREFIX, engid);
15666407Sjm199354 }
15676407Sjm199354 
15686407Sjm199354 
15696407Sjm199354 /*
15705440Sjm199354  *  vs_strtonum
15715440Sjm199354  *
15725440Sjm199354  *  Converts a size string in the format into an integer.
15735440Sjm199354  *
15745440Sjm199354  *  A size string is a numeric value followed by an optional unit
15755440Sjm199354  *  specifier which is used as a multiplier to calculate a raw
15765440Sjm199354  *  number.
15775440Sjm199354  *  The size string format is:  N[.N][KMGTP][B]
15785440Sjm199354  *
15795440Sjm199354  *  The numeric value can contain a decimal portion. Unit specifiers
15805440Sjm199354  *  are either a one-character or two-character string; i.e. "K" or
15815440Sjm199354  *  "KB" for kilobytes. Unit specifiers must follow the numeric portion
15825440Sjm199354  *  immediately, and are not case-sensitive.
15835440Sjm199354  *
15845440Sjm199354  *  If either "B" is specified, or there is no unit specifier portion
15855440Sjm199354  *  in the string, the numeric value is calculated with no multiplier
15865440Sjm199354  *  (assumes a basic unit of "bytes").
15875440Sjm199354  *
15885440Sjm199354  *  Returns:
15895440Sjm199354  *	-1:	Failure; errno set to specify the error.
15905440Sjm199354  *	 0:	Success.
15915440Sjm199354  */
15925440Sjm199354 int
vs_strtonum(const char * value,uint64_t * num)15935440Sjm199354 vs_strtonum(const char *value, uint64_t *num)
15945440Sjm199354 {
15955440Sjm199354 	char *end;
15965440Sjm199354 	int shift;
15975440Sjm199354 	double fval;
15985440Sjm199354 
15995440Sjm199354 	*num = 0;
16005440Sjm199354 
16015440Sjm199354 	/* Check to see if this looks like a number.  */
16025440Sjm199354 	if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
16035440Sjm199354 		errno = EINVAL;
16045440Sjm199354 		return (-1);
16055440Sjm199354 	}
16065440Sjm199354 
16075440Sjm199354 	/* Rely on stroll() to process the numeric portion.  */
16085440Sjm199354 	errno = 0;
16095440Sjm199354 	*num = strtoll(value, &end, 10);
16105440Sjm199354 
16115440Sjm199354 	/*
16125440Sjm199354 	 * Check for ERANGE, which indicates that the value is too large to
16135440Sjm199354 	 * fit in a 64-bit value.
16145440Sjm199354 	 */
16155440Sjm199354 	if (errno != 0)
16165440Sjm199354 		return (-1);
16175440Sjm199354 
16185440Sjm199354 	/*
16195440Sjm199354 	 * If we have a decimal value, then do the computation with floating
16205440Sjm199354 	 * point arithmetic.  Otherwise, use standard arithmetic.
16215440Sjm199354 	 */
16225440Sjm199354 	if (*end == '.') {
16235440Sjm199354 		fval = strtod(value, &end);
16245440Sjm199354 
16255440Sjm199354 		if ((shift = vs_strtoshift(end)) == -1)
16265440Sjm199354 			return (-1); /* errno set */
16275440Sjm199354 
16285440Sjm199354 		fval *= pow(2, shift);
16295440Sjm199354 		if (fval > UINT64_MAX) {
16305440Sjm199354 			errno = ERANGE;
16315440Sjm199354 			return (-1);
16325440Sjm199354 		}
16335440Sjm199354 
16345440Sjm199354 		*num = (uint64_t)fval;
16355440Sjm199354 	} else {
16365440Sjm199354 		if ((shift = vs_strtoshift(end)) == -1)
16375440Sjm199354 			return (-1); /* errno set */
16385440Sjm199354 
16395440Sjm199354 		/* Check for overflow */
16405440Sjm199354 		if (shift >= 64 || (*num << shift) >> shift != *num) {
16415440Sjm199354 			errno = ERANGE;
16425440Sjm199354 			return (-1);
16435440Sjm199354 		}
16445440Sjm199354 
16455440Sjm199354 		*num <<= shift;
16465440Sjm199354 	}
16475440Sjm199354 
16485440Sjm199354 	return (0);
16495440Sjm199354 }
16505440Sjm199354 
16515440Sjm199354 
16525440Sjm199354 /*
16535440Sjm199354  *  vs_strtoshift
16545440Sjm199354  *
16555440Sjm199354  *  Converts a unit specifier string into a number of bits that
16565440Sjm199354  *  a numeric value must be shifted.
16575440Sjm199354  *
16585440Sjm199354  *  Returns:
16595440Sjm199354  *	-1:	Failure; errno set to specify the error.
16605440Sjm199354  *	>-1:	Success; the shift count.
16615440Sjm199354  *
16625440Sjm199354  */
16635440Sjm199354 static int
vs_strtoshift(const char * buf)16645440Sjm199354 vs_strtoshift(const char *buf)
16655440Sjm199354 {
16665440Sjm199354 	const char *ends = "BKMGTPEZ";
16675440Sjm199354 	int i;
16685440Sjm199354 
16695440Sjm199354 	if (buf[0] == '\0')
16705440Sjm199354 		return (0);
16715440Sjm199354 	for (i = 0; i < strlen(ends); i++) {
16725440Sjm199354 		if (toupper(buf[0]) == ends[i])
16735440Sjm199354 			break;
16745440Sjm199354 	}
16755440Sjm199354 	if (i == strlen(ends)) {
16765440Sjm199354 		errno = EINVAL;
16775440Sjm199354 		return (-1);
16785440Sjm199354 	}
16795440Sjm199354 
16805440Sjm199354 	/* Allow trailing 'b' characters except in the case of 'BB'. */
16815440Sjm199354 	if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' &&
16825440Sjm199354 	    toupper(buf[0]) != 'B')) {
16835440Sjm199354 		return (10 * i);
16845440Sjm199354 	}
16855440Sjm199354 
16865440Sjm199354 	errno = EINVAL;
16875440Sjm199354 	return (-1);
16885440Sjm199354 }
1689