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 /* ARGSUSED */ 608 void 609 smb_trace(const char *s) 610 { 611 } 612 613 /* 614 * smb_tonetbiosname 615 * 616 * Creates a NetBIOS name based on the given name and suffix. 617 * NetBIOS name is 15 capital characters, padded with space if needed 618 * and the 16th byte is the suffix. 619 */ 620 void 621 smb_tonetbiosname(char *name, char *nb_name, char suffix) 622 { 623 char tmp_name[NETBIOS_NAME_SZ]; 624 smb_wchar_t wtmp_name[NETBIOS_NAME_SZ]; 625 int len; 626 size_t rc; 627 628 len = 0; 629 rc = smb_mbstowcs(wtmp_name, (const char *)name, NETBIOS_NAME_SZ); 630 631 if (rc != (size_t)-1) { 632 wtmp_name[NETBIOS_NAME_SZ - 1] = 0; 633 rc = ucstooem(tmp_name, wtmp_name, NETBIOS_NAME_SZ, 634 OEM_CPG_850); 635 if (rc > 0) 636 len = strlen(tmp_name); 637 } 638 639 (void) memset(nb_name, ' ', NETBIOS_NAME_SZ - 1); 640 if (len) { 641 (void) smb_strupr(tmp_name); 642 (void) memcpy(nb_name, tmp_name, len); 643 } 644 nb_name[NETBIOS_NAME_SZ - 1] = suffix; 645 } 646 647 int 648 smb_get_nameservers(smb_inaddr_t *ips, int sz) 649 { 650 union res_sockaddr_union set[MAXNS]; 651 int i, cnt; 652 struct __res_state res_state; 653 char ipstr[INET6_ADDRSTRLEN]; 654 655 if (ips == NULL) 656 return (0); 657 658 bzero(&res_state, sizeof (struct __res_state)); 659 if (res_ninit(&res_state) < 0) 660 return (0); 661 662 cnt = res_getservers(&res_state, set, MAXNS); 663 for (i = 0; i < cnt; i++) { 664 if (i >= sz) 665 break; 666 ips[i].a_family = AF_INET; 667 bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv4, NS_INADDRSZ); 668 if (inet_ntop(AF_INET, &ips[i].a_ipv4, ipstr, 669 INET_ADDRSTRLEN)) { 670 syslog(LOG_DEBUG, "Found %s name server\n", ipstr); 671 continue; 672 } 673 ips[i].a_family = AF_INET6; 674 bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv6, NS_IN6ADDRSZ); 675 if (inet_ntop(AF_INET6, &ips[i].a_ipv6, ipstr, 676 INET6_ADDRSTRLEN)) { 677 syslog(LOG_DEBUG, "Found %s name server\n", ipstr); 678 } 679 } 680 res_ndestroy(&res_state); 681 return (i); 682 } 683 684 /* 685 * smb_gethostbyname 686 * 687 * Looks up a host by the given name. The host entry can come 688 * from any of the sources for hosts specified in the 689 * /etc/nsswitch.conf and the NetBIOS cache. 690 * 691 * XXX Invokes nbt_name_resolve API once the NBTD is integrated 692 * to look in the NetBIOS cache if getipnodebyname fails. 693 * 694 * Caller should invoke freehostent to free the returned hostent. 695 */ 696 struct hostent * 697 smb_gethostbyname(const char *name, int *err_num) 698 { 699 struct hostent *h; 700 701 h = getipnodebyname(name, AF_INET, 0, err_num); 702 if ((h == NULL) || h->h_length != INADDRSZ) 703 h = getipnodebyname(name, AF_INET6, AI_DEFAULT, err_num); 704 return (h); 705 } 706 707 /* 708 * smb_gethostbyaddr 709 * 710 * Looks up a host by the given IP address. The host entry can come 711 * from any of the sources for hosts specified in the 712 * /etc/nsswitch.conf and the NetBIOS cache. 713 * 714 * XXX Invokes nbt API to resolve name by IP once the NBTD is integrated 715 * to look in the NetBIOS cache if getipnodebyaddr fails. 716 * 717 * Caller should invoke freehostent to free the returned hostent. 718 */ 719 struct hostent * 720 smb_gethostbyaddr(const char *addr, int len, int type, int *err_num) 721 { 722 struct hostent *h; 723 724 h = getipnodebyaddr(addr, len, type, err_num); 725 726 return (h); 727 } 728 729 uint32_t 730 smb_get_netlogon_flags(void) 731 { 732 int64_t val; 733 734 if (smb_config_getnum(SMB_CI_NETLOGON_FLAGS, &val) != SMBD_SMF_OK) 735 return (SMB_PI_NETLOGON_FLAGS_DEFAULT); 736 737 /* These are flags, and we only use the lowest 32 bits */ 738 return ((uint32_t)val); 739 } 740