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