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