2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#include <string.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <unistd.h>
2N/A#include <ctype.h>
2N/A#include <math.h>
2N/A#include <limits.h>
2N/A#include <libscf.h>
2N/A#include <errno.h>
2N/A#include <fcntl.h>
2N/A#include <door.h>
2N/A#include <pwd.h>
2N/A#include <auth_attr.h>
2N/A#include <secdb.h>
2N/A#include <sys/socket.h>
2N/A#include <arpa/inet.h>
2N/A#include <libintl.h>
2N/A#include <libvscan.h>
2N/A
2N/A#define VS_DOOR_CALL_RETRIES 3
2N/A
2N/A#define VS_INSTANCE_FMRI "svc:/system/filesystem/vscan:icap"
2N/A
2N/A/* SMF property group and property names */
2N/A#define VS_PGNAME_GENERAL "vs_general"
2N/A#define VS_PGNAME_ENGINE_PREFIX "vs_engine_"
2N/A#define VS_PGNAME_ENGINE_LEN VS_SE_NAME_LEN + 16
2N/A
2N/A#define VS_PNAME_MAXSIZE "maxsize"
2N/A#define VS_PNAME_MAXSIZE_ACTION "maxsize_action"
2N/A#define VS_PNAME_TYPES "types"
2N/A#define VS_PNAME_VLOG "viruslog"
2N/A
2N/A#define VS_PNAME_SE_ENABLE "enable"
2N/A#define VS_PNAME_SE_HOST "host"
2N/A#define VS_PNAME_SE_PORT "port"
2N/A#define VS_PNAME_SE_MAXCONN "max_connect"
2N/A#define VS_PNAME_VAUTH "value_authorization"
2N/A
2N/A
2N/A/* types string processing */
2N/A#define VS_TYPES_SEP ','
2N/A#define VS_TYPES_ESCAPE '\\'
2N/A#define VS_TYPES_RULES "+-"
2N/A
2N/A
2N/A/*
2N/A * The SCF context enapsulating the SCF objects used in the
2N/A * repository load and store routines vs_scf_values_get()
2N/A * and vs_scf_values_set().
2N/A *
2N/A * The context is always opened before a get or set, then
2N/A * closed when finished (or on error); the open does an
2N/A * initial setup, while inside the get and set functions,
2N/A * additional objects within the context may be selectively
2N/A * initialized for use, depending on the actions needed and
2N/A * the properties being operated on.
2N/A */
2N/Atypedef struct vs_scfctx {
2N/A scf_handle_t *vscf_handle;
2N/A scf_instance_t *vscf_inst;
2N/A scf_propertygroup_t *vscf_pgroup;
2N/A scf_transaction_t *vscf_tx;
2N/A scf_iter_t *vscf_iter;
2N/A scf_property_t *vscf_prop[VS_NUM_PROPIDS];
2N/A scf_transaction_entry_t *vscf_ent[VS_NUM_PROPIDS];
2N/A scf_value_t *vscf_val[VS_NUM_PROPIDS];
2N/A} vs_scfctx_t;
2N/A
2N/A/*
2N/A * The vscan property definition. Maps the property id with the name
2N/A * and type used to store the property in the repository.
2N/A * A table of these definitions is defined with a single entry per
2N/A * property.
2N/A */
2N/Atypedef struct {
2N/A const char *vpd_name;
2N/A uint64_t vpd_id;
2N/A scf_type_t vpd_type;
2N/A} vs_propdef_t;
2N/A
2N/Atypedef enum {
2N/A VS_PTYPE_GEN,
2N/A VS_PTYPE_SE
2N/A} vs_prop_type_t;
2N/A
2N/Atypedef struct vs_prop_hd {
2N/A vs_prop_type_t vp_type;
2N/A uint64_t vp_ids;
2N/A uint64_t vp_all;
2N/A union {
2N/A vs_props_t vp_gen;
2N/A vs_props_se_t vp_se;
2N/A } vp_props;
2N/A} vs_prop_hd_t;
2N/A
2N/A#define vp_gen vp_props.vp_gen
2N/A#define vp_se vp_props.vp_se
2N/A
2N/A/*
2N/A * Default values - these are used to return valid data
2N/A * to the caller in cases where invalid or unexpected values
2N/A * are found in the repository.
2N/A *
2N/A * Note: These values must be kept in sync with those defined
2N/A * in the service manifest.
2N/A */
2N/Astatic const boolean_t vs_dflt_allow = B_TRUE;
2N/Astatic const boolean_t vs_dflt_enable = B_TRUE;
2N/Astatic const char *vs_dflt_maxsize = "1GB";
2N/Astatic const char *vs_dflt_host = "";
2N/Astatic const uint16_t vs_dflt_port = 1344;
2N/Astatic const uint16_t vs_dflt_maxconn = 8;
2N/Astatic const char *vs_dflt_types = "+*";
2N/Astatic const char *vs_dflt_vlog = "";
2N/A
2N/A/* Property definition table */
2N/Astatic const vs_propdef_t vs_propdefs[] = {
2N/A /* general properties */
2N/A { VS_PNAME_MAXSIZE, VS_PROPID_MAXSIZE, SCF_TYPE_ASTRING },
2N/A { VS_PNAME_MAXSIZE_ACTION, VS_PROPID_MAXSIZE_ACTION, SCF_TYPE_BOOLEAN },
2N/A { VS_PNAME_TYPES, VS_PROPID_TYPES, SCF_TYPE_ASTRING },
2N/A { VS_PNAME_VLOG, VS_PROPID_VLOG, SCF_TYPE_ASTRING },
2N/A /* scan engine properties */
2N/A { VS_PNAME_SE_ENABLE, VS_PROPID_SE_ENABLE, SCF_TYPE_BOOLEAN },
2N/A { VS_PNAME_SE_HOST, VS_PROPID_SE_HOST, SCF_TYPE_HOST },
2N/A { VS_PNAME_SE_PORT, VS_PROPID_SE_PORT, SCF_TYPE_INTEGER },
2N/A { VS_PNAME_SE_MAXCONN, VS_PROPID_SE_MAXCONN, SCF_TYPE_INTEGER },
2N/A { VS_PNAME_VAUTH, VS_PROPID_VALUE_AUTH, SCF_TYPE_ASTRING }
2N/A};
2N/A
2N/Astatic const int vs_npropdefs = sizeof (vs_propdefs)/sizeof (vs_propdef_t);
2N/A
2N/A/* Local functions */
2N/Astatic const vs_propdef_t *vs_get_propdef(uint64_t);
2N/Astatic void vs_default_value(vs_prop_hd_t *, const uint64_t);
2N/A
2N/Astatic int vs_scf_values_get(const char *, vs_prop_hd_t *);
2N/Astatic int vs_scf_get(const vs_propdef_t *, vs_prop_hd_t *, vs_scfctx_t *, int);
2N/A
2N/Astatic int vs_scf_values_set(const char *, vs_prop_hd_t *);
2N/Astatic int vs_scf_set(const vs_propdef_t *, vs_prop_hd_t *, vs_scfctx_t *, int);
2N/Astatic int vs_scf_pg_create(const char *, vs_prop_hd_t *);
2N/Astatic int vs_scf_pg_delete(const char *);
2N/A
2N/Astatic int vs_scf_ctx_open(vs_scfctx_t *);
2N/Astatic void vs_scf_ctx_close(vs_scfctx_t *);
2N/A
2N/Astatic int vs_validate(const vs_prop_hd_t *, uint64_t);
2N/Astatic int vs_is_valid_types(const char *);
2N/Astatic int vs_is_valid_host(const char *);
2N/Astatic int vs_checkauth(char *);
2N/Astatic int vs_door_call(int, door_arg_t *);
2N/A
2N/Astatic int vs_props_get_engines(char *[], int *);
2N/Astatic void vs_engid_to_pgname(const char *, char [VS_PGNAME_ENGINE_LEN]);
2N/Astatic int vs_scf_pg_count(void);
2N/Astatic int vs_strtoshift(const char *);
2N/A
2N/A
2N/A/*
2N/A * vs_props_get_all
2N/A *
2N/A * Retrieves the general service properties and all properties
2N/A * for all scan engines from the repository.
2N/A *
2N/A * If invalid property values are found, the values are corrected to
2N/A * the default value.
2N/A *
2N/A * Return codes:
2N/A * VS_ERR_VS_ERR_NONE
2N/A * VS_ERR_SCF
2N/A * VS_ERR_SYS
2N/A */
2N/Aint
2N/Avs_props_get_all(vs_props_all_t *va)
2N/A{
2N/A int i, rc, n;
2N/A char *engids[VS_SE_MAX];
2N/A
2N/A (void) memset(va, 0, sizeof (vs_props_all_t));
2N/A if ((rc = vs_props_get(&va->va_props, VS_PROPID_GEN_ALL))
2N/A != VS_ERR_NONE)
2N/A return (rc);
2N/A
2N/A n = VS_SE_MAX;
2N/A if ((rc = vs_props_get_engines(engids, &n)) != VS_ERR_NONE)
2N/A return (rc);
2N/A
2N/A for (i = 0; i < n; i++) {
2N/A if ((rc = vs_props_se_get(engids[i],
2N/A &va->va_se[i], VS_PROPID_SE_ALL)) != VS_ERR_NONE)
2N/A break;
2N/A }
2N/A
2N/A /* free engids allocated in vs_props_get_engines */
2N/A for (i = 0; i < VS_SE_MAX; i++) {
2N/A if (engids[i] != NULL)
2N/A free(engids[i]);
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_props_get
2N/A *
2N/A * Retrieves values for the specified general service properties from
2N/A * the repository.
2N/A *
2N/A * If invalid property values are found, the values are corrected to
2N/A * the default value.
2N/A *
2N/A * Return codes:
2N/A * VS_ERR_VS_ERR_NONE
2N/A * VS_ERR_INVALID_PROPERTY
2N/A * VS_ERR_SCF
2N/A * VS_ERR_SYS
2N/A */
2N/Aint
2N/Avs_props_get(vs_props_t *vp, uint64_t propids)
2N/A{
2N/A int rc;
2N/A vs_prop_hd_t prop_hd;
2N/A
2N/A if ((propids & VS_PROPID_GEN_ALL) != propids)
2N/A return (VS_ERR_INVALID_PROPERTY);
2N/A
2N/A (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
2N/A prop_hd.vp_type = VS_PTYPE_GEN;
2N/A prop_hd.vp_ids = propids;
2N/A prop_hd.vp_all = VS_PROPID_GEN_ALL;
2N/A
2N/A rc = vs_scf_values_get(VS_PGNAME_GENERAL, &prop_hd);
2N/A
2N/A *vp = prop_hd.vp_gen;
2N/A return (rc);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_props_set
2N/A *
2N/A * Changes values for the specified general service properties
2N/A * in the repository.
2N/A *
2N/A * Return codes:
2N/A * VS_ERR_VS_ERR_NONE
2N/A * VS_ERR_INVALID_PROPERTY
2N/A * VS_ERR_INVALID_VALUE
2N/A * VS_ERR_SCF
2N/A * VS_ERR_SYS
2N/A */
2N/Aint
2N/Avs_props_set(const vs_props_t *vp, uint64_t propids)
2N/A{
2N/A vs_prop_hd_t prop_hd;
2N/A
2N/A if ((propids & VS_PROPID_GEN_ALL) != propids)
2N/A return (VS_ERR_INVALID_PROPERTY);
2N/A
2N/A (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
2N/A prop_hd.vp_type = VS_PTYPE_GEN;
2N/A prop_hd.vp_ids = propids;
2N/A prop_hd.vp_all = VS_PROPID_GEN_ALL;
2N/A prop_hd.vp_gen = *vp;
2N/A return (vs_scf_values_set(VS_PGNAME_GENERAL, &prop_hd));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_props_se_get
2N/A *
2N/A * Retrieves values for the specified scan engine properties from the
2N/A * repository.
2N/A *
2N/A * If the enable property is set (true), the host property is
2N/A * checked for validity. If it is not valid, the requested values
2N/A * are returned with the enable propery set to off (false)
2N/A *
2N/A * Return codes:
2N/A * VS_ERR_VS_ERR_NONE
2N/A * VS_ERR_INVALID_PROPERTY
2N/A * VS_ERR_SCF
2N/A * VS_ERR_SYS
2N/A */
2N/Aint
2N/Avs_props_se_get(char *engid, vs_props_se_t *sep, uint64_t propids)
2N/A{
2N/A int rc;
2N/A char pgname[VS_PGNAME_ENGINE_LEN];
2N/A vs_prop_hd_t prop_hd;
2N/A
2N/A /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
2N/A if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
2N/A return (VS_ERR_INVALID_SE);
2N/A
2N/A if ((propids & VS_PROPID_SE_ALL) != propids)
2N/A return (VS_ERR_INVALID_PROPERTY);
2N/A
2N/A (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
2N/A prop_hd.vp_type = VS_PTYPE_SE;
2N/A prop_hd.vp_ids = propids;
2N/A prop_hd.vp_all = VS_PROPID_SE_ALL;
2N/A (void) strlcpy(prop_hd.vp_se.vep_engid, engid, VS_SE_NAME_LEN);
2N/A
2N/A /* If getting enable, get the host property too */
2N/A if ((propids & VS_PROPID_SE_ENABLE))
2N/A prop_hd.vp_ids |= VS_PROPID_SE_HOST;
2N/A
2N/A /* Load values from the repository */
2N/A vs_engid_to_pgname(engid, pgname);
2N/A rc = vs_scf_values_get(pgname, &prop_hd);
2N/A if (rc != VS_ERR_NONE)
2N/A return (rc);
2N/A
2N/A /*
2N/A * If the host is invalid and the enable property is on,
2N/A * return enable property as off
2N/A */
2N/A if ((prop_hd.vp_ids & VS_PROPID_SE_HOST) &&
2N/A (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)) {
2N/A prop_hd.vp_se.vep_enable = B_FALSE;
2N/A }
2N/A
2N/A *sep = prop_hd.vp_se;
2N/A return (rc);
2N/A}
2N/A
2N/A
2N/A
2N/A/*
2N/A * vs_props_se_set
2N/A *
2N/A * Changes the values for the specified scan engine properties in the
2N/A * repository.
2N/A *
2N/A * If the enable property is being changed to true in this operation,
2N/A * a host property must also be specified, or already exist in the
2N/A * repository.
2N/A *
2N/A * Return codes:
2N/A * VS_ERR_NONE
2N/A * VS_ERR_INVALID_PROPERTY
2N/A * VS_ERR_INVALID_VALUE
2N/A * VS_ERR_SCF
2N/A * VS_ERR_SYS
2N/A */
2N/Aint
2N/Avs_props_se_set(char *engid, const vs_props_se_t *sep, uint64_t propids)
2N/A{
2N/A int rc;
2N/A char pgname[VS_PGNAME_ENGINE_LEN];
2N/A vs_prop_hd_t prop_hd;
2N/A
2N/A /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
2N/A if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
2N/A return (VS_ERR_INVALID_SE);
2N/A
2N/A if ((propids & VS_PROPID_SE_ALL) != propids)
2N/A return (VS_ERR_INVALID_PROPERTY);
2N/A
2N/A (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
2N/A prop_hd.vp_type = VS_PTYPE_SE;
2N/A prop_hd.vp_all = VS_PROPID_SE_ALL;
2N/A
2N/A vs_engid_to_pgname(engid, pgname);
2N/A
2N/A /*
2N/A * if enabling a scan engine, ensure that a valid host
2N/A * is also being set, or already exists in the repository
2N/A */
2N/A if ((propids & VS_PROPID_SE_ENABLE) && (sep->vep_enable == B_TRUE) &&
2N/A !(propids & VS_PROPID_SE_HOST)) {
2N/A
2N/A prop_hd.vp_ids = VS_PROPID_SE_HOST;
2N/A if ((rc = vs_scf_values_get(pgname, &prop_hd)) != VS_ERR_NONE)
2N/A return (rc);
2N/A
2N/A if (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)
2N/A return (VS_ERR_INVALID_HOST);
2N/A }
2N/A
2N/A prop_hd.vp_ids = propids;
2N/A prop_hd.vp_se = *sep;
2N/A
2N/A return (vs_scf_values_set(pgname, &prop_hd));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_props_se_create
2N/A */
2N/Aint
2N/Avs_props_se_create(char *engid, const vs_props_se_t *sep, uint64_t propids)
2N/A{
2N/A int n;
2N/A char pgname[VS_PGNAME_ENGINE_LEN];
2N/A vs_prop_hd_t prop_hd;
2N/A
2N/A if ((propids & VS_PROPID_SE_ALL) != propids)
2N/A return (VS_ERR_INVALID_PROPERTY);
2N/A
2N/A /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
2N/A if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
2N/A return (VS_ERR_INVALID_SE);
2N/A
2N/A if ((n = vs_scf_pg_count()) == -1)
2N/A return (VS_ERR_SCF);
2N/A
2N/A if (n == VS_SE_MAX)
2N/A return (VS_ERR_MAX_SE);
2N/A
2N/A vs_engid_to_pgname(engid, pgname);
2N/A
2N/A (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
2N/A prop_hd.vp_type = VS_PTYPE_SE;
2N/A prop_hd.vp_all = VS_PROPID_SE_ALL;
2N/A prop_hd.vp_ids = propids | VS_PROPID_VALUE_AUTH;
2N/A prop_hd.vp_se = *sep;
2N/A
2N/A /* if hostname not specified, default it to engid */
2N/A if ((propids & VS_PROPID_SE_HOST) == 0) {
2N/A (void) strlcpy(prop_hd.vp_se.vep_host, engid, MAXHOSTNAMELEN);
2N/A prop_hd.vp_ids |= VS_PROPID_SE_HOST;
2N/A }
2N/A
2N/A return (vs_scf_pg_create(pgname, &prop_hd));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_props_se_delete
2N/A */
2N/Aint
2N/Avs_props_se_delete(const char *engid)
2N/A{
2N/A char pgname[VS_PGNAME_ENGINE_LEN];
2N/A
2N/A /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
2N/A if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
2N/A return (VS_ERR_INVALID_SE);
2N/A
2N/A vs_engid_to_pgname(engid, pgname);
2N/A
2N/A return (vs_scf_pg_delete(pgname));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_strerror
2N/A */
2N/Aconst char *
2N/Avs_strerror(int error)
2N/A{
2N/A switch (error) {
2N/A case VS_ERR_NONE:
2N/A return (gettext("no error"));
2N/A case VS_ERR_INVALID_PROPERTY:
2N/A return (gettext("invalid property id"));
2N/A case VS_ERR_INVALID_VALUE:
2N/A return (gettext("invalid property value"));
2N/A case VS_ERR_INVALID_HOST:
2N/A return (gettext("invalid host"));
2N/A case VS_ERR_INVALID_SE:
2N/A return (gettext("invalid scan engine"));
2N/A case VS_ERR_MAX_SE:
2N/A return (gettext("max scan engines exceeded"));
2N/A case VS_ERR_AUTH:
2N/A return (gettext("insufficient privileges for action"));
2N/A case VS_ERR_DAEMON_COMM:
2N/A return (gettext("unable to contact vscand"));
2N/A case VS_ERR_SCF:
2N/A return (scf_strerror(scf_error()));
2N/A case VS_ERR_SYS:
2N/A return (strerror(errno));
2N/A default:
2N/A return (gettext("unknown error"));
2N/A }
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_get_propdef
2N/A *
2N/A * Finds and returns a property definition by property id.
2N/A */
2N/Astatic const vs_propdef_t *
2N/Avs_get_propdef(uint64_t propid)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < vs_npropdefs; i++) {
2N/A if (propid == vs_propdefs[i].vpd_id)
2N/A return (&vs_propdefs[i]);
2N/A }
2N/A
2N/A return (NULL);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_default_value
2N/A *
2N/A * Sets a property value that contains invalid data to its default value.
2N/A *
2N/A * Note that this function does not alter any values in the repository
2N/A * This is only to enable the caller to get valid data.
2N/A */
2N/Astatic void
2N/Avs_default_value(vs_prop_hd_t *prop_hd, const uint64_t propid)
2N/A{
2N/A vs_props_t *vp = &prop_hd->vp_gen;
2N/A vs_props_se_t *vep = &prop_hd->vp_se;
2N/A
2N/A switch (propid) {
2N/A case VS_PROPID_MAXSIZE:
2N/A (void) strlcpy(vp->vp_maxsize, vs_dflt_maxsize,
2N/A sizeof (vp->vp_maxsize));
2N/A break;
2N/A case VS_PROPID_MAXSIZE_ACTION:
2N/A vp->vp_maxsize_action = vs_dflt_allow;
2N/A break;
2N/A case VS_PROPID_TYPES:
2N/A (void) strlcpy(vp->vp_types, vs_dflt_types,
2N/A sizeof (vp->vp_types));
2N/A break;
2N/A case VS_PROPID_VLOG:
2N/A (void) strlcpy(vp->vp_vlog, vs_dflt_vlog,
2N/A sizeof (vp->vp_vlog));
2N/A break;
2N/A case VS_PROPID_SE_ENABLE:
2N/A vep->vep_enable = vs_dflt_enable;
2N/A break;
2N/A case VS_PROPID_SE_HOST:
2N/A (void) strlcpy(vep->vep_host, vs_dflt_host,
2N/A sizeof (vep->vep_host));
2N/A break;
2N/A case VS_PROPID_SE_PORT:
2N/A vep->vep_port = vs_dflt_port;
2N/A break;
2N/A case VS_PROPID_SE_MAXCONN:
2N/A vep->vep_maxconn = vs_dflt_maxconn;
2N/A break;
2N/A default:
2N/A break;
2N/A }
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_scf_values_get
2N/A *
2N/A * Gets property values for one or more properties from the repository.
2N/A * This is the single entry point for loading SMF values.
2N/A *
2N/A * While a transaction is not used for loading property values,
2N/A * the operation is parameterized by a property group. All properties
2N/A * retrieved in this function, then, must belong to the same property
2N/A * group.
2N/A */
2N/Aint
2N/Avs_scf_values_get(const char *pgname, vs_prop_hd_t *prop_hd)
2N/A{
2N/A vs_scfctx_t vsc;
2N/A int rc, np;
2N/A const vs_propdef_t *vpd;
2N/A uint64_t propid;
2N/A
2N/A if ((vs_scf_ctx_open(&vsc)) != 0) {
2N/A vs_scf_ctx_close(&vsc);
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
2N/A vs_scf_ctx_close(&vsc);
2N/A if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) {
2N/A rc = scf_error();
2N/A if ((rc == SCF_ERROR_NOT_FOUND) ||
2N/A (rc == SCF_ERROR_INVALID_ARGUMENT))
2N/A return (VS_ERR_INVALID_SE);
2N/A }
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A rc = VS_ERR_NONE;
2N/A np = 0;
2N/A for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
2N/A if ((prop_hd->vp_ids & propid) == 0)
2N/A continue;
2N/A
2N/A if ((vpd = vs_get_propdef(propid)) == NULL) {
2N/A rc = VS_ERR_INVALID_PROPERTY;
2N/A break;
2N/A }
2N/A
2N/A vsc.vscf_prop[np] = scf_property_create(vsc.vscf_handle);
2N/A vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
2N/A
2N/A if (vsc.vscf_prop[np] == NULL || vsc.vscf_val[np] == NULL) {
2N/A rc = VS_ERR_SCF;
2N/A break;
2N/A }
2N/A
2N/A if (scf_pg_get_property(vsc.vscf_pgroup, vpd->vpd_name,
2N/A vsc.vscf_prop[np]) == -1) {
2N/A if (scf_error() == SCF_ERROR_NOT_FOUND) {
2N/A vs_default_value(prop_hd, vpd->vpd_id);
2N/A continue;
2N/A }
2N/A rc = VS_ERR_SCF;
2N/A break;
2N/A }
2N/A
2N/A if ((rc = vs_scf_get(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
2N/A break;
2N/A
2N/A ++np;
2N/A }
2N/A
2N/A
2N/A vs_scf_ctx_close(&vsc);
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_scf_get
2N/A *
2N/A * Loads a single values from the repository into the appropriate vscan
2N/A * property structure member.
2N/A */
2N/Astatic int
2N/Avs_scf_get(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
2N/A vs_scfctx_t *vsc, int idx)
2N/A{
2N/A int rc;
2N/A int64_t port;
2N/A uint8_t valbool;
2N/A vs_props_t *vp = &prop_hd->vp_gen;
2N/A vs_props_se_t *vep = &prop_hd->vp_se;
2N/A
2N/A if ((rc = scf_property_get_value(vsc->vscf_prop[idx],
2N/A vsc->vscf_val[idx])) == -1) {
2N/A if (rc == SCF_ERROR_CONSTRAINT_VIOLATED ||
2N/A rc == SCF_ERROR_NOT_FOUND) {
2N/A vs_default_value(prop_hd, vpd->vpd_id);
2N/A return (VS_ERR_NONE);
2N/A }
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A rc = VS_ERR_NONE;
2N/A switch (vpd->vpd_id) {
2N/A case VS_PROPID_MAXSIZE:
2N/A if ((scf_value_get_astring(vsc->vscf_val[idx],
2N/A vp->vp_maxsize, sizeof (vp->vp_maxsize))) == -1) {
2N/A return (VS_ERR_SCF);
2N/A }
2N/A break;
2N/A case VS_PROPID_MAXSIZE_ACTION:
2N/A if ((scf_value_get_boolean(vsc->vscf_val[idx],
2N/A &valbool)) == -1) {
2N/A return (VS_ERR_SCF);
2N/A }
2N/A vp->vp_maxsize_action = (valbool == 0) ? B_FALSE : B_TRUE;
2N/A break;
2N/A case VS_PROPID_TYPES:
2N/A if ((scf_value_get_astring(vsc->vscf_val[idx],
2N/A vp->vp_types, sizeof (vp->vp_types))) == -1) {
2N/A return (VS_ERR_SCF);
2N/A }
2N/A break;
2N/A case VS_PROPID_VLOG:
2N/A if ((scf_value_get_astring(vsc->vscf_val[idx],
2N/A vp->vp_vlog, sizeof (vp->vp_vlog))) == -1) {
2N/A return (VS_ERR_SCF);
2N/A }
2N/A break;
2N/A case VS_PROPID_SE_ENABLE:
2N/A if ((scf_value_get_boolean(vsc->vscf_val[idx],
2N/A &valbool)) == -1) {
2N/A return (VS_ERR_SCF);
2N/A }
2N/A vep->vep_enable = (valbool == 0) ? B_FALSE : B_TRUE;
2N/A break;
2N/A case VS_PROPID_SE_HOST:
2N/A (void) scf_value_get_as_string_typed(vsc->vscf_val[idx],
2N/A vpd->vpd_type, vep->vep_host, sizeof (vep->vep_host));
2N/A break;
2N/A case VS_PROPID_SE_PORT:
2N/A if ((scf_value_get_integer(vsc->vscf_val[idx], &port)) == -1)
2N/A return (VS_ERR_SCF);
2N/A if (port <= 0 || port >= UINT16_MAX)
2N/A rc = VS_ERR_INVALID_VALUE;
2N/A else
2N/A vep->vep_port = (uint16_t)port;
2N/A break;
2N/A case VS_PROPID_SE_MAXCONN:
2N/A if ((scf_value_get_integer(vsc->vscf_val[idx],
2N/A (int64_t *)&vep->vep_maxconn)) == -1) {
2N/A return (VS_ERR_SCF);
2N/A }
2N/A break;
2N/A default:
2N/A break;
2N/A }
2N/A
2N/A if ((rc != VS_ERR_NONE) ||
2N/A (vs_validate(prop_hd, vpd->vpd_id) != VS_ERR_NONE)) {
2N/A vs_default_value(prop_hd, vpd->vpd_id);
2N/A }
2N/A
2N/A return (VS_ERR_NONE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_scf_pg_create
2N/A */
2N/Astatic int
2N/Avs_scf_pg_create(const char *pgname, vs_prop_hd_t *prop_hd)
2N/A{
2N/A int rc;
2N/A uint64_t propid;
2N/A vs_scfctx_t vsc;
2N/A
2N/A /* ensure that caller has authorization to refresh service */
2N/A if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
2N/A return (rc);
2N/A
2N/A if (vs_scf_ctx_open(&vsc) != 0) {
2N/A vs_scf_ctx_close(&vsc);
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A if (scf_instance_add_pg(vsc.vscf_inst, pgname,
2N/A SCF_GROUP_APPLICATION, 0, vsc.vscf_pgroup) == -1) {
2N/A vs_scf_ctx_close(&vsc);
2N/A if (scf_error() == SCF_ERROR_INVALID_ARGUMENT)
2N/A return (VS_ERR_INVALID_SE);
2N/A return (VS_ERR_SCF);
2N/A }
2N/A vs_scf_ctx_close(&vsc);
2N/A
2N/A /* set default values for those not specified */
2N/A for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
2N/A if ((propid & prop_hd->vp_all) && !(propid & prop_hd->vp_ids))
2N/A vs_default_value(prop_hd, propid);
2N/A }
2N/A
2N/A prop_hd->vp_ids = prop_hd->vp_all;
2N/A prop_hd->vp_ids |= VS_PROPID_VALUE_AUTH;
2N/A
2N/A rc = vs_scf_values_set(pgname, prop_hd);
2N/A if (rc != VS_ERR_NONE)
2N/A (void) vs_scf_pg_delete(pgname);
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_scf_pg_delete
2N/A */
2N/Astatic int
2N/Avs_scf_pg_delete(const char *pgname)
2N/A{
2N/A int rc;
2N/A vs_scfctx_t vsc;
2N/A
2N/A /* ensure that caller has authorization to refresh service */
2N/A if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
2N/A return (rc);
2N/A
2N/A if (vs_scf_ctx_open(&vsc) != 0) {
2N/A vs_scf_ctx_close(&vsc);
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
2N/A vs_scf_ctx_close(&vsc);
2N/A rc = scf_error();
2N/A if ((rc == SCF_ERROR_NOT_FOUND) ||
2N/A (rc == SCF_ERROR_INVALID_ARGUMENT))
2N/A return (VS_ERR_INVALID_SE);
2N/A else
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A if (scf_pg_delete(vsc.vscf_pgroup) == -1) {
2N/A vs_scf_ctx_close(&vsc);
2N/A rc = scf_error();
2N/A if ((rc == SCF_ERROR_NOT_FOUND) ||
2N/A (rc == SCF_ERROR_INVALID_ARGUMENT))
2N/A return (VS_ERR_INVALID_SE);
2N/A
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A vs_scf_ctx_close(&vsc);
2N/A
2N/A /* Notify the daemon that things have changed */
2N/A if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1) {
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A return (VS_ERR_NONE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_scf_values_set
2N/A *
2N/A * Sets property values in the repository. This is the single
2N/A * entry point for storing SMF values.
2N/A *
2N/A * Like loading values, this is an operation based on a single property
2N/A * group, so all property values changed in this function must belong
2N/A * to the same property group. Additionally, this operation is done in
2N/A * the context of a repository transaction; on any fatal error, the
2N/A * SCF context will be closed, destroying all SCF objects and aborting
2N/A * the transaction.
2N/A */
2N/Astatic int
2N/Avs_scf_values_set(const char *pgname, vs_prop_hd_t *prop_hd)
2N/A{
2N/A int rc, np;
2N/A const vs_propdef_t *vpd;
2N/A uint64_t propid;
2N/A vs_scfctx_t vsc;
2N/A
2N/A /* ensure that caller has authorization to refresh service */
2N/A if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
2N/A return (rc);
2N/A
2N/A if (vs_scf_ctx_open(&vsc) != 0) {
2N/A vs_scf_ctx_close(&vsc);
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
2N/A vs_scf_ctx_close(&vsc);
2N/A rc = scf_error();
2N/A if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) {
2N/A if ((rc == SCF_ERROR_NOT_FOUND) ||
2N/A (rc == SCF_ERROR_INVALID_ARGUMENT))
2N/A return (VS_ERR_INVALID_SE);
2N/A }
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A if (((vsc.vscf_tx = scf_transaction_create(vsc.vscf_handle)) == NULL) ||
2N/A (scf_transaction_start(vsc.vscf_tx, vsc.vscf_pgroup) == -1)) {
2N/A vs_scf_ctx_close(&vsc);
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A /* Process the value change for each specified property */
2N/A rc = 0;
2N/A np = 0;
2N/A for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
2N/A if ((prop_hd->vp_ids & propid) == 0)
2N/A continue;
2N/A
2N/A if ((vpd = vs_get_propdef(propid)) == NULL) {
2N/A rc = VS_ERR_INVALID_PROPERTY;
2N/A break;
2N/A }
2N/A
2N/A vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
2N/A vsc.vscf_ent[np] = scf_entry_create(vsc.vscf_handle);
2N/A
2N/A if (vsc.vscf_val[np] == NULL || vsc.vscf_ent[np] == NULL) {
2N/A rc = VS_ERR_SCF;
2N/A break;
2N/A }
2N/A
2N/A if ((rc = scf_transaction_property_change(vsc.vscf_tx,
2N/A vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type)) == -1) {
2N/A rc = scf_transaction_property_new(vsc.vscf_tx,
2N/A vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type);
2N/A }
2N/A if (rc == -1) {
2N/A rc = VS_ERR_SCF;
2N/A break;
2N/A }
2N/A
2N/A if ((rc = vs_scf_set(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
2N/A break;
2N/A
2N/A ++np;
2N/A }
2N/A
2N/A if (rc != VS_ERR_NONE) {
2N/A vs_scf_ctx_close(&vsc);
2N/A return (rc);
2N/A }
2N/A
2N/A /* Commit the transaction */
2N/A if (scf_transaction_commit(vsc.vscf_tx) == -1) {
2N/A vs_scf_ctx_close(&vsc);
2N/A return (VS_ERR_SCF);
2N/A }
2N/A vs_scf_ctx_close(&vsc);
2N/A
2N/A /* Notify the daemon that things have changed */
2N/A if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1)
2N/A return (VS_ERR_SCF);
2N/A
2N/A return (VS_ERR_NONE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_scf_set
2N/A *
2N/A * Stores a single value from the appropriate vscan property structure
2N/A * member into the repository.
2N/A *
2N/A * Values are set in the SCF value object, then the value object
2N/A * is added to the SCF property object.
2N/A */
2N/Astatic int
2N/Avs_scf_set(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
2N/A vs_scfctx_t *vsc, int idx)
2N/A{
2N/A int rc;
2N/A vs_props_t *vp = &prop_hd->vp_gen;
2N/A vs_props_se_t *vep = &prop_hd->vp_se;
2N/A
2N/A if ((rc = vs_validate(prop_hd, vpd->vpd_id)) != VS_ERR_NONE)
2N/A return (rc);
2N/A
2N/A rc = VS_ERR_NONE;
2N/A switch (vpd->vpd_id) {
2N/A case VS_PROPID_MAXSIZE:
2N/A if ((scf_value_set_astring(vsc->vscf_val[idx],
2N/A vp->vp_maxsize)) == -1) {
2N/A rc = VS_ERR_SCF;
2N/A }
2N/A break;
2N/A case VS_PROPID_MAXSIZE_ACTION:
2N/A scf_value_set_boolean(vsc->vscf_val[idx],
2N/A (uint8_t)vp->vp_maxsize_action);
2N/A break;
2N/A case VS_PROPID_TYPES:
2N/A if ((scf_value_set_astring(vsc->vscf_val[idx],
2N/A vp->vp_types)) == -1) {
2N/A return (VS_ERR_SCF);
2N/A }
2N/A break;
2N/A case VS_PROPID_SE_ENABLE:
2N/A scf_value_set_boolean(vsc->vscf_val[idx],
2N/A (uint8_t)vep->vep_enable);
2N/A break;
2N/A case VS_PROPID_SE_HOST:
2N/A if ((scf_value_set_from_string(vsc->vscf_val[idx],
2N/A vpd->vpd_type, vep->vep_host)) == -1) {
2N/A rc = VS_ERR_SCF;
2N/A }
2N/A break;
2N/A case VS_PROPID_SE_PORT:
2N/A scf_value_set_integer(vsc->vscf_val[idx], vep->vep_port);
2N/A break;
2N/A case VS_PROPID_SE_MAXCONN:
2N/A scf_value_set_integer(vsc->vscf_val[idx],
2N/A vep->vep_maxconn);
2N/A break;
2N/A case VS_PROPID_VALUE_AUTH:
2N/A if ((scf_value_set_astring(vsc->vscf_val[idx],
2N/A VS_VALUE_AUTH)) == -1) {
2N/A return (VS_ERR_SCF);
2N/A }
2N/A break;
2N/A default:
2N/A break;
2N/A }
2N/A
2N/A if ((scf_entry_add_value(vsc->vscf_ent[idx],
2N/A vsc->vscf_val[idx])) == -1) {
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_scf_ctx_open
2N/A *
2N/A * Opens an SCF context; creates the minumum SCF objects
2N/A * for use in loading/storing from the SMF repository (meaning
2N/A * vscf_property group data).
2N/A *
2N/A * Other SCF objects in the context may be initialized elsewher
2N/A * subsequent to open, but all initialized structures are destroyed
2N/A * in vs_scf_ctx_close().
2N/A */
2N/Astatic int
2N/Avs_scf_ctx_open(vs_scfctx_t *vsc)
2N/A{
2N/A (void) memset(vsc, 0, sizeof (vs_scfctx_t));
2N/A
2N/A if ((vsc->vscf_handle = scf_handle_create(SCF_VERSION)) == NULL)
2N/A return (VS_ERR_SCF);
2N/A
2N/A if (scf_handle_bind(vsc->vscf_handle) == -1)
2N/A return (VS_ERR_SCF);
2N/A
2N/A if ((vsc->vscf_inst = scf_instance_create(vsc->vscf_handle)) == NULL)
2N/A return (VS_ERR_SCF);
2N/A
2N/A if (scf_handle_decode_fmri(vsc->vscf_handle, VS_INSTANCE_FMRI,
2N/A NULL, NULL, vsc->vscf_inst, NULL, NULL,
2N/A SCF_DECODE_FMRI_EXACT) == -1) {
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A if ((vsc->vscf_pgroup = scf_pg_create(vsc->vscf_handle)) == NULL)
2N/A return (VS_ERR_SCF);
2N/A
2N/A return (VS_ERR_NONE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_scf_ctx_close
2N/A *
2N/A * Closes an SCF context; destroys all initialized SCF objects.
2N/A */
2N/Astatic void
2N/Avs_scf_ctx_close(vs_scfctx_t *vsc)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < VS_NUM_PROPIDS; i++) {
2N/A if (vsc->vscf_val[i])
2N/A scf_value_destroy(vsc->vscf_val[i]);
2N/A if (vsc->vscf_ent[i])
2N/A scf_entry_destroy(vsc->vscf_ent[i]);
2N/A if (vsc->vscf_prop[i])
2N/A scf_property_destroy(vsc->vscf_prop[i]);
2N/A }
2N/A
2N/A if (vsc->vscf_iter)
2N/A scf_iter_destroy(vsc->vscf_iter);
2N/A if (vsc->vscf_tx)
2N/A scf_transaction_destroy(vsc->vscf_tx);
2N/A if (vsc->vscf_pgroup)
2N/A scf_pg_destroy(vsc->vscf_pgroup);
2N/A if (vsc->vscf_inst)
2N/A scf_instance_destroy(vsc->vscf_inst);
2N/A if (vsc->vscf_handle)
2N/A scf_handle_destroy(vsc->vscf_handle);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_validate
2N/A *
2N/A * Validate property identified in propid.
2N/A *
2N/A * Returns: VS_ERR_NONE
2N/A * VS_ERR_INVALID_VALUE
2N/A * VS_ERR_INVALID_PROPERTY
2N/A */
2N/Astatic int
2N/Avs_validate(const vs_prop_hd_t *prop_hd, uint64_t propid)
2N/A{
2N/A uint64_t num;
2N/A const vs_props_t *vp = &prop_hd->vp_gen;
2N/A const vs_props_se_t *vep = &prop_hd->vp_se;
2N/A
2N/A switch (propid) {
2N/A case VS_PROPID_MAXSIZE:
2N/A if ((vs_strtonum(vp->vp_maxsize, &num) != 0) || (num == 0))
2N/A return (VS_ERR_INVALID_VALUE);
2N/A break;
2N/A case VS_PROPID_MAXSIZE_ACTION:
2N/A break;
2N/A case VS_PROPID_TYPES:
2N/A if (!vs_is_valid_types(vp->vp_types))
2N/A return (VS_ERR_INVALID_VALUE);
2N/A break;
2N/A case VS_PROPID_SE_ENABLE:
2N/A break;
2N/A case VS_PROPID_SE_PORT:
2N/A if (vep->vep_port == 0)
2N/A return (VS_ERR_INVALID_VALUE);
2N/A break;
2N/A case VS_PROPID_SE_HOST:
2N/A if (!vs_is_valid_host(vep->vep_host))
2N/A return (VS_ERR_INVALID_VALUE);
2N/A break;
2N/A case VS_PROPID_SE_MAXCONN:
2N/A if (vep->vep_maxconn < VS_VAL_SE_MAXCONN_MIN ||
2N/A vep->vep_maxconn > VS_VAL_SE_MAXCONN_MAX)
2N/A return (VS_ERR_INVALID_VALUE);
2N/A break;
2N/A case VS_PROPID_VALUE_AUTH:
2N/A case VS_PROPID_VLOG:
2N/A break;
2N/A default:
2N/A return (VS_ERR_INVALID_PROPERTY);
2N/A }
2N/A
2N/A return (VS_ERR_NONE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_props_validate
2N/A *
2N/A * Validate properties identified in propids.
2N/A *
2N/A * Returns: VS_ERR_NONE
2N/A * VS_ERR_INVALID_VALUE
2N/A * VS_ERR_INVALID_PROPERTY
2N/A */
2N/Aint
2N/Avs_props_validate(const vs_props_t *props, uint64_t propids)
2N/A{
2N/A uint64_t propid;
2N/A vs_prop_hd_t prop_hd;
2N/A
2N/A if ((propids & VS_PROPID_GEN_ALL) != propids)
2N/A return (VS_ERR_INVALID_PROPERTY);
2N/A
2N/A (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
2N/A prop_hd.vp_gen = *props;
2N/A prop_hd.vp_type = VS_PTYPE_GEN;
2N/A prop_hd.vp_ids = propids;
2N/A prop_hd.vp_all = VS_PROPID_GEN_ALL;
2N/A
2N/A for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
2N/A if ((propids & propid) == 0)
2N/A continue;
2N/A
2N/A if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
2N/A return (VS_ERR_INVALID_VALUE);
2N/A }
2N/A
2N/A return (VS_ERR_NONE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_props_se_validate
2N/A *
2N/A * Validate properties identified in propids.
2N/A *
2N/A * Returns: VS_ERR_NONE
2N/A * VS_ERR_INVALID_VALUE
2N/A * VS_ERR_INVALID_PROPERTY
2N/A */
2N/Aint
2N/Avs_props_se_validate(const vs_props_se_t *se_props, uint64_t propids)
2N/A{
2N/A uint64_t propid;
2N/A vs_prop_hd_t prop_hd;
2N/A
2N/A if ((propids & VS_PROPID_SE_ALL) != propids)
2N/A return (VS_ERR_INVALID_PROPERTY);
2N/A
2N/A (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
2N/A prop_hd.vp_se = *se_props;
2N/A prop_hd.vp_type = VS_PTYPE_SE;
2N/A prop_hd.vp_ids = propids;
2N/A prop_hd.vp_all = VS_PROPID_SE_ALL;
2N/A
2N/A for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
2N/A if ((propids & propid) == 0)
2N/A continue;
2N/A
2N/A if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
2N/A return (VS_ERR_INVALID_VALUE);
2N/A }
2N/A
2N/A return (VS_ERR_NONE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_is_valid_types
2N/A *
2N/A * Checks that types property is a valid format:
2N/A * - doesn't exceed VS_VAL_TYPES_MAX
2N/A * - doesn't contain VS_VAL_TYPES_INVALID_CHARS
2N/A * - is correctly formatted - passes the parsing tests
2N/A *
2N/A * Returns 1 on success, 0 on failure
2N/A */
2N/Astatic int
2N/Avs_is_valid_types(const char *types)
2N/A{
2N/A char buf[VS_VAL_TYPES_LEN];
2N/A uint32_t len = VS_VAL_TYPES_LEN;
2N/A
2N/A if (strlen(types) > VS_VAL_TYPES_LEN)
2N/A return (0);
2N/A
2N/A if (strpbrk(types, VS_VAL_TYPES_INVALID_CHARS) != NULL)
2N/A return (0);
2N/A
2N/A if (vs_parse_types(types, buf, &len) != 0)
2N/A return (0);
2N/A
2N/A return (1);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_is_valid_host
2N/A *
2N/A * Returns 1 on success, 0 on failure
2N/A */
2N/Astatic int
2N/Avs_is_valid_host(const char *host)
2N/A{
2N/A long naddr;
2N/A const char *p;
2N/A
2N/A if (!host || *host == '\0')
2N/A return (0);
2N/A
2N/A if ('0' <= host[0] && host[0] <= '9') {
2N/A /* ip address */
2N/A if ((inet_pton(AF_INET, host, &naddr)) == 0)
2N/A return (0);
2N/A if ((naddr & IN_CLASSA_NET) == 0)
2N/A return (0);
2N/A if ((naddr & IN_CLASSC_HOST) == 0)
2N/A return (0);
2N/A } else {
2N/A /* hostname */
2N/A p = host;
2N/A while (*p != '\0') {
2N/A if (!isascii(*p))
2N/A return (0);
2N/A
2N/A if (isalnum(*p) ||
2N/A (*p == '.') || (*p == '-') || (*p == '_')) {
2N/A ++p;
2N/A } else {
2N/A return (0);
2N/A }
2N/A }
2N/A }
2N/A
2N/A return (1);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_parse_types
2N/A *
2N/A * Replace comma separators with '\0'.
2N/A *
2N/A * Types contains comma separated rules each beginning with +|-
2N/A * - embedded commas are escaped by backslash
2N/A * - backslash is escaped by backslash
2N/A * - a single backslash not followed by comma is illegal
2N/A *
2N/A * On entry to the function len must contain the length of
2N/A * the buffer. On sucecssful exit len will contain the length
2N/A * of the parsed data within the buffer.
2N/A *
2N/A * Returns 0 on success, -1 on failure
2N/A */
2N/Aint
2N/Avs_parse_types(const char *types, char *buf, uint32_t *len)
2N/A{
2N/A char *p = (char *)types;
2N/A char *b = buf;
2N/A
2N/A if (strlen(types) > *len)
2N/A return (-1);
2N/A
2N/A if (strchr(VS_TYPES_RULES, *p) == NULL)
2N/A return (-1);
2N/A
2N/A (void) memset(buf, 0, *len);
2N/A
2N/A while (*p) {
2N/A switch (*p) {
2N/A case VS_TYPES_SEP:
2N/A if (*(p + 1) &&
2N/A (strchr(VS_TYPES_RULES, *(p + 1))) == NULL)
2N/A return (-1);
2N/A *b = '\0';
2N/A break;
2N/A case VS_TYPES_ESCAPE:
2N/A ++p;
2N/A if (*p == VS_TYPES_ESCAPE || *p == VS_TYPES_SEP)
2N/A *b = *p;
2N/A else
2N/A return (-1);
2N/A break;
2N/A default:
2N/A *b = *p;
2N/A }
2N/A ++p;
2N/A ++b;
2N/A }
2N/A
2N/A *len = (b - buf) + 1;
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_statistics
2N/A */
2N/Aint
2N/Avs_statistics(vs_stats_t *stats)
2N/A{
2N/A int door_fd, rc = VS_ERR_NONE;
2N/A vs_stats_req_t *req;
2N/A vs_stats_rsp_t *rsp;
2N/A door_arg_t arg;
2N/A
2N/A if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
2N/A return (VS_ERR_SYS);
2N/A
2N/A if ((rsp = calloc(1, sizeof (vs_stats_rsp_t))) == NULL) {
2N/A free(req);
2N/A return (VS_ERR_SYS);
2N/A }
2N/A
2N/A if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
2N/A free(req);
2N/A free(rsp);
2N/A return (VS_ERR_DAEMON_COMM);
2N/A }
2N/A
2N/A req->vsr_magic = VS_STATS_DOOR_MAGIC;
2N/A req->vsr_id = VS_STATS_GET;
2N/A
2N/A arg.data_ptr = (char *)req;
2N/A arg.data_size = sizeof (vs_stats_req_t);
2N/A arg.desc_ptr = NULL;
2N/A arg.desc_num = 0;
2N/A arg.rbuf = (char *)rsp;
2N/A arg.rsize = sizeof (vs_stats_rsp_t);
2N/A
2N/A rc = vs_door_call(door_fd, &arg);
2N/A
2N/A if ((rc == VS_ERR_NONE) && (rsp->vsr_magic == VS_STATS_DOOR_MAGIC))
2N/A *stats = rsp->vsr_stats;
2N/A else
2N/A rc = VS_ERR_DAEMON_COMM;
2N/A
2N/A (void) close(door_fd);
2N/A
2N/A free(req);
2N/A free(rsp);
2N/A return (rc);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_statistics_reset
2N/A */
2N/Aint
2N/Avs_statistics_reset()
2N/A{
2N/A int door_fd, rc;
2N/A vs_stats_req_t *req;
2N/A door_arg_t arg;
2N/A
2N/A /* ensure that caller has authorization to reset stats */
2N/A if ((rc = vs_checkauth(VS_VALUE_AUTH)) != VS_ERR_NONE)
2N/A return (rc);
2N/A
2N/A if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
2N/A return (VS_ERR_SYS);
2N/A
2N/A if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
2N/A free(req);
2N/A return (VS_ERR_DAEMON_COMM);
2N/A }
2N/A
2N/A req->vsr_magic = VS_STATS_DOOR_MAGIC;
2N/A req->vsr_id = VS_STATS_RESET;
2N/A
2N/A arg.data_ptr = (char *)req;
2N/A arg.data_size = sizeof (vs_stats_req_t);
2N/A arg.desc_ptr = NULL;
2N/A arg.desc_num = 0;
2N/A arg.rbuf = NULL;
2N/A arg.rsize = 0;
2N/A
2N/A rc = vs_door_call(door_fd, &arg);
2N/A
2N/A (void) close(door_fd);
2N/A free(req);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * Door call with retries.
2N/A *
2N/A * Returns VS_ERR_NONE on success, otherwise VS_ERR_DAEMON_COMM.
2N/A */
2N/Astatic int
2N/Avs_door_call(int fd, door_arg_t *arg)
2N/A{
2N/A int rc = -1;
2N/A int i;
2N/A
2N/A for (i = 0; i < VS_DOOR_CALL_RETRIES; ++i) {
2N/A errno = 0;
2N/A
2N/A if ((rc = door_call(fd, arg)) == 0)
2N/A break;
2N/A
2N/A if (errno != EAGAIN && errno != EINTR)
2N/A break;
2N/A }
2N/A
2N/A return ((rc == 0) ? VS_ERR_NONE : VS_ERR_DAEMON_COMM);
2N/A}
2N/A
2N/A/*
2N/A * vs_checkauth
2N/A */
2N/Astatic int
2N/Avs_checkauth(char *auth)
2N/A{
2N/A struct passwd *pw;
2N/A uid_t uid;
2N/A
2N/A uid = getuid();
2N/A
2N/A if ((pw = getpwuid(uid)) == NULL)
2N/A return (VS_ERR_SYS);
2N/A
2N/A if (chkauthattr(auth, pw->pw_name) != 1) {
2N/A return (VS_ERR_AUTH);
2N/A }
2N/A
2N/A return (VS_ERR_NONE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_props_get_engines
2N/A *
2N/A * On input, count specifies the maximum number of engine ids to
2N/A * return. engids must be an array with count entries.
2N/A * On return, count specifies the number of engine ids being
2N/A * returned in engids.
2N/A *
2N/A * Caller is responsible for free'ing the engids allocated herein.
2N/A */
2N/Astatic int
2N/Avs_props_get_engines(char *engids[], int *count)
2N/A{
2N/A int i, prefix_len;
2N/A char pgname[VS_PGNAME_ENGINE_LEN];
2N/A vs_scfctx_t vsc;
2N/A
2N/A
2N/A if (((vs_scf_ctx_open(&vsc)) != 0) ||
2N/A ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) ||
2N/A (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst,
2N/A SCF_GROUP_APPLICATION) != 0)) {
2N/A vs_scf_ctx_close(&vsc);
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A for (i = 0; i < *count; i++)
2N/A engids[i] = NULL;
2N/A
2N/A i = 0;
2N/A prefix_len = sizeof (VS_PGNAME_ENGINE_PREFIX) - 1;
2N/A
2N/A while ((i < VS_SE_MAX) &&
2N/A (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)) {
2N/A if (scf_pg_get_name(vsc.vscf_pgroup, pgname,
2N/A VS_PGNAME_ENGINE_LEN) < 0) {
2N/A vs_scf_ctx_close(&vsc);
2N/A return (VS_ERR_SCF);
2N/A }
2N/A
2N/A if (strncmp(pgname, VS_PGNAME_ENGINE_PREFIX, prefix_len) == 0) {
2N/A if ((engids[i] = strdup(pgname + prefix_len)) != NULL) {
2N/A if (++i == *count)
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A vs_scf_ctx_close(&vsc);
2N/A
2N/A *count = i;
2N/A return (VS_ERR_NONE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_scf_pg_count
2N/A */
2N/Astatic int
2N/Avs_scf_pg_count(void)
2N/A{
2N/A int count = 0;
2N/A vs_scfctx_t vsc;
2N/A
2N/A if ((vs_scf_ctx_open(&vsc) != 0) ||
2N/A ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) ||
2N/A (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst,
2N/A SCF_GROUP_APPLICATION) != 0)) {
2N/A vs_scf_ctx_close(&vsc);
2N/A return (-1);
2N/A }
2N/A
2N/A while (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)
2N/A ++count;
2N/A
2N/A vs_scf_ctx_close(&vsc);
2N/A
2N/A return (count);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_engid_to_pgname
2N/A *
2N/A * To convert an engine id (engid) to a property group name (pgname),
2N/A * the engine id is prefixed with VS_PGNAME_ENGINE_PREFIX.
2N/A */
2N/Astatic void
2N/Avs_engid_to_pgname(const char *engid, char pgname[VS_PGNAME_ENGINE_LEN])
2N/A{
2N/A (void) snprintf(pgname, VS_PGNAME_ENGINE_LEN, "%s%s",
2N/A VS_PGNAME_ENGINE_PREFIX, engid);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_strtonum
2N/A *
2N/A * Converts a size string in the format into an integer.
2N/A *
2N/A * A size string is a numeric value followed by an optional unit
2N/A * specifier which is used as a multiplier to calculate a raw
2N/A * number.
2N/A * The size string format is: N[.N][KMGTP][B]
2N/A *
2N/A * The numeric value can contain a decimal portion. Unit specifiers
2N/A * are either a one-character or two-character string; i.e. "K" or
2N/A * "KB" for kilobytes. Unit specifiers must follow the numeric portion
2N/A * immediately, and are not case-sensitive.
2N/A *
2N/A * If either "B" is specified, or there is no unit specifier portion
2N/A * in the string, the numeric value is calculated with no multiplier
2N/A * (assumes a basic unit of "bytes").
2N/A *
2N/A * Returns:
2N/A * -1: Failure; errno set to specify the error.
2N/A * 0: Success.
2N/A */
2N/Aint
2N/Avs_strtonum(const char *value, uint64_t *num)
2N/A{
2N/A char *end;
2N/A int shift;
2N/A double fval;
2N/A
2N/A *num = 0;
2N/A
2N/A /* Check to see if this looks like a number. */
2N/A if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
2N/A errno = EINVAL;
2N/A return (-1);
2N/A }
2N/A
2N/A /* Rely on stroll() to process the numeric portion. */
2N/A errno = 0;
2N/A *num = strtoll(value, &end, 10);
2N/A
2N/A /*
2N/A * Check for ERANGE, which indicates that the value is too large to
2N/A * fit in a 64-bit value.
2N/A */
2N/A if (errno != 0)
2N/A return (-1);
2N/A
2N/A /*
2N/A * If we have a decimal value, then do the computation with floating
2N/A * point arithmetic. Otherwise, use standard arithmetic.
2N/A */
2N/A if (*end == '.') {
2N/A fval = strtod(value, &end);
2N/A
2N/A if ((shift = vs_strtoshift(end)) == -1)
2N/A return (-1); /* errno set */
2N/A
2N/A fval *= pow(2, shift);
2N/A if (fval > UINT64_MAX) {
2N/A errno = ERANGE;
2N/A return (-1);
2N/A }
2N/A
2N/A *num = (uint64_t)fval;
2N/A } else {
2N/A if ((shift = vs_strtoshift(end)) == -1)
2N/A return (-1); /* errno set */
2N/A
2N/A /* Check for overflow */
2N/A if (shift >= 64 || (*num << shift) >> shift != *num) {
2N/A errno = ERANGE;
2N/A return (-1);
2N/A }
2N/A
2N/A *num <<= shift;
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * vs_strtoshift
2N/A *
2N/A * Converts a unit specifier string into a number of bits that
2N/A * a numeric value must be shifted.
2N/A *
2N/A * Returns:
2N/A * -1: Failure; errno set to specify the error.
2N/A * >-1: Success; the shift count.
2N/A *
2N/A */
2N/Astatic int
2N/Avs_strtoshift(const char *buf)
2N/A{
2N/A const char *ends = "BKMGTPEZ";
2N/A int i;
2N/A
2N/A if (buf[0] == '\0')
2N/A return (0);
2N/A for (i = 0; i < strlen(ends); i++) {
2N/A if (toupper(buf[0]) == ends[i])
2N/A break;
2N/A }
2N/A if (i == strlen(ends)) {
2N/A errno = EINVAL;
2N/A return (-1);
2N/A }
2N/A
2N/A /* Allow trailing 'b' characters except in the case of 'BB'. */
2N/A if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' &&
2N/A toupper(buf[0]) != 'B')) {
2N/A return (10 * i);
2N/A }
2N/A
2N/A errno = EINVAL;
2N/A return (-1);
2N/A}