2 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
3 * Copyright (c) 2000, Boris Popov
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Boris Popov.
17 * 4. Neither the name of the author nor the names of any co-contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * $Id: rq.c,v 1.4 2004/12/13 00:25:23 lindak Exp $
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/ioctl.h>
39 #include <sys/errno.h>
51 #include <netsmb/smb.h>
52 #include <netsmb/smb_lib.h>
55 #define MIN_REPLY_SIZE 4096
57 static uint32_t smb_map_doserr(uint8_t, uint16_t);
60 * Create and initialize a request structure, for either an
61 * "internal" request (one that does not use the driver) or
62 * a regular "driver" request, that uses driver ioctls.
64 * The two kinds are built a little differently:
65 * Driver requests are composed starting with the
66 * first word of the "variable word vector" section.
67 * The driver prepends the SMB header and word count.
68 * The driver also needs an output buffer to receive
69 * the response, filled in via copyout in the ioctl.
71 * Internal requests are composed entirely in this library.
72 * Space for the SMB header is reserved here, and later
73 * filled in by smb_rq_internal before the send/receive.
76 smb_rq_init(struct smb_ctx
*ctx
, uchar_t cmd
, struct smb_rq
**rqpp
)
80 rqp
= malloc(sizeof (*rqp
));
83 bzero(rqp
, sizeof (*rqp
));
88 * Setup the request buffer.
89 * Do the reply buffer later.
91 if (mb_init(&rqp
->rq_rq
))
94 /* Space for the SMB header. (filled in later) */
95 mb_put_mem(&rqp
->rq_rq
, NULL
, SMB_HDRLEN
, MB_MSYSTEM
);
98 * Copy the ctx flags here, so the caller can
99 * update the req flags before the OTW call.
101 rqp
->rq_hflags
= ctx
->ct_hflags
;
102 rqp
->rq_hflags2
= ctx
->ct_hflags2
;
116 smb_rq_done(struct smb_rq
*rqp
)
118 mb_done(&rqp
->rq_rp
);
119 mb_done(&rqp
->rq_rq
);
124 * Reserve space for the word count, which is filled in later by
125 * smb_rq_wend(). Also initialize the counter that it uses
126 * to figure out what value to fill in.
128 * Note that the word count happens to be 8-bits,
129 * which can lead to confusion.
132 smb_rq_wstart(struct smb_rq
*rqp
)
134 struct mbdata
*mbp
= &rqp
->rq_rq
;
136 (void) mb_fit(mbp
, 1, &rqp
->rq_wcntp
);
137 rqp
->rq_wcbase
= mbp
->mb_count
;
141 * Fill in the word count, in the space reserved by
145 smb_rq_wend(struct smb_rq
*rqp
)
147 struct mbdata
*mbp
= &rqp
->rq_rq
;
150 if (rqp
->rq_wcntp
== NULL
) {
151 DPRINT("no wcount ptr\n");
154 wcnt
= mbp
->mb_count
- rqp
->rq_wcbase
;
156 DPRINT("word count too large (%d)\n", wcnt
);
158 DPRINT("odd word count\n");
162 * Fill in the word count (8-bits).
163 * Also store it in the rq, in case
164 * we're using the ioctl path.
166 *rqp
->rq_wcntp
= (char)wcnt
;
170 * Reserve space for the byte count, which is filled in later by
171 * smb_rq_bend(). Also initialize the counter that it uses
172 * to figure out what value to fill in.
174 * Note that the byte count happens to be 16-bits,
175 * which can lead to confusion.
178 smb_rq_bstart(struct smb_rq
*rqp
)
180 struct mbdata
*mbp
= &rqp
->rq_rq
;
182 (void) mb_fit(mbp
, 2, &rqp
->rq_bcntp
);
183 rqp
->rq_bcbase
= mbp
->mb_count
;
187 * Fill in the byte count, in the space reserved by
191 smb_rq_bend(struct smb_rq
*rqp
)
193 struct mbdata
*mbp
= &rqp
->rq_rq
;
196 if (rqp
->rq_bcntp
== NULL
) {
197 DPRINT("no bcount ptr\n");
200 bcnt
= mbp
->mb_count
- rqp
->rq_bcbase
;
202 DPRINT("byte count too large (%d)\n", bcnt
);
204 * Fill in the byte count (16-bits).
205 * Also store it in the rq, in case
206 * we're using the ioctl path.
208 * The pointer is char * type due to
209 * typical off-by-one alignment.
211 rqp
->rq_bcntp
[0] = bcnt
& 0xFF;
212 rqp
->rq_bcntp
[1] = (bcnt
>> 8);
216 smb_rq_simple(struct smb_rq
*rqp
)
218 struct smbioc_rq krq
;
226 bzero(&krq
, sizeof (krq
));
227 krq
.ioc_cmd
= rqp
->rq_cmd
;
230 * Make the SMB request body contiguous,
231 * and fill in the ioctl request.
233 mbp
= smb_rq_getrequest(rqp
);
234 error
= m_lineup(mbp
->mb_top
, &mbp
->mb_top
);
238 data
= mtod(mbp
->mb_top
, char *);
239 len
= m_totlen(mbp
->mb_top
);
242 * _rq_init left space for the SMB header,
243 * which makes mb_count the offset from
244 * the beginning of the header (useful).
245 * However, in this code path the driver
246 * prepends the header, so we skip it.
248 krq
.ioc_tbufsz
= len
- SMB_HDRLEN
;
249 krq
.ioc_tbuf
= data
+ SMB_HDRLEN
;
252 * Setup a buffer to hold the reply,
253 * at least MIN_REPLY_SIZE, or larger
254 * if the caller increased rq_rpbufsz.
256 mbp
= smb_rq_getreply(rqp
);
257 rpbufsz
= rqp
->rq_rpbufsz
;
258 if (rpbufsz
< MIN_REPLY_SIZE
)
259 rpbufsz
= MIN_REPLY_SIZE
;
260 if ((error
= m_get(rpbufsz
, &m
)) != 0)
263 krq
.ioc_rbufsz
= rpbufsz
;
264 krq
.ioc_rbuf
= mtod(m
, char *);
269 if (ioctl(rqp
->rq_ctx
->ct_dev_fd
, SMBIOC_REQUEST
, &krq
) == -1)
273 * Initialize returned mbdata.
274 * SMB header already parsed.
276 m
->m_len
= krq
.ioc_rbufsz
;
283 smb_t2_request(int dev_fd
, int setupcount
, uint16_t *setup
,
285 int tparamcnt
, void *tparam
,
286 int tdatacnt
, void *tdata
,
287 int *rparamcnt
, void *rparam
,
288 int *rdatacnt
, void *rdata
,
294 krq
= (smbioc_t2rq_t
*)malloc(sizeof (smbioc_t2rq_t
));
295 bzero(krq
, sizeof (*krq
));
297 if (setupcount
< 0 || setupcount
>= SMBIOC_T2RQ_MAXSETUP
) {
298 /* Bogus setup count, or too many setup words */
301 for (i
= 0; i
< setupcount
; i
++)
302 krq
->ioc_setup
[i
] = setup
[i
];
303 krq
->ioc_setupcnt
= setupcount
;
304 strcpy(krq
->ioc_name
, name
);
305 krq
->ioc_tparamcnt
= tparamcnt
;
306 krq
->ioc_tparam
= tparam
;
307 krq
->ioc_tdatacnt
= tdatacnt
;
308 krq
->ioc_tdata
= tdata
;
310 krq
->ioc_rparamcnt
= *rparamcnt
;
311 krq
->ioc_rdatacnt
= *rdatacnt
;
312 krq
->ioc_rparam
= rparam
;
313 krq
->ioc_rdata
= rdata
;
315 if (ioctl(dev_fd
, SMBIOC_T2RQ
, krq
) == -1) {
319 *rparamcnt
= krq
->ioc_rparamcnt
;
320 *rdatacnt
= krq
->ioc_rdatacnt
;
321 *buffer_oflow
= (krq
->ioc_rpflags2
& SMB_FLAGS2_ERR_STATUS
) &&
322 (krq
->ioc_error
== NT_STATUS_BUFFER_OVERFLOW
);
330 * Do an over-the-wire call without using the nsmb driver.
331 * This is all "internal" to this library, and used only
332 * for connection setup (negotiate protocol, etc.)
335 smb_rq_internal(struct smb_ctx
*ctx
, struct smb_rq
*rqp
)
337 static const uint8_t ffsmb
[4] = SMB_SIGNATURE
;
338 struct smb_iods
*is
= &ctx
->ct_iods
;
340 struct mbdata mbtmp
, *mbp
;
344 rqp
->rq_uid
= is
->is_smbuid
;
345 rqp
->rq_tid
= SMB_TID_UNKNOWN
;
346 rqp
->rq_mid
= is
->is_next_mid
++;
349 * Fill in the NBT and SMB headers
350 * Using mbtmp so we can rewind without
351 * affecting the passed request mbdata.
353 bcopy(&rqp
->rq_rq
, &mbtmp
, sizeof (mbtmp
));
355 mbp
->mb_cur
= mbp
->mb_top
;
356 mbp
->mb_pos
= mbp
->mb_cur
->m_data
;
358 /* Have to save and restore m_len */
359 save_mlen
= mbp
->mb_cur
->m_len
;
360 mbp
->mb_cur
->m_len
= 0;
363 * rewind done; fill it in
365 mb_put_mem(mbp
, ffsmb
, SMB_SIGLEN
, MB_MSYSTEM
);
366 mb_put_uint8(mbp
, rqp
->rq_cmd
);
367 mb_put_uint32le(mbp
, 0); /* status */
368 mb_put_uint8(mbp
, rqp
->rq_hflags
);
369 mb_put_uint16le(mbp
, rqp
->rq_hflags2
);
370 /* pid_hi(2), signature(8), reserved(2) */
371 mb_put_mem(mbp
, NULL
, 12, MB_MZERO
);
372 mb_put_uint16le(mbp
, rqp
->rq_tid
);
373 mb_put_uint16le(mbp
, 0); /* pid_lo */
374 mb_put_uint16le(mbp
, rqp
->rq_uid
);
375 mb_put_uint16le(mbp
, rqp
->rq_mid
);
377 /* Restore original m_len */
378 mbp
->mb_cur
->m_len
= save_mlen
;
381 * Sign the message, if flags2 indicates.
383 if (rqp
->rq_hflags2
& SMB_FLAGS2_SECURITY_SIGNATURE
) {
388 * Send it, wait for the reply.
390 if ((err
= smb_ssn_send(ctx
, &rqp
->rq_rq
)) != 0)
393 if ((err
= smb_ssn_recv(ctx
, &rqp
->rq_rp
)) != 0)
397 * Should have an SMB header, at least.
400 if (mbp
->mb_cur
->m_len
< SMB_HDRLEN
) {
406 * If the request was signed, validate the
407 * signature on the response.
409 if (rqp
->rq_hflags2
& SMB_FLAGS2_SECURITY_SIGNATURE
) {
410 err
= smb_rq_verify(rqp
);
412 DPRINT("bad signature");
418 * Decode the SMB header.
420 md_get_mem(mbp
, (char *)sigbuf
, 4, MB_MSYSTEM
);
421 if (0 != bcmp(sigbuf
, ffsmb
, 4)) {
425 md_get_uint8(mbp
, &ctmp
); /* SMB cmd */
426 md_get_uint32le(mbp
, &rqp
->rq_status
);
427 md_get_uint8(mbp
, &rqp
->rq_hflags
);
428 md_get_uint16le(mbp
, &rqp
->rq_hflags2
);
429 /* pid_hi(2), signature(8), reserved(2) */
430 md_get_mem(mbp
, NULL
, 12, MB_MSYSTEM
);
431 md_get_uint16le(mbp
, &rqp
->rq_tid
);
432 md_get_uint16le(mbp
, NULL
); /* pid_lo */
433 md_get_uint16le(mbp
, &rqp
->rq_uid
);
434 md_get_uint16le(mbp
, &rqp
->rq_mid
);
437 * Figure out the status return.
438 * Caller looks at rq_status.
440 if ((rqp
->rq_hflags2
& SMB_FLAGS2_ERR_STATUS
) == 0) {
444 class = rqp
->rq_status
& 0xff;
445 serr
= rqp
->rq_status
>> 16;
446 rqp
->rq_status
= smb_map_doserr(class, serr
);
453 * Map old DOS errors (etc.) to NT status codes.
454 * We probably don't need this anymore, since
455 * the oldest server we talk to is NT. But if
456 * later find we do need this, add support here
457 * for the DOS errors we care about.
460 smb_map_doserr(uint8_t class, uint16_t serr
)
462 if (class == 0 && serr
== 0)
465 DPRINT("class 0x%x serr 0x%x", (int)class, (int)serr
);
466 return (NT_STATUS_UNSUCCESSFUL
);