xref: /freebsd/sys/netsmb/smb_smb.c (revision 5c52a79884070364bfc920fb8e492cfac61ec72f)
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 #include "opt_netsmb.h"
59 
60 struct smb_dialect {
61 	int		d_id;
62 	const char *	d_name;
63 };
64 
65 static 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 
79 static u_int32_t
80 smb_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 
97 static u_int32_t
98 smb_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 
110 static int
111 smb_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 
119 int
120 smb_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 	}
267 bad:
268 	smb_rq_done(rqp);
269 	return error;
270 }
271 
272 int
273 smb_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 
285 again:
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;
407 bad:
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 
416 int
417 smb_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 
446 static char smb_any_share[] = "?????";
447 
448 static char *
449 smb_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 
474 int
475 smb_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 
485 again:
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;
568 bad:
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 
579 int
580 smb_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 
603 static __inline int
604 smb_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 
684 static __inline int
685 smb_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 
741 static __inline int
742 smb_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 
799 int
800 smb_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 		resid = 0;
809 		len = tsize;
810 		error = smb_smb_read(ssp, fid, &len, &resid, uio, scred);
811 		if (error)
812 			break;
813 		tsize -= resid;
814 		if (resid < len)
815 			break;
816 	}
817 	return error;
818 }
819 
820 static __inline int
821 smb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
822 	struct uio *uio, struct smb_cred *scred)
823 {
824 	struct smb_rq *rqp;
825 	struct mbchain *mbp;
826 	struct mdchain *mdp;
827 	u_int16_t resid;
828 	u_int8_t wc;
829 	int error, blksz;
830 
831 	if (*len && SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
832 		return (smb_smb_writex(ssp, fid, len, rresid, uio, scred));
833 
834 	blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
835 	if (blksz > 0xffff)
836 		blksz = 0xffff;
837 
838 	resid = *len = min(blksz, *len);
839 
840 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
841 	if (error)
842 		return error;
843 	smb_rq_getrequest(rqp, &mbp);
844 	smb_rq_wstart(rqp);
845 	mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
846 	mb_put_uint16le(mbp, resid);
847 	mb_put_uint32le(mbp, uio->uio_offset);
848 	mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
849 	smb_rq_wend(rqp);
850 	smb_rq_bstart(rqp);
851 	mb_put_uint8(mbp, SMB_DT_DATA);
852 	mb_put_uint16le(mbp, resid);
853 	do {
854 		error = mb_put_uio(mbp, uio, resid);
855 		if (error)
856 			break;
857 		smb_rq_bend(rqp);
858 		error = smb_rq_simple(rqp);
859 		if (error)
860 			break;
861 		smb_rq_getreply(rqp, &mdp);
862 		md_get_uint8(mdp, &wc);
863 		if (wc != 1) {
864 			error = EBADRPC;
865 			break;
866 		}
867 		md_get_uint16le(mdp, &resid);
868 		*rresid = resid;
869 	} while(0);
870 	smb_rq_done(rqp);
871 	return error;
872 }
873 
874 int
875 smb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
876 	struct smb_cred *scred)
877 {
878 	int error = 0, len, tsize, resid;
879 	struct uio olduio;
880 
881 	tsize = uio->uio_resid;
882 	olduio = *uio;
883 	while (tsize > 0) {
884 		resid = 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 
908 int
909 smb_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