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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <stdarg.h> 30 #include <unistd.h> 31 #include <stdlib.h> 32 #include <time.h> 33 #include <synch.h> 34 #include <syslog.h> 35 #include <string.h> 36 #include <strings.h> 37 #include <errno.h> 38 #include <net/if.h> 39 #include <netdb.h> 40 #include <netinet/in.h> 41 #include <arpa/nameser.h> 42 #include <resolv.h> 43 #include <sys/sockio.h> 44 #include <smbsrv/smbinfo.h> 45 #include <smbsrv/netbios.h> 46 #include <smbsrv/libsmb.h> 47 48 static smb_ntdomain_t smbpdc_cache; 49 static mutex_t smbpdc_mtx; 50 static cond_t smbpdc_cv; 51 static mutex_t seqnum_mtx; 52 53 extern int getdomainname(char *, int); 54 55 /* 56 * smb_getdomaininfo 57 * 58 * Returns a pointer to the cached domain data. The caller can specify 59 * whether or not he is prepared to wait if the cache is not yet valid 60 * and for how long. The specified timeout is in seconds. 61 */ 62 smb_ntdomain_t * 63 smb_getdomaininfo(uint32_t timeout) 64 { 65 timestruc_t to; 66 int err; 67 68 if (timeout != 0) { 69 (void) mutex_lock(&smbpdc_mtx); 70 while (smbpdc_cache.ipaddr == 0) { 71 to.tv_sec = timeout; 72 to.tv_nsec = 0; 73 err = cond_reltimedwait(&smbpdc_cv, &smbpdc_mtx, &to); 74 if (err == ETIME) 75 break; 76 } 77 (void) mutex_unlock(&smbpdc_mtx); 78 } 79 80 if (smbpdc_cache.ipaddr != 0) 81 return (&smbpdc_cache); 82 else 83 return (0); 84 } 85 86 void 87 smb_logdomaininfo(smb_ntdomain_t *di) 88 { 89 char ipstr[16]; 90 91 (void) inet_ntop(AF_INET, (const void *)&di->ipaddr, ipstr, 92 sizeof (ipstr)); 93 syslog(LOG_DEBUG, "smbd: %s (%s:%s)", di->domain, di->server, ipstr); 94 } 95 96 /* 97 * smb_setdomaininfo 98 * 99 * Set the information for the specified domain. If the information is 100 * non-null, the notification event is raised to wakeup any threads 101 * blocking on the cache. 102 */ 103 void 104 smb_setdomaininfo(char *domain, char *server, uint32_t ipaddr) 105 { 106 char *p; 107 108 bzero(&smbpdc_cache, sizeof (smb_ntdomain_t)); 109 110 if (domain && server && ipaddr) { 111 (void) strlcpy(smbpdc_cache.domain, domain, SMB_PI_MAX_DOMAIN); 112 (void) strlcpy(smbpdc_cache.server, server, SMB_PI_MAX_DOMAIN); 113 114 /* 115 * Remove DNS domain name extension 116 * to avoid confusing NetBIOS. 117 */ 118 if ((p = strchr(smbpdc_cache.domain, '.')) != 0) 119 *p = '\0'; 120 121 if ((p = strchr(smbpdc_cache.server, '.')) != 0) 122 *p = '\0'; 123 124 (void) mutex_lock(&smbpdc_mtx); 125 smbpdc_cache.ipaddr = ipaddr; 126 (void) cond_broadcast(&smbpdc_cv); 127 (void) mutex_unlock(&smbpdc_mtx); 128 } 129 } 130 131 void 132 smb_load_kconfig(smb_kmod_cfg_t *kcfg) 133 { 134 int64_t citem; 135 136 bzero(kcfg, sizeof (smb_kmod_cfg_t)); 137 138 (void) smb_config_getnum(SMB_CI_MAX_WORKERS, &citem); 139 kcfg->skc_maxworkers = (uint32_t)citem; 140 (void) smb_config_getnum(SMB_CI_KEEPALIVE, &citem); 141 kcfg->skc_keepalive = (uint32_t)citem; 142 if ((kcfg->skc_keepalive != 0) && 143 (kcfg->skc_keepalive < SMB_PI_KEEP_ALIVE_MIN)) 144 kcfg->skc_keepalive = SMB_PI_KEEP_ALIVE_MIN; 145 146 (void) smb_config_getnum(SMB_CI_MAX_CONNECTIONS, &citem); 147 kcfg->skc_maxconnections = (uint32_t)citem; 148 kcfg->skc_restrict_anon = smb_config_getbool(SMB_CI_RESTRICT_ANON); 149 kcfg->skc_signing_enable = smb_config_getbool(SMB_CI_SIGNING_ENABLE); 150 kcfg->skc_signing_required = smb_config_getbool(SMB_CI_SIGNING_REQD); 151 kcfg->skc_signing_check = smb_config_getbool(SMB_CI_SIGNING_CHECK); 152 kcfg->skc_oplock_enable = smb_config_getbool(SMB_CI_OPLOCK_ENABLE); 153 kcfg->skc_sync_enable = smb_config_getbool(SMB_CI_SYNC_ENABLE); 154 kcfg->skc_secmode = smb_config_get_secmode(); 155 (void) smb_getdomainname(kcfg->skc_resource_domain, 156 sizeof (kcfg->skc_resource_domain)); 157 (void) smb_gethostname(kcfg->skc_hostname, sizeof (kcfg->skc_hostname), 158 1); 159 (void) smb_config_getstr(SMB_CI_SYS_CMNT, kcfg->skc_system_comment, 160 sizeof (kcfg->skc_system_comment)); 161 } 162 163 /* 164 * Get the current system NetBIOS name. The hostname is truncated at 165 * the first `.` or 15 bytes, whichever occurs first, and converted 166 * to uppercase (by smb_gethostname). Text that appears after the 167 * first '.' is considered to be part of the NetBIOS scope. 168 * 169 * Returns 0 on success, otherwise -1 to indicate an error. 170 */ 171 int 172 smb_getnetbiosname(char *buf, size_t buflen) 173 { 174 if (smb_gethostname(buf, buflen, 1) != 0) 175 return (-1); 176 177 if (buflen >= NETBIOS_NAME_SZ) 178 buf[NETBIOS_NAME_SZ - 1] = '\0'; 179 180 return (0); 181 } 182 183 /* 184 * Get the current system node name. The returned name is guaranteed 185 * to be null-terminated (gethostname may not null terminate the name). 186 * If the hostname has been fully-qualified for some reason, the domain 187 * part will be removed. If the caller would like the name in upper 188 * case, it is folded to uppercase. 189 * 190 * If gethostname fails, the returned buffer will contain an empty 191 * string. 192 */ 193 int 194 smb_gethostname(char *buf, size_t buflen, int upcase) 195 { 196 char *p; 197 198 if (buf == NULL || buflen == 0) 199 return (-1); 200 201 if (gethostname(buf, buflen) != 0) { 202 *buf = '\0'; 203 return (-1); 204 } 205 206 buf[buflen - 1] = '\0'; 207 208 if ((p = strchr(buf, '.')) != NULL) 209 *p = '\0'; 210 211 if (upcase) 212 (void) utf8_strupr(buf); 213 214 return (0); 215 } 216 217 /* 218 * Obtain the fully-qualified name for this machine. If the 219 * hostname is fully-qualified, accept it. Otherwise, try to 220 * find an appropriate domain name to append to the hostname. 221 */ 222 int 223 smb_getfqhostname(char *buf, size_t buflen) 224 { 225 char hostname[MAXHOSTNAMELEN]; 226 char domain[MAXHOSTNAMELEN]; 227 228 hostname[0] = '\0'; 229 domain[0] = '\0'; 230 231 if (smb_gethostname(hostname, MAXHOSTNAMELEN, 0) != 0) 232 return (-1); 233 234 if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0) 235 return (-1); 236 237 if (hostname[0] == '\0') 238 return (-1); 239 240 if (domain[0] == '\0') { 241 (void) strlcpy(buf, hostname, buflen); 242 return (0); 243 } 244 245 (void) snprintf(buf, buflen, "%s.%s", hostname, domain); 246 return (0); 247 } 248 249 /* 250 * smb_resolve_netbiosname 251 * 252 * Convert the fully-qualified domain name (i.e. fqdn) to a NETBIOS name. 253 * Upon success, the NETBIOS name will be returned via buf parameter. 254 * Returns 0 upon success. Otherwise, returns -1. 255 */ 256 int 257 smb_resolve_netbiosname(char *fqdn, char *buf, size_t buflen) 258 { 259 char *p; 260 261 if (!buf) 262 return (-1); 263 264 *buf = '\0'; 265 if (!fqdn) 266 return (-1); 267 268 (void) strlcpy(buf, fqdn, buflen); 269 if ((p = strchr(buf, '.')) != NULL) 270 *p = 0; 271 272 if (strlen(buf) >= NETBIOS_NAME_SZ) 273 buf[NETBIOS_NAME_SZ - 1] = '\0'; 274 275 return (0); 276 } 277 278 /* 279 * smb_getdomainname 280 * 281 * Returns NETBIOS name of the domain if the system is in domain 282 * mode. Or returns workgroup name if the system is in workgroup 283 * mode. 284 */ 285 int 286 smb_getdomainname(char *buf, size_t buflen) 287 { 288 char domain[MAXHOSTNAMELEN]; 289 int rc; 290 291 if (buf == NULL || buflen == 0) 292 return (-1); 293 294 *buf = '\0'; 295 rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, domain, 296 sizeof (domain)); 297 298 if ((rc != SMBD_SMF_OK) || (*domain == '\0')) 299 return (-1); 300 301 (void) smb_resolve_netbiosname(domain, buf, buflen); 302 return (0); 303 } 304 305 /* 306 * smb_getdomainsid 307 * 308 * Returns the domain SID if the system is in domain mode. 309 * Otherwise returns NULL. 310 * 311 * Note: Callers are responsible for freeing a returned SID. 312 */ 313 nt_sid_t * 314 smb_getdomainsid(void) 315 { 316 char buf[MAXHOSTNAMELEN]; 317 nt_sid_t *sid; 318 int security_mode; 319 int rc; 320 321 security_mode = smb_config_get_secmode(); 322 if (security_mode != SMB_SECMODE_DOMAIN) 323 return (NULL); 324 325 *buf = '\0'; 326 rc = smb_config_getstr(SMB_CI_DOMAIN_SID, buf, MAXHOSTNAMELEN); 327 if ((rc != SMBD_SMF_OK) || (*buf == '\0')) 328 return (NULL); 329 330 if ((sid = nt_sid_strtosid(buf)) == NULL) 331 return (NULL); 332 333 return (sid); 334 } 335 336 /* 337 * smb_resolve_fqdn 338 * 339 * Converts the NETBIOS name of the domain (i.e. nbt_domain) to a fully 340 * qualified domain name. The domain from either the domain field or 341 * search list field of the /etc/resolv.conf will be returned via the 342 * buf parameter if the first label of the domain matches the given 343 * NETBIOS name. 344 * 345 * Returns -1 upon error. If a match is found, returns 1. Otherwise, 346 * returns 0. 347 */ 348 int 349 smb_resolve_fqdn(char *nbt_domain, char *buf, size_t buflen) 350 { 351 struct __res_state res_state; 352 int i, found = 0; 353 char *p; 354 int dlen; 355 356 if (!buf) 357 return (-1); 358 359 *buf = '\0'; 360 if (!nbt_domain) 361 return (-1); 362 363 bzero(&res_state, sizeof (struct __res_state)); 364 if (res_ninit(&res_state)) 365 return (-1); 366 367 if (*nbt_domain == '\0') { 368 if (*res_state.defdname == '\0') { 369 res_ndestroy(&res_state); 370 return (0); 371 } 372 373 (void) strlcpy(buf, res_state.defdname, buflen); 374 res_ndestroy(&res_state); 375 return (1); 376 } 377 378 dlen = strlen(nbt_domain); 379 if (!strncasecmp(nbt_domain, res_state.defdname, dlen)) { 380 (void) strlcpy(buf, res_state.defdname, buflen); 381 res_ndestroy(&res_state); 382 return (1); 383 } 384 385 for (i = 0; (p = res_state.dnsrch[i]) != NULL; i++) { 386 if (!strncasecmp(nbt_domain, p, dlen)) { 387 (void) strlcpy(buf, p, buflen); 388 found = 1; 389 break; 390 } 391 392 } 393 394 res_ndestroy(&res_state); 395 return (found); 396 } 397 398 /* 399 * smb_getfqdomainname 400 * 401 * If the domain_name property value is FQDN, it will be returned. 402 * In domain mode, the domain from either the domain field or 403 * search list field of the /etc/resolv.conf will be returned via the 404 * buf parameter if the first label of the domain matches the 405 * domain_name property. In workgroup mode, it returns the local 406 * domain. 407 * 408 * Returns 0 upon success. Otherwise, returns -1. 409 */ 410 int 411 smb_getfqdomainname(char *buf, size_t buflen) 412 { 413 char domain[MAXHOSTNAMELEN]; 414 int rc = 0; 415 416 if (buf == NULL || buflen == 0) 417 return (-1); 418 419 *buf = '\0'; 420 if (smb_config_get_secmode() == SMB_SECMODE_DOMAIN) { 421 rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, domain, 422 sizeof (domain)); 423 424 if ((rc != SMBD_SMF_OK) || (*domain == '\0')) 425 return (-1); 426 427 if (strchr(domain, '.') == NULL) { 428 if (smb_resolve_fqdn(domain, buf, buflen) != 1) 429 rc = -1; 430 } else { 431 (void) strlcpy(buf, domain, buflen); 432 } 433 } else { 434 if (smb_resolve_fqdn("", buf, buflen) != 1) 435 rc = -1; 436 } 437 438 return (rc); 439 } 440 441 442 /* 443 * smb_set_machine_passwd 444 * 445 * This function should be used when setting the machine password property. 446 * The associated sequence number is incremented. 447 */ 448 static int 449 smb_set_machine_passwd(char *passwd) 450 { 451 int64_t num; 452 int rc = -1; 453 454 if (smb_config_set(SMB_CI_MACHINE_PASSWD, passwd) != SMBD_SMF_OK) 455 return (-1); 456 457 (void) mutex_lock(&seqnum_mtx); 458 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num); 459 if (smb_config_setnum(SMB_CI_KPASSWD_SEQNUM, ++num) 460 == SMBD_SMF_OK) 461 rc = 0; 462 (void) mutex_unlock(&seqnum_mtx); 463 return (rc); 464 } 465 466 /* 467 * smb_match_netlogon_seqnum 468 * 469 * A sequence number is associated with each machine password property 470 * update and the netlogon credential chain setup. If the 471 * sequence numbers don't match, a NETLOGON credential chain 472 * establishment is required. 473 * 474 * Returns 0 if kpasswd_seqnum equals to netlogon_seqnum. Otherwise, 475 * returns -1. 476 */ 477 boolean_t 478 smb_match_netlogon_seqnum(void) 479 { 480 int64_t setpasswd_seqnum; 481 int64_t netlogon_seqnum; 482 483 (void) mutex_lock(&seqnum_mtx); 484 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &setpasswd_seqnum); 485 (void) smb_config_getnum(SMB_CI_NETLOGON_SEQNUM, &netlogon_seqnum); 486 (void) mutex_unlock(&seqnum_mtx); 487 return (setpasswd_seqnum == netlogon_seqnum); 488 } 489 490 /* 491 * smb_getjoineddomain 492 * 493 * Returns the NETBIOS name of the domain to which the system is joined 494 * via smbadm CLI. If the system is in workgroup mode or any error has 495 * been encountered, an empty string will be returned via buf. 496 * 497 * Returns: 498 * -1 upon errors. 499 * 0 if in workgroup mode. 500 * 1 if in domain mode. 501 */ 502 int 503 smb_getjoineddomain(char *buf, size_t buflen) 504 { 505 if (buf == NULL || buflen == 0) 506 return (-1); 507 508 *buf = '\0'; 509 if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) 510 return (0); 511 512 return (smb_getdomainname(buf, buflen) ? -1 : 1); 513 } 514 515 /* 516 * smb_setdomainprops 517 * 518 * This function should be called after joining an AD to 519 * set all the domain related SMF properties. 520 * 521 * The kpasswd_domain property is the AD domain to which the system 522 * is joined via kclient. If this function is invoked by the SMB 523 * daemon, fqdn should be set to NULL. 524 */ 525 int 526 smb_setdomainprops(char *fqdn, char *server, char *passwd) 527 { 528 if (server == NULL || passwd == NULL) 529 return (-1); 530 531 if ((*server == '\0') || (*passwd == '\0')) 532 return (-1); 533 534 if (fqdn && (smb_config_set(SMB_CI_KPASSWD_DOMAIN, fqdn) != 0)) 535 return (-1); 536 537 if (smb_config_set(SMB_CI_KPASSWD_SRV, server) != 0) 538 return (-1); 539 540 if (smb_set_machine_passwd(passwd) != 0) { 541 syslog(LOG_ERR, "smb_setdomainprops: failed to set" 542 " machine account password"); 543 return (-1); 544 } 545 546 /* 547 * If we successfully create a trust account, we mark 548 * ourselves as a domain member in the environment so 549 * that we use the SAMLOGON version of the NETLOGON 550 * PDC location protocol. 551 */ 552 (void) smb_config_setbool(SMB_CI_DOMAIN_MEMB, B_TRUE); 553 554 return (0); 555 } 556 557 /* 558 * smb_update_netlogon_seqnum 559 * 560 * This function should only be called upon a successful netlogon 561 * credential chain establishment to set the sequence number of the 562 * netlogon to match with that of the kpasswd. 563 */ 564 void 565 smb_update_netlogon_seqnum(void) 566 { 567 int64_t num; 568 569 (void) mutex_lock(&seqnum_mtx); 570 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num); 571 (void) smb_config_setnum(SMB_CI_NETLOGON_SEQNUM, num); 572 (void) mutex_unlock(&seqnum_mtx); 573 } 574 575 576 /* 577 * Temporary fbt for dtrace until user space sdt enabled. 578 */ 579 void 580 smb_tracef(const char *fmt, ...) 581 { 582 va_list ap; 583 char buf[128]; 584 585 va_start(ap, fmt); 586 (void) vsnprintf(buf, 128, fmt, ap); 587 va_end(ap); 588 589 smb_trace(buf); 590 } 591 592 /* 593 * Temporary fbt for dtrace until user space sdt enabled. 594 */ 595 void 596 smb_trace(const char *s) 597 { 598 syslog(LOG_DEBUG, "%s", s); 599 } 600 601 /* 602 * smb_tonetbiosname 603 * 604 * Creates a NetBIOS name based on the given name and suffix. 605 * NetBIOS name is 15 capital characters, padded with space if needed 606 * and the 16th byte is the suffix. 607 */ 608 void 609 smb_tonetbiosname(char *name, char *nb_name, char suffix) 610 { 611 char tmp_name[NETBIOS_NAME_SZ]; 612 mts_wchar_t wtmp_name[NETBIOS_NAME_SZ]; 613 unsigned int cpid; 614 int len; 615 size_t rc; 616 617 len = 0; 618 rc = mts_mbstowcs(wtmp_name, (const char *)name, NETBIOS_NAME_SZ); 619 620 if (rc != (size_t)-1) { 621 wtmp_name[NETBIOS_NAME_SZ - 1] = 0; 622 cpid = oem_get_smb_cpid(); 623 rc = unicodestooems(tmp_name, wtmp_name, NETBIOS_NAME_SZ, cpid); 624 if (rc > 0) 625 len = strlen(tmp_name); 626 } 627 628 (void) memset(nb_name, ' ', NETBIOS_NAME_SZ - 1); 629 if (len) { 630 (void) utf8_strupr(tmp_name); 631 (void) memcpy(nb_name, tmp_name, len); 632 } 633 nb_name[NETBIOS_NAME_SZ - 1] = suffix; 634 } 635 636 int 637 smb_get_nameservers(struct in_addr *ips, int sz) 638 { 639 union res_sockaddr_union set[MAXNS]; 640 int i, cnt; 641 struct __res_state res_state; 642 643 if (ips == NULL) 644 return (0); 645 646 bzero(&res_state, sizeof (struct __res_state)); 647 if (res_ninit(&res_state) < 0) 648 return (0); 649 650 cnt = res_getservers(&res_state, set, MAXNS); 651 for (i = 0; i < cnt; i++) { 652 if (i >= sz) 653 break; 654 ips[i] = set[i].sin.sin_addr; 655 syslog(LOG_DEBUG, "NS Found %s name server\n", 656 inet_ntoa(ips[i])); 657 } 658 syslog(LOG_DEBUG, "NS Found %d name servers\n", i); 659 res_ndestroy(&res_state); 660 return (i); 661 } 662