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 2021 Tintri by DDN, 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/smb2.h>
52 #include <netsmb/smb_conn.h>
53 #include <netsmb/smb_subr.h>
54 #include <netsmb/smb_rq.h>
55
56 #include <smbfs/smbfs.h>
57 #include <smbfs/smbfs_node.h>
58 #include <smbfs/smbfs_subr.h>
59
60 /*
61 * Jan 1 1980 as 64 bit NT time.
62 * (tenths of microseconds since 1601)
63 */
64 const uint64_t NT1980 = 11960035200ULL*10000000ULL;
65
66
67 /*
68 * Helper for smbfs_getattr_otw
69 * used when we have an open FID
70 */
71 int
smbfs_smb_getfattr(struct smbnode * np,smb_fh_t * fhp,struct smbfattr * fap,struct smb_cred * scrp)72 smbfs_smb_getfattr(
73 struct smbnode *np,
74 smb_fh_t *fhp,
75 struct smbfattr *fap,
76 struct smb_cred *scrp)
77 {
78 struct smb_share *ssp = np->n_mount->smi_share;
79 int error;
80
81 if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
82 error = smbfs_smb2_qfileinfo(ssp, &fhp->fh_fid2, fap, scrp);
83 } else {
84 error = smbfs_smb1_trans2_query(np, fhp->fh_fid1, fap, scrp);
85 }
86
87 return (error);
88 }
89
90 /*
91 * Helper for smbfs_getattr_otw
92 * used when we don't have an open FID
93 *
94 * For SMB1 we can just use the path form of trans2 query.
95 * For SMB2 we need to do an attribute-only open.
96 * See smbfs_smb2_getpattr()
97 */
98 int
smbfs_smb_getpattr(struct smbnode * np,struct smbfattr * fap,struct smb_cred * scrp)99 smbfs_smb_getpattr(
100 struct smbnode *np,
101 struct smbfattr *fap,
102 struct smb_cred *scrp)
103 {
104 struct smb_share *ssp = np->n_mount->smi_share;
105 int error;
106
107 if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
108 error = smbfs_smb2_getpattr(np, fap, scrp);
109 } else {
110 uint16_t fid = SMB_FID_UNUSED;
111 error = smbfs_smb1_trans2_query(np, fid, fap, scrp);
112 }
113
114 return (error);
115 }
116
117 /*
118 * Get and parse FileFsAttributeInformation
119 */
120 int
smbfs_smb_qfsattr(struct smb_share * ssp,struct smb_fs_attr_info * fsa,struct smb_cred * scrp)121 smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
122 struct smb_cred *scrp)
123 {
124 int error;
125
126 if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
127 error = smbfs_smb2_qfsattr(ssp, fsa, scrp);
128 } else {
129 error = smbfs_smb1_qfsattr(ssp, fsa, scrp);
130 }
131
132 /*
133 * If fs_name starts with FAT, we can't set dates before 1980
134 */
135 if (0 == strncmp(fsa->fsa_tname, "FAT", 3)) {
136 SMB_SS_LOCK(ssp);
137 ssp->ss_flags |= SMBS_FST_FAT;
138 SMB_SS_UNLOCK(ssp);
139 }
140
141 return (error);
142 }
143
144 int
smbfs_smb_statfs(struct smb_share * ssp,statvfs64_t * sbp,struct smb_cred * scp)145 smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
146 struct smb_cred *scp)
147 {
148 struct smb_fs_size_info info;
149 struct smb_vc *vcp = SSTOVC(ssp);
150 uint32_t bps, spu;
151 int error;
152
153 if (vcp->vc_flags & SMBV_SMB2) {
154 error = smbfs_smb2_statfs(ssp, &info, scp);
155 } else {
156 error = smbfs_smb1_statfs(ssp, &info, scp);
157 }
158 if (error)
159 return (error);
160
161 /* A bit of paranoia. */
162 bps = info.bytes_per_sect;
163 if (bps < DEV_BSIZE)
164 bps = DEV_BSIZE;
165 spu = info.sect_per_unit;
166 if (spu == 0)
167 spu = 1;
168
169 /* preferred file system block size */
170 sbp->f_bsize = bps * spu;
171
172 /* file system block size ("fragment size") */
173 sbp->f_frsize = bps;
174
175 /* total blocks of f_frsize */
176 sbp->f_blocks = info.total_units * spu;
177
178 /* free blocks of f_frsize */
179 sbp->f_bfree = info.actual_avail * spu;
180
181 /* free blocks avail to non-superuser */
182 sbp->f_bavail = info.caller_avail * spu;
183
184 sbp->f_files = (-1); /* total file nodes in file system */
185 sbp->f_ffree = (-1); /* free file nodes in fs */
186
187 return (error);
188 }
189
190 int
smbfs_smb_setdisp(struct smb_share * ssp,smb_fh_t * fhp,uint8_t disp,struct smb_cred * scrp)191 smbfs_smb_setdisp(struct smb_share *ssp, smb_fh_t *fhp,
192 uint8_t disp, struct smb_cred *scrp)
193 {
194 int err;
195
196 if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
197 err = smbfs_smb2_setdisp(ssp, &fhp->fh_fid2, disp, scrp);
198 } else {
199 err = smbfs_smb1_setdisp(ssp, fhp->fh_fid1, disp, scrp);
200 }
201
202 return (err);
203 }
204
205 int
smbfs_smb_setfsize(struct smb_share * ssp,smb_fh_t * fhp,uint64_t size,struct smb_cred * scrp)206 smbfs_smb_setfsize(struct smb_share *ssp, smb_fh_t *fhp,
207 uint64_t size, struct smb_cred *scrp)
208 {
209 int error;
210
211 if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
212 error = smbfs_smb2_seteof(ssp, &fhp->fh_fid2, size, scrp);
213 } else {
214 error = smbfs_smb1_seteof(ssp, fhp->fh_fid1, size, scrp);
215 }
216
217 return (error);
218 }
219
220
221 /*
222 * Set file attributes (optionally: DOS attr, atime, mtime)
223 * Always have an open FID with set attr rights.
224 */
225 int
smbfs_smb_setfattr(struct smb_share * ssp,smb_fh_t * fhp,uint32_t attr,struct timespec * mtime,struct timespec * atime,struct smb_cred * scrp)226 smbfs_smb_setfattr(
227 struct smb_share *ssp,
228 smb_fh_t *fhp,
229 uint32_t attr,
230 struct timespec *mtime,
231 struct timespec *atime,
232 struct smb_cred *scrp)
233 {
234 struct mbchain mb_info;
235 struct mbchain *mbp = &mb_info;
236 uint64_t tm;
237 int error;
238
239 /*
240 * Build a struct FILE_BASIC_INFORMATION in mbp
241 * LARGE_INTEGER CreationTime;
242 * LARGE_INTEGER LastAccessTime;
243 * LARGE_INTEGER LastWriteTime;
244 * LARGE_INTEGER ChangeTime;
245 * ULONG FileAttributes;
246 * Zero in times means "no change".
247 */
248 mb_init(mbp);
249 mb_put_uint64le(mbp, 0); /* creation time */
250 if (atime) {
251 smb_time_local2NT(atime, &tm);
252 if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
253 tm < NT1980)
254 tm = NT1980;
255 } else
256 tm = 0;
257 mb_put_uint64le(mbp, tm); /* last access time */
258 if (mtime) {
259 smb_time_local2NT(mtime, &tm);
260 if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
261 tm < NT1980)
262 tm = NT1980;
263 } else
264 tm = 0;
265 mb_put_uint64le(mbp, tm); /* last write time */
266 mb_put_uint64le(mbp, 0); /* change time */
267 mb_put_uint32le(mbp, attr);
268 mb_put_uint32le(mbp, 0); /* reserved */
269
270 if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
271 error = smbfs_smb2_setfattr(ssp, &fhp->fh_fid2, mbp, scrp);
272 } else {
273 error = smbfs_smb1_setfattr(ssp, fhp->fh_fid1, mbp, scrp);
274 }
275
276 return (error);
277 }
278
279 int
smbfs_smb_flush(struct smb_share * ssp,smb_fh_t * fhp,struct smb_cred * scrp)280 smbfs_smb_flush(struct smb_share *ssp, smb_fh_t *fhp,
281 struct smb_cred *scrp)
282 {
283 int error;
284
285 if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
286 error = smbfs_smb2_flush(ssp, &fhp->fh_fid2, scrp);
287 } else {
288 error = smbfs_smb1_flush(ssp, fhp->fh_fid1, scrp);
289 }
290 return (error);
291 }
292
293 /*
294 * Modern create/open of file or directory.
295 * On success, fills in fhp->fh_fid* and fhp->fh_rights
296 */
297 int
smbfs_smb_ntcreatex(struct smbnode * np,const char * name,int nmlen,int xattr,uint32_t req_acc,uint32_t efa,uint32_t share_acc,uint32_t disp,uint32_t createopt,struct smb_cred * scrp,smb_fh_t * fhp,uint32_t * cr_act_p,struct smbfattr * fap)298 smbfs_smb_ntcreatex(
299 struct smbnode *np,
300 const char *name,
301 int nmlen,
302 int xattr, /* is named stream? */
303 uint32_t req_acc, /* requested access */
304 uint32_t efa, /* ext. file attrs (DOS attr +) */
305 uint32_t share_acc,
306 uint32_t disp, /* open disposition */
307 uint32_t createopt, /* NTCREATEX_OPTIONS_ */
308 struct smb_cred *scrp,
309 smb_fh_t *fhp, /* pre-made file handle to fill in */
310 uint32_t *cr_act_p, /* optional returned create action */
311 struct smbfattr *fap) /* optional returned attributes */
312 {
313 struct mbchain name_mb;
314 struct smb_share *ssp = np->n_mount->smi_share;
315 int err;
316
317 mb_init(&name_mb);
318
319 if (name == NULL)
320 nmlen = 0;
321 err = smbfs_fullpath(&name_mb, SSTOVC(ssp),
322 np, name, nmlen, xattr ? ':' : '\\');
323 if (err)
324 goto out;
325
326 err = smb_smb_ntcreate(ssp, &name_mb,
327 0, /* NTCREATEX_FLAGS... */
328 req_acc, efa, share_acc, disp, createopt,
329 NTCREATEX_IMPERSONATION_IMPERSONATION,
330 scrp, fhp, cr_act_p, fap);
331
332 out:
333 mb_done(&name_mb);
334
335 return (err);
336 }
337
338 /*
339 * Get a file handle with (at least) the specified rights.
340 *
341 * We'll try to borrow the node ->n_fid if we can. When we
342 * borrow n_fid, just take a hold on the smb_fh_t, and don't
343 * bump n_fidrefs as that tracks VFS-level opens. Similarly
344 * in _tmpclose we just release the smb_fh_t, not n_fidrefs.
345 */
346 int
smbfs_smb_tmpopen(struct smbnode * np,uint32_t rights,struct smb_cred * scrp,smb_fh_t ** fhpp)347 smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
348 smb_fh_t **fhpp)
349 {
350 struct smb_share *ssp = np->n_mount->smi_share;
351 smb_fh_t *fhp = NULL;
352 int error;
353
354 /* Can we re-use n_fid? or must we open anew? */
355 mutex_enter(&np->r_statelock);
356 if (np->n_fidrefs > 0 &&
357 (fhp = np->n_fid) != NULL &&
358 fhp->fh_vcgenid == ssp->ss_vcgenid &&
359 (fhp->fh_rights & rights) == rights) {
360 smb_fh_hold(fhp);
361 *fhpp = fhp;
362 mutex_exit(&np->r_statelock);
363 return (0);
364 }
365 mutex_exit(&np->r_statelock);
366
367 error = smb_fh_create(ssp, &fhp);
368 if (error != 0)
369 goto out;
370
371 /* re-open an existing file. */
372 error = smbfs_smb_ntcreatex(np,
373 NULL, 0, 0, /* name nmlen xattr */
374 rights, SMB_EFA_NORMAL,
375 NTCREATEX_SHARE_ACCESS_ALL,
376 NTCREATEX_DISP_OPEN,
377 0, /* create options */
378 scrp, fhp,
379 NULL, NULL); /* cr_act_p fa_p */
380 if (error != 0)
381 goto out;
382
383 fhp->fh_rights = rights;
384 smb_fh_opened(fhp);
385 *fhpp = fhp;
386 fhp = NULL;
387
388 out:
389 if (fhp != NULL)
390 smb_fh_rele(fhp);
391
392 return (error);
393 }
394
395 /* ARGSUSED */
396 void
smbfs_smb_tmpclose(struct smbnode * np,smb_fh_t * fhp)397 smbfs_smb_tmpclose(struct smbnode *np, smb_fh_t *fhp)
398 {
399 smb_fh_rele(fhp);
400 }
401
402 int
smbfs_smb_open(struct smbnode * np,const char * name,int nmlen,int xattr,uint32_t rights,struct smb_cred * scrp,smb_fh_t ** fhpp,smbfattr_t * fap)403 smbfs_smb_open(
404 struct smbnode *np,
405 const char *name,
406 int nmlen,
407 int xattr,
408 uint32_t rights,
409 struct smb_cred *scrp,
410 smb_fh_t **fhpp,
411 smbfattr_t *fap)
412 {
413 struct smb_share *ssp = np->n_mount->smi_share;
414 // struct smb_vc *vcp = SSTOVC(ssp);
415 smb_fh_t *fhp = NULL;
416 int error;
417
418 error = smb_fh_create(ssp, &fhp);
419 if (error != 0)
420 goto out;
421
422 /* open an existing file */
423 error = smbfs_smb_ntcreatex(np,
424 name, nmlen, xattr,
425 rights, SMB_EFA_NORMAL,
426 NTCREATEX_SHARE_ACCESS_ALL,
427 NTCREATEX_DISP_OPEN,
428 0, /* create options */
429 scrp, fhp, NULL, fap);
430 if (error != 0)
431 goto out;
432
433 fhp->fh_rights = rights;
434 smb_fh_opened(fhp);
435 *fhpp = fhp;
436 fhp = NULL;
437
438 out:
439 if (fhp != NULL)
440 smb_fh_rele(fhp);
441
442 return (error);
443 }
444
445 void
smbfs_smb_close(smb_fh_t * fhp)446 smbfs_smb_close(smb_fh_t *fhp)
447 {
448
449 smb_fh_close(fhp);
450 smb_fh_rele(fhp);
451 }
452
453 int
smbfs_smb_create(struct smbnode * dnp,const char * name,int nmlen,int xattr,uint32_t disp,struct smb_cred * scrp,smb_fh_t ** fhpp)454 smbfs_smb_create(
455 struct smbnode *dnp,
456 const char *name,
457 int nmlen,
458 int xattr,
459 uint32_t disp,
460 struct smb_cred *scrp,
461 smb_fh_t **fhpp)
462 {
463 struct smb_share *ssp = dnp->n_mount->smi_share;
464 // struct smb_vc *vcp = SSTOVC(ssp);
465 smb_fh_t *fhp = NULL;
466 uint32_t efa, rights;
467 int error;
468
469 error = smb_fh_create(ssp, &fhp);
470 if (error != 0)
471 goto out;
472
473 /*
474 * At present the only access we might need is to WRITE data,
475 * and that only if we are creating a "symlink". When/if the
476 * access needed gets more complex it should made a parameter
477 * and be set upstream.
478 */
479 rights = SA_RIGHT_FILE_WRITE_DATA;
480 efa = SMB_EFA_NORMAL;
481 if (!xattr && name && *name == '.')
482 efa = SMB_EFA_HIDDEN;
483 error = smbfs_smb_ntcreatex(dnp,
484 name, nmlen, xattr, rights, efa,
485 NTCREATEX_SHARE_ACCESS_ALL,
486 disp, /* != NTCREATEX_DISP_OPEN */
487 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
488 scrp, fhp, NULL, NULL);
489 if (error != 0)
490 goto out;
491
492 fhp->fh_rights = rights;
493 smb_fh_opened(fhp);
494 *fhpp = fhp;
495 fhp = NULL;
496
497 out:
498 if (fhp != NULL)
499 smb_fh_rele(fhp);
500
501 return (error);
502 }
503
504 int
smbfs_smb_rename(struct smbnode * sdnp,struct smbnode * np,struct smbnode * tdnp,const char * tname,int tnlen,smb_fh_t * fhp,struct smb_cred * scrp)505 smbfs_smb_rename(struct smbnode *sdnp, struct smbnode *np,
506 struct smbnode *tdnp, const char *tname, int tnlen,
507 smb_fh_t *fhp, struct smb_cred *scrp)
508 {
509 struct smb_share *ssp = np->n_mount->smi_share;
510 struct smb_vc *vcp = SSTOVC(ssp);
511 int err;
512
513 if (vcp->vc_flags & SMBV_SMB2) {
514 err = smbfs_smb2_rename(np, tdnp, tname, tnlen, 0,
515 &fhp->fh_fid2, scrp);
516 return (err);
517 }
518
519 /*
520 * SMB1 -- Want to use _t2rename if we can
521 * (rename in same dir and cap pass-through)
522 * Most SMB1 servers have cap pass-through.
523 */
524 if (sdnp == tdnp &&
525 (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) != 0) {
526 err = smbfs_smb1_t2rename(np, tname, tnlen, fhp->fh_fid1, scrp);
527 } else {
528 err = smbfs_smb1_oldrename(np, tdnp, tname, tnlen, scrp);
529 }
530
531 return (err);
532 }
533
534 int
smbfs_smb_mkdir(struct smbnode * dnp,const char * name,int nmlen,struct smb_cred * scrp)535 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen,
536 struct smb_cred *scrp)
537 {
538 smb_fh_t tmp_fh;
539 struct smb_share *ssp = dnp->n_mount->smi_share;
540 uint32_t efa, rights;
541 int error;
542
543 /*
544 * Using a faked-up handle here to avoid the work of
545 * creating and destroying a real "conn obj".
546 */
547 bzero(&tmp_fh, sizeof (tmp_fh));
548
549 /*
550 * We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
551 * just to be asking for something. The rights==0 case could
552 * easily be broken on some old or unusual servers.
553 */
554 rights = SA_RIGHT_FILE_READ_DATA;
555 efa = SMB_EFA_NORMAL;
556 if (name && *name == '.')
557 efa |= SMB_EFA_HIDDEN;
558 error = smbfs_smb_ntcreatex(dnp,
559 name, nmlen, 0, /* xattr */
560 rights, SMB_EFA_DIRECTORY,
561 NTCREATEX_SHARE_ACCESS_ALL,
562 NTCREATEX_DISP_CREATE,
563 NTCREATEX_OPTIONS_DIRECTORY,
564 scrp, &tmp_fh, NULL, NULL);
565 if (error == 0) {
566 (void) smb_smb_close(ssp, &tmp_fh, scrp);
567 }
568
569 return (error);
570 }
571
572 /*
573 * Protocol-level directory open
574 */
575 int
smbfs_smb_findopen(struct smbnode * dnp,const char * wild,int wlen,int attr,struct smb_cred * scrp,struct smbfs_fctx ** ctxpp)576 smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
577 int attr, struct smb_cred *scrp,
578 struct smbfs_fctx **ctxpp)
579 {
580 struct smb_share *ssp = dnp->n_mount->smi_share;
581 struct smb_vc *vcp = SSTOVC(ssp);
582 struct smbfs_fctx *ctx;
583 int error;
584
585 ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
586
587 ctx->f_flags = SMBFS_RDD_FINDFIRST;
588 ctx->f_dnp = dnp;
589 ctx->f_scred = scrp;
590 ctx->f_ssp = ssp;
591
592 if (dnp->n_flag & N_XATTR) {
593 error = smbfs_xa_findopen(ctx, dnp, wild, wlen);
594 goto out;
595 }
596
597 if (vcp->vc_flags & SMBV_SMB2) {
598 error = smbfs_smb2_findopen(ctx, dnp, wild, wlen, attr);
599 } else {
600 error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr);
601 }
602
603 out:
604 ctx->f_scred = NULL;
605 if (error) {
606 kmem_free(ctx, sizeof (*ctx));
607 } else {
608 *ctxpp = ctx;
609 }
610
611 return (error);
612 }
613
614 int
smbfs_smb_findnext(struct smbfs_fctx * ctx,int limit,struct smb_cred * scrp)615 smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
616 {
617 int error = 0;
618 uint16_t lim;
619
620 /*
621 * Note: "limit" (maxcount) needs to fit in a short!
622 */
623 if (limit > 0xffff)
624 limit = 0xffff;
625 lim = (uint16_t)limit;
626
627 ctx->f_scred = scrp;
628 for (;;) {
629 bzero(&ctx->f_attr, sizeof (ctx->f_attr));
630 switch (ctx->f_type) {
631
632 case ft_SMB2:
633 error = smbfs_smb2_findnext(ctx, lim);
634 break;
635 case ft_LM2:
636 error = smbfs_smb_findnextLM2(ctx, lim);
637 break;
638 case ft_XA:
639 error = smbfs_xa_findnext(ctx, lim);
640 break;
641 default:
642 ASSERT(0);
643 error = EINVAL;
644 break;
645 }
646 if (error)
647 break;
648 /*
649 * Skip "." or ".." - easy now that ctx->f_name
650 * has already been converted to utf-8 format.
651 */
652 if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
653 (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
654 ctx->f_name[1] == '.'))
655 continue;
656 break;
657 }
658 ctx->f_scred = NULL;
659 if (error != 0)
660 return (error);
661
662 ctx->f_inum = smbfs_getino(ctx->f_dnp,
663 ctx->f_name, ctx->f_nmlen);
664
665 #ifdef DEBUG
666 SMBVDEBUG("findnext: (%s)\n", ctx->f_name);
667 #endif
668
669 return (error);
670 }
671
672
673 int
smbfs_smb_findclose(struct smbfs_fctx * ctx,struct smb_cred * scrp)674 smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
675 {
676 int error;
677
678 ctx->f_scred = scrp;
679 switch (ctx->f_type) {
680 case ft_SMB2:
681 error = smbfs_smb2_findclose(ctx);
682 break;
683 case ft_LM2:
684 error = smbfs_smb_findcloseLM2(ctx);
685 break;
686 case ft_XA:
687 error = smbfs_xa_findclose(ctx);
688 break;
689 default:
690 error = ENOSYS;
691 break;
692 }
693 ctx->f_scred = NULL;
694 if (ctx->f_rname)
695 kmem_free(ctx->f_rname, ctx->f_rnamelen);
696 if (ctx->f_firstnm)
697 kmem_free(ctx->f_firstnm, ctx->f_firstnmlen);
698 kmem_free(ctx, sizeof (*ctx));
699 return (error);
700 }
701
702
703 int
smbfs_smb_lookup(struct smbnode * dnp,const char ** namep,int * nmlenp,struct smbfattr * fap,struct smb_cred * scrp)704 smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
705 struct smbfattr *fap, struct smb_cred *scrp)
706 {
707 struct smbfs_fctx *ctx;
708 int error, intr;
709 const char *name = (namep ? *namep : NULL);
710 int nmlen = (nmlenp ? *nmlenp : 0);
711
712 /* This is no longer called with a null dnp */
713 ASSERT(dnp);
714
715 /*
716 * Should not get here with "" anymore.
717 */
718 if (!name || !nmlen) {
719 DEBUG_ENTER("smbfs_smb_lookup: name is NULL");
720 return (EINVAL);
721 }
722
723 /*
724 * Should not get here with "." or ".." anymore.
725 */
726 if ((nmlen == 1 && name[0] == '.') ||
727 (nmlen == 2 && name[0] == '.' && name[1] == '.')) {
728 DEBUG_ENTER("smbfs_smb_lookup: name is '.' or '..'");
729 return (EINVAL);
730 }
731
732 /*
733 * Shared lock for n_fid use (smb_flush).
734 */
735 intr = dnp->n_mount->smi_flags & SMI_INT;
736 if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr))
737 return (EINTR);
738
739 error = smbfs_smb_findopen(dnp, name, nmlen,
740 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx);
741 if (error)
742 goto out;
743 ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
744 error = smbfs_smb_findnext(ctx, 1, scrp);
745 if (error == 0) {
746 *fap = ctx->f_attr;
747 /*
748 * Solaris smbfattr doesn't have fa_ino,
749 * and we don't allow name==NULL in this
750 * function anymore.
751 */
752 if (namep)
753 *namep = (const char *)smbfs_name_alloc(
754 ctx->f_name, ctx->f_nmlen);
755 if (nmlenp)
756 *nmlenp = ctx->f_nmlen;
757 }
758 (void) smbfs_smb_findclose(ctx, scrp);
759
760 out:
761 smbfs_rw_exit(&dnp->r_lkserlock);
762 return (error);
763 }
764
765 /*
766 * OTW function to Get a security descriptor (SD).
767 *
768 * Note: On success, this fills in mdp->md_top,
769 * which the caller should free.
770 */
771 int
smbfs_smb_getsec(struct smb_share * ssp,smb_fh_t * fhp,uint32_t selector,mblk_t ** res,uint32_t * reslen,struct smb_cred * scrp)772 smbfs_smb_getsec(struct smb_share *ssp, smb_fh_t *fhp,
773 uint32_t selector, mblk_t **res, uint32_t *reslen,
774 struct smb_cred *scrp)
775 {
776 struct smb_vc *vcp = SSTOVC(ssp);
777 int error, len;
778
779 *res = NULL;
780
781 if (vcp->vc_flags & SMBV_SMB2) {
782 error = smbfs_smb2_getsec(ssp, &fhp->fh_fid2,
783 selector, res, reslen, scrp);
784 } else {
785 error = smbfs_smb1_getsec(ssp, fhp->fh_fid1,
786 selector, res, reslen, scrp);
787 }
788
789 /*
790 * get the data part.
791 */
792 if (*res == NULL) {
793 error = EBADRPC;
794 goto done;
795 }
796
797 /*
798 * If message length is < returned SD_length,
799 * correct *reslen (reduce it). It greater,
800 * just ignore the extra data.
801 */
802 len = m_fixhdr(*res);
803 if (len < *reslen)
804 *reslen = len;
805
806 done:
807 if (error == 0 && *res == NULL) {
808 ASSERT(*res);
809 error = EBADRPC;
810 }
811
812 return (error);
813 }
814
815 /*
816 * OTW function to Set a security descriptor (SD).
817 * Caller data are carried in an mbchain_t.
818 *
819 * Note: This normally consumes mbp->mb_top, and clears
820 * that pointer when it does.
821 */
822 int
smbfs_smb_setsec(struct smb_share * ssp,smb_fh_t * fhp,uint32_t selector,mblk_t ** mp,struct smb_cred * scrp)823 smbfs_smb_setsec(struct smb_share *ssp, smb_fh_t *fhp,
824 uint32_t selector, mblk_t **mp,
825 struct smb_cred *scrp)
826 {
827 struct smb_vc *vcp = SSTOVC(ssp);
828 int error;
829
830 if (vcp->vc_flags & SMBV_SMB2) {
831 error = smbfs_smb2_setsec(ssp, &fhp->fh_fid2,
832 selector, mp, scrp);
833 } else {
834 error = smbfs_smb1_setsec(ssp, fhp->fh_fid1,
835 selector, mp, scrp);
836 }
837
838 return (error);
839 }
840