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