xref: /illumos-gate/usr/src/common/smbsrv/smb_netbios_util.c (revision 8622ec4569457733001d4982ef7f5b44427069be)
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 2011 Nexenta Systems, Inc.  All rights reserved.
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #ifdef _KERNEL
28 #include <sys/types.h>
29 #include <sys/sunddi.h>
30 #else
31 #include <string.h>
32 #endif
33 #include <smbsrv/string.h>
34 #include <smbsrv/netbios.h>
35 
36 static int domainname_is_valid(char *domain_name);
37 
38 /*
39  * Routines than support name compression.
40  *
41  *   The NetBIOS name representation in all NetBIOS packets (for NAME,
42  *   SESSION, and DATAGRAM services) is defined in the Domain Name
43  *   Service RFC 883[3] as "compressed" name messages.  This format is
44  *   called "second-level encoding" in the section entitled
45  *   "Representation of NetBIOS Names" in the Concepts and Methods
46  *   document.
47  *
48  *   For ease of description, the first two paragraphs from page 31,
49  *   the section titled "Domain name representation and compression",
50  *   of RFC 883 are replicated here:
51  *
52  *        Domain names messages are expressed in terms of a sequence
53  *        of labels.  Each label is represented as a one octet length
54  *        field followed by that number of octets.  Since every domain
55  *        name ends with the null label of the root, a compressed
56  *        domain name is terminated by a length byte of zero.  The
57  *        high order two bits of the length field must be zero, and
58  *        the remaining six bits of the length field limit the label
59  *        to 63 octets or less.
60  *
61  *        To simplify implementations, the total length of label
62  *        octets and label length octets that make up a domain name is
63  *        restricted to 255 octets or less.
64  *
65  *   The following is the uncompressed representation of the NetBIOS name
66  *   "FRED ", which is the 4 ASCII characters, F, R, E, D, followed by 12
67  *   space characters (0x20).  This name has the SCOPE_ID: "NETBIOS.COM"
68  *
69  *           EGFCEFEECACACACACACACACACACACACA.NETBIOS.COM
70  *
71  *   This uncompressed representation of names is called "first-level
72  *   encoding" in the section entitled "Representation of NetBIOS Names"
73  *   in the Concepts and Methods document.
74  *
75  *   The following is a pictographic representation of the compressed
76  *   representation of the previous uncompressed Domain Name
77  *   representation.
78  *
79  *                        1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
80  *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
81  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
82  *   |      0x20     |    E (0x45)   |    G (0x47)   |    F (0x46)   |
83  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84  *   |    C (0x43)   |    E (0x45)   |    F (0x46)   |    E (0x45)   |
85  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
86  *   |    E (0x45)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
87  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
89  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
91  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
92  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
93  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
95  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
97  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
98  *   |    A (0X41)   |      0x07     |    N (0x4E)   |    E (0x45)   |
99  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
100  *   |    T (0x54)   |    B (0x42)   |    I (0x49)   |    O (0x4F)   |
101  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102  *   |    S (0x53)   |      0x03     |    C (0x43)   |    O (0x4F)   |
103  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104  *   |    M (0x4D)   |      0x00     |
105  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106  *
107  *   Each section of a domain name is called a label [7 (page 31)].  A
108  *   label can be a maximum of 63 bytes.  The first byte of a label in
109  *   compressed representation is the number of bytes in the label.  For
110  *   the above example, the first 0x20 is the number of bytes in the
111  *   left-most label, EGFCEFEECACACACACACACACACACACACA, of the domain
112  *   name.  The bytes following the label length count are the characters
113  *   of the label.  The following labels are in sequence after the first
114  *   label, which is the encoded NetBIOS name, until a zero (0x00) length
115  *   count.  The zero length count represents the root label, which is
116  *   always null.
117  *
118  *   A label length count is actually a 6-bit field in the label length
119  *   field.  The most significant 2 bits of the field, bits 7 and 6, are
120  *   flags allowing an escape from the above compressed representation.
121  *   If bits 7 and 6 are both set (11), the following 14 bits are an
122  *   offset pointer into the full message to the actual label string from
123  *   another domain name that belongs in this name.  This label pointer
124  *   allows for a further compression of a domain name in a packet.
125  *
126  *   NetBIOS implementations can only use label string pointers in Name
127  *   Service packets.  They cannot be used in Session or Datagram Service
128  *   packets.
129  *
130  *   The other two possible values for bits 7 and 6 (01 and 10) of a label
131  *   length field are reserved for future use by RFC 883[2 (page 32)].
132  *
133  *   Note that the first octet of a compressed name must contain one of
134  *   the following bit patterns.  (An "x" indicates a bit whose value may
135  *   be either 0 or 1.):
136  *
137  *           00100000 -  Netbios name, length must be 32 (decimal)
138  *           11xxxxxx -  Label string pointer
139  *           10xxxxxx -  Reserved
140  *           01xxxxxx -  Reserved
141  */
142 
143 /*
144  * netbios_first_level_name_encode
145  *
146  * Put test description here.
147  *
148  * Inputs:
149  *	char *	in	-> Name to encode
150  *	char *	out	-> Buffer to encode into.
151  *	int	length	-> # of bytes to encode.
152  *
153  * Returns:
154  *	Nothing
155  */
156 int
157 netbios_first_level_name_encode(unsigned char *name, unsigned char *scope,
158     unsigned char *out, int max_out)
159 {
160 	unsigned char	ch, len;
161 	unsigned char	 *in;
162 	unsigned char	 *lp;
163 	unsigned char	 *op = out;
164 
165 	if (max_out < 0x21)
166 		return (-1);
167 
168 	in = name;
169 	*op++ = 0x20;
170 	for (len = 0; len < NETBIOS_NAME_SZ; len++) {
171 		ch = *in++;
172 		*op++ = 'A' + ((ch >> 4) & 0xF);
173 		*op++ = 'A' + ((ch) & 0xF);
174 	}
175 
176 	max_out -= 0x21;
177 
178 	in = scope;
179 	len = 0;
180 	lp = op++;
181 	while (((ch = *in++) != 0) && (max_out-- > 1)) {
182 		if (ch == 0) {
183 			if ((*lp = len) != 0)
184 				*op++ = 0;
185 			break;
186 		}
187 		if (ch == '.') {
188 			*lp = len;
189 			lp = op++;
190 			len = 0;
191 		} else {
192 			*op++ = ch;
193 			len++;
194 		}
195 	}
196 	*lp = len;
197 	if (len != 0)
198 		*op = 0;
199 
200 	/*LINTED E_PTRDIFF_OVERFLOW*/
201 	return (op - out);
202 }
203 
204 /*
205  * smb_first_level_name_decode
206  *
207  * The null terminated string "in" is the name to decode. The output
208  * is placed in the name_entry structure "name".
209  *
210  * The scope field is a series of length designated labels as described
211  * in the "Domain name representation and compression" section of RFC883.
212  * The two high order two bits of the length field must be zero, the
213  * remaining six bits contain the field length. The total length of the
214  * domain name is restricted to 255 octets but note that the trailing
215  * root label and its dot are not printed. When converting the labels,
216  * the length fields are replaced by dots.
217  *
218  * Returns the number of bytes scanned or -1 to indicate an error.
219  */
220 int
221 netbios_first_level_name_decode(char *in, char *name, char *scope)
222 {
223 	unsigned int	length, bytes;
224 	char		c1, c2;
225 	char		*cp;
226 	char		*out;
227 
228 	cp = in;
229 
230 	if ((length = *cp++) != 0x20) {
231 		return (-1);
232 	}
233 
234 	out = name;
235 	while (length > 0) {
236 		c1 = *cp++;
237 		c2 = *cp++;
238 
239 		if ('A' <= c1 && c1 <= 'P' && 'A' <= c2 && c2 <= 'P') {
240 			c1 -= 'A';
241 			c2 -= 'A';
242 			*out++ = (c1 << 4) | (c2);
243 		} else {
244 			return (-1);		/* conversion error */
245 		}
246 		length -= 2;
247 	}
248 
249 	out = scope;
250 	bytes = 0;
251 	for (length = *cp++; length != 0; length = *cp++) {
252 		if ((length & 0xc0) != 0x00) {
253 			/*
254 			 * This is a pointer or a reserved field. If it's
255 			 * a pointer (16-bits) we have to skip the next byte.
256 			 */
257 			if ((length & 0xc0) == 0xc0) {
258 				cp++;
259 				continue;
260 			}
261 		}
262 
263 		/*
264 		 * Replace the length with a '.', except for the first one.
265 		 */
266 		if (out != scope) {
267 			*out++ = '.';
268 			bytes++;
269 		}
270 
271 		while (length-- > 0) {
272 			if (bytes++ >= (NETBIOS_DOMAIN_NAME_MAX - 1)) {
273 				return (-1);
274 			}
275 			*out++ = *cp++;
276 		}
277 	}
278 	*out = 0;
279 
280 	/*
281 	 * We are supposed to preserve all 8-bits of the domain name
282 	 * but due to the single byte representation in the name cache
283 	 * and UTF-8 encoding everywhere else, we restrict domain names
284 	 * to Appendix 1 - Domain Name Syntax Specification in RFC883.
285 	 */
286 	if (domainname_is_valid(scope))	{
287 		(void) smb_strupr(scope);
288 		/*LINTED E_PTRDIFF_OVERFLOW*/
289 		return (cp - in);
290 	}
291 
292 	scope[0] = '\0';
293 	return (-1);
294 }
295 
296 /*
297  * smb_netbios_name_isvalid
298  *
299  * This function is provided to be used by session service
300  * which runs in kernel in order to hide name_entry definition.
301  *
302  * It returns the decoded name in the provided buffer as 'out'
303  * if it's not null.
304  *
305  * Returns 0 if decode fails, 1 if it succeeds.
306  */
307 int
308 netbios_name_isvalid(char *in, char *out)
309 {
310 	char name[NETBIOS_NAME_SZ];
311 	char scope[NETBIOS_DOMAIN_NAME_MAX];
312 
313 	if (netbios_first_level_name_decode(in, name, scope) < 0)
314 		return (0);
315 
316 	if (out)
317 		(void) strlcpy(out, name, NETBIOS_NAME_SZ);
318 
319 	return (1);
320 }
321 
322 /*
323  * Characters that we allow in DNS domain names, in addition to
324  * alphanumeric characters. This is not quite consistent with
325  * RFC883. This is global so that it can be patched if there is
326  * a need to change the valid characters in the field.
327  */
328 static const char dns_allowed[] = "-_";
329 
330 /*
331  * dns_is_allowed
332  *
333  * Check the dns_allowed characters and return true (1) if the character
334  * is in the table. Otherwise return false (0).
335  */
336 static int
337 dns_is_allowed(unsigned char c)
338 {
339 	const char *p = dns_allowed;
340 
341 	while (*p) {
342 		if ((char)c == *p++)
343 			return (1);
344 	}
345 
346 	return (0);
347 }
348 
349 
350 /*
351  * domainname_is_valid
352  *
353  * Check the specified domain name for mostly compliance with RFC883
354  * Appendix 1. Names may contain alphanumeric characters, hyphens,
355  * underscores and dots. The first character after a dot must be an
356  * alphabetic character. RFC883 doesn't mention underscores but we
357  * allow it due to common use, and we don't check that labels end
358  * with an alphanumeric character.
359  *
360  * Returns true (1) if the name is valid. Otherwise returns false (0).
361  */
362 static int
363 domainname_is_valid(char *domain_name)
364 {
365 	char *name;
366 	int first_char = 1;
367 
368 	if (domain_name == 0)
369 		return (0);
370 
371 	for (name = domain_name; *name != 0; ++name) {
372 		if (*name == '.') {
373 			first_char = 1;
374 			continue;
375 		}
376 
377 		if (first_char)	{
378 			if (smb_isalpha_ascii(*name) == 0)
379 				return (0);
380 
381 			first_char = 0;
382 			continue;
383 		}
384 
385 		if (smb_isalnum_ascii(*name) || dns_is_allowed(*name))
386 			continue;
387 
388 		return (0);
389 	}
390 
391 	return (1);
392 }
393