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 */
64const uint64_t NT1980 = 11960035200ULL*10000000ULL;
65
66
67/*
68 * Helper for smbfs_getattr_otw
69 * used when we have an open FID
70 */
71int
72smbfs_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 */
98int
99smbfs_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 */
120int
121smbfs_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
144int
145smbfs_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
190int
191smbfs_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
205int
206smbfs_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 */
225int
226smbfs_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
279int
280smbfs_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 */
297int
298smbfs_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
332out:
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 */
346int
347smbfs_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
388out:
389	if (fhp != NULL)
390		smb_fh_rele(fhp);
391
392	return (error);
393}
394
395/* ARGSUSED */
396void
397smbfs_smb_tmpclose(struct smbnode *np, smb_fh_t *fhp)
398{
399	smb_fh_rele(fhp);
400}
401
402int
403smbfs_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
438out:
439	if (fhp != NULL)
440		smb_fh_rele(fhp);
441
442	return (0);
443}
444
445void
446smbfs_smb_close(smb_fh_t *fhp)
447{
448
449	smb_fh_close(fhp);
450	smb_fh_rele(fhp);
451}
452
453int
454smbfs_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
497out:
498	if (fhp != NULL)
499		smb_fh_rele(fhp);
500
501	return (error);
502}
503
504int
505smbfs_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
534int
535smbfs_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 */
575int
576smbfs_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
603out:
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
614int
615smbfs_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
673int
674smbfs_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
703int
704smbfs_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
760out:
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 */
771int
772smbfs_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
806done:
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 */
822int
823smbfs_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