smb_smb.c revision 124087
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
33/*
34 * various SMB requests. Most of the routines merely packs data into mbufs.
35 */
36
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD: head/sys/netsmb/smb_smb.c 124087 2004-01-02 22:38:42Z tjr $");
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/malloc.h>
44#include <sys/proc.h>
45#include <sys/lock.h>
46#include <sys/sysctl.h>
47#include <sys/socket.h>
48#include <sys/uio.h>
49
50#include <sys/iconv.h>
51
52#include <netsmb/smb.h>
53#include <netsmb/smb_subr.h>
54#include <netsmb/smb_rq.h>
55#include <netsmb/smb_conn.h>
56#include <netsmb/smb_tran.h>
57
58#include "opt_netsmb.h"
59
60struct smb_dialect {
61	int		d_id;
62	const char *	d_name;
63};
64
65static struct smb_dialect smb_dialects[] = {
66	{SMB_DIALECT_CORE,	"PC NETWORK PROGRAM 1.0"},
67	{SMB_DIALECT_COREPLUS,	"MICROSOFT NETWORKS 1.03"},
68	{SMB_DIALECT_LANMAN1_0,	"MICROSOFT NETWORKS 3.0"},
69	{SMB_DIALECT_LANMAN1_0,	"LANMAN1.0"},
70	{SMB_DIALECT_LANMAN2_0,	"LM1.2X002"},
71	{SMB_DIALECT_LANMAN2_0,	"Samba"},
72	{SMB_DIALECT_NTLM0_12,	"NT LANMAN 1.0"},
73	{SMB_DIALECT_NTLM0_12,	"NT LM 0.12"},
74	{-1,			NULL}
75};
76
77#define	SMB_DIALECT_MAX	(sizeof(smb_dialects) / sizeof(struct smb_dialect) - 2)
78
79static u_int32_t
80smb_vc_maxread(struct smb_vc *vcp)
81{
82	/*
83	 * Specs say up to 64k data bytes, but Windows traffic
84	 * uses 60k... no doubt for some good reason.
85	 *
86	 * Don't exceed the server's buffer size if signatures
87	 * are enabled otherwise Windows 2003 chokes. Allow space
88	 * for the SMB header & a little bit extra.
89	 */
90	if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) &&
91	    (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0)
92		return (60*1024);
93	else
94		return (vcp->vc_sopt.sv_maxtx - SMB_HDRLEN - 64);
95}
96
97static u_int32_t
98smb_vc_maxwrite(struct smb_vc *vcp)
99{
100	/*
101	 * See comment above.
102	 */
103	if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) &&
104	    (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0)
105		return (60*1024);
106	else
107		return (vcp->vc_sopt.sv_maxtx - SMB_HDRLEN - 64);
108}
109
110static int
111smb_smb_nomux(struct smb_vc *vcp, struct smb_cred *scred, const char *name)
112{
113	if (scred->scr_td->td_proc == vcp->vc_iod->iod_p)
114		return 0;
115	SMBERROR("wrong function called(%s)\n", name);
116	return EINVAL;
117}
118
119int
120smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
121{
122	struct smb_dialect *dp;
123	struct smb_sopt *sp = NULL;
124	struct smb_rq *rqp;
125	struct mbchain *mbp;
126	struct mdchain *mdp;
127	u_int8_t wc, stime[8], sblen;
128	u_int16_t dindex, tw, tw1, swlen, bc;
129	int error, maxqsz;
130
131	if (smb_smb_nomux(vcp, scred, __func__) != 0)
132		return EINVAL;
133	vcp->vc_hflags = 0;
134	vcp->vc_hflags2 = 0;
135	vcp->obj.co_flags &= ~(SMBV_ENCRYPT);
136	sp = &vcp->vc_sopt;
137	bzero(sp, sizeof(struct smb_sopt));
138	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp);
139	if (error)
140		return error;
141	smb_rq_getrequest(rqp, &mbp);
142	smb_rq_wstart(rqp);
143	smb_rq_wend(rqp);
144	smb_rq_bstart(rqp);
145	for(dp = smb_dialects; dp->d_id != -1; dp++) {
146		mb_put_uint8(mbp, SMB_DT_DIALECT);
147		smb_put_dstring(mbp, vcp, dp->d_name, SMB_CS_NONE);
148	}
149	smb_rq_bend(rqp);
150	error = smb_rq_simple(rqp);
151	SMBSDEBUG("%d\n", error);
152	if (error)
153		goto bad;
154	smb_rq_getreply(rqp, &mdp);
155	do {
156		error = md_get_uint8(mdp, &wc);
157		if (error)
158			break;
159		error = md_get_uint16le(mdp, &dindex);
160		if (error)
161			break;
162		if (dindex > 7) {
163			SMBERROR("Don't know how to talk with server %s (%d)\n", "xxx", dindex);
164			error = EBADRPC;
165			break;
166		}
167		dp = smb_dialects + dindex;
168		sp->sv_proto = dp->d_id;
169		SMBSDEBUG("Dialect %s (%d, %d)\n", dp->d_name, dindex, wc);
170		error = EBADRPC;
171		if (dp->d_id >= SMB_DIALECT_NTLM0_12) {
172			if (wc != 17)
173				break;
174			md_get_uint8(mdp, &sp->sv_sm);
175			md_get_uint16le(mdp, &sp->sv_maxmux);
176			md_get_uint16le(mdp, &sp->sv_maxvcs);
177			md_get_uint32le(mdp, &sp->sv_maxtx);
178			md_get_uint32le(mdp, &sp->sv_maxraw);
179			md_get_uint32le(mdp, &sp->sv_skey);
180			md_get_uint32le(mdp, &sp->sv_caps);
181			md_get_mem(mdp, stime, 8, MB_MSYSTEM);
182			md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz);
183			md_get_uint8(mdp, &sblen);
184			if (sblen && (sp->sv_sm & SMB_SM_ENCRYPT)) {
185				if (sblen != SMB_MAXCHALLENGELEN) {
186					SMBERROR("Unexpected length of security blob (%d)\n", sblen);
187					break;
188				}
189				error = md_get_uint16(mdp, &bc);
190				if (error)
191					break;
192				if (sp->sv_caps & SMB_CAP_EXT_SECURITY)
193					md_get_mem(mdp, NULL, 16, MB_MSYSTEM);
194				error = md_get_mem(mdp, vcp->vc_ch, sblen, MB_MSYSTEM);
195				if (error)
196					break;
197				vcp->vc_chlen = sblen;
198				vcp->obj.co_flags |= SMBV_ENCRYPT;
199			}
200#ifdef NETSMBCRYPTO
201			if (sp->sv_sm & SMB_SM_SIGS_REQUIRE)
202				vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
203#endif
204			vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
205			if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
206			    sp->sv_maxtx < 4096 &&
207			    (sp->sv_caps & SMB_CAP_NT_SMBS) == 0) {
208				vcp->obj.co_flags |= SMBV_WIN95;
209				SMBSDEBUG("Win95 detected\n");
210			}
211		} else if (dp->d_id > SMB_DIALECT_CORE) {
212			md_get_uint16le(mdp, &tw);
213			sp->sv_sm = tw;
214			md_get_uint16le(mdp, &tw);
215			sp->sv_maxtx = tw;
216			md_get_uint16le(mdp, &sp->sv_maxmux);
217			md_get_uint16le(mdp, &sp->sv_maxvcs);
218			md_get_uint16le(mdp, &tw);	/* rawmode */
219			md_get_uint32le(mdp, &sp->sv_skey);
220			if (wc == 13) {		/* >= LANMAN1 */
221				md_get_uint16(mdp, &tw);		/* time */
222				md_get_uint16(mdp, &tw1);		/* date */
223				md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz);
224				md_get_uint16le(mdp, &swlen);
225				if (swlen > SMB_MAXCHALLENGELEN)
226					break;
227				md_get_uint16(mdp, NULL);	/* mbz */
228				if (md_get_uint16(mdp, &bc) != 0)
229					break;
230				if (bc < swlen)
231					break;
232				if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) {
233					error = md_get_mem(mdp, vcp->vc_ch, swlen, MB_MSYSTEM);
234					if (error)
235						break;
236					vcp->vc_chlen = swlen;
237					vcp->obj.co_flags |= SMBV_ENCRYPT;
238				}
239			}
240			vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
241		} else {	/* an old CORE protocol */
242			sp->sv_maxmux = 1;
243		}
244		error = 0;
245	} while (0);
246	if (error == 0) {
247		vcp->vc_maxvcs = sp->sv_maxvcs;
248		if (vcp->vc_maxvcs <= 1) {
249			if (vcp->vc_maxvcs == 0)
250				vcp->vc_maxvcs = 1;
251		}
252		if (sp->sv_maxtx <= 0 || sp->sv_maxtx > 0xffff)
253			sp->sv_maxtx = 1024;
254		else
255			sp->sv_maxtx = min(sp->sv_maxtx,
256					   63*1024 + SMB_HDRLEN + 16);
257		SMB_TRAN_GETPARAM(vcp, SMBTP_RCVSZ, &maxqsz);
258		vcp->vc_rxmax = min(smb_vc_maxread(vcp), maxqsz - 1024);
259		SMB_TRAN_GETPARAM(vcp, SMBTP_SNDSZ, &maxqsz);
260		vcp->vc_wxmax = min(smb_vc_maxwrite(vcp), maxqsz - 1024);
261		vcp->vc_txmax = min(sp->sv_maxtx, maxqsz);
262		SMBSDEBUG("TZ = %d\n", sp->sv_tz);
263		SMBSDEBUG("CAPS = %x\n", sp->sv_caps);
264		SMBSDEBUG("MAXMUX = %d\n", sp->sv_maxmux);
265		SMBSDEBUG("MAXVCS = %d\n", sp->sv_maxvcs);
266		SMBSDEBUG("MAXRAW = %d\n", sp->sv_maxraw);
267		SMBSDEBUG("MAXTX = %d\n", sp->sv_maxtx);
268	}
269bad:
270	smb_rq_done(rqp);
271	return error;
272}
273
274int
275smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
276{
277	struct smb_rq *rqp;
278	struct mbchain *mbp;
279/*	u_int8_t wc;
280	u_int16_t tw, tw1;*/
281	smb_uniptr unipp, ntencpass = NULL;
282	char *pp, *up, *pbuf, *encpass;
283	int error, plen, uniplen, ulen, upper;
284
285	upper = 0;
286
287again:
288
289	vcp->vc_smbuid = SMB_UID_UNKNOWN;
290
291	if (smb_smb_nomux(vcp, scred, __func__) != 0)
292		return EINVAL;
293
294	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, scred, &rqp);
295	if (error)
296		return error;
297	pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
298	encpass = malloc(24, M_SMBTEMP, M_WAITOK);
299	if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
300		/*
301		 * We try w/o uppercasing first so Samba mixed case
302		 * passwords work.  If that fails we come back and try
303		 * uppercasing to satisfy OS/2 and Windows for Workgroups.
304		 */
305		if (upper++) {
306			iconv_convstr(vcp->vc_toupper, pbuf,
307				      smb_vc_getpass(vcp)/*, SMB_MAXPASSWORDLEN*/);
308		} else {
309			strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN);
310			pbuf[SMB_MAXPASSWORDLEN] = '\0';
311		}
312		if (!SMB_UNICODE_STRINGS(vcp))
313			iconv_convstr(vcp->vc_toserver, pbuf, pbuf/*,
314				      SMB_MAXPASSWORDLEN*/);
315
316		if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
317			uniplen = plen = 24;
318			smb_encrypt(pbuf, vcp->vc_ch, encpass);
319			ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
320			if (SMB_UNICODE_STRINGS(vcp)) {
321				strncpy(pbuf, smb_vc_getpass(vcp),
322					SMB_MAXPASSWORDLEN);
323				pbuf[SMB_MAXPASSWORDLEN] = '\0';
324			} else
325				iconv_convstr(vcp->vc_toserver, pbuf,
326					      smb_vc_getpass(vcp)/*,
327					      SMB_MAXPASSWORDLEN*/);
328			smb_ntencrypt(pbuf, vcp->vc_ch, (u_char*)ntencpass);
329			pp = encpass;
330			unipp = ntencpass;
331		} else {
332			plen = strlen(pbuf) + 1;
333			pp = pbuf;
334			uniplen = plen * 2;
335			ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
336			smb_strtouni(ntencpass, smb_vc_getpass(vcp));
337			plen--;
338
339			/*
340			 * The uniplen is zeroed because Samba cannot deal
341			 * with this 2nd cleartext password.  This Samba
342			 * "bug" is actually a workaround for problems in
343			 * Microsoft clients.
344			 */
345			uniplen = 0/*-= 2*/;
346			unipp = ntencpass;
347		}
348	} else {
349		/*
350		 * In the share security mode password will be used
351		 * only in the tree authentication
352		 */
353		 pp = "";
354		 plen = 1;
355		 unipp = &smb_unieol;
356		 uniplen = 0 /* sizeof(smb_unieol) */;
357	}
358	smb_rq_wstart(rqp);
359	mbp = &rqp->sr_rq;
360	up = vcp->vc_username;
361	ulen = strlen(up) + 1;
362	/*
363	 * If userid is null we are attempting anonymous browse login
364	 * so passwords must be zero length.
365	 */
366	if (ulen == 1)
367		plen = uniplen = 0;
368	mb_put_uint8(mbp, 0xff);
369	mb_put_uint8(mbp, 0);
370	mb_put_uint16le(mbp, 0);
371	mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx);
372	mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux);
373	mb_put_uint16le(mbp, vcp->vc_number);
374	mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey);
375	mb_put_uint16le(mbp, plen);
376	if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) {
377		mb_put_uint32le(mbp, 0);
378		smb_rq_wend(rqp);
379		smb_rq_bstart(rqp);
380		mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
381		smb_put_dstring(mbp, vcp, up, SMB_CS_NONE);
382	} else {
383		mb_put_uint16le(mbp, uniplen);
384		mb_put_uint32le(mbp, 0);		/* reserved */
385		mb_put_uint32le(mbp, vcp->obj.co_flags & SMBV_UNICODE ?
386				     SMB_CAP_UNICODE : 0);
387		smb_rq_wend(rqp);
388		smb_rq_bstart(rqp);
389		mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
390		mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM);
391		smb_put_dstring(mbp, vcp, up, SMB_CS_NONE);		/* AccountName */
392		smb_put_dstring(mbp, vcp, vcp->vc_domain, SMB_CS_NONE);	/* PrimaryDomain */
393		smb_put_dstring(mbp, vcp, "FreeBSD", SMB_CS_NONE);	/* Client's OS */
394		smb_put_dstring(mbp, vcp, "NETSMB", SMB_CS_NONE);		/* Client name */
395	}
396	smb_rq_bend(rqp);
397	if (ntencpass)
398		free(ntencpass, M_SMBTEMP);
399	if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)
400		smb_calcmackey(vcp);
401	error = smb_rq_simple(rqp);
402	SMBSDEBUG("%d\n", error);
403	if (error) {
404		if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnoaccess)
405			error = EAUTH;
406		goto bad;
407	}
408	vcp->vc_smbuid = rqp->sr_rpuid;
409bad:
410	free(encpass, M_SMBTEMP);
411	free(pbuf, M_SMBTEMP);
412	smb_rq_done(rqp);
413	if (error && upper == 1 && vcp->vc_sopt.sv_sm & SMB_SM_USER)
414		goto again;
415	return error;
416}
417
418int
419smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred)
420{
421	struct smb_rq *rqp;
422	struct mbchain *mbp;
423	int error;
424
425	if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
426		return 0;
427
428	if (smb_smb_nomux(vcp, scred, __func__) != 0)
429		return EINVAL;
430
431	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
432	if (error)
433		return error;
434	mbp = &rqp->sr_rq;
435	smb_rq_wstart(rqp);
436	mb_put_uint8(mbp, 0xff);
437	mb_put_uint8(mbp, 0);
438	mb_put_uint16le(mbp, 0);
439	smb_rq_wend(rqp);
440	smb_rq_bstart(rqp);
441	smb_rq_bend(rqp);
442	error = smb_rq_simple(rqp);
443	SMBSDEBUG("%d\n", error);
444	smb_rq_done(rqp);
445	return error;
446}
447
448static char smb_any_share[] = "?????";
449
450static char *
451smb_share_typename(int stype)
452{
453	char *pp;
454
455	switch (stype) {
456	    case SMB_ST_DISK:
457		pp = "A:";
458		break;
459	    case SMB_ST_PRINTER:
460		pp = smb_any_share;		/* can't use LPT: here... */
461		break;
462	    case SMB_ST_PIPE:
463		pp = "IPC";
464		break;
465	    case SMB_ST_COMM:
466		pp = "COMM";
467		break;
468	    case SMB_ST_ANY:
469	    default:
470		pp = smb_any_share;
471		break;
472	}
473	return pp;
474}
475
476int
477smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
478{
479	struct smb_vc *vcp;
480	struct smb_rq rq, *rqp = &rq;
481	struct mbchain *mbp;
482	char *pp, *pbuf, *encpass;
483	int error, plen, caseopt, upper;
484
485	upper = 0;
486
487again:
488
489#if 0
490	/* Disable Unicode for SMB_COM_TREE_CONNECT_ANDX requests */
491	if (SSTOVC(ssp)->vc_hflags2 & SMB_FLAGS2_UNICODE) {
492		vcp = SSTOVC(ssp);
493		if (vcp->vc_toserver) {
494			iconv_close(vcp->vc_toserver);
495			/* Use NULL until UTF-8 -> ASCII works */
496			vcp->vc_toserver = NULL;
497		}
498		if (vcp->vc_tolocal) {
499			iconv_close(vcp->vc_tolocal);
500			/* Use NULL until ASCII -> UTF-8 works*/
501			vcp->vc_tolocal = NULL;
502		}
503		vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
504	}
505#endif
506
507	ssp->ss_tid = SMB_TID_UNKNOWN;
508	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp);
509	if (error)
510		return error;
511	vcp = rqp->sr_vc;
512	caseopt = SMB_CS_NONE;
513	if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
514		plen = 1;
515		pp = "";
516		pbuf = NULL;
517		encpass = NULL;
518	} else {
519		pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
520		encpass = malloc(24, M_SMBTEMP, M_WAITOK);
521		/*
522		 * We try w/o uppercasing first so Samba mixed case
523		 * passwords work.  If that fails we come back and try
524		 * uppercasing to satisfy OS/2 and Windows for Workgroups.
525		 */
526		if (upper++) {
527			iconv_convstr(vcp->vc_toupper, pbuf,
528				      smb_share_getpass(ssp)/*,
529				      SMB_MAXPASSWORDLEN*/);
530		} else {
531			strncpy(pbuf, smb_share_getpass(ssp),
532				SMB_MAXPASSWORDLEN);
533			pbuf[SMB_MAXPASSWORDLEN] = '\0';
534		}
535		if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
536			plen = 24;
537			smb_encrypt(pbuf, vcp->vc_ch, encpass);
538			pp = encpass;
539		} else {
540			plen = strlen(pbuf) + 1;
541			pp = pbuf;
542		}
543	}
544	mbp = &rqp->sr_rq;
545	smb_rq_wstart(rqp);
546	mb_put_uint8(mbp, 0xff);
547	mb_put_uint8(mbp, 0);
548	mb_put_uint16le(mbp, 0);
549	mb_put_uint16le(mbp, 0);		/* Flags */
550	mb_put_uint16le(mbp, plen);
551	smb_rq_wend(rqp);
552	smb_rq_bstart(rqp);
553	mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
554	smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt);
555	pp = vcp->vc_srvname;
556	smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt);
557	smb_put_dmem(mbp, vcp, "\\", 1, caseopt);
558	pp = ssp->ss_name;
559	smb_put_dstring(mbp, vcp, pp, caseopt);
560	pp = smb_share_typename(ssp->ss_type);
561	smb_put_dstring(mbp, vcp, pp, caseopt);
562	smb_rq_bend(rqp);
563	error = smb_rq_simple(rqp);
564	SMBSDEBUG("%d\n", error);
565	if (error)
566		goto bad;
567	ssp->ss_tid = rqp->sr_rptid;
568	ssp->ss_vcgenid = vcp->vc_genid;
569	ssp->ss_flags |= SMBS_CONNECTED;
570bad:
571	if (encpass)
572		free(encpass, M_SMBTEMP);
573	if (pbuf)
574		free(pbuf, M_SMBTEMP);
575	smb_rq_done(rqp);
576	if (error && upper == 1)
577		goto again;
578	return error;
579}
580
581int
582smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
583{
584	struct smb_rq *rqp;
585	struct mbchain *mbp;
586	int error;
587
588	if (ssp->ss_tid == SMB_TID_UNKNOWN)
589		return 0;
590	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
591	if (error)
592		return error;
593	mbp = &rqp->sr_rq;
594	smb_rq_wstart(rqp);
595	smb_rq_wend(rqp);
596	smb_rq_bstart(rqp);
597	smb_rq_bend(rqp);
598	error = smb_rq_simple(rqp);
599	SMBSDEBUG("%d\n", error);
600	smb_rq_done(rqp);
601	ssp->ss_tid = SMB_TID_UNKNOWN;
602	return error;
603}
604
605static __inline int
606smb_smb_readx(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
607	      struct uio *uio, struct smb_cred *scred)
608{
609	struct smb_rq *rqp;
610	struct mbchain *mbp;
611	struct mdchain *mdp;
612	u_int8_t wc;
613	int error;
614	u_int16_t residhi, residlo, off, doff;
615	u_int32_t resid;
616
617	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
618	if (error)
619		return error;
620	smb_rq_getrequest(rqp, &mbp);
621	smb_rq_wstart(rqp);
622	mb_put_uint8(mbp, 0xff);	/* no secondary command */
623	mb_put_uint8(mbp, 0);		/* MBZ */
624	mb_put_uint16le(mbp, 0);	/* offset to secondary */
625	mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
626	mb_put_uint32le(mbp, uio->uio_offset);
627	*len = min(SSTOVC(ssp)->vc_rxmax, *len);
628	mb_put_uint16le(mbp, *len);	/* MaxCount */
629	mb_put_uint16le(mbp, *len);	/* MinCount (only indicates blocking) */
630	mb_put_uint32le(mbp, (unsigned)*len >> 16);	/* MaxCountHigh */
631	mb_put_uint16le(mbp, *len);	/* Remaining ("obsolete") */
632	mb_put_uint32le(mbp, uio->uio_offset >> 32);	/* OffsetHigh */
633	smb_rq_wend(rqp);
634	smb_rq_bstart(rqp);
635	smb_rq_bend(rqp);
636	do {
637		error = smb_rq_simple(rqp);
638		if (error)
639			break;
640		smb_rq_getreply(rqp, &mdp);
641		off = SMB_HDRLEN;
642		md_get_uint8(mdp, &wc);
643		off++;
644		if (wc != 12) {
645			error = EBADRPC;
646			break;
647		}
648		md_get_uint8(mdp, NULL);
649		off++;
650		md_get_uint8(mdp, NULL);
651		off++;
652		md_get_uint16le(mdp, NULL);
653		off += 2;
654		md_get_uint16le(mdp, NULL);
655		off += 2;
656		md_get_uint16le(mdp, NULL);	/* data compaction mode */
657		off += 2;
658		md_get_uint16le(mdp, NULL);
659		off += 2;
660		md_get_uint16le(mdp, &residlo);
661		off += 2;
662		md_get_uint16le(mdp, &doff);	/* data offset */
663		off += 2;
664		md_get_uint16le(mdp, &residhi);
665		off += 2;
666		resid = (residhi << 16) | residlo;
667		md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
668		off += 4*2;
669		md_get_uint16le(mdp, NULL);	/* ByteCount */
670		off += 2;
671		if (doff > off)	/* pad byte(s)? */
672			md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
673		if (resid == 0) {
674			*rresid = resid;
675			break;
676		}
677		error = md_get_uio(mdp, uio, resid);
678		if (error)
679			break;
680		*rresid = resid;
681	} while(0);
682	smb_rq_done(rqp);
683	return (error);
684}
685
686static __inline int
687smb_smb_writex(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
688	struct uio *uio, struct smb_cred *scred)
689{
690	struct smb_rq *rqp;
691	struct mbchain *mbp;
692	struct mdchain *mdp;
693	int error;
694	u_int8_t wc;
695	u_int16_t resid;
696
697	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
698	if (error)
699		return (error);
700	smb_rq_getrequest(rqp, &mbp);
701	smb_rq_wstart(rqp);
702	mb_put_uint8(mbp, 0xff);	/* no secondary command */
703	mb_put_uint8(mbp, 0);		/* MBZ */
704	mb_put_uint16le(mbp, 0);	/* offset to secondary */
705	mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
706	mb_put_uint32le(mbp, uio->uio_offset);
707	mb_put_uint32le(mbp, 0);	/* MBZ (timeout) */
708	mb_put_uint16le(mbp, 0);	/* !write-thru */
709	mb_put_uint16le(mbp, 0);
710	*len = min(SSTOVC(ssp)->vc_wxmax, *len);
711	mb_put_uint16le(mbp, (unsigned)*len >> 16);
712	mb_put_uint16le(mbp, *len);
713	mb_put_uint16le(mbp, 64);	/* data offset from header start */
714	mb_put_uint32le(mbp, uio->uio_offset >> 32);	/* OffsetHigh */
715	smb_rq_wend(rqp);
716	smb_rq_bstart(rqp);
717	do {
718		mb_put_uint8(mbp, 0xee);	/* mimic xp pad byte! */
719		error = mb_put_uio(mbp, uio, *len);
720		if (error)
721			break;
722		smb_rq_bend(rqp);
723		error = smb_rq_simple(rqp);
724		if (error)
725			break;
726		smb_rq_getreply(rqp, &mdp);
727		md_get_uint8(mdp, &wc);
728		if (wc != 6) {
729			error = EBADRPC;
730			break;
731		}
732		md_get_uint8(mdp, NULL);
733		md_get_uint8(mdp, NULL);
734		md_get_uint16le(mdp, NULL);
735		md_get_uint16le(mdp, &resid);
736		*rresid = resid;
737	} while(0);
738
739	smb_rq_done(rqp);
740	return (error);
741}
742
743static __inline int
744smb_smb_read(struct smb_share *ssp, u_int16_t fid,
745	int *len, int *rresid, struct uio *uio, struct smb_cred *scred)
746{
747	struct smb_rq *rqp;
748	struct mbchain *mbp;
749	struct mdchain *mdp;
750	u_int16_t resid, bc;
751	u_int8_t wc;
752	int error, rlen, blksz;
753
754	if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
755		return (smb_smb_readx(ssp, fid, len, rresid, uio, scred));
756
757	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
758	if (error)
759		return error;
760
761	blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
762	rlen = *len = min(blksz, *len);
763
764	smb_rq_getrequest(rqp, &mbp);
765	smb_rq_wstart(rqp);
766	mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
767	mb_put_uint16le(mbp, rlen);
768	mb_put_uint32le(mbp, uio->uio_offset);
769	mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
770	smb_rq_wend(rqp);
771	smb_rq_bstart(rqp);
772	smb_rq_bend(rqp);
773	do {
774		error = smb_rq_simple(rqp);
775		if (error)
776			break;
777		smb_rq_getreply(rqp, &mdp);
778		md_get_uint8(mdp, &wc);
779		if (wc != 5) {
780			error = EBADRPC;
781			break;
782		}
783		md_get_uint16le(mdp, &resid);
784		md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
785		md_get_uint16le(mdp, &bc);
786		md_get_uint8(mdp, NULL);		/* ignore buffer type */
787		md_get_uint16le(mdp, &resid);
788		if (resid == 0) {
789			*rresid = resid;
790			break;
791		}
792		error = md_get_uio(mdp, uio, resid);
793		if (error)
794			break;
795		*rresid = resid;
796	} while(0);
797	smb_rq_done(rqp);
798	return error;
799}
800
801int
802smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
803	struct smb_cred *scred)
804{
805	int tsize, len, resid;
806	int error = 0;
807
808	tsize = uio->uio_resid;
809	while (tsize > 0) {
810		len = tsize;
811		error = smb_smb_read(ssp, fid, &len, &resid, uio, scred);
812		if (error)
813			break;
814		tsize -= resid;
815		if (resid < len)
816			break;
817	}
818	return error;
819}
820
821static __inline int
822smb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
823	struct uio *uio, struct smb_cred *scred)
824{
825	struct smb_rq *rqp;
826	struct mbchain *mbp;
827	struct mdchain *mdp;
828	u_int16_t resid;
829	u_int8_t wc;
830	int error, blksz;
831
832	if (*len && SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
833		return (smb_smb_writex(ssp, fid, len, rresid, uio, scred));
834
835	blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
836	if (blksz > 0xffff)
837		blksz = 0xffff;
838
839	resid = *len = min(blksz, *len);
840
841	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
842	if (error)
843		return error;
844	smb_rq_getrequest(rqp, &mbp);
845	smb_rq_wstart(rqp);
846	mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
847	mb_put_uint16le(mbp, resid);
848	mb_put_uint32le(mbp, uio->uio_offset);
849	mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
850	smb_rq_wend(rqp);
851	smb_rq_bstart(rqp);
852	mb_put_uint8(mbp, SMB_DT_DATA);
853	mb_put_uint16le(mbp, resid);
854	do {
855		error = mb_put_uio(mbp, uio, resid);
856		if (error)
857			break;
858		smb_rq_bend(rqp);
859		error = smb_rq_simple(rqp);
860		if (error)
861			break;
862		smb_rq_getreply(rqp, &mdp);
863		md_get_uint8(mdp, &wc);
864		if (wc != 1) {
865			error = EBADRPC;
866			break;
867		}
868		md_get_uint16le(mdp, &resid);
869		*rresid = resid;
870	} while(0);
871	smb_rq_done(rqp);
872	return error;
873}
874
875int
876smb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
877	struct smb_cred *scred)
878{
879	int error = 0, len, tsize, resid;
880	struct uio olduio;
881
882	tsize = uio->uio_resid;
883	olduio = *uio;
884	while (tsize > 0) {
885		len = tsize;
886		error = smb_smb_write(ssp, fid, &len, &resid, uio, scred);
887		if (error)
888			break;
889		if (resid < len) {
890			error = EIO;
891			break;
892		}
893		tsize -= resid;
894	}
895	if (error) {
896		/*
897		 * Errors can happen on the copyin, the rpc, etc.  So they
898		 * imply resid is unreliable.  The only safe thing is
899		 * to pretend zero bytes made it.  We needn't restore the
900		 * iovs because callers don't depend on them in error
901		 * paths - uio_resid and uio_offset are what matter.
902		 */
903		*uio = olduio;
904	}
905	return error;
906}
907
908int
909smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred)
910{
911	struct smb_rq *rqp;
912	struct mbchain *mbp;
913	int error;
914
915	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
916	if (error)
917		return error;
918	mbp = &rqp->sr_rq;
919	smb_rq_wstart(rqp);
920	mb_put_uint16le(mbp, 1);
921	smb_rq_wend(rqp);
922	smb_rq_bstart(rqp);
923	mb_put_uint32le(mbp, 0);
924	smb_rq_bend(rqp);
925	error = smb_rq_simple(rqp);
926	SMBSDEBUG("%d\n", error);
927	smb_rq_done(rqp);
928	return error;
929}
930