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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* auditd smf(7)/libscf(3LIB) interface - set and display audit parameters */ 26 #include <audit_scf.h> 27 #include <audit_policy.h> 28 29 /* propvec array must be NULL terminated */ 30 scf_propvec_t prop_vect[MAX_PROPVECS + 1]; 31 32 /* 33 * prt_error() - prt_error_va() wrapper; see prt_error_va() for more contextual 34 * information. Note, that the function disregards errno; if you need to print 35 * out strerror()/errno use directly prt_error_va(). 36 * Inputs - program error format and message. 37 */ 38 /*PRINTFLIKE1*/ 39 static void 40 prt_error(char *fmt, ...) 41 { 42 va_list args; 43 44 errno = 0; 45 46 va_start(args, fmt); 47 prt_error_va(fmt, args); 48 va_end(args); 49 } 50 51 /* 52 * prt_error_va() - prints an error message along with corresponding system 53 * error number. Inputs - program error format and the va_list already prepared 54 * by the preceding functions. 55 * 56 */ 57 /*PRINTFLIKE1*/ 58 void 59 prt_error_va(char *fmt, va_list args) 60 { 61 (void) vfprintf(stderr, fmt, args); 62 (void) fputc('\n', stderr); 63 if (errno) 64 (void) fprintf(stderr, "error: %s(%d)\n", 65 strerror(errno), errno); 66 (void) fflush(stderr); 67 } 68 69 /* 70 * prt_scf_err() - scf_error()/scf_strerror() wrapper. 71 */ 72 static void 73 prt_scf_err(void) 74 { 75 (void) fprintf(stderr, "error: %s\n", scf_strerror(scf_error())); 76 } 77 78 /* 79 * add_prop_vect_scf() - adds vector to the array of vectors later passed to 80 * get_/set_val_scf(). The first argument (vector) points to particular position 81 * in the vector of properties. 82 */ 83 static void 84 add_prop_vect_scf(scf_propvec_t *vector, const char *prop_str, 85 scf_type_t prop_type, void *prop_val_ptr) 86 { 87 vector->pv_prop = prop_str; 88 vector->pv_type = prop_type; 89 vector->pv_ptr = prop_val_ptr; 90 } 91 92 /* 93 * get_val_scf() - get a property values from the audit service 94 * 95 * Arguments: vector = pointers to the head end of array of property vectors 96 * pgroup_str = property group of property in AUDITD_FMRI 97 * 98 */ 99 static boolean_t 100 get_val_scf(scf_propvec_t *vector, char *pgroup_str) 101 { 102 scf_propvec_t *bad_prop_vec = NULL; 103 104 /* 105 * Get the property vector from the editing snapshot (B_FALSE). 106 * For documentation on property vectors see <libscf_priv.h>. 107 */ 108 if (scf_read_propvec(AUDITD_FMRI, pgroup_str, B_FALSE, vector, 109 &bad_prop_vec) != SCF_SUCCESS) { 110 prt_scf_err(); 111 if (bad_prop_vec != NULL) { 112 prt_error(gettext("Reading the %s property in the %s " 113 "property group failed.\n"), bad_prop_vec->pv_prop, 114 pgroup_str); 115 } 116 return (B_FALSE); 117 } 118 119 return (B_TRUE); 120 } 121 122 /* 123 * set_val_scf() - set property values of the audit service. 124 * 125 * arguments: vector = pointers to the head end of array of property vectors 126 * pgroup_str = property group of property in AUDITD_FMRI 127 * 128 */ 129 static boolean_t 130 set_val_scf(scf_propvec_t *vector, char *pgroup_str) 131 { 132 scf_propvec_t *bad_prop_vec = NULL; 133 134 /* for documentation on property vectors see <libscf_priv.h> */ 135 if (scf_write_propvec(AUDITD_FMRI, pgroup_str, vector, 136 &bad_prop_vec) != SCF_SUCCESS) { 137 prt_scf_err(); 138 if (bad_prop_vec != NULL) { 139 prt_error(gettext("Setting the %s property in the %s " 140 "property group failed.\n"), bad_prop_vec->pv_prop, 141 pgroup_str); 142 } 143 return (B_FALSE); 144 } 145 146 return (B_TRUE); 147 } 148 149 /* 150 * free_prop_vect() - deallocate heap memory used for propvect values. 151 */ 152 static void 153 free_prop_vect(void) 154 { 155 scf_propvec_t *prop_vect_ptr; 156 157 prop_vect_ptr = prop_vect; 158 159 while (prop_vect_ptr->pv_prop != NULL) { 160 if (stack_inbounds(prop_vect_ptr->pv_ptr) == 0) { 161 free(prop_vect_ptr->pv_ptr); 162 } 163 prop_vect_ptr++; 164 } 165 } 166 167 /* 168 * chk_prop_vect() - check for prop_vect boundaries and possibly process 169 * (typically) full prop_vect. 170 */ 171 static boolean_t 172 chk_prop_vect(scf_propvec_t **prop_vect_ptr, char *pgrp_str) 173 { 174 if (*prop_vect_ptr < prop_vect || 175 *prop_vect_ptr >= (prop_vect + MAX_PROPVECS)) { 176 DPRINT((dbfp, "prop_vect is full; flushing\n")); 177 if (!set_val_scf(prop_vect, pgrp_str)) { 178 return (B_FALSE); 179 } 180 free_prop_vect(); 181 bzero(prop_vect, sizeof (prop_vect)); 182 *prop_vect_ptr = prop_vect; 183 } 184 return (B_TRUE); 185 } 186 187 /* 188 * get_props_kva_all() - get all properties and fill in the plugin_kva. 189 */ 190 static boolean_t 191 get_props_kva_all(asi_scfhandle_t *handle, asi_scfhandle_iter_t *handle_iter, 192 kva_t **plugin_kva) 193 { 194 char key_buf[PLUGIN_MAXKEY]; 195 char val_buf[PLUGIN_MAXVAL]; 196 char attr_string[PLUGIN_MAXATT]; 197 char attr_buf[PLUGIN_MAXATT]; 198 int len = 0; 199 scf_type_t prop_type; 200 201 attr_string[0] = 0; 202 attr_buf[0] = 0; 203 204 while (scf_iter_next_property(handle_iter->prop, handle->prop) == 1) { 205 if (scf_property_get_name(handle->prop, key_buf, 206 PLUGIN_MAXKEY) == -1) { 207 prt_scf_err(); 208 return (B_FALSE); 209 } 210 211 /* 212 * We do not fully support multi-valued properties. 213 * scf_property_get_value() only supports single-valued 214 * properties. It returns SCF_ERROR_CONSTRAINT_VIOLATED and one 215 * of the property values. The audit service configuration 216 * values are all single-valued properties. The authorizations 217 * to configure and read the audit service properties may be 218 * multi-valued, these may safely be ignored here as not an 219 * error. 220 */ 221 if (scf_property_get_value(handle->prop, 222 handle_iter->prop_val) != 0 && 223 scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) { 224 prt_scf_err(); 225 return (B_FALSE); 226 } 227 if (scf_property_type(handle->prop, &prop_type) == -1) { 228 prt_scf_err(); 229 return (B_FALSE); 230 } 231 switch (prop_type) { 232 case SCF_TYPE_BOOLEAN: { 233 uint8_t pval_bool; 234 if (scf_value_get_boolean(handle_iter->prop_val, 235 &pval_bool) == -1) { 236 prt_scf_err(); 237 return (B_FALSE); 238 } 239 len = snprintf(attr_buf, PLUGIN_MAXATT, "%s=%d;", 240 key_buf, pval_bool); 241 if (len < 0 || len >= PLUGIN_MAXATT) { 242 prt_error(gettext("Too long attribute: %s\n"), 243 key_buf); 244 return (B_FALSE); 245 } 246 if (strlcat(attr_string, attr_buf, PLUGIN_MAXATT) >= 247 PLUGIN_MAXATT) { 248 prt_error(gettext("Too long attribute string: " 249 "%s\n"), key_buf); 250 return (B_FALSE); 251 } 252 break; 253 } 254 case SCF_TYPE_ASTRING: { 255 if (scf_value_get_as_string(handle_iter->prop_val, 256 val_buf, PLUGIN_MAXATT) == -1) { 257 prt_scf_err(); 258 return (B_FALSE); 259 } 260 len = snprintf(attr_buf, PLUGIN_MAXATT, "%s=%s;", 261 key_buf, val_buf); 262 if (len < 0 || len >= PLUGIN_MAXATT) { 263 prt_error(gettext("Too long attribute: %s\n"), 264 key_buf); 265 return (B_FALSE); 266 } 267 if (strlcat(attr_string, attr_buf, PLUGIN_MAXATT) >= 268 PLUGIN_MAXATT) { 269 prt_error(gettext("Too long attribute string: " 270 "%s\n"), key_buf); 271 return (B_FALSE); 272 } 273 break; 274 } 275 case SCF_TYPE_COUNT: { 276 uint64_t pval_count; 277 if (scf_value_get_count(handle_iter->prop_val, 278 &pval_count) == -1) { 279 prt_scf_err(); 280 return (B_FALSE); 281 } 282 len = snprintf(attr_buf, PLUGIN_MAXATT, "%s=%llu;", 283 key_buf, pval_count); 284 if (len < 0 || len >= PLUGIN_MAXATT) { 285 prt_error(gettext("Too long attribute: %s\n"), 286 key_buf); 287 return (B_FALSE); 288 } 289 if (strlcat(attr_string, attr_buf, PLUGIN_MAXATT) >= 290 PLUGIN_MAXATT) { 291 prt_error(gettext("Too long attribute string: " 292 "%s\n"), key_buf); 293 return (B_FALSE); 294 } 295 break; 296 } 297 default: 298 (void) printf("Unsupported value type %s [%d]\n", 299 key_buf, prop_type); 300 break; 301 } 302 } 303 304 if (*attr_string == '\0' || 305 (*plugin_kva = _str2kva(attr_string, "=", ";")) == NULL) { 306 prt_error(gettext("Empty or invalid attribute string.")); 307 return (B_FALSE); 308 } 309 310 return (B_TRUE); 311 } 312 313 /* 314 * get_plugin_kva() - get and save config attributes of given plugin plugin_str 315 * (or all plugins in case plugin_str == NULL) into scf_plugin_kva_node_t. 316 */ 317 static boolean_t 318 get_plugin_kva(asi_scfhandle_t *handle, asi_scfhandle_iter_t *handle_iter, 319 scf_plugin_kva_node_t **plugin_kva_ll, char *plugin_str) 320 { 321 322 scf_plugin_kva_node_t *node = NULL; 323 scf_plugin_kva_node_t *node_prev = NULL; 324 scf_plugin_kva_node_t *node_head = NULL; 325 char plugin_str_tmp[PLUGIN_MAXBUF]; 326 327 bzero(plugin_str_tmp, PLUGIN_MAXBUF); 328 329 if (scf_iter_instance_pgs_typed(handle_iter->pgrp, handle->inst, 330 (const char *)"plugin") == -1) { 331 prt_scf_err(); 332 return (B_FALSE); 333 } 334 335 while (scf_iter_next_pg(handle_iter->pgrp, handle->pgrp) == 1) { 336 if (scf_pg_get_name(handle->pgrp, plugin_str_tmp, 337 PLUGIN_MAXBUF) == -1) { 338 prt_scf_err(); 339 plugin_kva_ll_free(node); 340 return (B_FALSE); 341 } 342 343 if (plugin_str != NULL && 344 strcmp(plugin_str_tmp, plugin_str) != 0) { 345 continue; 346 } 347 348 if ((node = 349 calloc(1, sizeof (scf_plugin_kva_node_t))) == NULL) { 350 prt_error(gettext("No available memory.")); 351 plugin_kva_ll_free(node_prev); 352 return (B_FALSE); 353 } 354 if (node_head == NULL) { 355 node_head = node; 356 } 357 if (node_prev != NULL) { 358 node_prev->next = node; 359 node->prev = node_prev; 360 } 361 node_prev = node; 362 363 (void) strlcat((char *)&(node->plugin_name), plugin_str_tmp, 364 PLUGIN_MAXBUF); 365 366 if (scf_iter_pg_properties(handle_iter->prop, 367 handle->pgrp) != 0) { 368 prt_scf_err(); 369 plugin_kva_ll_free(node); 370 return (B_FALSE); 371 } 372 373 if (!get_props_kva_all(handle, handle_iter, 374 &(node->plugin_kva))) { 375 plugin_kva_ll_free(node); 376 return (B_FALSE); 377 } 378 } 379 380 #if DEBUG 381 { 382 scf_plugin_kva_node_t *node_debug = node_head; 383 char attr_string[PLUGIN_MAXATT]; 384 385 while (node_debug != NULL) { 386 if (_kva2str(node_debug->plugin_kva, attr_string, 387 PLUGIN_MAXATT, "=", ";") == 0) { 388 DPRINT((dbfp, "Found plugin - %s: %s\n", 389 node_debug->plugin_name, attr_string)); 390 } else { 391 DPRINT((dbfp, "Could not get attribute string " 392 "for %s\n", node_debug->plugin_name)); 393 } 394 node_debug = node_debug->prev; 395 } 396 } 397 #endif 398 399 *plugin_kva_ll = node_head; 400 401 return (B_TRUE); 402 } 403 404 /* 405 * scf_free() - free scf handles 406 */ 407 static void 408 scf_free(asi_scfhandle_t *handle) 409 { 410 if (handle == NULL) { 411 return; 412 } 413 414 if (handle->prop != NULL) { 415 scf_property_destroy(handle->prop); 416 } 417 if (handle->pgrp != NULL) { 418 scf_pg_destroy(handle->pgrp); 419 } 420 if (handle->inst != NULL) { 421 scf_instance_destroy(handle->inst); 422 } 423 if (handle->hndl != NULL) { 424 if (scf_handle_unbind(handle->hndl) == -1) { 425 prt_error(gettext("Internal error.")); 426 prt_scf_err(); 427 } 428 scf_handle_destroy(handle->hndl); 429 } 430 } 431 432 /* 433 * scf_init() - initiate scf handles 434 */ 435 static boolean_t 436 scf_init(asi_scfhandle_t *handle) 437 { 438 bzero(handle, sizeof (asi_scfhandle_t)); 439 440 if ((handle->hndl = scf_handle_create(SCF_VERSION)) == NULL || 441 scf_handle_bind(handle->hndl) != 0) { 442 goto err_out; 443 } 444 if ((handle->inst = scf_instance_create(handle->hndl)) == NULL) { 445 goto err_out; 446 } 447 if ((handle->pgrp = scf_pg_create(handle->hndl)) == NULL) { 448 goto err_out; 449 } 450 if ((handle->prop = scf_property_create(handle->hndl)) == NULL) { 451 goto err_out; 452 } 453 454 return (B_TRUE); 455 456 err_out: 457 prt_scf_err(); 458 scf_free(handle); 459 return (B_FALSE); 460 } 461 462 /* 463 * scf_free_iter() - free scf iter handles 464 */ 465 static void 466 scf_free_iter(asi_scfhandle_iter_t *handle_iter) 467 { 468 if (handle_iter == NULL) { 469 return; 470 } 471 472 if (handle_iter->pgrp != NULL) { 473 scf_iter_destroy(handle_iter->pgrp); 474 } 475 if (handle_iter->prop != NULL) { 476 scf_iter_destroy(handle_iter->prop); 477 } 478 if (handle_iter->prop_val != NULL) { 479 scf_value_destroy(handle_iter->prop_val); 480 } 481 } 482 483 /* 484 * scf_init_iter() - initiate scf iter handles 485 */ 486 static boolean_t 487 scf_init_iter(asi_scfhandle_iter_t *handle_iter, 488 asi_scfhandle_t *handle) 489 { 490 bzero(handle_iter, sizeof (asi_scfhandle_iter_t)); 491 492 if ((handle_iter->pgrp = scf_iter_create(handle->hndl)) == NULL) { 493 goto err_out; 494 } 495 if ((handle_iter->prop = scf_iter_create(handle->hndl)) == NULL) { 496 goto err_out; 497 } 498 if ((handle_iter->prop_val = scf_value_create(handle->hndl)) == NULL) { 499 goto err_out; 500 } 501 502 return (B_TRUE); 503 504 err_out: 505 prt_scf_err(); 506 scf_free_iter(handle_iter); 507 return (B_FALSE); 508 } 509 510 /* 511 * chk_policy_context() - does some policy based checks, checks the context 512 * (zone, smf) in which the policy could make some sense. 513 */ 514 static boolean_t 515 chk_policy_context(char *policy_str) 516 { 517 518 /* 519 * "all" and "none" policy flags, since they represent 520 * sub/set of auditing policies, are not stored in the 521 * AUDITD_FMRI service instance configuration. 522 */ 523 DPRINT((dbfp, "Walking policy - %s: ", policy_str)); 524 if (strcmp("all", policy_str) == 0 || 525 strcmp("none", policy_str) == 0) { 526 DPRINT((dbfp, "skipped\n")); 527 return (B_FALSE); 528 } 529 /* 530 * In the local zone (!= GLOBAL_ZONEID) we do not touch 531 * "ahlt" and "perzone" policy flags, since these are 532 * relevant only in the global zone. 533 */ 534 if ((getzoneid() != GLOBAL_ZONEID) && 535 (strcmp("ahlt", policy_str) == 0 || 536 strcmp("perzone", policy_str) == 0)) { 537 DPRINT((dbfp, "skipped\n")); 538 return (B_FALSE); 539 } 540 541 return (B_TRUE); 542 } 543 544 /* 545 * free_static_att_kva() - free hardcoded/static plugin attributes (key/value 546 * pairs) from the kva plugin structure. 547 */ 548 void 549 free_static_att_kva(kva_t *plugin_kva) 550 { 551 _kva_free_value(plugin_kva, PLUGIN_ACTIVE); 552 _kva_free_value(plugin_kva, PLUGIN_PATH); 553 _kva_free_value(plugin_kva, PLUGIN_QSIZE); 554 _kva_free_value(plugin_kva, "read_authorization"); 555 _kva_free_value(plugin_kva, "value_authorization"); 556 } 557 558 559 /* 560 * do_getqctrl_scf() - get the values of qctrl properties of the audit service 561 */ 562 boolean_t 563 do_getqctrl_scf(struct au_qctrl *cval) 564 { 565 scf_propvec_t *prop_vect_ptr; 566 scf_qctrl_t cval_scf; 567 568 bzero(prop_vect, sizeof (prop_vect)); 569 570 prop_vect_ptr = prop_vect; 571 add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QHIWATER, 572 SCF_TYPE_COUNT, &cval_scf.scf_qhiwater); 573 add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QLOWATER, 574 SCF_TYPE_COUNT, &cval_scf.scf_qlowater); 575 add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QBUFSZ, 576 SCF_TYPE_COUNT, &cval_scf.scf_qbufsz); 577 add_prop_vect_scf(prop_vect_ptr, QUEUECTRL_QDELAY, 578 SCF_TYPE_COUNT, &cval_scf.scf_qdelay); 579 580 if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) { 581 return (B_FALSE); 582 } 583 584 cval->aq_hiwater = (size_t)cval_scf.scf_qhiwater; 585 cval->aq_lowater = (size_t)cval_scf.scf_qlowater; 586 cval->aq_bufsz = (size_t)cval_scf.scf_qbufsz; 587 cval->aq_delay = (clock_t)cval_scf.scf_qdelay; 588 589 scf_clean_propvec(prop_vect); 590 591 return (B_TRUE); 592 } 593 594 /* 595 * do_getqbufsz_scf() - get the qbufsz audit service property value 596 */ 597 boolean_t 598 do_getqbufsz_scf(size_t *cval) 599 { 600 uint64_t cval_l; 601 602 bzero(prop_vect, sizeof (prop_vect)); 603 add_prop_vect_scf(prop_vect, QUEUECTRL_QBUFSZ, SCF_TYPE_COUNT, &cval_l); 604 605 if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) { 606 return (B_FALSE); 607 } 608 609 *cval = (size_t)cval_l; 610 611 return (B_TRUE); 612 } 613 614 /* 615 * do_getqdelay_scf() - get the qdelay audit service property value 616 */ 617 boolean_t 618 do_getqdelay_scf(clock_t *cval) 619 { 620 uint64_t cval_l; 621 622 bzero(prop_vect, sizeof (prop_vect)); 623 add_prop_vect_scf(prop_vect, QUEUECTRL_QDELAY, SCF_TYPE_COUNT, &cval_l); 624 625 if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) { 626 return (B_FALSE); 627 } 628 629 *cval = (clock_t)cval_l; 630 631 return (B_TRUE); 632 } 633 634 /* 635 * do_getqhiwater_scf() - get the qhiwater audit service property value 636 */ 637 boolean_t 638 do_getqhiwater_scf(size_t *cval) 639 { 640 uint64_t cval_l; 641 642 bzero(prop_vect, sizeof (prop_vect)); 643 add_prop_vect_scf(prop_vect, QUEUECTRL_QHIWATER, SCF_TYPE_COUNT, 644 &cval_l); 645 646 if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) { 647 return (B_FALSE); 648 } 649 650 *cval = (size_t)cval_l; 651 652 return (B_TRUE); 653 } 654 655 /* 656 * do_getqlowater_scf() - get the qlowater audit service property value 657 */ 658 boolean_t 659 do_getqlowater_scf(size_t *cval) 660 { 661 uint64_t cval_l; 662 663 bzero(prop_vect, sizeof (prop_vect)); 664 add_prop_vect_scf(prop_vect, QUEUECTRL_QLOWATER, SCF_TYPE_COUNT, 665 &cval_l); 666 667 if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) { 668 return (B_FALSE); 669 } 670 671 *cval = (size_t)cval_l; 672 673 return (B_TRUE); 674 } 675 676 /* 677 * do_getpolicy_scf() - get the audit policy flags from service 678 */ 679 boolean_t 680 do_getpolicy_scf(uint32_t *policy_mask) 681 { 682 int i; 683 scf_propvec_t *prop_vect_ptr; 684 char *cur_policy_str; 685 policy_sw_t policy_arr[POLICY_TBL_SZ + 1]; 686 policy_sw_t *policy_arr_ptr; 687 688 prop_vect_ptr = prop_vect; 689 policy_arr_ptr = policy_arr; 690 691 bzero(prop_vect, sizeof (prop_vect)); 692 bzero(policy_arr, sizeof (policy_arr)); 693 694 /* prepare the smf(7) query */ 695 for (i = 0; i < POLICY_TBL_SZ; i++) { 696 697 cur_policy_str = policy_table[i].policy_str; 698 699 /* Do some basic policy dependent checks */ 700 if (!chk_policy_context(cur_policy_str)) { 701 continue; 702 } 703 DPRINT((dbfp, "will be queried\n")); 704 705 add_prop_vect_scf(prop_vect_ptr++, cur_policy_str, 706 SCF_TYPE_BOOLEAN, &policy_arr_ptr->flag); 707 708 policy_arr_ptr->policy = cur_policy_str; 709 policy_arr_ptr++; 710 711 } 712 if (!get_val_scf(prop_vect, ASI_PGROUP_POLICY)) { 713 return (B_FALSE); 714 } 715 716 /* set the policy mask */ 717 policy_arr_ptr = policy_arr; 718 *policy_mask = 0; 719 while (policy_arr_ptr->policy != NULL) { 720 if (policy_arr_ptr->flag) { 721 *policy_mask |= get_policy(policy_arr_ptr->policy); 722 } 723 policy_arr_ptr++; 724 } 725 726 return (B_TRUE); 727 } 728 729 /* 730 * do_setpolicy_scf() - sets the policy flags in audit service configuration 731 */ 732 boolean_t 733 do_setpolicy_scf(uint32_t policy) 734 { 735 int i; 736 char *cur_policy_str; 737 scf_propvec_t *prop_vect_ptr; 738 boolean_t bool_arr[POLICY_TBL_SZ]; 739 boolean_t *bool_arr_ptr; 740 741 prop_vect_ptr = prop_vect; 742 bool_arr_ptr = bool_arr; 743 744 bzero(prop_vect, sizeof (prop_vect)); 745 bzero(bool_arr, sizeof (bool_arr)); 746 747 for (i = 0; i < POLICY_TBL_SZ; i++) { 748 749 cur_policy_str = policy_table[i].policy_str; 750 751 /* Do some basic policy dependent checks */ 752 if (!chk_policy_context(cur_policy_str)) { 753 continue; 754 } 755 756 if (policy_table[i].policy_mask & policy) { 757 *bool_arr_ptr = B_TRUE; 758 } else { 759 *bool_arr_ptr = B_FALSE; 760 } 761 762 DPRINT((dbfp, "%s%s\n", (*bool_arr_ptr == B_TRUE ? "+" : "-"), 763 cur_policy_str)); 764 765 add_prop_vect_scf(prop_vect_ptr++, cur_policy_str, 766 SCF_TYPE_BOOLEAN, bool_arr_ptr++); 767 768 } 769 770 return (set_val_scf(prop_vect, ASI_PGROUP_POLICY)); 771 } 772 773 /* 774 * do_setqctrl_scf() - set the values of qctrl properties of the audit service 775 */ 776 boolean_t 777 do_setqctrl_scf(struct au_qctrl *cval) 778 { 779 scf_propvec_t *prop_vect_ptr; 780 scf_qctrl_t cval_scf; 781 782 if (!CHK_BDRY_QHIWATER(cval->aq_lowater, cval->aq_hiwater) && 783 cval->aq_hiwater != 0) { 784 (void) printf(gettext("Specified audit queue hiwater mark is " 785 "outside of allowed boundaries.\n")); 786 return (B_FALSE); 787 } 788 if (!CHK_BDRY_QLOWATER(cval->aq_lowater, cval->aq_hiwater) && 789 cval->aq_lowater != 0) { 790 (void) printf(gettext("Specified audit queue lowater mark is " 791 "outside of allowed boundaries.\n")); 792 return (B_FALSE); 793 } 794 if (!CHK_BDRY_QBUFSZ(cval->aq_bufsz) && cval->aq_bufsz != 0) { 795 (void) printf(gettext("Specified audit queue buffer size is " 796 "outside of allowed boundaries.\n")); 797 return (B_FALSE); 798 } 799 if (!CHK_BDRY_QDELAY(cval->aq_delay) && cval->aq_delay != 0) { 800 (void) printf(gettext("Specified audit queue delay is " 801 "outside of allowed boundaries.\n")); 802 return (B_FALSE); 803 } 804 805 cval_scf.scf_qhiwater = (uint64_t)cval->aq_hiwater; 806 cval_scf.scf_qlowater = (uint64_t)cval->aq_lowater; 807 cval_scf.scf_qbufsz = (uint64_t)cval->aq_bufsz; 808 cval_scf.scf_qdelay = (uint64_t)cval->aq_delay; 809 810 bzero(prop_vect, sizeof (prop_vect)); 811 812 prop_vect_ptr = prop_vect; 813 add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QHIWATER, SCF_TYPE_COUNT, 814 &cval_scf.scf_qhiwater); 815 add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QLOWATER, SCF_TYPE_COUNT, 816 &cval_scf.scf_qlowater); 817 add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QBUFSZ, SCF_TYPE_COUNT, 818 &cval_scf.scf_qbufsz); 819 add_prop_vect_scf(prop_vect_ptr, QUEUECTRL_QDELAY, SCF_TYPE_COUNT, 820 &cval_scf.scf_qdelay); 821 822 return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)); 823 } 824 825 /* 826 * do_setqbufsz_scf() - set the qbufsz property value of the audit service 827 */ 828 boolean_t 829 do_setqbufsz_scf(size_t *cval) 830 { 831 uint64_t cval_l; 832 833 if (!CHK_BDRY_QBUFSZ(*cval) && *cval != 0) { 834 (void) printf(gettext("Specified audit queue buffer size is " 835 "outside of allowed boundaries.\n")); 836 return (B_FALSE); 837 } 838 839 cval_l = (uint64_t)*cval; 840 841 bzero(prop_vect, sizeof (prop_vect)); 842 add_prop_vect_scf(prop_vect, QUEUECTRL_QBUFSZ, SCF_TYPE_COUNT, &cval_l); 843 844 return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)); 845 } 846 847 /* 848 * do_setqdelay_scf() - set the qdelay property value of the audit service 849 */ 850 boolean_t 851 do_setqdelay_scf(clock_t *cval) 852 { 853 uint64_t cval_l; 854 855 if (!CHK_BDRY_QDELAY(*cval) && *cval != 0) { 856 (void) printf(gettext("Specified audit queue delay is " 857 "outside of allowed boundaries.\n")); 858 return (B_FALSE); 859 } 860 861 cval_l = (uint64_t)*cval; 862 863 bzero(prop_vect, sizeof (prop_vect)); 864 add_prop_vect_scf(prop_vect, QUEUECTRL_QDELAY, SCF_TYPE_COUNT, &cval_l); 865 866 return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)); 867 } 868 869 /* 870 * do_setqhiwater_scf() - set the qhiwater property value of the audit service 871 */ 872 boolean_t 873 do_setqhiwater_scf(size_t *cval) 874 { 875 uint64_t cval_l; 876 size_t cval_lowater; 877 878 if (!do_getqlowater_scf(&cval_lowater)) { 879 (void) printf(gettext("Could not get configured value of " 880 "queue lowater mark.\n")); 881 return (B_FALSE); 882 } 883 if (cval_lowater == 0) { 884 cval_lowater = AQ_MINLOW; 885 } 886 if (!CHK_BDRY_QHIWATER(cval_lowater, *cval) && *cval != 0) { 887 (void) printf(gettext("Specified audit queue hiwater mark is " 888 "outside of allowed boundaries.\n")); 889 return (B_FALSE); 890 } 891 892 cval_l = (uint64_t)*cval; 893 894 bzero(prop_vect, sizeof (prop_vect)); 895 add_prop_vect_scf(prop_vect, QUEUECTRL_QHIWATER, SCF_TYPE_COUNT, 896 &cval_l); 897 898 return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)); 899 } 900 901 /* 902 * do_setqlowater_scf() - set the qlowater property value of the audit service 903 */ 904 boolean_t 905 do_setqlowater_scf(size_t *cval) 906 { 907 uint64_t cval_l; 908 size_t cval_hiwater; 909 910 if (!do_getqhiwater_scf(&cval_hiwater)) { 911 (void) printf(gettext("Could not get configured value of " 912 "queue hiwater mark.\n")); 913 return (B_FALSE); 914 } 915 if (cval_hiwater == 0) { 916 cval_hiwater = AQ_MAXHIGH; 917 } 918 if (!CHK_BDRY_QLOWATER(*cval, cval_hiwater) && *cval != 0) { 919 (void) printf(gettext("Specified audit queue lowater mark is " 920 "outside of allowed boundaries.\n")); 921 return (B_FALSE); 922 } 923 924 cval_l = (uint64_t)*cval; 925 926 bzero(prop_vect, sizeof (prop_vect)); 927 add_prop_vect_scf(prop_vect, QUEUECTRL_QLOWATER, SCF_TYPE_COUNT, 928 &cval_l); 929 930 return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)); 931 } 932 933 /* 934 * do_getflags_scf() - get the audit attributable flags from service 935 */ 936 boolean_t 937 do_getflags_scf(char **flags) 938 { 939 bzero(prop_vect, sizeof (prop_vect)); 940 add_prop_vect_scf(prop_vect, PRESELECTION_FLAGS, SCF_TYPE_ASTRING, 941 flags); 942 943 if (!get_val_scf(prop_vect, ASI_PGROUP_PRESELECTION)) { 944 return (B_FALSE); 945 } 946 947 return (B_TRUE); 948 } 949 950 /* 951 * do_getnaflags_scf() - get the audit non-attributable flags from service 952 */ 953 boolean_t 954 do_getnaflags_scf(char **naflags) 955 { 956 bzero(prop_vect, sizeof (prop_vect)); 957 add_prop_vect_scf(prop_vect, PRESELECTION_NAFLAGS, SCF_TYPE_ASTRING, 958 naflags); 959 960 if (!get_val_scf(prop_vect, ASI_PGROUP_PRESELECTION)) { 961 return (B_FALSE); 962 } 963 964 return (B_TRUE); 965 } 966 967 /* 968 * do_setflags_scf() - set the attributable mask property value of the audit 969 * service 970 */ 971 boolean_t 972 do_setflags_scf(char *flags) 973 { 974 bzero(prop_vect, sizeof (prop_vect)); 975 add_prop_vect_scf(prop_vect, PRESELECTION_FLAGS, SCF_TYPE_ASTRING, 976 flags); 977 978 return (set_val_scf(prop_vect, ASI_PGROUP_PRESELECTION)); 979 } 980 981 /* 982 * do_setnaflags_scf() - set the attributable mask property value of the audit 983 * service 984 */ 985 boolean_t 986 do_setnaflags_scf(char *naflags) 987 { 988 bzero(prop_vect, sizeof (prop_vect)); 989 add_prop_vect_scf(prop_vect, PRESELECTION_NAFLAGS, SCF_TYPE_ASTRING, 990 naflags); 991 992 return (set_val_scf(prop_vect, ASI_PGROUP_PRESELECTION)); 993 } 994 995 /* 996 * plugin_avail_scf() - look for the plugin in the audit service configuration 997 */ 998 boolean_t 999 plugin_avail_scf(const char *plugin_str) 1000 { 1001 scf_simple_handle_t *sh; 1002 1003 if (plugin_str == NULL || *plugin_str == '\0') { 1004 return (B_FALSE); 1005 } 1006 1007 if ((sh = scf_general_pg_setup(AUDITD_FMRI, plugin_str)) == NULL) { 1008 DPRINT((dbfp, "No such plugin found: %s (%s)\n", plugin_str, 1009 scf_strerror(scf_error()))); 1010 return (B_FALSE); 1011 } 1012 1013 scf_simple_handle_destroy(sh); 1014 return (B_TRUE); 1015 } 1016 1017 /* 1018 * do_getpluginconfig_scf() - get plugin configuration from the audit service 1019 * configuration. 1020 */ 1021 boolean_t 1022 do_getpluginconfig_scf(char *plugin_str, scf_plugin_kva_node_t **plugin_kva_ll) 1023 { 1024 1025 char *asi_fmri; 1026 asi_scfhandle_t handle; 1027 asi_scfhandle_iter_t handle_iter; 1028 boolean_t plugin_all = B_FALSE; 1029 boolean_t rv = B_TRUE; 1030 1031 if (plugin_str == NULL || *plugin_str == '\0') { 1032 if (asprintf(&asi_fmri, "%s", AUDITD_FMRI) == -1) { 1033 prt_error(gettext("Out of memory.")); 1034 return (B_FALSE); 1035 } 1036 plugin_all = B_TRUE; 1037 } else { 1038 if (asprintf(&asi_fmri, "%s%s%s", AUDITD_FMRI, 1039 SCF_FMRI_PROPERTYGRP_PREFIX, plugin_str) == -1) { 1040 prt_error(gettext("Out of memory.")); 1041 return (B_FALSE); 1042 } 1043 } 1044 DPRINT((dbfp, "%s will be decoded\n", asi_fmri)); 1045 1046 if (!scf_init(&handle)) { 1047 prt_error(gettext("Unable to initialize scf handles.")); 1048 free(asi_fmri); 1049 return (B_FALSE); 1050 } 1051 1052 if (scf_handle_decode_fmri(handle.hndl, asi_fmri, NULL, NULL, 1053 handle.inst, plugin_all ? NULL : handle.pgrp, NULL, 1054 SCF_DECODE_FMRI_EXACT) == -1) { 1055 prt_scf_err(); 1056 scf_free(&handle); 1057 free(asi_fmri); 1058 return (B_FALSE); 1059 } 1060 1061 if (!scf_init_iter(&handle_iter, &handle)) { 1062 prt_error(gettext("Unable to initialize scf iter handles.")); 1063 scf_free(&handle); 1064 free(asi_fmri); 1065 return (B_FALSE); 1066 } 1067 1068 1069 if (plugin_all) { 1070 rv = get_plugin_kva(&handle, &handle_iter, plugin_kva_ll, NULL); 1071 } else { 1072 rv = get_plugin_kva(&handle, &handle_iter, plugin_kva_ll, 1073 plugin_str); 1074 } 1075 1076 scf_free(&handle); 1077 scf_free_iter(&handle_iter); 1078 free(asi_fmri); 1079 return (rv); 1080 } 1081 1082 /* 1083 * do_setpluginconfig_scf() - set plugin configuration in the audit service 1084 * configuration. 1085 */ 1086 boolean_t 1087 do_setpluginconfig_scf(char *plugin_str, boolean_t plugin_state, 1088 char *plugin_att, int plugin_qsize) 1089 { 1090 kva_t *plugin_att_kva = NULL; 1091 char *plugin_att_ptr = plugin_att; 1092 char *plugin_att_clr_ptr = plugin_att; 1093 scf_simple_prop_t *plugin_prop; 1094 scf_type_t plugin_prop_type; 1095 scf_propvec_t *prop_vect_ptr; 1096 int cnt = 0; 1097 kv_t *data; 1098 boolean_t rval = B_TRUE; 1099 uint64_t plugin_qsize_l = (uint64_t)plugin_qsize; 1100 1101 DPRINT((dbfp, "Auditd plugin configuration to be set:\n\tplugin=%s\n\t" 1102 "state=%d (%s)\n\tattributes=%s\n\tqsize=%d%s\n", plugin_str, 1103 plugin_state, plugin_state == B_TRUE ? "active" : "inactive", 1104 plugin_att == NULL ? " (unspecified)" : plugin_att, 1105 plugin_qsize, plugin_qsize == -1 ? " (unspecified)" : "")); 1106 1107 bzero(prop_vect, sizeof (prop_vect)); 1108 prop_vect_ptr = prop_vect; 1109 1110 if (plugin_att != NULL) { 1111 1112 /* get rid of white-space chars */ 1113 if (*plugin_att_ptr != '\0') { 1114 while (*plugin_att_ptr != '\0') { 1115 if (isspace(*plugin_att_ptr) == 0) { 1116 *plugin_att_clr_ptr++ = *plugin_att_ptr; 1117 } 1118 plugin_att_ptr++; 1119 } 1120 *plugin_att_clr_ptr = '\0'; 1121 } 1122 DPRINT((dbfp, "attributes (no white-space): %s\n", plugin_att)); 1123 1124 /* allow empty plugin_att */ 1125 if (*plugin_att == '\0') { 1126 cnt = 0; 1127 data = NULL; 1128 } else { 1129 plugin_att_kva = _str2kva(plugin_att, "=", ";"); 1130 if (plugin_att_kva == NULL) { 1131 prt_error(gettext("Could not parse plugin " 1132 "attributes.")); 1133 return (B_FALSE); 1134 } 1135 1136 free_static_att_kva(plugin_att_kva); 1137 cnt = plugin_att_kva->length; 1138 data = plugin_att_kva->data; 1139 } 1140 } 1141 1142 /* set state */ 1143 add_prop_vect_scf(prop_vect_ptr++, PLUGIN_ACTIVE, SCF_TYPE_BOOLEAN, 1144 &plugin_state); 1145 DPRINT((dbfp, "Prepared active -> %d\n", plugin_state)); 1146 1147 /* set attributes */ 1148 while (cnt) { 1149 if (data->value == NULL) { 1150 cnt--; 1151 data++; 1152 continue; 1153 } 1154 if (!chk_prop_vect(&prop_vect_ptr, plugin_str)) { 1155 rval = B_FALSE; 1156 goto err_out; 1157 } 1158 1159 if ((plugin_prop = scf_simple_prop_get(NULL, 1160 AUDITD_FMRI, plugin_str, data->key)) == NULL) { 1161 prt_error(gettext("Could not get configuration for " 1162 "attribute: %s"), data->key); 1163 prt_scf_err(); 1164 rval = B_FALSE; 1165 goto err_out; 1166 } 1167 if ((plugin_prop_type = scf_simple_prop_type(plugin_prop)) 1168 == -1) { 1169 prt_error(gettext("Could not get property type: %s"), 1170 data->key); 1171 prt_scf_err(); 1172 rval = B_FALSE; 1173 goto err_out; 1174 } 1175 1176 switch (plugin_prop_type) { 1177 case SCF_TYPE_BOOLEAN: { 1178 uint8_t *pval_bool; 1179 pval_bool = (uint8_t *)malloc(sizeof (uint8_t)); 1180 if (pval_bool == NULL) { 1181 prt_error(gettext("No free memory available.")); 1182 rval = B_FALSE; 1183 goto err_out; 1184 } 1185 *pval_bool = (uint8_t)atoi(data->value); 1186 add_prop_vect_scf(prop_vect_ptr++, data->key, 1187 SCF_TYPE_BOOLEAN, pval_bool); 1188 break; 1189 } 1190 case SCF_TYPE_ASTRING: { 1191 char *pval_str; 1192 if ((pval_str = strdup(data->value)) == NULL) { 1193 prt_error(gettext("No free memory available.")); 1194 rval = B_FALSE; 1195 goto err_out; 1196 } 1197 add_prop_vect_scf(prop_vect_ptr++, data->key, 1198 SCF_TYPE_ASTRING, pval_str); 1199 break; 1200 } 1201 case SCF_TYPE_COUNT: { 1202 uint64_t *pval_count; 1203 pval_count = (uint64_t *)malloc(sizeof (uint64_t)); 1204 if (pval_count == NULL) { 1205 prt_error(gettext("No free memory available.")); 1206 rval = B_FALSE; 1207 goto err_out; 1208 } 1209 *pval_count = (uint64_t)atoll(data->value); 1210 add_prop_vect_scf(prop_vect_ptr++, data->key, 1211 SCF_TYPE_COUNT, pval_count); 1212 break; 1213 } 1214 default: 1215 prt_error(gettext("Unsupported property type: %s (%d)"), 1216 data->key, plugin_prop_type); 1217 break; 1218 } 1219 1220 DPRINT((dbfp, "Prepared %s -> %s\n", data->key, data->value)); 1221 scf_simple_prop_free(plugin_prop); 1222 data++; 1223 cnt--; 1224 } 1225 1226 if (!chk_prop_vect(&prop_vect_ptr, plugin_str)) { 1227 rval = B_FALSE; 1228 goto err_out; 1229 } 1230 1231 /* set qsize */ 1232 if (plugin_qsize != -1) { 1233 add_prop_vect_scf(prop_vect_ptr, PLUGIN_QSIZE, SCF_TYPE_COUNT, 1234 &plugin_qsize_l); 1235 DPRINT((dbfp, "Prepared qsize -> %d\n", plugin_qsize)); 1236 } 1237 1238 if (!set_val_scf(prop_vect, plugin_str)) { 1239 rval = B_FALSE; 1240 } 1241 1242 err_out: 1243 free_prop_vect(); 1244 _kva_free(plugin_att_kva); 1245 return (rval); 1246 } 1247 1248 /* 1249 * plugin_kva_ll_free() - free the memory used by plugin kva linked list. 1250 */ 1251 void 1252 plugin_kva_ll_free(scf_plugin_kva_node_t *node) 1253 { 1254 scf_plugin_kva_node_t *node_next; 1255 1256 if (node == NULL) { 1257 return; 1258 } 1259 1260 while (node->prev != NULL) { 1261 node = node->prev; 1262 } 1263 while (node != NULL) { 1264 _kva_free(node->plugin_kva); 1265 node_next = node->next; 1266 free(node); 1267 node = node_next; 1268 } 1269 } 1270 1271 /* 1272 * get_policy() - get policy mask entry 1273 */ 1274 uint32_t 1275 get_policy(char *policy) 1276 { 1277 int i; 1278 1279 for (i = 0; i < POLICY_TBL_SZ; i++) { 1280 if (strcasecmp(policy, policy_table[i].policy_str) == 0) { 1281 return (policy_table[i].policy_mask); 1282 } 1283 } 1284 1285 return (0); 1286 } 1287