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