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