diff options
author | jm199354 <none@none> | 2007-11-08 16:09:20 -0800 |
---|---|---|
committer | jm199354 <none@none> | 2007-11-08 16:09:20 -0800 |
commit | 911106dfb16696472af8c1b7b4c554a829354fa8 (patch) | |
tree | 1079f40c9e9d30aeeb3e560055e314f48884b050 /usr/src/lib/libvscan | |
parent | 10e672b7a3135068856cad9c6564d7d0a38fd869 (diff) | |
download | illumos-joyent-911106dfb16696472af8c1b7b4c554a829354fa8.tar.gz |
PSARC 2007/118 VSCAN Service
6623189 Vscan Service - PSARC/2007/118
Diffstat (limited to 'usr/src/lib/libvscan')
-rw-r--r-- | usr/src/lib/libvscan/Makefile | 62 | ||||
-rw-r--r-- | usr/src/lib/libvscan/Makefile.com | 73 | ||||
-rw-r--r-- | usr/src/lib/libvscan/common/libvscan.c | 1615 | ||||
-rw-r--r-- | usr/src/lib/libvscan/common/libvscan.h | 222 | ||||
-rw-r--r-- | usr/src/lib/libvscan/common/llib-lvscan | 31 | ||||
-rw-r--r-- | usr/src/lib/libvscan/common/mapfile-vers | 46 | ||||
-rw-r--r-- | usr/src/lib/libvscan/i386/Makefile | 30 | ||||
-rw-r--r-- | usr/src/lib/libvscan/sparc/Makefile | 30 |
8 files changed, 2109 insertions, 0 deletions
diff --git a/usr/src/lib/libvscan/Makefile b/usr/src/lib/libvscan/Makefile new file mode 100644 index 0000000000..1cf8f5effa --- /dev/null +++ b/usr/src/lib/libvscan/Makefile @@ -0,0 +1,62 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.lib + +HDRS = libvscan.h +HDRDIR = common +SUBDIRS= $(MACH) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +POFILE = libvscan.po +MSGFILES = common/libvscan.c + +.KEEP_STATE: + +all clean clobber install lint _msg : $(SUBDIRS) + +$(POFILE): $(MSGFILES) + $(BUILDPO.msgfiles) + +install_h: $(ROOTHDRS) + +check: $(CHECKHDR) + +_msg: $(MSGDOMAINPOFILE) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include $(SRC)/Makefile.msg.targ +include ../Makefile.targ diff --git a/usr/src/lib/libvscan/Makefile.com b/usr/src/lib/libvscan/Makefile.com new file mode 100644 index 0000000000..be3f36305c --- /dev/null +++ b/usr/src/lib/libvscan/Makefile.com @@ -0,0 +1,73 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +LIBRARY= libvscan.a +VERS= .1 + +OBJS_SHARED= +OBJS_COMMON= libvscan.o + +OBJECTS= $(OBJS_COMMON) $(OBJS_SHARED) + +include ../../Makefile.lib + +LIBS= $(DYNLIB) $(LINTLIB) + +SRCDIR = ../common +SRCS= $(OBJS_COMMON:%.o=$(SRCDIR)/%.c) \ + $(OBJS_SHARED:%.o=$(SRC)/common/vscan/%.c) +$(LINTLIB) := SRCS= $(SRCDIR)/$(LINTSRC) + +# Reset the Makefile.lib macro ROOTLIBDIR to refer to usr/lib/vscan +ROOTLIBDIR = $(ROOT)/usr/lib/vscan +ROOTHDRDIR = $(ROOT)/usr/include +ROOTHDRS = $(HDRS:%=$(ROOTHDRDIR)/%) + +$(ROOTLIBDIR): + $(INS.dir) + +LDLIBS += -lc -lscf -lsecdb -lnsl -lm +CFLAGS += $(CCVERBOSE) +CPPFLAGS += -I$(SRCDIR) +DYNFLAGS += -R/usr/lib/vscan +LDLIBS32 += -L$(ROOT)/usr/lib/vscan + +#C99MODE= -xc99=%all +#C99LMODE= -Xc99=%all + +.KEEP_STATE: + +install: all $(ROOTLIBDIR) install_h + +install_h: $(ROOTHDRDIR) $(ROOTHDRS) + +all: $(LIBS) + +lint: lintcheck + +include ../../Makefile.targ + diff --git a/usr/src/lib/libvscan/common/libvscan.c b/usr/src/lib/libvscan/common/libvscan.c new file mode 100644 index 0000000000..f7d5170750 --- /dev/null +++ b/usr/src/lib/libvscan/common/libvscan.c @@ -0,0 +1,1615 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <math.h> +#include <limits.h> +#include <libscf.h> +#include <errno.h> +#include <fcntl.h> +#include <door.h> +#include <pwd.h> +#include <auth_attr.h> +#include <secdb.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <libintl.h> +#include <libvscan.h> + +#define VS_INSTANCE_FMRI "svc:/system/filesystem/vscan:icap" + +/* SMF property group and property names */ +#define VS_PGNAME_GENERAL "vs_general" +#define VS_PGNAME_ENGINE "vs_engine_%d" +#define VS_PGNAME_ENGINE_LEN 16 + +#define VS_PNAME_MAXSIZE "maxsize" +#define VS_PNAME_MAXSIZE_ACTION "maxsize_action" +#define VS_PNAME_TYPES "types" +#define VS_PNAME_VLOG "viruslog" + +#define VS_PNAME_SE_ENABLE "enable" +#define VS_PNAME_SE_HOST "host" +#define VS_PNAME_SE_PORT "port" +#define VS_PNAME_SE_MAXCONN "max_connect" +#define VS_PNAME_VAUTH "value_authorization" + + +/* types string processing */ +#define VS_TYPES_SEP ',' +#define VS_TYPES_ESCAPE '\\' +#define VS_TYPES_RULES "+-" + + +/* + * The SCF context enapsulating the SCF objects used in the + * repository load and store routines vs_scf_values_get() + * and vs_scf_values_set(). + * + * The context is always opened before a get or set, then + * closed when finished (or on error); the open does an + * initial setup, while inside the get and set functions, + * additional objects within the context may be selectively + * initialized for use, depending on the actions needed and + * the properties being operated on. + */ +typedef struct vs_scfctx { + scf_handle_t *vscf_handle; + scf_instance_t *vscf_inst; + scf_propertygroup_t *vscf_pgroup; + scf_transaction_t *vscf_tx; + scf_iter_t *vscf_iter; + scf_property_t *vscf_prop[VS_NUM_PROPIDS]; + scf_transaction_entry_t *vscf_ent[VS_NUM_PROPIDS]; + scf_value_t *vscf_val[VS_NUM_PROPIDS]; +} vs_scfctx_t; + +/* + * The vscan property definition. Maps the property id with the name + * and type used to store the property in the repository. + * A table of these definitions is defined with a single entry per + * property. + */ +typedef struct { + const char *vpd_name; + uint64_t vpd_id; + scf_type_t vpd_type; +} vs_propdef_t; + +typedef enum { + VS_PTYPE_GEN, + VS_PTYPE_SE +} vs_prop_type_t; + +typedef struct vs_prop_hd { + vs_prop_type_t vp_type; + uint64_t vp_ids; + uint64_t vp_all; + union { + vs_props_t vp_gen; + vs_props_se_t vp_se; + } vp_props; +} vs_prop_hd_t; + +#define vp_gen vp_props.vp_gen +#define vp_se vp_props.vp_se + +/* + * Default values - these are used to return valid data + * to the caller in cases where invalid or unexpected values + * are found in the repository. + * + * Note: These values must be kept in sync with those defined + * in the service manifest. + */ +static const boolean_t vs_dflt_allow = B_TRUE; +static const boolean_t vs_dflt_enable = B_TRUE; +static const char *vs_dflt_maxsize = "1GB"; +static const char *vs_dflt_host = ""; +static const uint16_t vs_dflt_port = 1344; +static const uint16_t vs_dflt_maxconn = 32L; +static const char *vs_dflt_types = "+*"; +static const char *vs_dflt_vlog = ""; + +/* Property definition table */ +static const vs_propdef_t vs_propdefs[] = { + /* general properties */ + { VS_PNAME_MAXSIZE, VS_PROPID_MAXSIZE, SCF_TYPE_ASTRING }, + { VS_PNAME_MAXSIZE_ACTION, VS_PROPID_MAXSIZE_ACTION, SCF_TYPE_BOOLEAN }, + { VS_PNAME_TYPES, VS_PROPID_TYPES, SCF_TYPE_ASTRING }, + { VS_PNAME_VLOG, VS_PROPID_VLOG, SCF_TYPE_ASTRING }, + /* scan engine properties */ + { VS_PNAME_SE_ENABLE, VS_PROPID_SE_ENABLE, SCF_TYPE_BOOLEAN }, + { VS_PNAME_SE_HOST, VS_PROPID_SE_HOST, SCF_TYPE_HOST }, + { VS_PNAME_SE_PORT, VS_PROPID_SE_PORT, SCF_TYPE_INTEGER }, + { VS_PNAME_SE_MAXCONN, VS_PROPID_SE_MAXCONN, SCF_TYPE_INTEGER }, + { VS_PNAME_VAUTH, VS_PROPID_VALUE_AUTH, SCF_TYPE_ASTRING } +}; + +static const int vs_npropdefs = sizeof (vs_propdefs)/sizeof (vs_propdef_t); + +/* Local functions */ +static const vs_propdef_t *vs_get_propdef(uint64_t); +static void vs_default_value(vs_prop_hd_t *, const uint64_t); + +static int vs_scf_values_get(const char *, vs_prop_hd_t *); +static int vs_scf_get(const vs_propdef_t *, vs_prop_hd_t *, vs_scfctx_t *, int); + +static int vs_scf_values_set(const char *, vs_prop_hd_t *); +static int vs_scf_set(const vs_propdef_t *, vs_prop_hd_t *, vs_scfctx_t *, int); +static int vs_scf_pg_create(const char *, vs_prop_hd_t *); + +static int vs_scf_ctx_open(vs_scfctx_t *); +static void vs_scf_ctx_close(vs_scfctx_t *); + +static int vs_validate(const vs_prop_hd_t *, uint64_t); +static int vs_is_valid_types(const char *); +static int vs_is_valid_host(const char *); +static int vs_checkauth(char *); + +typedef char vs_engid_t[VS_SE_NAME_LEN]; +static int vs_props_get_engines(vs_engid_t *engids, int *count); +static int vs_scf_pg_count(void); +static int vs_strtoshift(const char *); + + +/* + * vs_props_get_all + * + * Retrieves the general service properties and all properties + * for all scan engines from the repository. + * + * If invalid property values are found, the values are corrected to + * the default value. + * + * Return codes: + * VS_ERR_VS_ERR_NONE + * VS_ERR_SCF + * VS_ERR_SYS + */ +int +vs_props_get_all(vs_props_all_t *va) +{ + int i, rc, n; + char *engid; + vs_engid_t engids[VS_SE_MAX]; + + (void) memset(va, 0, sizeof (vs_props_all_t)); + if ((rc = vs_props_get(&va->va_props, VS_PROPID_GEN_ALL)) + != VS_ERR_NONE) + return (rc); + + n = VS_SE_MAX; + if ((rc = vs_props_get_engines(engids, &n)) != VS_ERR_NONE) + return (rc); + + if (n > VS_SE_MAX) + n = VS_SE_MAX; + + for (i = 0; i < n; i++) { + engid = engids[i]; + rc = vs_props_se_get(engid, &va->va_se[i], VS_PROPID_SE_ALL); + if (rc != VS_ERR_NONE) + return (rc); + } + + return (VS_ERR_NONE); +} + + +/* + * vs_props_get + * + * Retrieves values for the specified general service properties from + * the repository. + * + * If invalid property values are found, the values are corrected to + * the default value. + * + * Return codes: + * VS_ERR_VS_ERR_NONE + * VS_ERR_INVALID_PROPERTY + * VS_ERR_SCF + * VS_ERR_SYS + */ +int +vs_props_get(vs_props_t *vp, uint64_t propids) +{ + int rc; + vs_prop_hd_t prop_hd; + + if ((propids & VS_PROPID_GEN_ALL) != propids) + return (VS_ERR_INVALID_PROPERTY); + + (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t)); + prop_hd.vp_type = VS_PTYPE_GEN; + prop_hd.vp_ids = propids; + prop_hd.vp_all = VS_PROPID_GEN_ALL; + + rc = vs_scf_values_get(VS_PGNAME_GENERAL, &prop_hd); + + *vp = prop_hd.vp_gen; + return (rc); +} + + +/* + * vs_props_set + * + * Changes values for the specified general service properties + * in the repository. + * + * Return codes: + * VS_ERR_VS_ERR_NONE + * VS_ERR_INVALID_PROPERTY + * VS_ERR_INVALID_VALUE + * VS_ERR_SCF + * VS_ERR_SYS + */ +int +vs_props_set(const vs_props_t *vp, uint64_t propids) +{ + vs_prop_hd_t prop_hd; + + if ((propids & VS_PROPID_GEN_ALL) != propids) + return (VS_ERR_INVALID_PROPERTY); + + (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t)); + prop_hd.vp_type = VS_PTYPE_GEN; + prop_hd.vp_ids = propids; + prop_hd.vp_all = VS_PROPID_GEN_ALL; + prop_hd.vp_gen = *vp; + return (vs_scf_values_set(VS_PGNAME_GENERAL, &prop_hd)); +} + + +/* + * vs_props_se_get + * + * Retrieves values for the specified scan engine properties from the + * repository. + * + * If the enable property is set (true), the host property is + * checked for validity. If it is not valid, the requested values + * are returned with the enable propery set to off (false) + * + * Return codes: + * VS_ERR_VS_ERR_NONE + * VS_ERR_INVALID_PROPERTY + * VS_ERR_SCF + * VS_ERR_SYS + */ +int +vs_props_se_get(char *engid, vs_props_se_t *sep, uint64_t propids) +{ + int rc; + vs_prop_hd_t prop_hd; + + /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */ + if (strcmp(engid, VS_PGNAME_GENERAL) == 0) + return (VS_ERR_INVALID_SE); + + if ((propids & VS_PROPID_SE_ALL) != propids) + return (VS_ERR_INVALID_PROPERTY); + + (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t)); + prop_hd.vp_type = VS_PTYPE_SE; + prop_hd.vp_ids = propids; + prop_hd.vp_all = VS_PROPID_SE_ALL; + (void) strlcpy(prop_hd.vp_se.vep_engid, engid, VS_SE_NAME_LEN); + + /* If getting enable, get the host property too */ + if ((propids & VS_PROPID_SE_ENABLE)) + prop_hd.vp_ids |= VS_PROPID_SE_HOST; + + /* Load values from the repository */ + rc = vs_scf_values_get(engid, &prop_hd); + if (rc != VS_ERR_NONE) + return (rc); + + /* + * If the host is invalid and the enable property is on, + * return enable property as off + */ + if ((prop_hd.vp_ids & VS_PROPID_SE_HOST) && + (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)) { + prop_hd.vp_se.vep_enable = B_FALSE; + } + + *sep = prop_hd.vp_se; + return (rc); +} + + + +/* + * vs_props_se_set + * + * Changes the values for the specified scan engine properties in the + * repository. + * + * If the enable property is being changed to true in this operation, + * a host property must also be specified, or already exist in the + * repository. + * + * Return codes: + * VS_ERR_NONE + * VS_ERR_INVALID_PROPERTY + * VS_ERR_INVALID_VALUE + * VS_ERR_SCF + * VS_ERR_SYS + */ +int +vs_props_se_set(char *engid, const vs_props_se_t *sep, uint64_t propids) +{ + int rc; + vs_prop_hd_t prop_hd; + + /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */ + if (strcmp(engid, VS_PGNAME_GENERAL) == 0) + return (VS_ERR_INVALID_SE); + + if ((propids & VS_PROPID_SE_ALL) != propids) + return (VS_ERR_INVALID_PROPERTY); + + (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t)); + prop_hd.vp_type = VS_PTYPE_SE; + prop_hd.vp_all = VS_PROPID_SE_ALL; + + /* + * if enabling a scan engine, ensure that a valid host + * is also being set, or already exists in the repository + */ + if ((propids & VS_PROPID_SE_ENABLE) && (sep->vep_enable == B_TRUE) && + !(propids & VS_PROPID_SE_HOST)) { + + prop_hd.vp_ids = VS_PROPID_SE_HOST; + if ((rc = vs_scf_values_get(engid, &prop_hd)) != VS_ERR_NONE) + return (rc); + + if (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE) + return (VS_ERR_INVALID_HOST); + } + + prop_hd.vp_ids = propids; + prop_hd.vp_se = *sep; + + return (vs_scf_values_set(engid, &prop_hd)); +} + + +/* + * vs_props_se_create + */ +int +vs_props_se_create(char *engid, const vs_props_se_t *sep, uint64_t propids) +{ + int n; + vs_prop_hd_t prop_hd; + + if ((propids & VS_PROPID_SE_ALL) != propids) + return (VS_ERR_INVALID_PROPERTY); + + /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */ + if (strcmp(engid, VS_PGNAME_GENERAL) == 0) + return (VS_ERR_INVALID_SE); + + if ((n = vs_scf_pg_count()) == -1) + return (VS_ERR_SCF); + + if (n == VS_SE_MAX) + return (VS_ERR_MAX_SE); + + (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t)); + prop_hd.vp_type = VS_PTYPE_SE; + prop_hd.vp_all = VS_PROPID_SE_ALL; + prop_hd.vp_ids = propids | VS_PROPID_VALUE_AUTH; + prop_hd.vp_se = *sep; + + return (vs_scf_pg_create(engid, &prop_hd)); + +} + + +/* + * vs_props_se_delete + */ +int +vs_props_se_delete(const char *engid) +{ + int rc; + vs_scfctx_t vsc; + + /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */ + if (strcmp(engid, VS_PGNAME_GENERAL) == 0) + return (VS_ERR_INVALID_SE); + + /* ensure that caller has authorization to refresh service */ + if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE) + return (rc); + + if (vs_scf_ctx_open(&vsc) != 0) { + vs_scf_ctx_close(&vsc); + return (VS_ERR_SCF); + } + + if (scf_instance_get_pg(vsc.vscf_inst, engid, vsc.vscf_pgroup) == -1) { + vs_scf_ctx_close(&vsc); + rc = scf_error(); + if ((rc == SCF_ERROR_NOT_FOUND) || + (rc == SCF_ERROR_INVALID_ARGUMENT)) + return (VS_ERR_INVALID_SE); + else + return (VS_ERR_SCF); + } + + if (scf_pg_delete(vsc.vscf_pgroup) == -1) { + vs_scf_ctx_close(&vsc); + rc = scf_error(); + if ((rc == SCF_ERROR_NOT_FOUND) || + (rc == SCF_ERROR_INVALID_ARGUMENT)) + return (VS_ERR_INVALID_SE); + + return (VS_ERR_SCF); + } + + vs_scf_ctx_close(&vsc); + + /* Notify the daemon that things have changed */ + if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1) { + return (VS_ERR_SCF); + } + + return (VS_ERR_NONE); +} + + +/* + * vs_strerror + */ +const char * +vs_strerror(int error) +{ + switch (error) { + case VS_ERR_NONE: + return (gettext("no error")); + case VS_ERR_INVALID_PROPERTY: + return (gettext("invalid property id")); + case VS_ERR_INVALID_VALUE: + return (gettext("invalid property value")); + case VS_ERR_INVALID_HOST: + return (gettext("invalid host")); + case VS_ERR_INVALID_SE: + return (gettext("invalid scan engine")); + case VS_ERR_MAX_SE: + return (gettext("max scan engines exceeded")); + case VS_ERR_AUTH: + return (gettext("insufficient privileges for action")); + case VS_ERR_DAEMON_COMM: + return (gettext("unable to contact vscand")); + case VS_ERR_SCF: + return (scf_strerror(scf_error())); + case VS_ERR_SYS: + return (strerror(errno)); + default: + return (gettext("unknown error")); + } +} + + +/* + * vs_get_propdef + * + * Finds and returns a property definition by property id. + */ +static const vs_propdef_t * +vs_get_propdef(uint64_t propid) +{ + int i; + + for (i = 0; i < vs_npropdefs; i++) { + if (propid == vs_propdefs[i].vpd_id) + return (&vs_propdefs[i]); + } + + return (NULL); +} + + +/* + * vs_default_value + * + * Sets a property value that contains invalid data to its default value. + * + * Note that this function does not alter any values in the repository + * This is only to enable the caller to get valid data. + */ +static void +vs_default_value(vs_prop_hd_t *prop_hd, const uint64_t propid) +{ + vs_props_t *vp = &prop_hd->vp_gen; + vs_props_se_t *vep = &prop_hd->vp_se; + + switch (propid) { + case VS_PROPID_MAXSIZE: + (void) strlcpy(vp->vp_maxsize, vs_dflt_maxsize, + sizeof (vp->vp_maxsize)); + break; + case VS_PROPID_MAXSIZE_ACTION: + vp->vp_maxsize_action = vs_dflt_allow; + break; + case VS_PROPID_TYPES: + (void) strlcpy(vp->vp_types, vs_dflt_types, + sizeof (vp->vp_types)); + break; + case VS_PROPID_VLOG: + (void) strlcpy(vp->vp_vlog, vs_dflt_vlog, + sizeof (vp->vp_vlog)); + break; + case VS_PROPID_SE_ENABLE: + vep->vep_enable = vs_dflt_enable; + break; + case VS_PROPID_SE_HOST: + (void) strlcpy(vep->vep_host, vs_dflt_host, + sizeof (vep->vep_host)); + break; + case VS_PROPID_SE_PORT: + vep->vep_port = vs_dflt_port; + break; + case VS_PROPID_SE_MAXCONN: + vep->vep_maxconn = vs_dflt_maxconn; + break; + default: + break; + } +} + + +/* + * vs_scf_values_get + * + * Gets property values for one or more properties from the repository. + * This is the single entry point for loading SMF values. + * + * While a transaction is not used for loading property values, + * the operation is parameterized by a property group. All properties + * retrieved in this function, then, must belong to the same property + * group. + */ +int +vs_scf_values_get(const char *pgname, vs_prop_hd_t *prop_hd) +{ + vs_scfctx_t vsc; + int rc, np; + const vs_propdef_t *vpd; + uint64_t propid; + + if ((vs_scf_ctx_open(&vsc)) != 0) { + vs_scf_ctx_close(&vsc); + return (VS_ERR_SCF); + } + + if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) { + vs_scf_ctx_close(&vsc); + if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) { + rc = scf_error(); + if ((rc == SCF_ERROR_NOT_FOUND) || + (rc == SCF_ERROR_INVALID_ARGUMENT)) + return (VS_ERR_INVALID_SE); + } + return (VS_ERR_SCF); + } + + rc = VS_ERR_NONE; + np = 0; + for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) { + if ((prop_hd->vp_ids & propid) == 0) + continue; + + if ((vpd = vs_get_propdef(propid)) == NULL) { + rc = VS_ERR_INVALID_PROPERTY; + break; + } + + vsc.vscf_prop[np] = scf_property_create(vsc.vscf_handle); + vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle); + + if (vsc.vscf_prop[np] == NULL || vsc.vscf_val[np] == NULL) { + rc = VS_ERR_SCF; + break; + } + + if (scf_pg_get_property(vsc.vscf_pgroup, vpd->vpd_name, + vsc.vscf_prop[np]) == -1) { + if (scf_error() == SCF_ERROR_NOT_FOUND) { + vs_default_value(prop_hd, vpd->vpd_id); + continue; + } + rc = VS_ERR_SCF; + break; + } + + if ((rc = vs_scf_get(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE) + break; + + ++np; + } + + + vs_scf_ctx_close(&vsc); + + return (rc); +} + + +/* + * vs_scf_get + * + * Loads a single values from the repository into the appropriate vscan + * property structure member. + */ +static int +vs_scf_get(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd, + vs_scfctx_t *vsc, int idx) +{ + int rc; + int64_t port; + uint8_t valbool; + vs_props_t *vp = &prop_hd->vp_gen; + vs_props_se_t *vep = &prop_hd->vp_se; + + if ((rc = scf_property_get_value(vsc->vscf_prop[idx], + vsc->vscf_val[idx])) == -1) { + if (rc == SCF_ERROR_CONSTRAINT_VIOLATED || + rc == SCF_ERROR_NOT_FOUND) { + vs_default_value(prop_hd, vpd->vpd_id); + return (VS_ERR_NONE); + } + return (VS_ERR_SCF); + } + + rc = VS_ERR_NONE; + switch (vpd->vpd_id) { + case VS_PROPID_MAXSIZE: + if ((scf_value_get_astring(vsc->vscf_val[idx], + vp->vp_maxsize, sizeof (vp->vp_maxsize))) == -1) { + return (VS_ERR_SCF); + } + break; + case VS_PROPID_MAXSIZE_ACTION: + if ((scf_value_get_boolean(vsc->vscf_val[idx], + &valbool)) == -1) { + return (VS_ERR_SCF); + } + vp->vp_maxsize_action = (valbool == 0) ? B_FALSE : B_TRUE; + break; + case VS_PROPID_TYPES: + if ((scf_value_get_astring(vsc->vscf_val[idx], + vp->vp_types, sizeof (vp->vp_types))) == -1) { + return (VS_ERR_SCF); + } + break; + case VS_PROPID_VLOG: + if ((scf_value_get_astring(vsc->vscf_val[idx], + vp->vp_vlog, sizeof (vp->vp_vlog))) == -1) { + return (VS_ERR_SCF); + } + break; + case VS_PROPID_SE_ENABLE: + if ((scf_value_get_boolean(vsc->vscf_val[idx], + &valbool)) == -1) { + return (VS_ERR_SCF); + } + vep->vep_enable = (valbool == 0) ? B_FALSE : B_TRUE; + break; + case VS_PROPID_SE_HOST: + (void) scf_value_get_as_string_typed(vsc->vscf_val[idx], + vpd->vpd_type, vep->vep_host, sizeof (vep->vep_host)); + break; + case VS_PROPID_SE_PORT: + if ((scf_value_get_integer(vsc->vscf_val[idx], &port)) == -1) + return (VS_ERR_SCF); + if (port <= 0 || port >= UINT16_MAX) + rc = VS_ERR_INVALID_VALUE; + else + vep->vep_port = (uint16_t)port; + break; + case VS_PROPID_SE_MAXCONN: + if ((scf_value_get_integer(vsc->vscf_val[idx], + (int64_t *)&vep->vep_maxconn)) == -1) { + return (VS_ERR_SCF); + } + break; + default: + break; + } + + if ((rc != VS_ERR_NONE) || + (vs_validate(prop_hd, vpd->vpd_id) != VS_ERR_NONE)) { + vs_default_value(prop_hd, vpd->vpd_id); + } + + return (VS_ERR_NONE); +} + + +/* + * vs_scf_pg_create + */ +static int +vs_scf_pg_create(const char *pgname, vs_prop_hd_t *prop_hd) +{ + int rc; + uint64_t propid; + uint64_t propids = prop_hd->vp_ids; + vs_scfctx_t vsc; + + /* ensure that caller has authorization to refresh service */ + if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE) + return (rc); + + if (vs_scf_ctx_open(&vsc) != 0) { + vs_scf_ctx_close(&vsc); + return (VS_ERR_SCF); + } + + if (scf_instance_add_pg(vsc.vscf_inst, pgname, + SCF_GROUP_APPLICATION, 0, vsc.vscf_pgroup) == -1) { + vs_scf_ctx_close(&vsc); + if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) + return (VS_ERR_INVALID_SE); + return (VS_ERR_SCF); + } + vs_scf_ctx_close(&vsc); + + /* set default values for those not specified */ + for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) { + if ((propid & prop_hd->vp_all) && !(propid & prop_hd->vp_ids)) + vs_default_value(prop_hd, propid); + } + prop_hd->vp_ids = prop_hd->vp_all; + + + if ((propids & VS_PROPID_SE_HOST) == 0) + (void) strlcpy(prop_hd->vp_se.vep_host, pgname, MAXHOSTNAMELEN); + + prop_hd->vp_ids |= VS_PROPID_VALUE_AUTH; + + rc = vs_scf_values_set(pgname, prop_hd); + if (rc != VS_ERR_NONE) + (void) vs_props_se_delete(pgname); + + return (rc); +} + + +/* + * vs_scf_values_set + * + * Sets property values in the repository. This is the single + * entry point for storing SMF values. + * + * Like loading values, this is an operation based on a single property + * group, so all property values changed in this function must belong + * to the same property group. Additionally, this operation is done in + * the context of a repository transaction; on any fatal error, the + * SCF context will be closed, destroying all SCF objects and aborting + * the transaction. + */ +static int +vs_scf_values_set(const char *pgname, vs_prop_hd_t *prop_hd) +{ + int rc, np; + const vs_propdef_t *vpd; + uint64_t propid; + vs_scfctx_t vsc; + + + /* ensure that caller has authorization to refresh service */ + if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE) + return (rc); + + if (vs_scf_ctx_open(&vsc) != 0) { + vs_scf_ctx_close(&vsc); + return (VS_ERR_SCF); + } + + if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) { + vs_scf_ctx_close(&vsc); + rc = scf_error(); + if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) { + if ((rc == SCF_ERROR_NOT_FOUND) || + (rc == SCF_ERROR_INVALID_ARGUMENT)) + return (VS_ERR_INVALID_SE); + } + return (VS_ERR_SCF); + } + + if (((vsc.vscf_tx = scf_transaction_create(vsc.vscf_handle)) == NULL) || + (scf_transaction_start(vsc.vscf_tx, vsc.vscf_pgroup) == -1)) { + vs_scf_ctx_close(&vsc); + return (VS_ERR_SCF); + } + + /* Process the value change for each specified property */ + rc = 0; + np = 0; + for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) { + if ((prop_hd->vp_ids & propid) == 0) + continue; + + if ((vpd = vs_get_propdef(propid)) == NULL) { + rc = VS_ERR_INVALID_PROPERTY; + break; + } + + vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle); + vsc.vscf_ent[np] = scf_entry_create(vsc.vscf_handle); + + if (vsc.vscf_val[np] == NULL || vsc.vscf_ent[np] == NULL) { + rc = VS_ERR_SCF; + break; + } + + if ((rc = scf_transaction_property_change(vsc.vscf_tx, + vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type)) == -1) { + rc = scf_transaction_property_new(vsc.vscf_tx, + vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type); + } + if (rc == -1) { + rc = VS_ERR_SCF; + break; + } + + if ((rc = vs_scf_set(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE) + break; + + ++np; + } + + if (rc != VS_ERR_NONE) { + vs_scf_ctx_close(&vsc); + return (rc); + } + + /* Commit the transaction */ + if (scf_transaction_commit(vsc.vscf_tx) == -1) { + vs_scf_ctx_close(&vsc); + return (VS_ERR_SCF); + } + vs_scf_ctx_close(&vsc); + + /* Notify the daemon that things have changed */ + if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1) + return (VS_ERR_SCF); + + return (VS_ERR_NONE); +} + + +/* + * vs_scf_set + * + * Stores a single value from the appropriate vscan property structure + * member into the repository. + * + * Values are set in the SCF value object, then the value object + * is added to the SCF property object. + */ +static int +vs_scf_set(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd, + vs_scfctx_t *vsc, int idx) +{ + int rc; + vs_props_t *vp = &prop_hd->vp_gen; + vs_props_se_t *vep = &prop_hd->vp_se; + + if ((rc = vs_validate(prop_hd, vpd->vpd_id)) != VS_ERR_NONE) + return (rc); + + rc = VS_ERR_NONE; + switch (vpd->vpd_id) { + case VS_PROPID_MAXSIZE: + if ((scf_value_set_astring(vsc->vscf_val[idx], + vp->vp_maxsize)) == -1) { + rc = VS_ERR_SCF; + } + break; + case VS_PROPID_MAXSIZE_ACTION: + scf_value_set_boolean(vsc->vscf_val[idx], + (uint8_t)vp->vp_maxsize_action); + break; + case VS_PROPID_TYPES: + if ((scf_value_set_astring(vsc->vscf_val[idx], + vp->vp_types)) == -1) { + return (VS_ERR_SCF); + } + break; + case VS_PROPID_SE_ENABLE: + scf_value_set_boolean(vsc->vscf_val[idx], + (uint8_t)vep->vep_enable); + break; + case VS_PROPID_SE_HOST: + if ((scf_value_set_from_string(vsc->vscf_val[idx], + vpd->vpd_type, vep->vep_host)) == -1) { + rc = VS_ERR_SCF; + } + break; + case VS_PROPID_SE_PORT: + scf_value_set_integer(vsc->vscf_val[idx], vep->vep_port); + break; + case VS_PROPID_SE_MAXCONN: + scf_value_set_integer(vsc->vscf_val[idx], + vep->vep_maxconn); + break; + case VS_PROPID_VALUE_AUTH: + if ((scf_value_set_astring(vsc->vscf_val[idx], + VS_VALUE_AUTH)) == -1) { + return (VS_ERR_SCF); + } + break; + default: + break; + } + + if ((scf_entry_add_value(vsc->vscf_ent[idx], + vsc->vscf_val[idx])) == -1) { + return (VS_ERR_SCF); + } + + return (rc); +} + + +/* + * vs_scf_ctx_open + * + * Opens an SCF context; creates the minumum SCF objects + * for use in loading/storing from the SMF repository (meaning + * vscf_property group data). + * + * Other SCF objects in the context may be initialized elsewher + * subsequent to open, but all initialized structures are destroyed + * in vs_scf_ctx_close(). + */ +static int +vs_scf_ctx_open(vs_scfctx_t *vsc) +{ + (void) memset(vsc, 0, sizeof (vs_scfctx_t)); + + if ((vsc->vscf_handle = scf_handle_create(SCF_VERSION)) == NULL) + return (VS_ERR_SCF); + + if (scf_handle_bind(vsc->vscf_handle) == -1) + return (VS_ERR_SCF); + + if ((vsc->vscf_inst = scf_instance_create(vsc->vscf_handle)) == NULL) + return (VS_ERR_SCF); + + if (scf_handle_decode_fmri(vsc->vscf_handle, VS_INSTANCE_FMRI, + NULL, NULL, vsc->vscf_inst, NULL, NULL, + SCF_DECODE_FMRI_EXACT) == -1) { + return (VS_ERR_SCF); + } + + if ((vsc->vscf_pgroup = scf_pg_create(vsc->vscf_handle)) == NULL) + return (VS_ERR_SCF); + + return (VS_ERR_NONE); +} + + +/* + * vs_scf_ctx_close + * + * Closes an SCF context; destroys all initialized SCF objects. + */ +static void +vs_scf_ctx_close(vs_scfctx_t *vsc) +{ + int i; + + for (i = 0; i < VS_NUM_PROPIDS; i++) { + if (vsc->vscf_val[i]) + scf_value_destroy(vsc->vscf_val[i]); + if (vsc->vscf_ent[i]) + scf_entry_destroy(vsc->vscf_ent[i]); + if (vsc->vscf_prop[i]) + scf_property_destroy(vsc->vscf_prop[i]); + } + + if (vsc->vscf_iter) + scf_iter_destroy(vsc->vscf_iter); + if (vsc->vscf_tx) + scf_transaction_destroy(vsc->vscf_tx); + if (vsc->vscf_pgroup) + scf_pg_destroy(vsc->vscf_pgroup); + if (vsc->vscf_inst) + scf_instance_destroy(vsc->vscf_inst); + if (vsc->vscf_handle) + scf_handle_destroy(vsc->vscf_handle); +} + + +/* + * vs_validate + * + * Validate property identified in propid. + * + * Returns: VS_ERR_NONE + * VS_ERR_INVALID_VALUE + * VS_ERR_INVALID_PROPERTY + */ +static int +vs_validate(const vs_prop_hd_t *prop_hd, uint64_t propid) +{ + uint64_t num; + const vs_props_t *vp = &prop_hd->vp_gen; + const vs_props_se_t *vep = &prop_hd->vp_se; + + switch (propid) { + case VS_PROPID_MAXSIZE: + if ((vs_strtonum(vp->vp_maxsize, &num) != 0) || (num == 0)) + return (VS_ERR_INVALID_VALUE); + break; + case VS_PROPID_MAXSIZE_ACTION: + break; + case VS_PROPID_TYPES: + if (!vs_is_valid_types(vp->vp_types)) + return (VS_ERR_INVALID_VALUE); + break; + case VS_PROPID_SE_ENABLE: + break; + case VS_PROPID_SE_PORT: + if (vep->vep_port == 0) + return (VS_ERR_INVALID_VALUE); + break; + case VS_PROPID_SE_HOST: + if (!vs_is_valid_host(vep->vep_host)) + return (VS_ERR_INVALID_VALUE); + break; + case VS_PROPID_SE_MAXCONN: + if (vep->vep_maxconn < VS_VAL_SE_MAXCONN_MIN || + vep->vep_maxconn > VS_VAL_SE_MAXCONN_MAX) + return (VS_ERR_INVALID_VALUE); + break; + case VS_PROPID_VALUE_AUTH: + case VS_PROPID_VLOG: + break; + default: + return (VS_ERR_INVALID_PROPERTY); + } + + return (VS_ERR_NONE); +} + + +/* + * vs_props_validate + * + * Validate properties identified in propids. + * + * Returns: VS_ERR_NONE + * VS_ERR_INVALID_VALUE + * VS_ERR_INVALID_PROPERTY + */ +int +vs_props_validate(const vs_props_t *props, uint64_t propids) +{ + uint64_t propid; + vs_prop_hd_t prop_hd; + + if ((propids & VS_PROPID_GEN_ALL) != propids) + return (VS_ERR_INVALID_PROPERTY); + + (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t)); + prop_hd.vp_gen = *props; + prop_hd.vp_type = VS_PTYPE_GEN; + prop_hd.vp_ids = propids; + prop_hd.vp_all = VS_PROPID_GEN_ALL; + + for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) { + if ((propids & propid) == 0) + continue; + + if (vs_validate(&prop_hd, propid) != VS_ERR_NONE) + return (VS_ERR_INVALID_VALUE); + } + + return (VS_ERR_NONE); +} + + +/* + * vs_props_se_validate + * + * Validate properties identified in propids. + * + * Returns: VS_ERR_NONE + * VS_ERR_INVALID_VALUE + * VS_ERR_INVALID_PROPERTY + */ +int +vs_props_se_validate(const vs_props_se_t *se_props, uint64_t propids) +{ + uint64_t propid; + vs_prop_hd_t prop_hd; + + if ((propids & VS_PROPID_SE_ALL) != propids) + return (VS_ERR_INVALID_PROPERTY); + + (void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t)); + prop_hd.vp_se = *se_props; + prop_hd.vp_type = VS_PTYPE_SE; + prop_hd.vp_ids = propids; + prop_hd.vp_all = VS_PROPID_SE_ALL; + + for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) { + if ((propids & propid) == 0) + continue; + + if (vs_validate(&prop_hd, propid) != VS_ERR_NONE) + return (VS_ERR_INVALID_VALUE); + } + + return (VS_ERR_NONE); +} + + +/* + * vs_is_valid_types + * + * Checks that types property is a valid format: + * - doesn't exceed VS_VAL_TYPES_MAX + * - doesn't contain VS_VAL_TYPES_INVALID_CHARS + * - is correctly formatted - passes the parsing tests + * + * Returns 1 on success, 0 on failure + */ +static int +vs_is_valid_types(const char *types) +{ + char buf[VS_VAL_TYPES_LEN]; + uint32_t len = VS_VAL_TYPES_LEN; + + if (strlen(types) > VS_VAL_TYPES_LEN) + return (0); + + if (strpbrk(types, VS_VAL_TYPES_INVALID_CHARS) != NULL) + return (0); + + if (vs_parse_types(types, buf, &len) != 0) + return (0); + + return (1); +} + + +/* + * vs_is_valid_host + * + * Returns 1 on success, 0 on failure + */ +static int +vs_is_valid_host(const char *host) +{ + long naddr; + const char *p; + + if (!host || *host == '\0') + return (0); + + if ('0' <= host[0] && host[0] <= '9') { + /* ip address */ + if ((inet_pton(AF_INET, host, &naddr)) == 0) + return (0); + if ((naddr & IN_CLASSA_NET) == 0) + return (0); + if ((naddr & IN_CLASSC_HOST) == 0) + return (0); + } else { + /* hostname */ + p = host; + while (*p != '\0') { + if (!isascii(*p)) + return (0); + + if (isalnum(*p) || + (*p == '.') || (*p == '-') || (*p == '_')) { + ++p; + } else { + return (0); + } + } + } + + return (1); +} + + +/* + * vs_parse_types + * + * Replace comma separators with '\0'. + * + * Types contains comma separated rules each beginning with +|- + * - embedded commas are escaped by backslash + * - backslash is escaped by backslash + * - a single backslash not followed by comma is illegal + * + * On entry to the function len must contain the length of + * the buffer. On sucecssful exit len will contain the length + * of the parsed data within the buffer. + * + * Returns 0 on success, -1 on failure + */ +int +vs_parse_types(const char *types, char *buf, uint32_t *len) +{ + char *p = (char *)types; + char *b = buf; + + if (strlen(types) > *len) + return (-1); + + if (strchr(VS_TYPES_RULES, *p) == NULL) + return (-1); + + (void) memset(buf, 0, *len); + + while (*p) { + switch (*p) { + case VS_TYPES_SEP: + if (*(p + 1) && + (strchr(VS_TYPES_RULES, *(p + 1))) == NULL) + return (-1); + *b = '\0'; + break; + case VS_TYPES_ESCAPE: + ++p; + if (*p == VS_TYPES_ESCAPE || *p == VS_TYPES_SEP) + *b = *p; + else + return (-1); + break; + default: + *b = *p; + } + ++p; + ++b; + } + + *len = (b - buf) + 1; + + return (0); +} + + +/* + * vs_statistics + */ +int +vs_statistics(vs_stats_t *stats) +{ + int door_fd, rc = VS_ERR_NONE; + vs_stats_req_t *req; + vs_stats_t *buf; + door_arg_t arg; + + if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL) + return (VS_ERR_SYS); + + if ((buf = calloc(1, sizeof (vs_stats_t))) == NULL) { + free(req); + return (VS_ERR_SYS); + } + + if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) { + free(req); + free(buf); + return (VS_ERR_DAEMON_COMM); + } + + *req = VS_STATS_GET; + + arg.data_ptr = (char *)req; + arg.data_size = sizeof (vs_stats_req_t); + arg.desc_ptr = NULL; + arg.desc_num = 0; + arg.rbuf = (char *)buf; + arg.rsize = sizeof (vs_stats_t); + + if (door_call(door_fd, &arg) < 0) + rc = VS_ERR_DAEMON_COMM; + else + *stats = *buf; + + (void) close(door_fd); + + free(req); + free(buf); + return (rc); +} + + +/* + * vs_statistics_reset + */ +int +vs_statistics_reset() +{ + int door_fd, rc; + vs_stats_req_t *req; + door_arg_t arg; + + /* ensure that caller has authorization to reset stats */ + if ((rc = vs_checkauth(VS_VALUE_AUTH)) != VS_ERR_NONE) + return (rc); + + if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL) + return (VS_ERR_SYS); + + if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) { + free(req); + return (VS_ERR_DAEMON_COMM); + } + + *req = VS_STATS_RESET; + + arg.data_ptr = (char *)req; + arg.data_size = sizeof (vs_stats_req_t); + arg.desc_ptr = NULL; + arg.desc_num = 0; + arg.rbuf = NULL; + arg.rsize = 0; + + if (door_call(door_fd, &arg) < 0) + rc = VS_ERR_DAEMON_COMM; + else + rc = VS_ERR_NONE; + + (void) close(door_fd); + free(req); + return (rc); +} + + +/* + * vs_checkauth + */ +static int +vs_checkauth(char *auth) +{ + struct passwd *pw; + uid_t uid; + + uid = getuid(); + + if ((pw = getpwuid(uid)) == NULL) + return (VS_ERR_SYS); + + if (chkauthattr(auth, pw->pw_name) != 1) { + return (VS_ERR_AUTH); + } + + return (VS_ERR_NONE); +} + + +/* + * vs_props_get_engines + * On input, count specifies the maximum number of engine ids to + * return. engids must be an array with count entries. + * On return, count specifies the number of engine ids being + * returned in engids. + */ +static int +vs_props_get_engines(vs_engid_t *engids, int *count) +{ + int i = 0; + vs_scfctx_t vsc; + + + if (((vs_scf_ctx_open(&vsc)) != 0) || + ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) || + (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst, + SCF_GROUP_APPLICATION) != 0)) { + vs_scf_ctx_close(&vsc); + return (VS_ERR_SCF); + } + + while ((i < VS_SE_MAX) && + (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)) { + if (scf_pg_get_name(vsc.vscf_pgroup, engids[i], + VS_SE_NAME_LEN) < 0) { + vs_scf_ctx_close(&vsc); + return (VS_ERR_SCF); + } + + if (strcmp(engids[i], VS_PGNAME_GENERAL) == 0) + *engids[i] = 0; + else + if (++i == *count) + break; + } + vs_scf_ctx_close(&vsc); + + *count = i; + return (VS_ERR_NONE); +} + + +/* + * vs_scf_pg_count + */ +static int +vs_scf_pg_count(void) +{ + int count = 0; + vs_scfctx_t vsc; + + if ((vs_scf_ctx_open(&vsc) != 0) || + ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) || + (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst, + SCF_GROUP_APPLICATION) != 0)) { + vs_scf_ctx_close(&vsc); + return (-1); + } + + while (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1) + ++count; + + vs_scf_ctx_close(&vsc); + + return (count); +} + + +/* + * vs_strtonum + * + * Converts a size string in the format into an integer. + * + * A size string is a numeric value followed by an optional unit + * specifier which is used as a multiplier to calculate a raw + * number. + * The size string format is: N[.N][KMGTP][B] + * + * The numeric value can contain a decimal portion. Unit specifiers + * are either a one-character or two-character string; i.e. "K" or + * "KB" for kilobytes. Unit specifiers must follow the numeric portion + * immediately, and are not case-sensitive. + * + * If either "B" is specified, or there is no unit specifier portion + * in the string, the numeric value is calculated with no multiplier + * (assumes a basic unit of "bytes"). + * + * Returns: + * -1: Failure; errno set to specify the error. + * 0: Success. + */ +int +vs_strtonum(const char *value, uint64_t *num) +{ + char *end; + int shift; + double fval; + + *num = 0; + + /* Check to see if this looks like a number. */ + if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { + errno = EINVAL; + return (-1); + } + + /* Rely on stroll() to process the numeric portion. */ + errno = 0; + *num = strtoll(value, &end, 10); + + /* + * Check for ERANGE, which indicates that the value is too large to + * fit in a 64-bit value. + */ + if (errno != 0) + return (-1); + + /* + * If we have a decimal value, then do the computation with floating + * point arithmetic. Otherwise, use standard arithmetic. + */ + if (*end == '.') { + fval = strtod(value, &end); + + if ((shift = vs_strtoshift(end)) == -1) + return (-1); /* errno set */ + + fval *= pow(2, shift); + if (fval > UINT64_MAX) { + errno = ERANGE; + return (-1); + } + + *num = (uint64_t)fval; + } else { + if ((shift = vs_strtoshift(end)) == -1) + return (-1); /* errno set */ + + /* Check for overflow */ + if (shift >= 64 || (*num << shift) >> shift != *num) { + errno = ERANGE; + return (-1); + } + + *num <<= shift; + } + + return (0); +} + + +/* + * vs_strtoshift + * + * Converts a unit specifier string into a number of bits that + * a numeric value must be shifted. + * + * Returns: + * -1: Failure; errno set to specify the error. + * >-1: Success; the shift count. + * + */ +static int +vs_strtoshift(const char *buf) +{ + const char *ends = "BKMGTPEZ"; + int i; + + if (buf[0] == '\0') + return (0); + for (i = 0; i < strlen(ends); i++) { + if (toupper(buf[0]) == ends[i]) + break; + } + if (i == strlen(ends)) { + errno = EINVAL; + return (-1); + } + + /* Allow trailing 'b' characters except in the case of 'BB'. */ + if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && + toupper(buf[0]) != 'B')) { + return (10 * i); + } + + errno = EINVAL; + return (-1); +} diff --git a/usr/src/lib/libvscan/common/libvscan.h b/usr/src/lib/libvscan/common/libvscan.h new file mode 100644 index 0000000000..42de60a6a5 --- /dev/null +++ b/usr/src/lib/libvscan/common/libvscan.h @@ -0,0 +1,222 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef __LIBVS_H__ +#define __LIBVS_H__ + +#include <netdb.h> +#include <netinet/in.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Property IDs - general property group */ +#define VS_PROPID_MAXSIZE 0x01LL +#define VS_PROPID_MAXSIZE_ACTION 0x02LL +#define VS_PROPID_TYPES 0x04LL +#define VS_PROPID_VLOG 0x08LL + +#define VS_PROPID_GEN_ALL (VS_PROPID_MAXSIZE | \ + VS_PROPID_MAXSIZE_ACTION | VS_PROPID_TYPES | VS_PROPID_VLOG) + +#define VS_PROPID_VALUE_AUTH 0x010LL + +/* Property IDs - scan engine property groups */ +#define VS_PROPID_SE_ENABLE 0x100LL +#define VS_PROPID_SE_HOST 0x200LL +#define VS_PROPID_SE_PORT 0x400LL +#define VS_PROPID_SE_MAXCONN 0x800LL + +#define VS_PROPID_SE_ALL (VS_PROPID_SE_ENABLE | \ + VS_PROPID_SE_HOST | VS_PROPID_SE_PORT | VS_PROPID_SE_MAXCONN) + +/* Check for whether a property id is a scan engine id */ +#define VS_PROPID_IS_SE(id) ((id & VS_PROPID_SE_ALL) ? 1 : 0) + +/* The maximum property id value - across all property groups */ +#define VS_PROPID_MAX VS_PROPID_SE_MAXCONN + +/* The number of properties in the largest property group */ +#define VS_NUM_PROPIDS 5 + +/* Range of scan engine IDs and max number of scan engines supported */ +#define VS_SE_MAX 16 +#define VS_SE_NAME_LEN 64 + +/* Min & Max scan engine connections per engine */ +#define VS_VAL_SE_MAXCONN_MIN 1 +#define VS_VAL_SE_MAXCONN_MAX 512 + +/* Can accommodate a string-ified ULONG_MAX plus unit specifier */ +#define VS_VAL_MAXSIZE_LEN 32 + +#define VS_VAL_TYPES_LEN 4096 +#define VS_VAL_TYPES_INVALID_CHARS "." + +/* libvscan error codes */ +#define VS_ERR_NONE 0 +#define VS_ERR_INVALID_PROPERTY 1 +#define VS_ERR_INVALID_VALUE 2 +#define VS_ERR_INVALID_HOST 3 +#define VS_ERR_INVALID_SE 4 +#define VS_ERR_MAX_SE 5 +#define VS_ERR_AUTH 6 +#define VS_ERR_DAEMON_COMM 10 +#define VS_ERR_SCF 20 +#define VS_ERR_SYS 30 + + +/* RBAC authorizations */ +#define VS_VALUE_AUTH "solaris.smf.value.vscan" +#define VS_ACTION_AUTH "solaris.smf.manage.vscan" +#define VS_MODIFY_AUTH "solaris.smf.modify.application" + +/* statistics door interface */ +#define VS_STATS_DOOR_NAME "/var/run/vscan_stats_door" +#define VS_STATS_DOOR_VERSION 1 + +/* scan statistics door request type */ +typedef enum { + VS_STATS_GET, + VS_STATS_RESET +} vs_stats_req_t; + +typedef struct vs_stats { + uint64_t vss_scanned; + uint64_t vss_infected; + uint64_t vss_cleaned; + uint64_t vss_failed; + struct { + char vss_engid[VS_SE_NAME_LEN]; + uint64_t vss_errors; + } vss_eng[VS_SE_MAX]; +} vs_stats_t; + +/* + * General service configuration properties + */ +typedef struct vs_props { + char vp_maxsize[VS_VAL_MAXSIZE_LEN]; + boolean_t vp_maxsize_action; + char vp_types[VS_VAL_TYPES_LEN]; + char vp_vlog[MAXPATHLEN]; +} vs_props_t; + +/* + * Scan engine configuration properties. These are defined + * per-engine. + */ +typedef struct vs_props_se { + char vep_engid[VS_SE_NAME_LEN]; + boolean_t vep_enable; + char vep_host[MAXHOSTNAMELEN]; + uint16_t vep_port; + uint64_t vep_maxconn; +} vs_props_se_t; + +typedef struct vs_props_all { + vs_props_t va_props; + vs_props_se_t va_se[VS_SE_MAX]; +} vs_props_all_t; + + +/* + * General service configuration properties API + * These functions return VS_ERR_XXX error codes. + */ +int vs_props_get_all(vs_props_all_t *); +int vs_props_set(const vs_props_t *, uint64_t); +int vs_props_get(vs_props_t *, uint64_t); +int vs_props_validate(const vs_props_t *, uint64_t); + + +/* + * Scan engine configuration properties API + * These functions return VS_ERR_XXX error codes. + */ +int vs_props_se_create(char *, const vs_props_se_t *, uint64_t); +int vs_props_se_set(char *, const vs_props_se_t *, uint64_t); +int vs_props_se_get(char *, vs_props_se_t *, uint64_t); +int vs_props_se_validate(const vs_props_se_t *, uint64_t); +int vs_props_se_delete(const char *); + + +/* Get error string for error code */ +const char *vs_strerror(int); + +/* Functions to access/reset scan statistics in service daemon */ +int vs_statistics(vs_stats_t *); +int vs_statistics_reset(void); + + +/* Utility functions */ + +/* + * Replace comma separators with '\0'. + * + * Types contains comma separated rules each beginning with +|- + * - embedded commas are escaped by backslash + * - backslash is escaped by backslash + * - a single backslash not followed by comma is illegal + * + * On entry to the function len must contain the length of + * the buffer. On sucecssful exit len will contain the length + * of the parsed data within the buffer. + * + * Returns 0 on success, -1 on failure + */ +int vs_parse_types(const char *, char *, uint32_t *); + + +/* + * Converts a size string in the format into an integer. + * + * A size string is a numeric value followed by an optional unit + * specifier which is used as a multiplier to calculate a raw + * number. + * The size string format is: N[.N][KMGTP][B] + * + * The numeric value can contain a decimal portion. Unit specifiers + * are either a one-character or two-character string; i.e. "K" or + * "KB" for kilobytes. Unit specifiers must follow the numeric portion + * immediately, and are not case-sensitive. + * + * If either "B" is specified, or there is no unit specifier portion + * in the string, the numeric value is calculated with no multiplier + * (assumes a basic unit of "bytes"). + * + * Returns: -1: Failure; errno set to specify the error. + * 0: Success. + */ +int vs_strtonum(const char *, uint64_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBVS_H__ */ diff --git a/usr/src/lib/libvscan/common/llib-lvscan b/usr/src/lib/libvscan/common/llib-lvscan new file mode 100644 index 0000000000..edddd485fa --- /dev/null +++ b/usr/src/lib/libvscan/common/llib-lvscan @@ -0,0 +1,31 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/*LINTLIBRARY*/ +/*PROTOLIB1*/ + +#include <libvscan.h> diff --git a/usr/src/lib/libvscan/common/mapfile-vers b/usr/src/lib/libvscan/common/mapfile-vers new file mode 100644 index 0000000000..12cec43df9 --- /dev/null +++ b/usr/src/lib/libvscan/common/mapfile-vers @@ -0,0 +1,46 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate { + global: + vs_props_get_all; + vs_props_get; + vs_props_set; + vs_props_validate; + vs_props_se_get; + vs_props_se_set; + vs_props_se_validate; + vs_props_se_create; + vs_props_se_delete; + vs_statistics; + vs_statistics_reset; + vs_parse_types; + vs_strtonum; + vs_strerror; + local: + *; +}; diff --git a/usr/src/lib/libvscan/i386/Makefile b/usr/src/lib/libvscan/i386/Makefile new file mode 100644 index 0000000000..f91f0270e9 --- /dev/null +++ b/usr/src/lib/libvscan/i386/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libvscan/sparc/Makefile b/usr/src/lib/libvscan/sparc/Makefile new file mode 100644 index 0000000000..f91f0270e9 --- /dev/null +++ b/usr/src/lib/libvscan/sparc/Makefile @@ -0,0 +1,30 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) |