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