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