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