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 2020 Tintri by DDN, Inc. All rights reserved. 24 * Copyright 2022 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_short_names = smb_config_getbool(SMB_CI_SHORT_NAMES); 161 162 kcfg->skc_max_protocol = smb_config_get_max_protocol(); 163 kcfg->skc_min_protocol = smb_config_get_min_protocol(); 164 kcfg->skc_secmode = smb_config_get_secmode(); 165 kcfg->skc_encrypt = smb_config_get_require(SMB_CI_ENCRYPT); 166 kcfg->skc_encrypt_cipher = smb31_config_get_encrypt_cipher(); 167 168 (void) smb_getdomainname(kcfg->skc_nbdomain, 169 sizeof (kcfg->skc_nbdomain)); 170 (void) smb_getfqdomainname(kcfg->skc_fqdn, 171 sizeof (kcfg->skc_fqdn)); 172 (void) smb_getnetbiosname(kcfg->skc_hostname, 173 sizeof (kcfg->skc_hostname)); 174 (void) smb_config_getstr(SMB_CI_SYS_CMNT, kcfg->skc_system_comment, 175 sizeof (kcfg->skc_system_comment)); 176 smb_config_get_version(&kcfg->skc_version); 177 kcfg->skc_execflags = smb_config_get_execinfo(NULL, NULL, 0); 178 if (smb_config_get_localuuid(kcfg->skc_machine_uuid) < 0) { 179 syslog(LOG_ERR, "smb_load_kconfig: no machine_uuid"); 180 uuid_generate_time(kcfg->skc_machine_uuid); 181 } 182 /* skc_negtok, skc_negtok_len: see smbd_authsvc.c */ 183 184 (void) uname(&uts); 185 (void) snprintf(kcfg->skc_native_os, sizeof (kcfg->skc_native_os), 186 "%s %s %s", uts.sysname, uts.release, uts.version); 187 188 (void) strlcpy(kcfg->skc_native_lm, "Native SMB service", 189 sizeof (kcfg->skc_native_lm)); 190 } 191 192 /* 193 * Get the current system NetBIOS name. The hostname is truncated at 194 * the first `.` or 15 bytes, whichever occurs first, and converted 195 * to uppercase (by smb_gethostname). Text that appears after the 196 * first '.' is considered to be part of the NetBIOS scope. 197 * 198 * Returns 0 on success, otherwise -1 to indicate an error. 199 */ 200 int 201 smb_getnetbiosname(char *buf, size_t buflen) 202 { 203 if (smb_gethostname(buf, buflen, SMB_CASE_UPPER) != 0) 204 return (-1); 205 206 if (buflen >= NETBIOS_NAME_SZ) 207 buf[NETBIOS_NAME_SZ - 1] = '\0'; 208 209 return (0); 210 } 211 212 /* 213 * Get the SAM account of the current system. 214 * Returns 0 on success, otherwise, -1 to indicate an error. 215 */ 216 int 217 smb_getsamaccount(char *buf, size_t buflen) 218 { 219 if (smb_getnetbiosname(buf, buflen - 1) != 0) 220 return (-1); 221 222 (void) strlcat(buf, "$", buflen); 223 return (0); 224 } 225 226 /* 227 * Get the current system node name. The returned name is guaranteed 228 * to be null-terminated (gethostname may not null terminate the name). 229 * If the hostname has been fully-qualified for some reason, the domain 230 * part will be removed. The returned hostname is converted to the 231 * specified case (lower, upper, or preserved). 232 * 233 * If gethostname fails, the returned buffer will contain an empty 234 * string. 235 */ 236 int 237 smb_gethostname(char *buf, size_t buflen, smb_caseconv_t which) 238 { 239 char *p; 240 241 if (buf == NULL || buflen == 0) 242 return (-1); 243 244 if (gethostname(buf, buflen) != 0) { 245 *buf = '\0'; 246 return (-1); 247 } 248 249 buf[buflen - 1] = '\0'; 250 251 if ((p = strchr(buf, '.')) != NULL) 252 *p = '\0'; 253 254 switch (which) { 255 case SMB_CASE_LOWER: 256 (void) smb_strlwr(buf); 257 break; 258 259 case SMB_CASE_UPPER: 260 (void) smb_strupr(buf); 261 break; 262 263 case SMB_CASE_PRESERVE: 264 default: 265 break; 266 } 267 268 return (0); 269 } 270 271 /* 272 * Obtain the fully-qualified name for this machine in lower case. If 273 * the hostname is fully-qualified, accept it. Otherwise, try to find an 274 * appropriate domain name to append to the hostname. 275 */ 276 int 277 smb_getfqhostname(char *buf, size_t buflen) 278 { 279 char hostname[MAXHOSTNAMELEN]; 280 char domain[MAXHOSTNAMELEN]; 281 282 hostname[0] = '\0'; 283 domain[0] = '\0'; 284 285 if (smb_gethostname(hostname, MAXHOSTNAMELEN, 286 SMB_CASE_LOWER) != 0) 287 return (-1); 288 289 if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0) 290 return (-1); 291 292 if (hostname[0] == '\0') 293 return (-1); 294 295 if (domain[0] == '\0') { 296 (void) strlcpy(buf, hostname, buflen); 297 return (0); 298 } 299 300 (void) snprintf(buf, buflen, "%s.%s", hostname, domain); 301 return (0); 302 } 303 304 /* 305 * smb_getdomainname 306 * 307 * Returns NETBIOS name of the domain if the system is in domain 308 * mode. Or returns workgroup name if the system is in workgroup 309 * mode. 310 */ 311 int 312 smb_getdomainname(char *buf, size_t buflen) 313 { 314 int rc; 315 316 if (buf == NULL || buflen == 0) 317 return (-1); 318 319 *buf = '\0'; 320 rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, buf, buflen); 321 322 if ((rc != SMBD_SMF_OK) || (*buf == '\0')) 323 return (-1); 324 325 return (0); 326 } 327 328 /* 329 * smb_getfqdomainname 330 * 331 * In the system is in domain mode, the dns_domain property value 332 * is returned. Otherwise, it returns the local domain obtained via 333 * resolver. 334 * 335 * Returns 0 upon success. Otherwise, returns -1. 336 */ 337 int 338 smb_getfqdomainname(char *buf, size_t buflen) 339 { 340 struct __res_state res_state; 341 int rc; 342 343 if (buf == NULL || buflen == 0) 344 return (-1); 345 346 *buf = '\0'; 347 if (smb_config_get_secmode() == SMB_SECMODE_DOMAIN) { 348 rc = smb_config_getstr(SMB_CI_DOMAIN_FQDN, buf, buflen); 349 350 if ((rc != SMBD_SMF_OK) || (*buf == '\0')) 351 return (-1); 352 } else { 353 bzero(&res_state, sizeof (struct __res_state)); 354 if (res_ninit(&res_state)) 355 return (-1); 356 357 if (*res_state.defdname == '\0') { 358 res_ndestroy(&res_state); 359 return (-1); 360 } 361 362 (void) strlcpy(buf, res_state.defdname, buflen); 363 res_ndestroy(&res_state); 364 rc = 0; 365 } 366 367 return (rc); 368 } 369 370 371 /* 372 * smb_set_machine_passwd 373 * 374 * This function should be used when setting the machine password property. 375 * The associated sequence number is incremented. 376 */ 377 static int 378 smb_set_machine_passwd(char *passwd) 379 { 380 int64_t num; 381 int rc = -1; 382 383 if (smb_config_set(SMB_CI_MACHINE_PASSWD, passwd) != SMBD_SMF_OK) 384 return (-1); 385 386 (void) mutex_lock(&seqnum_mtx); 387 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num); 388 if (smb_config_setnum(SMB_CI_KPASSWD_SEQNUM, ++num) 389 == SMBD_SMF_OK) 390 rc = 0; 391 (void) mutex_unlock(&seqnum_mtx); 392 return (rc); 393 } 394 395 static int 396 smb_get_machine_passwd(uint8_t *buf, size_t buflen) 397 { 398 char pwd[SMB_PASSWD_MAXLEN + 1]; 399 int rc; 400 401 if (buflen < SMBAUTH_HASH_SZ) 402 return (-1); 403 404 rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD, pwd, sizeof (pwd)); 405 if ((rc != SMBD_SMF_OK) || *pwd == '\0') 406 return (-1); 407 408 if (smb_auth_ntlm_hash(pwd, buf) != 0) 409 return (-1); 410 411 return (rc); 412 } 413 414 /* 415 * Set up IPC connection credentials. 416 */ 417 void 418 smb_ipc_init(void) 419 { 420 int rc; 421 422 (void) rw_wrlock(&smb_ipc_lock); 423 bzero(&ipc_info, sizeof (smb_ipc_t)); 424 bzero(&ipc_orig_info, sizeof (smb_ipc_t)); 425 426 (void) smb_getsamaccount(ipc_info.user, SMB_USERNAME_MAXLEN); 427 rc = smb_get_machine_passwd(ipc_info.passwd, SMBAUTH_HASH_SZ); 428 if (rc != 0) 429 *ipc_info.passwd = 0; 430 (void) rw_unlock(&smb_ipc_lock); 431 432 } 433 434 /* 435 * Set the IPC username and password hash in memory. If the domain 436 * join succeeds, the credentials will be committed for use with 437 * authenticated IPC. Otherwise, they should be rolled back. 438 */ 439 void 440 smb_ipc_set(char *plain_user, uint8_t *passwd_hash) 441 { 442 (void) rw_wrlock(&smb_ipc_lock); 443 (void) strlcpy(ipc_info.user, plain_user, sizeof (ipc_info.user)); 444 (void) memcpy(ipc_info.passwd, passwd_hash, SMBAUTH_HASH_SZ); 445 (void) rw_unlock(&smb_ipc_lock); 446 447 } 448 449 /* 450 * Save the host credentials to be used for authenticated IPC. 451 * The credentials are also saved to the original IPC info as 452 * rollback data in case the join domain process fails later. 453 */ 454 void 455 smb_ipc_commit(void) 456 { 457 (void) rw_wrlock(&smb_ipc_lock); 458 (void) smb_getsamaccount(ipc_info.user, SMB_USERNAME_MAXLEN); 459 (void) smb_get_machine_passwd(ipc_info.passwd, SMBAUTH_HASH_SZ); 460 (void) memcpy(&ipc_orig_info, &ipc_info, sizeof (smb_ipc_t)); 461 (void) rw_unlock(&smb_ipc_lock); 462 } 463 464 /* 465 * Restore the original credentials 466 */ 467 void 468 smb_ipc_rollback(void) 469 { 470 (void) rw_wrlock(&smb_ipc_lock); 471 (void) strlcpy(ipc_info.user, ipc_orig_info.user, 472 sizeof (ipc_info.user)); 473 (void) memcpy(ipc_info.passwd, ipc_orig_info.passwd, 474 sizeof (ipc_info.passwd)); 475 (void) rw_unlock(&smb_ipc_lock); 476 } 477 478 void 479 smb_ipc_get_user(char *buf, size_t buflen) 480 { 481 (void) rw_rdlock(&smb_ipc_lock); 482 (void) strlcpy(buf, ipc_info.user, buflen); 483 (void) rw_unlock(&smb_ipc_lock); 484 } 485 486 void 487 smb_ipc_get_passwd(uint8_t *buf, size_t buflen) 488 { 489 if (buflen < SMBAUTH_HASH_SZ) 490 return; 491 492 (void) rw_rdlock(&smb_ipc_lock); 493 (void) memcpy(buf, ipc_info.passwd, SMBAUTH_HASH_SZ); 494 (void) rw_unlock(&smb_ipc_lock); 495 } 496 497 /* 498 * smb_match_netlogon_seqnum 499 * 500 * A sequence number is associated with each machine password property 501 * update and the netlogon credential chain setup. If the 502 * sequence numbers don't match, a NETLOGON credential chain 503 * establishment is required. 504 * 505 * Returns 0 if kpasswd_seqnum equals to netlogon_seqnum. Otherwise, 506 * returns -1. 507 */ 508 boolean_t 509 smb_match_netlogon_seqnum(void) 510 { 511 int64_t setpasswd_seqnum; 512 int64_t netlogon_seqnum; 513 514 (void) mutex_lock(&seqnum_mtx); 515 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &setpasswd_seqnum); 516 (void) smb_config_getnum(SMB_CI_NETLOGON_SEQNUM, &netlogon_seqnum); 517 (void) mutex_unlock(&seqnum_mtx); 518 return (setpasswd_seqnum == netlogon_seqnum); 519 } 520 521 /* 522 * smb_setdomainprops 523 * 524 * This function should be called after joining an AD to 525 * set all the domain related SMF properties. 526 * 527 * The kpasswd_domain property is the AD domain to which the system 528 * is joined via kclient. If this function is invoked by the SMB 529 * daemon, fqdn should be set to NULL. 530 */ 531 int 532 smb_setdomainprops(char *fqdn, char *server, char *passwd) 533 { 534 if (server == NULL || passwd == NULL) 535 return (-1); 536 537 if ((*server == '\0') || (*passwd == '\0')) 538 return (-1); 539 540 if (fqdn && (smb_config_set(SMB_CI_KPASSWD_DOMAIN, fqdn) != 0)) 541 return (-1); 542 543 if (smb_config_set(SMB_CI_KPASSWD_SRV, server) != 0) 544 return (-1); 545 546 if (smb_set_machine_passwd(passwd) != 0) { 547 syslog(LOG_ERR, "smb_setdomainprops: failed to set" 548 " machine account password"); 549 return (-1); 550 } 551 552 /* 553 * If we successfully create a trust account, we mark 554 * ourselves as a domain member in the environment so 555 * that we use the SAMLOGON version of the NETLOGON 556 * PDC location protocol. 557 */ 558 (void) smb_config_setbool(SMB_CI_DOMAIN_MEMB, B_TRUE); 559 560 return (0); 561 } 562 563 /* 564 * smb_update_netlogon_seqnum 565 * 566 * This function should only be called upon a successful netlogon 567 * credential chain establishment to set the sequence number of the 568 * netlogon to match with that of the kpasswd. 569 */ 570 void 571 smb_update_netlogon_seqnum(void) 572 { 573 int64_t num; 574 575 (void) mutex_lock(&seqnum_mtx); 576 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num); 577 (void) smb_config_setnum(SMB_CI_NETLOGON_SEQNUM, num); 578 (void) mutex_unlock(&seqnum_mtx); 579 } 580 581 582 /* 583 * Temporary fbt for dtrace until user space sdt enabled. 584 */ 585 void 586 smb_tracef(const char *fmt, ...) 587 { 588 va_list ap; 589 char buf[128]; 590 591 va_start(ap, fmt); 592 (void) vsnprintf(buf, 128, fmt, ap); 593 va_end(ap); 594 595 smb_trace(buf); 596 } 597 598 /* 599 * Temporary fbt for dtrace until user space sdt enabled. 600 * 601 * This function is designed to be used with dtrace, i.e. see: 602 * usr/src/cmd/smbsrv/dtrace/smbd-all.d 603 * 604 * Outside of dtrace, the messages passed to this function usually 605 * lack sufficient context to be useful, so we don't log them. 606 */ 607 void 608 smb_trace(const char *s __unused) 609 { 610 } 611 612 /* 613 * smb_tonetbiosname 614 * 615 * Creates a NetBIOS name based on the given name and suffix. 616 * NetBIOS name is 15 capital characters, padded with space if needed 617 * and the 16th byte is the suffix. 618 */ 619 void 620 smb_tonetbiosname(char *name, char *nb_name, char suffix) 621 { 622 char tmp_name[NETBIOS_NAME_SZ]; 623 smb_wchar_t wtmp_name[NETBIOS_NAME_SZ]; 624 int len; 625 size_t rc; 626 627 len = 0; 628 rc = smb_mbstowcs(wtmp_name, (const char *)name, NETBIOS_NAME_SZ); 629 630 if (rc != (size_t)-1) { 631 wtmp_name[NETBIOS_NAME_SZ - 1] = 0; 632 rc = ucstooem(tmp_name, wtmp_name, NETBIOS_NAME_SZ, 633 OEM_CPG_850); 634 if (rc > 0) 635 len = strlen(tmp_name); 636 } 637 638 (void) memset(nb_name, ' ', NETBIOS_NAME_SZ - 1); 639 if (len) { 640 (void) smb_strupr(tmp_name); 641 (void) memcpy(nb_name, tmp_name, len); 642 } 643 nb_name[NETBIOS_NAME_SZ - 1] = suffix; 644 } 645 646 int 647 smb_get_nameservers(smb_inaddr_t *ips, int sz) 648 { 649 union res_sockaddr_union set[MAXNS]; 650 int i, cnt; 651 struct __res_state res_state; 652 char ipstr[INET6_ADDRSTRLEN]; 653 654 if (ips == NULL) 655 return (0); 656 657 bzero(&res_state, sizeof (struct __res_state)); 658 if (res_ninit(&res_state) < 0) 659 return (0); 660 661 cnt = res_getservers(&res_state, set, MAXNS); 662 for (i = 0; i < cnt; i++) { 663 if (i >= sz) 664 break; 665 ips[i].a_family = AF_INET; 666 bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv4, NS_INADDRSZ); 667 if (inet_ntop(AF_INET, &ips[i].a_ipv4, ipstr, 668 INET_ADDRSTRLEN)) { 669 syslog(LOG_DEBUG, "Found %s name server\n", ipstr); 670 continue; 671 } 672 ips[i].a_family = AF_INET6; 673 bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv6, NS_IN6ADDRSZ); 674 if (inet_ntop(AF_INET6, &ips[i].a_ipv6, ipstr, 675 INET6_ADDRSTRLEN)) { 676 syslog(LOG_DEBUG, "Found %s name server\n", ipstr); 677 } 678 } 679 res_ndestroy(&res_state); 680 return (i); 681 } 682 683 /* 684 * smb_gethostbyname 685 * 686 * Looks up a host by the given name. The host entry can come 687 * from any of the sources for hosts specified in the 688 * /etc/nsswitch.conf and the NetBIOS cache. 689 * 690 * XXX Invokes nbt_name_resolve API once the NBTD is integrated 691 * to look in the NetBIOS cache if getipnodebyname fails. 692 * 693 * Caller should invoke freehostent to free the returned hostent. 694 */ 695 struct hostent * 696 smb_gethostbyname(const char *name, int *err_num) 697 { 698 struct hostent *h; 699 700 h = getipnodebyname(name, AF_INET, 0, err_num); 701 if ((h == NULL) || h->h_length != INADDRSZ) 702 h = getipnodebyname(name, AF_INET6, AI_DEFAULT, err_num); 703 return (h); 704 } 705 706 /* 707 * smb_gethostbyaddr 708 * 709 * Looks up a host by the given IP address. The host entry can come 710 * from any of the sources for hosts specified in the 711 * /etc/nsswitch.conf and the NetBIOS cache. 712 * 713 * XXX Invokes nbt API to resolve name by IP once the NBTD is integrated 714 * to look in the NetBIOS cache if getipnodebyaddr fails. 715 * 716 * Caller should invoke freehostent to free the returned hostent. 717 */ 718 struct hostent * 719 smb_gethostbyaddr(const char *addr, int len, int type, int *err_num) 720 { 721 struct hostent *h; 722 723 h = getipnodebyaddr(addr, len, type, err_num); 724 725 return (h); 726 } 727 728 uint32_t 729 smb_get_netlogon_flags(void) 730 { 731 int64_t val; 732 733 if (smb_config_getnum(SMB_CI_NETLOGON_FLAGS, &val) != SMBD_SMF_OK) 734 return (SMB_PI_NETLOGON_FLAGS_DEFAULT); 735 736 /* These are flags, and we only use the lowest 32 bits */ 737 return ((uint32_t)val); 738 } 739