xref: /titanic_51/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c (revision 430b4c467020edf2445feb0c21db01c88b86243a)
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 /*ARGSUSED*/
626 int
627 smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp,
628 	const char *tname, int tnmlen, struct smb_cred *scrp, int overwrite)
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 	int32_t *ucslenp;
635 	int error, cerror;
636 	uint16_t fid = 0;
637 
638 	/* Shared lock for n_fid use below. */
639 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
640 
641 	/* After reconnect, n_fid is invalid */
642 	if (np->n_vcgenid != ssp->ss_vcgenid)
643 		return (ESTALE);
644 
645 	if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU))
646 		return (ENOTSUP);
647 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
648 	    scrp, &t2p);
649 	if (error)
650 		return (error);
651 	if (tdnp) {
652 		error = smbfs_smb_tmpopen(tdnp, SA_RIGHT_FILE_READ_DATA, scrp,
653 		    &fid);
654 		if (error)
655 			goto exit;
656 	}
657 	mbp = &t2p->t2_tparam;
658 	mb_init(mbp);
659 	mb_put_uint16le(mbp, np->n_fid);
660 	mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
661 	mb_put_uint16le(mbp, 0); /* reserved, nowadays */
662 	mbp = &t2p->t2_tdata;
663 	mb_init(mbp);
664 	mb_put_uint32le(mbp, overwrite);
665 	mb_put_uint16le(mbp, fid); /* base for tname */
666 	mb_put_uint16le(mbp, 0); /* part of a 32bit fid? */
667 	ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t));
668 	mbp->mb_count = 0;
669 	error = smb_put_dstring(mbp, vcp, tname, SMB_CS_NONE);
670 	if (error)
671 		goto exit;
672 	mbp->mb_count--;	/* don't count the null */
673 	*ucslenp = htolel(mbp->mb_count);
674 	t2p->t2_maxpcount = 2;
675 	t2p->t2_maxdcount = 0;
676 	error = smb_t2_request(t2p);
677 exit:
678 	if (fid) {
679 		cerror = smbfs_smb_tmpclose(tdnp, fid, scrp);
680 		if (cerror)
681 			SMBVDEBUG("error %d closing %s\n",
682 			    cerror, tdnp->n_rpath);
683 	}
684 	smb_t2_done(t2p);
685 	return (error);
686 }
687 
688 int
689 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp)
690 {
691 	struct smb_share *ssp = np->n_mount->smi_share;
692 	struct smb_rq rq, *rqp = &rq;
693 	struct mbchain *mbp;
694 	int error;
695 
696 	/* Shared lock for n_fid use below. */
697 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
698 
699 	if (!(np->n_flag & NFLUSHWIRE))
700 		return (0);
701 	if (np->n_fidrefs == 0)
702 		return (0); /* not open */
703 
704 	/* After reconnect, n_fid is invalid */
705 	if (np->n_vcgenid != ssp->ss_vcgenid)
706 		return (ESTALE);
707 
708 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
709 	if (error)
710 		return (error);
711 	smb_rq_getrequest(rqp, &mbp);
712 	smb_rq_wstart(rqp);
713 	mb_put_uint16le(mbp, np->n_fid);
714 	smb_rq_wend(rqp);
715 	smb_rq_bstart(rqp);
716 	smb_rq_bend(rqp);
717 	error = smb_rq_simple(rqp);
718 	smb_rq_done(rqp);
719 	if (!error) {
720 		mutex_enter(&np->r_statelock);
721 		np->n_flag &= ~NFLUSHWIRE;
722 		mutex_exit(&np->r_statelock);
723 	}
724 	return (error);
725 }
726 
727 int
728 smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
729 			struct smb_cred *scrp)
730 {
731 	struct smb_share *ssp = np->n_mount->smi_share;
732 	struct smb_rq rq, *rqp = &rq;
733 	struct mbchain *mbp;
734 	int error;
735 
736 	if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
737 		/*
738 		 * This call knows about 64-bit offsets.
739 		 */
740 		error = smbfs_smb_seteof(ssp, fid, newsize, scrp);
741 		if (!error) {
742 			mutex_enter(&np->r_statelock);
743 			np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
744 			mutex_exit(&np->r_statelock);
745 			return (0);
746 		}
747 	}
748 
749 	/*
750 	 * OK, so fallback to SMB_COM_WRITE, but note:
751 	 * it only supports 32-bit file offsets.
752 	 */
753 	if (newsize > UINT32_MAX)
754 		return (EFBIG);
755 
756 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp);
757 	if (error)
758 		return (error);
759 	smb_rq_getrequest(rqp, &mbp);
760 	smb_rq_wstart(rqp);
761 	mb_put_uint16le(mbp, fid);
762 	mb_put_uint16le(mbp, 0);
763 	mb_put_uint32le(mbp, newsize);
764 	mb_put_uint16le(mbp, 0);
765 	smb_rq_wend(rqp);
766 	smb_rq_bstart(rqp);
767 	mb_put_uint8(mbp, SMB_DT_DATA);
768 	mb_put_uint16le(mbp, 0);
769 	smb_rq_bend(rqp);
770 	error = smb_rq_simple(rqp);
771 	smb_rq_done(rqp);
772 	mutex_enter(&np->r_statelock);
773 	np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
774 	mutex_exit(&np->r_statelock);
775 	return (error);
776 }
777 
778 /*
779  * Old method for getting file attributes.
780  */
781 int
782 smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
783 	struct smbfattr *fap, struct smb_cred *scrp)
784 {
785 	struct smb_rq rq, *rqp = &rq;
786 	struct smb_share *ssp = np->n_mount->smi_share;
787 	struct mbchain *mbp;
788 	struct mdchain *mdp;
789 	uint8_t wc;
790 	int error;
791 	uint16_t wattr;
792 	uint32_t longint;
793 
794 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp);
795 	if (error)
796 		return (error);
797 	smb_rq_getrequest(rqp, &mbp);
798 	smb_rq_wstart(rqp);
799 	smb_rq_wend(rqp);
800 	smb_rq_bstart(rqp);
801 	mb_put_uint8(mbp, SMB_DT_ASCII);
802 
803 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np,
804 	    name, nmlen, '\\');
805 	if (error)
806 		goto out;
807 	smb_rq_bend(rqp);
808 	error = smb_rq_simple(rqp);
809 	if (error)
810 		goto out;
811 	smb_rq_getreply(rqp, &mdp);
812 	error = md_get_uint8(mdp, &wc);
813 	if (error)
814 		goto out;
815 	if (wc != 10) {
816 		error = EBADRPC;
817 		goto out;
818 	}
819 	md_get_uint16le(mdp, &wattr);
820 	fap->fa_attr = wattr;
821 	/*
822 	 * Be careful using the time returned here, as
823 	 * with FAT on NT4SP6, at least, the time returned is low
824 	 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
825 	 * over about every seven minutes!
826 	 */
827 	md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
828 	smb_time_server2local(longint,
829 	    SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime);
830 	error = md_get_uint32le(mdp, &longint);
831 	fap->fa_size = longint;
832 
833 out:
834 	smb_rq_done(rqp);
835 	return (error);
836 }
837 
838 /*
839  * Set DOS file attributes. mtime should be NULL for dialects above lm10
840  */
841 int
842 smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len,
843 	uint32_t attr, struct timespec *mtime,
844 	struct smb_cred *scrp)
845 {
846 	struct smb_rq rq, *rqp = &rq;
847 	struct smb_share *ssp = np->n_mount->smi_share;
848 	struct mbchain *mbp;
849 	long time;
850 	int error, svtz;
851 
852 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp);
853 	if (error)
854 		return (error);
855 	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
856 	smb_rq_getrequest(rqp, &mbp);
857 	smb_rq_wstart(rqp);
858 	mb_put_uint16le(mbp, (uint16_t)attr);
859 	if (mtime) {
860 		smb_time_local2server(mtime, svtz, &time);
861 	} else
862 		time = 0;
863 	mb_put_uint32le(mbp, time);		/* mtime */
864 	mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
865 	smb_rq_wend(rqp);
866 	smb_rq_bstart(rqp);
867 	mb_put_uint8(mbp, SMB_DT_ASCII);
868 
869 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len, '\\');
870 	if (error)
871 		goto out;
872 	mb_put_uint8(mbp, SMB_DT_ASCII);
873 	if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
874 		mb_put_padbyte(mbp);
875 		mb_put_uint8(mbp, 0);	/* 1st byte NULL Unicode char */
876 	}
877 	mb_put_uint8(mbp, 0);
878 	smb_rq_bend(rqp);
879 	error = smb_rq_simple(rqp);
880 
881 out:
882 	smb_rq_done(rqp);
883 	return (error);
884 }
885 
886 int
887 smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
888 			struct smb_cred *scrp)
889 {
890 	struct smbfattr fa;
891 	int error;
892 	uint32_t attr;
893 
894 	error = smbfs_smb_query_info(np, name, len, &fa, scrp);
895 	attr = fa.fa_attr;
896 	if (!error && !(attr & SMB_FA_HIDDEN)) {
897 		attr |= SMB_FA_HIDDEN;
898 		error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
899 	}
900 	return (error);
901 }
902 
903 
904 int
905 smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
906 			struct smb_cred *scrp)
907 {
908 	struct smbfattr fa;
909 	uint32_t attr;
910 	int error;
911 
912 	error = smbfs_smb_query_info(np, name, len, &fa, scrp);
913 	attr = fa.fa_attr;
914 	if (!error && (attr & SMB_FA_HIDDEN)) {
915 		attr &= ~SMB_FA_HIDDEN;
916 		error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
917 	}
918 	return (error);
919 }
920 
921 /*
922  * Set file attributes (optionally: DOS attr, atime, mtime)
923  * either by open FID or by path name (FID == -1).
924  */
925 int
926 smbfs_smb_setfattr(
927 	struct smbnode *np,
928 	int fid,
929 	uint32_t attr,
930 	struct timespec *mtime,
931 	struct timespec *atime,
932 	struct smb_cred *scrp)
933 {
934 	struct smb_share *ssp = np->n_mount->smi_share;
935 	struct smb_vc *vcp = SSTOVC(ssp);
936 	int error;
937 
938 	/*
939 	 * Normally can use the trans2 call.
940 	 */
941 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
942 		error = smbfs_smb_setfattrNT(np, fid,
943 		    attr, mtime, atime, scrp);
944 		return (error);
945 	}
946 
947 	/*
948 	 * Fall-back for older protocols.
949 	 */
950 	if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) {
951 		error = smbfs_smb_setftime1(np, fid,
952 		    mtime, atime, scrp);
953 		return (error);
954 	}
955 	error = smbfs_smb_setpattr1(np, NULL, 0,
956 	    attr, mtime, scrp);
957 	return (error);
958 }
959 
960 /*
961  * Set file atime and mtime. Isn't supported by core dialect.
962  */
963 int
964 smbfs_smb_setftime1(
965 	struct smbnode *np,
966 	uint16_t fid,
967 	struct timespec *mtime,
968 	struct timespec *atime,
969 	struct smb_cred *scrp)
970 {
971 	struct smb_rq rq, *rqp = &rq;
972 	struct smb_share *ssp = np->n_mount->smi_share;
973 	struct mbchain *mbp;
974 	uint16_t date, time;
975 	int error, tzoff;
976 
977 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp);
978 	if (error)
979 		return (error);
980 
981 	tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
982 	smb_rq_getrequest(rqp, &mbp);
983 	smb_rq_wstart(rqp);
984 	mb_put_uint16le(mbp, fid);
985 	mb_put_uint32le(mbp, 0);		/* creation time */
986 
987 	if (atime)
988 		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
989 	else
990 		time = date = 0;
991 	mb_put_uint16le(mbp, date);
992 	mb_put_uint16le(mbp, time);
993 	if (mtime)
994 		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
995 	else
996 		time = date = 0;
997 	mb_put_uint16le(mbp, date);
998 	mb_put_uint16le(mbp, time);
999 	smb_rq_wend(rqp);
1000 	smb_rq_bstart(rqp);
1001 	smb_rq_bend(rqp);
1002 	error = smb_rq_simple(rqp);
1003 	SMBVDEBUG("%d\n", error);
1004 	smb_rq_done(rqp);
1005 	return (error);
1006 }
1007 
1008 /*
1009  * Set DOS file attributes, either via open FID or by path name.
1010  * Looks like this call can be used only if CAP_NT_SMBS bit is on.
1011  *
1012  * When setting via path (fid == -1):
1013  * *BASIC_INFO works with Samba, but Win2K servers say it is an
1014  * invalid information level on a SET_PATH_INFO.  Note Win2K does
1015  * support *BASIC_INFO on a SET_FILE_INFO, and they support the
1016  * equivalent *BASIC_INFORMATION on SET_PATH_INFO.  Go figure.
1017  */
1018 int
1019 smbfs_smb_setfattrNT(
1020 	struct smbnode *np,
1021 	int fid,		/* if fid == -1, set by path */
1022 	uint32_t attr,
1023 	struct timespec *mtime,
1024 	struct timespec *atime,
1025 	struct smb_cred *scrp)
1026 {
1027 	struct smb_t2rq *t2p;
1028 	struct smb_share *ssp = np->n_mount->smi_share;
1029 	struct smb_vc *vcp = SSTOVC(ssp);
1030 	struct mbchain *mbp;
1031 	uint64_t tm;
1032 	int error;
1033 	uint16_t cmd, level;
1034 
1035 	if (fid == -1) {
1036 		cmd = SMB_TRANS2_SET_PATH_INFORMATION;
1037 	} else {
1038 		if (fid > UINT16_MAX)
1039 			return (EINVAL);
1040 		cmd = SMB_TRANS2_SET_FILE_INFORMATION;
1041 	}
1042 	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
1043 		level = SMB_SFILEINFO_BASIC_INFORMATION;
1044 	else
1045 		level = SMB_SFILEINFO_BASIC_INFO;
1046 
1047 	error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
1048 	if (error)
1049 		return (error);
1050 
1051 	mbp = &t2p->t2_tparam;
1052 	mb_init(mbp);
1053 
1054 	if (cmd == SMB_TRANS2_SET_FILE_INFORMATION)
1055 		mb_put_uint16le(mbp, fid);
1056 
1057 	mb_put_uint16le(mbp, level);
1058 	mb_put_uint32le(mbp, 0);		/* MBZ */
1059 
1060 	if (cmd == SMB_TRANS2_SET_PATH_INFORMATION) {
1061 		error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
1062 		if (error != 0)
1063 			goto out;
1064 	}
1065 
1066 	/* FAT file systems don't support dates earlier than 1980. */
1067 
1068 	mbp = &t2p->t2_tdata;
1069 	mb_init(mbp);
1070 	mb_put_uint64le(mbp, 0);		/* creation time */
1071 	if (atime) {
1072 		smb_time_local2NT(atime, &tm);
1073 		if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
1074 		    tm < NT1980)
1075 			tm = NT1980;
1076 	} else
1077 		tm = 0;
1078 	mb_put_uint64le(mbp, tm);		/* access time */
1079 	if (mtime) {
1080 		smb_time_local2NT(mtime, &tm);
1081 		if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
1082 		    tm < NT1980)
1083 			tm = NT1980;
1084 	} else
1085 		tm = 0;
1086 	mb_put_uint64le(mbp, tm);		/* last write time */
1087 	mb_put_uint64le(mbp, 0);		/* ctime (no change) */
1088 	mb_put_uint32le(mbp, attr);
1089 	mb_put_uint32le(mbp, 0);		/* padding */
1090 	t2p->t2_maxpcount = 2;
1091 	t2p->t2_maxdcount = 0;
1092 	error = smb_t2_request(t2p);
1093 out:
1094 	smb_t2_done(t2p);
1095 	return (error);
1096 }
1097 
1098 /*
1099  * Modern create/open of file or directory.
1100  */
1101 int
1102 smbfs_smb_ntcreatex(
1103 	struct smbnode *np,
1104 	const char *name,
1105 	int nmlen,
1106 	int xattr,		/* is named stream? */
1107 	uint32_t req_acc,	/* requested access */
1108 	uint32_t efa,		/* ext. file attrs (DOS attr +) */
1109 	uint32_t share_acc,
1110 	uint32_t disp,		/* open disposition */
1111 	uint32_t createopt,	/* NTCREATEX_OPTIONS_ */
1112 	struct smb_cred *scrp,
1113 	uint16_t *fidp,		/* returned FID */
1114 	uint32_t *cr_act_p,	/* optional returned create action */
1115 	struct smbfattr *fap)	/* optional returned attributes */
1116 {
1117 	struct mbchain name_mb;
1118 	struct smb_share *ssp = np->n_mount->smi_share;
1119 	int err;
1120 
1121 	mb_init(&name_mb);
1122 
1123 	if (name == NULL)
1124 		nmlen = 0;
1125 	err = smbfs_fullpath(&name_mb, SSTOVC(ssp),
1126 	    np, name, nmlen, xattr ? ':' : '\\');
1127 	if (err)
1128 		goto out;
1129 
1130 	err = smb_smb_ntcreate(ssp, &name_mb,
1131 	    0,	/* NTCREATEX_FLAGS... */
1132 	    req_acc, efa, share_acc, disp, createopt,
1133 	    NTCREATEX_IMPERSONATION_IMPERSONATION,
1134 	    scrp, fidp, cr_act_p, fap);
1135 
1136 out:
1137 	mb_done(&name_mb);
1138 
1139 	return (err);
1140 }
1141 
1142 static uint32_t
1143 smb_mode2rights(int mode)
1144 {
1145 	mode = mode & SMB_AM_OPENMODE;
1146 	uint32_t rights =
1147 	    STD_RIGHT_SYNCHRONIZE_ACCESS |
1148 	    STD_RIGHT_READ_CONTROL_ACCESS;
1149 
1150 	if ((mode == SMB_AM_OPENREAD) ||
1151 	    (mode == SMB_AM_OPENRW)) {
1152 		rights |=
1153 		    SA_RIGHT_FILE_READ_ATTRIBUTES |
1154 		    SA_RIGHT_FILE_READ_DATA;
1155 	}
1156 
1157 	if ((mode == SMB_AM_OPENWRITE) ||
1158 	    (mode == SMB_AM_OPENRW)) {
1159 		rights |=
1160 		    SA_RIGHT_FILE_WRITE_ATTRIBUTES |
1161 		    SA_RIGHT_FILE_APPEND_DATA |
1162 		    SA_RIGHT_FILE_WRITE_DATA;
1163 	}
1164 
1165 	if (mode == SMB_AM_OPENEXEC) {
1166 		rights |=
1167 		    SA_RIGHT_FILE_READ_ATTRIBUTES |
1168 		    SA_RIGHT_FILE_EXECUTE;
1169 	}
1170 
1171 	return (rights);
1172 }
1173 
1174 static int
1175 smb_rights2mode(uint32_t rights)
1176 {
1177 	int accmode = SMB_AM_OPENEXEC; /* our fallback */
1178 
1179 	if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD |
1180 	    SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES |
1181 	    SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS |
1182 	    STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS))
1183 		accmode = SMB_AM_OPENWRITE;
1184 	if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES |
1185 	    SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS))
1186 		accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD
1187 		    : SMB_AM_OPENRW;
1188 	return (accmode);
1189 }
1190 
1191 static int
1192 smbfs_smb_oldopen(
1193 	struct smbnode *np,
1194 	const char *name,
1195 	int nmlen,
1196 	int xattr,
1197 	int accmode,
1198 	struct smb_cred *scrp,
1199 	uint16_t *fidp,
1200 	uint16_t *granted_mode_p,
1201 	smbfattr_t *fap)
1202 {
1203 	struct smb_rq rq, *rqp = &rq;
1204 	struct smb_share *ssp = np->n_mount->smi_share;
1205 	struct smb_vc *vcp = SSTOVC(ssp);
1206 	struct mbchain *mbp;
1207 	struct mdchain *mdp;
1208 	struct smbfattr fa;
1209 	uint8_t wc;
1210 	uint16_t wattr;
1211 	uint32_t longint;
1212 	int error;
1213 
1214 	bzero(&fa, sizeof (fa));
1215 
1216 	/*
1217 	 * XXX: move to callers...
1218 	 *
1219 	 * Use DENYNONE to give unixy semantics of permitting
1220 	 * everything not forbidden by permissions.  Ie denial
1221 	 * is up to server with clients/openers needing to use
1222 	 * advisory locks for further control.
1223 	 */
1224 	accmode |= SMB_SM_DENYNONE;
1225 
1226 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp);
1227 	if (error)
1228 		return (error);
1229 	smb_rq_getrequest(rqp, &mbp);
1230 	smb_rq_wstart(rqp);
1231 	mb_put_uint16le(mbp, accmode);
1232 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY |
1233 	    SMB_FA_DIR);
1234 	smb_rq_wend(rqp);
1235 	smb_rq_bstart(rqp);
1236 	mb_put_uint8(mbp, SMB_DT_ASCII);
1237 
1238 	error = smbfs_fullpath(mbp, vcp, np, name, nmlen,
1239 	    xattr ? ':' : '\\');
1240 	if (error)
1241 		goto done;
1242 	smb_rq_bend(rqp);
1243 	/*
1244 	 * Don't want to risk missing a successful
1245 	 * open response, or we could "leak" FIDs.
1246 	 */
1247 	rqp->sr_flags |= SMBR_NOINTR_RECV;
1248 	error = smb_rq_simple_timed(rqp, smb_timo_open);
1249 	if (error)
1250 		goto done;
1251 	smb_rq_getreply(rqp, &mdp);
1252 	/*
1253 	 * 8/2002 a DAVE server returned wc of 15 so we ignore that.
1254 	 * (the actual packet length and data was correct)
1255 	 */
1256 	error = md_get_uint8(mdp, &wc);
1257 	if (error)
1258 		goto done;
1259 	if (wc != 7 && wc != 15) {
1260 		error = EBADRPC;
1261 		goto done;
1262 	}
1263 	md_get_uint16le(mdp, fidp);
1264 	md_get_uint16le(mdp, &wattr);
1265 	fa.fa_attr = wattr;
1266 	/*
1267 	 * Be careful using the time returned here, as
1268 	 * with FAT on NT4SP6, at least, the time returned is low
1269 	 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
1270 	 * over about every seven minutes!
1271 	 */
1272 	md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
1273 	smb_time_server2local(longint, vcp->vc_sopt.sv_tz, &fa.fa_mtime);
1274 	md_get_uint32le(mdp, &longint);
1275 	fa.fa_size = longint;
1276 	error = md_get_uint16le(mdp, granted_mode_p);
1277 
1278 done:
1279 	smb_rq_done(rqp);
1280 	if (error)
1281 		return (error);
1282 
1283 	if (fap)
1284 		*fap = fa; /* struct copy */
1285 
1286 	return (0);
1287 }
1288 
1289 int
1290 smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
1291 			uint16_t *fidp)
1292 {
1293 	struct smb_share *ssp = np->n_mount->smi_share;
1294 	struct smb_vc *vcp = SSTOVC(ssp);
1295 	int accmode, error;
1296 
1297 	/* Shared lock for n_fid use below. */
1298 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
1299 
1300 	/* Can we re-use n_fid? or must we open anew? */
1301 	mutex_enter(&np->r_statelock);
1302 	if (np->n_fidrefs > 0 &&
1303 	    np->n_vcgenid == ssp->ss_vcgenid &&
1304 	    (rights & np->n_rights) == rights) {
1305 		np->n_fidrefs++;
1306 		*fidp = np->n_fid;
1307 		mutex_exit(&np->r_statelock);
1308 		return (0);
1309 	}
1310 	mutex_exit(&np->r_statelock);
1311 
1312 	/* re-open an existing file. */
1313 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1314 		error = smbfs_smb_ntcreatex(np,
1315 		    NULL, 0, 0,	/* name nmlen xattr */
1316 		    rights, SMB_EFA_NORMAL,
1317 		    NTCREATEX_SHARE_ACCESS_ALL,
1318 		    NTCREATEX_DISP_OPEN,
1319 		    0, /* create options */
1320 		    scrp, fidp,
1321 		    NULL, NULL); /* cr_act_p fa_p */
1322 		return (error);
1323 	}
1324 
1325 	accmode = smb_rights2mode(rights);
1326 	error = smbfs_smb_oldopen(np,
1327 	    NULL, 0, 0, /* name nmlen xattr */
1328 	    accmode, scrp,
1329 	    fidp,
1330 	    NULL, /* granted mode p */
1331 	    NULL); /* fa p */
1332 
1333 	return (error);
1334 }
1335 
1336 int
1337 smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp)
1338 {
1339 	struct smb_share *ssp = np->n_mount->smi_share;
1340 	int error = 0;
1341 	uint16_t oldfid = SMB_FID_UNUSED;
1342 
1343 	/* Shared lock for n_fid use below. */
1344 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
1345 
1346 	mutex_enter(&np->r_statelock);
1347 	if (fid == np->n_fid) {
1348 		ASSERT(np->n_fidrefs > 0);
1349 		if (--np->n_fidrefs == 0) {
1350 			/*
1351 			 * Don't expect to find the last reference
1352 			 * here in tmpclose.  Hard to deal with as
1353 			 * we don't have r_lkserlock exclusive.
1354 			 * Will close oldfid below.
1355 			 */
1356 			oldfid = np->n_fid;
1357 			np->n_fid = SMB_FID_UNUSED;
1358 		}
1359 	} else {
1360 		/* Will close the passed fid. */
1361 		oldfid = fid;
1362 	}
1363 	mutex_exit(&np->r_statelock);
1364 
1365 	if (oldfid != SMB_FID_UNUSED)
1366 		error = smbfs_smb_close(ssp, oldfid, NULL, scrp);
1367 
1368 	return (error);
1369 }
1370 
1371 int
1372 smbfs_smb_open(
1373 	struct smbnode *np,
1374 	const char *name,
1375 	int nmlen,
1376 	int xattr,
1377 	uint32_t rights,
1378 	struct smb_cred *scrp,
1379 	uint16_t *fidp,
1380 	uint32_t *rightsp,
1381 	smbfattr_t *fap)
1382 {
1383 	struct smb_share *ssp = np->n_mount->smi_share;
1384 	struct smb_vc *vcp = SSTOVC(ssp);
1385 	int accmode, error;
1386 	uint16_t grantedmode;
1387 
1388 	/* open an existing file */
1389 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1390 		error = smbfs_smb_ntcreatex(np,
1391 		    name, nmlen, xattr,
1392 		    rights, SMB_EFA_NORMAL,
1393 		    NTCREATEX_SHARE_ACCESS_ALL,
1394 		    NTCREATEX_DISP_OPEN,
1395 		    0, /* create options */
1396 		    scrp, fidp,
1397 		    NULL, fap); /* cr_act_p fa_p */
1398 		if (error != 0)
1399 			return (error);
1400 		*rightsp = rights;
1401 		return (0);
1402 	}
1403 
1404 	accmode = smb_rights2mode(rights);
1405 	error = smbfs_smb_oldopen(np,
1406 	    name, nmlen, xattr, accmode, scrp,
1407 	    fidp, &grantedmode, fap);
1408 	if (error != 0)
1409 		return (error);
1410 	*rightsp = smb_mode2rights(grantedmode);
1411 	(void) smbfs_smb_getfattr(np, fap, scrp);
1412 
1413 	return (0);
1414 }
1415 
1416 int
1417 smbfs_smb_close(struct smb_share *ssp, uint16_t fid,
1418 	struct timespec *mtime,	struct smb_cred *scrp)
1419 {
1420 	int error;
1421 
1422 	error = smb_smb_close(ssp, fid, mtime, scrp);
1423 
1424 	/*
1425 	 * ENOTCONN isn't interesting - if the connection is closed,
1426 	 * so are all our FIDs - and EIO is also not interesting,
1427 	 * as it means a forced unmount was done. (was ENXIO)
1428 	 * Also ETIME, which means we sent the request but gave up
1429 	 * waiting before the response came back.
1430 	 *
1431 	 * Don't clog up the system log with warnings about these
1432 	 * uninteresting failures on closes.
1433 	 */
1434 	switch (error) {
1435 	case ENOTCONN:
1436 	case ENXIO:
1437 	case EIO:
1438 	case ETIME:
1439 		error = 0;
1440 	}
1441 	return (error);
1442 }
1443 
1444 static int
1445 smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen,
1446 	int xattr, struct smb_cred *scrp, uint16_t *fidp)
1447 {
1448 	struct smb_rq rq, *rqp = &rq;
1449 	struct smb_share *ssp = dnp->n_mount->smi_share;
1450 	struct mbchain *mbp;
1451 	struct mdchain *mdp;
1452 	struct timespec ctime;
1453 	uint8_t wc;
1454 	long tm;
1455 	int error;
1456 	uint16_t attr = SMB_FA_ARCHIVE;
1457 
1458 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp);
1459 	if (error)
1460 		return (error);
1461 	smb_rq_getrequest(rqp, &mbp);
1462 	smb_rq_wstart(rqp);
1463 	if (name && *name == '.')
1464 		attr |= SMB_FA_HIDDEN;
1465 	mb_put_uint16le(mbp, attr);		/* attributes  */
1466 	gethrestime(&ctime);
1467 	smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
1468 	mb_put_uint32le(mbp, tm);
1469 	smb_rq_wend(rqp);
1470 	smb_rq_bstart(rqp);
1471 	mb_put_uint8(mbp, SMB_DT_ASCII);
1472 	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen,
1473 	    xattr ? ':' : '\\');
1474 	if (error)
1475 		goto out;
1476 	smb_rq_bend(rqp);
1477 	/*
1478 	 * Don't want to risk missing a successful
1479 	 * open response, or we could "leak" FIDs.
1480 	 */
1481 	rqp->sr_flags |= SMBR_NOINTR_RECV;
1482 	error = smb_rq_simple_timed(rqp, smb_timo_open);
1483 	if (error)
1484 		goto out;
1485 
1486 	smb_rq_getreply(rqp, &mdp);
1487 	md_get_uint8(mdp, &wc);
1488 	if (wc != 1) {
1489 		error = EBADRPC;
1490 		goto out;
1491 	}
1492 	error = md_get_uint16le(mdp, fidp);
1493 
1494 out:
1495 	smb_rq_done(rqp);
1496 	return (error);
1497 }
1498 
1499 int
1500 smbfs_smb_create(
1501 	struct smbnode *dnp,
1502 	const char *name,
1503 	int nmlen,
1504 	int xattr,
1505 	uint32_t disp,
1506 	struct smb_cred *scrp,
1507 	uint16_t *fidp)
1508 {
1509 	struct smb_share *ssp = dnp->n_mount->smi_share;
1510 	struct smb_vc *vcp = SSTOVC(ssp);
1511 	uint32_t efa, rights;
1512 	int error;
1513 
1514 	/*
1515 	 * At present the only access we might need is to WRITE data,
1516 	 * and that only if we are creating a "symlink".  When/if the
1517 	 * access needed gets more complex it should made a parameter
1518 	 * and be set upstream.
1519 	 */
1520 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1521 		rights = SA_RIGHT_FILE_WRITE_DATA;
1522 		efa = SMB_EFA_NORMAL;
1523 		if (!xattr && name && *name == '.')
1524 			efa = SMB_EFA_HIDDEN;
1525 		error = smbfs_smb_ntcreatex(dnp,
1526 		    name, nmlen, xattr, rights, efa,
1527 		    NTCREATEX_SHARE_ACCESS_ALL,
1528 		    disp, /* != NTCREATEX_DISP_OPEN */
1529 		    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
1530 		    scrp, fidp, NULL, NULL); /* cr_act_p fa_p */
1531 		return (error);
1532 	}
1533 
1534 	error = smbfs_smb_oldcreate(dnp, name, nmlen, xattr, scrp, fidp);
1535 	return (error);
1536 }
1537 
1538 int
1539 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name,
1540 			int nmlen, int xattr)
1541 {
1542 	struct smb_rq rq, *rqp = &rq;
1543 	struct smb_share *ssp = np->n_mount->smi_share;
1544 	struct mbchain *mbp;
1545 	int error;
1546 
1547 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp);
1548 	if (error)
1549 		return (error);
1550 	smb_rq_getrequest(rqp, &mbp);
1551 	smb_rq_wstart(rqp);
1552 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
1553 	smb_rq_wend(rqp);
1554 	smb_rq_bstart(rqp);
1555 	mb_put_uint8(mbp, SMB_DT_ASCII);
1556 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, nmlen,
1557 	    xattr ? ':' : '\\');
1558 	if (!error) {
1559 		smb_rq_bend(rqp);
1560 		error = smb_rq_simple(rqp);
1561 	}
1562 	smb_rq_done(rqp);
1563 	return (error);
1564 }
1565 
1566 int
1567 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
1568 	const char *tname, int tnmlen, struct smb_cred *scrp)
1569 {
1570 	struct smb_rq rq, *rqp = &rq;
1571 	struct smb_share *ssp = src->n_mount->smi_share;
1572 	struct mbchain *mbp;
1573 	int error;
1574 	uint16_t fa;
1575 	char sep;
1576 
1577 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
1578 	if (error)
1579 		return (error);
1580 	smb_rq_getrequest(rqp, &mbp);
1581 	smb_rq_wstart(rqp);
1582 	/* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
1583 	fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
1584 	fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
1585 	mb_put_uint16le(mbp, fa);
1586 	smb_rq_wend(rqp);
1587 	smb_rq_bstart(rqp);
1588 
1589 	/*
1590 	 * When we're not adding any component name, the
1591 	 * passed sep is ignored, so just pass sep=0.
1592 	 */
1593 	mb_put_uint8(mbp, SMB_DT_ASCII);
1594 	error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0);
1595 	if (error)
1596 		goto out;
1597 
1598 	/*
1599 	 * After XATTR directories, separator is ":"
1600 	 */
1601 	sep = (src->n_flag & N_XATTR) ? ':' : '\\';
1602 	mb_put_uint8(mbp, SMB_DT_ASCII);
1603 	error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, sep);
1604 	if (error)
1605 		goto out;
1606 
1607 	smb_rq_bend(rqp);
1608 	error = smb_rq_simple(rqp);
1609 out:
1610 	smb_rq_done(rqp);
1611 	return (error);
1612 }
1613 
1614 int
1615 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
1616 	const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp)
1617 {
1618 	struct smb_rq rq, *rqp = &rq;
1619 	struct smb_share *ssp = src->n_mount->smi_share;
1620 	struct mbchain *mbp;
1621 	int error;
1622 
1623 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp);
1624 	if (error)
1625 		return (error);
1626 	smb_rq_getrequest(rqp, &mbp);
1627 	smb_rq_wstart(rqp);
1628 	mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
1629 	mb_put_uint16le(mbp, 0x20);	/* delete target file */
1630 	mb_put_uint16le(mbp, flags);
1631 	smb_rq_wend(rqp);
1632 	smb_rq_bstart(rqp);
1633 	mb_put_uint8(mbp, SMB_DT_ASCII);
1634 
1635 	error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, '\\');
1636 	if (error)
1637 		goto out;
1638 	mb_put_uint8(mbp, SMB_DT_ASCII);
1639 	error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, '\\');
1640 	if (error)
1641 		goto out;
1642 	smb_rq_bend(rqp);
1643 	error = smb_rq_simple(rqp);
1644 
1645 out:
1646 	smb_rq_done(rqp);
1647 	return (error);
1648 }
1649 
1650 static int
1651 smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len,
1652 			struct smb_cred *scrp)
1653 {
1654 	struct smb_rq rq, *rqp = &rq;
1655 	struct smb_share *ssp = dnp->n_mount->smi_share;
1656 	struct mbchain *mbp;
1657 	int error;
1658 
1659 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp);
1660 	if (error)
1661 		return (error);
1662 	smb_rq_getrequest(rqp, &mbp);
1663 	smb_rq_wstart(rqp);
1664 	smb_rq_wend(rqp);
1665 	smb_rq_bstart(rqp);
1666 	mb_put_uint8(mbp, SMB_DT_ASCII);
1667 	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len, '\\');
1668 	if (!error) {
1669 		smb_rq_bend(rqp);
1670 		error = smb_rq_simple(rqp);
1671 	}
1672 	smb_rq_done(rqp);
1673 	return (error);
1674 }
1675 
1676 int
1677 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen,
1678 		struct smb_cred *scrp)
1679 {
1680 	struct smb_share *ssp = dnp->n_mount->smi_share;
1681 	struct smb_vc *vcp = SSTOVC(ssp);
1682 	uint32_t rights;
1683 	uint16_t fid;
1684 	int error;
1685 
1686 	/*
1687 	 * We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
1688 	 * just to be asking for something.  The rights==0 case could
1689 	 * easily be broken on some old or unusual servers.
1690 	 */
1691 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1692 		rights = SA_RIGHT_FILE_READ_DATA;
1693 		error = smbfs_smb_ntcreatex(dnp,
1694 		    name, nmlen, 0, /* xattr */
1695 		    rights, SMB_EFA_DIRECTORY,
1696 		    NTCREATEX_SHARE_ACCESS_ALL,
1697 		    NTCREATEX_DISP_CREATE,
1698 		    NTCREATEX_OPTIONS_DIRECTORY,
1699 		    scrp, &fid, NULL, NULL); /* cr_act_p fa_p */
1700 		if (error)
1701 			return (error);
1702 		(void) smbfs_smb_close(ssp, fid, NULL, scrp);
1703 		return (0);
1704 	}
1705 
1706 	error = smbfs_smb_oldmkdir(dnp, name, nmlen, scrp);
1707 	return (error);
1708 }
1709 
1710 int
1711 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp)
1712 {
1713 	struct smb_rq rq, *rqp = &rq;
1714 	struct smb_share *ssp = np->n_mount->smi_share;
1715 	struct mbchain *mbp;
1716 	int error;
1717 
1718 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp);
1719 	if (error)
1720 		return (error);
1721 	smb_rq_getrequest(rqp, &mbp);
1722 	smb_rq_wstart(rqp);
1723 	smb_rq_wend(rqp);
1724 	smb_rq_bstart(rqp);
1725 	mb_put_uint8(mbp, SMB_DT_ASCII);
1726 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0, '\\');
1727 	if (!error) {
1728 		smb_rq_bend(rqp);
1729 		error = smb_rq_simple(rqp);
1730 	}
1731 	smb_rq_done(rqp);
1732 	return (error);
1733 }
1734 
1735 static int
1736 smbfs_smb_search(struct smbfs_fctx *ctx)
1737 {
1738 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1739 	struct smb_rq *rqp;
1740 	struct mbchain *mbp;
1741 	struct mdchain *mdp;
1742 	uint8_t wc, bt;
1743 	uint16_t ec, dlen, bc;
1744 	int maxent, error, iseof = 0;
1745 
1746 	maxent = min(ctx->f_left,
1747 	    (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN);
1748 	if (ctx->f_rq) {
1749 		smb_rq_done(ctx->f_rq);
1750 		ctx->f_rq = NULL;
1751 	}
1752 	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH,
1753 	    ctx->f_scred, &rqp);
1754 	if (error)
1755 		return (error);
1756 	ctx->f_rq = rqp;
1757 	smb_rq_getrequest(rqp, &mbp);
1758 	smb_rq_wstart(rqp);
1759 	mb_put_uint16le(mbp, maxent);	/* max entries to return */
1760 	mb_put_uint16le(mbp, ctx->f_attrmask);
1761 	smb_rq_wend(rqp);
1762 	smb_rq_bstart(rqp);
1763 	mb_put_uint8(mbp, SMB_DT_ASCII);	/* buffer format */
1764 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1765 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
1766 		    ctx->f_wildcard, ctx->f_wclen, '\\');
1767 		if (error)
1768 			return (error);
1769 		mb_put_uint8(mbp, SMB_DT_VARIABLE);
1770 		mb_put_uint16le(mbp, 0);	/* context length */
1771 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
1772 	} else {
1773 		if (SMB_UNICODE_STRINGS(vcp)) {
1774 			mb_put_padbyte(mbp);
1775 			mb_put_uint8(mbp, 0);
1776 		}
1777 		mb_put_uint8(mbp, 0);
1778 		mb_put_uint8(mbp, SMB_DT_VARIABLE);
1779 		mb_put_uint16le(mbp, SMB_SKEYLEN);
1780 		mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
1781 	}
1782 	smb_rq_bend(rqp);
1783 	error = smb_rq_simple(rqp);
1784 	if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
1785 		error = 0;
1786 		iseof = 1;
1787 		ctx->f_flags |= SMBFS_RDD_EOF;
1788 	} else if (error)
1789 		return (error);
1790 	smb_rq_getreply(rqp, &mdp);
1791 	error = md_get_uint8(mdp, &wc);
1792 	if (error)
1793 		return (error);
1794 	if (wc != 1)
1795 		return (iseof ? ENOENT : EBADRPC);
1796 	md_get_uint16le(mdp, &ec);
1797 	md_get_uint16le(mdp, &bc);
1798 	md_get_uint8(mdp, &bt);
1799 	error = md_get_uint16le(mdp, &dlen);
1800 	if (error)
1801 		return (error);
1802 	if (ec == 0)
1803 		return (ENOENT);
1804 	ctx->f_ecnt = ec;
1805 	if (bc < 3)
1806 		return (EBADRPC);
1807 	bc -= 3;
1808 	if (bt != SMB_DT_VARIABLE)
1809 		return (EBADRPC);
1810 	if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
1811 		return (EBADRPC);
1812 	return (0);
1813 }
1814 
1815 
1816 /*ARGSUSED*/
1817 static int
1818 smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
1819     const char *wildcard, int wclen, uint16_t attr)
1820 {
1821 
1822 	ctx->f_type = ft_LM1;
1823 	ctx->f_attrmask = attr;
1824 	if (wildcard) {
1825 		if (wclen == 1 && wildcard[0] == '*') {
1826 			ctx->f_wildcard = "*.*";
1827 			ctx->f_wclen = 3;
1828 		} else {
1829 			ctx->f_wildcard = wildcard;
1830 			ctx->f_wclen = wclen;
1831 		}
1832 	} else {
1833 		ctx->f_wildcard = NULL;
1834 		ctx->f_wclen = 0;
1835 	}
1836 	ctx->f_name = (char *)ctx->f_fname;
1837 	ctx->f_namesz = 0;
1838 	return (0);
1839 }
1840 
1841 static int
1842 smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit)
1843 {
1844 	struct mdchain *mdp;
1845 	struct smb_rq *rqp;
1846 	char *cp;
1847 	uint8_t battr;
1848 	uint16_t date, time;
1849 	uint32_t size;
1850 	int error;
1851 	struct timespec ts;
1852 
1853 	if (ctx->f_ecnt == 0) {
1854 		if (ctx->f_flags & SMBFS_RDD_EOF)
1855 			return (ENOENT);
1856 		ctx->f_left = ctx->f_limit = limit;
1857 		gethrestime(&ts);
1858 		error = smbfs_smb_search(ctx);
1859 		if (error)
1860 			return (error);
1861 	}
1862 	rqp = ctx->f_rq;
1863 	smb_rq_getreply(rqp, &mdp);
1864 	md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
1865 	md_get_uint8(mdp, &battr);
1866 	md_get_uint16le(mdp, &time);
1867 	md_get_uint16le(mdp, &date);
1868 	md_get_uint32le(mdp, &size);
1869 	cp = ctx->f_name;
1870 	error = md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM);
1871 	cp[sizeof (ctx->f_fname) - 1] = 0;
1872 	cp += strlen(cp) - 1;
1873 	while (*cp == ' ' && cp >= ctx->f_name)
1874 		*cp-- = 0;
1875 	ctx->f_attr.fa_attr = battr;
1876 	smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
1877 	    &ctx->f_attr.fa_mtime);
1878 	ctx->f_attr.fa_size = size;
1879 	ctx->f_nmlen = strlen(ctx->f_name);
1880 	ctx->f_ecnt--;
1881 	ctx->f_left--;
1882 	return (0);
1883 }
1884 
1885 static int
1886 smbfs_smb_findcloseLM1(struct smbfs_fctx *ctx)
1887 {
1888 	if (ctx->f_rq)
1889 		smb_rq_done(ctx->f_rq);
1890 	return (0);
1891 }
1892 
1893 /*
1894  * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
1895  */
1896 static int
1897 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
1898 {
1899 	struct smb_t2rq *t2p;
1900 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1901 	struct mbchain *mbp;
1902 	struct mdchain *mdp;
1903 	uint16_t ecnt, eos, lno, flags;
1904 	int error;
1905 
1906 	if (ctx->f_t2) {
1907 		smb_t2_done(ctx->f_t2);
1908 		ctx->f_t2 = NULL;
1909 	}
1910 	flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
1911 	if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
1912 		flags |= FIND2_CLOSE_AFTER_REQUEST;
1913 		ctx->f_flags |= SMBFS_RDD_NOCLOSE;
1914 	}
1915 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1916 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
1917 		    ctx->f_scred, &t2p);
1918 		if (error)
1919 			return (error);
1920 		ctx->f_t2 = t2p;
1921 		mbp = &t2p->t2_tparam;
1922 		mb_init(mbp);
1923 		mb_put_uint16le(mbp, ctx->f_attrmask);
1924 		mb_put_uint16le(mbp, ctx->f_limit);
1925 		mb_put_uint16le(mbp, flags);
1926 		mb_put_uint16le(mbp, ctx->f_infolevel);
1927 		mb_put_uint32le(mbp, 0);
1928 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
1929 		    ctx->f_wildcard, ctx->f_wclen, '\\');
1930 		if (error)
1931 			return (error);
1932 	} else	{
1933 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
1934 		    ctx->f_scred, &t2p);
1935 		if (error)
1936 			return (error);
1937 		ctx->f_t2 = t2p;
1938 		mbp = &t2p->t2_tparam;
1939 		mb_init(mbp);
1940 		mb_put_uint16le(mbp, ctx->f_Sid);
1941 		mb_put_uint16le(mbp, ctx->f_limit);
1942 		mb_put_uint16le(mbp, ctx->f_infolevel);
1943 		/* Send whatever resume key we received... */
1944 		mb_put_uint32le(mbp, ctx->f_rkey);
1945 		mb_put_uint16le(mbp, flags);
1946 		/* ... and the resume name if we have one. */
1947 		if (ctx->f_rname) {
1948 			/* resume file name */
1949 			mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
1950 			    MB_MSYSTEM);
1951 		}
1952 		/* Add trailing null - 1 byte if ASCII, 2 if Unicode */
1953 		if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
1954 			mb_put_uint8(mbp, 0);	/* 1st byte NULL Unicode char */
1955 		mb_put_uint8(mbp, 0);
1956 	}
1957 	t2p->t2_maxpcount = 5 * 2;
1958 	t2p->t2_maxdcount = 0xF000;	/* 64K less some overhead */
1959 	error = smb_t2_request(t2p);
1960 	if (error)
1961 		return (error);
1962 
1963 	/*
1964 	 * This is the "resume name" we just sent.
1965 	 * We want the new one (if any) that may be
1966 	 * found in the response we just received and
1967 	 * will now begin parsing.  Free the old one
1968 	 * now so we'll know if we found a new one.
1969 	 */
1970 	if (ctx->f_rname) {
1971 		kmem_free(ctx->f_rname, ctx->f_rnamelen);
1972 		ctx->f_rname = NULL;
1973 		ctx->f_rnamelen = 0;
1974 	}
1975 
1976 	mdp = &t2p->t2_rparam;
1977 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1978 		if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0)
1979 			goto nodata;
1980 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
1981 	}
1982 	md_get_uint16le(mdp, &ecnt);		/* entry count */
1983 	md_get_uint16le(mdp, &eos);		/* end of search */
1984 	md_get_uint16le(mdp, NULL);		/* EA err. off. */
1985 	error = md_get_uint16le(mdp, &lno);	/* last name off. */
1986 	if (error != 0)
1987 		goto nodata;
1988 
1989 	/*
1990 	 * The "end of search" flag from an XP server sometimes
1991 	 * comes back zero when the prior find_next returned exactly
1992 	 * the number of entries requested.  in which case we'd try again
1993 	 * but the search has in fact been closed so an EBADF results.
1994 	 * our circumvention is to check here for a zero entry count.
1995 	 */
1996 	ctx->f_ecnt = ecnt;
1997 	if (eos || ctx->f_ecnt == 0)
1998 		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1999 	if (ctx->f_ecnt == 0)
2000 		return (ENOENT);
2001 
2002 	/* Last Name Off (LNO) is the entry with the resume name. */
2003 	ctx->f_rnameofs = lno;
2004 	ctx->f_eofs = 0;
2005 	return (0);
2006 
2007 nodata:
2008 	/*
2009 	 * Failed parsing the FindFirst or FindNext response.
2010 	 * Force this directory listing closed, otherwise the
2011 	 * calling process may hang in an infinite loop.
2012 	 */
2013 	ctx->f_ecnt = 0; /* Force closed. */
2014 	ctx->f_flags |= SMBFS_RDD_EOF;
2015 	return (EIO);
2016 }
2017 
2018 static int
2019 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
2020 {
2021 	struct smb_rq rq, *rqp = &rq;
2022 	struct mbchain *mbp;
2023 	int error;
2024 
2025 	error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
2026 	    ctx->f_scred);
2027 	if (error)
2028 		return (error);
2029 	smb_rq_getrequest(rqp, &mbp);
2030 	smb_rq_wstart(rqp);
2031 	mb_put_uint16le(mbp, ctx->f_Sid);
2032 	smb_rq_wend(rqp);
2033 	smb_rq_bstart(rqp);
2034 	smb_rq_bend(rqp);
2035 	/* Ditto comments at _smb_close */
2036 	rqp->sr_flags |= SMBR_NOINTR_SEND;
2037 	error = smb_rq_simple(rqp);
2038 	smb_rq_done(rqp);
2039 	return (error);
2040 }
2041 
2042 /*ARGSUSED*/
2043 static int
2044 smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
2045     const char *wildcard, int wclen, uint16_t attr)
2046 {
2047 
2048 	ctx->f_type = ft_LM2;
2049 	ctx->f_namesz = SMB_MAXFNAMELEN + 1;
2050 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2051 		ctx->f_namesz *= 2;
2052 	ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
2053 	ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp))
2054 	    < SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD :
2055 	    SMB_FIND_BOTH_DIRECTORY_INFO;
2056 	ctx->f_attrmask = attr;
2057 	ctx->f_wildcard = wildcard;
2058 	ctx->f_wclen = wclen;
2059 	return (0);
2060 }
2061 
2062 static int
2063 smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
2064 {
2065 	struct mdchain *mdp;
2066 	struct smb_t2rq *t2p;
2067 	char *cp;
2068 	uint8_t tb;
2069 	uint16_t date, time, wattr;
2070 	uint32_t size, next, dattr, resumekey = 0;
2071 	uint64_t llongint;
2072 	int error, svtz, cnt, fxsz, nmlen, recsz;
2073 	struct timespec ts;
2074 
2075 	if (ctx->f_ecnt == 0) {
2076 		if (ctx->f_flags & SMBFS_RDD_EOF)
2077 			return (ENOENT);
2078 		ctx->f_left = ctx->f_limit = limit;
2079 		gethrestime(&ts);
2080 		error = smbfs_smb_trans2find2(ctx);
2081 		if (error)
2082 			return (error);
2083 		ctx->f_otws++;
2084 	}
2085 	t2p = ctx->f_t2;
2086 	mdp = &t2p->t2_rdata;
2087 	svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
2088 	switch (ctx->f_infolevel) {
2089 	case SMB_FIND_STANDARD:
2090 		next = 0;
2091 		fxsz = 0;
2092 		md_get_uint16le(mdp, &date);
2093 		md_get_uint16le(mdp, &time);	/* creation time */
2094 		smb_dos2unixtime(date, time, 0, svtz,
2095 		    &ctx->f_attr.fa_createtime);
2096 		md_get_uint16le(mdp, &date);
2097 		md_get_uint16le(mdp, &time);	/* access time */
2098 		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
2099 		md_get_uint16le(mdp, &date);
2100 		md_get_uint16le(mdp, &time);	/* modify time */
2101 		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
2102 		md_get_uint32le(mdp, &size);
2103 		ctx->f_attr.fa_size = size;
2104 		md_get_uint32le(mdp, &size);	/* allocation size */
2105 		ctx->f_attr.fa_allocsz = size;
2106 		md_get_uint16le(mdp, &wattr);
2107 		ctx->f_attr.fa_attr = wattr;
2108 		error = md_get_uint8(mdp, &tb);
2109 		if (error)
2110 			goto nodata;
2111 		size = nmlen = tb;
2112 		fxsz = 23;
2113 		recsz = next = 24 + nmlen;	/* docs misses zero byte @end */
2114 		break;
2115 	case SMB_FIND_DIRECTORY_INFO:
2116 	case SMB_FIND_BOTH_DIRECTORY_INFO:
2117 		md_get_uint32le(mdp, &next);
2118 		md_get_uint32le(mdp, &resumekey); /* file index (resume key) */
2119 		md_get_uint64le(mdp, &llongint);	/* creation time */
2120 		smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime);
2121 		md_get_uint64le(mdp, &llongint);
2122 		smb_time_NT2local(llongint, &ctx->f_attr.fa_atime);
2123 		md_get_uint64le(mdp, &llongint);
2124 		smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime);
2125 		md_get_uint64le(mdp, &llongint);
2126 		smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime);
2127 		md_get_uint64le(mdp, &llongint);	/* file size */
2128 		ctx->f_attr.fa_size = llongint;
2129 		md_get_uint64le(mdp, &llongint);	/* alloc. size */
2130 		ctx->f_attr.fa_allocsz = llongint;
2131 		md_get_uint32le(mdp, &dattr);	/* ext. file attributes */
2132 		ctx->f_attr.fa_attr = dattr;
2133 		error = md_get_uint32le(mdp, &size);	/* name len */
2134 		if (error)
2135 			goto nodata;
2136 		fxsz = 64; /* size ofinfo up to filename */
2137 		if (ctx->f_infolevel == SMB_FIND_BOTH_DIRECTORY_INFO) {
2138 			/*
2139 			 * Skip EaSize(4 bytes), a byte of ShortNameLength,
2140 			 * a reserved byte, and ShortName(8.3 means 24 bytes,
2141 			 * as Leach defined it to always be Unicode)
2142 			 */
2143 			error = md_get_mem(mdp, NULL, 30, MB_MSYSTEM);
2144 			if (error)
2145 				goto nodata;
2146 			fxsz += 30;
2147 		}
2148 		recsz = next ? next : fxsz + size;
2149 		break;
2150 	default:
2151 		SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
2152 		return (EINVAL);
2153 	}
2154 
2155 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2156 		nmlen = min(size, SMB_MAXFNAMELEN * 2);
2157 	else
2158 		nmlen = min(size, SMB_MAXFNAMELEN);
2159 
2160 	/* Allocated f_name in findopen */
2161 	ASSERT(nmlen < ctx->f_namesz);
2162 	cp = ctx->f_name;
2163 
2164 	error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM);
2165 	if (error)
2166 		goto nodata;
2167 	if (next) {
2168 		/* How much data to skip? */
2169 		cnt = next - nmlen - fxsz;
2170 		if (cnt < 0) {
2171 			SMBVDEBUG("out of sync\n");
2172 			goto nodata;
2173 		}
2174 		if (cnt > 0)
2175 			md_get_mem(mdp, NULL, cnt, MB_MSYSTEM);
2176 	}
2177 	/* Don't count any trailing null in the name. */
2178 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
2179 		if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
2180 			nmlen -= 2;
2181 	} else {
2182 		if (nmlen && cp[nmlen - 1] == 0)
2183 			nmlen--;
2184 	}
2185 	if (nmlen == 0)
2186 		goto nodata;
2187 
2188 	/*
2189 	 * On a find-next we expect that the server will:
2190 	 * 1) if the continue bit is set, use the server's offset,
2191 	 * 2) else if the resume key is non-zero, use that offset,
2192 	 * 3) else if the resume name is set, use that offset,
2193 	 * 4) else use the server's idea of current offset.
2194 	 *
2195 	 * We always set the resume key flag. If the server returns
2196 	 * a resume key then we should always send it back to them.
2197 	 */
2198 	ctx->f_rkey = resumekey;
2199 
2200 	next = ctx->f_eofs + recsz;
2201 	if (ctx->f_rnameofs &&
2202 	    ctx->f_rnameofs >= ctx->f_eofs &&
2203 	    ctx->f_rnameofs < (int)next) {
2204 		/*
2205 		 * This entry is the "resume name".
2206 		 * Save it for the next request.
2207 		 */
2208 		if (ctx->f_rnamelen != nmlen) {
2209 			if (ctx->f_rname)
2210 				kmem_free(ctx->f_rname, ctx->f_rnamelen);
2211 			ctx->f_rname = kmem_alloc(nmlen, KM_SLEEP);
2212 			ctx->f_rnamelen = nmlen;
2213 		}
2214 		bcopy(ctx->f_name, ctx->f_rname, nmlen);
2215 	}
2216 	ctx->f_nmlen = nmlen;
2217 	ctx->f_eofs = next;
2218 	ctx->f_ecnt--;
2219 	ctx->f_left--;
2220 
2221 	smbfs_fname_tolocal(ctx);
2222 	return (0);
2223 
2224 nodata:
2225 	/*
2226 	 * Something bad has happened and we ran out of data
2227 	 * before we could parse all f_ecnt entries expected.
2228 	 * Force this directory listing closed, otherwise the
2229 	 * calling process may hang in an infinite loop.
2230 	 */
2231 	SMBVDEBUG("ran out of data\n");
2232 	ctx->f_ecnt = 0; /* Force closed. */
2233 	ctx->f_flags |= SMBFS_RDD_EOF;
2234 	return (EIO);
2235 }
2236 
2237 static int
2238 smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
2239 {
2240 	int error = 0;
2241 	if (ctx->f_name)
2242 		kmem_free(ctx->f_name, ctx->f_namesz);
2243 	if (ctx->f_t2)
2244 		smb_t2_done(ctx->f_t2);
2245 	/*
2246 	 * If SMBFS_RDD_FINDFIRST is still set, we were opened
2247 	 * but never saw a findfirst, so we don't have any
2248 	 * search handle to close.
2249 	 */
2250 	if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0)
2251 		error = smbfs_smb_findclose2(ctx);
2252 	return (error);
2253 }
2254 
2255 int
2256 smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
2257 			int attr, struct smb_cred *scrp,
2258 			struct smbfs_fctx **ctxpp)
2259 {
2260 	struct smbfs_fctx *ctx;
2261 	int error;
2262 
2263 	ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
2264 
2265 	ctx->f_flags = SMBFS_RDD_FINDFIRST;
2266 	ctx->f_dnp = dnp;
2267 	ctx->f_scred = scrp;
2268 	ctx->f_ssp = dnp->n_mount->smi_share;
2269 
2270 	if (dnp->n_flag & N_XATTR) {
2271 		error = smbfs_xa_findopen(ctx, dnp, wild, wlen);
2272 		goto out;
2273 	}
2274 
2275 	if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0) {
2276 		error = smbfs_smb_findopenLM1(ctx, dnp, wild, wlen, attr);
2277 	} else {
2278 		error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr);
2279 	}
2280 
2281 out:
2282 	if (error)
2283 		(void) smbfs_smb_findclose(ctx, scrp);
2284 	else
2285 		*ctxpp = ctx;
2286 	return (error);
2287 }
2288 
2289 int
2290 smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
2291 {
2292 	int error;
2293 
2294 	/*
2295 	 * Note: "limit" (maxcount) needs to fit in a short!
2296 	 */
2297 	if (limit > 0xffff)
2298 		limit = 0xffff;
2299 
2300 	ctx->f_scred = scrp;
2301 	for (;;) {
2302 		bzero(&ctx->f_attr, sizeof (ctx->f_attr));
2303 		switch (ctx->f_type) {
2304 		case ft_LM1:
2305 			error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit);
2306 			break;
2307 		case ft_LM2:
2308 			error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit);
2309 			break;
2310 		case ft_XA:
2311 			error = smbfs_xa_findnext(ctx, (uint16_t)limit);
2312 			break;
2313 		default:
2314 			ASSERT(0);
2315 			error = EINVAL;
2316 			break;
2317 		}
2318 		if (error)
2319 			return (error);
2320 		/*
2321 		 * Skip "." or ".." - easy now that ctx->f_name
2322 		 * has already been converted to utf-8 format.
2323 		 */
2324 		if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
2325 		    (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
2326 		    ctx->f_name[1] == '.'))
2327 			continue;
2328 		break;
2329 	}
2330 
2331 	/*
2332 	 * Moved the smbfs_fname_tolocal(ctx) call into
2333 	 * the ..._findnext functions above.
2334 	 */
2335 
2336 	ctx->f_inum = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
2337 	return (0);
2338 }
2339 
2340 
2341 int
2342 smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
2343 {
2344 	int error;
2345 
2346 	ctx->f_scred = scrp;
2347 	switch (ctx->f_type) {
2348 	case ft_LM1:
2349 		error = smbfs_smb_findcloseLM1(ctx);
2350 		break;
2351 	case ft_LM2:
2352 		error = smbfs_smb_findcloseLM2(ctx);
2353 		break;
2354 	case ft_XA:
2355 		error = smbfs_xa_findclose(ctx);
2356 		break;
2357 	}
2358 	if (ctx->f_rname)
2359 		kmem_free(ctx->f_rname, ctx->f_rnamelen);
2360 	if (ctx->f_firstnm)
2361 		kmem_free(ctx->f_firstnm, ctx->f_firstnmlen);
2362 	kmem_free(ctx, sizeof (*ctx));
2363 	return (error);
2364 }
2365 
2366 
2367 int
2368 smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
2369 	struct smbfattr *fap, struct smb_cred *scrp)
2370 {
2371 	struct smbfs_fctx *ctx;
2372 	int error, intr;
2373 	const char *name = (namep ? *namep : NULL);
2374 	int nmlen = (nmlenp ? *nmlenp : 0);
2375 
2376 	/* This is no longer called with a null dnp */
2377 	ASSERT(dnp);
2378 
2379 	/*
2380 	 * Should not get here with "" anymore.
2381 	 */
2382 	if (!name || !nmlen) {
2383 		DEBUG_ENTER("smbfs_smb_lookup: name is NULL");
2384 		return (EINVAL);
2385 	}
2386 
2387 	/*
2388 	 * Should not get here with "." or ".." anymore.
2389 	 */
2390 	if ((nmlen == 1 && name[0] == '.') ||
2391 	    (nmlen == 2 && name[0] == '.' && name[1] == '.')) {
2392 		DEBUG_ENTER("smbfs_smb_lookup: name is '.' or '..'");
2393 		return (EINVAL);
2394 	}
2395 
2396 	/*
2397 	 * XXX: Should use _qpathinfo here instead.
2398 	 * (if SMB_CAP_NT_SMBS)
2399 	 */
2400 
2401 	/*
2402 	 * Shared lock for n_fid use (smb_flush).
2403 	 */
2404 	intr = dnp->n_mount->smi_flags & SMI_INT;
2405 	if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr))
2406 		return (EINTR);
2407 
2408 	/*
2409 	 * This hides a server bug observable in Win98:
2410 	 * size changes may not show until a CLOSE or a FLUSH op
2411 	 * XXX: Make this conditional on !NTSMBs
2412 	 */
2413 	error = smbfs_smb_flush(dnp, scrp);
2414 	if (error)
2415 		goto out;
2416 	error = smbfs_smb_findopen(dnp, name, nmlen,
2417 	    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx);
2418 	if (error)
2419 		goto out;
2420 	ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
2421 	error = smbfs_smb_findnext(ctx, 1, scrp);
2422 	if (error == 0) {
2423 		*fap = ctx->f_attr;
2424 		/*
2425 		 * Solaris smbfattr doesn't have fa_ino,
2426 		 * and we don't allow name==NULL in this
2427 		 * function anymore.
2428 		 */
2429 		if (namep)
2430 			*namep = (const char *)smbfs_name_alloc(
2431 			    ctx->f_name, ctx->f_nmlen);
2432 		if (nmlenp)
2433 			*nmlenp = ctx->f_nmlen;
2434 	}
2435 	(void) smbfs_smb_findclose(ctx, scrp);
2436 
2437 out:
2438 	smbfs_rw_exit(&dnp->r_lkserlock);
2439 	return (error);
2440 }
2441 
2442 /*
2443  * OTW function to Get a security descriptor (SD).
2444  *
2445  * Note: On success, this fills in mdp->md_top,
2446  * which the caller should free.
2447  */
2448 int
2449 smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
2450 		struct smb_cred *scrp, uint32_t selector,
2451 		mblk_t **res, uint32_t *reslen)
2452 {
2453 	struct smb_ntrq *ntp;
2454 	struct mbchain *mbp;
2455 	struct mdchain *mdp;
2456 	int error, len;
2457 
2458 	error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
2459 	    scrp, &ntp);
2460 	if (error)
2461 		return (error);
2462 
2463 	/* Parameters part */
2464 	mbp = &ntp->nt_tparam;
2465 	mb_init(mbp);
2466 	mb_put_uint16le(mbp, fid);
2467 	mb_put_uint16le(mbp, 0); /* reserved */
2468 	mb_put_uint32le(mbp, selector);
2469 	/* Data part (none) */
2470 
2471 	/* Max. returned parameters and data. */
2472 	ntp->nt_maxpcount = 4;
2473 	ntp->nt_maxdcount = *reslen;
2474 
2475 	error = smb_nt_request(ntp);
2476 	if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
2477 		goto done;
2478 	*res = NULL;
2479 
2480 	/*
2481 	 * if there's more data than we said we could receive, here
2482 	 * is where we pick up the length of it
2483 	 */
2484 	mdp = &ntp->nt_rparam;
2485 	md_get_uint32le(mdp, reslen);
2486 	if (error)
2487 		goto done;
2488 
2489 	/*
2490 	 * get the data part.
2491 	 */
2492 	mdp = &ntp->nt_rdata;
2493 	if (mdp->md_top == NULL) {
2494 		SMBVDEBUG("null md_top? fid 0x%x\n", fid);
2495 		error = EBADRPC;
2496 		goto done;
2497 	}
2498 
2499 	/*
2500 	 * The returned parameter SD_length should match
2501 	 * the length of the returned data.  Unfortunately,
2502 	 * we have to work around server bugs here.
2503 	 */
2504 	len = m_fixhdr(mdp->md_top);
2505 	if (len != *reslen) {
2506 		SMBVDEBUG("len %d *reslen %d fid 0x%x\n",
2507 		    len, *reslen, fid);
2508 	}
2509 
2510 	/*
2511 	 * Actual data provided is < returned SD_length.
2512 	 *
2513 	 * The following "if (len < *reslen)" handles a Windows bug
2514 	 * observed when the underlying filesystem is FAT32.  In that
2515 	 * case a 32 byte security descriptor comes back (S-1-1-0, ie
2516 	 * "Everyone") but the Parameter Block claims 44 is the length
2517 	 * of the security descriptor.  (The Data Block length
2518 	 * claimed is 32.  This server bug was reported against NT
2519 	 * first and I've personally observed it with W2K.
2520 	 */
2521 	if (len < *reslen)
2522 		*reslen = len;
2523 
2524 	/*
2525 	 * Actual data provided is > returned SD_length.
2526 	 * (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0)
2527 	 * Narrow work-around for returned SD_length==0.
2528 	 */
2529 	if (len > *reslen) {
2530 		/*
2531 		 * Increase *reslen, but carefully.
2532 		 */
2533 		if (*reslen == 0 && len <= ntp->nt_maxdcount)
2534 			*reslen = len;
2535 	}
2536 	error = md_get_mbuf(mdp, len, res);
2537 
2538 done:
2539 	if (error == 0 && *res == NULL) {
2540 		ASSERT(*res);
2541 		error = EBADRPC;
2542 	}
2543 
2544 	smb_nt_done(ntp);
2545 	return (error);
2546 }
2547 
2548 #ifdef	APPLE
2549 /*
2550  * Wrapper for _getsd() compatible with darwin code.
2551  */
2552 int
2553 smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
2554 	uint32_t selector, struct ntsecdesc **res)
2555 {
2556 	int error;
2557 	uint32_t len, olen;
2558 	struct mdchain *mdp, md_store;
2559 	struct mbuf *m;
2560 
2561 	bzero(mdp, sizeof (*mdp));
2562 	len = 500; /* "overlarge" values => server errors */
2563 again:
2564 	olen = len;
2565 	error = smbfs_smb_getsec_m(ssp, fid, scrp, selector, &m, &len);
2566 	/*
2567 	 * Server may give us an error indicating that we
2568 	 * need a larger data buffer to receive the SD,
2569 	 * and the size we'll need.  Use the given size,
2570 	 * but only after a sanity check.
2571 	 *
2572 	 * XXX: Check for specific error values here?
2573 	 * XXX: also ... && len <= MAX_RAW_SD_SIZE
2574 	 */
2575 	if (error && len > olen)
2576 		goto again;
2577 
2578 	if (error)
2579 		return (error);
2580 
2581 	mdp = &md_store;
2582 	md_initm(mdp, m);
2583 	MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK);
2584 	error = md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM);
2585 	md_done(mdp);
2586 
2587 	return (error);
2588 }
2589 #endif /* APPLE */
2590 
2591 /*
2592  * OTW function to Set a security descriptor (SD).
2593  * Caller data are carried in an mbchain_t.
2594  *
2595  * Note: This normally consumes mbp->mb_top, and clears
2596  * that pointer when it does.
2597  */
2598 int  smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
2599 	struct smb_cred *scrp, uint32_t selector, mblk_t **mp)
2600 {
2601 	struct smb_ntrq *ntp;
2602 	struct mbchain *mbp;
2603 	int error;
2604 
2605 	error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
2606 	    scrp, &ntp);
2607 	if (error)
2608 		return (error);
2609 
2610 	/* Parameters part */
2611 	mbp = &ntp->nt_tparam;
2612 	mb_init(mbp);
2613 	mb_put_uint16le(mbp, fid);
2614 	mb_put_uint16le(mbp, 0); /* reserved */
2615 	mb_put_uint32le(mbp, selector);
2616 
2617 	/* Data part */
2618 	mbp = &ntp->nt_tdata;
2619 	mb_initm(mbp, *mp);
2620 	*mp = NULL; /* consumed */
2621 
2622 	/* No returned parameters or data. */
2623 	ntp->nt_maxpcount = 0;
2624 	ntp->nt_maxdcount = 0;
2625 
2626 	error = smb_nt_request(ntp);
2627 	smb_nt_done(ntp);
2628 
2629 	return (error);
2630 }
2631 
2632 #ifdef	APPLE
2633 /*
2634  * This function builds the SD given the various parts.
2635  */
2636 int
2637 smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
2638 	uint32_t selector, uint16_t flags, struct ntsid *owner,
2639 	struct ntsid *group, struct ntacl *sacl, struct ntacl *dacl)
2640 {
2641 	struct mbchain *mbp, mb_store;
2642 	struct ntsecdesc ntsd;
2643 	int error, off;
2644 
2645 	/*
2646 	 * Build the SD as its own mbuf chain and pass it to
2647 	 * smbfs_smb_setsec_m()
2648 	 */
2649 	mbp = &mb_store;
2650 	mb_init(mbp);
2651 	bzero(&ntsd, sizeof (ntsd));
2652 	wset_sdrevision(&ntsd);
2653 	/*
2654 	 * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN)
2655 	 * We set here only those bits we can be sure must be set.  The rest
2656 	 * are up to the caller.  In particular, the caller may intentionally
2657 	 * set an acl PRESENT bit while giving us a null pointer for the
2658 	 * acl - that sets a null acl, giving access to everyone.  Note also
2659 	 * that the AUTO_INHERITED bits should probably always be set unless
2660 	 * the server is NT.
2661 	 */
2662 	flags |= SD_SELF_RELATIVE;
2663 	off = sizeof (ntsd);
2664 	if (owner) {
2665 		wset_sdowneroff(&ntsd, off);
2666 		off += sidlen(owner);
2667 	}
2668 	if (group) {
2669 		wset_sdgroupoff(&ntsd, off);
2670 		off += sidlen(group);
2671 	}
2672 	if (sacl) {
2673 		flags |= SD_SACL_PRESENT;
2674 		wset_sdsacloff(&ntsd, off);
2675 		off += acllen(sacl);
2676 	}
2677 	if (dacl) {
2678 		flags |= SD_DACL_PRESENT;
2679 		wset_sddacloff(&ntsd, off);
2680 	}
2681 	wset_sdflags(&ntsd, flags);
2682 	mb_put_mem(mbp, (caddr_t)&ntsd, sizeof (ntsd), MB_MSYSTEM);
2683 	if (owner)
2684 		mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM);
2685 	if (group)
2686 		mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM);
2687 	if (sacl)
2688 		mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM);
2689 	if (dacl)
2690 		mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM);
2691 
2692 	/*
2693 	 * Just pass the mbuf to _setsec_m
2694 	 * It will clear mb_top if consumed.
2695 	 */
2696 	error = smbfs_smb_setsec_m(ssp, fid, scrp, selector, &mbp->mb_top);
2697 	mb_done(mbp);
2698 
2699 	return (error);
2700 }
2701 
2702 #endif /* APPLE */
2703