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