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