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