xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c (revision b819cea2f73f98c5662230cc9affc8cc84f77fcf)
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 2013 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 /*
53  * config parameter flags
54  */
55 #define	SMB_CF_PROTECTED	0x01
56 #define	SMB_CF_EXEC		0x02
57 
58 /* idmap SMF fmri and Property Group */
59 #define	IDMAP_FMRI_PREFIX		"system/idmap"
60 #define	MACHINE_SID			"machine_sid"
61 #define	IDMAP_DOMAIN			"domain_name"
62 #define	IDMAP_PG_NAME			"config"
63 
64 #define	SMB_SECMODE_WORKGRP_STR 	"workgroup"
65 #define	SMB_SECMODE_DOMAIN_STR  	"domain"
66 
67 #define	SMB_ENC_LEN	1024
68 #define	SMB_DEC_LEN	256
69 
70 static char *b64_data =
71 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
72 
73 static smb_cfg_param_t smb_cfg_table[] =
74 {
75 	{SMB_CI_VERSION, "sv_version", SCF_TYPE_ASTRING, 0},
76 
77 	/* Oplock configuration, Kernel Only */
78 	{SMB_CI_OPLOCK_ENABLE, "oplock_enable", SCF_TYPE_BOOLEAN, 0},
79 
80 	/* Autohome configuration */
81 	{SMB_CI_AUTOHOME_MAP, "autohome_map", SCF_TYPE_ASTRING, 0},
82 
83 	/* Domain/PDC configuration */
84 	{SMB_CI_DOMAIN_SID, "domain_sid", SCF_TYPE_ASTRING, 0},
85 	{SMB_CI_DOMAIN_MEMB, "domain_member", SCF_TYPE_BOOLEAN, 0},
86 	{SMB_CI_DOMAIN_NAME, "domain_name", SCF_TYPE_ASTRING, 0},
87 	{SMB_CI_DOMAIN_FQDN, "fqdn", SCF_TYPE_ASTRING, 0},
88 	{SMB_CI_DOMAIN_FOREST, "forest", SCF_TYPE_ASTRING, 0},
89 	{SMB_CI_DOMAIN_GUID, "domain_guid", SCF_TYPE_ASTRING, 0},
90 	{SMB_CI_DOMAIN_SRV, "pdc", SCF_TYPE_ASTRING, 0},
91 
92 	/* WINS configuration */
93 	{SMB_CI_WINS_SRV1, "wins_server_1", SCF_TYPE_ASTRING, 0},
94 	{SMB_CI_WINS_SRV2, "wins_server_2", SCF_TYPE_ASTRING, 0},
95 	{SMB_CI_WINS_EXCL, "wins_exclude", SCF_TYPE_ASTRING, 0},
96 
97 	/* Kmod specific configuration */
98 	{SMB_CI_MAX_WORKERS, "max_workers", SCF_TYPE_INTEGER, 0},
99 	{SMB_CI_MAX_CONNECTIONS, "max_connections", SCF_TYPE_INTEGER, 0},
100 	{SMB_CI_KEEPALIVE, "keep_alive", SCF_TYPE_INTEGER, 0},
101 	{SMB_CI_RESTRICT_ANON, "restrict_anonymous", SCF_TYPE_BOOLEAN, 0},
102 
103 	{SMB_CI_SIGNING_ENABLE, "signing_enabled", SCF_TYPE_BOOLEAN, 0},
104 	{SMB_CI_SIGNING_REQD, "signing_required", SCF_TYPE_BOOLEAN, 0},
105 
106 	/* Kmod tuning configuration */
107 	{SMB_CI_SYNC_ENABLE, "sync_enable", SCF_TYPE_BOOLEAN, 0},
108 
109 	/* SMBd configuration */
110 	{SMB_CI_SECURITY, "security", SCF_TYPE_ASTRING, 0},
111 	{SMB_CI_NETBIOS_ENABLE, "netbios_enable", SCF_TYPE_BOOLEAN, 0},
112 	{SMB_CI_NBSCOPE, "netbios_scope", SCF_TYPE_ASTRING, 0},
113 	{SMB_CI_SYS_CMNT, "system_comment", SCF_TYPE_ASTRING, 0},
114 	{SMB_CI_LM_LEVEL, "lmauth_level", SCF_TYPE_INTEGER, 0},
115 
116 	/* ADS Configuration */
117 	{SMB_CI_ADS_SITE, "ads_site", SCF_TYPE_ASTRING, 0},
118 
119 	/* Dynamic DNS */
120 	{SMB_CI_DYNDNS_ENABLE, "ddns_enable", SCF_TYPE_BOOLEAN, 0},
121 
122 	{SMB_CI_MACHINE_PASSWD, "machine_passwd", SCF_TYPE_ASTRING,
123 	    SMB_CF_PROTECTED},
124 	{SMB_CI_KPASSWD_SRV, "kpasswd_server", SCF_TYPE_ASTRING,
125 	    0},
126 	{SMB_CI_KPASSWD_DOMAIN, "kpasswd_domain", SCF_TYPE_ASTRING,
127 	    0},
128 	{SMB_CI_KPASSWD_SEQNUM, "kpasswd_seqnum", SCF_TYPE_INTEGER,
129 	    0},
130 	{SMB_CI_NETLOGON_SEQNUM, "netlogon_seqnum", SCF_TYPE_INTEGER,
131 	    0},
132 	{SMB_CI_IPV6_ENABLE, "ipv6_enable", SCF_TYPE_BOOLEAN, 0},
133 	{SMB_CI_PRINT_ENABLE, "print_enable", SCF_TYPE_BOOLEAN, 0},
134 	{SMB_CI_MAP, "map", SCF_TYPE_ASTRING, SMB_CF_EXEC},
135 	{SMB_CI_UNMAP, "unmap", SCF_TYPE_ASTRING, SMB_CF_EXEC},
136 	{SMB_CI_DISPOSITION, "disposition", SCF_TYPE_ASTRING, SMB_CF_EXEC},
137 	{SMB_CI_DFS_STDROOT_NUM, "dfs_stdroot_num", SCF_TYPE_INTEGER, 0},
138 	{SMB_CI_TRAVERSE_MOUNTS, "traverse_mounts", SCF_TYPE_BOOLEAN, 0},
139 	/* SMB_CI_MAX */
140 };
141 
142 static smb_cfg_param_t *smb_config_getent(smb_cfg_id_t);
143 
144 static boolean_t smb_is_base64(unsigned char c);
145 static char *smb_base64_encode(char *str_to_encode);
146 static char *smb_base64_decode(char *encoded_str);
147 
148 char *
149 smb_config_getname(smb_cfg_id_t id)
150 {
151 	smb_cfg_param_t *cfg;
152 	cfg = smb_config_getent(id);
153 	return (cfg->sc_name);
154 }
155 
156 static boolean_t
157 smb_is_base64(unsigned char c)
158 {
159 	return (isalnum(c) || (c == '+') || (c == '/'));
160 }
161 
162 /*
163  * smb_base64_encode
164  *
165  * Encode a string using base64 algorithm.
166  * Caller should free the returned buffer when done.
167  */
168 static char *
169 smb_base64_encode(char *str_to_encode)
170 {
171 	int ret_cnt = 0;
172 	int i = 0, j = 0;
173 	char arr_3[3], arr_4[4];
174 	int len = strlen(str_to_encode);
175 	char *ret = malloc(SMB_ENC_LEN);
176 
177 	if (ret == NULL) {
178 		return (NULL);
179 	}
180 
181 	while (len--) {
182 		arr_3[i++] = *(str_to_encode++);
183 		if (i == 3) {
184 			arr_4[0] = (arr_3[0] & 0xfc) >> 2;
185 			arr_4[1] = ((arr_3[0] & 0x03) << 4) +
186 			    ((arr_3[1] & 0xf0) >> 4);
187 			arr_4[2] = ((arr_3[1] & 0x0f) << 2) +
188 			    ((arr_3[2] & 0xc0) >> 6);
189 			arr_4[3] = arr_3[2] & 0x3f;
190 
191 			for (i = 0; i < 4; i++)
192 				ret[ret_cnt++] = b64_data[arr_4[i]];
193 			i = 0;
194 		}
195 	}
196 
197 	if (i) {
198 		for (j = i; j < 3; j++)
199 			arr_3[j] = '\0';
200 
201 		arr_4[0] = (arr_3[0] & 0xfc) >> 2;
202 		arr_4[1] = ((arr_3[0] & 0x03) << 4) +
203 		    ((arr_3[1] & 0xf0) >> 4);
204 		arr_4[2] = ((arr_3[1] & 0x0f) << 2) +
205 		    ((arr_3[2] & 0xc0) >> 6);
206 		arr_4[3] = arr_3[2] & 0x3f;
207 
208 		for (j = 0; j < (i + 1); j++)
209 			ret[ret_cnt++] = b64_data[arr_4[j]];
210 
211 		while (i++ < 3)
212 			ret[ret_cnt++] = '=';
213 	}
214 
215 	ret[ret_cnt++] = '\0';
216 	return (ret);
217 }
218 
219 /*
220  * smb_base64_decode
221  *
222  * Decode using base64 algorithm.
223  * Caller should free the returned buffer when done.
224  */
225 static char *
226 smb_base64_decode(char *encoded_str)
227 {
228 	int len = strlen(encoded_str);
229 	int i = 0, j = 0;
230 	int en_ind = 0;
231 	char arr_4[4], arr_3[3];
232 	int ret_cnt = 0;
233 	char *ret = malloc(SMB_DEC_LEN);
234 	char *p;
235 
236 	if (ret == NULL) {
237 		return (NULL);
238 	}
239 
240 	while (len-- && (encoded_str[en_ind] != '=') &&
241 	    smb_is_base64(encoded_str[en_ind])) {
242 		arr_4[i++] = encoded_str[en_ind];
243 		en_ind++;
244 		if (i == 4) {
245 			for (i = 0; i < 4; i++) {
246 				if ((p = strchr(b64_data, arr_4[i])) == NULL)
247 					return (NULL);
248 
249 				arr_4[i] = (int)(p - b64_data);
250 			}
251 
252 			arr_3[0] = (arr_4[0] << 2) +
253 			    ((arr_4[1] & 0x30) >> 4);
254 			arr_3[1] = ((arr_4[1] & 0xf) << 4) +
255 			    ((arr_4[2] & 0x3c) >> 2);
256 			arr_3[2] = ((arr_4[2] & 0x3) << 6) +
257 			    arr_4[3];
258 
259 			for (i = 0; i < 3; i++)
260 				ret[ret_cnt++] = arr_3[i];
261 
262 			i = 0;
263 		}
264 	}
265 
266 	if (i) {
267 		for (j = i; j < 4; j++)
268 			arr_4[j] = 0;
269 
270 		for (j = 0; j < 4; j++) {
271 			if ((p = strchr(b64_data, arr_4[j])) == NULL)
272 				return (NULL);
273 
274 			arr_4[j] = (int)(p - b64_data);
275 		}
276 		arr_3[0] = (arr_4[0] << 2) +
277 		    ((arr_4[1] & 0x30) >> 4);
278 		arr_3[1] = ((arr_4[1] & 0xf) << 4) +
279 		    ((arr_4[2] & 0x3c) >> 2);
280 		arr_3[2] = ((arr_4[2] & 0x3) << 6) +
281 		    arr_4[3];
282 		for (j = 0; j < (i - 1); j++)
283 			ret[ret_cnt++] = arr_3[j];
284 	}
285 
286 	ret[ret_cnt++] = '\0';
287 	return (ret);
288 }
289 
290 static char *
291 smb_config_getenv_generic(char *name, char *svc_fmri_prefix, char *svc_propgrp)
292 {
293 	smb_scfhandle_t *handle;
294 	char *value;
295 
296 	if ((value = malloc(MAX_VALUE_BUFLEN * sizeof (char))) == NULL)
297 		return (NULL);
298 
299 	handle = smb_smf_scf_init(svc_fmri_prefix);
300 	if (handle == NULL) {
301 		free(value);
302 		return (NULL);
303 	}
304 
305 	(void) smb_smf_create_service_pgroup(handle, svc_propgrp);
306 
307 	if (smb_smf_get_string_property(handle, name, value,
308 	    sizeof (char) * MAX_VALUE_BUFLEN) != 0) {
309 		smb_smf_scf_fini(handle);
310 		free(value);
311 		return (NULL);
312 	}
313 
314 	smb_smf_scf_fini(handle);
315 	return (value);
316 
317 }
318 
319 static int
320 smb_config_setenv_generic(char *svc_fmri_prefix, char *svc_propgrp,
321     char *name, char *value)
322 {
323 	smb_scfhandle_t *handle = NULL;
324 	int rc = 0;
325 
326 
327 	handle = smb_smf_scf_init(svc_fmri_prefix);
328 	if (handle == NULL) {
329 		return (1);
330 	}
331 
332 	(void) smb_smf_create_service_pgroup(handle, svc_propgrp);
333 
334 	if (smb_smf_start_transaction(handle) != SMBD_SMF_OK) {
335 		smb_smf_scf_fini(handle);
336 		return (1);
337 	}
338 
339 	if (smb_smf_set_string_property(handle, name, value) != SMBD_SMF_OK)
340 		rc = 1;
341 
342 	if (smb_smf_end_transaction(handle) != SMBD_SMF_OK)
343 		rc = 1;
344 
345 	smb_smf_scf_fini(handle);
346 	return (rc);
347 }
348 
349 /*
350  * smb_config_getstr
351  *
352  * Fetch the specified string configuration item from SMF
353  */
354 int
355 smb_config_getstr(smb_cfg_id_t id, char *cbuf, int bufsz)
356 {
357 	smb_scfhandle_t *handle;
358 	smb_cfg_param_t *cfg;
359 	int rc = SMBD_SMF_OK;
360 	char *pg;
361 	char protbuf[SMB_ENC_LEN];
362 	char *tmp;
363 
364 	*cbuf = '\0';
365 	cfg = smb_config_getent(id);
366 	assert(cfg->sc_type == SCF_TYPE_ASTRING);
367 
368 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
369 	if (handle == NULL)
370 		return (SMBD_SMF_SYSTEM_ERR);
371 
372 	if (cfg->sc_flags & SMB_CF_PROTECTED) {
373 		if ((rc = smb_smf_create_service_pgroup(handle,
374 		    SMBD_PROTECTED_PG_NAME)) != SMBD_SMF_OK)
375 			goto error;
376 
377 		if ((rc = smb_smf_get_string_property(handle, cfg->sc_name,
378 		    protbuf, sizeof (protbuf))) != SMBD_SMF_OK)
379 			goto error;
380 
381 		if (*protbuf != '\0') {
382 			tmp = smb_base64_decode(protbuf);
383 			(void) strlcpy(cbuf, tmp, bufsz);
384 			free(tmp);
385 		}
386 	} else {
387 		pg = (cfg->sc_flags & SMB_CF_EXEC) ? SMBD_EXEC_PG_NAME :
388 		    SMBD_PG_NAME;
389 		rc = smb_smf_create_service_pgroup(handle, pg);
390 		if (rc == SMBD_SMF_OK)
391 			rc = smb_smf_get_string_property(handle, cfg->sc_name,
392 			    cbuf, bufsz);
393 	}
394 
395 error:
396 	smb_smf_scf_fini(handle);
397 	return (rc);
398 }
399 
400 /*
401  * Translate the value of an astring SMF property into a binary
402  * IP address. If the value is neither a valid IPv4 nor IPv6
403  * address, attempt to look it up as a hostname using the
404  * configured address type.
405  */
406 int
407 smb_config_getip(smb_cfg_id_t sc_id, smb_inaddr_t *ipaddr)
408 {
409 	int rc, error;
410 	int a_family;
411 	char ipstr[MAXHOSTNAMELEN];
412 	struct hostent *h;
413 	smb_cfg_param_t *cfg;
414 
415 	if (ipaddr == NULL)
416 		return (SMBD_SMF_INVALID_ARG);
417 
418 	bzero(ipaddr, sizeof (smb_inaddr_t));
419 	rc = smb_config_getstr(sc_id, ipstr, sizeof (ipstr));
420 	if (rc == SMBD_SMF_OK) {
421 		if (*ipstr == '\0')
422 			return (SMBD_SMF_INVALID_ARG);
423 
424 		if (inet_pton(AF_INET, ipstr, &ipaddr->a_ipv4) == 1) {
425 			ipaddr->a_family = AF_INET;
426 			return (SMBD_SMF_OK);
427 		}
428 
429 		if (inet_pton(AF_INET6, ipstr, &ipaddr->a_ipv6) == 1) {
430 			ipaddr->a_family = AF_INET6;
431 			return (SMBD_SMF_OK);
432 		}
433 
434 		/*
435 		 * The value is neither an IPv4 nor IPv6 address;
436 		 * so check if it's a hostname.
437 		 */
438 		a_family = smb_config_getbool(SMB_CI_IPV6_ENABLE) ?
439 		    AF_INET6 : AF_INET;
440 		h = getipnodebyname(ipstr, a_family, AI_DEFAULT,
441 		    &error);
442 		if (h != NULL) {
443 			bcopy(*(h->h_addr_list), &ipaddr->a_ip,
444 			    h->h_length);
445 			ipaddr->a_family = a_family;
446 			freehostent(h);
447 			rc = SMBD_SMF_OK;
448 		} else {
449 			cfg = smb_config_getent(sc_id);
450 			syslog(LOG_ERR, "smbd/%s: %s unable to get %s "
451 			    "address: %d", cfg->sc_name, ipstr,
452 			    a_family == AF_INET ?  "IPv4" : "IPv6", error);
453 			rc = SMBD_SMF_INVALID_ARG;
454 		}
455 	}
456 
457 	return (rc);
458 }
459 
460 /*
461  * smb_config_getnum
462  *
463  * Returns the value of a numeric config param.
464  */
465 int
466 smb_config_getnum(smb_cfg_id_t id, int64_t *cint)
467 {
468 	smb_scfhandle_t *handle;
469 	smb_cfg_param_t *cfg;
470 	int rc = SMBD_SMF_OK;
471 
472 	*cint = 0;
473 	cfg = smb_config_getent(id);
474 	assert(cfg->sc_type == SCF_TYPE_INTEGER);
475 
476 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
477 	if (handle == NULL)
478 		return (SMBD_SMF_SYSTEM_ERR);
479 
480 	rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
481 	if (rc == SMBD_SMF_OK)
482 		rc = smb_smf_get_integer_property(handle, cfg->sc_name, cint);
483 	smb_smf_scf_fini(handle);
484 
485 	return (rc);
486 }
487 
488 /*
489  * smb_config_getbool
490  *
491  * Returns the value of a boolean config param.
492  */
493 boolean_t
494 smb_config_getbool(smb_cfg_id_t id)
495 {
496 	smb_scfhandle_t *handle;
497 	smb_cfg_param_t *cfg;
498 	int rc = SMBD_SMF_OK;
499 	uint8_t vbool;
500 
501 	cfg = smb_config_getent(id);
502 	assert(cfg->sc_type == SCF_TYPE_BOOLEAN);
503 
504 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
505 	if (handle == NULL)
506 		return (B_FALSE);
507 
508 	rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
509 	if (rc == SMBD_SMF_OK)
510 		rc = smb_smf_get_boolean_property(handle, cfg->sc_name, &vbool);
511 	smb_smf_scf_fini(handle);
512 
513 	return ((rc == SMBD_SMF_OK) ? (vbool == 1) : B_FALSE);
514 }
515 
516 /*
517  * smb_config_get
518  *
519  * This function returns the value of the requested config
520  * iterm regardless of its type in string format. This should
521  * be used when the config item type is not known by the caller.
522  */
523 int
524 smb_config_get(smb_cfg_id_t id, char *cbuf, int bufsz)
525 {
526 	smb_cfg_param_t *cfg;
527 	int64_t cint;
528 	int rc;
529 
530 	cfg = smb_config_getent(id);
531 	switch (cfg->sc_type) {
532 	case SCF_TYPE_ASTRING:
533 		return (smb_config_getstr(id, cbuf, bufsz));
534 
535 	case SCF_TYPE_INTEGER:
536 		rc = smb_config_getnum(id, &cint);
537 		if (rc == SMBD_SMF_OK)
538 			(void) snprintf(cbuf, bufsz, "%lld", cint);
539 		return (rc);
540 
541 	case SCF_TYPE_BOOLEAN:
542 		if (smb_config_getbool(id))
543 			(void) strlcpy(cbuf, "true", bufsz);
544 		else
545 			(void) strlcpy(cbuf, "false", bufsz);
546 		return (SMBD_SMF_OK);
547 	}
548 
549 	return (SMBD_SMF_INVALID_ARG);
550 }
551 
552 /*
553  * smb_config_setstr
554  *
555  * Set the specified config param with the given
556  * value.
557  */
558 int
559 smb_config_setstr(smb_cfg_id_t id, char *value)
560 {
561 	smb_scfhandle_t *handle;
562 	smb_cfg_param_t *cfg;
563 	int rc = SMBD_SMF_OK;
564 	boolean_t protected;
565 	char *tmp = NULL;
566 	char *pg;
567 
568 	cfg = smb_config_getent(id);
569 	assert(cfg->sc_type == SCF_TYPE_ASTRING);
570 
571 	protected = B_FALSE;
572 
573 	switch (cfg->sc_flags) {
574 	case SMB_CF_PROTECTED:
575 		protected = B_TRUE;
576 		pg = SMBD_PROTECTED_PG_NAME;
577 		break;
578 	case SMB_CF_EXEC:
579 		pg = SMBD_EXEC_PG_NAME;
580 		break;
581 	default:
582 		pg = SMBD_PG_NAME;
583 		break;
584 	}
585 
586 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
587 	if (handle == NULL)
588 		return (SMBD_SMF_SYSTEM_ERR);
589 
590 	rc = smb_smf_create_service_pgroup(handle, pg);
591 	if (rc == SMBD_SMF_OK)
592 		rc = smb_smf_start_transaction(handle);
593 
594 	if (rc != SMBD_SMF_OK) {
595 		smb_smf_scf_fini(handle);
596 		return (rc);
597 	}
598 
599 	if (protected && value && (*value != '\0')) {
600 		if ((tmp = smb_base64_encode(value)) == NULL) {
601 			(void) smb_smf_end_transaction(handle);
602 			smb_smf_scf_fini(handle);
603 			return (SMBD_SMF_NO_MEMORY);
604 		}
605 
606 		value = tmp;
607 	}
608 
609 	rc = smb_smf_set_string_property(handle, cfg->sc_name, value);
610 
611 	free(tmp);
612 	(void) smb_smf_end_transaction(handle);
613 	smb_smf_scf_fini(handle);
614 	return (rc);
615 }
616 
617 /*
618  * smb_config_setnum
619  *
620  * Sets a numeric configuration iterm
621  */
622 int
623 smb_config_setnum(smb_cfg_id_t id, int64_t value)
624 {
625 	smb_scfhandle_t *handle;
626 	smb_cfg_param_t *cfg;
627 	int rc = SMBD_SMF_OK;
628 
629 	cfg = smb_config_getent(id);
630 	assert(cfg->sc_type == SCF_TYPE_INTEGER);
631 
632 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
633 	if (handle == NULL)
634 		return (SMBD_SMF_SYSTEM_ERR);
635 
636 	rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
637 	if (rc == SMBD_SMF_OK)
638 		rc = smb_smf_start_transaction(handle);
639 
640 	if (rc != SMBD_SMF_OK) {
641 		smb_smf_scf_fini(handle);
642 		return (rc);
643 	}
644 
645 	rc = smb_smf_set_integer_property(handle, cfg->sc_name, value);
646 
647 	(void) smb_smf_end_transaction(handle);
648 	smb_smf_scf_fini(handle);
649 	return (rc);
650 }
651 
652 /*
653  * smb_config_setbool
654  *
655  * Sets a boolean configuration iterm
656  */
657 int
658 smb_config_setbool(smb_cfg_id_t id, boolean_t value)
659 {
660 	smb_scfhandle_t *handle;
661 	smb_cfg_param_t *cfg;
662 	int rc = SMBD_SMF_OK;
663 
664 	cfg = smb_config_getent(id);
665 	assert(cfg->sc_type == SCF_TYPE_BOOLEAN);
666 
667 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
668 	if (handle == NULL)
669 		return (SMBD_SMF_SYSTEM_ERR);
670 
671 	rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
672 	if (rc == SMBD_SMF_OK)
673 		rc = smb_smf_start_transaction(handle);
674 
675 	if (rc != SMBD_SMF_OK) {
676 		smb_smf_scf_fini(handle);
677 		return (rc);
678 	}
679 
680 	rc = smb_smf_set_boolean_property(handle, cfg->sc_name, value);
681 
682 	(void) smb_smf_end_transaction(handle);
683 	smb_smf_scf_fini(handle);
684 	return (rc);
685 }
686 
687 /*
688  * smb_config_set
689  *
690  * This function sets the value of the specified config
691  * iterm regardless of its type in string format. This should
692  * be used when the config item type is not known by the caller.
693  */
694 int
695 smb_config_set(smb_cfg_id_t id, char *value)
696 {
697 	smb_cfg_param_t *cfg;
698 	int64_t cint;
699 
700 	cfg = smb_config_getent(id);
701 	switch (cfg->sc_type) {
702 	case SCF_TYPE_ASTRING:
703 		return (smb_config_setstr(id, value));
704 
705 	case SCF_TYPE_INTEGER:
706 		cint = atoi(value);
707 		return (smb_config_setnum(id, cint));
708 
709 	case SCF_TYPE_BOOLEAN:
710 		return (smb_config_setbool(id, strcasecmp(value, "true") == 0));
711 	}
712 
713 	return (SMBD_SMF_INVALID_ARG);
714 }
715 
716 int
717 smb_config_get_debug()
718 {
719 	int64_t val64;
720 	int val = 0;	/* default */
721 	smb_scfhandle_t *handle = NULL;
722 
723 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
724 	if (handle == NULL) {
725 		return (val);
726 	}
727 
728 	if (smb_smf_create_service_pgroup(handle,
729 	    SMBD_PG_NAME) != SMBD_SMF_OK) {
730 		smb_smf_scf_fini(handle);
731 		return (val);
732 	}
733 
734 	if (smb_smf_get_integer_property(handle, "debug", &val64) != 0) {
735 		smb_smf_scf_fini(handle);
736 		return (val);
737 	}
738 	val = (int)val64;
739 
740 	smb_smf_scf_fini(handle);
741 
742 	return (val);
743 }
744 
745 uint8_t
746 smb_config_get_fg_flag()
747 {
748 	uint8_t run_fg = 0; /* Default is to run in daemon mode */
749 	smb_scfhandle_t *handle = NULL;
750 
751 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
752 	if (handle == NULL) {
753 		return (run_fg);
754 	}
755 
756 	if (smb_smf_create_service_pgroup(handle,
757 	    SMBD_PG_NAME) != SMBD_SMF_OK) {
758 		smb_smf_scf_fini(handle);
759 		return (run_fg);
760 	}
761 
762 	if (smb_smf_get_boolean_property(handle, "run_fg", &run_fg) != 0) {
763 		smb_smf_scf_fini(handle);
764 		return (run_fg);
765 	}
766 
767 	smb_smf_scf_fini(handle);
768 
769 	return (run_fg);
770 }
771 
772 /*
773  * smb_config_get_ads_enable
774  *
775  * Returns value of the "config/use_ads" parameter
776  * from the IDMAP SMF configuration repository.
777  *
778  */
779 boolean_t
780 smb_config_get_ads_enable(void)
781 {
782 	smb_scfhandle_t *handle = NULL;
783 	uint8_t vbool;
784 	int rc = 0;
785 
786 	handle = smb_smf_scf_init(IDMAP_FMRI_PREFIX);
787 	if (handle == NULL)
788 		return (B_FALSE);
789 
790 	rc = smb_smf_create_service_pgroup(handle, IDMAP_PG_NAME);
791 	if (rc == SMBD_SMF_OK)
792 		rc = smb_smf_get_boolean_property(handle, "use_ads", &vbool);
793 	smb_smf_scf_fini(handle);
794 
795 	return ((rc == SMBD_SMF_OK) ? (vbool == 1) : B_FALSE);
796 }
797 
798 /*
799  * smb_config_get_localsid
800  *
801  * Returns value of the "config/machine_sid" parameter
802  * from the IDMAP SMF configuration repository.
803  *
804  */
805 char *
806 smb_config_get_localsid(void)
807 {
808 	return (smb_config_getenv_generic(MACHINE_SID, IDMAP_FMRI_PREFIX,
809 	    IDMAP_PG_NAME));
810 }
811 
812 /*
813  * smb_config_set_idmap_domain
814  *
815  * Set the "config/domain_name" parameter from IDMAP SMF repository.
816  */
817 int
818 smb_config_set_idmap_domain(char *value)
819 {
820 	return (smb_config_setenv_generic(IDMAP_FMRI_PREFIX, IDMAP_PG_NAME,
821 	    IDMAP_DOMAIN, value));
822 }
823 
824 /*
825  * smb_config_refresh_idmap
826  *
827  * Refresh IDMAP SMF service after making changes to its configuration.
828  */
829 int
830 smb_config_refresh_idmap(void)
831 {
832 	char instance[32];
833 
834 	(void) snprintf(instance, sizeof (instance), "%s:default",
835 	    IDMAP_FMRI_PREFIX);
836 	return (smf_refresh_instance(instance));
837 }
838 
839 int
840 smb_config_secmode_fromstr(char *secmode)
841 {
842 	if (secmode == NULL)
843 		return (SMB_SECMODE_WORKGRP);
844 
845 	if (strcasecmp(secmode, SMB_SECMODE_DOMAIN_STR) == 0)
846 		return (SMB_SECMODE_DOMAIN);
847 
848 	return (SMB_SECMODE_WORKGRP);
849 }
850 
851 char *
852 smb_config_secmode_tostr(int secmode)
853 {
854 	if (secmode == SMB_SECMODE_DOMAIN)
855 		return (SMB_SECMODE_DOMAIN_STR);
856 
857 	return (SMB_SECMODE_WORKGRP_STR);
858 }
859 
860 int
861 smb_config_get_secmode()
862 {
863 	char p[16];
864 
865 	(void) smb_config_getstr(SMB_CI_SECURITY, p, sizeof (p));
866 	return (smb_config_secmode_fromstr(p));
867 }
868 
869 int
870 smb_config_set_secmode(int secmode)
871 {
872 	char *p;
873 
874 	p = smb_config_secmode_tostr(secmode);
875 	return (smb_config_setstr(SMB_CI_SECURITY, p));
876 }
877 
878 void
879 smb_config_getdomaininfo(char *domain, char *fqdn, char *sid, char *forest,
880     char *guid)
881 {
882 	if (domain)
883 		(void) smb_config_getstr(SMB_CI_DOMAIN_NAME, domain,
884 		    NETBIOS_NAME_SZ);
885 
886 	if (fqdn)
887 		(void) smb_config_getstr(SMB_CI_DOMAIN_FQDN, fqdn,
888 		    MAXHOSTNAMELEN);
889 
890 	if (sid)
891 		(void) smb_config_getstr(SMB_CI_DOMAIN_SID, sid,
892 		    SMB_SID_STRSZ);
893 
894 	if (forest)
895 		(void) smb_config_getstr(SMB_CI_DOMAIN_FOREST, forest,
896 		    MAXHOSTNAMELEN);
897 
898 	if (guid)
899 		(void) smb_config_getstr(SMB_CI_DOMAIN_GUID, guid,
900 		    UUID_PRINTABLE_STRING_LENGTH);
901 }
902 
903 void
904 smb_config_setdomaininfo(char *domain, char *fqdn, char *sid, char *forest,
905     char *guid)
906 {
907 	if (domain)
908 		(void) smb_config_setstr(SMB_CI_DOMAIN_NAME, domain);
909 	if (fqdn)
910 		(void) smb_config_setstr(SMB_CI_DOMAIN_FQDN, fqdn);
911 	if (sid)
912 		(void) smb_config_setstr(SMB_CI_DOMAIN_SID, sid);
913 	if (forest)
914 		(void) smb_config_setstr(SMB_CI_DOMAIN_FOREST, forest);
915 	if (guid)
916 		(void) smb_config_setstr(SMB_CI_DOMAIN_GUID, guid);
917 }
918 
919 /*
920  * The version stored in SMF in string format as N.N where
921  * N is a number defined by Microsoft. The first number represents
922  * the major version and the second number is the minor version.
923  * Current defined values can be found here in 'ver_table'.
924  *
925  * This function reads the SMF string value and converts it to
926  * two numbers returned in the given 'version' structure.
927  * Current default version number is 5.0 which is for Windows 2000.
928  */
929 void
930 smb_config_get_version(smb_version_t *version)
931 {
932 	smb_version_t tmpver;
933 	char verstr[SMB_VERSTR_LEN];
934 	char *p;
935 	int rc, i;
936 	static smb_version_t ver_table [] = {
937 		{ 0, SMB_MAJOR_NT,	SMB_MINOR_NT,		1381,	0 },
938 		{ 0, SMB_MAJOR_2000,	SMB_MINOR_2000,		2195,	0 },
939 		{ 0, SMB_MAJOR_XP,	SMB_MINOR_XP,		2196,	0 },
940 		{ 0, SMB_MAJOR_2003,	SMB_MINOR_2003,		2196,	0 },
941 		{ 0, SMB_MAJOR_VISTA,	SMB_MINOR_VISTA,	6000,	0 },
942 		{ 0, SMB_MAJOR_2008,	SMB_MINOR_2008,		6000,	0 },
943 		{ 0, SMB_MAJOR_2008R2,	SMB_MINOR_2008R2,	7007,	0 },
944 		{ 0, SMB_MAJOR_7,	SMB_MINOR_7,		7007,	0 }
945 	};
946 
947 	*version = ver_table[1];
948 	version->sv_size = sizeof (smb_version_t);
949 
950 	rc = smb_config_getstr(SMB_CI_VERSION, verstr, sizeof (verstr));
951 	if (rc != SMBD_SMF_OK)
952 		return;
953 
954 	if ((p = strchr(verstr, '.')) == NULL)
955 		return;
956 
957 	*p = '\0';
958 	tmpver.sv_major = (uint8_t)atoi(verstr);
959 	tmpver.sv_minor = (uint8_t)atoi(p + 1);
960 
961 	for (i = 0; i < sizeof (ver_table)/sizeof (ver_table[0]); ++i) {
962 		if ((tmpver.sv_major == ver_table[i].sv_major) &&
963 		    (tmpver.sv_minor == ver_table[i].sv_minor)) {
964 			*version = ver_table[i];
965 			version->sv_size = sizeof (smb_version_t);
966 			break;
967 		}
968 	}
969 }
970 
971 /*
972  * Reads share exec script properties
973  */
974 uint32_t
975 smb_config_get_execinfo(char *map, char *unmap, size_t bufsz)
976 {
977 	char buf[MAXPATHLEN];
978 	uint32_t flags = 0;
979 
980 	if (map == NULL) {
981 		map = buf;
982 		bufsz = MAXPATHLEN;
983 	}
984 
985 	*map = '\0';
986 	(void) smb_config_getstr(SMB_CI_MAP, map, bufsz);
987 	if (*map != '\0')
988 		flags |= SMB_EXEC_MAP;
989 
990 	if (unmap == NULL) {
991 		unmap = buf;
992 		bufsz = MAXPATHLEN;
993 	}
994 
995 	*unmap = '\0';
996 	(void) smb_config_getstr(SMB_CI_UNMAP, unmap, bufsz);
997 	if (*unmap != '\0')
998 		flags |= SMB_EXEC_UNMAP;
999 
1000 	*buf = '\0';
1001 	(void) smb_config_getstr(SMB_CI_DISPOSITION, buf, sizeof (buf));
1002 	if (*buf != '\0')
1003 		if (strcasecmp(buf, SMB_EXEC_DISP_TERMINATE) == 0)
1004 			flags |= SMB_EXEC_TERM;
1005 
1006 	return (flags);
1007 }
1008 
1009 static smb_cfg_param_t *
1010 smb_config_getent(smb_cfg_id_t id)
1011 {
1012 	int i;
1013 
1014 	for (i = 0; i < SMB_CI_MAX; i++)
1015 		if (smb_cfg_table[i].sc_id == id)
1016 			return (&smb_cfg_table[id]);
1017 
1018 	assert(0);
1019 	return (NULL);
1020 }
1021