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
++) {
233 * Retrieves values for the specified general service properties from
236 * If invalid property values are found, the values are corrected to
241 * VS_ERR_INVALID_PROPERTY
246 vs_props_get(vs_props_t
*vp
, uint64_t propids
)
249 vs_prop_hd_t prop_hd
;
251 if ((propids
& VS_PROPID_GEN_ALL
) != propids
)
252 return (VS_ERR_INVALID_PROPERTY
);
254 (void) memset(&prop_hd
, 0, sizeof (vs_prop_hd_t
));
255 prop_hd
.vp_type
= VS_PTYPE_GEN
;
256 prop_hd
.vp_ids
= propids
;
257 prop_hd
.vp_all
= VS_PROPID_GEN_ALL
;
259 rc
= vs_scf_values_get(VS_PGNAME_GENERAL
, &prop_hd
);
261 *vp
= prop_hd
.vp_gen
;
269 * Changes values for the specified general service properties
274 * VS_ERR_INVALID_PROPERTY
275 * VS_ERR_INVALID_VALUE
280 vs_props_set(const vs_props_t
*vp
, uint64_t propids
)
282 vs_prop_hd_t prop_hd
;
284 if ((propids
& VS_PROPID_GEN_ALL
) != propids
)
285 return (VS_ERR_INVALID_PROPERTY
);
287 (void) memset(&prop_hd
, 0, sizeof (vs_prop_hd_t
));
288 prop_hd
.vp_type
= VS_PTYPE_GEN
;
289 prop_hd
.vp_ids
= propids
;
290 prop_hd
.vp_all
= VS_PROPID_GEN_ALL
;
291 prop_hd
.vp_gen
= *vp
;
292 return (vs_scf_values_set(VS_PGNAME_GENERAL
, &prop_hd
));
299 * Retrieves values for the specified scan engine properties from the
302 * If the enable property is set (true), the host property is
303 * checked for validity. If it is not valid, the requested values
304 * are returned with the enable propery set to off (false)
308 * VS_ERR_INVALID_PROPERTY
313 vs_props_se_get(char *engid
, vs_props_se_t
*sep
, uint64_t propids
)
316 char pgname
[VS_PGNAME_ENGINE_LEN
];
317 vs_prop_hd_t prop_hd
;
319 /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
320 if (strcmp(engid
, VS_PGNAME_GENERAL
) == 0)
321 return (VS_ERR_INVALID_SE
);
323 if ((propids
& VS_PROPID_SE_ALL
) != propids
)
324 return (VS_ERR_INVALID_PROPERTY
);
326 (void) memset(&prop_hd
, 0, sizeof (vs_prop_hd_t
));
327 prop_hd
.vp_type
= VS_PTYPE_SE
;
328 prop_hd
.vp_ids
= propids
;
329 prop_hd
.vp_all
= VS_PROPID_SE_ALL
;
330 (void) strlcpy(prop_hd
.vp_se
.vep_engid
, engid
, VS_SE_NAME_LEN
);
332 /* If getting enable, get the host property too */
333 if ((propids
& VS_PROPID_SE_ENABLE
))
334 prop_hd
.vp_ids
|= VS_PROPID_SE_HOST
;
336 /* Load values from the repository */
337 vs_engid_to_pgname(engid
, pgname
);
338 rc
= vs_scf_values_get(pgname
, &prop_hd
);
339 if (rc
!= VS_ERR_NONE
)
343 * If the host is invalid and the enable property is on,
344 * return enable property as off
346 if ((prop_hd
.vp_ids
& VS_PROPID_SE_HOST
) &&
347 (vs_validate(&prop_hd
, VS_PROPID_SE_HOST
) != VS_ERR_NONE
)) {
348 prop_hd
.vp_se
.vep_enable
= B_FALSE
;
351 *sep
= prop_hd
.vp_se
;
360 * Changes the values for the specified scan engine properties in the
363 * If the enable property is being changed to true in this operation,
364 * a host property must also be specified, or already exist in the
369 * VS_ERR_INVALID_PROPERTY
370 * VS_ERR_INVALID_VALUE
375 vs_props_se_set(char *engid
, const vs_props_se_t
*sep
, uint64_t propids
)
378 char pgname
[VS_PGNAME_ENGINE_LEN
];
379 vs_prop_hd_t prop_hd
;
381 /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
382 if (strcmp(engid
, VS_PGNAME_GENERAL
) == 0)
383 return (VS_ERR_INVALID_SE
);
385 if ((propids
& VS_PROPID_SE_ALL
) != propids
)
386 return (VS_ERR_INVALID_PROPERTY
);
388 (void) memset(&prop_hd
, 0, sizeof (vs_prop_hd_t
));
389 prop_hd
.vp_type
= VS_PTYPE_SE
;
390 prop_hd
.vp_all
= VS_PROPID_SE_ALL
;
392 vs_engid_to_pgname(engid
, pgname
);
395 * if enabling a scan engine, ensure that a valid host
396 * is also being set, or already exists in the repository
398 if ((propids
& VS_PROPID_SE_ENABLE
) && (sep
->vep_enable
== B_TRUE
) &&
399 !(propids
& VS_PROPID_SE_HOST
)) {
401 prop_hd
.vp_ids
= VS_PROPID_SE_HOST
;
402 if ((rc
= vs_scf_values_get(pgname
, &prop_hd
)) != VS_ERR_NONE
)
405 if (vs_validate(&prop_hd
, VS_PROPID_SE_HOST
) != VS_ERR_NONE
)
406 return (VS_ERR_INVALID_HOST
);
409 prop_hd
.vp_ids
= propids
;
410 prop_hd
.vp_se
= *sep
;
412 return (vs_scf_values_set(pgname
, &prop_hd
));
420 vs_props_se_create(char *engid
, const vs_props_se_t
*sep
, uint64_t propids
)
423 char pgname
[VS_PGNAME_ENGINE_LEN
];
424 vs_prop_hd_t prop_hd
;
426 if ((propids
& VS_PROPID_SE_ALL
) != propids
)
427 return (VS_ERR_INVALID_PROPERTY
);
429 /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
430 if (strcmp(engid
, VS_PGNAME_GENERAL
) == 0)
431 return (VS_ERR_INVALID_SE
);
433 if ((n
= vs_scf_pg_count()) == -1)
437 return (VS_ERR_MAX_SE
);
439 vs_engid_to_pgname(engid
, pgname
);
441 (void) memset(&prop_hd
, 0, sizeof (vs_prop_hd_t
));
442 prop_hd
.vp_type
= VS_PTYPE_SE
;
443 prop_hd
.vp_all
= VS_PROPID_SE_ALL
;
444 prop_hd
.vp_ids
= propids
| VS_PROPID_VALUE_AUTH
;
445 prop_hd
.vp_se
= *sep
;
447 /* if hostname not specified, default it to engid */
448 if ((propids
& VS_PROPID_SE_HOST
) == 0) {
449 (void) strlcpy(prop_hd
.vp_se
.vep_host
, engid
, MAXHOSTNAMELEN
);
450 prop_hd
.vp_ids
|= VS_PROPID_SE_HOST
;
453 return (vs_scf_pg_create(pgname
, &prop_hd
));
461 vs_props_se_delete(const char *engid
)
463 char pgname
[VS_PGNAME_ENGINE_LEN
];
465 /* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
466 if (strcmp(engid
, VS_PGNAME_GENERAL
) == 0)
467 return (VS_ERR_INVALID_SE
);
469 vs_engid_to_pgname(engid
, pgname
);
471 return (vs_scf_pg_delete(pgname
));
479 vs_strerror(int error
)
483 return (gettext("no error"));
484 case VS_ERR_INVALID_PROPERTY
:
485 return (gettext("invalid property id"));
486 case VS_ERR_INVALID_VALUE
:
487 return (gettext("invalid property value"));
488 case VS_ERR_INVALID_HOST
:
489 return (gettext("invalid host"));
490 case VS_ERR_INVALID_SE
:
491 return (gettext("invalid scan engine"));
493 return (gettext("max scan engines exceeded"));
495 return (gettext("insufficient privileges for action"));
496 case VS_ERR_DAEMON_COMM
:
497 return (gettext("unable to contact vscand"));
499 return (scf_strerror(scf_error()));
501 return (strerror(errno
));
503 return (gettext("unknown error"));
511 * Finds and returns a property definition by property id.
513 static const vs_propdef_t
*
514 vs_get_propdef(uint64_t propid
)
518 for (i
= 0; i
< vs_npropdefs
; i
++) {
519 if (propid
== vs_propdefs
[i
].vpd_id
)
520 return (&vs_propdefs
[i
]);
530 * Sets a property value that contains invalid data to its default value.
532 * Note that this function does not alter any values in the repository
533 * This is only to enable the caller to get valid data.
536 vs_default_value(vs_prop_hd_t
*prop_hd
, const uint64_t propid
)
538 vs_props_t
*vp
= &prop_hd
->vp_gen
;
539 vs_props_se_t
*vep
= &prop_hd
->vp_se
;
542 case VS_PROPID_MAXSIZE
:
543 (void) strlcpy(vp
->vp_maxsize
, vs_dflt_maxsize
,
544 sizeof (vp
->vp_maxsize
));
546 case VS_PROPID_MAXSIZE_ACTION
:
547 vp
->vp_maxsize_action
= vs_dflt_allow
;
549 case VS_PROPID_TYPES
:
550 (void) strlcpy(vp
->vp_types
, vs_dflt_types
,
551 sizeof (vp
->vp_types
));
554 (void) strlcpy(vp
->vp_vlog
, vs_dflt_vlog
,
555 sizeof (vp
->vp_vlog
));
557 case VS_PROPID_SE_ENABLE
:
558 vep
->vep_enable
= vs_dflt_enable
;
560 case VS_PROPID_SE_HOST
:
561 (void) strlcpy(vep
->vep_host
, vs_dflt_host
,
562 sizeof (vep
->vep_host
));
564 case VS_PROPID_SE_PORT
:
565 vep
->vep_port
= vs_dflt_port
;
567 case VS_PROPID_SE_MAXCONN
:
568 vep
->vep_maxconn
= vs_dflt_maxconn
;
579 * Gets property values for one or more properties from the repository.
580 * This is the single entry point for loading SMF values.
582 * While a transaction is not used for loading property values,
583 * the operation is parameterized by a property group. All properties
584 * retrieved in this function, then, must belong to the same property
588 vs_scf_values_get(const char *pgname
, vs_prop_hd_t
*prop_hd
)
592 const vs_propdef_t
*vpd
;
595 if ((vs_scf_ctx_open(&vsc
)) != 0) {
596 vs_scf_ctx_close(&vsc
);
600 if (scf_instance_get_pg(vsc
.vscf_inst
, pgname
, vsc
.vscf_pgroup
) == -1) {
601 vs_scf_ctx_close(&vsc
);
602 if (strcmp(pgname
, "VS_PGNAME_GENERAL") != 0) {
604 if ((rc
== SCF_ERROR_NOT_FOUND
) ||
605 (rc
== SCF_ERROR_INVALID_ARGUMENT
))
606 return (VS_ERR_INVALID_SE
);
613 for (propid
= 1LL; propid
<= VS_PROPID_MAX
; propid
<<= 1) {
614 if ((prop_hd
->vp_ids
& propid
) == 0)
617 if ((vpd
= vs_get_propdef(propid
)) == NULL
) {
618 rc
= VS_ERR_INVALID_PROPERTY
;
622 vsc
.vscf_prop
[np
] = scf_property_create(vsc
.vscf_handle
);
623 vsc
.vscf_val
[np
] = scf_value_create(vsc
.vscf_handle
);
625 if (vsc
.vscf_prop
[np
] == NULL
|| vsc
.vscf_val
[np
] == NULL
) {
630 if (scf_pg_get_property(vsc
.vscf_pgroup
, vpd
->vpd_name
,
631 vsc
.vscf_prop
[np
]) == -1) {
632 if (scf_error() == SCF_ERROR_NOT_FOUND
) {
633 vs_default_value(prop_hd
, vpd
->vpd_id
);
640 if ((rc
= vs_scf_get(vpd
, prop_hd
, &vsc
, np
)) != VS_ERR_NONE
)
647 vs_scf_ctx_close(&vsc
);
656 * Loads a single values from the repository into the appropriate vscan
657 * property structure member.
660 vs_scf_get(const vs_propdef_t
*vpd
, vs_prop_hd_t
*prop_hd
,
661 vs_scfctx_t
*vsc
, int idx
)
666 vs_props_t
*vp
= &prop_hd
->vp_gen
;
667 vs_props_se_t
*vep
= &prop_hd
->vp_se
;
669 if ((rc
= scf_property_get_value(vsc
->vscf_prop
[idx
],
670 vsc
->vscf_val
[idx
])) == -1) {
671 if (rc
== SCF_ERROR_CONSTRAINT_VIOLATED
||
672 rc
== SCF_ERROR_NOT_FOUND
) {
673 vs_default_value(prop_hd
, vpd
->vpd_id
);
674 return (VS_ERR_NONE
);
680 switch (vpd
->vpd_id
) {
681 case VS_PROPID_MAXSIZE
:
682 if ((scf_value_get_astring(vsc
->vscf_val
[idx
],
683 vp
->vp_maxsize
, sizeof (vp
->vp_maxsize
))) == -1) {
687 case VS_PROPID_MAXSIZE_ACTION
:
688 if ((scf_value_get_boolean(vsc
->vscf_val
[idx
],
692 vp
->vp_maxsize_action
= (valbool
== 0) ? B_FALSE
: B_TRUE
;
694 case VS_PROPID_TYPES
:
695 if ((scf_value_get_astring(vsc
->vscf_val
[idx
],
696 vp
->vp_types
, sizeof (vp
->vp_types
))) == -1) {
701 if ((scf_value_get_astring(vsc
->vscf_val
[idx
],
702 vp
->vp_vlog
, sizeof (vp
->vp_vlog
))) == -1) {
706 case VS_PROPID_SE_ENABLE
:
707 if ((scf_value_get_boolean(vsc
->vscf_val
[idx
],
711 vep
->vep_enable
= (valbool
== 0) ? B_FALSE
: B_TRUE
;
713 case VS_PROPID_SE_HOST
:
714 (void) scf_value_get_as_string_typed(vsc
->vscf_val
[idx
],
715 vpd
->vpd_type
, vep
->vep_host
, sizeof (vep
->vep_host
));
717 case VS_PROPID_SE_PORT
:
718 if ((scf_value_get_integer(vsc
->vscf_val
[idx
], &port
)) == -1)
720 if (port
<= 0 || port
>= UINT16_MAX
)
721 rc
= VS_ERR_INVALID_VALUE
;
723 vep
->vep_port
= (uint16_t)port
;
725 case VS_PROPID_SE_MAXCONN
:
726 if ((scf_value_get_integer(vsc
->vscf_val
[idx
],
727 (int64_t *)&vep
->vep_maxconn
)) == -1) {
735 if ((rc
!= VS_ERR_NONE
) ||
736 (vs_validate(prop_hd
, vpd
->vpd_id
) != VS_ERR_NONE
)) {
737 vs_default_value(prop_hd
, vpd
->vpd_id
);
740 return (VS_ERR_NONE
);
748 vs_scf_pg_create(const char *pgname
, vs_prop_hd_t
*prop_hd
)
754 /* ensure that caller has authorization to refresh service */
755 if ((rc
= vs_checkauth(VS_ACTION_AUTH
)) != VS_ERR_NONE
)
758 if (vs_scf_ctx_open(&vsc
) != 0) {
759 vs_scf_ctx_close(&vsc
);
763 if (scf_instance_add_pg(vsc
.vscf_inst
, pgname
,
764 SCF_GROUP_APPLICATION
, 0, vsc
.vscf_pgroup
) == -1) {
765 vs_scf_ctx_close(&vsc
);
766 if (scf_error() == SCF_ERROR_INVALID_ARGUMENT
)
767 return (VS_ERR_INVALID_SE
);
770 vs_scf_ctx_close(&vsc
);
772 /* set default values for those not specified */
773 for (propid
= 1LL; propid
<= VS_PROPID_MAX
; propid
<<= 1) {
774 if ((propid
& prop_hd
->vp_all
) && !(propid
& prop_hd
->vp_ids
))
775 vs_default_value(prop_hd
, propid
);
778 prop_hd
->vp_ids
= prop_hd
->vp_all
;
779 prop_hd
->vp_ids
|= VS_PROPID_VALUE_AUTH
;
781 rc
= vs_scf_values_set(pgname
, prop_hd
);
782 if (rc
!= VS_ERR_NONE
)
783 (void) vs_scf_pg_delete(pgname
);
793 vs_scf_pg_delete(const char *pgname
)
798 /* ensure that caller has authorization to refresh service */
799 if ((rc
= vs_checkauth(VS_ACTION_AUTH
)) != VS_ERR_NONE
)
802 if (vs_scf_ctx_open(&vsc
) != 0) {
803 vs_scf_ctx_close(&vsc
);
807 if (scf_instance_get_pg(vsc
.vscf_inst
, pgname
, vsc
.vscf_pgroup
) == -1) {
808 vs_scf_ctx_close(&vsc
);
810 if ((rc
== SCF_ERROR_NOT_FOUND
) ||
811 (rc
== SCF_ERROR_INVALID_ARGUMENT
))
812 return (VS_ERR_INVALID_SE
);
817 if (scf_pg_delete(vsc
.vscf_pgroup
) == -1) {
818 vs_scf_ctx_close(&vsc
);
820 if ((rc
== SCF_ERROR_NOT_FOUND
) ||
821 (rc
== SCF_ERROR_INVALID_ARGUMENT
))
822 return (VS_ERR_INVALID_SE
);
827 vs_scf_ctx_close(&vsc
);
829 /* Notify the daemon that things have changed */
830 if ((smf_refresh_instance(VS_INSTANCE_FMRI
)) == -1) {
834 return (VS_ERR_NONE
);
841 * Sets property values in the repository. This is the single
842 * entry point for storing SMF values.
844 * Like loading values, this is an operation based on a single property
845 * group, so all property values changed in this function must belong
846 * to the same property group. Additionally, this operation is done in
847 * the context of a repository transaction; on any fatal error, the
848 * SCF context will be closed, destroying all SCF objects and aborting
852 vs_scf_values_set(const char *pgname
, vs_prop_hd_t
*prop_hd
)
855 const vs_propdef_t
*vpd
;
859 /* ensure that caller has authorization to refresh service */
860 if ((rc
= vs_checkauth(VS_ACTION_AUTH
)) != VS_ERR_NONE
)
863 if (vs_scf_ctx_open(&vsc
) != 0) {
864 vs_scf_ctx_close(&vsc
);
868 if (scf_instance_get_pg(vsc
.vscf_inst
, pgname
, vsc
.vscf_pgroup
) == -1) {
869 vs_scf_ctx_close(&vsc
);
871 if (strcmp(pgname
, "VS_PGNAME_GENERAL") != 0) {
872 if ((rc
== SCF_ERROR_NOT_FOUND
) ||
873 (rc
== SCF_ERROR_INVALID_ARGUMENT
))
874 return (VS_ERR_INVALID_SE
);
879 if (((vsc
.vscf_tx
= scf_transaction_create(vsc
.vscf_handle
)) == NULL
) ||
880 (scf_transaction_start(vsc
.vscf_tx
, vsc
.vscf_pgroup
) == -1)) {
881 vs_scf_ctx_close(&vsc
);
885 /* Process the value change for each specified property */
888 for (propid
= 1LL; propid
<= VS_PROPID_MAX
; propid
<<= 1) {
889 if ((prop_hd
->vp_ids
& propid
) == 0)
892 if ((vpd
= vs_get_propdef(propid
)) == NULL
) {
893 rc
= VS_ERR_INVALID_PROPERTY
;
897 vsc
.vscf_val
[np
] = scf_value_create(vsc
.vscf_handle
);
898 vsc
.vscf_ent
[np
] = scf_entry_create(vsc
.vscf_handle
);
900 if (vsc
.vscf_val
[np
] == NULL
|| vsc
.vscf_ent
[np
] == NULL
) {
905 if ((rc
= scf_transaction_property_change(vsc
.vscf_tx
,
906 vsc
.vscf_ent
[np
], vpd
->vpd_name
, vpd
->vpd_type
)) == -1) {
907 rc
= scf_transaction_property_new(vsc
.vscf_tx
,
908 vsc
.vscf_ent
[np
], vpd
->vpd_name
, vpd
->vpd_type
);
915 if ((rc
= vs_scf_set(vpd
, prop_hd
, &vsc
, np
)) != VS_ERR_NONE
)
921 if (rc
!= VS_ERR_NONE
) {
922 vs_scf_ctx_close(&vsc
);
926 /* Commit the transaction */
927 if (scf_transaction_commit(vsc
.vscf_tx
) == -1) {
928 vs_scf_ctx_close(&vsc
);
931 vs_scf_ctx_close(&vsc
);
933 /* Notify the daemon that things have changed */
934 if ((smf_refresh_instance(VS_INSTANCE_FMRI
)) == -1)
937 return (VS_ERR_NONE
);
944 * Stores a single value from the appropriate vscan property structure
945 * member into the repository.
947 * Values are set in the SCF value object, then the value object
948 * is added to the SCF property object.
951 vs_scf_set(const vs_propdef_t
*vpd
, vs_prop_hd_t
*prop_hd
,
952 vs_scfctx_t
*vsc
, int idx
)
955 vs_props_t
*vp
= &prop_hd
->vp_gen
;
956 vs_props_se_t
*vep
= &prop_hd
->vp_se
;
958 if ((rc
= vs_validate(prop_hd
, vpd
->vpd_id
)) != VS_ERR_NONE
)
962 switch (vpd
->vpd_id
) {
963 case VS_PROPID_MAXSIZE
:
964 if ((scf_value_set_astring(vsc
->vscf_val
[idx
],
965 vp
->vp_maxsize
)) == -1) {
969 case VS_PROPID_MAXSIZE_ACTION
:
970 scf_value_set_boolean(vsc
->vscf_val
[idx
],
971 (uint8_t)vp
->vp_maxsize_action
);
973 case VS_PROPID_TYPES
:
974 if ((scf_value_set_astring(vsc
->vscf_val
[idx
],
975 vp
->vp_types
)) == -1) {
979 case VS_PROPID_SE_ENABLE
:
980 scf_value_set_boolean(vsc
->vscf_val
[idx
],
981 (uint8_t)vep
->vep_enable
);
983 case VS_PROPID_SE_HOST
:
984 if ((scf_value_set_from_string(vsc
->vscf_val
[idx
],
985 vpd
->vpd_type
, vep
->vep_host
)) == -1) {
989 case VS_PROPID_SE_PORT
:
990 scf_value_set_integer(vsc
->vscf_val
[idx
], vep
->vep_port
);
992 case VS_PROPID_SE_MAXCONN
:
993 scf_value_set_integer(vsc
->vscf_val
[idx
],
996 case VS_PROPID_VALUE_AUTH
:
997 if ((scf_value_set_astring(vsc
->vscf_val
[idx
],
998 VS_VALUE_AUTH
)) == -1) {
1006 if ((scf_entry_add_value(vsc
->vscf_ent
[idx
],
1007 vsc
->vscf_val
[idx
])) == -1) {
1008 return (VS_ERR_SCF
);
1018 * Opens an SCF context; creates the minumum SCF objects
1019 * for use in loading/storing from the SMF repository (meaning
1020 * vscf_property group data).
1022 * Other SCF objects in the context may be initialized elsewher
1023 * subsequent to open, but all initialized structures are destroyed
1024 * in vs_scf_ctx_close().
1027 vs_scf_ctx_open(vs_scfctx_t
*vsc
)
1029 (void) memset(vsc
, 0, sizeof (vs_scfctx_t
));
1031 if ((vsc
->vscf_handle
= scf_handle_create(SCF_VERSION
)) == NULL
)
1032 return (VS_ERR_SCF
);
1034 if (scf_handle_bind(vsc
->vscf_handle
) == -1)
1035 return (VS_ERR_SCF
);
1037 if ((vsc
->vscf_inst
= scf_instance_create(vsc
->vscf_handle
)) == NULL
)
1038 return (VS_ERR_SCF
);
1040 if (scf_handle_decode_fmri(vsc
->vscf_handle
, VS_INSTANCE_FMRI
,
1041 NULL
, NULL
, vsc
->vscf_inst
, NULL
, NULL
,
1042 SCF_DECODE_FMRI_EXACT
) == -1) {
1043 return (VS_ERR_SCF
);
1046 if ((vsc
->vscf_pgroup
= scf_pg_create(vsc
->vscf_handle
)) == NULL
)
1047 return (VS_ERR_SCF
);
1049 return (VS_ERR_NONE
);
1056 * Closes an SCF context; destroys all initialized SCF objects.
1059 vs_scf_ctx_close(vs_scfctx_t
*vsc
)
1063 for (i
= 0; i
< VS_NUM_PROPIDS
; i
++) {
1064 if (vsc
->vscf_val
[i
])
1065 scf_value_destroy(vsc
->vscf_val
[i
]);
1066 if (vsc
->vscf_ent
[i
])
1067 scf_entry_destroy(vsc
->vscf_ent
[i
]);
1068 if (vsc
->vscf_prop
[i
])
1069 scf_property_destroy(vsc
->vscf_prop
[i
]);
1073 scf_iter_destroy(vsc
->vscf_iter
);
1075 scf_transaction_destroy(vsc
->vscf_tx
);
1076 if (vsc
->vscf_pgroup
)
1077 scf_pg_destroy(vsc
->vscf_pgroup
);
1079 scf_instance_destroy(vsc
->vscf_inst
);
1080 if (vsc
->vscf_handle
)
1081 scf_handle_destroy(vsc
->vscf_handle
);
1088 * Validate property identified in propid.
1090 * Returns: VS_ERR_NONE
1091 * VS_ERR_INVALID_VALUE
1092 * VS_ERR_INVALID_PROPERTY
1095 vs_validate(const vs_prop_hd_t
*prop_hd
, uint64_t propid
)
1098 const vs_props_t
*vp
= &prop_hd
->vp_gen
;
1099 const vs_props_se_t
*vep
= &prop_hd
->vp_se
;
1102 case VS_PROPID_MAXSIZE
:
1103 if ((vs_strtonum(vp
->vp_maxsize
, &num
) != 0) || (num
== 0))
1104 return (VS_ERR_INVALID_VALUE
);
1106 case VS_PROPID_MAXSIZE_ACTION
:
1108 case VS_PROPID_TYPES
:
1109 if (!vs_is_valid_types(vp
->vp_types
))
1110 return (VS_ERR_INVALID_VALUE
);
1112 case VS_PROPID_SE_ENABLE
:
1114 case VS_PROPID_SE_PORT
:
1115 if (vep
->vep_port
== 0)
1116 return (VS_ERR_INVALID_VALUE
);
1118 case VS_PROPID_SE_HOST
:
1119 if (!vs_is_valid_host(vep
->vep_host
))
1120 return (VS_ERR_INVALID_VALUE
);
1122 case VS_PROPID_SE_MAXCONN
:
1123 if (vep
->vep_maxconn
< VS_VAL_SE_MAXCONN_MIN
||
1124 vep
->vep_maxconn
> VS_VAL_SE_MAXCONN_MAX
)
1125 return (VS_ERR_INVALID_VALUE
);
1127 case VS_PROPID_VALUE_AUTH
:
1128 case VS_PROPID_VLOG
:
1131 return (VS_ERR_INVALID_PROPERTY
);
1134 return (VS_ERR_NONE
);
1141 * Validate properties identified in propids.
1143 * Returns: VS_ERR_NONE
1144 * VS_ERR_INVALID_VALUE
1145 * VS_ERR_INVALID_PROPERTY
1148 vs_props_validate(const vs_props_t
*props
, uint64_t propids
)
1151 vs_prop_hd_t prop_hd
;
1153 if ((propids
& VS_PROPID_GEN_ALL
) != propids
)
1154 return (VS_ERR_INVALID_PROPERTY
);
1156 (void) memset(&prop_hd
, 0, sizeof (vs_prop_hd_t
));
1157 prop_hd
.vp_gen
= *props
;
1158 prop_hd
.vp_type
= VS_PTYPE_GEN
;
1159 prop_hd
.vp_ids
= propids
;
1160 prop_hd
.vp_all
= VS_PROPID_GEN_ALL
;
1162 for (propid
= 1LL; propid
<= VS_PROPID_MAX
; propid
<<= 1) {
1163 if ((propids
& propid
) == 0)
1166 if (vs_validate(&prop_hd
, propid
) != VS_ERR_NONE
)
1167 return (VS_ERR_INVALID_VALUE
);
1170 return (VS_ERR_NONE
);
1175 * vs_props_se_validate
1177 * Validate properties identified in propids.
1179 * Returns: VS_ERR_NONE
1180 * VS_ERR_INVALID_VALUE
1181 * VS_ERR_INVALID_PROPERTY
1184 vs_props_se_validate(const vs_props_se_t
*se_props
, uint64_t propids
)
1187 vs_prop_hd_t prop_hd
;
1189 if ((propids
& VS_PROPID_SE_ALL
) != propids
)
1190 return (VS_ERR_INVALID_PROPERTY
);
1192 (void) memset(&prop_hd
, 0, sizeof (vs_prop_hd_t
));
1193 prop_hd
.vp_se
= *se_props
;
1194 prop_hd
.vp_type
= VS_PTYPE_SE
;
1195 prop_hd
.vp_ids
= propids
;
1196 prop_hd
.vp_all
= VS_PROPID_SE_ALL
;
1198 for (propid
= 1LL; propid
<= VS_PROPID_MAX
; propid
<<= 1) {
1199 if ((propids
& propid
) == 0)
1202 if (vs_validate(&prop_hd
, propid
) != VS_ERR_NONE
)
1203 return (VS_ERR_INVALID_VALUE
);
1206 return (VS_ERR_NONE
);
1213 * Checks that types property is a valid format:
1214 * - doesn't exceed VS_VAL_TYPES_MAX
1215 * - doesn't contain VS_VAL_TYPES_INVALID_CHARS
1216 * - is correctly formatted - passes the parsing tests
1218 * Returns 1 on success, 0 on failure
1221 vs_is_valid_types(const char *types
)
1223 char buf
[VS_VAL_TYPES_LEN
];
1224 uint32_t len
= VS_VAL_TYPES_LEN
;
1226 if (strlen(types
) > VS_VAL_TYPES_LEN
)
1229 if (strpbrk(types
, VS_VAL_TYPES_INVALID_CHARS
) != NULL
)
1232 if (vs_parse_types(types
, buf
, &len
) != 0)
1242 * Returns 1 on success, 0 on failure
1245 vs_is_valid_host(const char *host
)
1250 if (!host
|| *host
== '\0')
1253 if ('0' <= host
[0] && host
[0] <= '9') {
1255 if ((inet_pton(AF_INET
, host
, &naddr
)) == 0)
1257 if ((naddr
& IN_CLASSA_NET
) == 0)
1259 if ((naddr
& IN_CLASSC_HOST
) == 0)
1264 while (*p
!= '\0') {
1269 (*p
== '.') || (*p
== '-') || (*p
== '_')) {
1284 * Replace comma separators with '\0'.
1286 * Types contains comma separated rules each beginning with +|-
1287 * - embedded commas are escaped by backslash
1288 * - backslash is escaped by backslash
1289 * - a single backslash not followed by comma is illegal
1291 * On entry to the function len must contain the length of
1292 * the buffer. On sucecssful exit len will contain the length
1293 * of the parsed data within the buffer.
1295 * Returns 0 on success, -1 on failure
1298 vs_parse_types(const char *types
, char *buf
, uint32_t *len
)
1300 char *p
= (char *)types
;
1303 if (strlen(types
) > *len
)
1306 if (strchr(VS_TYPES_RULES
, *p
) == NULL
)
1309 (void) memset(buf
, 0, *len
);
1315 (strchr(VS_TYPES_RULES
, *(p
+ 1))) == NULL
)
1319 case VS_TYPES_ESCAPE
:
1321 if (*p
== VS_TYPES_ESCAPE
|| *p
== VS_TYPES_SEP
)
1333 *len
= (b
- buf
) + 1;
1343 vs_statistics(vs_stats_t
*stats
)
1345 int door_fd
, rc
= VS_ERR_NONE
;
1346 vs_stats_req_t
*req
;
1347 vs_stats_rsp_t
*rsp
;
1350 if ((req
= calloc(1, sizeof (vs_stats_req_t
))) == NULL
)
1351 return (VS_ERR_SYS
);
1353 if ((rsp
= calloc(1, sizeof (vs_stats_rsp_t
))) == NULL
) {
1355 return (VS_ERR_SYS
);
1358 if ((door_fd
= open(VS_STATS_DOOR_NAME
, O_RDONLY
)) < 0) {
1361 return (VS_ERR_DAEMON_COMM
);
1364 req
->vsr_magic
= VS_STATS_DOOR_MAGIC
;
1365 req
->vsr_id
= VS_STATS_GET
;
1367 arg
.data_ptr
= (char *)req
;
1368 arg
.data_size
= sizeof (vs_stats_req_t
);
1369 arg
.desc_ptr
= NULL
;
1371 arg
.rbuf
= (char *)rsp
;
1372 arg
.rsize
= sizeof (vs_stats_rsp_t
);
1374 rc
= vs_door_call(door_fd
, &arg
);
1376 if ((rc
== VS_ERR_NONE
) && (rsp
->vsr_magic
== VS_STATS_DOOR_MAGIC
))
1377 *stats
= rsp
->vsr_stats
;
1379 rc
= VS_ERR_DAEMON_COMM
;
1381 (void) close(door_fd
);
1390 * vs_statistics_reset
1393 vs_statistics_reset()
1396 vs_stats_req_t
*req
;
1399 /* ensure that caller has authorization to reset stats */
1400 if ((rc
= vs_checkauth(VS_VALUE_AUTH
)) != VS_ERR_NONE
)
1403 if ((req
= calloc(1, sizeof (vs_stats_req_t
))) == NULL
)
1404 return (VS_ERR_SYS
);
1406 if ((door_fd
= open(VS_STATS_DOOR_NAME
, O_RDONLY
)) < 0) {
1408 return (VS_ERR_DAEMON_COMM
);
1411 req
->vsr_magic
= VS_STATS_DOOR_MAGIC
;
1412 req
->vsr_id
= VS_STATS_RESET
;
1414 arg
.data_ptr
= (char *)req
;
1415 arg
.data_size
= sizeof (vs_stats_req_t
);
1416 arg
.desc_ptr
= NULL
;
1421 rc
= vs_door_call(door_fd
, &arg
);
1423 (void) close(door_fd
);
1429 * Door call with retries.
1431 * Returns VS_ERR_NONE on success, otherwise VS_ERR_DAEMON_COMM.
1434 vs_door_call(int fd
, door_arg_t
*arg
)
1439 for (i
= 0; i
< VS_DOOR_CALL_RETRIES
; ++i
) {
1442 if ((rc
= door_call(fd
, arg
)) == 0)
1445 if (errno
!= EAGAIN
&& errno
!= EINTR
)
1449 return ((rc
== 0) ? VS_ERR_NONE
: VS_ERR_DAEMON_COMM
);
1456 vs_checkauth(char *auth
)
1463 if ((pw
= getpwuid(uid
)) == NULL
)
1464 return (VS_ERR_SYS
);
1466 if (chkauthattr(auth
, pw
->pw_name
) != 1) {
1467 return (VS_ERR_AUTH
);
1470 return (VS_ERR_NONE
);
1475 * vs_props_get_engines
1477 * On input, count specifies the maximum number of engine ids to
1478 * return. engids must be an array with count entries.
1479 * On return, count specifies the number of engine ids being
1480 * returned in engids.
1482 * Caller is responsible for free'ing the engids allocated herein.
1485 vs_props_get_engines(char *engids
[], int *count
)
1488 char pgname
[VS_PGNAME_ENGINE_LEN
];
1492 if (((vs_scf_ctx_open(&vsc
)) != 0) ||
1493 ((vsc
.vscf_iter
= scf_iter_create(vsc
.vscf_handle
)) == NULL
) ||
1494 (scf_iter_instance_pgs_typed(vsc
.vscf_iter
, vsc
.vscf_inst
,
1495 SCF_GROUP_APPLICATION
) != 0)) {
1496 vs_scf_ctx_close(&vsc
);
1497 return (VS_ERR_SCF
);
1500 for (i
= 0; i
< *count
; i
++)
1504 prefix_len
= sizeof (VS_PGNAME_ENGINE_PREFIX
) - 1;
1506 while ((i
< VS_SE_MAX
) &&
1507 (scf_iter_next_pg(vsc
.vscf_iter
, vsc
.vscf_pgroup
) == 1)) {
1508 if (scf_pg_get_name(vsc
.vscf_pgroup
, pgname
,
1509 VS_PGNAME_ENGINE_LEN
) < 0) {
1510 vs_scf_ctx_close(&vsc
);
1511 return (VS_ERR_SCF
);
1514 if (strncmp(pgname
, VS_PGNAME_ENGINE_PREFIX
, prefix_len
) == 0) {
1515 if ((engids
[i
] = strdup(pgname
+ prefix_len
)) != NULL
) {
1521 vs_scf_ctx_close(&vsc
);
1524 return (VS_ERR_NONE
);
1532 vs_scf_pg_count(void)
1537 if ((vs_scf_ctx_open(&vsc
) != 0) ||
1538 ((vsc
.vscf_iter
= scf_iter_create(vsc
.vscf_handle
)) == NULL
) ||
1539 (scf_iter_instance_pgs_typed(vsc
.vscf_iter
, vsc
.vscf_inst
,
1540 SCF_GROUP_APPLICATION
) != 0)) {
1541 vs_scf_ctx_close(&vsc
);
1545 while (scf_iter_next_pg(vsc
.vscf_iter
, vsc
.vscf_pgroup
) == 1)
1548 vs_scf_ctx_close(&vsc
);
1555 * vs_engid_to_pgname
1557 * To convert an engine id (engid) to a property group name (pgname),
1558 * the engine id is prefixed with VS_PGNAME_ENGINE_PREFIX.
1561 vs_engid_to_pgname(const char *engid
, char pgname
[VS_PGNAME_ENGINE_LEN
])
1563 (void) snprintf(pgname
, VS_PGNAME_ENGINE_LEN
, "%s%s",
1564 VS_PGNAME_ENGINE_PREFIX
, engid
);
1571 * Converts a size string in the format into an integer.
1573 * A size string is a numeric value followed by an optional unit
1574 * specifier which is used as a multiplier to calculate a raw
1576 * The size string format is: N[.N][KMGTP][B]
1578 * The numeric value can contain a decimal portion. Unit specifiers
1579 * are either a one-character or two-character string; i.e. "K" or
1580 * "KB" for kilobytes. Unit specifiers must follow the numeric portion
1581 * immediately, and are not case-sensitive.
1583 * If either "B" is specified, or there is no unit specifier portion
1584 * in the string, the numeric value is calculated with no multiplier
1585 * (assumes a basic unit of "bytes").
1588 * -1: Failure; errno set to specify the error.
1592 vs_strtonum(const char *value
, uint64_t *num
)
1600 /* Check to see if this looks like a number. */
1601 if ((value
[0] < '0' || value
[0] > '9') && value
[0] != '.') {
1606 /* Rely on stroll() to process the numeric portion. */
1608 *num
= strtoll(value
, &end
, 10);
1611 * Check for ERANGE, which indicates that the value is too large to
1612 * fit in a 64-bit value.
1618 * If we have a decimal value, then do the computation with floating
1619 * point arithmetic. Otherwise, use standard arithmetic.
1622 fval
= strtod(value
, &end
);
1624 if ((shift
= vs_strtoshift(end
)) == -1)
1625 return (-1); /* errno set */
1627 fval
*= pow(2, shift
);
1628 if (fval
> UINT64_MAX
) {
1633 *num
= (uint64_t)fval
;
1635 if ((shift
= vs_strtoshift(end
)) == -1)
1636 return (-1); /* errno set */
1638 /* Check for overflow */
1639 if (shift
>= 64 || (*num
<< shift
) >> shift
!= *num
) {
1654 * Converts a unit specifier string into a number of bits that
1655 * a numeric value must be shifted.
1658 * -1: Failure; errno set to specify the error.
1659 * >-1: Success; the shift count.
1663 vs_strtoshift(const char *buf
)
1665 const char *ends
= "BKMGTPEZ";
1670 for (i
= 0; i
< strlen(ends
); i
++) {
1671 if (toupper(buf
[0]) == ends
[i
])
1674 if (i
== strlen(ends
)) {
1679 /* Allow trailing 'b' characters except in the case of 'BB'. */
1680 if (buf
[1] == '\0' || (toupper(buf
[1]) == 'B' && buf
[2] == '\0' &&
1681 toupper(buf
[0]) != 'B')) {