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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 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 void 62 dump_addrinfo(struct addrinfo *ai) 63 { 64 int i; 65 66 if (ai == NULL) { 67 printf("ai==NULL\n"); 68 return; 69 } 70 71 for (i = 0; ai; i++, ai = ai->ai_next) { 72 printf("ai[%d]: af=%d, len=%d", i, 73 ai->ai_family, ai->ai_addrlen); 74 dump_sockaddr(ai->ai_addr); 75 if (ai->ai_canonname) { 76 printf("ai[%d]: cname=\"%s\"\n", 77 i, ai->ai_canonname); 78 } 79 } 80 } 81 82 void 83 dump_sockaddr(struct sockaddr *sa) 84 { 85 char paddrbuf[INET6_ADDRSTRLEN]; 86 struct sockaddr_in *sin; 87 struct sockaddr_in6 *sin6; 88 int af = sa->sa_family; 89 const char *ip; 90 91 printf(" saf=%d,", af); 92 switch (af) { 93 case AF_NETBIOS: /* see nbns_rq.c */ 94 case AF_INET: 95 sin = (void *)sa; 96 ip = inet_ntop(AF_INET, &sin->sin_addr, 97 paddrbuf, sizeof (paddrbuf)); 98 break; 99 case AF_INET6: 100 sin6 = (void *)sa; 101 ip = inet_ntop(AF_INET6, &sin6->sin6_addr, 102 paddrbuf, sizeof (paddrbuf)); 103 break; 104 default: 105 ip = "?"; 106 break; 107 } 108 printf(" IP=%s\n", ip); 109 } 110 111 112 /* 113 * SMB client name resolution - normal, and/or NetBIOS. 114 * Returns an EAI_xxx error number like getaddrinfo(3) 115 */ 116 int 117 smb_ctx_getaddr(struct smb_ctx *ctx) 118 { 119 struct nb_ctx *nbc = ctx->ct_nb; 120 struct addrinfo hints, *res; 121 char *srvaddr_str; 122 int gaierr, gaierr2; 123 124 if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == '\0') 125 return (EAI_NONAME); 126 127 if (ctx->ct_addrinfo != NULL) { 128 freeaddrinfo(ctx->ct_addrinfo); 129 ctx->ct_addrinfo = NULL; 130 } 131 132 /* 133 * If the user specified an address, use it, 134 * and don't do NetBIOS lookup. 135 */ 136 if (ctx->ct_srvaddr_s) { 137 srvaddr_str = ctx->ct_srvaddr_s; 138 nbc->nb_flags &= ~NBCF_NS_ENABLE; 139 } else 140 srvaddr_str = ctx->ct_fullserver; 141 142 /* 143 * Default the server name we'll use in the 144 * protocol (i.e. NTLM, tree connect). 145 * If we get a canonical name, we'll 146 * overwrite this below. 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, NULL, &hints, &res); 161 if (gaierr == 0) { 162 #if 1 163 /* 164 * XXX Temporarily work-around CR 6831339: 165 * getaddrinfo() sets ai_canonname incorrectly 166 */ 167 char tmphost[256]; 168 gaierr2 = getnameinfo(res->ai_addr, res->ai_addrlen, 169 tmphost, sizeof (tmphost), 170 NULL, 0, NI_NAMEREQD); 171 if (gaierr2 == 0) { 172 DPRINT("cname: %s", tmphost); 173 strlcpy(ctx->ct_srvname, tmphost, 174 sizeof (ctx->ct_srvname)); 175 } 176 #else 177 if (res->ai_canonname) 178 strlcpy(ctx->ct_srvname, res->ai_canonname, 179 sizeof (ctx->ct_srvname)); 180 #endif 181 ctx->ct_addrinfo = res; 182 return (0); 183 } 184 185 /* 186 * If regular IP name lookup failed, try NetBIOS, 187 * but only if given a valid NetBIOS name and if 188 * NetBIOS name lookup is enabled. 189 * 190 * Note: we only have ssn_srvname if the full name 191 * was also a valid NetBIOS name. 192 */ 193 if (nbc->nb_flags & NBCF_NS_ENABLE) { 194 gaierr2 = nbns_getaddrinfo(ctx->ct_fullserver, nbc, &res); 195 if (gaierr2 == 0) { 196 if (res->ai_canonname) 197 strlcpy(ctx->ct_srvname, 198 res->ai_canonname, 199 sizeof (ctx->ct_srvname)); 200 ctx->ct_addrinfo = res; 201 return (0); 202 } 203 } 204 205 /* 206 * Return the original error from getaddrinfo 207 */ 208 if (smb_verbose) { 209 smb_error(dgettext(TEXT_DOMAIN, 210 "getaddrinfo: %s: %s"), 0, 211 ctx->ct_fullserver, 212 gai_strerror(gaierr)); 213 } 214 return (gaierr); 215 } 216