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