1 /*
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $Id: smb_smb.c,v 1.35.100.2 2005/06/02 00:55:39 lindak Exp $
33 */
34
35 /*
36 * Portions Copyright (C) 2001 - 2014 Apple Inc. All rights reserved.
37 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
38 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
39 */
40
41 /*
42 * various SMB requests. Most of the routines merely packs data into mbufs.
43 */
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kmem.h>
47 #include <sys/proc.h>
48 #include <sys/lock.h>
49 #include <sys/socket.h>
50 #include <sys/uio.h>
51 #include <sys/random.h>
52 #include <sys/note.h>
53 #include <sys/errno.h>
54 #include <sys/cmn_err.h>
55
56 #include <netsmb/smb_osdep.h>
57
58 #include <netsmb/smb.h>
59 #include <netsmb/smb_conn.h>
60 #include <netsmb/smb_rq.h>
61 #include <netsmb/smb_subr.h>
62 #include <netsmb/smb_tran.h>
63
64 #define STYPE_LEN 8 /* share type strings */
65
66 struct smb_dialect {
67 int d_id;
68 const char *d_name;
69 };
70
71 static struct smb_dialect smb_dialects[3] = {
72 {SMB_DIALECT_NTLM0_12, "NT LANMAN 1.0"},
73 {SMB_DIALECT_NTLM0_12, "NT LM 0.12"},
74 #define NDIALECT_SMB1 2
75 {SMB_DIALECT_SMB2_FF, "SMB 2.???"},
76 #define NDIALECT_SMB2 3
77 };
78
79 static const uint32_t smb_clnt_caps_mask =
80 SMB_CAP_UNICODE |
81 SMB_CAP_LARGE_FILES |
82 SMB_CAP_NT_SMBS |
83 SMB_CAP_STATUS32 |
84 SMB_CAP_EXT_SECURITY;
85
86 /*
87 * Default timeout values, all in seconds.
88 * Make these tunable (only via mdb for now).
89 */
90 int smb_timo_notice = 15;
91 int smb_timo_default = 30; /* was SMB_DEFRQTIMO */
92 int smb_timo_logon = 45;
93 int smb_timo_open = 45;
94 int smb_timo_read = 45;
95 int smb_timo_write = 60; /* was SMBWRTTIMO */
96 int smb_timo_append = 90;
97
98 int
smb_smb_negotiate(struct smb_vc * vcp,struct smb_cred * scred)99 smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
100 {
101 smb_sopt_t *sv = &vcp->vc_sopt;
102 smbioc_ssn_work_t *wk = &vcp->vc_work;
103 struct smb_rq *rqp = NULL;
104 struct mbchain *mbp = NULL;
105 struct mdchain *mdp = NULL;
106 struct smb_dialect *dp;
107 int err, sblen, tlen;
108 uint8_t wc, eklen;
109 uint16_t dindex, bc;
110 uint16_t ndialects;
111 boolean_t will_sign = B_FALSE;
112
113 /*
114 * Initialize: vc_hflags and vc_hflags2.
115 * Note: vcp->vc_hflags* are copied into the
116 * (per request) rqp->rq_hflags* by smb_rq_init.
117 *
118 * Like Windows, set FLAGS2_UNICODE in our first request,
119 * even though technically we don't yet know whether the
120 * server supports Unicode. Will clear this flag below
121 * if we find out it doesn't. Need to do this because
122 * some servers reject all non-Unicode requests.
123 */
124 vcp->vc_hflags =
125 SMB_FLAGS_CASELESS |
126 SMB_FLAGS_CANONICAL_PATHNAMES;
127 vcp->vc_hflags2 =
128 SMB_FLAGS2_KNOWS_LONG_NAMES |
129 SMB_FLAGS2_KNOWS_EAS |
130 SMB_FLAGS2_IS_LONG_NAME |
131 SMB_FLAGS2_EXT_SEC |
132 SMB_FLAGS2_ERR_STATUS |
133 SMB_FLAGS2_UNICODE;
134
135 /*
136 * The initial UID needs to be zero,
137 */
138 vcp->vc_smbuid = 0;
139
140 /*
141 * (Re)init negotiated values
142 */
143 bzero(sv, sizeof (*sv));
144 sv->sv_maxmux = 1;
145 sv->sv_maxvcs = 1;
146 sv->sv_maxtx = 1024;
147
148 /*
149 * Should we offer the magic SMB2 dialect?
150 */
151 if (vcp->vc_ssn.ssn_maxver >= SMB2_DIALECT_BASE)
152 ndialects = NDIALECT_SMB2;
153 else
154 ndialects = NDIALECT_SMB1;
155
156 err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp);
157 if (err)
158 return (err);
159
160 /*
161 * Build the SMB request.
162 */
163 smb_rq_getrequest(rqp, &mbp);
164 smb_rq_wstart(rqp);
165 smb_rq_wend(rqp);
166 smb_rq_bstart(rqp);
167 for (dindex = 0; dindex < ndialects; dindex++) {
168 dp = &smb_dialects[dindex];
169 mb_put_uint8(mbp, SMB_DT_DIALECT);
170 tlen = strlen(dp->d_name) + 1;
171 mb_put_mem(mbp, dp->d_name, tlen, MB_MSYSTEM);
172 }
173 smb_rq_bend(rqp);
174
175 /*
176 * Do the OTW call.
177 */
178 err = smb_rq_internal(rqp, smb_timo_default);
179 /*
180 * If it's an SMB1-to-SMB2 negotiate response,
181 * call the special handler and then skip the
182 * whole rest of this function.
183 */
184 if (err == EPROTO) {
185 err = smb2_parse_smb1nego_resp(rqp);
186 smb_rq_done(rqp);
187 return (err);
188 }
189 if (err) {
190 SMBSDEBUG("smb_rq_internal, err %d", err);
191 goto errout;
192 }
193 /* Should only get status success. */
194 if (rqp->sr_error != NT_STATUS_SUCCESS) {
195 err = ENOTSUP;
196 goto errout;
197 }
198
199 /*
200 * Decode the response
201 *
202 * Comments to right show names as described in
203 * The Microsoft SMB Protocol spec. [MS-SMB]
204 * section 2.2.3
205 */
206 smb_rq_getreply(rqp, &mdp);
207 (void) md_get_uint8(mdp, &wc);
208 err = md_get_uint16le(mdp, &dindex);
209 if (err != 0)
210 goto errout;
211 if (dindex >= ndialects) {
212 SMBERROR("Invalid dialect index from server: %s\n",
213 vcp->vc_srvname);
214 err = EBADRPC;
215 goto errout;
216 }
217 dp = smb_dialects + dindex;
218 sv->sv_proto = dp->d_id;
219 SMBSDEBUG("Dialect %s", dp->d_name);
220 if (dp->d_id < SMB_DIALECT_NTLM0_12) {
221 SMBSDEBUG("old dialect %s", dp->d_name);
222 goto errout;
223 }
224 if (wc != 17) {
225 SMBSDEBUG("bad wc %d", (int)wc);
226 goto errout;
227 }
228 md_get_uint8(mdp, &sv->sv_sm); /* SecurityMode */
229 md_get_uint16le(mdp, &sv->sv_maxmux); /* MaxMpxCount */
230 md_get_uint16le(mdp, &sv->sv_maxvcs); /* MaxCountVCs */
231 md_get_uint32le(mdp, &sv->sv_maxtx); /* MaxBufferSize */
232 md_get_uint32le(mdp, &sv->sv_maxraw); /* MaxRawSize */
233 md_get_uint32le(mdp, &sv->sv_skey); /* SessionKey */
234 md_get_uint32le(mdp, &sv->sv_caps); /* Capabilities */
235 md_get_mem(mdp, NULL, 8, MB_MSYSTEM); /* SystemTime(s) */
236 md_get_uint16le(mdp, (uint16_t *)&sv->sv_tz);
237 md_get_uint8(mdp, &eklen); /* EncryptionKeyLength */
238 err = md_get_uint16le(mdp, &bc); /* ByteCount */
239 if (err)
240 goto errout;
241
242 /* BEGIN CSTYLED */
243 /*
244 * Will we do SMB signing? Or block the connection?
245 * The table below describes this logic. References:
246 * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3]
247 * http://msdn.microsoft.com/en-us/library/cc212511.aspx
248 * http://msdn.microsoft.com/en-us/library/cc212929.aspx
249 *
250 * Srv/Cli | Required | Enabled | If Required | Disabled
251 * ------------+----------+------------+-------------+-----------
252 * Required | Signed | Signed | Signed | Blocked [1]
253 * ------------+----------+------------+-------------+-----------
254 * Enabled | Signed | Signed | Not Signed | Not Signed
255 * ------------+----------+------------+-------------+-----------
256 * If Required | Signed | Not Signed | Not Signed | Not Signed
257 * ------------+----------+------------+-------------+-----------
258 * Disabled | Blocked | Not Signed | Not Signed | Not Signed
259 *
260 * [1] Like Windows 2003 and later, we don't really implement
261 * the "Disabled" setting. Instead we implement "If Required",
262 * so we always sign if the server requires signing.
263 */
264 /* END CSTYLED */
265
266 if (sv->sv_sm & SMB_SM_SIGS_REQUIRE) {
267 /*
268 * Server requires signing. We will sign,
269 * even if local setting is "disabled".
270 */
271 will_sign = B_TRUE;
272 } else if (sv->sv_sm & SMB_SM_SIGS) {
273 /*
274 * Server enables signing (client's option).
275 * If enabled locally, do signing.
276 */
277 if (vcp->vc_vopt & SMBVOPT_SIGNING_ENABLED)
278 will_sign = B_TRUE;
279 /* else not signing. */
280 } else {
281 /*
282 * Server does not support signing.
283 * If we "require" it, bail now.
284 */
285 if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
286 SMBERROR("Client requires signing "
287 "but server has it disabled.");
288 err = EBADRPC;
289 goto errout;
290 }
291 }
292
293 /*
294 * Anonymous sessions can't sign.
295 */
296 if (vcp->vc_vopt & SMBVOPT_ANONYMOUS) {
297 will_sign = B_FALSE;
298 }
299
300 SMBSDEBUG("Security signatures: %d", (int)will_sign);
301 if (will_sign) {
302 vcp->vc_flags |= SMBV_SIGNING;
303 vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
304
305 /*
306 * MS-SMB 2.2.4.5 says that when SMB signing is enabled,
307 * we should NOT use "large read/write" even though the
308 * server might offer those capabilities.
309 */
310 sv->sv_caps &= ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX);
311 }
312
313 /* See comment above re. FLAGS2_UNICODE */
314 if ((sv->sv_caps & SMB_CAP_UNICODE) != 0)
315 vcp->vc_flags |= SMBV_UNICODE;
316 else
317 vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
318
319 if ((sv->sv_caps & SMB_CAP_STATUS32) == 0) {
320 /* They don't do NT error codes. */
321 vcp->vc_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
322 }
323
324 /*
325 * Warn if they don't support SMB_CAP_NT_SMBS
326 * (We'll try to use NtCreate anyway)
327 */
328 if ((sv->sv_caps & SMB_CAP_NT_SMBS) == 0) {
329 cmn_err(CE_NOTE, "%s does not support SMB_CAP_NT_SMBS",
330 vcp->vc_srvname);
331 }
332
333 /*
334 * The rest of the message varies depending on
335 * whether we've negotiated "extended security".
336 *
337 * With extended security, we have:
338 * Server_GUID (length 16)
339 * Security_BLOB
340 * Otherwise we have:
341 * EncryptionKey (length is eklen)
342 * PrimaryDomain
343 */
344 if (sv->sv_caps & SMB_CAP_EXT_SECURITY) {
345 SMBSDEBUG("Ext.Security: yes");
346
347 /*
348 * Skip the server GUID.
349 */
350 err = md_get_mem(mdp, NULL, SMB_GUIDLEN, MB_MSYSTEM);
351 if (err)
352 goto errout;
353 /*
354 * Remainder is the security blob.
355 * Note: eklen "must be ignored" [MS-SMB]
356 */
357 sblen = (int)bc - SMB_GUIDLEN;
358 if (sblen < 0)
359 goto errout;
360 /* Security blob (hint) is next */
361 } else {
362 SMBSDEBUG("Ext.Security: no");
363 err = ENOTSUP;
364 goto errout;
365 }
366
367 /*
368 * Copy the security blob out to user space.
369 * Buffer addr,size in vc_auth_rbuf,rlen
370 */
371 if (wk->wk_u_auth_rlen < sblen) {
372 SMBSDEBUG("vc_auth_rbuf too small");
373 /* Give caller required size. */
374 wk->wk_u_auth_rlen = sblen;
375 err = EMSGSIZE;
376 goto errout;
377 }
378 wk->wk_u_auth_rlen = sblen;
379 err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr, sblen, MB_MUSER);
380 if (err)
381 goto errout;
382
383 /*
384 * A few sanity checks on what we received,
385 * becuse we will send these in ssnsetup.
386 *
387 * Maximum outstanding requests (we care),
388 * and Max. VCs (we only use one). Also,
389 * MaxBufferSize lower limit per spec.
390 */
391 if (sv->sv_maxmux < 1)
392 sv->sv_maxmux = 1;
393 if (sv->sv_maxvcs < 1)
394 sv->sv_maxvcs = 1;
395 if (sv->sv_maxtx < 1024)
396 sv->sv_maxtx = 1024;
397
398 /*
399 * Maximum transfer size.
400 * Sanity checks:
401 *
402 * Let's be conservative about an upper limit here.
403 * Win2k uses 16644 (and others) so 32k should be a
404 * reasonable sanity limit for this value.
405 *
406 * Note that this limit does NOT affect READX/WRITEX
407 * with CAP_LARGE_..., which we nearly always use.
408 */
409 vcp->vc_txmax = sv->sv_maxtx;
410 if (vcp->vc_txmax > 0x8000)
411 vcp->vc_txmax = 0x8000;
412
413 /*
414 * Max read/write sizes, WITHOUT overhead.
415 * This is just the payload size, so we must
416 * leave room for the SMB headers, etc.
417 * This is just the ct_txmax value, but
418 * reduced and rounded down. Tricky bit:
419 *
420 * Servers typically give us a value that's
421 * some nice "round" number, i.e 0x4000 plus
422 * some overhead, i.e. Win2k: 16644==0x4104
423 * Subtract for the SMB header (32) and the
424 * SMB command word and byte vectors (34?),
425 * then round down to a 512 byte multiple.
426 */
427 tlen = vcp->vc_txmax - 68;
428 tlen &= 0xFE00;
429
430 vcp->vc_rwmax = tlen;
431 vcp->vc_rxmax = tlen;
432 vcp->vc_wxmax = tlen;
433
434 /*
435 * Most of the "capability" bits we offer in session setup
436 * are just copied from those offered by the server.
437 */
438 sv->sv_caps &= smb_clnt_caps_mask;
439
440 smb_rq_done(rqp);
441 return (0);
442
443 errout:
444 smb_rq_done(rqp);
445 if (err == 0)
446 err = EBADRPC;
447 return (err);
448 }
449
450 static const char NativeOS[] = "illumos";
451 static const char LanMan[] = "NETSMB";
452
453 int
smb_smb_ssnsetup(struct smb_vc * vcp,struct smb_cred * scred)454 smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
455 {
456 smb_sopt_t *sv = &vcp->vc_sopt;
457 smbioc_ssn_work_t *wk = &vcp->vc_work;
458 struct smb_rq *rqp = NULL;
459 struct mbchain *mbp = NULL;
460 struct mdchain *mdp = NULL;
461 char *sb;
462 int err, ret;
463 uint32_t caps;
464 uint16_t action, bc, sblen;
465 uint8_t wc;
466
467 caps = sv->sv_caps;
468 sb = wk->wk_u_auth_wbuf.lp_ptr;
469 sblen = (uint16_t)wk->wk_u_auth_wlen;
470
471 err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX,
472 scred, &rqp);
473 if (err != 0) {
474 ret = err;
475 goto out;
476 }
477
478 /*
479 * Build the SMB Session Setup request.
480 * Always extended security form.
481 */
482 mbp = &rqp->sr_rq;
483 smb_rq_wstart(rqp);
484 mb_put_uint16le(mbp, 0xff); /* 0: AndXCommand */
485 mb_put_uint16le(mbp, 0); /* 1: AndXOffset */
486 mb_put_uint16le(mbp, sv->sv_maxtx); /* 2: MaxBufferSize */
487 mb_put_uint16le(mbp, sv->sv_maxmux); /* 3: MaxMpxCount */
488 mb_put_uint16le(mbp, 1); /* 4: VcNumber */
489 mb_put_uint32le(mbp, sv->sv_skey); /* 5,6: Session Key */
490 mb_put_uint16le(mbp, sblen); /* 7: Sec. Blob Len */
491 mb_put_uint32le(mbp, 0); /* 8,9: reserved */
492 mb_put_uint32le(mbp, caps); /* 10,11: Capabilities */
493 smb_rq_wend(rqp); /* 12: Byte Count */
494 smb_rq_bstart(rqp);
495 err = mb_put_mem(mbp, sb, sblen, MB_MUSER);
496 if (err != 0) {
497 ret = err;
498 goto out;
499 }
500 (void) smb_put_dstring(mbp, vcp, NativeOS, SMB_CS_NONE);
501 (void) smb_put_dstring(mbp, vcp, LanMan, SMB_CS_NONE);
502 smb_rq_bend(rqp);
503
504 /*
505 * Run the request. The return value here should be the
506 * return from this function, unless we fail decoding.
507 * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and
508 * the caller expects EINPROGRESS for that case.
509 */
510 ret = smb_rq_internal(rqp, smb_timo_logon);
511 if (ret != 0)
512 goto out;
513 switch (rqp->sr_error) {
514 case NT_STATUS_SUCCESS:
515 break;
516 case NT_STATUS_MORE_PROCESSING_REQUIRED:
517 /* Keep going, but return... */
518 ret = EINPROGRESS;
519 break;
520 default:
521 ret = EAUTH;
522 goto out;
523 }
524
525 if (vcp->vc_smbuid == 0)
526 vcp->vc_smbuid = rqp->sr_rpuid;
527
528 /*
529 * Parse the reply
530 */
531 smb_rq_getreply(rqp, &mdp);
532
533 err = md_get_uint8(mdp, &wc);
534 if (err != 0)
535 wc = 0;
536 if (wc != 4) {
537 ret = EBADRPC;
538 goto out;
539 }
540 md_get_uint16le(mdp, NULL); /* secondary cmd */
541 md_get_uint16le(mdp, NULL); /* andxoffset */
542 md_get_uint16le(mdp, &action); /* action XXX */
543 md_get_uint16le(mdp, &sblen); /* sec. blob len */
544 md_get_uint16le(mdp, &bc); /* byte count */
545 /*
546 * Get the security blob, after
547 * sanity-checking the length.
548 */
549 if (sblen == 0 || sblen > bc) {
550 ret = EBADRPC;
551 goto out;
552 }
553 if (sblen > wk->wk_u_auth_rlen) {
554 ret = EBADRPC;
555 goto out;
556 }
557 sb = wk->wk_u_auth_rbuf.lp_ptr;
558 err = md_get_mem(mdp, sb, sblen, MB_MUSER);
559 if (err) {
560 ret = EBADRPC;
561 goto out;
562 }
563
564 /*
565 * Native OS, LANMGR, & Domain follow here.
566 * We don't need them and don't parse them.
567 */
568
569 out:
570 if (err != 0 && err != EINPROGRESS) {
571 /* UID no longer valid. */
572 vcp->vc_smbuid = 0;
573 }
574 if (rqp)
575 smb_rq_done(rqp);
576
577 return (ret);
578 }
579
580 int
smb_smb_logoff(struct smb_vc * vcp,struct smb_cred * scred)581 smb_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred)
582 {
583 struct smb_rq *rqp;
584 struct mbchain *mbp;
585 int error;
586
587 if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
588 return (0);
589
590 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
591 if (error)
592 return (error);
593 mbp = &rqp->sr_rq;
594 smb_rq_wstart(rqp);
595 mb_put_uint8(mbp, 0xff);
596 mb_put_uint8(mbp, 0);
597 mb_put_uint16le(mbp, 0);
598 smb_rq_wend(rqp);
599 smb_rq_bstart(rqp);
600 smb_rq_bend(rqp);
601
602 /*
603 * Run this with a relatively short timeout. (5 sec.)
604 * We don't really care about the result here.
605 * Also, don't reconnect for this, of course!
606 */
607 rqp->sr_flags |= SMBR_NORECONNECT;
608 error = smb_rq_internal(rqp, 5);
609 smb_rq_done(rqp);
610 return (error);
611 }
612
613 /*
614 * Get the string representation of a share "use" type,
615 * as needed for the "service" in tree connect.
616 */
617 static const char *
smb_share_typename(uint32_t stype)618 smb_share_typename(uint32_t stype)
619 {
620 const char *p;
621
622 switch (stype) {
623 case STYPE_DISKTREE:
624 p = "A:";
625 break;
626 case STYPE_PRINTQ:
627 p = "LPT1:";
628 break;
629 case STYPE_DEVICE:
630 p = "COMM";
631 break;
632 case STYPE_IPC:
633 p = "IPC";
634 break;
635 case STYPE_UNKNOWN:
636 default:
637 p = "?????";
638 break;
639 }
640 return (p);
641 }
642
643 /*
644 * Parse a share type name (inverse of above)
645 */
646 static uint32_t
smb_share_parsetype(char * name)647 smb_share_parsetype(char *name)
648 {
649 int stype;
650
651 switch (*name) {
652 case 'A': /* A: */
653 stype = STYPE_DISKTREE;
654 break;
655 case 'C': /* COMM */
656 stype = STYPE_DEVICE;
657 break;
658 case 'I': /* IPC */
659 stype = STYPE_IPC;
660 break;
661 case 'L': /* LPT: */
662 stype = STYPE_PRINTQ;
663 break;
664 default:
665 stype = STYPE_UNKNOWN;
666 break;
667 }
668 return (stype);
669 }
670
671 int
smb_smb_treeconnect(struct smb_share * ssp,struct smb_cred * scred)672 smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
673 {
674 struct smb_vc *vcp;
675 struct smb_rq *rqp = NULL;
676 struct mbchain *mbp;
677 struct mdchain *mdp;
678 const char *tname;
679 char *pbuf, *unc_name = NULL;
680 int error, tlen, plen, unc_len;
681 uint16_t bcnt, options;
682 uint8_t wc;
683 char stype_str[STYPE_LEN];
684
685 vcp = SSTOVC(ssp);
686
687 /*
688 * Make this a "VC-level" request, so it will have
689 * rqp->sr_share == NULL, and smb_iod_sendrq()
690 * will send it with TID = SMB_TID_UNKNOWN
691 *
692 * This also serves to bypass the wait for
693 * share state changes, which this call is
694 * trying to carry out.
695 */
696 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_CONNECT_ANDX,
697 scred, &rqp);
698 if (error)
699 return (error);
700
701 /*
702 * Build the UNC name, i.e. "//server/share"
703 * but with backslashes of course.
704 * size math: three slashes, one null.
705 */
706 unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name);
707 unc_name = kmem_alloc(unc_len, KM_SLEEP);
708 (void) snprintf(unc_name, unc_len, "\\\\%s\\%s",
709 vcp->vc_srvname, ssp->ss_name);
710 SMBSDEBUG("unc_name: \"%s\"", unc_name);
711
712
713 /*
714 * Share-level password (pre-computed in user-space)
715 * MS-SMB 2.2.6 says this should be null terminated,
716 * and the pw length includes the null.
717 */
718 pbuf = ssp->ss_pass;
719 plen = strlen(pbuf) + 1;
720
721 /*
722 * Build the request.
723 */
724 mbp = &rqp->sr_rq;
725 smb_rq_wstart(rqp);
726 mb_put_uint8(mbp, 0xff);
727 mb_put_uint8(mbp, 0);
728 mb_put_uint16le(mbp, 0);
729 mb_put_uint16le(mbp, 0); /* Flags */
730 mb_put_uint16le(mbp, plen);
731 smb_rq_wend(rqp);
732 smb_rq_bstart(rqp);
733
734 /* Tree connect password, if any */
735 error = mb_put_mem(mbp, pbuf, plen, MB_MSYSTEM);
736 if (error)
737 goto out;
738
739 /* UNC resource name */
740 error = smb_put_dstring(mbp, vcp, unc_name, SMB_CS_NONE);
741 if (error)
742 goto out;
743
744 /*
745 * Put the type string (always ASCII),
746 * including the null.
747 */
748 tname = smb_share_typename(ssp->ss_use);
749 tlen = strlen(tname) + 1;
750 error = mb_put_mem(mbp, tname, tlen, MB_MSYSTEM);
751 if (error)
752 goto out;
753
754 smb_rq_bend(rqp);
755
756 /*
757 * Run the request.
758 *
759 * Using NOINTR_RECV because we don't want to risk
760 * missing a successful tree connect response,
761 * which would "leak" Tree IDs.
762 */
763 rqp->sr_flags |= SMBR_NOINTR_RECV;
764 error = smb_rq_simple(rqp);
765 SMBSDEBUG("%d\n", error);
766 if (error) {
767 /*
768 * If we get the server name wrong, i.e. due to
769 * mis-configured name services, this will be
770 * NT_STATUS_DUPLICATE_NAME. Log this error.
771 */
772 SMBERROR("(%s) failed, status=0x%x",
773 unc_name, rqp->sr_error);
774 goto out;
775 }
776
777 /*
778 * Parse the TCON response
779 */
780 smb_rq_getreply(rqp, &mdp);
781 md_get_uint8(mdp, &wc);
782 if (wc != 3 && wc != 7) {
783 error = EBADRPC;
784 goto out;
785 }
786 md_get_uint16le(mdp, NULL); /* AndX cmd */
787 md_get_uint16le(mdp, NULL); /* AndX off */
788 md_get_uint16le(mdp, &options); /* option bits (DFS, search) */
789 if (wc == 7) {
790 md_get_uint32le(mdp, NULL); /* MaximalShareAccessRights */
791 md_get_uint32le(mdp, NULL); /* GuestMaximalShareAcc... */
792 }
793 error = md_get_uint16le(mdp, &bcnt); /* byte count */
794 if (error)
795 goto out;
796
797 /*
798 * Get the returned share type string, i.e. "IPC" or whatever.
799 * (See smb_share_typename, smb_share_parsetype). If we get
800 * an error reading the type, just say STYPE_UNKNOWN.
801 */
802 tlen = STYPE_LEN;
803 bzero(stype_str, tlen--);
804 if (tlen > bcnt)
805 tlen = bcnt;
806 md_get_mem(mdp, stype_str, tlen, MB_MSYSTEM);
807 stype_str[tlen] = '\0';
808 ssp->ss_type = smb_share_parsetype(stype_str);
809
810 /* Success! */
811 SMB_SS_LOCK(ssp);
812 ssp->ss_tid = rqp->sr_rptid;
813 ssp->ss_vcgenid = vcp->vc_genid;
814 ssp->ss_options = options;
815 ssp->ss_flags |= SMBS_CONNECTED;
816 SMB_SS_UNLOCK(ssp);
817
818 out:
819 if (unc_name)
820 kmem_free(unc_name, unc_len);
821 smb_rq_done(rqp);
822 return (error);
823 }
824
825 int
smb_smb_treedisconnect(struct smb_share * ssp,struct smb_cred * scred)826 smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
827 {
828 struct smb_vc *vcp;
829 struct smb_rq *rqp;
830 int error;
831
832 if (ssp->ss_tid == SMB_TID_UNKNOWN)
833 return (0);
834
835 /*
836 * Build this as a "VC-level" request, so it will
837 * avoid testing the _GONE flag on the share,
838 * which has already been set at this point.
839 * Add the share pointer "by hand" below, so
840 * smb_iod_sendrq will plug in the TID.
841 */
842 vcp = SSTOVC(ssp);
843 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
844 if (error)
845 return (error);
846 rqp->sr_share = ssp; /* by hand */
847
848 smb_rq_wstart(rqp);
849 smb_rq_wend(rqp);
850 smb_rq_bstart(rqp);
851 smb_rq_bend(rqp);
852
853 /*
854 * Run this with a relatively short timeout. (5 sec.)
855 * We don't really care about the result here, but we
856 * do need to make sure we send this out, or we could
857 * "leak" active tree IDs on interrupt or timeout.
858 * The NOINTR_SEND flag makes this request immune to
859 * interrupt or timeout until the send is done.
860 * Also, don't reconnect for this, of course!
861 */
862 rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
863 error = smb_rq_simple_timed(rqp, 5);
864 SMBSDEBUG("%d\n", error);
865 smb_rq_done(rqp);
866 ssp->ss_tid = SMB_TID_UNKNOWN;
867 return (error);
868 }
869
870 /*
871 * Modern create/open of file or directory.
872 */
873 int
smb1_smb_ntcreate(struct smb_share * ssp,struct mbchain * name_mb,uint32_t cr_flags,uint32_t req_acc,uint32_t efa,uint32_t share_acc,uint32_t open_disp,uint32_t createopt,uint32_t impersonate,struct smb_cred * scrp,uint16_t * fidp,uint32_t * cr_act_p,struct smbfattr * fap)874 smb1_smb_ntcreate(
875 struct smb_share *ssp,
876 struct mbchain *name_mb,
877 uint32_t cr_flags, /* create flags */
878 uint32_t req_acc, /* requested access */
879 uint32_t efa, /* ext. file attrs (DOS attr +) */
880 uint32_t share_acc,
881 uint32_t open_disp, /* open disposition */
882 uint32_t createopt, /* NTCREATEX_OPTIONS_ */
883 uint32_t impersonate, /* NTCREATEX_IMPERSONATION_... */
884 struct smb_cred *scrp,
885 uint16_t *fidp, /* returned FID */
886 uint32_t *cr_act_p, /* optional create action */
887 struct smbfattr *fap) /* optional attributes */
888 {
889 struct smb_rq rq, *rqp = &rq;
890 struct smb_vc *vcp = SSTOVC(ssp);
891 struct mbchain *mbp;
892 struct mdchain *mdp;
893 struct smbfattr fa;
894 uint64_t llongint;
895 uint32_t longint, createact;
896 uint16_t fid;
897 uint8_t wc;
898 int error;
899
900 bzero(&fa, sizeof (fa));
901 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp);
902 if (error)
903 return (error);
904 smb_rq_getrequest(rqp, &mbp);
905
906 /* Word parameters */
907 smb_rq_wstart(rqp);
908 mb_put_uint8(mbp, 0xff); /* secondary command */
909 mb_put_uint8(mbp, 0); /* MBZ */
910 mb_put_uint16le(mbp, 0); /* offset to next command (none) */
911 mb_put_uint8(mbp, 0); /* MBZ */
912 mb_put_uint16le(mbp, name_mb->mb_count);
913 mb_put_uint32le(mbp, cr_flags); /* NTCREATEX_FLAGS_* */
914 mb_put_uint32le(mbp, 0); /* FID - basis for path if not root */
915 mb_put_uint32le(mbp, req_acc);
916 mb_put_uint64le(mbp, 0); /* "initial allocation size" */
917 mb_put_uint32le(mbp, efa);
918 mb_put_uint32le(mbp, share_acc);
919 mb_put_uint32le(mbp, open_disp);
920 mb_put_uint32le(mbp, createopt);
921 mb_put_uint32le(mbp, impersonate);
922 mb_put_uint8(mbp, 0); /* security flags (?) */
923 smb_rq_wend(rqp);
924
925 /*
926 * Byte parameters: Just the path name, aligned.
927 * Note: mb_put_mbuf consumes mb_top, so clear it.
928 */
929 smb_rq_bstart(rqp);
930 if (SMB_UNICODE_STRINGS(vcp))
931 mb_put_padbyte(mbp);
932 mb_put_mbuf(mbp, name_mb->mb_top);
933 bzero(name_mb, sizeof (*name_mb));
934 smb_rq_bend(rqp);
935
936 /*
937 * Don't want to risk missing a successful
938 * open response, or we could "leak" FIDs.
939 */
940 rqp->sr_flags |= SMBR_NOINTR_RECV;
941 error = smb_rq_simple_timed(rqp, smb_timo_open);
942 if (error)
943 goto done;
944 smb_rq_getreply(rqp, &mdp);
945 /*
946 * spec says 26 for word count, but 34 words are defined
947 * and observed from win2000
948 */
949 error = md_get_uint8(mdp, &wc);
950 if (error)
951 goto done;
952 if (wc != 26 && wc < 34) {
953 error = EBADRPC;
954 goto done;
955 }
956 md_get_uint8(mdp, NULL); /* secondary cmd */
957 md_get_uint8(mdp, NULL); /* mbz */
958 md_get_uint16le(mdp, NULL); /* andxoffset */
959 md_get_uint8(mdp, NULL); /* oplock lvl granted */
960 md_get_uint16le(mdp, &fid); /* file ID */
961 md_get_uint32le(mdp, &createact); /* create_action */
962
963 md_get_uint64le(mdp, &llongint); /* creation time */
964 smb_time_NT2local(llongint, &fa.fa_createtime);
965 md_get_uint64le(mdp, &llongint); /* access time */
966 smb_time_NT2local(llongint, &fa.fa_atime);
967 md_get_uint64le(mdp, &llongint); /* write time */
968 smb_time_NT2local(llongint, &fa.fa_mtime);
969 md_get_uint64le(mdp, &llongint); /* change time */
970 smb_time_NT2local(llongint, &fa.fa_ctime);
971
972 md_get_uint32le(mdp, &longint); /* attributes */
973 fa.fa_attr = longint;
974 md_get_uint64le(mdp, &llongint); /* allocation size */
975 fa.fa_allocsz = llongint;
976 md_get_uint64le(mdp, &llongint); /* EOF position */
977 fa.fa_size = llongint;
978
979 error = md_get_uint16le(mdp, NULL); /* file type */
980 /* other stuff we don't care about */
981
982 done:
983 smb_rq_done(rqp);
984 if (error)
985 return (error);
986
987 *fidp = fid;
988 if (cr_act_p)
989 *cr_act_p = createact;
990 if (fap)
991 *fap = fa; /* struct copy */
992
993 return (0);
994 }
995
996 int
smb1_smb_close(struct smb_share * ssp,uint16_t fid,struct timespec * mtime,struct smb_cred * scrp)997 smb1_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
998 struct smb_cred *scrp)
999 {
1000 struct smb_rq rq, *rqp = &rq;
1001 struct mbchain *mbp;
1002 long time;
1003 int error;
1004
1005 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scrp);
1006 if (error)
1007 return (error);
1008 smb_rq_getrequest(rqp, &mbp);
1009 smb_rq_wstart(rqp);
1010 mb_put_uint16le(mbp, fid);
1011 if (mtime) {
1012 int sv_tz = SSTOVC(ssp)->vc_sopt.sv_tz;
1013 smb_time_local2server(mtime, sv_tz, &time);
1014 } else {
1015 time = 0;
1016 }
1017 mb_put_uint32le(mbp, time);
1018 smb_rq_wend(rqp);
1019 smb_rq_bstart(rqp);
1020 smb_rq_bend(rqp);
1021
1022 /* Make sure we send, but only if already connected */
1023 rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
1024 error = smb_rq_simple(rqp);
1025 smb_rq_done(rqp);
1026 return (error);
1027 }
1028
1029 int
smb_smb_open_prjob(struct smb_share * ssp,char * title,uint16_t setuplen,uint16_t mode,struct smb_cred * scrp,uint16_t * fidp)1030 smb_smb_open_prjob(
1031 struct smb_share *ssp,
1032 char *title,
1033 uint16_t setuplen,
1034 uint16_t mode,
1035 struct smb_cred *scrp,
1036 uint16_t *fidp)
1037 {
1038 struct smb_rq rq, *rqp = &rq;
1039 struct smb_vc *vcp = SSTOVC(ssp);
1040 struct mbchain *mbp;
1041 struct mdchain *mdp;
1042 uint16_t fid;
1043 uint8_t wc;
1044 int error;
1045
1046 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN_PRINT_FILE, scrp);
1047 if (error)
1048 return (error);
1049 smb_rq_getrequest(rqp, &mbp);
1050
1051 /* Word parameters */
1052 smb_rq_wstart(rqp);
1053 mb_put_uint16le(mbp, setuplen);
1054 mb_put_uint16le(mbp, mode);
1055 smb_rq_wend(rqp);
1056
1057 /*
1058 * Byte parameters: Just the title
1059 */
1060 smb_rq_bstart(rqp);
1061 mb_put_uint8(mbp, SMB_DT_ASCII);
1062 error = smb_put_dstring(mbp, vcp, title, SMB_CS_NONE);
1063 smb_rq_bend(rqp);
1064 if (error)
1065 goto done;
1066
1067 /*
1068 * Don't want to risk missing a successful
1069 * open response, or we could "leak" FIDs.
1070 */
1071 rqp->sr_flags |= SMBR_NOINTR_RECV;
1072 error = smb_rq_simple_timed(rqp, smb_timo_open);
1073 if (error)
1074 goto done;
1075
1076 smb_rq_getreply(rqp, &mdp);
1077 error = md_get_uint8(mdp, &wc);
1078 if (error || wc < 1) {
1079 error = EBADRPC;
1080 goto done;
1081 }
1082 error = md_get_uint16le(mdp, &fid);
1083
1084 done:
1085 smb_rq_done(rqp);
1086 if (error)
1087 return (error);
1088
1089 *fidp = fid;
1090 return (0);
1091 }
1092
1093 /*
1094 * Like smb_smb_close, but for print shares.
1095 */
1096 int
smb_smb_close_prjob(struct smb_share * ssp,uint16_t fid,struct smb_cred * scrp)1097 smb_smb_close_prjob(struct smb_share *ssp, uint16_t fid,
1098 struct smb_cred *scrp)
1099 {
1100 struct smb_rq rq, *rqp = &rq;
1101 struct mbchain *mbp;
1102 int error;
1103
1104 error = smb_rq_init(rqp, SSTOCP(ssp),
1105 SMB_COM_CLOSE_PRINT_FILE, scrp);
1106 if (error)
1107 return (error);
1108 smb_rq_getrequest(rqp, &mbp);
1109 smb_rq_wstart(rqp);
1110 mb_put_uint16le(mbp, fid);
1111 smb_rq_wend(rqp);
1112 smb_rq_bstart(rqp);
1113 smb_rq_bend(rqp);
1114
1115 /* Make sure we send but only if already connected */
1116 rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
1117 error = smb_rq_simple(rqp);
1118 smb_rq_done(rqp);
1119 return (error);
1120 }
1121
1122 int
smb_smb_readx(smb_fh_t * fhp,uint32_t * lenp,uio_t * uiop,smb_cred_t * scred,int timo)1123 smb_smb_readx(smb_fh_t *fhp, uint32_t *lenp,
1124 uio_t *uiop, smb_cred_t *scred, int timo)
1125 {
1126 struct smb_share *ssp = FHTOSS(fhp);
1127 struct smb_rq *rqp;
1128 struct mbchain *mbp;
1129 struct mdchain *mdp;
1130 int error;
1131 uint32_t offlo, offhi, rlen;
1132 uint16_t lenhi, lenlo, off, doff;
1133 uint8_t wc;
1134
1135 lenhi = (uint16_t)(*lenp >> 16);
1136 lenlo = (uint16_t)*lenp;
1137 offhi = (uint32_t)(uiop->uio_loffset >> 32);
1138 offlo = (uint32_t)uiop->uio_loffset;
1139
1140 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
1141 if (error)
1142 return (error);
1143 smb_rq_getrequest(rqp, &mbp);
1144 smb_rq_wstart(rqp);
1145 mb_put_uint8(mbp, 0xff); /* no secondary command */
1146 mb_put_uint8(mbp, 0); /* MBZ */
1147 mb_put_uint16le(mbp, 0); /* offset to secondary */
1148 mb_put_uint16le(mbp, fhp->fh_fid1);
1149 mb_put_uint32le(mbp, offlo); /* offset (low part) */
1150 mb_put_uint16le(mbp, lenlo); /* MaxCount */
1151 mb_put_uint16le(mbp, 1); /* MinCount */
1152 /* (only indicates blocking) */
1153 mb_put_uint32le(mbp, lenhi); /* MaxCountHigh */
1154 mb_put_uint16le(mbp, lenlo); /* Remaining ("obsolete") */
1155 mb_put_uint32le(mbp, offhi); /* offset (high part) */
1156 smb_rq_wend(rqp);
1157 smb_rq_bstart(rqp);
1158 smb_rq_bend(rqp);
1159
1160 if (timo == 0)
1161 timo = smb_timo_read;
1162 error = smb_rq_simple_timed(rqp, timo);
1163 if (error)
1164 goto out;
1165
1166 smb_rq_getreply(rqp, &mdp);
1167 error = md_get_uint8(mdp, &wc);
1168 if (error)
1169 goto out;
1170 if (wc != 12) {
1171 error = EBADRPC;
1172 goto out;
1173 }
1174 md_get_uint8(mdp, NULL);
1175 md_get_uint8(mdp, NULL);
1176 md_get_uint16le(mdp, NULL);
1177 md_get_uint16le(mdp, NULL);
1178 md_get_uint16le(mdp, NULL); /* data compaction mode */
1179 md_get_uint16le(mdp, NULL);
1180 md_get_uint16le(mdp, &lenlo); /* data len ret. */
1181 md_get_uint16le(mdp, &doff); /* data offset */
1182 md_get_uint16le(mdp, &lenhi);
1183 rlen = (lenhi << 16) | lenlo;
1184 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
1185 error = md_get_uint16le(mdp, NULL); /* ByteCount */
1186 if (error)
1187 goto out;
1188 /*
1189 * Does the data offset indicate padding?
1190 * The current offset is a constant, found
1191 * by counting the md_get_ calls above.
1192 */
1193 off = SMB_HDRLEN + 3 + (12 * 2); /* =59 */
1194 if (doff > off) /* pad byte(s)? */
1195 md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
1196 if (rlen == 0) {
1197 *lenp = rlen;
1198 goto out;
1199 }
1200 /* paranoid */
1201 if (rlen > *lenp) {
1202 SMBSDEBUG("bad server! rlen %d, len %d\n",
1203 rlen, *lenp);
1204 rlen = *lenp;
1205 }
1206 error = md_get_uio(mdp, uiop, rlen);
1207 if (error)
1208 goto out;
1209
1210 /* Success */
1211 *lenp = rlen;
1212
1213 out:
1214 smb_rq_done(rqp);
1215 return (error);
1216 }
1217
1218 int
smb_smb_writex(smb_fh_t * fhp,uint32_t * lenp,uio_t * uiop,smb_cred_t * scred,int timo)1219 smb_smb_writex(smb_fh_t *fhp, uint32_t *lenp,
1220 uio_t *uiop, smb_cred_t *scred, int timo)
1221 {
1222 struct smb_share *ssp = FHTOSS(fhp);
1223 struct smb_rq *rqp;
1224 struct mbchain *mbp;
1225 struct mdchain *mdp;
1226 int error;
1227 uint32_t offlo, offhi, rlen;
1228 uint16_t lenhi, lenlo;
1229 uint8_t wc;
1230
1231 lenhi = (uint16_t)(*lenp >> 16);
1232 lenlo = (uint16_t)*lenp;
1233 offhi = (uint32_t)(uiop->uio_loffset >> 32);
1234 offlo = (uint32_t)uiop->uio_loffset;
1235
1236 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
1237 if (error)
1238 return (error);
1239 smb_rq_getrequest(rqp, &mbp);
1240 smb_rq_wstart(rqp);
1241 mb_put_uint8(mbp, 0xff); /* no secondary command */
1242 mb_put_uint8(mbp, 0); /* MBZ */
1243 mb_put_uint16le(mbp, 0); /* offset to secondary */
1244 mb_put_uint16le(mbp, fhp->fh_fid1);
1245 mb_put_uint32le(mbp, offlo); /* offset (low part) */
1246 mb_put_uint32le(mbp, 0); /* MBZ (timeout) */
1247 mb_put_uint16le(mbp, 0); /* !write-thru */
1248 mb_put_uint16le(mbp, 0);
1249 mb_put_uint16le(mbp, lenhi);
1250 mb_put_uint16le(mbp, lenlo);
1251 mb_put_uint16le(mbp, 64); /* data offset from header start */
1252 mb_put_uint32le(mbp, offhi); /* offset (high part) */
1253 smb_rq_wend(rqp);
1254 smb_rq_bstart(rqp);
1255
1256 mb_put_uint8(mbp, 0); /* pad byte */
1257 error = mb_put_uio(mbp, uiop, *lenp);
1258 if (error)
1259 goto out;
1260 smb_rq_bend(rqp);
1261 if (timo == 0)
1262 timo = smb_timo_write;
1263 error = smb_rq_simple_timed(rqp, timo);
1264 if (error)
1265 goto out;
1266 smb_rq_getreply(rqp, &mdp);
1267 error = md_get_uint8(mdp, &wc);
1268 if (error)
1269 goto out;
1270 if (wc != 6) {
1271 error = EBADRPC;
1272 goto out;
1273 }
1274 md_get_uint8(mdp, NULL); /* andx cmd */
1275 md_get_uint8(mdp, NULL); /* reserved */
1276 md_get_uint16le(mdp, NULL); /* andx offset */
1277 md_get_uint16le(mdp, &lenlo); /* data len ret. */
1278 md_get_uint16le(mdp, NULL); /* remaining */
1279 error = md_get_uint16le(mdp, &lenhi);
1280 if (error)
1281 goto out;
1282
1283 /* Success */
1284 rlen = (lenhi << 16) | lenlo;
1285 *lenp = rlen;
1286
1287 out:
1288 smb_rq_done(rqp);
1289 return (error);
1290 }
1291
1292
1293 static u_int32_t smbechoes = 0;
1294
1295 /*
1296 * Note: the IOD calls this, so this request must not wait for
1297 * connection state changes, etc. (uses smb_rq_internal)
1298 */
1299 int
smb_smb_echo(struct smb_vc * vcp,struct smb_cred * scred,int timo)1300 smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
1301 {
1302 struct smb_rq *rqp;
1303 struct mbchain *mbp;
1304 int error;
1305
1306 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
1307 if (error)
1308 return (error);
1309 mbp = &rqp->sr_rq;
1310 smb_rq_wstart(rqp);
1311 mb_put_uint16le(mbp, 1); /* echo count */
1312 smb_rq_wend(rqp);
1313 smb_rq_bstart(rqp);
1314 mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes));
1315 smb_rq_bend(rqp);
1316 rqp->sr_flags |= SMBR_NORECONNECT;
1317 error = smb_rq_internal(rqp, timo);
1318 SMBSDEBUG("%d\n", error);
1319 smb_rq_done(rqp);
1320 return (error);
1321 }
1322