xref: /onnv-gate/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_netbios.c (revision 5772:237ac22142fe)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * NetBIOS support functions. NetBIOS is documented in the following
30  * RFC documents:
31  *
32  * RFC 1001: Protocol Standard for a NetBIOS Service on a TCP/UDP
33  *           Transport: Concepts and Methods
34  *
35  * RFC 1002: Protocol Standard for a NetBIOS Service on a TCP/UDP
36  *           Transport: Detailed Specifications
37  *
38  */
39 
40 #define	BSD_BYTE_STRING_PROTOTYPES
41 
42 #include <string.h>
43 #include <unistd.h>
44 #include <synch.h>
45 #include <sys/types.h>
46 #include <sys/uio.h>
47 #include <sys/time.h>
48 
49 #include <stdio.h>
50 #include <pthread.h>
51 
52 #define	MAX_NETBIOS_NAME_SIZE	16
53 
54 #define	SESSION_MESSAGE				0x00
55 #define	SESSION_REQUEST				0x81
56 #define	POSITIVE_SESSION_RESPONSE		0x82
57 #define	NEGATIVE_SESSION_RESPONSE		0x83
58 #define	RETARGET_SESSION_RESPONSE		0x84
59 #define	SESSION_KEEP_ALIVE			0x85
60 
61 #define	NB_READ_MSG_ERR_EOF			0
62 #define	NB_READ_MSG_ERR				-1
63 #define	NB_READ_MSG_ERR_OVERFLOW		-2
64 #define	NB_READ_MSG_ERR_UNDERFLOW		-3
65 #define	NB_RCV_MSG_ERR_INVTYPE			-4
66 
67 /*
68  * Semaphore object used to serialize access through NetBIOS exchange.
69  */
70 static mutex_t nb_mutex;
71 
72 static int nb_write_msg(int fd, unsigned char *buf, unsigned count, int type);
73 static int nb_read_msg(int fd, unsigned char *buf, unsigned max_buf,
74     int *type, long timeout);
75 static int nb_read_itter(int fd, unsigned char *buf, unsigned cnt);
76 static int nb_first_level_name_encode(char *name, char *scope,
77     unsigned char *out, int max_out);
78 
79 
80 /*
81  * nb_lock
82  *
83  * Acquire semaphore for doing netbios operations
84  */
85 void
86 nb_lock()
87 {
88 	(void) mutex_lock(&nb_mutex);
89 }
90 
91 /*
92  * nb_lock
93  *
94  * Release netbios semaphore.
95  */
96 void
97 nb_unlock()
98 {
99 	(void) mutex_unlock(&nb_mutex);
100 }
101 
102 void
103 nb_close(int fd)
104 {
105 	(void) mutex_lock(&nb_mutex);
106 	if (fd > 0) {
107 		(void) close(fd);
108 		(void) printf("[%d] socket (%d) closed\n", pthread_self(), fd);
109 	}
110 	(void) mutex_unlock(&nb_mutex);
111 }
112 
113 /*
114  * nb_keep_alive
115  *
116  * Send the NetBIOS keep alive message. No response is expected but we
117  * do need to ignore keep-alive messages in nb_exchange. The semaphore
118  * ensures compatibility/serialization with nb_exchange to allow us to
119  * call this function from a separate thread.
120  */
121 int
122 nb_keep_alive(int fd)
123 {
124 	int nothing;
125 	int rc;
126 
127 	(void) mutex_lock(&nb_mutex);
128 
129 	rc = nb_write_msg(fd, (unsigned char *)&nothing, 0, SESSION_KEEP_ALIVE);
130 
131 	(void) mutex_unlock(&nb_mutex);
132 	return (rc);
133 }
134 
135 /*
136  * nb_send
137  *
138  * This is just a wrapper round the nb_write_msg.
139  */
140 int
141 nb_send(int fd, unsigned char *send_buf, unsigned send_cnt)
142 {
143 	int rc;
144 
145 	rc = nb_write_msg(fd, send_buf, send_cnt, SESSION_MESSAGE);
146 	return (rc);
147 }
148 
149 /*
150  * nb_rcv
151  *
152  * This is a wrapper round the nb_read_msg() so that if a
153  * keep-alive message is received, just discard it and go
154  * back to look for the real response.
155  */
156 int
157 nb_rcv(int fd, unsigned char *recv_buf, unsigned recv_max, long timeout)
158 {
159 	int rc;
160 	int type;
161 
162 	do {
163 		rc = nb_read_msg(fd, recv_buf, recv_max, &type, timeout);
164 		if (rc < 0)
165 			return (rc);
166 	} while (type == SESSION_KEEP_ALIVE);
167 
168 	if (type != SESSION_MESSAGE)
169 		return (NB_RCV_MSG_ERR_INVTYPE);
170 
171 	return (rc);
172 }
173 
174 /*
175  * nb_exchange
176  *
177  * This is the NetBIOS workhorse function where we do the send/receive
178  * message exchange. A semaphore is used to serialize access because
179  * we may get swapped out between the send and receive operations and
180  * another thread could enter here and collect our response. If a
181  * keep-alive message is received, just discard it and go back to look
182  * for the real response.
183  *
184  * Note: With the addition of support for SMB over TCP, this function
185  * may be exchanging NetBIOS-less SMB data.
186  */
187 int
188 nb_exchange(int fd, unsigned char *send_buf, unsigned send_cnt,
189     unsigned char *recv_buf, unsigned recv_max, long timeout)
190 {
191 	int rc;
192 
193 	(void) mutex_lock(&nb_mutex);
194 
195 	rc = nb_send(fd, send_buf, send_cnt);
196 	if (rc == send_cnt)
197 		rc = nb_rcv(fd, recv_buf, recv_max, timeout);
198 
199 	(void) mutex_unlock(&nb_mutex);
200 	return (rc);
201 }
202 
203 /*
204  * nb_session_request
205  *
206  * We should never see descriptor 0 (stdin) or -1.
207  */
208 int
209 nb_session_request(int fd, char *called_name, char *called_scope,
210     char *calling_name, char *calling_scope)
211 {
212 	unsigned char sr_buf[200];
213 	int len;
214 	int rc;
215 	int type;
216 
217 	if (fd == 0 || fd == -1)
218 		return (-1);
219 
220 	rc = nb_first_level_name_encode(called_name, called_scope, sr_buf, 100);
221 	len = rc;
222 	rc = nb_first_level_name_encode(calling_name, calling_scope,
223 	    sr_buf+len, 100);
224 	len += rc;
225 
226 	(void) mutex_lock(&nb_mutex);
227 
228 	rc = nb_write_msg(fd, (unsigned char *)sr_buf, len, SESSION_REQUEST);
229 	if (rc < 0) {
230 		(void) mutex_unlock(&nb_mutex);
231 		return (rc);
232 	}
233 
234 	for (;;) {
235 		rc = nb_read_msg(fd, (unsigned char *)sr_buf,
236 		    sizeof (sr_buf), &type, 0);
237 		if (rc < 0) {
238 			(void) mutex_unlock(&nb_mutex);
239 			return (rc);
240 		}
241 
242 		if ((rc == 0) && (type == -1)) {
243 			(void) mutex_unlock(&nb_mutex);
244 			return (-1);		/* EOF */
245 		}
246 
247 		if (type == POSITIVE_SESSION_RESPONSE) {
248 			(void) mutex_unlock(&nb_mutex);
249 			return (0);
250 		}
251 
252 		if (type == NEGATIVE_SESSION_RESPONSE) {
253 			(void) mutex_unlock(&nb_mutex);
254 			return (-1);
255 		}
256 	}
257 
258 	/* NOTREACHED */
259 	(void) mutex_unlock(&nb_mutex);
260 	return (-1);
261 }
262 
263 
264 
265 /*
266  * nb_write_msg
267  */
268 static int
269 nb_write_msg(int fd, unsigned char *buf, unsigned count, int type)
270 {
271 	struct iovec iov[2];
272 	unsigned char header[4];
273 	int rc;
274 
275 	if (fd == 0 || fd == -1) {
276 		/*
277 		 * We should never see descriptor 0 (stdin).
278 		 */
279 		return (-1);
280 	}
281 
282 	/*
283 	 * The NetBIOS message length is limited to 17 bits but
284 	 * we use this layer for SMB over both NetBIOS and TCP
285 	 * (NetBIOS-less SMB). When using SMB over TCP the length
286 	 * is 24 bits but we are ignoring that for now because we
287 	 * don't expect any messages larger than 64KB.
288 	 */
289 	header[0] = type;
290 	header[1] = (count >> 16) & 1;
291 	header[2] = count >> 8;
292 	header[3] = count;
293 
294 	iov[0].iov_base = (caddr_t)header;
295 	iov[0].iov_len = 4;
296 	iov[1].iov_base = (caddr_t)buf;
297 	iov[1].iov_len = count;
298 
299 	rc = writev(fd, iov, 2);
300 	if (rc != 4 + count) {
301 		return (-3);		/* error */
302 	}
303 
304 	return (count);
305 }
306 
307 
308 /*
309  * nb_read_msg
310  *
311  * Added select to ensure that we don't block forever waiting for a
312  * message.
313  */
314 static int
315 nb_read_msg(int fd, unsigned char *buf, unsigned max_buf,
316     int *type, long timeout)
317 {
318 	unsigned char header[4];
319 	int length;
320 	int rc;
321 	fd_set readfds;
322 	struct timeval tval;
323 
324 	*type = -1;
325 
326 	if (fd == 0 || fd == -1) {
327 		/*
328 		 * We should never see descriptor 0 (stdin).
329 		 */
330 		return (NB_READ_MSG_ERR);
331 	}
332 
333 	FD_ZERO(&readfds);
334 	FD_SET(fd, &readfds);
335 	tval.tv_sec = (timeout == 0) ? 45 : timeout;
336 	tval.tv_usec = 0;
337 
338 	if ((rc = select(fd + 1, &readfds, 0, 0, &tval)) <= 0) {
339 		return (NB_READ_MSG_ERR);
340 	}
341 
342 	if ((rc = nb_read_itter(fd, header, 4)) < 0)
343 		return (rc);		/* error */
344 
345 	if (rc != 4)
346 		return (NB_READ_MSG_ERR_EOF);		/* EOF */
347 
348 	/*
349 	 * The NetBIOS message length is limited to 17 bits but
350 	 * we use this layer for SMB over both NetBIOS and TCP
351 	 * (NetBIOS-less SMB). When using SMB over TCP the length
352 	 * is 24 bits but we are ignoring that for now because we
353 	 * don't expect any messages larger than 64KB.
354 	 */
355 	*type = header[0];
356 	length = ((header[1]&1) << 16) + (header[2]<<8) + header[3];
357 
358 	if (length > max_buf)
359 		return (NB_READ_MSG_ERR_OVERFLOW);	/* error overflow */
360 
361 	if ((rc = nb_read_itter(fd, buf, length)) != length)
362 		return (NB_READ_MSG_ERR_UNDERFLOW);	/* error underflow */
363 
364 	return (rc);
365 }
366 
367 
368 /*
369  * nb_read_itter
370  *
371  * We should never see descriptor 0 (stdin) or -1.
372  */
373 static int
374 nb_read_itter(int fd, unsigned char *buf, unsigned cnt)
375 {
376 	int ix;
377 	int rc;
378 
379 	for (ix = 0; ix < cnt; ix += rc) {
380 		if (fd == 0 || fd == -1)
381 			return (-1);
382 
383 		if ((rc = read(fd, buf+ix, cnt-ix)) < 0)
384 			return (rc);
385 
386 		if (rc == 0)
387 			break;
388 	}
389 
390 	return (ix);
391 }
392 
393 
394 /*
395  * nb_first_level_name_encode
396  */
397 static int
398 nb_first_level_name_encode(char *name, char *scope,
399     unsigned char *out, int max_out)
400 {
401 	unsigned char ch, len;
402 	unsigned char *in;
403 	unsigned char *lp;
404 	unsigned char *op = out;
405 	unsigned char *op_end = op + max_out;
406 
407 	in = (unsigned char *)name;
408 	*op++ = 0x20;
409 	for (len = 0; ((ch = *in) != 0) && len < MAX_NETBIOS_NAME_SIZE;
410 	    len++, in++) {
411 		*op++ = 'A' + ((ch >> 4) & 0xF);
412 		*op++ = 'A' + ((ch) & 0xF);
413 	}
414 
415 	for (; len < MAX_NETBIOS_NAME_SIZE; len++) {
416 		ch = ' ';
417 		*op++ = 'A' + ((ch >> 4) & 0xF);
418 		*op++ = 'A' + ((ch) & 0xF);
419 	}
420 
421 	in = (unsigned char *)scope;
422 	len = 0;
423 	lp = op++;
424 	for (; op < op_end; in++) {
425 		ch = *in;
426 		if (ch == 0) {
427 			if ((*lp = len) != 0)
428 				*op++ = 0;
429 			break;
430 		}
431 		if (ch == '.') {
432 			*lp = (op - lp) - 1;
433 			lp = op++;
434 			len = 0;
435 		} else {
436 			*op++ = ch;
437 			len++;
438 		}
439 	}
440 
441 	return ((int)(op - out));
442 }
443