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: smbfs_smb.c,v 1.73.38.1 2005/05/27 02:35:28 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 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/time.h>
45 #include <sys/vnode.h>
46 #include <sys/cmn_err.h>
47 
48 #ifdef APPLE
49 #include <sys/smb_apple.h>
50 #include <sys/utfconv.h>
51 #else
52 #include <netsmb/smb_osdep.h>
53 #endif
54 
55 #include <netsmb/smb.h>
56 #include <netsmb/smb_conn.h>
57 #include <netsmb/smb_subr.h>
58 #include <netsmb/smb_rq.h>
59 
60 #include <smbfs/smbfs.h>
61 #include <smbfs/smbfs_node.h>
62 #include <smbfs/smbfs_subr.h>
63 
64 /*
65  * Local functions.
66  * Not static, to aid debugging.
67  */
68 
69 int smbfs_smb_qfileinfo(struct smbnode *np, struct smbfattr *fap,
70 	struct smb_cred *scrp, short infolevel);
71 int smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap,
72 	struct smb_cred *scrp, short infolevel);
73 int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
74 	struct smbfattr *fap, struct smb_cred *scrp);
75 
76 int smbfs_smb_statfsLM1(struct smb_share *ssp,
77 	statvfs64_t *sbp, struct smb_cred *scrp);
78 int smbfs_smb_statfsLM2(struct smb_share *ssp,
79 	statvfs64_t *sbp, struct smb_cred *scrp);
80 
81 int  smbfs_smb_setftime1(struct smbnode *np, uint16_t fid,
82 	struct timespec *mtime,	struct timespec *atime,
83 	struct smb_cred *scrp);
84 int  smbfs_smb_setfattrNT(struct smbnode *np, uint16_t fid,
85 	uint32_t attr, struct timespec *mtime,	struct timespec *atime,
86 	struct smb_cred *scrp);
87 
88 int  smbfs_smb_setpattr1(struct smbnode *np,
89 	const char *name, int len, uint32_t attr,
90 	struct timespec *mtime, struct smb_cred *scrp);
91 int  smbfs_smb_setpattr2(struct smbnode *np, uint32_t attr,
92 	struct timespec *mtime,	struct timespec *atime,
93 	struct smb_cred *scrp);
94 int  smbfs_smb_setpattrNT(struct smbnode *np, uint32_t attr,
95 	struct timespec *mtime, struct timespec *atime,
96 	struct smb_cred *scrp);
97 
98 
99 /*
100  * Todo: locking over-the-wire
101  */
102 #ifdef APPLE
103 
104 static int
105 smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid,
106 	offset_t start, uint64_t len, int largelock,
107 	struct smb_cred *scrp, uint32_t timeout)
108 {
109 	struct smb_share *ssp = np->n_mount->smi_share;
110 	struct smb_rq rq, *rqp = &rq;
111 	struct mbchain *mbp;
112 	uint8_t ltype = 0;
113 	int error;
114 
115 	/* Shared lock for n_fid use below. */
116 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
117 
118 	if (op == SMB_LOCK_SHARED)
119 		ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
120 	if (largelock)
121 		ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
122 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
123 	if (error)
124 		return (error);
125 	smb_rq_getrequest(rqp, &mbp);
126 	smb_rq_wstart(rqp);
127 	mb_put_uint8(mbp, 0xff);	/* secondary command */
128 	mb_put_uint8(mbp, 0);		/* MBZ */
129 	mb_put_uint16le(mbp, 0);
130 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
131 	mb_put_uint8(mbp, ltype);	/* locktype */
132 	mb_put_uint8(mbp, 0);		/* oplocklevel - 0 seems is NO_OPLOCK */
133 	mb_put_uint32le(mbp, timeout);	/* 0 nowait, -1 infinite wait */
134 	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
135 	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
136 	smb_rq_wend(rqp);
137 	smb_rq_bstart(rqp);
138 	mb_put_uint16le(mbp, pid);
139 	if (!largelock) {
140 		mb_put_uint32le(mbp, start);
141 		mb_put_uint32le(mbp, len);
142 	} else {
143 		mb_put_uint16le(mbp, 0); /* pad */
144 		mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
145 		mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
146 		mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
147 		mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
148 	}
149 	smb_rq_bend(rqp);
150 	/*
151 	 * Don't want to risk missing a successful
152 	 * unlock send or lock response, or we could
153 	 * lose track of an outstanding lock.
154 	 */
155 	if (op == SMB_LOCK_RELEASE)
156 		rqp->sr_flags |= SMBR_NOINTR_SEND;
157 	else
158 		rqp->sr_flags |= SMBR_NOINTR_RECV;
159 
160 	error = smb_rq_simple(rqp);
161 	smb_rq_done(rqp);
162 	return (error);
163 }
164 
165 int
166 smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
167 	offset_t start, uint64_t len,	int largelock,
168 	struct smb_cred *scrp, uint32_t timeout)
169 {
170 	struct smb_share *ssp = np->n_mount->smi_share;
171 
172 	if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
173 		/*
174 		 * TODO: use LOCK_BYTE_RANGE here.
175 		 */
176 		return (EINVAL);
177 	else
178 		return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len,
179 		    largelock, scrp, timeout));
180 }
181 
182 #endif /* APPLE */
183 
184 /*
185  * Helper for smbfs_getattr
186  * Something like nfs_getattr_otw
187  */
188 int
189 smbfs_smb_getfattr(
190 	struct smbnode *np,
191 	struct smbfattr *fap,
192 	struct smb_cred *scrp)
193 {
194 	int error;
195 
196 	/*
197 	 * This lock is really only necessary for qfileinfo,
198 	 * but hopefully we use that most of the time.
199 	 * Lock may be writer (via open) or reader.
200 	 */
201 	ASSERT(np->r_lkserlock.count != 0);
202 
203 	if (np->n_fidrefs)
204 		error = smbfs_smb_qfileinfo(np, fap, scrp, 0);
205 	else
206 		error = smbfs_smb_qpathinfo(np, fap, scrp, 0);
207 
208 	if (error == EINVAL) {
209 		/* fallback */
210 		error = smbfs_smb_query_info(np, NULL, 0, fap, scrp);
211 	}
212 
213 #if 0	/* Moved this part to caller. */
214 	if (!error && fap->fa_mtime.tv_sec == 0)
215 		smbfs_attr_touchdir(dnp);
216 #endif
217 
218 	return (error);
219 }
220 
221 
222 /*
223  * Nearly identical to smbfs_smb_qfileinfo (below).
224  * Please keep them in sync.
225  */
226 int
227 smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap,
228 		    struct smb_cred *scrp, short infolevel)
229 {
230 	struct smb_share *ssp = np->n_mount->smi_share;
231 	struct smb_vc *vcp = SSTOVC(ssp);
232 	struct smb_t2rq *t2p;
233 	int error, svtz, timesok = 1;
234 	struct mbchain *mbp;
235 	struct mdchain *mdp;
236 	uint16_t date, time, wattr;
237 	uint64_t llongint, lsize;
238 	uint32_t size, dattr;
239 
240 top:
241 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION,
242 	    scrp, &t2p);
243 	if (error)
244 		return (error);
245 	mbp = &t2p->t2_tparam;
246 	mb_init(mbp);
247 	if (!infolevel) {
248 		if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
249 			infolevel = SMB_QFILEINFO_STANDARD;
250 		else
251 			infolevel = SMB_QFILEINFO_ALL_INFO;
252 	}
253 	mb_put_uint16le(mbp, infolevel);
254 	mb_put_uint32le(mbp, 0);
255 	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
256 	error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
257 	if (error) {
258 		smb_t2_done(t2p);
259 		return (error);
260 	}
261 	t2p->t2_maxpcount = 2;
262 	t2p->t2_maxdcount = vcp->vc_txmax;
263 	error = smb_t2_request(t2p);
264 	if (error) {
265 		smb_t2_done(t2p);
266 		/* Invalid info level?  Try fallback. */
267 		if (error == EINVAL &&
268 		    infolevel == SMB_QFILEINFO_ALL_INFO) {
269 			infolevel = SMB_QFILEINFO_STANDARD;
270 			goto top;
271 		}
272 		return (error);
273 	}
274 	mdp = &t2p->t2_rdata;
275 	svtz = vcp->vc_sopt.sv_tz;
276 	switch (infolevel) {
277 	case SMB_QFILEINFO_STANDARD:
278 		timesok = 0;
279 		md_get_uint16le(mdp, NULL);
280 		md_get_uint16le(mdp, NULL);	/* creation time */
281 		md_get_uint16le(mdp, &date);
282 		md_get_uint16le(mdp, &time);	/* access time */
283 		if (date || time) {
284 			timesok++;
285 			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
286 		}
287 		md_get_uint16le(mdp, &date);
288 		md_get_uint16le(mdp, &time);	/* modify time */
289 		if (date || time) {
290 			timesok++;
291 			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
292 		}
293 		md_get_uint32le(mdp, &size);
294 		fap->fa_size = size;
295 		md_get_uint32(mdp, NULL);	/* allocation size */
296 		md_get_uint16le(mdp, &wattr);
297 		fap->fa_attr = wattr;
298 		break;
299 	case SMB_QFILEINFO_ALL_INFO:
300 		timesok = 0;
301 		/* creation time (discard) */
302 		md_get_uint64(mdp, NULL);
303 		/* last access time */
304 		md_get_uint64le(mdp, &llongint);
305 		if (llongint) {
306 			timesok++;
307 			smb_time_NT2local(llongint, svtz, &fap->fa_atime);
308 		}
309 		/* last write time */
310 		md_get_uint64le(mdp, &llongint);
311 		if (llongint) {
312 			timesok++;
313 			smb_time_NT2local(llongint, svtz, &fap->fa_mtime);
314 		}
315 		/* last change time */
316 		md_get_uint64le(mdp, &llongint);
317 		if (llongint) {
318 			timesok++;
319 			smb_time_NT2local(llongint, svtz, &fap->fa_ctime);
320 		}
321 		/* attributes */
322 		md_get_uint32le(mdp, &dattr);
323 		fap->fa_attr = dattr;
324 		/*
325 		 * 4-Byte alignment - discard
326 		 * Specs doesn't talk about this.
327 		 */
328 		md_get_uint32le(mdp, NULL);
329 		/* allocation size (discard) */
330 		md_get_uint64le(mdp, NULL);
331 		/* File size */
332 		md_get_uint64le(mdp, &lsize);
333 		fap->fa_size = lsize;
334 		break;
335 	default:
336 		SMBVDEBUG("unexpected info level %d\n", infolevel);
337 		error = EINVAL;
338 	}
339 	smb_t2_done(t2p);
340 	/*
341 	 * if all times are zero (observed with FAT on NT4SP6)
342 	 * then fall back to older info level
343 	 */
344 	if (!timesok) {
345 		if (infolevel == SMB_QFILEINFO_ALL_INFO) {
346 			infolevel = SMB_QFILEINFO_STANDARD;
347 			goto top;
348 		}
349 		error = EINVAL;
350 	}
351 	return (error);
352 }
353 
354 /*
355  * Nearly identical to smbfs_smb_qpathinfo (above).
356  * Please keep them in sync.
357  */
358 int
359 smbfs_smb_qfileinfo(struct smbnode *np, struct smbfattr *fap,
360 		    struct smb_cred *scrp, short infolevel)
361 {
362 	struct smb_share *ssp = np->n_mount->smi_share;
363 	struct smb_vc *vcp = SSTOVC(ssp);
364 	struct smb_t2rq *t2p;
365 	int error, svtz, timesok = 1;
366 	struct mbchain *mbp;
367 	struct mdchain *mdp;
368 	uint16_t date, time, wattr;
369 	uint64_t llongint, lsize;
370 	uint32_t size, dattr;
371 
372 	/*
373 	 * Shared lock for n_fid use below.
374 	 * See smbfs_smb_getfattr()
375 	 */
376 	ASSERT(np->r_lkserlock.count != 0);
377 
378 	if (np->n_fid == SMB_FID_UNUSED)
379 		return (EBADF);
380 
381 top:
382 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FILE_INFORMATION,
383 	    scrp, &t2p);
384 	if (error)
385 		return (error);
386 	mbp = &t2p->t2_tparam;
387 	mb_init(mbp);
388 	if (!infolevel) {
389 		if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
390 			infolevel = SMB_QFILEINFO_STANDARD;
391 		else
392 			infolevel = SMB_QFILEINFO_ALL_INFO;
393 	}
394 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
395 	mb_put_uint16le(mbp, infolevel);
396 	t2p->t2_maxpcount = 2;
397 	t2p->t2_maxdcount = vcp->vc_txmax;
398 	error = smb_t2_request(t2p);
399 	if (error) {
400 		smb_t2_done(t2p);
401 		/* Invalid info level?  Try fallback. */
402 		if (error == EINVAL &&
403 		    infolevel == SMB_QFILEINFO_ALL_INFO) {
404 			infolevel = SMB_QFILEINFO_STANDARD;
405 			goto top;
406 		}
407 		return (error);
408 	}
409 	mdp = &t2p->t2_rdata;
410 	svtz = vcp->vc_sopt.sv_tz;
411 	switch (infolevel) {
412 	case SMB_QFILEINFO_STANDARD:
413 		timesok = 0;
414 		md_get_uint16le(mdp, NULL);
415 		md_get_uint16le(mdp, NULL);	/* creation time */
416 		md_get_uint16le(mdp, &date);
417 		md_get_uint16le(mdp, &time);	/* access time */
418 		if (date || time) {
419 			timesok++;
420 			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
421 		}
422 		md_get_uint16le(mdp, &date);
423 		md_get_uint16le(mdp, &time);	/* modify time */
424 		if (date || time) {
425 			timesok++;
426 			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
427 		}
428 		md_get_uint32le(mdp, &size);
429 		fap->fa_size = size;
430 		md_get_uint32(mdp, NULL);	/* allocation size */
431 		md_get_uint16le(mdp, &wattr);
432 		fap->fa_attr = wattr;
433 		break;
434 	case SMB_QFILEINFO_ALL_INFO:
435 		timesok = 0;
436 		/* creation time (discard) */
437 		md_get_uint64(mdp, NULL);
438 		/* last access time */
439 		md_get_uint64le(mdp, &llongint);
440 		if (llongint) {
441 			timesok++;
442 			smb_time_NT2local(llongint, svtz, &fap->fa_atime);
443 		}
444 		/* last write time */
445 		md_get_uint64le(mdp, &llongint);
446 		if (llongint) {
447 			timesok++;
448 			smb_time_NT2local(llongint, svtz, &fap->fa_mtime);
449 		}
450 		/* last change time */
451 		md_get_uint64le(mdp, &llongint);
452 		if (llongint) {
453 			timesok++;
454 			smb_time_NT2local(llongint, svtz, &fap->fa_ctime);
455 		}
456 		/* attributes */
457 		md_get_uint32le(mdp, &dattr);
458 		fap->fa_attr = dattr;
459 		/*
460 		 * 4-Byte alignment - discard
461 		 * Specs doesn't talk about this.
462 		 */
463 		md_get_uint32le(mdp, NULL);
464 		/* allocation size (discard) */
465 		md_get_uint64le(mdp, NULL);
466 		/* File size */
467 		md_get_uint64le(mdp, &lsize);
468 		fap->fa_size = lsize;
469 		break;
470 	default:
471 		SMBVDEBUG("unexpected info level %d\n", infolevel);
472 		error = EINVAL;
473 	}
474 	smb_t2_done(t2p);
475 	/*
476 	 * if all times are zero (observed with FAT on NT4SP6)
477 	 * then fall back to older info level
478 	 */
479 	if (!timesok) {
480 		if (infolevel == SMB_QFILEINFO_ALL_INFO) {
481 			infolevel = SMB_QFILEINFO_STANDARD;
482 			goto top;
483 		}
484 		error = EINVAL;
485 	}
486 	return (error);
487 }
488 
489 /*
490  * Support functions for _qstreaminfo
491  * Todo: show NT file streams as
492  * Solaris named attributes.
493  */
494 #ifdef APPLE
495 
496 static char *
497 sfm2xattr(char *sfm)
498 {
499 	if (!strncasecmp(sfm, SFM_RESOURCEFORK_NAME,
500 	    sizeof (SFM_RESOURCEFORK_NAME)))
501 		return (XATTR_RESOURCEFORK_NAME);
502 	if (!strncasecmp(sfm, SFM_FINDERINFO_NAME,
503 	    sizeof (SFM_FINDERINFO_NAME)))
504 		return (XATTR_FINDERINFO_NAME);
505 	return (NULL);
506 }
507 
508 static int
509 smbfs_smb_undollardata(struct smbnode *np, struct smbfs_fctx *ctx)
510 {
511 	char *cp;
512 	int len = strlen(SMB_DATASTREAM);
513 
514 	if (!ctx->f_name)	/* sanity check */
515 		goto bad;
516 	if (ctx->f_nmlen < len + 1)	/* "::$DATA" at a minimum */
517 		goto bad;
518 	if (*ctx->f_name != ':')	/* leading colon - "always" */
519 		goto bad;
520 	cp =  &ctx->f_name[ctx->f_nmlen - len]; /* point to 2nd colon */
521 	if (bcmp(cp, SMB_DATASTREAM, len))
522 		goto bad;
523 	if (ctx->f_nmlen == len + 1)	/* merely the data fork? */
524 		return (0);		/* skip it */
525 	/*
526 	 * XXX here we should be calling KPI to validate the stream name
527 	 */
528 	if (ctx->f_nmlen >= 18 &&
529 	    !(bcmp(ctx->f_name, ":com.apple.system.", 18) == 0))
530 		return (0);	/* skip protected system attrs */
531 	if (ctx->f_nmlen - len > XATTR_MAXNAMELEN + 1)
532 		goto bad;	/* mustnt return more than 128 bytes */
533 	/*
534 	 * Un-count a colon and the $DATA, then the
535 	 * 2nd colon is replaced by a terminating null.
536 	 */
537 	ctx->f_nmlen -= len;
538 	*cp = '\0';
539 	return (1);
540 bad:
541 	SMBSDEBUG("file \"%.*s\" has bad stream \"%.*s\"\n",
542 	    np->n_nmlen, np->n_name, ctx->f_nmlen, ctx->f_name);
543 	return (0); /* skip it */
544 }
545 
546 PRIVSYM int
547 smbfs_smb_qstreaminfo(struct smbnode *np, struct smb_cred *scrp,
548 			uio_t uio, size_t *sizep)
549 {
550 	struct smb_share *ssp = np->n_mount->smi_share;
551 	struct smb_vc *vcp = SSTOVC(ssp);
552 	struct smb_t2rq *t2p;
553 	int error;
554 	struct mbchain *mbp;
555 	struct mdchain *mdp;
556 	uint32_t next, nlen, used;
557 	struct smbfs_fctx ctx;
558 
559 	*sizep = 0;
560 	ctx.f_ssp = ssp;
561 	ctx.f_name = NULL;
562 
563 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION,
564 	    scrp, &t2p);
565 	if (error)
566 		return (error);
567 	mbp = &t2p->t2_tparam;
568 	mb_init(mbp);
569 	/*
570 	 * SMB_QFILEINFO_STREAM_INFORMATION is an option to consider
571 	 * here.  Samba declined to support the older info level with
572 	 * a comment claiming doing so caused a BSOD.
573 	 */
574 	mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO);
575 	mb_put_uint32le(mbp, 0);
576 	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
577 	error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
578 	if (error)
579 		goto out;
580 	t2p->t2_maxpcount = 2;
581 	t2p->t2_maxdcount = vcp->vc_txmax;
582 	error = smb_t2_request(t2p);
583 	if (error) {
584 		if (smb_t2_err(t2p) == NT_STATUS_INVALID_PARAMETER)
585 			error = ENOTSUP;
586 		goto out;
587 	}
588 	mdp = &t2p->t2_rdata;
589 	/*
590 	 * On a directory Windows is likely to return a zero data count.
591 	 * Check for that now to avoid EBADRPC from md_get_uint32le
592 	 */
593 	if (mdp->md_cur == NULL)
594 		goto out;
595 	do {
596 		if ((error = md_get_uint32le(mdp, &next)))
597 			goto out;
598 		if ((error = md_get_uint32le(mdp, &nlen))) /* name length */
599 			goto out;
600 		if ((error = md_get_uint64le(mdp, NULL))) /* stream size */
601 			goto out;
602 		if ((error = md_get_uint64le(mdp, NULL))) /* allocated size */
603 			goto out;
604 		/*
605 		 * Sanity check to limit DoS or buffer overrun attempts.
606 		 * The arbitrary 16384 is sufficient for all legit packets.
607 		 */
608 		if (nlen > 16384) {
609 			SMBVDEBUG("huge name length in packet!\n");
610 			error = EBADRPC;
611 			goto out;
612 		}
613 		ctx.f_name = kmem_zalloc(nlen, KM_SLEEP);
614 		ctx.f_namesz = nlen;
615 		if ((error = md_get_mem(mdp, ctx.f_name, nlen, MB_MSYSTEM)))
616 			goto out;
617 		/*
618 		 * skip pad bytes and/or tail of overlong name
619 		 */
620 		used = 4 + 4 + 8 + 8 + nlen;
621 		if (next && next > used) {
622 			if (next - used > 16384) {
623 				SMBVDEBUG("huge offset in packet!\n");
624 				error = EBADRPC;
625 				goto out;
626 			}
627 			md_get_mem(mdp, NULL, next - used, MB_MSYSTEM);
628 		}
629 		/* ignore a trailing null, not that we expect them */
630 		if (SMB_UNICODE_STRINGS(vcp)) {
631 			if (nlen > 1 && !ctx.f_name[nlen - 1] &&
632 			    !ctx.f_name[nlen - 2])
633 				nlen -= 2;
634 		} else {
635 			if (nlen && !ctx.f_name[nlen - 1])
636 				nlen -= 1;
637 		}
638 		ctx.f_nmlen = nlen;
639 		smbfs_fname_tolocal(&ctx); /* converts from UCS2LE */
640 		/*
641 		 * We should now have a name in the form
642 		 * : <foo> :$DATA
643 		 * Where <foo> is UTF-8 w/o null termination
644 		 * If it isn't in that form we want to LOG it and skip it.
645 		 * Note we want to skip w/o logging the "data fork" entry,
646 		 * which is simply ::$DATA
647 		 * Otherwise we want to uiomove out <foo> with a null added.
648 		 */
649 		if (smbfs_smb_undollardata(np, &ctx)) {
650 			char *s;
651 
652 			/* the "+ 1" skips over the leading colon */
653 			s = sfm2xattr(ctx.f_name + 1);
654 #ifndef DUAL_EAS	/* XXX */
655 	/*
656 	 * In Tiger Carbon still accesses dot-underscore files directly, so...
657 	 * For Tiger we preserve the SFM/Thursby AFP_* stream names rather
658 	 * than mapping them to com.apple.*.  This means our copy engines
659 	 * will preserve SFM/Thursby resource-fork and finder-info.
660 	 */
661 			s = NULL;
662 #endif
663 			if (s)
664 				ctx.f_nmlen = strlen(s) + 1;
665 			else
666 				s = ctx.f_name + 1;
667 			if (uio)
668 				uiomove(s, ctx.f_nmlen, uio);
669 			else
670 				*sizep += ctx.f_nmlen;
671 		}
672 		kmem_free(ctx.f_name, ctx.f_namesz);
673 		ctx.f_name = NULL;
674 	} while (next && !error);
675 out:
676 	if (ctx.f_name)
677 		kmem_free(ctx.f_name, ctx.f_namesz);
678 	smb_t2_done(t2p);
679 	return (error);
680 }
681 
682 #endif /* APPLE */
683 
684 int
685 smbfs_smb_qfsattr(struct smb_share *ssp, uint32_t *attrp,
686 			struct smb_cred *scrp)
687 {
688 	struct smb_t2rq *t2p;
689 	struct mbchain *mbp;
690 	struct mdchain *mdp;
691 	uint32_t nlen;
692 	int error;
693 	char *fs_name;	/* will malloc whatever the size is */
694 	struct smbfs_fctx	ctx;
695 
696 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
697 	    scrp, &t2p);
698 	if (error)
699 		return (error);
700 	mbp = &t2p->t2_tparam;
701 	mb_init(mbp);
702 	mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO);
703 	t2p->t2_maxpcount = 4;
704 	t2p->t2_maxdcount = 4 * 3 + 512;
705 	error = smb_t2_request(t2p);
706 	if (error) {
707 		smb_t2_done(t2p);
708 		return (error);
709 	}
710 	mdp = &t2p->t2_rdata;
711 	md_get_uint32le(mdp, attrp);
712 	md_get_uint32le(mdp, &ssp->ss_maxfilenamelen);
713 	md_get_uint32le(mdp, &nlen);	/* fs name length */
714 	if (ssp->ss_fsname == NULL && nlen) {
715 		ctx.f_ssp = ssp;
716 		ctx.f_name = kmem_alloc(nlen, KM_SLEEP);
717 		ctx.f_namesz = nlen;
718 		md_get_mem(mdp, ctx.f_name, nlen, MB_MSYSTEM);
719 		ctx.f_nmlen = nlen;
720 		smbfs_fname_tolocal(&ctx);
721 		fs_name = kmem_alloc(ctx.f_nmlen+1, KM_SLEEP);
722 		bcopy(ctx.f_name, fs_name, ctx.f_nmlen);
723 		fs_name[ctx.f_nmlen] = '\0';
724 		ssp->ss_fsname = fs_name;
725 		kmem_free(ctx.f_name, ctx.f_namesz);
726 		/*
727 		 * If fs_name isn't NTFS they probably require resume keys.
728 		 * This is another example of the client trying to fix a server
729 		 * bug. This code uses the logic created by PR-3983209. See
730 		 * long block comment in smbfs_smb_findnextLM2.
731 		 */
732 		if (strcmp(fs_name, "NTFS")) {
733 			SMB_SS_LOCK(ssp);
734 			ssp->ss_flags |= SMBS_RESUMEKEYS;
735 			SMB_SS_UNLOCK(ssp);
736 		}
737 		SMBVDEBUG("(fyi) share '%s', attr 0x%x, maxfilename %d\n",
738 		    ssp->ss_fsname, *attrp, ssp->ss_maxfilenamelen);
739 	}
740 	smb_t2_done(t2p);
741 	return (0);
742 }
743 
744 int
745 smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
746 	struct smb_cred *scp)
747 {
748 	int error;
749 
750 	if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
751 		error = smbfs_smb_statfsLM2(ssp, sbp, scp);
752 	else
753 		error = smbfs_smb_statfsLM1(ssp, sbp, scp);
754 
755 	return (error);
756 }
757 
758 int
759 smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp,
760 	struct smb_cred *scrp)
761 {
762 	struct smb_t2rq *t2p;
763 	struct mbchain *mbp;
764 	struct mdchain *mdp;
765 	uint16_t bsize;
766 	uint32_t units, bpu, funits;
767 	uint64_t s, t, f;
768 	int error;
769 
770 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
771 	    scrp, &t2p);
772 	if (error)
773 		return (error);
774 	mbp = &t2p->t2_tparam;
775 	mb_init(mbp);
776 	mb_put_uint16le(mbp, SMB_QFS_ALLOCATION);
777 	t2p->t2_maxpcount = 4;
778 	t2p->t2_maxdcount = 4 * 4 + 2;
779 	error = smb_t2_request(t2p);
780 	if (error) {
781 		smb_t2_done(t2p);
782 		return (error);
783 	}
784 	mdp = &t2p->t2_rdata;
785 	md_get_uint32(mdp, NULL);	/* fs id */
786 	md_get_uint32le(mdp, &bpu);
787 	md_get_uint32le(mdp, &units);
788 	md_get_uint32le(mdp, &funits);
789 	md_get_uint16le(mdp, &bsize);
790 	s = bsize;
791 	s *= bpu;
792 	t = units;
793 	f = funits;
794 	/*
795 	 * Don't allow over-large blocksizes as they determine
796 	 * Finder List-view size granularities.  On the other
797 	 * hand, we mustn't let the block count overflow the
798 	 * 31 bits available.
799 	 */
800 	while (s > 16 * 1024) {
801 		if (t > LONG_MAX)
802 			break;
803 		s /= 2;
804 		t *= 2;
805 		f *= 2;
806 	}
807 	while (t > LONG_MAX) {
808 		t /= 2;
809 		f /= 2;
810 		s *= 2;
811 	}
812 	sbp->f_bsize  = (ulong_t)s;	/* file system block size */
813 	sbp->f_blocks = t;	/* total data blocks in file system */
814 	sbp->f_bfree  = f;	/* free blocks in fs */
815 	sbp->f_bavail = f;	/* free blocks avail to non-superuser */
816 	sbp->f_files  = (-1);	/* total file nodes in file system */
817 	sbp->f_ffree  = (-1);	/* free file nodes in fs */
818 	smb_t2_done(t2p);
819 	return (0);
820 }
821 
822 int
823 smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp,
824 	struct smb_cred *scrp)
825 {
826 	struct smb_rq rq, *rqp = &rq;
827 	struct mdchain *mdp;
828 	uint16_t units, bpu, bsize, funits;
829 	uint64_t s, t, f;
830 	int error;
831 
832 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
833 	    scrp);
834 	if (error)
835 		return (error);
836 	smb_rq_wstart(rqp);
837 	smb_rq_wend(rqp);
838 	smb_rq_bstart(rqp);
839 	smb_rq_bend(rqp);
840 	error = smb_rq_simple(rqp);
841 	if (error) {
842 		smb_rq_done(rqp);
843 		return (error);
844 	}
845 	smb_rq_getreply(rqp, &mdp);
846 	md_get_uint16le(mdp, &units);
847 	md_get_uint16le(mdp, &bpu);
848 	md_get_uint16le(mdp, &bsize);
849 	md_get_uint16le(mdp, &funits);
850 	s = bsize;
851 	s *= bpu;
852 	t = units;
853 	f = funits;
854 	/*
855 	 * Don't allow over-large blocksizes as they determine
856 	 * Finder List-view size granularities.  On the other
857 	 * hand, we mustn't let the block count overflow the
858 	 * 31 bits available.
859 	 */
860 	while (s > 16 * 1024) {
861 		if (t > LONG_MAX)
862 			break;
863 		s /= 2;
864 		t *= 2;
865 		f *= 2;
866 	}
867 	while (t > LONG_MAX) {
868 		t /= 2;
869 		f /= 2;
870 		s *= 2;
871 	}
872 	sbp->f_bsize = (ulong_t)s;	/* file system block size */
873 	sbp->f_blocks = t;	/* total data blocks in file system */
874 	sbp->f_bfree = f;	/* free blocks in fs */
875 	sbp->f_bavail = f;	/* free blocks avail to non-superuser */
876 	sbp->f_files = (-1);		/* total file nodes in file system */
877 	sbp->f_ffree = (-1);		/* free file nodes in fs */
878 	smb_rq_done(rqp);
879 	return (0);
880 }
881 
882 int
883 smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
884 			struct smb_cred *scrp)
885 {
886 	struct smb_t2rq *t2p;
887 	struct smb_vc *vcp = SSTOVC(ssp);
888 	struct mbchain *mbp;
889 	int error;
890 
891 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
892 	    scrp, &t2p);
893 	if (error)
894 		return (error);
895 	mbp = &t2p->t2_tparam;
896 	mb_init(mbp);
897 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
898 	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
899 		mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION);
900 	else
901 		mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO);
902 	mb_put_uint32le(mbp, 0); /* XXX should be 16 not 32(?) */
903 	mbp = &t2p->t2_tdata;
904 	mb_init(mbp);
905 	mb_put_uint64le(mbp, newsize);
906 	mb_put_uint32le(mbp, 0);			/* padding */
907 	mb_put_uint16le(mbp, 0);
908 	t2p->t2_maxpcount = 2;
909 	t2p->t2_maxdcount = 0;
910 	error = smb_t2_request(t2p);
911 	smb_t2_done(t2p);
912 	return (error);
913 }
914 
915 /*ARGSUSED*/
916 int
917 smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp,
918 	const char *tname, int tnmlen, struct smb_cred *scrp, int overwrite)
919 {
920 	struct smb_t2rq *t2p;
921 	struct smb_share *ssp = np->n_mount->smi_share;
922 	struct smb_vc *vcp = SSTOVC(ssp);
923 	struct mbchain *mbp;
924 	int32_t *ucslenp;
925 	int error, cerror;
926 	uint16_t fid = 0;
927 
928 	/* Shared lock for n_fid use below. */
929 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
930 
931 	if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU))
932 		return (ENOTSUP);
933 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
934 	    scrp, &t2p);
935 	if (error)
936 		return (error);
937 	if (tdnp) {
938 		error = smbfs_smb_tmpopen(tdnp, SA_RIGHT_FILE_READ_DATA, scrp,
939 		    &fid);
940 		if (error)
941 			goto exit;
942 	}
943 	mbp = &t2p->t2_tparam;
944 	mb_init(mbp);
945 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
946 	mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
947 	mb_put_uint16le(mbp, 0); /* reserved, nowadays */
948 	mbp = &t2p->t2_tdata;
949 	mb_init(mbp);
950 	mb_put_uint32le(mbp, overwrite);
951 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); /* base for tname */
952 	mb_put_uint16le(mbp, 0); /* part of a 32bit fid? */
953 	ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t));
954 	mbp->mb_count = 0;
955 	error = smb_put_dstring(mbp, vcp, tname, SMB_CS_NONE);
956 	if (error)
957 		goto exit;
958 	mbp->mb_count--;	/* don't count the null */
959 	*ucslenp = htolel(mbp->mb_count);
960 	t2p->t2_maxpcount = 2;
961 	t2p->t2_maxdcount = 0;
962 	error = smb_t2_request(t2p);
963 exit:
964 	if (fid) {
965 		cerror = smbfs_smb_tmpclose(tdnp, fid, scrp);
966 		if (cerror)
967 			SMBERROR("error %d closing fid %d\n", cerror, fid);
968 	}
969 	smb_t2_done(t2p);
970 	return (error);
971 }
972 
973 int
974 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp)
975 {
976 	struct smb_share *ssp = np->n_mount->smi_share;
977 	struct smb_rq rq, *rqp = &rq;
978 	struct mbchain *mbp;
979 	int error;
980 
981 	/* Shared lock for n_fid use below. */
982 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
983 
984 	if (!(np->n_flag & NFLUSHWIRE))
985 		return (0);
986 	if (np->r_count == 0)
987 		return (0); /* not open */
988 	if (np->r_vnode->v_type != VREG)
989 		return (0); /* not a file */
990 
991 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
992 	if (error)
993 		return (error);
994 	smb_rq_getrequest(rqp, &mbp);
995 	smb_rq_wstart(rqp);
996 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
997 	smb_rq_wend(rqp);
998 	smb_rq_bstart(rqp);
999 	smb_rq_bend(rqp);
1000 	error = smb_rq_simple(rqp);
1001 	smb_rq_done(rqp);
1002 	if (!error) {
1003 		mutex_enter(&np->r_statelock);
1004 		np->n_flag &= ~NFLUSHWIRE;
1005 		mutex_exit(&np->r_statelock);
1006 	}
1007 	return (error);
1008 }
1009 
1010 int
1011 smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
1012 			struct smb_cred *scrp)
1013 {
1014 	struct smb_share *ssp = np->n_mount->smi_share;
1015 	struct smb_rq rq, *rqp = &rq;
1016 	struct mbchain *mbp;
1017 	int error;
1018 
1019 	/*
1020 	 * This call knows about 64-bit offsets.
1021 	 */
1022 	error = smbfs_smb_seteof(ssp, fid, newsize, scrp);
1023 	if (!error) {
1024 		mutex_enter(&np->r_statelock);
1025 		np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
1026 		mutex_exit(&np->r_statelock);
1027 		return (0);
1028 	}
1029 
1030 	/*
1031 	 * If we have SMB_CAP_LARGE_FILES, the above
1032 	 * should have worked.  XXX: Don't fallback?
1033 	 * XXX: Or fallback on specific errors?
1034 	 */
1035 	if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) {
1036 		SMBVDEBUG("Have CAP_LARGE but _seteof error=%d\n", error);
1037 	}
1038 
1039 	/*
1040 	 * OK, so fallback to SMB_COM_WRITE, but note:
1041 	 * it only supports 32-bit file offsets.
1042 	 */
1043 	if (newsize > UINT32_MAX)
1044 		return (EFBIG);
1045 
1046 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp);
1047 	if (error)
1048 		return (error);
1049 	smb_rq_getrequest(rqp, &mbp);
1050 	smb_rq_wstart(rqp);
1051 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
1052 	mb_put_uint16le(mbp, 0);
1053 	mb_put_uint32le(mbp, newsize);
1054 	mb_put_uint16le(mbp, 0);
1055 	smb_rq_wend(rqp);
1056 	smb_rq_bstart(rqp);
1057 	mb_put_uint8(mbp, SMB_DT_DATA);
1058 	mb_put_uint16le(mbp, 0);
1059 	smb_rq_bend(rqp);
1060 	error = smb_rq_simple(rqp);
1061 	smb_rq_done(rqp);
1062 	mutex_enter(&np->r_statelock);
1063 	np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
1064 	mutex_exit(&np->r_statelock);
1065 	return (error);
1066 }
1067 
1068 int
1069 smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
1070 	struct smbfattr *fap, struct smb_cred *scrp)
1071 {
1072 	struct smb_rq rq, *rqp = &rq;
1073 	struct smb_share *ssp = np->n_mount->smi_share;
1074 	struct mbchain *mbp;
1075 	struct mdchain *mdp;
1076 	uint8_t wc;
1077 	int error;
1078 	uint16_t wattr;
1079 	uint32_t longint;
1080 
1081 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp);
1082 	if (error)
1083 		return (error);
1084 	smb_rq_getrequest(rqp, &mbp);
1085 	smb_rq_wstart(rqp);
1086 	smb_rq_wend(rqp);
1087 	smb_rq_bstart(rqp);
1088 	mb_put_uint8(mbp, SMB_DT_ASCII);
1089 	do {
1090 		error = smbfs_fullpath(mbp, SSTOVC(ssp), np,
1091 		    name, &nmlen, '\\');
1092 		if (error)
1093 			break;
1094 		smb_rq_bend(rqp);
1095 		error = smb_rq_simple(rqp);
1096 		if (error)
1097 			break;
1098 		smb_rq_getreply(rqp, &mdp);
1099 		if (md_get_uint8(mdp, &wc) != 0 || wc != 10) {
1100 			error = EBADRPC;
1101 			break;
1102 		}
1103 		md_get_uint16le(mdp, &wattr);
1104 		fap->fa_attr = wattr;
1105 		/*
1106 		 * Be careful using the time returned here, as
1107 		 * with FAT on NT4SP6, at least, the time returned is low
1108 		 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
1109 		 * over about every seven minutes!
1110 		 */
1111 		md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
1112 		if (longint)	/* avoid bogus zero returns */
1113 			smb_time_server2local(longint,
1114 			    SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime);
1115 		md_get_uint32le(mdp, &longint);
1116 		fap->fa_size = longint;
1117 		/*LINTED*/
1118 	} while (0);
1119 	smb_rq_done(rqp);
1120 	return (error);
1121 }
1122 
1123 int
1124 smbfs_smb_setpattr(struct smbnode *np, uint32_t attr,
1125 	struct timespec *mtime,	struct timespec *atime,
1126 	struct smb_cred *scrp)
1127 {
1128 	struct smb_share *ssp = np->n_mount->smi_share;
1129 	struct smb_vc *vcp = SSTOVC(ssp);
1130 	int error;
1131 
1132 	/*
1133 	 * This is the logic that was in smbfs_vnops.c
1134 	 */
1135 	if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) &&
1136 	    (vcp->vc_flags & SMBV_NT4) == 0) {
1137 		/*
1138 		 * NT4 doesn't understand "NT" style SMBs;
1139 		 * for NT4 we use the old SET_PATH_INFO
1140 		 * XXX Actually, I think the issue is that
1141 		 * NT requires an open handle for this.
1142 		 */
1143 		error = smbfs_smb_setpattrNT(np,
1144 		    attr, mtime, atime, scrp);
1145 		if (error != EBADRPC)
1146 			return (error);
1147 
1148 		/* NT4 response, remember */
1149 		SMB_VC_LOCK(vcp);
1150 		vcp->vc_flags |= SMBV_NT4;
1151 		SMB_VC_UNLOCK(vcp);
1152 	}
1153 
1154 	if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) {
1155 		error = smbfs_smb_setpattr2(np,
1156 		    attr, mtime, atime, scrp);
1157 	} else {
1158 		error = smbfs_smb_setpattr1(np, NULL, 0,
1159 		    attr, mtime, scrp);
1160 	}
1161 
1162 	return (error);
1163 }
1164 
1165 /*
1166  * Set DOS file attributes. mtime should be NULL for dialects above lm10
1167  */
1168 int
1169 smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len,
1170 	uint32_t attr, struct timespec *mtime,
1171 	struct smb_cred *scrp)
1172 {
1173 	struct smb_rq rq, *rqp = &rq;
1174 	struct smb_share *ssp = np->n_mount->smi_share;
1175 	struct mbchain *mbp;
1176 	long time;
1177 	int error, svtz;
1178 
1179 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp);
1180 	if (error)
1181 		return (error);
1182 	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
1183 	smb_rq_getrequest(rqp, &mbp);
1184 	smb_rq_wstart(rqp);
1185 	mb_put_uint16le(mbp, (uint16_t)attr);
1186 	if (mtime) {
1187 		smb_time_local2server(mtime, svtz, &time);
1188 	} else
1189 		time = 0;
1190 	mb_put_uint32le(mbp, time);		/* mtime */
1191 	mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
1192 	smb_rq_wend(rqp);
1193 	smb_rq_bstart(rqp);
1194 	mb_put_uint8(mbp, SMB_DT_ASCII);
1195 	do {
1196 		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &len, '\\');
1197 		if (error)
1198 			break;
1199 		mb_put_uint8(mbp, SMB_DT_ASCII);
1200 		if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
1201 			mb_put_padbyte(mbp);
1202 			mb_put_uint8(mbp, 0);	/* 1st byte NULL Unicode char */
1203 		}
1204 		mb_put_uint8(mbp, 0);
1205 		smb_rq_bend(rqp);
1206 		error = smb_rq_simple(rqp);
1207 		if (error)
1208 			break;
1209 		/*LINTED*/
1210 	} while (0);
1211 	smb_rq_done(rqp);
1212 	return (error);
1213 }
1214 
1215 int
1216 smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
1217 			struct smb_cred *scrp)
1218 {
1219 	struct smbfattr fa;
1220 	int error;
1221 	uint32_t attr;
1222 
1223 	error = smbfs_smb_query_info(np, name, len, &fa, scrp);
1224 	attr = fa.fa_attr;
1225 	if (!error && !(attr & SMB_FA_HIDDEN)) {
1226 		attr |= SMB_FA_HIDDEN;
1227 		error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
1228 	}
1229 	return (error);
1230 }
1231 
1232 
1233 int
1234 smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
1235 			struct smb_cred *scrp)
1236 {
1237 	struct smbfattr fa;
1238 	uint32_t attr;
1239 	int error;
1240 
1241 	error = smbfs_smb_query_info(np, name, len, &fa, scrp);
1242 	attr = fa.fa_attr;
1243 	if (!error && (attr & SMB_FA_HIDDEN)) {
1244 		attr &= ~SMB_FA_HIDDEN;
1245 		error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
1246 	}
1247 	return (error);
1248 }
1249 
1250 /*
1251  * Note, win95 doesn't support this call.
1252  */
1253 int
1254 smbfs_smb_setpattr2(struct smbnode *np, uint32_t attr,
1255 	struct timespec *mtime,	struct timespec *atime,
1256 	struct smb_cred *scrp)
1257 {
1258 	struct smb_t2rq *t2p;
1259 	struct smb_share *ssp = np->n_mount->smi_share;
1260 	struct smb_vc *vcp = SSTOVC(ssp);
1261 	struct mbchain *mbp;
1262 	uint16_t date, time;
1263 	int error, tzoff;
1264 
1265 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
1266 	    scrp, &t2p);
1267 	if (error)
1268 		return (error);
1269 	mbp = &t2p->t2_tparam;
1270 	mb_init(mbp);
1271 	mb_put_uint16le(mbp, SMB_SFILEINFO_STANDARD);
1272 	mb_put_uint32le(mbp, 0);		/* MBZ */
1273 	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
1274 	error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
1275 	if (error) {
1276 		smb_t2_done(t2p);
1277 		return (error);
1278 	}
1279 	tzoff = vcp->vc_sopt.sv_tz;
1280 	mbp = &t2p->t2_tdata;
1281 	mb_init(mbp);
1282 	mb_put_uint32le(mbp, 0);		/* creation time */
1283 	if (atime)
1284 		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
1285 	else
1286 		time = date = 0;
1287 	mb_put_uint16le(mbp, date);
1288 	mb_put_uint16le(mbp, time);
1289 	if (mtime)
1290 		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
1291 	else
1292 		time = date = 0;
1293 	mb_put_uint16le(mbp, date);
1294 	mb_put_uint16le(mbp, time);
1295 	mb_put_uint32le(mbp, 0);		/* file size */
1296 	mb_put_uint32le(mbp, 0);		/* allocation unit size */
1297 	mb_put_uint16le(mbp, attr);	/* DOS attr */
1298 	mb_put_uint32le(mbp, 0);		/* EA size */
1299 	t2p->t2_maxpcount = 5 * 2;
1300 	t2p->t2_maxdcount = vcp->vc_txmax;
1301 	error = smb_t2_request(t2p);
1302 	smb_t2_done(t2p);
1303 	return (error);
1304 }
1305 
1306 /*
1307  * *BASIC_INFO works with Samba, but Win2K servers say it is an
1308  * invalid information level on a SET_PATH_INFO.  Note Win2K does
1309  * support *BASIC_INFO on a SET_FILE_INFO, and they support the
1310  * equivalent *BASIC_INFORMATION on SET_PATH_INFO.  Go figure.
1311  */
1312 int
1313 smbfs_smb_setpattrNT(struct smbnode *np, uint32_t attr,
1314 	struct timespec *mtime, struct timespec *atime,
1315 	struct smb_cred *scrp)
1316 {
1317 	struct smb_t2rq *t2p;
1318 	struct smb_share *ssp = np->n_mount->smi_share;
1319 	struct smb_vc *vcp = SSTOVC(ssp);
1320 	struct mbchain *mbp;
1321 	uint64_t tm;
1322 	int error, tzoff;
1323 	/* 64 bit value for Jan 1 1980 */
1324 	PRIVSYM uint64_t DIFF1980TO1601 = 11960035200ULL*10000000ULL;
1325 
1326 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
1327 	    scrp, &t2p);
1328 	if (error)
1329 		return (error);
1330 	mbp = &t2p->t2_tparam;
1331 	mb_init(mbp);
1332 	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
1333 		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION);
1334 	else
1335 		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFO);
1336 	mb_put_uint32le(mbp, 0);		/* MBZ */
1337 	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
1338 	error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
1339 	if (error) {
1340 		smb_t2_done(t2p);
1341 		return (error);
1342 	}
1343 	tzoff = vcp->vc_sopt.sv_tz;
1344 
1345 	/* do we know it won't support dates < 1980? */
1346 	if (!(ssp->ss_flags & SMBS_1980)) {
1347 		mbp = &t2p->t2_tdata;
1348 		mb_init(mbp);
1349 		mb_put_uint64le(mbp, 0);		/* creation time */
1350 		if (atime) {
1351 			smb_time_local2NT(atime, tzoff, &tm);
1352 		} else
1353 			tm = 0;
1354 		mb_put_uint64le(mbp, tm);		/* access time */
1355 		if (mtime) {
1356 			smb_time_local2NT(mtime, tzoff, &tm);
1357 		} else
1358 			tm = 0;
1359 		mb_put_uint64le(mbp, tm);		/* last write time */
1360 		mb_put_uint64le(mbp, tm);		/* change time */
1361 		mb_put_uint32le(mbp, attr);		/* attr */
1362 		mb_put_uint32le(mbp, 0);	/* undocumented padding */
1363 		t2p->t2_maxpcount = 24;
1364 		t2p->t2_maxdcount = 56;
1365 		error = smb_t2_request(t2p);
1366 	}
1367 	/*
1368 	 * "invalid argument" error probably means it's a
1369 	 * FAT drive that doesn't accept dates earlier
1370 	 * than 1980, so adjust dates and retry. If the
1371 	 * 1980 flag is on we fell thru the if {} above
1372 	 */
1373 	if ((ssp->ss_flags & SMBS_1980) || (error == EINVAL)) {
1374 		mbp = &t2p->t2_tdata;
1375 		mb_init(mbp);
1376 		mb_put_uint64le(mbp, 0);		/* creation time */
1377 		if (atime) {
1378 			smb_time_local2NT(atime, tzoff, &tm);
1379 			if (tm < DIFF1980TO1601)
1380 				tm = DIFF1980TO1601;
1381 		} else
1382 			tm = 0;
1383 		mb_put_uint64le(mbp, tm);		/* access time */
1384 		if (mtime) {
1385 			smb_time_local2NT(mtime, tzoff, &tm);
1386 			if (tm < DIFF1980TO1601)
1387 				tm = DIFF1980TO1601;
1388 		} else
1389 			tm = 0;
1390 		mb_put_uint64le(mbp, tm);		/* last write time */
1391 		mb_put_uint64le(mbp, tm);		/* change time */
1392 		mb_put_uint32le(mbp, attr);		/* attr */
1393 		mb_put_uint32le(mbp, 0);	/* undocumented padding */
1394 		t2p->t2_maxpcount = 24;
1395 		t2p->t2_maxdcount = 56;
1396 		error = smb_t2_request(t2p);
1397 
1398 		/* if this worked set flag to do the right thing next time */
1399 		if (!(error)) {
1400 			SMB_SS_LOCK(ssp);
1401 			ssp->ss_flags |= SMBS_1980;
1402 			SMB_SS_UNLOCK(ssp);
1403 		}
1404 	}
1405 	smb_t2_done(t2p);
1406 	return (error);
1407 }
1408 
1409 int
1410 smbfs_smb_setfattr(struct smbnode *np, uint16_t fid,
1411 	uint32_t attr, struct timespec *mtime,
1412 	struct timespec *atime, struct smb_cred *scrp)
1413 {
1414 	struct smb_share *ssp = np->n_mount->smi_share;
1415 	struct smb_vc *vcp = SSTOVC(ssp);
1416 	int error;
1417 
1418 	/*
1419 	 * This is the logic that was in smbfs_vnops.c
1420 	 * Might not be quite right for older dialects.
1421 	 * (XXX: What about the DOS attributes?)
1422 	 */
1423 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)
1424 		error = smbfs_smb_setfattrNT(np, fid,
1425 		    np->n_dosattr, mtime, atime, scrp);
1426 	else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0)
1427 		error = smbfs_smb_setftime1(np, fid,
1428 		    mtime, atime, scrp);
1429 	else
1430 		error = smbfs_smb_setpattr1(np, NULL, 0,
1431 		    attr, mtime, scrp);
1432 
1433 	return (error);
1434 }
1435 
1436 /*
1437  * Set file atime and mtime. Isn't supported by core dialect.
1438  */
1439 int
1440 smbfs_smb_setftime1(
1441 	struct smbnode *np,
1442 	uint16_t fid,
1443 	struct timespec *mtime,
1444 	struct timespec *atime,
1445 	struct smb_cred *scrp)
1446 {
1447 	struct smb_rq rq, *rqp = &rq;
1448 	struct smb_share *ssp = np->n_mount->smi_share;
1449 	struct mbchain *mbp;
1450 	uint16_t date, time;
1451 	int error, tzoff;
1452 
1453 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp);
1454 	if (error)
1455 		return (error);
1456 	tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
1457 	smb_rq_getrequest(rqp, &mbp);
1458 	smb_rq_wstart(rqp);
1459 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
1460 	mb_put_uint32le(mbp, 0);		/* creation time */
1461 
1462 	if (atime)
1463 		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
1464 	else
1465 		time = date = 0;
1466 	mb_put_uint16le(mbp, date);
1467 	mb_put_uint16le(mbp, time);
1468 	if (mtime)
1469 		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
1470 	else
1471 		time = date = 0;
1472 	mb_put_uint16le(mbp, date);
1473 	mb_put_uint16le(mbp, time);
1474 	smb_rq_wend(rqp);
1475 	smb_rq_bstart(rqp);
1476 	smb_rq_bend(rqp);
1477 	error = smb_rq_simple(rqp);
1478 	SMBVDEBUG("%d\n", error);
1479 	smb_rq_done(rqp);
1480 	return (error);
1481 }
1482 
1483 /*
1484  * Set DOS file attributes.
1485  * Looks like this call can be used only if CAP_NT_SMBS bit is on.
1486  */
1487 int
1488 smbfs_smb_setfattrNT(struct smbnode *np, uint16_t fid,
1489 	uint32_t attr, struct timespec *mtime,
1490 	struct timespec *atime, struct smb_cred *scrp)
1491 {
1492 	struct smb_t2rq *t2p;
1493 	struct smb_share *ssp = np->n_mount->smi_share;
1494 	struct smb_vc *vcp = SSTOVC(ssp);
1495 	struct mbchain *mbp;
1496 	uint64_t tm;
1497 	int error, svtz;
1498 
1499 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
1500 	    scrp, &t2p);
1501 	if (error)
1502 		return (error);
1503 	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
1504 	mbp = &t2p->t2_tparam;
1505 	mb_init(mbp);
1506 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
1507 	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
1508 		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION);
1509 	else
1510 		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFO);
1511 	mb_put_uint32le(mbp, 0); /* XXX should be 16 not 32(?) */
1512 	mbp = &t2p->t2_tdata;
1513 	mb_init(mbp);
1514 	mb_put_uint64le(mbp, 0);		/* creation time */
1515 	if (atime) {
1516 		smb_time_local2NT(atime, svtz, &tm);
1517 	} else
1518 		tm = 0;
1519 	mb_put_uint64le(mbp, tm);		/* access time */
1520 	if (mtime) {
1521 		smb_time_local2NT(mtime, svtz, &tm);
1522 	} else
1523 		tm = 0;
1524 	mb_put_uint64le(mbp, tm);		/* last write time */
1525 	mb_put_uint64le(mbp, tm);		/* change time */
1526 	mb_put_uint32le(mbp, attr);
1527 	mb_put_uint32le(mbp, 0);			/* padding */
1528 	t2p->t2_maxpcount = 2;
1529 	t2p->t2_maxdcount = 0;
1530 	error = smb_t2_request(t2p);
1531 	smb_t2_done(t2p);
1532 	return (error);
1533 }
1534 
1535 /*
1536  * Modern create/open of file or directory.
1537  *
1538  * If disp is ..._DISP_OPEN, or ...DISP_OPEN_IF, or...
1539  * then this is an open attempt, and:
1540  *   If xattr then name is the stream to be opened at np,
1541  *   Else np should be opened.
1542  *   ...we won't touch *fidp,
1543  *   ...we will set or clear *attrcacheupdated.
1544  * Else this is a creation attempt, and:
1545  *   If xattr then name is the stream to create at np,
1546  *   Else name is the thing to create under directory np.
1547  *   ...we will return *fidp,
1548  *   ...we won't touch *attrcacheupdated.
1549  *
1550  * Note, We use: disp = ...OPEN_IF, ...OVERWRITE_IF, etc.
1551  * now too, which may or may not create a new object.
1552  */
1553 int
1554 smbfs_smb_ntcreatex(struct smbnode *np, uint32_t rights,
1555 		    struct smb_cred *scrp, enum vtype vt,
1556 		    int *attrcacheupdated, uint16_t *fidp,
1557 		    const char *name, int nmlen, uint32_t disp, int xattr,
1558 		    len_t *sizep, uint32_t *rightsp)
1559 {
1560 	struct smb_rq rq, *rqp = &rq;
1561 	struct smb_share *ssp = np->n_mount->smi_share;
1562 	struct smb_vc *vcp = SSTOVC(ssp);
1563 	struct mbchain *mbp;
1564 	struct mdchain *mdp;
1565 	struct smbfattr fap;
1566 	uint8_t wc;
1567 	uint32_t longint, createact, createopt, efa;
1568 	uint64_t llongint;
1569 	int error;
1570 	uint16_t fid, *namelenp;
1571 
1572 	/*
1573 	 * Set the File attributes and Create options.
1574 	 * WinXP uses EFA_NORMAL in all of these cases.
1575 	 */
1576 	createopt = (vt == VDIR) ?
1577 	    NTCREATEX_OPTIONS_DIRECTORY :
1578 	    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
1579 	efa = SMB_EFA_NORMAL;
1580 	if (disp != NTCREATEX_DISP_OPEN && !xattr) {
1581 		if (name && *name == '.')
1582 			efa = SMB_EFA_HIDDEN;
1583 	}
1584 
1585 	gethrestime(&fap.fa_reqtime);
1586 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp);
1587 	if (error)
1588 		return (error);
1589 	smb_rq_getrequest(rqp, &mbp);
1590 	smb_rq_wstart(rqp);
1591 	mb_put_uint8(mbp, 0xff);	/* secondary command */
1592 	mb_put_uint8(mbp, 0);		/* MBZ */
1593 	mb_put_uint16le(mbp, 0);	/* offset to next command (none) */
1594 	mb_put_uint8(mbp, 0);		/* MBZ */
1595 	namelenp = (uint16_t *)mb_reserve(mbp, sizeof (uint16_t));
1596 	/*
1597 	 * XP to a W2K Server does not use NTCREATEX_FLAGS_OPEN_DIRECTORY
1598 	 * for creating nor for opening a directory.  Samba ignores the bit.
1599 	 */
1600 #if 0 /* causes sharing violation when making dir on W2K! */
1601 	mb_put_uint32le(mbp, vt == VDIR ?  NTCREATEX_FLAGS_OPEN_DIRECTORY : 0);
1602 #else
1603 	mb_put_uint32le(mbp, 0);	/* NTCREATEX_FLAGS_* */
1604 #endif
1605 	mb_put_uint32le(mbp, 0);	/* FID - basis for path if not root */
1606 	mb_put_uint32le(mbp, rights);
1607 	mb_put_uint64le(mbp, 0);	/* "initial allocation size" */
1608 	mb_put_uint32le(mbp, efa);
1609 	mb_put_uint32le(mbp, NTCREATEX_SHARE_ACCESS_ALL);
1610 	mb_put_uint32le(mbp, disp);
1611 	mb_put_uint32le(mbp, createopt);
1612 	mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */
1613 	mb_put_uint8(mbp, 0);   /* security flags (?) */
1614 	smb_rq_wend(rqp);
1615 	smb_rq_bstart(rqp);
1616 	do {
1617 		if (name == NULL)
1618 			nmlen = 0;
1619 		error = smbfs_fullpath(mbp, vcp, np, name, &nmlen,
1620 		    xattr ? ':' : '\\');
1621 		if (error)
1622 			break;
1623 		*namelenp = htoles(nmlen); /* includes null */
1624 		smb_rq_bend(rqp);
1625 		/*
1626 		 * Don't want to risk missing a successful
1627 		 * open response, or we could "leak" FIDs.
1628 		 */
1629 		rqp->sr_flags |= SMBR_NOINTR_RECV;
1630 		error = smb_rq_simple_timed(rqp, smb_timo_open);
1631 		if (error)
1632 			break;
1633 		smb_rq_getreply(rqp, &mdp);
1634 		/*
1635 		 * spec says 26 for word count, but 34 words are defined
1636 		 * and observed from win2000
1637 		 */
1638 		if (md_get_uint8(mdp, &wc) != 0 ||
1639 		    (wc != 26 && wc != 34 && wc != 42)) {
1640 			error = EBADRPC;
1641 			break;
1642 		}
1643 		md_get_uint8(mdp, NULL);	/* secondary cmd */
1644 		md_get_uint8(mdp, NULL);	/* mbz */
1645 		md_get_uint16le(mdp, NULL);	/* andxoffset */
1646 		md_get_uint8(mdp, NULL);	/* oplock lvl granted */
1647 		md_get_uint16(mdp, &fid);	/* yes, leaving it LE */
1648 		md_get_uint32le(mdp, &createact);	/* create_action */
1649 		md_get_uint64le(mdp, &llongint);	/* creation time */
1650 		md_get_uint64le(mdp, &llongint);	/* access time */
1651 		if (llongint)	/* avoid bogus 0 time (on FAT roots) */
1652 			smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz,
1653 			    &fap.fa_atime);
1654 		md_get_uint64le(mdp, &llongint);	/* write time */
1655 		if (llongint)	/* avoid bogus 0 time (on FAT roots) */
1656 			smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz,
1657 			    &fap.fa_mtime);
1658 		md_get_uint64le(mdp, &llongint);	/* change time */
1659 		if (llongint)	/* avoid bogus 0 time (on FAT roots) */
1660 			smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz,
1661 			    &fap.fa_ctime);
1662 		md_get_uint32le(mdp, &longint);	/* attributes */
1663 		fap.fa_attr = longint;
1664 		md_get_uint64le(mdp, NULL);	/* allocation size */
1665 		md_get_uint64le(mdp, &llongint);   /* EOF */
1666 		fap.fa_size = llongint;
1667 		if (sizep)
1668 			*sizep = fap.fa_size;
1669 		md_get_uint16le(mdp, NULL);	/* file type */
1670 		md_get_uint16le(mdp, NULL);	/* device state */
1671 		md_get_uint8(mdp, NULL);	/* directory (boolean) */
1672 		/*LINTED*/
1673 	} while (0);
1674 	smb_rq_done(rqp);
1675 	if (error)
1676 		return (error);
1677 	if (fidp)
1678 		*fidp = fid;
1679 	if (rightsp)
1680 		*rightsp = rights;
1681 	/*
1682 	 * Is it possible that we have cached attributes?
1683 	 * Assume "not cached" if we created the object.
1684 	 */
1685 	if (createact == NTCREATEX_ACTION_CREATED || xattr)
1686 		goto uncached;
1687 	if (attrcacheupdated)
1688 		*attrcacheupdated = 0;
1689 	/*
1690 	 * Update the cached attributes if they are still valid
1691 	 * in the cache and if nothing has changed.
1692 	 */
1693 	if (np->r_vnode == NULL)
1694 		goto uncached;
1695 	if (smbfs_attr_cachelookup(np->r_vnode, NULL) != 0)
1696 		goto uncached;  /* the cached attributes are not valid */
1697 	if (fap.fa_size != np->n_size)
1698 		goto uncached;  /* the size is different */
1699 	if (fap.fa_attr != np->n_dosattr)
1700 		goto uncached;  /* the attrs are different */
1701 	/*
1702 	 * fap.fa_mtime is in two second increments while np->n_mtime
1703 	 * may be in one second increments, so comparing the times is
1704 	 * somewhat sloppy.
1705 	 *
1706 	 * XXX: true fap.fa_mtime resolution must depend upon server's
1707 	 * local filesystem and is thus indeterminate... XXX ...TBD how that
1708 	 * affects this code... note wire resolution here is 100ns versus
1709 	 * 1sec down in smbfs_smb_oldopen(SMB_COM_OPEN)
1710 	 */
1711 	if (fap.fa_mtime.tv_sec != np->n_mtime.tv_sec &&
1712 	    fap.fa_mtime.tv_sec != np->n_mtime.tv_sec - 1 &&
1713 	    fap.fa_mtime.tv_sec != np->n_mtime.tv_sec + 1)
1714 		goto uncached;  /* the mod time is different */
1715 
1716 	fap.fa_mtime.tv_sec = np->n_mtime.tv_sec; /* keep higher res time */
1717 	smbfs_attr_cacheenter(np->r_vnode, &fap);
1718 	if (attrcacheupdated)
1719 		*attrcacheupdated = 1;
1720 uncached:
1721 	return (0);
1722 }
1723 
1724 static uint32_t
1725 smb_mode2rights(int mode)
1726 {
1727 	mode = mode & SMB_AM_OPENMODE;
1728 
1729 	switch (mode) {
1730 	case SMB_AM_OPENREAD:
1731 		return (GENERIC_RIGHT_READ_ACCESS);
1732 	case SMB_AM_OPENWRITE:
1733 		return (GENERIC_RIGHT_WRITE_ACCESS);
1734 	case SMB_AM_OPENRW:
1735 		return (GENERIC_RIGHT_ALL_ACCESS);
1736 	case SMB_AM_OPENEXEC:
1737 		return (GENERIC_RIGHT_EXECUTE_ACCESS);
1738 	}
1739 	return (0);
1740 }
1741 
1742 static int
1743 smb_rights2mode(uint32_t rights)
1744 {
1745 	int accmode = SMB_AM_OPENEXEC; /* our fallback */
1746 
1747 	if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD |
1748 	    SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES |
1749 	    SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS |
1750 	    STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS |
1751 	    GENERIC_RIGHT_ALL_ACCESS | GENERIC_RIGHT_WRITE_ACCESS))
1752 		accmode = SMB_AM_OPENWRITE;
1753 	if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES |
1754 	    SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS |
1755 	    GENERIC_RIGHT_ALL_ACCESS | GENERIC_RIGHT_READ_ACCESS))
1756 		accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD
1757 		    : SMB_AM_OPENRW;
1758 	return (accmode);
1759 }
1760 
1761 static int
1762 smbfs_smb_oldopen(struct smbnode *np, int accmode, struct smb_cred *scrp,
1763 		int *attrcacheupdated, uint16_t *fidp, const char *name,
1764 		int nmlen, int xattr, len_t *sizep, uint32_t *rightsp)
1765 {
1766 	struct smb_rq rq, *rqp = &rq;
1767 	struct smb_share *ssp = np->n_mount->smi_share;
1768 	struct smb_vc *vcp = SSTOVC(ssp);
1769 	struct mbchain *mbp;
1770 	struct mdchain *mdp;
1771 	struct smbfattr fap;
1772 	uint8_t wc;
1773 	uint16_t fid, wattr, grantedmode;
1774 	uint32_t longint;
1775 	int error;
1776 
1777 	/*
1778 	 * Use DENYNONE to give unixy semantics of permitting
1779 	 * everything not forbidden by permissions.  Ie denial
1780 	 * is up to server with clients/openers needing to use
1781 	 * advisory locks for further control.
1782 	 */
1783 	accmode |= SMB_SM_DENYNONE;
1784 
1785 	gethrestime(&fap.fa_reqtime);
1786 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp);
1787 	if (error)
1788 		return (error);
1789 	smb_rq_getrequest(rqp, &mbp);
1790 	smb_rq_wstart(rqp);
1791 	mb_put_uint16le(mbp, accmode);
1792 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY |
1793 	    SMB_FA_DIR);
1794 	smb_rq_wend(rqp);
1795 	smb_rq_bstart(rqp);
1796 	mb_put_uint8(mbp, SMB_DT_ASCII);
1797 	do {
1798 		error = smbfs_fullpath(mbp, vcp, np, name, &nmlen,
1799 		    xattr ? ':' : '\\');
1800 		if (error)
1801 			break;
1802 		smb_rq_bend(rqp);
1803 		/*
1804 		 * Don't want to risk missing a successful
1805 		 * open response, or we could "leak" FIDs.
1806 		 */
1807 		rqp->sr_flags |= SMBR_NOINTR_RECV;
1808 		error = smb_rq_simple_timed(rqp, smb_timo_open);
1809 		if (error)
1810 			break;
1811 		smb_rq_getreply(rqp, &mdp);
1812 		/*
1813 		 * 8/2002 a DAVE server returned wc of 15 so we ignore that.
1814 		 * (the actual packet length and data was correct)
1815 		 */
1816 		if (md_get_uint8(mdp, &wc) != 0 || (wc != 7 && wc != 15)) {
1817 			error = EBADRPC;
1818 			break;
1819 		}
1820 		md_get_uint16(mdp, &fid); /* yes, we leave it LE */
1821 		md_get_uint16le(mdp, &wattr);
1822 		fap.fa_attr = wattr;
1823 		/*
1824 		 * Be careful using the time returned here, as
1825 		 * with FAT on NT4SP6, at least, the time returned is low
1826 		 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
1827 		 * over about every seven minutes!
1828 		 */
1829 		md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
1830 		if (longint)	/* avoid bogus zero returns */
1831 			smb_time_server2local(longint, vcp->vc_sopt.sv_tz,
1832 			    &fap.fa_mtime);
1833 		md_get_uint32le(mdp, &longint);
1834 		fap.fa_size = longint;
1835 		if (sizep)
1836 			*sizep = fap.fa_size;
1837 		md_get_uint16le(mdp, &grantedmode);
1838 		/*LINTED*/
1839 	} while (0);
1840 	smb_rq_done(rqp);
1841 	if (error)
1842 		return (error);
1843 	if (fidp)
1844 		*fidp = fid;
1845 	if (xattr)
1846 		goto uncached;
1847 	if (rightsp)
1848 		*rightsp = smb_mode2rights(grantedmode);
1849 	if (attrcacheupdated)
1850 		*attrcacheupdated = 0;
1851 	/*
1852 	 * Update the cached attributes if they are still valid
1853 	 * in the cache and if nothing has changed.
1854 	 * Note that this won't ever update if the file size is
1855 	 * greater than the 32-bits returned by SMB_COM_OPEN.
1856 	 * For 64-bit file sizes, SMB_COM_NT_CREATE_ANDX must
1857 	 * be used instead of SMB_COM_OPEN.
1858 	 */
1859 	if (np->r_vnode == NULL)
1860 		goto uncached;
1861 	if (smbfs_attr_cachelookup(np->r_vnode, NULL) != 0)
1862 		goto uncached;	/* the cached attributes are not valid */
1863 	if (fap.fa_size != np->n_size)
1864 		goto uncached;	/* the size is different */
1865 	if (fap.fa_attr != np->n_dosattr)
1866 		goto uncached;	/* the attrs are different */
1867 	/*
1868 	 * fap.fa_mtime is in two second increments while np->n_mtime
1869 	 * may be in one second increments, so comparing the times is
1870 	 * somewhat sloppy.
1871 	 */
1872 	if (fap.fa_mtime.tv_sec != np->n_mtime.tv_sec &&
1873 	    fap.fa_mtime.tv_sec != np->n_mtime.tv_sec - 1 &&
1874 	    fap.fa_mtime.tv_sec != np->n_mtime.tv_sec + 1)
1875 		goto uncached;	/* the mod time is different */
1876 
1877 	fap.fa_mtime.tv_sec = np->n_mtime.tv_sec; /* keep higher res time */
1878 	smbfs_attr_cacheenter(np->r_vnode, &fap);
1879 	if (attrcacheupdated)
1880 		*attrcacheupdated = 1;
1881 uncached:
1882 	return (0);
1883 }
1884 
1885 int
1886 smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
1887 			uint16_t *fidp)
1888 {
1889 	struct smb_vc *vcp = SSTOVC(np->n_mount->smi_share);
1890 	enum vtype vt = VREG;
1891 	int error;
1892 
1893 	/* Shared lock for n_fid use below. */
1894 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
1895 
1896 	mutex_enter(&np->r_statelock);
1897 	if (np->n_fidrefs && (rights & np->n_rights) == rights) {
1898 		np->n_fidrefs++;
1899 		*fidp = np->n_fid;
1900 		mutex_exit(&np->r_statelock);
1901 		return (0);
1902 	}
1903 	mutex_exit(&np->r_statelock);
1904 
1905 	if (!(vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) {
1906 		int mode = smb_rights2mode(rights);
1907 		error = smbfs_smb_oldopen(np, mode, scrp,
1908 		    NULL, fidp, NULL, 0, 0, NULL, NULL);
1909 	} else {
1910 		if (SMBTOV(np))
1911 			vt = SMBTOV(np)->v_type;
1912 		error = smbfs_smb_ntcreatex(np, rights, scrp, vt,
1913 		    NULL, fidp, NULL, 0, NTCREATEX_DISP_OPEN, 0,
1914 		    NULL, NULL);
1915 	}
1916 
1917 	if (*fidp == np->n_fid) {
1918 		/*
1919 		 * Oh no, the server gave us the same FID again?
1920 		 * This will cause us to close np->n_fid early!
1921 		 */
1922 		SMBVDEBUG("duplicate fid: 0x%x\n", *fidp);
1923 	}
1924 
1925 	return (error);
1926 }
1927 
1928 int
1929 smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp)
1930 {
1931 	struct smb_share *ssp = np->n_mount->smi_share;
1932 	int error = 0;
1933 	uint16_t oldfid = SMB_FID_UNUSED;
1934 
1935 	/* Shared lock for n_fid use below. */
1936 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
1937 
1938 	mutex_enter(&np->r_statelock);
1939 	if (fid == np->n_fid) {
1940 		ASSERT(np->n_fidrefs > 0);
1941 		if (--np->n_fidrefs == 0) {
1942 			/*
1943 			 * Don't expect to find the last reference
1944 			 * here in tmpclose.  Hard to deal with as
1945 			 * we don't have r_lkserlock exclusive.
1946 			 * Will close oldfid below.
1947 			 */
1948 			oldfid = np->n_fid;
1949 			np->n_fid = SMB_FID_UNUSED;
1950 		}
1951 	} else {
1952 		/* Will close the passed fid. */
1953 		oldfid = fid;
1954 	}
1955 	mutex_exit(&np->r_statelock);
1956 
1957 	if (oldfid != SMB_FID_UNUSED)
1958 		error = smbfs_smb_close(ssp, oldfid, NULL, scrp);
1959 
1960 	return (error);
1961 }
1962 
1963 int
1964 smbfs_smb_open(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
1965 	int *attrcacheupdated, uint16_t *fidp, const char *name,
1966 	int nmlen, int xattr, len_t *sizep, uint32_t *rightsp)
1967 {
1968 	int error;
1969 	struct smb_share *ssp = np->n_mount->smi_share;
1970 	struct smb_vc *vcp = SSTOVC(ssp);
1971 	enum vtype vt = VREG;
1972 
1973 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1974 		if (SMBTOV(np))
1975 			vt = SMBTOV(np)->v_type;
1976 		error = smbfs_smb_ntcreatex(np, rights, scrp, vt,
1977 		    attrcacheupdated, fidp, name, nmlen,
1978 		    NTCREATEX_DISP_OPEN, xattr, sizep, rightsp);
1979 	} else {
1980 		error = smbfs_smb_oldopen(np, smb_rights2mode(rights), scrp,
1981 		    attrcacheupdated, fidp, name, nmlen, xattr, sizep, rightsp);
1982 	}
1983 #if 0 /* let caller do this */
1984 	if (!error && !name)
1985 		np->n_fidrefs++;
1986 #endif
1987 	return (error);
1988 }
1989 
1990 int
1991 smbfs_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
1992 	struct smb_cred *scrp)
1993 {
1994 	struct smb_rq rq, *rqp = &rq;
1995 	struct mbchain *mbp;
1996 	long time;
1997 	int error;
1998 
1999 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scrp);
2000 	if (error)
2001 		return (error);
2002 	smb_rq_getrequest(rqp, &mbp);
2003 	smb_rq_wstart(rqp);
2004 	mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
2005 	if (mtime) {
2006 		smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
2007 	} else
2008 		time = 0;
2009 	mb_put_uint32le(mbp, time);
2010 	smb_rq_wend(rqp);
2011 	smb_rq_bstart(rqp);
2012 	smb_rq_bend(rqp);
2013 
2014 	/*
2015 	 * We don't really care about the result here, but we
2016 	 * do need to make sure we send this out, or we could
2017 	 * "leak" open file handles on interrupt or timeout.
2018 	 * The NOINTR_SEND flag makes this request immune to
2019 	 * interrupt or timeout until the send is done.
2020 	 */
2021 	rqp->sr_flags |= SMBR_NOINTR_SEND;
2022 	error = smb_rq_simple(rqp);
2023 	smb_rq_done(rqp);
2024 	/*
2025 	 * ENOTCONN isn't interesting - if the connection is closed,
2026 	 * so are all our FIDs - and EIO is also not interesting,
2027 	 * as it means a forced unmount was done. (was ENXIO)
2028 	 * Also ETIME, which means we sent the request but gave up
2029 	 * waiting before the response came back.
2030 	 *
2031 	 * Don't clog up the system log with warnings about these
2032 	 * uninteresting failures on closes.
2033 	 */
2034 	switch (error) {
2035 	case ENOTCONN:
2036 	case ENXIO:
2037 	case EIO:
2038 	case ETIME:
2039 		error = 0;
2040 	}
2041 	return (error);
2042 }
2043 
2044 static int
2045 smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen,
2046 	struct smb_cred *scrp, uint16_t *fidp, int xattr)
2047 {
2048 	struct smb_rq rq, *rqp = &rq;
2049 	struct smb_share *ssp = dnp->n_mount->smi_share;
2050 	struct mbchain *mbp;
2051 	struct mdchain *mdp;
2052 	struct timespec ctime;
2053 	uint8_t wc;
2054 	long tm;
2055 	int error;
2056 	uint16_t attr = SMB_FA_ARCHIVE;
2057 
2058 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp);
2059 	if (error)
2060 		return (error);
2061 	smb_rq_getrequest(rqp, &mbp);
2062 	smb_rq_wstart(rqp);
2063 	if (name && *name == '.')
2064 		attr |= SMB_FA_HIDDEN;
2065 	mb_put_uint16le(mbp, attr);		/* attributes  */
2066 	gethrestime(&ctime);
2067 	smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
2068 	mb_put_uint32le(mbp, tm);
2069 	smb_rq_wend(rqp);
2070 	smb_rq_bstart(rqp);
2071 	mb_put_uint8(mbp, SMB_DT_ASCII);
2072 	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &nmlen,
2073 	    xattr ? ':' : '\\');
2074 	if (!error) {
2075 		smb_rq_bend(rqp);
2076 		/*
2077 		 * Don't want to risk missing a successful
2078 		 * open response, or we could "leak" FIDs.
2079 		 */
2080 		rqp->sr_flags |= SMBR_NOINTR_RECV;
2081 		error = smb_rq_simple_timed(rqp, smb_timo_open);
2082 		if (!error) {
2083 			smb_rq_getreply(rqp, &mdp);
2084 			md_get_uint8(mdp, &wc);
2085 			if (wc == 1)
2086 				md_get_uint16(mdp, fidp);
2087 			else
2088 				error = EBADRPC;
2089 		}
2090 	}
2091 	smb_rq_done(rqp);
2092 	return (error);
2093 }
2094 
2095 int
2096 smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
2097 	struct smb_cred *scrp, uint16_t *fidp, uint32_t disp, int xattr)
2098 {
2099 	struct smb_vc *vcp = SSTOVC(dnp->n_mount->smi_share);
2100 
2101 	/*
2102 	 * At present the only access we might need is to WRITE data,
2103 	 * and that only if we are creating a "symlink".  When/if the
2104 	 * access needed gets more complex it should made a parameter
2105 	 * and be set upstream.
2106 	 */
2107 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
2108 		return (smbfs_smb_ntcreatex(dnp, SA_RIGHT_FILE_WRITE_DATA,
2109 		    scrp, VREG, NULL, fidp, name, nmlen, disp, xattr,
2110 		    NULL, NULL));
2111 	} else
2112 		return (smbfs_smb_oldcreate(dnp, name, nmlen, scrp, fidp,
2113 		    xattr));
2114 }
2115 
2116 int
2117 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name,
2118 			int nmlen, int xattr)
2119 {
2120 	struct smb_rq rq, *rqp = &rq;
2121 	struct smb_share *ssp = np->n_mount->smi_share;
2122 	struct mbchain *mbp;
2123 	int error;
2124 
2125 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp);
2126 	if (error)
2127 		return (error);
2128 	smb_rq_getrequest(rqp, &mbp);
2129 	smb_rq_wstart(rqp);
2130 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
2131 	smb_rq_wend(rqp);
2132 	smb_rq_bstart(rqp);
2133 	mb_put_uint8(mbp, SMB_DT_ASCII);
2134 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &nmlen,
2135 	    xattr ? ':' : '\\');
2136 	if (!error) {
2137 		smb_rq_bend(rqp);
2138 		error = smb_rq_simple(rqp);
2139 	}
2140 	smb_rq_done(rqp);
2141 	return (error);
2142 }
2143 
2144 int
2145 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
2146 	const char *tname, int tnmlen, struct smb_cred *scrp)
2147 {
2148 	struct smb_rq rq, *rqp = &rq;
2149 	struct smb_share *ssp = src->n_mount->smi_share;
2150 	struct mbchain *mbp;
2151 	int error;
2152 	uint16_t fa;
2153 
2154 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
2155 	if (error)
2156 		return (error);
2157 	smb_rq_getrequest(rqp, &mbp);
2158 	smb_rq_wstart(rqp);
2159 	/* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
2160 	fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
2161 	fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
2162 	mb_put_uint16le(mbp, fa);
2163 	smb_rq_wend(rqp);
2164 	smb_rq_bstart(rqp);
2165 	mb_put_uint8(mbp, SMB_DT_ASCII);
2166 	do {
2167 		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, '\\');
2168 		if (error)
2169 			break;
2170 		mb_put_uint8(mbp, SMB_DT_ASCII);
2171 		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen,
2172 		    '\\');
2173 		if (error)
2174 			break;
2175 		smb_rq_bend(rqp);
2176 		error = smb_rq_simple(rqp);
2177 		/*LINTED*/
2178 	} while (0);
2179 	smb_rq_done(rqp);
2180 	return (error);
2181 }
2182 
2183 int
2184 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
2185 	const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp)
2186 {
2187 	struct smb_rq rq, *rqp = &rq;
2188 	struct smb_share *ssp = src->n_mount->smi_share;
2189 	struct mbchain *mbp;
2190 	int error;
2191 
2192 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp);
2193 	if (error)
2194 		return (error);
2195 	smb_rq_getrequest(rqp, &mbp);
2196 	smb_rq_wstart(rqp);
2197 	mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
2198 	mb_put_uint16le(mbp, 0x20);	/* delete target file */
2199 	mb_put_uint16le(mbp, flags);
2200 	smb_rq_wend(rqp);
2201 	smb_rq_bstart(rqp);
2202 	mb_put_uint8(mbp, SMB_DT_ASCII);
2203 	do {
2204 		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, '\\');
2205 		if (error)
2206 			break;
2207 		mb_put_uint8(mbp, SMB_DT_ASCII);
2208 		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen,
2209 		    '\\');
2210 		if (error)
2211 			break;
2212 		smb_rq_bend(rqp);
2213 		error = smb_rq_simple(rqp);
2214 		/*LINTED*/
2215 	} while (0);
2216 	smb_rq_done(rqp);
2217 	return (error);
2218 }
2219 
2220 static int
2221 smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len,
2222 			struct smb_cred *scrp)
2223 {
2224 	struct smb_rq rq, *rqp = &rq;
2225 	struct smb_share *ssp = dnp->n_mount->smi_share;
2226 	struct mbchain *mbp;
2227 	int error;
2228 
2229 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp);
2230 	if (error)
2231 		return (error);
2232 	smb_rq_getrequest(rqp, &mbp);
2233 	smb_rq_wstart(rqp);
2234 	smb_rq_wend(rqp);
2235 	smb_rq_bstart(rqp);
2236 	mb_put_uint8(mbp, SMB_DT_ASCII);
2237 	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &len, '\\');
2238 	if (!error) {
2239 		smb_rq_bend(rqp);
2240 		error = smb_rq_simple(rqp);
2241 	}
2242 	smb_rq_done(rqp);
2243 	return (error);
2244 }
2245 
2246 int
2247 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
2248 		struct smb_cred *scrp)
2249 {
2250 	struct smb_share *ssp = dnp->n_mount->smi_share;
2251 	uint16_t fid;
2252 	int error;
2253 
2254 	/*
2255 	 * We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
2256 	 * just to be asking for something.  The rights==0 case could
2257 	 * easily be broken on some old or unusual servers.
2258 	 */
2259 	if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
2260 		error = smbfs_smb_ntcreatex(dnp, SA_RIGHT_FILE_READ_DATA,
2261 		    scrp, VDIR, NULL, &fid, name, len,
2262 		    NTCREATEX_DISP_CREATE, 0, NULL, NULL);
2263 		if (error)
2264 			return (error);
2265 		error = smbfs_smb_close(ssp, fid, NULL, scrp);
2266 		if (error)
2267 			SMBERROR("error %d closing fid %d\n", error, fid);
2268 		return (0);
2269 	} else
2270 		return (smbfs_smb_oldmkdir(dnp, name, len, scrp));
2271 }
2272 
2273 int
2274 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp)
2275 {
2276 	struct smb_rq rq, *rqp = &rq;
2277 	struct smb_share *ssp = np->n_mount->smi_share;
2278 	struct mbchain *mbp;
2279 	int error;
2280 
2281 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp);
2282 	if (error)
2283 		return (error);
2284 	smb_rq_getrequest(rqp, &mbp);
2285 	smb_rq_wstart(rqp);
2286 	smb_rq_wend(rqp);
2287 	smb_rq_bstart(rqp);
2288 	mb_put_uint8(mbp, SMB_DT_ASCII);
2289 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, NULL, '\\');
2290 	if (!error) {
2291 		smb_rq_bend(rqp);
2292 		error = smb_rq_simple(rqp);
2293 	}
2294 	smb_rq_done(rqp);
2295 	return (error);
2296 }
2297 
2298 static int
2299 smbfs_smb_search(struct smbfs_fctx *ctx)
2300 {
2301 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
2302 	struct smb_rq *rqp;
2303 	struct mbchain *mbp;
2304 	struct mdchain *mdp;
2305 	uint8_t wc, bt;
2306 	uint16_t ec, dlen, bc;
2307 	int len, maxent, error, iseof = 0;
2308 
2309 	maxent = min(ctx->f_left,
2310 	    (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN);
2311 	if (ctx->f_rq) {
2312 		smb_rq_done(ctx->f_rq);
2313 		ctx->f_rq = NULL;
2314 	}
2315 	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH,
2316 	    ctx->f_scred, &rqp);
2317 	if (error)
2318 		return (error);
2319 	ctx->f_rq = rqp;
2320 	smb_rq_getrequest(rqp, &mbp);
2321 	smb_rq_wstart(rqp);
2322 	mb_put_uint16le(mbp, maxent);	/* max entries to return */
2323 	mb_put_uint16le(mbp, ctx->f_attrmask);
2324 	smb_rq_wend(rqp);
2325 	smb_rq_bstart(rqp);
2326 	mb_put_uint8(mbp, SMB_DT_ASCII);	/* buffer format */
2327 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
2328 		len = ctx->f_wclen;
2329 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard,
2330 		    &len, '\\');
2331 		if (error)
2332 			return (error);
2333 		mb_put_uint8(mbp, SMB_DT_VARIABLE);
2334 		mb_put_uint16le(mbp, 0);	/* context length */
2335 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
2336 	} else {
2337 		if (SMB_UNICODE_STRINGS(vcp)) {
2338 			mb_put_padbyte(mbp);
2339 			mb_put_uint8(mbp, 0);
2340 		}
2341 		mb_put_uint8(mbp, 0);
2342 		mb_put_uint8(mbp, SMB_DT_VARIABLE);
2343 		mb_put_uint16le(mbp, SMB_SKEYLEN);
2344 		mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
2345 	}
2346 	smb_rq_bend(rqp);
2347 	error = smb_rq_simple(rqp);
2348 	if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
2349 		error = 0;
2350 		iseof = 1;
2351 		ctx->f_flags |= SMBFS_RDD_EOF;
2352 	} else if (error)
2353 		return (error);
2354 	smb_rq_getreply(rqp, &mdp);
2355 	md_get_uint8(mdp, &wc);
2356 	if (wc != 1)
2357 		return (iseof ? ENOENT : EBADRPC);
2358 	md_get_uint16le(mdp, &ec);
2359 	if (ec == 0)
2360 		return (ENOENT);
2361 	ctx->f_ecnt = ec;
2362 	md_get_uint16le(mdp, &bc);
2363 	if (bc < 3)
2364 		return (EBADRPC);
2365 	bc -= 3;
2366 	md_get_uint8(mdp, &bt);
2367 	if (bt != SMB_DT_VARIABLE)
2368 		return (EBADRPC);
2369 	md_get_uint16le(mdp, &dlen);
2370 	if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
2371 		return (EBADRPC);
2372 	return (0);
2373 }
2374 
2375 
2376 /*ARGSUSED*/
2377 static int
2378 smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
2379     const char *wildcard, int wclen, uint16_t attr, struct smb_cred *scrp)
2380 {
2381 	/* #pragma unused(dnp, scrp) */
2382 	ctx->f_attrmask = attr;
2383 	if (wildcard) {
2384 		if (wclen == 1 && wildcard[0] == '*') {
2385 			ctx->f_wildcard = "*.*";
2386 			ctx->f_wclen = 3;
2387 		} else {
2388 			ctx->f_wildcard = wildcard;
2389 			ctx->f_wclen = wclen;
2390 		}
2391 	} else {
2392 		ctx->f_wildcard = NULL;
2393 		ctx->f_wclen = 0;
2394 	}
2395 	ctx->f_name = (char *)ctx->f_fname;
2396 	ctx->f_namesz = 0;
2397 	return (0);
2398 }
2399 
2400 static int
2401 smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit)
2402 {
2403 	struct mdchain *mdp;
2404 	struct smb_rq *rqp;
2405 	char *cp;
2406 	uint8_t battr;
2407 	uint16_t date, time;
2408 	uint32_t size;
2409 	int error;
2410 	struct timespec ts;
2411 
2412 	if (ctx->f_ecnt == 0) {
2413 		if (ctx->f_flags & SMBFS_RDD_EOF)
2414 			return (ENOENT);
2415 		ctx->f_left = ctx->f_limit = limit;
2416 		gethrestime(&ts);
2417 		error = smbfs_smb_search(ctx);
2418 		if (error)
2419 			return (error);
2420 		ctx->f_attr.fa_reqtime = ts;
2421 	}
2422 	rqp = ctx->f_rq;
2423 	smb_rq_getreply(rqp, &mdp);
2424 	md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
2425 	md_get_uint8(mdp, &battr);
2426 	md_get_uint16le(mdp, &time);
2427 	md_get_uint16le(mdp, &date);
2428 	md_get_uint32le(mdp, &size);
2429 	cp = ctx->f_name;
2430 	md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM);
2431 	cp[sizeof (ctx->f_fname) - 1] = 0;
2432 	cp += strlen(cp) - 1;
2433 	while (*cp == ' ' && cp >= ctx->f_name)
2434 		*cp-- = 0;
2435 	ctx->f_attr.fa_attr = battr;
2436 	smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
2437 	    &ctx->f_attr.fa_mtime);
2438 	ctx->f_attr.fa_size = size;
2439 	ctx->f_nmlen = strlen(ctx->f_name);
2440 	ctx->f_ecnt--;
2441 	ctx->f_left--;
2442 	return (0);
2443 }
2444 
2445 static int
2446 smbfs_smb_findcloseLM1(struct smbfs_fctx *ctx)
2447 {
2448 	if (ctx->f_rq)
2449 		smb_rq_done(ctx->f_rq);
2450 	return (0);
2451 }
2452 
2453 /*
2454  * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
2455  */
2456 static int
2457 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
2458 {
2459 	struct smb_t2rq *t2p;
2460 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
2461 	struct mbchain *mbp;
2462 	struct mdchain *mdp;
2463 	uint16_t tw, flags;
2464 	int len, error;
2465 
2466 	if (ctx->f_t2) {
2467 		smb_t2_done(ctx->f_t2);
2468 		ctx->f_t2 = NULL;
2469 	}
2470 	ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
2471 	flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
2472 	if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
2473 		flags |= FIND2_CLOSE_AFTER_REQUEST;
2474 		ctx->f_flags |= SMBFS_RDD_NOCLOSE;
2475 	}
2476 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
2477 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
2478 		    ctx->f_scred, &t2p);
2479 		if (error)
2480 			return (error);
2481 		ctx->f_t2 = t2p;
2482 		mbp = &t2p->t2_tparam;
2483 		mb_init(mbp);
2484 		mb_put_uint16le(mbp, ctx->f_attrmask);
2485 		mb_put_uint16le(mbp, ctx->f_limit);
2486 		mb_put_uint16le(mbp, flags);
2487 		mb_put_uint16le(mbp, ctx->f_infolevel);
2488 		mb_put_uint32le(mbp, 0);
2489 		/* mb_put_uint8(mbp, SMB_DT_ASCII); specs? hah! */
2490 		len = ctx->f_wclen;
2491 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard,
2492 		    &len, '\\');
2493 		if (error)
2494 			return (error);
2495 	} else	{
2496 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
2497 		    ctx->f_scred, &t2p);
2498 		if (error)
2499 			return (error);
2500 		ctx->f_t2 = t2p;
2501 		mbp = &t2p->t2_tparam;
2502 		mb_init(mbp);
2503 		mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
2504 		mb_put_uint16le(mbp, ctx->f_limit);
2505 		mb_put_uint16le(mbp, ctx->f_infolevel);
2506 		if (ctx->f_ssp->ss_flags & SMBS_RESUMEKEYS) {
2507 			mb_put_uint32le(mbp, ctx->f_rkey);
2508 		} else
2509 			mb_put_uint32le(mbp, 0);
2510 		mb_put_uint16le(mbp, flags);
2511 		if (ctx->f_rname) {
2512 			/* resume file name */
2513 			mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
2514 			    MB_MSYSTEM);
2515 		}
2516 		/* Add trailing null - 1 byte if ASCII, 2 if Unicode */
2517 		if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2518 			mb_put_uint8(mbp, 0);	/* 1st byte NULL Unicode char */
2519 		mb_put_uint8(mbp, 0);
2520 #if 0
2521 		struct timespec ts;
2522 		ts.tv_sec = 0;
2523 		ts.tv_nsec = 200 * 1000 * 1000;	/* 200ms */
2524 		if (vcp->vc_flags & SMBC_WIN95) {
2525 			/*
2526 			 * some implementations suggests to sleep here
2527 			 * for 200ms, due to the bug in the Win95.
2528 			 * I've didn't notice any problem, but put code
2529 			 * for it.
2530 			 */
2531 			msleep(&flags, 0, PVFS, "fix95", &ts);
2532 		}
2533 #endif
2534 	}
2535 	t2p->t2_maxpcount = 5 * 2;
2536 	t2p->t2_maxdcount = vcp->vc_txmax;
2537 	error = smb_t2_request(t2p);
2538 	if (error)
2539 		return (error);
2540 	mdp = &t2p->t2_rparam;
2541 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
2542 		if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
2543 			return (error);
2544 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
2545 	}
2546 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
2547 		return (error);
2548 	ctx->f_ecnt = tw; /* search count - # entries returned */
2549 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
2550 		return (error);
2551 	/*
2552 	 * tw now is the "end of search" flag. against an XP server tw
2553 	 * comes back zero when the prior find_next returned exactly
2554 	 * the number of entries requested.  in which case we'd try again
2555 	 * but the search has in fact been closed so an EBADF results.  our
2556 	 * circumvention is to check here for a zero search count.
2557 	 */
2558 	if (tw || ctx->f_ecnt == 0)
2559 		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
2560 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
2561 		return (error);
2562 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
2563 		return (error);
2564 	if (ctx->f_ecnt == 0)
2565 		return (ENOENT);
2566 	ctx->f_rnameofs = tw;
2567 	mdp = &t2p->t2_rdata;
2568 	if (mdp->md_top == NULL) {
2569 		SMBVDEBUG("ecnt = %d, but data is NULL\n", ctx->f_ecnt);
2570 		return (ENOENT);
2571 	}
2572 #ifdef APPLE
2573 	if (mdp->md_top->m_len == 0) {
2574 		printf("bug: ecnt = %d, but m_len = 0 and m_next = %p "
2575 		    "(please report)\n", ctx->f_ecnt, mbp->mb_top->m_next);
2576 		return (ENOENT);
2577 	}
2578 #endif
2579 	ctx->f_eofs = 0;
2580 	return (0);
2581 }
2582 
2583 static int
2584 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
2585 {
2586 	struct smb_rq rq, *rqp = &rq;
2587 	struct mbchain *mbp;
2588 	int error;
2589 
2590 	error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
2591 	    ctx->f_scred);
2592 	if (error)
2593 		return (error);
2594 	smb_rq_getrequest(rqp, &mbp);
2595 	smb_rq_wstart(rqp);
2596 	mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
2597 	smb_rq_wend(rqp);
2598 	smb_rq_bstart(rqp);
2599 	smb_rq_bend(rqp);
2600 	/* Ditto comments at _smb_close */
2601 	rqp->sr_flags |= SMBR_NOINTR_SEND;
2602 	error = smb_rq_simple(rqp);
2603 	smb_rq_done(rqp);
2604 	return (error);
2605 }
2606 
2607 /*ARGSUSED*/
2608 static int
2609 smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
2610     const char *wildcard, int wclen, uint16_t attr, struct smb_cred *scrp)
2611 {
2612 	ctx->f_namesz = SMB_MAXFNAMELEN;
2613 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2614 		ctx->f_namesz *= 2;
2615 	ctx->f_name = kmem_zalloc(ctx->f_namesz, KM_SLEEP);
2616 	ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp))
2617 	    < SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD :
2618 	    SMB_FIND_BOTH_DIRECTORY_INFO;
2619 	ctx->f_attrmask = attr;
2620 	ctx->f_wildcard = wildcard;
2621 	ctx->f_wclen = wclen;
2622 	return (0);
2623 }
2624 
2625 static int
2626 smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
2627 {
2628 	struct mdchain *mdp;
2629 	struct smb_t2rq *t2p;
2630 	char *cp;
2631 	uint8_t tb;
2632 	uint16_t date, time, wattr;
2633 	uint32_t size, next, dattr, resumekey = 0;
2634 	uint64_t llongint;
2635 	int error, svtz, cnt, fxsz, nmlen, recsz, otw;
2636 	struct timespec ts;
2637 
2638 again:
2639 	otw = 0;	/* nothing sent Over The Wire (yet) */
2640 	if (ctx->f_ecnt == 0) {
2641 		if (ctx->f_flags & SMBFS_RDD_EOF)
2642 			return (ENOENT);
2643 		ctx->f_left = ctx->f_limit = limit;
2644 		gethrestime(&ts);
2645 		error = smbfs_smb_trans2find2(ctx);
2646 		if (error)
2647 			return (error);
2648 		ctx->f_attr.fa_reqtime = ts;
2649 		ctx->f_otws++;
2650 		otw = 1;
2651 	}
2652 	t2p = ctx->f_t2;
2653 	mdp = &t2p->t2_rdata;
2654 	svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
2655 	switch (ctx->f_infolevel) {
2656 	case SMB_FIND_STANDARD:
2657 		next = 0;
2658 		fxsz = 0;
2659 		md_get_uint16le(mdp, &date);
2660 		md_get_uint16le(mdp, &time);	/* creation time */
2661 		md_get_uint16le(mdp, &date);
2662 		md_get_uint16le(mdp, &time);	/* access time */
2663 		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
2664 		md_get_uint16le(mdp, &date);
2665 		md_get_uint16le(mdp, &time);	/* modify time */
2666 		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
2667 		md_get_uint32le(mdp, &size);
2668 		ctx->f_attr.fa_size = size;
2669 		md_get_uint32(mdp, NULL);	/* allocation size */
2670 		md_get_uint16le(mdp, &wattr);
2671 		ctx->f_attr.fa_attr = wattr;
2672 		md_get_uint8(mdp, &tb);
2673 		size = nmlen = tb;
2674 		fxsz = 23;
2675 		recsz = next = 24 + nmlen;	/* docs misses zero byte @end */
2676 		break;
2677 	case SMB_FIND_DIRECTORY_INFO:
2678 	case SMB_FIND_BOTH_DIRECTORY_INFO:
2679 		md_get_uint32le(mdp, &next);
2680 		md_get_uint32le(mdp, &resumekey); /* file index (resume key) */
2681 		md_get_uint64(mdp, NULL);	/* creation time */
2682 		md_get_uint64le(mdp, &llongint);
2683 		smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_atime);
2684 		md_get_uint64le(mdp, &llongint);
2685 		smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_mtime);
2686 		md_get_uint64le(mdp, &llongint);
2687 		smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_ctime);
2688 		md_get_uint64le(mdp, &llongint);	/* file size */
2689 		ctx->f_attr.fa_size = llongint;
2690 		md_get_uint64(mdp, NULL);	/* real size (should use) */
2691 		/* freebsd bug: fa_attr endian bug */
2692 		md_get_uint32le(mdp, &dattr);	/* extended file attributes */
2693 		ctx->f_attr.fa_attr = dattr;
2694 		md_get_uint32le(mdp, &size);	/* name len */
2695 		fxsz = 64; /* size ofinfo up to filename */
2696 		if (ctx->f_infolevel == SMB_FIND_BOTH_DIRECTORY_INFO) {
2697 			/*
2698 			 * Skip EaSize(4 bytes), a byte of ShortNameLength,
2699 			 * a reserved byte, and ShortName(8.3 means 24 bytes,
2700 			 * as Leach defined it to always be Unicode)
2701 			 */
2702 			md_get_mem(mdp, NULL, 30, MB_MSYSTEM);
2703 			fxsz += 30;
2704 		}
2705 		recsz = next ? next : fxsz + size;
2706 		break;
2707 	default:
2708 		SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
2709 		return (EINVAL);
2710 	}
2711 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2712 		nmlen = min(size, SMB_MAXFNAMELEN * 2);
2713 	else
2714 		nmlen = min(size, SMB_MAXFNAMELEN);
2715 	if (ctx->f_name)
2716 		kmem_free(ctx->f_name, ctx->f_namesz);
2717 	cp = ctx->f_name = kmem_alloc(nmlen, KM_SLEEP);
2718 	ctx->f_namesz = nmlen;
2719 	error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM);
2720 	if (error)
2721 		return (error);
2722 	if (next) {
2723 		cnt = next - nmlen - fxsz;
2724 		if (cnt > 0)
2725 			md_get_mem(mdp, NULL, cnt, MB_MSYSTEM);
2726 		else if (cnt < 0) {
2727 			SMBVDEBUG("out of sync\n");
2728 			return (EBADRPC);
2729 		}
2730 	}
2731 	/* Don't count any trailing null in the name. */
2732 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
2733 		if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
2734 			nmlen -= 2;
2735 	} else {
2736 		if (nmlen && cp[nmlen - 1] == 0)
2737 			nmlen--;
2738 	}
2739 	if (nmlen == 0)
2740 		return (EBADRPC);
2741 
2742 	/*
2743 	 * Ref radar 3983209.  On a find-next we expect a server will
2744 	 * 1) if the continue bit is set, use the server's idea of current loc,
2745 	 * 2) else if the resume key is non-zero, use that location,
2746 	 * 3) else if the resume name is set, use that location,
2747 	 * 4) else use the server's idea of current location.
2748 	 *
2749 	 * Current NetApps don't do that.  If we send no continue bit, a zero
2750 	 * resume key, and a resume name, the NetApp ignores the resume name
2751 	 * and acts on the (zero) resume key, sending back the start of the
2752 	 * directory again.  Panther doesn't expose the netapp bug; Panther used
2753 	 * the continue bit, but that was changed for 2866172. Win2000 as a
2754 	 * client also relies upon the resume name, but they request a very
2755 	 * large number of files, so the bug would be seen only with very
2756 	 * large directories.
2757 	 *
2758 	 * Our fix is to notice if the second OTW op (the first find-next)
2759 	 * returns, in the first filename, the same filename we got back
2760 	 * at the start of the first OTW (the find-first).  In that case
2761 	 * we've detected the server bug and set SMBS_RESUMEKEYS, causing us
2762 	 * to send non-zero resume keys henceforth.
2763 	 *
2764 	 * Caveat: if there's a netapp so old it doesn't negotiate NTLM 0.12
2765 	 * then we get no resume keys so f_rkey stays zero and this "fix"
2766 	 * changes nothing.
2767 	 *
2768 	 * Note due to a similar problem (4051871) we also set SMBS_RESUMEKEYS
2769 	 * for FAT volumes, at mount time.
2770 	 */
2771 	if (otw && !(ctx->f_ssp->ss_flags & SMBS_RESUMEKEYS)) {
2772 		if (ctx->f_otws == 1) {
2773 			ctx->f_firstnmlen = nmlen;
2774 			ctx->f_firstnm = kmem_alloc(nmlen, KM_SLEEP);
2775 			bcopy(ctx->f_name, ctx->f_firstnm, nmlen);
2776 		} else if (ctx->f_otws == 2 && nmlen == ctx->f_firstnmlen &&
2777 		    !(bcmp(ctx->f_name, ctx->f_firstnm, nmlen) == 0)) {
2778 			struct smb_share *ssp = ctx->f_ssp;
2779 			SMBERROR(
2780 			    "server resume_name bug seen; using resume keys\n");
2781 			SMB_SS_LOCK(ssp);
2782 			ssp->ss_flags |= SMBS_RESUMEKEYS;
2783 			SMB_SS_UNLOCK(ssp);
2784 			ctx->f_ecnt = 0;
2785 			goto again; /* must redo last otw op! */
2786 		}
2787 	}
2788 	ctx->f_rkey = resumekey;
2789 
2790 	next = ctx->f_eofs + recsz;
2791 	if (ctx->f_rnameofs &&
2792 	    (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
2793 	    (ctx->f_rnameofs >= ctx->f_eofs &&
2794 	    ctx->f_rnameofs < (int)next)) {
2795 		/*
2796 		 * Server needs a resume filename.
2797 		 */
2798 		if (ctx->f_rnamelen != nmlen) {
2799 			if (ctx->f_rname)
2800 				kmem_free(ctx->f_rname, ctx->f_rnamelen);
2801 			ctx->f_rname = kmem_alloc(nmlen, KM_SLEEP);
2802 			ctx->f_rnamelen = nmlen;
2803 		}
2804 		bcopy(ctx->f_name, ctx->f_rname, nmlen);
2805 		ctx->f_flags |= SMBFS_RDD_GOTRNAME;
2806 	}
2807 	ctx->f_nmlen = nmlen;
2808 	ctx->f_eofs = next;
2809 	ctx->f_ecnt--;
2810 	ctx->f_left--;
2811 	return (0);
2812 }
2813 
2814 static int
2815 smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
2816 {
2817 	int error = 0;
2818 	if (ctx->f_name)
2819 		kmem_free(ctx->f_name, ctx->f_namesz);
2820 	if (ctx->f_t2)
2821 		smb_t2_done(ctx->f_t2);
2822 	if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
2823 		error = smbfs_smb_findclose2(ctx);
2824 	return (error);
2825 }
2826 
2827 int
2828 smbfs_smb_findopen(struct smbnode *dnp, const char *wildcard, int wclen,
2829 			int attr, struct smb_cred *scrp,
2830 			struct smbfs_fctx **ctxpp)
2831 {
2832 	struct smbfs_fctx *ctx;
2833 	int error;
2834 
2835 	ctx = kmem_alloc(sizeof (*ctx), KM_SLEEP);
2836 	if (ctx == NULL)
2837 		return (ENOMEM);
2838 	bzero(ctx, sizeof (*ctx));
2839 	if (dnp->n_mount->smi_share) {
2840 		ctx->f_ssp = dnp->n_mount->smi_share;
2841 	}
2842 	ctx->f_dnp = dnp;
2843 	ctx->f_flags = SMBFS_RDD_FINDFIRST;
2844 	ctx->f_scred = scrp;
2845 	if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
2846 	    (dnp->n_mount->smi_args.flags & SMBFS_MOUNT_NO_LONG)) {
2847 		ctx->f_flags |= SMBFS_RDD_USESEARCH;
2848 		error = smbfs_smb_findopenLM1(ctx, dnp, wildcard, wclen,
2849 		    attr, scrp);
2850 	} else
2851 		error = smbfs_smb_findopenLM2(ctx, dnp, wildcard, wclen,
2852 		    attr, scrp);
2853 	if (error)
2854 		(void) smbfs_smb_findclose(ctx, scrp);
2855 	else
2856 		*ctxpp = ctx;
2857 	return (error);
2858 }
2859 
2860 int
2861 smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
2862 {
2863 	int error;
2864 
2865 	/*
2866 	 * Note: "limit" (maxcount) needs to fit in a short!
2867 	 *
2868 	 * smb_lookup always uses 1, which is OK (no wildcards).
2869 	 * Otherwise, this is smbfs_readdir, and we want to force
2870 	 * limit to be in the range 3 to 1000.  The low limit (3)
2871 	 * is so we can always give the caller one "real" entry
2872 	 * (something other than "." or "..") The high limit is
2873 	 * just tuning. WinNT used 512, Win2k 1366.  We use 1000.
2874 	 *
2875 	 * XXX: Move the [skip . ..] gunk to our caller (readdir).
2876 	 */
2877 	if ((ctx->f_flags & SMBFS_RDD_FINDSINGLE) == 0) {
2878 		if (limit < 3)
2879 			limit = 3;
2880 		if (limit > 1000)
2881 			limit = 1000;
2882 	}
2883 
2884 	ctx->f_scred = scrp;
2885 	for (;;) {
2886 		if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
2887 			error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit);
2888 		} else
2889 			error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit);
2890 		if (error)
2891 			return (error);
2892 		if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
2893 			/*LINTED*/
2894 			uint16_t *up = (uint16_t *)ctx->f_name;
2895 
2896 			/* Do comparisons on UCS-2LE characters */
2897 			if ((ctx->f_nmlen == 2 && up[0] == htoles('.')) ||
2898 			    (ctx->f_nmlen == 4 && up[0] == htoles('.') &&
2899 			    up[1] == htoles('.')))
2900 				continue;
2901 		} else {
2902 			if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
2903 			    (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
2904 			    ctx->f_name[1] == '.'))
2905 				continue;
2906 		}
2907 		break;
2908 	}
2909 	smbfs_fname_tolocal(ctx);
2910 	ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name,
2911 	    ctx->f_nmlen);
2912 	return (0);
2913 }
2914 
2915 
2916 int
2917 smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
2918 {
2919 	int error;
2920 	ctx->f_scred = scrp;
2921 	if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
2922 		error = smbfs_smb_findcloseLM1(ctx);
2923 	} else
2924 		error = smbfs_smb_findcloseLM2(ctx);
2925 	if (ctx->f_rname)
2926 		kmem_free(ctx->f_rname, ctx->f_rnamelen);
2927 	if (ctx->f_firstnm)
2928 		kmem_free(ctx->f_firstnm, ctx->f_firstnmlen);
2929 	kmem_free(ctx, sizeof (*ctx));
2930 	return (error);
2931 }
2932 
2933 
2934 int
2935 smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
2936 	struct smbfattr *fap, struct smb_cred *scrp)
2937 {
2938 	struct smbfs_fctx *ctx;
2939 	int error, intr;
2940 	const char *name = (namep ? *namep : NULL);
2941 	int nmlen = (nmlenp ? *nmlenp : 0);
2942 
2943 	/* This is no longer called with a null dnp */
2944 	ASSERT(dnp);
2945 
2946 	/*
2947 	 * Should not get here with "" anymore.
2948 	 */
2949 	if (!name || !nmlen) {
2950 		DEBUG_ENTER("smbfs_smb_lookup: name is NULL");
2951 		return (EINVAL);
2952 	}
2953 
2954 	/*
2955 	 * Should not get here with "." or ".." anymore.
2956 	 */
2957 	if ((nmlen == 1 && name[0] == '.') ||
2958 	    (nmlen == 2 && name[0] == '.' && name[1] == '.')) {
2959 		DEBUG_ENTER("smbfs_smb_lookup: name is '.' or '..'");
2960 		return (EINVAL);
2961 	}
2962 
2963 	/*
2964 	 * Shared lock for n_fid use (smb_flush).
2965 	 */
2966 	intr = dnp->n_mount->smi_flags & SMI_INT;
2967 	if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr))
2968 		return (EINTR);
2969 
2970 	bzero(fap, sizeof (*fap));
2971 
2972 	/*
2973 	 * This hides a server bug observable in Win98:
2974 	 * size changes may not show until a CLOSE or a FLUSH op
2975 	 * XXX: Make this conditional on !NTSMBs
2976 	 */
2977 	error = smbfs_smb_flush(dnp, scrp);
2978 	if (error)
2979 		goto out;
2980 	error = smbfs_smb_findopen(dnp, name, nmlen,
2981 	    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx);
2982 	if (error)
2983 		goto out;
2984 	ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
2985 	error = smbfs_smb_findnext(ctx, 1, scrp);
2986 	if (error == 0) {
2987 		*fap = ctx->f_attr;
2988 		if (name == NULL)
2989 			fap->fa_ino = dnp->n_ino;
2990 		if (namep)
2991 			*namep = (const char *)smbfs_name_alloc(
2992 			    ctx->f_name, ctx->f_nmlen);
2993 		if (nmlenp)
2994 			*nmlenp = ctx->f_nmlen;
2995 	}
2996 	(void) smbfs_smb_findclose(ctx, scrp);
2997 
2998 out:
2999 	smbfs_rw_exit(&dnp->r_lkserlock);
3000 	return (error);
3001 }
3002 
3003 /*
3004  * OTW function to Get a security descriptor (SD).
3005  *
3006  * Note: On success, this fills in mdp->md_top,
3007  * which the caller should free.
3008  */
3009 int
3010 smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
3011 		struct smb_cred *scrp, uint32_t selector,
3012 		mblk_t **res, uint32_t *reslen)
3013 {
3014 	struct smb_ntrq *ntp;
3015 	struct mbchain *mbp;
3016 	struct mdchain *mdp;
3017 	int error, len;
3018 
3019 	error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
3020 	    scrp, &ntp);
3021 	if (error)
3022 		return (error);
3023 
3024 	/* Parameters part */
3025 	mbp = &ntp->nt_tparam;
3026 	mb_init(mbp);
3027 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
3028 	mb_put_uint16le(mbp, 0); /* reserved */
3029 	mb_put_uint32le(mbp, selector);
3030 	/* Data part (none) */
3031 
3032 	/* Max. returned parameters and data. */
3033 	ntp->nt_maxpcount = 4;
3034 	ntp->nt_maxdcount = *reslen;
3035 
3036 	error = smb_nt_request(ntp);
3037 	if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
3038 		goto done;
3039 	*res = NULL;
3040 
3041 	/*
3042 	 * if there's more data than we said we could receive, here
3043 	 * is where we pick up the length of it
3044 	 */
3045 	mdp = &ntp->nt_rparam;
3046 	md_get_uint32le(mdp, reslen);
3047 	if (error)
3048 		goto done;
3049 
3050 	/*
3051 	 * get the data part.
3052 	 */
3053 	mdp = &ntp->nt_rdata;
3054 	if (mdp->md_top == NULL) {
3055 		SMBVDEBUG("null md_top? fid 0x%x\n", letohs(fid));
3056 		error = EBADRPC;
3057 		goto done;
3058 	}
3059 
3060 	/*
3061 	 * The returned parameter SD_length should match
3062 	 * the length of the returned data.  Unfortunately,
3063 	 * we have to work around server bugs here.
3064 	 */
3065 	len = m_fixhdr(mdp->md_top);
3066 	if (len != *reslen) {
3067 		SMBVDEBUG("len %d *reslen %d fid 0x%x\n",
3068 		    len, *reslen, letohs(fid));
3069 	}
3070 
3071 	/*
3072 	 * Actual data provided is < returned SD_length.
3073 	 *
3074 	 * The following "if (len < *reslen)" handles a Windows bug
3075 	 * observed when the underlying filesystem is FAT32.  In that
3076 	 * case a 32 byte security descriptor comes back (S-1-1-0, ie
3077 	 * "Everyone") but the Parameter Block claims 44 is the length
3078 	 * of the security descriptor.  (The Data Block length
3079 	 * claimed is 32.  This server bug was reported against NT
3080 	 * first and I've personally observed it with W2K.
3081 	 */
3082 	if (len < *reslen)
3083 		*reslen = len;
3084 
3085 	/*
3086 	 * Actual data provided is > returned SD_length.
3087 	 * (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0)
3088 	 * Narrow work-around for returned SD_length==0.
3089 	 */
3090 	if (len > *reslen) {
3091 		/*
3092 		 * Increase *reslen, but carefully.
3093 		 */
3094 		if (*reslen == 0 && len <= ntp->nt_maxdcount)
3095 			*reslen = len;
3096 	}
3097 	error = md_get_mbuf(mdp, len, res);
3098 
3099 done:
3100 	if (error == 0 && *res == NULL) {
3101 		ASSERT(*res);
3102 		error = EBADRPC;
3103 	}
3104 
3105 	smb_nt_done(ntp);
3106 	return (error);
3107 }
3108 
3109 #ifdef	APPLE
3110 /*
3111  * Wrapper for _getsd() compatible with darwin code.
3112  */
3113 int
3114 smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
3115 	uint32_t selector, struct ntsecdesc **res)
3116 {
3117 	int error;
3118 	uint32_t len, olen;
3119 	struct mdchain *mdp, md_store;
3120 	struct mbuf *m;
3121 
3122 	bzero(mdp, sizeof (*mdp));
3123 	len = 500; /* "overlarge" values => server errors */
3124 again:
3125 	olen = len;
3126 	error = smbfs_smb_getsec_m(ssp, fid, scrp, selector, &m, &len);
3127 	/*
3128 	 * Server may give us an error indicating that we
3129 	 * need a larger data buffer to receive the SD,
3130 	 * and the size we'll need.  Use the given size,
3131 	 * but only after a sanity check.
3132 	 *
3133 	 * XXX: Check for specific error values here?
3134 	 * XXX: also ... && len <= MAX_RAW_SD_SIZE
3135 	 */
3136 	if (error && len > olen)
3137 		goto again;
3138 
3139 	if (error)
3140 		return (error);
3141 
3142 	mdp = &md_store;
3143 	md_initm(mdp, m);
3144 	MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK);
3145 	error = md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM);
3146 	md_done(mdp);
3147 
3148 	return (error);
3149 }
3150 #endif /* APPLE */
3151 
3152 /*
3153  * OTW function to Set a security descriptor (SD).
3154  * Caller data are carried in an mbchain_t.
3155  *
3156  * Note: This normally consumes mbp->mb_top, and clears
3157  * that pointer when it does.
3158  */
3159 int  smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
3160 	struct smb_cred *scrp, uint32_t selector, mblk_t **mp)
3161 {
3162 	struct smb_ntrq *ntp;
3163 	struct mbchain *mbp;
3164 	int error;
3165 
3166 	error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
3167 	    scrp, &ntp);
3168 	if (error)
3169 		return (error);
3170 
3171 	/* Parameters part */
3172 	mbp = &ntp->nt_tparam;
3173 	mb_init(mbp);
3174 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
3175 	mb_put_uint16le(mbp, 0); /* reserved */
3176 	mb_put_uint32le(mbp, selector);
3177 
3178 	/* Data part */
3179 	mbp = &ntp->nt_tdata;
3180 	mb_initm(mbp, *mp);
3181 	*mp = NULL; /* consumed */
3182 
3183 	/* No returned parameters or data. */
3184 	ntp->nt_maxpcount = 0;
3185 	ntp->nt_maxdcount = 0;
3186 
3187 	error = smb_nt_request(ntp);
3188 	smb_nt_done(ntp);
3189 
3190 	return (error);
3191 }
3192 
3193 #ifdef	APPLE
3194 /*
3195  * This function builds the SD given the various parts.
3196  */
3197 int
3198 smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
3199 	uint32_t selector, uint16_t flags, struct ntsid *owner,
3200 	struct ntsid *group, struct ntacl *sacl, struct ntacl *dacl)
3201 {
3202 	struct mbchain *mbp, mb_store;
3203 	struct ntsecdesc ntsd;
3204 	int error, off;
3205 
3206 	/*
3207 	 * Build the SD as its own mbuf chain and pass it to
3208 	 * smbfs_smb_setsec_m()
3209 	 */
3210 	mbp = &mb_store;
3211 	mb_init(mbp);
3212 	bzero(&ntsd, sizeof (ntsd));
3213 	wset_sdrevision(&ntsd);
3214 	/*
3215 	 * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN)
3216 	 * We set here only those bits we can be sure must be set.  The rest
3217 	 * are up to the caller.  In particular, the caller may intentionally
3218 	 * set an acl PRESENT bit while giving us a null pointer for the
3219 	 * acl - that sets a null acl, giving access to everyone.  Note also
3220 	 * that the AUTO_INHERITED bits should probably always be set unless
3221 	 * the server is NT.
3222 	 */
3223 	flags |= SD_SELF_RELATIVE;
3224 	off = sizeof (ntsd);
3225 	if (owner) {
3226 		wset_sdowneroff(&ntsd, off);
3227 		off += sidlen(owner);
3228 	}
3229 	if (group) {
3230 		wset_sdgroupoff(&ntsd, off);
3231 		off += sidlen(group);
3232 	}
3233 	if (sacl) {
3234 		flags |= SD_SACL_PRESENT;
3235 		wset_sdsacloff(&ntsd, off);
3236 		off += acllen(sacl);
3237 	}
3238 	if (dacl) {
3239 		flags |= SD_DACL_PRESENT;
3240 		wset_sddacloff(&ntsd, off);
3241 	}
3242 	wset_sdflags(&ntsd, flags);
3243 	mb_put_mem(mbp, (caddr_t)&ntsd, sizeof (ntsd), MB_MSYSTEM);
3244 	if (owner)
3245 		mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM);
3246 	if (group)
3247 		mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM);
3248 	if (sacl)
3249 		mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM);
3250 	if (dacl)
3251 		mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM);
3252 
3253 	/*
3254 	 * Just pass the mbuf to _setsec_m
3255 	 * It will clear mb_top if consumed.
3256 	 */
3257 	error = smbfs_smb_setsec_m(ssp, fid, scrp, selector, &mbp->mb_top);
3258 	mb_done(mbp);
3259 
3260 	return (error);
3261 }
3262 
3263 #endif /* APPLE */
3264