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 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 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 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 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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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