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