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