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