15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw 225331Samw /* 23*5772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 245331Samw * Use is subject to license terms. 255331Samw */ 265331Samw 275331Samw #pragma ident "%Z%%M% %I% %E% SMI" 285331Samw 295331Samw /* 305331Samw * SMB specific functions 315331Samw */ 325331Samw #include <stdio.h> 335331Samw #include <string.h> 345331Samw #include <ctype.h> 355331Samw #include <stdlib.h> 365331Samw #include <unistd.h> 375331Samw #include <zone.h> 385331Samw #include <errno.h> 395331Samw #include <locale.h> 405331Samw #include <fcntl.h> 415331Samw #include <sys/types.h> 425331Samw #include <sys/stat.h> 435331Samw #include <syslog.h> 445331Samw #include "libshare.h" 455331Samw #include "libshare_impl.h" 465331Samw #include <pwd.h> 475331Samw #include <limits.h> 485331Samw #include <libscf.h> 495331Samw #include <strings.h> 505331Samw #include "libshare_smb.h" 515331Samw #include <rpcsvc/daemon_utils.h> 525331Samw #include <smbsrv/lmshare.h> 535331Samw #include <smbsrv/lmshare_door.h> 545331Samw #include <smbsrv/smbinfo.h> 555331Samw #include <smbsrv/libsmb.h> 565331Samw 575331Samw /* internal functions */ 585331Samw static int smb_share_init(void); 595331Samw static void smb_share_fini(void); 605331Samw static int smb_enable_share(sa_share_t); 615331Samw static int smb_share_changed(sa_share_t); 625331Samw static int smb_resource_changed(sa_resource_t); 635331Samw static int smb_rename_resource(sa_handle_t, sa_resource_t, char *); 645331Samw static int smb_disable_share(sa_share_t share, char *); 655331Samw static int smb_validate_property(sa_property_t, sa_optionset_t); 665331Samw static int smb_set_proto_prop(sa_property_t); 675331Samw static sa_protocol_properties_t smb_get_proto_set(void); 685331Samw static char *smb_get_status(void); 695331Samw static int smb_parse_optstring(sa_group_t, char *); 705331Samw static char *smb_format_options(sa_group_t, int); 715331Samw 725331Samw static int smb_enable_service(void); 735331Samw 745331Samw static int range_check_validator(int, char *); 755331Samw static int range_check_validator_zero_ok(int, char *); 765331Samw static int string_length_check_validator(int, char *); 775331Samw static int true_false_validator(int, char *); 785331Samw static int ip_address_validator_empty_ok(int, char *); 795331Samw static int ip_address_csv_list_validator_empty_ok(int, char *); 805331Samw static int path_validator(int, char *); 815331Samw 825331Samw static int smb_enable_resource(sa_resource_t); 835331Samw static int smb_disable_resource(sa_resource_t); 845331Samw static uint64_t smb_share_features(void); 855331Samw static int smb_list_transient(sa_handle_t); 86*5772Sas200622 87*5772Sas200622 extern void lmshrd_door_close(void); 885331Samw 895331Samw /* size of basic format allocation */ 905331Samw #define OPT_CHUNK 1024 915331Samw 92*5772Sas200622 /* size of string for types - big enough to hold "dependency" */ 93*5772Sas200622 #define SCFTYPE_LEN 32 94*5772Sas200622 955331Samw /* 965331Samw * Indexes of entries in smb_proto_options table. 975331Samw * Changes to smb_proto_options table may require 985331Samw * an update to these values. 995331Samw */ 1005331Samw #define PROTO_OPT_WINS1 6 1015331Samw #define PROTO_OPT_WINS_EXCLUDE 8 1025331Samw 1035331Samw 1045331Samw /* 1055331Samw * ops vector that provides the protocol specific info and operations 1065331Samw * for share management. 1075331Samw */ 1085331Samw 1095331Samw struct sa_plugin_ops sa_plugin_ops = { 1105331Samw SA_PLUGIN_VERSION, 1115331Samw SMB_PROTOCOL_NAME, 1125331Samw smb_share_init, 1135331Samw smb_share_fini, 1145331Samw smb_enable_share, 1155331Samw smb_disable_share, 1165331Samw smb_validate_property, 1175331Samw NULL, 1185331Samw NULL, 1195331Samw smb_parse_optstring, 1205331Samw smb_format_options, 1215331Samw smb_set_proto_prop, 1225331Samw smb_get_proto_set, 1235331Samw smb_get_status, 1245331Samw NULL, 1255331Samw NULL, 1265331Samw NULL, 1275331Samw smb_share_changed, 1285331Samw smb_enable_resource, 1295331Samw smb_disable_resource, 1305331Samw smb_share_features, 1315331Samw smb_list_transient, 1325331Samw smb_resource_changed, 1335331Samw smb_rename_resource, 1345331Samw NULL, 1355331Samw NULL 1365331Samw }; 1375331Samw 1385331Samw /* 1395331Samw * option definitions. Make sure to keep the #define for the option 1405331Samw * index just before the entry it is the index for. Changing the order 1415331Samw * can cause breakage. 1425331Samw */ 1435331Samw 1445331Samw struct option_defs optdefs[] = { 1455331Samw {SHOPT_AD_CONTAINER, OPT_TYPE_STRING}, 1465331Samw {SHOPT_NAME, OPT_TYPE_NAME}, 1475331Samw {NULL, NULL}, 1485331Samw }; 1495331Samw 1505331Samw /* 1515331Samw * findopt(name) 1525331Samw * 1535331Samw * Lookup option "name" in the option table and return the table 1545331Samw * index. 1555331Samw */ 1565331Samw 1575331Samw static int 1585331Samw findopt(char *name) 1595331Samw { 1605331Samw int i; 1615331Samw if (name != NULL) { 1625331Samw for (i = 0; optdefs[i].tag != NULL; i++) { 1635331Samw if (strcmp(optdefs[i].tag, name) == 0) 1645331Samw return (i); 1655331Samw } 1665331Samw } 1675331Samw return (-1); 1685331Samw } 1695331Samw 1705331Samw /* 1715331Samw * is_a_number(number) 1725331Samw * 1735331Samw * is the string a number in one of the forms we want to use? 1745331Samw */ 1755331Samw 1765331Samw static int 1775331Samw is_a_number(char *number) 1785331Samw { 1795331Samw int ret = 1; 1805331Samw int hex = 0; 1815331Samw 1825331Samw if (strncmp(number, "0x", 2) == 0) { 1835331Samw number += 2; 1845331Samw hex = 1; 1855331Samw } else if (*number == '-') { 1865331Samw number++; /* skip the minus */ 1875331Samw } 1885331Samw 1895331Samw while (ret == 1 && *number != '\0') { 1905331Samw if (hex) { 1915331Samw ret = isxdigit(*number++); 1925331Samw } else { 1935331Samw ret = isdigit(*number++); 1945331Samw } 1955331Samw } 1965331Samw return (ret); 1975331Samw } 1985331Samw 1995331Samw /* 2005331Samw * validresource(name) 2015331Samw * 2025331Samw * Check that name only has valid characters in it. The current valid 2035331Samw * set are the printable characters but not including: 2045331Samw * " / \ [ ] : | < > + ; , ? * = \t 2055331Samw * Note that space is included and there is a maximum length. 2065331Samw */ 2075331Samw static int 2085331Samw validresource(const char *name) 2095331Samw { 2105331Samw const char *cp; 2115331Samw size_t len; 2125331Samw 2135331Samw if (name == NULL) 2145331Samw return (B_FALSE); 2155331Samw 2165331Samw len = strlen(name); 2175331Samw if (len == 0 || len > SA_MAX_RESOURCE_NAME) 2185331Samw return (B_FALSE); 2195331Samw 2205331Samw if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) { 2215331Samw return (B_FALSE); 2225331Samw } 2235331Samw 2245331Samw for (cp = name; *cp != '\0'; cp++) 2255331Samw if (iscntrl(*cp)) 2265331Samw return (B_FALSE); 2275331Samw 2285331Samw return (B_TRUE); 2295331Samw } 2305331Samw 2315331Samw /* 2325331Samw * smb_isonline() 2335331Samw * 2345331Samw * Determine if the SMF service instance is in the online state or 2355331Samw * not. A number of operations depend on this state. 2365331Samw */ 2375331Samw static boolean_t 2385331Samw smb_isonline(void) 2395331Samw { 2405331Samw char *str; 2415331Samw boolean_t ret = B_FALSE; 2425331Samw 2435331Samw if ((str = smf_get_state(SMBD_DEFAULT_INSTANCE_FMRI)) != NULL) { 2445331Samw ret = (strcmp(str, SCF_STATE_STRING_ONLINE) == 0); 2455331Samw free(str); 2465331Samw } 2475331Samw return (ret); 2485331Samw } 2495331Samw 2505331Samw /* 251*5772Sas200622 * smb_isdisabled() 252*5772Sas200622 * 253*5772Sas200622 * Determine if the SMF service instance is in the disabled state or 254*5772Sas200622 * not. A number of operations depend on this state. 255*5772Sas200622 */ 256*5772Sas200622 static boolean_t 257*5772Sas200622 smb_isdisabled(void) 258*5772Sas200622 { 259*5772Sas200622 char *str; 260*5772Sas200622 boolean_t ret = B_FALSE; 261*5772Sas200622 262*5772Sas200622 if ((str = smf_get_state(SMBD_DEFAULT_INSTANCE_FMRI)) != NULL) { 263*5772Sas200622 ret = (strcmp(str, SCF_STATE_STRING_DISABLED) == 0); 264*5772Sas200622 free(str); 265*5772Sas200622 } 266*5772Sas200622 return (ret); 267*5772Sas200622 } 268*5772Sas200622 269*5772Sas200622 /* 270*5772Sas200622 * smb_isautoenable() 271*5772Sas200622 * 272*5772Sas200622 * Determine if the SMF service instance auto_enabled set or not. A 273*5772Sas200622 * number of operations depend on this state. The property not being 274*5772Sas200622 * set or being set to true means autoenable. Only being set to false 275*5772Sas200622 * is not autoenabled. 276*5772Sas200622 */ 277*5772Sas200622 static boolean_t 278*5772Sas200622 smb_isautoenable(void) 279*5772Sas200622 { 280*5772Sas200622 boolean_t ret = B_TRUE; 281*5772Sas200622 scf_simple_prop_t *prop; 282*5772Sas200622 uint8_t *retstr; 283*5772Sas200622 284*5772Sas200622 prop = scf_simple_prop_get(NULL, SMBD_DEFAULT_INSTANCE_FMRI, 285*5772Sas200622 "application", "auto_enable"); 286*5772Sas200622 if (prop != NULL) { 287*5772Sas200622 retstr = scf_simple_prop_next_boolean(prop); 288*5772Sas200622 ret = *retstr != 0; 289*5772Sas200622 scf_simple_prop_free(prop); 290*5772Sas200622 } 291*5772Sas200622 return (ret); 292*5772Sas200622 } 293*5772Sas200622 294*5772Sas200622 /* 2955331Samw * smb_enable_share tells the implementation that it is to enable the share. 2965331Samw * This entails converting the path and options into the appropriate ioctl 2975331Samw * calls. It is assumed that all error checking of paths, etc. were 2985331Samw * done earlier. 2995331Samw */ 3005331Samw static int 3015331Samw smb_enable_share(sa_share_t share) 3025331Samw { 3035331Samw char *path; 3045331Samw char *rname; 3055331Samw lmshare_info_t si; 3065331Samw sa_resource_t resource; 3075331Samw boolean_t iszfs; 3085331Samw boolean_t privileged; 3095331Samw int err = SA_OK; 3105331Samw priv_set_t *priv_effective; 3115331Samw boolean_t online; 3125331Samw 3135331Samw priv_effective = priv_allocset(); 3145331Samw (void) getppriv(PRIV_EFFECTIVE, priv_effective); 3155331Samw privileged = (priv_isfullset(priv_effective) == B_TRUE); 3165331Samw priv_freeset(priv_effective); 3175331Samw 3185331Samw /* get the path since it is important in several places */ 3195331Samw path = sa_get_share_attr(share, "path"); 3205331Samw if (path == NULL) 3215331Samw return (SA_NO_SUCH_PATH); 3225331Samw 323*5772Sas200622 /* 324*5772Sas200622 * If administratively disabled, don't try to start anything. 325*5772Sas200622 */ 3265331Samw online = smb_isonline(); 327*5772Sas200622 if (!online && !smb_isautoenable() && smb_isdisabled()) 328*5772Sas200622 goto done; 3295331Samw 3305331Samw iszfs = sa_path_is_zfs(path); 3315331Samw 3325331Samw if (iszfs) { 3335331Samw 3345331Samw if (privileged == B_FALSE && !online) { 3355331Samw 3365331Samw if (!online) { 3375331Samw (void) printf(dgettext(TEXT_DOMAIN, 3385331Samw "SMB: Cannot share remove " 3395331Samw "file system: %s\n"), path); 3405331Samw (void) printf(dgettext(TEXT_DOMAIN, 3415331Samw "SMB: Service needs to be enabled " 3425331Samw "by a privileged user\n")); 3435331Samw err = SA_NO_PERMISSION; 3445331Samw errno = EPERM; 3455331Samw } 3465331Samw if (err) { 3475331Samw sa_free_attr_string(path); 3485331Samw return (err); 3495331Samw } 3505331Samw 3515331Samw } 3525331Samw } 3535331Samw 3545331Samw if (privileged == B_TRUE && !online) { 3555331Samw err = smb_enable_service(); 3565331Samw if (err != SA_OK) { 3575331Samw (void) printf(dgettext(TEXT_DOMAIN, 3585331Samw "SMB: Unable to enable service\n")); 3595331Samw /* 3605331Samw * For now, it is OK to not be able to enable 3615331Samw * the service. 3625331Samw */ 3635331Samw if (err == SA_BUSY) 3645331Samw err = SA_OK; 3655331Samw } else { 3665331Samw online = B_TRUE; 3675331Samw } 3685331Samw } 3695331Samw 3705331Samw /* 3715331Samw * Don't bother trying to start shares if the service isn't 3725331Samw * running. 3735331Samw */ 3745331Samw if (!online) 3755331Samw goto done; 3765331Samw 3775331Samw /* Each share can have multiple resources */ 3785331Samw for (resource = sa_get_share_resource(share, NULL); 3795331Samw resource != NULL; 3805331Samw resource = sa_get_next_resource(resource)) { 3815331Samw sa_optionset_t opts; 3825331Samw bzero(&si, sizeof (lmshare_info_t)); 3835331Samw rname = sa_get_resource_attr(resource, "name"); 3845331Samw if (rname == NULL) { 3855331Samw sa_free_attr_string(path); 3865331Samw return (SA_NO_SUCH_RESOURCE); 3875331Samw } 3885331Samw 3895331Samw opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1); 3905331Samw smb_build_lmshare_info(rname, path, opts, &si); 3915331Samw sa_free_attr_string(rname); 3925331Samw 3935331Samw sa_free_derived_optionset(opts); 3945331Samw if (!iszfs) { 3955331Samw err = lmshrd_add(&si); 3965331Samw } else { 3975331Samw share_t sh; 3985331Samw 3995331Samw sa_sharetab_fill_zfs(share, &sh, "smb"); 4005331Samw err = sa_share_zfs(share, (char *)path, &sh, 4015331Samw &si, ZFS_SHARE_SMB); 4025331Samw 4035331Samw sa_emptyshare(&sh); 4045331Samw } 4055331Samw } 4065331Samw if (!iszfs) 4075331Samw (void) sa_update_sharetab(share, "smb"); 4085331Samw done: 4095331Samw sa_free_attr_string(path); 4105331Samw 4115331Samw return (err == NERR_DuplicateShare ? 0 : err); 4125331Samw } 4135331Samw 4145331Samw /* 4155331Samw * This is the share for CIFS all shares have resource names. 4165331Samw * Enable tells the smb server to update its hash. If it fails 4175331Samw * because smb server is down, we just ignore as smb server loads 4185331Samw * the resources from sharemanager at startup. 4195331Samw */ 4205331Samw 4215331Samw static int 4225331Samw smb_enable_resource(sa_resource_t resource) 4235331Samw { 4245331Samw char *path; 4255331Samw char *rname; 4265331Samw sa_optionset_t opts; 4275331Samw sa_share_t share; 4285331Samw lmshare_info_t si; 429*5772Sas200622 int ret = SA_OK; 430*5772Sas200622 int err; 431*5772Sas200622 boolean_t isonline; 4325331Samw 4335331Samw share = sa_get_resource_parent(resource); 4345331Samw if (share == NULL) 4355331Samw return (SA_NO_SUCH_PATH); 436*5772Sas200622 437*5772Sas200622 /* 438*5772Sas200622 * If administratively disabled, don't try to start anything. 439*5772Sas200622 */ 440*5772Sas200622 isonline = smb_isonline(); 441*5772Sas200622 if (!isonline && !smb_isautoenable() && smb_isdisabled()) 442*5772Sas200622 goto done; 443*5772Sas200622 444*5772Sas200622 if (!isonline) 445*5772Sas200622 ret = smb_enable_service(); 446*5772Sas200622 if (!smb_isonline()) { 447*5772Sas200622 ret = SA_OK; 448*5772Sas200622 goto done; 449*5772Sas200622 } 450*5772Sas200622 4515331Samw path = sa_get_share_attr(share, "path"); 4525331Samw if (path == NULL) 4535331Samw return (SA_SYSTEM_ERR); 4545331Samw rname = sa_get_resource_attr(resource, "name"); 4555331Samw if (rname == NULL) { 4565331Samw sa_free_attr_string(path); 4575331Samw return (SA_NO_SUCH_RESOURCE); 4585331Samw } 4595331Samw 4605331Samw opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1); 4615331Samw smb_build_lmshare_info(rname, path, opts, &si); 4625331Samw sa_free_attr_string(path); 4635331Samw sa_free_attr_string(rname); 4645331Samw sa_free_derived_optionset(opts); 465*5772Sas200622 466*5772Sas200622 /* 467*5772Sas200622 * Attempt to add the share. Any error that occurs if it was 468*5772Sas200622 * online is an error but don't count NERR_DuplicateName if 469*5772Sas200622 * smb/server had to be brought online since bringing the 470*5772Sas200622 * service up will enable the share that was just added prior 471*5772Sas200622 * to the attempt to enable. 472*5772Sas200622 */ 473*5772Sas200622 474*5772Sas200622 err = lmshrd_add(&si); 475*5772Sas200622 if (err == NERR_Success || !(!isonline && err == NERR_DuplicateName)) 476*5772Sas200622 (void) sa_update_sharetab(share, "smb"); 477*5772Sas200622 else 4785331Samw return (SA_NOT_SHARED); 4795331Samw 4805331Samw done: 4815331Samw return (ret); 4825331Samw } 4835331Samw 4845331Samw /* 4855331Samw * Remove it from smb server hash. 4865331Samw */ 4875331Samw static int 4885331Samw smb_disable_resource(sa_resource_t resource) 4895331Samw { 4905331Samw char *rname; 4915331Samw DWORD res; 4925331Samw sa_share_t share; 4935331Samw 4945331Samw rname = sa_get_resource_attr(resource, "name"); 4955331Samw if (rname == NULL) 4965331Samw return (SA_NO_SUCH_RESOURCE); 4975331Samw 4985331Samw if (smb_isonline()) { 4995331Samw res = lmshrd_delete(rname); 5005331Samw if (res != NERR_Success) { 5015331Samw sa_free_attr_string(rname); 5025331Samw return (SA_CONFIG_ERR); 5035331Samw } 5045331Samw sa_free_attr_string(rname); 5055331Samw rname = NULL; 5065331Samw } 5075331Samw share = sa_get_resource_parent(resource); 5085331Samw if (share != NULL) { 5095331Samw rname = sa_get_share_attr(share, "path"); 5105331Samw if (rname != NULL) { 5115331Samw (void) sa_delete_sharetab(rname, "smb"); 5125331Samw sa_free_attr_string(rname); 5135331Samw rname = NULL; 5145331Samw } 5155331Samw } 5165331Samw if (rname != NULL) 5175331Samw sa_free_attr_string(rname); 5185331Samw /* 5195331Samw * Always return OK as smb/server may be down and 5205331Samw * Shares will be picked up when loaded. 5215331Samw */ 5225331Samw return (SA_OK); 5235331Samw } 5245331Samw 5255331Samw /* 5265331Samw * smb_share_changed(sa_share_t share) 5275331Samw * 5285331Samw * The specified share has changed. 5295331Samw */ 5305331Samw static int 5315331Samw smb_share_changed(sa_share_t share) 5325331Samw { 5335331Samw char *path; 5345331Samw sa_resource_t resource; 5355331Samw 5365331Samw /* get the path since it is important in several places */ 5375331Samw path = sa_get_share_attr(share, "path"); 5385331Samw if (path == NULL) 5395331Samw return (SA_NO_SUCH_PATH); 5405331Samw for (resource = sa_get_share_resource(share, NULL); 5415331Samw resource != NULL; 5425331Samw resource = sa_get_next_resource(resource)) 5435331Samw (void) smb_resource_changed(resource); 5445331Samw 5455331Samw sa_free_attr_string(path); 5465331Samw 5475331Samw return (SA_OK); 5485331Samw } 5495331Samw 5505331Samw /* 5515331Samw * smb_resource_changed(sa_resource_t resource) 5525331Samw * 5535331Samw * The specified resource has changed. 5545331Samw */ 5555331Samw static int 5565331Samw smb_resource_changed(sa_resource_t resource) 5575331Samw { 5585331Samw DWORD res; 5595331Samw lmshare_info_t si; 5605331Samw lmshare_info_t new_si; 5615331Samw char *rname, *path; 5625331Samw sa_optionset_t opts; 5635331Samw sa_share_t share; 5645331Samw 5655331Samw rname = sa_get_resource_attr(resource, "name"); 5665331Samw if (rname == NULL) 5675331Samw return (SA_NO_SUCH_RESOURCE); 5685331Samw 5695331Samw share = sa_get_resource_parent(resource); 5705331Samw if (share == NULL) { 5715331Samw sa_free_attr_string(rname); 5725331Samw return (SA_CONFIG_ERR); 5735331Samw } 5745331Samw 5755331Samw path = sa_get_share_attr(share, "path"); 5765331Samw if (path == NULL) { 5775331Samw sa_free_attr_string(rname); 5785331Samw return (SA_NO_SUCH_PATH); 5795331Samw } 5805331Samw 5815331Samw if (!smb_isonline()) { 5825331Samw sa_free_attr_string(rname); 5835331Samw return (SA_OK); 5845331Samw } 5855331Samw 5865331Samw /* Update the share cache in smb/server */ 5875331Samw res = lmshrd_getinfo(rname, &si); 5885331Samw if (res != NERR_Success) { 5895331Samw sa_free_attr_string(path); 5905331Samw sa_free_attr_string(rname); 5915331Samw return (SA_CONFIG_ERR); 5925331Samw } 5935331Samw 5945331Samw opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1); 5955331Samw smb_build_lmshare_info(rname, path, opts, &new_si); 5965331Samw sa_free_derived_optionset(opts); 5975331Samw sa_free_attr_string(path); 5985331Samw sa_free_attr_string(rname); 5995331Samw 6005331Samw /* 6015331Samw * Update all fields from sa_share_t 6025331Samw * Get derived values. 6035331Samw */ 6045331Samw if (lmshrd_setinfo(&new_si) != LMSHR_DOOR_SRV_SUCCESS) 6055331Samw return (SA_CONFIG_ERR); 6065331Samw return (smb_enable_service()); 6075331Samw } 6085331Samw 6095331Samw /* 6105331Samw * smb_disable_share(sa_share_t share) 6115331Samw * 6125331Samw * Unshare the specified share. 6135331Samw */ 6145331Samw static int 6155331Samw smb_disable_share(sa_share_t share, char *path) 6165331Samw { 6175331Samw char *rname; 6185331Samw sa_resource_t resource; 6195331Samw boolean_t iszfs; 6205331Samw int err = SA_OK; 6215331Samw 6225331Samw iszfs = sa_path_is_zfs(path); 6235331Samw if (!smb_isonline()) 6245331Samw goto done; 6255331Samw 6265331Samw for (resource = sa_get_share_resource(share, NULL); 6275331Samw resource != NULL; 6285331Samw resource = sa_get_next_resource(resource)) { 6295331Samw rname = sa_get_resource_attr(resource, "name"); 6305331Samw if (rname == NULL) { 6315331Samw continue; 6325331Samw } 6335331Samw if (!iszfs) { 6345331Samw err = lmshrd_delete(rname); 6355331Samw switch (err) { 6365331Samw case NERR_NetNameNotFound: 6375331Samw case NERR_Success: 6385331Samw err = SA_OK; 6395331Samw break; 6405331Samw default: 6415331Samw err = SA_CONFIG_ERR; 6425331Samw break; 6435331Samw } 6445331Samw } else { 6455331Samw share_t sh; 6465331Samw 6475331Samw sa_sharetab_fill_zfs(share, &sh, "smb"); 6485331Samw err = sa_share_zfs(share, (char *)path, &sh, 6495331Samw rname, ZFS_UNSHARE_SMB); 6505331Samw sa_emptyshare(&sh); 6515331Samw } 6525331Samw sa_free_attr_string(rname); 6535331Samw } 6545331Samw done: 6555331Samw if (!iszfs) 6565331Samw (void) sa_delete_sharetab(path, "smb"); 6575331Samw return (err); 6585331Samw } 6595331Samw 6605331Samw /* 6615331Samw * smb_validate_property(property, parent) 6625331Samw * 6635331Samw * Check that the property has a legitimate value for its type. 6645331Samw */ 6655331Samw 6665331Samw static int 6675331Samw smb_validate_property(sa_property_t property, sa_optionset_t parent) 6685331Samw { 6695331Samw int ret = SA_OK; 6705331Samw char *propname; 6715331Samw int optindex; 6725331Samw sa_group_t parent_group; 6735331Samw char *value; 6745331Samw 6755331Samw propname = sa_get_property_attr(property, "type"); 6765331Samw 6775331Samw if ((optindex = findopt(propname)) < 0) 6785331Samw ret = SA_NO_SUCH_PROP; 6795331Samw 6805331Samw /* need to validate value range here as well */ 6815331Samw if (ret == SA_OK) { 6825331Samw parent_group = sa_get_parent_group((sa_share_t)parent); 6835331Samw if (optdefs[optindex].share && !sa_is_share(parent_group)) 6845331Samw ret = SA_PROP_SHARE_ONLY; 6855331Samw } 6865331Samw if (ret != SA_OK) { 6875331Samw if (propname != NULL) 6885331Samw sa_free_attr_string(propname); 6895331Samw return (ret); 6905331Samw } 6915331Samw 6925331Samw value = sa_get_property_attr(property, "value"); 6935331Samw if (value != NULL) { 6945331Samw /* first basic type checking */ 6955331Samw switch (optdefs[optindex].type) { 6965331Samw case OPT_TYPE_NUMBER: 6975331Samw /* check that the value is all digits */ 6985331Samw if (!is_a_number(value)) 6995331Samw ret = SA_BAD_VALUE; 7005331Samw break; 7015331Samw case OPT_TYPE_BOOLEAN: 7025331Samw if (strlen(value) == 0 || 7035331Samw strcasecmp(value, "true") == 0 || 7045331Samw strcmp(value, "1") == 0 || 7055331Samw strcasecmp(value, "false") == 0 || 7065331Samw strcmp(value, "0") == 0) { 7075331Samw ret = SA_OK; 7085331Samw } else { 7095331Samw ret = SA_BAD_VALUE; 7105331Samw } 7115331Samw break; 7125331Samw case OPT_TYPE_NAME: 7135331Samw /* 7145331Samw * Make sure no invalid characters 7155331Samw */ 7165331Samw if (validresource(value) == B_FALSE) 7175331Samw ret = SA_BAD_VALUE; 7185331Samw break; 7195331Samw case OPT_TYPE_STRING: 7205331Samw /* whatever is here should be ok */ 7215331Samw break; 7225331Samw default: 7235331Samw break; 7245331Samw } 7255331Samw } 7265331Samw 7275331Samw if (value != NULL) 7285331Samw sa_free_attr_string(value); 7295331Samw if (ret == SA_OK && optdefs[optindex].check != NULL) 7305331Samw /* do the property specific check */ 7315331Samw ret = optdefs[optindex].check(property); 7325331Samw 7335331Samw if (propname != NULL) 7345331Samw sa_free_attr_string(propname); 7355331Samw return (ret); 7365331Samw } 7375331Samw 7385331Samw /* 7395331Samw * Protocol management functions 7405331Samw * 7415331Samw * properties defined in the default files are defined in 7425331Samw * proto_option_defs for parsing and validation. 7435331Samw */ 7445331Samw 7455331Samw struct smb_proto_option_defs { 7465331Samw int smb_index; 7475331Samw int32_t minval; 7485331Samw int32_t maxval; /* In case of length of string this should be max */ 7495331Samw int (*validator)(int, char *); 7505331Samw int32_t refresh; 7515331Samw } smb_proto_options[] = { 752*5772Sas200622 { SMB_CI_SYS_CMNT, 0, MAX_VALUE_BUFLEN, 753*5772Sas200622 string_length_check_validator, SMB_REFRESH_REFRESH }, 754*5772Sas200622 { SMB_CI_MAX_WORKERS, 64, 1024, range_check_validator, 755*5772Sas200622 SMB_REFRESH_REFRESH }, 756*5772Sas200622 { SMB_CI_NBSCOPE, 0, MAX_VALUE_BUFLEN, 757*5772Sas200622 string_length_check_validator, 0 }, 758*5772Sas200622 { SMB_CI_LM_LEVEL, 2, 5, range_check_validator, 0 }, 759*5772Sas200622 { SMB_CI_KEEPALIVE, 20, 5400, range_check_validator_zero_ok, 760*5772Sas200622 SMB_REFRESH_REFRESH }, 761*5772Sas200622 { SMB_CI_WINS_SRV1, 0, MAX_VALUE_BUFLEN, 762*5772Sas200622 ip_address_validator_empty_ok, SMB_REFRESH_REFRESH }, 763*5772Sas200622 { SMB_CI_WINS_SRV2, 0, MAX_VALUE_BUFLEN, 764*5772Sas200622 ip_address_validator_empty_ok, SMB_REFRESH_REFRESH }, 765*5772Sas200622 { SMB_CI_WINS_EXCL, 0, MAX_VALUE_BUFLEN, 766*5772Sas200622 ip_address_csv_list_validator_empty_ok, SMB_REFRESH_REFRESH }, 767*5772Sas200622 { SMB_CI_SIGNING_ENABLE, 0, 0, true_false_validator, 768*5772Sas200622 SMB_REFRESH_REFRESH }, 769*5772Sas200622 { SMB_CI_SIGNING_REQD, 0, 0, true_false_validator, 770*5772Sas200622 SMB_REFRESH_REFRESH }, 771*5772Sas200622 { SMB_CI_RESTRICT_ANON, 0, 0, true_false_validator, 772*5772Sas200622 SMB_REFRESH_REFRESH }, 773*5772Sas200622 { SMB_CI_DOMAIN_SRV, 0, MAX_VALUE_BUFLEN, 774*5772Sas200622 ip_address_validator_empty_ok, 0 }, 775*5772Sas200622 { SMB_CI_ADS_SITE, 0, MAX_VALUE_BUFLEN, 776*5772Sas200622 string_length_check_validator, SMB_REFRESH_REFRESH }, 777*5772Sas200622 { SMB_CI_DYNDNS_ENABLE, 0, 0, true_false_validator, 0 }, 778*5772Sas200622 { SMB_CI_AUTOHOME_MAP, 0, MAX_VALUE_BUFLEN, path_validator, 0 }, 7795331Samw }; 7805331Samw 781*5772Sas200622 #define SMB_OPT_NUM \ 782*5772Sas200622 (sizeof (smb_proto_options) / sizeof (smb_proto_options[0])) 783*5772Sas200622 7845331Samw /* 7855331Samw * Check the range of value as int range. 7865331Samw */ 7875331Samw static int 7885331Samw range_check_validator(int index, char *value) 7895331Samw { 7905331Samw int ret = SA_OK; 7915331Samw 7925331Samw if (!is_a_number(value)) { 7935331Samw ret = SA_BAD_VALUE; 7945331Samw } else { 7955331Samw int val; 7965331Samw val = strtoul(value, NULL, 0); 7975331Samw if (val < smb_proto_options[index].minval || 7985331Samw val > smb_proto_options[index].maxval) 7995331Samw ret = SA_BAD_VALUE; 8005331Samw } 8015331Samw return (ret); 8025331Samw } 8035331Samw 8045331Samw /* 8055331Samw * Check the range of value as int range. 8065331Samw */ 8075331Samw static int 8085331Samw range_check_validator_zero_ok(int index, char *value) 8095331Samw { 8105331Samw int ret = SA_OK; 8115331Samw 8125331Samw if (!is_a_number(value)) { 8135331Samw ret = SA_BAD_VALUE; 8145331Samw } else { 8155331Samw int val; 8165331Samw val = strtoul(value, NULL, 0); 8175331Samw if (val == 0) 8185331Samw ret = SA_OK; 8195331Samw else { 8205331Samw if (val < smb_proto_options[index].minval || 8215331Samw val > smb_proto_options[index].maxval) 8225331Samw ret = SA_BAD_VALUE; 8235331Samw } 8245331Samw } 8255331Samw return (ret); 8265331Samw } 8275331Samw 8285331Samw /* 8295331Samw * Check the length of the string 8305331Samw */ 8315331Samw static int 8325331Samw string_length_check_validator(int index, char *value) 8335331Samw { 8345331Samw int ret = SA_OK; 8355331Samw 8365331Samw if (value == NULL) 8375331Samw return (SA_BAD_VALUE); 8385331Samw if (strlen(value) > smb_proto_options[index].maxval) 8395331Samw ret = SA_BAD_VALUE; 8405331Samw return (ret); 8415331Samw } 8425331Samw 8435331Samw /* 8445331Samw * Check yes/no 8455331Samw */ 8465331Samw /*ARGSUSED*/ 8475331Samw static int 8485331Samw true_false_validator(int index, char *value) 8495331Samw { 8505331Samw if (value == NULL) 8515331Samw return (SA_BAD_VALUE); 8525331Samw if ((strcasecmp(value, "true") == 0) || 8535331Samw (strcasecmp(value, "false") == 0)) 8545331Samw return (SA_OK); 8555331Samw return (SA_BAD_VALUE); 8565331Samw } 8575331Samw 8585331Samw /* 8595331Samw * Check IP address. 8605331Samw */ 8615331Samw /*ARGSUSED*/ 8625331Samw static int 8635331Samw ip_address_validator_empty_ok(int index, char *value) 8645331Samw { 8655331Samw char sbytes[16]; 8665331Samw int len; 8675331Samw 8685331Samw if (value == NULL) 8695331Samw return (SA_OK); 8705331Samw len = strlen(value); 8715331Samw if (len == 0) 8725331Samw return (SA_OK); 8735331Samw if (inet_pton(AF_INET, value, (void *)sbytes) != 1) 8745331Samw return (SA_BAD_VALUE); 8755331Samw 8765331Samw return (SA_OK); 8775331Samw } 8785331Samw 8795331Samw /* 8805331Samw * Check IP address list 8815331Samw */ 8825331Samw /*ARGSUSED*/ 8835331Samw static int 8845331Samw ip_address_csv_list_validator_empty_ok(int index, char *value) 8855331Samw { 8865331Samw char sbytes[16]; 8875331Samw char *ip, *tmp, *ctx; 8885331Samw 8895331Samw if (value == NULL || *value == '\0') 8905331Samw return (SA_OK); 8915331Samw 8925331Samw if (strlen(value) > MAX_VALUE_BUFLEN) 8935331Samw return (SA_BAD_VALUE); 8945331Samw 8955331Samw if ((tmp = strdup(value)) == NULL) 8965331Samw return (SA_NO_MEMORY); 8975331Samw 8985331Samw ip = strtok_r(tmp, ",", &ctx); 8995331Samw while (ip) { 9005331Samw if (strlen(ip) == 0) { 9015331Samw free(tmp); 9025331Samw return (SA_BAD_VALUE); 9035331Samw } 9045331Samw if (*ip != 0) { 9055331Samw if (inet_pton(AF_INET, ip, 9065331Samw (void *)sbytes) != 1) { 9075331Samw free(tmp); 9085331Samw return (SA_BAD_VALUE); 9095331Samw } 9105331Samw } 9115331Samw ip = strtok_r(0, ",", &ctx); 9125331Samw } 9135331Samw 9145331Samw free(tmp); 9155331Samw return (SA_OK); 9165331Samw } 9175331Samw 9185331Samw /* 9195331Samw * Check path 9205331Samw */ 9215331Samw /*ARGSUSED*/ 9225331Samw static int 9235331Samw path_validator(int index, char *value) 9245331Samw { 9255331Samw struct stat buffer; 9265331Samw int fd, status; 9275331Samw 9285331Samw if (value == NULL) 9295331Samw return (SA_BAD_VALUE); 9305331Samw 9315331Samw fd = open(value, O_RDONLY); 9325331Samw if (fd < 0) 9335331Samw return (SA_BAD_VALUE); 9345331Samw 9355331Samw status = fstat(fd, &buffer); 9365331Samw (void) close(fd); 9375331Samw 9385331Samw if (status < 0) 9395331Samw return (SA_BAD_VALUE); 9405331Samw 9415331Samw if (buffer.st_mode & S_IFDIR) 9425331Samw return (SA_OK); 9435331Samw return (SA_BAD_VALUE); 9445331Samw } 9455331Samw 9465331Samw /* 9475331Samw * the protoset holds the defined options so we don't have to read 9485331Samw * them multiple times 9495331Samw */ 9505331Samw static sa_protocol_properties_t protoset; 9515331Samw 9525331Samw static int 9535331Samw findprotoopt(char *name) 9545331Samw { 9555331Samw int i; 956*5772Sas200622 char *sc_name; 957*5772Sas200622 958*5772Sas200622 for (i = 0; i < SMB_OPT_NUM; i++) { 959*5772Sas200622 sc_name = smb_config_getname(smb_proto_options[i].smb_index); 960*5772Sas200622 if (strcasecmp(sc_name, name) == 0) 9615331Samw return (i); 9625331Samw } 963*5772Sas200622 9645331Samw return (-1); 9655331Samw } 9665331Samw 9675331Samw /* 9685331Samw * smb_load_proto_properties() 9695331Samw * 9705331Samw * read the smb config values from SMF. 9715331Samw */ 9725331Samw 9735331Samw static int 9745331Samw smb_load_proto_properties() 9755331Samw { 9765331Samw sa_property_t prop; 977*5772Sas200622 char value[MAX_VALUE_BUFLEN]; 978*5772Sas200622 char *name; 9795331Samw int index; 980*5772Sas200622 int rc; 9815331Samw 9825331Samw protoset = sa_create_protocol_properties(SMB_PROTOCOL_NAME); 9835331Samw if (protoset == NULL) 9845331Samw return (SA_NO_MEMORY); 9855331Samw 986*5772Sas200622 for (index = 0; index < SMB_OPT_NUM; index++) { 987*5772Sas200622 rc = smb_config_get(smb_proto_options[index].smb_index, 988*5772Sas200622 value, sizeof (value)); 989*5772Sas200622 if (rc != SMBD_SMF_OK) 990*5772Sas200622 continue; 991*5772Sas200622 name = smb_config_getname(smb_proto_options[index].smb_index); 992*5772Sas200622 prop = sa_create_property(name, value); 9935454Sdougm if (prop != NULL) 9945454Sdougm (void) sa_add_protocol_property(protoset, prop); 9955331Samw } 9965331Samw return (SA_OK); 9975331Samw } 9985331Samw 9995331Samw /* 10005331Samw * smb_share_init() 10015331Samw * 10025331Samw * Initialize the smb plugin. 10035331Samw */ 10045331Samw 10055331Samw static int 10065331Samw smb_share_init(void) 10075331Samw { 10085331Samw int ret = SA_OK; 10095331Samw 10105331Samw if (sa_plugin_ops.sa_init != smb_share_init) 10115331Samw return (SA_SYSTEM_ERR); 10125331Samw 10135331Samw if (smb_load_proto_properties() != SA_OK) 10145331Samw return (SA_SYSTEM_ERR); 10155331Samw 10165331Samw return (ret); 10175331Samw } 10185331Samw 10195331Samw /* 10205331Samw * smb_share_fini() 10215331Samw * 10225331Samw */ 10235331Samw static void 10245331Samw smb_share_fini(void) 10255331Samw { 10265331Samw xmlFreeNode(protoset); 10275331Samw protoset = NULL; 1028*5772Sas200622 1029*5772Sas200622 (void) lmshrd_door_close(); 10305331Samw } 10315331Samw 10325331Samw /* 10335331Samw * smb_get_proto_set() 10345331Samw * 10355331Samw * Return an optionset with all the protocol specific properties in 10365331Samw * it. 10375331Samw */ 10385331Samw static sa_protocol_properties_t 10395331Samw smb_get_proto_set(void) 10405331Samw { 10415331Samw return (protoset); 10425331Samw } 10435331Samw 10445331Samw /* 1045*5772Sas200622 * smb_enable_dependencies() 1046*5772Sas200622 * 1047*5772Sas200622 * SMBD_DEFAULT_INSTANCE_FMRI may have some dependencies that aren't 1048*5772Sas200622 * enabled. This will attempt to enable all of them. 1049*5772Sas200622 */ 1050*5772Sas200622 static void 1051*5772Sas200622 smb_enable_dependencies(const char *fmri) 1052*5772Sas200622 { 1053*5772Sas200622 scf_handle_t *handle; 1054*5772Sas200622 scf_service_t *service; 1055*5772Sas200622 scf_instance_t *inst = NULL; 1056*5772Sas200622 scf_iter_t *iter; 1057*5772Sas200622 scf_property_t *prop; 1058*5772Sas200622 scf_value_t *value; 1059*5772Sas200622 scf_propertygroup_t *pg; 1060*5772Sas200622 scf_scope_t *scope; 1061*5772Sas200622 char type[SCFTYPE_LEN]; 1062*5772Sas200622 char *dependency; 1063*5772Sas200622 char *servname; 1064*5772Sas200622 int maxlen; 1065*5772Sas200622 1066*5772Sas200622 /* 1067*5772Sas200622 * Get all required handles and storage. 1068*5772Sas200622 */ 1069*5772Sas200622 handle = scf_handle_create(SCF_VERSION); 1070*5772Sas200622 if (handle == NULL) 1071*5772Sas200622 return; 1072*5772Sas200622 1073*5772Sas200622 if (scf_handle_bind(handle) != 0) { 1074*5772Sas200622 scf_handle_destroy(handle); 1075*5772Sas200622 return; 1076*5772Sas200622 } 1077*5772Sas200622 1078*5772Sas200622 maxlen = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 1079*5772Sas200622 if (maxlen == (ssize_t)-1) 1080*5772Sas200622 maxlen = MAXPATHLEN; 1081*5772Sas200622 1082*5772Sas200622 dependency = malloc(maxlen); 1083*5772Sas200622 1084*5772Sas200622 service = scf_service_create(handle); 1085*5772Sas200622 1086*5772Sas200622 iter = scf_iter_create(handle); 1087*5772Sas200622 1088*5772Sas200622 pg = scf_pg_create(handle); 1089*5772Sas200622 1090*5772Sas200622 prop = scf_property_create(handle); 1091*5772Sas200622 1092*5772Sas200622 value = scf_value_create(handle); 1093*5772Sas200622 1094*5772Sas200622 scope = scf_scope_create(handle); 1095*5772Sas200622 1096*5772Sas200622 if (service == NULL || iter == NULL || pg == NULL || prop == NULL || 1097*5772Sas200622 value == NULL || scope == NULL || dependency == NULL) 1098*5772Sas200622 goto done; 1099*5772Sas200622 1100*5772Sas200622 /* 1101*5772Sas200622 * We passed in the FMRI for the default instance but for 1102*5772Sas200622 * some things we need the simple form so construct it. Since 1103*5772Sas200622 * we reuse the storage that dependency points to, we need to 1104*5772Sas200622 * use the servname early. 1105*5772Sas200622 */ 1106*5772Sas200622 (void) snprintf(dependency, maxlen, "%s", fmri + sizeof ("svc:")); 1107*5772Sas200622 servname = strrchr(dependency, ':'); 1108*5772Sas200622 if (servname == NULL) 1109*5772Sas200622 goto done; 1110*5772Sas200622 *servname = '\0'; 1111*5772Sas200622 servname = dependency; 1112*5772Sas200622 1113*5772Sas200622 /* 1114*5772Sas200622 * Setup to iterate over the service property groups, only 1115*5772Sas200622 * looking at those that are "dependency" types. The "entity" 1116*5772Sas200622 * property will have the FMRI of the service we are dependent 1117*5772Sas200622 * on. 1118*5772Sas200622 */ 1119*5772Sas200622 if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) != 0) 1120*5772Sas200622 goto done; 1121*5772Sas200622 1122*5772Sas200622 if (scf_scope_get_service(scope, servname, service) != 0) 1123*5772Sas200622 goto done; 1124*5772Sas200622 1125*5772Sas200622 if (scf_iter_service_pgs(iter, service) != 0) 1126*5772Sas200622 goto done; 1127*5772Sas200622 1128*5772Sas200622 while (scf_iter_next_pg(iter, pg) > 0) { 1129*5772Sas200622 char *services[2]; 1130*5772Sas200622 /* 1131*5772Sas200622 * Have a property group for the service. See if it is 1132*5772Sas200622 * a dependency pg and only do operations on those. 1133*5772Sas200622 */ 1134*5772Sas200622 if (scf_pg_get_type(pg, type, SCFTYPE_LEN) <= 0) 1135*5772Sas200622 continue; 1136*5772Sas200622 1137*5772Sas200622 if (strncmp(type, SCF_GROUP_DEPENDENCY, SCFTYPE_LEN) != 0) 1138*5772Sas200622 continue; 1139*5772Sas200622 /* 1140*5772Sas200622 * Have a dependency. Attempt to enable it. 1141*5772Sas200622 */ 1142*5772Sas200622 if (scf_pg_get_property(pg, SCF_PROPERTY_ENTITIES, prop) != 0) 1143*5772Sas200622 continue; 1144*5772Sas200622 1145*5772Sas200622 if (scf_property_get_value(prop, value) != 0) 1146*5772Sas200622 continue; 1147*5772Sas200622 1148*5772Sas200622 services[1] = NULL; 1149*5772Sas200622 1150*5772Sas200622 if (scf_value_get_as_string(value, dependency, maxlen) > 0) { 1151*5772Sas200622 services[0] = dependency; 1152*5772Sas200622 _check_services(services); 1153*5772Sas200622 } 1154*5772Sas200622 } 1155*5772Sas200622 1156*5772Sas200622 done: 1157*5772Sas200622 if (dependency != NULL) 1158*5772Sas200622 free(dependency); 1159*5772Sas200622 if (value != NULL) 1160*5772Sas200622 scf_value_destroy(value); 1161*5772Sas200622 if (prop != NULL) 1162*5772Sas200622 scf_property_destroy(prop); 1163*5772Sas200622 if (pg != NULL) 1164*5772Sas200622 scf_pg_destroy(pg); 1165*5772Sas200622 if (iter != NULL) 1166*5772Sas200622 scf_iter_destroy(iter); 1167*5772Sas200622 if (scope != NULL) 1168*5772Sas200622 scf_scope_destroy(scope); 1169*5772Sas200622 if (inst != NULL) 1170*5772Sas200622 scf_instance_destroy(inst); 1171*5772Sas200622 if (service != NULL) 1172*5772Sas200622 scf_service_destroy(service); 1173*5772Sas200622 1174*5772Sas200622 (void) scf_handle_unbind(handle); 1175*5772Sas200622 scf_handle_destroy(handle); 1176*5772Sas200622 } 1177*5772Sas200622 1178*5772Sas200622 /* 11795331Samw * How long to wait for service to come online 11805331Samw */ 11815331Samw #define WAIT_FOR_SERVICE 15 11825331Samw 11835331Samw /* 11845331Samw * smb_enable_service() 11855331Samw * 11865331Samw */ 11875331Samw static int 11885331Samw smb_enable_service(void) 11895331Samw { 11905331Samw int i; 11915331Samw int ret = SA_OK; 1192*5772Sas200622 char *service[] = { SMBD_DEFAULT_INSTANCE_FMRI, NULL }; 11935331Samw 11945331Samw if (!smb_isonline()) { 1195*5772Sas200622 /* 1196*5772Sas200622 * Attempt to start the idmap, and other dependent 1197*5772Sas200622 * services, first. If it fails, the SMB service will 1198*5772Sas200622 * ultimately fail so we use that as the error. If we 1199*5772Sas200622 * don't try to enable idmap, smb won't start the 1200*5772Sas200622 * first time unless the admin has done it 1201*5772Sas200622 * manually. The service could be administratively 1202*5772Sas200622 * disabled so we won't always get started. 1203*5772Sas200622 */ 1204*5772Sas200622 smb_enable_dependencies(SMBD_DEFAULT_INSTANCE_FMRI); 1205*5772Sas200622 _check_services(service); 12065331Samw 12075331Samw /* Wait for service to come online */ 12085331Samw for (i = 0; i < WAIT_FOR_SERVICE; i++) { 12095331Samw if (smb_isonline()) { 1210*5772Sas200622 ret = SA_OK; 12115331Samw break; 12125331Samw } else { 12135331Samw ret = SA_BUSY; 12145331Samw (void) sleep(1); 12155331Samw } 12165331Samw } 12175331Samw } 12185331Samw return (ret); 12195331Samw } 12205331Samw 12215331Samw /* 12225331Samw * smb_validate_proto_prop(index, name, value) 12235331Samw * 12245331Samw * Verify that the property specified by name can take the new 12255331Samw * value. This is a sanity check to prevent bad values getting into 12265331Samw * the default files. 12275331Samw */ 12285331Samw static int 12295331Samw smb_validate_proto_prop(int index, char *name, char *value) 12305331Samw { 12315331Samw if ((name == NULL) || (index < 0)) 12325331Samw return (SA_BAD_VALUE); 12335331Samw 12345331Samw if (smb_proto_options[index].validator == NULL) 12355331Samw return (SA_OK); 12365331Samw 12375331Samw if (smb_proto_options[index].validator(index, value) == SA_OK) 12385331Samw return (SA_OK); 12395331Samw return (SA_BAD_VALUE); 12405331Samw } 12415331Samw 12425331Samw /* 12435331Samw * smb_set_proto_prop(prop) 12445331Samw * 12455331Samw * check that prop is valid. 12465331Samw */ 12475331Samw /*ARGSUSED*/ 12485331Samw static int 12495331Samw smb_set_proto_prop(sa_property_t prop) 12505331Samw { 12515331Samw int ret = SA_OK; 12525331Samw char *name; 12535331Samw char *value; 12545331Samw int index = -1; 12555521Sas200622 struct smb_proto_option_defs *opt; 12565331Samw 12575331Samw name = sa_get_property_attr(prop, "type"); 12585331Samw value = sa_get_property_attr(prop, "value"); 12595331Samw if (name != NULL && value != NULL) { 12605331Samw index = findprotoopt(name); 12615331Samw if (index >= 0) { 12625331Samw /* should test for valid value */ 12635331Samw ret = smb_validate_proto_prop(index, name, value); 12645331Samw if (ret == SA_OK) { 12655521Sas200622 opt = &smb_proto_options[index]; 12665521Sas200622 12675331Samw /* Save to SMF */ 1268*5772Sas200622 (void) smb_config_set(opt->smb_index, value); 12695331Samw /* 12705331Samw * Specialized refresh mechanisms can 12715331Samw * be flagged in the proto_options and 12725331Samw * processed here. 12735331Samw */ 12745521Sas200622 if (opt->refresh & SMB_REFRESH_REFRESH) 12755521Sas200622 (void) smb_config_refresh(); 12765521Sas200622 else if (opt->refresh & SMB_REFRESH_RESTART) 12775331Samw (void) smf_restart_instance( 12785331Samw SMBD_DEFAULT_INSTANCE_FMRI); 12795331Samw } 12805331Samw } 12815331Samw } 12825521Sas200622 12835331Samw if (name != NULL) 12845331Samw sa_free_attr_string(name); 12855331Samw if (value != NULL) 12865331Samw sa_free_attr_string(value); 12875331Samw 12885331Samw return (ret); 12895331Samw } 12905331Samw 12915331Samw /* 12925331Samw * smb_get_status() 12935331Samw * 12945331Samw * What is the current status of the smbd? We use the SMF state here. 12955331Samw * Caller must free the returned value. 12965331Samw */ 12975331Samw 12985331Samw static char * 12995331Samw smb_get_status(void) 13005331Samw { 13015331Samw char *state = NULL; 13025331Samw state = smf_get_state(SMBD_DEFAULT_INSTANCE_FMRI); 13035331Samw return (state != NULL ? state : "-"); 13045331Samw } 13055331Samw 13065331Samw /* 13075331Samw * This protocol plugin require resource names 13085331Samw */ 13095331Samw static uint64_t 13105331Samw smb_share_features(void) 13115331Samw { 13125331Samw return (SA_FEATURE_RESOURCE | SA_FEATURE_ALLOWSUBDIRS | 13135331Samw SA_FEATURE_ALLOWPARDIRS); 13145331Samw } 13155331Samw 13165331Samw /* 13175331Samw * This should be used to convert lmshare_info to sa_resource_t 13185331Samw * Should only be needed to build temp shares/resources to be 13195331Samw * supplied to sharemanager to display temp shares. 13205331Samw */ 13215331Samw static int 13225331Samw smb_build_tmp_sa_resource(sa_handle_t handle, lmshare_info_t *si) 13235331Samw { 13245331Samw int err; 13255331Samw sa_share_t share; 13265331Samw sa_group_t group; 13275331Samw sa_resource_t resource; 13285331Samw 13295331Samw if (si == NULL) 13305331Samw return (SA_INVALID_NAME); 13315331Samw 13325331Samw /* 13335331Samw * First determine if the "share path" is already shared 13345331Samw * somewhere. If it is, we have to use it as the authority on 13355331Samw * where the transient share lives so will use it's parent 13365331Samw * group. If it doesn't exist, it needs to land in "smb". 13375331Samw */ 13385331Samw 13395331Samw share = sa_find_share(handle, si->directory); 13405331Samw if (share != NULL) { 13415331Samw group = sa_get_parent_group(share); 13425331Samw } else { 13435331Samw group = smb_get_smb_share_group(handle); 13445331Samw if (group == NULL) 13455331Samw return (SA_NO_SUCH_GROUP); 13465331Samw share = sa_get_share(group, si->directory); 13475331Samw if (share == NULL) { 13485331Samw share = sa_add_share(group, si->directory, 13495331Samw SA_SHARE_TRANSIENT, &err); 13505331Samw if (share == NULL) 13515331Samw return (SA_NO_SUCH_PATH); 13525331Samw } 13535331Samw } 13545331Samw 13555331Samw /* 13565331Samw * Now handle the resource. Make sure that the resource is 13575331Samw * transient and added to the share. 13585331Samw */ 13595331Samw resource = sa_get_share_resource(share, si->share_name); 13605331Samw if (resource == NULL) { 13615331Samw resource = sa_add_resource(share, 13625331Samw si->share_name, SA_SHARE_TRANSIENT, &err); 13635331Samw if (resource == NULL) 13645331Samw return (SA_NO_SUCH_RESOURCE); 13655331Samw } 13665331Samw 13675331Samw /* set resource attributes now */ 13685331Samw (void) sa_set_resource_attr(resource, "description", si->comment); 13695331Samw (void) sa_set_resource_attr(resource, SHOPT_AD_CONTAINER, 13705331Samw si->container); 13715331Samw 13725331Samw return (SA_OK); 13735331Samw } 13745331Samw 13755331Samw /* 13765331Samw * Return smb transient shares. Note that we really want to look at 13775331Samw * all current shares from SMB in order to determine this. Transient 13785331Samw * shares should be those that don't appear in either the SMF or ZFS 13795331Samw * configurations. Those that are in the repositories will be 13805331Samw * filtered out by smb_build_tmp_sa_resource. 13815331Samw */ 13825331Samw static int 13835331Samw smb_list_transient(sa_handle_t handle) 13845331Samw { 13855331Samw int i, offset, num; 13865331Samw lmshare_list_t list; 13875331Samw int res; 13885331Samw 13895331Samw num = lmshrd_num_shares(); 13905331Samw if (num <= 0) 13915331Samw return (SA_OK); 13925331Samw offset = 0; 13935331Samw while (lmshrd_list(offset, &list) != NERR_InternalError) { 13945331Samw if (list.no == 0) 13955331Samw break; 13965331Samw for (i = 0; i < list.no; i++) { 13975331Samw res = smb_build_tmp_sa_resource(handle, 13985331Samw &(list.smbshr[i])); 13995331Samw if (res != SA_OK) 14005331Samw return (res); 14015331Samw } 14025331Samw offset += list.no; 14035331Samw } 14045331Samw 14055331Samw return (SA_OK); 14065331Samw } 14075331Samw 14085331Samw /* 14095331Samw * fix_resource_name(share, name, prefix) 14105331Samw * 14115331Samw * Construct a name where the ZFS dataset has the prefix replaced with "name". 14125331Samw */ 14135331Samw static char * 14145331Samw fix_resource_name(sa_share_t share, char *name, char *prefix) 14155331Samw { 14165331Samw char *dataset = NULL; 14175331Samw char *newname = NULL; 14185331Samw size_t psize; 14195331Samw size_t nsize; 14205331Samw 14215331Samw dataset = sa_get_share_attr(share, "dataset"); 14225331Samw 14235331Samw if (dataset != NULL && strcmp(dataset, prefix) != 0) { 14245331Samw psize = strlen(prefix); 14255331Samw if (strncmp(dataset, prefix, psize) == 0) { 14265331Samw /* need string plus ',' and NULL */ 14275331Samw nsize = (strlen(dataset) - psize) + strlen(name) + 2; 14285331Samw newname = calloc(nsize, 1); 14295331Samw if (newname != NULL) { 14305331Samw (void) snprintf(newname, nsize, "%s%s", name, 14315331Samw dataset + psize); 14325331Samw sa_fix_resource_name(newname); 14335331Samw } 14345331Samw sa_free_attr_string(dataset); 14355331Samw return (newname); 14365331Samw } 14375331Samw } 14385331Samw if (dataset != NULL) 14395331Samw sa_free_attr_string(dataset); 14405331Samw return (strdup(name)); 14415331Samw } 14425331Samw 14435331Samw /* 14445331Samw * smb_parse_optstring(group, options) 14455331Samw * 14465331Samw * parse a compact option string into individual options. This allows 14475331Samw * ZFS sharesmb and sharemgr "share" command to work. group can be a 14485331Samw * group, a share or a resource. 14495331Samw */ 14505331Samw static int 14515331Samw smb_parse_optstring(sa_group_t group, char *options) 14525331Samw { 14535331Samw char *dup; 14545331Samw char *base; 14555331Samw char *lasts; 14565331Samw char *token; 14575331Samw sa_optionset_t optionset; 14585331Samw sa_group_t parent = NULL; 14595331Samw sa_resource_t resource = NULL; 14605331Samw int iszfs = 0; 14615331Samw int persist = 0; 14625331Samw int need_optionset = 0; 14635331Samw int ret = SA_OK; 14645331Samw sa_property_t prop; 14655331Samw 14665331Samw /* 14675331Samw * In order to not attempt to change ZFS properties unless 14685331Samw * absolutely necessary, we never do it in the legacy parsing 14695331Samw * so we need to keep track of this. 14705331Samw */ 14715331Samw if (sa_is_share(group)) { 14725331Samw char *zfs; 14735331Samw 14745331Samw parent = sa_get_parent_group(group); 14755331Samw if (parent != NULL) { 14765331Samw zfs = sa_get_group_attr(parent, "zfs"); 14775331Samw if (zfs != NULL) { 14785331Samw sa_free_attr_string(zfs); 14795331Samw iszfs = 1; 14805331Samw } 14815331Samw } 14825331Samw } else { 14835331Samw iszfs = sa_group_is_zfs(group); 14845331Samw /* 14855331Samw * If a ZFS group, then we need to see if a resource 14865331Samw * name is being set. If so, bail with 14875331Samw * SA_PROP_SHARE_ONLY, so we come back in with a share 14885331Samw * instead of a group. 14895331Samw */ 14905331Samw if (strncmp(options, "name=", sizeof ("name=") - 1) == 0 || 14915331Samw strstr(options, ",name=") != NULL) { 14925331Samw return (SA_PROP_SHARE_ONLY); 14935331Samw } 14945331Samw } 14955331Samw 14965331Samw /* do we have an existing optionset? */ 14975331Samw optionset = sa_get_optionset(group, "smb"); 14985331Samw if (optionset == NULL) { 14995331Samw /* didn't find existing optionset so create one */ 15005331Samw optionset = sa_create_optionset(group, "smb"); 15015331Samw if (optionset == NULL) 15025331Samw return (SA_NO_MEMORY); 15035331Samw } else { 15045331Samw /* 15055331Samw * If an optionset already exists, we've come through 15065331Samw * twice so ignore the second time. 15075331Samw */ 15085331Samw return (ret); 15095331Samw } 15105331Samw 15115331Samw /* We need a copy of options for the next part. */ 15125331Samw dup = strdup(options); 15135331Samw if (dup == NULL) 15145331Samw return (SA_NO_MEMORY); 15155331Samw 15165331Samw /* 15175331Samw * SMB properties are straightforward and are strings, 15185331Samw * integers or booleans. Properties are separated by 15195331Samw * commas. It will be necessary to parse quotes due to some 15205331Samw * strings not having a restricted characters set. 15215331Samw * 15225331Samw * Note that names will create a resource. For now, if there 15235331Samw * is a set of properties "before" the first name="", those 15245331Samw * properties will be placed on the group. 15255331Samw */ 15265331Samw persist = sa_is_persistent(group); 15275331Samw base = dup; 15285331Samw token = dup; 15295331Samw lasts = NULL; 15305331Samw while (token != NULL && ret == SA_OK) { 15315331Samw ret = SA_OK; 15325331Samw token = strtok_r(base, ",", &lasts); 15335331Samw base = NULL; 15345331Samw if (token != NULL) { 15355331Samw char *value; 15365331Samw /* 15375331Samw * All SMB properties have values so there 15385331Samw * MUST be an '=' character. If it doesn't, 15395331Samw * it is a syntax error. 15405331Samw */ 15415331Samw value = strchr(token, '='); 15425331Samw if (value != NULL) { 15435331Samw *value++ = '\0'; 15445331Samw } else { 15455331Samw ret = SA_SYNTAX_ERR; 15465331Samw break; 15475331Samw } 15485331Samw /* 15495331Samw * We may need to handle a "name" property 15505331Samw * that is a ZFS imposed resource name. Each 15515331Samw * name would trigger getting a new "resource" 15525331Samw * to put properties on. For now, assume no 15535331Samw * "name" property for special handling. 15545331Samw */ 15555331Samw 15565331Samw if (strcmp(token, "name") == 0) { 15575331Samw char *prefix; 15585331Samw char *name = NULL; 15595331Samw /* 15605331Samw * We have a name, so now work on the 15615331Samw * resource level. We have a "share" 15625331Samw * in "group" due to the caller having 15635331Samw * added it. If we are called with a 15645331Samw * group, the check for group/share 15655331Samw * at the beginning of this function 15665331Samw * will bail out the parse if there is a 15675331Samw * "name" but no share. 15685331Samw */ 15695331Samw if (!iszfs) { 15705331Samw ret = SA_SYNTAX_ERR; 15715331Samw break; 15725331Samw } 15735331Samw /* 15745331Samw * Make sure the parent group has the 15755331Samw * "prefix" property since we will 15765331Samw * need to use this for constructing 15775331Samw * inherited name= values. 15785331Samw */ 15795331Samw prefix = sa_get_group_attr(parent, "prefix"); 15805331Samw if (prefix == NULL) { 15815331Samw prefix = sa_get_group_attr(parent, 15825331Samw "name"); 15835331Samw if (prefix != NULL) { 15845331Samw (void) sa_set_group_attr(parent, 15855331Samw "prefix", prefix); 15865331Samw } 15875331Samw } 15885331Samw name = fix_resource_name((sa_share_t)group, 15895331Samw value, prefix); 15905331Samw if (name != NULL) { 15915331Samw resource = sa_add_resource( 15925331Samw (sa_share_t)group, name, 15935331Samw SA_SHARE_TRANSIENT, &ret); 15945331Samw sa_free_attr_string(name); 15955331Samw } else { 15965331Samw ret = SA_NO_MEMORY; 15975331Samw } 15985331Samw if (prefix != NULL) 15995331Samw sa_free_attr_string(prefix); 16005331Samw 16015331Samw /* A resource level optionset is needed */ 16025331Samw 16035331Samw need_optionset = 1; 16045331Samw if (resource == NULL) { 16055331Samw ret = SA_NO_MEMORY; 16065331Samw break; 16075331Samw } 16085331Samw continue; 16095331Samw } 16105331Samw 16115331Samw if (need_optionset) { 16125331Samw optionset = sa_create_optionset(resource, 16135331Samw "smb"); 16145331Samw need_optionset = 0; 16155331Samw } 16165331Samw 16175331Samw prop = sa_create_property(token, value); 16185331Samw if (prop == NULL) 16195331Samw ret = SA_NO_MEMORY; 16205331Samw else 16215331Samw ret = sa_add_property(optionset, prop); 16225331Samw if (ret != SA_OK) 16235331Samw break; 16245331Samw if (!iszfs) 16255331Samw ret = sa_commit_properties(optionset, !persist); 16265331Samw } 16275331Samw } 16285331Samw free(dup); 16295331Samw return (ret); 16305331Samw } 16315331Samw 16325331Samw /* 16335331Samw * smb_sprint_option(rbuff, rbuffsize, incr, prop, sep) 16345331Samw * 16355331Samw * provides a mechanism to format SMB properties into legacy output 16365331Samw * format. If the buffer would overflow, it is reallocated and grown 16375331Samw * as appropriate. Special cases of converting internal form of values 16385331Samw * to those used by "share" are done. this function does one property 16395331Samw * at a time. 16405331Samw */ 16415331Samw 16425331Samw static void 16435331Samw smb_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr, 16445331Samw sa_property_t prop, int sep) 16455331Samw { 16465331Samw char *name; 16475331Samw char *value; 16485331Samw int curlen; 16495331Samw char *buff = *rbuff; 16505331Samw size_t buffsize = *rbuffsize; 16515331Samw 16525331Samw name = sa_get_property_attr(prop, "type"); 16535331Samw value = sa_get_property_attr(prop, "value"); 16545331Samw if (buff != NULL) 16555331Samw curlen = strlen(buff); 16565331Samw else 16575331Samw curlen = 0; 16585331Samw if (name != NULL) { 16595331Samw int len; 16605331Samw len = strlen(name) + sep; 16615331Samw 16625331Samw /* 16635331Samw * A future RFE would be to replace this with more 16645331Samw * generic code and to possibly handle more types. 16655331Samw * 16665331Samw * For now, everything else is treated as a string. If 16675331Samw * we get any properties that aren't exactly 16685331Samw * name/value pairs, we may need to 16695331Samw * interpret/transform. 16705331Samw */ 16715331Samw if (value != NULL) 16725331Samw len += 1 + strlen(value); 16735331Samw 16745331Samw while (buffsize <= (curlen + len)) { 16755331Samw /* need more room */ 16765331Samw buffsize += incr; 16775331Samw buff = realloc(buff, buffsize); 16785331Samw *rbuff = buff; 16795331Samw *rbuffsize = buffsize; 16805331Samw if (buff == NULL) { 16815331Samw /* realloc failed so free everything */ 16825331Samw if (*rbuff != NULL) 16835331Samw free(*rbuff); 16845331Samw goto err; 16855331Samw } 16865331Samw } 16875331Samw if (buff == NULL) 16885331Samw goto err; 16895331Samw (void) snprintf(buff + curlen, buffsize - curlen, 16905331Samw "%s%s=%s", sep ? "," : "", 16915331Samw name, value != NULL ? value : "\"\""); 16925331Samw 16935331Samw } 16945331Samw err: 16955331Samw if (name != NULL) 16965331Samw sa_free_attr_string(name); 16975331Samw if (value != NULL) 16985331Samw sa_free_attr_string(value); 16995331Samw } 17005331Samw 17015331Samw /* 17025331Samw * smb_format_resource_options(resource, hier) 17035331Samw * 17045331Samw * format all the options on the group into a flattened option 17055331Samw * string. If hier is non-zero, walk up the tree to get inherited 17065331Samw * options. 17075331Samw */ 17085331Samw 17095331Samw static char * 17105331Samw smb_format_options(sa_group_t group, int hier) 17115331Samw { 17125331Samw sa_optionset_t options = NULL; 17135331Samw sa_property_t prop; 17145331Samw int sep = 0; 17155331Samw char *buff; 17165331Samw size_t buffsize; 17175331Samw 17185331Samw 17195331Samw buff = malloc(OPT_CHUNK); 17205331Samw if (buff == NULL) 17215331Samw return (NULL); 17225331Samw 17235331Samw buff[0] = '\0'; 17245331Samw buffsize = OPT_CHUNK; 17255331Samw 17265331Samw /* 17275331Samw * We may have a an optionset relative to this item. format 17285331Samw * these if we find them and then add any security definitions. 17295331Samw */ 17305331Samw 17315331Samw options = sa_get_derived_optionset(group, "smb", hier); 17325331Samw 17335331Samw /* 17345331Samw * do the default set first but skip any option that is also 17355331Samw * in the protocol specific optionset. 17365331Samw */ 17375331Samw if (options != NULL) { 17385331Samw for (prop = sa_get_property(options, NULL); 17395331Samw prop != NULL; prop = sa_get_next_property(prop)) { 17405331Samw /* 17415331Samw * use this one since we skipped any 17425331Samw * of these that were also in 17435331Samw * optdefault 17445331Samw */ 17455331Samw smb_sprint_option(&buff, &buffsize, OPT_CHUNK, 17465331Samw prop, sep); 17475331Samw if (buff == NULL) { 17485331Samw /* 17495331Samw * buff could become NULL if there 17505331Samw * isn't enough memory for 17515331Samw * smb_sprint_option to realloc() 17525331Samw * as necessary. We can't really 17535331Samw * do anything about it at this 17545331Samw * point so we return NULL. The 17555331Samw * caller should handle the 17565331Samw * failure. 17575331Samw */ 17585331Samw if (options != NULL) 17595331Samw sa_free_derived_optionset( 17605331Samw options); 17615331Samw return (buff); 17625331Samw } 17635331Samw sep = 1; 17645331Samw } 17655331Samw } 17665331Samw 17675331Samw if (options != NULL) 17685331Samw sa_free_derived_optionset(options); 17695331Samw return (buff); 17705331Samw } 17715331Samw 17725331Samw /* 17735331Samw * smb_rename_resource(resource, newname) 17745331Samw * 17755331Samw * Change the current exported name of the resource to newname. 17765331Samw */ 17775331Samw /*ARGSUSED*/ 17785331Samw int 17795331Samw smb_rename_resource(sa_handle_t handle, sa_resource_t resource, char *newname) 17805331Samw { 17815331Samw int ret = SA_OK; 17825331Samw int err; 17835331Samw char *oldname; 17845331Samw 17855331Samw oldname = sa_get_resource_attr(resource, "name"); 17865331Samw if (oldname == NULL) 17875331Samw return (SA_NO_SUCH_RESOURCE); 17885331Samw 17895331Samw err = lmshrd_rename(oldname, newname); 17905331Samw 17915331Samw /* improve error values somewhat */ 17925331Samw switch (err) { 17935331Samw case NERR_Success: 17945331Samw break; 17955331Samw case NERR_InternalError: 17965331Samw ret = SA_SYSTEM_ERR; 17975331Samw break; 17985331Samw case NERR_DuplicateShare: 17995331Samw ret = SA_DUPLICATE_NAME; 18005331Samw break; 18015331Samw default: 18025331Samw ret = SA_CONFIG_ERR; 18035331Samw break; 18045331Samw } 18055331Samw 18065331Samw return (ret); 18075331Samw } 1808