xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c (revision 78801af7286cd73dbc996d470f789e75993cf15d)
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 
33 /*
34  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
35  * Use is subject to license terms.
36  *
37  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/inttypes.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 /*
61  * Todo: locking over-the-wire
62  */
63 #if 0	// todo
64 
65 int
66 smbfs_smb1_lockandx(struct smbnode *np, int op, uint32_t pid,
67 	offset_t start, uint64_t len, int largelock,
68 	struct smb_cred *scrp, uint32_t timeout)
69 {
70 	struct smb_share *ssp = np->n_mount->smi_share;
71 	struct smb_rq rq, *rqp = &rq;
72 	struct mbchain *mbp;
73 	uint8_t ltype = 0;
74 	int error;
75 
76 	/* Shared lock for n_fid use below. */
77 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
78 
79 	/* After reconnect, n_fid is invalid */
80 	if (np->n_vcgenid != ssp->ss_vcgenid)
81 		return (ESTALE);
82 
83 	if (op == SMB_LOCK_SHARED)
84 		ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
85 	/* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */
86 	if (largelock)
87 		ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
88 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
89 	if (error)
90 		return (error);
91 	smb_rq_getrequest(rqp, &mbp);
92 	smb_rq_wstart(rqp);
93 	mb_put_uint8(mbp, 0xff);	/* secondary command */
94 	mb_put_uint8(mbp, 0);		/* MBZ */
95 	mb_put_uint16le(mbp, 0);
96 	mb_put_uint16le(mbp, np->n_fid);
97 	mb_put_uint8(mbp, ltype);	/* locktype */
98 	mb_put_uint8(mbp, 0);		/* oplocklevel - 0 seems is NO_OPLOCK */
99 	mb_put_uint32le(mbp, timeout);	/* 0 nowait, -1 infinite wait */
100 	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
101 	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
102 	smb_rq_wend(rqp);
103 	smb_rq_bstart(rqp);
104 	mb_put_uint16le(mbp, pid);
105 	if (!largelock) {
106 		mb_put_uint32le(mbp, start);
107 		mb_put_uint32le(mbp, len);
108 	} else {
109 		mb_put_uint16le(mbp, 0); /* pad */
110 		mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
111 		mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
112 		mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
113 		mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
114 	}
115 	smb_rq_bend(rqp);
116 	/*
117 	 * Don't want to risk missing a successful
118 	 * unlock send or lock response, or we could
119 	 * lose track of an outstanding lock.
120 	 */
121 	if (op == SMB_LOCK_RELEASE)
122 		rqp->sr_flags |= SMBR_NOINTR_SEND;
123 	else
124 		rqp->sr_flags |= SMBR_NOINTR_RECV;
125 
126 	error = smb_rq_simple(rqp);
127 	smb_rq_done(rqp);
128 	return (error);
129 }
130 
131 #endif	// todo
132 
133 /*
134  * Common function for QueryFileInfo, QueryPathInfo.
135  */
136 int
137 smbfs_smb1_trans2_query(struct smbnode *np,  uint16_t fid,
138 	struct smbfattr *fap, struct smb_cred *scrp)
139 {
140 	struct smb_share *ssp = np->n_mount->smi_share;
141 	struct smb_vc *vcp = SSTOVC(ssp);
142 	struct smb_t2rq *t2p;
143 	struct mbchain *mbp;
144 	struct mdchain *mdp;
145 	uint16_t cmd;
146 	uint16_t infolevel = SMB_QFILEINFO_ALL_INFO;
147 	int error;
148 
149 	/*
150 	 * If we have a valid open FID, use it.
151 	 */
152 	if (fid != SMB_FID_UNUSED)
153 		cmd = SMB_TRANS2_QUERY_FILE_INFORMATION;
154 	else
155 		cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
156 
157 	error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
158 	if (error)
159 		return (error);
160 	mbp = &t2p->t2_tparam;
161 	mb_init(mbp);
162 
163 	if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION)
164 		mb_put_uint16le(mbp, fid);
165 
166 	mb_put_uint16le(mbp, infolevel);
167 
168 	if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) {
169 		mb_put_uint32le(mbp, 0);
170 		/* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
171 		error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
172 		if (error)
173 			goto out;
174 	}
175 
176 	t2p->t2_maxpcount = 2;
177 	t2p->t2_maxdcount = vcp->vc_txmax;
178 	error = smb_t2_request(t2p);
179 	if (error)
180 		goto out;
181 
182 	/*
183 	 * Parse the SMB_QFILEINFO_ALL_INFO
184 	 */
185 	mdp = &t2p->t2_rdata;
186 	error = smbfs_decode_file_all_info(ssp, mdp, fap);
187 
188 out:
189 	smb_t2_done(t2p);
190 
191 	return (error);
192 }
193 
194 /*
195  * Get some FS information
196  */
197 static int
198 smbfs_smb1_query_fs_info(struct smb_share *ssp, struct mdchain *info_mdp,
199 	uint16_t level, struct smb_cred *scrp)
200 {
201 	struct smb_t2rq *t2p;
202 	struct mbchain *mbp;
203 	struct mdchain *mdp;
204 	int error;
205 
206 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
207 	    scrp, &t2p);
208 	if (error)
209 		return (error);
210 	mbp = &t2p->t2_tparam;
211 	mb_init(mbp);
212 	mb_put_uint16le(mbp, level);
213 	t2p->t2_maxpcount = 4;
214 	t2p->t2_maxdcount = 1024;
215 	error = smb_t2_request(t2p);
216 	if (error)
217 		goto out;
218 
219 	mdp = &t2p->t2_rdata;
220 	*info_mdp = *mdp;
221 	bzero(mdp, sizeof (*mdp));
222 
223 out:
224 	smb_t2_done(t2p);
225 	return (error);
226 }
227 
228 /*
229  * Get FILE_FS_ATTRIBUTE_INFORMATION
230  */
231 int
232 smbfs_smb1_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
233 	struct smb_cred *scrp)
234 {
235 	struct mdchain info_mdc, *mdp = &info_mdc;
236 	int error;
237 
238 	bzero(mdp, sizeof (*mdp));
239 
240 	error = smbfs_smb1_query_fs_info(ssp, mdp,
241 	    SMB_QFS_ATTRIBUTE_INFO, scrp);
242 	if (error)
243 		goto out;
244 	error = smbfs_decode_fs_attr_info(ssp, mdp, fsa);
245 
246 out:
247 	md_done(mdp);
248 
249 	return (error);
250 }
251 
252 /*
253  * Get FileFsFullSizeInformation and
254  * parse into *info
255  */
256 int
257 smbfs_smb1_statfs(struct smb_share *ssp,
258 	struct smb_fs_size_info *info,
259 	struct smb_cred *scrp)
260 {
261 	struct mdchain info_mdc, *mdp = &info_mdc;
262 	struct smb_vc *vcp = SSTOVC(ssp);
263 	uint16_t level;
264 	int error;
265 
266 	bzero(mdp, sizeof (*mdp));
267 
268 	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
269 		level = SMB_QFS_FULL_SIZE_INFORMATION;
270 	else
271 		level = SMB_QFS_SIZE_INFO;
272 	error = smbfs_smb1_query_fs_info(ssp, mdp, level, scrp);
273 	if (error)
274 		goto out;
275 
276 	md_get_uint64le(mdp, &info->total_units);
277 	md_get_uint64le(mdp, &info->caller_avail);
278 	if (level == SMB_QFS_FULL_SIZE_INFORMATION)
279 		md_get_uint64le(mdp, &info->actual_avail);
280 	else
281 		info->actual_avail = info->caller_avail;
282 
283 	md_get_uint32le(mdp, &info->sect_per_unit);
284 	error = md_get_uint32le(mdp, &info->bytes_per_sect);
285 
286 out:
287 	md_done(mdp);
288 
289 	return (error);
290 }
291 
292 int
293 smbfs_smb1_flush(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp)
294 {
295 	struct smb_rq rq, *rqp = &rq;
296 	struct mbchain *mbp;
297 	int error;
298 
299 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
300 	if (error)
301 		return (error);
302 	smb_rq_getrequest(rqp, &mbp);
303 	smb_rq_wstart(rqp);
304 	mb_put_uint16le(mbp, fid);
305 	smb_rq_wend(rqp);
306 	smb_rq_bstart(rqp);
307 	smb_rq_bend(rqp);
308 	error = smb_rq_simple(rqp);
309 	smb_rq_done(rqp);
310 	return (error);
311 }
312 
313 /*
314  * Set file info via an open handle.
315  * Caller provides payload, info level.
316  */
317 static int
318 smbfs_smb1_setinfo_file(struct smb_share *ssp, uint16_t fid,
319 	struct mbchain *info_mbp, uint16_t level, struct smb_cred *scrp)
320 {
321 	struct smb_t2rq *t2p = NULL;
322 	struct mbchain *mbp;
323 	uint16_t cmd = SMB_TRANS2_SET_FILE_INFORMATION;
324 	int error;
325 
326 	ASSERT(fid != SMB_FID_UNUSED);
327 
328 	error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
329 	if (error)
330 		return (error);
331 	mbp = &t2p->t2_tparam;
332 	mb_init(mbp);
333 	mb_put_uint16le(mbp, fid);
334 	mb_put_uint16le(mbp, level);
335 	mb_put_uint16le(mbp, 0); /* pad */
336 
337 	/* put the payload */
338 	mbp = &t2p->t2_tdata;
339 	mb_init(mbp);
340 	error = mb_put_mbchain(mbp, info_mbp);
341 	if (error)
342 		goto out;
343 
344 	t2p->t2_maxpcount = 2;
345 	t2p->t2_maxdcount = 0;
346 	error = smb_t2_request(t2p);
347 
348 out:
349 	smb_t2_done(t2p);
350 
351 	return (error);
352 }
353 
354 int
355 smbfs_smb1_seteof(struct smb_share *ssp, uint16_t fid,
356 	uint64_t newsize, struct smb_cred *scrp)
357 {
358 	struct mbchain data_mb, *mbp = &data_mb;
359 	uint16_t level;
360 	int error;
361 
362 	if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
363 		level = SMB_SFILEINFO_END_OF_FILE_INFORMATION;
364 	else
365 		level = SMB_SFILEINFO_END_OF_FILE_INFO;
366 
367 	mb_init(mbp);
368 	error = mb_put_uint64le(mbp, newsize);
369 	if (error)
370 		goto out;
371 	error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
372 
373 out:
374 	mb_done(mbp);
375 	return (error);
376 }
377 
378 int
379 smbfs_smb1_setdisp(struct smb_share *ssp, uint16_t fid,
380 	uint8_t newdisp, struct smb_cred *scrp)
381 {
382 	struct mbchain data_mb, *mbp = &data_mb;
383 	uint16_t level;
384 	int error;
385 
386 	if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
387 		level = SMB_SFILEINFO_DISPOSITION_INFORMATION;
388 	else
389 		level = SMB_SFILEINFO_DISPOSITION_INFO;
390 
391 	mb_init(mbp);
392 	error = mb_put_uint8(mbp, newdisp);
393 	if (error)
394 		goto out;
395 	error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
396 
397 out:
398 	mb_done(mbp);
399 
400 	return (error);
401 }
402 
403 /*
404  * Set FileBasicInformation on an open handle
405  * Caller builds the mbchain.
406  * Always have a FID here.
407  */
408 int
409 smbfs_smb1_setfattr(struct smb_share *ssp, uint16_t fid,
410 	struct mbchain *mbp, struct smb_cred *scrp)
411 {
412 	uint16_t level;
413 	int error;
414 
415 	if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
416 		level = SMB_SFILEINFO_BASIC_INFORMATION;
417 	else
418 		level = SMB_SFILEINFO_BASIC_INFO;
419 	error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
420 
421 	return (error);
422 }
423 
424 /*
425  * On SMB1, the trans2 rename only allows a rename where the
426  * source and target are in the same directory.  If you give
427  * the server any separators, you get "status not supported".
428  *
429  * Why bother using this instead of smbfs_smb1_oldrename?
430  * Because it works with an open file, and some servers don't
431  * allow oldrename of a file that's currently open.  We call
432  * this when deleting an open file in smbfsremove(), where
433  * the rename is always in the same directory.
434  */
435 /*ARGSUSED*/
436 int
437 smbfs_smb1_t2rename(struct smbnode *np,
438 	const char *tname, int tnlen,
439 	uint16_t fid, struct smb_cred *scrp)
440 {
441 	struct smb_share *ssp = np->n_mount->smi_share;
442 	struct mbchain data_mb, *mbp = &data_mb;
443 	struct smb_vc *vcp = SSTOVC(ssp);
444 	uint32_t *name_lenp;
445 	uint16_t level = SMB_SFILEINFO_RENAME_INFORMATION;
446 	int base, len;
447 	int error;
448 
449 	mb_init(mbp);
450 	mb_put_uint32le(mbp, 0); /* don't overwrite */
451 	mb_put_uint32le(mbp, 0); /* obsolete target dir fid */
452 	name_lenp = mb_reserve(mbp, 4);	/* name len */
453 
454 	/* New name */
455 	base = mbp->mb_count;
456 	error = smb_put_dmem(mbp, vcp, tname, tnlen, SMB_CS_NONE, NULL);
457 	if (error)
458 		goto out;
459 	len = mbp->mb_count - base;
460 	*name_lenp = htolel(len);
461 
462 	error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
463 
464 out:
465 	mb_done(mbp);
466 	return (error);
467 }
468 
469 /*
470  * Do an SMB1 (old style) rename using a full dest. path.
471  * This is used when renaming to a different directory,
472  * because the (preferred) t2rename can't do that.
473  */
474 int
475 smbfs_smb1_oldrename(struct smbnode *src, struct smbnode *tdnp,
476     const char *tname, int tnmlen, struct smb_cred *scrp)
477 {
478 	struct smb_rq rq, *rqp = &rq;
479 	struct smb_share *ssp = src->n_mount->smi_share;
480 	struct mbchain *mbp;
481 	int error;
482 	uint16_t fa;
483 	char sep;
484 
485 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
486 	if (error)
487 		return (error);
488 	smb_rq_getrequest(rqp, &mbp);
489 	smb_rq_wstart(rqp);
490 	/* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
491 	fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
492 	fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
493 	mb_put_uint16le(mbp, fa);
494 	smb_rq_wend(rqp);
495 	smb_rq_bstart(rqp);
496 
497 	/*
498 	 * When we're not adding any component name, the
499 	 * passed sep is ignored, so just pass sep=0.
500 	 */
501 	mb_put_uint8(mbp, SMB_DT_ASCII);
502 	error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0);
503 	if (error)
504 		goto out;
505 
506 	/*
507 	 * After XATTR directories, separator is ":"
508 	 */
509 	sep = (src->n_flag & N_XATTR) ? ':' : '\\';
510 	mb_put_uint8(mbp, SMB_DT_ASCII);
511 	error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, sep);
512 	if (error)
513 		goto out;
514 
515 	smb_rq_bend(rqp);
516 	error = smb_rq_simple(rqp);
517 out:
518 	smb_rq_done(rqp);
519 	return (error);
520 }
521 
522 
523 /*
524  * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
525  */
526 static int
527 smbfs_smb1_trans2find2(struct smbfs_fctx *ctx)
528 {
529 	struct smb_t2rq *t2p;
530 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
531 	struct mbchain *mbp;
532 	struct mdchain *mdp;
533 	uint16_t ecnt, eos, lno, flags;
534 	uint16_t amask, limit;
535 	int error;
536 
537 	/* smbfs_smb_findnextLM2 sets this */
538 	limit = ctx->f_limit;
539 	amask = (uint16_t)ctx->f_attrmask;
540 
541 	if (ctx->f_t2) {
542 		smb_t2_done(ctx->f_t2);
543 		ctx->f_t2 = NULL;
544 	}
545 	flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
546 	if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
547 		flags |= FIND2_CLOSE_AFTER_REQUEST;
548 		ctx->f_flags |= SMBFS_RDD_NOCLOSE;
549 	}
550 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
551 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
552 		    ctx->f_scred, &t2p);
553 		if (error)
554 			return (error);
555 		ctx->f_t2 = t2p;
556 		mbp = &t2p->t2_tparam;
557 		mb_init(mbp);
558 		mb_put_uint16le(mbp, amask);
559 		mb_put_uint16le(mbp, limit);
560 		mb_put_uint16le(mbp, flags);
561 		mb_put_uint16le(mbp, ctx->f_infolevel);
562 		mb_put_uint32le(mbp, 0);
563 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
564 		    ctx->f_wildcard, ctx->f_wclen, '\\');
565 		if (error)
566 			return (error);
567 	} else	{
568 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
569 		    ctx->f_scred, &t2p);
570 		if (error)
571 			return (error);
572 		ctx->f_t2 = t2p;
573 		mbp = &t2p->t2_tparam;
574 		mb_init(mbp);
575 		mb_put_uint16le(mbp, ctx->f_Sid);
576 		mb_put_uint16le(mbp, limit);
577 		mb_put_uint16le(mbp, ctx->f_infolevel);
578 		/* Send whatever resume key we received... */
579 		mb_put_uint32le(mbp, ctx->f_rkey);
580 		mb_put_uint16le(mbp, flags);
581 		/* ... and the resume name if we have one. */
582 		if (ctx->f_rname) {
583 			/* resume file name */
584 			mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
585 			    MB_MSYSTEM);
586 		}
587 		/* Add trailing null - 1 byte if ASCII, 2 if Unicode */
588 		if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
589 			mb_put_uint8(mbp, 0);	/* 1st byte NULL Unicode char */
590 		mb_put_uint8(mbp, 0);
591 	}
592 	t2p->t2_maxpcount = 5 * 2;
593 	t2p->t2_maxdcount = 0xF000;	/* 64K less some overhead */
594 	error = smb_t2_request(t2p);
595 	if (error)
596 		return (error);
597 
598 	/*
599 	 * This is the "resume name" we just sent.
600 	 * We want the new one (if any) that may be
601 	 * found in the response we just received and
602 	 * will now begin parsing.  Free the old one
603 	 * now so we'll know if we found a new one.
604 	 */
605 	if (ctx->f_rname) {
606 		kmem_free(ctx->f_rname, ctx->f_rnamelen);
607 		ctx->f_rname = NULL;
608 		ctx->f_rnamelen = 0;
609 	}
610 
611 	mdp = &t2p->t2_rparam;
612 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
613 		if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0)
614 			goto nodata;
615 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
616 	}
617 	md_get_uint16le(mdp, &ecnt);		/* entry count */
618 	md_get_uint16le(mdp, &eos);		/* end of search */
619 	md_get_uint16le(mdp, NULL);		/* EA err. off. */
620 	error = md_get_uint16le(mdp, &lno);	/* last name off. */
621 	if (error != 0)
622 		goto nodata;
623 
624 	/*
625 	 * The "end of search" flag from an XP server sometimes
626 	 * comes back zero when the prior find_next returned exactly
627 	 * the number of entries requested.  in which case we'd try again
628 	 * but the search has in fact been closed so an EBADF results.
629 	 * our circumvention is to check here for a zero entry count.
630 	 */
631 	ctx->f_ecnt = ecnt;
632 	if (eos || ctx->f_ecnt == 0)
633 		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
634 	if (ctx->f_ecnt == 0)
635 		return (ENOENT);
636 
637 	/* Last Name Off (LNO) is the entry with the resume name. */
638 	ctx->f_rnameofs = lno;
639 	ctx->f_eofs = 0;
640 
641 	/*
642 	 * Have data. Put the payload in ctx->f_mdchain
643 	 * Note struct assignments here.
644 	 */
645 	mdp = &t2p->t2_rdata;
646 	md_done(&ctx->f_mdchain);
647 	ctx->f_mdchain = *mdp;
648 	ctx->f_left = m_fixhdr(mdp->md_top);
649 	bzero(mdp, sizeof (*mdp));
650 
651 	return (0);
652 
653 nodata:
654 	/*
655 	 * Failed parsing the FindFirst or FindNext response.
656 	 * Force this directory listing closed, otherwise the
657 	 * calling process may hang in an infinite loop.
658 	 */
659 	ctx->f_ecnt = 0; /* Force closed. */
660 	ctx->f_flags |= SMBFS_RDD_EOF;
661 	return (EIO);
662 }
663 
664 static int
665 smbfs_smb1_findclose2(struct smbfs_fctx *ctx)
666 {
667 	struct smb_rq rq, *rqp = &rq;
668 	struct mbchain *mbp;
669 	int error;
670 
671 	error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
672 	    ctx->f_scred);
673 	if (error)
674 		return (error);
675 	smb_rq_getrequest(rqp, &mbp);
676 	smb_rq_wstart(rqp);
677 	mb_put_uint16le(mbp, ctx->f_Sid);
678 	smb_rq_wend(rqp);
679 	smb_rq_bstart(rqp);
680 	smb_rq_bend(rqp);
681 	/* Ditto comments at _smb_close */
682 	rqp->sr_flags |= SMBR_NOINTR_SEND;
683 	error = smb_rq_simple(rqp);
684 	smb_rq_done(rqp);
685 	return (error);
686 }
687 
688 /*ARGSUSED*/
689 int
690 smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
691     const char *wildcard, int wclen, uint32_t attr)
692 {
693 
694 	ctx->f_type = ft_LM2;
695 	ctx->f_namesz = SMB_MAXFNAMELEN + 1;
696 	ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
697 	ctx->f_infolevel = SMB_FIND_FULL_DIRECTORY_INFO;
698 	ctx->f_attrmask = attr;
699 	ctx->f_wildcard = wildcard;
700 	ctx->f_wclen = wclen;
701 	return (0);
702 }
703 
704 int
705 smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
706 {
707 	int error = 0;
708 	if (ctx->f_name)
709 		kmem_free(ctx->f_name, ctx->f_namesz);
710 	if (ctx->f_t2)
711 		smb_t2_done(ctx->f_t2);
712 	md_done(&ctx->f_mdchain);
713 
714 	/*
715 	 * If SMBFS_RDD_FINDFIRST is still set, we were opened
716 	 * but never saw a findfirst, so we don't have any
717 	 * search handle to close.
718 	 */
719 	if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0)
720 		error = smbfs_smb1_findclose2(ctx);
721 	return (error);
722 }
723 
724 /*
725  * Get a buffer of directory entries (if we don't already have
726  * some remaining in the current buffer) then decode one.
727  */
728 int
729 smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
730 {
731 	int error;
732 
733 	/*
734 	 * If we've scanned to the end of the current buffer
735 	 * try to read anohther buffer of dir entries.
736 	 * Treat anything less than 8 bytes as an "empty"
737 	 * buffer to ensure we can read something.
738 	 * (There may be up to 8 bytes of padding.)
739 	 */
740 	if ((ctx->f_eofs + 8) > ctx->f_left) {
741 		/* Scanned the whole buffer. */
742 		if (ctx->f_flags & SMBFS_RDD_EOF)
743 			return (ENOENT);
744 		ctx->f_limit = limit;
745 		error = smbfs_smb1_trans2find2(ctx);
746 		if (error)
747 			return (error);
748 		ctx->f_otws++;
749 	}
750 
751 	/*
752 	 * Decode one entry, advance f_eofs
753 	 */
754 	error = smbfs_decode_dirent(ctx);
755 
756 	return (error);
757 }
758 
759 /*
760  * Helper for smbfs_xa_get_streaminfo
761  * Query stream info
762  */
763 int
764 smbfs_smb1_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
765 	struct smb_cred *scrp)
766 {
767 	smb_share_t *ssp = np->n_mount->smi_share;
768 	struct smb_vc *vcp = SSTOVC(ssp);
769 	struct smb_t2rq *t2p = NULL;
770 	struct mbchain *mbp;
771 	mblk_t *m;
772 	uint16_t cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
773 	int error;
774 
775 	error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
776 	if (error)
777 		return (error);
778 
779 	mbp = &t2p->t2_tparam;
780 	(void) mb_init(mbp);
781 	(void) mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO);
782 	(void) mb_put_uint32le(mbp, 0);
783 	error = smbfs_fullpath(mbp, vcp, np, NULL, 0, 0);
784 	if (error)
785 		goto out;
786 
787 	t2p->t2_maxpcount = 2;
788 	t2p->t2_maxdcount = INT16_MAX;
789 	error = smb_t2_request(t2p);
790 	if (error) {
791 		if (t2p->t2_sr_error == NT_STATUS_INVALID_PARAMETER)
792 			error = ENOTSUP;
793 		goto out;
794 	}
795 
796 	/*
797 	 * Have data.  Move it to *mdp
798 	 */
799 	m = t2p->t2_rdata.md_top;
800 	if (m == NULL) {
801 		error = EBADRPC;
802 		goto out;
803 	}
804 	t2p->t2_rdata.md_top = NULL;
805 	md_initm(mdp, m);
806 
807 out:
808 	smb_t2_done(t2p);
809 	return (error);
810 }
811 
812 /*
813  * OTW function to Get a security descriptor (SD).
814  *
815  * The *reslen param is bufsize(in) / length(out)
816  * Note: On success, this fills in mdp->md_top,
817  * which the caller should free.
818  */
819 int
820 smbfs_smb1_getsec(struct smb_share *ssp, uint16_t fid,
821 	uint32_t selector, mblk_t **res, uint32_t *reslen,
822 	struct smb_cred *scrp)
823 {
824 	struct smb_ntrq *ntp;
825 	struct mbchain *mbp;
826 	struct mdchain *mdp;
827 	uint32_t dlen;
828 	int error;
829 
830 	*res = NULL;
831 
832 	error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
833 	    scrp, &ntp);
834 	if (error)
835 		return (error);
836 
837 	/* Parameters part */
838 	mbp = &ntp->nt_tparam;
839 	mb_init(mbp);
840 	mb_put_uint16le(mbp, fid);
841 	mb_put_uint16le(mbp, 0); /* reserved */
842 	mb_put_uint32le(mbp, selector);
843 	/* Data part (none) */
844 
845 	/* Max. returned parameters and data. */
846 	ntp->nt_maxpcount = 4;
847 	ntp->nt_maxdcount = *reslen;	// out buf size
848 
849 	error = smb_nt_request(ntp);
850 	if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
851 		goto done;
852 
853 	/* Get data len */
854 	mdp = &ntp->nt_rparam;
855 	error = md_get_uint32le(mdp, &dlen);
856 	if (error)
857 		goto done;
858 
859 	/*
860 	 * if there's more data than we said we could receive,
861 	 * here is where we pick up the length of it
862 	 */
863 	*reslen = dlen;
864 	if (dlen == 0) {
865 		error = EBADRPC;
866 		goto done;
867 	}
868 
869 	/*
870 	 * get the SD data part.
871 	 */
872 	mdp = &ntp->nt_rdata;
873 	error = md_get_mbuf(mdp, dlen, res);
874 
875 done:
876 	if (error == 0 && *res == NULL) {
877 		ASSERT(*res);
878 		error = EBADRPC;
879 	}
880 
881 	smb_nt_done(ntp);
882 	return (error);
883 }
884 
885 
886 /*
887  * OTW function to Set a security descriptor (SD).
888  * Caller data are carried in an mbchain_t.
889  *
890  * Note: This normally consumes mbp->mb_top, and clears
891  * that pointer when it does.
892  */
893 int
894 smbfs_smb1_setsec(struct smb_share *ssp, uint16_t fid,
895 	uint32_t selector, mblk_t **mp, struct smb_cred *scrp)
896 {
897 	struct smb_ntrq *ntp;
898 	struct mbchain *mbp;
899 	int error;
900 
901 	error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
902 	    scrp, &ntp);
903 	if (error)
904 		return (error);
905 
906 	/* Parameters part */
907 	mbp = &ntp->nt_tparam;
908 	mb_init(mbp);
909 	mb_put_uint16le(mbp, fid);
910 	mb_put_uint16le(mbp, 0); /* reserved */
911 	mb_put_uint32le(mbp, selector);
912 
913 	/* Data part */
914 	mbp = &ntp->nt_tdata;
915 	mb_initm(mbp, *mp);
916 	*mp = NULL; /* consumed */
917 
918 	/* No returned parameters or data. */
919 	ntp->nt_maxpcount = 0;
920 	ntp->nt_maxdcount = 0;
921 
922 	error = smb_nt_request(ntp);
923 	smb_nt_done(ntp);
924 
925 	return (error);
926 }
927