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