1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <string.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <ctype.h>
33 #include <math.h>
34 #include <limits.h>
35 #include <libscf.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <door.h>
39 #include <pwd.h>
40 #include <auth_attr.h>
41 #include <secdb.h>
42 #include <sys/socket.h>
43 #include <arpa/inet.h>
44 #include <libintl.h>
45 #include <libvscan.h>
46 
47 #define	VS_INSTANCE_FMRI	"svc:/system/filesystem/vscan:icap"
48 
49 /* SMF property group and property names */
50 #define	VS_PGNAME_GENERAL		"vs_general"
51 #define	VS_PGNAME_ENGINE		"vs_engine_%d"
52 #define	VS_PGNAME_ENGINE_LEN		16
53 
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"
58 
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"
64 
65 
66 /* types string processing */
67 #define	VS_TYPES_SEP		','
68 #define	VS_TYPES_ESCAPE		'\\'
69 #define	VS_TYPES_RULES		"+-"
70 
71 
72 /*
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().
76  *
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.
83  */
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];
93 } vs_scfctx_t;
94 
95 /*
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
99  * property.
100  */
101 typedef struct {
102 	const char *vpd_name;
103 	uint64_t vpd_id;
104 	scf_type_t vpd_type;
105 } vs_propdef_t;
106 
107 typedef enum {
108 	VS_PTYPE_GEN,
109 	VS_PTYPE_SE
110 } vs_prop_type_t;
111 
112 typedef struct vs_prop_hd {
113 	vs_prop_type_t vp_type;
114 	uint64_t vp_ids;
115 	uint64_t vp_all;
116 	union {
117 		vs_props_t vp_gen;
118 		vs_props_se_t vp_se;
119 	} vp_props;
120 } vs_prop_hd_t;
121 
122 #define	vp_gen	vp_props.vp_gen
123 #define	vp_se	vp_props.vp_se
124 
125 /*
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.
129  *
130  * Note: These values must be kept in sync with those defined
131  * in the service manifest.
132  */
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 = 32L;
139 static const  char *vs_dflt_types = "+*";
140 static const char *vs_dflt_vlog = "";
141 
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 }
155 };
156 
157 static const int vs_npropdefs = sizeof (vs_propdefs)/sizeof (vs_propdef_t);
158 
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);
162 
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);
165 
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 
170 static int vs_scf_ctx_open(vs_scfctx_t *);
171 static void vs_scf_ctx_close(vs_scfctx_t *);
172 
173 static int vs_validate(const vs_prop_hd_t *, uint64_t);
174 static int vs_is_valid_types(const char *);
175 static int vs_is_valid_host(const char *);
176 static int vs_checkauth(char *);
177 
178 typedef char vs_engid_t[VS_SE_NAME_LEN];
179 static int vs_props_get_engines(vs_engid_t *engids, int *count);
180 static int vs_scf_pg_count(void);
181 static int vs_strtoshift(const char *);
182 
183 
184 /*
185  * vs_props_get_all
186  *
187  * Retrieves the general service properties and all properties
188  * for all scan engines from the repository.
189  *
190  * If invalid property values are found, the values are corrected to
191  * the default value.
192  *
193  * Return codes:
194  *	VS_ERR_VS_ERR_NONE
195  *	VS_ERR_SCF
196  *	VS_ERR_SYS
197  */
198 int
199 vs_props_get_all(vs_props_all_t *va)
200 {
201 	int i, rc, n;
202 	char *engid;
203 	vs_engid_t engids[VS_SE_MAX];
204 
205 	(void) memset(va, 0, sizeof (vs_props_all_t));
206 	if ((rc = vs_props_get(&va->va_props, VS_PROPID_GEN_ALL))
207 	    != VS_ERR_NONE)
208 		return (rc);
209 
210 	n = VS_SE_MAX;
211 	if ((rc = vs_props_get_engines(engids, &n)) != VS_ERR_NONE)
212 		return (rc);
213 
214 	if (n > VS_SE_MAX)
215 		n = VS_SE_MAX;
216 
217 	for (i = 0; i < n; i++) {
218 		engid = engids[i];
219 		rc = vs_props_se_get(engid, &va->va_se[i], VS_PROPID_SE_ALL);
220 		if (rc != VS_ERR_NONE)
221 			return (rc);
222 	}
223 
224 	return (VS_ERR_NONE);
225 }
226 
227 
228 /*
229  * vs_props_get
230  *
231  * Retrieves values for the specified general service properties from
232  * the repository.
233  *
234  * If invalid property values are found, the values are corrected to
235  * the default value.
236  *
237  * Return codes:
238  *	VS_ERR_VS_ERR_NONE
239  *	VS_ERR_INVALID_PROPERTY
240  *	VS_ERR_SCF
241  *	VS_ERR_SYS
242  */
243 int
244 vs_props_get(vs_props_t *vp, uint64_t propids)
245 {
246 	int  rc;
247 	vs_prop_hd_t prop_hd;
248 
249 	if ((propids & VS_PROPID_GEN_ALL) != propids)
250 		return (VS_ERR_INVALID_PROPERTY);
251 
252 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
253 	prop_hd.vp_type = VS_PTYPE_GEN;
254 	prop_hd.vp_ids = propids;
255 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
256 
257 	rc = vs_scf_values_get(VS_PGNAME_GENERAL, &prop_hd);
258 
259 	*vp = prop_hd.vp_gen;
260 	return (rc);
261 }
262 
263 
264 /*
265  * vs_props_set
266  *
267  * Changes values for the specified general service properties
268  * in the repository.
269  *
270  * Return codes:
271  *	VS_ERR_VS_ERR_NONE
272  *	VS_ERR_INVALID_PROPERTY
273  *	VS_ERR_INVALID_VALUE
274  *	VS_ERR_SCF
275  *	VS_ERR_SYS
276  */
277 int
278 vs_props_set(const vs_props_t *vp, uint64_t propids)
279 {
280 	vs_prop_hd_t prop_hd;
281 
282 	if ((propids & VS_PROPID_GEN_ALL) != propids)
283 		return (VS_ERR_INVALID_PROPERTY);
284 
285 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
286 	prop_hd.vp_type = VS_PTYPE_GEN;
287 	prop_hd.vp_ids = propids;
288 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
289 	prop_hd.vp_gen = *vp;
290 	return (vs_scf_values_set(VS_PGNAME_GENERAL, &prop_hd));
291 }
292 
293 
294 /*
295  * vs_props_se_get
296  *
297  * Retrieves values for the specified scan engine properties from the
298  * repository.
299  *
300  * If the enable property is set (true), the host property is
301  * checked for validity. If it is not valid, the requested values
302  * are returned with the enable propery set to off (false)
303  *
304  * Return codes:
305  *	VS_ERR_VS_ERR_NONE
306  *	VS_ERR_INVALID_PROPERTY
307  *	VS_ERR_SCF
308  *	VS_ERR_SYS
309  */
310 int
311 vs_props_se_get(char *engid, vs_props_se_t *sep, uint64_t propids)
312 {
313 	int rc;
314 	vs_prop_hd_t prop_hd;
315 
316 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
317 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
318 		return (VS_ERR_INVALID_SE);
319 
320 	if ((propids & VS_PROPID_SE_ALL) != propids)
321 		return (VS_ERR_INVALID_PROPERTY);
322 
323 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
324 	prop_hd.vp_type = VS_PTYPE_SE;
325 	prop_hd.vp_ids = propids;
326 	prop_hd.vp_all = VS_PROPID_SE_ALL;
327 	(void) strlcpy(prop_hd.vp_se.vep_engid, engid, VS_SE_NAME_LEN);
328 
329 	/* If getting enable, get the host property too */
330 	if ((propids & VS_PROPID_SE_ENABLE))
331 		prop_hd.vp_ids |= VS_PROPID_SE_HOST;
332 
333 	/* Load values from the repository */
334 	rc = vs_scf_values_get(engid, &prop_hd);
335 	if (rc != VS_ERR_NONE)
336 		return (rc);
337 
338 	/*
339 	 *  If the host is invalid and the enable property is on,
340 	 *  return enable property as off
341 	 */
342 	if ((prop_hd.vp_ids & VS_PROPID_SE_HOST) &&
343 	    (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)) {
344 		prop_hd.vp_se.vep_enable = B_FALSE;
345 	}
346 
347 	*sep = prop_hd.vp_se;
348 	return (rc);
349 }
350 
351 
352 
353 /*
354  * vs_props_se_set
355  *
356  * Changes the values for the specified scan engine properties in the
357  * repository.
358  *
359  * If the enable property is being changed to true in this operation,
360  * a host property must also be specified, or already exist in the
361  * repository.
362  *
363  * Return codes:
364  *	VS_ERR_NONE
365  *	VS_ERR_INVALID_PROPERTY
366  *	VS_ERR_INVALID_VALUE
367  *	VS_ERR_SCF
368  *	VS_ERR_SYS
369  */
370 int
371 vs_props_se_set(char *engid, const vs_props_se_t *sep, uint64_t propids)
372 {
373 	int rc;
374 	vs_prop_hd_t prop_hd;
375 
376 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
377 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
378 		return (VS_ERR_INVALID_SE);
379 
380 	if ((propids & VS_PROPID_SE_ALL) != propids)
381 		return (VS_ERR_INVALID_PROPERTY);
382 
383 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
384 	prop_hd.vp_type = VS_PTYPE_SE;
385 	prop_hd.vp_all = VS_PROPID_SE_ALL;
386 
387 	/*
388 	 * if enabling a scan engine, ensure that a valid host
389 	 * is also being set, or already exists in the repository
390 	 */
391 	if ((propids & VS_PROPID_SE_ENABLE) && (sep->vep_enable == B_TRUE) &&
392 	    !(propids & VS_PROPID_SE_HOST)) {
393 
394 		prop_hd.vp_ids = VS_PROPID_SE_HOST;
395 		if ((rc = vs_scf_values_get(engid, &prop_hd)) != VS_ERR_NONE)
396 			return (rc);
397 
398 		if (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)
399 			return (VS_ERR_INVALID_HOST);
400 	}
401 
402 	prop_hd.vp_ids = propids;
403 	prop_hd.vp_se = *sep;
404 
405 	return (vs_scf_values_set(engid, &prop_hd));
406 }
407 
408 
409 /*
410  * vs_props_se_create
411  */
412 int
413 vs_props_se_create(char *engid, const vs_props_se_t *sep, uint64_t propids)
414 {
415 	int n;
416 	vs_prop_hd_t prop_hd;
417 
418 	if ((propids & VS_PROPID_SE_ALL) != propids)
419 		return (VS_ERR_INVALID_PROPERTY);
420 
421 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
422 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
423 		return (VS_ERR_INVALID_SE);
424 
425 	if ((n = vs_scf_pg_count()) == -1)
426 		return (VS_ERR_SCF);
427 
428 	if (n == VS_SE_MAX)
429 		return (VS_ERR_MAX_SE);
430 
431 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
432 	prop_hd.vp_type = VS_PTYPE_SE;
433 	prop_hd.vp_all = VS_PROPID_SE_ALL;
434 	prop_hd.vp_ids = propids | VS_PROPID_VALUE_AUTH;
435 	prop_hd.vp_se = *sep;
436 
437 	return (vs_scf_pg_create(engid, &prop_hd));
438 
439 }
440 
441 
442 /*
443  * vs_props_se_delete
444  */
445 int
446 vs_props_se_delete(const char *engid)
447 {
448 	int rc;
449 	vs_scfctx_t vsc;
450 
451 	/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
452 	if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
453 		return (VS_ERR_INVALID_SE);
454 
455 	/* ensure that caller has authorization to refresh service */
456 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
457 		return (rc);
458 
459 	if (vs_scf_ctx_open(&vsc) != 0) {
460 		vs_scf_ctx_close(&vsc);
461 		return (VS_ERR_SCF);
462 	}
463 
464 	if (scf_instance_get_pg(vsc.vscf_inst, engid, vsc.vscf_pgroup) == -1) {
465 		vs_scf_ctx_close(&vsc);
466 		rc = scf_error();
467 		if ((rc == SCF_ERROR_NOT_FOUND) ||
468 		    (rc == SCF_ERROR_INVALID_ARGUMENT))
469 			return (VS_ERR_INVALID_SE);
470 		else
471 			return (VS_ERR_SCF);
472 	}
473 
474 	if (scf_pg_delete(vsc.vscf_pgroup) == -1) {
475 		vs_scf_ctx_close(&vsc);
476 		rc = scf_error();
477 		if ((rc == SCF_ERROR_NOT_FOUND) ||
478 		    (rc == SCF_ERROR_INVALID_ARGUMENT))
479 			return (VS_ERR_INVALID_SE);
480 
481 		return (VS_ERR_SCF);
482 	}
483 
484 	vs_scf_ctx_close(&vsc);
485 
486 	/* Notify the daemon that things have changed */
487 	if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1) {
488 		return (VS_ERR_SCF);
489 	}
490 
491 	return (VS_ERR_NONE);
492 }
493 
494 
495 /*
496  * vs_strerror
497  */
498 const char *
499 vs_strerror(int error)
500 {
501 	switch (error) {
502 	case VS_ERR_NONE:
503 		return (gettext("no error"));
504 	case VS_ERR_INVALID_PROPERTY:
505 		return (gettext("invalid property id"));
506 	case VS_ERR_INVALID_VALUE:
507 		return (gettext("invalid property value"));
508 	case VS_ERR_INVALID_HOST:
509 		return (gettext("invalid host"));
510 	case VS_ERR_INVALID_SE:
511 		return (gettext("invalid scan engine"));
512 	case VS_ERR_MAX_SE:
513 		return (gettext("max scan engines exceeded"));
514 	case VS_ERR_AUTH:
515 		return (gettext("insufficient privileges for action"));
516 	case VS_ERR_DAEMON_COMM:
517 		return (gettext("unable to contact vscand"));
518 	case VS_ERR_SCF:
519 		return (scf_strerror(scf_error()));
520 	case VS_ERR_SYS:
521 		return (strerror(errno));
522 	default:
523 		return (gettext("unknown error"));
524 	}
525 }
526 
527 
528 /*
529  * vs_get_propdef
530  *
531  * Finds and returns a property definition by property id.
532  */
533 static const vs_propdef_t *
534 vs_get_propdef(uint64_t propid)
535 {
536 	int i;
537 
538 	for (i = 0; i < vs_npropdefs; i++) {
539 		if (propid == vs_propdefs[i].vpd_id)
540 			return (&vs_propdefs[i]);
541 	}
542 
543 	return (NULL);
544 }
545 
546 
547 /*
548  * vs_default_value
549  *
550  * Sets a property value that contains invalid data to its default value.
551  *
552  * Note that this function does not alter any values in the repository
553  * This is only to enable the caller to get valid data.
554  */
555 static void
556 vs_default_value(vs_prop_hd_t *prop_hd, const uint64_t propid)
557 {
558 	vs_props_t *vp = &prop_hd->vp_gen;
559 	vs_props_se_t *vep = &prop_hd->vp_se;
560 
561 	switch (propid) {
562 	case VS_PROPID_MAXSIZE:
563 		(void) strlcpy(vp->vp_maxsize, vs_dflt_maxsize,
564 		    sizeof (vp->vp_maxsize));
565 		break;
566 	case VS_PROPID_MAXSIZE_ACTION:
567 		vp->vp_maxsize_action = vs_dflt_allow;
568 		break;
569 	case VS_PROPID_TYPES:
570 		(void) strlcpy(vp->vp_types, vs_dflt_types,
571 		    sizeof (vp->vp_types));
572 		break;
573 	case VS_PROPID_VLOG:
574 		(void) strlcpy(vp->vp_vlog, vs_dflt_vlog,
575 		    sizeof (vp->vp_vlog));
576 		break;
577 	case VS_PROPID_SE_ENABLE:
578 		vep->vep_enable = vs_dflt_enable;
579 		break;
580 	case VS_PROPID_SE_HOST:
581 		(void) strlcpy(vep->vep_host, vs_dflt_host,
582 		    sizeof (vep->vep_host));
583 		break;
584 	case VS_PROPID_SE_PORT:
585 		vep->vep_port = vs_dflt_port;
586 		break;
587 	case VS_PROPID_SE_MAXCONN:
588 		vep->vep_maxconn = vs_dflt_maxconn;
589 		break;
590 	default:
591 		break;
592 	}
593 }
594 
595 
596 /*
597  * vs_scf_values_get
598  *
599  * Gets property values for one or more properties from the repository.
600  * This is the single entry point for loading SMF values.
601  *
602  * While a transaction is not used for loading property values,
603  * the operation is parameterized by a property group. All properties
604  * retrieved in this function, then, must belong to the same property
605  * group.
606  */
607 int
608 vs_scf_values_get(const char *pgname, vs_prop_hd_t *prop_hd)
609 {
610 	vs_scfctx_t vsc;
611 	int rc, np;
612 	const vs_propdef_t *vpd;
613 	uint64_t propid;
614 
615 	if ((vs_scf_ctx_open(&vsc)) != 0) {
616 		vs_scf_ctx_close(&vsc);
617 		return (VS_ERR_SCF);
618 	}
619 
620 	if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
621 		vs_scf_ctx_close(&vsc);
622 		if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) {
623 			rc = scf_error();
624 			if ((rc == SCF_ERROR_NOT_FOUND) ||
625 			    (rc == SCF_ERROR_INVALID_ARGUMENT))
626 				return (VS_ERR_INVALID_SE);
627 		}
628 		return (VS_ERR_SCF);
629 	}
630 
631 	rc = VS_ERR_NONE;
632 	np = 0;
633 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
634 		if ((prop_hd->vp_ids & propid) == 0)
635 			continue;
636 
637 		if ((vpd = vs_get_propdef(propid)) == NULL) {
638 			rc = VS_ERR_INVALID_PROPERTY;
639 			break;
640 		}
641 
642 		vsc.vscf_prop[np] = scf_property_create(vsc.vscf_handle);
643 		vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
644 
645 		if (vsc.vscf_prop[np] == NULL || vsc.vscf_val[np] == NULL) {
646 			rc = VS_ERR_SCF;
647 			break;
648 		}
649 
650 		if (scf_pg_get_property(vsc.vscf_pgroup, vpd->vpd_name,
651 		    vsc.vscf_prop[np]) == -1) {
652 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
653 				vs_default_value(prop_hd, vpd->vpd_id);
654 				continue;
655 			}
656 			rc = VS_ERR_SCF;
657 			break;
658 		}
659 
660 		if ((rc = vs_scf_get(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
661 			break;
662 
663 		++np;
664 	}
665 
666 
667 	vs_scf_ctx_close(&vsc);
668 
669 	return (rc);
670 }
671 
672 
673 /*
674  * vs_scf_get
675  *
676  * Loads a single values from the repository into the appropriate vscan
677  * property structure member.
678  */
679 static int
680 vs_scf_get(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
681 	vs_scfctx_t *vsc, int idx)
682 {
683 	int rc;
684 	int64_t port;
685 	uint8_t valbool;
686 	vs_props_t *vp = &prop_hd->vp_gen;
687 	vs_props_se_t *vep = &prop_hd->vp_se;
688 
689 	if ((rc = scf_property_get_value(vsc->vscf_prop[idx],
690 	    vsc->vscf_val[idx])) == -1) {
691 		if (rc == SCF_ERROR_CONSTRAINT_VIOLATED ||
692 		    rc == SCF_ERROR_NOT_FOUND) {
693 			vs_default_value(prop_hd, vpd->vpd_id);
694 			return (VS_ERR_NONE);
695 		}
696 		return (VS_ERR_SCF);
697 	}
698 
699 	rc = VS_ERR_NONE;
700 	switch (vpd->vpd_id) {
701 	case VS_PROPID_MAXSIZE:
702 		if ((scf_value_get_astring(vsc->vscf_val[idx],
703 		    vp->vp_maxsize, sizeof (vp->vp_maxsize))) == -1) {
704 			return (VS_ERR_SCF);
705 		}
706 		break;
707 	case VS_PROPID_MAXSIZE_ACTION:
708 		if ((scf_value_get_boolean(vsc->vscf_val[idx],
709 		    &valbool)) == -1) {
710 			return (VS_ERR_SCF);
711 		}
712 		vp->vp_maxsize_action = (valbool == 0) ? B_FALSE : B_TRUE;
713 		break;
714 	case VS_PROPID_TYPES:
715 		if ((scf_value_get_astring(vsc->vscf_val[idx],
716 		    vp->vp_types, sizeof (vp->vp_types))) == -1) {
717 			return (VS_ERR_SCF);
718 		}
719 		break;
720 	case VS_PROPID_VLOG:
721 		if ((scf_value_get_astring(vsc->vscf_val[idx],
722 		    vp->vp_vlog, sizeof (vp->vp_vlog))) == -1) {
723 			return (VS_ERR_SCF);
724 		}
725 		break;
726 	case VS_PROPID_SE_ENABLE:
727 		if ((scf_value_get_boolean(vsc->vscf_val[idx],
728 		    &valbool)) == -1) {
729 			return (VS_ERR_SCF);
730 		}
731 		vep->vep_enable = (valbool == 0) ? B_FALSE : B_TRUE;
732 		break;
733 	case VS_PROPID_SE_HOST:
734 		(void) scf_value_get_as_string_typed(vsc->vscf_val[idx],
735 		    vpd->vpd_type, vep->vep_host, sizeof (vep->vep_host));
736 		break;
737 	case VS_PROPID_SE_PORT:
738 		if ((scf_value_get_integer(vsc->vscf_val[idx], &port)) == -1)
739 			return (VS_ERR_SCF);
740 		if (port <= 0 || port >= UINT16_MAX)
741 			rc = VS_ERR_INVALID_VALUE;
742 		else
743 			vep->vep_port = (uint16_t)port;
744 		break;
745 	case VS_PROPID_SE_MAXCONN:
746 		if ((scf_value_get_integer(vsc->vscf_val[idx],
747 		    (int64_t *)&vep->vep_maxconn)) == -1) {
748 			return (VS_ERR_SCF);
749 		}
750 		break;
751 	default:
752 		break;
753 	}
754 
755 	if ((rc != VS_ERR_NONE) ||
756 	    (vs_validate(prop_hd, vpd->vpd_id) != VS_ERR_NONE)) {
757 		vs_default_value(prop_hd, vpd->vpd_id);
758 	}
759 
760 	return (VS_ERR_NONE);
761 }
762 
763 
764 /*
765  * vs_scf_pg_create
766  */
767 static int
768 vs_scf_pg_create(const char *pgname, vs_prop_hd_t *prop_hd)
769 {
770 	int rc;
771 	uint64_t propid;
772 	uint64_t propids = prop_hd->vp_ids;
773 	vs_scfctx_t vsc;
774 
775 	/* ensure that caller has authorization to refresh service */
776 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
777 		return (rc);
778 
779 	if (vs_scf_ctx_open(&vsc) != 0) {
780 		vs_scf_ctx_close(&vsc);
781 		return (VS_ERR_SCF);
782 	}
783 
784 	if (scf_instance_add_pg(vsc.vscf_inst, pgname,
785 	    SCF_GROUP_APPLICATION, 0, vsc.vscf_pgroup) == -1) {
786 		vs_scf_ctx_close(&vsc);
787 		if (scf_error() == SCF_ERROR_INVALID_ARGUMENT)
788 			return (VS_ERR_INVALID_SE);
789 		return (VS_ERR_SCF);
790 	}
791 	vs_scf_ctx_close(&vsc);
792 
793 	/* set default values for those not specified */
794 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
795 		if ((propid & prop_hd->vp_all) && !(propid & prop_hd->vp_ids))
796 			vs_default_value(prop_hd, propid);
797 	}
798 	prop_hd->vp_ids = prop_hd->vp_all;
799 
800 
801 	if ((propids & VS_PROPID_SE_HOST) == 0)
802 		(void) strlcpy(prop_hd->vp_se.vep_host, pgname, MAXHOSTNAMELEN);
803 
804 	prop_hd->vp_ids |= VS_PROPID_VALUE_AUTH;
805 
806 	rc = vs_scf_values_set(pgname, prop_hd);
807 	if (rc != VS_ERR_NONE)
808 		(void) vs_props_se_delete(pgname);
809 
810 	return (rc);
811 }
812 
813 
814 /*
815  * vs_scf_values_set
816  *
817  * Sets property values in the repository.  This is the single
818  * entry point for storing SMF values.
819  *
820  * Like loading values, this is an operation based on a single property
821  * group, so all property values changed in this function must belong
822  * to the same property group. Additionally, this operation is done in
823  * the context of a repository transaction; on any fatal error, the
824  * SCF context will be closed, destroying all SCF objects and aborting
825  * the transaction.
826  */
827 static int
828 vs_scf_values_set(const char *pgname, vs_prop_hd_t *prop_hd)
829 {
830 	int rc, np;
831 	const vs_propdef_t *vpd;
832 	uint64_t propid;
833 	vs_scfctx_t vsc;
834 
835 
836 	/* ensure that caller has authorization to refresh service */
837 	if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
838 		return (rc);
839 
840 	if (vs_scf_ctx_open(&vsc) != 0) {
841 		vs_scf_ctx_close(&vsc);
842 		return (VS_ERR_SCF);
843 	}
844 
845 	if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
846 		vs_scf_ctx_close(&vsc);
847 		rc = scf_error();
848 		if (strcmp(pgname, "VS_PGNAME_GENERAL") != 0) {
849 			if ((rc == SCF_ERROR_NOT_FOUND) ||
850 			    (rc == SCF_ERROR_INVALID_ARGUMENT))
851 				return (VS_ERR_INVALID_SE);
852 		}
853 		return (VS_ERR_SCF);
854 	}
855 
856 	if (((vsc.vscf_tx = scf_transaction_create(vsc.vscf_handle)) == NULL) ||
857 	    (scf_transaction_start(vsc.vscf_tx, vsc.vscf_pgroup) == -1)) {
858 		vs_scf_ctx_close(&vsc);
859 		return (VS_ERR_SCF);
860 	}
861 
862 	/* Process the value change for each specified property */
863 	rc = 0;
864 	np = 0;
865 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
866 		if ((prop_hd->vp_ids & propid) == 0)
867 			continue;
868 
869 		if ((vpd = vs_get_propdef(propid)) == NULL) {
870 			rc = VS_ERR_INVALID_PROPERTY;
871 			break;
872 		}
873 
874 		vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
875 		vsc.vscf_ent[np] = scf_entry_create(vsc.vscf_handle);
876 
877 		if (vsc.vscf_val[np] == NULL || vsc.vscf_ent[np] == NULL) {
878 			rc = VS_ERR_SCF;
879 			break;
880 		}
881 
882 		if ((rc = scf_transaction_property_change(vsc.vscf_tx,
883 		    vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type)) == -1) {
884 			rc = scf_transaction_property_new(vsc.vscf_tx,
885 			    vsc.vscf_ent[np], vpd->vpd_name, vpd->vpd_type);
886 		}
887 		if (rc == -1) {
888 			rc = VS_ERR_SCF;
889 			break;
890 		}
891 
892 		if ((rc = vs_scf_set(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
893 			break;
894 
895 		++np;
896 	}
897 
898 	if (rc != VS_ERR_NONE) {
899 		vs_scf_ctx_close(&vsc);
900 		return (rc);
901 	}
902 
903 	/* Commit the transaction */
904 	if (scf_transaction_commit(vsc.vscf_tx) == -1) {
905 		vs_scf_ctx_close(&vsc);
906 		return (VS_ERR_SCF);
907 	}
908 	vs_scf_ctx_close(&vsc);
909 
910 	/* Notify the daemon that things have changed */
911 	if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1)
912 		return (VS_ERR_SCF);
913 
914 	return (VS_ERR_NONE);
915 }
916 
917 
918 /*
919  * vs_scf_set
920  *
921  * Stores a single value from the appropriate vscan property structure
922  * member into the repository.
923  *
924  * Values are set in the SCF value object, then the value object
925  * is added to the SCF property object.
926  */
927 static int
928 vs_scf_set(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
929     vs_scfctx_t *vsc, int idx)
930 {
931 	int rc;
932 	vs_props_t *vp = &prop_hd->vp_gen;
933 	vs_props_se_t *vep = &prop_hd->vp_se;
934 
935 	if ((rc = vs_validate(prop_hd, vpd->vpd_id)) != VS_ERR_NONE)
936 		return (rc);
937 
938 	rc = VS_ERR_NONE;
939 	switch (vpd->vpd_id) {
940 	case VS_PROPID_MAXSIZE:
941 		if ((scf_value_set_astring(vsc->vscf_val[idx],
942 		    vp->vp_maxsize)) == -1) {
943 			rc = VS_ERR_SCF;
944 		}
945 		break;
946 	case VS_PROPID_MAXSIZE_ACTION:
947 		scf_value_set_boolean(vsc->vscf_val[idx],
948 		    (uint8_t)vp->vp_maxsize_action);
949 		break;
950 	case VS_PROPID_TYPES:
951 		if ((scf_value_set_astring(vsc->vscf_val[idx],
952 		    vp->vp_types)) == -1) {
953 			return (VS_ERR_SCF);
954 		}
955 		break;
956 	case VS_PROPID_SE_ENABLE:
957 		scf_value_set_boolean(vsc->vscf_val[idx],
958 		    (uint8_t)vep->vep_enable);
959 		break;
960 	case VS_PROPID_SE_HOST:
961 		if ((scf_value_set_from_string(vsc->vscf_val[idx],
962 		    vpd->vpd_type, vep->vep_host)) == -1) {
963 			rc = VS_ERR_SCF;
964 		}
965 		break;
966 	case VS_PROPID_SE_PORT:
967 		scf_value_set_integer(vsc->vscf_val[idx], vep->vep_port);
968 		break;
969 	case VS_PROPID_SE_MAXCONN:
970 		scf_value_set_integer(vsc->vscf_val[idx],
971 		    vep->vep_maxconn);
972 		break;
973 	case VS_PROPID_VALUE_AUTH:
974 		if ((scf_value_set_astring(vsc->vscf_val[idx],
975 		    VS_VALUE_AUTH)) == -1) {
976 			return (VS_ERR_SCF);
977 		}
978 		break;
979 	default:
980 		break;
981 	}
982 
983 	if ((scf_entry_add_value(vsc->vscf_ent[idx],
984 	    vsc->vscf_val[idx])) == -1) {
985 		return (VS_ERR_SCF);
986 	}
987 
988 	return (rc);
989 }
990 
991 
992 /*
993  * vs_scf_ctx_open
994  *
995  * Opens an SCF context; creates the minumum SCF objects
996  * for use in loading/storing from the SMF repository (meaning
997  * vscf_property group data).
998  *
999  * Other SCF objects in the context may be initialized elsewher
1000  * subsequent to open, but all initialized structures are destroyed
1001  * in vs_scf_ctx_close().
1002  */
1003 static int
1004 vs_scf_ctx_open(vs_scfctx_t *vsc)
1005 {
1006 	(void) memset(vsc, 0, sizeof (vs_scfctx_t));
1007 
1008 	if ((vsc->vscf_handle = scf_handle_create(SCF_VERSION)) == NULL)
1009 		return (VS_ERR_SCF);
1010 
1011 	if (scf_handle_bind(vsc->vscf_handle) == -1)
1012 		return (VS_ERR_SCF);
1013 
1014 	if ((vsc->vscf_inst = scf_instance_create(vsc->vscf_handle)) == NULL)
1015 		return (VS_ERR_SCF);
1016 
1017 	if (scf_handle_decode_fmri(vsc->vscf_handle, VS_INSTANCE_FMRI,
1018 	    NULL, NULL, vsc->vscf_inst, NULL, NULL,
1019 	    SCF_DECODE_FMRI_EXACT) == -1) {
1020 		return (VS_ERR_SCF);
1021 	}
1022 
1023 	if ((vsc->vscf_pgroup = scf_pg_create(vsc->vscf_handle)) == NULL)
1024 		return (VS_ERR_SCF);
1025 
1026 	return (VS_ERR_NONE);
1027 }
1028 
1029 
1030 /*
1031  * vs_scf_ctx_close
1032  *
1033  * Closes an SCF context; destroys all initialized SCF objects.
1034  */
1035 static void
1036 vs_scf_ctx_close(vs_scfctx_t *vsc)
1037 {
1038 	int i;
1039 
1040 	for (i = 0; i < VS_NUM_PROPIDS; i++) {
1041 		if (vsc->vscf_val[i])
1042 			scf_value_destroy(vsc->vscf_val[i]);
1043 		if (vsc->vscf_ent[i])
1044 			scf_entry_destroy(vsc->vscf_ent[i]);
1045 		if (vsc->vscf_prop[i])
1046 			scf_property_destroy(vsc->vscf_prop[i]);
1047 	}
1048 
1049 	if (vsc->vscf_iter)
1050 		scf_iter_destroy(vsc->vscf_iter);
1051 	if (vsc->vscf_tx)
1052 		scf_transaction_destroy(vsc->vscf_tx);
1053 	if (vsc->vscf_pgroup)
1054 		scf_pg_destroy(vsc->vscf_pgroup);
1055 	if (vsc->vscf_inst)
1056 		scf_instance_destroy(vsc->vscf_inst);
1057 	if (vsc->vscf_handle)
1058 		scf_handle_destroy(vsc->vscf_handle);
1059 }
1060 
1061 
1062 /*
1063  * vs_validate
1064  *
1065  * Validate property identified in propid.
1066  *
1067  * Returns: VS_ERR_NONE
1068  *          VS_ERR_INVALID_VALUE
1069  *          VS_ERR_INVALID_PROPERTY
1070  */
1071 static int
1072 vs_validate(const vs_prop_hd_t *prop_hd, uint64_t propid)
1073 {
1074 	uint64_t num;
1075 	const vs_props_t *vp = &prop_hd->vp_gen;
1076 	const vs_props_se_t *vep = &prop_hd->vp_se;
1077 
1078 	switch (propid) {
1079 	case VS_PROPID_MAXSIZE:
1080 		if ((vs_strtonum(vp->vp_maxsize, &num) != 0) || (num == 0))
1081 			return (VS_ERR_INVALID_VALUE);
1082 		break;
1083 	case VS_PROPID_MAXSIZE_ACTION:
1084 		break;
1085 	case VS_PROPID_TYPES:
1086 		if (!vs_is_valid_types(vp->vp_types))
1087 			return (VS_ERR_INVALID_VALUE);
1088 		break;
1089 	case VS_PROPID_SE_ENABLE:
1090 		break;
1091 	case VS_PROPID_SE_PORT:
1092 		if (vep->vep_port == 0)
1093 			return (VS_ERR_INVALID_VALUE);
1094 		break;
1095 	case VS_PROPID_SE_HOST:
1096 		if (!vs_is_valid_host(vep->vep_host))
1097 			return (VS_ERR_INVALID_VALUE);
1098 		break;
1099 	case VS_PROPID_SE_MAXCONN:
1100 		if (vep->vep_maxconn < VS_VAL_SE_MAXCONN_MIN ||
1101 		    vep->vep_maxconn > VS_VAL_SE_MAXCONN_MAX)
1102 			return (VS_ERR_INVALID_VALUE);
1103 		break;
1104 	case VS_PROPID_VALUE_AUTH:
1105 	case VS_PROPID_VLOG:
1106 		break;
1107 	default:
1108 		return (VS_ERR_INVALID_PROPERTY);
1109 	}
1110 
1111 	return (VS_ERR_NONE);
1112 }
1113 
1114 
1115 /*
1116  * vs_props_validate
1117  *
1118  * Validate  properties identified in propids.
1119  *
1120  * Returns: VS_ERR_NONE
1121  *          VS_ERR_INVALID_VALUE
1122  *          VS_ERR_INVALID_PROPERTY
1123  */
1124 int
1125 vs_props_validate(const vs_props_t *props, uint64_t propids)
1126 {
1127 	uint64_t propid;
1128 	vs_prop_hd_t prop_hd;
1129 
1130 	if ((propids & VS_PROPID_GEN_ALL) != propids)
1131 		return (VS_ERR_INVALID_PROPERTY);
1132 
1133 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
1134 	prop_hd.vp_gen = *props;
1135 	prop_hd.vp_type = VS_PTYPE_GEN;
1136 	prop_hd.vp_ids = propids;
1137 	prop_hd.vp_all = VS_PROPID_GEN_ALL;
1138 
1139 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
1140 		if ((propids & propid) == 0)
1141 			continue;
1142 
1143 		if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
1144 			return (VS_ERR_INVALID_VALUE);
1145 	}
1146 
1147 	return (VS_ERR_NONE);
1148 }
1149 
1150 
1151 /*
1152  * vs_props_se_validate
1153  *
1154  * Validate properties identified in propids.
1155  *
1156  * Returns: VS_ERR_NONE
1157  *          VS_ERR_INVALID_VALUE
1158  *          VS_ERR_INVALID_PROPERTY
1159  */
1160 int
1161 vs_props_se_validate(const vs_props_se_t *se_props, uint64_t propids)
1162 {
1163 	uint64_t propid;
1164 	vs_prop_hd_t prop_hd;
1165 
1166 	if ((propids & VS_PROPID_SE_ALL) != propids)
1167 		return (VS_ERR_INVALID_PROPERTY);
1168 
1169 	(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
1170 	prop_hd.vp_se = *se_props;
1171 	prop_hd.vp_type = VS_PTYPE_SE;
1172 	prop_hd.vp_ids = propids;
1173 	prop_hd.vp_all = VS_PROPID_SE_ALL;
1174 
1175 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
1176 		if ((propids & propid) == 0)
1177 			continue;
1178 
1179 		if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
1180 			return (VS_ERR_INVALID_VALUE);
1181 	}
1182 
1183 	return (VS_ERR_NONE);
1184 }
1185 
1186 
1187 /*
1188  * vs_is_valid_types
1189  *
1190  * Checks that types property is a valid format:
1191  * - doesn't exceed VS_VAL_TYPES_MAX
1192  * - doesn't contain VS_VAL_TYPES_INVALID_CHARS
1193  * - is correctly formatted - passes the parsing tests
1194  *
1195  * Returns 1 on success, 0 on failure
1196  */
1197 static int
1198 vs_is_valid_types(const char *types)
1199 {
1200 	char buf[VS_VAL_TYPES_LEN];
1201 	uint32_t len = VS_VAL_TYPES_LEN;
1202 
1203 	if (strlen(types) > VS_VAL_TYPES_LEN)
1204 		return (0);
1205 
1206 	if (strpbrk(types, VS_VAL_TYPES_INVALID_CHARS) != NULL)
1207 		return (0);
1208 
1209 	if (vs_parse_types(types, buf, &len) != 0)
1210 		return (0);
1211 
1212 	return (1);
1213 }
1214 
1215 
1216 /*
1217  * vs_is_valid_host
1218  *
1219  * Returns 1 on success, 0 on failure
1220  */
1221 static int
1222 vs_is_valid_host(const char *host)
1223 {
1224 	long naddr;
1225 	const char *p;
1226 
1227 	if (!host || *host == '\0')
1228 		return (0);
1229 
1230 	if ('0' <= host[0] && host[0] <= '9') {
1231 		/* ip address */
1232 		if ((inet_pton(AF_INET, host, &naddr)) == 0)
1233 			return (0);
1234 		if ((naddr & IN_CLASSA_NET) == 0)
1235 			return (0);
1236 		if ((naddr & IN_CLASSC_HOST) == 0)
1237 			return (0);
1238 	} else {
1239 		/* hostname */
1240 		p = host;
1241 		while (*p != '\0') {
1242 			if (!isascii(*p))
1243 				return (0);
1244 
1245 			if (isalnum(*p) ||
1246 			    (*p == '.') || (*p == '-') || (*p == '_')) {
1247 				++p;
1248 			} else {
1249 				return (0);
1250 			}
1251 		}
1252 	}
1253 
1254 	return (1);
1255 }
1256 
1257 
1258 /*
1259  * vs_parse_types
1260  *
1261  * Replace comma separators with '\0'.
1262  *
1263  * Types contains comma separated rules each beginning with +|-
1264  *   - embedded commas are escaped by backslash
1265  *   - backslash is escaped by backslash
1266  *   - a single backslash not followed by comma is illegal
1267  *
1268  * On entry to the function len must contain the length of
1269  * the buffer. On sucecssful exit len will contain the length
1270  * of the parsed data within the buffer.
1271  *
1272  * Returns 0 on success, -1 on failure
1273  */
1274 int
1275 vs_parse_types(const char *types, char *buf, uint32_t *len)
1276 {
1277 	char *p = (char *)types;
1278 	char *b = buf;
1279 
1280 	if (strlen(types) > *len)
1281 		return (-1);
1282 
1283 	if (strchr(VS_TYPES_RULES, *p) == NULL)
1284 		return (-1);
1285 
1286 	(void) memset(buf, 0, *len);
1287 
1288 	while (*p) {
1289 		switch (*p) {
1290 		case VS_TYPES_SEP:
1291 			if (*(p + 1) &&
1292 			    (strchr(VS_TYPES_RULES, *(p + 1))) == NULL)
1293 				return (-1);
1294 			*b = '\0';
1295 			break;
1296 		case VS_TYPES_ESCAPE:
1297 			++p;
1298 			if (*p == VS_TYPES_ESCAPE || *p == VS_TYPES_SEP)
1299 				*b = *p;
1300 			else
1301 				return (-1);
1302 			break;
1303 		default:
1304 			*b = *p;
1305 		}
1306 		++p;
1307 		++b;
1308 	}
1309 
1310 	*len = (b - buf) + 1;
1311 
1312 	return (0);
1313 }
1314 
1315 
1316 /*
1317  * vs_statistics
1318  */
1319 int
1320 vs_statistics(vs_stats_t *stats)
1321 {
1322 	int door_fd, rc = VS_ERR_NONE;
1323 	vs_stats_req_t *req;
1324 	vs_stats_t *buf;
1325 	door_arg_t arg;
1326 
1327 	if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
1328 		return (VS_ERR_SYS);
1329 
1330 	if ((buf = calloc(1, sizeof (vs_stats_t))) == NULL) {
1331 		free(req);
1332 		return (VS_ERR_SYS);
1333 	}
1334 
1335 	if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
1336 		free(req);
1337 		free(buf);
1338 		return (VS_ERR_DAEMON_COMM);
1339 	}
1340 
1341 	*req = VS_STATS_GET;
1342 
1343 	arg.data_ptr = (char *)req;
1344 	arg.data_size = sizeof (vs_stats_req_t);
1345 	arg.desc_ptr = NULL;
1346 	arg.desc_num = 0;
1347 	arg.rbuf = (char *)buf;
1348 	arg.rsize = sizeof (vs_stats_t);
1349 
1350 	if (door_call(door_fd, &arg) < 0)
1351 		rc = VS_ERR_DAEMON_COMM;
1352 	else
1353 		*stats = *buf;
1354 
1355 	(void) close(door_fd);
1356 
1357 	free(req);
1358 	free(buf);
1359 	return (rc);
1360 }
1361 
1362 
1363 /*
1364  * vs_statistics_reset
1365  */
1366 int
1367 vs_statistics_reset()
1368 {
1369 	int door_fd, rc;
1370 	vs_stats_req_t *req;
1371 	door_arg_t arg;
1372 
1373 	/* ensure that caller has authorization to reset stats */
1374 	if ((rc = vs_checkauth(VS_VALUE_AUTH)) != VS_ERR_NONE)
1375 		return (rc);
1376 
1377 	if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
1378 		return (VS_ERR_SYS);
1379 
1380 	if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
1381 		free(req);
1382 		return (VS_ERR_DAEMON_COMM);
1383 	}
1384 
1385 	*req = VS_STATS_RESET;
1386 
1387 	arg.data_ptr = (char *)req;
1388 	arg.data_size = sizeof (vs_stats_req_t);
1389 	arg.desc_ptr = NULL;
1390 	arg.desc_num = 0;
1391 	arg.rbuf = NULL;
1392 	arg.rsize = 0;
1393 
1394 	if (door_call(door_fd, &arg) < 0)
1395 		rc = VS_ERR_DAEMON_COMM;
1396 	else
1397 		rc = VS_ERR_NONE;
1398 
1399 	(void) close(door_fd);
1400 	free(req);
1401 	return (rc);
1402 }
1403 
1404 
1405 /*
1406  * vs_checkauth
1407  */
1408 static int
1409 vs_checkauth(char *auth)
1410 {
1411 	struct passwd *pw;
1412 	uid_t uid;
1413 
1414 	uid = getuid();
1415 
1416 	if ((pw = getpwuid(uid)) == NULL)
1417 		return (VS_ERR_SYS);
1418 
1419 	if (chkauthattr(auth, pw->pw_name) != 1) {
1420 		return (VS_ERR_AUTH);
1421 	}
1422 
1423 	return (VS_ERR_NONE);
1424 }
1425 
1426 
1427 /*
1428  * vs_props_get_engines
1429  * On input, count specifies the maximum number of engine ids to
1430  * return. engids must be an array with count entries.
1431  * On return, count specifies the number of engine ids being
1432  * returned in engids.
1433  */
1434 static int
1435 vs_props_get_engines(vs_engid_t *engids, int *count)
1436 {
1437 	int i = 0;
1438 	vs_scfctx_t vsc;
1439 
1440 
1441 	if (((vs_scf_ctx_open(&vsc)) != 0) ||
1442 	    ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) ||
1443 	    (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst,
1444 	    SCF_GROUP_APPLICATION) != 0)) {
1445 		vs_scf_ctx_close(&vsc);
1446 		return (VS_ERR_SCF);
1447 	}
1448 
1449 	while ((i < VS_SE_MAX) &&
1450 	    (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)) {
1451 		if (scf_pg_get_name(vsc.vscf_pgroup, engids[i],
1452 		    VS_SE_NAME_LEN) < 0) {
1453 			vs_scf_ctx_close(&vsc);
1454 			return (VS_ERR_SCF);
1455 		}
1456 
1457 		if (strcmp(engids[i], VS_PGNAME_GENERAL) == 0)
1458 			*engids[i] = 0;
1459 		else
1460 			if (++i == *count)
1461 			break;
1462 	}
1463 	vs_scf_ctx_close(&vsc);
1464 
1465 	*count = i;
1466 	return (VS_ERR_NONE);
1467 }
1468 
1469 
1470 /*
1471  * vs_scf_pg_count
1472  */
1473 static int
1474 vs_scf_pg_count(void)
1475 {
1476 	int count = 0;
1477 	vs_scfctx_t vsc;
1478 
1479 	if ((vs_scf_ctx_open(&vsc) != 0) ||
1480 	    ((vsc.vscf_iter = scf_iter_create(vsc.vscf_handle)) == NULL) ||
1481 	    (scf_iter_instance_pgs_typed(vsc.vscf_iter, vsc.vscf_inst,
1482 	    SCF_GROUP_APPLICATION) != 0)) {
1483 		vs_scf_ctx_close(&vsc);
1484 		return (-1);
1485 	}
1486 
1487 	while (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)
1488 		++count;
1489 
1490 	vs_scf_ctx_close(&vsc);
1491 
1492 	return (count);
1493 }
1494 
1495 
1496 /*
1497  *  vs_strtonum
1498  *
1499  *  Converts a size string in the format into an integer.
1500  *
1501  *  A size string is a numeric value followed by an optional unit
1502  *  specifier which is used as a multiplier to calculate a raw
1503  *  number.
1504  *  The size string format is:  N[.N][KMGTP][B]
1505  *
1506  *  The numeric value can contain a decimal portion. Unit specifiers
1507  *  are either a one-character or two-character string; i.e. "K" or
1508  *  "KB" for kilobytes. Unit specifiers must follow the numeric portion
1509  *  immediately, and are not case-sensitive.
1510  *
1511  *  If either "B" is specified, or there is no unit specifier portion
1512  *  in the string, the numeric value is calculated with no multiplier
1513  *  (assumes a basic unit of "bytes").
1514  *
1515  *  Returns:
1516  *	-1:	Failure; errno set to specify the error.
1517  *	 0:	Success.
1518  */
1519 int
1520 vs_strtonum(const char *value, uint64_t *num)
1521 {
1522 	char *end;
1523 	int shift;
1524 	double fval;
1525 
1526 	*num = 0;
1527 
1528 	/* Check to see if this looks like a number.  */
1529 	if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
1530 		errno = EINVAL;
1531 		return (-1);
1532 	}
1533 
1534 	/* Rely on stroll() to process the numeric portion.  */
1535 	errno = 0;
1536 	*num = strtoll(value, &end, 10);
1537 
1538 	/*
1539 	 * Check for ERANGE, which indicates that the value is too large to
1540 	 * fit in a 64-bit value.
1541 	 */
1542 	if (errno != 0)
1543 		return (-1);
1544 
1545 	/*
1546 	 * If we have a decimal value, then do the computation with floating
1547 	 * point arithmetic.  Otherwise, use standard arithmetic.
1548 	 */
1549 	if (*end == '.') {
1550 		fval = strtod(value, &end);
1551 
1552 		if ((shift = vs_strtoshift(end)) == -1)
1553 			return (-1); /* errno set */
1554 
1555 		fval *= pow(2, shift);
1556 		if (fval > UINT64_MAX) {
1557 			errno = ERANGE;
1558 			return (-1);
1559 		}
1560 
1561 		*num = (uint64_t)fval;
1562 	} else {
1563 		if ((shift = vs_strtoshift(end)) == -1)
1564 			return (-1); /* errno set */
1565 
1566 		/* Check for overflow */
1567 		if (shift >= 64 || (*num << shift) >> shift != *num) {
1568 			errno = ERANGE;
1569 			return (-1);
1570 		}
1571 
1572 		*num <<= shift;
1573 	}
1574 
1575 	return (0);
1576 }
1577 
1578 
1579 /*
1580  *  vs_strtoshift
1581  *
1582  *  Converts a unit specifier string into a number of bits that
1583  *  a numeric value must be shifted.
1584  *
1585  *  Returns:
1586  *	-1:	Failure; errno set to specify the error.
1587  *	>-1:	Success; the shift count.
1588  *
1589  */
1590 static int
1591 vs_strtoshift(const char *buf)
1592 {
1593 	const char *ends = "BKMGTPEZ";
1594 	int i;
1595 
1596 	if (buf[0] == '\0')
1597 		return (0);
1598 	for (i = 0; i < strlen(ends); i++) {
1599 		if (toupper(buf[0]) == ends[i])
1600 			break;
1601 	}
1602 	if (i == strlen(ends)) {
1603 		errno = EINVAL;
1604 		return (-1);
1605 	}
1606 
1607 	/* Allow trailing 'b' characters except in the case of 'BB'. */
1608 	if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' &&
1609 	    toupper(buf[0]) != 'B')) {
1610 		return (10 * i);
1611 	}
1612 
1613 	errno = EINVAL;
1614 	return (-1);
1615 }
1616