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