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