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
66struct smb_dialect {
67	int		d_id;
68	const char	*d_name;
69};
70
71static 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
79static 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 */
90int smb_timo_notice = 15;
91int smb_timo_default = 30;	/* was SMB_DEFRQTIMO */
92int smb_timo_logon = 45;
93int smb_timo_open = 45;
94int smb_timo_read = 45;
95int smb_timo_write = 60;	/* was SMBWRTTIMO */
96int smb_timo_append = 90;
97
98int
99smb_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
443errout:
444	smb_rq_done(rqp);
445	if (err == 0)
446		err = EBADRPC;
447	return (err);
448}
449
450static const char NativeOS[] = "illumos";
451static const char LanMan[] = "NETSMB";
452
453int
454smb_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
569out:
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
580int
581smb_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 */
617static const char *
618smb_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 */
646static uint32_t
647smb_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
671int
672smb_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
818out:
819	if (unc_name)
820		kmem_free(unc_name, unc_len);
821	smb_rq_done(rqp);
822	return (error);
823}
824
825int
826smb_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 */
873int
874smb1_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
982done:
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
996int
997smb1_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
1029int
1030smb_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
1084done:
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 */
1096int
1097smb_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
1122int
1123smb_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
1213out:
1214	smb_rq_done(rqp);
1215	return (error);
1216}
1217
1218int
1219smb_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
1287out:
1288	smb_rq_done(rqp);
1289	return (error);
1290}
1291
1292
1293static 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 */
1299int
1300smb_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