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 
46 typedef 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 
53 struct 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 
79 static char *b64_data =
80 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
81 
82 static 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  */
168 static struct str_val
169 smb_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  */
182 static struct str_val
183 smb31_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 
189 static smb_cfg_param_t *smb_config_getent(smb_cfg_id_t);
190 
191 static boolean_t smb_is_base64(unsigned char c);
192 static char *smb_base64_encode(char *str_to_encode);
193 static char *smb_base64_decode(char *encoded_str);
194 static int smb_config_get_idmap_preferred_dc(char *, int);
195 static int smb_config_set_idmap_preferred_dc(char *);
196 static int smb_config_get_idmap_site_name(char *, int);
197 static int smb_config_set_idmap_site_name(char *);
198 
199 static uint32_t
200 smb_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 
213 char *
214 smb_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 
221 static boolean_t
222 smb_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  */
233 static char *
234 smb_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  */
290 static char *
291 smb_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 
355 static char *
356 smb_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 
384 static int
385 smb_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  */
419 int
420 smb_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 
465 error:
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  */
476 int
477 smb_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  */
535 int
536 smb_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  */
563 boolean_t
564 smb_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  */
593 int
594 smb_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  */
628 int
629 smb_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  */
739 int
740 smb_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  */
774 int
775 smb_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  */
811 int
812 smb_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 
833 int
834 smb_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 
862 uint8_t
863 smb_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  */
896 boolean_t
897 smb_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  */
922 char *
923 smb_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  */
936 int
937 smb_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 
955 static int
956 smb_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 
972 static int
973 smb_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 
979 static int
980 smb_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 
996 static int
997 smb_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  */
1008 int
1009 smb_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  */
1020 int
1021 smb_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 
1030 int
1031 smb_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 
1042 char *
1043 smb_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 
1051 int
1052 smb_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 
1060 int
1061 smb_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 
1069 void
1070 smb_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 
1094 void
1095 smb_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  */
1120 void
1121 smb_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  */
1165 uint32_t
1166 smb_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 
1200 static smb_cfg_param_t *
1201 smb_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 
1213 static uint32_t
1214 smb_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  */
1240 uint32_t max_protocol_default = SMB_VERS_3_11;
1241 
1242 uint32_t
1243 smb_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  */
1256 uint32_t min_protocol_default = SMB_VERS_1;
1257 
1258 uint32_t
1259 smb_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 
1269 int
1270 smb_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  */
1283 uint16_t
1284 smb31_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  */
1310 static void
1311 upgrade_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 
1395 out:
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  */
1404 void
1405 smb_config_upgrade(void)
1406 {
1407 	upgrade_smb2_enable();
1408 }
1409 
1410 smb_cfg_val_t
1411 smb_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