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