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 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * SMB specific functions 31 */ 32 #include <stdio.h> 33 #include <string.h> 34 #include <ctype.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <zone.h> 38 #include <errno.h> 39 #include <locale.h> 40 #include <fcntl.h> 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #include <syslog.h> 44 #include "libshare.h" 45 #include "libshare_impl.h" 46 #include <pwd.h> 47 #include <limits.h> 48 #include <libscf.h> 49 #include <strings.h> 50 #include "libshare_smb.h" 51 #include <rpcsvc/daemon_utils.h> 52 #include <smbsrv/lmshare.h> 53 #include <smbsrv/lmshare_door.h> 54 #include <smbsrv/smbinfo.h> 55 #include <smbsrv/libsmb.h> 56 57 /* internal functions */ 58 static int smb_share_init(void); 59 static void smb_share_fini(void); 60 static int smb_enable_share(sa_share_t); 61 static int smb_share_changed(sa_share_t); 62 static int smb_resource_changed(sa_resource_t); 63 static int smb_rename_resource(sa_handle_t, sa_resource_t, char *); 64 static int smb_disable_share(sa_share_t share, char *); 65 static int smb_validate_property(sa_property_t, sa_optionset_t); 66 static int smb_set_proto_prop(sa_property_t); 67 static sa_protocol_properties_t smb_get_proto_set(void); 68 static char *smb_get_status(void); 69 static int smb_parse_optstring(sa_group_t, char *); 70 static char *smb_format_options(sa_group_t, int); 71 72 static int smb_enable_service(void); 73 74 static int range_check_validator(int, char *); 75 static int range_check_validator_zero_ok(int, char *); 76 static int string_length_check_validator(int, char *); 77 static int true_false_validator(int, char *); 78 static int ip_address_validator_empty_ok(int, char *); 79 static int ip_address_csv_list_validator_empty_ok(int, char *); 80 static int ipc_mode_validator(int, char *); 81 static int path_validator(int, char *); 82 83 static int smb_enable_resource(sa_resource_t); 84 static int smb_disable_resource(sa_resource_t); 85 static uint64_t smb_share_features(void); 86 static int smb_list_transient(sa_handle_t); 87 static int smb_domain_change_event(char *new_domain); 88 89 /* size of basic format allocation */ 90 #define OPT_CHUNK 1024 91 92 /* 93 * Indexes of entries in smb_proto_options table. 94 * Changes to smb_proto_options table may require 95 * an update to these values. 96 */ 97 #define PROTO_OPT_WINS1 6 98 #define PROTO_OPT_WINS_EXCLUDE 8 99 100 101 /* 102 * ops vector that provides the protocol specific info and operations 103 * for share management. 104 */ 105 106 struct sa_plugin_ops sa_plugin_ops = { 107 SA_PLUGIN_VERSION, 108 SMB_PROTOCOL_NAME, 109 smb_share_init, 110 smb_share_fini, 111 smb_enable_share, 112 smb_disable_share, 113 smb_validate_property, 114 NULL, 115 NULL, 116 smb_parse_optstring, 117 smb_format_options, 118 smb_set_proto_prop, 119 smb_get_proto_set, 120 smb_get_status, 121 NULL, 122 NULL, 123 NULL, 124 smb_share_changed, 125 smb_enable_resource, 126 smb_disable_resource, 127 smb_share_features, 128 smb_list_transient, 129 smb_resource_changed, 130 smb_rename_resource, 131 NULL, 132 NULL 133 }; 134 135 /* 136 * option definitions. Make sure to keep the #define for the option 137 * index just before the entry it is the index for. Changing the order 138 * can cause breakage. 139 */ 140 141 struct option_defs optdefs[] = { 142 {SHOPT_AD_CONTAINER, OPT_TYPE_STRING}, 143 {SHOPT_NAME, OPT_TYPE_NAME}, 144 {NULL, NULL}, 145 }; 146 147 /* 148 * findopt(name) 149 * 150 * Lookup option "name" in the option table and return the table 151 * index. 152 */ 153 154 static int 155 findopt(char *name) 156 { 157 int i; 158 if (name != NULL) { 159 for (i = 0; optdefs[i].tag != NULL; i++) { 160 if (strcmp(optdefs[i].tag, name) == 0) 161 return (i); 162 } 163 } 164 return (-1); 165 } 166 167 /* 168 * is_a_number(number) 169 * 170 * is the string a number in one of the forms we want to use? 171 */ 172 173 static int 174 is_a_number(char *number) 175 { 176 int ret = 1; 177 int hex = 0; 178 179 if (strncmp(number, "0x", 2) == 0) { 180 number += 2; 181 hex = 1; 182 } else if (*number == '-') { 183 number++; /* skip the minus */ 184 } 185 186 while (ret == 1 && *number != '\0') { 187 if (hex) { 188 ret = isxdigit(*number++); 189 } else { 190 ret = isdigit(*number++); 191 } 192 } 193 return (ret); 194 } 195 196 /* 197 * validresource(name) 198 * 199 * Check that name only has valid characters in it. The current valid 200 * set are the printable characters but not including: 201 * " / \ [ ] : | < > + ; , ? * = \t 202 * Note that space is included and there is a maximum length. 203 */ 204 static int 205 validresource(const char *name) 206 { 207 const char *cp; 208 size_t len; 209 210 if (name == NULL) 211 return (B_FALSE); 212 213 len = strlen(name); 214 if (len == 0 || len > SA_MAX_RESOURCE_NAME) 215 return (B_FALSE); 216 217 if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) { 218 return (B_FALSE); 219 } 220 221 for (cp = name; *cp != '\0'; cp++) 222 if (iscntrl(*cp)) 223 return (B_FALSE); 224 225 return (B_TRUE); 226 } 227 228 /* 229 * smb_isonline() 230 * 231 * Determine if the SMF service instance is in the online state or 232 * not. A number of operations depend on this state. 233 */ 234 static boolean_t 235 smb_isonline(void) 236 { 237 char *str; 238 boolean_t ret = B_FALSE; 239 240 if ((str = smf_get_state(SMBD_DEFAULT_INSTANCE_FMRI)) != NULL) { 241 ret = (strcmp(str, SCF_STATE_STRING_ONLINE) == 0); 242 free(str); 243 } 244 return (ret); 245 } 246 247 /* 248 * smb_enable_share tells the implementation that it is to enable the share. 249 * This entails converting the path and options into the appropriate ioctl 250 * calls. It is assumed that all error checking of paths, etc. were 251 * done earlier. 252 */ 253 static int 254 smb_enable_share(sa_share_t share) 255 { 256 char *path; 257 char *rname; 258 lmshare_info_t si; 259 sa_resource_t resource; 260 boolean_t iszfs; 261 boolean_t privileged; 262 int err = SA_OK; 263 priv_set_t *priv_effective; 264 boolean_t online; 265 266 priv_effective = priv_allocset(); 267 (void) getppriv(PRIV_EFFECTIVE, priv_effective); 268 privileged = (priv_isfullset(priv_effective) == B_TRUE); 269 priv_freeset(priv_effective); 270 271 /* get the path since it is important in several places */ 272 path = sa_get_share_attr(share, "path"); 273 if (path == NULL) 274 return (SA_NO_SUCH_PATH); 275 276 online = smb_isonline(); 277 278 iszfs = sa_path_is_zfs(path); 279 280 if (iszfs) { 281 282 if (privileged == B_FALSE && !online) { 283 284 if (!online) { 285 (void) printf(dgettext(TEXT_DOMAIN, 286 "SMB: Cannot share remove " 287 "file system: %s\n"), path); 288 (void) printf(dgettext(TEXT_DOMAIN, 289 "SMB: Service needs to be enabled " 290 "by a privileged user\n")); 291 err = SA_NO_PERMISSION; 292 errno = EPERM; 293 } 294 if (err) { 295 sa_free_attr_string(path); 296 return (err); 297 } 298 299 } 300 } 301 302 if (privileged == B_TRUE && !online) { 303 err = smb_enable_service(); 304 if (err != SA_OK) { 305 (void) printf(dgettext(TEXT_DOMAIN, 306 "SMB: Unable to enable service\n")); 307 /* 308 * For now, it is OK to not be able to enable 309 * the service. 310 */ 311 if (err == SA_BUSY) 312 err = SA_OK; 313 } else { 314 online = B_TRUE; 315 } 316 } 317 318 /* 319 * Don't bother trying to start shares if the service isn't 320 * running. 321 */ 322 if (!online) 323 goto done; 324 325 /* Each share can have multiple resources */ 326 for (resource = sa_get_share_resource(share, NULL); 327 resource != NULL; 328 resource = sa_get_next_resource(resource)) { 329 sa_optionset_t opts; 330 bzero(&si, sizeof (lmshare_info_t)); 331 rname = sa_get_resource_attr(resource, "name"); 332 if (rname == NULL) { 333 sa_free_attr_string(path); 334 return (SA_NO_SUCH_RESOURCE); 335 } 336 337 opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1); 338 smb_build_lmshare_info(rname, path, opts, &si); 339 sa_free_attr_string(rname); 340 341 sa_free_derived_optionset(opts); 342 if (!iszfs) { 343 err = lmshrd_add(&si); 344 } else { 345 share_t sh; 346 347 sa_sharetab_fill_zfs(share, &sh, "smb"); 348 err = sa_share_zfs(share, (char *)path, &sh, 349 &si, ZFS_SHARE_SMB); 350 351 sa_emptyshare(&sh); 352 } 353 } 354 if (!iszfs) 355 (void) sa_update_sharetab(share, "smb"); 356 done: 357 sa_free_attr_string(path); 358 359 return (err == NERR_DuplicateShare ? 0 : err); 360 } 361 362 /* 363 * This is the share for CIFS all shares have resource names. 364 * Enable tells the smb server to update its hash. If it fails 365 * because smb server is down, we just ignore as smb server loads 366 * the resources from sharemanager at startup. 367 */ 368 369 static int 370 smb_enable_resource(sa_resource_t resource) 371 { 372 char *path; 373 char *rname; 374 sa_optionset_t opts; 375 sa_share_t share; 376 lmshare_info_t si; 377 int ret; 378 379 share = sa_get_resource_parent(resource); 380 if (share == NULL) 381 return (SA_NO_SUCH_PATH); 382 path = sa_get_share_attr(share, "path"); 383 if (path == NULL) 384 return (SA_SYSTEM_ERR); 385 rname = sa_get_resource_attr(resource, "name"); 386 if (rname == NULL) { 387 sa_free_attr_string(path); 388 return (SA_NO_SUCH_RESOURCE); 389 } 390 391 ret = smb_enable_service(); 392 393 if (!smb_isonline()) { 394 ret = SA_OK; 395 goto done; 396 } 397 398 opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1); 399 smb_build_lmshare_info(rname, path, opts, &si); 400 sa_free_attr_string(path); 401 sa_free_attr_string(rname); 402 sa_free_derived_optionset(opts); 403 if (lmshrd_add(&si) != NERR_Success) 404 return (SA_NOT_SHARED); 405 (void) sa_update_sharetab(share, "smb"); 406 407 done: 408 return (ret); 409 } 410 411 /* 412 * Remove it from smb server hash. 413 */ 414 static int 415 smb_disable_resource(sa_resource_t resource) 416 { 417 char *rname; 418 DWORD res; 419 sa_share_t share; 420 421 rname = sa_get_resource_attr(resource, "name"); 422 if (rname == NULL) 423 return (SA_NO_SUCH_RESOURCE); 424 425 if (smb_isonline()) { 426 res = lmshrd_delete(rname); 427 if (res != NERR_Success) { 428 sa_free_attr_string(rname); 429 return (SA_CONFIG_ERR); 430 } 431 sa_free_attr_string(rname); 432 rname = NULL; 433 } 434 share = sa_get_resource_parent(resource); 435 if (share != NULL) { 436 rname = sa_get_share_attr(share, "path"); 437 if (rname != NULL) { 438 (void) sa_delete_sharetab(rname, "smb"); 439 sa_free_attr_string(rname); 440 rname = NULL; 441 } 442 } 443 if (rname != NULL) 444 sa_free_attr_string(rname); 445 /* 446 * Always return OK as smb/server may be down and 447 * Shares will be picked up when loaded. 448 */ 449 return (SA_OK); 450 } 451 452 /* 453 * smb_share_changed(sa_share_t share) 454 * 455 * The specified share has changed. 456 */ 457 static int 458 smb_share_changed(sa_share_t share) 459 { 460 char *path; 461 sa_resource_t resource; 462 463 /* get the path since it is important in several places */ 464 path = sa_get_share_attr(share, "path"); 465 if (path == NULL) 466 return (SA_NO_SUCH_PATH); 467 for (resource = sa_get_share_resource(share, NULL); 468 resource != NULL; 469 resource = sa_get_next_resource(resource)) 470 (void) smb_resource_changed(resource); 471 472 sa_free_attr_string(path); 473 474 return (SA_OK); 475 } 476 477 /* 478 * smb_resource_changed(sa_resource_t resource) 479 * 480 * The specified resource has changed. 481 */ 482 static int 483 smb_resource_changed(sa_resource_t resource) 484 { 485 DWORD res; 486 lmshare_info_t si; 487 lmshare_info_t new_si; 488 char *rname, *path; 489 sa_optionset_t opts; 490 sa_share_t share; 491 492 rname = sa_get_resource_attr(resource, "name"); 493 if (rname == NULL) 494 return (SA_NO_SUCH_RESOURCE); 495 496 share = sa_get_resource_parent(resource); 497 if (share == NULL) { 498 sa_free_attr_string(rname); 499 return (SA_CONFIG_ERR); 500 } 501 502 path = sa_get_share_attr(share, "path"); 503 if (path == NULL) { 504 sa_free_attr_string(rname); 505 return (SA_NO_SUCH_PATH); 506 } 507 508 if (!smb_isonline()) { 509 sa_free_attr_string(rname); 510 return (SA_OK); 511 } 512 513 /* Update the share cache in smb/server */ 514 res = lmshrd_getinfo(rname, &si); 515 if (res != NERR_Success) { 516 sa_free_attr_string(path); 517 sa_free_attr_string(rname); 518 return (SA_CONFIG_ERR); 519 } 520 521 opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1); 522 smb_build_lmshare_info(rname, path, opts, &new_si); 523 sa_free_derived_optionset(opts); 524 sa_free_attr_string(path); 525 sa_free_attr_string(rname); 526 527 /* 528 * Update all fields from sa_share_t 529 * Get derived values. 530 */ 531 if (lmshrd_setinfo(&new_si) != LMSHR_DOOR_SRV_SUCCESS) 532 return (SA_CONFIG_ERR); 533 return (smb_enable_service()); 534 } 535 536 /* 537 * smb_disable_share(sa_share_t share) 538 * 539 * Unshare the specified share. 540 */ 541 static int 542 smb_disable_share(sa_share_t share, char *path) 543 { 544 char *rname; 545 sa_resource_t resource; 546 boolean_t iszfs; 547 int err = SA_OK; 548 549 iszfs = sa_path_is_zfs(path); 550 if (!smb_isonline()) 551 goto done; 552 553 for (resource = sa_get_share_resource(share, NULL); 554 resource != NULL; 555 resource = sa_get_next_resource(resource)) { 556 rname = sa_get_resource_attr(resource, "name"); 557 if (rname == NULL) { 558 continue; 559 } 560 if (!iszfs) { 561 err = lmshrd_delete(rname); 562 switch (err) { 563 case NERR_NetNameNotFound: 564 case NERR_Success: 565 err = SA_OK; 566 break; 567 default: 568 err = SA_CONFIG_ERR; 569 break; 570 } 571 } else { 572 share_t sh; 573 574 sa_sharetab_fill_zfs(share, &sh, "smb"); 575 err = sa_share_zfs(share, (char *)path, &sh, 576 rname, ZFS_UNSHARE_SMB); 577 sa_emptyshare(&sh); 578 } 579 sa_free_attr_string(rname); 580 } 581 done: 582 if (!iszfs) 583 (void) sa_delete_sharetab(path, "smb"); 584 return (err); 585 } 586 587 /* 588 * smb_validate_property(property, parent) 589 * 590 * Check that the property has a legitimate value for its type. 591 */ 592 593 static int 594 smb_validate_property(sa_property_t property, sa_optionset_t parent) 595 { 596 int ret = SA_OK; 597 char *propname; 598 int optindex; 599 sa_group_t parent_group; 600 char *value; 601 602 propname = sa_get_property_attr(property, "type"); 603 604 if ((optindex = findopt(propname)) < 0) 605 ret = SA_NO_SUCH_PROP; 606 607 /* need to validate value range here as well */ 608 if (ret == SA_OK) { 609 parent_group = sa_get_parent_group((sa_share_t)parent); 610 if (optdefs[optindex].share && !sa_is_share(parent_group)) 611 ret = SA_PROP_SHARE_ONLY; 612 } 613 if (ret != SA_OK) { 614 if (propname != NULL) 615 sa_free_attr_string(propname); 616 return (ret); 617 } 618 619 value = sa_get_property_attr(property, "value"); 620 if (value != NULL) { 621 /* first basic type checking */ 622 switch (optdefs[optindex].type) { 623 case OPT_TYPE_NUMBER: 624 /* check that the value is all digits */ 625 if (!is_a_number(value)) 626 ret = SA_BAD_VALUE; 627 break; 628 case OPT_TYPE_BOOLEAN: 629 if (strlen(value) == 0 || 630 strcasecmp(value, "true") == 0 || 631 strcmp(value, "1") == 0 || 632 strcasecmp(value, "false") == 0 || 633 strcmp(value, "0") == 0) { 634 ret = SA_OK; 635 } else { 636 ret = SA_BAD_VALUE; 637 } 638 break; 639 case OPT_TYPE_NAME: 640 /* 641 * Make sure no invalid characters 642 */ 643 if (validresource(value) == B_FALSE) 644 ret = SA_BAD_VALUE; 645 break; 646 case OPT_TYPE_STRING: 647 /* whatever is here should be ok */ 648 break; 649 default: 650 break; 651 } 652 } 653 654 if (value != NULL) 655 sa_free_attr_string(value); 656 if (ret == SA_OK && optdefs[optindex].check != NULL) 657 /* do the property specific check */ 658 ret = optdefs[optindex].check(property); 659 660 if (propname != NULL) 661 sa_free_attr_string(propname); 662 return (ret); 663 } 664 665 /* 666 * Protocol management functions 667 * 668 * properties defined in the default files are defined in 669 * proto_option_defs for parsing and validation. 670 */ 671 672 struct smb_proto_option_defs { 673 char *name; /* display name -- remove protocol identifier */ 674 int smb_index; 675 int32_t minval; 676 int32_t maxval; /* In case of length of string this should be max */ 677 int (*validator)(int, char *); 678 int32_t refresh; 679 } smb_proto_options[] = { 680 { SMB_CD_SYS_CMNT, 681 SMB_CI_SYS_CMNT, 0, MAX_VALUE_BUFLEN, 682 string_length_check_validator, SMB_REFRESH_REFRESH}, 683 { SMB_CD_MAX_WORKERS, 684 SMB_CI_MAX_WORKERS, 64, 1024, range_check_validator, 685 SMB_REFRESH_REFRESH}, 686 { SMB_CD_NBSCOPE, 687 SMB_CI_NBSCOPE, 0, MAX_VALUE_BUFLEN, 688 string_length_check_validator, SMB_REFRESH_REFRESH}, 689 { SMB_CD_RDR_IPCMODE, 690 SMB_CI_RDR_IPCMODE, 0, 0, ipc_mode_validator, SMB_REFRESH_REFRESH}, 691 { SMB_CD_LM_LEVEL, 692 SMB_CI_LM_LEVEL, 2, 5, range_check_validator, SMB_REFRESH_REFRESH}, 693 { SMB_CD_KEEPALIVE, 694 SMB_CI_KEEPALIVE, 20, 5400, range_check_validator_zero_ok, 695 SMB_REFRESH_REFRESH}, 696 { SMB_CD_WINS_SRV1, 697 SMB_CI_WINS_SRV1, 0, MAX_VALUE_BUFLEN, 698 ip_address_validator_empty_ok, SMB_REFRESH_REFRESH}, 699 { SMB_CD_WINS_SRV2, 700 SMB_CI_WINS_SRV2, 0, MAX_VALUE_BUFLEN, 701 ip_address_validator_empty_ok, SMB_REFRESH_REFRESH}, 702 { SMB_CD_WINS_EXCL, 703 SMB_CI_WINS_EXCL, 0, MAX_VALUE_BUFLEN, 704 ip_address_csv_list_validator_empty_ok, SMB_REFRESH_REFRESH}, 705 { SMB_CD_SIGNING_ENABLE, 706 SMB_CI_SIGNING_ENABLE, 0, 0, true_false_validator, 707 SMB_REFRESH_REFRESH}, 708 { SMB_CD_SIGNING_REQD, 709 SMB_CI_SIGNING_REQD, 0, 0, true_false_validator, 710 SMB_REFRESH_REFRESH}, 711 { SMB_CD_RESTRICT_ANON, 712 SMB_CI_RESTRICT_ANON, 0, 0, true_false_validator, 713 SMB_REFRESH_REFRESH}, 714 { SMB_CD_DOMAIN_SRV, 715 SMB_CI_DOMAIN_SRV, 0, MAX_VALUE_BUFLEN, 716 ip_address_validator_empty_ok, SMB_REFRESH_REFRESH}, 717 { SMB_CD_ADS_ENABLE, 718 SMB_CI_ADS_ENABLE, 0, 0, true_false_validator, SMB_REFRESH_REFRESH}, 719 { SMB_CD_ADS_USER, 720 SMB_CI_ADS_USER, 0, MAX_VALUE_BUFLEN, 721 string_length_check_validator, SMB_REFRESH_REFRESH}, 722 { SMB_CD_ADS_USER_CONTAINER, 723 SMB_CI_ADS_USER_CONTAINER, 0, MAX_VALUE_BUFLEN, 724 string_length_check_validator, SMB_REFRESH_REFRESH}, 725 { SMB_CD_ADS_DOMAIN, 726 SMB_CI_ADS_DOMAIN, 0, MAX_VALUE_BUFLEN, 727 string_length_check_validator, SMB_REFRESH_REFRESH}, 728 { SMB_CD_ADS_PASSWD, 729 SMB_CI_ADS_PASSWD, 0, MAX_VALUE_BUFLEN, 730 string_length_check_validator, SMB_REFRESH_REFRESH}, 731 { SMB_CD_ADS_IPLOOKUP, 732 SMB_CI_ADS_IPLOOKUP, 0, 0, true_false_validator, 733 SMB_REFRESH_REFRESH}, 734 { SMB_CD_ADS_SITE, 735 SMB_CI_ADS_SITE, 0, MAX_VALUE_BUFLEN, 736 string_length_check_validator, SMB_REFRESH_REFRESH}, 737 { SMB_CD_DYNDNS_ENABLE, 738 SMB_CI_DYNDNS_ENABLE, 0, 0, true_false_validator, 739 SMB_REFRESH_REFRESH}, 740 { SMB_CD_DYNDNS_RETRY_SEC, 741 SMB_CI_DYNDNS_RETRY_SEC, 0, 20, range_check_validator, 742 SMB_REFRESH_REFRESH}, 743 { SMB_CD_DYNDNS_RETRY_COUNT, 744 SMB_CI_DYNDNS_RETRY_COUNT, 3, 5, range_check_validator, 745 SMB_REFRESH_REFRESH}, 746 { SMB_CD_AUTOHOME_MAP, 747 SMB_CI_AUTOHOME_MAP, 0, MAX_VALUE_BUFLEN, 748 path_validator}, 749 {NULL, -1, 0, 0, NULL} 750 }; 751 752 /* 753 * Check the range of value as int range. 754 */ 755 static int 756 range_check_validator(int index, char *value) 757 { 758 int ret = SA_OK; 759 760 if (!is_a_number(value)) { 761 ret = SA_BAD_VALUE; 762 } else { 763 int val; 764 val = strtoul(value, NULL, 0); 765 if (val < smb_proto_options[index].minval || 766 val > smb_proto_options[index].maxval) 767 ret = SA_BAD_VALUE; 768 } 769 return (ret); 770 } 771 772 /* 773 * Check the range of value as int range. 774 */ 775 static int 776 range_check_validator_zero_ok(int index, char *value) 777 { 778 int ret = SA_OK; 779 780 if (!is_a_number(value)) { 781 ret = SA_BAD_VALUE; 782 } else { 783 int val; 784 val = strtoul(value, NULL, 0); 785 if (val == 0) 786 ret = SA_OK; 787 else { 788 if (val < smb_proto_options[index].minval || 789 val > smb_proto_options[index].maxval) 790 ret = SA_BAD_VALUE; 791 } 792 } 793 return (ret); 794 } 795 796 /* 797 * Check the length of the string 798 */ 799 static int 800 string_length_check_validator(int index, char *value) 801 { 802 int ret = SA_OK; 803 804 if (value == NULL) 805 return (SA_BAD_VALUE); 806 if (strlen(value) > smb_proto_options[index].maxval) 807 ret = SA_BAD_VALUE; 808 return (ret); 809 } 810 811 /* 812 * Check yes/no 813 */ 814 /*ARGSUSED*/ 815 static int 816 true_false_validator(int index, char *value) 817 { 818 if (value == NULL) 819 return (SA_BAD_VALUE); 820 if ((strcasecmp(value, "true") == 0) || 821 (strcasecmp(value, "false") == 0)) 822 return (SA_OK); 823 return (SA_BAD_VALUE); 824 } 825 826 /* 827 * Check IP address. 828 */ 829 /*ARGSUSED*/ 830 static int 831 ip_address_validator_empty_ok(int index, char *value) 832 { 833 char sbytes[16]; 834 int len; 835 836 if (value == NULL) 837 return (SA_OK); 838 len = strlen(value); 839 if (len == 0) 840 return (SA_OK); 841 if (inet_pton(AF_INET, value, (void *)sbytes) != 1) 842 return (SA_BAD_VALUE); 843 844 return (SA_OK); 845 } 846 847 /* 848 * Check IP address list 849 */ 850 /*ARGSUSED*/ 851 static int 852 ip_address_csv_list_validator_empty_ok(int index, char *value) 853 { 854 char sbytes[16]; 855 char *ip, *tmp, *ctx; 856 857 if (value == NULL || *value == '\0') 858 return (SA_OK); 859 860 if (strlen(value) > MAX_VALUE_BUFLEN) 861 return (SA_BAD_VALUE); 862 863 if ((tmp = strdup(value)) == NULL) 864 return (SA_NO_MEMORY); 865 866 ip = strtok_r(tmp, ",", &ctx); 867 while (ip) { 868 if (strlen(ip) == 0) { 869 free(tmp); 870 return (SA_BAD_VALUE); 871 } 872 if (*ip != 0) { 873 if (inet_pton(AF_INET, ip, 874 (void *)sbytes) != 1) { 875 free(tmp); 876 return (SA_BAD_VALUE); 877 } 878 } 879 ip = strtok_r(0, ",", &ctx); 880 } 881 882 free(tmp); 883 return (SA_OK); 884 } 885 886 /* 887 * Check IPC mode 888 */ 889 /*ARGSUSED*/ 890 static int 891 ipc_mode_validator(int index, char *value) 892 { 893 if (value == NULL) 894 return (SA_BAD_VALUE); 895 if (strcasecmp(value, "anon") == 0) 896 return (SA_OK); 897 if (strcasecmp(value, "auth") == 0) 898 return (SA_OK); 899 return (SA_BAD_VALUE); 900 } 901 902 /* 903 * Check path 904 */ 905 /*ARGSUSED*/ 906 static int 907 path_validator(int index, char *value) 908 { 909 struct stat buffer; 910 int fd, status; 911 912 if (value == NULL) 913 return (SA_BAD_VALUE); 914 915 fd = open(value, O_RDONLY); 916 if (fd < 0) 917 return (SA_BAD_VALUE); 918 919 status = fstat(fd, &buffer); 920 (void) close(fd); 921 922 if (status < 0) 923 return (SA_BAD_VALUE); 924 925 if (buffer.st_mode & S_IFDIR) 926 return (SA_OK); 927 return (SA_BAD_VALUE); 928 } 929 930 /* 931 * the protoset holds the defined options so we don't have to read 932 * them multiple times 933 */ 934 static sa_protocol_properties_t protoset; 935 936 static int 937 findprotoopt(char *name) 938 { 939 int i; 940 for (i = 0; smb_proto_options[i].name != NULL; i++) { 941 if (strcasecmp(smb_proto_options[i].name, name) == 0) 942 return (i); 943 } 944 return (-1); 945 } 946 947 /* 948 * smb_load_proto_properties() 949 * 950 * read the smb config values from SMF. 951 */ 952 953 static int 954 smb_load_proto_properties() 955 { 956 sa_property_t prop; 957 int index; 958 char *value; 959 960 protoset = sa_create_protocol_properties(SMB_PROTOCOL_NAME); 961 if (protoset == NULL) 962 return (SA_NO_MEMORY); 963 964 if (smb_config_load() != 0) 965 return (SA_CONFIG_ERR); 966 for (index = 0; smb_proto_options[index].name != NULL; index++) { 967 value = smb_config_getenv(smb_proto_options[index].smb_index); 968 prop = sa_create_property( 969 smb_proto_options[index].name, value != NULL ? value : ""); 970 if (value != NULL) 971 free(value); 972 if (prop != NULL) 973 (void) sa_add_protocol_property(protoset, prop); 974 } 975 return (SA_OK); 976 } 977 978 /* 979 * smb_share_init() 980 * 981 * Initialize the smb plugin. 982 */ 983 984 static int 985 smb_share_init(void) 986 { 987 int ret = SA_OK; 988 989 if (sa_plugin_ops.sa_init != smb_share_init) 990 return (SA_SYSTEM_ERR); 991 992 if (smb_load_proto_properties() != SA_OK) 993 return (SA_SYSTEM_ERR); 994 995 return (ret); 996 } 997 998 /* 999 * smb_share_fini() 1000 * 1001 */ 1002 static void 1003 smb_share_fini(void) 1004 { 1005 xmlFreeNode(protoset); 1006 protoset = NULL; 1007 } 1008 1009 /* 1010 * smb_get_proto_set() 1011 * 1012 * Return an optionset with all the protocol specific properties in 1013 * it. 1014 */ 1015 static sa_protocol_properties_t 1016 smb_get_proto_set(void) 1017 { 1018 return (protoset); 1019 } 1020 1021 /* 1022 * How long to wait for service to come online 1023 */ 1024 #define WAIT_FOR_SERVICE 15 1025 1026 /* 1027 * smb_enable_service() 1028 * 1029 */ 1030 static int 1031 smb_enable_service(void) 1032 { 1033 int i; 1034 int ret = SA_OK; 1035 1036 if (!smb_isonline()) { 1037 if (smf_enable_instance(SMBD_DEFAULT_INSTANCE_FMRI, 0) != 0) { 1038 (void) fprintf(stderr, 1039 dgettext(TEXT_DOMAIN, 1040 "%s failed to restart: %s\n"), 1041 SMBD_DEFAULT_INSTANCE_FMRI, 1042 scf_strerror(scf_error())); 1043 return (SA_CONFIG_ERR); 1044 } 1045 1046 /* Wait for service to come online */ 1047 for (i = 0; i < WAIT_FOR_SERVICE; i++) { 1048 if (smb_isonline()) { 1049 ret = SA_OK; 1050 break; 1051 } else { 1052 ret = SA_BUSY; 1053 (void) sleep(1); 1054 } 1055 } 1056 } 1057 return (ret); 1058 } 1059 1060 /* 1061 * smb_validate_proto_prop(index, name, value) 1062 * 1063 * Verify that the property specified by name can take the new 1064 * value. This is a sanity check to prevent bad values getting into 1065 * the default files. 1066 */ 1067 static int 1068 smb_validate_proto_prop(int index, char *name, char *value) 1069 { 1070 if ((name == NULL) || (index < 0)) 1071 return (SA_BAD_VALUE); 1072 1073 if (smb_proto_options[index].validator == NULL) 1074 return (SA_OK); 1075 1076 if (smb_proto_options[index].validator(index, value) == SA_OK) 1077 return (SA_OK); 1078 return (SA_BAD_VALUE); 1079 } 1080 1081 /* 1082 * smb_domain_change_event 1083 * 1084 * This function is called whenever ads_domain is changed via sharectl. 1085 * It will make a door call to trigger the ADS domain change event. 1086 */ 1087 static int 1088 smb_domain_change_event(char *new_domain) 1089 { 1090 char *orig_domain; 1091 int rc = SA_OK; 1092 1093 orig_domain = smb_config_getenv(SMB_CI_ADS_DOMAIN); 1094 if (orig_domain == NULL) 1095 return (rc); 1096 1097 if (strcasecmp(orig_domain, new_domain) == 0) { 1098 free(orig_domain); 1099 return (rc); 1100 } 1101 1102 if (!smb_isonline()) { 1103 free(orig_domain); 1104 return (SA_NO_SERVICE); 1105 } 1106 1107 /* 1108 * Clear the ADS_HOST_INFO cache 1109 * and remove old keys from the 1110 * Kerberos keytab. 1111 */ 1112 if (smb_ads_domain_change_notify(orig_domain) != 0) 1113 rc = SA_KRB_KEYTAB_ERR; 1114 1115 free(orig_domain); 1116 return (rc); 1117 } 1118 1119 1120 /* 1121 * smb_set_proto_prop(prop) 1122 * 1123 * check that prop is valid. 1124 */ 1125 /*ARGSUSED*/ 1126 static int 1127 smb_set_proto_prop(sa_property_t prop) 1128 { 1129 int ret = SA_OK; 1130 char *name; 1131 char *value; 1132 int index = -1; 1133 struct smb_proto_option_defs *opt; 1134 1135 name = sa_get_property_attr(prop, "type"); 1136 value = sa_get_property_attr(prop, "value"); 1137 if (name != NULL && value != NULL) { 1138 index = findprotoopt(name); 1139 if (index >= 0) { 1140 /* should test for valid value */ 1141 ret = smb_validate_proto_prop(index, name, value); 1142 if (ret == SA_OK) { 1143 opt = &smb_proto_options[index]; 1144 if ((opt->smb_index == SMB_CI_ADS_DOMAIN) && 1145 (ret = smb_domain_change_event(value)) 1146 != SA_OK) 1147 goto cleanup; 1148 1149 /* Save to SMF */ 1150 smb_config_setenv(opt->smb_index, value); 1151 /* 1152 * Specialized refresh mechanisms can 1153 * be flagged in the proto_options and 1154 * processed here. 1155 */ 1156 if (opt->refresh & SMB_REFRESH_REFRESH) 1157 (void) smb_config_refresh(); 1158 else if (opt->refresh & SMB_REFRESH_RESTART) 1159 (void) smf_restart_instance( 1160 SMBD_DEFAULT_INSTANCE_FMRI); 1161 } 1162 } 1163 } 1164 1165 cleanup: 1166 if (name != NULL) 1167 sa_free_attr_string(name); 1168 if (value != NULL) 1169 sa_free_attr_string(value); 1170 1171 return (ret); 1172 } 1173 1174 /* 1175 * smb_get_status() 1176 * 1177 * What is the current status of the smbd? We use the SMF state here. 1178 * Caller must free the returned value. 1179 */ 1180 1181 static char * 1182 smb_get_status(void) 1183 { 1184 char *state = NULL; 1185 state = smf_get_state(SMBD_DEFAULT_INSTANCE_FMRI); 1186 return (state != NULL ? state : "-"); 1187 } 1188 1189 /* 1190 * This protocol plugin require resource names 1191 */ 1192 static uint64_t 1193 smb_share_features(void) 1194 { 1195 return (SA_FEATURE_RESOURCE | SA_FEATURE_ALLOWSUBDIRS | 1196 SA_FEATURE_ALLOWPARDIRS); 1197 } 1198 1199 /* 1200 * This should be used to convert lmshare_info to sa_resource_t 1201 * Should only be needed to build temp shares/resources to be 1202 * supplied to sharemanager to display temp shares. 1203 */ 1204 static int 1205 smb_build_tmp_sa_resource(sa_handle_t handle, lmshare_info_t *si) 1206 { 1207 int err; 1208 sa_share_t share; 1209 sa_group_t group; 1210 sa_resource_t resource; 1211 1212 if (si == NULL) 1213 return (SA_INVALID_NAME); 1214 1215 /* 1216 * First determine if the "share path" is already shared 1217 * somewhere. If it is, we have to use it as the authority on 1218 * where the transient share lives so will use it's parent 1219 * group. If it doesn't exist, it needs to land in "smb". 1220 */ 1221 1222 share = sa_find_share(handle, si->directory); 1223 if (share != NULL) { 1224 group = sa_get_parent_group(share); 1225 } else { 1226 group = smb_get_smb_share_group(handle); 1227 if (group == NULL) 1228 return (SA_NO_SUCH_GROUP); 1229 share = sa_get_share(group, si->directory); 1230 if (share == NULL) { 1231 share = sa_add_share(group, si->directory, 1232 SA_SHARE_TRANSIENT, &err); 1233 if (share == NULL) 1234 return (SA_NO_SUCH_PATH); 1235 } 1236 } 1237 1238 /* 1239 * Now handle the resource. Make sure that the resource is 1240 * transient and added to the share. 1241 */ 1242 resource = sa_get_share_resource(share, si->share_name); 1243 if (resource == NULL) { 1244 resource = sa_add_resource(share, 1245 si->share_name, SA_SHARE_TRANSIENT, &err); 1246 if (resource == NULL) 1247 return (SA_NO_SUCH_RESOURCE); 1248 } 1249 1250 /* set resource attributes now */ 1251 (void) sa_set_resource_attr(resource, "description", si->comment); 1252 (void) sa_set_resource_attr(resource, SHOPT_AD_CONTAINER, 1253 si->container); 1254 1255 return (SA_OK); 1256 } 1257 1258 /* 1259 * Return smb transient shares. Note that we really want to look at 1260 * all current shares from SMB in order to determine this. Transient 1261 * shares should be those that don't appear in either the SMF or ZFS 1262 * configurations. Those that are in the repositories will be 1263 * filtered out by smb_build_tmp_sa_resource. 1264 */ 1265 static int 1266 smb_list_transient(sa_handle_t handle) 1267 { 1268 int i, offset, num; 1269 lmshare_list_t list; 1270 int res; 1271 1272 num = lmshrd_num_shares(); 1273 if (num <= 0) 1274 return (SA_OK); 1275 offset = 0; 1276 while (lmshrd_list(offset, &list) != NERR_InternalError) { 1277 if (list.no == 0) 1278 break; 1279 for (i = 0; i < list.no; i++) { 1280 res = smb_build_tmp_sa_resource(handle, 1281 &(list.smbshr[i])); 1282 if (res != SA_OK) 1283 return (res); 1284 } 1285 offset += list.no; 1286 } 1287 1288 return (SA_OK); 1289 } 1290 1291 /* 1292 * fix_resource_name(share, name, prefix) 1293 * 1294 * Construct a name where the ZFS dataset has the prefix replaced with "name". 1295 */ 1296 static char * 1297 fix_resource_name(sa_share_t share, char *name, char *prefix) 1298 { 1299 char *dataset = NULL; 1300 char *newname = NULL; 1301 size_t psize; 1302 size_t nsize; 1303 1304 dataset = sa_get_share_attr(share, "dataset"); 1305 1306 if (dataset != NULL && strcmp(dataset, prefix) != 0) { 1307 psize = strlen(prefix); 1308 if (strncmp(dataset, prefix, psize) == 0) { 1309 /* need string plus ',' and NULL */ 1310 nsize = (strlen(dataset) - psize) + strlen(name) + 2; 1311 newname = calloc(nsize, 1); 1312 if (newname != NULL) { 1313 (void) snprintf(newname, nsize, "%s%s", name, 1314 dataset + psize); 1315 sa_fix_resource_name(newname); 1316 } 1317 sa_free_attr_string(dataset); 1318 return (newname); 1319 } 1320 } 1321 if (dataset != NULL) 1322 sa_free_attr_string(dataset); 1323 return (strdup(name)); 1324 } 1325 1326 /* 1327 * smb_parse_optstring(group, options) 1328 * 1329 * parse a compact option string into individual options. This allows 1330 * ZFS sharesmb and sharemgr "share" command to work. group can be a 1331 * group, a share or a resource. 1332 */ 1333 static int 1334 smb_parse_optstring(sa_group_t group, char *options) 1335 { 1336 char *dup; 1337 char *base; 1338 char *lasts; 1339 char *token; 1340 sa_optionset_t optionset; 1341 sa_group_t parent = NULL; 1342 sa_resource_t resource = NULL; 1343 int iszfs = 0; 1344 int persist = 0; 1345 int need_optionset = 0; 1346 int ret = SA_OK; 1347 sa_property_t prop; 1348 1349 /* 1350 * In order to not attempt to change ZFS properties unless 1351 * absolutely necessary, we never do it in the legacy parsing 1352 * so we need to keep track of this. 1353 */ 1354 if (sa_is_share(group)) { 1355 char *zfs; 1356 1357 parent = sa_get_parent_group(group); 1358 if (parent != NULL) { 1359 zfs = sa_get_group_attr(parent, "zfs"); 1360 if (zfs != NULL) { 1361 sa_free_attr_string(zfs); 1362 iszfs = 1; 1363 } 1364 } 1365 } else { 1366 iszfs = sa_group_is_zfs(group); 1367 /* 1368 * If a ZFS group, then we need to see if a resource 1369 * name is being set. If so, bail with 1370 * SA_PROP_SHARE_ONLY, so we come back in with a share 1371 * instead of a group. 1372 */ 1373 if (strncmp(options, "name=", sizeof ("name=") - 1) == 0 || 1374 strstr(options, ",name=") != NULL) { 1375 return (SA_PROP_SHARE_ONLY); 1376 } 1377 } 1378 1379 /* do we have an existing optionset? */ 1380 optionset = sa_get_optionset(group, "smb"); 1381 if (optionset == NULL) { 1382 /* didn't find existing optionset so create one */ 1383 optionset = sa_create_optionset(group, "smb"); 1384 if (optionset == NULL) 1385 return (SA_NO_MEMORY); 1386 } else { 1387 /* 1388 * If an optionset already exists, we've come through 1389 * twice so ignore the second time. 1390 */ 1391 return (ret); 1392 } 1393 1394 /* We need a copy of options for the next part. */ 1395 dup = strdup(options); 1396 if (dup == NULL) 1397 return (SA_NO_MEMORY); 1398 1399 /* 1400 * SMB properties are straightforward and are strings, 1401 * integers or booleans. Properties are separated by 1402 * commas. It will be necessary to parse quotes due to some 1403 * strings not having a restricted characters set. 1404 * 1405 * Note that names will create a resource. For now, if there 1406 * is a set of properties "before" the first name="", those 1407 * properties will be placed on the group. 1408 */ 1409 persist = sa_is_persistent(group); 1410 base = dup; 1411 token = dup; 1412 lasts = NULL; 1413 while (token != NULL && ret == SA_OK) { 1414 ret = SA_OK; 1415 token = strtok_r(base, ",", &lasts); 1416 base = NULL; 1417 if (token != NULL) { 1418 char *value; 1419 /* 1420 * All SMB properties have values so there 1421 * MUST be an '=' character. If it doesn't, 1422 * it is a syntax error. 1423 */ 1424 value = strchr(token, '='); 1425 if (value != NULL) { 1426 *value++ = '\0'; 1427 } else { 1428 ret = SA_SYNTAX_ERR; 1429 break; 1430 } 1431 /* 1432 * We may need to handle a "name" property 1433 * that is a ZFS imposed resource name. Each 1434 * name would trigger getting a new "resource" 1435 * to put properties on. For now, assume no 1436 * "name" property for special handling. 1437 */ 1438 1439 if (strcmp(token, "name") == 0) { 1440 char *prefix; 1441 char *name = NULL; 1442 /* 1443 * We have a name, so now work on the 1444 * resource level. We have a "share" 1445 * in "group" due to the caller having 1446 * added it. If we are called with a 1447 * group, the check for group/share 1448 * at the beginning of this function 1449 * will bail out the parse if there is a 1450 * "name" but no share. 1451 */ 1452 if (!iszfs) { 1453 ret = SA_SYNTAX_ERR; 1454 break; 1455 } 1456 /* 1457 * Make sure the parent group has the 1458 * "prefix" property since we will 1459 * need to use this for constructing 1460 * inherited name= values. 1461 */ 1462 prefix = sa_get_group_attr(parent, "prefix"); 1463 if (prefix == NULL) { 1464 prefix = sa_get_group_attr(parent, 1465 "name"); 1466 if (prefix != NULL) { 1467 (void) sa_set_group_attr(parent, 1468 "prefix", prefix); 1469 } 1470 } 1471 name = fix_resource_name((sa_share_t)group, 1472 value, prefix); 1473 if (name != NULL) { 1474 resource = sa_add_resource( 1475 (sa_share_t)group, name, 1476 SA_SHARE_TRANSIENT, &ret); 1477 sa_free_attr_string(name); 1478 } else { 1479 ret = SA_NO_MEMORY; 1480 } 1481 if (prefix != NULL) 1482 sa_free_attr_string(prefix); 1483 1484 /* A resource level optionset is needed */ 1485 1486 need_optionset = 1; 1487 if (resource == NULL) { 1488 ret = SA_NO_MEMORY; 1489 break; 1490 } 1491 continue; 1492 } 1493 1494 if (need_optionset) { 1495 optionset = sa_create_optionset(resource, 1496 "smb"); 1497 need_optionset = 0; 1498 } 1499 1500 prop = sa_create_property(token, value); 1501 if (prop == NULL) 1502 ret = SA_NO_MEMORY; 1503 else 1504 ret = sa_add_property(optionset, prop); 1505 if (ret != SA_OK) 1506 break; 1507 if (!iszfs) 1508 ret = sa_commit_properties(optionset, !persist); 1509 } 1510 } 1511 free(dup); 1512 return (ret); 1513 } 1514 1515 /* 1516 * smb_sprint_option(rbuff, rbuffsize, incr, prop, sep) 1517 * 1518 * provides a mechanism to format SMB properties into legacy output 1519 * format. If the buffer would overflow, it is reallocated and grown 1520 * as appropriate. Special cases of converting internal form of values 1521 * to those used by "share" are done. this function does one property 1522 * at a time. 1523 */ 1524 1525 static void 1526 smb_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr, 1527 sa_property_t prop, int sep) 1528 { 1529 char *name; 1530 char *value; 1531 int curlen; 1532 char *buff = *rbuff; 1533 size_t buffsize = *rbuffsize; 1534 1535 name = sa_get_property_attr(prop, "type"); 1536 value = sa_get_property_attr(prop, "value"); 1537 if (buff != NULL) 1538 curlen = strlen(buff); 1539 else 1540 curlen = 0; 1541 if (name != NULL) { 1542 int len; 1543 len = strlen(name) + sep; 1544 1545 /* 1546 * A future RFE would be to replace this with more 1547 * generic code and to possibly handle more types. 1548 * 1549 * For now, everything else is treated as a string. If 1550 * we get any properties that aren't exactly 1551 * name/value pairs, we may need to 1552 * interpret/transform. 1553 */ 1554 if (value != NULL) 1555 len += 1 + strlen(value); 1556 1557 while (buffsize <= (curlen + len)) { 1558 /* need more room */ 1559 buffsize += incr; 1560 buff = realloc(buff, buffsize); 1561 *rbuff = buff; 1562 *rbuffsize = buffsize; 1563 if (buff == NULL) { 1564 /* realloc failed so free everything */ 1565 if (*rbuff != NULL) 1566 free(*rbuff); 1567 goto err; 1568 } 1569 } 1570 if (buff == NULL) 1571 goto err; 1572 (void) snprintf(buff + curlen, buffsize - curlen, 1573 "%s%s=%s", sep ? "," : "", 1574 name, value != NULL ? value : "\"\""); 1575 1576 } 1577 err: 1578 if (name != NULL) 1579 sa_free_attr_string(name); 1580 if (value != NULL) 1581 sa_free_attr_string(value); 1582 } 1583 1584 /* 1585 * smb_format_resource_options(resource, hier) 1586 * 1587 * format all the options on the group into a flattened option 1588 * string. If hier is non-zero, walk up the tree to get inherited 1589 * options. 1590 */ 1591 1592 static char * 1593 smb_format_options(sa_group_t group, int hier) 1594 { 1595 sa_optionset_t options = NULL; 1596 sa_property_t prop; 1597 int sep = 0; 1598 char *buff; 1599 size_t buffsize; 1600 1601 1602 buff = malloc(OPT_CHUNK); 1603 if (buff == NULL) 1604 return (NULL); 1605 1606 buff[0] = '\0'; 1607 buffsize = OPT_CHUNK; 1608 1609 /* 1610 * We may have a an optionset relative to this item. format 1611 * these if we find them and then add any security definitions. 1612 */ 1613 1614 options = sa_get_derived_optionset(group, "smb", hier); 1615 1616 /* 1617 * do the default set first but skip any option that is also 1618 * in the protocol specific optionset. 1619 */ 1620 if (options != NULL) { 1621 for (prop = sa_get_property(options, NULL); 1622 prop != NULL; prop = sa_get_next_property(prop)) { 1623 /* 1624 * use this one since we skipped any 1625 * of these that were also in 1626 * optdefault 1627 */ 1628 smb_sprint_option(&buff, &buffsize, OPT_CHUNK, 1629 prop, sep); 1630 if (buff == NULL) { 1631 /* 1632 * buff could become NULL if there 1633 * isn't enough memory for 1634 * smb_sprint_option to realloc() 1635 * as necessary. We can't really 1636 * do anything about it at this 1637 * point so we return NULL. The 1638 * caller should handle the 1639 * failure. 1640 */ 1641 if (options != NULL) 1642 sa_free_derived_optionset( 1643 options); 1644 return (buff); 1645 } 1646 sep = 1; 1647 } 1648 } 1649 1650 if (options != NULL) 1651 sa_free_derived_optionset(options); 1652 return (buff); 1653 } 1654 1655 /* 1656 * smb_rename_resource(resource, newname) 1657 * 1658 * Change the current exported name of the resource to newname. 1659 */ 1660 /*ARGSUSED*/ 1661 int 1662 smb_rename_resource(sa_handle_t handle, sa_resource_t resource, char *newname) 1663 { 1664 int ret = SA_OK; 1665 int err; 1666 char *oldname; 1667 1668 oldname = sa_get_resource_attr(resource, "name"); 1669 if (oldname == NULL) 1670 return (SA_NO_SUCH_RESOURCE); 1671 1672 err = lmshrd_rename(oldname, newname); 1673 1674 /* improve error values somewhat */ 1675 switch (err) { 1676 case NERR_Success: 1677 break; 1678 case NERR_InternalError: 1679 ret = SA_SYSTEM_ERR; 1680 break; 1681 case NERR_DuplicateShare: 1682 ret = SA_DUPLICATE_NAME; 1683 break; 1684 default: 1685 ret = SA_CONFIG_ERR; 1686 break; 1687 } 1688 1689 return (ret); 1690 } 1691