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