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