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 #include <sys/param.h>
36 #include <sys/socket.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <strings.h>
43 #include <libintl.h>
44 #include <assert.h>
45
46 #include <netsmb/netbios.h>
47 #include <netsmb/smb_lib.h>
48 #include <netsmb/nb_lib.h>
49 #include <netsmb/mchain.h>
50 #include "private.h"
51
52 int
nb_snballoc(struct sockaddr_nb ** dst)53 nb_snballoc(struct sockaddr_nb **dst)
54 {
55 struct sockaddr_nb *snb;
56 int slen;
57
58 slen = sizeof (struct sockaddr_nb);
59 snb = malloc(slen);
60 if (snb == NULL)
61 return (ENOMEM);
62 bzero(snb, slen);
63 snb->snb_family = AF_NETBIOS;
64 *dst = snb;
65 return (0);
66 }
67
68 void
nb_snbfree(struct sockaddr * snb)69 nb_snbfree(struct sockaddr *snb)
70 {
71 free(snb);
72 }
73
74 /*
75 * Create a full NETBIOS address
76 * Passed names should already be upper case.
77 * Stores the names truncated or blank padded.
78 * NetBIOS name encoding happens later.
79 */
80 int
nb_sockaddr(struct sockaddr * peer,struct nb_name * np,struct sockaddr_nb ** dst)81 nb_sockaddr(struct sockaddr *peer, struct nb_name *np,
82 struct sockaddr_nb **dst)
83
84 {
85 struct sockaddr_nb *snb;
86 struct sockaddr_in *sin;
87 int error;
88
89 if (peer && (peer->sa_family != AF_INET))
90 return (EPROTONOSUPPORT);
91 error = nb_snballoc(&snb);
92 if (error)
93 return (error);
94
95 if (strcmp(np->nn_name, "*") == 0) {
96 /* Star is special: No blanks, type, etc. */
97 snb->snb_name[0] = '*';
98 } else {
99 /* Normal name: pad with blanks, add type. */
100 snprintf(snb->snb_name, NB_NAMELEN,
101 "%-15.15s", np->nn_name);
102 snb->snb_name[15] = (char)np->nn_type;
103 }
104
105 if (peer) {
106 /*LINTED*/
107 sin = (struct sockaddr_in *)peer;
108 snb->snb_ipaddr = sin->sin_addr.s_addr;
109 }
110 *dst = snb;
111 return (0);
112 }
113
114 int
nb_name_len(struct nb_name * np)115 nb_name_len(struct nb_name *np)
116 {
117 char *name;
118 int len, sclen;
119
120 len = 1 + NB_ENCNAMELEN;
121 if (np->nn_scope == NULL)
122 return (len + 1);
123 sclen = 0;
124 for (name = np->nn_scope; *name; name++) {
125 if (*name == '.') {
126 sclen = 0;
127 } else {
128 if (sclen < NB_MAXLABLEN) {
129 sclen++;
130 len++;
131 }
132 }
133 }
134 return (len + 1);
135 }
136
137 int
nb_encname_len(const uchar_t * str)138 nb_encname_len(const uchar_t *str)
139 {
140 const uchar_t *cp = str;
141 int len, blen;
142
143 if ((cp[0] & 0xc0) == 0xc0)
144 return (-1); /* first two bytes are offset to name */
145
146 len = 1;
147 for (;;) {
148 blen = *cp;
149 if (blen++ == 0)
150 break;
151 len += blen;
152 cp += blen;
153 }
154 return (len);
155 }
156
157 int
nb_name_encode(struct mbdata * mbp,struct nb_name * nn)158 nb_name_encode(struct mbdata *mbp, struct nb_name *nn)
159 {
160 char *plen;
161 uchar_t ch;
162 char *p, namebuf[NB_NAMELEN+1];
163 int i, lblen;
164
165 bcopy(nn->nn_name, namebuf, NB_NAMELEN);
166 namebuf[NB_NAMELEN-1] = (char)nn->nn_type;
167 namebuf[NB_NAMELEN] = '\0'; /* for debug */
168
169 /*
170 * Do the NetBIOS "first-level encoding" here.
171 * (RFC1002 explains this weirdness...)
172 *
173 * Here is what we marshall:
174 * uint8_t NAME_LENGTH (always 32)
175 * uint8_t ENCODED_NAME[32]
176 * uint8_t SCOPE_LENGTH
177 * Scope follows here, then another null.
178 */
179
180 /* NAME_LENGTH */
181 mb_put_uint8(mbp, (2 * NB_NAMELEN));
182
183 /* ENCODED_NAME */
184 for (i = 0; i < NB_NAMELEN; i++) {
185 ch = namebuf[i];
186 mb_put_uint8(mbp, 'A' + ((ch >> 4) & 0xF));
187 mb_put_uint8(mbp, 'A' + ((ch) & 0xF));
188 }
189
190 /*
191 * NetBIOS "scope" sting encoding,
192 * a.k.a second-level encoding.
193 * See RFC1002 for the details.
194 *
195 * Note: plen points to the length byte at the
196 * start of each string. This keeps a pointer
197 * to the location and fills it in after the
198 * length of the string is determined.
199 *
200 * One string of length zero terminates.
201 * With no scope string, the zero-length
202 * string is the only thing there.
203 */
204 if (nn->nn_scope == NULL) {
205 mb_put_uint8(mbp, 0);
206 return (0);
207 }
208
209 (void) mb_fit(mbp, 1, &plen);
210 *plen = 0; /* will update below */
211 lblen = 0;
212 for (p = nn->nn_scope; ; p++) {
213 if (*p == '\0') {
214 *plen = lblen;
215 if (lblen)
216 mb_put_uint8(mbp, 0);
217 break;
218 }
219 if (*p == '.') {
220 *plen = lblen;
221 (void) mb_fit(mbp, 1, &plen);
222 *plen = 0;
223 lblen = 0;
224 } else {
225 if (lblen < NB_MAXLABLEN) {
226 mb_put_uint8(mbp, *p);
227 lblen++;
228 }
229 }
230 }
231
232 return (0);
233 }
234