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 2011 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 #include <assert.h> 27 #include <sys/types.h> 28 #include <stdarg.h> 29 #include <unistd.h> 30 #include <stdlib.h> 31 #include <time.h> 32 #include <synch.h> 33 #include <syslog.h> 34 #include <string.h> 35 #include <strings.h> 36 #include <errno.h> 37 #include <net/if.h> 38 #include <netdb.h> 39 #include <netinet/in.h> 40 #include <arpa/nameser.h> 41 #include <resolv.h> 42 #include <sys/sockio.h> 43 #include <sys/socket.h> 44 #include <smbsrv/smbinfo.h> 45 #include <smbsrv/netbios.h> 46 #include <smbsrv/libsmb.h> 47 48 static mutex_t seqnum_mtx; 49 50 /* 51 * IPC connection information that may be passed to the SMB Redirector. 52 */ 53 typedef struct { 54 char user[SMB_USERNAME_MAXLEN]; 55 uint8_t passwd[SMBAUTH_HASH_SZ]; 56 } smb_ipc_t; 57 58 static smb_ipc_t ipc_info; 59 static smb_ipc_t ipc_orig_info; 60 static rwlock_t smb_ipc_lock; 61 62 /* 63 * Some older clients (Windows 98) only handle the low byte 64 * of the max workers value. If the low byte is less than 65 * SMB_PI_MAX_WORKERS_MIN set it to SMB_PI_MAX_WORKERS_MIN. 66 */ 67 void 68 smb_load_kconfig(smb_kmod_cfg_t *kcfg) 69 { 70 int64_t citem; 71 72 bzero(kcfg, sizeof (smb_kmod_cfg_t)); 73 74 (void) smb_config_getnum(SMB_CI_MAX_WORKERS, &citem); 75 kcfg->skc_maxworkers = (uint32_t)citem; 76 if ((kcfg->skc_maxworkers & 0xFF) < SMB_PI_MAX_WORKERS_MIN) { 77 kcfg->skc_maxworkers &= ~0xFF; 78 kcfg->skc_maxworkers += SMB_PI_MAX_WORKERS_MIN; 79 } 80 81 (void) smb_config_getnum(SMB_CI_KEEPALIVE, &citem); 82 kcfg->skc_keepalive = (uint32_t)citem; 83 if ((kcfg->skc_keepalive != 0) && 84 (kcfg->skc_keepalive < SMB_PI_KEEP_ALIVE_MIN)) 85 kcfg->skc_keepalive = SMB_PI_KEEP_ALIVE_MIN; 86 87 (void) smb_config_getnum(SMB_CI_MAX_CONNECTIONS, &citem); 88 kcfg->skc_maxconnections = (uint32_t)citem; 89 kcfg->skc_restrict_anon = smb_config_getbool(SMB_CI_RESTRICT_ANON); 90 kcfg->skc_signing_enable = smb_config_getbool(SMB_CI_SIGNING_ENABLE); 91 kcfg->skc_signing_required = smb_config_getbool(SMB_CI_SIGNING_REQD); 92 kcfg->skc_ipv6_enable = smb_config_getbool(SMB_CI_IPV6_ENABLE); 93 kcfg->skc_print_enable = smb_config_getbool(SMB_CI_PRINT_ENABLE); 94 kcfg->skc_oplock_enable = smb_config_getbool(SMB_CI_OPLOCK_ENABLE); 95 kcfg->skc_sync_enable = smb_config_getbool(SMB_CI_SYNC_ENABLE); 96 kcfg->skc_traverse_mounts = smb_config_getbool(SMB_CI_TRAVERSE_MOUNTS); 97 kcfg->skc_secmode = smb_config_get_secmode(); 98 (void) smb_getdomainname(kcfg->skc_nbdomain, 99 sizeof (kcfg->skc_nbdomain)); 100 (void) smb_getfqdomainname(kcfg->skc_fqdn, 101 sizeof (kcfg->skc_fqdn)); 102 (void) smb_getnetbiosname(kcfg->skc_hostname, 103 sizeof (kcfg->skc_hostname)); 104 (void) smb_config_getstr(SMB_CI_SYS_CMNT, kcfg->skc_system_comment, 105 sizeof (kcfg->skc_system_comment)); 106 smb_config_get_version(&kcfg->skc_version); 107 kcfg->skc_execflags = smb_config_get_execinfo(NULL, NULL, 0); 108 } 109 110 /* 111 * Get the current system NetBIOS name. The hostname is truncated at 112 * the first `.` or 15 bytes, whichever occurs first, and converted 113 * to uppercase (by smb_gethostname). Text that appears after the 114 * first '.' is considered to be part of the NetBIOS scope. 115 * 116 * Returns 0 on success, otherwise -1 to indicate an error. 117 */ 118 int 119 smb_getnetbiosname(char *buf, size_t buflen) 120 { 121 if (smb_gethostname(buf, buflen, SMB_CASE_UPPER) != 0) 122 return (-1); 123 124 if (buflen >= NETBIOS_NAME_SZ) 125 buf[NETBIOS_NAME_SZ - 1] = '\0'; 126 127 return (0); 128 } 129 130 /* 131 * Get the SAM account of the current system. 132 * Returns 0 on success, otherwise, -1 to indicate an error. 133 */ 134 int 135 smb_getsamaccount(char *buf, size_t buflen) 136 { 137 if (smb_getnetbiosname(buf, buflen - 1) != 0) 138 return (-1); 139 140 (void) strlcat(buf, "$", buflen); 141 return (0); 142 } 143 144 /* 145 * Get the current system node name. The returned name is guaranteed 146 * to be null-terminated (gethostname may not null terminate the name). 147 * If the hostname has been fully-qualified for some reason, the domain 148 * part will be removed. The returned hostname is converted to the 149 * specified case (lower, upper, or preserved). 150 * 151 * If gethostname fails, the returned buffer will contain an empty 152 * string. 153 */ 154 int 155 smb_gethostname(char *buf, size_t buflen, smb_caseconv_t which) 156 { 157 char *p; 158 159 if (buf == NULL || buflen == 0) 160 return (-1); 161 162 if (gethostname(buf, buflen) != 0) { 163 *buf = '\0'; 164 return (-1); 165 } 166 167 buf[buflen - 1] = '\0'; 168 169 if ((p = strchr(buf, '.')) != NULL) 170 *p = '\0'; 171 172 switch (which) { 173 case SMB_CASE_LOWER: 174 (void) smb_strlwr(buf); 175 break; 176 177 case SMB_CASE_UPPER: 178 (void) smb_strupr(buf); 179 break; 180 181 case SMB_CASE_PRESERVE: 182 default: 183 break; 184 } 185 186 return (0); 187 } 188 189 /* 190 * Obtain the fully-qualified name for this machine in lower case. If 191 * the hostname is fully-qualified, accept it. Otherwise, try to find an 192 * appropriate domain name to append to the hostname. 193 */ 194 int 195 smb_getfqhostname(char *buf, size_t buflen) 196 { 197 char hostname[MAXHOSTNAMELEN]; 198 char domain[MAXHOSTNAMELEN]; 199 200 hostname[0] = '\0'; 201 domain[0] = '\0'; 202 203 if (smb_gethostname(hostname, MAXHOSTNAMELEN, 204 SMB_CASE_LOWER) != 0) 205 return (-1); 206 207 if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0) 208 return (-1); 209 210 if (hostname[0] == '\0') 211 return (-1); 212 213 if (domain[0] == '\0') { 214 (void) strlcpy(buf, hostname, buflen); 215 return (0); 216 } 217 218 (void) snprintf(buf, buflen, "%s.%s", hostname, domain); 219 return (0); 220 } 221 222 /* 223 * smb_getdomainname 224 * 225 * Returns NETBIOS name of the domain if the system is in domain 226 * mode. Or returns workgroup name if the system is in workgroup 227 * mode. 228 */ 229 int 230 smb_getdomainname(char *buf, size_t buflen) 231 { 232 int rc; 233 234 if (buf == NULL || buflen == 0) 235 return (-1); 236 237 *buf = '\0'; 238 rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, buf, buflen); 239 240 if ((rc != SMBD_SMF_OK) || (*buf == '\0')) 241 return (-1); 242 243 return (0); 244 } 245 246 /* 247 * smb_getfqdomainname 248 * 249 * In the system is in domain mode, the dns_domain property value 250 * is returned. Otherwise, it returns the local domain obtained via 251 * resolver. 252 * 253 * Returns 0 upon success. Otherwise, returns -1. 254 */ 255 int 256 smb_getfqdomainname(char *buf, size_t buflen) 257 { 258 struct __res_state res_state; 259 int rc; 260 261 if (buf == NULL || buflen == 0) 262 return (-1); 263 264 *buf = '\0'; 265 if (smb_config_get_secmode() == SMB_SECMODE_DOMAIN) { 266 rc = smb_config_getstr(SMB_CI_DOMAIN_FQDN, buf, buflen); 267 268 if ((rc != SMBD_SMF_OK) || (*buf == '\0')) 269 return (-1); 270 } else { 271 bzero(&res_state, sizeof (struct __res_state)); 272 if (res_ninit(&res_state)) 273 return (-1); 274 275 if (*res_state.defdname == '\0') { 276 res_ndestroy(&res_state); 277 return (-1); 278 } 279 280 (void) strlcpy(buf, res_state.defdname, buflen); 281 res_ndestroy(&res_state); 282 rc = 0; 283 } 284 285 return (rc); 286 } 287 288 289 /* 290 * smb_set_machine_passwd 291 * 292 * This function should be used when setting the machine password property. 293 * The associated sequence number is incremented. 294 */ 295 static int 296 smb_set_machine_passwd(char *passwd) 297 { 298 int64_t num; 299 int rc = -1; 300 301 if (smb_config_set(SMB_CI_MACHINE_PASSWD, passwd) != SMBD_SMF_OK) 302 return (-1); 303 304 (void) mutex_lock(&seqnum_mtx); 305 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num); 306 if (smb_config_setnum(SMB_CI_KPASSWD_SEQNUM, ++num) 307 == SMBD_SMF_OK) 308 rc = 0; 309 (void) mutex_unlock(&seqnum_mtx); 310 return (rc); 311 } 312 313 static int 314 smb_get_machine_passwd(uint8_t *buf, size_t buflen) 315 { 316 char pwd[SMB_PASSWD_MAXLEN + 1]; 317 int rc; 318 319 if (buflen < SMBAUTH_HASH_SZ) 320 return (-1); 321 322 rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD, pwd, sizeof (pwd)); 323 if ((rc != SMBD_SMF_OK) || *pwd == '\0') 324 return (-1); 325 326 if (smb_auth_ntlm_hash(pwd, buf) != 0) 327 return (-1); 328 329 return (rc); 330 } 331 332 /* 333 * Set up IPC connection credentials. 334 */ 335 void 336 smb_ipc_init(void) 337 { 338 int rc; 339 340 (void) rw_wrlock(&smb_ipc_lock); 341 bzero(&ipc_info, sizeof (smb_ipc_t)); 342 bzero(&ipc_orig_info, sizeof (smb_ipc_t)); 343 344 (void) smb_getsamaccount(ipc_info.user, SMB_USERNAME_MAXLEN); 345 rc = smb_get_machine_passwd(ipc_info.passwd, SMBAUTH_HASH_SZ); 346 if (rc != 0) 347 *ipc_info.passwd = 0; 348 (void) rw_unlock(&smb_ipc_lock); 349 350 } 351 352 /* 353 * Set the IPC username and password hash in memory. If the domain 354 * join succeeds, the credentials will be committed for use with 355 * authenticated IPC. Otherwise, they should be rolled back. 356 */ 357 void 358 smb_ipc_set(char *plain_user, uint8_t *passwd_hash) 359 { 360 (void) rw_wrlock(&smb_ipc_lock); 361 (void) strlcpy(ipc_info.user, plain_user, sizeof (ipc_info.user)); 362 (void) memcpy(ipc_info.passwd, passwd_hash, SMBAUTH_HASH_SZ); 363 (void) rw_unlock(&smb_ipc_lock); 364 365 } 366 367 /* 368 * Save the host credentials to be used for authenticated IPC. 369 * The credentials are also saved to the original IPC info as 370 * rollback data in case the join domain process fails later. 371 */ 372 void 373 smb_ipc_commit(void) 374 { 375 (void) rw_wrlock(&smb_ipc_lock); 376 (void) smb_getsamaccount(ipc_info.user, SMB_USERNAME_MAXLEN); 377 (void) smb_get_machine_passwd(ipc_info.passwd, SMBAUTH_HASH_SZ); 378 (void) memcpy(&ipc_orig_info, &ipc_info, sizeof (smb_ipc_t)); 379 (void) rw_unlock(&smb_ipc_lock); 380 } 381 382 /* 383 * Restore the original credentials 384 */ 385 void 386 smb_ipc_rollback(void) 387 { 388 (void) rw_wrlock(&smb_ipc_lock); 389 (void) strlcpy(ipc_info.user, ipc_orig_info.user, 390 sizeof (ipc_info.user)); 391 (void) memcpy(ipc_info.passwd, ipc_orig_info.passwd, 392 sizeof (ipc_info.passwd)); 393 (void) rw_unlock(&smb_ipc_lock); 394 } 395 396 void 397 smb_ipc_get_user(char *buf, size_t buflen) 398 { 399 (void) rw_rdlock(&smb_ipc_lock); 400 (void) strlcpy(buf, ipc_info.user, buflen); 401 (void) rw_unlock(&smb_ipc_lock); 402 } 403 404 void 405 smb_ipc_get_passwd(uint8_t *buf, size_t buflen) 406 { 407 if (buflen < SMBAUTH_HASH_SZ) 408 return; 409 410 (void) rw_rdlock(&smb_ipc_lock); 411 (void) memcpy(buf, ipc_info.passwd, SMBAUTH_HASH_SZ); 412 (void) rw_unlock(&smb_ipc_lock); 413 } 414 415 /* 416 * smb_match_netlogon_seqnum 417 * 418 * A sequence number is associated with each machine password property 419 * update and the netlogon credential chain setup. If the 420 * sequence numbers don't match, a NETLOGON credential chain 421 * establishment is required. 422 * 423 * Returns 0 if kpasswd_seqnum equals to netlogon_seqnum. Otherwise, 424 * returns -1. 425 */ 426 boolean_t 427 smb_match_netlogon_seqnum(void) 428 { 429 int64_t setpasswd_seqnum; 430 int64_t netlogon_seqnum; 431 432 (void) mutex_lock(&seqnum_mtx); 433 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &setpasswd_seqnum); 434 (void) smb_config_getnum(SMB_CI_NETLOGON_SEQNUM, &netlogon_seqnum); 435 (void) mutex_unlock(&seqnum_mtx); 436 return (setpasswd_seqnum == netlogon_seqnum); 437 } 438 439 /* 440 * smb_setdomainprops 441 * 442 * This function should be called after joining an AD to 443 * set all the domain related SMF properties. 444 * 445 * The kpasswd_domain property is the AD domain to which the system 446 * is joined via kclient. If this function is invoked by the SMB 447 * daemon, fqdn should be set to NULL. 448 */ 449 int 450 smb_setdomainprops(char *fqdn, char *server, char *passwd) 451 { 452 if (server == NULL || passwd == NULL) 453 return (-1); 454 455 if ((*server == '\0') || (*passwd == '\0')) 456 return (-1); 457 458 if (fqdn && (smb_config_set(SMB_CI_KPASSWD_DOMAIN, fqdn) != 0)) 459 return (-1); 460 461 if (smb_config_set(SMB_CI_KPASSWD_SRV, server) != 0) 462 return (-1); 463 464 if (smb_set_machine_passwd(passwd) != 0) { 465 syslog(LOG_ERR, "smb_setdomainprops: failed to set" 466 " machine account password"); 467 return (-1); 468 } 469 470 /* 471 * If we successfully create a trust account, we mark 472 * ourselves as a domain member in the environment so 473 * that we use the SAMLOGON version of the NETLOGON 474 * PDC location protocol. 475 */ 476 (void) smb_config_setbool(SMB_CI_DOMAIN_MEMB, B_TRUE); 477 478 return (0); 479 } 480 481 /* 482 * smb_update_netlogon_seqnum 483 * 484 * This function should only be called upon a successful netlogon 485 * credential chain establishment to set the sequence number of the 486 * netlogon to match with that of the kpasswd. 487 */ 488 void 489 smb_update_netlogon_seqnum(void) 490 { 491 int64_t num; 492 493 (void) mutex_lock(&seqnum_mtx); 494 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num); 495 (void) smb_config_setnum(SMB_CI_NETLOGON_SEQNUM, num); 496 (void) mutex_unlock(&seqnum_mtx); 497 } 498 499 500 /* 501 * Temporary fbt for dtrace until user space sdt enabled. 502 */ 503 void 504 smb_tracef(const char *fmt, ...) 505 { 506 va_list ap; 507 char buf[128]; 508 509 va_start(ap, fmt); 510 (void) vsnprintf(buf, 128, fmt, ap); 511 va_end(ap); 512 513 smb_trace(buf); 514 } 515 516 /* 517 * Temporary fbt for dtrace until user space sdt enabled. 518 */ 519 void 520 smb_trace(const char *s) 521 { 522 syslog(LOG_DEBUG, "%s", s); 523 } 524 525 /* 526 * smb_tonetbiosname 527 * 528 * Creates a NetBIOS name based on the given name and suffix. 529 * NetBIOS name is 15 capital characters, padded with space if needed 530 * and the 16th byte is the suffix. 531 */ 532 void 533 smb_tonetbiosname(char *name, char *nb_name, char suffix) 534 { 535 char tmp_name[NETBIOS_NAME_SZ]; 536 smb_wchar_t wtmp_name[NETBIOS_NAME_SZ]; 537 int len; 538 size_t rc; 539 540 len = 0; 541 rc = smb_mbstowcs(wtmp_name, (const char *)name, NETBIOS_NAME_SZ); 542 543 if (rc != (size_t)-1) { 544 wtmp_name[NETBIOS_NAME_SZ - 1] = 0; 545 rc = ucstooem(tmp_name, wtmp_name, NETBIOS_NAME_SZ, 546 OEM_CPG_850); 547 if (rc > 0) 548 len = strlen(tmp_name); 549 } 550 551 (void) memset(nb_name, ' ', NETBIOS_NAME_SZ - 1); 552 if (len) { 553 (void) smb_strupr(tmp_name); 554 (void) memcpy(nb_name, tmp_name, len); 555 } 556 nb_name[NETBIOS_NAME_SZ - 1] = suffix; 557 } 558 559 int 560 smb_get_nameservers(smb_inaddr_t *ips, int sz) 561 { 562 union res_sockaddr_union set[MAXNS]; 563 int i, cnt; 564 struct __res_state res_state; 565 char ipstr[INET6_ADDRSTRLEN]; 566 567 if (ips == NULL) 568 return (0); 569 570 bzero(&res_state, sizeof (struct __res_state)); 571 if (res_ninit(&res_state) < 0) 572 return (0); 573 574 cnt = res_getservers(&res_state, set, MAXNS); 575 for (i = 0; i < cnt; i++) { 576 if (i >= sz) 577 break; 578 ips[i].a_family = AF_INET; 579 bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv4, INADDRSZ); 580 if (inet_ntop(AF_INET, &ips[i].a_ipv4, ipstr, 581 INET_ADDRSTRLEN)) { 582 syslog(LOG_DEBUG, "Found %s name server\n", ipstr); 583 continue; 584 } 585 ips[i].a_family = AF_INET6; 586 bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv6, IPV6_ADDR_LEN); 587 if (inet_ntop(AF_INET6, &ips[i].a_ipv6, ipstr, 588 INET6_ADDRSTRLEN)) { 589 syslog(LOG_DEBUG, "Found %s name server\n", ipstr); 590 } 591 } 592 res_ndestroy(&res_state); 593 return (i); 594 } 595 596 /* 597 * smb_gethostbyname 598 * 599 * Looks up a host by the given name. The host entry can come 600 * from any of the sources for hosts specified in the 601 * /etc/nsswitch.conf and the NetBIOS cache. 602 * 603 * XXX Invokes nbt_name_resolve API once the NBTD is integrated 604 * to look in the NetBIOS cache if getipnodebyname fails. 605 * 606 * Caller should invoke freehostent to free the returned hostent. 607 */ 608 struct hostent * 609 smb_gethostbyname(const char *name, int *err_num) 610 { 611 struct hostent *h; 612 613 h = getipnodebyname(name, AF_INET, 0, err_num); 614 if ((h == NULL) || h->h_length != INADDRSZ) 615 h = getipnodebyname(name, AF_INET6, AI_DEFAULT, err_num); 616 return (h); 617 } 618 619 /* 620 * smb_gethostbyaddr 621 * 622 * Looks up a host by the given IP address. The host entry can come 623 * from any of the sources for hosts specified in the 624 * /etc/nsswitch.conf and the NetBIOS cache. 625 * 626 * XXX Invokes nbt API to resolve name by IP once the NBTD is integrated 627 * to look in the NetBIOS cache if getipnodebyaddr fails. 628 * 629 * Caller should invoke freehostent to free the returned hostent. 630 */ 631 struct hostent * 632 smb_gethostbyaddr(const char *addr, int len, int type, int *err_num) 633 { 634 struct hostent *h; 635 636 h = getipnodebyaddr(addr, len, type, err_num); 637 638 return (h); 639 } 640