xref: /illumos-gate/usr/src/lib/libshare/smbfs/libshare_smbfs.c (revision e688a0bc223983e7c7fedad44c92b8d0292a10f7)
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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * SMB specific functions
31  */
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <zone.h>
38 #include <errno.h>
39 #include <locale.h>
40 #include <signal.h>
41 #include <fcntl.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <syslog.h>
45 #include "libshare.h"
46 #include "libshare_impl.h"
47 #include <pwd.h>
48 #include <limits.h>
49 #include <libscf.h>
50 #include <strings.h>
51 #include "libshare_smbfs.h"
52 #include <rpcsvc/daemon_utils.h>
53 #include <arpa/inet.h>
54 #include <uuid/uuid.h>
55 #include <netsmb/smb_lib.h>
56 
57 #define	SMBFS_PROTOCOL_NAME	"smbfs"
58 
59 /* internal functions */
60 static uint64_t smbfs_features();
61 static int smbfs_init();
62 static void smbfs_fini();
63 static int smbfs_set_proto_prop(sa_property_t);
64 static sa_protocol_properties_t smbfs_get_proto_set();
65 static char *smbfs_get_status();
66 static int smbfs_delete_section(char *);
67 static int smbfs_delete_property_group(char *);
68 
69 static int range_check_validator(int, char *, char *);
70 static int string_length_check_validator(int, char *, char *);
71 static int yes_no_validator(int, char *, char *);
72 static int ip_address_validator(int, char *, char *);
73 static int minauth_validator(int, char *, char *);
74 static int password_validator(int, char *, char *);
75 #ifdef NOT_DEFINED
76 static int nbscope_validator(int, char *, char *);
77 #endif
78 
79 int propset_changed = 0;
80 
81 /*
82  * ops vector that provides the protocol specific info and operations
83  * for share management.
84  */
85 
86 struct sa_plugin_ops sa_plugin_ops = {
87 	SA_PLUGIN_VERSION,
88 	SMBFS_PROTOCOL_NAME,
89 	smbfs_init,
90 	smbfs_fini,
91 	NULL,	/* share */
92 	NULL,	/* unshare */
93 	NULL,	/* valid_prop */
94 	NULL,	/* valid_space */
95 	NULL,	/* security_prop */
96 	NULL,	/* legacy_opts */
97 	NULL,	/* legacy_format */
98 	smbfs_set_proto_prop,
99 	smbfs_get_proto_set,
100 	smbfs_get_status,
101 	NULL,	/* space_alias */
102 	NULL,	/* update_legacy */
103 	NULL,	/* delete_legacy */
104 	NULL,	/* change_notify */
105 	NULL,	/* enable_resource */
106 	NULL,	/* disable_resource */
107 	smbfs_features,
108 	NULL,	/* get_transient_shares */
109 	NULL,	/* notify_resource */
110 	NULL,	/* rename_resource */
111 	NULL,	/* run_command */
112 	NULL,	/* command_help */
113 	smbfs_delete_section,
114 };
115 
116 /*
117  * is_a_number(number)
118  *
119  * is the string a number in one of the forms we want to use?
120  */
121 
122 static int
123 is_a_number(char *number)
124 {
125 	int ret = 1;
126 	int hex = 0;
127 
128 	if (strncmp(number, "0x", 2) == 0) {
129 		number += 2;
130 		hex = 1;
131 	} else if (*number == '-') {
132 		number++; /* skip the minus */
133 	}
134 
135 	while (ret == 1 && *number != '\0') {
136 		if (hex) {
137 			ret = isxdigit(*number++);
138 		} else {
139 			ret = isdigit(*number++);
140 		}
141 	}
142 	return (ret);
143 }
144 
145 /*
146  * Protocol management functions
147  *
148  * properties defined in the default files are defined in
149  * proto_option_defs for parsing and validation.
150  */
151 
152 struct smbclnt_proto_option_defs smbclnt_proto_options[] = {
153 	{ "section", NULL, PROTO_OPT_SECTION,
154 	    0, 0, MAX_VALUE_BUFLEN,
155 	    string_length_check_validator},
156 	{ "addr", NULL, PROTO_OPT_ADDR,
157 	    0, 0, MAX_VALUE_BUFLEN,
158 	    ip_address_validator},
159 	{ "minauth", NULL, PROTO_OPT_MINAUTH,
160 	    0, 0, MAX_VALUE_BUFLEN,
161 	    minauth_validator},
162 	{ "nbns_broadcast", NULL, PROTO_OPT_NBNS_BROADCAST,
163 	    0, 0, 0,
164 	    yes_no_validator},
165 	{ "nbns_enable", NULL, PROTO_OPT_NBNS_ENABLE,
166 	    0, 0, 0,
167 	    yes_no_validator},
168 	{ "nbns", NULL, PROTO_OPT_NBNSADDR,
169 	    0, 0, MAX_VALUE_BUFLEN,
170 	    ip_address_validator},
171 	{ "password", NULL, PROTO_OPT_PASSWORD,
172 	    0, 0, MAX_VALUE_BUFLEN,
173 	    password_validator},
174 	{ "timeout", NULL, PROTO_OPT_TIMEOUT,
175 	    0, 0, 60,
176 	    range_check_validator},
177 	{ "user", NULL, PROTO_OPT_USER,
178 	    0, 0, MAX_VALUE_BUFLEN,
179 	    string_length_check_validator},
180 	{ "domain", NULL, PROTO_OPT_DOMAIN,
181 	    0, 0, MAX_VALUE_BUFLEN,
182 	    string_length_check_validator},
183 	{ "workgroup", NULL, PROTO_OPT_WORKGROUP,
184 	    0, 0, MAX_VALUE_BUFLEN,
185 	    string_length_check_validator},
186 #ifdef NOT_DEFINED
187 	{ "nbscope", NULL, PROTO_OPT_NBSCOPE,
188 	    0, 0, MAX_VALUE_BUFLEN,
189 	    nbscope_validator},
190 	{ "nbtimeout", NULL, PROTO_OPT_NBTIMEOUT,
191 	    0, 0, 60,
192 	    range_check_validator},
193 	{ "retry_count", NULL, PROTO_OPT_RETRY_COUNT,
194 	    0, 0, 10,
195 	    range_check_validator},
196 	{ "use_negprot_domain", NULL, PROTO_OPT_USE_NEGPROT_DOMAIN,
197 	    0, 0, 0,
198 	    yes_no_validator},
199 	{ "charset", NULL, PROTO_OPT_CHARSETS,
200 	    0, 0, MAX_VALUE_BUFLEN,
201 	    ip_address_validator},
202 #endif
203 	{NULL}
204 };
205 
206 /*
207  * Check the range of value as int range.
208  */
209 /*ARGSUSED*/
210 static int
211 range_check_validator(int index, char *section, char *value)
212 {
213 	int ret = SA_OK;
214 
215 	if (value == NULL)
216 		return (SA_BAD_VALUE);
217 	if (strlen(value) == 0)
218 		return (SA_OK);
219 	if (!is_a_number(value)) {
220 		ret = SA_BAD_VALUE;
221 	} else {
222 		int val;
223 		val = strtoul(value, NULL, 0);
224 		if (val < smbclnt_proto_options[index].minval ||
225 		    val > smbclnt_proto_options[index].maxval)
226 			ret = SA_BAD_VALUE;
227 	}
228 	return (ret);
229 }
230 
231 /*
232  * Check the length of the string
233  */
234 /*ARGSUSED*/
235 static int
236 string_length_check_validator(int index, char *section, char *value)
237 {
238 	int ret = SA_OK;
239 
240 	if (value == NULL)
241 		return (SA_BAD_VALUE);
242 	if (strlen(value) == 0)
243 		return (SA_OK);
244 	if (strlen(value) > smbclnt_proto_options[index].maxval)
245 		ret = SA_BAD_VALUE;
246 	return (ret);
247 }
248 
249 /*
250  * Check yes/no
251  */
252 /*ARGSUSED*/
253 static int
254 yes_no_validator(int index, char *section, char *value)
255 {
256 	if (value == NULL)
257 		return (SA_BAD_VALUE);
258 	if (strlen(value) == 0)
259 		return (SA_OK);
260 	if ((strcasecmp(value, "yes") == 0) ||
261 	    (strcasecmp(value, "no") == 0) ||
262 	    (strcasecmp(value, "true") == 0) ||
263 	    (strcasecmp(value, "false") == 0))
264 		return (SA_OK);
265 	return (SA_BAD_VALUE);
266 }
267 
268 /*
269  * Check IP address.
270  */
271 /*ARGSUSED*/
272 static int
273 ip_address_validator(int index, char *section, char *value)
274 {
275 	int len;
276 
277 	if (value == NULL)
278 		return (SA_BAD_VALUE);
279 	len = strlen(value);
280 	if (len == 0)
281 		return (SA_OK);
282 	if (len > MAX_VALUE_BUFLEN)
283 		return (SA_BAD_VALUE);
284 	return (SA_OK);
285 }
286 
287 /*ARGSUSED*/
288 static int
289 minauth_validator(int index, char *section, char *value)
290 {
291 	if (value == NULL)
292 		return (SA_BAD_VALUE);
293 	if (strlen(value) == 0)
294 		return (SA_OK);
295 	if (strcmp(value, "kerberos") == 0 ||
296 	    strcmp(value, "ntlmv2") == 0 ||
297 	    strcmp(value, "ntlm") == 0 ||
298 	    strcmp(value, "lm") == 0 ||
299 	    strcmp(value, "none") == 0)
300 		return (SA_OK);
301 	else
302 		return (SA_BAD_VALUE);
303 }
304 
305 #ifdef NOT_DEFINED
306 /*ARGSUSED*/
307 static int
308 nbscope_validator(int index, char *section, char *value)
309 {
310 	/*
311 	 * XXX - not sure what's legal here.  Looks like it's not
312 	 * used in nb_name_encode() right now anyway.
313 	 */
314 	return (SA_OK);
315 }
316 #endif
317 
318 /*ARGSUSED*/
319 static int
320 password_validator(int index, char *section, char *value)
321 {
322 	char buffer[100];
323 
324 	/* mangled passwords will start with this pattern */
325 	if (strlen(value) == 0)
326 		return (SA_OK);
327 	if (strncmp(value, "$$1", 3) != 0)
328 		return (SA_PASSWORD_ENC);
329 	if (smb_simpledecrypt(buffer, value) != 0)
330 		return (SA_BAD_VALUE);
331 	return (SA_OK);
332 }
333 
334 
335 /*
336  * the protoset holds the defined options so we don't have to read
337  * them multiple times
338  */
339 sa_protocol_properties_t protoset;
340 
341 static int
342 findprotoopt(char *name)
343 {
344 	int i;
345 	for (i = 0; smbclnt_proto_options[i].name != NULL; i++) {
346 		if (strcasecmp(smbclnt_proto_options[i].name, name) == 0)
347 			return (i);
348 	}
349 	return (-1);
350 }
351 
352 /*
353  * Load the persistent settings from SMF.  Each section is an SMF
354  * property group with an "S-" prefix and a UUID, and the section
355  * is itself a property which can have a more flexible name than
356  * a property group name can have.  The section name need not be
357  * the first property, so we have to be a little flexible, but
358  * the change of name of the property groups is a reliable way
359  * to know that we're seeing a different section.
360  */
361 int
362 smbclnt_config_load()
363 {
364 	scf_simple_app_props_t *props = NULL;
365 	scf_simple_prop_t *prop = NULL, *lastprop = NULL;
366 	char *lastpgname = NULL, *pgname = NULL;
367 	char *name = NULL, *value = NULL;
368 	sa_property_t sect, node;
369 	int pending = 0;
370 #ifdef DEBUG
371 	char *sectname = NULL;
372 #endif
373 
374 	props = scf_simple_app_props_get(NULL, SMBC_DEFAULT_INSTANCE_FMRI);
375 	if (props == NULL)
376 		return (-1);
377 
378 	while ((prop = (scf_simple_prop_t *)
379 	    scf_simple_app_props_next(props, lastprop)) != NULL) {
380 
381 		/* Ignore properties that don't have our prefix */
382 		pgname = scf_simple_prop_pgname(prop);
383 		if (strncmp("S-", pgname, 2) != 0) {
384 			lastprop = prop;
385 			continue;
386 		}
387 
388 		/* Note property group name changes, which mark sections */
389 		if (lastpgname == NULL || strcmp(lastpgname, pgname) != 0) {
390 #ifdef DEBUG
391 			if (pending)
392 				fprintf(stderr, "smbclnt_config_load: "
393 				    "Ignoring empty section %s\n", sectname);
394 			fprintf(stderr, "smbclnt_config_load: new pg=%s\n",
395 			    pgname);
396 #endif
397 			sect = sa_create_section(NULL, pgname+2);
398 			(void) xmlSetProp(sect, (xmlChar *)"type",
399 			    (xmlChar *)SMBFS_PROTOCOL_NAME);
400 			if (lastpgname)
401 				free(lastpgname);
402 			lastpgname = strdup(pgname);
403 			pending = 1;
404 		}
405 		name = scf_simple_prop_name(prop);
406 		value = scf_simple_prop_next_astring(prop);
407 
408 		/* If we get a section name, apply it and consume it */
409 		if (strncmp("section", name, 7) == 0 && value != NULL) {
410 #ifdef DEBUG
411 			if (sectname)
412 				free(sectname);
413 			sectname = strdup(value);
414 			fprintf(stderr, "smbclnt_config_load: section=%s\n",
415 			    sectname);
416 #endif
417 			(void) xmlSetProp(sect, (xmlChar *)"name",
418 			    (xmlChar *)value);
419 			lastprop = prop;
420 			continue;
421 		}
422 #ifdef DEBUG
423 		fprintf(stderr, "pg=%s, sect=%s, nm=%s, val=%s\n",
424 		    pgname, sectname ? sectname : "NULL", name, value);
425 #endif
426 		/*
427 		 * If we have an ordinary property, add to the section.
428 		 * Also, if this is the first ordinary property, we
429 		 * can commit the non-empty section to the protoset.
430 		 */
431 		node = sa_create_property(name, value);
432 		(void) sa_add_protocol_property(sect, node);
433 		lastprop = prop;
434 		if (pending) {
435 			(void) sa_add_protocol_property(protoset, sect);
436 			pending = 0;
437 		}
438 	}
439 	scf_simple_app_props_free(props);
440 	if (pending) {
441 #ifdef DEBUG
442 		fprintf(stderr, "smbclnt_config_load: "
443 		    "Deleting empty section %s\n", sectname);
444 #endif
445 		(void) smbfs_delete_property_group(lastpgname);
446 	}
447 	if (lastpgname)
448 		free(lastpgname);
449 	return (0);
450 }
451 
452 /*
453  * Save the set of properties for a particular section, which is
454  * stored as a single property group.  Properties will have been
455  * changed earlier by one or more calls to smbfs_save_property(),
456  * which only set the value in our array and marked them as
457  * SMBC_MODIFIED.
458  */
459 int
460 smbfs_save_propset()
461 {
462 	smb_scfhandle_t *handle = NULL;
463 	char propgroup[256];
464 	char *section = smbclnt_proto_options[PROTO_OPT_SECTION].value;
465 	char *uu = NULL;
466 	uuid_t uuid;
467 	int i, ret = 0;
468 	sa_property_t propset;
469 	int new = 0, nonnull = 0;
470 
471 	propset = sa_get_protocol_section(protoset, section);
472 	(void) strncpy(propgroup, SMBC_PG_PREFIX, SMBC_PG_PREFIX_LEN);
473 	propgroup[SMBC_PG_PREFIX_LEN] = '\0';
474 	uu = sa_get_property_attr(propset, "extra");
475 	if (uu != NULL) {
476 		(void) strncat(propgroup, uu, UUID_PRINTABLE_STRING_LENGTH);
477 		free(uu);
478 	} else {
479 		new = 1;
480 		smbclnt_proto_options[PROTO_OPT_SECTION].flags |= SMBC_MODIFIED;
481 		uuid_generate(uuid);
482 		uuid_unparse(uuid, &propgroup[SMBC_PG_PREFIX_LEN]);
483 	}
484 #ifdef DEBUG
485 	fprintf(stderr, "smbfs_save_propset: %s pgname=%s\n",
486 	    new ? "new" : "old", propgroup);
487 #endif
488 
489 	handle = smb_smf_scf_init(SMBC_FMRI_PREFIX);
490 	if (handle == NULL) {
491 		return (1);
492 	}
493 
494 	if ((ret = smb_smf_instance_create(handle, SMBC_FMRI_PREFIX,
495 	    SMBC_PG_INSTANCE)) != SMBC_SMF_OK) {
496 		goto out;
497 	}
498 
499 	if ((ret = smb_smf_create_instance_pgroup(handle, propgroup))
500 	    != SMBC_SMF_OK) {
501 		goto out;
502 	}
503 
504 	if ((ret = smb_smf_start_transaction(handle)) != SMBC_SMF_OK) {
505 		goto out;
506 	}
507 
508 	for (i = PROTO_OPT_SECTION+1; i <= SMBC_OPT_MAX; i++) {
509 		if ((smbclnt_proto_options[i].flags & SMBC_MODIFIED) == 0)
510 			continue;
511 #ifdef DEBUG
512 		fprintf(stderr, "smbfs_save_propset: saving "
513 		    "i=%d/name=%s/value=%s\n", i,
514 		    smbclnt_proto_options[i].name,
515 		    smbclnt_proto_options[i].value);
516 #endif
517 		if (strcmp(smbclnt_proto_options[i].value, "") == 0)
518 			ret = smb_smf_delete_property(handle,
519 			    smbclnt_proto_options[i].name);
520 		else {
521 			ret = smb_smf_set_string_property(handle,
522 			    smbclnt_proto_options[i].name,
523 			    smbclnt_proto_options[i].value);
524 			nonnull = 1;
525 		}
526 		free(smbclnt_proto_options[i].value);
527 		smbclnt_proto_options[i].value = NULL;
528 		smbclnt_proto_options[i].flags &= ~SMBC_MODIFIED;
529 		if (ret != SMBC_SMF_OK)
530 			goto outtrans;
531 	}
532 	/*
533 	 * Suppress new, null entries by not saving the section name.
534 	 */
535 	if (!new || nonnull) {
536 #ifdef DEBUG
537 		fprintf(stderr, "smbfs_save_propset: saving "
538 		    "i=%d/name=%s/value=%s\n", PROTO_OPT_SECTION,
539 		    smbclnt_proto_options[PROTO_OPT_SECTION].name,
540 		    smbclnt_proto_options[PROTO_OPT_SECTION].value);
541 #endif
542 		ret = smb_smf_set_string_property(handle,
543 		    smbclnt_proto_options[PROTO_OPT_SECTION].name,
544 		    smbclnt_proto_options[PROTO_OPT_SECTION].value);
545 		free(smbclnt_proto_options[PROTO_OPT_SECTION].value);
546 		smbclnt_proto_options[PROTO_OPT_SECTION].value = NULL;
547 		smbclnt_proto_options[PROTO_OPT_SECTION].flags &=
548 		    ~SMBC_MODIFIED;
549 	}
550 	propset_changed = 0;
551 
552 outtrans:
553 	ret = smb_smf_end_transaction(handle);
554 out:
555 	smb_smf_scf_fini(handle);
556 	return (ret);
557 }
558 
559 /*
560  * initprotofromdefault()
561  *
562  * read the default file(s) and add the defined values to the
563  * protoset.  Note that default values are known from the built in
564  * table in case the file doesn't have a definition.
565  */
566 
567 static int
568 initprotofromdefault()
569 {
570 	protoset = sa_create_protocol_properties(SMBFS_PROTOCOL_NAME);
571 	if (protoset == NULL)
572 		return (SA_NO_MEMORY);
573 	if (smbclnt_config_load() != 0)
574 		return (SA_OK);
575 
576 	return (SA_OK);
577 }
578 
579 /*
580  *
581  * smbfs_features()
582  *
583  * Report the plugin's features
584  */
585 static uint64_t
586 smbfs_features()
587 {
588 	return (SA_FEATURE_HAS_SECTIONS | SA_FEATURE_ADD_PROPERTIES);
589 }
590 
591 /*
592  * smbfs_init()
593  *
594  * Initialize the smb plugin.
595  */
596 
597 static int
598 smbfs_init()
599 {
600 	int ret = SA_OK;
601 
602 	if (sa_plugin_ops.sa_init != smbfs_init) {
603 		return (SA_SYSTEM_ERR);
604 	}
605 
606 	if (initprotofromdefault() != SA_OK) {
607 		return (SA_SYSTEM_ERR);
608 	}
609 
610 	return (ret);
611 }
612 
613 /*
614  * smbfs_fini()
615  *
616  * uninitialize the smb plugin. Want to avoid memory leaks.
617  */
618 
619 static void
620 smbfs_fini()
621 {
622 	if (propset_changed)
623 		(void) smbfs_save_propset();
624 }
625 
626 /*
627  * smbfs_get_proto_set()
628  *
629  * Return an optionset with all the protocol specific properties in
630  * it.
631  */
632 
633 static sa_protocol_properties_t
634 smbfs_get_proto_set()
635 {
636 	return (protoset);
637 }
638 
639 /*
640  * smbfs_validate_proto_prop(index, name, value)
641  *
642  * Verify that the property specifed by name can take the new
643  * value. This is a sanity check to prevent bad values getting into
644  * the default files.
645  */
646 static int
647 smbfs_validate_proto_prop(int index, char *section, char *name, char *value)
648 {
649 	if ((section == NULL) || (name == NULL) || (index < 0))
650 		return (SA_BAD_VALUE);
651 
652 	if (smbclnt_proto_options[index].validator == NULL)
653 		return (SA_OK);
654 
655 	return (smbclnt_proto_options[index].validator(index, section, value));
656 }
657 
658 /*
659  * Save a property to our array; it will be stored to SMF later by
660  * smbfs_save_propset().
661  */
662 int
663 smbfs_save_property(int index, char *section, char *value)
664 {
665 	char *s;
666 
667 	if (index == PROTO_OPT_WORKGROUP) {
668 #ifdef DEBUG
669 		fprintf(stderr, "smbfs_save_property: "
670 		    "index %d being mapped to %d\n",
671 		    index, PROTO_OPT_DOMAIN);
672 #endif
673 		index = PROTO_OPT_DOMAIN;
674 	}
675 #ifdef DEBUG
676 	fprintf(stderr, "smbfs_save_property: "
677 	    "section=%s, index=%d, name=%s, value=%s\n",
678 	    section, index, smbclnt_proto_options[index].name, value);
679 #endif
680 	propset_changed = 1;
681 	s = strdup(section);
682 	if (s == NULL)
683 		return (-1);
684 	smbclnt_proto_options[PROTO_OPT_SECTION].value = s;
685 	s = strdup(value);
686 	if (s == NULL)
687 		return (-1);
688 	smbclnt_proto_options[index].value = s;
689 	smbclnt_proto_options[index].flags |= SMBC_MODIFIED;
690 	return (0);
691 }
692 
693 /*
694  * smbfs_set_proto_prop(prop)
695  *
696  * check that prop is valid.
697  */
698 /*ARGSUSED*/
699 static int
700 smbfs_set_proto_prop(sa_property_t prop)
701 {
702 	int ret = SA_OK;
703 	char *name;
704 	char *value;
705 	char *section;
706 	int i = -1;
707 
708 	section = sa_get_property_attr(prop, "section");
709 	if (section == NULL)
710 		return (SA_NO_SECTION);
711 	name = sa_get_property_attr(prop, "type");
712 	value = sa_get_property_attr(prop, "value");
713 	if (name != NULL && value != NULL) {
714 		i = findprotoopt(name);
715 		if (i >= 0) {
716 			ret = smbfs_validate_proto_prop(i, section,
717 			    name, value);
718 			if (ret == SA_OK) {
719 				if (smbfs_save_property(i, section,
720 				    value) != 0) {
721 					ret = SA_SYSTEM_ERR;
722 					errno = EIO;
723 				}
724 			}
725 		} else
726 			ret = SA_INVALID_NAME;
727 	}
728 	if (name != NULL)
729 		sa_free_attr_string(name);
730 	if (value != NULL)
731 		sa_free_attr_string(value);
732 
733 	return (ret);
734 }
735 
736 /*
737  * smbfs_get_status()
738  *
739  * What is the current status of the smbd? We use the SMF state here.
740  * Caller must free the returned value.
741  */
742 
743 static char *
744 smbfs_get_status()
745 {
746 	char *state = "enabled";
747 	state = smf_get_state(SMBC_DEFAULT_INSTANCE_FMRI);
748 	return (state != NULL ? state : strdup("-"));
749 }
750 
751 /*
752  * Delete a section by its name, which we will have read into an
753  * XML optionset above.  We need to find it and find its UUID to
754  * be able to generate the property group name in order to call
755  * smbfs_delete_property_group().
756  */
757 static int
758 smbfs_delete_section(char *section)
759 {
760 	char propgroup[256];
761 	char *uu = NULL;
762 	sa_property_t propset;
763 	int ret = SA_SYSTEM_ERR;
764 
765 	propset = sa_get_protocol_section(protoset, section);
766 	(void) strncpy(propgroup, SMBC_PG_PREFIX, SMBC_PG_PREFIX_LEN);
767 	propgroup[SMBC_PG_PREFIX_LEN] = '\0';
768 	uu = sa_get_property_attr(propset, "extra");
769 	if (uu == NULL)
770 		goto out;
771 	(void) strncat(propgroup, uu, UUID_PRINTABLE_STRING_LENGTH);
772 	free(uu);
773 	if ((ret = smbfs_delete_property_group(propgroup)) != SMBC_SMF_OK)
774 		goto out;
775 	ret = SA_OK;
776 out:
777 	return (ret);
778 }
779 
780 /*
781  * Delete a property group by its name.  Called to do a 'delsect'
782  * or called when smbclnt_config_load() notices an empty section
783  * at the end of the properties.
784  */
785 static int
786 smbfs_delete_property_group(char *propgroup)
787 {
788 	smb_scfhandle_t *handle = NULL;
789 	int ret = SA_SYSTEM_ERR;
790 
791 #ifdef DEBUG
792 	fprintf(stderr, "smbfs_delete_property_group: pgname=%s\n", propgroup);
793 #endif
794 
795 	handle = smb_smf_scf_init(SMBC_FMRI_PREFIX);
796 	if (handle == NULL)
797 		goto out;
798 
799 	if ((ret = smb_smf_instance_create(handle, SMBC_FMRI_PREFIX,
800 	    SMBC_PG_INSTANCE)) != SMBC_SMF_OK)
801 		goto out;
802 
803 	if ((ret = smb_smf_delete_instance_pgroup(handle, propgroup))
804 	    != SMBC_SMF_OK)
805 		goto out;
806 	ret = SA_OK;
807 out:
808 	smb_smf_scf_fini(handle);
809 #ifdef DEBUG
810 	fprintf(stderr, "smbfs_delete_property_group: returning %d\n", ret);
811 #endif
812 	return (ret);
813 }
814