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