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
smbfs_smb1_trans2_query(struct smbnode * np,uint16_t fid,struct smbfattr * fap,struct smb_cred * scrp)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
smbfs_smb1_query_fs_info(struct smb_share * ssp,struct mdchain * info_mdp,uint16_t level,struct smb_cred * scrp)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
smbfs_smb1_qfsattr(struct smb_share * ssp,struct smb_fs_attr_info * fsa,struct smb_cred * scrp)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
smbfs_smb1_statfs(struct smb_share * ssp,struct smb_fs_size_info * info,struct smb_cred * scrp)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
smbfs_smb1_flush(struct smb_share * ssp,uint16_t fid,struct smb_cred * scrp)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
smbfs_smb1_setinfo_file(struct smb_share * ssp,uint16_t fid,struct mbchain * info_mbp,uint16_t level,struct smb_cred * scrp)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
smbfs_smb1_seteof(struct smb_share * ssp,uint16_t fid,uint64_t newsize,struct smb_cred * scrp)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
smbfs_smb1_setdisp(struct smb_share * ssp,uint16_t fid,uint8_t newdisp,struct smb_cred * scrp)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
smbfs_smb1_setfattr(struct smb_share * ssp,uint16_t fid,struct mbchain * mbp,struct smb_cred * scrp)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
smbfs_smb1_t2rename(struct smbnode * np,const char * tname,int tnlen,uint16_t fid,struct smb_cred * scrp)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
smbfs_smb1_oldrename(struct smbnode * src,struct smbnode * tdnp,const char * tname,int tnmlen,struct smb_cred * scrp)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
smbfs_smb1_trans2find2(struct smbfs_fctx * ctx)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
smbfs_smb1_findclose2(struct smbfs_fctx * ctx)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
smbfs_smb_findopenLM2(struct smbfs_fctx * ctx,struct smbnode * dnp,const char * wildcard,int wclen,uint32_t attr)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
smbfs_smb_findcloseLM2(struct smbfs_fctx * ctx)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
smbfs_smb_findnextLM2(struct smbfs_fctx * ctx,uint16_t limit)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
smbfs_smb1_get_streaminfo(smbnode_t * np,struct mdchain * mdp,struct smb_cred * scrp)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
smbfs_smb1_getsec(struct smb_share * ssp,uint16_t fid,uint32_t selector,mblk_t ** res,uint32_t * reslen,struct smb_cred * scrp)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
smbfs_smb1_setsec(struct smb_share * ssp,uint16_t fid,uint32_t selector,mblk_t ** mp,struct smb_cred * scrp)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