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