xref: /titanic_50/usr/src/lib/libsmbfs/smb/nb_ssn.c (revision 15359501f7d4b9abebd7b7bf6efd5982a8e7eb27)
1613a2f6bSGordon Ross /*
2613a2f6bSGordon Ross  * CDDL HEADER START
3613a2f6bSGordon Ross  *
4613a2f6bSGordon Ross  * The contents of this file are subject to the terms of the
5613a2f6bSGordon Ross  * Common Development and Distribution License (the "License").
6613a2f6bSGordon Ross  * You may not use this file except in compliance with the License.
7613a2f6bSGordon Ross  *
8613a2f6bSGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9613a2f6bSGordon Ross  * or http://www.opensolaris.org/os/licensing.
10613a2f6bSGordon Ross  * See the License for the specific language governing permissions
11613a2f6bSGordon Ross  * and limitations under the License.
12613a2f6bSGordon Ross  *
13613a2f6bSGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
14613a2f6bSGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15613a2f6bSGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
16613a2f6bSGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
17613a2f6bSGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
18613a2f6bSGordon Ross  *
19613a2f6bSGordon Ross  * CDDL HEADER END
20613a2f6bSGordon Ross  */
21613a2f6bSGordon Ross 
22613a2f6bSGordon Ross /*
23*15359501SGordon Ross  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24613a2f6bSGordon Ross  */
25613a2f6bSGordon Ross 
26613a2f6bSGordon Ross /*
27613a2f6bSGordon Ross  * NetBIOS session service functions
28613a2f6bSGordon Ross  */
29613a2f6bSGordon Ross 
30613a2f6bSGordon Ross #include <errno.h>
31613a2f6bSGordon Ross #include <stdio.h>
32613a2f6bSGordon Ross #include <stdlib.h>
33613a2f6bSGordon Ross #include <string.h>
34613a2f6bSGordon Ross #include <strings.h>
35613a2f6bSGordon Ross #include <libintl.h>
36613a2f6bSGordon Ross #include <xti.h>
37613a2f6bSGordon Ross #include <assert.h>
38613a2f6bSGordon Ross 
39613a2f6bSGordon Ross #include <sys/types.h>
40613a2f6bSGordon Ross #include <sys/socket.h>
41613a2f6bSGordon Ross #include <sys/poll.h>
42613a2f6bSGordon Ross 
43613a2f6bSGordon Ross #include <netsmb/netbios.h>
44613a2f6bSGordon Ross #include <netsmb/smb_lib.h>
45613a2f6bSGordon Ross #include <netsmb/nb_lib.h>
46613a2f6bSGordon Ross #include <netsmb/mchain.h>
47613a2f6bSGordon Ross 
48613a2f6bSGordon Ross #include "private.h"
49613a2f6bSGordon Ross #include "charsets.h"
50613a2f6bSGordon Ross 
51613a2f6bSGordon Ross static int nb_ssn_send(struct smb_ctx *, struct mbdata *, int, int);
52613a2f6bSGordon Ross static int nb_ssn_recv(struct smb_ctx *, struct mbdata *, int *, int *);
53613a2f6bSGordon Ross static int nb_ssn_pollin(struct smb_ctx *, int);
54613a2f6bSGordon Ross 
55613a2f6bSGordon Ross /*
56613a2f6bSGordon Ross  * Send a data message.
57613a2f6bSGordon Ross  */
58613a2f6bSGordon Ross int
smb_ssn_send(struct smb_ctx * ctx,struct mbdata * mbp)59613a2f6bSGordon Ross smb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp)
60613a2f6bSGordon Ross {
61613a2f6bSGordon Ross 	return (nb_ssn_send(ctx, mbp, 0, mbp->mb_count));
62613a2f6bSGordon Ross }
63613a2f6bSGordon Ross 
64613a2f6bSGordon Ross /*
65613a2f6bSGordon Ross  * Send a NetBIOS message, after
66613a2f6bSGordon Ross  * prepending the 4-byte header.
67613a2f6bSGordon Ross  */
68613a2f6bSGordon Ross static int
nb_ssn_send(struct smb_ctx * ctx,struct mbdata * mbp,int mtype,int mlen)69613a2f6bSGordon Ross nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp,
70613a2f6bSGordon Ross 	    int mtype, int mlen)
71613a2f6bSGordon Ross {
72*15359501SGordon Ross 	mbuf_t *m;
73613a2f6bSGordon Ross 	uint32_t hdr, hdrbuf;
74*15359501SGordon Ross 	int err;
75613a2f6bSGordon Ross 
76*15359501SGordon Ross 	m = mbp->mb_top;
77613a2f6bSGordon Ross 	if (m == NULL)
78613a2f6bSGordon Ross 		return (EINVAL);
79613a2f6bSGordon Ross 
80613a2f6bSGordon Ross 	/*
81613a2f6bSGordon Ross 	 * Prepend the NetBIOS header.
82*15359501SGordon Ross 	 * Our mbufs leave space for this.
83613a2f6bSGordon Ross 	 */
84613a2f6bSGordon Ross 	hdr = (mtype << 24) | mlen;
85613a2f6bSGordon Ross 	hdrbuf = htonl(hdr);
86613a2f6bSGordon Ross 	m->m_data -= 4;
87613a2f6bSGordon Ross 	m->m_len  += 4;
88613a2f6bSGordon Ross 	bcopy(&hdrbuf, m->m_data, 4);
89613a2f6bSGordon Ross 
90*15359501SGordon Ross 	/*
91*15359501SGordon Ross 	 * Get contiguous data (so TCP won't fragment)
92*15359501SGordon Ross 	 * Note: replaces mb_top.
93*15359501SGordon Ross 	 */
94*15359501SGordon Ross 	err = m_lineup(mbp->mb_top, &mbp->mb_top);
95*15359501SGordon Ross 	if (err)
96*15359501SGordon Ross 		return (err);
97*15359501SGordon Ross 	m = mbp->mb_top;
98*15359501SGordon Ross 
99*15359501SGordon Ross 	/*
100*15359501SGordon Ross 	 * Send it.
101*15359501SGordon Ross 	 */
102*15359501SGordon Ross 	if (t_snd(ctx->ct_tran_fd, m->m_data, m->m_len, 0) < 0) {
103613a2f6bSGordon Ross 		if (t_errno == TSYSERR)
104613a2f6bSGordon Ross 			err = errno;
105613a2f6bSGordon Ross 		else
106613a2f6bSGordon Ross 			err = EPROTO;
107613a2f6bSGordon Ross 		DPRINT("t_snd: t_errno %d, err %d", t_errno, err);
108613a2f6bSGordon Ross 		return (err);
109613a2f6bSGordon Ross 	}
110*15359501SGordon Ross 
111613a2f6bSGordon Ross 	return (0);
112613a2f6bSGordon Ross }
113613a2f6bSGordon Ross 
114613a2f6bSGordon Ross /*
115613a2f6bSGordon Ross  * Receive a data message.  Discard anything else.
116613a2f6bSGordon Ross  * Caller must deal with EAGAIN, EINTR.
117613a2f6bSGordon Ross  */
118613a2f6bSGordon Ross int
smb_ssn_recv(struct smb_ctx * ctx,struct mbdata * mbp)119613a2f6bSGordon Ross smb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mbp)
120613a2f6bSGordon Ross {
121613a2f6bSGordon Ross 	int err, mtype, mlen;
122613a2f6bSGordon Ross 	err = nb_ssn_recv(ctx, mbp, &mtype, &mlen);
123613a2f6bSGordon Ross 	if (err)
124613a2f6bSGordon Ross 		return (err);
125613a2f6bSGordon Ross 	if (mtype != NB_SSN_MESSAGE) {
126613a2f6bSGordon Ross 		DPRINT("discard type 0x%x", mtype);
127613a2f6bSGordon Ross 		mb_done(mbp);
128613a2f6bSGordon Ross 		return (EAGAIN);
129613a2f6bSGordon Ross 	}
130613a2f6bSGordon Ross 	if (mlen == 0) {
131613a2f6bSGordon Ross 		DPRINT("zero length");
132613a2f6bSGordon Ross 		mb_done(mbp);
133613a2f6bSGordon Ross 		return (EAGAIN);
134613a2f6bSGordon Ross 	}
135613a2f6bSGordon Ross 
136613a2f6bSGordon Ross 	return (0);
137613a2f6bSGordon Ross }
138613a2f6bSGordon Ross 
139613a2f6bSGordon Ross /*
140613a2f6bSGordon Ross  * Receive a NetBIOS message, any type.
141613a2f6bSGordon Ross  * Give caller type and length.
142613a2f6bSGordon Ross  */
143613a2f6bSGordon Ross static int
nb_ssn_recv(struct smb_ctx * ctx,struct mbdata * mb,int * mtype,int * mlen)144613a2f6bSGordon Ross nb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mb,
145613a2f6bSGordon Ross 	    int *mtype, int *mlen)
146613a2f6bSGordon Ross {
147613a2f6bSGordon Ross 	char *buf;
148613a2f6bSGordon Ross 	uint32_t hdr, hdrbuf;
149613a2f6bSGordon Ross 	int cnt, len, err, moreflag;
150613a2f6bSGordon Ross 	int fd = ctx->ct_tran_fd;
151613a2f6bSGordon Ross 	int tmo = smb_recv_timeout * 1000;
152613a2f6bSGordon Ross 
153613a2f6bSGordon Ross 	/*
154613a2f6bSGordon Ross 	 * Start by getting the header
155613a2f6bSGordon Ross 	 * (four bytes)
156613a2f6bSGordon Ross 	 */
157613a2f6bSGordon Ross 	if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
158613a2f6bSGordon Ross 		DPRINT("pollin err %d", err);
159613a2f6bSGordon Ross 		return (err);
160613a2f6bSGordon Ross 	}
161613a2f6bSGordon Ross 	moreflag = 0;
162613a2f6bSGordon Ross 	cnt = t_rcv(fd, &hdrbuf, sizeof (hdrbuf), &moreflag);
163613a2f6bSGordon Ross 	if (cnt < 0) {
164613a2f6bSGordon Ross 		err = get_xti_err(fd);
165613a2f6bSGordon Ross 		DPRINT("t_errno %d err %d", t_errno, err);
166613a2f6bSGordon Ross 		return (err);
167613a2f6bSGordon Ross 	}
168613a2f6bSGordon Ross 
169613a2f6bSGordon Ross 	if (cnt != sizeof (hdrbuf)) {
170613a2f6bSGordon Ross 		DPRINT("hdr cnt %d", cnt);
171613a2f6bSGordon Ross 		return (EPROTO);
172613a2f6bSGordon Ross 	}
173613a2f6bSGordon Ross 
174613a2f6bSGordon Ross 	/*
175613a2f6bSGordon Ross 	 * Decode the header, get the length.
176613a2f6bSGordon Ross 	 */
177613a2f6bSGordon Ross 	hdr = ntohl(hdrbuf);
178613a2f6bSGordon Ross 	*mtype = (hdr >> 24) & 0xff;
179613a2f6bSGordon Ross 	*mlen = hdr & 0xffffff;
180613a2f6bSGordon Ross 
181613a2f6bSGordon Ross 	if (mlen == 0)
182613a2f6bSGordon Ross 		return (0);
183613a2f6bSGordon Ross 
184613a2f6bSGordon Ross 	/*
185613a2f6bSGordon Ross 	 * Get a message buffer, read the payload
186613a2f6bSGordon Ross 	 */
18702d09e03SGordon Ross 	if ((err = mb_init_sz(mb, *mlen)) != 0)
188613a2f6bSGordon Ross 		return (err);
189613a2f6bSGordon Ross 	buf = mb->mb_top->m_data;
190613a2f6bSGordon Ross 	len = *mlen;
191613a2f6bSGordon Ross 	while (len > 0) {
192613a2f6bSGordon Ross 		if (!moreflag) {
193613a2f6bSGordon Ross 			if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
194613a2f6bSGordon Ross 				DPRINT("pollin err %d", err);
195613a2f6bSGordon Ross 				return (err);
196613a2f6bSGordon Ross 			}
197613a2f6bSGordon Ross 		}
198613a2f6bSGordon Ross 
199613a2f6bSGordon Ross 		moreflag = 0;
200613a2f6bSGordon Ross 		cnt = t_rcv(fd, buf, len, &moreflag);
201613a2f6bSGordon Ross 		if (cnt < 0) {
202613a2f6bSGordon Ross 			err = get_xti_err(fd);
203613a2f6bSGordon Ross 			DPRINT("t_errno %d err %d", t_errno, err);
204613a2f6bSGordon Ross 			return (err);
205613a2f6bSGordon Ross 		}
206613a2f6bSGordon Ross 		buf += cnt;
207613a2f6bSGordon Ross 		len -= cnt;
208613a2f6bSGordon Ross 	}
209613a2f6bSGordon Ross 	mb->mb_top->m_len = *mlen;
210613a2f6bSGordon Ross 	mb->mb_count = *mlen;
211613a2f6bSGordon Ross 
212613a2f6bSGordon Ross 	return (0);
213613a2f6bSGordon Ross }
214613a2f6bSGordon Ross 
215613a2f6bSGordon Ross int
get_xti_err(int fd)216613a2f6bSGordon Ross get_xti_err(int fd)
217613a2f6bSGordon Ross {
218613a2f6bSGordon Ross 	int look;
219613a2f6bSGordon Ross 	if (t_errno == TSYSERR)
220613a2f6bSGordon Ross 		return (errno);
221613a2f6bSGordon Ross 
222613a2f6bSGordon Ross 	if (t_errno == TLOOK) {
223613a2f6bSGordon Ross 		look = t_look(fd);
224613a2f6bSGordon Ross 		switch (look) {
225613a2f6bSGordon Ross 		case T_DISCONNECT:
226613a2f6bSGordon Ross 			(void) t_rcvdis(fd, NULL);
227613a2f6bSGordon Ross 			(void) t_snddis(fd, NULL);
228613a2f6bSGordon Ross 			return (ECONNRESET);
229613a2f6bSGordon Ross 		case T_ORDREL:
230613a2f6bSGordon Ross 			/* Received orderly release indication */
231613a2f6bSGordon Ross 			(void) t_rcvrel(fd);
232613a2f6bSGordon Ross 			/* Send orderly release indicator */
233613a2f6bSGordon Ross 			(void) t_sndrel(fd);
234613a2f6bSGordon Ross 			return (ECONNRESET);
235613a2f6bSGordon Ross 		}
236613a2f6bSGordon Ross 	}
237613a2f6bSGordon Ross 	return (EPROTO);
238613a2f6bSGordon Ross }
239613a2f6bSGordon Ross 
240613a2f6bSGordon Ross /*
241613a2f6bSGordon Ross  * Wait for data we can receive.
242613a2f6bSGordon Ross  * Timeout is mSec., as for poll(2)
243613a2f6bSGordon Ross  */
244613a2f6bSGordon Ross static int
nb_ssn_pollin(struct smb_ctx * ctx,int tmo)245613a2f6bSGordon Ross nb_ssn_pollin(struct smb_ctx *ctx, int tmo)
246613a2f6bSGordon Ross {
247613a2f6bSGordon Ross 	struct pollfd pfd[1];
248613a2f6bSGordon Ross 	int cnt, err;
249613a2f6bSGordon Ross 
250613a2f6bSGordon Ross 	pfd[0].fd = ctx->ct_tran_fd;
251613a2f6bSGordon Ross 	pfd[0].events = POLLIN | POLLPRI;
252613a2f6bSGordon Ross 	pfd[0].revents = 0;
253613a2f6bSGordon Ross 	cnt = poll(pfd, 1, tmo);
254613a2f6bSGordon Ross 	switch (cnt) {
255613a2f6bSGordon Ross 	case 0:
256613a2f6bSGordon Ross 		err = ETIME;
257613a2f6bSGordon Ross 		break;
258613a2f6bSGordon Ross 	case -1:
259613a2f6bSGordon Ross 		err = errno;
260613a2f6bSGordon Ross 		break;
261613a2f6bSGordon Ross 	default:
262613a2f6bSGordon Ross 		err = 0;
263613a2f6bSGordon Ross 		break;
264613a2f6bSGordon Ross 	}
265613a2f6bSGordon Ross 	return (err);
266613a2f6bSGordon Ross }
267613a2f6bSGordon Ross 
268613a2f6bSGordon Ross /*
269613a2f6bSGordon Ross  * Send a NetBIOS session request and
270613a2f6bSGordon Ross  * wait for the response.
271613a2f6bSGordon Ross  */
272613a2f6bSGordon Ross int
nb_ssn_request(struct smb_ctx * ctx,char * srvname)273613a2f6bSGordon Ross nb_ssn_request(struct smb_ctx *ctx, char *srvname)
274613a2f6bSGordon Ross {
275613a2f6bSGordon Ross 	struct mbdata req, res;
276613a2f6bSGordon Ross 	struct nb_name lcl, srv;
277613a2f6bSGordon Ross 	int err, mtype, mlen;
278613a2f6bSGordon Ross 	char *ucwks;
279613a2f6bSGordon Ross 
280613a2f6bSGordon Ross 	bzero(&req, sizeof (req));
281613a2f6bSGordon Ross 	bzero(&res, sizeof (res));
282613a2f6bSGordon Ross 
28302d09e03SGordon Ross 	if ((err = mb_init(&req)) != 0)
284613a2f6bSGordon Ross 		goto errout;
285613a2f6bSGordon Ross 
286613a2f6bSGordon Ross 	ucwks = utf8_str_toupper(ctx->ct_locname);
287613a2f6bSGordon Ross 	if (ucwks == NULL) {
288613a2f6bSGordon Ross 		err = ENOMEM;
289613a2f6bSGordon Ross 		goto errout;
290613a2f6bSGordon Ross 	}
291613a2f6bSGordon Ross 
292613a2f6bSGordon Ross 	/* Local NB name. */
293613a2f6bSGordon Ross 	snprintf(lcl.nn_name, NB_NAMELEN, "%-15.15s", ucwks);
294613a2f6bSGordon Ross 	lcl.nn_type = NBT_WKSTA;
295613a2f6bSGordon Ross 	lcl.nn_scope = ctx->ct_nb->nb_scope;
296613a2f6bSGordon Ross 
297613a2f6bSGordon Ross 	/* Server NB name */
298613a2f6bSGordon Ross 	snprintf(srv.nn_name, NB_NAMELEN, "%-15.15s", srvname);
299613a2f6bSGordon Ross 	srv.nn_type = NBT_SERVER;
300613a2f6bSGordon Ross 	srv.nn_scope = ctx->ct_nb->nb_scope;
301613a2f6bSGordon Ross 
302613a2f6bSGordon Ross 	/*
303613a2f6bSGordon Ross 	 * Build the request.  Header is prepended later.
304613a2f6bSGordon Ross 	 */
305613a2f6bSGordon Ross 	if ((err = nb_name_encode(&req, &srv)) != 0)
306613a2f6bSGordon Ross 		goto errout;
307613a2f6bSGordon Ross 	if ((err = nb_name_encode(&req, &lcl)) != 0)
308613a2f6bSGordon Ross 		goto errout;
309613a2f6bSGordon Ross 
310613a2f6bSGordon Ross 	/*
311613a2f6bSGordon Ross 	 * Send it, wait for the reply.
312613a2f6bSGordon Ross 	 */
313613a2f6bSGordon Ross 	err = nb_ssn_send(ctx, &req, NB_SSN_REQUEST, req.mb_count);
314613a2f6bSGordon Ross 	if (err) {
315613a2f6bSGordon Ross 		DPRINT("send, err %d", err);
316613a2f6bSGordon Ross 		goto errout;
317613a2f6bSGordon Ross 	}
318613a2f6bSGordon Ross 	err = nb_ssn_recv(ctx, &res, &mtype, &mlen);
319613a2f6bSGordon Ross 	if (err) {
320613a2f6bSGordon Ross 		DPRINT("recv, err %d", err);
321613a2f6bSGordon Ross 		goto errout;
322613a2f6bSGordon Ross 	}
323613a2f6bSGordon Ross 
324613a2f6bSGordon Ross 	if (mtype != NB_SSN_POSRESP) {
325613a2f6bSGordon Ross 		DPRINT("recv, mtype 0x%x", mtype);
326613a2f6bSGordon Ross 		err = ECONNREFUSED;
327613a2f6bSGordon Ross 		goto errout;
328613a2f6bSGordon Ross 	}
329613a2f6bSGordon Ross 
330613a2f6bSGordon Ross 	return (0);
331613a2f6bSGordon Ross 
332613a2f6bSGordon Ross errout:
333613a2f6bSGordon Ross 	mb_done(&res);
334613a2f6bSGordon Ross 	mb_done(&req);
335613a2f6bSGordon Ross 	return (err);
336613a2f6bSGordon Ross }
337