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