xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c (revision 3afe87ebb25691cb6d158edaa34a6fb9b703a691)
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  * $Id: smb_smb.c,v 1.35.100.2 2005/06/02 00:55:39 lindak Exp $
33  */
34 
35 /*
36  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37  * Use is subject to license terms.
38  */
39 
40 /*
41  * various SMB requests. Most of the routines merely packs data into mbufs.
42  */
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kmem.h>
46 #include <sys/proc.h>
47 #include <sys/lock.h>
48 #include <sys/socket.h>
49 #include <sys/uio.h>
50 #include <sys/random.h>
51 #include <sys/note.h>
52 #include <sys/cmn_err.h>
53 
54 #ifdef APPLE
55 #include <sys/smb_apple.h>
56 #include <sys/utfconv.h>
57 #else
58 #include <netsmb/smb_osdep.h>
59 #endif
60 
61 #include <netsmb/smb.h>
62 #include <netsmb/smb_conn.h>
63 #include <netsmb/smb_rq.h>
64 #include <netsmb/smb_subr.h>
65 #include <netsmb/smb_tran.h>
66 
67 /*
68  * Largest size to use with LARGE_READ/LARGE_WRITE.
69  * Specs say up to 64k data bytes, but Windows traffic
70  * uses 60k... no doubt for some good reason.
71  * (Probably to keep 4k block alignment.)
72  * XXX: Move to smb.h maybe?
73  */
74 #define	SMB_MAX_LARGE_RW_SIZE (60*1024)
75 
76 /*
77  * Default timeout values, all in seconds.
78  * Make these tunable (only via mdb for now).
79  */
80 int smb_timo_notice = 15;
81 int smb_timo_default = 30;	/* was SMB_DEFRQTIMO */
82 int smb_timo_open = 45;
83 int smb_timo_read = 45;
84 int smb_timo_write = 60;	/* was SMBWRTTIMO */
85 int smb_timo_append = 90;
86 
87 /*
88  * Debug/test feature to disable NTMLv2.
89  * Set this to zero to skip NTLMv2
90  */
91 int nsmb_enable_ntlmv2 = 1;
92 
93 static int smb_smb_read(struct smb_share *ssp, u_int16_t fid,
94 	uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
95 static int smb_smb_write(struct smb_share *ssp, u_int16_t fid,
96 	uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
97 
98 static int smb_smb_readx(struct smb_share *ssp, u_int16_t fid,
99 	uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
100 static int smb_smb_writex(struct smb_share *ssp, u_int16_t fid,
101 	uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
102 
103 struct smb_dialect {
104 	int		d_id;
105 	const char	*d_name;
106 };
107 
108 smb_unichar smb_unieol = 0;
109 
110 static struct smb_dialect smb_dialects[] = {
111 	{SMB_DIALECT_CORE,	"PC NETWORK PROGRAM 1.0"},
112 	{SMB_DIALECT_LANMAN1_0,	"LANMAN1.0"},
113 	{SMB_DIALECT_LANMAN2_0,	"LM1.2X002"},
114 	{SMB_DIALECT_LANMAN2_1,	"LANMAN2.1"},
115 	{SMB_DIALECT_NTLM0_12,	"NT LM 0.12"},
116 	{-1,			NULL}
117 };
118 
119 #define	SMB_DIALECT_MAX \
120 	(sizeof (smb_dialects) / sizeof (struct smb_dialect) - 2)
121 
122 /*
123  * Number of seconds between 1970 and 1601 year
124  */
125 const u_int64_t DIFF1970TO1601 = 11644473600ULL;
126 
127 void
128 smb_time_local2server(struct timespec *tsp, int tzoff, long *seconds)
129 {
130 	/*
131 	 * XXX - what if we connected to the server when it was in
132 	 * daylight savings/summer time and we've subsequently switched
133 	 * to standard time, or vice versa, so that the time zone
134 	 * offset we got from the server is now wrong?
135 	 */
136 	*seconds = tsp->tv_sec - tzoff * 60;
137 	/* - tz.tz_minuteswest * 60 - (wall_cmos_clock ? adjkerntz : 0) */
138 }
139 
140 void
141 smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp)
142 {
143 	/*
144 	 * XXX - what if we connected to the server when it was in
145 	 * daylight savings/summer time and we've subsequently switched
146 	 * to standard time, or vice versa, so that the time zone
147 	 * offset we got from the server is now wrong?
148 	 */
149 	tsp->tv_sec = seconds + tzoff * 60;
150 	    /* + tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); */
151 	tsp->tv_nsec = 0;
152 }
153 
154 /*
155  * Time from server comes as UTC, so no need to use tz
156  */
157 /*ARGSUSED*/
158 void
159 smb_time_NT2local(u_int64_t nsec, int tzoff, struct timespec *tsp)
160 {
161 	smb_time_server2local(nsec / 10000000 - DIFF1970TO1601, 0, tsp);
162 }
163 
164 /*ARGSUSED*/
165 void
166 smb_time_local2NT(struct timespec *tsp, int tzoff, u_int64_t *nsec)
167 {
168 	long seconds;
169 
170 	smb_time_local2server(tsp, 0, &seconds);
171 	*nsec = (((u_int64_t)(seconds) & ~1) + DIFF1970TO1601) *
172 	    (u_int64_t)10000000;
173 }
174 
175 #if defined(NOICONVSUPPORT) || defined(lint)
176 extern int iconv_open(const char *to, const char *from, void **handle);
177 extern int iconv_close(void *handle);
178 #endif
179 
180 int
181 smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
182 {
183 	struct smb_dialect *dp;
184 	struct smb_sopt *sp = NULL;
185 	struct smb_rq *rqp;
186 	struct mbchain *mbp;
187 	struct mdchain *mdp;
188 	u_int8_t wc, stime[8], sblen;
189 	u_int16_t dindex, tw, tw1, swlen, bc;
190 	int error;
191 	int unicode = 0;
192 	char *servercs;
193 	void *servercshandle = NULL;
194 	void *localcshandle = NULL;
195 	int negotiated_signing = 0;
196 	u_int16_t toklen;
197 
198 	/*
199 	 * We set various flags below to keep track of
200 	 * interesting things we learn from negotiation.
201 	 * Clear all the flags except these two, which
202 	 * are operational rather than protocol info.
203 	 */
204 	SMB_VC_LOCK(vcp);
205 	vcp->vc_flags &= (SMBV_GONE | SMBV_RECONNECTING);
206 	SMB_VC_UNLOCK(vcp);
207 
208 	/*
209 	 * Now vc_hflags and vc_hflags2.  Careful with this:
210 	 * Leave SMB_FLAGS2_UNICODE off so mb_put_dstring
211 	 * marshalls the dialect strings in plain ascii.
212 	 * We'll turn that on below, if appropriate.
213 	 *
214 	 * Note: These flags are marshalled into the request
215 	 * when we call smb_rq_alloc, so changing them after
216 	 * this point does not affect THIS request.
217 	 */
218 	vcp->vc_hflags = SMB_FLAGS_CASELESS;
219 	vcp->vc_hflags2 = (SMB_FLAGS2_ERR_STATUS |
220 	    SMB_FLAGS2_KNOWS_LONG_NAMES);
221 
222 	/* User-level may ask for extended security. */
223 	if (vcp->vc_vopt & SMBVOPT_EXT_SEC)
224 		vcp->vc_hflags2 |= SMB_FLAGS2_EXT_SEC;
225 
226 	/* Also clear any old key (for reconnect) */
227 	if (vcp->vc_mackey != NULL) {
228 		kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
229 		vcp->vc_mackey = NULL;
230 		vcp->vc_mackeylen = 0;
231 		vcp->vc_seqno = 0;
232 	}
233 
234 	sp = &vcp->vc_sopt;
235 	bzero(sp, sizeof (struct smb_sopt));
236 	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp);
237 	if (error)
238 		return (error);
239 	smb_rq_getrequest(rqp, &mbp);
240 	smb_rq_wstart(rqp);
241 	smb_rq_wend(rqp);
242 	smb_rq_bstart(rqp);
243 	for (dp = smb_dialects; dp->d_id != -1; dp++) {
244 		mb_put_uint8(mbp, SMB_DT_DIALECT);
245 		smb_put_dstring(mbp, vcp, dp->d_name, SMB_CS_NONE);
246 	}
247 	smb_rq_bend(rqp);
248 
249 	/*
250 	 * This request should not wait for
251 	 * connection state changes, etc.
252 	 */
253 	rqp->sr_flags |= SMBR_INTERNAL;
254 	error = smb_rq_simple(rqp);
255 	SMBSDEBUG("%d\n", error);
256 	if (error)
257 		goto bad;
258 
259 	smb_rq_getreply(rqp, &mdp);
260 	do {
261 		error = md_get_uint8(mdp, &wc);
262 		if (error)
263 			break;
264 		error = md_get_uint16le(mdp, &dindex);
265 		if (error)
266 			break;
267 		error = EBADRPC;
268 		if (dindex > SMB_DIALECT_MAX) {
269 			SMBERROR(
270 			    "Don't know how to talk with server %s (%d)\n",
271 			    vcp->vc_srvname, dindex);
272 			break;
273 		}
274 		dp = smb_dialects + dindex;
275 		if (dindex < SMB_DIALECT_MAX) {
276 			SMBERROR(
277 			    "Server %s negotiated old dialect (%s)\n",
278 			    vcp->vc_srvname, dp->d_name);
279 		}
280 		sp->sv_proto = dp->d_id;
281 		SMBSDEBUG("Dialect %s (%d, %d)\n", dp->d_name, dindex, wc);
282 		if (dp->d_id >= SMB_DIALECT_NTLM0_12) {
283 			if (wc != 17)
284 				break;
285 			md_get_uint8(mdp, &sp->sv_sm);
286 			md_get_uint16le(mdp, &sp->sv_maxmux);
287 			md_get_uint16le(mdp, &sp->sv_maxvcs);
288 			md_get_uint32le(mdp, &sp->sv_maxtx);
289 			md_get_uint32le(mdp, &sp->sv_maxraw);
290 			md_get_uint32le(mdp, &sp->sv_skey);
291 			md_get_uint32le(mdp, &sp->sv_caps);
292 			md_get_mem(mdp, (char *)stime, 8, MB_MSYSTEM);
293 			md_get_uint16le(mdp, (u_int16_t *)&sp->sv_tz);
294 			md_get_uint8(mdp, &sblen);
295 			error = md_get_uint16le(mdp, &bc);
296 			if (error)
297 				break;
298 
299 			/* BEGIN CSTYLED */
300 	/*
301 	 * Will we do SMB signing?  Or block the connection?
302 	 * The table below describes this logic.  References:
303 	 * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3]
304 	 * http://msdn.microsoft.com/en-us/library/cc212511.aspx
305 	 * http://msdn.microsoft.com/en-us/library/cc212929.aspx
306 	 *
307 	 * Srv/Cli     | Required | Enabled    | If Required | Disabled
308 	 * ------------+----------+------------+-------------+-----------
309 	 * Required    | Signed   | Signed     | Signed      | Blocked [1]
310 	 * ------------+----------+------------+-------------+-----------
311 	 * Enabled     | Signed   | Signed     | Not Signed  | Not Signed
312 	 * ------------+----------+------------+-------------+-----------
313 	 * If Required | Signed   | Not Signed | Not Signed  | Not Signed
314 	 * ------------+----------+------------+-------------+-----------
315 	 * Disabled    | Blocked  | Not Signed | Not Signed  | Not Signed
316 	 *
317 	 * [1] Like Windows 2003 and later, we don't really implement
318 	 * the "Disabled" setting.  Instead we implement "If Required",
319 	 * so we always sign if the server requires signing.
320 	 */
321 			/* END CSTYLED */
322 
323 			if (sp->sv_sm & SMB_SM_SIGS_REQUIRE) {
324 				/*
325 				 * Server requires signing.
326 				 */
327 				negotiated_signing = 1;
328 			} else if (sp->sv_sm & SMB_SM_SIGS) {
329 				/*
330 				 * Server enables signing (client's option).
331 				 * If enabled locally, do signing.
332 				 */
333 				if (vcp->vc_vopt & SMBVOPT_SIGNING_ENABLED)
334 					negotiated_signing = 1;
335 				/* else not signing. */
336 			} else {
337 				/*
338 				 * Server does not support signing.
339 				 * If we "require" it, bail now.
340 				 */
341 				if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
342 					SMBERROR("Client requires signing "
343 					    "but server has it disabled.\n");
344 					error = EBADRPC;
345 					break;
346 				}
347 			}
348 			SMBSDEBUG("Security signatures: %d\n",
349 			    negotiated_signing);
350 			if (negotiated_signing) {
351 				SMB_VC_LOCK(vcp);
352 				vcp->vc_flags |= SMBV_WILL_SIGN;
353 				SMB_VC_UNLOCK(vcp);
354 			}
355 
356 			if (sp->sv_caps & SMB_CAP_UNICODE) {
357 				SMB_VC_LOCK(vcp);
358 				vcp->vc_flags |= SMBV_UNICODE;
359 				SMB_VC_UNLOCK(vcp);
360 				unicode = 1;
361 			}
362 			if (!(sp->sv_caps & SMB_CAP_STATUS32)) {
363 				/*
364 				 * They don't do NT error codes.
365 				 *
366 				 * If we send requests with
367 				 * SMB_FLAGS2_ERR_STATUS set in
368 				 * Flags2, Windows 98, at least,
369 				 * appears to send replies with that
370 				 * bit set even though it sends back
371 				 * DOS error codes.  (They probably
372 				 * just use the request header as
373 				 * a template for the reply header,
374 				 * and don't bother clearing that bit.)
375 				 *
376 				 * Therefore, we clear that bit in
377 				 * our vc_hflags2 field.
378 				 */
379 				vcp->vc_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
380 			}
381 			if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
382 			    sp->sv_maxtx < 4096 &&
383 			    (sp->sv_caps & SMB_CAP_NT_SMBS) == 0) {
384 				SMB_VC_LOCK(vcp);
385 				vcp->vc_flags |= SMBV_WIN95;
386 				SMB_VC_UNLOCK(vcp);
387 				SMBSDEBUG("Win95 detected\n");
388 			}
389 
390 			/*
391 			 * 3 cases here:
392 			 *
393 			 * 1) Extended security.
394 			 * Read bc bytes below for security blob.
395 			 * Note that we DON'T put the Caps flag in outtok.
396 			 * outtoklen = bc
397 			 *
398 			 * 2) No extended security, have challenge data and
399 			 * possibly a domain name (which might be zero
400 			 * bytes long, meaning "missing").
401 			 * Copy challenge stuff to vcp->vc_ch (sblen bytes),
402 			 * then copy Cap flags and domain name (bc-sblen
403 			 * bytes) to outtok.
404 			 * outtoklen = bc-sblen+4, where the 4 is for the
405 			 * Caps flag.
406 			 *
407 			 * 3) No extended security, no challenge data, just
408 			 * possibly a domain name.
409 			 * Copy Capsflags and domain name (bc) to outtok.
410 			 * outtoklen = bc+4, where 4 is for the Caps flag
411 			 */
412 
413 			/*
414 			 * Sanity check: make sure the challenge length
415 			 * isn't bigger than the byte count.
416 			 */
417 			if (sblen > bc) {
418 				error = EBADRPC;
419 				break;
420 			}
421 			toklen = bc;
422 
423 			if (sblen && sblen <= SMB_MAXCHALLENGELEN &&
424 			    sp->sv_sm & SMB_SM_ENCRYPT) {
425 				error = md_get_mem(mdp,
426 				    (char *)vcp->vc_challenge,
427 				    sblen, MB_MSYSTEM);
428 				if (error)
429 					break;
430 				vcp->vc_chlen = sblen;
431 				toklen -= sblen;
432 
433 				SMB_VC_LOCK(vcp);
434 				vcp->vc_flags |= SMBV_ENCRYPT;
435 				SMB_VC_UNLOCK(vcp);
436 			}
437 
438 			/*
439 			 * For servers that don't support unicode
440 			 * there are 2 things we could do:
441 			 * 1) Pass the server Caps flags up to the
442 			 * user level so the logic up there will
443 			 * know whether the domain name is unicode
444 			 * (this is what I did).
445 			 * 2) Try to convert the non-unicode string
446 			 * to unicode. This doubles the length of
447 			 * the outtok buffer and would be guessing that
448 			 * the string was single-byte ascii, and that
449 			 * might be wrong. Why ask for trouble?
450 			 */
451 
452 			/* Warning: NetApp may omit the GUID */
453 
454 			if (!(sp->sv_caps & SMB_CAP_EXT_SECURITY)) {
455 				/*
456 				 * No extended security.
457 				 * Stick domain name, if present,
458 				 * and caps in outtok.
459 				 */
460 				toklen = toklen + 4; /* space for Caps flags */
461 				vcp->vc_outtoklen =  toklen;
462 				vcp->vc_outtok = kmem_alloc(toklen, KM_SLEEP);
463 				/* first store server capability bits */
464 				/*LINTED*/
465 				ASSERT(vcp->vc_outtok ==
466 				    (caddr_t)(((u_int32_t *)vcp->vc_outtok)));
467 				/*LINTED*/
468 				*(u_int32_t *)(vcp->vc_outtok) = sp->sv_caps;
469 
470 				/*
471 				 * Then store the domain name if present;
472 				 * be sure to subtract 4 from the length
473 				 * for the Caps flag.
474 				 */
475 				if (toklen > 4) {
476 					error = md_get_mem(mdp,
477 					    vcp->vc_outtok+4, toklen-4,
478 					    MB_MSYSTEM);
479 				}
480 			} else {
481 				/*
482 				 * Extended security.
483 				 * Stick the rest of the buffer in outtok.
484 				 */
485 				vcp->vc_outtoklen =  toklen;
486 				vcp->vc_outtok = kmem_alloc(toklen, KM_SLEEP);
487 				error = md_get_mem(mdp, vcp->vc_outtok, toklen,
488 				    MB_MSYSTEM);
489 			}
490 			break;
491 		}
492 		vcp->vc_hflags2 &= ~(SMB_FLAGS2_EXT_SEC|SMB_FLAGS2_DFS|
493 		    SMB_FLAGS2_ERR_STATUS|SMB_FLAGS2_UNICODE);
494 		if (dp->d_id > SMB_DIALECT_CORE) {
495 			md_get_uint16le(mdp, &tw);
496 			sp->sv_sm = (uchar_t)tw;
497 			md_get_uint16le(mdp, &tw);
498 			sp->sv_maxtx = tw;
499 			md_get_uint16le(mdp, &sp->sv_maxmux);
500 			md_get_uint16le(mdp, &sp->sv_maxvcs);
501 			md_get_uint16le(mdp, &tw);	/* rawmode */
502 			md_get_uint32le(mdp, &sp->sv_skey);
503 			if (wc == 13) {		/* >= LANMAN1 */
504 				md_get_uint16(mdp, &tw);	/* time */
505 				md_get_uint16(mdp, &tw1);	/* date */
506 				md_get_uint16le(mdp, (u_int16_t *)&sp->sv_tz);
507 				md_get_uint16le(mdp, &swlen);
508 				if (swlen > SMB_MAXCHALLENGELEN)
509 					break;
510 				md_get_uint16(mdp, NULL);	/* mbz */
511 				if (md_get_uint16le(mdp, &bc) != 0)
512 					break;
513 				if (bc < swlen)
514 					break;
515 				if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) {
516 					error = md_get_mem(mdp,
517 					    (char *)vcp->vc_challenge,
518 					    swlen, MB_MSYSTEM);
519 					if (error)
520 						break;
521 					vcp->vc_chlen = swlen;
522 
523 					SMB_VC_LOCK(vcp);
524 					vcp->vc_flags |= SMBV_ENCRYPT;
525 					SMB_VC_UNLOCK(vcp);
526 				}
527 			}
528 		} else {	/* an old CORE protocol */
529 			vcp->vc_hflags2 &= ~SMB_FLAGS2_KNOWS_LONG_NAMES;
530 			sp->sv_maxmux = 1;
531 		}
532 		error = 0;
533 		/*LINTED*/
534 	} while (0);
535 	if (error == 0) {
536 		uint32_t x;
537 
538 		/*
539 		 * Maximum outstanding requests.
540 		 */
541 		if (vcp->vc_maxmux < 1)
542 			vcp->vc_maxmux = 1;
543 
544 		/*
545 		 * Max VCs between server and client.
546 		 * We only use one.
547 		 */
548 		vcp->vc_maxvcs = sp->sv_maxvcs;
549 		if (vcp->vc_maxvcs < 1)
550 			vcp->vc_maxvcs = 1;
551 
552 		/*
553 		 * Maximum transfer size.
554 		 * Sanity checks:
555 		 *
556 		 * Spec. says lower limit is 1024.  OK.
557 		 *
558 		 * Let's be conservative about an upper limit here.
559 		 * Win2k uses 16644 (and others) so 32k should be a
560 		 * reasonable sanity limit for this value.
561 		 *
562 		 * Note that this limit does NOT affect READX/WRITEX
563 		 * with CAP_LARGE_xxx, which we nearly always use.
564 		 */
565 		vcp->vc_txmax = sp->sv_maxtx;
566 		if (vcp->vc_txmax < 1024)
567 			vcp->vc_txmax = 1024;
568 		if (vcp->vc_txmax > 0x8000)
569 			vcp->vc_txmax = 0x8000;
570 
571 		/*
572 		 * Max read/write sizes, WITHOUT overhead.
573 		 * This is just the payload size, so we must
574 		 * leave room for the SMB headers, etc.
575 		 * This is just the vc_txmax value, but
576 		 * reduced and rounded down.  Tricky bit:
577 		 *
578 		 * Servers typically give us a value that's
579 		 * some nice "round" number, i.e 0x4000 plus
580 		 * some overhead, i.e. Win2k: 16644==0x4104
581 		 * Subtract for the SMB header (32) and the
582 		 * SMB command word and byte vectors (34?),
583 		 * then round down to a 512 byte multiple.
584 		 */
585 		x = (vcp->vc_txmax - 68) & 0xFE00;
586 		vcp->vc_rxmax = x;
587 		vcp->vc_wxmax = x;
588 
589 		SMBSDEBUG("TZ = %d\n", sp->sv_tz);
590 		SMBSDEBUG("CAPS = %x\n", sp->sv_caps);
591 
592 		SMBSDEBUG("maxmux = %d\n", vcp->vc_maxmux);
593 		SMBSDEBUG("maxvcs = %d\n", vcp->vc_maxvcs);
594 		SMBSDEBUG("txmax = %d\n", vcp->vc_txmax);
595 		SMBSDEBUG("rxmax = %d\n", vcp->vc_rxmax);
596 		SMBSDEBUG("wxmax = %d\n", vcp->vc_wxmax);
597 	}
598 
599 	/*
600 	 * If the server supports Unicode, set up to use Unicode
601 	 * when talking to them.  Othewise, use code page 437.
602 	 */
603 	if (unicode)
604 		servercs = "ucs-2";
605 	else {
606 		/*
607 		 * todo: if we can't determine the server's encoding, we
608 		 * need to try a best-guess here.
609 		 */
610 		servercs = "cp437";
611 	}
612 #if defined(NOICONVSUPPORT) || defined(lint)
613 	/*
614 	 * REVISIT
615 	 */
616 	error = iconv_open(servercs, "utf-8", &servercshandle);
617 	if (error != 0)
618 		goto bad;
619 	error = iconv_open("utf-8", servercs, &localcshandle);
620 	if (error != 0) {
621 		iconv_close(servercshandle);
622 		goto bad;
623 	}
624 	if (vcp->vc_toserver)
625 		iconv_close(vcp->vc_toserver);
626 	if (vcp->vc_tolocal)
627 		iconv_close(vcp->vc_tolocal);
628 	vcp->vc_toserver = servercshandle;
629 	vcp->vc_tolocal  = localcshandle;
630 #endif
631 	if (unicode)
632 		vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE;
633 bad:
634 	smb_rq_done(rqp);
635 	return (error);
636 }
637 
638 static void
639 get_ascii_password(struct smb_vc *vcp, int upper, char *pbuf)
640 {
641 	const char *pw = smb_vc_getpass(vcp);
642 	if (upper)
643 		smb_toupper(pw, pbuf, SMB_MAXPASSWORDLEN);
644 	else
645 		strncpy(pbuf, pw, SMB_MAXPASSWORDLEN);
646 	pbuf[SMB_MAXPASSWORDLEN] = '\0';
647 }
648 
649 #ifdef APPLE
650 static void
651 get_unicode_password(struct smb_vc *vcp, char *pbuf)
652 {
653 	strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN);
654 	pbuf[SMB_MAXPASSWORDLEN] = '\0';
655 }
656 #endif
657 
658 /*ARGSUSED*/
659 static uchar_t *
660 add_name_to_blob(uchar_t *blobnames, struct smb_vc *vcp, const uchar_t *name,
661     size_t namelen, int nametype, int uppercase)
662 {
663 	struct ntlmv2_namehdr namehdr;
664 	char *namebuf;
665 	u_int16_t *uninamebuf;
666 	size_t uninamelen;
667 
668 	if (name != NULL) {
669 		uninamebuf = kmem_alloc(2 * namelen, KM_SLEEP);
670 		if (uppercase) {
671 			namebuf = kmem_alloc(namelen + 1, KM_SLEEP);
672 			smb_toupper((const char *)name, namebuf, namelen);
673 			namebuf[namelen] = '\0';
674 			uninamelen = smb_strtouni(uninamebuf, namebuf, namelen,
675 			    UCONV_IGNORE_NULL);
676 			kmem_free(namebuf, namelen + 1);
677 		} else {
678 			uninamelen = smb_strtouni(uninamebuf, (char *)name,
679 			    namelen, UCONV_IGNORE_NULL);
680 		}
681 	} else {
682 		uninamelen = 0;
683 		uninamebuf = NULL;
684 	}
685 	namehdr.type = htoles(nametype);
686 	namehdr.len = htoles(uninamelen);
687 	bcopy(&namehdr, blobnames, sizeof (namehdr));
688 	blobnames += sizeof (namehdr);
689 	if (uninamebuf != NULL) {
690 		bcopy(uninamebuf, blobnames, uninamelen);
691 		blobnames += uninamelen;
692 		kmem_free(uninamebuf, namelen * 2);
693 	}
694 	return (blobnames);
695 }
696 
697 static uchar_t *
698 make_ntlmv2_blob(struct smb_vc *vcp, u_int64_t client_nonce,
699 	size_t *bloblen, size_t *blob_allocsz)
700 {
701 	uchar_t *blob;
702 	size_t blobsize;
703 	size_t domainlen, srvlen;
704 	struct ntlmv2_blobhdr *blobhdr;
705 	struct timespec now;
706 	u_int64_t timestamp;
707 	uchar_t *blobnames;
708 	ptrdiff_t diff;
709 
710 	/*
711 	 * XXX - the information at
712 	 *
713 	 * http://davenport.sourceforge.net/ntlm.html#theNtlmv2Response
714 	 *
715 	 * says that the "target information" comes from the Type 2 message,
716 	 * but, as we're not doing NTLMSSP, we don't have that.
717 	 *
718 	 * Should we use the names from the NegProt response?  Can we trust
719 	 * the NegProt response?  (I've seen captures where the primary
720 	 * domain name has an extra byte in front of it.)
721 	 *
722 	 * For now, we don't trust it - we use vcp->vc_domain and
723 	 * vcp->vc_srvname, instead.  We upper-case them and convert
724 	 * them to Unicode, as that's what's supposed to be in the blob.
725 	 */
726 	domainlen = strlen(vcp->vc_domain);
727 	srvlen = strlen(vcp->vc_srvname);
728 	blobsize = sizeof (struct ntlmv2_blobhdr)
729 	    + 3*sizeof (struct ntlmv2_namehdr) + 4 + 2*domainlen + 2*srvlen;
730 	*blob_allocsz = blobsize;
731 	blobhdr = kmem_zalloc(blobsize, KM_SLEEP);
732 	blob = (uchar_t *)blobhdr;
733 	blobhdr->header = htolel(0x00000101);
734 	gethrestime(&now);
735 	smb_time_local2NT(&now, 0, &timestamp);
736 	blobhdr->timestamp = htoleq(timestamp);
737 	blobhdr->client_nonce = client_nonce;
738 	blobnames = blob + sizeof (struct ntlmv2_blobhdr);
739 	blobnames = add_name_to_blob(blobnames, vcp, (uchar_t *)vcp->vc_domain,
740 	    domainlen, NAMETYPE_DOMAIN_NB, 1);
741 	blobnames = add_name_to_blob(blobnames, vcp, (uchar_t *)vcp->vc_srvname,
742 	    srvlen, NAMETYPE_MACHINE_NB, 1);
743 	blobnames = add_name_to_blob(blobnames, vcp, NULL, 0, NAMETYPE_EOL, 0);
744 	diff = (intptr_t)blobnames - (intptr_t)blob;
745 	ASSERT(diff == (ptrdiff_t)((size_t)diff));
746 	*bloblen = (size_t)diff;
747 	return (blob);
748 }
749 
750 /*
751  * When not doing Kerberos, we can try, in order:
752  *
753  *	NTLMv2
754  *	NTLM (and maybe LM)
755  *
756  * if the server supports encrypted passwords, or
757  *
758  *	plain-text with the ASCII password not upper-cased
759  *	plain-text with the ASCII password upper-cased
760  *
761  * if it doesn't.
762  */
763 typedef enum {
764 	ClearUC,	/* Cleartext p/w, upper case */
765 	ClearMC,	/* Cleartext p/w, mixed case */
766 	NTLMv1,
767 	NTLMv2,
768 	ExtSec,		/* Extended Security (Kerberos) */
769 	NullSes		/* Null session (keep last) */
770 } authtype_t;
771 
772 int
773 smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
774 {
775 	struct smb_rq *rqp;
776 	struct mbchain *mbp;
777 	struct mdchain *mdp;
778 	u_int8_t wc;
779 	int minauth;
780 	smb_uniptr unipp = NULL, ntencpass = NULL;
781 	char *pp = NULL, *up = NULL, *ucup = NULL;
782 	char *ucdp = vcp->vc_domain; /* already upper case */
783 	char *encpass = NULL;
784 	int error = 0;
785 	size_t plen = 0, plen_alloc = 0;
786 	size_t uniplen = 0, uniplen_alloc = 0;
787 	size_t ucup_sl = 0;
788 	authtype_t authtype;
789 	size_t ntlmv2_bloblen, ntlmv2_blob_allocsz;
790 	uchar_t *ntlmv2_blob;
791 	u_int64_t client_nonce;
792 	u_int32_t caps;
793 	u_int16_t bl; /* BLOB length */
794 	u_int16_t bc; /* byte count */
795 	u_int16_t action;
796 	u_int16_t rpflags2;
797 	int declinedguest = 0;
798 	uchar_t v2hash[16];
799 	static const char NativeOS[] = "Solaris";
800 	static const char LanMan[] = "NETSMB";
801 	/*
802 	 * Most of the "capability" bits we offer should be copied
803 	 * from those offered by the server, with a mask applied.
804 	 * This is the mask of capabilies copied from the server.
805 	 * Some others get special handling below.
806 	 */
807 	static const uint32_t caps_mask =
808 	    SMB_CAP_UNICODE |
809 	    SMB_CAP_LARGE_FILES |
810 	    SMB_CAP_NT_SMBS |
811 	    SMB_CAP_STATUS32;
812 
813 	caps = vcp->vc_sopt.sv_caps & caps_mask;
814 	minauth = vcp->vc_vopt & SMBVOPT_MINAUTH;
815 
816 	/*
817 	 * This function tries authentication types in a
818 	 * sequence going stronger to weaker, until it
819 	 * succeeds or runs into "minauth" and fails.
820 	 *
821 	 * Extended security is a special case because
822 	 * fall-back requires a return to user-level and
823 	 * a new connection, new SMB negotiate, etc.
824 	 * Null session is also special - no fall-back.
825 	 *
826 	 * Otherwise if the server supports encryption,
827 	 * try NTLMv2, then NTLM, etc.
828 	 */
829 	if (vcp->vc_intok)
830 		authtype = ExtSec;
831 	else if (vcp->vc_username[0] == '\0')
832 		authtype = NullSes;
833 	else if ((vcp->vc_sopt.sv_sm & SMB_SM_USER) == 0) {
834 		/* Share-level security. */
835 		authtype = NullSes;
836 	} else {
837 		/* Have SMB_SM_USER.  Encryption? */
838 		if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
839 			if (nsmb_enable_ntlmv2)
840 				authtype = NTLMv2;
841 			else
842 				authtype = NTLMv1;
843 		} else {
844 			/*
845 			 * This is normally disallowed
846 			 * by the minauth check below.
847 			 */
848 			authtype = ClearMC;
849 		}
850 	}
851 
852 	/*
853 	 * If server does not support encryption,
854 	 * disable unicode too.  (Spec. for this?)
855 	 */
856 	if ((vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) == 0) {
857 		if (vcp->vc_flags & SMBV_UNICODE) {
858 			vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
859 			vcp->vc_toserver = 0;
860 		}
861 	}
862 
863 again:
864 	SMBSDEBUG("authtype = %d\n", authtype);
865 
866 	/*
867 	 * Now disallow auth. types that fall below
868 	 * the minimum strength configured.
869 	 * We hold no kmem here.
870 	 */
871 	switch (minauth) {
872 
873 	case SMBVOPT_MINAUTH_NONE:
874 		break;
875 
876 	case SMBVOPT_MINAUTH_LM:
877 	case SMBVOPT_MINAUTH_NTLM:
878 		if (authtype < NTLMv1) {
879 			error = EAUTH;
880 			goto ssn_exit;
881 		}
882 		break;
883 
884 	case SMBVOPT_MINAUTH_NTLMV2:
885 		if (authtype < NTLMv2) {
886 			error = EAUTH;
887 			goto ssn_exit;
888 		}
889 		break;
890 
891 	case SMBVOPT_MINAUTH_KERBEROS:
892 		if (authtype < ExtSec) {
893 			error = EAUTH;
894 			goto ssn_exit;
895 		}
896 		break;
897 
898 	default:
899 		SMBSDEBUG("bad minauth 0x%x\n", minauth);
900 		error = EAUTH;
901 		goto ssn_exit;
902 	}
903 
904 	/*
905 	 * See comment in smb_iod_sendrq()
906 	 * about vc_smbuid initialization.
907 	 */
908 	vcp->vc_smbuid = SMB_UID_UNKNOWN;
909 
910 	/*
911 	 * Within this switch, we may allocate either or both:
912 	 * encpass, ntencpass (len: plen_alloc, uniplen_alloc)
913 	 * and will free these below (see the label "bad")
914 	 */
915 	switch (authtype) {
916 
917 	case ExtSec:
918 		/*
919 		 * With extended security, the whole blob is
920 		 * passed in from user-level (vc_intok)
921 		 */
922 		ASSERT(vcp->vc_intok != NULL);
923 		caps |= SMB_CAP_EXT_SECURITY;
924 		/* XXX Need Session Key  */
925 		if (vcp->vc_intoklen > 65536 ||
926 		    !(vcp->vc_hflags2 & SMB_FLAGS2_EXT_SEC) ||
927 		    SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) {
928 			/* We hold no kmem here. */
929 			error = EINVAL;
930 			goto ssn_exit;
931 		}
932 		vcp->vc_smbuid = 0;
933 		break;
934 
935 	case NullSes:
936 		pp = "";
937 		plen = 1;
938 		unipp = &smb_unieol;
939 		uniplen = sizeof (smb_unieol);
940 		break;
941 
942 	case NTLMv2:
943 		/*
944 		 * Compute the LMv2 and NTLMv2 responses,
945 		 * derived from the challenge, the user name,
946 		 * the domain/workgroup into which we're
947 		 * logging, and the Unicode password.
948 		 */
949 
950 		/*
951 		 * Construct the client nonce by getting
952 		 * a bunch of random data.
953 		 */
954 		(void) random_get_pseudo_bytes((void *)
955 		    &client_nonce,  sizeof (client_nonce));
956 
957 		/*
958 		 * Convert the user name to upper-case, as
959 		 * that's what's used when computing LMv2
960 		 * and NTLMv2 responses.
961 		 */
962 		ucup_sl = strlen(vcp->vc_username);
963 		ucup = kmem_alloc(ucup_sl + 1, KM_SLEEP);
964 		smb_toupper((const char *)vcp->vc_username,
965 		    ucup, ucup_sl);
966 		ucup[ucup_sl] = '\0';
967 
968 		/*
969 		 * Compute the NTLMv2 hash, which is
970 		 * derived from the NTLMv1 hash and
971 		 * the upper-case user + domain.
972 		 */
973 		smb_ntlmv2hash(vcp->vc_nthash,
974 		    ucup, ucdp, v2hash);
975 
976 		/*
977 		 * Compute the LMv2 response, derived from
978 		 * the v2hash, the server challenge, and
979 		 * the client nonce (random bits).
980 		 * Note: kmem_alloc encpass (plen)
981 		 */
982 		smb_ntlmv2response(v2hash,
983 		    vcp->vc_challenge,
984 		    (uchar_t *)&client_nonce, 8,
985 		    (uchar_t **)&encpass, &plen);
986 		plen_alloc = plen;
987 		pp = encpass;
988 
989 		/*
990 		 * Construct the blob.
991 		 * Note: kmem_alloc ntlmv2_blob
992 		 */
993 		ntlmv2_blob = make_ntlmv2_blob(vcp,
994 		    client_nonce, &ntlmv2_bloblen,
995 		    &ntlmv2_blob_allocsz);
996 
997 		/*
998 		 * Compute the NTLMv2 response, derived
999 		 * from the server challenge, the
1000 		 * user name, the domain/workgroup
1001 		 * into which we're logging, the
1002 		 * blob, and the v2 hash.
1003 		 * Note: kmem_alloc ntencpass (uniplen)
1004 		 */
1005 		smb_ntlmv2response(v2hash,
1006 		    vcp->vc_challenge,
1007 		    ntlmv2_blob, ntlmv2_bloblen,
1008 		    (uchar_t **)&ntencpass, &uniplen);
1009 		uniplen_alloc = uniplen;
1010 		unipp = ntencpass;
1011 
1012 		/*
1013 		 * If we negotiated signing, compute the MAC key
1014 		 * and start signing messages, but only on the
1015 		 * first non-null session login.
1016 		 */
1017 		if ((vcp->vc_flags & SMBV_WILL_SIGN) &&
1018 		    !(vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)) {
1019 			vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
1020 			smb_calcv2mackey(vcp, v2hash,
1021 			    (uchar_t *)ntencpass, uniplen);
1022 		}
1023 		kmem_free(ucup, ucup_sl + 1);
1024 		kmem_free(ntlmv2_blob, ntlmv2_blob_allocsz);
1025 		break;
1026 
1027 	case NTLMv1:
1028 		/*
1029 		 * Compute the LM response, derived
1030 		 * from the challenge and the ASCII
1031 		 * password.  (If minauth allows it.)
1032 		 */
1033 		plen_alloc = plen = 24;
1034 		encpass = kmem_zalloc(plen, KM_SLEEP);
1035 		if (minauth < SMBVOPT_MINAUTH_NTLM) {
1036 			smb_lmresponse(vcp->vc_lmhash,
1037 			    vcp->vc_challenge,
1038 			    (uchar_t *)encpass);
1039 		}
1040 		pp = encpass;
1041 
1042 		/*
1043 		 * Compute the NTLM response, derived from
1044 		 * the challenge and the NT hash.
1045 		 */
1046 		uniplen_alloc = uniplen = 24;
1047 		ntencpass = kmem_alloc(uniplen, KM_SLEEP);
1048 		smb_lmresponse(vcp->vc_nthash,
1049 		    vcp->vc_challenge,
1050 		    (uchar_t *)ntencpass);
1051 		unipp = ntencpass;
1052 
1053 		/*
1054 		 * If we negotiated signing, compute the MAC key
1055 		 * and start signing messages, but only on the
1056 		 * first non-null session login.
1057 		 */
1058 		if ((vcp->vc_flags & SMBV_WILL_SIGN) &&
1059 		    !(vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)) {
1060 			vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
1061 			smb_calcmackey(vcp, vcp->vc_nthash,
1062 			    (uchar_t *)ntencpass, uniplen);
1063 		}
1064 		break;
1065 
1066 	case ClearMC:
1067 	case ClearUC:
1068 		/*
1069 		 * We try w/o uppercasing first so Samba mixed case
1070 		 * passwords work.  If that fails, we come back and
1071 		 * try uppercasing to satisfy OS/2 and Windows for
1072 		 * Workgroups.
1073 		 */
1074 		plen_alloc = plen = SMB_MAXPASSWORDLEN + 1;
1075 		encpass = kmem_zalloc(plen, KM_SLEEP);
1076 		get_ascii_password(vcp, (authtype == ClearUC), encpass);
1077 		plen = strlen(encpass) + 1;
1078 		pp = encpass;
1079 		uniplen_alloc = uniplen = plen * 2;
1080 		ntencpass = kmem_alloc(uniplen, KM_SLEEP);
1081 		(void) smb_strtouni(ntencpass, smb_vc_getpass(vcp), 0, 0);
1082 		plen--;
1083 		/*
1084 		 * The uniplen is zeroed because Samba cannot deal
1085 		 * with this 2nd cleartext password.  This Samba
1086 		 * "bug" is actually a workaround for problems in
1087 		 * Microsoft clients.
1088 		 */
1089 		uniplen = 0; /* -= 2 */
1090 		unipp = ntencpass;
1091 		break;
1092 
1093 	default:
1094 		ASSERT(0);
1095 		error = EAUTH;
1096 		goto ssn_exit;
1097 
1098 	} /* switch authtype */
1099 
1100 
1101 	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX,
1102 	    scred, &rqp);
1103 	if (error)
1104 		goto bad;
1105 
1106 	/*
1107 	 * Build the request.
1108 	 */
1109 	smb_rq_wstart(rqp);
1110 	mbp = &rqp->sr_rq;
1111 	up = vcp->vc_username;
1112 	/*
1113 	 * If userid is null we are attempting anonymous browse login
1114 	 * so passwords must be zero length.
1115 	 */
1116 	if (*up == '\0') {
1117 		plen = uniplen = 0;
1118 	}
1119 	mb_put_uint8(mbp, 0xff);
1120 	mb_put_uint8(mbp, 0);
1121 	mb_put_uint16le(mbp, 0);
1122 	mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx);
1123 	mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux);
1124 	mb_put_uint16le(mbp, vcp->vc_number);
1125 	mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey);
1126 	if ((SMB_DIALECT(vcp)) < SMB_DIALECT_NTLM0_12) {
1127 		mb_put_uint16le(mbp, plen);
1128 		mb_put_uint32le(mbp, 0);
1129 		smb_rq_wend(rqp);
1130 		smb_rq_bstart(rqp);
1131 		mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
1132 		smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* user */
1133 		smb_put_dstring(mbp, vcp, ucdp, SMB_CS_NONE); /* domain */
1134 	} else {
1135 		if (vcp->vc_intok) {
1136 			mb_put_uint16le(mbp, vcp->vc_intoklen);
1137 			mb_put_uint32le(mbp, 0);		/* reserved */
1138 			mb_put_uint32le(mbp, caps);		/* my caps */
1139 			smb_rq_wend(rqp);
1140 			smb_rq_bstart(rqp);
1141 			mb_put_mem(mbp, vcp->vc_intok, vcp->vc_intoklen,
1142 			    MB_MSYSTEM);	/* security blob */
1143 		} else {
1144 			mb_put_uint16le(mbp, plen);
1145 			mb_put_uint16le(mbp, uniplen);
1146 			mb_put_uint32le(mbp, 0);		/* reserved */
1147 			mb_put_uint32le(mbp, caps);		/* my caps */
1148 			smb_rq_wend(rqp);
1149 			smb_rq_bstart(rqp);
1150 			mb_put_mem(mbp, pp, plen, MB_MSYSTEM); /* password */
1151 			mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM);
1152 			smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* user */
1153 			smb_put_dstring(mbp, vcp, ucdp, SMB_CS_NONE); /* dom */
1154 		}
1155 	}
1156 	smb_put_dstring(mbp, vcp, NativeOS, SMB_CS_NONE); /* OS */
1157 	smb_put_dstring(mbp, vcp, LanMan, SMB_CS_NONE); /* LAN Mgr */
1158 	smb_rq_bend(rqp);
1159 
1160 	/*
1161 	 * This request should not wait for
1162 	 * connection state changes, etc.
1163 	 */
1164 	rqp->sr_flags |= SMBR_INTERNAL;
1165 	error = smb_rq_simple_timed(rqp, SMBSSNSETUPTIMO);
1166 	SMBSDEBUG("%d\n", error);
1167 	if (error) {
1168 		if (rqp->sr_errclass == ERRDOS &&
1169 		    rqp->sr_serror == ERRnoaccess)
1170 			error = EAUTH;
1171 		if (!(rqp->sr_errclass == ERRDOS &&
1172 		    rqp->sr_serror == ERRmoredata))
1173 			goto bad;
1174 	}
1175 
1176 	/*
1177 	 * Parse the reply
1178 	 */
1179 	rpflags2 = rqp->sr_rpflags2;
1180 	vcp->vc_smbuid = rqp->sr_rpuid;
1181 	smb_rq_getreply(rqp, &mdp);
1182 	error = md_get_uint8(mdp, &wc);
1183 	if (error)
1184 		goto bad;
1185 	error = EBADRPC;
1186 	if (vcp->vc_intok) {
1187 		if (wc != 4)
1188 			goto bad;
1189 	} else if (wc != 3)
1190 		goto bad;
1191 	md_get_uint8(mdp, NULL);	/* secondary cmd */
1192 	md_get_uint8(mdp, NULL);	/* mbz */
1193 	md_get_uint16le(mdp, NULL);	/* andxoffset */
1194 	md_get_uint16le(mdp, &action);	/* action */
1195 	if (vcp->vc_intok)
1196 		md_get_uint16le(mdp, &bl);	/* ext security */
1197 	md_get_uint16le(mdp, &bc); /* byte count */
1198 	if (vcp->vc_intok) {
1199 		vcp->vc_outtoklen = bl;
1200 		vcp->vc_outtok = kmem_alloc(bl, KM_SLEEP);
1201 		error = md_get_mem(mdp, vcp->vc_outtok, bl, MB_MSYSTEM);
1202 		if (error)
1203 			goto bad;
1204 	}
1205 
1206 	/*
1207 	 * Server OS, LANMGR, & Domain follow here.
1208 	 * XXX: Should store these strings (later).
1209 	 *
1210 	 * Windows systems do not suport CAP_LARGE_...
1211 	 * when signing is enabled, so adjust sv_caps.
1212 	 * Match first 8 characters of server's OS
1213 	 * with the UCS-2LE string: "Windows "
1214 	 */
1215 	if (bc > 16) {
1216 		static const char WindowsU[16] =
1217 		    "W\0i\0n\0d\0o\0w\0s\0 ";
1218 		char osbuf[16];
1219 
1220 		/* align(2) */
1221 		if (((uintptr_t)mdp->md_pos) & 1)
1222 			md_get_uint8(mdp, NULL);
1223 
1224 		bzero(osbuf, sizeof (osbuf));
1225 		md_get_mem(mdp, osbuf, sizeof (osbuf), MB_MSYSTEM);
1226 		if (0 == bcmp(WindowsU, osbuf, sizeof (osbuf))) {
1227 			SMBSDEBUG("Server is Windows\n");
1228 			if (vcp->vc_flags & SMBV_WILL_SIGN) {
1229 				SMBSDEBUG("disable CAP_LARGE_(r/w)\n");
1230 				vcp->vc_sopt.sv_caps &=
1231 				    ~(SMB_CAP_LARGE_READX
1232 				    | SMB_CAP_LARGE_WRITEX);
1233 			}
1234 		}
1235 	}
1236 
1237 	/* success! */
1238 	error = 0;
1239 
1240 bad:
1241 
1242 	/*
1243 	 * When authentication fails and we're (possibly) doing
1244 	 * fall-back to another method, we have to reset things.
1245 	 */
1246 	if (error && vcp->vc_mackey) {
1247 		vcp->vc_hflags2 &= ~SMB_FLAGS2_SECURITY_SIGNATURE;
1248 		kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
1249 		vcp->vc_mackey = NULL;
1250 		vcp->vc_mackeylen = 0;
1251 		vcp->vc_seqno = 0;
1252 	}
1253 
1254 	if (rqp) {
1255 		smb_rq_done(rqp);
1256 		rqp = NULL;
1257 	}
1258 	if (encpass) {
1259 		kmem_free(encpass, plen_alloc);
1260 		encpass = NULL;
1261 	}
1262 	if (ntencpass) {
1263 		kmem_free(ntencpass, uniplen_alloc);
1264 		ntencpass = NULL;
1265 	}
1266 
1267 	/*
1268 	 * Shall we try again with another auth type?
1269 	 * Note: We hold no kmem here.
1270 	 */
1271 	switch (authtype) {
1272 
1273 	case NullSes:
1274 	case ExtSec:
1275 		/* Error or not, we're done. (no fallback) */
1276 		break;
1277 
1278 	case NTLMv2:
1279 		/*
1280 		 * We're doing user-level authentication (so we are actually
1281 		 * sending authentication stuff over the wire), and we're
1282 		 * not doing extended security, and the stuff we tried
1283 		 * failed (or we we're trying to login a real user but
1284 		 * got granted guest access instead.)
1285 		 *
1286 		 * See radar 4134676.  This check works around the way a
1287 		 * certain old server grants limited Guest access when we
1288 		 * try NTLMv2, but works fine with NTLM.  The fingerprint
1289 		 * we are looking for is DOS error codes and no-Unicode.
1290 		 * Note XP grants Guest access but uses Unicode and
1291 		 * NT error codes.
1292 		 */
1293 		if (error == 0 && (action & SMB_ACT_GUEST) &&
1294 		    !(rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
1295 		    !(rpflags2 & SMB_FLAGS2_UNICODE)) {
1296 			/* force fallback */
1297 			declinedguest = 1;
1298 			error = EAUTH;
1299 		}
1300 		/* FALLTHROUGH */
1301 	case NTLMv1:
1302 	case ClearMC:
1303 		if (error) {
1304 			authtype = authtype - 1;
1305 			goto again;
1306 		}
1307 		break;
1308 
1309 	case ClearUC:
1310 	default:
1311 		/* no more fallbacks */
1312 		break;
1313 	}
1314 
1315 ssn_exit:
1316 	if (error && declinedguest)
1317 		SMBERROR("we declined ntlmv2 guest access. errno will be %d\n",
1318 		    error);
1319 
1320 	return (error);
1321 }
1322 
1323 int
1324 smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred)
1325 {
1326 	struct smb_rq *rqp;
1327 	struct mbchain *mbp;
1328 	int error;
1329 
1330 	if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
1331 		return (0);
1332 
1333 	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
1334 	if (error)
1335 		return (error);
1336 	mbp = &rqp->sr_rq;
1337 	smb_rq_wstart(rqp);
1338 	mb_put_uint8(mbp, 0xff);
1339 	mb_put_uint8(mbp, 0);
1340 	mb_put_uint16le(mbp, 0);
1341 	smb_rq_wend(rqp);
1342 	smb_rq_bstart(rqp);
1343 	smb_rq_bend(rqp);
1344 	/*
1345 	 * Run this with a relatively short timeout.
1346 	 * We don't really care about the result,
1347 	 * as we're just trying to play nice and
1348 	 * "say goodbye" before we hangup.
1349 	 * XXX: Add SMBLOGOFFTIMO somewhere?
1350 	 */
1351 	error = smb_rq_simple_timed(rqp, 5);
1352 	SMBSDEBUG("%d\n", error);
1353 	smb_rq_done(rqp);
1354 	return (error);
1355 }
1356 
1357 static char smb_any_share[] = "?????";
1358 
1359 static char *
1360 smb_share_typename(int stype)
1361 {
1362 	char *pp;
1363 
1364 	switch (stype) {
1365 	case STYPE_DISKTREE:
1366 		pp = "A:";
1367 		break;
1368 	case STYPE_PRINTQ:
1369 		pp = smb_any_share;		/* can't use LPT: here... */
1370 		break;
1371 	case STYPE_DEVICE:
1372 		pp = "COMM";
1373 		break;
1374 	case STYPE_IPC:
1375 		pp = "IPC";
1376 		break;
1377 	default:
1378 		pp = smb_any_share;
1379 		break;
1380 	}
1381 	return (pp);
1382 }
1383 
1384 int
1385 smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
1386 {
1387 	struct smb_vc *vcp;
1388 	struct smb_rq rq, *rqp = &rq;
1389 	struct mbchain *mbp;
1390 	char *pp, *pbuf, *encpass;
1391 	const char *pw;
1392 	uchar_t hash[SMB_PWH_MAX];
1393 	int error, plen, caseopt;
1394 	int upper = 0;
1395 
1396 again:
1397 	vcp = SSTOVC(ssp);
1398 
1399 	/*
1400 	 * Make this a "VC-level" request, so it will have
1401 	 * rqp->sr_share == NULL, and smb_iod_sendrq()
1402 	 * will send it with TID = SMB_TID_UNKNOWN
1403 	 *
1404 	 * This also serves to bypass the wait for
1405 	 * share state changes, which this call is
1406 	 * trying to carry out.
1407 	 *
1408 	 * No longer need to set ssp->ss_tid
1409 	 * here, but it's harmless enough.
1410 	 */
1411 	ssp->ss_tid = SMB_TID_UNKNOWN;
1412 	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_CONNECT_ANDX,
1413 	    scred, &rqp);
1414 	if (error)
1415 		return (error);
1416 	caseopt = SMB_CS_NONE;
1417 	if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
1418 		plen = 1;
1419 		pp = "";
1420 		pbuf = NULL;
1421 		encpass = NULL;
1422 	} else {
1423 		pbuf = kmem_alloc(SMB_MAXPASSWORDLEN + 1, KM_SLEEP);
1424 		encpass = kmem_alloc(24, KM_SLEEP);
1425 		pw = smb_share_getpass(ssp);
1426 		/*
1427 		 * We try w/o uppercasing first so Samba mixed case
1428 		 * passwords work.  If that fails we come back and try
1429 		 * uppercasing to satisfy OS/2 and Windows for Workgroups.
1430 		 */
1431 		if (upper++) {
1432 			smb_toupper(pw, pbuf, SMB_MAXPASSWORDLEN);
1433 			smb_oldlm_hash(pw, hash);
1434 		} else {
1435 			strncpy(pbuf, pw, SMB_MAXPASSWORDLEN);
1436 			smb_ntlmv1hash(pw, hash);
1437 		}
1438 		pbuf[SMB_MAXPASSWORDLEN] = '\0';
1439 
1440 #ifdef NOICONVSUPPORT
1441 		/*
1442 		 * We need to convert here to the server codeset.
1443 		 * Initially we will send the same stuff and see what happens
1444 		 * witout the conversion.  REVISIT.
1445 		 */
1446 		iconv_convstr(vcp->vc_toserver, pbuf, pbuf, SMB_MAXPASSWORDLEN);
1447 #endif
1448 		if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
1449 			plen = 24;
1450 			smb_lmresponse(hash,
1451 			    vcp->vc_challenge,
1452 			    (uchar_t *)encpass);
1453 			pp = encpass;
1454 		} else {
1455 			plen = strlen(pbuf) + 1;
1456 			pp = pbuf;
1457 		}
1458 	}
1459 	mbp = &rqp->sr_rq;
1460 	smb_rq_wstart(rqp);
1461 	mb_put_uint8(mbp, 0xff);
1462 	mb_put_uint8(mbp, 0);
1463 	mb_put_uint16le(mbp, 0);
1464 	mb_put_uint16le(mbp, 0);		/* Flags */
1465 	mb_put_uint16le(mbp, plen);
1466 	smb_rq_wend(rqp);
1467 	smb_rq_bstart(rqp);
1468 	error = mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
1469 	if (error) {
1470 		SMBSDEBUG("error %d from mb_put_mem for pp\n", error);
1471 		goto bad;
1472 	}
1473 	smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt, NULL);
1474 	pp = vcp->vc_srvname;
1475 	error = smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt, NULL);
1476 	if (error) {
1477 		SMBSDEBUG("error %d from smb_put_dmem for srvname\n", error);
1478 		goto bad;
1479 	}
1480 	smb_put_dmem(mbp, vcp, "\\", 1, caseopt, NULL);
1481 	pp = ssp->ss_name;
1482 	error = smb_put_dstring(mbp, vcp, pp, caseopt);
1483 	if (error) {
1484 		SMBSDEBUG("error %d from smb_put_dstring for ss_name\n", error);
1485 		goto bad;
1486 	}
1487 	/* The type name is always ASCII */
1488 	pp = smb_share_typename(ssp->ss_type);
1489 	error = mb_put_mem(mbp, pp, strlen(pp) + 1, MB_MSYSTEM);
1490 	if (error) {
1491 		SMBSDEBUG("error %d from mb_put_mem for ss_type\n", error);
1492 		goto bad;
1493 	}
1494 	smb_rq_bend(rqp);
1495 	/*
1496 	 * Don't want to risk missing a successful
1497 	 * tree connect response.
1498 	 */
1499 	rqp->sr_flags |= SMBR_NOINTR_RECV;
1500 	error = smb_rq_simple(rqp);
1501 	SMBSDEBUG("%d\n", error);
1502 	if (error)
1503 		goto bad;
1504 
1505 	/* Success! */
1506 	SMB_SS_LOCK(ssp);
1507 	ssp->ss_tid = rqp->sr_rptid;
1508 	ssp->ss_vcgenid = vcp->vc_genid;
1509 	ssp->ss_flags |= SMBS_CONNECTED;
1510 	SMB_SS_UNLOCK(ssp);
1511 
1512 bad:
1513 	if (encpass)
1514 		kmem_free(encpass, 24);
1515 	if (pbuf)
1516 		kmem_free(pbuf, SMB_MAXPASSWORDLEN + 1);
1517 	smb_rq_done(rqp);
1518 	if (error && upper == 1)
1519 		goto again;
1520 	return (error);
1521 }
1522 
1523 int
1524 smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
1525 {
1526 	struct smb_vc *vcp;
1527 	struct smb_rq *rqp;
1528 	struct mbchain *mbp;
1529 	int error;
1530 
1531 	if (ssp->ss_tid == SMB_TID_UNKNOWN)
1532 		return (0);
1533 
1534 	/*
1535 	 * Build this as a "VC-level" request, so it will
1536 	 * avoid testing the _GONE flag on the share,
1537 	 * which has already been set at this point.
1538 	 * Add the share pointer "by hand" below, so
1539 	 * smb_iod_sendrq will plug in the TID.
1540 	 */
1541 	vcp = SSTOVC(ssp);
1542 	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
1543 	if (error)
1544 		return (error);
1545 	rqp->sr_share = ssp; /* by hand */
1546 	mbp = &rqp->sr_rq;
1547 #ifdef lint
1548 	mbp = mbp;
1549 #endif
1550 	smb_rq_wstart(rqp);
1551 	smb_rq_wend(rqp);
1552 	smb_rq_bstart(rqp);
1553 	smb_rq_bend(rqp);
1554 
1555 	/*
1556 	 * Run this with a relatively short timeout. (5 sec.)
1557 	 * We don't really care about the result here, but we
1558 	 * do need to make sure we send this out, or we could
1559 	 * "leak" active tree IDs on interrupt or timeout.
1560 	 * The NOINTR_SEND flag makes this request immune to
1561 	 * interrupt or timeout until the send is done.
1562 	 */
1563 	rqp->sr_flags |= SMBR_NOINTR_SEND;
1564 	error = smb_rq_simple_timed(rqp, 5);
1565 	SMBSDEBUG("%d\n", error);
1566 	smb_rq_done(rqp);
1567 	ssp->ss_tid = SMB_TID_UNKNOWN;
1568 	return (error);
1569 }
1570 
1571 /*
1572  * Common function for read/write with UIO.
1573  * Called by netsmb smb_usr_rw,
1574  *  smbfs_readvnode, smbfs_writevnode
1575  */
1576 int
1577 smb_rwuio(struct smb_share *ssp, uint16_t fid, uio_rw_t rw,
1578 	uio_t *uiop, smb_cred_t *scred, int timo)
1579 {
1580 	struct smb_vc *vcp = SSTOVC(ssp);
1581 	ssize_t  save_resid;
1582 	uint32_t len, rlen, maxlen;
1583 	int error = 0;
1584 	int (*iofun)(struct smb_share *, uint16_t, uint32_t *,
1585 	    uio_t *, smb_cred_t *, int);
1586 
1587 	/*
1588 	 * Determine which function to use,
1589 	 * and the transfer size per call.
1590 	 */
1591 	if (SMB_DIALECT(vcp) >= SMB_DIALECT_NTLM0_12) {
1592 		/*
1593 		 * Using NT LM 0.12, so readx, writex.
1594 		 * Make sure we can represent the offset.
1595 		 */
1596 		if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 &&
1597 		    (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
1598 			return (EFBIG);
1599 
1600 		if (rw == UIO_READ) {
1601 			iofun = smb_smb_readx;
1602 			if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
1603 				maxlen = SMB_MAX_LARGE_RW_SIZE;
1604 			else
1605 				maxlen = vcp->vc_rxmax;
1606 		} else { /* UIO_WRITE */
1607 			iofun = smb_smb_writex;
1608 			if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
1609 				maxlen = SMB_MAX_LARGE_RW_SIZE;
1610 			else
1611 				maxlen = vcp->vc_wxmax;
1612 		}
1613 	} else {
1614 		/*
1615 		 * Using the old SMB_READ and SMB_WRITE so
1616 		 * we're limited to 32-bit offsets, etc.
1617 		 * XXX: Someday, punt the old dialects.
1618 		 */
1619 		if ((uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
1620 			return (EFBIG);
1621 
1622 		if (rw == UIO_READ) {
1623 			iofun = smb_smb_read;
1624 			maxlen = vcp->vc_rxmax;
1625 		} else { /* UIO_WRITE */
1626 			iofun = smb_smb_write;
1627 			maxlen = vcp->vc_wxmax;
1628 		}
1629 	}
1630 
1631 	save_resid = uiop->uio_resid;
1632 	while (uiop->uio_resid > 0) {
1633 		/* Lint: uio_resid may be 64-bits */
1634 		rlen = len = (uint32_t)min(maxlen, uiop->uio_resid);
1635 
1636 		SMBSDEBUG("rw=%d, off %lld, len %d\n",
1637 		    rw, uiop->uio_loffset, len);
1638 
1639 		error = (*iofun)(ssp, fid, &rlen, uiop, scred, timo);
1640 
1641 		/*
1642 		 * Note: the iofun called uio_update, so
1643 		 * not doing that here as one might expect.
1644 		 *
1645 		 * Quit the loop either on error, or if we
1646 		 * transferred less then requested.
1647 		 */
1648 		if (error || (rlen < len))
1649 			break;
1650 
1651 		timo = 0; /* only first I/O should wait */
1652 	}
1653 	if (error && (save_resid != uiop->uio_resid)) {
1654 		/*
1655 		 * Stopped on an error after having
1656 		 * successfully transferred data.
1657 		 * Suppress this error.
1658 		 */
1659 		SMBSDEBUG("error %d suppressed\n", error);
1660 		error = 0;
1661 	}
1662 
1663 	return (error);
1664 }
1665 
1666 static int
1667 smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
1668 	uio_t *uiop, smb_cred_t *scred, int timo)
1669 {
1670 	struct smb_rq *rqp;
1671 	struct mbchain *mbp;
1672 	struct mdchain *mdp;
1673 	int error;
1674 	uint32_t offlo, offhi, rlen;
1675 	uint16_t lenhi, lenlo, off, doff;
1676 	uint8_t wc;
1677 
1678 	lenhi = (uint16_t)(*lenp >> 16);
1679 	lenlo = (uint16_t)*lenp;
1680 	offhi = (uint32_t)(uiop->uio_loffset >> 32);
1681 	offlo = (uint32_t)uiop->uio_loffset;
1682 
1683 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
1684 	if (error)
1685 		return (error);
1686 	smb_rq_getrequest(rqp, &mbp);
1687 	smb_rq_wstart(rqp);
1688 	mb_put_uint8(mbp, 0xff);	/* no secondary command */
1689 	mb_put_uint8(mbp, 0);		/* MBZ */
1690 	mb_put_uint16le(mbp, 0);	/* offset to secondary */
1691 	mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
1692 	mb_put_uint32le(mbp, offlo);	/* offset (low part) */
1693 	mb_put_uint16le(mbp, lenlo);	/* MaxCount */
1694 	mb_put_uint16le(mbp, 1);	/* MinCount */
1695 					/* (only indicates blocking) */
1696 	mb_put_uint32le(mbp, lenhi);	/* MaxCountHigh */
1697 	mb_put_uint16le(mbp, lenlo);	/* Remaining ("obsolete") */
1698 	mb_put_uint32le(mbp, offhi);	/* offset (high part) */
1699 	smb_rq_wend(rqp);
1700 	smb_rq_bstart(rqp);
1701 	smb_rq_bend(rqp);
1702 	do {
1703 		if (timo == 0)
1704 			timo = smb_timo_read;
1705 		error = smb_rq_simple_timed(rqp, timo);
1706 		if (error)
1707 			break;
1708 		smb_rq_getreply(rqp, &mdp);
1709 		md_get_uint8(mdp, &wc);
1710 		if (wc != 12) {
1711 			error = EBADRPC;
1712 			break;
1713 		}
1714 		md_get_uint8(mdp, NULL);
1715 		md_get_uint8(mdp, NULL);
1716 		md_get_uint16le(mdp, NULL);
1717 		md_get_uint16le(mdp, NULL);
1718 		md_get_uint16le(mdp, NULL);	/* data compaction mode */
1719 		md_get_uint16le(mdp, NULL);
1720 		md_get_uint16le(mdp, &lenlo);	/* data len ret. */
1721 		md_get_uint16le(mdp, &doff);	/* data offset */
1722 		md_get_uint16le(mdp, &lenhi);
1723 		rlen = (lenhi << 16) | lenlo;
1724 		md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
1725 		md_get_uint16le(mdp, NULL);	/* ByteCount */
1726 		/*
1727 		 * Does the data offset indicate padding?
1728 		 * Add up the gets above, we have:
1729 		 */
1730 		off = SMB_HDRLEN + 3 + (12 * 2); /* =59 */
1731 		if (doff > off)	/* pad byte(s)? */
1732 			md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
1733 		if (rlen == 0) {
1734 			*lenp = rlen;
1735 			break;
1736 		}
1737 		/* paranoid */
1738 		if (rlen > *lenp) {
1739 			SMBSDEBUG("bad server! rlen %d, len %d\n",
1740 			    rlen, *lenp);
1741 			rlen = *lenp;
1742 		}
1743 		error = md_get_uio(mdp, uiop, rlen);
1744 		if (error)
1745 			break;
1746 		*lenp = rlen;
1747 		/*LINTED*/
1748 	} while (0);
1749 	smb_rq_done(rqp);
1750 	return (error);
1751 }
1752 
1753 static int
1754 smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
1755 	uio_t *uiop, smb_cred_t *scred, int timo)
1756 {
1757 	struct smb_rq *rqp;
1758 	struct mbchain *mbp;
1759 	struct mdchain *mdp;
1760 	int error;
1761 	uint32_t offlo, offhi, rlen;
1762 	uint16_t lenhi, lenlo;
1763 	uint8_t wc;
1764 
1765 	lenhi = (uint16_t)(*lenp >> 16);
1766 	lenlo = (uint16_t)*lenp;
1767 	offhi = (uint32_t)(uiop->uio_loffset >> 32);
1768 	offlo = (uint32_t)uiop->uio_loffset;
1769 
1770 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
1771 	if (error)
1772 		return (error);
1773 	smb_rq_getrequest(rqp, &mbp);
1774 	smb_rq_wstart(rqp);
1775 	mb_put_uint8(mbp, 0xff);	/* no secondary command */
1776 	mb_put_uint8(mbp, 0);		/* MBZ */
1777 	mb_put_uint16le(mbp, 0);	/* offset to secondary */
1778 	mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
1779 	mb_put_uint32le(mbp, offlo);	/* offset (low part) */
1780 	mb_put_uint32le(mbp, 0);	/* MBZ (timeout) */
1781 	mb_put_uint16le(mbp, 0);	/* !write-thru */
1782 	mb_put_uint16le(mbp, 0);
1783 	mb_put_uint16le(mbp, lenhi);
1784 	mb_put_uint16le(mbp, lenlo);
1785 	mb_put_uint16le(mbp, 64);	/* data offset from header start */
1786 	mb_put_uint32le(mbp, offhi);	/* offset (high part) */
1787 	smb_rq_wend(rqp);
1788 	smb_rq_bstart(rqp);
1789 	do {
1790 		mb_put_uint8(mbp, 0);	/* pad byte */
1791 		error = mb_put_uio(mbp, uiop, *lenp);
1792 		if (error)
1793 			break;
1794 		smb_rq_bend(rqp);
1795 		if (timo == 0)
1796 			timo = smb_timo_write;
1797 		error = smb_rq_simple_timed(rqp, timo);
1798 		if (error)
1799 			break;
1800 		smb_rq_getreply(rqp, &mdp);
1801 		md_get_uint8(mdp, &wc);
1802 		if (wc != 6) {
1803 			error = EBADRPC;
1804 			break;
1805 		}
1806 		md_get_uint8(mdp, NULL);	/* andx cmd */
1807 		md_get_uint8(mdp, NULL);	/* reserved */
1808 		md_get_uint16le(mdp, NULL);	/* andx offset */
1809 		md_get_uint16le(mdp, &lenlo);	/* data len ret. */
1810 		md_get_uint16le(mdp, NULL);	/* remaining */
1811 		md_get_uint16le(mdp, &lenhi);
1812 		rlen = (lenhi << 16) | lenlo;
1813 		*lenp = rlen;
1814 		/*LINTED*/
1815 	} while (0);
1816 
1817 	smb_rq_done(rqp);
1818 	return (error);
1819 }
1820 
1821 static int
1822 smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
1823 	uio_t *uiop, smb_cred_t *scred, int timo)
1824 {
1825 	struct smb_rq *rqp;
1826 	struct mbchain *mbp;
1827 	struct mdchain *mdp;
1828 	int error;
1829 	uint32_t off32;
1830 	uint16_t bc, cnt, dlen, rcnt, todo;
1831 	uint8_t wc;
1832 
1833 	ASSERT(uiop->uio_loffset <= UINT32_MAX);
1834 	off32 = (uint32_t)uiop->uio_loffset;
1835 	ASSERT(*lenp <= UINT16_MAX);
1836 	cnt = (uint16_t)*lenp;
1837 	/* This next is an "estimate" of planned reads. */
1838 	todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX);
1839 
1840 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
1841 	if (error)
1842 		return (error);
1843 	smb_rq_getrequest(rqp, &mbp);
1844 	smb_rq_wstart(rqp);
1845 	mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
1846 	mb_put_uint16le(mbp, cnt);
1847 	mb_put_uint32le(mbp, off32);
1848 	mb_put_uint16le(mbp, todo);
1849 	smb_rq_wend(rqp);
1850 	smb_rq_bstart(rqp);
1851 	smb_rq_bend(rqp);
1852 	do {
1853 		if (timo == 0)
1854 			timo = smb_timo_read;
1855 		error = smb_rq_simple_timed(rqp, timo);
1856 		if (error)
1857 			break;
1858 		smb_rq_getreply(rqp, &mdp);
1859 		md_get_uint8(mdp, &wc);
1860 		if (wc != 5) {
1861 			error = EBADRPC;
1862 			break;
1863 		}
1864 		md_get_uint16le(mdp, &rcnt);	/* ret. count */
1865 		md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);  /* res. */
1866 		md_get_uint16le(mdp, &bc);	/* byte count */
1867 		md_get_uint8(mdp, NULL);	/* buffer format */
1868 		md_get_uint16le(mdp, &dlen);	/* data len */
1869 		if (dlen < rcnt) {
1870 			SMBSDEBUG("oops: dlen=%d rcnt=%d\n",
1871 			    (int)dlen, (int)rcnt);
1872 			rcnt = dlen;
1873 		}
1874 		if (rcnt == 0) {
1875 			*lenp = 0;
1876 			break;
1877 		}
1878 		/* paranoid */
1879 		if (rcnt > cnt) {
1880 			SMBSDEBUG("bad server! rcnt %d, cnt %d\n",
1881 			    (int)rcnt, (int)cnt);
1882 			rcnt = cnt;
1883 		}
1884 		error = md_get_uio(mdp, uiop, (int)rcnt);
1885 		if (error)
1886 			break;
1887 		*lenp = (int)rcnt;
1888 		/*LINTED*/
1889 	} while (0);
1890 	smb_rq_done(rqp);
1891 	return (error);
1892 }
1893 
1894 static int
1895 smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
1896 	uio_t *uiop, smb_cred_t *scred, int timo)
1897 {
1898 	struct smb_rq *rqp;
1899 	struct mbchain *mbp;
1900 	struct mdchain *mdp;
1901 	int error;
1902 	uint32_t off32;
1903 	uint16_t cnt, rcnt, todo;
1904 	uint8_t wc;
1905 
1906 	ASSERT(uiop->uio_loffset <= UINT32_MAX);
1907 	off32 = (uint32_t)uiop->uio_loffset;
1908 	ASSERT(*lenp <= UINT16_MAX);
1909 	cnt = (uint16_t)*lenp;
1910 	/* This next is an "estimate" of planned writes. */
1911 	todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX);
1912 
1913 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
1914 	if (error)
1915 		return (error);
1916 	smb_rq_getrequest(rqp, &mbp);
1917 	smb_rq_wstart(rqp);
1918 	mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
1919 	mb_put_uint16le(mbp, cnt);
1920 	mb_put_uint32le(mbp, off32);
1921 	mb_put_uint16le(mbp, todo);
1922 	smb_rq_wend(rqp);
1923 	smb_rq_bstart(rqp);
1924 	mb_put_uint8(mbp, SMB_DT_DATA);
1925 	mb_put_uint16le(mbp, cnt);
1926 	do {
1927 		error = mb_put_uio(mbp, uiop, *lenp);
1928 		if (error)
1929 			break;
1930 		smb_rq_bend(rqp);
1931 		if (timo == 0)
1932 			timo = smb_timo_write;
1933 		error = smb_rq_simple_timed(rqp, timo);
1934 		if (error)
1935 			break;
1936 		smb_rq_getreply(rqp, &mdp);
1937 		md_get_uint8(mdp, &wc);
1938 		if (wc != 1) {
1939 			error = EBADRPC;
1940 			break;
1941 		}
1942 		md_get_uint16le(mdp, &rcnt);
1943 		*lenp = rcnt;
1944 		/*LINTED*/
1945 	} while (0);
1946 	smb_rq_done(rqp);
1947 	return (error);
1948 }
1949 
1950 
1951 static u_int32_t	smbechoes = 0;
1952 
1953 int
1954 smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
1955 {
1956 	struct smb_rq *rqp;
1957 	struct mbchain *mbp;
1958 	int error;
1959 
1960 	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
1961 	if (error)
1962 		return (error);
1963 	mbp = &rqp->sr_rq;
1964 	smb_rq_wstart(rqp);
1965 	mb_put_uint16le(mbp, 1); /* echo count */
1966 	smb_rq_wend(rqp);
1967 	smb_rq_bstart(rqp);
1968 	mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes));
1969 	smb_rq_bend(rqp);
1970 	/*
1971 	 * Note: the IOD calls this, so
1972 	 * this request must not wait for
1973 	 * connection state changes, etc.
1974 	 */
1975 	rqp->sr_flags |= SMBR_INTERNAL;
1976 	error = smb_rq_simple_timed(rqp, timo);
1977 	SMBSDEBUG("%d\n", error);
1978 	smb_rq_done(rqp);
1979 	return (error);
1980 }
1981 
1982 #ifdef APPLE
1983 int
1984 smb_smb_checkdir(struct smb_share *ssp, void *dnp, char *name,
1985 		int nmlen, struct smb_cred *scred)
1986 {
1987 	struct smb_rq *rqp;
1988 	struct mbchain *mbp;
1989 	int error;
1990 
1991 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CHECK_DIRECTORY, scred, &rqp);
1992 	if (error)
1993 		return (error);
1994 
1995 	smb_rq_getrequest(rqp, &mbp);
1996 	smb_rq_wstart(rqp);
1997 	smb_rq_wend(rqp);
1998 	smb_rq_bstart(rqp);
1999 	mb_put_uint8(mbp, SMB_DT_ASCII);
2000 	/*
2001 	 * All we need to do is marshall the path: "\\"
2002 	 * (the root of the share) into this request.
2003 	 * We essentially in-line smbfs_fullpath() here,
2004 	 * except no mb_put_padbyte (already aligned).
2005 	 */
2006 	smb_put_dstring(mbp, SSTOVC(ssp), "\\", SMB_CS_NONE);
2007 	smb_rq_bend(rqp);
2008 
2009 	error = smb_rq_simple(rqp);
2010 	SMBSDEBUG("%d\n", error);
2011 	smb_rq_done(rqp);
2012 
2013 	return (error);
2014 }
2015 #endif /* APPLE */
2016