1 /* 2 * Copyright (c) 2000, Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: nb_name.c,v 1.11 2004/12/11 05:23:59 lindak Exp $ 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 #include <sys/param.h> 38 #include <sys/socket.h> 39 #include <ctype.h> 40 #include <errno.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <strings.h> 45 #include <libintl.h> 46 #include <assert.h> 47 48 #include <netsmb/netbios.h> 49 #include <netsmb/smb_lib.h> 50 #include <netsmb/nb_lib.h> 51 #include <netsmb/mchain.h> 52 53 int 54 nb_snballoc(int namelen, struct sockaddr_nb **dst) 55 { 56 struct sockaddr_nb *snb; 57 int slen; 58 59 slen = sizeof (struct sockaddr_nb); 60 snb = malloc(slen); 61 if (snb == NULL) 62 return (ENOMEM); 63 bzero(snb, slen); 64 snb->snb_family = AF_NETBIOS; 65 *dst = snb; 66 return (0); 67 } 68 69 void 70 nb_snbfree(struct sockaddr *snb) 71 { 72 free(snb); 73 } 74 75 /* 76 * Create a full NETBIOS address 77 */ 78 int 79 nb_sockaddr(struct sockaddr *peer, struct nb_name *np, 80 struct sockaddr_nb **dst) 81 82 { 83 struct sockaddr_nb *snb; 84 struct sockaddr_in *sin; 85 struct hostent *hst; 86 int nmlen, error; 87 88 if (peer && (peer->sa_family != AF_INET)) 89 return (EPROTONOSUPPORT); 90 #if NOT_DEFINED /* moved encoding into kernel */ 91 nmlen = nb_name_len(np); 92 if (nmlen < NB_ENCNAMELEN) 93 return (EINVAL); 94 #else 95 nmlen = NB_NAMELEN; 96 #endif 97 error = nb_snballoc(nmlen, &snb); 98 if (error) 99 return (error); 100 101 /* 102 * Moved toupper() work to callers. 103 * 104 * Moved NetBIOS name encoding into the driver 105 * so we have readable names right up until the 106 * point where we marshall them in to a message. 107 * Just makes debugging easier. 108 */ 109 #if NOT_DEFINED 110 if (nmlen != nb_name_encode(np, snb->snb_name)) 111 printf(dgettext(TEXT_DOMAIN, 112 "a bug somewhere in the nb_name* code\n")); 113 /* XXX */ 114 #else 115 /* 116 * OK, nb_snballoc() did bzero, set snb_family. 117 * Hacks for "*" moved here from nb_name_encode(), 118 * but belongs where nn_name is filled in... 119 * XXX fix later 120 */ 121 if (strcmp(np->nn_name, "*") == 0) { 122 /* Star is special: No blanks, type, etc. */ 123 snb->snb_name[0] = '*'; 124 } else { 125 /* Normal name: pad with blanks, add type. */ 126 assert(NB_NAMELEN == 16); 127 snprintf(snb->snb_name, NB_NAMELEN, 128 "%-15.15s", np->nn_name); 129 snb->snb_name[15] = (char)np->nn_type; 130 } 131 #endif 132 133 if (peer) { 134 /*LINTED*/ 135 sin = (struct sockaddr_in *)peer; 136 snb->snb_ipaddr = sin->sin_addr.s_addr; 137 } 138 *dst = snb; 139 return (0); 140 } 141 142 int 143 nb_name_len(struct nb_name *np) 144 { 145 char *name; 146 int len, sclen; 147 148 len = 1 + NB_ENCNAMELEN; 149 if (np->nn_scope == NULL) 150 return (len + 1); 151 sclen = 0; 152 for (name = np->nn_scope; *name; name++) { 153 if (*name == '.') { 154 sclen = 0; 155 } else { 156 if (sclen < NB_MAXLABLEN) { 157 sclen++; 158 len++; 159 } 160 } 161 } 162 return (len + 1); 163 } 164 165 int 166 nb_encname_len(const uchar_t *str) 167 { 168 const uchar_t *cp = str; 169 int len, blen; 170 171 if ((cp[0] & 0xc0) == 0xc0) 172 return (-1); /* first two bytes are offset to name */ 173 174 len = 1; 175 for (;;) { 176 blen = *cp; 177 if (blen++ == 0) 178 break; 179 len += blen; 180 cp += blen; 181 } 182 return (len); 183 } 184 185 int 186 nb_name_encode(struct nb_name *np, uchar_t *dst) 187 { 188 char *name; 189 uchar_t *plen; 190 uchar_t ch, *cp = dst; 191 char *p, buf1[NB_NAMELEN+1]; 192 int i, lblen; 193 194 /* 195 * XXX: I'd rather see this part moved into 196 * callers of this function, leaving just 197 * the pure NB encoding here. -GWR 198 */ 199 name = np->nn_name; 200 if (name[0] == '*') { 201 /* Star is special: No blanks, type, etc. */ 202 bzero(buf1, NB_NAMELEN); 203 buf1[0] = '*'; 204 } else { 205 /* Normal name: pad with blanks, add type. */ 206 assert(NB_NAMELEN == 16); 207 snprintf(buf1, NB_NAMELEN, 208 "%-15.15s", name); 209 buf1[15] = (char)np->nn_type; 210 } 211 name = buf1; 212 213 /* 214 * Do the NetBIOS "first-level encoding" here. 215 * (RFC1002 explains this wierdness...) 216 * See similar code in kernel nsmb module: 217 * uts/common/fs/smbclnt/netsmb/smb_trantcp.c 218 * 219 * Here is what we marshall: 220 * uint8_t NAME_LENGTH (always 32) 221 * uint8_t ENCODED_NAME[32] 222 * uint8_t SCOPE_LENGTH 223 * Scope follows here, then another null. 224 */ 225 226 /* NAME_LENGTH */ 227 *cp++ = (2 * NB_NAMELEN); 228 229 /* ENCODED_NAME */ 230 for (i = 0; i < NB_NAMELEN; i++) { 231 ch = name[i]; 232 *cp++ = 'A' + ((ch >> 4) & 0xF); 233 *cp++ = 'A' + ((ch) & 0xF); 234 } 235 236 /* 237 * NetBIOS "scope" sting encoding, 238 * a.k.a second-level encoding. 239 * See RFC1002 for the details. 240 * 241 * Note: plen points to the length byte at the 242 * start of each string. This keeps a pointer 243 * to the location and fills it in after the 244 * length of the string is determined. 245 */ 246 #if NOT_DEFINED /* XXX: not yet */ 247 if (np->nn_scope) { 248 plen = cp++; 249 *plen = 0; /* fill in later */ 250 lblen = 0; 251 for (p = np->nn_scope; ; p++) { 252 if (*p == '.' || *p == 0) { 253 *plen = lblen; 254 if (*p == 0) 255 break; 256 plen = cp++; 257 *plen = 0; 258 lblen = 0; 259 } else { 260 if (lblen < NB_MAXLABLEN) { 261 *cp++ = *p; 262 lblen++; 263 } 264 } 265 } 266 } else 267 #endif /* XXX: not yet */ 268 { 269 *cp++ = 0; 270 } 271 272 return (cp - dst); 273 } 274