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 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * Functions to get list of addresses (TCP and/or NetBIOS)
  29  */
  30 
  31 #include <errno.h>
  32 #include <stdio.h>
  33 #include <stdlib.h>
  34 #include <string.h>
  35 #include <strings.h>
  36 #include <unistd.h>
  37 #include <netdb.h>
  38 #include <libintl.h>
  39 #include <xti.h>
  40 #include <assert.h>
  41 
  42 #include <sys/types.h>
  43 #include <sys/time.h>
  44 #include <sys/byteorder.h>
  45 #include <sys/socket.h>
  46 #include <sys/fcntl.h>
  47 
  48 #include <netinet/in.h>
  49 #include <netinet/tcp.h>
  50 #include <arpa/inet.h>
  51 
  52 #include <netsmb/smb.h>
  53 #include <netsmb/smb_lib.h>
  54 #include <netsmb/netbios.h>
  55 #include <netsmb/nb_lib.h>
  56 #include <netsmb/smb_dev.h>
  57 
  58 #include "charsets.h"
  59 #include "private.h"
  60 
  61 static char smb_port[16] = "445";
  62 
  63 void
  64 dump_addrinfo(struct addrinfo *ai)
  65 {
  66         int i;
  67 
  68         if (ai == NULL) {
  69                 printf("ai==NULL\n");
  70                 return;
  71         }
  72 
  73         for (i = 0; ai; i++, ai = ai->ai_next) {
  74                 printf("ai[%d]: af=%d, len=%d", i,
  75                     ai->ai_family, ai->ai_addrlen);
  76                 dump_sockaddr(ai->ai_addr);
  77                 if (ai->ai_canonname) {
  78                         printf("ai[%d]: cname=\"%s\"\n",
  79                             i, ai->ai_canonname);
  80                 }
  81         }
  82 }
  83 
  84 void
  85 dump_sockaddr(struct sockaddr *sa)
  86 {
  87         char paddrbuf[INET6_ADDRSTRLEN];
  88         struct sockaddr_in *sin;
  89         struct sockaddr_in6 *sin6;
  90         int af = sa->sa_family;
  91         const char *ip;
  92 
  93         printf(" saf=%d,", af);
  94         switch (af) {
  95         case AF_NETBIOS: /* see nbns_rq.c */
  96         case AF_INET:
  97                 sin = (void *)sa;
  98                 ip = inet_ntop(AF_INET, &sin->sin_addr,
  99                     paddrbuf, sizeof (paddrbuf));
 100                 break;
 101         case AF_INET6:
 102                 sin6 = (void *)sa;
 103                 ip = inet_ntop(AF_INET6, &sin6->sin6_addr,
 104                     paddrbuf, sizeof (paddrbuf));
 105                 break;
 106         default:
 107                 ip = "?";
 108                 break;
 109         }
 110         printf(" IP=%s\n", ip);
 111 }
 112 
 113 
 114 /*
 115  * SMB client name resolution - normal, and/or NetBIOS.
 116  * Returns an EAI_xxx error number like getaddrinfo(3)
 117  */
 118 int
 119 smb_ctx_getaddr(struct smb_ctx *ctx)
 120 {
 121         struct nb_ctx   *nbc = ctx->ct_nb;
 122         struct addrinfo hints, *res;
 123         char *srvaddr_str;
 124         int gaierr;
 125 
 126         if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == '\0')
 127                 return (EAI_NONAME);
 128 
 129         if (ctx->ct_addrinfo != NULL) {
 130                 freeaddrinfo(ctx->ct_addrinfo);
 131                 ctx->ct_addrinfo = NULL;
 132         }
 133 
 134         /*
 135          * If the user specified an address, use it,
 136          * and don't do NetBIOS lookup.
 137          */
 138         if (ctx->ct_srvaddr_s) {
 139                 srvaddr_str = ctx->ct_srvaddr_s;
 140                 nbc->nb_flags &= ~NBCF_NS_ENABLE;
 141         } else
 142                 srvaddr_str = ctx->ct_fullserver;
 143 
 144         /*
 145          * Default the server name we'll use in the
 146          * protocol (i.e. NTLM, tree connect).
 147          */
 148         strlcpy(ctx->ct_srvname, ctx->ct_fullserver,
 149             sizeof (ctx->ct_srvname));
 150 
 151         /*
 152          * Try to lookup the host address using the
 153          * normal name-to-IP address mechanisms.
 154          * If that fails, we MAY try NetBIOS.
 155          */
 156         memset(&hints, 0, sizeof (hints));
 157         hints.ai_flags = AI_CANONNAME;
 158         hints.ai_family = PF_UNSPEC;
 159         hints.ai_socktype = SOCK_STREAM;
 160         gaierr = getaddrinfo(srvaddr_str, smb_port, &hints, &res);
 161         if (gaierr == 0) {
 162                 ctx->ct_addrinfo = res;
 163                 return (0);
 164         }
 165 
 166         /*
 167          * If we really want to support NetBIOS, we should add
 168          * an AF_NETBIOS entry to the address list here.
 169          * For now, let's just skip NetBIOS.
 170          * (Can we just kill NetBIOS?  Please? :)
 171          */
 172 #if 0   /* XXX Just kill NetBIOS? */
 173         /*
 174          * If regular IP name lookup failed, try NetBIOS,
 175          * but only if given a valid NetBIOS name and if
 176          * NetBIOS name lookup is enabled.
 177          */
 178         if (nbc->nb_flags & NBCF_NS_ENABLE) {
 179                 int gaierr2 = nbns_getaddrinfo(ctx->ct_fullserver, nbc, &res);
 180                 if (gaierr2 == 0) {
 181                         if (res->ai_canonname)
 182                                 strlcpy(ctx->ct_srvname,
 183                                     res->ai_canonname,
 184                                     sizeof (ctx->ct_srvname));
 185                         ctx->ct_addrinfo = res;
 186                         return (0);
 187                 }
 188         }
 189 #endif
 190 
 191         /*
 192          * Return the original error from getaddrinfo
 193          */
 194         if (smb_verbose) {
 195                 smb_error(dgettext(TEXT_DOMAIN,
 196                     "getaddrinfo: %s: %s"), 0,
 197                     ctx->ct_fullserver,
 198                     gai_strerror(gaierr));
 199         }
 200         return (gaierr);
 201 }