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