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); 969 (void) sa_add_protocol_property(protoset, prop); 970 } 971 return (SA_OK); 972 } 973 974 /* 975 * smb_share_init() 976 * 977 * Initialize the smb plugin. 978 */ 979 980 static int 981 smb_share_init(void) 982 { 983 int ret = SA_OK; 984 985 if (sa_plugin_ops.sa_init != smb_share_init) 986 return (SA_SYSTEM_ERR); 987 988 if (smb_load_proto_properties() != SA_OK) 989 return (SA_SYSTEM_ERR); 990 991 return (ret); 992 } 993 994 /* 995 * smb_share_fini() 996 * 997 */ 998 static void 999 smb_share_fini(void) 1000 { 1001 xmlFreeNode(protoset); 1002 protoset = NULL; 1003 } 1004 1005 /* 1006 * smb_get_proto_set() 1007 * 1008 * Return an optionset with all the protocol specific properties in 1009 * it. 1010 */ 1011 static sa_protocol_properties_t 1012 smb_get_proto_set(void) 1013 { 1014 return (protoset); 1015 } 1016 1017 /* 1018 * How long to wait for service to come online 1019 */ 1020 #define WAIT_FOR_SERVICE 15 1021 1022 /* 1023 * smb_enable_service() 1024 * 1025 */ 1026 static int 1027 smb_enable_service(void) 1028 { 1029 int i; 1030 int ret = SA_OK; 1031 1032 if (!smb_isonline()) { 1033 if (smf_enable_instance(SMBD_DEFAULT_INSTANCE_FMRI, 0) != 0) { 1034 (void) fprintf(stderr, 1035 dgettext(TEXT_DOMAIN, 1036 "%s failed to restart: %s\n"), 1037 scf_strerror(scf_error())); 1038 return (SA_CONFIG_ERR); 1039 } 1040 1041 /* Wait for service to come online */ 1042 for (i = 0; i < WAIT_FOR_SERVICE; i++) { 1043 if (smb_isonline()) { 1044 ret = SA_OK; 1045 break; 1046 } else { 1047 ret = SA_BUSY; 1048 (void) sleep(1); 1049 } 1050 } 1051 } 1052 return (ret); 1053 } 1054 1055 /* 1056 * smb_validate_proto_prop(index, name, value) 1057 * 1058 * Verify that the property specified by name can take the new 1059 * value. This is a sanity check to prevent bad values getting into 1060 * the default files. 1061 */ 1062 static int 1063 smb_validate_proto_prop(int index, char *name, char *value) 1064 { 1065 if ((name == NULL) || (index < 0)) 1066 return (SA_BAD_VALUE); 1067 1068 if (smb_proto_options[index].validator == NULL) 1069 return (SA_OK); 1070 1071 if (smb_proto_options[index].validator(index, value) == SA_OK) 1072 return (SA_OK); 1073 return (SA_BAD_VALUE); 1074 } 1075 1076 /* 1077 * smb_set_proto_prop(prop) 1078 * 1079 * check that prop is valid. 1080 */ 1081 /*ARGSUSED*/ 1082 static int 1083 smb_set_proto_prop(sa_property_t prop) 1084 { 1085 int ret = SA_OK; 1086 char *name; 1087 char *value; 1088 int index = -1; 1089 1090 name = sa_get_property_attr(prop, "type"); 1091 value = sa_get_property_attr(prop, "value"); 1092 if (name != NULL && value != NULL) { 1093 index = findprotoopt(name); 1094 if (index >= 0) { 1095 /* should test for valid value */ 1096 ret = smb_validate_proto_prop(index, name, value); 1097 if (ret == SA_OK) { 1098 /* Save to SMF */ 1099 smb_config_setenv( 1100 smb_proto_options[index].smb_index, value); 1101 /* 1102 * Specialized refresh mechanisms can 1103 * be flagged in the proto_options and 1104 * processed here. 1105 */ 1106 if (smb_proto_options[index].refresh & 1107 SMB_REFRESH_REFRESH) 1108 (void) smf_refresh_instance( 1109 SMBD_DEFAULT_INSTANCE_FMRI); 1110 else if (smb_proto_options[index].refresh & 1111 SMB_REFRESH_RESTART) 1112 (void) smf_restart_instance( 1113 SMBD_DEFAULT_INSTANCE_FMRI); 1114 } 1115 } 1116 } 1117 if (name != NULL) 1118 sa_free_attr_string(name); 1119 if (value != NULL) 1120 sa_free_attr_string(value); 1121 1122 return (ret); 1123 } 1124 1125 /* 1126 * smb_get_status() 1127 * 1128 * What is the current status of the smbd? We use the SMF state here. 1129 * Caller must free the returned value. 1130 */ 1131 1132 static char * 1133 smb_get_status(void) 1134 { 1135 char *state = NULL; 1136 state = smf_get_state(SMBD_DEFAULT_INSTANCE_FMRI); 1137 return (state != NULL ? state : "-"); 1138 } 1139 1140 /* 1141 * This protocol plugin require resource names 1142 */ 1143 static uint64_t 1144 smb_share_features(void) 1145 { 1146 return (SA_FEATURE_RESOURCE | SA_FEATURE_ALLOWSUBDIRS | 1147 SA_FEATURE_ALLOWPARDIRS); 1148 } 1149 1150 /* 1151 * This should be used to convert lmshare_info to sa_resource_t 1152 * Should only be needed to build temp shares/resources to be 1153 * supplied to sharemanager to display temp shares. 1154 */ 1155 static int 1156 smb_build_tmp_sa_resource(sa_handle_t handle, lmshare_info_t *si) 1157 { 1158 int err; 1159 sa_share_t share; 1160 sa_group_t group; 1161 sa_resource_t resource; 1162 1163 if (si == NULL) 1164 return (SA_INVALID_NAME); 1165 1166 /* 1167 * First determine if the "share path" is already shared 1168 * somewhere. If it is, we have to use it as the authority on 1169 * where the transient share lives so will use it's parent 1170 * group. If it doesn't exist, it needs to land in "smb". 1171 */ 1172 1173 share = sa_find_share(handle, si->directory); 1174 if (share != NULL) { 1175 group = sa_get_parent_group(share); 1176 } else { 1177 group = smb_get_smb_share_group(handle); 1178 if (group == NULL) 1179 return (SA_NO_SUCH_GROUP); 1180 share = sa_get_share(group, si->directory); 1181 if (share == NULL) { 1182 share = sa_add_share(group, si->directory, 1183 SA_SHARE_TRANSIENT, &err); 1184 if (share == NULL) 1185 return (SA_NO_SUCH_PATH); 1186 } 1187 } 1188 1189 /* 1190 * Now handle the resource. Make sure that the resource is 1191 * transient and added to the share. 1192 */ 1193 resource = sa_get_share_resource(share, si->share_name); 1194 if (resource == NULL) { 1195 resource = sa_add_resource(share, 1196 si->share_name, SA_SHARE_TRANSIENT, &err); 1197 if (resource == NULL) 1198 return (SA_NO_SUCH_RESOURCE); 1199 } 1200 1201 /* set resource attributes now */ 1202 (void) sa_set_resource_attr(resource, "description", si->comment); 1203 (void) sa_set_resource_attr(resource, SHOPT_AD_CONTAINER, 1204 si->container); 1205 1206 return (SA_OK); 1207 } 1208 1209 /* 1210 * Return smb transient shares. Note that we really want to look at 1211 * all current shares from SMB in order to determine this. Transient 1212 * shares should be those that don't appear in either the SMF or ZFS 1213 * configurations. Those that are in the repositories will be 1214 * filtered out by smb_build_tmp_sa_resource. 1215 */ 1216 static int 1217 smb_list_transient(sa_handle_t handle) 1218 { 1219 int i, offset, num; 1220 lmshare_list_t list; 1221 int res; 1222 1223 num = lmshrd_num_shares(); 1224 if (num <= 0) 1225 return (SA_OK); 1226 offset = 0; 1227 while (lmshrd_list(offset, &list) != NERR_InternalError) { 1228 if (list.no == 0) 1229 break; 1230 for (i = 0; i < list.no; i++) { 1231 res = smb_build_tmp_sa_resource(handle, 1232 &(list.smbshr[i])); 1233 if (res != SA_OK) 1234 return (res); 1235 } 1236 offset += list.no; 1237 } 1238 1239 return (SA_OK); 1240 } 1241 1242 /* 1243 * fix_resource_name(share, name, prefix) 1244 * 1245 * Construct a name where the ZFS dataset has the prefix replaced with "name". 1246 */ 1247 static char * 1248 fix_resource_name(sa_share_t share, char *name, char *prefix) 1249 { 1250 char *dataset = NULL; 1251 char *newname = NULL; 1252 size_t psize; 1253 size_t nsize; 1254 1255 dataset = sa_get_share_attr(share, "dataset"); 1256 1257 if (dataset != NULL && strcmp(dataset, prefix) != 0) { 1258 psize = strlen(prefix); 1259 if (strncmp(dataset, prefix, psize) == 0) { 1260 /* need string plus ',' and NULL */ 1261 nsize = (strlen(dataset) - psize) + strlen(name) + 2; 1262 newname = calloc(nsize, 1); 1263 if (newname != NULL) { 1264 (void) snprintf(newname, nsize, "%s%s", name, 1265 dataset + psize); 1266 sa_fix_resource_name(newname); 1267 } 1268 sa_free_attr_string(dataset); 1269 return (newname); 1270 } 1271 } 1272 if (dataset != NULL) 1273 sa_free_attr_string(dataset); 1274 return (strdup(name)); 1275 } 1276 1277 /* 1278 * smb_parse_optstring(group, options) 1279 * 1280 * parse a compact option string into individual options. This allows 1281 * ZFS sharesmb and sharemgr "share" command to work. group can be a 1282 * group, a share or a resource. 1283 */ 1284 static int 1285 smb_parse_optstring(sa_group_t group, char *options) 1286 { 1287 char *dup; 1288 char *base; 1289 char *lasts; 1290 char *token; 1291 sa_optionset_t optionset; 1292 sa_group_t parent = NULL; 1293 sa_resource_t resource = NULL; 1294 int iszfs = 0; 1295 int persist = 0; 1296 int need_optionset = 0; 1297 int ret = SA_OK; 1298 sa_property_t prop; 1299 1300 /* 1301 * In order to not attempt to change ZFS properties unless 1302 * absolutely necessary, we never do it in the legacy parsing 1303 * so we need to keep track of this. 1304 */ 1305 if (sa_is_share(group)) { 1306 char *zfs; 1307 1308 parent = sa_get_parent_group(group); 1309 if (parent != NULL) { 1310 zfs = sa_get_group_attr(parent, "zfs"); 1311 if (zfs != NULL) { 1312 sa_free_attr_string(zfs); 1313 iszfs = 1; 1314 } 1315 } 1316 } else { 1317 iszfs = sa_group_is_zfs(group); 1318 /* 1319 * If a ZFS group, then we need to see if a resource 1320 * name is being set. If so, bail with 1321 * SA_PROP_SHARE_ONLY, so we come back in with a share 1322 * instead of a group. 1323 */ 1324 if (strncmp(options, "name=", sizeof ("name=") - 1) == 0 || 1325 strstr(options, ",name=") != NULL) { 1326 return (SA_PROP_SHARE_ONLY); 1327 } 1328 } 1329 1330 /* do we have an existing optionset? */ 1331 optionset = sa_get_optionset(group, "smb"); 1332 if (optionset == NULL) { 1333 /* didn't find existing optionset so create one */ 1334 optionset = sa_create_optionset(group, "smb"); 1335 if (optionset == NULL) 1336 return (SA_NO_MEMORY); 1337 } else { 1338 /* 1339 * If an optionset already exists, we've come through 1340 * twice so ignore the second time. 1341 */ 1342 return (ret); 1343 } 1344 1345 /* We need a copy of options for the next part. */ 1346 dup = strdup(options); 1347 if (dup == NULL) 1348 return (SA_NO_MEMORY); 1349 1350 /* 1351 * SMB properties are straightforward and are strings, 1352 * integers or booleans. Properties are separated by 1353 * commas. It will be necessary to parse quotes due to some 1354 * strings not having a restricted characters set. 1355 * 1356 * Note that names will create a resource. For now, if there 1357 * is a set of properties "before" the first name="", those 1358 * properties will be placed on the group. 1359 */ 1360 persist = sa_is_persistent(group); 1361 base = dup; 1362 token = dup; 1363 lasts = NULL; 1364 while (token != NULL && ret == SA_OK) { 1365 ret = SA_OK; 1366 token = strtok_r(base, ",", &lasts); 1367 base = NULL; 1368 if (token != NULL) { 1369 char *value; 1370 /* 1371 * All SMB properties have values so there 1372 * MUST be an '=' character. If it doesn't, 1373 * it is a syntax error. 1374 */ 1375 value = strchr(token, '='); 1376 if (value != NULL) { 1377 *value++ = '\0'; 1378 } else { 1379 ret = SA_SYNTAX_ERR; 1380 break; 1381 } 1382 /* 1383 * We may need to handle a "name" property 1384 * that is a ZFS imposed resource name. Each 1385 * name would trigger getting a new "resource" 1386 * to put properties on. For now, assume no 1387 * "name" property for special handling. 1388 */ 1389 1390 if (strcmp(token, "name") == 0) { 1391 char *prefix; 1392 char *name = NULL; 1393 /* 1394 * We have a name, so now work on the 1395 * resource level. We have a "share" 1396 * in "group" due to the caller having 1397 * added it. If we are called with a 1398 * group, the check for group/share 1399 * at the beginning of this function 1400 * will bail out the parse if there is a 1401 * "name" but no share. 1402 */ 1403 if (!iszfs) { 1404 ret = SA_SYNTAX_ERR; 1405 break; 1406 } 1407 /* 1408 * Make sure the parent group has the 1409 * "prefix" property since we will 1410 * need to use this for constructing 1411 * inherited name= values. 1412 */ 1413 prefix = sa_get_group_attr(parent, "prefix"); 1414 if (prefix == NULL) { 1415 prefix = sa_get_group_attr(parent, 1416 "name"); 1417 if (prefix != NULL) { 1418 (void) sa_set_group_attr(parent, 1419 "prefix", prefix); 1420 } 1421 } 1422 name = fix_resource_name((sa_share_t)group, 1423 value, prefix); 1424 if (name != NULL) { 1425 resource = sa_add_resource( 1426 (sa_share_t)group, name, 1427 SA_SHARE_TRANSIENT, &ret); 1428 sa_free_attr_string(name); 1429 } else { 1430 ret = SA_NO_MEMORY; 1431 } 1432 if (prefix != NULL) 1433 sa_free_attr_string(prefix); 1434 1435 /* A resource level optionset is needed */ 1436 1437 need_optionset = 1; 1438 if (resource == NULL) { 1439 ret = SA_NO_MEMORY; 1440 break; 1441 } 1442 continue; 1443 } 1444 1445 if (need_optionset) { 1446 optionset = sa_create_optionset(resource, 1447 "smb"); 1448 need_optionset = 0; 1449 } 1450 1451 prop = sa_create_property(token, value); 1452 if (prop == NULL) 1453 ret = SA_NO_MEMORY; 1454 else 1455 ret = sa_add_property(optionset, prop); 1456 if (ret != SA_OK) 1457 break; 1458 if (!iszfs) 1459 ret = sa_commit_properties(optionset, !persist); 1460 } 1461 } 1462 free(dup); 1463 return (ret); 1464 } 1465 1466 /* 1467 * smb_sprint_option(rbuff, rbuffsize, incr, prop, sep) 1468 * 1469 * provides a mechanism to format SMB properties into legacy output 1470 * format. If the buffer would overflow, it is reallocated and grown 1471 * as appropriate. Special cases of converting internal form of values 1472 * to those used by "share" are done. this function does one property 1473 * at a time. 1474 */ 1475 1476 static void 1477 smb_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr, 1478 sa_property_t prop, int sep) 1479 { 1480 char *name; 1481 char *value; 1482 int curlen; 1483 char *buff = *rbuff; 1484 size_t buffsize = *rbuffsize; 1485 1486 name = sa_get_property_attr(prop, "type"); 1487 value = sa_get_property_attr(prop, "value"); 1488 if (buff != NULL) 1489 curlen = strlen(buff); 1490 else 1491 curlen = 0; 1492 if (name != NULL) { 1493 int len; 1494 len = strlen(name) + sep; 1495 1496 /* 1497 * A future RFE would be to replace this with more 1498 * generic code and to possibly handle more types. 1499 * 1500 * For now, everything else is treated as a string. If 1501 * we get any properties that aren't exactly 1502 * name/value pairs, we may need to 1503 * interpret/transform. 1504 */ 1505 if (value != NULL) 1506 len += 1 + strlen(value); 1507 1508 while (buffsize <= (curlen + len)) { 1509 /* need more room */ 1510 buffsize += incr; 1511 buff = realloc(buff, buffsize); 1512 *rbuff = buff; 1513 *rbuffsize = buffsize; 1514 if (buff == NULL) { 1515 /* realloc failed so free everything */ 1516 if (*rbuff != NULL) 1517 free(*rbuff); 1518 goto err; 1519 } 1520 } 1521 if (buff == NULL) 1522 goto err; 1523 (void) snprintf(buff + curlen, buffsize - curlen, 1524 "%s%s=%s", sep ? "," : "", 1525 name, value != NULL ? value : "\"\""); 1526 1527 } 1528 err: 1529 if (name != NULL) 1530 sa_free_attr_string(name); 1531 if (value != NULL) 1532 sa_free_attr_string(value); 1533 } 1534 1535 /* 1536 * smb_format_resource_options(resource, hier) 1537 * 1538 * format all the options on the group into a flattened option 1539 * string. If hier is non-zero, walk up the tree to get inherited 1540 * options. 1541 */ 1542 1543 static char * 1544 smb_format_options(sa_group_t group, int hier) 1545 { 1546 sa_optionset_t options = NULL; 1547 sa_property_t prop; 1548 int sep = 0; 1549 char *buff; 1550 size_t buffsize; 1551 1552 1553 buff = malloc(OPT_CHUNK); 1554 if (buff == NULL) 1555 return (NULL); 1556 1557 buff[0] = '\0'; 1558 buffsize = OPT_CHUNK; 1559 1560 /* 1561 * We may have a an optionset relative to this item. format 1562 * these if we find them and then add any security definitions. 1563 */ 1564 1565 options = sa_get_derived_optionset(group, "smb", hier); 1566 1567 /* 1568 * do the default set first but skip any option that is also 1569 * in the protocol specific optionset. 1570 */ 1571 if (options != NULL) { 1572 for (prop = sa_get_property(options, NULL); 1573 prop != NULL; prop = sa_get_next_property(prop)) { 1574 /* 1575 * use this one since we skipped any 1576 * of these that were also in 1577 * optdefault 1578 */ 1579 smb_sprint_option(&buff, &buffsize, OPT_CHUNK, 1580 prop, sep); 1581 if (buff == NULL) { 1582 /* 1583 * buff could become NULL if there 1584 * isn't enough memory for 1585 * smb_sprint_option to realloc() 1586 * as necessary. We can't really 1587 * do anything about it at this 1588 * point so we return NULL. The 1589 * caller should handle the 1590 * failure. 1591 */ 1592 if (options != NULL) 1593 sa_free_derived_optionset( 1594 options); 1595 return (buff); 1596 } 1597 sep = 1; 1598 } 1599 } 1600 1601 if (options != NULL) 1602 sa_free_derived_optionset(options); 1603 return (buff); 1604 } 1605 1606 /* 1607 * smb_rename_resource(resource, newname) 1608 * 1609 * Change the current exported name of the resource to newname. 1610 */ 1611 /*ARGSUSED*/ 1612 int 1613 smb_rename_resource(sa_handle_t handle, sa_resource_t resource, char *newname) 1614 { 1615 int ret = SA_OK; 1616 int err; 1617 char *oldname; 1618 1619 oldname = sa_get_resource_attr(resource, "name"); 1620 if (oldname == NULL) 1621 return (SA_NO_SUCH_RESOURCE); 1622 1623 err = lmshrd_rename(oldname, newname); 1624 1625 /* improve error values somewhat */ 1626 switch (err) { 1627 case NERR_Success: 1628 break; 1629 case NERR_InternalError: 1630 ret = SA_SYSTEM_ERR; 1631 break; 1632 case NERR_DuplicateShare: 1633 ret = SA_DUPLICATE_NAME; 1634 break; 1635 default: 1636 ret = SA_CONFIG_ERR; 1637 break; 1638 } 1639 1640 return (ret); 1641 } 1642