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