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