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
smb_ssn_send(struct smb_ctx * ctx,struct mbdata * mbp)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
nb_ssn_send(struct smb_ctx * ctx,struct mbdata * mbp,int mtype,int mlen)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
smb_ssn_recv(struct smb_ctx * ctx,struct mbdata * mbp)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
nb_ssn_recv(struct smb_ctx * ctx,struct mbdata * mb,int * mtype,int * mlen)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
get_xti_err(int fd)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
nb_ssn_pollin(struct smb_ctx * ctx,int tmo)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
nb_ssn_request(struct smb_ctx * ctx,char * srvname)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