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