xref: /titanic_50/usr/src/lib/libsmbfs/smb/nb_ssn.c (revision a9cb953c2b4375a6f08dd835c3394fe354138e94)
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 /*
23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * NetBIOS session service functions
28  */
29 
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <libintl.h>
36 #include <xti.h>
37 #include <assert.h>
38 
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/poll.h>
42 
43 #include <netsmb/netbios.h>
44 #include <netsmb/smb_lib.h>
45 #include <netsmb/nb_lib.h>
46 #include <netsmb/mchain.h>
47 
48 #include "private.h"
49 #include "charsets.h"
50 
51 static int nb_ssn_send(struct smb_ctx *, struct mbdata *, int, int);
52 static int nb_ssn_recv(struct smb_ctx *, struct mbdata *, int *, int *);
53 static int nb_ssn_pollin(struct smb_ctx *, int);
54 
55 /*
56  * Send a data message.
57  */
58 int
59 smb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp)
60 {
61 	return (nb_ssn_send(ctx, mbp, 0, mbp->mb_count));
62 }
63 
64 /*
65  * Send a NetBIOS message, after
66  * prepending the 4-byte header.
67  */
68 static int
69 nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp,
70 	    int mtype, int mlen)
71 {
72 	mbuf_t *m;
73 	uint32_t hdr, hdrbuf;
74 	int err;
75 
76 	m = mbp->mb_top;
77 	if (m == NULL)
78 		return (EINVAL);
79 
80 	/*
81 	 * Prepend the NetBIOS header.
82 	 * Our mbufs leave space for this.
83 	 */
84 	hdr = (mtype << 24) | mlen;
85 	hdrbuf = htonl(hdr);
86 	m->m_data -= 4;
87 	m->m_len  += 4;
88 	bcopy(&hdrbuf, m->m_data, 4);
89 
90 	/*
91 	 * Get contiguous data (so TCP won't fragment)
92 	 * Note: replaces mb_top.
93 	 */
94 	err = m_lineup(mbp->mb_top, &mbp->mb_top);
95 	if (err)
96 		return (err);
97 	m = mbp->mb_top;
98 
99 	/*
100 	 * Send it.
101 	 */
102 	if (t_snd(ctx->ct_tran_fd, m->m_data, m->m_len, 0) < 0) {
103 		if (t_errno == TSYSERR)
104 			err = errno;
105 		else
106 			err = EPROTO;
107 		DPRINT("t_snd: t_errno %d, err %d", t_errno, err);
108 		return (err);
109 	}
110 
111 	return (0);
112 }
113 
114 /*
115  * Receive a data message.  Discard anything else.
116  * Caller must deal with EAGAIN, EINTR.
117  */
118 int
119 smb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mbp)
120 {
121 	int err, mtype, mlen;
122 	err = nb_ssn_recv(ctx, mbp, &mtype, &mlen);
123 	if (err)
124 		return (err);
125 	if (mtype != NB_SSN_MESSAGE) {
126 		DPRINT("discard type 0x%x", mtype);
127 		mb_done(mbp);
128 		return (EAGAIN);
129 	}
130 	if (mlen == 0) {
131 		DPRINT("zero length");
132 		mb_done(mbp);
133 		return (EAGAIN);
134 	}
135 
136 	return (0);
137 }
138 
139 /*
140  * Receive a NetBIOS message, any type.
141  * Give caller type and length.
142  */
143 static int
144 nb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mb,
145 	    int *mtype, int *mlen)
146 {
147 	char *buf;
148 	uint32_t hdr, hdrbuf;
149 	int cnt, len, err, moreflag;
150 	int fd = ctx->ct_tran_fd;
151 	int tmo = smb_recv_timeout * 1000;
152 
153 	/*
154 	 * Start by getting the header
155 	 * (four bytes)
156 	 */
157 	if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
158 		DPRINT("pollin err %d", err);
159 		return (err);
160 	}
161 	moreflag = 0;
162 	cnt = t_rcv(fd, &hdrbuf, sizeof (hdrbuf), &moreflag);
163 	if (cnt < 0) {
164 		err = get_xti_err(fd);
165 		DPRINT("t_errno %d err %d", t_errno, err);
166 		return (err);
167 	}
168 
169 	if (cnt != sizeof (hdrbuf)) {
170 		DPRINT("hdr cnt %d", cnt);
171 		return (EPROTO);
172 	}
173 
174 	/*
175 	 * Decode the header, get the length.
176 	 */
177 	hdr = ntohl(hdrbuf);
178 	*mtype = (hdr >> 24) & 0xff;
179 	*mlen = hdr & 0xffffff;
180 
181 	if (mlen == 0)
182 		return (0);
183 
184 	/*
185 	 * Get a message buffer, read the payload
186 	 */
187 	if ((err = mb_init_sz(mb, *mlen)) != 0)
188 		return (err);
189 	buf = mb->mb_top->m_data;
190 	len = *mlen;
191 	while (len > 0) {
192 		if (!moreflag) {
193 			if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
194 				DPRINT("pollin err %d", err);
195 				return (err);
196 			}
197 		}
198 
199 		moreflag = 0;
200 		cnt = t_rcv(fd, buf, len, &moreflag);
201 		if (cnt < 0) {
202 			err = get_xti_err(fd);
203 			DPRINT("t_errno %d err %d", t_errno, err);
204 			return (err);
205 		}
206 		buf += cnt;
207 		len -= cnt;
208 	}
209 	mb->mb_top->m_len = *mlen;
210 	mb->mb_count = *mlen;
211 
212 	return (0);
213 }
214 
215 int
216 get_xti_err(int fd)
217 {
218 	int look;
219 	if (t_errno == TSYSERR)
220 		return (errno);
221 
222 	if (t_errno == TLOOK) {
223 		look = t_look(fd);
224 		switch (look) {
225 		case T_DISCONNECT:
226 			(void) t_rcvdis(fd, NULL);
227 			(void) t_snddis(fd, NULL);
228 			return (ECONNRESET);
229 		case T_ORDREL:
230 			/* Received orderly release indication */
231 			(void) t_rcvrel(fd);
232 			/* Send orderly release indicator */
233 			(void) t_sndrel(fd);
234 			return (ECONNRESET);
235 		}
236 	}
237 	return (EPROTO);
238 }
239 
240 /*
241  * Wait for data we can receive.
242  * Timeout is mSec., as for poll(2)
243  */
244 static int
245 nb_ssn_pollin(struct smb_ctx *ctx, int tmo)
246 {
247 	struct pollfd pfd[1];
248 	int cnt, err;
249 
250 	pfd[0].fd = ctx->ct_tran_fd;
251 	pfd[0].events = POLLIN | POLLPRI;
252 	pfd[0].revents = 0;
253 	cnt = poll(pfd, 1, tmo);
254 	switch (cnt) {
255 	case 0:
256 		err = ETIME;
257 		break;
258 	case -1:
259 		err = errno;
260 		break;
261 	default:
262 		err = 0;
263 		break;
264 	}
265 	return (err);
266 }
267 
268 /*
269  * Send a NetBIOS session request and
270  * wait for the response.
271  */
272 int
273 nb_ssn_request(struct smb_ctx *ctx, char *srvname)
274 {
275 	struct mbdata req, res;
276 	struct nb_name lcl, srv;
277 	int err, mtype, mlen;
278 	char *ucwks;
279 
280 	bzero(&req, sizeof (req));
281 	bzero(&res, sizeof (res));
282 
283 	if ((err = mb_init(&req)) != 0)
284 		goto errout;
285 
286 	ucwks = utf8_str_toupper(ctx->ct_locname);
287 	if (ucwks == NULL) {
288 		err = ENOMEM;
289 		goto errout;
290 	}
291 
292 	/* Local NB name. */
293 	snprintf(lcl.nn_name, NB_NAMELEN, "%-15.15s", ucwks);
294 	lcl.nn_type = NBT_WKSTA;
295 	lcl.nn_scope = ctx->ct_nb->nb_scope;
296 
297 	/* Server NB name */
298 	snprintf(srv.nn_name, NB_NAMELEN, "%-15.15s", srvname);
299 	srv.nn_type = NBT_SERVER;
300 	srv.nn_scope = ctx->ct_nb->nb_scope;
301 
302 	/*
303 	 * Build the request.  Header is prepended later.
304 	 */
305 	if ((err = nb_name_encode(&req, &srv)) != 0)
306 		goto errout;
307 	if ((err = nb_name_encode(&req, &lcl)) != 0)
308 		goto errout;
309 
310 	/*
311 	 * Send it, wait for the reply.
312 	 */
313 	err = nb_ssn_send(ctx, &req, NB_SSN_REQUEST, req.mb_count);
314 	if (err) {
315 		DPRINT("send, err %d", err);
316 		goto errout;
317 	}
318 	err = nb_ssn_recv(ctx, &res, &mtype, &mlen);
319 	if (err) {
320 		DPRINT("recv, err %d", err);
321 		goto errout;
322 	}
323 
324 	if (mtype != NB_SSN_POSRESP) {
325 		DPRINT("recv, mtype 0x%x", mtype);
326 		err = ECONNREFUSED;
327 		goto errout;
328 	}
329 
330 	return (0);
331 
332 errout:
333 	mb_done(&res);
334 	mb_done(&req);
335 	return (err);
336 }
337