ses: SUN plugin doesn't actually need libnvfru
[unleashed.git] / usr / src / lib / libsmbfs / smb / rq.c
blobc4e929eff971b307886487ac0182452b579125c5
1 /*
2 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
3 * Copyright (c) 2000, Boris Popov
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
31 * SUCH DAMAGE.
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>
40 #include <sys/stat.h>
42 #include <ctype.h>
43 #include <errno.h>
44 #include <stdio.h>
45 #include <unistd.h>
46 #include <strings.h>
47 #include <stdlib.h>
48 #include <sysexits.h>
49 #include <libintl.h>
51 #include <netsmb/smb.h>
52 #include <netsmb/smb_lib.h>
53 #include "private.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.
75 int
76 smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, struct smb_rq **rqpp)
78 struct smb_rq *rqp;
80 rqp = malloc(sizeof (*rqp));
81 if (rqp == NULL)
82 goto errout;
83 bzero(rqp, sizeof (*rqp));
84 rqp->rq_cmd = cmd;
85 rqp->rq_ctx = ctx;
88 * Setup the request buffer.
89 * Do the reply buffer later.
91 if (mb_init(&rqp->rq_rq))
92 goto errout;
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;
104 *rqpp = rqp;
105 return (0);
107 errout:
108 if (rqp) {
109 smb_rq_done(rqp);
110 free(rqp);
112 return (ENOMEM);
115 void
116 smb_rq_done(struct smb_rq *rqp)
118 mb_done(&rqp->rq_rp);
119 mb_done(&rqp->rq_rq);
120 free(rqp);
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.
131 void
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
142 * smb_rq_wstart().
144 void
145 smb_rq_wend(struct smb_rq *rqp)
147 struct mbdata *mbp = &rqp->rq_rq;
148 int wcnt;
150 if (rqp->rq_wcntp == NULL) {
151 DPRINT("no wcount ptr\n");
152 return;
154 wcnt = mbp->mb_count - rqp->rq_wcbase;
155 if (wcnt > 0x1ff)
156 DPRINT("word count too large (%d)\n", wcnt);
157 if (wcnt & 1)
158 DPRINT("odd word count\n");
159 wcnt >>= 1;
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.
177 void
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
188 * smb_rq_bstart().
190 void
191 smb_rq_bend(struct smb_rq *rqp)
193 struct mbdata *mbp = &rqp->rq_rq;
194 int bcnt;
196 if (rqp->rq_bcntp == NULL) {
197 DPRINT("no bcount ptr\n");
198 return;
200 bcnt = mbp->mb_count - rqp->rq_bcbase;
201 if (bcnt > 0xffff)
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;
219 struct mbdata *mbp;
220 mbuf_t *m;
221 char *data;
222 uint32_t len;
223 size_t rpbufsz;
224 int error;
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);
235 if (error)
236 return (error);
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)
261 return (error);
262 mb_initm(mbp, m);
263 krq.ioc_rbufsz = rpbufsz;
264 krq.ioc_rbuf = mtod(m, char *);
267 * Call the driver
269 if (ioctl(rqp->rq_ctx->ct_dev_fd, SMBIOC_REQUEST, &krq) == -1)
270 return (errno);
273 * Initialize returned mbdata.
274 * SMB header already parsed.
276 m->m_len = krq.ioc_rbufsz;
278 return (0);
283 smb_t2_request(int dev_fd, int setupcount, uint16_t *setup,
284 const char *name,
285 int tparamcnt, void *tparam,
286 int tdatacnt, void *tdata,
287 int *rparamcnt, void *rparam,
288 int *rdatacnt, void *rdata,
289 int *buffer_oflow)
291 smbioc_t2rq_t *krq;
292 int i;
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 */
299 return (EINVAL);
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) {
316 return (errno);
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);
323 free(krq);
325 return (0);
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;
339 uint32_t sigbuf[2];
340 struct mbdata mbtmp, *mbp;
341 int err, save_mlen;
342 uint8_t ctmp;
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));
354 mbp = &mbtmp;
355 mbp->mb_cur = mbp->mb_top;
356 mbp->mb_pos = mbp->mb_cur->m_data;
357 mbp->mb_count = 0;
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) {
384 smb_rq_sign(rqp);
388 * Send it, wait for the reply.
390 if ((err = smb_ssn_send(ctx, &rqp->rq_rq)) != 0)
391 return (err);
393 if ((err = smb_ssn_recv(ctx, &rqp->rq_rp)) != 0)
394 return (err);
397 * Should have an SMB header, at least.
399 mbp = &rqp->rq_rp;
400 if (mbp->mb_cur->m_len < SMB_HDRLEN) {
401 DPRINT("len < 32");
402 return (EBADRPC);
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);
411 if (err) {
412 DPRINT("bad signature");
413 return (err);
418 * Decode the SMB header.
420 md_get_mem(mbp, (char *)sigbuf, 4, MB_MSYSTEM);
421 if (0 != bcmp(sigbuf, ffsmb, 4)) {
422 DPRINT("not SMB");
423 return (EBADRPC);
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) {
441 uint16_t serr;
442 uint8_t class;
444 class = rqp->rq_status & 0xff;
445 serr = rqp->rq_status >> 16;
446 rqp->rq_status = smb_map_doserr(class, serr);
449 return (0);
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.
459 static uint32_t
460 smb_map_doserr(uint8_t class, uint16_t serr)
462 if (class == 0 && serr == 0)
463 return (0);
465 DPRINT("class 0x%x serr 0x%x", (int)class, (int)serr);
466 return (NT_STATUS_UNSUCCESSFUL);