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