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