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