xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c (revision 698f4ab6008be205f4362675967638572eef4f21)
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 2019 Nexenta 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
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
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
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
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
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
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
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
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
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
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
397 smbfs_smb_tmpclose(struct smbnode *np, smb_fh_t *fhp)
398 {
399 	smb_fh_rele(fhp);
400 }
401 
402 int
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 (0);
443 }
444 
445 void
446 smbfs_smb_close(smb_fh_t *fhp)
447 {
448 
449 	smb_fh_close(fhp);
450 	smb_fh_rele(fhp);
451 }
452 
453 int
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
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
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
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
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
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
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
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
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