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