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