1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 26 */ 27 28 /* helper functions for using libscf with CIFS */ 29 30 #include <libscf.h> 31 #include <string.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <syslog.h> 35 #include <errno.h> 36 #include <libintl.h> 37 #include <assert.h> 38 #include <strings.h> 39 40 #include <uuid/uuid.h> 41 #include <sys/param.h> 42 43 #include <smbsrv/libsmb.h> 44 45 /* 46 * smb_smf_scf_log_error(msg) 47 * Logs error messages from scf API's 48 */ 49 static void 50 smb_smf_scf_log_error(char *msg) 51 { 52 if (msg == NULL) 53 msg = "SMBD SMF problem"; 54 55 syslog(LOG_ERR, " %s: %s", msg, scf_strerror(scf_error())); 56 } 57 58 /* 59 * smb_smf_create_service_pgroup(handle, pgroup) 60 * 61 * create a new property group at service level. 62 */ 63 int 64 smb_smf_create_service_pgroup(smb_scfhandle_t *handle, char *pgroup) 65 { 66 int ret = SMBD_SMF_OK; 67 int err; 68 69 if (handle == NULL) 70 return (SMBD_SMF_SYSTEM_ERR); 71 72 /* 73 * only create a handle if it doesn't exist. It is ok to exist 74 * since the pg handle will be set as a side effect. 75 */ 76 if (handle->scf_pg == NULL) 77 if ((handle->scf_pg = 78 scf_pg_create(handle->scf_handle)) == NULL) 79 return (SMBD_SMF_SYSTEM_ERR); 80 81 /* 82 * if the pgroup exists, we are done. If it doesn't, then we 83 * need to actually add one to the service instance. 84 */ 85 if (scf_service_get_pg(handle->scf_service, 86 pgroup, handle->scf_pg) != 0) { 87 /* doesn't exist so create one */ 88 if (scf_service_add_pg(handle->scf_service, pgroup, 89 SCF_GROUP_APPLICATION, 0, handle->scf_pg) != 0) { 90 err = scf_error(); 91 if (err != SCF_ERROR_NONE) 92 smb_smf_scf_log_error(NULL); 93 switch (err) { 94 case SCF_ERROR_PERMISSION_DENIED: 95 ret = SMBD_SMF_NO_PERMISSION; 96 break; 97 default: 98 ret = SMBD_SMF_SYSTEM_ERR; 99 break; 100 } 101 } 102 } 103 return (ret); 104 } 105 106 /* 107 * Start transaction on current pg in handle. 108 * The pg could be service or instance level. 109 * Must be called after pg handle is obtained 110 * from create or get. 111 */ 112 int 113 smb_smf_start_transaction(smb_scfhandle_t *handle) 114 { 115 int ret = SMBD_SMF_OK; 116 117 if (!handle || (!handle->scf_pg)) 118 return (SMBD_SMF_SYSTEM_ERR); 119 120 /* 121 * lookup the property group and create it if it doesn't already 122 * exist. 123 */ 124 if (handle->scf_state == SCH_STATE_INIT) { 125 if (ret == SMBD_SMF_OK) { 126 handle->scf_trans = 127 scf_transaction_create(handle->scf_handle); 128 if (handle->scf_trans != NULL) { 129 if (scf_transaction_start(handle->scf_trans, 130 handle->scf_pg) != 0) { 131 ret = SMBD_SMF_SYSTEM_ERR; 132 scf_transaction_destroy( 133 handle->scf_trans); 134 handle->scf_trans = NULL; 135 } 136 } else { 137 ret = SMBD_SMF_SYSTEM_ERR; 138 } 139 } 140 } 141 if (ret == SMBD_SMF_SYSTEM_ERR && 142 scf_error() == SCF_ERROR_PERMISSION_DENIED) 143 ret = SMBD_SMF_NO_PERMISSION; 144 145 return (ret); 146 } 147 148 /* 149 * smb_smf_end_transaction(handle) 150 * 151 * Commit the changes that were added to the transaction in the 152 * handle. Do all necessary cleanup. 153 */ 154 int 155 smb_smf_end_transaction(smb_scfhandle_t *handle) 156 { 157 int ret = SMBD_SMF_OK; 158 int rc; 159 160 if (handle == NULL) 161 return (SMBD_SMF_SYSTEM_ERR); 162 163 if (handle->scf_trans == NULL) { 164 ret = SMBD_SMF_SYSTEM_ERR; 165 } else { 166 rc = scf_transaction_commit(handle->scf_trans); 167 if (rc == 1) { 168 ret = SMBD_SMF_OK; 169 } else if (rc == 0) { 170 ret = SMBD_SMF_INVALID_ARG; 171 smb_smf_scf_log_error("Failed to commit, old pg: " 172 "transaction: %s"); 173 } else { 174 ret = SMBD_SMF_SYSTEM_ERR; 175 smb_smf_scf_log_error("Failed to commit, error: " 176 "transaction: %s"); 177 } 178 scf_transaction_destroy_children(handle->scf_trans); 179 scf_transaction_destroy(handle->scf_trans); 180 handle->scf_trans = NULL; 181 } 182 return (ret); 183 } 184 185 /* 186 * Sets string property in current pg 187 */ 188 int 189 smb_smf_set_string_property(smb_scfhandle_t *handle, 190 char *propname, char *valstr) 191 { 192 int ret = SMBD_SMF_OK; 193 scf_value_t *value = NULL; 194 scf_transaction_entry_t *entry = NULL; 195 196 if (handle == NULL) 197 return (SMBD_SMF_SYSTEM_ERR); 198 199 /* 200 * properties must be set in transactions and don't take 201 * effect until the transaction has been ended/committed. 202 */ 203 value = scf_value_create(handle->scf_handle); 204 entry = scf_entry_create(handle->scf_handle); 205 if (value != NULL && entry != NULL) { 206 if (scf_transaction_property_change(handle->scf_trans, entry, 207 propname, SCF_TYPE_ASTRING) == 0 || 208 scf_transaction_property_new(handle->scf_trans, entry, 209 propname, SCF_TYPE_ASTRING) == 0) { 210 if (scf_value_set_astring(value, valstr) == 0) { 211 if (scf_entry_add_value(entry, value) != 0) { 212 ret = SMBD_SMF_SYSTEM_ERR; 213 scf_value_destroy(value); 214 } 215 /* the value is in the transaction */ 216 value = NULL; 217 } else { 218 /* value couldn't be constructed */ 219 ret = SMBD_SMF_SYSTEM_ERR; 220 } 221 /* the entry is in the transaction */ 222 entry = NULL; 223 } else { 224 ret = SMBD_SMF_SYSTEM_ERR; 225 } 226 } else { 227 ret = SMBD_SMF_SYSTEM_ERR; 228 } 229 if (ret == SMBD_SMF_SYSTEM_ERR) { 230 switch (scf_error()) { 231 case SCF_ERROR_PERMISSION_DENIED: 232 ret = SMBD_SMF_NO_PERMISSION; 233 break; 234 } 235 } 236 237 /* 238 * cleanup if there were any errors that didn't leave these 239 * values where they would be cleaned up later. 240 */ 241 if (value != NULL) 242 scf_value_destroy(value); 243 if (entry != NULL) 244 scf_entry_destroy(entry); 245 return (ret); 246 } 247 248 /* 249 * Gets string property value.upto sz size. 250 * Caller is responsible to have enough memory allocated. 251 */ 252 int 253 smb_smf_get_string_property(smb_scfhandle_t *handle, char *propname, 254 char *valstr, size_t sz) 255 { 256 int ret = SMBD_SMF_OK; 257 scf_value_t *value; 258 scf_property_t *prop; 259 260 if (handle == NULL) 261 return (SMBD_SMF_SYSTEM_ERR); 262 263 value = scf_value_create(handle->scf_handle); 264 prop = scf_property_create(handle->scf_handle); 265 if (value && prop && 266 (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { 267 if (scf_property_get_value(prop, value) == 0) { 268 if (scf_value_get_astring(value, valstr, sz) < 0) { 269 ret = SMBD_SMF_SYSTEM_ERR; 270 } 271 } else { 272 ret = SMBD_SMF_SYSTEM_ERR; 273 } 274 } else { 275 ret = SMBD_SMF_SYSTEM_ERR; 276 } 277 if (value != NULL) 278 scf_value_destroy(value); 279 if (prop != NULL) 280 scf_property_destroy(prop); 281 return (ret); 282 } 283 284 /* 285 * Set integer value of property. 286 * The value is returned as int64_t value 287 * Caller ensures appropriate translation. 288 */ 289 int 290 smb_smf_set_integer_property(smb_scfhandle_t *handle, char *propname, 291 int64_t valint) 292 { 293 int ret = SMBD_SMF_OK; 294 scf_value_t *value = NULL; 295 scf_transaction_entry_t *entry = NULL; 296 297 if (handle == NULL) 298 return (SMBD_SMF_SYSTEM_ERR); 299 300 /* 301 * properties must be set in transactions and don't take 302 * effect until the transaction has been ended/committed. 303 */ 304 value = scf_value_create(handle->scf_handle); 305 entry = scf_entry_create(handle->scf_handle); 306 if (value != NULL && entry != NULL) { 307 if (scf_transaction_property_change(handle->scf_trans, entry, 308 propname, SCF_TYPE_INTEGER) == 0 || 309 scf_transaction_property_new(handle->scf_trans, entry, 310 propname, SCF_TYPE_INTEGER) == 0) { 311 scf_value_set_integer(value, valint); 312 if (scf_entry_add_value(entry, value) != 0) { 313 ret = SMBD_SMF_SYSTEM_ERR; 314 scf_value_destroy(value); 315 } 316 /* the value is in the transaction */ 317 value = NULL; 318 } 319 /* the entry is in the transaction */ 320 entry = NULL; 321 } else { 322 ret = SMBD_SMF_SYSTEM_ERR; 323 } 324 if (ret == SMBD_SMF_SYSTEM_ERR) { 325 switch (scf_error()) { 326 case SCF_ERROR_PERMISSION_DENIED: 327 ret = SMBD_SMF_NO_PERMISSION; 328 break; 329 } 330 } 331 /* 332 * cleanup if there were any errors that didn't leave these 333 * values where they would be cleaned up later. 334 */ 335 if (value != NULL) 336 scf_value_destroy(value); 337 if (entry != NULL) 338 scf_entry_destroy(entry); 339 return (ret); 340 } 341 342 /* 343 * Gets integer property value. 344 * Caller is responsible to have enough memory allocated. 345 */ 346 int 347 smb_smf_get_integer_property(smb_scfhandle_t *handle, char *propname, 348 int64_t *valint) 349 { 350 int ret = SMBD_SMF_OK; 351 scf_value_t *value = NULL; 352 scf_property_t *prop = NULL; 353 354 if (handle == NULL) 355 return (SMBD_SMF_SYSTEM_ERR); 356 357 value = scf_value_create(handle->scf_handle); 358 prop = scf_property_create(handle->scf_handle); 359 if ((prop) && (value) && 360 (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { 361 if (scf_property_get_value(prop, value) == 0) { 362 if (scf_value_get_integer(value, 363 valint) != 0) { 364 ret = SMBD_SMF_SYSTEM_ERR; 365 } 366 } else { 367 ret = SMBD_SMF_SYSTEM_ERR; 368 } 369 } else { 370 ret = SMBD_SMF_SYSTEM_ERR; 371 } 372 if (value != NULL) 373 scf_value_destroy(value); 374 if (prop != NULL) 375 scf_property_destroy(prop); 376 return (ret); 377 } 378 379 /* 380 * Set boolean value of property. 381 * The value is returned as int64_t value 382 * Caller ensures appropriate translation. 383 */ 384 int 385 smb_smf_set_boolean_property(smb_scfhandle_t *handle, char *propname, 386 uint8_t valbool) 387 { 388 int ret = SMBD_SMF_OK; 389 scf_value_t *value = NULL; 390 scf_transaction_entry_t *entry = NULL; 391 392 if (handle == NULL) 393 return (SMBD_SMF_SYSTEM_ERR); 394 395 /* 396 * properties must be set in transactions and don't take 397 * effect until the transaction has been ended/committed. 398 */ 399 value = scf_value_create(handle->scf_handle); 400 entry = scf_entry_create(handle->scf_handle); 401 if (value != NULL && entry != NULL) { 402 if (scf_transaction_property_change(handle->scf_trans, entry, 403 propname, SCF_TYPE_BOOLEAN) == 0 || 404 scf_transaction_property_new(handle->scf_trans, entry, 405 propname, SCF_TYPE_BOOLEAN) == 0) { 406 scf_value_set_boolean(value, valbool); 407 if (scf_entry_add_value(entry, value) != 0) { 408 ret = SMBD_SMF_SYSTEM_ERR; 409 scf_value_destroy(value); 410 } 411 /* the value is in the transaction */ 412 value = NULL; 413 } 414 /* the entry is in the transaction */ 415 entry = NULL; 416 } else { 417 ret = SMBD_SMF_SYSTEM_ERR; 418 } 419 if (ret == SMBD_SMF_SYSTEM_ERR) { 420 switch (scf_error()) { 421 case SCF_ERROR_PERMISSION_DENIED: 422 ret = SMBD_SMF_NO_PERMISSION; 423 break; 424 } 425 } 426 /* 427 * cleanup if there were any errors that didn't leave these 428 * values where they would be cleaned up later. 429 */ 430 if (value != NULL) 431 scf_value_destroy(value); 432 if (entry != NULL) 433 scf_entry_destroy(entry); 434 return (ret); 435 } 436 437 /* 438 * Gets boolean property value. 439 * Caller is responsible to have enough memory allocated. 440 */ 441 int 442 smb_smf_get_boolean_property(smb_scfhandle_t *handle, char *propname, 443 uint8_t *valbool) 444 { 445 int ret = SMBD_SMF_OK; 446 scf_value_t *value = NULL; 447 scf_property_t *prop = NULL; 448 449 if (handle == NULL) 450 return (SMBD_SMF_SYSTEM_ERR); 451 452 value = scf_value_create(handle->scf_handle); 453 prop = scf_property_create(handle->scf_handle); 454 if ((prop) && (value) && 455 (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { 456 if (scf_property_get_value(prop, value) == 0) { 457 if (scf_value_get_boolean(value, 458 valbool) != 0) { 459 ret = SMBD_SMF_SYSTEM_ERR; 460 } 461 } else { 462 ret = SMBD_SMF_SYSTEM_ERR; 463 } 464 } else { 465 ret = SMBD_SMF_SYSTEM_ERR; 466 } 467 if (value != NULL) 468 scf_value_destroy(value); 469 if (prop != NULL) 470 scf_property_destroy(prop); 471 return (ret); 472 } 473 474 /* 475 * Sets a blob property value. 476 */ 477 int 478 smb_smf_set_opaque_property(smb_scfhandle_t *handle, char *propname, 479 void *voidval, size_t sz) 480 { 481 int ret = SMBD_SMF_OK; 482 scf_value_t *value; 483 scf_transaction_entry_t *entry; 484 485 if (handle == NULL) 486 return (SMBD_SMF_SYSTEM_ERR); 487 488 /* 489 * properties must be set in transactions and don't take 490 * effect until the transaction has been ended/committed. 491 */ 492 value = scf_value_create(handle->scf_handle); 493 entry = scf_entry_create(handle->scf_handle); 494 if (value != NULL && entry != NULL) { 495 if (scf_transaction_property_change(handle->scf_trans, entry, 496 propname, SCF_TYPE_OPAQUE) == 0 || 497 scf_transaction_property_new(handle->scf_trans, entry, 498 propname, SCF_TYPE_OPAQUE) == 0) { 499 if (scf_value_set_opaque(value, voidval, sz) == 0) { 500 if (scf_entry_add_value(entry, value) != 0) { 501 ret = SMBD_SMF_SYSTEM_ERR; 502 scf_value_destroy(value); 503 } 504 /* the value is in the transaction */ 505 value = NULL; 506 } else { 507 /* value couldn't be constructed */ 508 ret = SMBD_SMF_SYSTEM_ERR; 509 } 510 /* the entry is in the transaction */ 511 entry = NULL; 512 } else { 513 ret = SMBD_SMF_SYSTEM_ERR; 514 } 515 } else { 516 ret = SMBD_SMF_SYSTEM_ERR; 517 } 518 if (ret == SMBD_SMF_SYSTEM_ERR) { 519 switch (scf_error()) { 520 case SCF_ERROR_PERMISSION_DENIED: 521 ret = SMBD_SMF_NO_PERMISSION; 522 break; 523 } 524 } 525 /* 526 * cleanup if there were any errors that didn't leave these 527 * values where they would be cleaned up later. 528 */ 529 if (value != NULL) 530 scf_value_destroy(value); 531 if (entry != NULL) 532 scf_entry_destroy(entry); 533 return (ret); 534 } 535 536 /* 537 * Gets a blob property value. 538 * Caller is responsible to have enough memory allocated. 539 */ 540 int 541 smb_smf_get_opaque_property(smb_scfhandle_t *handle, char *propname, 542 void *v, size_t sz) 543 { 544 int ret = SMBD_SMF_OK; 545 scf_value_t *value = NULL; 546 scf_property_t *prop = NULL; 547 548 if (handle == NULL) 549 return (SMBD_SMF_SYSTEM_ERR); 550 551 value = scf_value_create(handle->scf_handle); 552 prop = scf_property_create(handle->scf_handle); 553 if ((prop) && (value) && 554 (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { 555 if (scf_property_get_value(prop, value) == 0) { 556 if (scf_value_get_opaque(value, (char *)v, sz) != sz) { 557 ret = SMBD_SMF_SYSTEM_ERR; 558 } 559 } else { 560 ret = SMBD_SMF_SYSTEM_ERR; 561 } 562 } else { 563 ret = SMBD_SMF_SYSTEM_ERR; 564 } 565 if (value != NULL) 566 scf_value_destroy(value); 567 if (prop != NULL) 568 scf_property_destroy(prop); 569 return (ret); 570 } 571 572 /* 573 * Delete a property (for properties obsoleted during an upgrade). 574 */ 575 int 576 smb_smf_delete_property(smb_scfhandle_t *handle, char *propname) 577 { 578 scf_transaction_entry_t *entry; 579 int ret = SMBD_SMF_OK; 580 581 if (handle == NULL) 582 return (SMBD_SMF_SYSTEM_ERR); 583 if (handle->scf_trans == NULL) 584 return (SMBD_SMF_SYSTEM_ERR); 585 586 /* 587 * properties must be set in transactions and don't take 588 * effect until the transaction has been ended/committed. 589 */ 590 entry = scf_entry_create(handle->scf_handle); 591 if (entry == NULL) { 592 ret = SMBD_SMF_SYSTEM_ERR; 593 goto out; 594 } 595 596 if (scf_transaction_property_delete(handle->scf_trans, 597 entry, propname) == 0) { 598 /* the entry is in the transaction */ 599 entry = NULL; 600 } else { 601 switch (scf_error()) { 602 case SCF_ERROR_NOT_FOUND: 603 /* Did not exist. We're done. */ 604 ret = SMBD_SMF_OK; 605 goto out; 606 case SCF_ERROR_PERMISSION_DENIED: 607 ret = SMBD_SMF_NO_PERMISSION; 608 goto out; 609 default: 610 ret = SMBD_SMF_SYSTEM_ERR; 611 goto out; 612 } 613 } 614 615 out: 616 scf_entry_destroy(entry); 617 return (ret); 618 } 619 620 /* 621 * Put the smb service into maintenance mode. 622 */ 623 int 624 smb_smf_maintenance_mode(void) 625 { 626 return (smf_maintain_instance(SMBD_DEFAULT_INSTANCE_FMRI, 0)); 627 } 628 629 /* 630 * Restart the smb service. 631 */ 632 int 633 smb_smf_restart_service(void) 634 { 635 return (smf_restart_instance(SMBD_DEFAULT_INSTANCE_FMRI)); 636 } 637 638 /* 639 * smb_smf_scf_init() 640 * 641 * must be called before using any of the SCF functions. 642 * Returns smb_scfhandle_t pointer if success. 643 */ 644 smb_scfhandle_t * 645 smb_smf_scf_init(char *svc_name) 646 { 647 smb_scfhandle_t *handle; 648 649 handle = malloc(sizeof (smb_scfhandle_t)); 650 if (handle != NULL) { 651 bzero((char *)handle, sizeof (smb_scfhandle_t)); 652 handle->scf_state = SCH_STATE_INITIALIZING; 653 handle->scf_handle = scf_handle_create(SCF_VERSION); 654 if (handle->scf_handle != NULL) { 655 if (scf_handle_bind(handle->scf_handle) == 0) { 656 handle->scf_scope = 657 scf_scope_create(handle->scf_handle); 658 659 if (handle->scf_scope == NULL) 660 goto err; 661 662 if (scf_handle_get_local_scope( 663 handle->scf_handle, handle->scf_scope) != 0) 664 goto err; 665 666 handle->scf_service = 667 scf_service_create(handle->scf_handle); 668 669 if (handle->scf_service == NULL) 670 goto err; 671 672 if (scf_scope_get_service(handle->scf_scope, 673 svc_name, handle->scf_service) 674 != SCF_SUCCESS) { 675 goto err; 676 } 677 handle->scf_pg = 678 scf_pg_create(handle->scf_handle); 679 680 if (handle->scf_pg == NULL) 681 goto err; 682 683 handle->scf_state = SCH_STATE_INIT; 684 } else { 685 goto err; 686 } 687 } else { 688 free(handle); 689 handle = NULL; 690 smb_smf_scf_log_error("Could not access SMF " 691 "repository: %s\n"); 692 } 693 } 694 return (handle); 695 696 /* error handling/unwinding */ 697 err: 698 (void) smb_smf_scf_fini(handle); 699 (void) smb_smf_scf_log_error("SMF initialization problem: %s\n"); 700 return (NULL); 701 } 702 703 /* 704 * smb_smf_scf_fini(handle) 705 * 706 * must be called when done. Called with the handle allocated in 707 * smb_smf_scf_init(), it cleans up the state and frees any SCF resources 708 * still in use. 709 */ 710 void 711 smb_smf_scf_fini(smb_scfhandle_t *handle) 712 { 713 if (handle != NULL) { 714 int unbind = 0; 715 scf_iter_destroy(handle->scf_pg_iter); 716 handle->scf_pg_iter = NULL; 717 718 scf_iter_destroy(handle->scf_inst_iter); 719 handle->scf_inst_iter = NULL; 720 721 unbind = 1; 722 scf_scope_destroy(handle->scf_scope); 723 handle->scf_scope = NULL; 724 725 scf_instance_destroy(handle->scf_instance); 726 handle->scf_instance = NULL; 727 728 scf_service_destroy(handle->scf_service); 729 handle->scf_service = NULL; 730 731 scf_pg_destroy(handle->scf_pg); 732 handle->scf_pg = NULL; 733 734 handle->scf_state = SCH_STATE_UNINIT; 735 if (unbind) 736 (void) scf_handle_unbind(handle->scf_handle); 737 scf_handle_destroy(handle->scf_handle); 738 handle->scf_handle = NULL; 739 740 free(handle); 741 } 742 } 743