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