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