xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c (revision 3e2c0c0978d26f8b8020b49760008c6bb6e59221)
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  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
24  */
25 
26 /*
27  * CIFS configuration management library
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <synch.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <syslog.h>
37 #include <netdb.h>
38 #include <ctype.h>
39 #include <sys/types.h>
40 #include <libscf.h>
41 #include <assert.h>
42 #include <uuid/uuid.h>
43 #include <smbsrv/libsmb.h>
44 
45 typedef struct smb_cfg_param {
46 	smb_cfg_id_t sc_id;
47 	char *sc_name;
48 	int sc_type;
49 	uint32_t sc_flags;
50 } smb_cfg_param_t;
51 
52 struct str_val {
53 	char *str;
54 	uint32_t val;
55 };
56 
57 /*
58  * config parameter flags
59  */
60 #define	SMB_CF_PROTECTED	0x01
61 #define	SMB_CF_EXEC		0x02
62 
63 /* idmap SMF fmri and Property Group */
64 #define	IDMAP_FMRI_PREFIX		"system/idmap"
65 #define	MACHINE_SID			"machine_sid"
66 #define	MACHINE_UUID			"machine_uuid"
67 #define	IDMAP_DOMAIN			"domain_name"
68 #define	IDMAP_PREF_DC			"preferred_dc"
69 #define	IDMAP_SITE_NAME			"site_name"
70 #define	IDMAP_PG_NAME			"config"
71 
72 #define	SMB_SECMODE_WORKGRP_STR		"workgroup"
73 #define	SMB_SECMODE_DOMAIN_STR		"domain"
74 
75 #define	SMB_ENC_LEN	1024
76 #define	SMB_DEC_LEN	256
77 
78 static char *b64_data =
79 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
80 
81 static smb_cfg_param_t smb_cfg_table[] =
82 {
83 	{SMB_CI_VERSION, "sv_version", SCF_TYPE_ASTRING, 0},
84 
85 	/* Oplock configuration, Kernel Only */
86 	{SMB_CI_OPLOCK_ENABLE, "oplock_enable", SCF_TYPE_BOOLEAN, 0},
87 
88 	/* Autohome configuration */
89 	{SMB_CI_AUTOHOME_MAP, "autohome_map", SCF_TYPE_ASTRING, 0},
90 
91 	/* Domain/PDC configuration */
92 	{SMB_CI_DOMAIN_SID, "domain_sid", SCF_TYPE_ASTRING, 0},
93 	{SMB_CI_DOMAIN_MEMB, "domain_member", SCF_TYPE_BOOLEAN, 0},
94 	{SMB_CI_DOMAIN_NAME, "domain_name", SCF_TYPE_ASTRING, 0},
95 	{SMB_CI_DOMAIN_FQDN, "fqdn", SCF_TYPE_ASTRING, 0},
96 	{SMB_CI_DOMAIN_FOREST, "forest", SCF_TYPE_ASTRING, 0},
97 	{SMB_CI_DOMAIN_GUID, "domain_guid", SCF_TYPE_ASTRING, 0},
98 	{SMB_CI_DOMAIN_SRV, "pdc", SCF_TYPE_ASTRING, 0},
99 
100 	/* WINS configuration */
101 	{SMB_CI_WINS_SRV1, "wins_server_1", SCF_TYPE_ASTRING, 0},
102 	{SMB_CI_WINS_SRV2, "wins_server_2", SCF_TYPE_ASTRING, 0},
103 	{SMB_CI_WINS_EXCL, "wins_exclude", SCF_TYPE_ASTRING, 0},
104 
105 	/* Kmod specific configuration */
106 	{SMB_CI_MAX_WORKERS, "max_workers", SCF_TYPE_INTEGER, 0},
107 	{SMB_CI_MAX_CONNECTIONS, "max_connections", SCF_TYPE_INTEGER, 0},
108 	{SMB_CI_KEEPALIVE, "keep_alive", SCF_TYPE_INTEGER, 0},
109 	{SMB_CI_RESTRICT_ANON, "restrict_anonymous", SCF_TYPE_BOOLEAN, 0},
110 
111 	{SMB_CI_SIGNING_ENABLE, "signing_enabled", SCF_TYPE_BOOLEAN, 0},
112 	{SMB_CI_SIGNING_REQD, "signing_required", SCF_TYPE_BOOLEAN, 0},
113 
114 	/* Kmod tuning configuration */
115 	{SMB_CI_SYNC_ENABLE, "sync_enable", SCF_TYPE_BOOLEAN, 0},
116 
117 	/* SMBd configuration */
118 	{SMB_CI_SECURITY, "security", SCF_TYPE_ASTRING, 0},
119 	{SMB_CI_NETBIOS_ENABLE, "netbios_enable", SCF_TYPE_BOOLEAN, 0},
120 	{SMB_CI_NBSCOPE, "netbios_scope", SCF_TYPE_ASTRING, 0},
121 	{SMB_CI_SYS_CMNT, "system_comment", SCF_TYPE_ASTRING, 0},
122 	{SMB_CI_LM_LEVEL, "lmauth_level", SCF_TYPE_INTEGER, 0},
123 
124 	/* ADS Configuration */
125 	{SMB_CI_ADS_SITE, "ads_site", SCF_TYPE_ASTRING, 0},
126 
127 	/* Dynamic DNS */
128 	{SMB_CI_DYNDNS_ENABLE, "ddns_enable", SCF_TYPE_BOOLEAN, 0},
129 
130 	{SMB_CI_MACHINE_PASSWD, "machine_passwd", SCF_TYPE_ASTRING,
131 	    SMB_CF_PROTECTED},
132 
133 	{SMB_CI_MACHINE_UUID, "machine_uuid", SCF_TYPE_ASTRING, 0},
134 	{SMB_CI_KPASSWD_SRV, "kpasswd_server", SCF_TYPE_ASTRING, 0},
135 	{SMB_CI_KPASSWD_DOMAIN, "kpasswd_domain", SCF_TYPE_ASTRING, 0},
136 	{SMB_CI_KPASSWD_SEQNUM, "kpasswd_seqnum", SCF_TYPE_INTEGER, 0},
137 	{SMB_CI_NETLOGON_SEQNUM, "netlogon_seqnum", SCF_TYPE_INTEGER, 0},
138 	{SMB_CI_IPV6_ENABLE, "ipv6_enable", SCF_TYPE_BOOLEAN, 0},
139 	{SMB_CI_PRINT_ENABLE, "print_enable", SCF_TYPE_BOOLEAN, 0},
140 	{SMB_CI_MAP, "map", SCF_TYPE_ASTRING, SMB_CF_EXEC},
141 	{SMB_CI_UNMAP, "unmap", SCF_TYPE_ASTRING, SMB_CF_EXEC},
142 	{SMB_CI_DISPOSITION, "disposition", SCF_TYPE_ASTRING, SMB_CF_EXEC},
143 	{SMB_CI_DFS_STDROOT_NUM, "dfs_stdroot_num", SCF_TYPE_INTEGER, 0},
144 	{SMB_CI_TRAVERSE_MOUNTS, "traverse_mounts", SCF_TYPE_BOOLEAN, 0},
145 	{SMB_CI_SMB2_ENABLE_OLD, "smb2_enable", SCF_TYPE_BOOLEAN, 0},
146 	{SMB_CI_INITIAL_CREDITS, "initial_credits", SCF_TYPE_INTEGER, 0},
147 	{SMB_CI_MAXIMUM_CREDITS, "maximum_credits", SCF_TYPE_INTEGER, 0},
148 	{SMB_CI_MAX_PROTOCOL, "max_protocol", SCF_TYPE_ASTRING, 0},
149 	{SMB_CI_ENCRYPT, "encrypt", SCF_TYPE_ASTRING, 0},
150 	{SMB_CI_MIN_PROTOCOL, "min_protocol", SCF_TYPE_ASTRING, 0},
151 
152 	/* SMB_CI_MAX */
153 };
154 
155 /*
156  * We store the max SMB protocol version in SMF as a string,
157  * (for convenience of svccfg etc) but the programmatic get/set
158  * interfaces use the numeric form.
159  *
160  * The numeric values are as defined in the [MS-SMB2] spec.
161  * except for how we represent "1" (for SMB1) which is an
162  * arbitrary value below SMB2_VERS_BASE.
163  */
164 static struct str_val
165 smb_versions[] = {
166 	{ "3.0",	SMB_VERS_3_0 },
167 	{ "2.1",	SMB_VERS_2_1 },
168 	{ "2.002",	SMB_VERS_2_002 },
169 	{ "1",		SMB_VERS_1 },
170 	{ NULL,		0 }
171 };
172 
173 static smb_cfg_param_t *smb_config_getent(smb_cfg_id_t);
174 
175 static boolean_t smb_is_base64(unsigned char c);
176 static char *smb_base64_encode(char *str_to_encode);
177 static char *smb_base64_decode(char *encoded_str);
178 static int smb_config_get_idmap_preferred_dc(char *, int);
179 static int smb_config_set_idmap_preferred_dc(char *);
180 static int smb_config_get_idmap_site_name(char *, int);
181 static int smb_config_set_idmap_site_name(char *);
182 
183 static uint32_t
184 smb_convert_version_str(const char *version)
185 {
186 	uint32_t dialect = 0;
187 	int i;
188 
189 	for (i = 0; smb_versions[i].str != NULL; i++) {
190 		if (strcmp(version, smb_versions[i].str) == 0)
191 			dialect = smb_versions[i].val;
192 	}
193 
194 	return (dialect);
195 }
196 
197 char *
198 smb_config_getname(smb_cfg_id_t id)
199 {
200 	smb_cfg_param_t *cfg;
201 	cfg = smb_config_getent(id);
202 	return (cfg->sc_name);
203 }
204 
205 static boolean_t
206 smb_is_base64(unsigned char c)
207 {
208 	return (isalnum(c) || (c == '+') || (c == '/'));
209 }
210 
211 /*
212  * smb_base64_encode
213  *
214  * Encode a string using base64 algorithm.
215  * Caller should free the returned buffer when done.
216  */
217 static char *
218 smb_base64_encode(char *str_to_encode)
219 {
220 	int ret_cnt = 0;
221 	int i = 0, j = 0;
222 	char arr_3[3], arr_4[4];
223 	int len = strlen(str_to_encode);
224 	char *ret = malloc(SMB_ENC_LEN);
225 
226 	if (ret == NULL) {
227 		return (NULL);
228 	}
229 
230 	while (len--) {
231 		arr_3[i++] = *(str_to_encode++);
232 		if (i == 3) {
233 			arr_4[0] = (arr_3[0] & 0xfc) >> 2;
234 			arr_4[1] = ((arr_3[0] & 0x03) << 4) +
235 			    ((arr_3[1] & 0xf0) >> 4);
236 			arr_4[2] = ((arr_3[1] & 0x0f) << 2) +
237 			    ((arr_3[2] & 0xc0) >> 6);
238 			arr_4[3] = arr_3[2] & 0x3f;
239 
240 			for (i = 0; i < 4; i++)
241 				ret[ret_cnt++] = b64_data[arr_4[i]];
242 			i = 0;
243 		}
244 	}
245 
246 	if (i) {
247 		for (j = i; j < 3; j++)
248 			arr_3[j] = '\0';
249 
250 		arr_4[0] = (arr_3[0] & 0xfc) >> 2;
251 		arr_4[1] = ((arr_3[0] & 0x03) << 4) +
252 		    ((arr_3[1] & 0xf0) >> 4);
253 		arr_4[2] = ((arr_3[1] & 0x0f) << 2) +
254 		    ((arr_3[2] & 0xc0) >> 6);
255 		arr_4[3] = arr_3[2] & 0x3f;
256 
257 		for (j = 0; j < (i + 1); j++)
258 			ret[ret_cnt++] = b64_data[arr_4[j]];
259 
260 		while (i++ < 3)
261 			ret[ret_cnt++] = '=';
262 	}
263 
264 	ret[ret_cnt++] = '\0';
265 	return (ret);
266 }
267 
268 /*
269  * smb_base64_decode
270  *
271  * Decode using base64 algorithm.
272  * Caller should free the returned buffer when done.
273  */
274 static char *
275 smb_base64_decode(char *encoded_str)
276 {
277 	int len = strlen(encoded_str);
278 	int i = 0, j = 0;
279 	int en_ind = 0;
280 	char arr_4[4], arr_3[3];
281 	int ret_cnt = 0;
282 	char *ret = malloc(SMB_DEC_LEN);
283 	char *p;
284 
285 	if (ret == NULL) {
286 		return (NULL);
287 	}
288 
289 	while (len-- && (encoded_str[en_ind] != '=') &&
290 	    smb_is_base64(encoded_str[en_ind])) {
291 		arr_4[i++] = encoded_str[en_ind];
292 		en_ind++;
293 		if (i == 4) {
294 			for (i = 0; i < 4; i++) {
295 				if ((p = strchr(b64_data, arr_4[i])) == NULL)
296 					return (NULL);
297 
298 				arr_4[i] = (int)(p - b64_data);
299 			}
300 
301 			arr_3[0] = (arr_4[0] << 2) +
302 			    ((arr_4[1] & 0x30) >> 4);
303 			arr_3[1] = ((arr_4[1] & 0xf) << 4) +
304 			    ((arr_4[2] & 0x3c) >> 2);
305 			arr_3[2] = ((arr_4[2] & 0x3) << 6) +
306 			    arr_4[3];
307 
308 			for (i = 0; i < 3; i++)
309 				ret[ret_cnt++] = arr_3[i];
310 
311 			i = 0;
312 		}
313 	}
314 
315 	if (i) {
316 		for (j = i; j < 4; j++)
317 			arr_4[j] = 0;
318 
319 		for (j = 0; j < 4; j++) {
320 			if ((p = strchr(b64_data, arr_4[j])) == NULL)
321 				return (NULL);
322 
323 			arr_4[j] = (int)(p - b64_data);
324 		}
325 		arr_3[0] = (arr_4[0] << 2) +
326 		    ((arr_4[1] & 0x30) >> 4);
327 		arr_3[1] = ((arr_4[1] & 0xf) << 4) +
328 		    ((arr_4[2] & 0x3c) >> 2);
329 		arr_3[2] = ((arr_4[2] & 0x3) << 6) +
330 		    arr_4[3];
331 		for (j = 0; j < (i - 1); j++)
332 			ret[ret_cnt++] = arr_3[j];
333 	}
334 
335 	ret[ret_cnt++] = '\0';
336 	return (ret);
337 }
338 
339 static char *
340 smb_config_getenv_generic(char *name, char *svc_fmri_prefix, char *svc_propgrp)
341 {
342 	smb_scfhandle_t *handle;
343 	char *value;
344 
345 	if ((value = malloc(MAX_VALUE_BUFLEN * sizeof (char))) == NULL)
346 		return (NULL);
347 
348 	handle = smb_smf_scf_init(svc_fmri_prefix);
349 	if (handle == NULL) {
350 		free(value);
351 		return (NULL);
352 	}
353 
354 	(void) smb_smf_create_service_pgroup(handle, svc_propgrp);
355 
356 	if (smb_smf_get_string_property(handle, name, value,
357 	    sizeof (char) * MAX_VALUE_BUFLEN) != 0) {
358 		smb_smf_scf_fini(handle);
359 		free(value);
360 		return (NULL);
361 	}
362 
363 	smb_smf_scf_fini(handle);
364 	return (value);
365 
366 }
367 
368 static int
369 smb_config_setenv_generic(char *svc_fmri_prefix, char *svc_propgrp,
370     char *name, char *value)
371 {
372 	smb_scfhandle_t *handle = NULL;
373 	int rc = 0;
374 
375 
376 	handle = smb_smf_scf_init(svc_fmri_prefix);
377 	if (handle == NULL) {
378 		return (1);
379 	}
380 
381 	(void) smb_smf_create_service_pgroup(handle, svc_propgrp);
382 
383 	if (smb_smf_start_transaction(handle) != SMBD_SMF_OK) {
384 		smb_smf_scf_fini(handle);
385 		return (1);
386 	}
387 
388 	if (smb_smf_set_string_property(handle, name, value) != SMBD_SMF_OK)
389 		rc = 1;
390 
391 	if (smb_smf_end_transaction(handle) != SMBD_SMF_OK)
392 		rc = 1;
393 
394 	smb_smf_scf_fini(handle);
395 	return (rc);
396 }
397 
398 /*
399  * smb_config_getstr
400  *
401  * Fetch the specified string configuration item from SMF
402  */
403 int
404 smb_config_getstr(smb_cfg_id_t id, char *cbuf, int bufsz)
405 {
406 	smb_scfhandle_t *handle;
407 	smb_cfg_param_t *cfg;
408 	int rc = SMBD_SMF_OK;
409 	char *pg;
410 	char protbuf[SMB_ENC_LEN];
411 	char *tmp;
412 
413 	*cbuf = '\0';
414 	cfg = smb_config_getent(id);
415 	assert(cfg->sc_type == SCF_TYPE_ASTRING);
416 
417 	if (id == SMB_CI_ADS_SITE)
418 		return (smb_config_get_idmap_site_name(cbuf, bufsz));
419 	if (id == SMB_CI_DOMAIN_SRV)
420 		return (smb_config_get_idmap_preferred_dc(cbuf, bufsz));
421 
422 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
423 	if (handle == NULL)
424 		return (SMBD_SMF_SYSTEM_ERR);
425 
426 	if (cfg->sc_flags & SMB_CF_PROTECTED) {
427 		if ((rc = smb_smf_create_service_pgroup(handle,
428 		    SMBD_PROTECTED_PG_NAME)) != SMBD_SMF_OK)
429 			goto error;
430 
431 		if ((rc = smb_smf_get_string_property(handle, cfg->sc_name,
432 		    protbuf, sizeof (protbuf))) != SMBD_SMF_OK)
433 			goto error;
434 
435 		if (*protbuf != '\0') {
436 			tmp = smb_base64_decode(protbuf);
437 			(void) strlcpy(cbuf, tmp, bufsz);
438 			free(tmp);
439 		}
440 	} else {
441 		pg = (cfg->sc_flags & SMB_CF_EXEC) ? SMBD_EXEC_PG_NAME :
442 		    SMBD_PG_NAME;
443 		rc = smb_smf_create_service_pgroup(handle, pg);
444 		if (rc == SMBD_SMF_OK)
445 			rc = smb_smf_get_string_property(handle, cfg->sc_name,
446 			    cbuf, bufsz);
447 	}
448 
449 error:
450 	smb_smf_scf_fini(handle);
451 	return (rc);
452 }
453 
454 /*
455  * Translate the value of an astring SMF property into a binary
456  * IP address. If the value is neither a valid IPv4 nor IPv6
457  * address, attempt to look it up as a hostname using the
458  * configured address type.
459  */
460 int
461 smb_config_getip(smb_cfg_id_t sc_id, smb_inaddr_t *ipaddr)
462 {
463 	int rc, error;
464 	int a_family;
465 	char ipstr[MAXHOSTNAMELEN];
466 	struct hostent *h;
467 	smb_cfg_param_t *cfg;
468 
469 	if (ipaddr == NULL)
470 		return (SMBD_SMF_INVALID_ARG);
471 
472 	bzero(ipaddr, sizeof (smb_inaddr_t));
473 	rc = smb_config_getstr(sc_id, ipstr, sizeof (ipstr));
474 	if (rc == SMBD_SMF_OK) {
475 		if (*ipstr == '\0')
476 			return (SMBD_SMF_INVALID_ARG);
477 
478 		if (inet_pton(AF_INET, ipstr, &ipaddr->a_ipv4) == 1) {
479 			ipaddr->a_family = AF_INET;
480 			return (SMBD_SMF_OK);
481 		}
482 
483 		if (inet_pton(AF_INET6, ipstr, &ipaddr->a_ipv6) == 1) {
484 			ipaddr->a_family = AF_INET6;
485 			return (SMBD_SMF_OK);
486 		}
487 
488 		/*
489 		 * The value is neither an IPv4 nor IPv6 address;
490 		 * so check if it's a hostname.
491 		 */
492 		a_family = smb_config_getbool(SMB_CI_IPV6_ENABLE) ?
493 		    AF_INET6 : AF_INET;
494 		h = getipnodebyname(ipstr, a_family, AI_DEFAULT,
495 		    &error);
496 		if (h != NULL) {
497 			bcopy(*(h->h_addr_list), &ipaddr->a_ip,
498 			    h->h_length);
499 			ipaddr->a_family = a_family;
500 			freehostent(h);
501 			rc = SMBD_SMF_OK;
502 		} else {
503 			cfg = smb_config_getent(sc_id);
504 			syslog(LOG_ERR, "smbd/%s: %s unable to get %s "
505 			    "address: %d", cfg->sc_name, ipstr,
506 			    a_family == AF_INET ?  "IPv4" : "IPv6", error);
507 			rc = SMBD_SMF_INVALID_ARG;
508 		}
509 	}
510 
511 	return (rc);
512 }
513 
514 /*
515  * smb_config_getnum
516  *
517  * Returns the value of a numeric config param.
518  */
519 int
520 smb_config_getnum(smb_cfg_id_t id, int64_t *cint)
521 {
522 	smb_scfhandle_t *handle;
523 	smb_cfg_param_t *cfg;
524 	int rc = SMBD_SMF_OK;
525 
526 	*cint = 0;
527 	cfg = smb_config_getent(id);
528 	assert(cfg->sc_type == SCF_TYPE_INTEGER);
529 
530 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
531 	if (handle == NULL)
532 		return (SMBD_SMF_SYSTEM_ERR);
533 
534 	rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
535 	if (rc == SMBD_SMF_OK)
536 		rc = smb_smf_get_integer_property(handle, cfg->sc_name, cint);
537 	smb_smf_scf_fini(handle);
538 
539 	return (rc);
540 }
541 
542 /*
543  * smb_config_getbool
544  *
545  * Returns the value of a boolean config param.
546  */
547 boolean_t
548 smb_config_getbool(smb_cfg_id_t id)
549 {
550 	smb_scfhandle_t *handle;
551 	smb_cfg_param_t *cfg;
552 	int rc = SMBD_SMF_OK;
553 	uint8_t vbool;
554 
555 	cfg = smb_config_getent(id);
556 	assert(cfg->sc_type == SCF_TYPE_BOOLEAN);
557 
558 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
559 	if (handle == NULL)
560 		return (B_FALSE);
561 
562 	rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
563 	if (rc == SMBD_SMF_OK)
564 		rc = smb_smf_get_boolean_property(handle, cfg->sc_name, &vbool);
565 	smb_smf_scf_fini(handle);
566 
567 	return ((rc == SMBD_SMF_OK) ? (vbool == 1) : B_FALSE);
568 }
569 
570 /*
571  * smb_config_get
572  *
573  * This function returns the value of the requested config
574  * iterm regardless of its type in string format. This should
575  * be used when the config item type is not known by the caller.
576  */
577 int
578 smb_config_get(smb_cfg_id_t id, char *cbuf, int bufsz)
579 {
580 	smb_cfg_param_t *cfg;
581 	int64_t cint;
582 	int rc;
583 
584 	cfg = smb_config_getent(id);
585 	switch (cfg->sc_type) {
586 	case SCF_TYPE_ASTRING:
587 		return (smb_config_getstr(id, cbuf, bufsz));
588 
589 	case SCF_TYPE_INTEGER:
590 		rc = smb_config_getnum(id, &cint);
591 		if (rc == SMBD_SMF_OK)
592 			(void) snprintf(cbuf, bufsz, "%lld", cint);
593 		return (rc);
594 
595 	case SCF_TYPE_BOOLEAN:
596 		if (smb_config_getbool(id))
597 			(void) strlcpy(cbuf, "true", bufsz);
598 		else
599 			(void) strlcpy(cbuf, "false", bufsz);
600 		return (SMBD_SMF_OK);
601 	}
602 
603 	return (SMBD_SMF_INVALID_ARG);
604 }
605 
606 /*
607  * smb_config_setstr
608  *
609  * Set the specified config param with the given
610  * value.
611  */
612 int
613 smb_config_setstr(smb_cfg_id_t id, char *value)
614 {
615 	smb_scfhandle_t *handle;
616 	smb_cfg_param_t *cfg;
617 	int rc = SMBD_SMF_OK;
618 	boolean_t protected;
619 	char *tmp = NULL;
620 	char *pg;
621 
622 	cfg = smb_config_getent(id);
623 	assert(cfg->sc_type == SCF_TYPE_ASTRING);
624 
625 	if (id == SMB_CI_ADS_SITE)
626 		return (smb_config_set_idmap_site_name(value));
627 	if (id == SMB_CI_DOMAIN_SRV)
628 		return (smb_config_set_idmap_preferred_dc(value));
629 
630 	protected = B_FALSE;
631 
632 	switch (cfg->sc_flags) {
633 	case SMB_CF_PROTECTED:
634 		protected = B_TRUE;
635 		pg = SMBD_PROTECTED_PG_NAME;
636 		break;
637 	case SMB_CF_EXEC:
638 		pg = SMBD_EXEC_PG_NAME;
639 		break;
640 	default:
641 		pg = SMBD_PG_NAME;
642 		break;
643 	}
644 
645 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
646 	if (handle == NULL)
647 		return (SMBD_SMF_SYSTEM_ERR);
648 
649 	rc = smb_smf_create_service_pgroup(handle, pg);
650 	if (rc == SMBD_SMF_OK)
651 		rc = smb_smf_start_transaction(handle);
652 
653 	if (rc != SMBD_SMF_OK) {
654 		smb_smf_scf_fini(handle);
655 		return (rc);
656 	}
657 
658 	if (protected && value && (*value != '\0')) {
659 		if ((tmp = smb_base64_encode(value)) == NULL) {
660 			(void) smb_smf_end_transaction(handle);
661 			smb_smf_scf_fini(handle);
662 			return (SMBD_SMF_NO_MEMORY);
663 		}
664 
665 		value = tmp;
666 	}
667 
668 	/*
669 	 * We don't want people who care enough about protecting their data
670 	 * by requiring encryption to accidentally expose their data
671 	 * by lowering the protocol, so prevent them from going below 3.0
672 	 * if encryption is required.
673 	 * Also, ensure that max_protocol >= min_protocol.
674 	 */
675 	if (id == SMB_CI_MAX_PROTOCOL) {
676 		smb_cfg_val_t encrypt;
677 		uint32_t min;
678 		uint32_t val;
679 
680 		encrypt = smb_config_get_require(SMB_CI_ENCRYPT);
681 		min = smb_config_get_min_protocol();
682 		val = smb_convert_version_str(value);
683 
684 		if (encrypt == SMB_CONFIG_REQUIRED &&
685 		    val < SMB_VERS_3_0) {
686 			syslog(LOG_ERR, "Cannot set smbd/max_protocol below 3.0"
687 			    " while smbd/encrypt == required.");
688 			rc = SMBD_SMF_INVALID_ARG;
689 		} else if (val < min) {
690 			syslog(LOG_ERR, "Cannot set smbd/max_protocol to less"
691 			    " than smbd/min_protocol.");
692 			rc = SMBD_SMF_INVALID_ARG;
693 		}
694 	} else if (id == SMB_CI_MIN_PROTOCOL) {
695 		uint32_t max;
696 		uint32_t val;
697 
698 		max = smb_config_get_max_protocol();
699 		val = smb_convert_version_str(value);
700 
701 		if (val > max) {
702 			syslog(LOG_ERR, "Cannot set smbd/min_protocol to more"
703 			    " than smbd/max_protocol.");
704 			rc = SMBD_SMF_INVALID_ARG;
705 		}
706 	}
707 
708 	if (rc == SMBD_SMF_OK) {
709 		rc = smb_smf_set_string_property(handle, cfg->sc_name, value);
710 	}
711 
712 	free(tmp);
713 	(void) smb_smf_end_transaction(handle);
714 	smb_smf_scf_fini(handle);
715 	return (rc);
716 }
717 
718 /*
719  * smb_config_setnum
720  *
721  * Sets a numeric configuration iterm
722  */
723 int
724 smb_config_setnum(smb_cfg_id_t id, int64_t value)
725 {
726 	smb_scfhandle_t *handle;
727 	smb_cfg_param_t *cfg;
728 	int rc = SMBD_SMF_OK;
729 
730 	cfg = smb_config_getent(id);
731 	assert(cfg->sc_type == SCF_TYPE_INTEGER);
732 
733 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
734 	if (handle == NULL)
735 		return (SMBD_SMF_SYSTEM_ERR);
736 
737 	rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
738 	if (rc == SMBD_SMF_OK)
739 		rc = smb_smf_start_transaction(handle);
740 
741 	if (rc != SMBD_SMF_OK) {
742 		smb_smf_scf_fini(handle);
743 		return (rc);
744 	}
745 
746 	rc = smb_smf_set_integer_property(handle, cfg->sc_name, value);
747 
748 	(void) smb_smf_end_transaction(handle);
749 	smb_smf_scf_fini(handle);
750 	return (rc);
751 }
752 
753 /*
754  * smb_config_setbool
755  *
756  * Sets a boolean configuration iterm
757  */
758 int
759 smb_config_setbool(smb_cfg_id_t id, boolean_t value)
760 {
761 	smb_scfhandle_t *handle;
762 	smb_cfg_param_t *cfg;
763 	int rc = SMBD_SMF_OK;
764 
765 	cfg = smb_config_getent(id);
766 	assert(cfg->sc_type == SCF_TYPE_BOOLEAN);
767 
768 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
769 	if (handle == NULL)
770 		return (SMBD_SMF_SYSTEM_ERR);
771 
772 	rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
773 	if (rc == SMBD_SMF_OK)
774 		rc = smb_smf_start_transaction(handle);
775 
776 	if (rc != SMBD_SMF_OK) {
777 		smb_smf_scf_fini(handle);
778 		return (rc);
779 	}
780 
781 	rc = smb_smf_set_boolean_property(handle, cfg->sc_name, value);
782 
783 	(void) smb_smf_end_transaction(handle);
784 	smb_smf_scf_fini(handle);
785 	return (rc);
786 }
787 
788 /*
789  * smb_config_set
790  *
791  * This function sets the value of the specified config
792  * iterm regardless of its type in string format. This should
793  * be used when the config item type is not known by the caller.
794  */
795 int
796 smb_config_set(smb_cfg_id_t id, char *value)
797 {
798 	smb_cfg_param_t *cfg;
799 	int64_t cint;
800 
801 	cfg = smb_config_getent(id);
802 	switch (cfg->sc_type) {
803 	case SCF_TYPE_ASTRING:
804 		return (smb_config_setstr(id, value));
805 
806 	case SCF_TYPE_INTEGER:
807 		cint = atoi(value);
808 		return (smb_config_setnum(id, cint));
809 
810 	case SCF_TYPE_BOOLEAN:
811 		return (smb_config_setbool(id, strcasecmp(value, "true") == 0));
812 	}
813 
814 	return (SMBD_SMF_INVALID_ARG);
815 }
816 
817 int
818 smb_config_get_debug()
819 {
820 	int64_t val64;
821 	int val = 0;	/* default */
822 	smb_scfhandle_t *handle = NULL;
823 
824 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
825 	if (handle == NULL) {
826 		return (val);
827 	}
828 
829 	if (smb_smf_create_service_pgroup(handle,
830 	    SMBD_PG_NAME) != SMBD_SMF_OK) {
831 		smb_smf_scf_fini(handle);
832 		return (val);
833 	}
834 
835 	if (smb_smf_get_integer_property(handle, "debug", &val64) != 0) {
836 		smb_smf_scf_fini(handle);
837 		return (val);
838 	}
839 	val = (int)val64;
840 
841 	smb_smf_scf_fini(handle);
842 
843 	return (val);
844 }
845 
846 uint8_t
847 smb_config_get_fg_flag()
848 {
849 	uint8_t run_fg = 0; /* Default is to run in daemon mode */
850 	smb_scfhandle_t *handle = NULL;
851 
852 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
853 	if (handle == NULL) {
854 		return (run_fg);
855 	}
856 
857 	if (smb_smf_create_service_pgroup(handle,
858 	    SMBD_PG_NAME) != SMBD_SMF_OK) {
859 		smb_smf_scf_fini(handle);
860 		return (run_fg);
861 	}
862 
863 	if (smb_smf_get_boolean_property(handle, "run_fg", &run_fg) != 0) {
864 		smb_smf_scf_fini(handle);
865 		return (run_fg);
866 	}
867 
868 	smb_smf_scf_fini(handle);
869 
870 	return (run_fg);
871 }
872 
873 /*
874  * smb_config_get_ads_enable
875  *
876  * Returns value of the "config/use_ads" parameter
877  * from the IDMAP SMF configuration repository.
878  *
879  */
880 boolean_t
881 smb_config_get_ads_enable(void)
882 {
883 	smb_scfhandle_t *handle = NULL;
884 	uint8_t vbool;
885 	int rc = 0;
886 
887 	handle = smb_smf_scf_init(IDMAP_FMRI_PREFIX);
888 	if (handle == NULL)
889 		return (B_FALSE);
890 
891 	rc = smb_smf_create_service_pgroup(handle, IDMAP_PG_NAME);
892 	if (rc == SMBD_SMF_OK)
893 		rc = smb_smf_get_boolean_property(handle, "use_ads", &vbool);
894 	smb_smf_scf_fini(handle);
895 
896 	return ((rc == SMBD_SMF_OK) ? (vbool == 1) : B_TRUE);
897 }
898 
899 /*
900  * smb_config_get_localsid
901  *
902  * Returns value of the "config/machine_sid" parameter
903  * from the IDMAP SMF configuration repository.
904  * Result is allocated; caller should free.
905  */
906 char *
907 smb_config_get_localsid(void)
908 {
909 	return (smb_config_getenv_generic(MACHINE_SID, IDMAP_FMRI_PREFIX,
910 	    IDMAP_PG_NAME));
911 }
912 
913 /*
914  * smb_config_get_localuuid
915  *
916  * Returns value of the "config/machine_uuid" parameter
917  * from the IDMAP SMF configuration repository.
918  *
919  */
920 int
921 smb_config_get_localuuid(uuid_t uu)
922 {
923 	char *s;
924 
925 	uuid_clear(uu);
926 	s = smb_config_getenv_generic(MACHINE_UUID, IDMAP_FMRI_PREFIX,
927 	    IDMAP_PG_NAME);
928 	if (s == NULL)
929 		return (-1);
930 
931 	if (uuid_parse(s, uu) < 0) {
932 		free(s);
933 		return (-1);
934 	}
935 
936 	return (0);
937 }
938 
939 static int
940 smb_config_get_idmap_preferred_dc(char *cbuf, int bufsz)
941 {
942 	char *s;
943 	int len, rc = -1;
944 
945 	s = smb_config_getenv_generic(IDMAP_PREF_DC,
946 	    IDMAP_FMRI_PREFIX, IDMAP_PG_NAME);
947 	if (s != NULL) {
948 		len = strlcpy(cbuf, s, bufsz);
949 		if (len < bufsz)
950 			rc = 0;
951 		free(s);
952 	}
953 	return (rc);
954 }
955 
956 static int
957 smb_config_set_idmap_preferred_dc(char *value)
958 {
959 	return (smb_config_setenv_generic(IDMAP_FMRI_PREFIX, IDMAP_PG_NAME,
960 	    IDMAP_PREF_DC, value));
961 }
962 
963 static int
964 smb_config_get_idmap_site_name(char *cbuf, int bufsz)
965 {
966 	char *s;
967 	int len, rc = -1;
968 
969 	s = smb_config_getenv_generic(IDMAP_SITE_NAME,
970 	    IDMAP_FMRI_PREFIX, IDMAP_PG_NAME);
971 	if (s != NULL) {
972 		len = strlcpy(cbuf, s, bufsz);
973 		if (len < bufsz)
974 			rc = 0;
975 		free(s);
976 	}
977 	return (rc);
978 }
979 
980 static int
981 smb_config_set_idmap_site_name(char *value)
982 {
983 	return (smb_config_setenv_generic(IDMAP_FMRI_PREFIX, IDMAP_PG_NAME,
984 	    IDMAP_SITE_NAME, value));
985 }
986 
987 /*
988  * smb_config_set_idmap_domain
989  *
990  * Set the "config/domain_name" parameter from IDMAP SMF repository.
991  */
992 int
993 smb_config_set_idmap_domain(char *value)
994 {
995 	return (smb_config_setenv_generic(IDMAP_FMRI_PREFIX, IDMAP_PG_NAME,
996 	    IDMAP_DOMAIN, value));
997 }
998 
999 /*
1000  * smb_config_refresh_idmap
1001  *
1002  * Refresh IDMAP SMF service after making changes to its configuration.
1003  */
1004 int
1005 smb_config_refresh_idmap(void)
1006 {
1007 	char instance[32];
1008 
1009 	(void) snprintf(instance, sizeof (instance), "%s:default",
1010 	    IDMAP_FMRI_PREFIX);
1011 	return (smf_refresh_instance(instance));
1012 }
1013 
1014 int
1015 smb_config_secmode_fromstr(char *secmode)
1016 {
1017 	if (secmode == NULL)
1018 		return (SMB_SECMODE_WORKGRP);
1019 
1020 	if (strcasecmp(secmode, SMB_SECMODE_DOMAIN_STR) == 0)
1021 		return (SMB_SECMODE_DOMAIN);
1022 
1023 	return (SMB_SECMODE_WORKGRP);
1024 }
1025 
1026 char *
1027 smb_config_secmode_tostr(int secmode)
1028 {
1029 	if (secmode == SMB_SECMODE_DOMAIN)
1030 		return (SMB_SECMODE_DOMAIN_STR);
1031 
1032 	return (SMB_SECMODE_WORKGRP_STR);
1033 }
1034 
1035 int
1036 smb_config_get_secmode()
1037 {
1038 	char p[16];
1039 
1040 	(void) smb_config_getstr(SMB_CI_SECURITY, p, sizeof (p));
1041 	return (smb_config_secmode_fromstr(p));
1042 }
1043 
1044 int
1045 smb_config_set_secmode(int secmode)
1046 {
1047 	char *p;
1048 
1049 	p = smb_config_secmode_tostr(secmode);
1050 	return (smb_config_setstr(SMB_CI_SECURITY, p));
1051 }
1052 
1053 void
1054 smb_config_getdomaininfo(char *domain, char *fqdn, char *sid, char *forest,
1055     char *guid)
1056 {
1057 	if (domain)
1058 		(void) smb_config_getstr(SMB_CI_DOMAIN_NAME, domain,
1059 		    NETBIOS_NAME_SZ);
1060 
1061 	if (fqdn)
1062 		(void) smb_config_getstr(SMB_CI_DOMAIN_FQDN, fqdn,
1063 		    MAXHOSTNAMELEN);
1064 
1065 	if (sid)
1066 		(void) smb_config_getstr(SMB_CI_DOMAIN_SID, sid,
1067 		    SMB_SID_STRSZ);
1068 
1069 	if (forest)
1070 		(void) smb_config_getstr(SMB_CI_DOMAIN_FOREST, forest,
1071 		    MAXHOSTNAMELEN);
1072 
1073 	if (guid)
1074 		(void) smb_config_getstr(SMB_CI_DOMAIN_GUID, guid,
1075 		    UUID_PRINTABLE_STRING_LENGTH);
1076 }
1077 
1078 void
1079 smb_config_setdomaininfo(char *domain, char *fqdn, char *sid, char *forest,
1080     char *guid)
1081 {
1082 	if (domain)
1083 		(void) smb_config_setstr(SMB_CI_DOMAIN_NAME, domain);
1084 	if (fqdn)
1085 		(void) smb_config_setstr(SMB_CI_DOMAIN_FQDN, fqdn);
1086 	if (sid)
1087 		(void) smb_config_setstr(SMB_CI_DOMAIN_SID, sid);
1088 	if (forest)
1089 		(void) smb_config_setstr(SMB_CI_DOMAIN_FOREST, forest);
1090 	if (guid)
1091 		(void) smb_config_setstr(SMB_CI_DOMAIN_GUID, guid);
1092 }
1093 
1094 /*
1095  * The version stored in SMF in string format as N.N where
1096  * N is a number defined by Microsoft. The first number represents
1097  * the major version and the second number is the minor version.
1098  * Current defined values can be found here in 'ver_table'.
1099  *
1100  * This function reads the SMF string value and converts it to
1101  * two numbers returned in the given 'version' structure.
1102  * Current default version number is 5.0 which is for Windows 2000.
1103  */
1104 void
1105 smb_config_get_version(smb_version_t *version)
1106 {
1107 	smb_version_t tmpver;
1108 	char verstr[SMB_VERSTR_LEN];
1109 	char *p;
1110 	int rc, i;
1111 	static smb_version_t ver_table [] = {
1112 		{ 0, SMB_MAJOR_NT,	SMB_MINOR_NT,		1381,	0 },
1113 		{ 0, SMB_MAJOR_2000,	SMB_MINOR_2000,		2195,	0 },
1114 		{ 0, SMB_MAJOR_XP,	SMB_MINOR_XP,		2196,	0 },
1115 		{ 0, SMB_MAJOR_2003,	SMB_MINOR_2003,		2196,	0 },
1116 		{ 0, SMB_MAJOR_VISTA,	SMB_MINOR_VISTA,	6000,	0 },
1117 		{ 0, SMB_MAJOR_2008,	SMB_MINOR_2008,		6000,	0 },
1118 		{ 0, SMB_MAJOR_2008R2,	SMB_MINOR_2008R2,	7007,	0 },
1119 		{ 0, SMB_MAJOR_7,	SMB_MINOR_7,		7007,	0 }
1120 	};
1121 
1122 	*version = ver_table[1];
1123 	version->sv_size = sizeof (smb_version_t);
1124 
1125 	rc = smb_config_getstr(SMB_CI_VERSION, verstr, sizeof (verstr));
1126 	if (rc != SMBD_SMF_OK)
1127 		return;
1128 
1129 	if ((p = strchr(verstr, '.')) == NULL)
1130 		return;
1131 
1132 	*p = '\0';
1133 	tmpver.sv_major = (uint8_t)atoi(verstr);
1134 	tmpver.sv_minor = (uint8_t)atoi(p + 1);
1135 
1136 	for (i = 0; i < sizeof (ver_table)/sizeof (ver_table[0]); ++i) {
1137 		if ((tmpver.sv_major == ver_table[i].sv_major) &&
1138 		    (tmpver.sv_minor == ver_table[i].sv_minor)) {
1139 			*version = ver_table[i];
1140 			version->sv_size = sizeof (smb_version_t);
1141 			break;
1142 		}
1143 	}
1144 }
1145 
1146 /*
1147  * Reads share exec script properties
1148  */
1149 uint32_t
1150 smb_config_get_execinfo(char *map, char *unmap, size_t bufsz)
1151 {
1152 	char buf[MAXPATHLEN];
1153 	uint32_t flags = 0;
1154 
1155 	if (map == NULL) {
1156 		map = buf;
1157 		bufsz = MAXPATHLEN;
1158 	}
1159 
1160 	*map = '\0';
1161 	(void) smb_config_getstr(SMB_CI_MAP, map, bufsz);
1162 	if (*map != '\0')
1163 		flags |= SMB_EXEC_MAP;
1164 
1165 	if (unmap == NULL) {
1166 		unmap = buf;
1167 		bufsz = MAXPATHLEN;
1168 	}
1169 
1170 	*unmap = '\0';
1171 	(void) smb_config_getstr(SMB_CI_UNMAP, unmap, bufsz);
1172 	if (*unmap != '\0')
1173 		flags |= SMB_EXEC_UNMAP;
1174 
1175 	*buf = '\0';
1176 	(void) smb_config_getstr(SMB_CI_DISPOSITION, buf, sizeof (buf));
1177 	if (*buf != '\0')
1178 		if (strcasecmp(buf, SMB_EXEC_DISP_TERMINATE) == 0)
1179 			flags |= SMB_EXEC_TERM;
1180 
1181 	return (flags);
1182 }
1183 
1184 static smb_cfg_param_t *
1185 smb_config_getent(smb_cfg_id_t id)
1186 {
1187 	int i;
1188 
1189 	for (i = 0; i < SMB_CI_MAX; i++)
1190 		if (smb_cfg_table[i].sc_id == id)
1191 			return (&smb_cfg_table[id]);
1192 
1193 	assert(0);
1194 	return (NULL);
1195 }
1196 
1197 static uint32_t
1198 smb_config_get_protocol(smb_cfg_id_t id, char *name, uint32_t default_val)
1199 {
1200 	char str[SMB_VERSTR_LEN];
1201 	int rc;
1202 	uint32_t val;
1203 
1204 	rc = smb_config_getstr(id, str, sizeof (str));
1205 	if (rc == SMBD_SMF_OK) {
1206 		val = smb_convert_version_str(str);
1207 		if (val != 0)
1208 			return (val);
1209 		if (str[0] != '\0') {
1210 			syslog(LOG_ERR, "smbd/%s value invalid: %s", name, str);
1211 		}
1212 	}
1213 
1214 	return (default_val);
1215 }
1216 
1217 /*
1218  * The service manifest has empty values by default for min_protocol and
1219  * max_protocol. The expectation is that when those values are empty, we don't
1220  * constrain the range of supported protocol versions (and allow use of the
1221  * whole range that we implement). For that reason, this should usually be the
1222  * highest protocol version we implement.
1223  */
1224 uint32_t max_protocol_default = SMB_VERS_3_0;
1225 
1226 uint32_t
1227 smb_config_get_max_protocol(void)
1228 {
1229 	uint32_t max;
1230 
1231 	max = smb_config_get_protocol(SMB_CI_MAX_PROTOCOL, "max_protocol",
1232 	    max_protocol_default);
1233 
1234 	return (max);
1235 }
1236 
1237 /*
1238  * This should eventually be SMB_VERS_2_BASE
1239  */
1240 uint32_t min_protocol_default = SMB_VERS_1;
1241 
1242 uint32_t
1243 smb_config_get_min_protocol(void)
1244 {
1245 	uint32_t min;
1246 
1247 	min = smb_config_get_protocol(SMB_CI_MIN_PROTOCOL, "min_protocol",
1248 	    min_protocol_default);
1249 
1250 	return (min);
1251 }
1252 
1253 int
1254 smb_config_check_protocol(char *value)
1255 {
1256 	if (smb_convert_version_str(value) != 0)
1257 		return (0);
1258 
1259 	return (-1);
1260 }
1261 
1262 /*
1263  * If smb2_enable is present and max_protocol is empty,
1264  * set max_protocol.  Delete smb2_enable.
1265  */
1266 static void
1267 upgrade_smb2_enable()
1268 {
1269 	smb_scfhandle_t *handle;
1270 	char *s2e_name = "smb2_enable";
1271 	char *s2e_sval;
1272 	uint8_t	s2e_bval;
1273 	char *maxp_name = "max_protocol";
1274 	char *maxp_sval;
1275 	char verstr[SMB_VERSTR_LEN];
1276 	int rc;
1277 
1278 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
1279 	if (handle == NULL)
1280 		return;
1281 	rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
1282 	if (rc != SMBD_SMF_OK)
1283 		goto out;
1284 
1285 	/* Is there an "smb2_enable" property? */
1286 	rc = smb_smf_get_boolean_property(handle, s2e_name, &s2e_bval);
1287 	if (rc != SMBD_SMF_OK) {
1288 		syslog(LOG_DEBUG, "upgrade: smb2_enable not found");
1289 		goto out;
1290 	}
1291 
1292 	/*
1293 	 * We will try to delete the smb2_enable property, so we need
1294 	 * the transaction to start now, before we modify max_protocol
1295 	 */
1296 	if ((rc = smb_smf_start_transaction(handle)) != 0) {
1297 		syslog(LOG_DEBUG, "upgrade_smb2_enable: start trans (%d)", rc);
1298 		goto out;
1299 	}
1300 
1301 	/*
1302 	 * Old (smb2_enable) property exists.
1303 	 * Does the new one? (max_protocol)
1304 	 */
1305 	rc = smb_smf_get_string_property(handle, maxp_name,
1306 	    verstr, sizeof (verstr));
1307 	if (rc == SMBD_SMF_OK && !smb_config_check_protocol(verstr)) {
1308 		syslog(LOG_DEBUG, "upgrade: found %s = %s",
1309 		    maxp_name, verstr);
1310 		/* Leave existing max_protocol as we found it. */
1311 	} else {
1312 		/*
1313 		 * New property missing or invalid.
1314 		 * Upgrade from "smb2_enable".
1315 		 */
1316 		if (s2e_bval == 0) {
1317 			s2e_sval = "false";
1318 			maxp_sval = "1";
1319 		} else {
1320 			s2e_sval = "true";
1321 			maxp_sval = "2.1";
1322 		}
1323 		/*
1324 		 * Note: Need this in the same transaction as the
1325 		 * delete of smb2_enable below.
1326 		 */
1327 		rc = smb_smf_set_string_property(handle, maxp_name, maxp_sval);
1328 		if (rc != SMBD_SMF_OK) {
1329 			syslog(LOG_ERR, "failed to set smbd/%d (%d)",
1330 			    maxp_name, rc);
1331 			goto out;
1332 		}
1333 		syslog(LOG_INFO, "upgrade smbd/smb2_enable=%s "
1334 		    "converted to smbd/max_protocol=%s",
1335 		    s2e_sval, maxp_sval);
1336 	}
1337 
1338 	/*
1339 	 * Delete the old smb2_enable property.
1340 	 */
1341 	if ((rc = smb_smf_delete_property(handle, s2e_name)) != 0) {
1342 		syslog(LOG_DEBUG, "upgrade_smb2_enable: delete prop (%d)", rc);
1343 	} else if ((rc = smb_smf_end_transaction(handle)) != 0) {
1344 		syslog(LOG_DEBUG, "upgrade_smb2_enable: end trans (%d)", rc);
1345 	}
1346 	if (rc != 0) {
1347 		syslog(LOG_ERR, "failed to delete property smbd/%d (%d)",
1348 		    s2e_name, rc);
1349 	}
1350 
1351 out:
1352 	(void) smb_smf_end_transaction(handle);
1353 	smb_smf_scf_fini(handle);
1354 }
1355 
1356 
1357 /*
1358  * Run once at startup convert old SMF settings to current.
1359  */
1360 void
1361 smb_config_upgrade(void)
1362 {
1363 	upgrade_smb2_enable();
1364 }
1365 
1366 smb_cfg_val_t
1367 smb_config_get_require(smb_cfg_id_t id)
1368 {
1369 	int rc;
1370 	char str[sizeof ("required")];
1371 
1372 	rc = smb_config_getstr(id, str, sizeof (str));
1373 	if (rc != SMBD_SMF_OK)
1374 		return (SMB_CONFIG_DISABLED);
1375 
1376 	if (strncmp(str, "required", sizeof (str)) == 0)
1377 		return (SMB_CONFIG_REQUIRED);
1378 	if (strncmp(str, "enabled", sizeof (str)) == 0)
1379 		return (SMB_CONFIG_ENABLED);
1380 
1381 	return (SMB_CONFIG_DISABLED);
1382 }
1383