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