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