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