xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c (revision 572bd1dd3cdc2b70a38ef613ddd9b5be448d94c7)
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 (c) 2011 - 2013 Apple Inc. All rights reserved.
38  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
39  * Copyright 2025 RackTop Systems, Inc.
40  */
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/inttypes.h>
45 #include <sys/time.h>
46 #include <sys/vnode.h>
47 #include <sys/sunddi.h>
48 #include <sys/cmn_err.h>
49 
50 #include <netsmb/smb_osdep.h>
51 
52 #include <netsmb/smb.h>
53 #include <netsmb/smb2.h>
54 #include <netsmb/smb_conn.h>
55 #include <netsmb/smb_subr.h>
56 #include <netsmb/smb_rq.h>
57 #include <netsmb/smb2_rq.h>
58 
59 #include <smbfs/smbfs.h>
60 #include <smbfs/smbfs_node.h>
61 #include <smbfs/smbfs_subr.h>
62 
63 
64 /*
65  * Todo: locking over-the-wire
66  */
67 #if 0	// todo
68 
69 int
70 smbfs_smb2_locking(struct smbnode *np, int op, uint32_t pid,
71 	offset_t start, uint64_t len, int largelock,
72 	struct smb_cred *scrp, uint32_t timeout)
73 {
74 	return (ENOTSUP);
75 }
76 
77 #endif	// todo
78 
79 /*
80  * Helper for smbfs_getattr_otw
81  * used when we don't have an open FID
82  *
83  * For SMB2 we need to do an attribute-only open.  The
84  * data returned by open gets us everything we need, so
85  * just close the handle and we're done.
86  */
87 int
smbfs_smb2_getpattr(struct smbnode * np,struct smbfattr * fap,struct smb_cred * scrp)88 smbfs_smb2_getpattr(
89 	struct smbnode *np,
90 	struct smbfattr *fap,
91 	struct smb_cred *scrp)
92 {
93 	smb_fh_t tmp_fh;
94 	struct smb_share *ssp = np->n_mount->smi_share;
95 	uint32_t rights = (STD_RIGHT_READ_CONTROL_ACCESS |
96 	    SA_RIGHT_FILE_READ_ATTRIBUTES);
97 	int error;
98 
99 	bzero(&tmp_fh, sizeof (tmp_fh));
100 	error = smbfs_smb_ntcreatex(np,
101 	    NULL, 0, 0,	/* name nmlen xattr */
102 	    rights, SMB_EFA_NORMAL,
103 	    NTCREATEX_SHARE_ACCESS_ALL,
104 	    NTCREATEX_DISP_OPEN,
105 	    0, /* create options */
106 	    scrp, &tmp_fh,
107 	    NULL, fap);
108 	if (error == 0) {
109 		(void) smb_smb_close(ssp, &tmp_fh, scrp);
110 	}
111 
112 	return (error);
113 }
114 
115 /*
116  * Common SMB2 query file info
117  */
118 static int
smbfs_smb2_query_info(struct smb_share * ssp,smb2fid_t * fid,struct mdchain * info_mdp,uint32_t * iolen,uint8_t type,uint8_t level,uint32_t addl_info,struct smb_cred * scrp)119 smbfs_smb2_query_info(struct smb_share *ssp, smb2fid_t *fid,
120 	struct mdchain *info_mdp, uint32_t *iolen,
121 	uint8_t type, uint8_t level, uint32_t addl_info,
122 	struct smb_cred *scrp)
123 {
124 	struct smb_rq *rqp = NULL;
125 	struct mbchain *mbp;
126 	struct mdchain *mdp;
127 	uint32_t dlen = 0;
128 	uint16_t doff = 0;
129 	uint16_t ssize = 0;
130 	int error;
131 
132 	error = smb_rq_alloc(SSTOCP(ssp), SMB2_QUERY_INFO, scrp, &rqp);
133 	if (error)
134 		goto out;
135 
136 	/*
137 	 * Build the SMB 2 Query Info req.
138 	 */
139 	smb_rq_getrequest(rqp, &mbp);
140 	mb_put_uint16le(mbp, 41);		// struct size
141 	mb_put_uint8(mbp, type);
142 	mb_put_uint8(mbp, level);
143 	mb_put_uint32le(mbp, *iolen);		// out buf len
144 	mb_put_uint16le(mbp, 0);		// in buf off
145 	mb_put_uint16le(mbp, 0);		// reserved
146 	mb_put_uint32le(mbp, 0);		// in buf len
147 	mb_put_uint32le(mbp, addl_info);
148 	mb_put_uint32le(mbp, 0);		// flags
149 	mb_put_uint64le(mbp, fid->fid_persistent);
150 	mb_put_uint64le(mbp, fid->fid_volatile);
151 
152 	error = smb2_rq_simple(rqp);
153 	if (error) {
154 		if (rqp->sr_error == NT_STATUS_INVALID_PARAMETER)
155 			error = ENOTSUP;
156 		goto out;
157 	}
158 
159 	/*
160 	 * Parse SMB 2 Query Info response
161 	 */
162 	smb_rq_getreply(rqp, &mdp);
163 
164 	/* Check structure size is 9 */
165 	md_get_uint16le(mdp, &ssize);
166 	if (ssize != 9) {
167 		error = EBADRPC;
168 		goto out;
169 	}
170 
171 	/* Get data off, len */
172 	md_get_uint16le(mdp, &doff);
173 	md_get_uint32le(mdp, &dlen);
174 	*iolen = dlen;
175 
176 	/*
177 	 * Skip ahead to the payload, as needed.
178 	 * Current offset is SMB2_HDRLEN + 8.
179 	 */
180 	if (dlen != 0) {
181 		mblk_t *m = NULL;
182 		int skip = (int)doff - (SMB2_HDRLEN + 8);
183 		if (skip < 0) {
184 			error = EBADRPC;
185 			goto out;
186 		}
187 		if (skip > 0) {
188 			md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
189 		}
190 		error = md_get_mbuf(mdp, dlen, &m);
191 		if (error)
192 			goto out;
193 		md_initm(info_mdp, m);
194 	}
195 
196 out:
197 	smb_rq_done(rqp);
198 
199 	return (error);
200 }
201 
202 
203 /*
204  * Get FileAllInformation for an open file
205  * and parse into *fap
206  */
207 int
smbfs_smb2_qfileinfo(struct smb_share * ssp,smb2fid_t * fid,struct smbfattr * fap,struct smb_cred * scrp)208 smbfs_smb2_qfileinfo(struct smb_share *ssp, smb2fid_t *fid,
209 	struct smbfattr *fap, struct smb_cred *scrp)
210 {
211 	struct mdchain info_mdc, *mdp = &info_mdc;
212 	uint32_t iolen = 1024;
213 	int error;
214 
215 	bzero(mdp, sizeof (*mdp));
216 
217 	error = smbfs_smb2_query_info(ssp, fid, mdp, &iolen,
218 	    SMB2_0_INFO_FILE, FileAllInformation, 0, scrp);
219 	if (error)
220 		goto out;
221 
222 	error = smbfs_decode_file_all_info(ssp, mdp, fap);
223 
224 out:
225 	md_done(mdp);
226 
227 	return (error);
228 }
229 
230 /*
231  * Get some SMB2_0_INFO_FILESYSTEM info
232  *
233  * Note: This can be called during mount.  We don't have any
234  * smbfs_node_t or pathname, so do our own attr. open on
235  * the root of the share to get a handle for this request.
236  */
237 static int
smbfs_smb2_query_fs_info(struct smb_share * ssp,struct mdchain * mdp,uint8_t level,struct smb_cred * scrp)238 smbfs_smb2_query_fs_info(struct smb_share *ssp, struct mdchain *mdp,
239 	uint8_t level, struct smb_cred *scrp)
240 {
241 	smb2fid_t fid;
242 	uint32_t iolen = 1024;
243 	boolean_t opened = B_FALSE;
244 	int error;
245 
246 	/*
247 	 * Need a FID for smb2, and this is called during mount
248 	 * so "go behind" the usual open/close functions.
249 	 */
250 	error = smb2_smb_ntcreate(
251 	    ssp, NULL,	// name
252 	    NULL, NULL, // create ctx in, out
253 	    0,	/* NTCREATEX_FLAGS... */
254 	    SA_RIGHT_FILE_READ_ATTRIBUTES,
255 	    SMB_EFA_NORMAL,
256 	    NTCREATEX_SHARE_ACCESS_ALL,
257 	    NTCREATEX_DISP_OPEN,
258 	    0, /* create options */
259 	    NTCREATEX_IMPERSONATION_IMPERSONATION,
260 	    scrp, &fid, NULL, NULL);
261 	if (error != 0)
262 		goto out;
263 	opened = B_TRUE;
264 
265 	error = smbfs_smb2_query_info(ssp, &fid, mdp, &iolen,
266 	    SMB2_0_INFO_FILESYSTEM, level, 0, scrp);
267 
268 out:
269 	if (opened)
270 		(void) smb2_smb_close(ssp, &fid, scrp);
271 
272 	return (error);
273 }
274 
275 /*
276  * Get FileFsAttributeInformation and
277  * parse into *info
278  */
279 int
smbfs_smb2_qfsattr(struct smb_share * ssp,struct smb_fs_attr_info * info,struct smb_cred * scrp)280 smbfs_smb2_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *info,
281 	struct smb_cred *scrp)
282 {
283 	struct mdchain info_mdc, *mdp = &info_mdc;
284 	int error;
285 
286 	bzero(mdp, sizeof (*mdp));
287 
288 	error = smbfs_smb2_query_fs_info(ssp, mdp,
289 	    FileFsAttributeInformation, scrp);
290 	if (error)
291 		goto out;
292 	error = smbfs_decode_fs_attr_info(ssp, mdp, info);
293 
294 out:
295 	md_done(mdp);
296 
297 	return (error);
298 }
299 
300 /*
301  * Get FileFsFullSizeInformation and
302  * parse into *info
303  */
304 int
smbfs_smb2_statfs(struct smb_share * ssp,struct smb_fs_size_info * info,struct smb_cred * scrp)305 smbfs_smb2_statfs(struct smb_share *ssp,
306 	struct smb_fs_size_info *info,
307 	struct smb_cred *scrp)
308 {
309 	struct mdchain info_mdc, *mdp = &info_mdc;
310 	int error;
311 
312 	bzero(mdp, sizeof (*mdp));
313 
314 	error = smbfs_smb2_query_fs_info(ssp, mdp,
315 	    FileFsFullSizeInformation, scrp);
316 	if (error)
317 		goto out;
318 
319 	md_get_uint64le(mdp, &info->total_units);
320 	md_get_uint64le(mdp, &info->caller_avail);
321 	md_get_uint64le(mdp, &info->actual_avail);
322 
323 	md_get_uint32le(mdp, &info->sect_per_unit);
324 	error = md_get_uint32le(mdp, &info->bytes_per_sect);
325 
326 out:
327 	md_done(mdp);
328 
329 	return (error);
330 }
331 
332 int
smbfs_smb2_flush(struct smb_share * ssp,smb2fid_t * fid,struct smb_cred * scrp)333 smbfs_smb2_flush(struct smb_share *ssp, smb2fid_t *fid,
334 	struct smb_cred *scrp)
335 {
336 	struct smb_rq *rqp;
337 	struct mbchain *mbp;
338 	int error;
339 
340 	error = smb_rq_alloc(SSTOCP(ssp), SMB2_FLUSH, scrp, &rqp);
341 	if (error)
342 		return (error);
343 
344 	/*
345 	 * Build the SMB 2 Flush Request
346 	 */
347 	smb_rq_getrequest(rqp, &mbp);
348 	mb_put_uint16le(mbp, 24);	/* struct size */
349 	mb_put_uint16le(mbp, 0);	/* reserved */
350 	mb_put_uint32le(mbp, 0);	/* reserved */
351 
352 	mb_put_uint64le(mbp, fid->fid_persistent);
353 	mb_put_uint64le(mbp, fid->fid_volatile);
354 
355 	rqp->sr_flags |= SMBR_NORECONNECT;
356 	error = smb2_rq_simple(rqp);
357 	smb_rq_done(rqp);
358 
359 	return (error);
360 }
361 
362 /*
363  * Set file info via an open handle.
364  * Caller provides payload, info level.
365  */
366 static int
smbfs_smb2_set_info(struct smb_share * ssp,smb2fid_t * fid,struct mbchain * info_mbp,uint8_t type,uint8_t level,uint32_t addl_info,struct smb_cred * scrp)367 smbfs_smb2_set_info(struct smb_share *ssp, smb2fid_t *fid,
368 	struct mbchain *info_mbp, uint8_t type, uint8_t level,
369 	uint32_t addl_info, struct smb_cred *scrp)
370 {
371 	struct smb_rq *rqp = NULL;
372 	struct mbchain *mbp;
373 	uint32_t *buffer_lenp;
374 	int base, len;
375 	int error;
376 
377 	error = smb_rq_alloc(SSTOCP(ssp), SMB2_SET_INFO, scrp, &rqp);
378 	if (error)
379 		goto out;
380 
381 	/*
382 	 * Build the SMB 2 Set Info req.
383 	 */
384 	smb_rq_getrequest(rqp, &mbp);
385 	mb_put_uint16le(mbp, 33);		// struct size
386 	mb_put_uint8(mbp, type);
387 	mb_put_uint8(mbp, level);
388 	buffer_lenp = mb_reserve(mbp, sizeof (uint32_t));
389 	mb_put_uint16le(mbp, SMB2_HDRLEN + 32);	// Buffer Offset
390 	mb_put_uint16le(mbp, 0);		// Reserved
391 	mb_put_uint32le(mbp, addl_info);	// Additional Info
392 
393 	mb_put_uint64le(mbp, fid->fid_persistent);
394 	mb_put_uint64le(mbp, fid->fid_volatile);
395 
396 	/*
397 	 * Now the payload
398 	 */
399 	base = mbp->mb_count;
400 	error = mb_put_mbchain(mbp, info_mbp);
401 	if (error)
402 		goto out;
403 	len = mbp->mb_count - base;
404 	*buffer_lenp = htolel(len);
405 	if (error)
406 		goto out;
407 
408 	/*
409 	 * Run the request.
410 	 * Don't care about the (empty) reply.
411 	 */
412 	error = smb2_rq_simple(rqp);
413 
414 out:
415 	smb_rq_done(rqp);
416 
417 	return (error);
418 }
419 
420 int
smbfs_smb2_seteof(struct smb_share * ssp,smb2fid_t * fid,uint64_t newsize,struct smb_cred * scrp)421 smbfs_smb2_seteof(struct smb_share *ssp, smb2fid_t *fid,
422 	uint64_t newsize, struct smb_cred *scrp)
423 {
424 	struct mbchain data_mb, *mbp = &data_mb;
425 	uint8_t level = FileEndOfFileInformation;
426 	int error;
427 
428 	mb_init(mbp);
429 	mb_put_uint64le(mbp, newsize);
430 	error = smbfs_smb2_set_info(ssp, fid, mbp,
431 	    SMB2_0_INFO_FILE, level, 0, scrp);
432 	mb_done(mbp);
433 
434 	return (error);
435 }
436 
437 int
smbfs_smb2_setdisp(struct smb_share * ssp,smb2fid_t * fid,uint8_t newdisp,struct smb_cred * scrp)438 smbfs_smb2_setdisp(struct smb_share *ssp, smb2fid_t *fid,
439 	uint8_t newdisp, struct smb_cred *scrp)
440 {
441 	struct mbchain data_mb, *mbp = &data_mb;
442 	uint8_t level = FileDispositionInformation;
443 	int error;
444 
445 	mb_init(mbp);
446 	mb_put_uint8(mbp, newdisp);
447 	error = smbfs_smb2_set_info(ssp, fid, mbp,
448 	    SMB2_0_INFO_FILE,  level, 0, scrp);
449 	mb_done(mbp);
450 
451 	return (error);
452 }
453 
454 /*
455  * Set FileBasicInformation on an open handle
456  * Caller builds the mbchain.
457  */
458 int
smbfs_smb2_setfattr(struct smb_share * ssp,smb2fid_t * fid,struct mbchain * mbp,struct smb_cred * scrp)459 smbfs_smb2_setfattr(struct smb_share *ssp, smb2fid_t *fid,
460 	struct mbchain *mbp, struct smb_cred *scrp)
461 {
462 	uint8_t level = FileBasicInformation;
463 	int error;
464 
465 	error = smbfs_smb2_set_info(ssp, fid, mbp,
466 	    SMB2_0_INFO_FILE,  level, 0, scrp);
467 	return (error);
468 }
469 
470 /*
471  * Build a FileRenameInformation and call setinfo
472  */
473 int
smbfs_smb2_rename(struct smbnode * np,struct smbnode * tdnp,const char * tname,int tnlen,int overwrite,smb2fid_t * fid,struct smb_cred * scrp)474 smbfs_smb2_rename(struct smbnode *np, struct smbnode *tdnp,
475 	const char *tname, int tnlen, int overwrite,
476 	smb2fid_t *fid, struct smb_cred *scrp)
477 {
478 	struct smb_share *ssp = np->n_mount->smi_share;
479 	struct mbchain data_mb, *mbp = &data_mb;
480 	uint32_t *name_lenp;
481 	uint8_t level = FileRenameInformation;
482 	int base, len;
483 	int error;
484 
485 	mb_init(mbp);
486 
487 	mb_put_uint32le(mbp, (overwrite & 1));
488 	mb_put_uint32le(mbp, 0);		// reserved
489 	mb_put_uint64le(mbp, 0);		// Root Dir
490 	name_lenp = mb_reserve(mbp, 4);
491 
492 	/* Target name (full path) */
493 	base = mbp->mb_count;
494 	if (tnlen > 0) {
495 		error = smbfs_fullpath(mbp, SSTOVC(ssp),
496 		    tdnp, tname, tnlen, '\\');
497 		if (error)
498 			goto out;
499 	}
500 	len = mbp->mb_count - base;
501 	*name_lenp = htolel(len);
502 
503 	error = smbfs_smb2_set_info(ssp, fid, mbp,
504 	    SMB2_0_INFO_FILE,  level, 0, scrp);
505 
506 out:
507 	mb_done(mbp);
508 
509 	return (error);
510 }
511 
512 /*
513  * Later servers have maxtransact at a megabyte or more,
514  * but we don't want to buffer up that much data, so use
515  * the lesser of that or 64k.
516  */
517 #define	SMBFS_QDIR_MAX_BUF	(1<<16)
518 
519 /*
520  * SMB2 query directory
521  *
522  * On success, puts qdir response payload in ctx->f_mdchain
523  * and initializes ctx->f_left, ctx->f_eofs for parsing.
524  *
525  * Returns:
526  *	zero: caller should continue reading
527  *	ENOENT: at end of directory, no records copied
528  *	other, eg EIO: something unexpected happened
529  */
530 static int
smbfs_smb2_qdir(struct smbfs_fctx * ctx)531 smbfs_smb2_qdir(struct smbfs_fctx *ctx)
532 {
533 	smb_fh_t *fhp = ctx->f_fhp;
534 	smb_share_t *ssp = ctx->f_ssp;
535 	smb_vc_t *vcp = SSTOVC(ssp);
536 	struct smb_rq *rqp;
537 	struct mbchain *mbp;
538 	struct mdchain *mdp;
539 	uint16_t *name_lenp;
540 	uint8_t level, flags;
541 	uint16_t ssize = 0;
542 	uint16_t obuf_off = 0;
543 	uint32_t obuf_len = 0;
544 	uint32_t obuf_req;
545 	int error;
546 
547 	level = (uint8_t)ctx->f_infolevel;
548 	flags = 0;
549 	if (ctx->f_flags & SMBFS_RDD_FINDSINGLE)
550 		flags |= SMB2_QDIR_FLAG_SINGLE;
551 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST)
552 		ctx->f_rkey = 0;
553 	else
554 		flags |= SMB2_QDIR_FLAG_INDEX;
555 
556 	obuf_req = SMBFS_QDIR_MAX_BUF;
557 	if (obuf_req > vcp->vc_sopt.sv2_maxtransact)
558 		obuf_req = vcp->vc_sopt.sv2_maxtransact;
559 
560 	if (ctx->f_rq) {
561 		smb_rq_done(ctx->f_rq);
562 		ctx->f_rq = NULL;
563 	}
564 	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB2_QUERY_DIRECTORY,
565 	    ctx->f_scred, &rqp);
566 	if (error)
567 		return (error);
568 	ctx->f_rq = rqp;
569 
570 	/*
571 	 * Build an SMB2 Query Dir req.
572 	 */
573 	smb_rq_getrequest(rqp, &mbp);
574 
575 	mb_put_uint16le(mbp, 33);			/* Struct size */
576 	mb_put_uint8(mbp, level);
577 	mb_put_uint8(mbp, flags);
578 	mb_put_uint32le(mbp, ctx->f_rkey);		/* FileIndex */
579 
580 	mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
581 	mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
582 
583 	mb_put_uint16le(mbp, 96);
584 	name_lenp = mb_reserve(mbp, sizeof (uint16_t));	/* FileNameLen */
585 	mb_put_uint32le(mbp, obuf_req);			/* Output Buf Len */
586 
587 	/* Add in the name if any */
588 	if (ctx->f_wclen > 0) {
589 		int base, len;
590 
591 		/* Put the match pattern. */
592 		base = mbp->mb_count;
593 		error = smb_put_dmem(mbp, vcp,
594 		    ctx->f_wildcard, ctx->f_wclen,
595 		    SMB_CS_NONE, NULL);
596 		if (error)
597 			return (error);
598 
599 		/* Update the FileNameLen */
600 		len = mbp->mb_count - base;
601 		*name_lenp = htoles(len);
602 	} else {
603 		/* Empty string */
604 		mb_put_uint16le(mbp, 0);
605 		*name_lenp = 0;
606 	}
607 
608 	error = smb2_rq_simple(rqp);
609 	if (error != 0)
610 		goto out;
611 
612 	/*
613 	 * Parse the SMB2 Query Dir response
614 	 */
615 	smb_rq_getreply(rqp, &mdp);
616 
617 	/* Check structure size is 9 */
618 	md_get_uint16le(mdp, &ssize);
619 	if (ssize != 9) {
620 		error = EBADRPC;
621 		goto out;
622 	}
623 
624 	/* Get output buffer offset, length */
625 	md_get_uint16le(mdp, &obuf_off);
626 	md_get_uint32le(mdp, &obuf_len);
627 
628 	/*
629 	 * After read at EOF we'll have just one word:
630 	 * NextEntryOffset == 0  Allow some padding.
631 	 */
632 	if (obuf_len < 8) {
633 		error = ENOENT;
634 		goto out;
635 	}
636 
637 	/*
638 	 * Have data. Put the payload in ctx->f_mdchain
639 	 * Current offset is SMB2_HDRLEN + 8.
640 	 */
641 	{
642 		mblk_t *m = NULL;
643 		int skip = (int)obuf_off - (SMB2_HDRLEN + 8);
644 		if (skip < 0) {
645 			error = EBADRPC;
646 			goto out;
647 		}
648 		if (skip > 0) {
649 			md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
650 		}
651 		error = md_get_mbuf(mdp, obuf_len, &m);
652 		if (error)
653 			goto out;
654 		md_done(&ctx->f_mdchain);
655 		md_initm(&ctx->f_mdchain, m);
656 	}
657 
658 	/*
659 	 * SMB2 Query Directory does not provie an EntryCount.
660 	 * Instead, we'll advance f_eofs (entry offset)
661 	 * through the range [0..f_left]
662 	 */
663 	ctx->f_left = obuf_len;
664 	ctx->f_eofs = 0;
665 	return (0);
666 
667 out:
668 	if (error != 0) {
669 		/*
670 		 * Failed parsing the FindFirst or FindNext response.
671 		 * Force this directory listing closed, otherwise the
672 		 * calling process may hang in an infinite loop.
673 		 */
674 		ctx->f_left = 0;
675 		ctx->f_eofs = 0;
676 		ctx->f_flags |= SMBFS_RDD_EOF;
677 	}
678 
679 	return (error);
680 }
681 
682 int
smbfs_smb2_findopen(struct smbfs_fctx * ctx,struct smbnode * dnp,const char * wildcard,int wclen,uint32_t attr)683 smbfs_smb2_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
684     const char *wildcard, int wclen, uint32_t attr)
685 {
686 	smb_fh_t *fhp = NULL;
687 	uint32_t rights =
688 	    STD_RIGHT_READ_CONTROL_ACCESS |
689 	    SA_RIGHT_FILE_READ_ATTRIBUTES |
690 	    SA_RIGHT_FILE_READ_DATA;
691 	int error;
692 
693 	/*
694 	 * Set f_type no matter what, so cleanup will call
695 	 * smbfs_smb2_findclose, error or not.
696 	 */
697 	ctx->f_type = ft_SMB2;
698 	ASSERT(ctx->f_dnp == dnp);
699 
700 	/*
701 	 * Get a file handle on the directory
702 	 */
703 	error = smb_fh_create(ctx->f_ssp, &fhp);
704 	if (error != 0)
705 		goto errout;
706 
707 	error = smbfs_smb_ntcreatex(dnp,
708 	    NULL, 0, 0,	/* name nmlen xattr */
709 	    rights, SMB_EFA_NORMAL,
710 	    NTCREATEX_SHARE_ACCESS_ALL,
711 	    NTCREATEX_DISP_OPEN,
712 	    0, /* create options */
713 	    ctx->f_scred, fhp,
714 	    NULL, NULL); /* cr_act_p fa_p */
715 	if (error != 0)
716 		goto errout;
717 
718 	fhp->fh_rights = rights;
719 	smb_fh_opened(fhp);
720 	ctx->f_fhp = fhp;
721 
722 	ctx->f_namesz = SMB_MAXFNAMELEN + 1;
723 	ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
724 	ctx->f_infolevel = FileFullDirectoryInformation;
725 	ctx->f_attrmask = attr;
726 	ctx->f_wildcard = wildcard;
727 	ctx->f_wclen = wclen;
728 
729 	return (0);
730 
731 errout:
732 	if (fhp != NULL)
733 		smb_fh_rele(fhp);
734 	return (error);
735 }
736 
737 int
smbfs_smb2_findclose(struct smbfs_fctx * ctx)738 smbfs_smb2_findclose(struct smbfs_fctx *ctx)
739 {
740 	smb_fh_t *fhp = NULL;
741 
742 	if ((fhp = ctx->f_fhp) != NULL) {
743 		ctx->f_fhp = NULL;
744 		smb_fh_rele(fhp);
745 	}
746 	if (ctx->f_name)
747 		kmem_free(ctx->f_name, ctx->f_namesz);
748 	if (ctx->f_rq)
749 		smb_rq_done(ctx->f_rq);
750 	md_done(&ctx->f_mdchain);
751 
752 	return (0);
753 }
754 
755 /*
756  * Get a buffer of directory entries (if we don't already have
757  * some remaining in the current buffer) then decode one.
758  */
759 int
smbfs_smb2_findnext(struct smbfs_fctx * ctx,uint16_t limit)760 smbfs_smb2_findnext(struct smbfs_fctx *ctx, uint16_t limit)
761 {
762 	int error;
763 
764 	/*
765 	 * If we've scanned to the end of the current buffer
766 	 * try to read anohther buffer of dir entries.
767 	 * Treat anything less than 8 bytes as an "empty"
768 	 * buffer to ensure we can read something.
769 	 * (There may be up to 8 bytes of padding.)
770 	 */
771 	if ((ctx->f_eofs + 8) > ctx->f_left) {
772 		/* Scanned the whole buffer. */
773 		if (ctx->f_flags & SMBFS_RDD_EOF)
774 			return (ENOENT);
775 		ctx->f_limit = limit;
776 		error = smbfs_smb2_qdir(ctx);
777 		if (error)
778 			return (error);
779 		ctx->f_otws++;
780 	}
781 
782 	/*
783 	 * Decode one entry
784 	 */
785 	error = smbfs_decode_dirent(ctx);
786 
787 	return (error);
788 }
789 
790 
791 /*
792  * Helper for smbfs_xa_get_streaminfo
793  * Query stream info
794  */
795 int
smbfs_smb2_get_streaminfo(smbnode_t * np,struct mdchain * mdp,struct smb_cred * scrp)796 smbfs_smb2_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
797 	struct smb_cred *scrp)
798 {
799 	smb_share_t *ssp = np->n_mount->smi_share;
800 	smb_fh_t *fhp = NULL;
801 	uint32_t rights =
802 	    STD_RIGHT_READ_CONTROL_ACCESS |
803 	    SA_RIGHT_FILE_READ_ATTRIBUTES;
804 	uint32_t iolen = INT16_MAX;
805 	int error;
806 
807 	/*
808 	 * Get a file handle on the object
809 	 * with read attr. rights.
810 	 */
811 	error = smb_fh_create(ssp, &fhp);
812 	if (error != 0)
813 		goto out;
814 	error = smbfs_smb_ntcreatex(np,
815 	    NULL, 0, 0,	/* name nmlen xattr */
816 	    rights, SMB_EFA_NORMAL,
817 	    NTCREATEX_SHARE_ACCESS_ALL,
818 	    NTCREATEX_DISP_OPEN,
819 	    0, /* create options */
820 	    scrp, fhp, NULL, NULL);
821 	if (error != 0)
822 		goto out;
823 
824 	smb_fh_opened(fhp);
825 
826 	/*
827 	 * Query stream info
828 	 */
829 	error = smbfs_smb2_query_info(ssp, &fhp->fh_fid2, mdp, &iolen,
830 	    SMB2_0_INFO_FILE, FileStreamInformation, 0, scrp);
831 
832 out:
833 	if (fhp != NULL)
834 		smb_fh_rele(fhp);
835 	return (error);
836 }
837 
838 
839 /*
840  * OTW function to Get a security descriptor (SD).
841  *
842  * The *reslen param is bufsize(in) / length(out)
843  * Note: On success, this fills in mdp->md_top,
844  * which the caller should free.
845  */
846 int
smbfs_smb2_getsec(struct smb_share * ssp,smb2fid_t * fid,uint32_t selector,mblk_t ** res,uint32_t * reslen,struct smb_cred * scrp)847 smbfs_smb2_getsec(struct smb_share *ssp, smb2fid_t *fid,
848 	uint32_t selector, mblk_t **res, uint32_t *reslen,
849 	struct smb_cred *scrp)
850 {
851 	struct mdchain info_mdc, *mdp = &info_mdc;
852 	int error;
853 
854 	bzero(mdp, sizeof (*mdp));
855 
856 	error = smbfs_smb2_query_info(ssp, fid, mdp, reslen,
857 	    SMB2_0_INFO_SECURITY, 0, selector, scrp);
858 	if (error)
859 		goto out;
860 
861 	if (mdp->md_top == NULL) {
862 		error = EBADRPC;
863 		goto out;
864 	}
865 	*res = mdp->md_top;
866 	mdp->md_top = NULL;
867 
868 out:
869 	md_done(mdp);
870 	return (error);
871 }
872 
873 
874 /*
875  * OTW function to Set a security descriptor (SD).
876  * Caller data are carried in an mbchain_t.
877  *
878  * Note: This normally consumes mbp->mb_top, and clears
879  * that pointer when it does.
880  */
881 int
smbfs_smb2_setsec(struct smb_share * ssp,smb2fid_t * fid,uint32_t selector,mblk_t ** mp,struct smb_cred * scrp)882 smbfs_smb2_setsec(struct smb_share *ssp, smb2fid_t *fid,
883 	uint32_t selector, mblk_t **mp, struct smb_cred *scrp)
884 {
885 	struct mbchain info_mbp, *mbp = &info_mbp;
886 	int error;
887 
888 	ASSERT(*mp != NULL);
889 	mb_initm(mbp, *mp);
890 	*mp = NULL; /* consumed */
891 
892 	error = smbfs_smb2_set_info(ssp, fid, mbp,
893 	    SMB2_0_INFO_SECURITY, 0, selector, scrp);
894 
895 	mb_done(mbp);
896 
897 	return (error);
898 }
899