xref: /illumos-gate/usr/src/common/smbsrv/smb_netbios_util.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
26  */
27 
28 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
29 #include <sys/types.h>
30 #include <sys/sunddi.h>
31 #else
32 #include <string.h>
33 #endif
34 #include <smbsrv/string.h>
35 #include <smbsrv/netbios.h>
36 
37 /*
38  * Routines than support name compression.
39  *
40  *   The NetBIOS name representation in all NetBIOS packets (for NAME,
41  *   SESSION, and DATAGRAM services) is defined in the Domain Name
42  *   Service RFC 883[3] as "compressed" name messages.  This format is
43  *   called "second-level encoding" in the section entitled
44  *   "Representation of NetBIOS Names" in the Concepts and Methods
45  *   document.
46  *
47  *   For ease of description, the first two paragraphs from page 31,
48  *   the section titled "Domain name representation and compression",
49  *   of RFC 883 are replicated here:
50  *
51  *        Domain names messages are expressed in terms of a sequence
52  *        of labels.  Each label is represented as a one octet length
53  *        field followed by that number of octets.  Since every domain
54  *        name ends with the null label of the root, a compressed
55  *        domain name is terminated by a length byte of zero.  The
56  *        high order two bits of the length field must be zero, and
57  *        the remaining six bits of the length field limit the label
58  *        to 63 octets or less.
59  *
60  *        To simplify implementations, the total length of label
61  *        octets and label length octets that make up a domain name is
62  *        restricted to 255 octets or less.
63  *
64  *   The following is the uncompressed representation of the NetBIOS name
65  *   "FRED ", which is the 4 ASCII characters, F, R, E, D, followed by 12
66  *   space characters (0x20).  This name has the SCOPE_ID: "NETBIOS.COM"
67  *
68  *           EGFCEFEECACACACACACACACACACACACA.NETBIOS.COM
69  *
70  *   This uncompressed representation of names is called "first-level
71  *   encoding" in the section entitled "Representation of NetBIOS Names"
72  *   in the Concepts and Methods document.
73  *
74  *   The following is a pictographic representation of the compressed
75  *   representation of the previous uncompressed Domain Name
76  *   representation.
77  *
78  *                        1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
79  *    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
80  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
81  *   |      0x20     |    E (0x45)   |    G (0x47)   |    F (0x46)   |
82  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
83  *   |    C (0x43)   |    E (0x45)   |    F (0x46)   |    E (0x45)   |
84  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
85  *   |    E (0x45)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
86  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
88  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
89  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
90  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
91  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
92  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
93  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
94  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
95  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
96  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97  *   |    A (0X41)   |      0x07     |    N (0x4E)   |    E (0x45)   |
98  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99  *   |    T (0x54)   |    B (0x42)   |    I (0x49)   |    O (0x4F)   |
100  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
101  *   |    S (0x53)   |      0x03     |    C (0x43)   |    O (0x4F)   |
102  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
103  *   |    M (0x4D)   |      0x00     |
104  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
105  *
106  *   Each section of a domain name is called a label [7 (page 31)].  A
107  *   label can be a maximum of 63 bytes.  The first byte of a label in
108  *   compressed representation is the number of bytes in the label.  For
109  *   the above example, the first 0x20 is the number of bytes in the
110  *   left-most label, EGFCEFEECACACACACACACACACACACACA, of the domain
111  *   name.  The bytes following the label length count are the characters
112  *   of the label.  The following labels are in sequence after the first
113  *   label, which is the encoded NetBIOS name, until a zero (0x00) length
114  *   count.  The zero length count represents the root label, which is
115  *   always null.
116  *
117  *   A label length count is actually a 6-bit field in the label length
118  *   field.  The most significant 2 bits of the field, bits 7 and 6, are
119  *   flags allowing an escape from the above compressed representation.
120  *   If bits 7 and 6 are both set (11), the following 14 bits are an
121  *   offset pointer into the full message to the actual label string from
122  *   another domain name that belongs in this name.  This label pointer
123  *   allows for a further compression of a domain name in a packet.
124  *
125  *   NetBIOS implementations can only use label string pointers in Name
126  *   Service packets.  They cannot be used in Session or Datagram Service
127  *   packets.
128  *
129  *   The other two possible values for bits 7 and 6 (01 and 10) of a label
130  *   length field are reserved for future use by RFC 883[2 (page 32)].
131  *
132  *   Note that the first octet of a compressed name must contain one of
133  *   the following bit patterns.  (An "x" indicates a bit whose value may
134  *   be either 0 or 1.):
135  *
136  *           00100000 -  Netbios name, length must be 32 (decimal)
137  *           11xxxxxx -  Label string pointer
138  *           10xxxxxx -  Reserved
139  *           01xxxxxx -  Reserved
140  */
141 
142 /*
143  * netbios_first_level_name_encode
144  *
145  * Put test description here.
146  *
147  * Inputs:
148  *	char *	in	-> Name to encode
149  *	char *	out	-> Buffer to encode into.
150  *	int	length	-> # of bytes to encode.
151  *
152  * Returns:
153  *	Nothing
154  */
155 int
156 netbios_first_level_name_encode(unsigned char *name, unsigned char *scope,
157     unsigned char *out, int max_out)
158 {
159 	unsigned char	ch, len;
160 	unsigned char	 *in;
161 	unsigned char	 *lp;
162 	unsigned char	 *op = out;
163 
164 	if (max_out < 0x21)
165 		return (-1);
166 
167 	in = name;
168 	*op++ = 0x20;
169 	for (len = 0; len < NETBIOS_NAME_SZ; len++) {
170 		ch = *in++;
171 		*op++ = 'A' + ((ch >> 4) & 0xF);
172 		*op++ = 'A' + ((ch) & 0xF);
173 	}
174 
175 	max_out -= 0x21;
176 
177 	in = scope;
178 	len = 0;
179 	lp = op++;
180 	while (((ch = *in++) != 0) && (max_out-- > 1)) {
181 		if (ch == 0) {
182 			if ((*lp = len) != 0)
183 				*op++ = 0;
184 			break;
185 		}
186 		if (ch == '.') {
187 			*lp = len;
188 			lp = op++;
189 			len = 0;
190 		} else {
191 			*op++ = ch;
192 			len++;
193 		}
194 	}
195 	*lp = len;
196 	if (len != 0)
197 		*op = 0;
198 
199 	/*LINTED E_PTRDIFF_OVERFLOW*/
200 	return (op - out);
201 }
202 
203 /*
204  * smb_first_level_name_decode
205  *
206  * The null terminated string "in" is the name to decode. The output
207  * is placed in the name_entry structure "name".
208  *
209  * The scope field is a series of length designated labels as described
210  * in the "Domain name representation and compression" section of RFC883.
211  * The two high order two bits of the length field must be zero, the
212  * remaining six bits contain the field length. The total length of the
213  * domain name is restricted to 255 octets but note that the trailing
214  * root label and its dot are not printed. When converting the labels,
215  * the length fields are replaced by dots.
216  *
217  * Returns the number of bytes scanned or -1 to indicate an error.
218  */
219 int
220 netbios_first_level_name_decode(char *in, char *name, char *scope)
221 {
222 	unsigned int	length;
223 	char		c1, c2;
224 	char		*cp;
225 	char		*out;
226 
227 	cp = in;
228 
229 	if ((length = *cp++) != 0x20) {
230 		return (-1);
231 	}
232 
233 	out = name;
234 	while (length > 0) {
235 		c1 = *cp++;
236 		c2 = *cp++;
237 
238 		if ('A' <= c1 && c1 <= 'P' && 'A' <= c2 && c2 <= 'P') {
239 			c1 -= 'A';
240 			c2 -= 'A';
241 			*out++ = (c1 << 4) | (c2);
242 		} else {
243 			return (-1);		/* conversion error */
244 		}
245 		length -= 2;
246 	}
247 
248 	/*
249 	 * Don't bother decoding the scope.  Not supported.
250 	 */
251 	if ((length = *cp++) != 0)
252 		return (-1);
253 	scope[0] = '\0';
254 
255 	/*LINTED E_PTRDIFF_OVERFLOW*/
256 	return (cp - in);
257 }
258 
259 /*
260  * smb_netbios_name_isvalid
261  *
262  * This function is provided to be used by session service
263  * which runs in kernel in order to hide name_entry definition.
264  *
265  * It returns the decoded name in the provided buffer as 'out'
266  * if it's not null.
267  *
268  * Returns 0 if decode fails, 1 if it succeeds.
269  */
270 int
271 netbios_name_isvalid(char *in, char *out)
272 {
273 	char name[NETBIOS_NAME_SZ];
274 	char scope[NETBIOS_DOMAIN_NAME_MAX];
275 
276 	if (netbios_first_level_name_decode(in, name, scope) < 0)
277 		return (0);
278 
279 	if (out)
280 		(void) strlcpy(out, name, NETBIOS_NAME_SZ);
281 
282 	return (1);
283 }
284