xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c (revision 8329232e00f1048795bae53acb230316243aadb5)
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 2009 Sun Microsystems, Inc.  All rights reserved.
37  * Use is subject to license terms.
38  *
39  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
40  */
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/inttypes.h>
45 #include <sys/time.h>
46 #include <sys/vnode.h>
47 #include <sys/sunddi.h>
48 #include <sys/cmn_err.h>
49 
50 #include <netsmb/smb_osdep.h>
51 
52 #include <netsmb/smb.h>
53 #include <netsmb/smb_conn.h>
54 #include <netsmb/smb_subr.h>
55 #include <netsmb/smb_rq.h>
56 
57 #include <smbfs/smbfs.h>
58 #include <smbfs/smbfs_node.h>
59 #include <smbfs/smbfs_subr.h>
60 
61 /*
62  * Jan 1 1980 as 64 bit NT time.
63  * (tenths of microseconds since 1601)
64  */
65 const uint64_t NT1980 = 11960035200ULL*10000000ULL;
66 
67 /*
68  * Local functions.
69  * Not static, to aid debugging.
70  */
71 
72 int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
73 	struct smbfattr *fap, struct smb_cred *scrp);
74 int smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
75 	struct smb_cred *scrp, uint16_t infolevel);
76 
77 int smbfs_smb_statfsLM1(struct smb_share *ssp,
78 	statvfs64_t *sbp, struct smb_cred *scrp);
79 int smbfs_smb_statfsLM2(struct smb_share *ssp,
80 	statvfs64_t *sbp, struct smb_cred *scrp);
81 
82 int  smbfs_smb_setfattrNT(struct smbnode *np, int fid,
83 	uint32_t attr, struct timespec *mtime,	struct timespec *atime,
84 	struct smb_cred *scrp);
85 
86 int  smbfs_smb_setftime1(struct smbnode *np, uint16_t fid,
87 	struct timespec *mtime,	struct timespec *atime,
88 	struct smb_cred *scrp);
89 
90 int  smbfs_smb_setpattr1(struct smbnode *np,
91 	const char *name, int len, uint32_t attr,
92 	struct timespec *mtime, struct smb_cred *scrp);
93 
94 
95 /*
96  * Todo: locking over-the-wire
97  */
98 #ifdef APPLE
99 
100 static int
101 smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid,
102 	offset_t start, uint64_t len, int largelock,
103 	struct smb_cred *scrp, uint32_t timeout)
104 {
105 	struct smb_share *ssp = np->n_mount->smi_share;
106 	struct smb_rq rq, *rqp = &rq;
107 	struct mbchain *mbp;
108 	uint8_t ltype = 0;
109 	int error;
110 
111 	/* Shared lock for n_fid use below. */
112 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
113 
114 	/* After reconnect, n_fid is invalid */
115 	if (np->n_vcgenid != ssp->ss_vcgenid)
116 		return (ESTALE);
117 
118 	if (op == SMB_LOCK_SHARED)
119 		ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
120 	/* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */
121 	if (largelock)
122 		ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
123 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
124 	if (error)
125 		return (error);
126 	smb_rq_getrequest(rqp, &mbp);
127 	smb_rq_wstart(rqp);
128 	mb_put_uint8(mbp, 0xff);	/* secondary command */
129 	mb_put_uint8(mbp, 0);		/* MBZ */
130 	mb_put_uint16le(mbp, 0);
131 	mb_put_uint16le(mbp, np->n_fid);
132 	mb_put_uint8(mbp, ltype);	/* locktype */
133 	mb_put_uint8(mbp, 0);		/* oplocklevel - 0 seems is NO_OPLOCK */
134 	mb_put_uint32le(mbp, timeout);	/* 0 nowait, -1 infinite wait */
135 	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
136 	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
137 	smb_rq_wend(rqp);
138 	smb_rq_bstart(rqp);
139 	mb_put_uint16le(mbp, pid);
140 	if (!largelock) {
141 		mb_put_uint32le(mbp, start);
142 		mb_put_uint32le(mbp, len);
143 	} else {
144 		mb_put_uint16le(mbp, 0); /* pad */
145 		mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
146 		mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
147 		mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
148 		mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
149 	}
150 	smb_rq_bend(rqp);
151 	/*
152 	 * Don't want to risk missing a successful
153 	 * unlock send or lock response, or we could
154 	 * lose track of an outstanding lock.
155 	 */
156 	if (op == SMB_LOCK_RELEASE)
157 		rqp->sr_flags |= SMBR_NOINTR_SEND;
158 	else
159 		rqp->sr_flags |= SMBR_NOINTR_RECV;
160 
161 	error = smb_rq_simple(rqp);
162 	smb_rq_done(rqp);
163 	return (error);
164 }
165 
166 int
167 smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
168 	offset_t start, uint64_t len,	int largelock,
169 	struct smb_cred *scrp, uint32_t timeout)
170 {
171 	struct smb_share *ssp = np->n_mount->smi_share;
172 
173 	if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
174 		/*
175 		 * TODO: use LOCK_BYTE_RANGE here.
176 		 */
177 		return (EINVAL);
178 
179 	/*
180 	 * XXX: compute largelock via:
181 	 * (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)?
182 	 */
183 	return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len,
184 	    largelock, scrp, timeout));
185 }
186 
187 #endif /* APPLE */
188 
189 /*
190  * Helper for smbfs_getattr
191  * Something like nfs_getattr_otw
192  */
193 int
194 smbfs_smb_getfattr(
195 	struct smbnode *np,
196 	struct smbfattr *fap,
197 	struct smb_cred *scrp)
198 {
199 	int error;
200 
201 	/*
202 	 * This lock is necessary for FID-based calls.
203 	 * Lock may be writer (via open) or reader.
204 	 */
205 	ASSERT(np->r_lkserlock.count != 0);
206 
207 	/*
208 	 * Extended attribute directory or file.
209 	 */
210 	if (np->n_flag & N_XATTR) {
211 		error = smbfs_xa_getfattr(np, fap, scrp);
212 		return (error);
213 	}
214 
215 	error = smbfs_smb_trans2_query(np, fap, scrp, 0);
216 	if (error != EINVAL)
217 		return (error);
218 
219 	/* fallback */
220 	error = smbfs_smb_query_info(np, NULL, 0, fap, scrp);
221 
222 	return (error);
223 }
224 
225 /*
226  * Common function for QueryFileInfo, QueryPathInfo.
227  */
228 int
229 smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
230 	struct smb_cred *scrp, uint16_t infolevel)
231 {
232 	struct smb_share *ssp = np->n_mount->smi_share;
233 	struct smb_vc *vcp = SSTOVC(ssp);
234 	struct smb_t2rq *t2p;
235 	int error, svtz, timesok = 1;
236 	struct mbchain *mbp;
237 	struct mdchain *mdp;
238 	uint16_t cmd, date, time, wattr;
239 	uint64_t llongint, lsize;
240 	uint32_t size, dattr;
241 
242 	/*
243 	 * Shared lock for n_fid use below.
244 	 * See smbfs_smb_getfattr()
245 	 */
246 	ASSERT(np->r_lkserlock.count != 0);
247 
248 	/*
249 	 * If we have a valid open FID, use it.
250 	 */
251 	if ((np->n_fidrefs > 0) &&
252 	    (np->n_fid != SMB_FID_UNUSED) &&
253 	    (np->n_vcgenid == ssp->ss_vcgenid))
254 		cmd = SMB_TRANS2_QUERY_FILE_INFORMATION;
255 	else
256 		cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
257 
258 top:
259 	error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
260 	if (error)
261 		return (error);
262 	mbp = &t2p->t2_tparam;
263 	mb_init(mbp);
264 	if (!infolevel) {
265 		if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
266 			infolevel = SMB_QFILEINFO_STANDARD;
267 		else
268 			infolevel = SMB_QFILEINFO_ALL_INFO;
269 	}
270 
271 	if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION)
272 		mb_put_uint16le(mbp, np->n_fid);
273 
274 	mb_put_uint16le(mbp, infolevel);
275 
276 	if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) {
277 		mb_put_uint32le(mbp, 0);
278 		/* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
279 		error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
280 		if (error) {
281 			smb_t2_done(t2p);
282 			return (error);
283 		}
284 	}
285 
286 	t2p->t2_maxpcount = 2;
287 	t2p->t2_maxdcount = vcp->vc_txmax;
288 	error = smb_t2_request(t2p);
289 	if (error) {
290 		smb_t2_done(t2p);
291 		/* Invalid info level?  Try fallback. */
292 		if (error == EINVAL &&
293 		    infolevel == SMB_QFILEINFO_ALL_INFO) {
294 			infolevel = SMB_QFILEINFO_STANDARD;
295 			goto top;
296 		}
297 		return (error);
298 	}
299 	mdp = &t2p->t2_rdata;
300 	svtz = vcp->vc_sopt.sv_tz;
301 	switch (infolevel) {
302 	case SMB_QFILEINFO_STANDARD:
303 		md_get_uint16le(mdp, &date);
304 		md_get_uint16le(mdp, &time);	/* creation time */
305 		smb_dos2unixtime(date, time, 0, svtz, &fap->fa_createtime);
306 		md_get_uint16le(mdp, &date);
307 		md_get_uint16le(mdp, &time);	/* access time */
308 		smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
309 		md_get_uint16le(mdp, &date);
310 		md_get_uint16le(mdp, &time);	/* modify time */
311 		smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
312 		md_get_uint32le(mdp, &size);	/* EOF position */
313 		fap->fa_size = size;
314 		md_get_uint32le(mdp, &size);	/* allocation size */
315 		fap->fa_allocsz = size;
316 		error = md_get_uint16le(mdp, &wattr);
317 		fap->fa_attr = wattr;
318 		timesok = 1;
319 		break;
320 	case SMB_QFILEINFO_ALL_INFO:
321 		timesok = 0;
322 		/* creation time */
323 		md_get_uint64le(mdp, &llongint);
324 		if (llongint)
325 			timesok++;
326 		smb_time_NT2local(llongint, &fap->fa_createtime);
327 
328 		/* last access time */
329 		md_get_uint64le(mdp, &llongint);
330 		if (llongint)
331 			timesok++;
332 		smb_time_NT2local(llongint, &fap->fa_atime);
333 
334 		/* last write time */
335 		md_get_uint64le(mdp, &llongint);
336 		if (llongint)
337 			timesok++;
338 		smb_time_NT2local(llongint, &fap->fa_mtime);
339 
340 		/* last change time */
341 		md_get_uint64le(mdp, &llongint);
342 		if (llongint)
343 			timesok++;
344 		smb_time_NT2local(llongint, &fap->fa_ctime);
345 
346 		/* attributes */
347 		md_get_uint32le(mdp, &dattr);
348 		fap->fa_attr = dattr;
349 
350 		/*
351 		 * 4-Byte alignment - discard
352 		 * Specs don't talk about this.
353 		 */
354 		md_get_uint32le(mdp, NULL);
355 		/* allocation size */
356 		md_get_uint64le(mdp, &lsize);
357 		fap->fa_allocsz = lsize;
358 		/* File size */
359 		error = md_get_uint64le(mdp, &lsize);
360 		fap->fa_size = lsize;
361 		break;
362 	default:
363 		SMBVDEBUG("unexpected info level %d\n", infolevel);
364 		error = EINVAL;
365 	}
366 	smb_t2_done(t2p);
367 	/*
368 	 * if all times are zero (observed with FAT on NT4SP6)
369 	 * then fall back to older info level
370 	 */
371 	if (!timesok) {
372 		if (infolevel == SMB_QFILEINFO_ALL_INFO) {
373 			infolevel = SMB_QFILEINFO_STANDARD;
374 			goto top;
375 		}
376 		error = EINVAL;
377 	}
378 	return (error);
379 }
380 
381 /*
382  * Support functions for _qstreaminfo
383  * Moved to smbfs_xattr.c
384  */
385 
386 int
387 smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
388 	struct smb_cred *scrp)
389 {
390 	struct smb_t2rq *t2p;
391 	struct mbchain *mbp;
392 	struct mdchain *mdp;
393 	int error;
394 	uint32_t nlen;
395 
396 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
397 	    scrp, &t2p);
398 	if (error)
399 		return (error);
400 	mbp = &t2p->t2_tparam;
401 	mb_init(mbp);
402 	mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO);
403 	t2p->t2_maxpcount = 4;
404 	t2p->t2_maxdcount = 4 * 3 + 512;
405 	error = smb_t2_request(t2p);
406 	if (error)
407 		goto out;
408 
409 	mdp = &t2p->t2_rdata;
410 	md_get_uint32le(mdp, &fsa->fsa_aflags);
411 	md_get_uint32le(mdp, &fsa->fsa_maxname);
412 	error = md_get_uint32le(mdp, &nlen);	/* fs name length */
413 	if (error)
414 		goto out;
415 
416 	/*
417 	 * Get the FS type name.
418 	 */
419 	bzero(fsa->fsa_tname, FSTYPSZ);
420 	if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
421 		uint16_t tmpbuf[FSTYPSZ];
422 		size_t tmplen, outlen;
423 
424 		if (nlen > sizeof (tmpbuf))
425 			nlen = sizeof (tmpbuf);
426 		error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
427 		tmplen = nlen / 2;	/* UCS-2 chars */
428 		outlen = FSTYPSZ - 1;
429 		(void) uconv_u16tou8(tmpbuf, &tmplen,
430 		    (uchar_t *)fsa->fsa_tname, &outlen,
431 		    UCONV_IN_LITTLE_ENDIAN);
432 	} else {
433 		if (nlen > (FSTYPSZ - 1))
434 			nlen = FSTYPSZ - 1;
435 		error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
436 	}
437 
438 	/*
439 	 * If fs_name starts with FAT, we can't set dates before 1980
440 	 */
441 	if (0 == strncmp(fsa->fsa_tname, "FAT", 3)) {
442 		SMB_SS_LOCK(ssp);
443 		ssp->ss_flags |= SMBS_FST_FAT;
444 		SMB_SS_UNLOCK(ssp);
445 	}
446 
447 out:
448 	smb_t2_done(t2p);
449 	return (0);
450 }
451 
452 int
453 smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
454 	struct smb_cred *scp)
455 {
456 	int error;
457 
458 	if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
459 		error = smbfs_smb_statfsLM2(ssp, sbp, scp);
460 	else
461 		error = smbfs_smb_statfsLM1(ssp, sbp, scp);
462 
463 	return (error);
464 }
465 
466 int
467 smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp,
468 	struct smb_cred *scrp)
469 {
470 	struct smb_t2rq *t2p;
471 	struct mbchain *mbp;
472 	struct mdchain *mdp;
473 	uint16_t bsize;
474 	uint32_t units, bpu, funits;
475 	uint64_t s, t, f;
476 	int error;
477 
478 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
479 	    scrp, &t2p);
480 	if (error)
481 		return (error);
482 	mbp = &t2p->t2_tparam;
483 	mb_init(mbp);
484 	mb_put_uint16le(mbp, SMB_QFS_ALLOCATION);
485 	t2p->t2_maxpcount = 4;
486 	t2p->t2_maxdcount = 4 * 4 + 2;
487 	error = smb_t2_request(t2p);
488 	if (error)
489 		goto out;
490 
491 	mdp = &t2p->t2_rdata;
492 	md_get_uint32le(mdp, NULL);	/* fs id */
493 	md_get_uint32le(mdp, &bpu);
494 	md_get_uint32le(mdp, &units);
495 	md_get_uint32le(mdp, &funits);
496 	error = md_get_uint16le(mdp, &bsize);
497 	if (error)
498 		goto out;
499 	s = bsize;
500 	s *= bpu;
501 	t = units;
502 	f = funits;
503 	/*
504 	 * Don't allow over-large blocksizes as they determine
505 	 * Finder List-view size granularities.  On the other
506 	 * hand, we mustn't let the block count overflow the
507 	 * 31 bits available.
508 	 */
509 	while (s > 16 * 1024) {
510 		if (t > LONG_MAX)
511 			break;
512 		s /= 2;
513 		t *= 2;
514 		f *= 2;
515 	}
516 	while (t > LONG_MAX) {
517 		t /= 2;
518 		f /= 2;
519 		s *= 2;
520 	}
521 	sbp->f_bsize  = (ulong_t)s;	/* file system block size */
522 	sbp->f_blocks = t;	/* total data blocks in file system */
523 	sbp->f_bfree  = f;	/* free blocks in fs */
524 	sbp->f_bavail = f;	/* free blocks avail to non-superuser */
525 	sbp->f_files  = (-1);	/* total file nodes in file system */
526 	sbp->f_ffree  = (-1);	/* free file nodes in fs */
527 
528 out:
529 	smb_t2_done(t2p);
530 	return (0);
531 }
532 
533 int
534 smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp,
535 	struct smb_cred *scrp)
536 {
537 	struct smb_rq rq, *rqp = &rq;
538 	struct mdchain *mdp;
539 	uint16_t units, bpu, bsize, funits;
540 	uint64_t s, t, f;
541 	int error;
542 
543 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
544 	    scrp);
545 	if (error)
546 		return (error);
547 	smb_rq_wstart(rqp);
548 	smb_rq_wend(rqp);
549 	smb_rq_bstart(rqp);
550 	smb_rq_bend(rqp);
551 	error = smb_rq_simple(rqp);
552 	if (error)
553 		goto out;
554 
555 	smb_rq_getreply(rqp, &mdp);
556 	md_get_uint16le(mdp, &units);
557 	md_get_uint16le(mdp, &bpu);
558 	md_get_uint16le(mdp, &bsize);
559 	error = md_get_uint16le(mdp, &funits);
560 	if (error)
561 		goto out;
562 	s = bsize;
563 	s *= bpu;
564 	t = units;
565 	f = funits;
566 	/*
567 	 * Don't allow over-large blocksizes as they determine
568 	 * Finder List-view size granularities.  On the other
569 	 * hand, we mustn't let the block count overflow the
570 	 * 31 bits available.
571 	 */
572 	while (s > 16 * 1024) {
573 		if (t > LONG_MAX)
574 			break;
575 		s /= 2;
576 		t *= 2;
577 		f *= 2;
578 	}
579 	while (t > LONG_MAX) {
580 		t /= 2;
581 		f /= 2;
582 		s *= 2;
583 	}
584 	sbp->f_bsize = (ulong_t)s;	/* file system block size */
585 	sbp->f_blocks = t;	/* total data blocks in file system */
586 	sbp->f_bfree = f;	/* free blocks in fs */
587 	sbp->f_bavail = f;	/* free blocks avail to non-superuser */
588 	sbp->f_files = (-1);		/* total file nodes in file system */
589 	sbp->f_ffree = (-1);		/* free file nodes in fs */
590 
591 out:
592 	smb_rq_done(rqp);
593 	return (0);
594 }
595 
596 int
597 smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
598 			struct smb_cred *scrp)
599 {
600 	struct smb_t2rq *t2p;
601 	struct smb_vc *vcp = SSTOVC(ssp);
602 	struct mbchain *mbp;
603 	int error;
604 
605 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
606 	    scrp, &t2p);
607 	if (error)
608 		return (error);
609 	mbp = &t2p->t2_tparam;
610 	mb_init(mbp);
611 	mb_put_uint16le(mbp, fid);
612 	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
613 		mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION);
614 	else
615 		mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO);
616 	mb_put_uint16le(mbp, 0); /* pad */
617 	mbp = &t2p->t2_tdata;
618 	mb_init(mbp);
619 	mb_put_uint64le(mbp, newsize);
620 	t2p->t2_maxpcount = 2;
621 	t2p->t2_maxdcount = 0;
622 	error = smb_t2_request(t2p);
623 	smb_t2_done(t2p);
624 	return (error);
625 }
626 
627 int
628 smbfs_smb_setdisp(struct smbnode *np, uint16_t fid, uint8_t newdisp,
629 	struct smb_cred *scrp)
630 {
631 	struct smb_t2rq *t2p;
632 	struct smb_share *ssp = np->n_mount->smi_share;
633 	struct smb_vc *vcp = SSTOVC(ssp);
634 	struct mbchain *mbp;
635 	int error;
636 
637 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
638 	    scrp, &t2p);
639 	if (error)
640 		return (error);
641 	mbp = &t2p->t2_tparam;
642 	mb_init(mbp);
643 	mb_put_uint16le(mbp, fid);
644 	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
645 		mb_put_uint16le(mbp, SMB_SFILEINFO_DISPOSITION_INFORMATION);
646 	else
647 		mb_put_uint16le(mbp, SMB_SFILEINFO_DISPOSITION_INFO);
648 	mb_put_uint16le(mbp, 0); /* pad */
649 	mbp = &t2p->t2_tdata;
650 	mb_init(mbp);
651 	mb_put_uint8(mbp, newdisp);
652 	t2p->t2_maxpcount = 2;
653 	t2p->t2_maxdcount = 0;
654 	error = smb_t2_request(t2p);
655 	smb_t2_done(t2p);
656 	return (error);
657 }
658 
659 /*
660  * On SMB1, the trans2 rename only allows a rename where the
661  * source and target are in the same directory.  If you give
662  * the server any separators, you get "status not supported".
663  */
664 
665 /*ARGSUSED*/
666 int
667 smbfs_smb_t2rename(struct smbnode *np,
668 	const char *tname, int tnlen, struct smb_cred *scrp,
669 	uint16_t fid, int overwrite)
670 {
671 	struct smb_t2rq *t2p;
672 	struct smb_share *ssp = np->n_mount->smi_share;
673 	struct smb_vc *vcp = SSTOVC(ssp);
674 	struct mbchain *mbp;
675 	int32_t *ucslenp;
676 	int error;
677 
678 	if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU))
679 		return (ENOTSUP);
680 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
681 	    scrp, &t2p);
682 	if (error)
683 		return (error);
684 
685 	mbp = &t2p->t2_tparam;
686 	mb_init(mbp);
687 	mb_put_uint16le(mbp, fid);
688 	mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
689 	mb_put_uint16le(mbp, 0); /* reserved, nowadays */
690 
691 	mbp = &t2p->t2_tdata;
692 	mb_init(mbp);
693 	mb_put_uint32le(mbp, overwrite); /* one or zero */
694 	mb_put_uint32le(mbp, 0); /* obsolete target dir fid */
695 
696 	ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t));
697 	mbp->mb_count = 0;
698 	error = smb_put_dmem(mbp, vcp, tname, tnlen, SMB_CS_NONE, NULL);
699 	if (error)
700 		goto out;
701 	*ucslenp = htolel(mbp->mb_count);
702 
703 	t2p->t2_maxpcount = 2;
704 	t2p->t2_maxdcount = 0;
705 	error = smb_t2_request(t2p);
706 out:
707 	smb_t2_done(t2p);
708 	return (error);
709 }
710 
711 int
712 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp)
713 {
714 	struct smb_share *ssp = np->n_mount->smi_share;
715 	struct smb_rq rq, *rqp = &rq;
716 	struct mbchain *mbp;
717 	int error;
718 
719 	/* Shared lock for n_fid use below. */
720 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
721 
722 	if (!(np->n_flag & NFLUSHWIRE))
723 		return (0);
724 	if (np->n_fidrefs == 0)
725 		return (0); /* not open */
726 
727 	/* After reconnect, n_fid is invalid */
728 	if (np->n_vcgenid != ssp->ss_vcgenid)
729 		return (ESTALE);
730 
731 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
732 	if (error)
733 		return (error);
734 	smb_rq_getrequest(rqp, &mbp);
735 	smb_rq_wstart(rqp);
736 	mb_put_uint16le(mbp, np->n_fid);
737 	smb_rq_wend(rqp);
738 	smb_rq_bstart(rqp);
739 	smb_rq_bend(rqp);
740 	error = smb_rq_simple(rqp);
741 	smb_rq_done(rqp);
742 	if (!error) {
743 		mutex_enter(&np->r_statelock);
744 		np->n_flag &= ~NFLUSHWIRE;
745 		mutex_exit(&np->r_statelock);
746 	}
747 	return (error);
748 }
749 
750 int
751 smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
752 			struct smb_cred *scrp)
753 {
754 	struct smb_share *ssp = np->n_mount->smi_share;
755 	struct smb_rq rq, *rqp = &rq;
756 	struct mbchain *mbp;
757 	int error;
758 
759 	if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
760 		/*
761 		 * This call knows about 64-bit offsets.
762 		 */
763 		error = smbfs_smb_seteof(ssp, fid, newsize, scrp);
764 		if (!error) {
765 			mutex_enter(&np->r_statelock);
766 			np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
767 			mutex_exit(&np->r_statelock);
768 			return (0);
769 		}
770 	}
771 
772 	/*
773 	 * OK, so fallback to SMB_COM_WRITE, but note:
774 	 * it only supports 32-bit file offsets.
775 	 */
776 	if (newsize > UINT32_MAX)
777 		return (EFBIG);
778 
779 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp);
780 	if (error)
781 		return (error);
782 	smb_rq_getrequest(rqp, &mbp);
783 	smb_rq_wstart(rqp);
784 	mb_put_uint16le(mbp, fid);
785 	mb_put_uint16le(mbp, 0);
786 	mb_put_uint32le(mbp, newsize);
787 	mb_put_uint16le(mbp, 0);
788 	smb_rq_wend(rqp);
789 	smb_rq_bstart(rqp);
790 	mb_put_uint8(mbp, SMB_DT_DATA);
791 	mb_put_uint16le(mbp, 0);
792 	smb_rq_bend(rqp);
793 	error = smb_rq_simple(rqp);
794 	smb_rq_done(rqp);
795 	mutex_enter(&np->r_statelock);
796 	np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
797 	mutex_exit(&np->r_statelock);
798 	return (error);
799 }
800 
801 /*
802  * Old method for getting file attributes.
803  */
804 int
805 smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
806 	struct smbfattr *fap, struct smb_cred *scrp)
807 {
808 	struct smb_rq rq, *rqp = &rq;
809 	struct smb_share *ssp = np->n_mount->smi_share;
810 	struct mbchain *mbp;
811 	struct mdchain *mdp;
812 	uint8_t wc;
813 	int error;
814 	uint16_t wattr;
815 	uint32_t longint;
816 
817 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp);
818 	if (error)
819 		return (error);
820 	smb_rq_getrequest(rqp, &mbp);
821 	smb_rq_wstart(rqp);
822 	smb_rq_wend(rqp);
823 	smb_rq_bstart(rqp);
824 	mb_put_uint8(mbp, SMB_DT_ASCII);
825 
826 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np,
827 	    name, nmlen, '\\');
828 	if (error)
829 		goto out;
830 	smb_rq_bend(rqp);
831 	error = smb_rq_simple(rqp);
832 	if (error)
833 		goto out;
834 	smb_rq_getreply(rqp, &mdp);
835 	error = md_get_uint8(mdp, &wc);
836 	if (error)
837 		goto out;
838 	if (wc != 10) {
839 		error = EBADRPC;
840 		goto out;
841 	}
842 	md_get_uint16le(mdp, &wattr);
843 	fap->fa_attr = wattr;
844 	/*
845 	 * Be careful using the time returned here, as
846 	 * with FAT on NT4SP6, at least, the time returned is low
847 	 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
848 	 * over about every seven minutes!
849 	 */
850 	md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
851 	smb_time_server2local(longint,
852 	    SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime);
853 	error = md_get_uint32le(mdp, &longint);
854 	fap->fa_size = longint;
855 
856 out:
857 	smb_rq_done(rqp);
858 	return (error);
859 }
860 
861 /*
862  * Set DOS file attributes. mtime should be NULL for dialects above lm10
863  */
864 int
865 smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len,
866 	uint32_t attr, struct timespec *mtime,
867 	struct smb_cred *scrp)
868 {
869 	struct smb_rq rq, *rqp = &rq;
870 	struct smb_share *ssp = np->n_mount->smi_share;
871 	struct mbchain *mbp;
872 	long time;
873 	int error, svtz;
874 
875 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp);
876 	if (error)
877 		return (error);
878 	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
879 	smb_rq_getrequest(rqp, &mbp);
880 	smb_rq_wstart(rqp);
881 	mb_put_uint16le(mbp, (uint16_t)attr);
882 	if (mtime) {
883 		smb_time_local2server(mtime, svtz, &time);
884 	} else
885 		time = 0;
886 	mb_put_uint32le(mbp, time);		/* mtime */
887 	mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
888 	smb_rq_wend(rqp);
889 	smb_rq_bstart(rqp);
890 	mb_put_uint8(mbp, SMB_DT_ASCII);
891 
892 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len, '\\');
893 	if (error)
894 		goto out;
895 	mb_put_uint8(mbp, SMB_DT_ASCII);
896 	if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
897 		mb_put_padbyte(mbp);
898 		mb_put_uint8(mbp, 0);	/* 1st byte NULL Unicode char */
899 	}
900 	mb_put_uint8(mbp, 0);
901 	smb_rq_bend(rqp);
902 	error = smb_rq_simple(rqp);
903 
904 out:
905 	smb_rq_done(rqp);
906 	return (error);
907 }
908 
909 int
910 smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
911 			struct smb_cred *scrp)
912 {
913 	struct smbfattr fa;
914 	int error;
915 	uint32_t attr;
916 
917 	error = smbfs_smb_query_info(np, name, len, &fa, scrp);
918 	attr = fa.fa_attr;
919 	if (!error && !(attr & SMB_FA_HIDDEN)) {
920 		attr |= SMB_FA_HIDDEN;
921 		error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
922 	}
923 	return (error);
924 }
925 
926 
927 int
928 smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
929 			struct smb_cred *scrp)
930 {
931 	struct smbfattr fa;
932 	uint32_t attr;
933 	int error;
934 
935 	error = smbfs_smb_query_info(np, name, len, &fa, scrp);
936 	attr = fa.fa_attr;
937 	if (!error && (attr & SMB_FA_HIDDEN)) {
938 		attr &= ~SMB_FA_HIDDEN;
939 		error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
940 	}
941 	return (error);
942 }
943 
944 /*
945  * Set file attributes (optionally: DOS attr, atime, mtime)
946  * either by open FID or by path name (FID == -1).
947  */
948 int
949 smbfs_smb_setfattr(
950 	struct smbnode *np,
951 	int fid,
952 	uint32_t attr,
953 	struct timespec *mtime,
954 	struct timespec *atime,
955 	struct smb_cred *scrp)
956 {
957 	struct smb_share *ssp = np->n_mount->smi_share;
958 	struct smb_vc *vcp = SSTOVC(ssp);
959 	int error;
960 
961 	/*
962 	 * Normally can use the trans2 call.
963 	 */
964 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
965 		error = smbfs_smb_setfattrNT(np, fid,
966 		    attr, mtime, atime, scrp);
967 		return (error);
968 	}
969 
970 	/*
971 	 * Fall-back for older protocols.
972 	 */
973 	if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) {
974 		error = smbfs_smb_setftime1(np, fid,
975 		    mtime, atime, scrp);
976 		return (error);
977 	}
978 	error = smbfs_smb_setpattr1(np, NULL, 0,
979 	    attr, mtime, scrp);
980 	return (error);
981 }
982 
983 /*
984  * Set file atime and mtime. Isn't supported by core dialect.
985  */
986 int
987 smbfs_smb_setftime1(
988 	struct smbnode *np,
989 	uint16_t fid,
990 	struct timespec *mtime,
991 	struct timespec *atime,
992 	struct smb_cred *scrp)
993 {
994 	struct smb_rq rq, *rqp = &rq;
995 	struct smb_share *ssp = np->n_mount->smi_share;
996 	struct mbchain *mbp;
997 	uint16_t date, time;
998 	int error, tzoff;
999 
1000 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp);
1001 	if (error)
1002 		return (error);
1003 
1004 	tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
1005 	smb_rq_getrequest(rqp, &mbp);
1006 	smb_rq_wstart(rqp);
1007 	mb_put_uint16le(mbp, fid);
1008 	mb_put_uint32le(mbp, 0);		/* creation time */
1009 
1010 	if (atime)
1011 		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
1012 	else
1013 		time = date = 0;
1014 	mb_put_uint16le(mbp, date);
1015 	mb_put_uint16le(mbp, time);
1016 	if (mtime)
1017 		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
1018 	else
1019 		time = date = 0;
1020 	mb_put_uint16le(mbp, date);
1021 	mb_put_uint16le(mbp, time);
1022 	smb_rq_wend(rqp);
1023 	smb_rq_bstart(rqp);
1024 	smb_rq_bend(rqp);
1025 	error = smb_rq_simple(rqp);
1026 	SMBVDEBUG("%d\n", error);
1027 	smb_rq_done(rqp);
1028 	return (error);
1029 }
1030 
1031 /*
1032  * Set DOS file attributes, either via open FID or by path name.
1033  * Looks like this call can be used only if CAP_NT_SMBS bit is on.
1034  *
1035  * When setting via path (fid == -1):
1036  * *BASIC_INFO works with Samba, but Win2K servers say it is an
1037  * invalid information level on a SET_PATH_INFO.  Note Win2K does
1038  * support *BASIC_INFO on a SET_FILE_INFO, and they support the
1039  * equivalent *BASIC_INFORMATION on SET_PATH_INFO.  Go figure.
1040  */
1041 int
1042 smbfs_smb_setfattrNT(
1043 	struct smbnode *np,
1044 	int fid,		/* if fid == -1, set by path */
1045 	uint32_t attr,
1046 	struct timespec *mtime,
1047 	struct timespec *atime,
1048 	struct smb_cred *scrp)
1049 {
1050 	struct smb_t2rq *t2p;
1051 	struct smb_share *ssp = np->n_mount->smi_share;
1052 	struct smb_vc *vcp = SSTOVC(ssp);
1053 	struct mbchain *mbp;
1054 	uint64_t tm;
1055 	int error;
1056 	uint16_t cmd, level;
1057 
1058 	if (fid == -1) {
1059 		cmd = SMB_TRANS2_SET_PATH_INFORMATION;
1060 	} else {
1061 		if (fid > UINT16_MAX)
1062 			return (EINVAL);
1063 		cmd = SMB_TRANS2_SET_FILE_INFORMATION;
1064 	}
1065 	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
1066 		level = SMB_SFILEINFO_BASIC_INFORMATION;
1067 	else
1068 		level = SMB_SFILEINFO_BASIC_INFO;
1069 
1070 	error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
1071 	if (error)
1072 		return (error);
1073 
1074 	mbp = &t2p->t2_tparam;
1075 	mb_init(mbp);
1076 
1077 	if (cmd == SMB_TRANS2_SET_FILE_INFORMATION)
1078 		mb_put_uint16le(mbp, fid);
1079 
1080 	mb_put_uint16le(mbp, level);
1081 	mb_put_uint32le(mbp, 0);		/* MBZ */
1082 
1083 	if (cmd == SMB_TRANS2_SET_PATH_INFORMATION) {
1084 		error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
1085 		if (error != 0)
1086 			goto out;
1087 	}
1088 
1089 	/* FAT file systems don't support dates earlier than 1980. */
1090 
1091 	mbp = &t2p->t2_tdata;
1092 	mb_init(mbp);
1093 	mb_put_uint64le(mbp, 0);		/* creation time */
1094 	if (atime) {
1095 		smb_time_local2NT(atime, &tm);
1096 		if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
1097 		    tm < NT1980)
1098 			tm = NT1980;
1099 	} else
1100 		tm = 0;
1101 	mb_put_uint64le(mbp, tm);		/* access time */
1102 	if (mtime) {
1103 		smb_time_local2NT(mtime, &tm);
1104 		if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
1105 		    tm < NT1980)
1106 			tm = NT1980;
1107 	} else
1108 		tm = 0;
1109 	mb_put_uint64le(mbp, tm);		/* last write time */
1110 	mb_put_uint64le(mbp, 0);		/* ctime (no change) */
1111 	mb_put_uint32le(mbp, attr);
1112 	mb_put_uint32le(mbp, 0);		/* padding */
1113 	t2p->t2_maxpcount = 2;
1114 	t2p->t2_maxdcount = 0;
1115 	error = smb_t2_request(t2p);
1116 out:
1117 	smb_t2_done(t2p);
1118 	return (error);
1119 }
1120 
1121 /*
1122  * Modern create/open of file or directory.
1123  */
1124 int
1125 smbfs_smb_ntcreatex(
1126 	struct smbnode *np,
1127 	const char *name,
1128 	int nmlen,
1129 	int xattr,		/* is named stream? */
1130 	uint32_t req_acc,	/* requested access */
1131 	uint32_t efa,		/* ext. file attrs (DOS attr +) */
1132 	uint32_t share_acc,
1133 	uint32_t disp,		/* open disposition */
1134 	uint32_t createopt,	/* NTCREATEX_OPTIONS_ */
1135 	struct smb_cred *scrp,
1136 	uint16_t *fidp,		/* returned FID */
1137 	uint32_t *cr_act_p,	/* optional returned create action */
1138 	struct smbfattr *fap)	/* optional returned attributes */
1139 {
1140 	struct mbchain name_mb;
1141 	struct smb_share *ssp = np->n_mount->smi_share;
1142 	int err;
1143 
1144 	mb_init(&name_mb);
1145 
1146 	if (name == NULL)
1147 		nmlen = 0;
1148 	err = smbfs_fullpath(&name_mb, SSTOVC(ssp),
1149 	    np, name, nmlen, xattr ? ':' : '\\');
1150 	if (err)
1151 		goto out;
1152 
1153 	err = smb_smb_ntcreate(ssp, &name_mb,
1154 	    0,	/* NTCREATEX_FLAGS... */
1155 	    req_acc, efa, share_acc, disp, createopt,
1156 	    NTCREATEX_IMPERSONATION_IMPERSONATION,
1157 	    scrp, fidp, cr_act_p, fap);
1158 
1159 out:
1160 	mb_done(&name_mb);
1161 
1162 	return (err);
1163 }
1164 
1165 static uint32_t
1166 smb_mode2rights(int mode)
1167 {
1168 	mode = mode & SMB_AM_OPENMODE;
1169 	uint32_t rights =
1170 	    STD_RIGHT_SYNCHRONIZE_ACCESS |
1171 	    STD_RIGHT_READ_CONTROL_ACCESS;
1172 
1173 	if ((mode == SMB_AM_OPENREAD) ||
1174 	    (mode == SMB_AM_OPENRW)) {
1175 		rights |=
1176 		    SA_RIGHT_FILE_READ_ATTRIBUTES |
1177 		    SA_RIGHT_FILE_READ_DATA;
1178 	}
1179 
1180 	if ((mode == SMB_AM_OPENWRITE) ||
1181 	    (mode == SMB_AM_OPENRW)) {
1182 		rights |=
1183 		    SA_RIGHT_FILE_WRITE_ATTRIBUTES |
1184 		    SA_RIGHT_FILE_APPEND_DATA |
1185 		    SA_RIGHT_FILE_WRITE_DATA;
1186 	}
1187 
1188 	if (mode == SMB_AM_OPENEXEC) {
1189 		rights |=
1190 		    SA_RIGHT_FILE_READ_ATTRIBUTES |
1191 		    SA_RIGHT_FILE_EXECUTE;
1192 	}
1193 
1194 	return (rights);
1195 }
1196 
1197 static int
1198 smb_rights2mode(uint32_t rights)
1199 {
1200 	int accmode = SMB_AM_OPENEXEC; /* our fallback */
1201 
1202 	if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD |
1203 	    SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES |
1204 	    SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS |
1205 	    STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS))
1206 		accmode = SMB_AM_OPENWRITE;
1207 	if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES |
1208 	    SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS))
1209 		accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD
1210 		    : SMB_AM_OPENRW;
1211 	return (accmode);
1212 }
1213 
1214 static int
1215 smbfs_smb_oldopen(
1216 	struct smbnode *np,
1217 	const char *name,
1218 	int nmlen,
1219 	int xattr,
1220 	int accmode,
1221 	struct smb_cred *scrp,
1222 	uint16_t *fidp,
1223 	uint16_t *granted_mode_p,
1224 	smbfattr_t *fap)
1225 {
1226 	struct smb_rq rq, *rqp = &rq;
1227 	struct smb_share *ssp = np->n_mount->smi_share;
1228 	struct smb_vc *vcp = SSTOVC(ssp);
1229 	struct mbchain *mbp;
1230 	struct mdchain *mdp;
1231 	struct smbfattr fa;
1232 	uint8_t wc;
1233 	uint16_t wattr;
1234 	uint32_t longint;
1235 	int error;
1236 
1237 	bzero(&fa, sizeof (fa));
1238 
1239 	/*
1240 	 * XXX: move to callers...
1241 	 *
1242 	 * Use DENYNONE to give unixy semantics of permitting
1243 	 * everything not forbidden by permissions.  Ie denial
1244 	 * is up to server with clients/openers needing to use
1245 	 * advisory locks for further control.
1246 	 */
1247 	accmode |= SMB_SM_DENYNONE;
1248 
1249 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp);
1250 	if (error)
1251 		return (error);
1252 	smb_rq_getrequest(rqp, &mbp);
1253 	smb_rq_wstart(rqp);
1254 	mb_put_uint16le(mbp, accmode);
1255 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY |
1256 	    SMB_FA_DIR);
1257 	smb_rq_wend(rqp);
1258 	smb_rq_bstart(rqp);
1259 	mb_put_uint8(mbp, SMB_DT_ASCII);
1260 
1261 	error = smbfs_fullpath(mbp, vcp, np, name, nmlen,
1262 	    xattr ? ':' : '\\');
1263 	if (error)
1264 		goto done;
1265 	smb_rq_bend(rqp);
1266 	/*
1267 	 * Don't want to risk missing a successful
1268 	 * open response, or we could "leak" FIDs.
1269 	 */
1270 	rqp->sr_flags |= SMBR_NOINTR_RECV;
1271 	error = smb_rq_simple_timed(rqp, smb_timo_open);
1272 	if (error)
1273 		goto done;
1274 	smb_rq_getreply(rqp, &mdp);
1275 	/*
1276 	 * 8/2002 a DAVE server returned wc of 15 so we ignore that.
1277 	 * (the actual packet length and data was correct)
1278 	 */
1279 	error = md_get_uint8(mdp, &wc);
1280 	if (error)
1281 		goto done;
1282 	if (wc != 7 && wc != 15) {
1283 		error = EBADRPC;
1284 		goto done;
1285 	}
1286 	md_get_uint16le(mdp, fidp);
1287 	md_get_uint16le(mdp, &wattr);
1288 	fa.fa_attr = wattr;
1289 	/*
1290 	 * Be careful using the time returned here, as
1291 	 * with FAT on NT4SP6, at least, the time returned is low
1292 	 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
1293 	 * over about every seven minutes!
1294 	 */
1295 	md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
1296 	smb_time_server2local(longint, vcp->vc_sopt.sv_tz, &fa.fa_mtime);
1297 	md_get_uint32le(mdp, &longint);
1298 	fa.fa_size = longint;
1299 	error = md_get_uint16le(mdp, granted_mode_p);
1300 
1301 done:
1302 	smb_rq_done(rqp);
1303 	if (error)
1304 		return (error);
1305 
1306 	if (fap)
1307 		*fap = fa; /* struct copy */
1308 
1309 	return (0);
1310 }
1311 
1312 int
1313 smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
1314 			uint16_t *fidp)
1315 {
1316 	struct smb_share *ssp = np->n_mount->smi_share;
1317 	struct smb_vc *vcp = SSTOVC(ssp);
1318 	int accmode, error;
1319 
1320 	/* Shared lock for n_fid use below. */
1321 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
1322 
1323 	/* Can we re-use n_fid? or must we open anew? */
1324 	mutex_enter(&np->r_statelock);
1325 	if (np->n_fidrefs > 0 &&
1326 	    np->n_vcgenid == ssp->ss_vcgenid &&
1327 	    (rights & np->n_rights) == rights) {
1328 		np->n_fidrefs++;
1329 		*fidp = np->n_fid;
1330 		mutex_exit(&np->r_statelock);
1331 		return (0);
1332 	}
1333 	mutex_exit(&np->r_statelock);
1334 
1335 	/* re-open an existing file. */
1336 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1337 		error = smbfs_smb_ntcreatex(np,
1338 		    NULL, 0, 0,	/* name nmlen xattr */
1339 		    rights, SMB_EFA_NORMAL,
1340 		    NTCREATEX_SHARE_ACCESS_ALL,
1341 		    NTCREATEX_DISP_OPEN,
1342 		    0, /* create options */
1343 		    scrp, fidp,
1344 		    NULL, NULL); /* cr_act_p fa_p */
1345 		return (error);
1346 	}
1347 
1348 	accmode = smb_rights2mode(rights);
1349 	error = smbfs_smb_oldopen(np,
1350 	    NULL, 0, 0, /* name nmlen xattr */
1351 	    accmode, scrp,
1352 	    fidp,
1353 	    NULL, /* granted mode p */
1354 	    NULL); /* fa p */
1355 
1356 	return (error);
1357 }
1358 
1359 int
1360 smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp)
1361 {
1362 	struct smb_share *ssp = np->n_mount->smi_share;
1363 	int error = 0;
1364 	uint16_t oldfid = SMB_FID_UNUSED;
1365 
1366 	/* Shared lock for n_fid use below. */
1367 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
1368 
1369 	mutex_enter(&np->r_statelock);
1370 	if (fid == np->n_fid) {
1371 		ASSERT(np->n_fidrefs > 0);
1372 		if (--np->n_fidrefs == 0) {
1373 			/*
1374 			 * Don't expect to find the last reference
1375 			 * here in tmpclose.  Hard to deal with as
1376 			 * we don't have r_lkserlock exclusive.
1377 			 * Will close oldfid below.
1378 			 */
1379 			oldfid = np->n_fid;
1380 			np->n_fid = SMB_FID_UNUSED;
1381 		}
1382 	} else {
1383 		/* Will close the passed fid. */
1384 		oldfid = fid;
1385 	}
1386 	mutex_exit(&np->r_statelock);
1387 
1388 	if (oldfid != SMB_FID_UNUSED)
1389 		error = smbfs_smb_close(ssp, oldfid, NULL, scrp);
1390 
1391 	return (error);
1392 }
1393 
1394 int
1395 smbfs_smb_open(
1396 	struct smbnode *np,
1397 	const char *name,
1398 	int nmlen,
1399 	int xattr,
1400 	uint32_t rights,
1401 	struct smb_cred *scrp,
1402 	uint16_t *fidp,
1403 	uint32_t *rightsp,
1404 	smbfattr_t *fap)
1405 {
1406 	struct smb_share *ssp = np->n_mount->smi_share;
1407 	struct smb_vc *vcp = SSTOVC(ssp);
1408 	int accmode, error;
1409 	uint16_t grantedmode;
1410 
1411 	/* open an existing file */
1412 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1413 		error = smbfs_smb_ntcreatex(np,
1414 		    name, nmlen, xattr,
1415 		    rights, SMB_EFA_NORMAL,
1416 		    NTCREATEX_SHARE_ACCESS_ALL,
1417 		    NTCREATEX_DISP_OPEN,
1418 		    0, /* create options */
1419 		    scrp, fidp,
1420 		    NULL, fap); /* cr_act_p fa_p */
1421 		if (error != 0)
1422 			return (error);
1423 		*rightsp = rights;
1424 		return (0);
1425 	}
1426 
1427 	accmode = smb_rights2mode(rights);
1428 	error = smbfs_smb_oldopen(np,
1429 	    name, nmlen, xattr, accmode, scrp,
1430 	    fidp, &grantedmode, fap);
1431 	if (error != 0)
1432 		return (error);
1433 	*rightsp = smb_mode2rights(grantedmode);
1434 	(void) smbfs_smb_getfattr(np, fap, scrp);
1435 
1436 	return (0);
1437 }
1438 
1439 int
1440 smbfs_smb_close(struct smb_share *ssp, uint16_t fid,
1441 	struct timespec *mtime,	struct smb_cred *scrp)
1442 {
1443 	int error;
1444 
1445 	error = smb_smb_close(ssp, fid, mtime, scrp);
1446 
1447 	/*
1448 	 * ENOTCONN isn't interesting - if the connection is closed,
1449 	 * so are all our FIDs - and EIO is also not interesting,
1450 	 * as it means a forced unmount was done. (was ENXIO)
1451 	 * Also ETIME, which means we sent the request but gave up
1452 	 * waiting before the response came back.
1453 	 *
1454 	 * Don't clog up the system log with warnings about these
1455 	 * uninteresting failures on closes.
1456 	 */
1457 	switch (error) {
1458 	case ENOTCONN:
1459 	case ENXIO:
1460 	case EIO:
1461 	case ETIME:
1462 		error = 0;
1463 	}
1464 	return (error);
1465 }
1466 
1467 static int
1468 smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen,
1469 	int xattr, struct smb_cred *scrp, uint16_t *fidp)
1470 {
1471 	struct smb_rq rq, *rqp = &rq;
1472 	struct smb_share *ssp = dnp->n_mount->smi_share;
1473 	struct mbchain *mbp;
1474 	struct mdchain *mdp;
1475 	struct timespec ctime;
1476 	uint8_t wc;
1477 	long tm;
1478 	int error;
1479 	uint16_t attr = SMB_FA_ARCHIVE;
1480 
1481 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp);
1482 	if (error)
1483 		return (error);
1484 	smb_rq_getrequest(rqp, &mbp);
1485 	smb_rq_wstart(rqp);
1486 	if (name && *name == '.')
1487 		attr |= SMB_FA_HIDDEN;
1488 	mb_put_uint16le(mbp, attr);		/* attributes  */
1489 	gethrestime(&ctime);
1490 	smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
1491 	mb_put_uint32le(mbp, tm);
1492 	smb_rq_wend(rqp);
1493 	smb_rq_bstart(rqp);
1494 	mb_put_uint8(mbp, SMB_DT_ASCII);
1495 	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen,
1496 	    xattr ? ':' : '\\');
1497 	if (error)
1498 		goto out;
1499 	smb_rq_bend(rqp);
1500 	/*
1501 	 * Don't want to risk missing a successful
1502 	 * open response, or we could "leak" FIDs.
1503 	 */
1504 	rqp->sr_flags |= SMBR_NOINTR_RECV;
1505 	error = smb_rq_simple_timed(rqp, smb_timo_open);
1506 	if (error)
1507 		goto out;
1508 
1509 	smb_rq_getreply(rqp, &mdp);
1510 	md_get_uint8(mdp, &wc);
1511 	if (wc != 1) {
1512 		error = EBADRPC;
1513 		goto out;
1514 	}
1515 	error = md_get_uint16le(mdp, fidp);
1516 
1517 out:
1518 	smb_rq_done(rqp);
1519 	return (error);
1520 }
1521 
1522 int
1523 smbfs_smb_create(
1524 	struct smbnode *dnp,
1525 	const char *name,
1526 	int nmlen,
1527 	int xattr,
1528 	uint32_t disp,
1529 	struct smb_cred *scrp,
1530 	uint16_t *fidp)
1531 {
1532 	struct smb_share *ssp = dnp->n_mount->smi_share;
1533 	struct smb_vc *vcp = SSTOVC(ssp);
1534 	uint32_t efa, rights;
1535 	int error;
1536 
1537 	/*
1538 	 * At present the only access we might need is to WRITE data,
1539 	 * and that only if we are creating a "symlink".  When/if the
1540 	 * access needed gets more complex it should made a parameter
1541 	 * and be set upstream.
1542 	 */
1543 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1544 		rights = SA_RIGHT_FILE_WRITE_DATA;
1545 		efa = SMB_EFA_NORMAL;
1546 		if (!xattr && name && *name == '.')
1547 			efa = SMB_EFA_HIDDEN;
1548 		error = smbfs_smb_ntcreatex(dnp,
1549 		    name, nmlen, xattr, rights, efa,
1550 		    NTCREATEX_SHARE_ACCESS_ALL,
1551 		    disp, /* != NTCREATEX_DISP_OPEN */
1552 		    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
1553 		    scrp, fidp, NULL, NULL); /* cr_act_p fa_p */
1554 		return (error);
1555 	}
1556 
1557 	error = smbfs_smb_oldcreate(dnp, name, nmlen, xattr, scrp, fidp);
1558 	return (error);
1559 }
1560 
1561 int
1562 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name,
1563 			int nmlen, int xattr)
1564 {
1565 	struct smb_rq rq, *rqp = &rq;
1566 	struct smb_share *ssp = np->n_mount->smi_share;
1567 	struct mbchain *mbp;
1568 	int error;
1569 
1570 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp);
1571 	if (error)
1572 		return (error);
1573 	smb_rq_getrequest(rqp, &mbp);
1574 	smb_rq_wstart(rqp);
1575 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
1576 	smb_rq_wend(rqp);
1577 	smb_rq_bstart(rqp);
1578 	mb_put_uint8(mbp, SMB_DT_ASCII);
1579 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, nmlen,
1580 	    xattr ? ':' : '\\');
1581 	if (!error) {
1582 		smb_rq_bend(rqp);
1583 		error = smb_rq_simple(rqp);
1584 	}
1585 	smb_rq_done(rqp);
1586 	return (error);
1587 }
1588 
1589 int
1590 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
1591 	const char *tname, int tnmlen, struct smb_cred *scrp)
1592 {
1593 	struct smb_rq rq, *rqp = &rq;
1594 	struct smb_share *ssp = src->n_mount->smi_share;
1595 	struct mbchain *mbp;
1596 	int error;
1597 	uint16_t fa;
1598 	char sep;
1599 
1600 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
1601 	if (error)
1602 		return (error);
1603 	smb_rq_getrequest(rqp, &mbp);
1604 	smb_rq_wstart(rqp);
1605 	/* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
1606 	fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
1607 	fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
1608 	mb_put_uint16le(mbp, fa);
1609 	smb_rq_wend(rqp);
1610 	smb_rq_bstart(rqp);
1611 
1612 	/*
1613 	 * When we're not adding any component name, the
1614 	 * passed sep is ignored, so just pass sep=0.
1615 	 */
1616 	mb_put_uint8(mbp, SMB_DT_ASCII);
1617 	error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0);
1618 	if (error)
1619 		goto out;
1620 
1621 	/*
1622 	 * After XATTR directories, separator is ":"
1623 	 */
1624 	sep = (src->n_flag & N_XATTR) ? ':' : '\\';
1625 	mb_put_uint8(mbp, SMB_DT_ASCII);
1626 	error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, sep);
1627 	if (error)
1628 		goto out;
1629 
1630 	smb_rq_bend(rqp);
1631 	error = smb_rq_simple(rqp);
1632 out:
1633 	smb_rq_done(rqp);
1634 	return (error);
1635 }
1636 
1637 int
1638 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
1639 	const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp)
1640 {
1641 	struct smb_rq rq, *rqp = &rq;
1642 	struct smb_share *ssp = src->n_mount->smi_share;
1643 	struct mbchain *mbp;
1644 	int error;
1645 
1646 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp);
1647 	if (error)
1648 		return (error);
1649 	smb_rq_getrequest(rqp, &mbp);
1650 	smb_rq_wstart(rqp);
1651 	mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
1652 	mb_put_uint16le(mbp, 0x20);	/* delete target file */
1653 	mb_put_uint16le(mbp, flags);
1654 	smb_rq_wend(rqp);
1655 	smb_rq_bstart(rqp);
1656 	mb_put_uint8(mbp, SMB_DT_ASCII);
1657 
1658 	error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, '\\');
1659 	if (error)
1660 		goto out;
1661 	mb_put_uint8(mbp, SMB_DT_ASCII);
1662 	error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, '\\');
1663 	if (error)
1664 		goto out;
1665 	smb_rq_bend(rqp);
1666 	error = smb_rq_simple(rqp);
1667 
1668 out:
1669 	smb_rq_done(rqp);
1670 	return (error);
1671 }
1672 
1673 static int
1674 smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len,
1675 			struct smb_cred *scrp)
1676 {
1677 	struct smb_rq rq, *rqp = &rq;
1678 	struct smb_share *ssp = dnp->n_mount->smi_share;
1679 	struct mbchain *mbp;
1680 	int error;
1681 
1682 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp);
1683 	if (error)
1684 		return (error);
1685 	smb_rq_getrequest(rqp, &mbp);
1686 	smb_rq_wstart(rqp);
1687 	smb_rq_wend(rqp);
1688 	smb_rq_bstart(rqp);
1689 	mb_put_uint8(mbp, SMB_DT_ASCII);
1690 	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len, '\\');
1691 	if (!error) {
1692 		smb_rq_bend(rqp);
1693 		error = smb_rq_simple(rqp);
1694 	}
1695 	smb_rq_done(rqp);
1696 	return (error);
1697 }
1698 
1699 int
1700 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen,
1701 		struct smb_cred *scrp)
1702 {
1703 	struct smb_share *ssp = dnp->n_mount->smi_share;
1704 	struct smb_vc *vcp = SSTOVC(ssp);
1705 	uint32_t rights;
1706 	uint16_t fid;
1707 	int error;
1708 
1709 	/*
1710 	 * We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
1711 	 * just to be asking for something.  The rights==0 case could
1712 	 * easily be broken on some old or unusual servers.
1713 	 */
1714 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1715 		rights = SA_RIGHT_FILE_READ_DATA;
1716 		error = smbfs_smb_ntcreatex(dnp,
1717 		    name, nmlen, 0, /* xattr */
1718 		    rights, SMB_EFA_DIRECTORY,
1719 		    NTCREATEX_SHARE_ACCESS_ALL,
1720 		    NTCREATEX_DISP_CREATE,
1721 		    NTCREATEX_OPTIONS_DIRECTORY,
1722 		    scrp, &fid, NULL, NULL); /* cr_act_p fa_p */
1723 		if (error)
1724 			return (error);
1725 		(void) smbfs_smb_close(ssp, fid, NULL, scrp);
1726 		return (0);
1727 	}
1728 
1729 	error = smbfs_smb_oldmkdir(dnp, name, nmlen, scrp);
1730 	return (error);
1731 }
1732 
1733 int
1734 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp)
1735 {
1736 	struct smb_rq rq, *rqp = &rq;
1737 	struct smb_share *ssp = np->n_mount->smi_share;
1738 	struct mbchain *mbp;
1739 	int error;
1740 
1741 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp);
1742 	if (error)
1743 		return (error);
1744 	smb_rq_getrequest(rqp, &mbp);
1745 	smb_rq_wstart(rqp);
1746 	smb_rq_wend(rqp);
1747 	smb_rq_bstart(rqp);
1748 	mb_put_uint8(mbp, SMB_DT_ASCII);
1749 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0, '\\');
1750 	if (!error) {
1751 		smb_rq_bend(rqp);
1752 		error = smb_rq_simple(rqp);
1753 	}
1754 	smb_rq_done(rqp);
1755 	return (error);
1756 }
1757 
1758 static int
1759 smbfs_smb_search(struct smbfs_fctx *ctx)
1760 {
1761 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1762 	struct smb_rq *rqp;
1763 	struct mbchain *mbp;
1764 	struct mdchain *mdp;
1765 	uint8_t wc, bt;
1766 	uint16_t ec, dlen, bc;
1767 	int maxent, error, iseof = 0;
1768 
1769 	maxent = min(ctx->f_left,
1770 	    (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN);
1771 	if (ctx->f_rq) {
1772 		smb_rq_done(ctx->f_rq);
1773 		ctx->f_rq = NULL;
1774 	}
1775 	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH,
1776 	    ctx->f_scred, &rqp);
1777 	if (error)
1778 		return (error);
1779 	ctx->f_rq = rqp;
1780 	smb_rq_getrequest(rqp, &mbp);
1781 	smb_rq_wstart(rqp);
1782 	mb_put_uint16le(mbp, maxent);	/* max entries to return */
1783 	mb_put_uint16le(mbp, ctx->f_attrmask);
1784 	smb_rq_wend(rqp);
1785 	smb_rq_bstart(rqp);
1786 	mb_put_uint8(mbp, SMB_DT_ASCII);	/* buffer format */
1787 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1788 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
1789 		    ctx->f_wildcard, ctx->f_wclen, '\\');
1790 		if (error)
1791 			return (error);
1792 		mb_put_uint8(mbp, SMB_DT_VARIABLE);
1793 		mb_put_uint16le(mbp, 0);	/* context length */
1794 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
1795 	} else {
1796 		if (SMB_UNICODE_STRINGS(vcp)) {
1797 			mb_put_padbyte(mbp);
1798 			mb_put_uint8(mbp, 0);
1799 		}
1800 		mb_put_uint8(mbp, 0);
1801 		mb_put_uint8(mbp, SMB_DT_VARIABLE);
1802 		mb_put_uint16le(mbp, SMB_SKEYLEN);
1803 		mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
1804 	}
1805 	smb_rq_bend(rqp);
1806 	error = smb_rq_simple(rqp);
1807 	if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
1808 		error = 0;
1809 		iseof = 1;
1810 		ctx->f_flags |= SMBFS_RDD_EOF;
1811 	} else if (error)
1812 		return (error);
1813 	smb_rq_getreply(rqp, &mdp);
1814 	error = md_get_uint8(mdp, &wc);
1815 	if (error)
1816 		return (error);
1817 	if (wc != 1)
1818 		return (iseof ? ENOENT : EBADRPC);
1819 	md_get_uint16le(mdp, &ec);
1820 	md_get_uint16le(mdp, &bc);
1821 	md_get_uint8(mdp, &bt);
1822 	error = md_get_uint16le(mdp, &dlen);
1823 	if (error)
1824 		return (error);
1825 	if (ec == 0)
1826 		return (ENOENT);
1827 	ctx->f_ecnt = ec;
1828 	if (bc < 3)
1829 		return (EBADRPC);
1830 	bc -= 3;
1831 	if (bt != SMB_DT_VARIABLE)
1832 		return (EBADRPC);
1833 	if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
1834 		return (EBADRPC);
1835 	return (0);
1836 }
1837 
1838 
1839 /*ARGSUSED*/
1840 static int
1841 smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
1842     const char *wildcard, int wclen, uint16_t attr)
1843 {
1844 
1845 	ctx->f_type = ft_LM1;
1846 	ctx->f_attrmask = attr;
1847 	if (wildcard) {
1848 		if (wclen == 1 && wildcard[0] == '*') {
1849 			ctx->f_wildcard = "*.*";
1850 			ctx->f_wclen = 3;
1851 		} else {
1852 			ctx->f_wildcard = wildcard;
1853 			ctx->f_wclen = wclen;
1854 		}
1855 	} else {
1856 		ctx->f_wildcard = NULL;
1857 		ctx->f_wclen = 0;
1858 	}
1859 	ctx->f_name = (char *)ctx->f_fname;
1860 	ctx->f_namesz = 0;
1861 	return (0);
1862 }
1863 
1864 static int
1865 smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit)
1866 {
1867 	struct mdchain *mdp;
1868 	struct smb_rq *rqp;
1869 	char *cp;
1870 	uint8_t battr;
1871 	uint16_t date, time;
1872 	uint32_t size;
1873 	int error;
1874 	struct timespec ts;
1875 
1876 	if (ctx->f_ecnt == 0) {
1877 		if (ctx->f_flags & SMBFS_RDD_EOF)
1878 			return (ENOENT);
1879 		ctx->f_left = ctx->f_limit = limit;
1880 		gethrestime(&ts);
1881 		error = smbfs_smb_search(ctx);
1882 		if (error)
1883 			return (error);
1884 	}
1885 	rqp = ctx->f_rq;
1886 	smb_rq_getreply(rqp, &mdp);
1887 	md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
1888 	md_get_uint8(mdp, &battr);
1889 	md_get_uint16le(mdp, &time);
1890 	md_get_uint16le(mdp, &date);
1891 	md_get_uint32le(mdp, &size);
1892 	cp = ctx->f_name;
1893 	error = md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM);
1894 	cp[sizeof (ctx->f_fname) - 1] = 0;
1895 	cp += strlen(cp) - 1;
1896 	while (*cp == ' ' && cp >= ctx->f_name)
1897 		*cp-- = 0;
1898 	ctx->f_attr.fa_attr = battr;
1899 	smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
1900 	    &ctx->f_attr.fa_mtime);
1901 	ctx->f_attr.fa_size = size;
1902 	ctx->f_nmlen = strlen(ctx->f_name);
1903 	ctx->f_ecnt--;
1904 	ctx->f_left--;
1905 	return (0);
1906 }
1907 
1908 static int
1909 smbfs_smb_findcloseLM1(struct smbfs_fctx *ctx)
1910 {
1911 	if (ctx->f_rq)
1912 		smb_rq_done(ctx->f_rq);
1913 	return (0);
1914 }
1915 
1916 /*
1917  * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
1918  */
1919 static int
1920 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
1921 {
1922 	struct smb_t2rq *t2p;
1923 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1924 	struct mbchain *mbp;
1925 	struct mdchain *mdp;
1926 	uint16_t ecnt, eos, lno, flags;
1927 	int error;
1928 
1929 	if (ctx->f_t2) {
1930 		smb_t2_done(ctx->f_t2);
1931 		ctx->f_t2 = NULL;
1932 	}
1933 	flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
1934 	if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
1935 		flags |= FIND2_CLOSE_AFTER_REQUEST;
1936 		ctx->f_flags |= SMBFS_RDD_NOCLOSE;
1937 	}
1938 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1939 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
1940 		    ctx->f_scred, &t2p);
1941 		if (error)
1942 			return (error);
1943 		ctx->f_t2 = t2p;
1944 		mbp = &t2p->t2_tparam;
1945 		mb_init(mbp);
1946 		mb_put_uint16le(mbp, ctx->f_attrmask);
1947 		mb_put_uint16le(mbp, ctx->f_limit);
1948 		mb_put_uint16le(mbp, flags);
1949 		mb_put_uint16le(mbp, ctx->f_infolevel);
1950 		mb_put_uint32le(mbp, 0);
1951 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
1952 		    ctx->f_wildcard, ctx->f_wclen, '\\');
1953 		if (error)
1954 			return (error);
1955 	} else	{
1956 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
1957 		    ctx->f_scred, &t2p);
1958 		if (error)
1959 			return (error);
1960 		ctx->f_t2 = t2p;
1961 		mbp = &t2p->t2_tparam;
1962 		mb_init(mbp);
1963 		mb_put_uint16le(mbp, ctx->f_Sid);
1964 		mb_put_uint16le(mbp, ctx->f_limit);
1965 		mb_put_uint16le(mbp, ctx->f_infolevel);
1966 		/* Send whatever resume key we received... */
1967 		mb_put_uint32le(mbp, ctx->f_rkey);
1968 		mb_put_uint16le(mbp, flags);
1969 		/* ... and the resume name if we have one. */
1970 		if (ctx->f_rname) {
1971 			/* resume file name */
1972 			mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
1973 			    MB_MSYSTEM);
1974 		}
1975 		/* Add trailing null - 1 byte if ASCII, 2 if Unicode */
1976 		if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
1977 			mb_put_uint8(mbp, 0);	/* 1st byte NULL Unicode char */
1978 		mb_put_uint8(mbp, 0);
1979 	}
1980 	t2p->t2_maxpcount = 5 * 2;
1981 	t2p->t2_maxdcount = 0xF000;	/* 64K less some overhead */
1982 	error = smb_t2_request(t2p);
1983 	if (error)
1984 		return (error);
1985 
1986 	/*
1987 	 * This is the "resume name" we just sent.
1988 	 * We want the new one (if any) that may be
1989 	 * found in the response we just received and
1990 	 * will now begin parsing.  Free the old one
1991 	 * now so we'll know if we found a new one.
1992 	 */
1993 	if (ctx->f_rname) {
1994 		kmem_free(ctx->f_rname, ctx->f_rnamelen);
1995 		ctx->f_rname = NULL;
1996 		ctx->f_rnamelen = 0;
1997 	}
1998 
1999 	mdp = &t2p->t2_rparam;
2000 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
2001 		if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0)
2002 			goto nodata;
2003 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
2004 	}
2005 	md_get_uint16le(mdp, &ecnt);		/* entry count */
2006 	md_get_uint16le(mdp, &eos);		/* end of search */
2007 	md_get_uint16le(mdp, NULL);		/* EA err. off. */
2008 	error = md_get_uint16le(mdp, &lno);	/* last name off. */
2009 	if (error != 0)
2010 		goto nodata;
2011 
2012 	/*
2013 	 * The "end of search" flag from an XP server sometimes
2014 	 * comes back zero when the prior find_next returned exactly
2015 	 * the number of entries requested.  in which case we'd try again
2016 	 * but the search has in fact been closed so an EBADF results.
2017 	 * our circumvention is to check here for a zero entry count.
2018 	 */
2019 	ctx->f_ecnt = ecnt;
2020 	if (eos || ctx->f_ecnt == 0)
2021 		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
2022 	if (ctx->f_ecnt == 0)
2023 		return (ENOENT);
2024 
2025 	/* Last Name Off (LNO) is the entry with the resume name. */
2026 	ctx->f_rnameofs = lno;
2027 	ctx->f_eofs = 0;
2028 	return (0);
2029 
2030 nodata:
2031 	/*
2032 	 * Failed parsing the FindFirst or FindNext response.
2033 	 * Force this directory listing closed, otherwise the
2034 	 * calling process may hang in an infinite loop.
2035 	 */
2036 	ctx->f_ecnt = 0; /* Force closed. */
2037 	ctx->f_flags |= SMBFS_RDD_EOF;
2038 	return (EIO);
2039 }
2040 
2041 static int
2042 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
2043 {
2044 	struct smb_rq rq, *rqp = &rq;
2045 	struct mbchain *mbp;
2046 	int error;
2047 
2048 	error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
2049 	    ctx->f_scred);
2050 	if (error)
2051 		return (error);
2052 	smb_rq_getrequest(rqp, &mbp);
2053 	smb_rq_wstart(rqp);
2054 	mb_put_uint16le(mbp, ctx->f_Sid);
2055 	smb_rq_wend(rqp);
2056 	smb_rq_bstart(rqp);
2057 	smb_rq_bend(rqp);
2058 	/* Ditto comments at _smb_close */
2059 	rqp->sr_flags |= SMBR_NOINTR_SEND;
2060 	error = smb_rq_simple(rqp);
2061 	smb_rq_done(rqp);
2062 	return (error);
2063 }
2064 
2065 /*ARGSUSED*/
2066 static int
2067 smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
2068     const char *wildcard, int wclen, uint16_t attr)
2069 {
2070 
2071 	ctx->f_type = ft_LM2;
2072 	ctx->f_namesz = SMB_MAXFNAMELEN + 1;
2073 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2074 		ctx->f_namesz *= 2;
2075 	ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
2076 	ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp))
2077 	    < SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD :
2078 	    SMB_FIND_BOTH_DIRECTORY_INFO;
2079 	ctx->f_attrmask = attr;
2080 	ctx->f_wildcard = wildcard;
2081 	ctx->f_wclen = wclen;
2082 	return (0);
2083 }
2084 
2085 static int
2086 smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
2087 {
2088 	struct mdchain *mdp;
2089 	struct smb_t2rq *t2p;
2090 	char *cp;
2091 	uint8_t tb;
2092 	uint16_t date, time, wattr;
2093 	uint32_t size, next, dattr, resumekey = 0;
2094 	uint64_t llongint;
2095 	int error, svtz, cnt, fxsz, nmlen, recsz;
2096 	struct timespec ts;
2097 
2098 	if (ctx->f_ecnt == 0) {
2099 		if (ctx->f_flags & SMBFS_RDD_EOF)
2100 			return (ENOENT);
2101 		ctx->f_left = ctx->f_limit = limit;
2102 		gethrestime(&ts);
2103 		error = smbfs_smb_trans2find2(ctx);
2104 		if (error)
2105 			return (error);
2106 		ctx->f_otws++;
2107 	}
2108 	t2p = ctx->f_t2;
2109 	mdp = &t2p->t2_rdata;
2110 	svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
2111 	switch (ctx->f_infolevel) {
2112 	case SMB_FIND_STANDARD:
2113 		next = 0;
2114 		fxsz = 0;
2115 		md_get_uint16le(mdp, &date);
2116 		md_get_uint16le(mdp, &time);	/* creation time */
2117 		smb_dos2unixtime(date, time, 0, svtz,
2118 		    &ctx->f_attr.fa_createtime);
2119 		md_get_uint16le(mdp, &date);
2120 		md_get_uint16le(mdp, &time);	/* access time */
2121 		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
2122 		md_get_uint16le(mdp, &date);
2123 		md_get_uint16le(mdp, &time);	/* modify time */
2124 		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
2125 		md_get_uint32le(mdp, &size);
2126 		ctx->f_attr.fa_size = size;
2127 		md_get_uint32le(mdp, &size);	/* allocation size */
2128 		ctx->f_attr.fa_allocsz = size;
2129 		md_get_uint16le(mdp, &wattr);
2130 		ctx->f_attr.fa_attr = wattr;
2131 		error = md_get_uint8(mdp, &tb);
2132 		if (error)
2133 			goto nodata;
2134 		size = nmlen = tb;
2135 		fxsz = 23;
2136 		recsz = next = 24 + nmlen;	/* docs misses zero byte @end */
2137 		break;
2138 	case SMB_FIND_DIRECTORY_INFO:
2139 	case SMB_FIND_BOTH_DIRECTORY_INFO:
2140 		md_get_uint32le(mdp, &next);
2141 		md_get_uint32le(mdp, &resumekey); /* file index (resume key) */
2142 		md_get_uint64le(mdp, &llongint);	/* creation time */
2143 		smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime);
2144 		md_get_uint64le(mdp, &llongint);
2145 		smb_time_NT2local(llongint, &ctx->f_attr.fa_atime);
2146 		md_get_uint64le(mdp, &llongint);
2147 		smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime);
2148 		md_get_uint64le(mdp, &llongint);
2149 		smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime);
2150 		md_get_uint64le(mdp, &llongint);	/* file size */
2151 		ctx->f_attr.fa_size = llongint;
2152 		md_get_uint64le(mdp, &llongint);	/* alloc. size */
2153 		ctx->f_attr.fa_allocsz = llongint;
2154 		md_get_uint32le(mdp, &dattr);	/* ext. file attributes */
2155 		ctx->f_attr.fa_attr = dattr;
2156 		error = md_get_uint32le(mdp, &size);	/* name len */
2157 		if (error)
2158 			goto nodata;
2159 		fxsz = 64; /* size ofinfo up to filename */
2160 		if (ctx->f_infolevel == SMB_FIND_BOTH_DIRECTORY_INFO) {
2161 			/*
2162 			 * Skip EaSize(4 bytes), a byte of ShortNameLength,
2163 			 * a reserved byte, and ShortName(8.3 means 24 bytes,
2164 			 * as Leach defined it to always be Unicode)
2165 			 */
2166 			error = md_get_mem(mdp, NULL, 30, MB_MSYSTEM);
2167 			if (error)
2168 				goto nodata;
2169 			fxsz += 30;
2170 		}
2171 		recsz = next ? next : fxsz + size;
2172 		break;
2173 	default:
2174 		SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
2175 		return (EINVAL);
2176 	}
2177 
2178 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2179 		nmlen = min(size, SMB_MAXFNAMELEN * 2);
2180 	else
2181 		nmlen = min(size, SMB_MAXFNAMELEN);
2182 
2183 	/* Allocated f_name in findopen */
2184 	ASSERT(nmlen < ctx->f_namesz);
2185 	cp = ctx->f_name;
2186 
2187 	error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM);
2188 	if (error)
2189 		goto nodata;
2190 	if (next) {
2191 		/* How much data to skip? */
2192 		cnt = next - nmlen - fxsz;
2193 		if (cnt < 0) {
2194 			SMBVDEBUG("out of sync\n");
2195 			goto nodata;
2196 		}
2197 		if (cnt > 0)
2198 			md_get_mem(mdp, NULL, cnt, MB_MSYSTEM);
2199 	}
2200 	/* Don't count any trailing null in the name. */
2201 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
2202 		if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
2203 			nmlen -= 2;
2204 	} else {
2205 		if (nmlen && cp[nmlen - 1] == 0)
2206 			nmlen--;
2207 	}
2208 	if (nmlen == 0)
2209 		goto nodata;
2210 
2211 	/*
2212 	 * On a find-next we expect that the server will:
2213 	 * 1) if the continue bit is set, use the server's offset,
2214 	 * 2) else if the resume key is non-zero, use that offset,
2215 	 * 3) else if the resume name is set, use that offset,
2216 	 * 4) else use the server's idea of current offset.
2217 	 *
2218 	 * We always set the resume key flag. If the server returns
2219 	 * a resume key then we should always send it back to them.
2220 	 */
2221 	ctx->f_rkey = resumekey;
2222 
2223 	next = ctx->f_eofs + recsz;
2224 	if (ctx->f_rnameofs &&
2225 	    ctx->f_rnameofs >= ctx->f_eofs &&
2226 	    ctx->f_rnameofs < (int)next) {
2227 		/*
2228 		 * This entry is the "resume name".
2229 		 * Save it for the next request.
2230 		 */
2231 		if (ctx->f_rnamelen != nmlen) {
2232 			if (ctx->f_rname)
2233 				kmem_free(ctx->f_rname, ctx->f_rnamelen);
2234 			ctx->f_rname = kmem_alloc(nmlen, KM_SLEEP);
2235 			ctx->f_rnamelen = nmlen;
2236 		}
2237 		bcopy(ctx->f_name, ctx->f_rname, nmlen);
2238 	}
2239 	ctx->f_nmlen = nmlen;
2240 	ctx->f_eofs = next;
2241 	ctx->f_ecnt--;
2242 	ctx->f_left--;
2243 
2244 	smbfs_fname_tolocal(ctx);
2245 	return (0);
2246 
2247 nodata:
2248 	/*
2249 	 * Something bad has happened and we ran out of data
2250 	 * before we could parse all f_ecnt entries expected.
2251 	 * Force this directory listing closed, otherwise the
2252 	 * calling process may hang in an infinite loop.
2253 	 */
2254 	SMBVDEBUG("ran out of data\n");
2255 	ctx->f_ecnt = 0; /* Force closed. */
2256 	ctx->f_flags |= SMBFS_RDD_EOF;
2257 	return (EIO);
2258 }
2259 
2260 static int
2261 smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
2262 {
2263 	int error = 0;
2264 	if (ctx->f_name)
2265 		kmem_free(ctx->f_name, ctx->f_namesz);
2266 	if (ctx->f_t2)
2267 		smb_t2_done(ctx->f_t2);
2268 	/*
2269 	 * If SMBFS_RDD_FINDFIRST is still set, we were opened
2270 	 * but never saw a findfirst, so we don't have any
2271 	 * search handle to close.
2272 	 */
2273 	if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0)
2274 		error = smbfs_smb_findclose2(ctx);
2275 	return (error);
2276 }
2277 
2278 int
2279 smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
2280 			int attr, struct smb_cred *scrp,
2281 			struct smbfs_fctx **ctxpp)
2282 {
2283 	struct smbfs_fctx *ctx;
2284 	int error;
2285 
2286 	ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
2287 
2288 	ctx->f_flags = SMBFS_RDD_FINDFIRST;
2289 	ctx->f_dnp = dnp;
2290 	ctx->f_scred = scrp;
2291 	ctx->f_ssp = dnp->n_mount->smi_share;
2292 
2293 	if (dnp->n_flag & N_XATTR) {
2294 		error = smbfs_xa_findopen(ctx, dnp, wild, wlen);
2295 		goto out;
2296 	}
2297 
2298 	if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0) {
2299 		error = smbfs_smb_findopenLM1(ctx, dnp, wild, wlen, attr);
2300 	} else {
2301 		error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr);
2302 	}
2303 
2304 out:
2305 	if (error)
2306 		(void) smbfs_smb_findclose(ctx, scrp);
2307 	else
2308 		*ctxpp = ctx;
2309 	return (error);
2310 }
2311 
2312 int
2313 smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
2314 {
2315 	int error;
2316 
2317 	/*
2318 	 * Note: "limit" (maxcount) needs to fit in a short!
2319 	 */
2320 	if (limit > 0xffff)
2321 		limit = 0xffff;
2322 
2323 	ctx->f_scred = scrp;
2324 	for (;;) {
2325 		bzero(&ctx->f_attr, sizeof (ctx->f_attr));
2326 		switch (ctx->f_type) {
2327 		case ft_LM1:
2328 			error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit);
2329 			break;
2330 		case ft_LM2:
2331 			error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit);
2332 			break;
2333 		case ft_XA:
2334 			error = smbfs_xa_findnext(ctx, (uint16_t)limit);
2335 			break;
2336 		default:
2337 			ASSERT(0);
2338 			error = EINVAL;
2339 			break;
2340 		}
2341 		if (error)
2342 			return (error);
2343 		/*
2344 		 * Skip "." or ".." - easy now that ctx->f_name
2345 		 * has already been converted to utf-8 format.
2346 		 */
2347 		if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
2348 		    (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
2349 		    ctx->f_name[1] == '.'))
2350 			continue;
2351 		break;
2352 	}
2353 
2354 	/*
2355 	 * Moved the smbfs_fname_tolocal(ctx) call into
2356 	 * the ..._findnext functions above.
2357 	 */
2358 
2359 	ctx->f_inum = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
2360 	return (0);
2361 }
2362 
2363 
2364 int
2365 smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
2366 {
2367 	int error;
2368 
2369 	ctx->f_scred = scrp;
2370 	switch (ctx->f_type) {
2371 	case ft_LM1:
2372 		error = smbfs_smb_findcloseLM1(ctx);
2373 		break;
2374 	case ft_LM2:
2375 		error = smbfs_smb_findcloseLM2(ctx);
2376 		break;
2377 	case ft_XA:
2378 		error = smbfs_xa_findclose(ctx);
2379 		break;
2380 	default:
2381 		error = ENOSYS;
2382 		break;
2383 	}
2384 	if (ctx->f_rname)
2385 		kmem_free(ctx->f_rname, ctx->f_rnamelen);
2386 	if (ctx->f_firstnm)
2387 		kmem_free(ctx->f_firstnm, ctx->f_firstnmlen);
2388 	kmem_free(ctx, sizeof (*ctx));
2389 	return (error);
2390 }
2391 
2392 
2393 int
2394 smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
2395 	struct smbfattr *fap, struct smb_cred *scrp)
2396 {
2397 	struct smbfs_fctx *ctx;
2398 	int error, intr;
2399 	const char *name = (namep ? *namep : NULL);
2400 	int nmlen = (nmlenp ? *nmlenp : 0);
2401 
2402 	/* This is no longer called with a null dnp */
2403 	ASSERT(dnp);
2404 
2405 	/*
2406 	 * Should not get here with "" anymore.
2407 	 */
2408 	if (!name || !nmlen) {
2409 		DEBUG_ENTER("smbfs_smb_lookup: name is NULL");
2410 		return (EINVAL);
2411 	}
2412 
2413 	/*
2414 	 * Should not get here with "." or ".." anymore.
2415 	 */
2416 	if ((nmlen == 1 && name[0] == '.') ||
2417 	    (nmlen == 2 && name[0] == '.' && name[1] == '.')) {
2418 		DEBUG_ENTER("smbfs_smb_lookup: name is '.' or '..'");
2419 		return (EINVAL);
2420 	}
2421 
2422 	/*
2423 	 * XXX: Should use _qpathinfo here instead.
2424 	 * (if SMB_CAP_NT_SMBS)
2425 	 */
2426 
2427 	/*
2428 	 * Shared lock for n_fid use (smb_flush).
2429 	 */
2430 	intr = dnp->n_mount->smi_flags & SMI_INT;
2431 	if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr))
2432 		return (EINTR);
2433 
2434 	/*
2435 	 * This hides a server bug observable in Win98:
2436 	 * size changes may not show until a CLOSE or a FLUSH op
2437 	 * XXX: Make this conditional on !NTSMBs
2438 	 */
2439 	error = smbfs_smb_flush(dnp, scrp);
2440 	if (error)
2441 		goto out;
2442 	error = smbfs_smb_findopen(dnp, name, nmlen,
2443 	    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx);
2444 	if (error)
2445 		goto out;
2446 	ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
2447 	error = smbfs_smb_findnext(ctx, 1, scrp);
2448 	if (error == 0) {
2449 		*fap = ctx->f_attr;
2450 		/*
2451 		 * Solaris smbfattr doesn't have fa_ino,
2452 		 * and we don't allow name==NULL in this
2453 		 * function anymore.
2454 		 */
2455 		if (namep)
2456 			*namep = (const char *)smbfs_name_alloc(
2457 			    ctx->f_name, ctx->f_nmlen);
2458 		if (nmlenp)
2459 			*nmlenp = ctx->f_nmlen;
2460 	}
2461 	(void) smbfs_smb_findclose(ctx, scrp);
2462 
2463 out:
2464 	smbfs_rw_exit(&dnp->r_lkserlock);
2465 	return (error);
2466 }
2467 
2468 /*
2469  * OTW function to Get a security descriptor (SD).
2470  *
2471  * Note: On success, this fills in mdp->md_top,
2472  * which the caller should free.
2473  */
2474 int
2475 smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
2476 		struct smb_cred *scrp, uint32_t selector,
2477 		mblk_t **res, uint32_t *reslen)
2478 {
2479 	struct smb_ntrq *ntp;
2480 	struct mbchain *mbp;
2481 	struct mdchain *mdp;
2482 	int error, len;
2483 
2484 	error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
2485 	    scrp, &ntp);
2486 	if (error)
2487 		return (error);
2488 
2489 	/* Parameters part */
2490 	mbp = &ntp->nt_tparam;
2491 	mb_init(mbp);
2492 	mb_put_uint16le(mbp, fid);
2493 	mb_put_uint16le(mbp, 0); /* reserved */
2494 	mb_put_uint32le(mbp, selector);
2495 	/* Data part (none) */
2496 
2497 	/* Max. returned parameters and data. */
2498 	ntp->nt_maxpcount = 4;
2499 	ntp->nt_maxdcount = *reslen;
2500 
2501 	error = smb_nt_request(ntp);
2502 	if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
2503 		goto done;
2504 	*res = NULL;
2505 
2506 	/*
2507 	 * if there's more data than we said we could receive, here
2508 	 * is where we pick up the length of it
2509 	 */
2510 	mdp = &ntp->nt_rparam;
2511 	md_get_uint32le(mdp, reslen);
2512 	if (error)
2513 		goto done;
2514 
2515 	/*
2516 	 * get the data part.
2517 	 */
2518 	mdp = &ntp->nt_rdata;
2519 	if (mdp->md_top == NULL) {
2520 		SMBVDEBUG("null md_top? fid 0x%x\n", fid);
2521 		error = EBADRPC;
2522 		goto done;
2523 	}
2524 
2525 	/*
2526 	 * The returned parameter SD_length should match
2527 	 * the length of the returned data.  Unfortunately,
2528 	 * we have to work around server bugs here.
2529 	 */
2530 	len = m_fixhdr(mdp->md_top);
2531 	if (len != *reslen) {
2532 		SMBVDEBUG("len %d *reslen %d fid 0x%x\n",
2533 		    len, *reslen, fid);
2534 	}
2535 
2536 	/*
2537 	 * Actual data provided is < returned SD_length.
2538 	 *
2539 	 * The following "if (len < *reslen)" handles a Windows bug
2540 	 * observed when the underlying filesystem is FAT32.  In that
2541 	 * case a 32 byte security descriptor comes back (S-1-1-0, ie
2542 	 * "Everyone") but the Parameter Block claims 44 is the length
2543 	 * of the security descriptor.  (The Data Block length
2544 	 * claimed is 32.  This server bug was reported against NT
2545 	 * first and I've personally observed it with W2K.
2546 	 */
2547 	if (len < *reslen)
2548 		*reslen = len;
2549 
2550 	/*
2551 	 * Actual data provided is > returned SD_length.
2552 	 * (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0)
2553 	 * Narrow work-around for returned SD_length==0.
2554 	 */
2555 	if (len > *reslen) {
2556 		/*
2557 		 * Increase *reslen, but carefully.
2558 		 */
2559 		if (*reslen == 0 && len <= ntp->nt_maxdcount)
2560 			*reslen = len;
2561 	}
2562 	error = md_get_mbuf(mdp, len, res);
2563 
2564 done:
2565 	if (error == 0 && *res == NULL) {
2566 		ASSERT(*res);
2567 		error = EBADRPC;
2568 	}
2569 
2570 	smb_nt_done(ntp);
2571 	return (error);
2572 }
2573 
2574 #ifdef	APPLE
2575 /*
2576  * Wrapper for _getsd() compatible with darwin code.
2577  */
2578 int
2579 smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
2580 	uint32_t selector, struct ntsecdesc **res)
2581 {
2582 	int error;
2583 	uint32_t len, olen;
2584 	struct mdchain *mdp, md_store;
2585 	struct mbuf *m;
2586 
2587 	bzero(mdp, sizeof (*mdp));
2588 	len = 500; /* "overlarge" values => server errors */
2589 again:
2590 	olen = len;
2591 	error = smbfs_smb_getsec_m(ssp, fid, scrp, selector, &m, &len);
2592 	/*
2593 	 * Server may give us an error indicating that we
2594 	 * need a larger data buffer to receive the SD,
2595 	 * and the size we'll need.  Use the given size,
2596 	 * but only after a sanity check.
2597 	 *
2598 	 * XXX: Check for specific error values here?
2599 	 * XXX: also ... && len <= MAX_RAW_SD_SIZE
2600 	 */
2601 	if (error && len > olen)
2602 		goto again;
2603 
2604 	if (error)
2605 		return (error);
2606 
2607 	mdp = &md_store;
2608 	md_initm(mdp, m);
2609 	MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK);
2610 	error = md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM);
2611 	md_done(mdp);
2612 
2613 	return (error);
2614 }
2615 #endif /* APPLE */
2616 
2617 /*
2618  * OTW function to Set a security descriptor (SD).
2619  * Caller data are carried in an mbchain_t.
2620  *
2621  * Note: This normally consumes mbp->mb_top, and clears
2622  * that pointer when it does.
2623  */
2624 int  smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
2625 	struct smb_cred *scrp, uint32_t selector, mblk_t **mp)
2626 {
2627 	struct smb_ntrq *ntp;
2628 	struct mbchain *mbp;
2629 	int error;
2630 
2631 	error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
2632 	    scrp, &ntp);
2633 	if (error)
2634 		return (error);
2635 
2636 	/* Parameters part */
2637 	mbp = &ntp->nt_tparam;
2638 	mb_init(mbp);
2639 	mb_put_uint16le(mbp, fid);
2640 	mb_put_uint16le(mbp, 0); /* reserved */
2641 	mb_put_uint32le(mbp, selector);
2642 
2643 	/* Data part */
2644 	mbp = &ntp->nt_tdata;
2645 	mb_initm(mbp, *mp);
2646 	*mp = NULL; /* consumed */
2647 
2648 	/* No returned parameters or data. */
2649 	ntp->nt_maxpcount = 0;
2650 	ntp->nt_maxdcount = 0;
2651 
2652 	error = smb_nt_request(ntp);
2653 	smb_nt_done(ntp);
2654 
2655 	return (error);
2656 }
2657 
2658 #ifdef	APPLE
2659 /*
2660  * This function builds the SD given the various parts.
2661  */
2662 int
2663 smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
2664 	uint32_t selector, uint16_t flags, struct ntsid *owner,
2665 	struct ntsid *group, struct ntacl *sacl, struct ntacl *dacl)
2666 {
2667 	struct mbchain *mbp, mb_store;
2668 	struct ntsecdesc ntsd;
2669 	int error, off;
2670 
2671 	/*
2672 	 * Build the SD as its own mbuf chain and pass it to
2673 	 * smbfs_smb_setsec_m()
2674 	 */
2675 	mbp = &mb_store;
2676 	mb_init(mbp);
2677 	bzero(&ntsd, sizeof (ntsd));
2678 	wset_sdrevision(&ntsd);
2679 	/*
2680 	 * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN)
2681 	 * We set here only those bits we can be sure must be set.  The rest
2682 	 * are up to the caller.  In particular, the caller may intentionally
2683 	 * set an acl PRESENT bit while giving us a null pointer for the
2684 	 * acl - that sets a null acl, giving access to everyone.  Note also
2685 	 * that the AUTO_INHERITED bits should probably always be set unless
2686 	 * the server is NT.
2687 	 */
2688 	flags |= SD_SELF_RELATIVE;
2689 	off = sizeof (ntsd);
2690 	if (owner) {
2691 		wset_sdowneroff(&ntsd, off);
2692 		off += sidlen(owner);
2693 	}
2694 	if (group) {
2695 		wset_sdgroupoff(&ntsd, off);
2696 		off += sidlen(group);
2697 	}
2698 	if (sacl) {
2699 		flags |= SD_SACL_PRESENT;
2700 		wset_sdsacloff(&ntsd, off);
2701 		off += acllen(sacl);
2702 	}
2703 	if (dacl) {
2704 		flags |= SD_DACL_PRESENT;
2705 		wset_sddacloff(&ntsd, off);
2706 	}
2707 	wset_sdflags(&ntsd, flags);
2708 	mb_put_mem(mbp, (caddr_t)&ntsd, sizeof (ntsd), MB_MSYSTEM);
2709 	if (owner)
2710 		mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM);
2711 	if (group)
2712 		mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM);
2713 	if (sacl)
2714 		mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM);
2715 	if (dacl)
2716 		mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM);
2717 
2718 	/*
2719 	 * Just pass the mbuf to _setsec_m
2720 	 * It will clear mb_top if consumed.
2721 	 */
2722 	error = smbfs_smb_setsec_m(ssp, fid, scrp, selector, &mbp->mb_top);
2723 	mb_done(mbp);
2724 
2725 	return (error);
2726 }
2727 
2728 #endif /* APPLE */
2729