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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <ctype.h>
31 #include <math.h>
32 #include <limits.h>
33 #include <libscf.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <door.h>
37 #include <pwd.h>
38 #include <auth_attr.h>
39 #include <secdb.h>
40 #include <sys/socket.h>
41 #include <arpa/inet.h>
42 #include <libintl.h>
43 #include <libvscan.h>
44
45 #define VS_DOOR_CALL_RETRIES 3
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_PREFIX "vs_engine_"
52 #define VS_PGNAME_ENGINE_LEN VS_SE_NAME_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 = 8;
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 static int vs_scf_pg_delete(const char *);
170
171 static int vs_scf_ctx_open(vs_scfctx_t *);
172 static void vs_scf_ctx_close(vs_scfctx_t *);
173
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 *);
179
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 *);
184
185
186 /*
187 * vs_props_get_all
188 *
189 * Retrieves the general service properties and all properties
190 * for all scan engines from the repository.
191 *
192 * If invalid property values are found, the values are corrected to
193 * the default value.
194 *
195 * Return codes:
196 * VS_ERR_VS_ERR_NONE
197 * VS_ERR_SCF
198 * VS_ERR_SYS
199 */
200 int
vs_props_get_all(vs_props_all_t * va)201 vs_props_get_all(vs_props_all_t *va)
202 {
203 int i, rc, n;
204 char *engids[VS_SE_MAX];
205
206 (void) memset(va, 0, sizeof (vs_props_all_t));
207 if ((rc = vs_props_get(&va->va_props, VS_PROPID_GEN_ALL))
208 != VS_ERR_NONE)
209 return (rc);
210
211 n = VS_SE_MAX;
212 if ((rc = vs_props_get_engines(engids, &n)) != VS_ERR_NONE)
213 return (rc);
214
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)
218 break;
219 }
220
221 /* free engids allocated in vs_props_get_engines */
222 for (i = 0; i < VS_SE_MAX; i++) {
223 if (engids[i] != NULL)
224 free(engids[i]);
225 }
226
227 return (rc);
228 }
229
230
231 /*
232 * vs_props_get
233 *
234 * Retrieves values for the specified general service properties from
235 * the repository.
236 *
237 * If invalid property values are found, the values are corrected to
238 * the default value.
239 *
240 * Return codes:
241 * VS_ERR_VS_ERR_NONE
242 * VS_ERR_INVALID_PROPERTY
243 * VS_ERR_SCF
244 * VS_ERR_SYS
245 */
246 int
vs_props_get(vs_props_t * vp,uint64_t propids)247 vs_props_get(vs_props_t *vp, uint64_t propids)
248 {
249 int rc;
250 vs_prop_hd_t prop_hd;
251
252 if ((propids & VS_PROPID_GEN_ALL) != propids)
253 return (VS_ERR_INVALID_PROPERTY);
254
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;
259
260 rc = vs_scf_values_get(VS_PGNAME_GENERAL, &prop_hd);
261
262 *vp = prop_hd.vp_gen;
263 return (rc);
264 }
265
266
267 /*
268 * vs_props_set
269 *
270 * Changes values for the specified general service properties
271 * in the repository.
272 *
273 * Return codes:
274 * VS_ERR_VS_ERR_NONE
275 * VS_ERR_INVALID_PROPERTY
276 * VS_ERR_INVALID_VALUE
277 * VS_ERR_SCF
278 * VS_ERR_SYS
279 */
280 int
vs_props_set(const vs_props_t * vp,uint64_t propids)281 vs_props_set(const vs_props_t *vp, uint64_t propids)
282 {
283 vs_prop_hd_t prop_hd;
284
285 if ((propids & VS_PROPID_GEN_ALL) != propids)
286 return (VS_ERR_INVALID_PROPERTY);
287
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));
294 }
295
296
297 /*
298 * vs_props_se_get
299 *
300 * Retrieves values for the specified scan engine properties from the
301 * repository.
302 *
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)
306 *
307 * Return codes:
308 * VS_ERR_VS_ERR_NONE
309 * VS_ERR_INVALID_PROPERTY
310 * VS_ERR_SCF
311 * VS_ERR_SYS
312 */
313 int
vs_props_se_get(char * engid,vs_props_se_t * sep,uint64_t propids)314 vs_props_se_get(char *engid, vs_props_se_t *sep, uint64_t propids)
315 {
316 int rc;
317 char pgname[VS_PGNAME_ENGINE_LEN];
318 vs_prop_hd_t prop_hd;
319
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);
323
324 if ((propids & VS_PROPID_SE_ALL) != propids)
325 return (VS_ERR_INVALID_PROPERTY);
326
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);
332
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;
336
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)
341 return (rc);
342
343 /*
344 * If the host is invalid and the enable property is on,
345 * return enable property as off
346 */
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;
350 }
351
352 *sep = prop_hd.vp_se;
353 return (rc);
354 }
355
356
357
358 /*
359 * vs_props_se_set
360 *
361 * Changes the values for the specified scan engine properties in the
362 * repository.
363 *
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
366 * repository.
367 *
368 * Return codes:
369 * VS_ERR_NONE
370 * VS_ERR_INVALID_PROPERTY
371 * VS_ERR_INVALID_VALUE
372 * VS_ERR_SCF
373 * VS_ERR_SYS
374 */
375 int
vs_props_se_set(char * engid,const vs_props_se_t * sep,uint64_t propids)376 vs_props_se_set(char *engid, const vs_props_se_t *sep, uint64_t propids)
377 {
378 int rc;
379 char pgname[VS_PGNAME_ENGINE_LEN];
380 vs_prop_hd_t prop_hd;
381
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);
385
386 if ((propids & VS_PROPID_SE_ALL) != propids)
387 return (VS_ERR_INVALID_PROPERTY);
388
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;
392
393 vs_engid_to_pgname(engid, pgname);
394
395 /*
396 * if enabling a scan engine, ensure that a valid host
397 * is also being set, or already exists in the repository
398 */
399 if ((propids & VS_PROPID_SE_ENABLE) && (sep->vep_enable == B_TRUE) &&
400 !(propids & VS_PROPID_SE_HOST)) {
401
402 prop_hd.vp_ids = VS_PROPID_SE_HOST;
403 if ((rc = vs_scf_values_get(pgname, &prop_hd)) != VS_ERR_NONE)
404 return (rc);
405
406 if (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)
407 return (VS_ERR_INVALID_HOST);
408 }
409
410 prop_hd.vp_ids = propids;
411 prop_hd.vp_se = *sep;
412
413 return (vs_scf_values_set(pgname, &prop_hd));
414 }
415
416
417 /*
418 * vs_props_se_create
419 */
420 int
vs_props_se_create(char * engid,const vs_props_se_t * sep,uint64_t propids)421 vs_props_se_create(char *engid, const vs_props_se_t *sep, uint64_t propids)
422 {
423 int n;
424 char pgname[VS_PGNAME_ENGINE_LEN];
425 vs_prop_hd_t prop_hd;
426
427 if ((propids & VS_PROPID_SE_ALL) != propids)
428 return (VS_ERR_INVALID_PROPERTY);
429
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);
433
434 if ((n = vs_scf_pg_count()) == -1)
435 return (VS_ERR_SCF);
436
437 if (n == VS_SE_MAX)
438 return (VS_ERR_MAX_SE);
439
440 vs_engid_to_pgname(engid, pgname);
441
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;
447
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;
452 }
453
454 return (vs_scf_pg_create(pgname, &prop_hd));
455 }
456
457
458 /*
459 * vs_props_se_delete
460 */
461 int
vs_props_se_delete(const char * engid)462 vs_props_se_delete(const char *engid)
463 {
464 char pgname[VS_PGNAME_ENGINE_LEN];
465
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);
469
470 vs_engid_to_pgname(engid, pgname);
471
472 return (vs_scf_pg_delete(pgname));
473 }
474
475
476 /*
477 * vs_strerror
478 */
479 const char *
vs_strerror(int error)480 vs_strerror(int error)
481 {
482 switch (error) {
483 case VS_ERR_NONE:
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"));
493 case VS_ERR_MAX_SE:
494 return (gettext("max scan engines exceeded"));
495 case VS_ERR_AUTH:
496 return (gettext("insufficient privileges for action"));
497 case VS_ERR_DAEMON_COMM:
498 return (gettext("unable to contact vscand"));
499 case VS_ERR_SCF:
500 return (scf_strerror(scf_error()));
501 case VS_ERR_SYS:
502 return (strerror(errno));
503 default:
504 return (gettext("unknown error"));
505 }
506 }
507
508
509 /*
510 * vs_get_propdef
511 *
512 * Finds and returns a property definition by property id.
513 */
514 static const vs_propdef_t *
vs_get_propdef(uint64_t propid)515 vs_get_propdef(uint64_t propid)
516 {
517 int i;
518
519 for (i = 0; i < vs_npropdefs; i++) {
520 if (propid == vs_propdefs[i].vpd_id)
521 return (&vs_propdefs[i]);
522 }
523
524 return (NULL);
525 }
526
527
528 /*
529 * vs_default_value
530 *
531 * Sets a property value that contains invalid data to its default value.
532 *
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.
535 */
536 static void
vs_default_value(vs_prop_hd_t * prop_hd,const uint64_t propid)537 vs_default_value(vs_prop_hd_t *prop_hd, const uint64_t propid)
538 {
539 vs_props_t *vp = &prop_hd->vp_gen;
540 vs_props_se_t *vep = &prop_hd->vp_se;
541
542 switch (propid) {
543 case VS_PROPID_MAXSIZE:
544 (void) strlcpy(vp->vp_maxsize, vs_dflt_maxsize,
545 sizeof (vp->vp_maxsize));
546 break;
547 case VS_PROPID_MAXSIZE_ACTION:
548 vp->vp_maxsize_action = vs_dflt_allow;
549 break;
550 case VS_PROPID_TYPES:
551 (void) strlcpy(vp->vp_types, vs_dflt_types,
552 sizeof (vp->vp_types));
553 break;
554 case VS_PROPID_VLOG:
555 (void) strlcpy(vp->vp_vlog, vs_dflt_vlog,
556 sizeof (vp->vp_vlog));
557 break;
558 case VS_PROPID_SE_ENABLE:
559 vep->vep_enable = vs_dflt_enable;
560 break;
561 case VS_PROPID_SE_HOST:
562 (void) strlcpy(vep->vep_host, vs_dflt_host,
563 sizeof (vep->vep_host));
564 break;
565 case VS_PROPID_SE_PORT:
566 vep->vep_port = vs_dflt_port;
567 break;
568 case VS_PROPID_SE_MAXCONN:
569 vep->vep_maxconn = vs_dflt_maxconn;
570 break;
571 default:
572 break;
573 }
574 }
575
576
577 /*
578 * vs_scf_values_get
579 *
580 * Gets property values for one or more properties from the repository.
581 * This is the single entry point for loading SMF values.
582 *
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
586 * group.
587 */
588 int
vs_scf_values_get(const char * pgname,vs_prop_hd_t * prop_hd)589 vs_scf_values_get(const char *pgname, vs_prop_hd_t *prop_hd)
590 {
591 vs_scfctx_t vsc;
592 int rc, np;
593 const vs_propdef_t *vpd;
594 uint64_t propid;
595
596 if ((vs_scf_ctx_open(&vsc)) != 0) {
597 vs_scf_ctx_close(&vsc);
598 return (VS_ERR_SCF);
599 }
600
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) {
604 rc = scf_error();
605 if ((rc == SCF_ERROR_NOT_FOUND) ||
606 (rc == SCF_ERROR_INVALID_ARGUMENT))
607 return (VS_ERR_INVALID_SE);
608 }
609 return (VS_ERR_SCF);
610 }
611
612 rc = VS_ERR_NONE;
613 np = 0;
614 for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
615 if ((prop_hd->vp_ids & propid) == 0)
616 continue;
617
618 if ((vpd = vs_get_propdef(propid)) == NULL) {
619 rc = VS_ERR_INVALID_PROPERTY;
620 break;
621 }
622
623 vsc.vscf_prop[np] = scf_property_create(vsc.vscf_handle);
624 vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
625
626 if (vsc.vscf_prop[np] == NULL || vsc.vscf_val[np] == NULL) {
627 rc = VS_ERR_SCF;
628 break;
629 }
630
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);
635 continue;
636 }
637 rc = VS_ERR_SCF;
638 break;
639 }
640
641 if ((rc = vs_scf_get(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
642 break;
643
644 ++np;
645 }
646
647
648 vs_scf_ctx_close(&vsc);
649
650 return (rc);
651 }
652
653
654 /*
655 * vs_scf_get
656 *
657 * Loads a single values from the repository into the appropriate vscan
658 * property structure member.
659 */
660 static int
vs_scf_get(const vs_propdef_t * vpd,vs_prop_hd_t * prop_hd,vs_scfctx_t * vsc,int idx)661 vs_scf_get(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
662 vs_scfctx_t *vsc, int idx)
663 {
664 int rc;
665 int64_t port;
666 uint8_t valbool;
667 vs_props_t *vp = &prop_hd->vp_gen;
668 vs_props_se_t *vep = &prop_hd->vp_se;
669
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);
676 }
677 return (VS_ERR_SCF);
678 }
679
680 rc = 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) {
685 return (VS_ERR_SCF);
686 }
687 break;
688 case VS_PROPID_MAXSIZE_ACTION:
689 if ((scf_value_get_boolean(vsc->vscf_val[idx],
690 &valbool)) == -1) {
691 return (VS_ERR_SCF);
692 }
693 vp->vp_maxsize_action = (valbool == 0) ? B_FALSE : B_TRUE;
694 break;
695 case VS_PROPID_TYPES:
696 if ((scf_value_get_astring(vsc->vscf_val[idx],
697 vp->vp_types, sizeof (vp->vp_types))) == -1) {
698 return (VS_ERR_SCF);
699 }
700 break;
701 case VS_PROPID_VLOG:
702 if ((scf_value_get_astring(vsc->vscf_val[idx],
703 vp->vp_vlog, sizeof (vp->vp_vlog))) == -1) {
704 return (VS_ERR_SCF);
705 }
706 break;
707 case VS_PROPID_SE_ENABLE:
708 if ((scf_value_get_boolean(vsc->vscf_val[idx],
709 &valbool)) == -1) {
710 return (VS_ERR_SCF);
711 }
712 vep->vep_enable = (valbool == 0) ? B_FALSE : B_TRUE;
713 break;
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));
717 break;
718 case VS_PROPID_SE_PORT:
719 if ((scf_value_get_integer(vsc->vscf_val[idx], &port)) == -1)
720 return (VS_ERR_SCF);
721 if (port <= 0 || port >= UINT16_MAX)
722 rc = VS_ERR_INVALID_VALUE;
723 else
724 vep->vep_port = (uint16_t)port;
725 break;
726 case VS_PROPID_SE_MAXCONN:
727 if ((scf_value_get_integer(vsc->vscf_val[idx],
728 (int64_t *)&vep->vep_maxconn)) == -1) {
729 return (VS_ERR_SCF);
730 }
731 break;
732 default:
733 break;
734 }
735
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);
739 }
740
741 return (VS_ERR_NONE);
742 }
743
744
745 /*
746 * vs_scf_pg_create
747 */
748 static int
vs_scf_pg_create(const char * pgname,vs_prop_hd_t * prop_hd)749 vs_scf_pg_create(const char *pgname, vs_prop_hd_t *prop_hd)
750 {
751 int rc;
752 uint64_t propid;
753 vs_scfctx_t vsc;
754
755 /* ensure that caller has authorization to refresh service */
756 if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
757 return (rc);
758
759 if (vs_scf_ctx_open(&vsc) != 0) {
760 vs_scf_ctx_close(&vsc);
761 return (VS_ERR_SCF);
762 }
763
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);
769 return (VS_ERR_SCF);
770 }
771 vs_scf_ctx_close(&vsc);
772
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);
777 }
778
779 prop_hd->vp_ids = prop_hd->vp_all;
780 prop_hd->vp_ids |= VS_PROPID_VALUE_AUTH;
781
782 rc = vs_scf_values_set(pgname, prop_hd);
783 if (rc != VS_ERR_NONE)
784 (void) vs_scf_pg_delete(pgname);
785
786 return (rc);
787 }
788
789
790 /*
791 * vs_scf_pg_delete
792 */
793 static int
vs_scf_pg_delete(const char * pgname)794 vs_scf_pg_delete(const char *pgname)
795 {
796 int rc;
797 vs_scfctx_t vsc;
798
799 /* ensure that caller has authorization to refresh service */
800 if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
801 return (rc);
802
803 if (vs_scf_ctx_open(&vsc) != 0) {
804 vs_scf_ctx_close(&vsc);
805 return (VS_ERR_SCF);
806 }
807
808 if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
809 vs_scf_ctx_close(&vsc);
810 rc = scf_error();
811 if ((rc == SCF_ERROR_NOT_FOUND) ||
812 (rc == SCF_ERROR_INVALID_ARGUMENT))
813 return (VS_ERR_INVALID_SE);
814 else
815 return (VS_ERR_SCF);
816 }
817
818 if (scf_pg_delete(vsc.vscf_pgroup) == -1) {
819 vs_scf_ctx_close(&vsc);
820 rc = scf_error();
821 if ((rc == SCF_ERROR_NOT_FOUND) ||
822 (rc == SCF_ERROR_INVALID_ARGUMENT))
823 return (VS_ERR_INVALID_SE);
824
825 return (VS_ERR_SCF);
826 }
827
828 vs_scf_ctx_close(&vsc);
829
830 /* Notify the daemon that things have changed */
831 if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1) {
832 return (VS_ERR_SCF);
833 }
834
835 return (VS_ERR_NONE);
836 }
837
838
839 /*
840 * vs_scf_values_set
841 *
842 * Sets property values in the repository. This is the single
843 * entry point for storing SMF values.
844 *
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
850 * the transaction.
851 */
852 static int
vs_scf_values_set(const char * pgname,vs_prop_hd_t * prop_hd)853 vs_scf_values_set(const char *pgname, vs_prop_hd_t *prop_hd)
854 {
855 int rc, np;
856 const vs_propdef_t *vpd;
857 uint64_t propid;
858 vs_scfctx_t vsc;
859
860 /* ensure that caller has authorization to refresh service */
861 if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
862 return (rc);
863
864 if (vs_scf_ctx_open(&vsc) != 0) {
865 vs_scf_ctx_close(&vsc);
866 return (VS_ERR_SCF);
867 }
868
869 if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
870 vs_scf_ctx_close(&vsc);
871 rc = scf_error();
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);
876 }
877 return (VS_ERR_SCF);
878 }
879
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);
883 return (VS_ERR_SCF);
884 }
885
886 /* Process the value change for each specified property */
887 rc = 0;
888 np = 0;
889 for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
890 if ((prop_hd->vp_ids & propid) == 0)
891 continue;
892
893 if ((vpd = vs_get_propdef(propid)) == NULL) {
894 rc = VS_ERR_INVALID_PROPERTY;
895 break;
896 }
897
898 vsc.vscf_val[np] = scf_value_create(vsc.vscf_handle);
899 vsc.vscf_ent[np] = scf_entry_create(vsc.vscf_handle);
900
901 if (vsc.vscf_val[np] == NULL || vsc.vscf_ent[np] == NULL) {
902 rc = VS_ERR_SCF;
903 break;
904 }
905
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);
910 }
911 if (rc == -1) {
912 rc = VS_ERR_SCF;
913 break;
914 }
915
916 if ((rc = vs_scf_set(vpd, prop_hd, &vsc, np)) != VS_ERR_NONE)
917 break;
918
919 ++np;
920 }
921
922 if (rc != VS_ERR_NONE) {
923 vs_scf_ctx_close(&vsc);
924 return (rc);
925 }
926
927 /* Commit the transaction */
928 if (scf_transaction_commit(vsc.vscf_tx) == -1) {
929 vs_scf_ctx_close(&vsc);
930 return (VS_ERR_SCF);
931 }
932 vs_scf_ctx_close(&vsc);
933
934 /* Notify the daemon that things have changed */
935 if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1)
936 return (VS_ERR_SCF);
937
938 return (VS_ERR_NONE);
939 }
940
941
942 /*
943 * vs_scf_set
944 *
945 * Stores a single value from the appropriate vscan property structure
946 * member into the repository.
947 *
948 * Values are set in the SCF value object, then the value object
949 * is added to the SCF property object.
950 */
951 static int
vs_scf_set(const vs_propdef_t * vpd,vs_prop_hd_t * prop_hd,vs_scfctx_t * vsc,int idx)952 vs_scf_set(const vs_propdef_t *vpd, vs_prop_hd_t *prop_hd,
953 vs_scfctx_t *vsc, int idx)
954 {
955 int rc;
956 vs_props_t *vp = &prop_hd->vp_gen;
957 vs_props_se_t *vep = &prop_hd->vp_se;
958
959 if ((rc = vs_validate(prop_hd, vpd->vpd_id)) != VS_ERR_NONE)
960 return (rc);
961
962 rc = 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) {
967 rc = VS_ERR_SCF;
968 }
969 break;
970 case VS_PROPID_MAXSIZE_ACTION:
971 scf_value_set_boolean(vsc->vscf_val[idx],
972 (uint8_t)vp->vp_maxsize_action);
973 break;
974 case VS_PROPID_TYPES:
975 if ((scf_value_set_astring(vsc->vscf_val[idx],
976 vp->vp_types)) == -1) {
977 return (VS_ERR_SCF);
978 }
979 break;
980 case VS_PROPID_SE_ENABLE:
981 scf_value_set_boolean(vsc->vscf_val[idx],
982 (uint8_t)vep->vep_enable);
983 break;
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) {
987 rc = VS_ERR_SCF;
988 }
989 break;
990 case VS_PROPID_SE_PORT:
991 scf_value_set_integer(vsc->vscf_val[idx], vep->vep_port);
992 break;
993 case VS_PROPID_SE_MAXCONN:
994 scf_value_set_integer(vsc->vscf_val[idx],
995 vep->vep_maxconn);
996 break;
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);
1001 }
1002 break;
1003 default:
1004 break;
1005 }
1006
1007 if ((scf_entry_add_value(vsc->vscf_ent[idx],
1008 vsc->vscf_val[idx])) == -1) {
1009 return (VS_ERR_SCF);
1010 }
1011
1012 return (rc);
1013 }
1014
1015
1016 /*
1017 * vs_scf_ctx_open
1018 *
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).
1022 *
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().
1026 */
1027 static int
vs_scf_ctx_open(vs_scfctx_t * vsc)1028 vs_scf_ctx_open(vs_scfctx_t *vsc)
1029 {
1030 (void) memset(vsc, 0, sizeof (vs_scfctx_t));
1031
1032 if ((vsc->vscf_handle = scf_handle_create(SCF_VERSION)) == NULL)
1033 return (VS_ERR_SCF);
1034
1035 if (scf_handle_bind(vsc->vscf_handle) == -1)
1036 return (VS_ERR_SCF);
1037
1038 if ((vsc->vscf_inst = scf_instance_create(vsc->vscf_handle)) == NULL)
1039 return (VS_ERR_SCF);
1040
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);
1045 }
1046
1047 if ((vsc->vscf_pgroup = scf_pg_create(vsc->vscf_handle)) == NULL)
1048 return (VS_ERR_SCF);
1049
1050 return (VS_ERR_NONE);
1051 }
1052
1053
1054 /*
1055 * vs_scf_ctx_close
1056 *
1057 * Closes an SCF context; destroys all initialized SCF objects.
1058 */
1059 static void
vs_scf_ctx_close(vs_scfctx_t * vsc)1060 vs_scf_ctx_close(vs_scfctx_t *vsc)
1061 {
1062 int i;
1063
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]);
1071 }
1072
1073 if (vsc->vscf_iter)
1074 scf_iter_destroy(vsc->vscf_iter);
1075 if (vsc->vscf_tx)
1076 scf_transaction_destroy(vsc->vscf_tx);
1077 if (vsc->vscf_pgroup)
1078 scf_pg_destroy(vsc->vscf_pgroup);
1079 if (vsc->vscf_inst)
1080 scf_instance_destroy(vsc->vscf_inst);
1081 if (vsc->vscf_handle)
1082 scf_handle_destroy(vsc->vscf_handle);
1083 }
1084
1085
1086 /*
1087 * vs_validate
1088 *
1089 * Validate property identified in propid.
1090 *
1091 * Returns: VS_ERR_NONE
1092 * VS_ERR_INVALID_VALUE
1093 * VS_ERR_INVALID_PROPERTY
1094 */
1095 static int
vs_validate(const vs_prop_hd_t * prop_hd,uint64_t propid)1096 vs_validate(const vs_prop_hd_t *prop_hd, uint64_t propid)
1097 {
1098 uint64_t num;
1099 const vs_props_t *vp = &prop_hd->vp_gen;
1100 const vs_props_se_t *vep = &prop_hd->vp_se;
1101
1102 switch (propid) {
1103 case VS_PROPID_MAXSIZE:
1104 if ((vs_strtonum(vp->vp_maxsize, &num) != 0) || (num == 0))
1105 return (VS_ERR_INVALID_VALUE);
1106 break;
1107 case VS_PROPID_MAXSIZE_ACTION:
1108 break;
1109 case VS_PROPID_TYPES:
1110 if (!vs_is_valid_types(vp->vp_types))
1111 return (VS_ERR_INVALID_VALUE);
1112 break;
1113 case VS_PROPID_SE_ENABLE:
1114 break;
1115 case VS_PROPID_SE_PORT:
1116 if (vep->vep_port == 0)
1117 return (VS_ERR_INVALID_VALUE);
1118 break;
1119 case VS_PROPID_SE_HOST:
1120 if (!vs_is_valid_host(vep->vep_host))
1121 return (VS_ERR_INVALID_VALUE);
1122 break;
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);
1127 break;
1128 case VS_PROPID_VALUE_AUTH:
1129 case VS_PROPID_VLOG:
1130 break;
1131 default:
1132 return (VS_ERR_INVALID_PROPERTY);
1133 }
1134
1135 return (VS_ERR_NONE);
1136 }
1137
1138
1139 /*
1140 * vs_props_validate
1141 *
1142 * Validate properties identified in propids.
1143 *
1144 * Returns: VS_ERR_NONE
1145 * VS_ERR_INVALID_VALUE
1146 * VS_ERR_INVALID_PROPERTY
1147 */
1148 int
vs_props_validate(const vs_props_t * props,uint64_t propids)1149 vs_props_validate(const vs_props_t *props, uint64_t propids)
1150 {
1151 uint64_t propid;
1152 vs_prop_hd_t prop_hd;
1153
1154 if ((propids & VS_PROPID_GEN_ALL) != propids)
1155 return (VS_ERR_INVALID_PROPERTY);
1156
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;
1162
1163 for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
1164 if ((propids & propid) == 0)
1165 continue;
1166
1167 if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
1168 return (VS_ERR_INVALID_VALUE);
1169 }
1170
1171 return (VS_ERR_NONE);
1172 }
1173
1174
1175 /*
1176 * vs_props_se_validate
1177 *
1178 * Validate properties identified in propids.
1179 *
1180 * Returns: VS_ERR_NONE
1181 * VS_ERR_INVALID_VALUE
1182 * VS_ERR_INVALID_PROPERTY
1183 */
1184 int
vs_props_se_validate(const vs_props_se_t * se_props,uint64_t propids)1185 vs_props_se_validate(const vs_props_se_t *se_props, uint64_t propids)
1186 {
1187 uint64_t propid;
1188 vs_prop_hd_t prop_hd;
1189
1190 if ((propids & VS_PROPID_SE_ALL) != propids)
1191 return (VS_ERR_INVALID_PROPERTY);
1192
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;
1198
1199 for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
1200 if ((propids & propid) == 0)
1201 continue;
1202
1203 if (vs_validate(&prop_hd, propid) != VS_ERR_NONE)
1204 return (VS_ERR_INVALID_VALUE);
1205 }
1206
1207 return (VS_ERR_NONE);
1208 }
1209
1210
1211 /*
1212 * vs_is_valid_types
1213 *
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
1218 *
1219 * Returns 1 on success, 0 on failure
1220 */
1221 static int
vs_is_valid_types(const char * types)1222 vs_is_valid_types(const char *types)
1223 {
1224 char buf[VS_VAL_TYPES_LEN];
1225 uint32_t len = VS_VAL_TYPES_LEN;
1226
1227 if (strlen(types) > VS_VAL_TYPES_LEN)
1228 return (0);
1229
1230 if (strpbrk(types, VS_VAL_TYPES_INVALID_CHARS) != NULL)
1231 return (0);
1232
1233 if (vs_parse_types(types, buf, &len) != 0)
1234 return (0);
1235
1236 return (1);
1237 }
1238
1239
1240 /*
1241 * vs_is_valid_host
1242 *
1243 * Returns 1 on success, 0 on failure
1244 */
1245 static int
vs_is_valid_host(const char * host)1246 vs_is_valid_host(const char *host)
1247 {
1248 long naddr;
1249 const char *p;
1250
1251 if (!host || *host == '\0')
1252 return (0);
1253
1254 if ('0' <= host[0] && host[0] <= '9') {
1255 /* ip address */
1256 if ((inet_pton(AF_INET, host, &naddr)) == 0)
1257 return (0);
1258 if ((naddr & IN_CLASSA_NET) == 0)
1259 return (0);
1260 if ((naddr & IN_CLASSC_HOST) == 0)
1261 return (0);
1262 } else {
1263 /* hostname */
1264 p = host;
1265 while (*p != '\0') {
1266 if (!isascii(*p))
1267 return (0);
1268
1269 if (isalnum(*p) ||
1270 (*p == '.') || (*p == '-') || (*p == '_')) {
1271 ++p;
1272 } else {
1273 return (0);
1274 }
1275 }
1276 }
1277
1278 return (1);
1279 }
1280
1281
1282 /*
1283 * vs_parse_types
1284 *
1285 * Replace comma separators with '\0'.
1286 *
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
1291 *
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.
1295 *
1296 * Returns 0 on success, -1 on failure
1297 */
1298 int
vs_parse_types(const char * types,char * buf,uint32_t * len)1299 vs_parse_types(const char *types, char *buf, uint32_t *len)
1300 {
1301 char *p = (char *)types;
1302 char *b = buf;
1303
1304 if (strlen(types) > *len)
1305 return (-1);
1306
1307 if (strchr(VS_TYPES_RULES, *p) == NULL)
1308 return (-1);
1309
1310 (void) memset(buf, 0, *len);
1311
1312 while (*p) {
1313 switch (*p) {
1314 case VS_TYPES_SEP:
1315 if (*(p + 1) &&
1316 (strchr(VS_TYPES_RULES, *(p + 1))) == NULL)
1317 return (-1);
1318 *b = '\0';
1319 break;
1320 case VS_TYPES_ESCAPE:
1321 ++p;
1322 if (*p == VS_TYPES_ESCAPE || *p == VS_TYPES_SEP)
1323 *b = *p;
1324 else
1325 return (-1);
1326 break;
1327 default:
1328 *b = *p;
1329 }
1330 ++p;
1331 ++b;
1332 }
1333
1334 *len = (b - buf) + 1;
1335
1336 return (0);
1337 }
1338
1339
1340 /*
1341 * vs_statistics
1342 */
1343 int
vs_statistics(vs_stats_t * stats)1344 vs_statistics(vs_stats_t *stats)
1345 {
1346 int door_fd, rc = VS_ERR_NONE;
1347 vs_stats_req_t *req;
1348 vs_stats_rsp_t *rsp;
1349 door_arg_t arg;
1350
1351 if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
1352 return (VS_ERR_SYS);
1353
1354 if ((rsp = calloc(1, sizeof (vs_stats_rsp_t))) == NULL) {
1355 free(req);
1356 return (VS_ERR_SYS);
1357 }
1358
1359 if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
1360 free(req);
1361 free(rsp);
1362 return (VS_ERR_DAEMON_COMM);
1363 }
1364
1365 req->vsr_magic = VS_STATS_DOOR_MAGIC;
1366 req->vsr_id = VS_STATS_GET;
1367
1368 arg.data_ptr = (char *)req;
1369 arg.data_size = sizeof (vs_stats_req_t);
1370 arg.desc_ptr = NULL;
1371 arg.desc_num = 0;
1372 arg.rbuf = (char *)rsp;
1373 arg.rsize = sizeof (vs_stats_rsp_t);
1374
1375 rc = vs_door_call(door_fd, &arg);
1376
1377 if ((rc == VS_ERR_NONE) && (rsp->vsr_magic == VS_STATS_DOOR_MAGIC))
1378 *stats = rsp->vsr_stats;
1379 else
1380 rc = VS_ERR_DAEMON_COMM;
1381
1382 (void) close(door_fd);
1383
1384 free(req);
1385 free(rsp);
1386 return (rc);
1387 }
1388
1389
1390 /*
1391 * vs_statistics_reset
1392 */
1393 int
vs_statistics_reset()1394 vs_statistics_reset()
1395 {
1396 int door_fd, rc;
1397 vs_stats_req_t *req;
1398 door_arg_t arg;
1399
1400 /* ensure that caller has authorization to reset stats */
1401 if ((rc = vs_checkauth(VS_VALUE_AUTH)) != VS_ERR_NONE)
1402 return (rc);
1403
1404 if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
1405 return (VS_ERR_SYS);
1406
1407 if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
1408 free(req);
1409 return (VS_ERR_DAEMON_COMM);
1410 }
1411
1412 req->vsr_magic = VS_STATS_DOOR_MAGIC;
1413 req->vsr_id = VS_STATS_RESET;
1414
1415 arg.data_ptr = (char *)req;
1416 arg.data_size = sizeof (vs_stats_req_t);
1417 arg.desc_ptr = NULL;
1418 arg.desc_num = 0;
1419 arg.rbuf = NULL;
1420 arg.rsize = 0;
1421
1422 rc = vs_door_call(door_fd, &arg);
1423
1424 (void) close(door_fd);
1425 free(req);
1426 return (rc);
1427 }
1428
1429 /*
1430 * Door call with retries.
1431 *
1432 * Returns VS_ERR_NONE on success, otherwise VS_ERR_DAEMON_COMM.
1433 */
1434 static int
vs_door_call(int fd,door_arg_t * arg)1435 vs_door_call(int fd, door_arg_t *arg)
1436 {
1437 int rc = -1;
1438 int i;
1439
1440 for (i = 0; i < VS_DOOR_CALL_RETRIES; ++i) {
1441 errno = 0;
1442
1443 if ((rc = door_call(fd, arg)) == 0)
1444 break;
1445
1446 if (errno != EAGAIN && errno != EINTR)
1447 break;
1448 }
1449
1450 return ((rc == 0) ? VS_ERR_NONE : VS_ERR_DAEMON_COMM);
1451 }
1452
1453 /*
1454 * vs_checkauth
1455 */
1456 static int
vs_checkauth(char * auth)1457 vs_checkauth(char *auth)
1458 {
1459 struct passwd *pw;
1460 uid_t uid;
1461
1462 uid = getuid();
1463
1464 if ((pw = getpwuid(uid)) == NULL)
1465 return (VS_ERR_SYS);
1466
1467 if (chkauthattr(auth, pw->pw_name) != 1) {
1468 return (VS_ERR_AUTH);
1469 }
1470
1471 return (VS_ERR_NONE);
1472 }
1473
1474
1475 /*
1476 * vs_props_get_engines
1477 *
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.
1482 *
1483 * Caller is responsible for free'ing the engids allocated herein.
1484 */
1485 static int
vs_props_get_engines(char * engids[],int * count)1486 vs_props_get_engines(char *engids[], int *count)
1487 {
1488 int i, prefix_len;
1489 char pgname[VS_PGNAME_ENGINE_LEN];
1490 vs_scfctx_t vsc;
1491
1492
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);
1499 }
1500
1501 for (i = 0; i < *count; i++)
1502 engids[i] = NULL;
1503
1504 i = 0;
1505 prefix_len = sizeof (VS_PGNAME_ENGINE_PREFIX) - 1;
1506
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);
1513 }
1514
1515 if (strncmp(pgname, VS_PGNAME_ENGINE_PREFIX, prefix_len) == 0) {
1516 if ((engids[i] = strdup(pgname + prefix_len)) != NULL) {
1517 if (++i == *count)
1518 break;
1519 }
1520 }
1521 }
1522 vs_scf_ctx_close(&vsc);
1523
1524 *count = i;
1525 return (VS_ERR_NONE);
1526 }
1527
1528
1529 /*
1530 * vs_scf_pg_count
1531 */
1532 static int
vs_scf_pg_count(void)1533 vs_scf_pg_count(void)
1534 {
1535 int count = 0;
1536 vs_scfctx_t vsc;
1537
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);
1543 return (-1);
1544 }
1545
1546 while (scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)
1547 ++count;
1548
1549 vs_scf_ctx_close(&vsc);
1550
1551 return (count);
1552 }
1553
1554
1555 /*
1556 * vs_engid_to_pgname
1557 *
1558 * To convert an engine id (engid) to a property group name (pgname),
1559 * the engine id is prefixed with VS_PGNAME_ENGINE_PREFIX.
1560 */
1561 static void
vs_engid_to_pgname(const char * engid,char pgname[VS_PGNAME_ENGINE_LEN])1562 vs_engid_to_pgname(const char *engid, char pgname[VS_PGNAME_ENGINE_LEN])
1563 {
1564 (void) snprintf(pgname, VS_PGNAME_ENGINE_LEN, "%s%s",
1565 VS_PGNAME_ENGINE_PREFIX, engid);
1566 }
1567
1568
1569 /*
1570 * vs_strtonum
1571 *
1572 * Converts a size string in the format into an integer.
1573 *
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
1576 * number.
1577 * The size string format is: N[.N][KMGTP][B]
1578 *
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.
1583 *
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").
1587 *
1588 * Returns:
1589 * -1: Failure; errno set to specify the error.
1590 * 0: Success.
1591 */
1592 int
vs_strtonum(const char * value,uint64_t * num)1593 vs_strtonum(const char *value, uint64_t *num)
1594 {
1595 char *end;
1596 int shift;
1597 double fval;
1598
1599 *num = 0;
1600
1601 /* Check to see if this looks like a number. */
1602 if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
1603 errno = EINVAL;
1604 return (-1);
1605 }
1606
1607 /* Rely on stroll() to process the numeric portion. */
1608 errno = 0;
1609 *num = strtoll(value, &end, 10);
1610
1611 /*
1612 * Check for ERANGE, which indicates that the value is too large to
1613 * fit in a 64-bit value.
1614 */
1615 if (errno != 0)
1616 return (-1);
1617
1618 /*
1619 * If we have a decimal value, then do the computation with floating
1620 * point arithmetic. Otherwise, use standard arithmetic.
1621 */
1622 if (*end == '.') {
1623 fval = strtod(value, &end);
1624
1625 if ((shift = vs_strtoshift(end)) == -1)
1626 return (-1); /* errno set */
1627
1628 fval *= pow(2, shift);
1629 if (fval > UINT64_MAX) {
1630 errno = ERANGE;
1631 return (-1);
1632 }
1633
1634 *num = (uint64_t)fval;
1635 } else {
1636 if ((shift = vs_strtoshift(end)) == -1)
1637 return (-1); /* errno set */
1638
1639 /* Check for overflow */
1640 if (shift >= 64 || (*num << shift) >> shift != *num) {
1641 errno = ERANGE;
1642 return (-1);
1643 }
1644
1645 *num <<= shift;
1646 }
1647
1648 return (0);
1649 }
1650
1651
1652 /*
1653 * vs_strtoshift
1654 *
1655 * Converts a unit specifier string into a number of bits that
1656 * a numeric value must be shifted.
1657 *
1658 * Returns:
1659 * -1: Failure; errno set to specify the error.
1660 * >-1: Success; the shift count.
1661 *
1662 */
1663 static int
vs_strtoshift(const char * buf)1664 vs_strtoshift(const char *buf)
1665 {
1666 const char *ends = "BKMGTPEZ";
1667 int i;
1668
1669 if (buf[0] == '\0')
1670 return (0);
1671 for (i = 0; i < strlen(ends); i++) {
1672 if (toupper(buf[0]) == ends[i])
1673 break;
1674 }
1675 if (i == strlen(ends)) {
1676 errno = EINVAL;
1677 return (-1);
1678 }
1679
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')) {
1683 return (10 * i);
1684 }
1685
1686 errno = EINVAL;
1687 return (-1);
1688 }
1689