4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
38 #include <auth_attr.h>
40 #include <sys/socket.h>
41 #include <arpa/inet.h>
45 #define VS_DOOR_CALL_RETRIES 3
47 #define VS_INSTANCE_FMRI "svc:/system/filesystem/vscan:icap"
49 /* SMF property group and property names */
50 #define VS_PGNAME_GENERAL "vs_general"
51 #define VS_PGNAME_ENGINE_PREFIX "vs_engine_"
52 #define VS_PGNAME_ENGINE_LEN VS_SE_NAME_LEN + 16
54 #define VS_PNAME_MAXSIZE "maxsize"
55 #define VS_PNAME_MAXSIZE_ACTION "maxsize_action"
56 #define VS_PNAME_TYPES "types"
57 #define VS_PNAME_VLOG "viruslog"
59 #define VS_PNAME_SE_ENABLE "enable"
60 #define VS_PNAME_SE_HOST "host"
61 #define VS_PNAME_SE_PORT "port"
62 #define VS_PNAME_SE_MAXCONN "max_connect"
63 #define VS_PNAME_VAUTH "value_authorization"
66 /* types string processing */
67 #define VS_TYPES_SEP ','
68 #define VS_TYPES_ESCAPE '\\'
69 #define VS_TYPES_RULES "+-"
73 * The SCF context enapsulating the SCF objects used in the
74 * repository load and store routines vs_scf_values_get()
75 * and vs_scf_values_set().
77 * The context is always opened before a get or set, then
78 * closed when finished (or on error); the open does an
79 * initial setup, while inside the get and set functions,
80 * additional objects within the context may be selectively
81 * initialized for use, depending on the actions needed and
82 * the properties being operated on.
84 typedef struct vs_scfctx
{
85 scf_handle_t
*vscf_handle
;
86 scf_instance_t
*vscf_inst
;
87 scf_propertygroup_t
*vscf_pgroup
;
88 scf_transaction_t
*vscf_tx
;
89 scf_iter_t
*vscf_iter
;
90 scf_property_t
*vscf_prop
[VS_NUM_PROPIDS
];
91 scf_transaction_entry_t
*vscf_ent
[VS_NUM_PROPIDS
];
92 scf_value_t
*vscf_val
[VS_NUM_PROPIDS
];
96 * The vscan property definition. Maps the property id with the name
97 * and type used to store the property in the repository.
98 * A table of these definitions is defined with a single entry per
102 const char *vpd_name
;
112 typedef struct vs_prop_hd
{
113 vs_prop_type_t vp_type
;
122 #define vp_gen vp_props.vp_gen
123 #define vp_se vp_props.vp_se
126 * Default values - these are used to return valid data
127 * to the caller in cases where invalid or unexpected values
128 * are found in the repository.
130 * Note: These values must be kept in sync with those defined
131 * in the service manifest.
133 static const boolean_t vs_dflt_allow
= B_TRUE
;
134 static const boolean_t vs_dflt_enable
= B_TRUE
;
135 static const char *vs_dflt_maxsize
= "1GB";
136 static const char *vs_dflt_host
= "";
137 static const uint16_t vs_dflt_port
= 1344;
138 static const uint16_t vs_dflt_maxconn
= 8;
139 static const char *vs_dflt_types
= "+*";
140 static const char *vs_dflt_vlog
= "";
142 /* Property definition table */
143 static const vs_propdef_t vs_propdefs
[] = {
144 /* general properties */
145 { VS_PNAME_MAXSIZE
, VS_PROPID_MAXSIZE
, SCF_TYPE_ASTRING
},
146 { VS_PNAME_MAXSIZE_ACTION
, VS_PROPID_MAXSIZE_ACTION
, SCF_TYPE_BOOLEAN
},
147 { VS_PNAME_TYPES
, VS_PROPID_TYPES
, SCF_TYPE_ASTRING
},
148 { VS_PNAME_VLOG
, VS_PROPID_VLOG
, SCF_TYPE_ASTRING
},
149 /* scan engine properties */
150 { VS_PNAME_SE_ENABLE
, VS_PROPID_SE_ENABLE
, SCF_TYPE_BOOLEAN
},
151 { VS_PNAME_SE_HOST
, VS_PROPID_SE_HOST
, SCF_TYPE_HOST
},
152 { VS_PNAME_SE_PORT
, VS_PROPID_SE_PORT
, SCF_TYPE_INTEGER
},
153 { VS_PNAME_SE_MAXCONN
, VS_PROPID_SE_MAXCONN
, SCF_TYPE_INTEGER
},
154 { VS_PNAME_VAUTH
, VS_PROPID_VALUE_AUTH
, SCF_TYPE_ASTRING
}
157 static const int vs_npropdefs
= sizeof (vs_propdefs
)/sizeof (vs_propdef_t
);
159 /* Local functions */
160 static const vs_propdef_t
*vs_get_propdef(uint64_t);
161 static void vs_default_value(vs_prop_hd_t
*, const uint64_t);
163 static int vs_scf_values_get(const char *, vs_prop_hd_t
*);
164 static int vs_scf_get(const vs_propdef_t
*, vs_prop_hd_t
*, vs_scfctx_t
*, int);
166 static int vs_scf_values_set(const char *, vs_prop_hd_t
*);
167 static int vs_scf_set(const vs_propdef_t
*, vs_prop_hd_t
*, vs_scfctx_t
*, int);
168 static int vs_scf_pg_create(const char *, vs_prop_hd_t
*);
169 static int vs_scf_pg_delete(const char *);
171 static int vs_scf_ctx_open(vs_scfctx_t
*);
172 static void vs_scf_ctx_close(vs_scfctx_t
*);
174 static int vs_validate(const vs_prop_hd_t
*, uint64_t);
175 static int vs_is_valid_types(const char *);
176 static int vs_is_valid_host(const char *);
177 static int vs_checkauth(char *);
178 static int vs_door_call(int, door_arg_t
*);
180 static int vs_props_get_engines(char *[], int *);
181 static void vs_engid_to_pgname(const char *, char [VS_PGNAME_ENGINE_LEN
]);
182 static int vs_scf_pg_count(void);
183 static int vs_strtoshift(const char *);
189 * Retrieves the general service properties and all properties
190 * for all scan engines from the repository.
192 * If invalid property values are found, the values are corrected to
201 vs_props_get_all(vs_props_all_t
*va
)
204 char *engids
[VS_SE_MAX
];
206 (void) memset(va
, 0, sizeof (vs_props_all_t
));
207 if ((rc
= vs_props_get(&va
->va_props
, VS_PROPID_GEN_ALL
))
212 if ((rc
= vs_props_get_engines(engids
, &n
)) != VS_ERR_NONE
)
215 for (i
= 0; i
< n
; i
++) {
216 if ((rc
= vs_props_se_get(engids
[i
],
217 &va
->va_se
[i
], VS_PROPID_SE_ALL
)) != VS_ERR_NONE
)
221 /* free engids allocated in vs_props_get_engines */
222 for (i
= 0; i
< VS_SE_MAX
; i
++) {
223 if (engids
[i
] != NULL
)
234 * Retrieves values for the specified general service properties from
237 * If invalid property values are found, the values are corrected to
242 * VS_ERR_INVALID_PROPERTY
247 vs_props_get(vs_props_t
*vp
, uint64_t propids
)
250 vs_prop_hd_t prop_hd
;
252 if ((propids
& VS_PROPID_GEN_ALL
) != propids
)
253 return (VS_ERR_INVALID_PROPERTY
);
255 (void) memset(&prop_hd
, 0, sizeof (vs_prop_hd_t
));
256 prop_hd
.vp_type
= VS_PTYPE_GEN
;
257 prop_hd
.vp_ids
= propids
;
258 prop_hd
.vp_all
= VS_PROPID_GEN_ALL
;
260 rc
= vs_scf_values_get(VS_PGNAME_GENERAL
, &prop_hd
);
262 *vp
= prop_hd
.vp_gen
;
270 * Changes values for the specified general service properties
275 * VS_ERR_INVALID_PROPERTY
276 * VS_ERR_INVALID_VALUE
281 vs_props_set(const vs_props_t
*vp
, uint64_t propids
)
283 vs_prop_hd_t prop_hd
;
285 if ((propids
& VS_PROPID_GEN_ALL
) != propids
)
286 return (VS_ERR_INVALID_PROPERTY
);
288 (void) memset(&prop_hd
, 0, sizeof (vs_prop_hd_t
));
289 prop_hd
.vp_type
= VS_PTYPE_GEN
;
290 prop_hd
.vp_ids
= propids
;
291 prop_hd
.vp_all
= VS_PROPID_GEN_ALL
;
292 prop_hd
.vp_gen
= *vp
;
293 return (vs_scf_values_set(VS_PGNAME_GENERAL
, &prop_hd
));
300 * Retrieves values for the specified scan engine properties from the
303 * If the enable property is set (true), the host property is
304 * checked for validity. If it is not valid, the requested values
305 * are returned with the enable propery set to off (false)
309 * VS_ERR_INVALID_PROPERTY
314 vs_props_se_get(char *engid
, vs_props_se_t
*sep
, uint64_t propids
)
317 char pgname
[VS_PGNAME_ENGINE_LEN
];
318 vs_prop_hd_t prop_hd
;
320 /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
321 if (strcmp(engid
, VS_PGNAME_GENERAL
) == 0)
322 return (VS_ERR_INVALID_SE
);
324 if ((propids
& VS_PROPID_SE_ALL
) != propids
)
325 return (VS_ERR_INVALID_PROPERTY
);
327 (void) memset(&prop_hd
, 0, sizeof (vs_prop_hd_t
));
328 prop_hd
.vp_type
= VS_PTYPE_SE
;
329 prop_hd
.vp_ids
= propids
;
330 prop_hd
.vp_all
= VS_PROPID_SE_ALL
;
331 (void) strlcpy(prop_hd
.vp_se
.vep_engid
, engid
, VS_SE_NAME_LEN
);
333 /* If getting enable, get the host property too */
334 if ((propids
& VS_PROPID_SE_ENABLE
))
335 prop_hd
.vp_ids
|= VS_PROPID_SE_HOST
;
337 /* Load values from the repository */
338 vs_engid_to_pgname(engid
, pgname
);
339 rc
= vs_scf_values_get(pgname
, &prop_hd
);
340 if (rc
!= VS_ERR_NONE
)
344 * If the host is invalid and the enable property is on,
345 * return enable property as off
347 if ((prop_hd
.vp_ids
& VS_PROPID_SE_HOST
) &&
348 (vs_validate(&prop_hd
, VS_PROPID_SE_HOST
) != VS_ERR_NONE
)) {
349 prop_hd
.vp_se
.vep_enable
= B_FALSE
;
352 *sep
= prop_hd
.vp_se
;
361 * Changes the values for the specified scan engine properties in the
364 * If the enable property is being changed to true in this operation,
365 * a host property must also be specified, or already exist in the
370 * VS_ERR_INVALID_PROPERTY
371 * VS_ERR_INVALID_VALUE
376 vs_props_se_set(char *engid
, const vs_props_se_t
*sep
, uint64_t propids
)
379 char pgname
[VS_PGNAME_ENGINE_LEN
];
380 vs_prop_hd_t prop_hd
;
382 /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
383 if (strcmp(engid
, VS_PGNAME_GENERAL
) == 0)
384 return (VS_ERR_INVALID_SE
);
386 if ((propids
& VS_PROPID_SE_ALL
) != propids
)
387 return (VS_ERR_INVALID_PROPERTY
);
389 (void) memset(&prop_hd
, 0, sizeof (vs_prop_hd_t
));
390 prop_hd
.vp_type
= VS_PTYPE_SE
;
391 prop_hd
.vp_all
= VS_PROPID_SE_ALL
;
393 vs_engid_to_pgname(engid
, pgname
);
396 * if enabling a scan engine, ensure that a valid host
397 * is also being set, or already exists in the repository
399 if ((propids
& VS_PROPID_SE_ENABLE
) && (sep
->vep_enable
== B_TRUE
) &&
400 !(propids
& VS_PROPID_SE_HOST
)) {
402 prop_hd
.vp_ids
= VS_PROPID_SE_HOST
;
403 if ((rc
= vs_scf_values_get(pgname
, &prop_hd
)) != VS_ERR_NONE
)
406 if (vs_validate(&prop_hd
, VS_PROPID_SE_HOST
) != VS_ERR_NONE
)
407 return (VS_ERR_INVALID_HOST
);
410 prop_hd
.vp_ids
= propids
;
411 prop_hd
.vp_se
= *sep
;
413 return (vs_scf_values_set(pgname
, &prop_hd
));
421 vs_props_se_create(char *engid
, const vs_props_se_t
*sep
, uint64_t propids
)
424 char pgname
[VS_PGNAME_ENGINE_LEN
];
425 vs_prop_hd_t prop_hd
;
427 if ((propids
& VS_PROPID_SE_ALL
) != propids
)
428 return (VS_ERR_INVALID_PROPERTY
);
430 /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
431 if (strcmp(engid
, VS_PGNAME_GENERAL
) == 0)
432 return (VS_ERR_INVALID_SE
);
434 if ((n
= vs_scf_pg_count()) == -1)
438 return (VS_ERR_MAX_SE
);
440 vs_engid_to_pgname(engid
, pgname
);
442 (void) memset(&prop_hd
, 0, sizeof (vs_prop_hd_t
));
443 prop_hd
.vp_type
= VS_PTYPE_SE
;
444 prop_hd
.vp_all
= VS_PROPID_SE_ALL
;
445 prop_hd
.vp_ids
= propids
| VS_PROPID_VALUE_AUTH
;
446 prop_hd
.vp_se
= *sep
;
448 /* if hostname not specified, default it to engid */
449 if ((propids
& VS_PROPID_SE_HOST
) == 0) {
450 (void) strlcpy(prop_hd
.vp_se
.vep_host
, engid
, MAXHOSTNAMELEN
);
451 prop_hd
.vp_ids
|= VS_PROPID_SE_HOST
;
454 return (vs_scf_pg_create(pgname
, &prop_hd
));
462 vs_props_se_delete(const char *engid
)
464 char pgname
[VS_PGNAME_ENGINE_LEN
];
466 /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
467 if (strcmp(engid
, VS_PGNAME_GENERAL
) == 0)
468 return (VS_ERR_INVALID_SE
);
470 vs_engid_to_pgname(engid
, pgname
);
472 return (vs_scf_pg_delete(pgname
));
480 vs_strerror(int error
)
484 return (gettext("no error"));
485 case VS_ERR_INVALID_PROPERTY
:
486 return (gettext("invalid property id"));
487 case VS_ERR_INVALID_VALUE
:
488 return (gettext("invalid property value"));
489 case VS_ERR_INVALID_HOST
:
490 return (gettext("invalid host"));
491 case VS_ERR_INVALID_SE
:
492 return (gettext("invalid scan engine"));
494 return (gettext("max scan engines exceeded"));
496 return (gettext("insufficient privileges for action"));
497 case VS_ERR_DAEMON_COMM
:
498 return (gettext("unable to contact vscand"));
500 return (scf_strerror(scf_error()));
502 return (strerror(errno
));
504 return (gettext("unknown error"));
512 * Finds and returns a property definition by property id.
514 static const vs_propdef_t
*
515 vs_get_propdef(uint64_t propid
)
519 for (i
= 0; i
< vs_npropdefs
; i
++) {
520 if (propid
== vs_propdefs
[i
].vpd_id
)
521 return (&vs_propdefs
[i
]);
531 * Sets a property value that contains invalid data to its default value.
533 * Note that this function does not alter any values in the repository
534 * This is only to enable the caller to get valid data.
537 vs_default_value(vs_prop_hd_t
*prop_hd
, const uint64_t propid
)
539 vs_props_t
*vp
= &prop_hd
->vp_gen
;
540 vs_props_se_t
*vep
= &prop_hd
->vp_se
;
543 case VS_PROPID_MAXSIZE
:
544 (void) strlcpy(vp
->vp_maxsize
, vs_dflt_maxsize
,
545 sizeof (vp
->vp_maxsize
));
547 case VS_PROPID_MAXSIZE_ACTION
:
548 vp
->vp_maxsize_action
= vs_dflt_allow
;
550 case VS_PROPID_TYPES
:
551 (void) strlcpy(vp
->vp_types
, vs_dflt_types
,
552 sizeof (vp
->vp_types
));
555 (void) strlcpy(vp
->vp_vlog
, vs_dflt_vlog
,
556 sizeof (vp
->vp_vlog
));
558 case VS_PROPID_SE_ENABLE
:
559 vep
->vep_enable
= vs_dflt_enable
;
561 case VS_PROPID_SE_HOST
:
562 (void) strlcpy(vep
->vep_host
, vs_dflt_host
,
563 sizeof (vep
->vep_host
));
565 case VS_PROPID_SE_PORT
:
566 vep
->vep_port
= vs_dflt_port
;
568 case VS_PROPID_SE_MAXCONN
:
569 vep
->vep_maxconn
= vs_dflt_maxconn
;
580 * Gets property values for one or more properties from the repository.
581 * This is the single entry point for loading SMF values.
583 * While a transaction is not used for loading property values,
584 * the operation is parameterized by a property group. All properties
585 * retrieved in this function, then, must belong to the same property
589 vs_scf_values_get(const char *pgname
, vs_prop_hd_t
*prop_hd
)
593 const vs_propdef_t
*vpd
;
596 if ((vs_scf_ctx_open(&vsc
)) != 0) {
597 vs_scf_ctx_close(&vsc
);
601 if (scf_instance_get_pg(vsc
.vscf_inst
, pgname
, vsc
.vscf_pgroup
) == -1) {
602 vs_scf_ctx_close(&vsc
);
603 if (strcmp(pgname
, "VS_PGNAME_GENERAL") != 0) {
605 if ((rc
== SCF_ERROR_NOT_FOUND
) ||
606 (rc
== SCF_ERROR_INVALID_ARGUMENT
))
607 return (VS_ERR_INVALID_SE
);
614 for (propid
= 1LL; propid
<= VS_PROPID_MAX
; propid
<<= 1) {
615 if ((prop_hd
->vp_ids
& propid
) == 0)
618 if ((vpd
= vs_get_propdef(propid
)) == NULL
) {
619 rc
= VS_ERR_INVALID_PROPERTY
;
623 vsc
.vscf_prop
[np
] = scf_property_create(vsc
.vscf_handle
);
624 vsc
.vscf_val
[np
] = scf_value_create(vsc
.vscf_handle
);
626 if (vsc
.vscf_prop
[np
] == NULL
|| vsc
.vscf_val
[np
] == NULL
) {
631 if (scf_pg_get_property(vsc
.vscf_pgroup
, vpd
->vpd_name
,
632 vsc
.vscf_prop
[np
]) == -1) {
633 if (scf_error() == SCF_ERROR_NOT_FOUND
) {
634 vs_default_value(prop_hd
, vpd
->vpd_id
);
641 if ((rc
= vs_scf_get(vpd
, prop_hd
, &vsc
, np
)) != VS_ERR_NONE
)
648 vs_scf_ctx_close(&vsc
);
657 * Loads a single values from the repository into the appropriate vscan
658 * property structure member.
661 vs_scf_get(const vs_propdef_t
*vpd
, vs_prop_hd_t
*prop_hd
,
662 vs_scfctx_t
*vsc
, int idx
)
667 vs_props_t
*vp
= &prop_hd
->vp_gen
;
668 vs_props_se_t
*vep
= &prop_hd
->vp_se
;
670 if ((rc
= scf_property_get_value(vsc
->vscf_prop
[idx
],
671 vsc
->vscf_val
[idx
])) == -1) {
672 if (rc
== SCF_ERROR_CONSTRAINT_VIOLATED
||
673 rc
== SCF_ERROR_NOT_FOUND
) {
674 vs_default_value(prop_hd
, vpd
->vpd_id
);
675 return (VS_ERR_NONE
);
681 switch (vpd
->vpd_id
) {
682 case VS_PROPID_MAXSIZE
:
683 if ((scf_value_get_astring(vsc
->vscf_val
[idx
],
684 vp
->vp_maxsize
, sizeof (vp
->vp_maxsize
))) == -1) {
688 case VS_PROPID_MAXSIZE_ACTION
:
689 if ((scf_value_get_boolean(vsc
->vscf_val
[idx
],
693 vp
->vp_maxsize_action
= (valbool
== 0) ? B_FALSE
: B_TRUE
;
695 case VS_PROPID_TYPES
:
696 if ((scf_value_get_astring(vsc
->vscf_val
[idx
],
697 vp
->vp_types
, sizeof (vp
->vp_types
))) == -1) {
702 if ((scf_value_get_astring(vsc
->vscf_val
[idx
],
703 vp
->vp_vlog
, sizeof (vp
->vp_vlog
))) == -1) {
707 case VS_PROPID_SE_ENABLE
:
708 if ((scf_value_get_boolean(vsc
->vscf_val
[idx
],
712 vep
->vep_enable
= (valbool
== 0) ? B_FALSE
: B_TRUE
;
714 case VS_PROPID_SE_HOST
:
715 (void) scf_value_get_as_string_typed(vsc
->vscf_val
[idx
],
716 vpd
->vpd_type
, vep
->vep_host
, sizeof (vep
->vep_host
));
718 case VS_PROPID_SE_PORT
:
719 if ((scf_value_get_integer(vsc
->vscf_val
[idx
], &port
)) == -1)
721 if (port
<= 0 || port
>= UINT16_MAX
)
722 rc
= VS_ERR_INVALID_VALUE
;
724 vep
->vep_port
= (uint16_t)port
;
726 case VS_PROPID_SE_MAXCONN
:
727 if ((scf_value_get_integer(vsc
->vscf_val
[idx
],
728 (int64_t *)&vep
->vep_maxconn
)) == -1) {
736 if ((rc
!= VS_ERR_NONE
) ||
737 (vs_validate(prop_hd
, vpd
->vpd_id
) != VS_ERR_NONE
)) {
738 vs_default_value(prop_hd
, vpd
->vpd_id
);
741 return (VS_ERR_NONE
);
749 vs_scf_pg_create(const char *pgname
, vs_prop_hd_t
*prop_hd
)
755 /* ensure that caller has authorization to refresh service */
756 if ((rc
= vs_checkauth(VS_ACTION_AUTH
)) != VS_ERR_NONE
)
759 if (vs_scf_ctx_open(&vsc
) != 0) {
760 vs_scf_ctx_close(&vsc
);
764 if (scf_instance_add_pg(vsc
.vscf_inst
, pgname
,
765 SCF_GROUP_APPLICATION
, 0, vsc
.vscf_pgroup
) == -1) {
766 vs_scf_ctx_close(&vsc
);
767 if (scf_error() == SCF_ERROR_INVALID_ARGUMENT
)
768 return (VS_ERR_INVALID_SE
);
771 vs_scf_ctx_close(&vsc
);
773 /* set default values for those not specified */
774 for (propid
= 1LL; propid
<= VS_PROPID_MAX
; propid
<<= 1) {
775 if ((propid
& prop_hd
->vp_all
) && !(propid
& prop_hd
->vp_ids
))
776 vs_default_value(prop_hd
, propid
);
779 prop_hd
->vp_ids
= prop_hd
->vp_all
;
780 prop_hd
->vp_ids
|= VS_PROPID_VALUE_AUTH
;
782 rc
= vs_scf_values_set(pgname
, prop_hd
);
783 if (rc
!= VS_ERR_NONE
)
784 (void) vs_scf_pg_delete(pgname
);
794 vs_scf_pg_delete(const char *pgname
)
799 /* ensure that caller has authorization to refresh service */
800 if ((rc
= vs_checkauth(VS_ACTION_AUTH
)) != VS_ERR_NONE
)
803 if (vs_scf_ctx_open(&vsc
) != 0) {
804 vs_scf_ctx_close(&vsc
);
808 if (scf_instance_get_pg(vsc
.vscf_inst
, pgname
, vsc
.vscf_pgroup
) == -1) {
809 vs_scf_ctx_close(&vsc
);
811 if ((rc
== SCF_ERROR_NOT_FOUND
) ||
812 (rc
== SCF_ERROR_INVALID_ARGUMENT
))
813 return (VS_ERR_INVALID_SE
);
818 if (scf_pg_delete(vsc
.vscf_pgroup
) == -1) {
819 vs_scf_ctx_close(&vsc
);
821 if ((rc
== SCF_ERROR_NOT_FOUND
) ||
822 (rc
== SCF_ERROR_INVALID_ARGUMENT
))
823 return (VS_ERR_INVALID_SE
);
828 vs_scf_ctx_close(&vsc
);
830 /* Notify the daemon that things have changed */
831 if ((smf_refresh_instance(VS_INSTANCE_FMRI
)) == -1) {
835 return (VS_ERR_NONE
);
842 * Sets property values in the repository. This is the single
843 * entry point for storing SMF values.
845 * Like loading values, this is an operation based on a single property
846 * group, so all property values changed in this function must belong
847 * to the same property group. Additionally, this operation is done in
848 * the context of a repository transaction; on any fatal error, the
849 * SCF context will be closed, destroying all SCF objects and aborting
853 vs_scf_values_set(const char *pgname
, vs_prop_hd_t
*prop_hd
)
856 const vs_propdef_t
*vpd
;
860 /* ensure that caller has authorization to refresh service */
861 if ((rc
= vs_checkauth(VS_ACTION_AUTH
)) != VS_ERR_NONE
)
864 if (vs_scf_ctx_open(&vsc
) != 0) {
865 vs_scf_ctx_close(&vsc
);
869 if (scf_instance_get_pg(vsc
.vscf_inst
, pgname
, vsc
.vscf_pgroup
) == -1) {
870 vs_scf_ctx_close(&vsc
);
872 if (strcmp(pgname
, "VS_PGNAME_GENERAL") != 0) {
873 if ((rc
== SCF_ERROR_NOT_FOUND
) ||
874 (rc
== SCF_ERROR_INVALID_ARGUMENT
))
875 return (VS_ERR_INVALID_SE
);
880 if (((vsc
.vscf_tx
= scf_transaction_create(vsc
.vscf_handle
)) == NULL
) ||
881 (scf_transaction_start(vsc
.vscf_tx
, vsc
.vscf_pgroup
) == -1)) {
882 vs_scf_ctx_close(&vsc
);
886 /* Process the value change for each specified property */
889 for (propid
= 1LL; propid
<= VS_PROPID_MAX
; propid
<<= 1) {
890 if ((prop_hd
->vp_ids
& propid
) == 0)
893 if ((vpd
= vs_get_propdef(propid
)) == NULL
) {
894 rc
= VS_ERR_INVALID_PROPERTY
;
898 vsc
.vscf_val
[np
] = scf_value_create(vsc
.vscf_handle
);
899 vsc
.vscf_ent
[np
] = scf_entry_create(vsc
.vscf_handle
);
901 if (vsc
.vscf_val
[np
] == NULL
|| vsc
.vscf_ent
[np
] == NULL
) {
906 if ((rc
= scf_transaction_property_change(vsc
.vscf_tx
,
907 vsc
.vscf_ent
[np
], vpd
->vpd_name
, vpd
->vpd_type
)) == -1) {
908 rc
= scf_transaction_property_new(vsc
.vscf_tx
,
909 vsc
.vscf_ent
[np
], vpd
->vpd_name
, vpd
->vpd_type
);
916 if ((rc
= vs_scf_set(vpd
, prop_hd
, &vsc
, np
)) != VS_ERR_NONE
)
922 if (rc
!= VS_ERR_NONE
) {
923 vs_scf_ctx_close(&vsc
);
927 /* Commit the transaction */
928 if (scf_transaction_commit(vsc
.vscf_tx
) == -1) {
929 vs_scf_ctx_close(&vsc
);
932 vs_scf_ctx_close(&vsc
);
934 /* Notify the daemon that things have changed */
935 if ((smf_refresh_instance(VS_INSTANCE_FMRI
)) == -1)
938 return (VS_ERR_NONE
);
945 * Stores a single value from the appropriate vscan property structure
946 * member into the repository.
948 * Values are set in the SCF value object, then the value object
949 * is added to the SCF property object.
952 vs_scf_set(const vs_propdef_t
*vpd
, vs_prop_hd_t
*prop_hd
,
953 vs_scfctx_t
*vsc
, int idx
)
956 vs_props_t
*vp
= &prop_hd
->vp_gen
;
957 vs_props_se_t
*vep
= &prop_hd
->vp_se
;
959 if ((rc
= vs_validate(prop_hd
, vpd
->vpd_id
)) != VS_ERR_NONE
)
963 switch (vpd
->vpd_id
) {
964 case VS_PROPID_MAXSIZE
:
965 if ((scf_value_set_astring(vsc
->vscf_val
[idx
],
966 vp
->vp_maxsize
)) == -1) {
970 case VS_PROPID_MAXSIZE_ACTION
:
971 scf_value_set_boolean(vsc
->vscf_val
[idx
],
972 (uint8_t)vp
->vp_maxsize_action
);
974 case VS_PROPID_TYPES
:
975 if ((scf_value_set_astring(vsc
->vscf_val
[idx
],
976 vp
->vp_types
)) == -1) {
980 case VS_PROPID_SE_ENABLE
:
981 scf_value_set_boolean(vsc
->vscf_val
[idx
],
982 (uint8_t)vep
->vep_enable
);
984 case VS_PROPID_SE_HOST
:
985 if ((scf_value_set_from_string(vsc
->vscf_val
[idx
],
986 vpd
->vpd_type
, vep
->vep_host
)) == -1) {
990 case VS_PROPID_SE_PORT
:
991 scf_value_set_integer(vsc
->vscf_val
[idx
], vep
->vep_port
);
993 case VS_PROPID_SE_MAXCONN
:
994 scf_value_set_integer(vsc
->vscf_val
[idx
],
997 case VS_PROPID_VALUE_AUTH
:
998 if ((scf_value_set_astring(vsc
->vscf_val
[idx
],
999 VS_VALUE_AUTH
)) == -1) {
1000 return (VS_ERR_SCF
);
1007 if ((scf_entry_add_value(vsc
->vscf_ent
[idx
],
1008 vsc
->vscf_val
[idx
])) == -1) {
1009 return (VS_ERR_SCF
);
1019 * Opens an SCF context; creates the minumum SCF objects
1020 * for use in loading/storing from the SMF repository (meaning
1021 * vscf_property group data).
1023 * Other SCF objects in the context may be initialized elsewher
1024 * subsequent to open, but all initialized structures are destroyed
1025 * in vs_scf_ctx_close().
1028 vs_scf_ctx_open(vs_scfctx_t
*vsc
)
1030 (void) memset(vsc
, 0, sizeof (vs_scfctx_t
));
1032 if ((vsc
->vscf_handle
= scf_handle_create(SCF_VERSION
)) == NULL
)
1033 return (VS_ERR_SCF
);
1035 if (scf_handle_bind(vsc
->vscf_handle
) == -1)
1036 return (VS_ERR_SCF
);
1038 if ((vsc
->vscf_inst
= scf_instance_create(vsc
->vscf_handle
)) == NULL
)
1039 return (VS_ERR_SCF
);
1041 if (scf_handle_decode_fmri(vsc
->vscf_handle
, VS_INSTANCE_FMRI
,
1042 NULL
, NULL
, vsc
->vscf_inst
, NULL
, NULL
,
1043 SCF_DECODE_FMRI_EXACT
) == -1) {
1044 return (VS_ERR_SCF
);
1047 if ((vsc
->vscf_pgroup
= scf_pg_create(vsc
->vscf_handle
)) == NULL
)
1048 return (VS_ERR_SCF
);
1050 return (VS_ERR_NONE
);
1057 * Closes an SCF context; destroys all initialized SCF objects.
1060 vs_scf_ctx_close(vs_scfctx_t
*vsc
)
1064 for (i
= 0; i
< VS_NUM_PROPIDS
; i
++) {
1065 if (vsc
->vscf_val
[i
])
1066 scf_value_destroy(vsc
->vscf_val
[i
]);
1067 if (vsc
->vscf_ent
[i
])
1068 scf_entry_destroy(vsc
->vscf_ent
[i
]);
1069 if (vsc
->vscf_prop
[i
])
1070 scf_property_destroy(vsc
->vscf_prop
[i
]);
1074 scf_iter_destroy(vsc
->vscf_iter
);
1076 scf_transaction_destroy(vsc
->vscf_tx
);
1077 if (vsc
->vscf_pgroup
)
1078 scf_pg_destroy(vsc
->vscf_pgroup
);
1080 scf_instance_destroy(vsc
->vscf_inst
);
1081 if (vsc
->vscf_handle
)
1082 scf_handle_destroy(vsc
->vscf_handle
);
1089 * Validate property identified in propid.
1091 * Returns: VS_ERR_NONE
1092 * VS_ERR_INVALID_VALUE
1093 * VS_ERR_INVALID_PROPERTY
1096 vs_validate(const vs_prop_hd_t
*prop_hd
, uint64_t propid
)
1099 const vs_props_t
*vp
= &prop_hd
->vp_gen
;
1100 const vs_props_se_t
*vep
= &prop_hd
->vp_se
;
1103 case VS_PROPID_MAXSIZE
:
1104 if ((vs_strtonum(vp
->vp_maxsize
, &num
) != 0) || (num
== 0))
1105 return (VS_ERR_INVALID_VALUE
);
1107 case VS_PROPID_MAXSIZE_ACTION
:
1109 case VS_PROPID_TYPES
:
1110 if (!vs_is_valid_types(vp
->vp_types
))
1111 return (VS_ERR_INVALID_VALUE
);
1113 case VS_PROPID_SE_ENABLE
:
1115 case VS_PROPID_SE_PORT
:
1116 if (vep
->vep_port
== 0)
1117 return (VS_ERR_INVALID_VALUE
);
1119 case VS_PROPID_SE_HOST
:
1120 if (!vs_is_valid_host(vep
->vep_host
))
1121 return (VS_ERR_INVALID_VALUE
);
1123 case VS_PROPID_SE_MAXCONN
:
1124 if (vep
->vep_maxconn
< VS_VAL_SE_MAXCONN_MIN
||
1125 vep
->vep_maxconn
> VS_VAL_SE_MAXCONN_MAX
)
1126 return (VS_ERR_INVALID_VALUE
);
1128 case VS_PROPID_VALUE_AUTH
:
1129 case VS_PROPID_VLOG
:
1132 return (VS_ERR_INVALID_PROPERTY
);
1135 return (VS_ERR_NONE
);
1142 * Validate properties identified in propids.
1144 * Returns: VS_ERR_NONE
1145 * VS_ERR_INVALID_VALUE
1146 * VS_ERR_INVALID_PROPERTY
1149 vs_props_validate(const vs_props_t
*props
, uint64_t propids
)
1152 vs_prop_hd_t prop_hd
;
1154 if ((propids
& VS_PROPID_GEN_ALL
) != propids
)
1155 return (VS_ERR_INVALID_PROPERTY
);
1157 (void) memset(&prop_hd
, 0, sizeof (vs_prop_hd_t
));
1158 prop_hd
.vp_gen
= *props
;
1159 prop_hd
.vp_type
= VS_PTYPE_GEN
;
1160 prop_hd
.vp_ids
= propids
;
1161 prop_hd
.vp_all
= VS_PROPID_GEN_ALL
;
1163 for (propid
= 1LL; propid
<= VS_PROPID_MAX
; propid
<<= 1) {
1164 if ((propids
& propid
) == 0)
1167 if (vs_validate(&prop_hd
, propid
) != VS_ERR_NONE
)
1168 return (VS_ERR_INVALID_VALUE
);
1171 return (VS_ERR_NONE
);
1176 * vs_props_se_validate
1178 * Validate properties identified in propids.
1180 * Returns: VS_ERR_NONE
1181 * VS_ERR_INVALID_VALUE
1182 * VS_ERR_INVALID_PROPERTY
1185 vs_props_se_validate(const vs_props_se_t
*se_props
, uint64_t propids
)
1188 vs_prop_hd_t prop_hd
;
1190 if ((propids
& VS_PROPID_SE_ALL
) != propids
)
1191 return (VS_ERR_INVALID_PROPERTY
);
1193 (void) memset(&prop_hd
, 0, sizeof (vs_prop_hd_t
));
1194 prop_hd
.vp_se
= *se_props
;
1195 prop_hd
.vp_type
= VS_PTYPE_SE
;
1196 prop_hd
.vp_ids
= propids
;
1197 prop_hd
.vp_all
= VS_PROPID_SE_ALL
;
1199 for (propid
= 1LL; propid
<= VS_PROPID_MAX
; propid
<<= 1) {
1200 if ((propids
& propid
) == 0)
1203 if (vs_validate(&prop_hd
, propid
) != VS_ERR_NONE
)
1204 return (VS_ERR_INVALID_VALUE
);
1207 return (VS_ERR_NONE
);
1214 * Checks that types property is a valid format:
1215 * - doesn't exceed VS_VAL_TYPES_MAX
1216 * - doesn't contain VS_VAL_TYPES_INVALID_CHARS
1217 * - is correctly formatted - passes the parsing tests
1219 * Returns 1 on success, 0 on failure
1222 vs_is_valid_types(const char *types
)
1224 char buf
[VS_VAL_TYPES_LEN
];
1225 uint32_t len
= VS_VAL_TYPES_LEN
;
1227 if (strlen(types
) > VS_VAL_TYPES_LEN
)
1230 if (strpbrk(types
, VS_VAL_TYPES_INVALID_CHARS
) != NULL
)
1233 if (vs_parse_types(types
, buf
, &len
) != 0)
1243 * Returns 1 on success, 0 on failure
1246 vs_is_valid_host(const char *host
)
1251 if (!host
|| *host
== '\0')
1254 if ('0' <= host
[0] && host
[0] <= '9') {
1256 if ((inet_pton(AF_INET
, host
, &naddr
)) == 0)
1258 if ((naddr
& IN_CLASSA_NET
) == 0)
1260 if ((naddr
& IN_CLASSC_HOST
) == 0)
1265 while (*p
!= '\0') {
1270 (*p
== '.') || (*p
== '-') || (*p
== '_')) {
1285 * Replace comma separators with '\0'.
1287 * Types contains comma separated rules each beginning with +|-
1288 * - embedded commas are escaped by backslash
1289 * - backslash is escaped by backslash
1290 * - a single backslash not followed by comma is illegal
1292 * On entry to the function len must contain the length of
1293 * the buffer. On sucecssful exit len will contain the length
1294 * of the parsed data within the buffer.
1296 * Returns 0 on success, -1 on failure
1299 vs_parse_types(const char *types
, char *buf
, uint32_t *len
)
1301 char *p
= (char *)types
;
1304 if (strlen(types
) > *len
)
1307 if (strchr(VS_TYPES_RULES
, *p
) == NULL
)
1310 (void) memset(buf
, 0, *len
);
1316 (strchr(VS_TYPES_RULES
, *(p
+ 1))) == NULL
)
1320 case VS_TYPES_ESCAPE
:
1322 if (*p
== VS_TYPES_ESCAPE
|| *p
== VS_TYPES_SEP
)
1334 *len
= (b
- buf
) + 1;
1344 vs_statistics(vs_stats_t
*stats
)
1346 int door_fd
, rc
= VS_ERR_NONE
;
1347 vs_stats_req_t
*req
;
1348 vs_stats_rsp_t
*rsp
;
1351 if ((req
= calloc(1, sizeof (vs_stats_req_t
))) == NULL
)
1352 return (VS_ERR_SYS
);
1354 if ((rsp
= calloc(1, sizeof (vs_stats_rsp_t
))) == NULL
) {
1356 return (VS_ERR_SYS
);
1359 if ((door_fd
= open(VS_STATS_DOOR_NAME
, O_RDONLY
)) < 0) {
1362 return (VS_ERR_DAEMON_COMM
);
1365 req
->vsr_magic
= VS_STATS_DOOR_MAGIC
;
1366 req
->vsr_id
= VS_STATS_GET
;
1368 arg
.data_ptr
= (char *)req
;
1369 arg
.data_size
= sizeof (vs_stats_req_t
);
1370 arg
.desc_ptr
= NULL
;
1372 arg
.rbuf
= (char *)rsp
;
1373 arg
.rsize
= sizeof (vs_stats_rsp_t
);
1375 rc
= vs_door_call(door_fd
, &arg
);
1377 if ((rc
== VS_ERR_NONE
) && (rsp
->vsr_magic
== VS_STATS_DOOR_MAGIC
))
1378 *stats
= rsp
->vsr_stats
;
1380 rc
= VS_ERR_DAEMON_COMM
;
1382 (void) close(door_fd
);
1391 * vs_statistics_reset
1394 vs_statistics_reset()
1397 vs_stats_req_t
*req
;
1400 /* ensure that caller has authorization to reset stats */
1401 if ((rc
= vs_checkauth(VS_VALUE_AUTH
)) != VS_ERR_NONE
)
1404 if ((req
= calloc(1, sizeof (vs_stats_req_t
))) == NULL
)
1405 return (VS_ERR_SYS
);
1407 if ((door_fd
= open(VS_STATS_DOOR_NAME
, O_RDONLY
)) < 0) {
1409 return (VS_ERR_DAEMON_COMM
);
1412 req
->vsr_magic
= VS_STATS_DOOR_MAGIC
;
1413 req
->vsr_id
= VS_STATS_RESET
;
1415 arg
.data_ptr
= (char *)req
;
1416 arg
.data_size
= sizeof (vs_stats_req_t
);
1417 arg
.desc_ptr
= NULL
;
1422 rc
= vs_door_call(door_fd
, &arg
);
1424 (void) close(door_fd
);
1430 * Door call with retries.
1432 * Returns VS_ERR_NONE on success, otherwise VS_ERR_DAEMON_COMM.
1435 vs_door_call(int fd
, door_arg_t
*arg
)
1440 for (i
= 0; i
< VS_DOOR_CALL_RETRIES
; ++i
) {
1443 if ((rc
= door_call(fd
, arg
)) == 0)
1446 if (errno
!= EAGAIN
&& errno
!= EINTR
)
1450 return ((rc
== 0) ? VS_ERR_NONE
: VS_ERR_DAEMON_COMM
);
1457 vs_checkauth(char *auth
)
1464 if ((pw
= getpwuid(uid
)) == NULL
)
1465 return (VS_ERR_SYS
);
1467 if (chkauthattr(auth
, pw
->pw_name
) != 1) {
1468 return (VS_ERR_AUTH
);
1471 return (VS_ERR_NONE
);
1476 * vs_props_get_engines
1478 * On input, count specifies the maximum number of engine ids to
1479 * return. engids must be an array with count entries.
1480 * On return, count specifies the number of engine ids being
1481 * returned in engids.
1483 * Caller is responsible for free'ing the engids allocated herein.
1486 vs_props_get_engines(char *engids
[], int *count
)
1489 char pgname
[VS_PGNAME_ENGINE_LEN
];
1493 if (((vs_scf_ctx_open(&vsc
)) != 0) ||
1494 ((vsc
.vscf_iter
= scf_iter_create(vsc
.vscf_handle
)) == NULL
) ||
1495 (scf_iter_instance_pgs_typed(vsc
.vscf_iter
, vsc
.vscf_inst
,
1496 SCF_GROUP_APPLICATION
) != 0)) {
1497 vs_scf_ctx_close(&vsc
);
1498 return (VS_ERR_SCF
);
1501 for (i
= 0; i
< *count
; i
++)
1505 prefix_len
= sizeof (VS_PGNAME_ENGINE_PREFIX
) - 1;
1507 while ((i
< VS_SE_MAX
) &&
1508 (scf_iter_next_pg(vsc
.vscf_iter
, vsc
.vscf_pgroup
) == 1)) {
1509 if (scf_pg_get_name(vsc
.vscf_pgroup
, pgname
,
1510 VS_PGNAME_ENGINE_LEN
) < 0) {
1511 vs_scf_ctx_close(&vsc
);
1512 return (VS_ERR_SCF
);
1515 if (strncmp(pgname
, VS_PGNAME_ENGINE_PREFIX
, prefix_len
) == 0) {
1516 if ((engids
[i
] = strdup(pgname
+ prefix_len
)) != NULL
) {
1522 vs_scf_ctx_close(&vsc
);
1525 return (VS_ERR_NONE
);
1533 vs_scf_pg_count(void)
1538 if ((vs_scf_ctx_open(&vsc
) != 0) ||
1539 ((vsc
.vscf_iter
= scf_iter_create(vsc
.vscf_handle
)) == NULL
) ||
1540 (scf_iter_instance_pgs_typed(vsc
.vscf_iter
, vsc
.vscf_inst
,
1541 SCF_GROUP_APPLICATION
) != 0)) {
1542 vs_scf_ctx_close(&vsc
);
1546 while (scf_iter_next_pg(vsc
.vscf_iter
, vsc
.vscf_pgroup
) == 1)
1549 vs_scf_ctx_close(&vsc
);
1556 * vs_engid_to_pgname
1558 * To convert an engine id (engid) to a property group name (pgname),
1559 * the engine id is prefixed with VS_PGNAME_ENGINE_PREFIX.
1562 vs_engid_to_pgname(const char *engid
, char pgname
[VS_PGNAME_ENGINE_LEN
])
1564 (void) snprintf(pgname
, VS_PGNAME_ENGINE_LEN
, "%s%s",
1565 VS_PGNAME_ENGINE_PREFIX
, engid
);
1572 * Converts a size string in the format into an integer.
1574 * A size string is a numeric value followed by an optional unit
1575 * specifier which is used as a multiplier to calculate a raw
1577 * The size string format is: N[.N][KMGTP][B]
1579 * The numeric value can contain a decimal portion. Unit specifiers
1580 * are either a one-character or two-character string; i.e. "K" or
1581 * "KB" for kilobytes. Unit specifiers must follow the numeric portion
1582 * immediately, and are not case-sensitive.
1584 * If either "B" is specified, or there is no unit specifier portion
1585 * in the string, the numeric value is calculated with no multiplier
1586 * (assumes a basic unit of "bytes").
1589 * -1: Failure; errno set to specify the error.
1593 vs_strtonum(const char *value
, uint64_t *num
)
1601 /* Check to see if this looks like a number. */
1602 if ((value
[0] < '0' || value
[0] > '9') && value
[0] != '.') {
1607 /* Rely on stroll() to process the numeric portion. */
1609 *num
= strtoll(value
, &end
, 10);
1612 * Check for ERANGE, which indicates that the value is too large to
1613 * fit in a 64-bit value.
1619 * If we have a decimal value, then do the computation with floating
1620 * point arithmetic. Otherwise, use standard arithmetic.
1623 fval
= strtod(value
, &end
);
1625 if ((shift
= vs_strtoshift(end
)) == -1)
1626 return (-1); /* errno set */
1628 fval
*= pow(2, shift
);
1629 if (fval
> UINT64_MAX
) {
1634 *num
= (uint64_t)fval
;
1636 if ((shift
= vs_strtoshift(end
)) == -1)
1637 return (-1); /* errno set */
1639 /* Check for overflow */
1640 if (shift
>= 64 || (*num
<< shift
) >> shift
!= *num
) {
1655 * Converts a unit specifier string into a number of bits that
1656 * a numeric value must be shifted.
1659 * -1: Failure; errno set to specify the error.
1660 * >-1: Success; the shift count.
1664 vs_strtoshift(const char *buf
)
1666 const char *ends
= "BKMGTPEZ";
1671 for (i
= 0; i
< strlen(ends
); i
++) {
1672 if (toupper(buf
[0]) == ends
[i
])
1675 if (i
== strlen(ends
)) {
1680 /* Allow trailing 'b' characters except in the case of 'BB'. */
1681 if (buf
[1] == '\0' || (toupper(buf
[1]) == 'B' && buf
[2] == '\0' &&
1682 toupper(buf
[0]) != 'B')) {