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 if (scf_error() == SCF_ERROR_PERMISSION_DENIED) { 232 ret = SMBD_SMF_NO_PERMISSION; 233 } 234 } 235 236 /* 237 * cleanup if there were any errors that didn't leave these 238 * values where they would be cleaned up later. 239 */ 240 if (value != NULL) 241 scf_value_destroy(value); 242 if (entry != NULL) 243 scf_entry_destroy(entry); 244 return (ret); 245 } 246 247 /* 248 * Gets string property value.upto sz size. 249 * Caller is responsible to have enough memory allocated. 250 */ 251 int 252 smb_smf_get_string_property(smb_scfhandle_t *handle, char *propname, 253 char *valstr, size_t sz) 254 { 255 int ret = SMBD_SMF_OK; 256 scf_value_t *value; 257 scf_property_t *prop; 258 259 if (handle == NULL) 260 return (SMBD_SMF_SYSTEM_ERR); 261 262 value = scf_value_create(handle->scf_handle); 263 prop = scf_property_create(handle->scf_handle); 264 if (value && prop && 265 (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { 266 if (scf_property_get_value(prop, value) == 0) { 267 if (scf_value_get_astring(value, valstr, sz) < 0) { 268 ret = SMBD_SMF_SYSTEM_ERR; 269 } 270 } else { 271 ret = SMBD_SMF_SYSTEM_ERR; 272 } 273 } else { 274 ret = SMBD_SMF_SYSTEM_ERR; 275 } 276 if (value != NULL) 277 scf_value_destroy(value); 278 if (prop != NULL) 279 scf_property_destroy(prop); 280 return (ret); 281 } 282 283 /* 284 * Set integer value of property. 285 * The value is returned as int64_t value 286 * Caller ensures appropriate translation. 287 */ 288 int 289 smb_smf_set_integer_property(smb_scfhandle_t *handle, char *propname, 290 int64_t valint) 291 { 292 int ret = SMBD_SMF_OK; 293 scf_value_t *value = NULL; 294 scf_transaction_entry_t *entry = NULL; 295 296 if (handle == NULL) 297 return (SMBD_SMF_SYSTEM_ERR); 298 299 /* 300 * properties must be set in transactions and don't take 301 * effect until the transaction has been ended/committed. 302 */ 303 value = scf_value_create(handle->scf_handle); 304 entry = scf_entry_create(handle->scf_handle); 305 if (value != NULL && entry != NULL) { 306 if (scf_transaction_property_change(handle->scf_trans, entry, 307 propname, SCF_TYPE_INTEGER) == 0 || 308 scf_transaction_property_new(handle->scf_trans, entry, 309 propname, SCF_TYPE_INTEGER) == 0) { 310 scf_value_set_integer(value, valint); 311 if (scf_entry_add_value(entry, value) != 0) { 312 ret = SMBD_SMF_SYSTEM_ERR; 313 scf_value_destroy(value); 314 } 315 /* the value is in the transaction */ 316 value = NULL; 317 } 318 /* the entry is in the transaction */ 319 entry = NULL; 320 } else { 321 ret = SMBD_SMF_SYSTEM_ERR; 322 } 323 if (ret == SMBD_SMF_SYSTEM_ERR) { 324 if (scf_error() == SCF_ERROR_PERMISSION_DENIED) { 325 ret = SMBD_SMF_NO_PERMISSION; 326 } 327 } 328 /* 329 * cleanup if there were any errors that didn't leave these 330 * values where they would be cleaned up later. 331 */ 332 if (value != NULL) 333 scf_value_destroy(value); 334 if (entry != NULL) 335 scf_entry_destroy(entry); 336 return (ret); 337 } 338 339 /* 340 * Gets integer property value. 341 * Caller is responsible to have enough memory allocated. 342 */ 343 int 344 smb_smf_get_integer_property(smb_scfhandle_t *handle, char *propname, 345 int64_t *valint) 346 { 347 int ret = SMBD_SMF_OK; 348 scf_value_t *value = NULL; 349 scf_property_t *prop = NULL; 350 351 if (handle == NULL) 352 return (SMBD_SMF_SYSTEM_ERR); 353 354 value = scf_value_create(handle->scf_handle); 355 prop = scf_property_create(handle->scf_handle); 356 if ((prop) && (value) && 357 (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { 358 if (scf_property_get_value(prop, value) == 0) { 359 if (scf_value_get_integer(value, 360 valint) != 0) { 361 ret = SMBD_SMF_SYSTEM_ERR; 362 } 363 } else { 364 ret = SMBD_SMF_SYSTEM_ERR; 365 } 366 } else { 367 ret = SMBD_SMF_SYSTEM_ERR; 368 } 369 if (value != NULL) 370 scf_value_destroy(value); 371 if (prop != NULL) 372 scf_property_destroy(prop); 373 return (ret); 374 } 375 376 /* 377 * Set boolean value of property. 378 * The value is returned as int64_t value 379 * Caller ensures appropriate translation. 380 */ 381 int 382 smb_smf_set_boolean_property(smb_scfhandle_t *handle, char *propname, 383 uint8_t valbool) 384 { 385 int ret = SMBD_SMF_OK; 386 scf_value_t *value = NULL; 387 scf_transaction_entry_t *entry = NULL; 388 389 if (handle == NULL) 390 return (SMBD_SMF_SYSTEM_ERR); 391 392 /* 393 * properties must be set in transactions and don't take 394 * effect until the transaction has been ended/committed. 395 */ 396 value = scf_value_create(handle->scf_handle); 397 entry = scf_entry_create(handle->scf_handle); 398 if (value != NULL && entry != NULL) { 399 if (scf_transaction_property_change(handle->scf_trans, entry, 400 propname, SCF_TYPE_BOOLEAN) == 0 || 401 scf_transaction_property_new(handle->scf_trans, entry, 402 propname, SCF_TYPE_BOOLEAN) == 0) { 403 scf_value_set_boolean(value, valbool); 404 if (scf_entry_add_value(entry, value) != 0) { 405 ret = SMBD_SMF_SYSTEM_ERR; 406 scf_value_destroy(value); 407 } 408 /* the value is in the transaction */ 409 value = NULL; 410 } 411 /* the entry is in the transaction */ 412 entry = NULL; 413 } else { 414 ret = SMBD_SMF_SYSTEM_ERR; 415 } 416 if (ret == SMBD_SMF_SYSTEM_ERR) { 417 if (scf_error() == SCF_ERROR_PERMISSION_DENIED) { 418 ret = SMBD_SMF_NO_PERMISSION; 419 } 420 } 421 /* 422 * cleanup if there were any errors that didn't leave these 423 * values where they would be cleaned up later. 424 */ 425 if (value != NULL) 426 scf_value_destroy(value); 427 if (entry != NULL) 428 scf_entry_destroy(entry); 429 return (ret); 430 } 431 432 /* 433 * Gets boolean property value. 434 * Caller is responsible to have enough memory allocated. 435 */ 436 int 437 smb_smf_get_boolean_property(smb_scfhandle_t *handle, char *propname, 438 uint8_t *valbool) 439 { 440 int ret = SMBD_SMF_OK; 441 scf_value_t *value = NULL; 442 scf_property_t *prop = NULL; 443 444 if (handle == NULL) 445 return (SMBD_SMF_SYSTEM_ERR); 446 447 value = scf_value_create(handle->scf_handle); 448 prop = scf_property_create(handle->scf_handle); 449 if ((prop) && (value) && 450 (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { 451 if (scf_property_get_value(prop, value) == 0) { 452 if (scf_value_get_boolean(value, 453 valbool) != 0) { 454 ret = SMBD_SMF_SYSTEM_ERR; 455 } 456 } else { 457 ret = SMBD_SMF_SYSTEM_ERR; 458 } 459 } else { 460 ret = SMBD_SMF_SYSTEM_ERR; 461 } 462 if (value != NULL) 463 scf_value_destroy(value); 464 if (prop != NULL) 465 scf_property_destroy(prop); 466 return (ret); 467 } 468 469 /* 470 * Sets a blob property value. 471 */ 472 int 473 smb_smf_set_opaque_property(smb_scfhandle_t *handle, char *propname, 474 void *voidval, size_t sz) 475 { 476 int ret = SMBD_SMF_OK; 477 scf_value_t *value; 478 scf_transaction_entry_t *entry; 479 480 if (handle == NULL) 481 return (SMBD_SMF_SYSTEM_ERR); 482 483 /* 484 * properties must be set in transactions and don't take 485 * effect until the transaction has been ended/committed. 486 */ 487 value = scf_value_create(handle->scf_handle); 488 entry = scf_entry_create(handle->scf_handle); 489 if (value != NULL && entry != NULL) { 490 if (scf_transaction_property_change(handle->scf_trans, entry, 491 propname, SCF_TYPE_OPAQUE) == 0 || 492 scf_transaction_property_new(handle->scf_trans, entry, 493 propname, SCF_TYPE_OPAQUE) == 0) { 494 if (scf_value_set_opaque(value, voidval, sz) == 0) { 495 if (scf_entry_add_value(entry, value) != 0) { 496 ret = SMBD_SMF_SYSTEM_ERR; 497 scf_value_destroy(value); 498 } 499 /* the value is in the transaction */ 500 value = NULL; 501 } else { 502 /* value couldn't be constructed */ 503 ret = SMBD_SMF_SYSTEM_ERR; 504 } 505 /* the entry is in the transaction */ 506 entry = NULL; 507 } else { 508 ret = SMBD_SMF_SYSTEM_ERR; 509 } 510 } else { 511 ret = SMBD_SMF_SYSTEM_ERR; 512 } 513 if (ret == SMBD_SMF_SYSTEM_ERR) { 514 if (scf_error() == SCF_ERROR_PERMISSION_DENIED) { 515 ret = SMBD_SMF_NO_PERMISSION; 516 } 517 } 518 /* 519 * cleanup if there were any errors that didn't leave these 520 * values where they would be cleaned up later. 521 */ 522 if (value != NULL) 523 scf_value_destroy(value); 524 if (entry != NULL) 525 scf_entry_destroy(entry); 526 return (ret); 527 } 528 529 /* 530 * Gets a blob property value. 531 * Caller is responsible to have enough memory allocated. 532 */ 533 int 534 smb_smf_get_opaque_property(smb_scfhandle_t *handle, char *propname, 535 void *v, size_t sz) 536 { 537 int ret = SMBD_SMF_OK; 538 scf_value_t *value = NULL; 539 scf_property_t *prop = NULL; 540 541 if (handle == NULL) 542 return (SMBD_SMF_SYSTEM_ERR); 543 544 value = scf_value_create(handle->scf_handle); 545 prop = scf_property_create(handle->scf_handle); 546 if ((prop) && (value) && 547 (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) { 548 if (scf_property_get_value(prop, value) == 0) { 549 if (scf_value_get_opaque(value, (char *)v, sz) != sz) { 550 ret = SMBD_SMF_SYSTEM_ERR; 551 } 552 } else { 553 ret = SMBD_SMF_SYSTEM_ERR; 554 } 555 } else { 556 ret = SMBD_SMF_SYSTEM_ERR; 557 } 558 if (value != NULL) 559 scf_value_destroy(value); 560 if (prop != NULL) 561 scf_property_destroy(prop); 562 return (ret); 563 } 564 565 /* 566 * Delete a property (for properties obsoleted during an upgrade). 567 */ 568 int 569 smb_smf_delete_property(smb_scfhandle_t *handle, char *propname) 570 { 571 scf_transaction_entry_t *entry; 572 int ret = SMBD_SMF_OK; 573 574 if (handle == NULL) 575 return (SMBD_SMF_SYSTEM_ERR); 576 if (handle->scf_trans == NULL) 577 return (SMBD_SMF_SYSTEM_ERR); 578 579 /* 580 * properties must be set in transactions and don't take 581 * effect until the transaction has been ended/committed. 582 */ 583 entry = scf_entry_create(handle->scf_handle); 584 if (entry == NULL) { 585 ret = SMBD_SMF_SYSTEM_ERR; 586 goto out; 587 } 588 589 if (scf_transaction_property_delete(handle->scf_trans, 590 entry, propname) == 0) { 591 /* the entry is in the transaction */ 592 entry = NULL; 593 } else { 594 switch (scf_error()) { 595 case SCF_ERROR_NOT_FOUND: 596 /* Did not exist. We're done. */ 597 ret = SMBD_SMF_OK; 598 goto out; 599 case SCF_ERROR_PERMISSION_DENIED: 600 ret = SMBD_SMF_NO_PERMISSION; 601 goto out; 602 default: 603 ret = SMBD_SMF_SYSTEM_ERR; 604 goto out; 605 } 606 } 607 608 out: 609 scf_entry_destroy(entry); 610 return (ret); 611 } 612 613 /* 614 * Put the smb service into maintenance mode. 615 */ 616 int 617 smb_smf_maintenance_mode(void) 618 { 619 return (smf_maintain_instance(SMBD_DEFAULT_INSTANCE_FMRI, 0)); 620 } 621 622 /* 623 * Restart the smb service. 624 */ 625 int 626 smb_smf_restart_service(void) 627 { 628 return (smf_restart_instance(SMBD_DEFAULT_INSTANCE_FMRI)); 629 } 630 631 /* 632 * smb_smf_scf_init() 633 * 634 * must be called before using any of the SCF functions. 635 * Returns smb_scfhandle_t pointer if success. 636 */ 637 smb_scfhandle_t * 638 smb_smf_scf_init(char *svc_name) 639 { 640 smb_scfhandle_t *handle; 641 642 handle = malloc(sizeof (smb_scfhandle_t)); 643 if (handle != NULL) { 644 bzero((char *)handle, sizeof (smb_scfhandle_t)); 645 handle->scf_state = SCH_STATE_INITIALIZING; 646 handle->scf_handle = scf_handle_create(SCF_VERSION); 647 if (handle->scf_handle != NULL) { 648 if (scf_handle_bind(handle->scf_handle) == 0) { 649 handle->scf_scope = 650 scf_scope_create(handle->scf_handle); 651 652 if (handle->scf_scope == NULL) 653 goto err; 654 655 if (scf_handle_get_local_scope( 656 handle->scf_handle, handle->scf_scope) != 0) 657 goto err; 658 659 handle->scf_service = 660 scf_service_create(handle->scf_handle); 661 662 if (handle->scf_service == NULL) 663 goto err; 664 665 if (scf_scope_get_service(handle->scf_scope, 666 svc_name, handle->scf_service) 667 != SCF_SUCCESS) { 668 goto err; 669 } 670 handle->scf_pg = 671 scf_pg_create(handle->scf_handle); 672 673 if (handle->scf_pg == NULL) 674 goto err; 675 676 handle->scf_state = SCH_STATE_INIT; 677 } else { 678 goto err; 679 } 680 } else { 681 free(handle); 682 handle = NULL; 683 smb_smf_scf_log_error( 684 "Could not access SMF repository"); 685 } 686 } 687 return (handle); 688 689 /* error handling/unwinding */ 690 err: 691 (void) smb_smf_scf_fini(handle); 692 if (scf_error() != SCF_ERROR_NOT_FOUND) 693 (void) smb_smf_scf_log_error("SMF initialization problem"); 694 return (NULL); 695 } 696 697 /* 698 * smb_smf_scf_fini(handle) 699 * 700 * must be called when done. Called with the handle allocated in 701 * smb_smf_scf_init(), it cleans up the state and frees any SCF resources 702 * still in use. 703 */ 704 void 705 smb_smf_scf_fini(smb_scfhandle_t *handle) 706 { 707 if (handle != NULL) { 708 int unbind = 0; 709 scf_iter_destroy(handle->scf_pg_iter); 710 handle->scf_pg_iter = NULL; 711 712 scf_iter_destroy(handle->scf_inst_iter); 713 handle->scf_inst_iter = NULL; 714 715 unbind = 1; 716 scf_scope_destroy(handle->scf_scope); 717 handle->scf_scope = NULL; 718 719 scf_instance_destroy(handle->scf_instance); 720 handle->scf_instance = NULL; 721 722 scf_service_destroy(handle->scf_service); 723 handle->scf_service = NULL; 724 725 scf_pg_destroy(handle->scf_pg); 726 handle->scf_pg = NULL; 727 728 handle->scf_state = SCH_STATE_UNINIT; 729 if (unbind) 730 (void) scf_handle_unbind(handle->scf_handle); 731 scf_handle_destroy(handle->scf_handle); 732 handle->scf_handle = NULL; 733 734 free(handle); 735 } 736 } 737