xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c (revision 942c5e3c2dd127463517e5cc1694ee94ca45e021)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * CIFS configuration management library
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <synch.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <syslog.h>
39 #include <netdb.h>
40 #include <ctype.h>
41 #include <sys/types.h>
42 #include <libscf.h>
43 #include <smbsrv/libsmb.h>
44 
45 typedef struct smb_cfg_param {
46 	char *sc_pg;
47 	char *sc_name;
48 	int sc_type;
49 	char *sc_value;
50 	uint32_t sc_flags;
51 } smb_cfg_param_t;
52 
53 /*
54  * config parameter flags
55  */
56 #define	SMB_CF_NOTINIT		0x00	/* Not initialized yet */
57 #define	SMB_CF_DEFINED		0x01	/* Defined/read from env */
58 #define	SMB_CF_MODIFIED		0x02	/* Has been modified */
59 #define	SMB_CF_SYSTEM		0x04    /* system; not part of cifs config */
60 
61 #define	SMB_CL_NONE	0
62 #define	SMB_CL_READ	1
63 #define	SMB_CL_WRITE    2
64 
65 /* idmap SMF fmri and Property Group */
66 #define	IDMAP_FMRI_PREFIX		"system/idmap"
67 #define	MACHINE_SID			"machine_sid"
68 #define	IDMAP_DOMAIN			"domain_name"
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 rwlock_t smb_cfg_rwlk;
81 static int lock_type = SMB_CL_NONE;
82 
83 /*
84  * IMPORTANT: any changes to the order of this table's entries
85  * need to be reflected in smb_cfg_id_t enum in libsmb.h
86  */
87 static smb_cfg_param_t smb_cfg_table[] =
88 {
89 	/* Redirector configuration, User space */
90 	{SMBD_PG_NAME, SMB_CD_RDR_IPCMODE, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
91 	{SMBD_PROTECTED_PG_NAME, SMB_CD_RDR_IPCUSER,
92 	    SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
93 	{SMBD_PROTECTED_PG_NAME, SMB_CD_RDR_IPCPWD,
94 	    SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
95 
96 	/* Oplock configuration, Kernel Only */
97 	{SMBD_PG_NAME, SMB_CD_OPLOCK_ENABLE,
98 	    SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
99 	{SMBD_PG_NAME, SMB_CD_OPLOCK_TIMEOUT,
100 	    SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
101 
102 	/* Autohome configuration */
103 	{SMBD_PG_NAME, SMB_CD_AUTOHOME_MAP,
104 	    SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
105 
106 	/* Domain/PDC configuration */
107 	{SMBD_PG_NAME, SMB_CD_DOMAIN_SID, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
108 	{SMBD_PG_NAME, SMB_CD_DOMAIN_MEMB, SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
109 	{SMBD_PG_NAME, SMB_CD_DOMAIN_NAME, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
110 	{SMBD_PG_NAME, SMB_CD_DOMAIN_SRV, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
111 
112 	/* WINS configuration */
113 	{SMBD_PG_NAME, SMB_CD_WINS_SRV1, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
114 	{SMBD_PG_NAME, SMB_CD_WINS_SRV2, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
115 	{SMBD_PG_NAME, SMB_CD_WINS_EXCL, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
116 
117 	/* RPC services configuration */
118 	{SMBD_PG_NAME, SMB_CD_SRVSVC_SHRSET_ENABLE,
119 	    SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
120 	{SMBD_PG_NAME, SMB_CD_LOGR_ENABLE, SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
121 	{SMBD_PG_NAME, SMB_CD_MLRPC_KALIVE,
122 	    SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
123 
124 	/* Kmod specific configuration */
125 	{SMBD_PG_NAME, SMB_CD_MAX_BUFSIZE, SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
126 	{SMBD_PG_NAME, SMB_CD_MAX_WORKERS, SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
127 	{SMBD_PG_NAME, SMB_CD_MAX_CONNECTIONS,
128 	    SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
129 	{SMBD_PG_NAME, SMB_CD_KEEPALIVE, SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
130 	{SMBD_PG_NAME, SMB_CD_RESTRICT_ANON,
131 	    SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
132 
133 	{SMBD_PG_NAME, SMB_CD_SIGNING_ENABLE,
134 	    SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
135 	{SMBD_PG_NAME, SMB_CD_SIGNING_REQD,
136 	    SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
137 	{SMBD_PG_NAME, SMB_CD_SIGNING_CHECK,
138 	    SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
139 
140 	/* Kmod tuning configuration */
141 	{SMBD_PG_NAME, SMB_CD_FLUSH_REQUIRED,
142 	    SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
143 	{SMBD_PG_NAME, SMB_CD_SYNC_ENABLE, SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
144 	{SMBD_PG_NAME, SMB_CD_DIRSYMLINK_DISABLE,
145 	    SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
146 	{SMBD_PG_NAME, SMB_CD_ANNONCE_QUOTA,
147 	    SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
148 
149 	/* SMBd configuration */
150 	{SMBD_PG_NAME, SMB_CD_SECURITY,	SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
151 	{SMBD_PG_NAME, SMB_CD_NBSCOPE, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
152 	{SMBD_PG_NAME, SMB_CD_SYS_CMNT,	SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
153 	{SMBD_PG_NAME, SMB_CD_LM_LEVEL,	SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
154 	{SMBD_PG_NAME, SMB_CD_MSDCS_DISABLE,
155 	    SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
156 
157 	/* ADS Configuration */
158 	{SMBD_PG_NAME, SMB_CD_ADS_ENABLE, SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
159 	{SMBD_PROTECTED_PG_NAME, SMB_CD_ADS_USER,
160 	    SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
161 	{SMBD_PROTECTED_PG_NAME, SMB_CD_ADS_PASSWD,
162 	    SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
163 	{SMBD_PG_NAME, SMB_CD_ADS_DOMAIN, SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
164 	{SMBD_PG_NAME, SMB_CD_ADS_USER_CONTAINER,
165 	    SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
166 	{SMBD_PG_NAME, SMB_CD_ADS_SITE,	SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT},
167 	{SMBD_PG_NAME, SMB_CD_ADS_IPLOOKUP,
168 	    SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
169 
170 	/* Dynamic DNS */
171 	{SMBD_PG_NAME, SMB_CD_DYNDNS_ENABLE,
172 	    SCF_TYPE_BOOLEAN, 0, SMB_CF_NOTINIT},
173 	{SMBD_PG_NAME, SMB_CD_DYNDNS_RETRY_COUNT,
174 	    SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
175 	{SMBD_PG_NAME, SMB_CD_DYNDNS_RETRY_SEC,
176 	    SCF_TYPE_INTEGER, 0, SMB_CF_NOTINIT},
177 
178 	{SMBD_PROTECTED_PG_NAME, SMB_CD_MACHINE_PASSWD,
179 	    SCF_TYPE_ASTRING, 0, SMB_CF_NOTINIT}
180 	/* SMB_CI_MAX */
181 };
182 
183 static boolean_t smb_is_base64(unsigned char c);
184 static char *smb_base64_encode(char *str_to_encode);
185 static char *smb_base64_decode(char *encoded_str);
186 static int smb_config_update(smb_cfg_param_t *cfg, char *value);
187 static int smb_config_save_all();
188 static int smb_config_save(char *pgname);
189 
190 static boolean_t
191 smb_is_base64(unsigned char c)
192 {
193 	return (isalnum(c) || (c == '+') || (c == '/'));
194 }
195 
196 /*
197  * smb_base64_encode
198  *
199  * Encode a string using base64 algorithm.
200  * Caller should free the returned buffer when done.
201  */
202 static char *
203 smb_base64_encode(char *str_to_encode)
204 {
205 	int ret_cnt = 0;
206 	int i = 0, j = 0;
207 	char arr_3[3], arr_4[4];
208 	int len = strlen(str_to_encode);
209 	char *ret = malloc(SMB_ENC_LEN);
210 
211 	if (ret == NULL) {
212 		return (NULL);
213 	}
214 
215 	while (len--) {
216 		arr_3[i++] = *(str_to_encode++);
217 		if (i == 3) {
218 			arr_4[0] = (arr_3[0] & 0xfc) >> 2;
219 			arr_4[1] = ((arr_3[0] & 0x03) << 4) +
220 			    ((arr_3[1] & 0xf0) >> 4);
221 			arr_4[2] = ((arr_3[1] & 0x0f) << 2) +
222 			    ((arr_3[2] & 0xc0) >> 6);
223 			arr_4[3] = arr_3[2] & 0x3f;
224 
225 			for (i = 0; i < 4; i++)
226 				ret[ret_cnt++] = b64_data[arr_4[i]];
227 			i = 0;
228 		}
229 	}
230 
231 	if (i) {
232 		for (j = i; j < 3; j++)
233 			arr_3[j] = '\0';
234 
235 		arr_4[0] = (arr_3[0] & 0xfc) >> 2;
236 		arr_4[1] = ((arr_3[0] & 0x03) << 4) +
237 		    ((arr_3[1] & 0xf0) >> 4);
238 		arr_4[2] = ((arr_3[1] & 0x0f) << 2) +
239 		    ((arr_3[2] & 0xc0) >> 6);
240 		arr_4[3] = arr_3[2] & 0x3f;
241 
242 		for (j = 0; j < (i + 1); j++)
243 			ret[ret_cnt++] = b64_data[arr_4[j]];
244 
245 		while (i++ < 3)
246 			ret[ret_cnt++] = '=';
247 	}
248 
249 	ret[ret_cnt++] = '\0';
250 	return (ret);
251 }
252 
253 /*
254  * smb_base64_decode
255  *
256  * Decode using base64 algorithm.
257  * Caller should free the returned buffer when done.
258  */
259 static char *
260 smb_base64_decode(char *encoded_str)
261 {
262 	int len = strlen(encoded_str);
263 	int i = 0, j = 0;
264 	int en_ind = 0;
265 	char arr_4[4], arr_3[3];
266 	int ret_cnt = 0;
267 	char *ret = malloc(SMB_DEC_LEN);
268 	char *p;
269 
270 	if (ret == NULL) {
271 		return (NULL);
272 	}
273 
274 	while (len-- && (encoded_str[en_ind] != '=') &&
275 	    smb_is_base64(encoded_str[en_ind])) {
276 		arr_4[i++] = encoded_str[en_ind];
277 		en_ind++;
278 		if (i == 4) {
279 			for (i = 0; i < 4; i++) {
280 				if ((p = strchr(b64_data, arr_4[i])) == NULL)
281 					return (NULL);
282 
283 				arr_4[i] = (int)(p - b64_data);
284 			}
285 
286 			arr_3[0] = (arr_4[0] << 2) +
287 			    ((arr_4[1] & 0x30) >> 4);
288 			arr_3[1] = ((arr_4[1] & 0xf) << 4) +
289 			    ((arr_4[2] & 0x3c) >> 2);
290 			arr_3[2] = ((arr_4[2] & 0x3) << 6) +
291 			    arr_4[3];
292 
293 			for (i = 0; i < 3; i++)
294 				ret[ret_cnt++] = arr_3[i];
295 
296 			i = 0;
297 		}
298 	}
299 
300 	if (i) {
301 		for (j = i; j < 4; j++)
302 			arr_4[j] = 0;
303 
304 		for (j = 0; j < 4; j++) {
305 			if ((p = strchr(b64_data, arr_4[j])) == NULL)
306 				return (NULL);
307 
308 			arr_4[j] = (int)(p - b64_data);
309 		}
310 		arr_3[0] = (arr_4[0] << 2) +
311 		    ((arr_4[1] & 0x30) >> 4);
312 		arr_3[1] = ((arr_4[1] & 0xf) << 4) +
313 		    ((arr_4[2] & 0x3c) >> 2);
314 		arr_3[2] = ((arr_4[2] & 0x3) << 6) +
315 		    arr_4[3];
316 		for (j = 0; j < (i - 1); j++)
317 			ret[ret_cnt++] = arr_3[j];
318 	}
319 
320 	ret[ret_cnt++] = '\0';
321 	return (ret);
322 }
323 
324 /*
325  * Basically commit the transaction.
326  */
327 static int
328 smb_config_saveenv(smb_scfhandle_t *handle)
329 {
330 	int ret = 0;
331 
332 	ret = smb_smf_end_transaction(handle);
333 
334 	smb_smf_scf_fini(handle);
335 	return (ret);
336 }
337 
338 /*
339  * smb_config_getenv
340  *
341  * Get the property value from SMF.
342  */
343 char *
344 smb_config_getenv(smb_cfg_id_t id)
345 {
346 	smb_scfhandle_t *handle;
347 	char *value;
348 
349 	if ((value = malloc(MAX_VALUE_BUFLEN * sizeof (char))) == NULL)
350 		return (NULL);
351 
352 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
353 	if (handle == NULL) {
354 		free(value);
355 		return (NULL);
356 	}
357 
358 	(void) smb_smf_create_service_pgroup(handle, smb_cfg_table[id].sc_pg);
359 
360 	if (smb_smf_get_property(handle, smb_cfg_table[id].sc_type,
361 	    smb_cfg_table[id].sc_name, value,
362 	    sizeof (char) * MAX_VALUE_BUFLEN) != 0) {
363 		smb_smf_scf_fini(handle);
364 		free(value);
365 		return (NULL);
366 	}
367 
368 	smb_smf_scf_fini(handle);
369 	return (value);
370 }
371 
372 /*
373  * smb_config_getenv_dec
374  *
375  * For protected property, the value obtained from SMF will be decoded.
376  * The decoded property value will be returned.
377  *
378  * This function should only be called by smb_config_load to populate
379  * the SMB config cache.
380  */
381 static char *
382 smb_config_getenv_dec(smb_cfg_id_t id)
383 {
384 	smb_scfhandle_t *handle;
385 	char *value;
386 	char *dec;
387 
388 	if ((value = malloc(MAX_VALUE_BUFLEN * sizeof (char))) == NULL)
389 		return (NULL);
390 
391 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
392 	if (handle == NULL) {
393 		free(value);
394 		return (NULL);
395 	}
396 
397 	(void) smb_smf_create_service_pgroup(handle, smb_cfg_table[id].sc_pg);
398 
399 	if (smb_smf_get_property(handle, smb_cfg_table[id].sc_type,
400 	    smb_cfg_table[id].sc_name, value,
401 	    sizeof (char) * MAX_VALUE_BUFLEN) != 0) {
402 		smb_smf_scf_fini(handle);
403 		free(value);
404 		return (NULL);
405 	}
406 	smb_smf_scf_fini(handle);
407 	if (strcmp(smb_cfg_table[id].sc_pg, SMBD_PROTECTED_PG_NAME))
408 		return (value);
409 
410 	if (!value)
411 		return (NULL);
412 
413 	if (*value == '\0') {
414 		free(value);
415 		return (NULL);
416 	}
417 
418 	dec = smb_base64_decode(value);
419 	free(value);
420 	return (dec);
421 }
422 
423 static char *
424 smb_config_getenv_generic(char *name, char *svc_fmri_prefix, char *svc_propgrp)
425 {
426 	smb_scfhandle_t *handle;
427 	char *value;
428 
429 	if ((value = malloc(MAX_VALUE_BUFLEN * sizeof (char))) == NULL)
430 		return (NULL);
431 
432 	handle = smb_smf_scf_init(svc_fmri_prefix);
433 	if (handle == NULL) {
434 		free(value);
435 		return (NULL);
436 	}
437 
438 	(void) smb_smf_create_service_pgroup(handle, svc_propgrp);
439 
440 	if (smb_smf_get_string_property(handle, name, value,
441 	    sizeof (char) * MAX_VALUE_BUFLEN) != 0) {
442 		smb_smf_scf_fini(handle);
443 		free(value);
444 		return (NULL);
445 	}
446 
447 	smb_smf_scf_fini(handle);
448 	return (value);
449 
450 }
451 
452 int
453 smb_config_setenv_generic(char *svc_fmri_prefix, char *svc_propgrp,
454     char *name, char *value)
455 {
456 	smb_scfhandle_t *handle = NULL;
457 	int rc = 0;
458 
459 
460 	handle = smb_smf_scf_init(svc_fmri_prefix);
461 	if (handle == NULL) {
462 		return (1);
463 	}
464 
465 	(void) smb_smf_create_service_pgroup(handle, svc_propgrp);
466 
467 	if (smb_smf_start_transaction(handle) != SMBD_SMF_OK) {
468 		smb_smf_scf_fini(handle);
469 		return (1);
470 	}
471 
472 	if (smb_smf_set_string_property(handle, name, value) != SMBD_SMF_OK)
473 		rc = 1;
474 
475 	if (smb_smf_end_transaction(handle) != SMBD_SMF_OK)
476 		rc = 1;
477 
478 	smb_smf_scf_fini(handle);
479 	return (rc);
480 }
481 
482 /*
483  * smb_config_setenv
484  *
485  * For protected properties, the value will be encoded using base64
486  * algorithm. The encoded string will be stored in SMF.
487  */
488 int
489 smb_config_setenv(smb_cfg_id_t id, char *value)
490 {
491 	smb_scfhandle_t *handle = NULL;
492 	char *enc = NULL;
493 	int is_protected = 0;
494 
495 	if ((id >= SMB_CI_MAX) || (id < 0)) {
496 		return (1);
497 	}
498 
499 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
500 	if (handle == NULL) {
501 		return (1);
502 	}
503 
504 	(void) smb_smf_create_service_pgroup(handle, smb_cfg_table[id].sc_pg);
505 
506 	if (smb_smf_start_transaction(handle) != SMBD_SMF_OK) {
507 		smb_smf_scf_fini(handle);
508 		return (1);
509 	}
510 
511 	if (strcmp(smb_cfg_table[id].sc_pg, SMBD_PROTECTED_PG_NAME) == 0) {
512 		if ((value == NULL) || (*value == '\0')) {
513 			(void) smb_smf_end_transaction(handle);
514 			smb_smf_scf_fini(handle);
515 			return (1);
516 		}
517 
518 		if ((enc = smb_base64_encode(value)) == NULL) {
519 			(void) smb_smf_end_transaction(handle);
520 			smb_smf_scf_fini(handle);
521 			return (1);
522 		}
523 
524 		is_protected = 1;
525 	}
526 
527 	if (smb_smf_set_property(handle, smb_cfg_table[id].sc_type,
528 	    smb_cfg_table[id].sc_name, is_protected ? enc : value)
529 	    != SMBD_SMF_OK) {
530 		if (enc)
531 			free(enc);
532 		(void) smb_smf_end_transaction(handle);
533 		smb_smf_scf_fini(handle);
534 		return (1);
535 	}
536 
537 	if (enc)
538 		free(enc);
539 
540 	if (smb_smf_end_transaction(handle) != SMBD_SMF_OK) {
541 		smb_smf_scf_fini(handle);
542 		return (1);
543 	}
544 
545 	smb_smf_scf_fini(handle);
546 	return (0);
547 }
548 
549 static void
550 smb_config_setenv_trans(smb_scfhandle_t *handle, int type,
551     char *name, char *value)
552 {
553 	if (smb_smf_set_property(handle, type, name, value) != SMBD_SMF_OK) {
554 		syslog(LOG_ERR, "Failed to save service property %s", name);
555 	}
556 }
557 
558 /*
559  * smb_config_setenv_trans_protected
560  *
561  * This function should only be called to set protected properties
562  * in SMF. The argument 'value' will be encoded using base64 algorithm.
563  * The encoded string will be stored in SMF.
564  */
565 static void
566 smb_config_setenv_trans_protected(smb_scfhandle_t *handle, char *name,
567     char *value)
568 {
569 	char *enc;
570 
571 	if ((value == NULL) || (*value == '\0'))
572 		return;
573 
574 	if ((enc = smb_base64_encode(value)) == NULL)
575 		return;
576 
577 	if (smb_smf_set_string_property(handle, name, enc) != SMBD_SMF_OK) {
578 		syslog(LOG_ERR, "Failed to save service protected property"
579 		    " %s", name);
580 	}
581 
582 	free(enc);
583 }
584 
585 int
586 smb_config_unsetenv(smb_cfg_id_t id)
587 {
588 	smb_scfhandle_t *handle = NULL;
589 	int ret = 1;
590 
591 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
592 	if (handle == NULL) {
593 		return (ret);
594 	}
595 
596 	(void) smb_smf_create_service_pgroup(handle, smb_cfg_table[id].sc_pg);
597 	if (smb_smf_start_transaction(handle) != SMBD_SMF_OK) {
598 		smb_smf_scf_fini(handle);
599 		return (ret);
600 	}
601 	ret = smb_smf_delete_property(handle, smb_cfg_table[id].sc_name);
602 	(void) smb_smf_end_transaction(handle);
603 
604 	smb_smf_scf_fini(handle);
605 	return (ret);
606 }
607 
608 static int
609 smb_config_unsetenv_trans(smb_scfhandle_t *handle, char *name)
610 {
611 	return (smb_smf_delete_property(handle, name));
612 }
613 
614 /*
615  * smb_config_load
616  *
617  * Loads all the CIFS configuration parameters and sets up the
618  * config table.
619  */
620 int
621 smb_config_load()
622 {
623 	smb_cfg_id_t id;
624 	smb_cfg_param_t *cfg;
625 	char *value;
626 
627 	(void) rw_rdlock(&smb_cfg_rwlk);
628 	for (id = 0; id < SMB_CI_MAX; id++) {
629 		value = smb_config_getenv_dec(id);
630 		cfg = &smb_cfg_table[id];
631 		/*
632 		 * enval == 0 could mean two things, either the
633 		 * config param is not defined, or it has been
634 		 * removed. If the variable has already been defined
635 		 * and now enval is 0, it should be removed, otherwise
636 		 * we don't need to do anything in this case.
637 		 */
638 		if ((cfg->sc_flags & SMB_CF_DEFINED) || value) {
639 			if (smb_config_update(cfg, value) != 0) {
640 				(void) rw_unlock(&smb_cfg_rwlk);
641 				if (value)
642 					free(value);
643 				return (1);
644 			}
645 		}
646 		if (value) {
647 			free(value);
648 		}
649 	}
650 
651 	(void) rw_unlock(&smb_cfg_rwlk);
652 
653 	return (0);
654 }
655 
656 /*
657  * smb_config_get
658  *
659  * Returns value of the specified config param.
660  * The return value is a string pointer to the locally
661  * allocated memory if the config param is defined
662  * otherwise it would be NULL.
663  *
664  * This function MUST be called after a smb_config_rd/wrlock
665  * function. Caller MUST NOT modify the returned buffer directly.
666  */
667 char *
668 smb_config_get(smb_cfg_id_t id)
669 {
670 	if (id < SMB_CI_MAX)
671 		return (smb_cfg_table[id].sc_value);
672 
673 	return (0);
674 }
675 
676 /*
677  * smb_config_getstr
678  *
679  * Returns value of the specified config param.
680  * The returned pointer never will be NULL if the given
681  * 'id' is valid. If the config param is not defined its
682  * default value will be returned.
683  *
684  * This function MUST be called after a smb_config_rd/wrlock
685  * function. Caller MUST NOT modify the returned buffer directly.
686  */
687 char *
688 smb_config_getstr(smb_cfg_id_t id)
689 {
690 	smb_cfg_param_t *cfg;
691 
692 	if (id < SMB_CI_MAX) {
693 		cfg = &smb_cfg_table[id];
694 		if (cfg->sc_value)
695 			return (cfg->sc_value);
696 	}
697 
698 	return (NULL);
699 }
700 
701 /*
702  * smb_config_getnum
703  *
704  * Returns the value of a numeric config param.
705  * If the config param is not defined it'll return the
706  * default value.
707  *
708  * This function MUST be called after a smb_config_rd/wrlock
709  * function.
710  */
711 uint32_t
712 smb_config_getnum(smb_cfg_id_t id)
713 {
714 	smb_cfg_param_t *cfg;
715 	char *strval = NULL;
716 
717 	if (id < SMB_CI_MAX) {
718 		cfg = &smb_cfg_table[id];
719 		if (cfg->sc_value)
720 			strval = cfg->sc_value;
721 
722 		if (strval)
723 			return (strtol(strval, 0, 10));
724 	}
725 
726 	return (0);
727 }
728 
729 /*
730  * smb_config_getyorn
731  *
732  * Returns the value of a yes/no config param.
733  * Returns 1 is config is set to "yes", otherwise 0.
734  *
735  * This function MUST be called after a smb_config_rd/wrlock
736  * function.
737  */
738 int
739 smb_config_getyorn(smb_cfg_id_t id)
740 {
741 	char *val;
742 
743 	val = smb_config_get(id);
744 	if (val) {
745 		if (strcasecmp(val, "true") == 0)
746 			return (1);
747 	}
748 
749 	return (0);
750 }
751 
752 /*
753  * smb_config_set
754  *
755  * Set/update the specified config param with the given
756  * value. If the value is NULL the config param will be
757  * unset as if it is not defined.
758  *
759  * This function MUST be called after a smb_config_wrlock
760  * function.
761  */
762 int
763 smb_config_set(smb_cfg_id_t id, char *value)
764 {
765 	smb_cfg_param_t *cfg;
766 	int rc = 0;
767 
768 	if (id < SMB_CI_MAX) {
769 		cfg = &smb_cfg_table[id];
770 		rc = smb_config_update(cfg, value);
771 		if (rc == 0)
772 			cfg->sc_flags |= SMB_CF_MODIFIED;
773 		return (rc);
774 	}
775 
776 	return (1);
777 }
778 
779 /*
780  * smb_config_setnum
781  *
782  * Set/update the specified config param with the given
783  * value. This is used for numeric config params. The given
784  * number will be converted to string before setting the
785  * config param.
786  *
787  * This function MUST be called after a smb_config_wrlock
788  * function.
789  */
790 int
791 smb_config_setnum(smb_cfg_id_t id, uint32_t num)
792 {
793 	smb_cfg_param_t *cfg;
794 	char value[32];
795 	int rc = 0;
796 
797 	if (id < SMB_CI_MAX) {
798 		cfg = &smb_cfg_table[id];
799 		(void) snprintf(value, sizeof (value), "%u", num);
800 		rc = smb_config_update(cfg, value);
801 		if (rc == 0)
802 			cfg->sc_flags |= SMB_CF_MODIFIED;
803 		return (rc);
804 	}
805 
806 	return (1);
807 }
808 
809 /*
810  * smb_config_rdlock
811  *
812  * Lock the config table for read access.
813  * This function MUST be called before any kind of
814  * read access to the config table i.e. all flavors of
815  * smb_config_get function
816  */
817 void
818 smb_config_rdlock()
819 {
820 	(void) rw_rdlock(&smb_cfg_rwlk);
821 	lock_type = SMB_CL_READ;
822 }
823 
824 /*
825  * smb_config_wrlock
826  *
827  * Lock the config table for write access.
828  * This function MUST be called before any kind of
829  * write access to the config table i.e. all flavors of
830  * smb_config_set function
831  */
832 void
833 smb_config_wrlock()
834 {
835 	(void) rw_wrlock(&smb_cfg_rwlk);
836 	lock_type = SMB_CL_WRITE;
837 }
838 
839 /*
840  * smb_config_wrlock
841  *
842  * Unlock the config table.
843  * If the config table has been locked for write access
844  * smb_config_save_all() will be called to save the changes
845  * before unlocking the table.
846  *
847  * This function MUST be called after smb_config_rd/wrlock
848  */
849 void
850 smb_config_unlock()
851 {
852 	if (lock_type == SMB_CL_WRITE)
853 		(void) smb_config_save_all();
854 	(void) rw_unlock(&smb_cfg_rwlk);
855 }
856 
857 /*
858  * smb_config_save_all
859  *
860  * Save all modified parameters to SMF.
861  */
862 static int
863 smb_config_save_all()
864 {
865 	int rc;
866 
867 	if ((rc = smb_config_save(SMBD_PG_NAME)) != 0)
868 		return (rc);
869 
870 	return (smb_config_save(SMBD_PROTECTED_PG_NAME));
871 }
872 
873 /*
874  * smb_config_save
875  *
876  * Scan the config table and call smb_config_setenv/smb_config_unsetenv
877  * for params in the specified property group that has been modified.
878  * When the scan is finished, smb_config_saveenv() will be called to
879  * make the changes persistent.
880  */
881 static int
882 smb_config_save(char *pgname)
883 {
884 	smb_cfg_id_t id;
885 	smb_cfg_param_t *cfg;
886 	smb_scfhandle_t *handle = NULL;
887 	int dorefresh = 0;
888 
889 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
890 	if (handle == NULL) {
891 		syslog(LOG_ERR, "smbd: cannot save configuration");
892 		return (1);
893 	}
894 
895 	(void) smb_smf_create_service_pgroup(handle, pgname);
896 	if (smb_smf_start_transaction(handle) != SMBD_SMF_OK) {
897 		syslog(LOG_ERR, "smbd: cannot save configuration");
898 		return (1);
899 	}
900 
901 	for (id = 0; id < SMB_CI_MAX; id++) {
902 		cfg = &smb_cfg_table[id];
903 		if (strcmp(cfg->sc_pg, pgname))
904 			continue;
905 
906 		if (cfg->sc_flags & SMB_CF_MODIFIED) {
907 			if (cfg->sc_value) {
908 				if (strcmp(pgname, SMBD_PG_NAME) == 0)
909 					smb_config_setenv_trans(handle,
910 					    cfg->sc_type, cfg->sc_name,
911 					    cfg->sc_value);
912 				else
913 					smb_config_setenv_trans_protected(
914 					    handle, cfg->sc_name,
915 					    cfg->sc_value);
916 			} else {
917 				(void) smb_config_unsetenv_trans(handle,
918 				    cfg->sc_name);
919 			}
920 			cfg->sc_flags &= ~SMB_CF_MODIFIED;
921 			dorefresh = 1;
922 		}
923 	}
924 
925 	if (smb_config_saveenv(handle) != 0) {
926 		syslog(LOG_ERR, "smbd: cannot save configuration");
927 		return (1);
928 	}
929 	if (dorefresh)
930 		(void) smf_refresh_instance(SMBD_DEFAULT_INSTANCE_FMRI);
931 	return (0);
932 }
933 
934 /*
935  * smb_config_update
936  *
937  * Updates the specified config param with the given value.
938  * This function is called both on (re)load and set.
939  */
940 static int
941 smb_config_update(smb_cfg_param_t *cfg, char *value)
942 {
943 	char *curval;
944 	int rc = 0;
945 	int len;
946 
947 	if (value) {
948 		len = strlen(value);
949 		if (cfg->sc_value) {
950 			curval = (char *)realloc(cfg->sc_value,
951 			    (len + 1));
952 		} else {
953 			curval = (char *)malloc(len + 1);
954 		}
955 
956 		if (curval) {
957 			cfg->sc_value = curval;
958 			(void) strcpy(cfg->sc_value, value);
959 			cfg->sc_flags |= SMB_CF_DEFINED;
960 		} else {
961 			rc = 1;
962 		}
963 	} else if (cfg->sc_value) {
964 		free(cfg->sc_value);
965 		cfg->sc_value = NULL;
966 		cfg->sc_flags &= ~SMB_CF_DEFINED;
967 	}
968 
969 	return (rc);
970 }
971 
972 uint8_t
973 smb_config_get_fg_flag()
974 {
975 	uint8_t run_fg = 0; /* Default is to run in daemon mode */
976 	smb_scfhandle_t *handle = NULL;
977 
978 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
979 	if (handle == NULL) {
980 		return (run_fg);
981 	}
982 
983 	if (smb_smf_create_service_pgroup(handle,
984 	    SMBD_PG_NAME) != SMBD_SMF_OK) {
985 		smb_smf_scf_fini(handle);
986 		return (run_fg);
987 	}
988 
989 	if (smb_smf_get_boolean_property(handle, "run_fg", &run_fg) != 0) {
990 		smb_smf_scf_fini(handle);
991 		return (run_fg);
992 	}
993 
994 	smb_smf_scf_fini(handle);
995 
996 	return (run_fg);
997 }
998 
999 /*
1000  * smb_config_get_localsid
1001  *
1002  * Returns value of the "config/machine_sid" parameter
1003  * from the IDMAP SMF configuration repository.
1004  *
1005  */
1006 char *
1007 smb_config_get_localsid(void)
1008 {
1009 	return (smb_config_getenv_generic(MACHINE_SID, IDMAP_FMRI_PREFIX,
1010 	    IDMAP_PG_NAME));
1011 }
1012 
1013 /*
1014  * smb_config_set_idmap_domain
1015  *
1016  * Set the "config/domain_name" parameter from IDMAP SMF repository.
1017  */
1018 int
1019 smb_config_set_idmap_domain(char *value)
1020 {
1021 	return (smb_config_setenv_generic(IDMAP_FMRI_PREFIX, IDMAP_PG_NAME,
1022 	    IDMAP_DOMAIN, value));
1023 }
1024 
1025 /*
1026  * smb_config_refresh_idmap
1027  *
1028  * Refresh IDMAP SMF service after making changes to its configuration.
1029  */
1030 int
1031 smb_config_refresh_idmap(void)
1032 {
1033 	char instance[32];
1034 
1035 	(void) snprintf(instance, sizeof (instance), "%s:default",
1036 	    IDMAP_FMRI_PREFIX);
1037 	return (smf_refresh_instance(instance));
1038 }
1039 
1040 /*
1041  * smb_config_refresh
1042  *
1043  * Refresh SMB SMF service.
1044  */
1045 int
1046 smb_config_refresh(void)
1047 {
1048 	return (smf_refresh_instance(SMBD_DEFAULT_INSTANCE_FMRI));
1049 }
1050 
1051 int
1052 smb_config_secmode_fromstr(char *secmode)
1053 {
1054 	if (secmode == NULL)
1055 		return (SMB_SECMODE_WORKGRP);
1056 
1057 	if (strcasecmp(secmode, SMB_SECMODE_DOMAIN_STR) == 0)
1058 		return (SMB_SECMODE_DOMAIN);
1059 
1060 	return (SMB_SECMODE_WORKGRP);
1061 }
1062 
1063 char *
1064 smb_config_secmode_tostr(int secmode)
1065 {
1066 	if (secmode == SMB_SECMODE_DOMAIN)
1067 		return (SMB_SECMODE_DOMAIN_STR);
1068 
1069 	return (SMB_SECMODE_WORKGRP_STR);
1070 }
1071 
1072 int
1073 smb_config_get_secmode()
1074 {
1075 	char *p;
1076 
1077 	p = smb_config_getstr(SMB_CI_SECURITY);
1078 	return (smb_config_secmode_fromstr(p));
1079 }
1080 
1081 int
1082 smb_config_set_secmode(int secmode)
1083 {
1084 	char *p;
1085 
1086 	p = smb_config_secmode_tostr(secmode);
1087 	return (smb_config_set(SMB_CI_SECURITY, p));
1088 }
1089