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