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