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