summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/Makefile2
-rw-r--r--usr/src/lib/libfakekernel/Makefile.com7
-rw-r--r--usr/src/lib/libfakekernel/common/copy.c30
-rw-r--r--usr/src/lib/libfakekernel/common/cred.c60
-rw-r--r--usr/src/lib/libfakekernel/common/kmisc.c13
-rw-r--r--usr/src/lib/libfakekernel/common/mapfile-vers12
-rw-r--r--usr/src/lib/libfakekernel/common/printf.c29
-rw-r--r--usr/src/lib/libfakekernel/common/rwlock.c1
-rw-r--r--usr/src/lib/libfakekernel/common/sys/cmn_err.h8
-rw-r--r--usr/src/lib/libfakekernel/common/sys/cred.h5
-rw-r--r--usr/src/lib/libfakekernel/common/sys/cyclic.h87
-rw-r--r--usr/src/lib/libfakekernel/common/uio.c4
-rw-r--r--usr/src/lib/libproc/common/libproc.h4
-rw-r--r--usr/src/lib/libproc/common/mapfile-vers3
-rw-r--r--usr/src/lib/libproc/common/proc_names.c40
-rw-r--r--usr/src/lib/libshare/smbfs/libshare_smbfs.c39
-rw-r--r--usr/src/lib/libshare/smbfs/libshare_smbfs.h6
-rw-r--r--usr/src/lib/libsmbfs/Makefile.com27
-rw-r--r--usr/src/lib/libsmbfs/cflib.h4
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smb_lib.h45
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smbfs_api.h7
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip2
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip2
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip2
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip2
-rw-r--r--usr/src/lib/libsmbfs/smb/acl_api.c8
-rw-r--r--usr/src/lib/libsmbfs/smb/connect.c650
-rw-r--r--usr/src/lib/libsmbfs/smb/ctx.c246
-rw-r--r--usr/src/lib/libsmbfs/smb/file.c51
-rw-r--r--usr/src/lib/libsmbfs/smb/findvc.c7
-rw-r--r--usr/src/lib/libsmbfs/smb/getaddr.c17
-rw-r--r--usr/src/lib/libsmbfs/smb/iod_wk.c96
-rw-r--r--usr/src/lib/libsmbfs/smb/keychain.c6
-rw-r--r--usr/src/lib/libsmbfs/smb/krb5ssp.c61
-rw-r--r--usr/src/lib/libsmbfs/smb/lgrep.awk68
-rw-r--r--usr/src/lib/libsmbfs/smb/mapfile-vers31
-rw-r--r--usr/src/lib/libsmbfs/smb/nb_ssn.c336
-rw-r--r--usr/src/lib/libsmbfs/smb/negprot.c457
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlm.c47
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlm.h20
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlmssp.c113
-rw-r--r--usr/src/lib/libsmbfs/smb/print.c33
-rw-r--r--usr/src/lib/libsmbfs/smb/private.h68
-rw-r--r--usr/src/lib/libsmbfs/smb/rap.c446
-rw-r--r--usr/src/lib/libsmbfs/smb/rc_scf.c231
-rw-r--r--usr/src/lib/libsmbfs/smb/rcfile.c86
-rw-r--r--usr/src/lib/libsmbfs/smb/rcfile_priv.h28
-rw-r--r--usr/src/lib/libsmbfs/smb/rq.c467
-rw-r--r--usr/src/lib/libsmbfs/smb/signing.c263
-rw-r--r--usr/src/lib/libsmbfs/smb/ssnsetup.c459
-rw-r--r--usr/src/lib/smbclnt/Makefile24
-rw-r--r--usr/src/lib/smbclnt/Makefile.lib51
-rw-r--r--usr/src/lib/smbclnt/Makefile.smbclnt66
-rw-r--r--usr/src/lib/smbclnt/Makefile.subdirs43
-rw-r--r--usr/src/lib/smbclnt/Makefile.targ50
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/Makefile16
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/Makefile.com109
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/amd64/Makefile21
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_ddi.c133
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_fio.c105
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_kmem.c45
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_ktli.c432
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_pkey.c48
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_policy.c90
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_sdt.c50
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_softc.c263
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_stream.c1377
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_strsubr.c160
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_xti.h314
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c163
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/libfknsmb.h45
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/llib-lfknsmb19
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers134
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/ftrace.h67
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/kidmap.h183
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/policy.h50
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/sdt.h70
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/strft.h65
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/sunddi.h141
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/vfs.h622
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/vfs_opreg.h116
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/vnode.h1452
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/i386/Makefile18
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/sparc/Makefile18
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/sparcv9/Makefile23
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/Makefile16
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/Makefile.com139
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/amd64/Makefile23
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_fssub.c432
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_getdents.c96
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_lookup.c173
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_misc.c108
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_modconf.c195
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_nbmlock.c124
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_open.c340
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_rename.c123
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_rw.c203
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_stat.c96
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_unlink.c91
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_vfs.c2155
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_vnode.c2026
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_zone.c76
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fksmbfs_rwlock.c235
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/libfksmbfs.h73
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/llib-lfksmbfs19
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/mapfile-vers68
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/i386/Makefile20
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/sparc/Makefile20
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/sparcv9/Makefile24
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c4
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c4
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samlib.c8
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c4
113 files changed, 14866 insertions, 3348 deletions
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index a6877bb589..c0c5625ad5 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -271,6 +271,7 @@ SUBDIRS += \
rpcsec_gss \
sasl_plugins \
scsi \
+ smbclnt \
smbsrv \
smhba \
sun_fc \
@@ -722,6 +723,7 @@ raidcfg_plugins: libraidcfg librcm libcfgadm libpicl libpicltree
rpcsec_gss: libgss
sasl_plugins: pkcs11 libgss libsasl
scsi: libfru libumem libdevid libdevinfo
+smbclnt: libfakekernel pkcs11
smbsrv: libxnet libpthread librt libshare libidmap pkcs11 libsqlite \
libcryptoutil libreparse libcmdutils libresolv2 libsmbfs \
libuuid libfakekernel libads libgss libldap5 krb5 libmlrpc
diff --git a/usr/src/lib/libfakekernel/Makefile.com b/usr/src/lib/libfakekernel/Makefile.com
index ef1abe4072..f9135717e6 100644
--- a/usr/src/lib/libfakekernel/Makefile.com
+++ b/usr/src/lib/libfakekernel/Makefile.com
@@ -56,10 +56,15 @@ $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
CSTD = $(CSTD_GNU99)
C99LMODE = -Xc99=%all
+CFLAGS += $(CCVERBOSE)
+
# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+# Also Note: intentionally override CPPFLAGS, not +=
CPPFLAGS.first += -I../common
+CPPFLAGS= $(CPPFLAGS.first)
+
+INCS += -I$(SRC)/uts/common
-CFLAGS += $(CCVERBOSE)
CPPFLAGS += $(INCS) -D_REENTRANT -D_FAKE_KERNEL
CPPFLAGS += -D_FILE_OFFSET_BITS=64
diff --git a/usr/src/lib/libfakekernel/common/copy.c b/usr/src/lib/libfakekernel/common/copy.c
index b1eb215b5c..77bf2e8415 100644
--- a/usr/src/lib/libfakekernel/common/copy.c
+++ b/usr/src/lib/libfakekernel/common/copy.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
@@ -20,6 +20,20 @@
#include <sys/errno.h>
int
+copyin(const void *u, void *k, size_t s)
+{
+ bcopy(u, k, s);
+ return (0);
+}
+
+int
+copyout(const void *k, void *u, size_t s)
+{
+ bcopy(k, u, s);
+ return (0);
+}
+
+int
copyinstr(const char *src, char *dst, size_t max_len, size_t *copied)
{
return (copystr(src, dst, max_len, copied));
@@ -48,3 +62,17 @@ ovbcopy(const void *src, void *dst, size_t len)
{
(void) memmove(dst, src, len);
}
+
+/* ARGSUSED */
+int
+ddi_copyin(const void *buf, void *kernbuf, size_t size, int flags)
+{
+ return (copyin(buf, kernbuf, size));
+}
+
+/* ARGSUSED */
+int
+ddi_copyout(const void *buf, void *kernbuf, size_t size, int flags)
+{
+ return (copyout(buf, kernbuf, size));
+}
diff --git a/usr/src/lib/libfakekernel/common/cred.c b/usr/src/lib/libfakekernel/common/cred.c
index 1563f02ac9..0920599d0a 100644
--- a/usr/src/lib/libfakekernel/common/cred.c
+++ b/usr/src/lib/libfakekernel/common/cred.c
@@ -10,28 +10,51 @@
*/
/*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* Copyright 2017 RackTop Systems.
*/
-
#include <sys/types.h>
#include <sys/time.h>
#include <sys/thread.h>
#include <sys/cred.h>
+#include <sys/sid.h>
+#include <strings.h>
+
+/*
+ * This library does not implement real credentials. All contexts
+ * use an opaque cred_t object, and all activity happens in the
+ * context of the user who runs the program.
+ */
+
+extern struct zone zone0;
struct cred {
+ uid_t cr_uid;
+ ksid_t *cr_ksid;
uint32_t pad[100];
};
cred_t cred0;
cred_t *kcred = &cred0;
+/*
+ * Note that fksmbd uses CRED() for SMB user logons, but uses
+ * zone_kcred() for operations done internally by the server.
+ * Let CRED() (_curcred()) return &cred1, so it's different from
+ * kcred, otherwise tests like: (cred == kcred) are always true.
+ * Also, only cred1 will have a ksid (not kcred).
+ * The UID and SID are both "nobody".
+ */
+ksiddomain_t ksdom1 = {1, 5, "S-1-0", {0}};
+ksid_t ksid1 = { 60001, 0, 0, &ksdom1};
+cred_t cred1 = { 60001, &ksid1 };
+
cred_t *
_curcred(void)
{
/* Thread-specific data? */
- return (&cred0);
+ return (&cred1);
}
/*ARGSUSED*/
@@ -50,14 +73,14 @@ crhold(cred_t *cr)
uid_t
crgetuid(const cred_t *cr)
{
- return (0);
+ return (cr->cr_uid);
}
/*ARGSUSED*/
uid_t
crgetruid(const cred_t *cr)
{
- return (0);
+ return (cr->cr_uid);
}
/*ARGSUSED*/
@@ -81,8 +104,35 @@ crgetgroups(const cred_t *cr)
return (NULL);
}
+/*ARGSUSED*/
+zoneid_t
+crgetzoneid(const cred_t *cr)
+{
+ return (GLOBAL_ZONEID);
+}
+
+/*ARGSUSED*/
+struct zone *
+crgetzone(const cred_t *cr)
+{
+ return (&zone0);
+}
+
cred_t *
zone_kcred(void)
{
return (kcred);
}
+
+/*ARGSUSED*/
+ksid_t *
+crgetsid(const cred_t *cr, int i)
+{
+ return (cr->cr_ksid);
+}
+
+cred_t *
+ddi_get_cred(void)
+{
+ return (_curcred());
+}
diff --git a/usr/src/lib/libfakekernel/common/kmisc.c b/usr/src/lib/libfakekernel/common/kmisc.c
index 2849552a66..5feaa66a28 100644
--- a/usr/src/lib/libfakekernel/common/kmisc.c
+++ b/usr/src/lib/libfakekernel/common/kmisc.c
@@ -30,9 +30,12 @@
#include <fakekernel.h>
pri_t minclsyspri = 60;
+extern zone_t zone0;
/* Some kernel code takes the address of this. */
-proc_t p0;
+proc_t p0 = {
+ .p_zone = &zone0, 0
+};
proc_t *
_curproc(void)
@@ -99,11 +102,10 @@ ddi_strtoul(const char *str, char **endp, int base, unsigned long *res)
}
int
-ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *res)
+ddi_strtoull(const char *str, char **endp, int base, u_longlong_t *res)
{
- char *end;
-
- *res = strtoull(str, &end, base);
+ errno = 0;
+ *res = strtoull(str, endp, base);
if (*res == 0)
return (errno);
return (0);
@@ -116,6 +118,7 @@ delay(clock_t ticks)
(void) poll(0, 0, msec);
}
+/* ARGSUSED */
int
issig(int why)
{
diff --git a/usr/src/lib/libfakekernel/common/mapfile-vers b/usr/src/lib/libfakekernel/common/mapfile-vers
index 1c41dd9b58..aa59ad2e46 100644
--- a/usr/src/lib/libfakekernel/common/mapfile-vers
+++ b/usr/src/lib/libfakekernel/common/mapfile-vers
@@ -43,7 +43,9 @@ SYMBOL_VERSION SUNWprivate_1.1 {
aok { FLAGS = NODIRECT };
boot_time;
cmn_err;
+ copyin;
copyinstr;
+ copyout;
copystr;
cyclic_add;
@@ -56,6 +58,8 @@ SYMBOL_VERSION SUNWprivate_1.1 {
crgetgid;
crgetngroups;
crgetgroups;
+ crgetzone;
+ crgetzoneid;
crhold;
cv_broadcast;
@@ -70,12 +74,16 @@ SYMBOL_VERSION SUNWprivate_1.1 {
cv_wait;
cv_wait_sig;
+ ddi_copyin;
+ ddi_copyout;
+ ddi_get_cred;
ddi_get_lbolt64;
ddi_get_lbolt;
ddi_get_pid;
ddi_strtoul;
ddi_strtoull;
+ debug_enter;
delay;
fm_panic;
@@ -197,7 +205,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
strfree;
system_taskq;
- system_taskq_fini;
+ system_taskq_fini;
system_taskq_init;
taskq_create;
taskq_create_proc;
@@ -227,8 +235,10 @@ SYMBOL_VERSION SUNWprivate_1.1 {
vcmn_err;
vmem_qcache_reap;
vpanic;
+ vzprintf;
zone0;
zone_kcred;
+ zprintf;
zthread_create;
zthread_exit;
diff --git a/usr/src/lib/libfakekernel/common/printf.c b/usr/src/lib/libfakekernel/common/printf.c
index c8f459dd8c..bbf350b75e 100644
--- a/usr/src/lib/libfakekernel/common/printf.c
+++ b/usr/src/lib/libfakekernel/common/printf.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* Copyright 2017 RackTop Systems.
* Copyright (c) 2018, Joyent, Inc.
*/
@@ -36,6 +36,7 @@
#include <fakekernel.h>
void abort(void) __NORETURN;
+void debug_enter(char *);
char *volatile panicstr;
va_list panicargs;
@@ -100,6 +101,24 @@ fakekernel_cprintf(const char *fmt, va_list adx, int flags,
fakekernel_putlog(bufp, len, flags);
}
+/* ARGSUSED */
+void
+vzprintf(zoneid_t zoneid, const char *fmt, va_list adx)
+{
+ fakekernel_cprintf(fmt, adx, SL_CONSOLE | SL_NOTE, "", "");
+}
+
+/*PRINTFLIKE2*/
+void
+zprintf(zoneid_t zoneid, const char *fmt, ...)
+{
+ va_list adx;
+
+ va_start(adx, fmt);
+ vzprintf(zoneid, fmt, adx);
+ va_end(adx);
+}
+
/*
* "User-level crash dump", if you will.
*/
@@ -116,6 +135,7 @@ vpanic(const char *fmt, va_list adx)
/* Call libc`assfail() so that mdb ::status works */
(void) vsnprintf(panicbuf, sizeof (panicbuf), fmt, adx);
+ debug_enter(panicbuf);
(void) assfail(panicbuf, "(panic)", 0);
abort(); /* avoid "noreturn" warnings */
@@ -164,3 +184,10 @@ cmn_err(int ce, const char *fmt, ...)
vcmn_err(ce, fmt, adx);
va_end(adx);
}
+
+/* ARGSUSED */
+void
+debug_enter(char *str)
+{
+ /* Just a place for a break point. */
+}
diff --git a/usr/src/lib/libfakekernel/common/rwlock.c b/usr/src/lib/libfakekernel/common/rwlock.c
index 17b4ca604d..edc9bfd092 100644
--- a/usr/src/lib/libfakekernel/common/rwlock.c
+++ b/usr/src/lib/libfakekernel/common/rwlock.c
@@ -23,7 +23,6 @@
#include <sys/errno.h>
#include <sys/debug.h>
#include <sys/param.h>
-#include <sys/synch32.h>
#include <sys/thread.h>
/* avoiding synch.h */
diff --git a/usr/src/lib/libfakekernel/common/sys/cmn_err.h b/usr/src/lib/libfakekernel/common/sys/cmn_err.h
index c77b22b868..b9818f58c5 100644
--- a/usr/src/lib/libfakekernel/common/sys/cmn_err.h
+++ b/usr/src/lib/libfakekernel/common/sys/cmn_err.h
@@ -64,6 +64,10 @@ extern void cmn_err(int, const char *, ...)
extern void vcmn_err(int, const char *, __va_list)
__KVPRINTFLIKE(2);
+/*PRINTFLIKE3*/
+extern void zcmn_err(zoneid_t, int, const char *, ...)
+ __KPRINTFLIKE(3);
+
/*PRINTFLIKE1*/
extern void panic(const char *, ...)
__KPRINTFLIKE(1) __NORETURN;
@@ -71,6 +75,10 @@ extern void panic(const char *, ...)
extern void vpanic(const char *, __va_list)
__KVPRINTFLIKE(1) __NORETURN;
+/*PRINTFLIKE2*/
+extern void zprintf(zoneid_t, const char *, ...)
+ __KPRINTFLIKE(2);
+
#endif /* !_ASM && (_KERNEL || _FAKE_KERNEL) */
#ifdef __cplusplus
diff --git a/usr/src/lib/libfakekernel/common/sys/cred.h b/usr/src/lib/libfakekernel/common/sys/cred.h
index d544e04275..a338214843 100644
--- a/usr/src/lib/libfakekernel/common/sys/cred.h
+++ b/usr/src/lib/libfakekernel/common/sys/cred.h
@@ -27,7 +27,7 @@
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley 4.3 BSD
@@ -66,6 +66,8 @@ extern void cred_init(void);
extern void crhold(cred_t *);
extern void crfree(cred_t *);
+extern int groupmember(gid_t, const cred_t *);
+
extern cred_t *zone_kcred(void);
extern uid_t crgetuid(const cred_t *);
@@ -75,6 +77,7 @@ extern gid_t crgetgid(const cred_t *);
extern gid_t crgetrgid(const cred_t *);
extern gid_t crgetsgid(const cred_t *);
extern zoneid_t crgetzoneid(const cred_t *);
+extern struct zone *crgetzone(const cred_t *);
extern projid_t crgetprojid(const cred_t *);
extern const gid_t *crgetgroups(const cred_t *);
diff --git a/usr/src/lib/libfakekernel/common/sys/cyclic.h b/usr/src/lib/libfakekernel/common/sys/cyclic.h
new file mode 100644
index 0000000000..56589ae7f1
--- /dev/null
+++ b/usr/src/lib/libfakekernel/common/sys/cyclic.h
@@ -0,0 +1,87 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 RackTop Systems.
+ */
+
+#ifndef _SYS_CYCLIC_H
+#define _SYS_CYCLIC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ASM
+#include <sys/time.h>
+#endif /* !_ASM */
+
+#define CY_LOW_LEVEL 0
+#define CY_LOCK_LEVEL 1
+#define CY_HIGH_LEVEL 2
+#define CY_SOFT_LEVELS 2
+#define CY_LEVELS 3
+
+#ifndef _ASM
+
+typedef uintptr_t cyclic_id_t;
+typedef int cyc_index_t;
+typedef int cyc_cookie_t;
+typedef uint16_t cyc_level_t;
+typedef void (*cyc_func_t)(void *);
+typedef void *cyb_arg_t;
+
+#define CYCLIC_NONE ((cyclic_id_t)0)
+
+typedef struct cyc_handler {
+ cyc_func_t cyh_func;
+ void *cyh_arg;
+ cyc_level_t cyh_level;
+} cyc_handler_t;
+
+typedef struct cyc_time {
+ hrtime_t cyt_when;
+ hrtime_t cyt_interval;
+} cyc_time_t;
+
+#define CY_INFINITY INT64_MAX
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+extern cyclic_id_t cyclic_add(cyc_handler_t *, cyc_time_t *);
+extern void cyclic_remove(cyclic_id_t);
+extern int cyclic_reprogram(cyclic_id_t, hrtime_t);
+extern hrtime_t cyclic_getres();
+
+extern void cyclic_suspend();
+extern void cyclic_resume();
+
+#endif /* _KERNEL || _FAKE_KERNEL */
+
+#endif /* !_ASM */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CYCLIC_H */
diff --git a/usr/src/lib/libfakekernel/common/uio.c b/usr/src/lib/libfakekernel/common/uio.c
index 3048faff58..99cb4e04e8 100644
--- a/usr/src/lib/libfakekernel/common/uio.c
+++ b/usr/src/lib/libfakekernel/common/uio.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -42,10 +42,10 @@ uiomove(void *p, size_t n, enum uio_rw rw, struct uio *uio)
}
switch (uio->uio_segflg) {
- case UIO_USERSPACE:
case UIO_USERISPACE:
return (EINVAL);
+ case UIO_USERSPACE:
case UIO_SYSSPACE:
if (rw == UIO_READ)
bcopy(p, iov->iov_base, cnt);
diff --git a/usr/src/lib/libproc/common/libproc.h b/usr/src/lib/libproc/common/libproc.h
index eb73039a21..dd7bd9f99b 100644
--- a/usr/src/lib/libproc/common/libproc.h
+++ b/usr/src/lib/libproc/common/libproc.h
@@ -27,6 +27,8 @@
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright 2018, Joyent, Inc.
* Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2019, Carlos Neira <cneirabustos@gmail.com>
+ * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
*/
/*
@@ -710,10 +712,12 @@ extern int proc_get_secflags(pid_t, prsecflags_t **);
*/
#define FLT2STR_MAX 32 /* max. string length of faults (like SIG2STR_MAX) */
#define SYS2STR_MAX 32 /* max. string length of syscalls (like SIG2STR_MAX) */
+#define DMODELSTR_MAX 32 /* max. string length of data model names */
extern char *proc_fltname(int, char *, size_t);
extern char *proc_signame(int, char *, size_t);
extern char *proc_sysname(int, char *, size_t);
+extern char *proc_dmodelname(int, char *, size_t);
/*
* Utility functions for debugging tools to convert fault, signal, and system
diff --git a/usr/src/lib/libproc/common/mapfile-vers b/usr/src/lib/libproc/common/mapfile-vers
index 3b2fe58812..6e5ff2c21a 100644
--- a/usr/src/lib/libproc/common/mapfile-vers
+++ b/usr/src/lib/libproc/common/mapfile-vers
@@ -23,6 +23,8 @@
# Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
# Copyright 2018 Joyent, Inc.
# Copyright (c) 2013 by Delphix. All rights reserved.
+# Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
+# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
#
#
@@ -204,6 +206,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
proc_arg_xgrab;
proc_arg_xpsinfo;
proc_content2str;
+ proc_dmodelname;
proc_finistdio;
proc_fltname;
proc_fltset2str;
diff --git a/usr/src/lib/libproc/common/proc_names.c b/usr/src/lib/libproc/common/proc_names.c
index 634a79b312..314b01fbcd 100644
--- a/usr/src/lib/libproc/common/proc_names.c
+++ b/usr/src/lib/libproc/common/proc_names.c
@@ -22,6 +22,8 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, Joyent, Inc. All rights reserved.
+ * Copyright 2019, Carlos Neira <cneirabustos@gmail.com>
+ * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
*/
#include <stdio.h>
@@ -31,6 +33,7 @@
#include <signal.h>
#include <errno.h>
#include "libproc.h"
+#include <sys/procfs_isa.h>
static const char *
rawfltname(int flt)
@@ -482,7 +485,7 @@ proc_str2sys(const char *str, int *sysnum)
*/
char *
proc_fltset2str(const fltset_t *set, const char *delim, int m,
- char *buf, size_t len)
+ char *buf, size_t len)
{
char name[FLT2STR_MAX], *p = buf;
size_t n;
@@ -522,7 +525,7 @@ proc_fltset2str(const fltset_t *set, const char *delim, int m,
*/
char *
proc_sigset2str(const sigset_t *set, const char *delim, int m,
- char *buf, size_t len)
+ char *buf, size_t len)
{
char name[SIG2STR_MAX], *p = buf;
size_t n;
@@ -568,7 +571,7 @@ proc_sigset2str(const sigset_t *set, const char *delim, int m,
*/
char *
proc_sysset2str(const sysset_t *set, const char *delim, int m,
- char *buf, size_t len)
+ char *buf, size_t len)
{
char name[SYS2STR_MAX], *p = buf;
size_t n;
@@ -703,3 +706,34 @@ proc_str2sysset(const char *s, const char *delim, int m, sysset_t *set)
}
return (NULL);
}
+
+/*
+ * Returns a string representation of a process data model.
+ * See <sys/procfs_isa.h> for possible values.
+ */
+char *
+proc_dmodelname(int dmodel, char *buf, size_t bufsz)
+{
+ static const char *const dmdls[] = {
+ "PR_MODEL_UNKNOWN",
+ "PR_MODEL_ILP32",
+ "PR_MODEL_LP64",
+ NULL
+ };
+ size_t len;
+
+ if (bufsz == 0)
+ return (NULL);
+
+ if (dmodel > PR_MODEL_LP64 || dmodel < PR_MODEL_UNKNOWN) {
+ len = snprintf(buf, bufsz, "DMODEL#%d", dmodel);
+ } else {
+ len = strlen(dmdls[dmodel]);
+ (void) strncpy(buf, dmdls[dmodel], bufsz);
+ }
+
+ if (len >= bufsz)
+ buf[bufsz-1] = '\0';
+
+ return (buf);
+}
diff --git a/usr/src/lib/libshare/smbfs/libshare_smbfs.c b/usr/src/lib/libshare/smbfs/libshare_smbfs.c
index b1f19f917d..7c9b4fa58a 100644
--- a/usr/src/lib/libshare/smbfs/libshare_smbfs.c
+++ b/usr/src/lib/libshare/smbfs/libshare_smbfs.c
@@ -22,6 +22,8 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -70,6 +72,7 @@ static int yes_no_validator(int, char *, char *);
static int ip_address_validator(int, char *, char *);
static int minauth_validator(int, char *, char *);
static int password_validator(int, char *, char *);
+static int protocol_validator(int, char *, char *);
static int signing_validator(int, char *, char *);
int propset_changed = 0;
@@ -182,6 +185,12 @@ struct smbclnt_proto_option_defs smbclnt_proto_options[] = {
{ "signing", NULL, PROTO_OPT_SIGNING,
0, 0, MAX_VALUE_BUFLEN,
signing_validator},
+ { "min_protocol", NULL, PROTO_OPT_MIN_PROTOCOL,
+ 0, 0, MAX_VALUE_BUFLEN,
+ protocol_validator},
+ { "max_protocol", NULL, PROTO_OPT_MAX_PROTOCOL,
+ 0, 0, MAX_VALUE_BUFLEN,
+ protocol_validator},
{NULL}
};
@@ -270,18 +279,30 @@ ip_address_validator(int index, char *section, char *value)
static int
minauth_validator(int index, char *section, char *value)
{
+ int ival;
+
if (value == NULL)
return (SA_BAD_VALUE);
- if (strlen(value) == 0)
- return (SA_OK);
- if (strcmp(value, "kerberos") == 0 ||
- strcmp(value, "ntlmv2") == 0 ||
- strcmp(value, "ntlm") == 0 ||
- strcmp(value, "lm") == 0 ||
- strcmp(value, "none") == 0)
- return (SA_OK);
- else
+ ival = smb_cf_minauth_from_str(value);
+ if (ival == -1)
return (SA_BAD_VALUE);
+
+ return (SA_OK);
+}
+
+/*ARGSUSED*/
+static int
+protocol_validator(int index, char *section, char *value)
+{
+ int ival;
+
+ if (value == NULL)
+ return (SA_BAD_VALUE);
+ ival = smb_cf_version_from_str(value);
+ if (ival == -1)
+ return (SA_BAD_VALUE);
+
+ return (SA_OK);
}
/*ARGSUSED*/
diff --git a/usr/src/lib/libshare/smbfs/libshare_smbfs.h b/usr/src/lib/libshare/smbfs/libshare_smbfs.h
index 8f95e7de68..d77fef814a 100644
--- a/usr/src/lib/libshare/smbfs/libshare_smbfs.h
+++ b/usr/src/lib/libshare/smbfs/libshare_smbfs.h
@@ -22,6 +22,8 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -59,8 +61,10 @@ extern struct smbclnt_proto_option_defs smbclnt_proto_options[];
#define PROTO_OPT_DOMAIN 9
#define PROTO_OPT_WORKGROUP 10
#define PROTO_OPT_SIGNING 11
+#define PROTO_OPT_MIN_PROTOCOL 12
+#define PROTO_OPT_MAX_PROTOCOL 13
-#define SMBC_OPT_MAX PROTO_OPT_SIGNING
+#define SMBC_OPT_MAX PROTO_OPT_MAX_PROTOCOL
/*
* Flags values
diff --git a/usr/src/lib/libsmbfs/Makefile.com b/usr/src/lib/libsmbfs/Makefile.com
index 160494aff1..be5ad05c42 100644
--- a/usr/src/lib/libsmbfs/Makefile.com
+++ b/usr/src/lib/libsmbfs/Makefile.com
@@ -24,7 +24,7 @@
# Use is subject to license terms.
# Copyright 2015 Igor Kozhukhov <ikozhukhov@gmail.com>
#
-# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
#
# Copyright (c) 2018, Joyent, Inc.
@@ -57,21 +57,16 @@ OBJ_LIB=\
nb.o \
nb_name.o \
nb_net.o \
- nb_ssn.o \
nbns_rq.o \
- negprot.o \
newvc.o \
nls.o \
ntlm.o \
ntlmssp.o \
print.o \
- rap.o \
rcfile.o \
- rq.o \
- signing.o \
+ rc_scf.o \
spnego.o \
spnegoparse.o \
- ssnsetup.o \
ssp.o \
subr.o \
ui-sun.o \
@@ -95,7 +90,7 @@ $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
CSTD= $(CSTD_GNU99)
-LDLIBS += -lsocket -lnsl -lc -lmd -lpkcs11 -lkrb5 -lsec -lidmap
+LDLIBS += -lsocket -lnsl -lc -lmd -lpkcs11 -lkrb5 -lsec -lidmap -lscf -luuid
# normal warnings...
CFLAGS += $(CCVERBOSE)
@@ -111,23 +106,21 @@ CPPFLAGS += -D__EXTENSIONS__ -D_REENTRANT -DMIA \
-I$(SRC)/uts/common \
-I$(SRC)/common/smbclnt
+# This is pretty mature code, so let's just ignore these.
+LINTCHECKFLAGS += -erroff=E_INCONS_ARG_DECL2
+LINTCHECKFLAGS += -erroff=E_INCONS_VAL_TYPE_DECL2
+LINTCHECKFLAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2
+LINTCHECKFLAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2
+
# Debugging
${NOT_RELEASE_BUILD} CPPFLAGS += -DDEBUG
-# Filter out the less important lint.
-# See lgrep.awk
-LGREP = $(AWK) -f $(SRCDIR)/lgrep.awk
-LTAIL += 2>&1 | $(LGREP)
-
all: $(LIBS)
-lint: lintcheck_t
+lint: lintcheck
include ../../Makefile.targ
-lintcheck_t: $$(SRCS)
- $(LINT.c) $(LINTCHECKFLAGS) $(SRCS) $(LDLIBS) $(LTAIL)
-
objs/%.o pics/%.o: $(CMNDIR)/%.c
$(COMPILE.c) -o $@ $<
$(POST_PROCESS_O)
diff --git a/usr/src/lib/libsmbfs/cflib.h b/usr/src/lib/libsmbfs/cflib.h
index 0e8d6b57ee..85db96fcfd 100644
--- a/usr/src/lib/libsmbfs/cflib.h
+++ b/usr/src/lib/libsmbfs/cflib.h
@@ -35,6 +35,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _CFLIB_H_
@@ -85,6 +87,8 @@ int cf_getopt(int, char * const *, const char *);
void cf_opt_lock(void);
void cf_opt_unlock(void);
+char *cf_get_client_uuid(void);
+
int rc_getstringptr(struct rcfile *, const char *, const char *, char **);
int rc_getstring(struct rcfile *, const char *, const char *, size_t, char *);
int rc_getint(struct rcfile *, const char *, const char *, int *);
diff --git a/usr/src/lib/libsmbfs/netsmb/smb_lib.h b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
index c1dc6886ac..ae71332e97 100644
--- a/usr/src/lib/libsmbfs/netsmb/smb_lib.h
+++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_LIB_H_
@@ -103,28 +103,21 @@ struct smb_ctx {
struct addrinfo *ct_addrinfo; /* IP addresses of the server */
struct nb_ctx *ct_nb; /* NetBIOS info. */
char *ct_locname; /* local (machine) name */
- smb_iod_ssn_t ct_iod_ssn;
- /* smbioc_oshare_t ct_sh; XXX */
int ct_minauth;
int ct_shtype_req; /* share type wanted */
char *ct_origshare;
char *ct_home;
char *ct_rpath; /* remote file name */
- /* Connection setup SMB stuff. */
- /* Strings from the SMB negotiate response. */
- char *ct_srv_OS;
- char *ct_srv_LM;
- uint32_t ct_clnt_caps;
+ /* See ssp.c */
+ void *ct_ssp_ctx;
+ smbioc_ssn_work_t ct_work;
+ smb_iod_ssn_t ct_iod_ssn;
/* NTLM auth. stuff */
uchar_t ct_clnonce[NTLM_CHAL_SZ];
uchar_t ct_srv_chal[NTLM_CHAL_SZ];
char ct_password[SMBIOC_MAX_NAME];
-
- /* See ssp.c */
- void *ct_ssp_ctx;
- smbioc_ssn_work_t ct_work;
};
@@ -133,25 +126,20 @@ struct smb_ctx {
*/
#define ct_ssn ct_iod_ssn.iod_ossn
#define ct_vopt ct_iod_ssn.iod_ossn.ssn_vopt
+#define ct_minver ct_iod_ssn.iod_ossn.ssn_minver
+#define ct_maxver ct_iod_ssn.iod_ossn.ssn_maxver
#define ct_owner ct_iod_ssn.iod_ossn.ssn_owner
#define ct_srvaddr ct_iod_ssn.iod_ossn.ssn_srvaddr
#define ct_domain ct_iod_ssn.iod_ossn.ssn_domain
-#define ct_user ct_iod_ssn.iod_ossn.ssn_user
-#define ct_srvname ct_iod_ssn.iod_ossn.ssn_srvname
+#define ct_user ct_iod_ssn.iod_ossn.ssn_user
+#define ct_srvname ct_iod_ssn.iod_ossn.ssn_srvname
#define ct_authflags ct_iod_ssn.iod_authflags
#define ct_nthash ct_iod_ssn.iod_nthash
#define ct_lmhash ct_iod_ssn.iod_lmhash
-#define ct_sopt ct_work.wk_sopt
-#define ct_iods ct_work.wk_iods
-#define ct_tran_fd ct_work.wk_iods.is_tran_fd
-#define ct_hflags ct_work.wk_iods.is_hflags
-#define ct_hflags2 ct_work.wk_iods.is_hflags2
-#define ct_vcflags ct_work.wk_iods.is_vcflags
-#define ct_ssn_key ct_work.wk_iods.is_ssn_key
-#define ct_mac_seqno ct_work.wk_iods.is_next_seq
-#define ct_mackeylen ct_work.wk_iods.is_u_maclen
-#define ct_mackey ct_work.wk_iods.is_u_mackey.lp_ptr
+#define ct_vcflags ct_work.wk_vcflags
+#define ct_ssnkey_len ct_work.wk_u_ssnkey_len
+#define ct_ssnkey_buf ct_work.wk_u_ssnkey_buf.lp_ptr
/*
@@ -169,9 +157,7 @@ struct smb_ctx {
#define SMBCF_BROWSEOK 0x00200000 /* browser dialogue may be used */
#define SMBCF_AUTHREQ 0x00400000 /* auth. dialog requested */
#define SMBCF_KCSAVE 0x00800000 /* add to keychain requested */
-#define SMBCF_XXX 0x01000000 /* mount-all, a very bad thing */
-#define SMBCF_SSNACTIVE 0x02000000 /* session setup succeeded */
-#define SMBCF_KCDOMAIN 0x04000000 /* use domain in KC lookup */
+#define SMBCF_KCDOMAIN 0x01000000 /* use domain in KC lookup */
/*
@@ -181,6 +167,8 @@ struct smb_ctx {
int smb_ctx_init(struct smb_ctx *);
void smb_ctx_done(struct smb_ctx *);
int smb_open_driver(void);
+int nsmb_ioctl(int, int, void *);
+int nsmb_close(int);
int smb_ctx_gethandle(struct smb_ctx *);
int smb_ctx_findvc(struct smb_ctx *);
@@ -208,6 +196,9 @@ int smb_iod_work(struct smb_ctx *);
int smb_open_rcfile(char *);
void smb_close_rcfile(void);
+int smb_cf_minauth_from_str(char *);
+int smb_cf_version_from_str(char *);
+
void smb_simplecrypt(char *dst, const char *src);
int smb_simpledecrypt(char *dst, const char *src);
diff --git a/usr/src/lib/libsmbfs/netsmb/smbfs_api.h b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h
index b1f4b1e198..7b87b571ff 100644
--- a/usr/src/lib/libsmbfs/netsmb/smbfs_api.h
+++ b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h
@@ -22,7 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMBFS_API_H
@@ -48,7 +49,7 @@ extern "C" {
* EAUTH is used for CIFS authentication errors.
*/
#ifndef EBADRPC
-#define EBADRPC 113
+#define EBADRPC 113
#endif
#ifndef EAUTH
#define EAUTH 114
@@ -122,6 +123,8 @@ int smb_ctx_setauthflags(struct smb_ctx *, int);
int smb_ctx_setcharset(struct smb_ctx *, const char *);
int smb_ctx_setfullserver(struct smb_ctx *, const char *);
int smb_ctx_setsigning(struct smb_ctx *, int ena, int req);
+int smb_ctx_setminver(struct smb_ctx *, int ver);
+int smb_ctx_setmaxver(struct smb_ctx *, int ver);
int smb_ctx_setnbflags(struct smb_ctx *, int ena, int bcast);
int smb_ctx_setscope(struct smb_ctx *, const char *);
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip
index aa3d6ad7e1..35fdfd0404 100644
--- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip
@@ -1 +1 @@
-PORTIONS OF LIBSMBFS IN CIFS CLIENT
+PORTIONS OF LIBSMBFS IN SMB CLIENT
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip
index d7cc9ebbd7..35fdfd0404 100644
--- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip
@@ -1 +1 @@
-CIFS CLIENT SOFTWARE
+PORTIONS OF LIBSMBFS IN SMB CLIENT
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip
index aa3d6ad7e1..35fdfd0404 100644
--- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip
@@ -1 +1 @@
-PORTIONS OF LIBSMBFS IN CIFS CLIENT
+PORTIONS OF LIBSMBFS IN SMB CLIENT
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip
index aa3d6ad7e1..35fdfd0404 100644
--- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip
@@ -1 +1 @@
-PORTIONS OF LIBSMBFS IN CIFS CLIENT
+PORTIONS OF LIBSMBFS IN SMB CLIENT
diff --git a/usr/src/lib/libsmbfs/smb/acl_api.c b/usr/src/lib/libsmbfs/smb/acl_api.c
index 052539316b..92a3262f79 100644
--- a/usr/src/lib/libsmbfs/smb/acl_api.c
+++ b/usr/src/lib/libsmbfs/smb/acl_api.c
@@ -22,6 +22,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -83,6 +85,7 @@ smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp)
return (error);
m = mbp->mb_top;
+ bzero(&iocb, sizeof (iocb));
iocb.addr = mtod(m, uintptr_t);
iocb.alloc = m->m_maxlen;
iocb.used = 0;
@@ -91,7 +94,7 @@ smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp)
/*
* This does the OTW Get.
*/
- if (ioctl(fd, SMBFSIO_GETSD, &iocb) < 0) {
+ if (nsmb_ioctl(fd, SMBFSIO_GETSD, &iocb) < 0) {
error = errno;
goto errout;
}
@@ -120,6 +123,7 @@ smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp)
if (mbp->mb_top != m)
mb_initm(mbp, m);
+ bzero(&iocb, sizeof (iocb));
iocb.addr = mtod(m, uintptr_t);
iocb.alloc = m->m_maxlen;
iocb.used = m->m_len;
@@ -128,7 +132,7 @@ smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp)
/*
* This does the OTW Set.
*/
- if (ioctl(fd, SMBFSIO_SETSD, &iocb) < 0)
+ if (nsmb_ioctl(fd, SMBFSIO_SETSD, &iocb) < 0)
error = errno;
return (error);
diff --git a/usr/src/lib/libsmbfs/smb/connect.c b/usr/src/lib/libsmbfs/smb/connect.c
index c2ccc3361d..c231fe0e8a 100644
--- a/usr/src/lib/libsmbfs/smb/connect.c
+++ b/usr/src/lib/libsmbfs/smb/connect.c
@@ -22,7 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -50,336 +51,89 @@
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
+#include <uuid/uuid.h>
#include <netsmb/smb.h>
#include <netsmb/smb_lib.h>
+#include <netsmb/mchain.h>
#include <netsmb/netbios.h>
#include <netsmb/nb_lib.h>
#include <netsmb/smb_dev.h>
+#include <cflib.h>
+
#include "charsets.h"
#include "private.h"
-
-/*
- * SMB messages are up to 64K.
- * Let's leave room for two.
- */
-static int smb_tcpsndbuf = 0x20000;
-static int smb_tcprcvbuf = 0x20000;
-static int smb_connect_timeout = 30; /* seconds */
-int smb_recv_timeout = 30; /* seconds */
-
-int conn_tcp6(struct smb_ctx *, const struct sockaddr *, int);
-int conn_tcp4(struct smb_ctx *, const struct sockaddr *, int);
-int conn_nbt(struct smb_ctx *, const struct sockaddr *, char *);
-
-/*
- * Internal set sockopt for int-sized options.
- * Borrowed from: libnsl/rpc/ti_opts.c
- */
-static int
-smb_setopt_int(int fd, int level, int name, int val)
-{
- struct t_optmgmt oreq, ores;
- struct {
- struct t_opthdr oh;
- int ival;
- } opts;
-
- /* opt header */
- opts.oh.len = sizeof (opts);
- opts.oh.level = level;
- opts.oh.name = name;
- opts.oh.status = 0;
- opts.ival = val;
-
- oreq.flags = T_NEGOTIATE;
- oreq.opt.buf = (void *)&opts;
- oreq.opt.len = sizeof (opts);
-
- ores.flags = 0;
- ores.opt.buf = NULL;
- ores.opt.maxlen = 0;
-
- if (t_optmgmt(fd, &oreq, &ores) < 0) {
- DPRINT("t_opgmgnt, t_errno = %d", t_errno);
- if (t_errno == TSYSERR)
- return (errno);
- return (EPROTO);
- }
- if (ores.flags != T_SUCCESS) {
- DPRINT("flags 0x%x, status 0x%x",
- (int)ores.flags, (int)opts.oh.status);
- return (EPROTO);
- }
-
- return (0);
-}
+#include "smb_crypt.h"
static int
-smb_setopts(int fd)
-{
- int err;
-
- /*
- * Set various socket/TCP options.
- * Failures here are not fatal -
- * just log a complaint.
- *
- * We don't need these two:
- * SO_RCVTIMEO, SO_SNDTIMEO
- */
-
- err = smb_setopt_int(fd, SOL_SOCKET, SO_SNDBUF, smb_tcpsndbuf);
- if (err) {
- DPRINT("set SO_SNDBUF, err %d", err);
- }
-
- err = smb_setopt_int(fd, SOL_SOCKET, SO_RCVBUF, smb_tcprcvbuf);
- if (err) {
- DPRINT("set SO_RCVBUF, err %d", err);
- }
+smb__ssnsetup(struct smb_ctx *ctx,
+ struct mbdata *mbc1, struct mbdata *mbc2);
- err = smb_setopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, 1);
- if (err) {
- DPRINT("set SO_KEEPALIVE, err %d", err);
- }
+int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);
- err = smb_setopt_int(fd, IPPROTO_TCP, TCP_NODELAY, 1);
- if (err) {
- DPRINT("set TCP_NODELAY, err %d", err);
- }
-
- /* Set the connect timeout (in milliseconds). */
- err = smb_setopt_int(fd, IPPROTO_TCP,
- TCP_CONN_ABORT_THRESHOLD,
- smb_connect_timeout * 1000);
- if (err) {
- DPRINT("set connect timeout, err %d", err);
- }
- return (0);
-}
-
-
-int
-conn_tcp6(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
+const char *
+smb_iod_state_name(enum smbiod_state st)
{
- struct sockaddr_in6 sin6;
- char *dev = "/dev/tcp6";
- char paddrbuf[INET6_ADDRSTRLEN];
- struct t_call sndcall;
- int fd, err;
-
- if (sa->sa_family != AF_INET6) {
- DPRINT("bad af %d", sa->sa_family);
- return (EINVAL);
- }
- bcopy(sa, &sin6, sizeof (sin6));
- sin6.sin6_port = htons(port);
-
- DPRINT("tcp6: %s (%d)",
- inet_ntop(AF_INET6, &sin6.sin6_addr,
- paddrbuf, sizeof (paddrbuf)), port);
+ const char *n = "(?)";
- fd = t_open(dev, O_RDWR, NULL);
- if (fd < 0) {
- /* Assume t_errno = TSYSERR */
- err = errno;
- perror(dev);
- return (err);
- }
- if ((err = smb_setopts(fd)) != 0)
- goto errout;
- if (t_bind(fd, NULL, NULL) < 0) {
- DPRINT("t_bind t_errno %d", t_errno);
- if (t_errno == TSYSERR)
- err = errno;
- else
- err = EPROTO;
- goto errout;
- }
- sndcall.addr.maxlen = sizeof (sin6);
- sndcall.addr.len = sizeof (sin6);
- sndcall.addr.buf = (void *) &sin6;
- sndcall.opt.len = 0;
- sndcall.udata.len = 0;
- if (t_connect(fd, &sndcall, NULL) < 0) {
- err = get_xti_err(fd);
- DPRINT("connect, err %d", err);
- goto errout;
- }
-
- DPRINT("tcp6: connected, fd=%d", fd);
- ctx->ct_tran_fd = fd;
- return (0);
-
-errout:
- close(fd);
- return (err);
-}
-
-/*
- * This is used for both SMB over TCP (port 445)
- * and NetBIOS - see conn_nbt().
- */
-int
-conn_tcp4(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
-{
- struct sockaddr_in sin;
- char *dev = "/dev/tcp";
- char paddrbuf[INET_ADDRSTRLEN];
- struct t_call sndcall;
- int fd, err;
-
- if (sa->sa_family != AF_INET) {
- DPRINT("bad af %d", sa->sa_family);
- return (EINVAL);
- }
- bcopy(sa, &sin, sizeof (sin));
- sin.sin_port = htons(port);
-
- DPRINT("tcp4: %s (%d)",
- inet_ntop(AF_INET, &sin.sin_addr,
- paddrbuf, sizeof (paddrbuf)), port);
-
- fd = t_open(dev, O_RDWR, NULL);
- if (fd < 0) {
- /* Assume t_errno = TSYSERR */
- err = errno;
- perror(dev);
- return (err);
- }
- if ((err = smb_setopts(fd)) != 0)
- goto errout;
- if (t_bind(fd, NULL, NULL) < 0) {
- DPRINT("t_bind t_errno %d", t_errno);
- if (t_errno == TSYSERR)
- err = errno;
- else
- err = EPROTO;
- goto errout;
- }
- sndcall.addr.maxlen = sizeof (sin);
- sndcall.addr.len = sizeof (sin);
- sndcall.addr.buf = (void *) &sin;
- sndcall.opt.len = 0;
- sndcall.udata.len = 0;
- if (t_connect(fd, &sndcall, NULL) < 0) {
- err = get_xti_err(fd);
- DPRINT("connect, err %d", err);
- goto errout;
- }
-
- DPRINT("tcp4: connected, fd=%d", fd);
- ctx->ct_tran_fd = fd;
- return (0);
-
-errout:
- close(fd);
- return (err);
-}
-
-/*
- * Open a NetBIOS connection (session, port 139)
- *
- * The optional name parameter, if passed, means
- * we found the sockaddr via NetBIOS name lookup,
- * and can just use that for our session request.
- * Otherwise (if name is NULL), we're connecting
- * by IP address, and need to come up with the
- * NetBIOS name by other means.
- */
-int
-conn_nbt(struct smb_ctx *ctx, const struct sockaddr *saarg, char *name)
-{
- struct sockaddr_in sin;
- struct sockaddr *sa;
- char server[NB_NAMELEN];
- char workgroup[NB_NAMELEN];
- int err, nberr, port;
-
- bcopy(saarg, &sin, sizeof (sin));
- sa = (struct sockaddr *)&sin;
-
- switch (sin.sin_family) {
- case AF_NETBIOS: /* our fake AF */
- sin.sin_family = AF_INET;
+ switch (st) {
+ case SMBIOD_ST_UNINIT:
+ n = "UNINIT!";
break;
- case AF_INET:
+ case SMBIOD_ST_IDLE:
+ n = "IDLE";
+ break;
+ case SMBIOD_ST_RECONNECT:
+ n = "RECONNECT";
+ break;
+ case SMBIOD_ST_RCFAILED:
+ n = "RCFAILED";
+ break;
+ case SMBIOD_ST_CONNECTED:
+ n = "CONNECTED";
+ break;
+ case SMBIOD_ST_NEGOTIATED:
+ n = "NEGOTIATED";
+ break;
+ case SMBIOD_ST_AUTHCONT:
+ n = "AUTHCONT";
+ break;
+ case SMBIOD_ST_AUTHFAIL:
+ n = "AUTHFAIL";
+ break;
+ case SMBIOD_ST_AUTHOK:
+ n = "AUTHOK";
+ break;
+ case SMBIOD_ST_VCACTIVE:
+ n = "VCACTIVE";
+ break;
+ case SMBIOD_ST_DEAD:
+ n = "DEAD";
break;
- default:
- DPRINT("bad af %d", sin.sin_family);
- return (EINVAL);
- }
- port = IPPORT_NETBIOS_SSN;
-
- /*
- * If we have a NetBIOS name, just use it.
- * This is the path taken when we've done a
- * NetBIOS name lookup on this name to get
- * the IP address in the passed sa. Otherwise,
- * we're connecting by IP address, and need to
- * figure out what NetBIOS name to use.
- */
- if (name) {
- strlcpy(server, name, sizeof (server));
- DPRINT("given name: %s", server);
- } else {
- /*
- *
- * Try a NetBIOS node status query,
- * which searches for a type=[20] name.
- * If that doesn't work, just use the
- * (fake) "*SMBSERVER" name.
- */
- DPRINT("try node status");
- server[0] = '\0';
- nberr = nbns_getnodestatus(ctx->ct_nb,
- &sin.sin_addr, server, workgroup);
- if (nberr == 0 && server[0] != '\0') {
- /* Found the name. Save for reconnect. */
- DPRINT("found name: %s", server);
- strlcpy(ctx->ct_srvname, server,
- sizeof (ctx->ct_srvname));
- } else {
- DPRINT("getnodestatus, nberr %d", nberr);
- strlcpy(server, "*SMBSERVER", sizeof (server));
- }
- }
-
- /*
- * Establish the TCP connection.
- * Careful to close it on errors.
- */
- if ((err = conn_tcp4(ctx, sa, port)) != 0) {
- DPRINT("TCP connect: err=%d", err);
- goto out;
}
- /* Connected. Do NetBIOS session request. */
- err = nb_ssn_request(ctx, server);
- if (err)
- DPRINT("ssn_rq, err %d", err);
-
-out:
- if (err) {
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- }
- }
- return (err);
+ return (n);
}
/*
* Make a new connection, or reconnect.
+ *
+ * This is called first from the door service thread in smbiod
+ * (so that can report success or failure to the door client)
+ * and thereafter it's called when we need to reconnect after a
+ * network outage (or whatever might cause connection loss).
*/
int
smb_iod_connect(smb_ctx_t *ctx)
{
- struct sockaddr *sa;
- int err, err2;
+ smbioc_ossn_t *ossn = &ctx->ct_ssn;
+ smbioc_ssn_work_t *work = &ctx->ct_work;
+ char *uuid_str;
+ int err;
struct mbdata blob;
+ char *nego_buf = NULL;
+ uint32_t nego_len;
memset(&blob, 0, sizeof (blob));
@@ -393,15 +147,6 @@ smb_iod_connect(smb_ctx_t *ctx)
dump_ctx("smb_iod_connect", ctx);
/*
- * This may be a reconnect, so
- * cleanup if necessary.
- */
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- }
-
- /*
* Get local machine name.
* Full name - not a NetBIOS name.
*/
@@ -415,114 +160,235 @@ smb_iod_connect(smb_ctx_t *ctx)
}
/*
+ * Get local machine uuid.
+ */
+ uuid_str = cf_get_client_uuid();
+ if (uuid_str == NULL) {
+ err = EINVAL;
+ smb_error(dgettext(TEXT_DOMAIN,
+ "can't get local UUID"), err);
+ return (err);
+ }
+ (void) uuid_parse(uuid_str, ctx->ct_work.wk_cl_guid);
+ free(uuid_str);
+ uuid_str = NULL;
+
+ /*
* We're called with each IP address
* already copied into ct_srvaddr.
*/
ctx->ct_flags |= SMBCF_RESOLVED;
- sa = &ctx->ct_srvaddr.sa;
- switch (sa->sa_family) {
-
- case AF_INET6:
- err = conn_tcp6(ctx, sa, IPPORT_SMB);
- break;
-
- case AF_INET:
- err = conn_tcp4(ctx, sa, IPPORT_SMB);
- /*
- * If port 445 was not listening, try port 139.
- * Note: Not doing NetBIOS name lookup here.
- * We already have the IP address.
- */
- switch (err) {
- case ECONNRESET:
- case ECONNREFUSED:
- err2 = conn_nbt(ctx, sa, NULL);
- if (err2 == 0)
- err = 0;
- }
- break;
-
- case AF_NETBIOS:
- /* Like AF_INET, but use NetBIOS ssn. */
- err = conn_nbt(ctx, sa, ctx->ct_srvname);
- break;
-
- default:
- DPRINT("skipped family %d", sa->sa_family);
- err = EPROTONOSUPPORT;
- break;
- }
-
-
- if (err) {
- DPRINT("connect, err=%d", err);
+ /*
+ * Ask the drvier to connect.
+ */
+ DPRINT("Try ioctl connect...");
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_CONNECT, work) < 0) {
+ err = errno;
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: connect failed"),
+ err, ossn->ssn_srvname);
return (err);
}
+ DPRINT("Connect OK, new state=%s",
+ smb_iod_state_name(work->wk_out_state));
/*
- * Do SMB Negotiate Protocol.
+ * Setup a buffer to recv the nego. hint.
*/
- err = smb_negprot(ctx, &blob);
+ nego_len = 4096;
+ err = mb_init_sz(&blob, nego_len);
if (err)
goto out;
+ nego_buf = blob.mb_top->m_data;
+ work->wk_u_auth_rbuf.lp_ptr = nego_buf;
+ work->wk_u_auth_rlen = nego_len;
/*
- * Empty user name means an explicit request for
- * NULL session setup, which is a special case.
- * If negotiate determined that we want to do
- * SMB signing, we have to turn that off for a
- * NULL session. [MS-SMB 3.3.5.3].
+ * Ask the driver for SMB negotiate
*/
- if (ctx->ct_user[0] == '\0') {
- /* Null user should have null domain too. */
- ctx->ct_domain[0] = '\0';
- ctx->ct_authflags = SMB_AT_ANON;
- ctx->ct_clnt_caps &= ~SMB_CAP_EXT_SECURITY;
- ctx->ct_vcflags &= ~SMBV_WILL_SIGN;
+ DPRINT("Try ioctl negotiate...");
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_NEGOTIATE, work) < 0) {
+ err = errno;
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: negotiate failed"),
+ err, ossn->ssn_srvname);
+ goto out;
+ }
+ DPRINT("Negotiate OK, new state=%s",
+ smb_iod_state_name(work->wk_out_state));
+
+ nego_len = work->wk_u_auth_rlen;
+ blob.mb_top->m_len = nego_len;
+
+ if (smb_debug) {
+ DPRINT("Sec. blob: %d", nego_len);
+ smb_hexdump(nego_buf, nego_len);
}
/*
* Do SMB Session Setup (authenticate)
- *
- * If the server negotiated extended security,
- * run the SPNEGO state machine, otherwise do
- * one of the old-style variants.
+ * Always "extended security" now (SPNEGO)
*/
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- err = smb_ssnsetup_spnego(ctx, &blob);
- } else {
- /*
- * Server did NOT negotiate extended security.
- * Try NTLMv2, NTLMv1, or ANON (if enabled).
- */
- if (ctx->ct_authflags & SMB_AT_NTLM2) {
- err = smb_ssnsetup_ntlm2(ctx);
- } else if (ctx->ct_authflags & SMB_AT_NTLM1) {
- err = smb_ssnsetup_ntlm1(ctx);
- } else if (ctx->ct_authflags & SMB_AT_ANON) {
- err = smb_ssnsetup_null(ctx);
- } else {
+ DPRINT("Do session setup...");
+ err = smb_ssnsetup_spnego(ctx, &blob);
+ if (err != 0) {
+ DPRINT("Session setup err=%d", err);
+ goto out;
+ }
+
+ /*
+ * Success! We return zero now, and our caller (normally
+ * the smbiod program) will then call smb_iod_work in a
+ * new thread to service this VC as long as necessary.
+ */
+ DPRINT("Session setup OK");
+
+out:
+ mb_done(&blob);
+
+ return (err);
+}
+
+/*
+ * smb_ssnsetup_spnego
+ *
+ * This does an SMB session setup sequence using SPNEGO.
+ * The state changes seen during this sequence are there
+ * just to help track what's going on.
+ */
+int
+smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
+{
+ struct mbdata send_mb, recv_mb;
+ smbioc_ssn_work_t *work = &ctx->ct_work;
+ int err;
+
+ bzero(&send_mb, sizeof (send_mb));
+ bzero(&recv_mb, sizeof (recv_mb));
+
+ err = ssp_ctx_create_client(ctx, hint_mb);
+ if (err)
+ goto out;
+
+ /* NULL input indicates first call. */
+ err = ssp_ctx_next_token(ctx, NULL, &send_mb);
+ if (err) {
+ DPRINT("smb__ssnsetup, ssp next, err=%d", err);
+ goto out;
+ }
+ for (;;) {
+ err = smb__ssnsetup(ctx, &send_mb, &recv_mb);
+ DPRINT("smb__ssnsetup rc=%d, new state=%s", err,
+ smb_iod_state_name(work->wk_out_state));
+
+ if (err == 0) {
+ /*
+ * Session setup complete w/ success.
+ * Should have state AUTHOK
+ */
+ if (work->wk_out_state != SMBIOD_ST_AUTHOK) {
+ DPRINT("Wrong state (expected AUTHOK)");
+ }
+ break;
+ }
+
+ if (err != EINPROGRESS) {
/*
- * Don't return EAUTH, because a new
- * password prompt will not help.
+ * Session setup complete w/ failure.
+ * Should have state AUTHFAIL
*/
- DPRINT("No NTLM authflags");
- err = ENOTSUP;
+ if (work->wk_out_state != SMBIOD_ST_AUTHFAIL) {
+ DPRINT("Wrong state (expected AUTHFAIL)");
+ }
+ goto out;
+ }
+
+ /*
+ * err == EINPROGRESS
+ * Session setup continuing.
+ * Should have state AUTHCONT
+ */
+ if (work->wk_out_state != SMBIOD_ST_AUTHCONT) {
+ DPRINT("Wrong state (expected AUTHCONT)");
+ }
+
+ /* middle calls get both in, out */
+ err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
+ if (err) {
+ DPRINT("smb__ssnsetup, ssp next, err=%d", err);
+ goto out;
}
}
+ /*
+ * Only get here via break in the err==0 case above,
+ * so we're finalizing a successful session setup.
+ *
+ * NULL output token here indicates the final call.
+ */
+ (void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
+
+ /*
+ * The session key is in ctx->ct_ssnkey_buf
+ * (a.k.a. ct_work.wk_u_ssn_key_buf)
+ */
+
out:
- mb_done(&blob);
+ /* Done with ctx->ct_ssp_ctx */
+ ssp_ctx_destroy(ctx);
- if (err) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- } else {
- /* Tell library code we have a session. */
- ctx->ct_flags |= SMBCF_SSNACTIVE;
- DPRINT("tran_fd = %d", ctx->ct_tran_fd);
+ return (err);
+}
+
+int smb_max_authtok_sz = 0x10000;
+
+/*
+ * Session Setup function, calling the nsmb driver.
+ *
+ * Args
+ * send_mb: [in] outgoing blob data to send
+ * recv_mb: [out] received blob data buffer
+ */
+static int
+smb__ssnsetup(struct smb_ctx *ctx,
+ struct mbdata *send_mb, struct mbdata *recv_mb)
+{
+ smbioc_ossn_t *ossn = &ctx->ct_ssn;
+ smbioc_ssn_work_t *work = &ctx->ct_work;
+ mbuf_t *m;
+ int err;
+
+ /* Setup receive buffer for the auth data. */
+ err = mb_init_sz(recv_mb, smb_max_authtok_sz);
+ if (err != 0)
+ return (err);
+ m = recv_mb->mb_top;
+ work->wk_u_auth_rbuf.lp_ptr = m->m_data;
+ work->wk_u_auth_rlen = m->m_maxlen;
+
+ /* ... and the auth data to send. */
+ m = send_mb->mb_top;
+ work->wk_u_auth_wbuf.lp_ptr = m->m_data;
+ work->wk_u_auth_wlen = m->m_len;
+
+ DPRINT("Session setup ioctl...");
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_SSNSETUP, work) < 0) {
+ err = errno;
+ if (err != 0 && err != EINPROGRESS) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: session setup "),
+ err, ossn->ssn_srvname);
+ }
}
+ DPRINT("Session setup ret %d", err);
+
+ /* Free the auth data we sent. */
+ mb_done(send_mb);
+
+ /* Setup length of received auth data */
+ m = recv_mb->mb_top;
+ m->m_len = work->wk_u_auth_rlen;
return (err);
}
diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c
index 9455a92344..3aa67fd5f5 100644
--- a/usr/src/lib/libsmbfs/smb/ctx.c
+++ b/usr/src/lib/libsmbfs/smb/ctx.c
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -148,10 +148,6 @@ dump_ctx_flags(int flags)
printf("AUTHREQ ");
if (flags & SMBCF_KCSAVE)
printf("KCSAVE ");
- if (flags & SMBCF_XXX)
- printf("XXX ");
- if (flags & SMBCF_SSNACTIVE)
- printf("SSNACTIVE ");
if (flags & SMBCF_KCDOMAIN)
printf("KCDOMAIN ");
printf("\n");
@@ -169,6 +165,8 @@ dump_iod_ssn(smb_iod_ssn_t *is)
ssn->ssn_domain, ssn->ssn_user);
printf(" ct_vopt=0x%x, ct_owner=%d\n",
ssn->ssn_vopt, ssn->ssn_owner);
+ printf(" ct_minver=0x%x, ct_maxver=0x%x\n",
+ ssn->ssn_minver, ssn->ssn_maxver);
printf(" ct_authflags=0x%x\n", is->iod_authflags);
printf(" ct_nthash:");
@@ -254,16 +252,16 @@ smb_ctx_init(struct smb_ctx *ctx)
ctx->ct_dev_fd = -1;
ctx->ct_door_fd = -1;
- ctx->ct_tran_fd = -1;
ctx->ct_parsedlevel = SMBL_NONE;
ctx->ct_minlevel = SMBL_NONE;
ctx->ct_maxlevel = SMBL_PATH;
/* Fill in defaults */
- ctx->ct_vopt = SMBVOPT_EXT_SEC;
+ ctx->ct_vopt = SMBVOPT_SIGNING_ENABLED;
ctx->ct_owner = SMBM_ANY_OWNER;
ctx->ct_authflags = SMB_AT_DEFAULT;
ctx->ct_minauth = SMB_AT_MINAUTH;
+ ctx->ct_maxver = SMB2_DIALECT_MAX;
/*
* Default domain, user, ...
@@ -333,7 +331,12 @@ smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv,
cf_opt_lock();
/* Careful: no return/goto before cf_opt_unlock! */
while (error == 0) {
- opt = cf_getopt(argc, argv, STDPARAM_OPT);
+ /*
+ * Leading ':' tells this to skip unknown opts.
+ * Just get -A and -U here so we know the user
+ * for config file parsing.
+ */
+ opt = cf_getopt(argc, argv, ":AU:");
if (opt == -1)
break;
arg = cf_optarg;
@@ -398,17 +401,13 @@ smb_ctx_done(struct smb_ctx *ctx)
rpc_cleanup_smbctx(ctx);
if (ctx->ct_dev_fd != -1) {
- close(ctx->ct_dev_fd);
+ nsmb_close(ctx->ct_dev_fd);
ctx->ct_dev_fd = -1;
}
if (ctx->ct_door_fd != -1) {
close(ctx->ct_door_fd);
ctx->ct_door_fd = -1;
}
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- }
if (ctx->ct_srvaddr_s) {
free(ctx->ct_srvaddr_s);
ctx->ct_srvaddr_s = NULL;
@@ -441,17 +440,9 @@ smb_ctx_done(struct smb_ctx *ctx)
free(ctx->ct_rpath);
ctx->ct_rpath = NULL;
}
- if (ctx->ct_srv_OS) {
- free(ctx->ct_srv_OS);
- ctx->ct_srv_OS = NULL;
- }
- if (ctx->ct_srv_LM) {
- free(ctx->ct_srv_LM);
- ctx->ct_srv_LM = NULL;
- }
- if (ctx->ct_mackey) {
- free(ctx->ct_mackey);
- ctx->ct_mackey = NULL;
+ if (ctx->ct_ssnkey_buf) {
+ free(ctx->ct_ssnkey_buf);
+ ctx->ct_ssnkey_buf = NULL;
}
}
@@ -868,6 +859,37 @@ smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require)
return (0);
}
+/*
+ * Handle .nsmbrc "minver" option.
+ * Must be <= maxver
+ */
+int
+smb_ctx_setminver(struct smb_ctx *ctx, int ver)
+{
+ if (ver < 0 || ver > ctx->ct_maxver)
+ return (EINVAL);
+ ctx->ct_minver = (uint16_t)ver;
+ return (0);
+}
+
+/*
+ * Handle .nsmbrc "maxver" option.
+ * Must be >= minver
+ *
+ * Any "too high" value is just clamped, so the caller
+ * doesn't need to know what's the highest we support.
+ */
+int
+smb_ctx_setmaxver(struct smb_ctx *ctx, int ver)
+{
+ if (ver < 1 || ver < ctx->ct_minver)
+ return (EINVAL);
+ if (ver > SMB2_DIALECT_MAX)
+ ver = SMB2_DIALECT_MAX;
+ ctx->ct_maxver = (uint16_t)ver;
+ return (0);
+}
+
static int
smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
{
@@ -899,12 +921,11 @@ smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
}
/*
- * Suport a securty options arg, i.e. -S noext,lm,ntlm
+ * Suport a securty options arg, i.e. -S lm,ntlm
* for testing various type of authenticators.
*/
static struct nv
sectype_table[] = {
- /* noext - handled below */
{ "anon", SMB_AT_ANON },
{ "lm", SMB_AT_LM1 },
{ "ntlm", SMB_AT_NTLM1 },
@@ -930,13 +951,6 @@ smb_parse_secopts(struct smb_ctx *ctx, const char *arg)
if (nlen == 0)
break;
- if (nlen == 5 && 0 == strncmp(p, "noext", nlen)) {
- /* Don't offer extended security. */
- ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
- p += nlen;
- continue;
- }
-
/* This is rarely called, so not optimized. */
for (nv = sectype_table; nv->name; nv++) {
tlen = strlen(nv->name);
@@ -1117,6 +1131,19 @@ smb_ctx_resolve(struct smb_ctx *ctx)
assert(ctx->ct_addrinfo != NULL);
/*
+ * Empty user name means an explicit request for
+ * NULL session setup, which is a special case.
+ * (No SMB signing, per [MS-SMB] 3.3.5.3)
+ */
+ if (ctx->ct_user[0] == '\0') {
+ /* Null user should have null domain too. */
+ ctx->ct_domain[0] = '\0';
+ ctx->ct_authflags = SMB_AT_ANON;
+ ctx->ct_vopt |= SMBVOPT_ANONYMOUS;
+ ctx->ct_vopt &= ~SMBVOPT_SIGNING_REQUIRED;
+ }
+
+ /*
* If we have a user name but no password,
* check for a keychain entry.
* XXX: Only for auth NTLM?
@@ -1127,13 +1154,18 @@ smb_ctx_resolve(struct smb_ctx *ctx)
* If we don't have a p/w yet,
* try the keychain.
*/
- if (ctx->ct_password[0] == '\0')
- (void) smb_get_keychain(ctx);
+ if (ctx->ct_password[0] == '\0' &&
+ smb_get_keychain(ctx) == 0) {
+ strlcpy(ctx->ct_password, "$HASH",
+ sizeof (ctx->ct_password));
+ }
+
/*
* Mask out disallowed auth types.
*/
ctx->ct_authflags &= ctx->ct_minauth;
}
+
if (ctx->ct_authflags == 0) {
smb_error(dgettext(TEXT_DOMAIN,
"no valid auth. types"), 0);
@@ -1147,6 +1179,10 @@ smb_ctx_resolve(struct smb_ctx *ctx)
return (0);
}
+/*
+ * Note: The next three have NODIRECT binding so the
+ * "fksmbcl" development tool can provide its own.
+ */
int
smb_open_driver()
{
@@ -1164,6 +1200,19 @@ smb_open_driver()
}
int
+nsmb_close(int fd)
+{
+ return (close(fd));
+}
+
+int
+nsmb_ioctl(int fd, int cmd, void *arg)
+{
+ return (ioctl(fd, cmd, arg));
+}
+
+
+int
smb_ctx_gethandle(struct smb_ctx *ctx)
{
int fd, err;
@@ -1171,9 +1220,8 @@ smb_ctx_gethandle(struct smb_ctx *ctx)
if (ctx->ct_dev_fd != -1) {
rpc_cleanup_smbctx(ctx);
- close(ctx->ct_dev_fd);
+ nsmb_close(ctx->ct_dev_fd);
ctx->ct_dev_fd = -1;
- ctx->ct_flags &= ~SMBCF_SSNACTIVE;
}
fd = smb_open_driver();
@@ -1187,12 +1235,12 @@ smb_ctx_gethandle(struct smb_ctx *ctx)
/*
* Check the driver version (paranoia)
*/
- if (ioctl(fd, SMBIOC_GETVERS, &version) < 0)
+ if (nsmb_ioctl(fd, SMBIOC_GETVERS, &version) < 0)
version = 0;
if (version != NSMB_VERSION) {
smb_error(dgettext(TEXT_DOMAIN,
"incorrect driver version"), 0);
- close(fd);
+ nsmb_close(fd);
return (ENODEV);
}
@@ -1221,6 +1269,15 @@ smb_ctx_get_ssn(struct smb_ctx *ctx)
DPRINT("found an existing VC");
} else {
/*
+ * If we're authenticating (real user, not NULL session)
+ * and we don't yet have a password, return EAUTH and
+ * the caller will prompt for it and call again.
+ */
+ if (ctx->ct_user[0] != '\0' &&
+ ctx->ct_password[0] == '\0')
+ return (EAUTH);
+
+ /*
* This calls the IOD to create a new session.
*/
DPRINT("setup a new VC");
@@ -1272,7 +1329,7 @@ smb_ctx_get_tree(struct smb_ctx *ctx)
*
* The driver does the actual TCON call.
*/
- if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
+ if (nsmb_ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
err = errno;
goto out;
}
@@ -1303,7 +1360,7 @@ smb_ctx_flags2(struct smb_ctx *ctx)
{
uint16_t flags2;
- if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
smb_error(dgettext(TEXT_DOMAIN,
"can't get flags2 for a session"), errno);
return (-1);
@@ -1321,7 +1378,7 @@ smb_fh_getssnkey(int dev_fd, uchar_t *key, size_t len)
if (len < SMBIOC_HASH_SZ)
return (EINVAL);
- if (ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1)
+ if (nsmb_ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1)
return (errno);
return (0);
@@ -1343,6 +1400,35 @@ minauth_table[] = {
{ NULL }
};
+int
+smb_cf_minauth_from_str(char *str)
+{
+ struct nv *nvp;
+
+ for (nvp = minauth_table; nvp->name; nvp++)
+ if (strcmp(nvp->name, str) == 0)
+ return (nvp->value);
+ return (-1);
+}
+
+
+static struct nv
+smbver_table[] = {
+ { "2.1", SMB2_DIALECT_0210 },
+ { "1", 1 },
+ { NULL, 0 }
+};
+
+int
+smb_cf_version_from_str(char *str)
+{
+ struct nv *nvp;
+
+ for (nvp = smbver_table; nvp->name; nvp++)
+ if (strcmp(nvp->name, str) == 0)
+ return (nvp->value);
+ return (-1);
+}
/*
* level values:
@@ -1355,7 +1441,9 @@ static int
smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
{
char *p;
+ int ival;
int error;
+ int minver, maxver;
#ifdef KICONV_SUPPORT
if (level > 0) {
@@ -1373,19 +1461,79 @@ smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
if (level <= 1) {
/* Section is: [default] or [server] */
+ /*
+ * Handle min_protocol, max_protocol
+ * (SMB protocol versions)
+ */
+ minver = -1;
+ rc_getstringptr(smb_rc, sname, "min_protocol", &p);
+ if (p != NULL) {
+ minver = smb_cf_version_from_str(p);
+ if (minver == -1) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid min_protocol value \"%s\" specified in the section %s"),
+ 0, p, sname);
+ }
+ }
+ maxver = -1;
+ rc_getstringptr(smb_rc, sname, "max_protocol", &p);
+ if (p != NULL) {
+ maxver = smb_cf_version_from_str(p);
+ if (maxver == -1) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid max_protocol value \"%s\" specified in the section %s"),
+ 0, p, sname);
+ }
+ }
+
+ /*
+ * If setting both min/max protocol,
+ * validate against each other
+ */
+ if (minver != -1 && maxver != -1) {
+ if (minver > maxver) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid min/max protocol combination in the section %s"),
+ 0, sname);
+ } else {
+ ctx->ct_minver = minver;
+ ctx->ct_maxver = maxver;
+ }
+ }
+
+ /*
+ * Setting just min or max, validate against
+ * current settings
+ */
+ if (minver != -1) {
+ if (minver > ctx->ct_maxver) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid min/max protocol combination in the section %s"),
+ 0, sname);
+ } else {
+ ctx->ct_minver = minver;
+ }
+ }
+ if (maxver != -1) {
+ if (maxver < ctx->ct_minver) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid min/max protocol combination in the section %s"),
+ 0, sname);
+ } else {
+ ctx->ct_maxver = maxver;
+ }
+ }
+
rc_getstringptr(smb_rc, sname, "minauth", &p);
if (p) {
/*
* "minauth" was set in this section; override
* the current minimum authentication setting.
*/
- struct nv *nvp;
- for (nvp = minauth_table; nvp->name; nvp++)
- if (strcmp(p, nvp->name) == 0)
- break;
- if (nvp->name)
- ctx->ct_minauth = nvp->value;
- else {
+ ival = smb_cf_minauth_from_str(p);
+ if (ival != -1) {
+ ctx->ct_minauth = ival;
+ } else {
/*
* Unknown minimum authentication level.
*/
diff --git a/usr/src/lib/libsmbfs/smb/file.c b/usr/src/lib/libsmbfs/smb/file.c
index 8ca9d2cee1..3d2a431142 100644
--- a/usr/src/lib/libsmbfs/smb/file.c
+++ b/usr/src/lib/libsmbfs/smb/file.c
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -62,10 +63,16 @@
#include "private.h"
+/*
+ * It's not actually necessary to call the CLOSEFH ioctl, but doing it
+ * makes debugging a little easier. If we were to skip the ioctl,
+ * nsmb_close would cleanup the handle, here or in process exit.
+ */
int
smb_fh_close(int fd)
{
- return (close(fd));
+ (void) nsmb_ioctl(fd, SMBIOC_CLOSEFH, NULL);
+ return (nsmb_close(fd));
}
int
@@ -96,7 +103,7 @@ smb_fh_ntcreate(
goto errout;
}
from_fd = ctx->ct_dev_fd;
- if (ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) {
+ if (nsmb_ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) {
err = errno;
goto errout;
}
@@ -111,7 +118,7 @@ smb_fh_ntcreate(
ioc.ioc_share_acc = share_acc;
ioc.ioc_open_disp = open_disp;
ioc.ioc_creat_opts = create_opts;
- if (ioctl(new_fd, SMBIOC_NTCREATE, &ioc) == -1) {
+ if (nsmb_ioctl(new_fd, SMBIOC_NTCREATE, &ioc) == -1) {
err = errno;
goto errout;
}
@@ -120,7 +127,7 @@ smb_fh_ntcreate(
errout:
if (new_fd != -1)
- close(new_fd);
+ nsmb_close(new_fd);
errno = err;
return (-1);
}
@@ -210,11 +217,10 @@ smb_fh_read(int fd, off64_t offset, size_t count,
struct smbioc_rw rwrq;
bzero(&rwrq, sizeof (rwrq));
- rwrq.ioc_fh = -1; /* tell driver to supply this */
rwrq.ioc_base = dst;
rwrq.ioc_cnt = count;
rwrq.ioc_offset = offset;
- if (ioctl(fd, SMBIOC_READ, &rwrq) == -1) {
+ if (nsmb_ioctl(fd, SMBIOC_READ, &rwrq) == -1) {
return (-1);
}
return (rwrq.ioc_cnt);
@@ -227,11 +233,10 @@ smb_fh_write(int fd, off64_t offset, size_t count,
struct smbioc_rw rwrq;
bzero(&rwrq, sizeof (rwrq));
- rwrq.ioc_fh = -1; /* tell driver to supply this */
rwrq.ioc_base = (char *)src;
rwrq.ioc_cnt = count;
rwrq.ioc_offset = offset;
- if (ioctl(fd, SMBIOC_WRITE, &rwrq) == -1) {
+ if (nsmb_ioctl(fd, SMBIOC_WRITE, &rwrq) == -1) {
return (-1);
}
return (rwrq.ioc_cnt);
@@ -251,21 +256,23 @@ smb_fh_xactnp(int fd,
int *rdlen, char *rdata, /* receive */
int *more)
{
- int err, rparamcnt;
- uint16_t setup[2];
-
- setup[0] = TRANS_TRANSACT_NAMED_PIPE;
- setup[1] = 0xFFFF; /* driver replaces this */
- rparamcnt = 0;
+ smbioc_xnp_t ioc;
- err = smb_t2_request(fd, 2, setup, "\\PIPE\\",
- 0, NULL, /* TX paramcnt, params */
- tdlen, (void *)tdata,
- &rparamcnt, NULL, /* no RX params */
- rdlen, rdata, more);
+ /* this gets copyin & copyout */
+ bzero(&ioc, sizeof (ioc));
+ ioc.ioc_tdlen = tdlen;
+ ioc.ioc_rdlen = *rdlen;
+ ioc.ioc_more = 0;
+ ioc.ioc_tdata = (char *)tdata;
+ ioc.ioc_rdata = rdata;
- if (err)
+ if (nsmb_ioctl(fd, SMBIOC_XACTNP, &ioc) == -1) {
*rdlen = 0;
+ return (-1);
+ }
+
+ *rdlen = ioc.ioc_rdlen;
+ *more = ioc.ioc_more;
- return (err);
+ return (0);
}
diff --git a/usr/src/lib/libsmbfs/smb/findvc.c b/usr/src/lib/libsmbfs/smb/findvc.c
index 63c6cce242..0e781f7099 100644
--- a/usr/src/lib/libsmbfs/smb/findvc.c
+++ b/usr/src/lib/libsmbfs/smb/findvc.c
@@ -22,6 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -76,7 +78,7 @@ findvc(struct smb_ctx *ctx, struct addrinfo *ai)
bzero(&ssn->ssn_srvaddr, sizeof (ssn->ssn_srvaddr));
bcopy(ai->ai_addr, &ssn->ssn_srvaddr, ai->ai_addrlen);
- if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_FIND, ssn) == -1)
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_FIND, ssn) == -1)
return (errno);
return (0);
@@ -119,7 +121,6 @@ smb_ctx_findvc(struct smb_ctx *ctx)
if (err == 0) {
/* re-use an existing VC */
- ctx->ct_flags |= SMBCF_SSNACTIVE;
return (0);
}
}
@@ -137,7 +138,7 @@ int
smb_ctx_kill(struct smb_ctx *ctx)
{
- if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_KILL, NULL) == -1)
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_KILL, NULL) == -1)
return (errno);
return (0);
diff --git a/usr/src/lib/libsmbfs/smb/getaddr.c b/usr/src/lib/libsmbfs/smb/getaddr.c
index 67e61567a1..7c01b0d7c9 100644
--- a/usr/src/lib/libsmbfs/smb/getaddr.c
+++ b/usr/src/lib/libsmbfs/smb/getaddr.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -57,6 +58,8 @@
#include "charsets.h"
#include "private.h"
+static char smb_port[16] = "445";
+
void
dump_addrinfo(struct addrinfo *ai)
{
@@ -118,7 +121,7 @@ smb_ctx_getaddr(struct smb_ctx *ctx)
struct nb_ctx *nbc = ctx->ct_nb;
struct addrinfo hints, *res;
char *srvaddr_str;
- int gaierr, gaierr2;
+ int gaierr;
if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == '\0')
return (EAI_NONAME);
@@ -154,19 +157,26 @@ smb_ctx_getaddr(struct smb_ctx *ctx)
hints.ai_flags = AI_CANONNAME;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- gaierr = getaddrinfo(srvaddr_str, NULL, &hints, &res);
+ gaierr = getaddrinfo(srvaddr_str, smb_port, &hints, &res);
if (gaierr == 0) {
ctx->ct_addrinfo = res;
return (0);
}
/*
+ * If we really want to support NetBIOS, we should add
+ * an AF_NETBIOS entry to the address list here.
+ * For now, let's just skip NetBIOS.
+ * (Can we just kill NetBIOS? Please? :)
+ */
+#if 0 /* XXX Just kill NetBIOS? */
+ /*
* If regular IP name lookup failed, try NetBIOS,
* but only if given a valid NetBIOS name and if
* NetBIOS name lookup is enabled.
*/
if (nbc->nb_flags & NBCF_NS_ENABLE) {
- gaierr2 = nbns_getaddrinfo(ctx->ct_fullserver, nbc, &res);
+ int gaierr2 = nbns_getaddrinfo(ctx->ct_fullserver, nbc, &res);
if (gaierr2 == 0) {
if (res->ai_canonname)
strlcpy(ctx->ct_srvname,
@@ -176,6 +186,7 @@ smb_ctx_getaddr(struct smb_ctx *ctx)
return (0);
}
}
+#endif
/*
* Return the original error from getaddrinfo
diff --git a/usr/src/lib/libsmbfs/smb/iod_wk.c b/usr/src/lib/libsmbfs/smb/iod_wk.c
index 53f3c515be..38e9d5e0de 100644
--- a/usr/src/lib/libsmbfs/smb/iod_wk.c
+++ b/usr/src/lib/libsmbfs/smb/iod_wk.c
@@ -20,9 +20,10 @@
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -59,22 +60,21 @@
#include "private.h"
/*
- * Be the reader thread for this VC.
+ * The user agent (smbiod) calls smb_iod_connect for the first
+ * connection to some server, and if that succeeds, will start a
+ * thread running this function, passing the smb_ctx_t
+ *
+ * This thread now enters the driver and stays there, reading
+ * network responses as long as the connection is alive.
*/
int
smb_iod_work(smb_ctx_t *ctx)
{
smbioc_ssn_work_t *work = &ctx->ct_work;
- int vcst, err = 0;
+ int err = 0;
DPRINT("server: %s", ctx->ct_srvname);
- /* Calle should have opened these */
- if (ctx->ct_tran_fd == -1 || ctx->ct_dev_fd == -1) {
- err = EINVAL;
- goto out;
- }
-
/*
* This is the reader / reconnect loop.
*
@@ -84,34 +84,35 @@ smb_iod_work(smb_ctx_t *ctx)
*
* XXX: Add some syslog calls in here?
*/
- vcst = SMBIOD_ST_VCACTIVE;
for (;;) {
- switch (vcst) {
+ DPRINT("state: %s",
+ smb_iod_state_name(work->wk_out_state));
+
+ switch (work->wk_out_state) {
case SMBIOD_ST_IDLE:
/*
* Wait for driver requests to arrive
* for this VC, then return here.
* Next state is normally RECONNECT.
*/
- DPRINT("state: idle");
- if (ioctl(ctx->ct_dev_fd,
- SMBIOC_IOD_IDLE, &vcst) == -1) {
+ DPRINT("Call _ioc_idle...");
+ if (nsmb_ioctl(ctx->ct_dev_fd,
+ SMBIOC_IOD_IDLE, work) == -1) {
err = errno;
DPRINT("ioc_idle: err %d", err);
goto out;
}
+ DPRINT("Ret. from _ioc_idle");
continue;
case SMBIOD_ST_RECONNECT:
- DPRINT("state: reconnect");
+ DPRINT("Call _iod_connect...");
err = smb_iod_connect(ctx);
- if (err == 0) {
- vcst = SMBIOD_ST_VCACTIVE;
+ if (err == 0)
continue;
- }
- DPRINT("_iod_connect: err %d", err);
+ DPRINT("iod_connect: err %d", err);
/*
* If the error was EAUTH, retry is
* not likely to succeed either, so
@@ -119,64 +120,57 @@ smb_iod_work(smb_ctx_t *ctx)
* will need to run smbutil to get
* a new thread with new auth info.
*/
- if (err == EAUTH)
+ if (err == EAUTH) {
+ DPRINT("iod_connect: EAUTH (give up)");
goto out;
- vcst = SMBIOD_ST_RCFAILED;
- continue;
-
- case SMBIOD_ST_RCFAILED:
- DPRINT("state: rcfailed");
+ }
/*
- * Reconnect failed. Kill off any
- * requests waiting in the driver,
- * then get ready to try again.
- * Next state is normally IDLE.
+ * Reconnect failed. Notify any requests
+ * that we're not connected, and delay.
+ * Next state will be IDLE or RECONNECT.
*/
- if (ioctl(ctx->ct_dev_fd,
- SMBIOC_IOD_RCFAIL, &vcst) == -1) {
+ DPRINT("Call _iod_rcfail...");
+ if (nsmb_ioctl(ctx->ct_dev_fd,
+ SMBIOC_IOD_RCFAIL, work) == -1) {
err = errno;
- DPRINT("ioc_rcfail: err %d", err);
+ DPRINT("iod_rcfail: err %d", err);
goto out;
}
continue;
- case SMBIOD_ST_VCACTIVE:
- DPRINT("state: active");
- if (ioctl(ctx->ct_dev_fd,
+ case SMBIOD_ST_AUTHOK:
+ /*
+ * This is where we enter the driver and
+ * stay there. While the connection is up
+ * the VC will have SMBIOD_ST_VCACTIVE
+ */
+ DPRINT("Call _iod_work...");
+ if (nsmb_ioctl(ctx->ct_dev_fd,
SMBIOC_IOD_WORK, work) == -1) {
err = errno;
- DPRINT("ioc_work: err %d", err);
+ DPRINT("iod_work: err %d", err);
goto out;
}
- vcst = work->wk_out_state;
- /*
- * Go ahead and close the transport now,
- * rather than wait until reconnect to
- * this server.
- */
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
+ DPRINT("Ret. from _ioc_work");
continue;
case SMBIOD_ST_DEAD:
- DPRINT("state: dead");
+ DPRINT("got state=DEAD");
err = 0;
goto out;
default:
- DPRINT("state: BAD(%d)", vcst);
+ DPRINT("Unexpected state: %d (%s)",
+ work->wk_out_state,
+ smb_iod_state_name(work->wk_out_state));
err = EFAULT;
goto out;
}
}
out:
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- }
if (ctx->ct_dev_fd != -1) {
- close(ctx->ct_dev_fd);
+ nsmb_close(ctx->ct_dev_fd);
ctx->ct_dev_fd = -1;
}
diff --git a/usr/src/lib/libsmbfs/smb/keychain.c b/usr/src/lib/libsmbfs/smb/keychain.c
index fd9bcc9496..3a89fbd550 100644
--- a/usr/src/lib/libsmbfs/smb/keychain.c
+++ b/usr/src/lib/libsmbfs/smb/keychain.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -128,7 +128,7 @@ smbfs_keychain_cmn(
}
err = 0;
- if (ioctl(fd, cmd, &pk) < 0) {
+ if (nsmb_ioctl(fd, cmd, &pk) < 0) {
err = errno;
goto out;
}
@@ -142,7 +142,7 @@ smbfs_keychain_cmn(
out:
if (fd != -1)
- close(fd);
+ nsmb_close(fd);
return (err);
}
diff --git a/usr/src/lib/libsmbfs/smb/krb5ssp.c b/usr/src/lib/libsmbfs/smb/krb5ssp.c
index 208ec6d0a4..421a0bda37 100644
--- a/usr/src/lib/libsmbfs/smb/krb5ssp.c
+++ b/usr/src/lib/libsmbfs/smb/krb5ssp.c
@@ -32,6 +32,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -90,7 +91,7 @@ extern MECH_OID g_stcMechOIDList [];
typedef struct krb5ssp_state {
/* Filled in by krb5ssp_init_client */
krb5_context ss_krb5ctx; /* krb5 context (ptr) */
- krb5_ccache ss_krb5cc; /* credentials cache (ptr) */
+ krb5_ccache ss_krb5cc; /* credentials cache (ptr) */
krb5_principal ss_krb5clp; /* client principal (ptr) */
/* Filled in by krb5ssp_get_tkt */
krb5_auth_context ss_auth; /* auth ctx. w/ server (ptr) */
@@ -107,8 +108,8 @@ krb5ssp_tkt2gtok(uchar_t *tkt, ulong_t tktlen,
ulong_t len;
ulong_t bloblen = tktlen;
uchar_t krbapreq[2] = { KRB_AP_REQ, 0 };
- uchar_t *blob = NULL; /* result */
- uchar_t *b;
+ uchar_t *blob = NULL; /* result */
+ uchar_t *b;
bloblen += sizeof (krbapreq);
bloblen += g_stcMechOIDList[spnego_mech_oid_Kerberos_V5].iLen;
@@ -168,7 +169,7 @@ krb5ssp_get_tkt(krb5ssp_state_t *ss, char *server,
krb5_data outdata = {0};
krb5_error_code kerr = 0;
const char *fn = NULL;
- uchar_t *tkt;
+ uchar_t *tkt;
/* Should have these from krb5ssp_init_client. */
if (kctx == NULL || kcc == NULL) {
@@ -252,9 +253,9 @@ krb5ssp_put_request(struct ssp_ctx *sp, struct mbdata *out_mb)
int err;
struct smb_ctx *ctx = sp->smb_ctx;
krb5ssp_state_t *ss = sp->sp_private;
- uchar_t *tkt = NULL;
+ uchar_t *tkt = NULL;
ulong_t tktlen;
- uchar_t *gtok = NULL; /* gssapi token */
+ uchar_t *gtok = NULL; /* gssapi token */
ulong_t gtoklen; /* gssapi token length */
char *prin = ctx->ct_srvname;
@@ -268,9 +269,6 @@ krb5ssp_put_request(struct ssp_ctx *sp, struct mbdata *out_mb)
if ((err = mb_put_mem(out_mb, gtok, gtoklen, MB_MSYSTEM)) != 0)
goto out;
- if (ctx->ct_vcflags & SMBV_WILL_SIGN)
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
-
out:
if (gtok)
free(gtok);
@@ -383,7 +381,7 @@ krb5ssp_final(struct ssp_ctx *sp)
struct smb_ctx *ctx = sp->smb_ctx;
krb5ssp_state_t *ss = sp->sp_private;
krb5_keyblock *ssn_key = NULL;
- int err, len;
+ int err;
/*
* Save the session key, used for SMB signing
@@ -398,35 +396,32 @@ krb5ssp_final(struct ssp_ctx *sp)
err = EAUTH;
goto out;
}
- memset(ctx->ct_ssn_key, 0, SMBIOC_HASH_SZ);
- if ((len = ssn_key->length) > SMBIOC_HASH_SZ)
- len = SMBIOC_HASH_SZ;
- memcpy(ctx->ct_ssn_key, ssn_key->contents, len);
+
+ /* Sanity check the length */
+ if (ssn_key->length > 1024) {
+ DPRINT("session key too long");
+ err = EAUTH;
+ goto out;
+ }
/*
- * Set the MAC key on the first successful auth.
+ * Update/save the session key.
*/
- if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
- (ctx->ct_mackey == NULL)) {
- ctx->ct_mackeylen = ssn_key->length;
- ctx->ct_mackey = malloc(ctx->ct_mackeylen);
- if (ctx->ct_mackey == NULL) {
- ctx->ct_mackeylen = 0;
- err = ENOMEM;
- goto out;
- }
- memcpy(ctx->ct_mackey, ssn_key->contents,
- ctx->ct_mackeylen);
- /*
- * Apparently, the server used seq. no. zero
- * for our previous message, so next is two.
- */
- ctx->ct_mac_seqno = 2;
+ if (ctx->ct_ssnkey_buf != NULL) {
+ free(ctx->ct_ssnkey_buf);
+ ctx->ct_ssnkey_buf = NULL;
+ }
+ ctx->ct_ssnkey_buf = malloc(ssn_key->length);
+ if (ctx->ct_ssnkey_buf == NULL) {
+ err = ENOMEM;
+ goto out;
}
+ ctx->ct_ssnkey_len = ssn_key->length;
+ memcpy(ctx->ct_ssnkey_buf, ssn_key->contents, ctx->ct_ssnkey_len);
err = 0;
out:
- if (ssn_key)
+ if (ssn_key != NULL)
krb5_free_keyblock(ss->ss_krb5ctx, ssn_key);
return (err);
@@ -508,7 +503,7 @@ krb5ssp_init_client(struct ssp_ctx *sp)
krb5ssp_state_t *ss;
krb5_error_code kerr;
krb5_context kctx = NULL;
- krb5_ccache kcc = NULL;
+ krb5_ccache kcc = NULL;
krb5_principal kprin = NULL;
if ((sp->smb_ctx->ct_authflags & SMB_AT_KRB5) == 0) {
diff --git a/usr/src/lib/libsmbfs/smb/lgrep.awk b/usr/src/lib/libsmbfs/smb/lgrep.awk
deleted file mode 100644
index fe6e8fa0b9..0000000000
--- a/usr/src/lib/libsmbfs/smb/lgrep.awk
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-
-#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
-# Copyright 2012 Milan Jurik. All rights reserved.
-#
-
-# This is a "lint tail" that removes all the
-# uninteresting lines from our lint output.
-# It's nawk because sed doesn't do (a|b).
-# Also comments are easier here.
-
-# There's no lintlib for krb5 yet (CR 6911968)
-/: Warning: -lkrb5 not found/ { next; }
-/: Warning: library -lkrb5 not found/ { next; }
-
-# Kill noise from xti.h with _XOPEN_SOURCE vs not. (CR 6911717)
-/: _xti_.* .E_INCONS_ARG_DECL2./ { next; }
-/: _xti_.* .E_INCONS_ARG_USED2./ { next; }
-/: _xti_.* .E_INCONS_VAL_TYPE_DECL2./ { next; }
-
-# This is third-party code we'd rather not "fix"
-/\/spnego.c.* .E_STMT_NOT_REACHED./ { next; }
-
-# The mb_put/md_get functions are intentionally used both
-# with and without return value checks. Not a concern.
-/: mb_put_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: md_get_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-
-# The rc_get* functions clear the out arg even on failure,
-# so most callers don't need to check the return value.
-/: rc_get[a-z]* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-
-# These have uninteresting return values, usually ignored.
-/: (n|sm)b_ctx_readrcsection .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: nls_str_(lower|upper) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: rc_(close|freesect) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-
-# Other functions for which we often ignore return values.
-/: [a-z]*close .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: [a-z]*flush .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: [a-z]*printf .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: mem(cpy|move|set) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: mutex_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: str[ln]?(cat|cpy) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-
-{ print; }
diff --git a/usr/src/lib/libsmbfs/smb/mapfile-vers b/usr/src/lib/libsmbfs/smb/mapfile-vers
index 8f0c3905c6..a94b3bc6e1 100644
--- a/usr/src/lib/libsmbfs/smb/mapfile-vers
+++ b/usr/src/lib/libsmbfs/smb/mapfile-vers
@@ -19,7 +19,7 @@
#
#
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
#
#
@@ -36,6 +36,11 @@
# MAPFILE HEADER END
#
+#
+# Note that several things in here are NODIRECT so that the
+# "fksmbcl" development tool can provide its own versions.
+#
+
$mapfile_version 2
SYMBOL_VERSION SUNWprivate {
@@ -60,6 +65,12 @@ SYMBOL_VERSION SUNWprivate {
nls_str_toloc;
nls_str_upper;
+ nsmb_close { FLAGS = NODIRECT };
+ nsmb_ioctl { FLAGS = NODIRECT };
+
+ smb_cf_minauth_from_str;
+ smb_cf_version_from_str;
+
smb_close_rcfile;
smb_ctx_alloc;
@@ -72,6 +83,7 @@ SYMBOL_VERSION SUNWprivate {
smb_ctx_gethandle;
smb_ctx_init;
smb_ctx_kill;
+ smb_ctx_newvc { FLAGS = NODIRECT };
smb_ctx_opt;
smb_ctx_parseunc;
smb_ctx_readrc;
@@ -82,6 +94,8 @@ SYMBOL_VERSION SUNWprivate {
smb_ctx_setauthflags;
smb_ctx_setdomain;
smb_ctx_setfullserver;
+ smb_ctx_setminver;
+ smb_ctx_setmaxver;
smb_ctx_setnbflags;
smb_ctx_setpassword;
smb_ctx_setpwhash;
@@ -108,25 +122,16 @@ SYMBOL_VERSION SUNWprivate {
smb_getprogname;
smb_iod_connect;
smb_iod_door_path;
- smb_iod_open_door;
- smb_iod_start;
+ smb_iod_open_door { FLAGS = NODIRECT };
+ smb_iod_start { FLAGS = NODIRECT };
smb_iod_work;
smb_lib_init;
+ smb_open_driver { FLAGS = NODIRECT };
smb_open_printer;
smb_open_rcfile;
smb_simplecrypt;
smb_simpledecrypt;
smb_strerror;
-#
-# Functions to support the Remote Access Protocol (RAP)
- smb_rap_create;
- smb_rap_done;
- smb_rap_error;
- smb_rap_getNparam;
- smb_rap_request;
- smb_rap_setNparam;
- smb_rap_setPparam;
-#
smb_verbose { FLAGS = NODIRECT }; # data
#
# Functions to support Access Control Lists (ACLs)
diff --git a/usr/src/lib/libsmbfs/smb/nb_ssn.c b/usr/src/lib/libsmbfs/smb/nb_ssn.c
deleted file mode 100644
index 319e250296..0000000000
--- a/usr/src/lib/libsmbfs/smb/nb_ssn.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/*
- * NetBIOS session service functions
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <libintl.h>
-#include <xti.h>
-#include <assert.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-
-#include <netsmb/netbios.h>
-#include <netsmb/smb_lib.h>
-#include <netsmb/nb_lib.h>
-#include <netsmb/mchain.h>
-
-#include "private.h"
-#include "charsets.h"
-
-static int nb_ssn_send(struct smb_ctx *, struct mbdata *, int, int);
-static int nb_ssn_recv(struct smb_ctx *, struct mbdata *, int *, int *);
-static int nb_ssn_pollin(struct smb_ctx *, int);
-
-/*
- * Send a data message.
- */
-int
-smb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp)
-{
- return (nb_ssn_send(ctx, mbp, 0, mbp->mb_count));
-}
-
-/*
- * Send a NetBIOS message, after
- * prepending the 4-byte header.
- */
-static int
-nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp,
- int mtype, int mlen)
-{
- mbuf_t *m;
- uint32_t hdr, hdrbuf;
- int err;
-
- m = mbp->mb_top;
- if (m == NULL)
- return (EINVAL);
-
- /*
- * Prepend the NetBIOS header.
- * Our mbufs leave space for this.
- */
- hdr = (mtype << 24) | mlen;
- hdrbuf = htonl(hdr);
- m->m_data -= 4;
- m->m_len += 4;
- bcopy(&hdrbuf, m->m_data, 4);
-
- /*
- * Get contiguous data (so TCP won't fragment)
- * Note: replaces mb_top.
- */
- err = m_lineup(mbp->mb_top, &mbp->mb_top);
- if (err)
- return (err);
- m = mbp->mb_top;
-
- /*
- * Send it.
- */
- if (t_snd(ctx->ct_tran_fd, m->m_data, m->m_len, 0) < 0) {
- if (t_errno == TSYSERR)
- err = errno;
- else
- err = EPROTO;
- DPRINT("t_snd: t_errno %d, err %d", t_errno, err);
- return (err);
- }
-
- return (0);
-}
-
-/*
- * Receive a data message. Discard anything else.
- * Caller must deal with EAGAIN, EINTR.
- */
-int
-smb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mbp)
-{
- int err, mtype, mlen;
- err = nb_ssn_recv(ctx, mbp, &mtype, &mlen);
- if (err)
- return (err);
- if (mtype != NB_SSN_MESSAGE) {
- DPRINT("discard type 0x%x", mtype);
- mb_done(mbp);
- return (EAGAIN);
- }
- if (mlen == 0) {
- DPRINT("zero length");
- mb_done(mbp);
- return (EAGAIN);
- }
-
- return (0);
-}
-
-/*
- * Receive a NetBIOS message, any type.
- * Give caller type and length.
- */
-static int
-nb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mb,
- int *mtype, int *mlen)
-{
- char *buf;
- uint32_t hdr, hdrbuf;
- int cnt, len, err, moreflag;
- int fd = ctx->ct_tran_fd;
- int tmo = smb_recv_timeout * 1000;
-
- /*
- * Start by getting the header
- * (four bytes)
- */
- if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
- DPRINT("pollin err %d", err);
- return (err);
- }
- moreflag = 0;
- cnt = t_rcv(fd, &hdrbuf, sizeof (hdrbuf), &moreflag);
- if (cnt < 0) {
- err = get_xti_err(fd);
- DPRINT("t_errno %d err %d", t_errno, err);
- return (err);
- }
-
- if (cnt != sizeof (hdrbuf)) {
- DPRINT("hdr cnt %d", cnt);
- return (EPROTO);
- }
-
- /*
- * Decode the header, get the length.
- */
- hdr = ntohl(hdrbuf);
- *mtype = (hdr >> 24) & 0xff;
- *mlen = hdr & 0xffffff;
-
- if (mlen == 0)
- return (0);
-
- /*
- * Get a message buffer, read the payload
- */
- if ((err = mb_init_sz(mb, *mlen)) != 0)
- return (err);
- buf = mb->mb_top->m_data;
- len = *mlen;
- while (len > 0) {
- if (!moreflag) {
- if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
- DPRINT("pollin err %d", err);
- return (err);
- }
- }
-
- moreflag = 0;
- cnt = t_rcv(fd, buf, len, &moreflag);
- if (cnt < 0) {
- err = get_xti_err(fd);
- DPRINT("t_errno %d err %d", t_errno, err);
- return (err);
- }
- buf += cnt;
- len -= cnt;
- }
- mb->mb_top->m_len = *mlen;
- mb->mb_count = *mlen;
-
- return (0);
-}
-
-int
-get_xti_err(int fd)
-{
- int look;
- if (t_errno == TSYSERR)
- return (errno);
-
- if (t_errno == TLOOK) {
- look = t_look(fd);
- switch (look) {
- case T_DISCONNECT:
- (void) t_rcvdis(fd, NULL);
- (void) t_snddis(fd, NULL);
- return (ECONNRESET);
- case T_ORDREL:
- /* Received orderly release indication */
- (void) t_rcvrel(fd);
- /* Send orderly release indicator */
- (void) t_sndrel(fd);
- return (ECONNRESET);
- }
- }
- return (EPROTO);
-}
-
-/*
- * Wait for data we can receive.
- * Timeout is mSec., as for poll(2)
- */
-static int
-nb_ssn_pollin(struct smb_ctx *ctx, int tmo)
-{
- struct pollfd pfd[1];
- int cnt, err;
-
- pfd[0].fd = ctx->ct_tran_fd;
- pfd[0].events = POLLIN | POLLPRI;
- pfd[0].revents = 0;
- cnt = poll(pfd, 1, tmo);
- switch (cnt) {
- case 0:
- err = ETIME;
- break;
- case -1:
- err = errno;
- break;
- default:
- err = 0;
- break;
- }
- return (err);
-}
-
-/*
- * Send a NetBIOS session request and
- * wait for the response.
- */
-int
-nb_ssn_request(struct smb_ctx *ctx, char *srvname)
-{
- struct mbdata req, res;
- struct nb_name lcl, srv;
- int err, mtype, mlen;
- char *ucwks;
-
- bzero(&req, sizeof (req));
- bzero(&res, sizeof (res));
-
- if ((err = mb_init(&req)) != 0)
- goto errout;
-
- ucwks = utf8_str_toupper(ctx->ct_locname);
- if (ucwks == NULL) {
- err = ENOMEM;
- goto errout;
- }
-
- /* Local NB name. */
- snprintf(lcl.nn_name, NB_NAMELEN, "%-15.15s", ucwks);
- lcl.nn_type = NBT_WKSTA;
- lcl.nn_scope = ctx->ct_nb->nb_scope;
-
- /* Server NB name */
- snprintf(srv.nn_name, NB_NAMELEN, "%-15.15s", srvname);
- srv.nn_type = NBT_SERVER;
- srv.nn_scope = ctx->ct_nb->nb_scope;
-
- /*
- * Build the request. Header is prepended later.
- */
- if ((err = nb_name_encode(&req, &srv)) != 0)
- goto errout;
- if ((err = nb_name_encode(&req, &lcl)) != 0)
- goto errout;
-
- /*
- * Send it, wait for the reply.
- */
- err = nb_ssn_send(ctx, &req, NB_SSN_REQUEST, req.mb_count);
- if (err) {
- DPRINT("send, err %d", err);
- goto errout;
- }
- err = nb_ssn_recv(ctx, &res, &mtype, &mlen);
- if (err) {
- DPRINT("recv, err %d", err);
- goto errout;
- }
-
- if (mtype != NB_SSN_POSRESP) {
- DPRINT("recv, mtype 0x%x", mtype);
- err = ECONNREFUSED;
- goto errout;
- }
-
- return (0);
-
-errout:
- mb_done(&res);
- mb_done(&req);
- return (err);
-}
diff --git a/usr/src/lib/libsmbfs/smb/negprot.c b/usr/src/lib/libsmbfs/smb/negprot.c
deleted file mode 100644
index 770b742c44..0000000000
--- a/usr/src/lib/libsmbfs/smb/negprot.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright (c) 2000-2001 Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-/*
- * SMB Negotiate Protocol, and related.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <strings.h>
-#include <netdb.h>
-#include <libintl.h>
-#include <xti.h>
-#include <assert.h>
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/byteorder.h>
-#include <sys/socket.h>
-#include <sys/fcntl.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-
-#include <netsmb/smb.h>
-#include <netsmb/smb_lib.h>
-#include <netsmb/netbios.h>
-#include <netsmb/nb_lib.h>
-#include <netsmb/smb_dev.h>
-
-#include "charsets.h"
-#include "smb_crypt.h"
-#include "private.h"
-
-/*
- * SMB dialects that we know about.
- */
-struct smb_dialect {
- int d_id;
- const char *d_name;
-};
-static struct smb_dialect smb_dialects[] = {
- {SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"},
- {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"},
- {SMB_DIALECT_LANMAN2_0, "LM1.2X002"},
- {SMB_DIALECT_LANMAN2_1, "LANMAN2.1"},
- {SMB_DIALECT_NTLM0_12, "NT LM 0.12"},
- {-1, NULL}
-};
-
-#define SMB_DIALECT_MAX \
- (sizeof (smb_dialects) / sizeof (struct smb_dialect) - 2)
-
-static const uint32_t smb_clnt_caps_mask =
- SMB_CAP_UNICODE |
- SMB_CAP_LARGE_FILES |
- SMB_CAP_NT_SMBS |
- SMB_CAP_STATUS32 |
- SMB_CAP_EXT_SECURITY;
-
-/*
- * SMB Negotiate Protocol
- * Based on code from the driver: smb_smb.c
- *
- * If using Extended Security, oblob (output)
- * will hold the initial security "hint".
- */
-int
-smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob)
-{
- struct smb_sopt *sv = &ctx->ct_sopt;
- struct smb_iods *is = &ctx->ct_iods;
- struct smb_rq *rqp;
- struct mbdata *mbp;
- struct smb_dialect *dp;
- int err, len;
- uint8_t wc, eklen;
- uint16_t dindex, bc;
- int will_sign = 0;
-
- /*
- * Initialize: vc_hflags and vc_hflags2.
- * Note: ctx->ct_hflags* are copied into the
- * (per request) rqp->rq_hflags* by smb_rq_init.
- *
- * Like Windows, set FLAGS2_UNICODE in our first request,
- * even though technically we don't yet know whether the
- * server supports Unicode. Will clear this flag below
- * if we find out it doesn't. Need to do this because
- * some servers reject all non-Unicode requests.
- */
- ctx->ct_hflags =
- SMB_FLAGS_CASELESS |
- SMB_FLAGS_CANONICAL_PATHNAMES;
- ctx->ct_hflags2 =
- SMB_FLAGS2_KNOWS_LONG_NAMES |
- SMB_FLAGS2_KNOWS_EAS |
- /* SMB_FLAGS2_IS_LONG_NAME |? */
- /* EXT_SEC (see below) */
- SMB_FLAGS2_ERR_STATUS |
- SMB_FLAGS2_UNICODE;
-
- /*
- * Sould we offer extended security?
- * We'll turn this back off below if
- * the server doesn't support it.
- */
- if (ctx->ct_vopt & SMBVOPT_EXT_SEC)
- ctx->ct_hflags2 |= SMB_FLAGS2_EXT_SEC;
-
- /*
- * The initial UID needs to be zero,
- * or Windows XP says "bad user".
- * The initial TID is all ones, but
- * we don't use it or store it here
- * because the driver handles that.
- */
- is->is_smbuid = 0;
-
- /*
- * In case we're reconnecting,
- * free previous stuff.
- */
- ctx->ct_mac_seqno = 0;
- if (ctx->ct_mackey != NULL) {
- free(ctx->ct_mackey);
- ctx->ct_mackey = NULL;
- ctx->ct_mackeylen = 0;
- }
-
- sv = &ctx->ct_sopt;
- bzero(sv, sizeof (struct smb_sopt));
-
- err = smb_rq_init(ctx, SMB_COM_NEGOTIATE, &rqp);
- if (err)
- return (err);
-
- /*
- * Build the SMB request.
- */
- mbp = &rqp->rq_rq;
- mb_put_uint8(mbp, 0); /* word count */
- smb_rq_bstart(rqp);
- for (dp = smb_dialects; dp->d_id != -1; dp++) {
- mb_put_uint8(mbp, SMB_DT_DIALECT);
- mb_put_astring(mbp, dp->d_name);
- }
- smb_rq_bend(rqp);
-
- /*
- * This does the OTW call
- */
- err = smb_rq_internal(ctx, rqp);
- if (err) {
- DPRINT("call failed, err %d", err);
- goto errout;
- }
- if (rqp->rq_status != 0) {
- DPRINT("nt status 0x%x", rqp->rq_status);
- err = EBADRPC;
- goto errout;
- }
-
- /*
- * Decode the response
- *
- * Comments to right show names as described in
- * The Microsoft SMB Protocol spec. [MS-SMB]
- * section 2.2.3
- */
- mbp = &rqp->rq_rp;
- (void) md_get_uint8(mbp, &wc);
- err = md_get_uint16le(mbp, &dindex);
- if (err || dindex > SMB_DIALECT_MAX) {
- DPRINT("err %d dindex %d", err, (int)dindex);
- goto errout;
- }
- dp = smb_dialects + dindex;
- sv->sv_proto = dp->d_id;
- DPRINT("Dialect %s", dp->d_name);
- if (dp->d_id < SMB_DIALECT_NTLM0_12) {
- /* XXX: User-visible warning too? */
- DPRINT("old dialect %s", dp->d_name);
- goto errout;
- }
- if (wc != 17) {
- DPRINT("bad wc %d", (int)wc);
- goto errout;
- }
- md_get_uint8(mbp, &sv->sv_sm); /* SecurityMode */
- md_get_uint16le(mbp, &sv->sv_maxmux); /* MaxMpxCount */
- md_get_uint16le(mbp, &sv->sv_maxvcs); /* MaxCountVCs */
- md_get_uint32le(mbp, &sv->sv_maxtx); /* MaxBufferSize */
- md_get_uint32le(mbp, &sv->sv_maxraw); /* MaxRawSize */
- md_get_uint32le(mbp, &sv->sv_skey); /* SessionKey */
- md_get_uint32le(mbp, &sv->sv_caps); /* Capabilities */
- md_get_mem(mbp, NULL, 8, MB_MSYSTEM); /* SystemTime(s) */
- md_get_uint16le(mbp, (uint16_t *)&sv->sv_tz);
- md_get_uint8(mbp, &eklen); /* EncryptionKeyLength */
- err = md_get_uint16le(mbp, &bc); /* ByteCount */
- if (err)
- goto errout;
-
- /* BEGIN CSTYLED */
- /*
- * Will we do SMB signing? Or block the connection?
- * The table below describes this logic. References:
- * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3]
- * http://msdn.microsoft.com/en-us/library/cc212511.aspx
- * http://msdn.microsoft.com/en-us/library/cc212929.aspx
- *
- * Srv/Cli | Required | Enabled | If Required | Disabled
- * ------------+----------+------------+-------------+-----------
- * Required | Signed | Signed | Signed | Blocked [1]
- * ------------+----------+------------+-------------+-----------
- * Enabled | Signed | Signed | Not Signed | Not Signed
- * ------------+----------+------------+-------------+-----------
- * If Required | Signed | Not Signed | Not Signed | Not Signed
- * ------------+----------+------------+-------------+-----------
- * Disabled | Blocked | Not Signed | Not Signed | Not Signed
- *
- * [1] Like Windows 2003 and later, we don't really implement
- * the "Disabled" setting. Instead we implement "If Required",
- * so we always sign if the server requires signing.
- */
- /* END CSTYLED */
-
- if (sv->sv_sm & SMB_SM_SIGS_REQUIRE) {
- /*
- * Server requires signing. We will sign,
- * even if local setting is "disabled".
- */
- will_sign = 1;
- } else if (sv->sv_sm & SMB_SM_SIGS) {
- /*
- * Server enables signing (client's option).
- * If enabled locally, do signing.
- */
- if (ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED)
- will_sign = 1;
- /* else not signing. */
- } else {
- /*
- * Server does not support signing.
- * If we "require" it, bail now.
- */
- if (ctx->ct_vopt & SMBVOPT_SIGNING_REQUIRED) {
- DPRINT("Client requires signing "
- "but server has it disabled.");
- err = EBADRPC;
- goto errout;
- }
- }
-
- if (will_sign) {
- ctx->ct_vcflags |= SMBV_WILL_SIGN;
- }
- DPRINT("Security signatures: %d", will_sign);
-
- /* See comment above re. FLAGS2_UNICODE */
- if (sv->sv_caps & SMB_CAP_UNICODE)
- ctx->ct_vcflags |= SMBV_UNICODE;
- else
- ctx->ct_hflags2 &= ~SMB_FLAGS2_UNICODE;
-
- if ((sv->sv_caps & SMB_CAP_STATUS32) == 0) {
- /*
- * They don't do NT error codes.
- *
- * If we send requests with
- * SMB_FLAGS2_ERR_STATUS set in
- * Flags2, Windows 98, at least,
- * appears to send replies with that
- * bit set even though it sends back
- * DOS error codes. (They probably
- * just use the request header as
- * a template for the reply header,
- * and don't bother clearing that bit.)
- *
- * Therefore, we clear that bit in
- * our vc_hflags2 field.
- */
- ctx->ct_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
- }
- if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
- sv->sv_maxtx < 4096 &&
- (sv->sv_caps & SMB_CAP_NT_SMBS) == 0) {
- ctx->ct_vcflags |= SMBV_WIN95;
- DPRINT("Win95 detected");
- }
-
- /*
- * The rest of the message varies depending on
- * whether we've negotiated "extended security".
- *
- * With extended security, we have:
- * Server_GUID (length 16)
- * Security_BLOB
- * Otherwise we have:
- * EncryptionKey (length is eklen)
- * PrimaryDomain
- */
- if (sv->sv_caps & SMB_CAP_EXT_SECURITY) {
- struct mbuf *m;
- DPRINT("Ext.Security: yes");
-
- /*
- * Skip the server GUID.
- */
- err = md_get_mem(mbp, NULL, SMB_GUIDLEN, MB_MSYSTEM);
- if (err)
- goto errout;
- /*
- * Remainder is the security blob.
- * Note: eklen "must be ignored" [MS-SMB]
- */
- len = (int)bc - SMB_GUIDLEN;
- if (len < 0)
- goto errout;
-
- /*
- * Get the (optional) SPNEGO "hint".
- */
- err = md_get_mbuf(mbp, len, &m);
- if (err)
- goto errout;
- mb_initm(oblob, m);
- oblob->mb_count = len;
- } else {
- DPRINT("Ext.Security: no");
- ctx->ct_hflags2 &= ~SMB_FLAGS2_EXT_SEC;
-
- /*
- * Save the "Encryption Key" (the challenge).
- *
- * Sanity check: make sure the sec. blob length
- * isn't bigger than the byte count.
- */
- if (bc < eklen || eklen < NTLM_CHAL_SZ) {
- err = EBADRPC;
- goto errout;
- }
- err = md_get_mem(mbp, ctx->ct_srv_chal,
- NTLM_CHAL_SZ, MB_MSYSTEM);
- /*
- * Server domain follows (ignored)
- * Note: NOT aligned(2) - unusual!
- */
- }
-
- smb_rq_done(rqp);
-
- /*
- * A few sanity checks on what we received,
- * becuse we will send these in ssnsetup.
- *
- * Maximum outstanding requests (we care),
- * and Max. VCs (we only use one). Also,
- * MaxBufferSize lower limit per spec.
- */
- if (sv->sv_maxmux < 1)
- sv->sv_maxmux = 1;
- if (sv->sv_maxvcs < 1)
- sv->sv_maxvcs = 1;
- if (sv->sv_maxtx < 1024)
- sv->sv_maxtx = 1024;
-
- /*
- * Maximum transfer size.
- * Sanity checks:
- *
- * Let's be conservative about an upper limit here.
- * Win2k uses 16644 (and others) so 32k should be a
- * reasonable sanity limit for this value.
- *
- * Note that this limit does NOT affect READX/WRITEX
- * with CAP_LARGE_..., which we nearly always use.
- */
- is->is_txmax = sv->sv_maxtx;
- if (is->is_txmax > 0x8000)
- is->is_txmax = 0x8000;
-
- /*
- * Max read/write sizes, WITHOUT overhead.
- * This is just the payload size, so we must
- * leave room for the SMB headers, etc.
- * This is just the ct_txmax value, but
- * reduced and rounded down. Tricky bit:
- *
- * Servers typically give us a value that's
- * some nice "round" number, i.e 0x4000 plus
- * some overhead, i.e. Win2k: 16644==0x4104
- * Subtract for the SMB header (32) and the
- * SMB command word and byte vectors (34?),
- * then round down to a 512 byte multiple.
- */
- len = is->is_txmax - 68;
- len &= 0xFE00;
- /* XXX: Not sure yet which of these to keep. */
- is->is_rwmax = len;
- is->is_rxmax = len;
- is->is_wxmax = len;
-
- /*
- * Most of the "capability" bits we offer in session setup
- * are just copied from those offered by the server.
- */
- ctx->ct_clnt_caps = sv->sv_caps & smb_clnt_caps_mask;
-
- /* Get the client nonce. */
- (void) smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
-
- return (0);
-
-errout:
- smb_rq_done(rqp);
- if (err == 0)
- err = EBADRPC;
- return (err);
-}
diff --git a/usr/src/lib/libsmbfs/smb/ntlm.c b/usr/src/lib/libsmbfs/smb/ntlm.c
index 9f08a2eaca..44b26f54e6 100644
--- a/usr/src/lib/libsmbfs/smb/ntlm.c
+++ b/usr/src/lib/libsmbfs/smb/ntlm.c
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -184,7 +184,8 @@ ntlm_v1_session_key(uchar_t *ssn_key, const uchar_t *nt_hash)
*/
int
ntlm_put_v1_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssn_key)
{
uchar_t *lmresp, *ntresp;
int err;
@@ -229,7 +230,7 @@ ntlm_put_v1_responses(struct smb_ctx *ctx,
/*
* Compute the session key
*/
- ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash);
+ ntlm_v1_session_key(ssn_key, ctx->ct_nthash);
return (err);
}
@@ -245,7 +246,8 @@ ntlm_put_v1_responses(struct smb_ctx *ctx,
*/
int
ntlm_put_v1x_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssn_key)
{
MD5_CTX context;
uchar_t challenges[2 * NTLM_CHAL_SZ];
@@ -299,7 +301,7 @@ ntlm_put_v1x_responses(struct smb_ctx *ctx,
/*
* Compute the session key
*/
- ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash);
+ ntlm_v1_session_key(ssn_key, ctx->ct_nthash);
return (err);
}
@@ -477,7 +479,8 @@ ntlm_v2_session_key(uchar_t *ssn_key,
*/
int
ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssn_key)
{
uchar_t *lmresp, *ntresp;
int err;
@@ -547,7 +550,7 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
/*
* Compute the session key
*/
- ntlm_v2_session_key(ctx->ct_ssn_key, v2hash, ntresp);
+ ntlm_v2_session_key(ssn_key, v2hash, ntresp);
out:
if (err) {
@@ -650,37 +653,13 @@ out:
}
/*
- * Build the MAC key (for SMB signing)
- */
-int
-ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp)
-{
- struct mbuf *m;
- size_t len;
- char *p;
-
- /*
- * MAC_key = concat(session_key, nt_response)
- */
- m = ntresp_mbp->mb_top;
- len = NTLM_HASH_SZ + m->m_len;
- if ((p = malloc(len)) == NULL)
- return (ENOMEM);
- ctx->ct_mackeylen = len;
- ctx->ct_mackey = p;
- memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
- memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
-
- return (0);
-}
-
-/*
* Helper for ntlmssp_put_type3 - Build the "key exchange key"
* used when we have both NTLM(v1) and NTLMSSP_NEGOTIATE_NTLM2.
* HMAC_MD5(SessionBaseKey, concat(ServerChallenge, LmResponse[0..7]))
*/
void
-ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey)
+ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp,
+ uchar_t *ssn_key, uchar_t *kxkey)
{
uchar_t data[NTLM_HASH_SZ];
uchar_t *p = mtod(lm_mbp->mb_top, uchar_t *);
@@ -690,6 +669,6 @@ ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey)
memcpy(data + NTLM_CHAL_SZ, p, NTLM_CHAL_SZ);
/* HMAC_MD5(SessionBaseKey, concat(...)) */
- HMACT64(kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ,
+ HMACT64(kxkey, ssn_key, NTLM_HASH_SZ,
data, NTLM_HASH_SZ);
}
diff --git a/usr/src/lib/libsmbfs/smb/ntlm.h b/usr/src/lib/libsmbfs/smb/ntlm.h
index 447033b516..d0c093689a 100644
--- a/usr/src/lib/libsmbfs/smb/ntlm.h
+++ b/usr/src/lib/libsmbfs/smb/ntlm.h
@@ -22,7 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NTLM_H
@@ -38,7 +39,7 @@
* NTLM_HASH_SZ: 16 bytes (see smb_lib.h)
* NTLM_CHAL_SZ: 8 bytes (see smb_lib.h)
*/
-#define NTLM_V1_RESP_SZ 24 /* response size */
+#define NTLM_V1_RESP_SZ 24 /* response size */
#define NAMETYPE_EOL 0x0000 /* end of list of names */
#define NAMETYPE_MACHINE_NB 0x0001 /* NetBIOS machine name */
@@ -57,20 +58,21 @@ ntlm_build_target_info(struct smb_ctx *, struct mbuf *, struct mbdata *);
int
ntlm_put_v1_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssnkey);
int
ntlm_put_v1x_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssnkey);
int
ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp);
-
-int
-ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp);
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssnkey);
void
-ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey);
+ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp,
+ uchar_t *ssn_key, uchar_t *kxkey);
#endif /* _NTLM_H */
diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.c b/usr/src/lib/libsmbfs/smb/ntlmssp.c
index f39fa594ec..5ae583114d 100644
--- a/usr/src/lib/libsmbfs/smb/ntlmssp.c
+++ b/usr/src/lib/libsmbfs/smb/ntlmssp.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -67,13 +67,14 @@
#include "ntlmssp.h"
/* A shorter alias for a crazy long name from [MS-NLMP] */
-#define NTLMSSP_NEGOTIATE_NTLM2 \
+#define NTLMSSP_NEGOTIATE_ESS \
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
typedef struct ntlmssp_state {
uint32_t ss_flags;
char *ss_target_name; /* Primary domain or server name */
struct mbuf *ss_target_info;
+ uchar_t ss_ssnkey[NTLM_HASH_SZ];
uchar_t ss_kxkey[NTLM_HASH_SZ];
} ntlmssp_state_t;
@@ -90,8 +91,7 @@ struct sec_buf {
static const char ntlmssp_id[ID_SZ] = "NTLMSSP";
static int
-ntlm_rand_ssn_key(struct smb_ctx *ctx,
- ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp);
+ntlm_rand_ssn_key(ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp);
/*
* Get a "security buffer" (header part)
@@ -249,16 +249,14 @@ ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
NTLMSSP_NEGOTIATE_SEAL |
/* NTLMSSP_NEGOTIATE_LM_KEY (never) */
NTLMSSP_NEGOTIATE_NTLM |
- /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN (set below) */
- NTLMSSP_NEGOTIATE_NTLM2 |
+ NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
+ NTLMSSP_NEGOTIATE_ESS |
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_KEY_EXCH |
NTLMSSP_NEGOTIATE_56;
- if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
- ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
- }
+ if ((ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED) == 0)
+ ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
hdr.h_type = NTLMSSP_MSGTYPE_NEGOTIATE;
@@ -447,15 +445,20 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
/*
* We're setting up a NULL session, meaning
* the lm_mbc, nt_mbc parts remain empty.
- * Let's add the "anon" flag (hint).
- * As there is no session key, disable the
- * fancy session key stuff.
+ * Let's add the "anon" flag (hint), and
+ * as we have no OWF hashes, we can't use
+ * "extended session security" (_ESS).
+ * The SessionBaseKey is all zeros, so
+ * the KeyExchangeKey is too. Otherwise
+ * this is like NTLMv2/LMv2
*/
- hdr.h_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
- ssp_st->ss_flags &= ~(
- NTLMSSP_NEGOTIATE_NTLM2 |
- NTLMSSP_NEGOTIATE_KEY_EXCH);
+ ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
+ ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ESS;
+ hdr.h_flags = ssp_st->ss_flags;
err = 0;
+ /* KeyExchangeKey = SessionBaseKey = (zeros) */
+ memset(ssp_st->ss_ssnkey, 0, NTLM_HASH_SZ);
+ memset(ssp_st->ss_kxkey, 0, NTLM_HASH_SZ);
} else if (ctx->ct_authflags & SMB_AT_NTLM2) {
/*
* Doing NTLMv2/LMv2
@@ -465,47 +468,49 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
if (err)
goto out;
err = ntlm_put_v2_responses(ctx, &ti_mbc,
- &lm_mbc, &nt_mbc);
+ &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
if (err)
goto out;
- /* The "key exg. key" is the session base key */
- memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ);
-
- } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ /* KeyExchangeKey = SessionBaseKey (v2) */
+ memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
+ } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_ESS) {
/*
* Doing NTLM ("v1x") which is NTLM with
* "Extended Session Security"
*/
err = ntlm_put_v1x_responses(ctx,
- &lm_mbc, &nt_mbc);
+ &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
if (err)
goto out;
- /* Compute the "Key exchange key". */
- ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_kxkey);
+ /*
+ * "v1x computes the KeyExchangeKey from both the
+ * server and client nonce and (v1) SessionBaseKey.
+ */
+ ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_ssnkey,
+ ssp_st->ss_kxkey);
} else {
/*
* Doing plain old NTLM (and LM if enabled)
*/
err = ntlm_put_v1_responses(ctx,
- &lm_mbc, &nt_mbc);
+ &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
if (err)
goto out;
- /* The "key exg. key" is the session base key */
- memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ);
+ /* KeyExchangeKey = SessionBaseKey (v1) */
+ memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
}
/*
- * Compute the "Exported Session Key" and (possibly)
- * the "Encrypted Random Sesion Key".
- * [MS-NLMP 3.1.5.1.2]
+ * Compute the "ExportedSessionKey" and (possibly) the
+ * "EncryptedRandomSesionKey". [MS-NLMP 3.1.5.1.2]
*/
if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
- err = ntlm_rand_ssn_key(ctx, ssp_st, &ek_mbc);
+ err = ntlm_rand_ssn_key(ssp_st, &ek_mbc);
if (err)
goto out;
} else {
/* ExportedSessionKey is the KeyExchangeKey */
- memcpy(ctx->ct_ssn_key, ssp_st->ss_kxkey, NTLM_HASH_SZ);
+ memcpy(ssp_st->ss_ssnkey, ssp_st->ss_kxkey, NTLM_HASH_SZ);
/* EncryptedRandomSessionKey remains NULL */
}
@@ -590,7 +595,6 @@ out:
*/
static int
ntlm_rand_ssn_key(
- struct smb_ctx *ctx,
ntlmssp_state_t *ssp_st,
struct mbdata *ek_mbp)
{
@@ -603,12 +607,12 @@ ntlm_rand_ssn_key(
encr_ssn_key = mb_reserve(ek_mbp, NTLM_HASH_SZ);
/* Set "ExportedSessionKey to NONCE(16) */
- (void) smb_get_urandom(ctx->ct_ssn_key, NTLM_HASH_SZ);
+ (void) smb_get_urandom(ssp_st->ss_ssnkey, NTLM_HASH_SZ);
/* Set "EncryptedRandomSessionKey" to RC4(...) */
err = smb_encrypt_RC4(encr_ssn_key, NTLM_HASH_SZ,
ssp_st->ss_kxkey, NTLM_HASH_SZ,
- ctx->ct_ssn_key, NTLM_HASH_SZ);
+ ssp_st->ss_ssnkey, NTLM_HASH_SZ);
return (err);
}
@@ -617,34 +621,29 @@ ntlm_rand_ssn_key(
* ntlmssp_final
*
* Called after successful authentication.
- * Setup the MAC key for signing.
+ * Save the session key.
*/
int
ntlmssp_final(struct ssp_ctx *sp)
{
struct smb_ctx *ctx = sp->smb_ctx;
+ ntlmssp_state_t *ssp_st = sp->sp_private;
int err = 0;
/*
- * MAC_key is just the session key, but
- * Only on the first successful auth.
+ * Update/save the session key.
*/
- if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
- (ctx->ct_mackey == NULL)) {
- ctx->ct_mackeylen = NTLM_HASH_SZ;
- ctx->ct_mackey = malloc(ctx->ct_mackeylen);
- if (ctx->ct_mackey == NULL) {
- ctx->ct_mackeylen = 0;
- err = ENOMEM;
- goto out;
- }
- memcpy(ctx->ct_mackey, ctx->ct_ssn_key, NTLM_HASH_SZ);
- /*
- * Apparently, the server used seq. no. zero
- * for our previous message, so next is two.
- */
- ctx->ct_mac_seqno = 2;
+ if (ctx->ct_ssnkey_buf != NULL) {
+ free(ctx->ct_ssnkey_buf);
+ ctx->ct_ssnkey_buf = NULL;
}
+ ctx->ct_ssnkey_buf = malloc(NTLM_HASH_SZ);
+ if (ctx->ct_ssnkey_buf == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+ ctx->ct_ssnkey_len = NTLM_HASH_SZ;
+ memcpy(ctx->ct_ssnkey_buf, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
out:
return (err);
@@ -728,13 +727,17 @@ int
ntlmssp_init_client(struct ssp_ctx *sp)
{
ntlmssp_state_t *ssp_st;
+ smb_ctx_t *ctx = sp->smb_ctx;
- if ((sp->smb_ctx->ct_authflags &
+ if ((ctx->ct_authflags &
(SMB_AT_NTLM2 | SMB_AT_NTLM1 | SMB_AT_ANON)) == 0) {
DPRINT("No NTLM authflags");
return (EINVAL);
}
+ /* Get the client nonce. */
+ (void) smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
+
ssp_st = calloc(1, sizeof (*ssp_st));
if (ssp_st == NULL)
return (ENOMEM);
diff --git a/usr/src/lib/libsmbfs/smb/print.c b/usr/src/lib/libsmbfs/smb/print.c
index c59bef81b4..698dd8359f 100644
--- a/usr/src/lib/libsmbfs/smb/print.c
+++ b/usr/src/lib/libsmbfs/smb/print.c
@@ -1,5 +1,4 @@
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2000, Boris Popov
* All rights reserved.
*
@@ -33,6 +32,10 @@
* $Id: print.c,v 1.1.1.3 2001/07/06 22:38:43 conrad Exp $
*/
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/time.h>
@@ -54,12 +57,24 @@
#include "private.h"
+/*
+ * Replacing invalid characters in print job titles:
+ *
+ * The spec. is unclear about what characters are allowed in a
+ * print job title (used with NtCreate) so out of caution this
+ * makes sure the title contains none of the characters that
+ * are known to be illegal in a file name component.
+ */
+static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS;
+
int
smb_open_printer(struct smb_ctx *ctx, const char *title,
int setuplen, int mode)
{
smbioc_printjob_t ioc;
- int err, tlen, new_fd;
+ char *p;
+ int err, tlen;
+ int new_fd = -1;
int32_t from_fd;
tlen = strlen(title);
@@ -75,7 +90,7 @@ smb_open_printer(struct smb_ctx *ctx, const char *title,
if (new_fd < 0)
return (errno);
from_fd = ctx->ct_dev_fd;
- if (ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) {
+ if (nsmb_ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) {
err = errno;
goto errout;
}
@@ -88,7 +103,15 @@ smb_open_printer(struct smb_ctx *ctx, const char *title,
ioc.ioc_prmode = mode;
strlcpy(ioc.ioc_title, title, SMBIOC_MAX_NAME);
- if (ioctl(new_fd, SMBIOC_PRINTJOB, &ioc) == -1) {
+ /*
+ * The title is used in NtCreate so sanitize by
+ * replacing any illegal chars with spaces.
+ */
+ for (p = ioc.ioc_title; *p != '\0'; p++)
+ if (strchr(invalid_chars, *p) != NULL)
+ *p = ' ';
+
+ if (nsmb_ioctl(new_fd, SMBIOC_PRINTJOB, &ioc) == -1) {
err = errno;
goto errout;
}
@@ -96,7 +119,7 @@ smb_open_printer(struct smb_ctx *ctx, const char *title,
return (new_fd);
errout:
- close(new_fd);
+ nsmb_close(new_fd);
errno = err;
return (-1);
}
diff --git a/usr/src/lib/libsmbfs/smb/private.h b/usr/src/lib/libsmbfs/smb/private.h
index febca40126..d877cafa1d 100644
--- a/usr/src/lib/libsmbfs/smb/private.h
+++ b/usr/src/lib/libsmbfs/smb/private.h
@@ -31,9 +31,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _PRIVATE_H
@@ -61,60 +62,6 @@ extern void dprint(const char *, const char *, ...)
#endif
/*
- * Flags bits in ct_vcflags (copied from smb_conn.h)
- * Pass these to the driver?
- */
-#define SMBV_RECONNECTING 0x0002 /* conn in process of reconnection */
-#define SMBV_LONGNAMES 0x0004 /* conn configured to use long names */
-#define SMBV_ENCRYPT 0x0008 /* server demands encrypted password */
-#define SMBV_WIN95 0x0010 /* used to apply bugfixes for this OS */
-#define SMBV_NT4 0x0020 /* used when NT4 issues invalid resp */
-#define SMBV_UNICODE 0x0040 /* conn configured to use Unicode */
-#define SMBV_EXT_SEC 0x0080 /* conn to use extended security */
-#define SMBV_WILL_SIGN 0x0100 /* negotiated signing */
-
-/*
- * request handling structures
- */
-struct smb_rq {
- struct smb_ctx *rq_ctx;
- struct mbdata rq_rq;
- struct mbdata rq_rp;
- int rq_rpbufsz;
- uint8_t rq_cmd;
- uint8_t rq_hflags;
- uint16_t rq_hflags2;
- uint32_t rq_status;
- uint16_t rq_uid;
- uint16_t rq_tid;
- uint16_t rq_mid;
- uint32_t rq_seqno;
- /* See rq_[bw]{start,end} functions */
- char *rq_wcntp;
- int rq_wcbase;
- char *rq_bcntp;
- int rq_bcbase;
-};
-typedef struct smb_rq smb_rq_t;
-
-#define smb_rq_getrequest(rqp) (&(rqp)->rq_rq)
-#define smb_rq_getreply(rqp) (&(rqp)->rq_rp)
-
-int smb_rq_init(struct smb_ctx *, uchar_t, struct smb_rq **);
-void smb_rq_done(struct smb_rq *);
-void smb_rq_bstart(struct smb_rq *);
-void smb_rq_bend(struct smb_rq *);
-void smb_rq_wstart(struct smb_rq *);
-void smb_rq_wend(struct smb_rq *);
-int smb_rq_simple(struct smb_rq *);
-int smb_rq_dmem(struct mbdata *, const char *, size_t);
-int smb_rq_internal(struct smb_ctx *, struct smb_rq *);
-void smb_rq_sign(struct smb_rq *);
-int smb_rq_verify(struct smb_rq *);
-int smb_t2_request(int, int, uint16_t *, const char *,
- int, void *, int, void *, int *, void *, int *, void *, int *);
-
-/*
* This library extends the mchain.h function set a little.
*/
int m_getm(struct mbuf *, int, struct mbuf **);
@@ -174,16 +121,7 @@ int smb_ctx_getaddr(struct smb_ctx *ctx);
int smb_ctx_gethandle(struct smb_ctx *ctx);
int smb_iod_start(struct smb_ctx *);
-
-int smb_ssn_send(struct smb_ctx *, struct mbdata *);
-int smb_ssn_recv(struct smb_ctx *, struct mbdata *);
-
-int smb_negprot(struct smb_ctx *, struct mbdata *);
-
-int smb_ssnsetup_null(struct smb_ctx *);
-int smb_ssnsetup_ntlm1(struct smb_ctx *);
-int smb_ssnsetup_ntlm2(struct smb_ctx *);
-int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);
+const char *smb_iod_state_name(enum smbiod_state st);
void smb_time_local2server(struct timeval *, int, long *);
void smb_time_server2local(ulong_t, int, struct timeval *);
diff --git a/usr/src/lib/libsmbfs/smb/rap.c b/usr/src/lib/libsmbfs/smb/rap.c
deleted file mode 100644
index 546ee46f05..0000000000
--- a/usr/src/lib/libsmbfs/smb/rap.c
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2000, Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id: rap.c,v 1.5 2004/12/13 00:25:23 lindak Exp $
- *
- * This is very simple implementation of RAP protocol.
- */
-
-#include <sys/param.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
-#include <sys/isa_defs.h>
-
-#include <ctype.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <libintl.h>
-#include <sysexits.h>
-
-#include <netsmb/mchain.h>
-#include <netsmb/smb_lib.h>
-#include <netsmb/smb_rap.h>
-#include "private.h"
-
-static int
-smb_rap_parserqparam(const char *s, char **next, int *rlen)
-{
- char *np;
- int len;
-
- switch (*s++) {
- case 'L':
- case 'T':
- case 'W':
- len = 2;
- break;
- case 'D':
- case 'O':
- len = 4;
- break;
- case 'b':
- case 'F':
- len = 1;
- break;
- case 'r':
- case 's':
- len = 0;
- break;
- default:
- return (EINVAL);
- }
- if (isdigit(*s)) {
- len *= strtoul(s, &np, 10);
- s = np;
- }
- *rlen = len;
- *(const char **)next = s;
- return (0);
-}
-
-static int
-smb_rap_parserpparam(const char *s, char **next, int *rlen)
-{
- char *np;
- int len = 0;
-
- switch (*s++) {
- case 'e':
- case 'h':
- len = 2;
- break;
- case 'i':
- len = 4;
- break;
- case 'g':
- len = 1;
- break;
- default:
- return (EINVAL);
- }
- if (isdigit(*s)) {
- len *= strtoul(s, &np, 10);
- s = np;
- }
- *rlen = len;
- *(const char **)next = s;
- return (0);
-}
-
-static int
-smb_rap_parserpdata(const char *s, char **next, int *rlen)
-{
- char *np;
- int len;
-
- switch (*s++) {
- case 'B':
- len = 1;
- break;
- case 'W':
- len = 2;
- break;
- case 'D':
- case 'O':
- case 'z':
- len = 4;
- break;
- default:
- return (EINVAL);
- }
- if (isdigit(*s)) {
- len *= strtoul(s, &np, 10);
- s = np;
- }
- *rlen = len;
- *(const char **)next = s;
- return (0);
-}
-
-static int
-smb_rap_rqparam_z(struct smb_rap *rap, const char *value)
-{
- int len = strlen(value) + 1;
-
- bcopy(value, rap->r_npbuf, len);
- rap->r_npbuf += len;
- rap->r_plen += len;
- return (0);
-}
-
-/*
- * Marshal RAP request parameters.
- * Note: value is in host order.
- */
-static int
-smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, int value)
-{
- int len = 0;
- uint_t uv = (uint_t)value;
- uint32_t *lp;
- uint16_t *sp;
- char *p;
-
- switch (ptype) {
- case 'L':
- case 'W':
- /* LINTED */
- sp = (uint16_t *)rap->r_npbuf;
- *sp = htoles(uv);
- len = sizeof (*sp);
- break;
- case 'D':
- /* LINTED */
- lp = (uint32_t *)rap->r_npbuf;
- *lp = htolel(uv);
- len = sizeof (*lp);
- break;
- case 'b':
- p = rap->r_npbuf;
- memset(p, uv, plen);
- len = plen;
- break;
- default:
- return (EINVAL);
- }
- rap->r_npbuf += len;
- rap->r_plen += len;
- return (0);
-}
-
-int
-smb_rap_create(int fn, const char *param, const char *data,
- struct smb_rap **rapp)
-{
- struct smb_rap *rap;
- char *p;
- int plen = 0, len = 0;
-
- rap = malloc(sizeof (*rap));
- if (rap == NULL)
- return (ENOMEM);
- bzero(rap, sizeof (*rap));
- p = rap->r_sparam = rap->r_nparam = strdup(param);
- rap->r_sdata = rap->r_ndata = strdup(data);
-
- /*
- * Calculate length of request parameter block
- */
- len = 2 + strlen(param) + 1 + strlen(data) + 1;
- while (*p) {
- if (smb_rap_parserqparam(p, &p, &plen) != 0)
- break;
- len += plen;
- }
- rap->r_pbuf = rap->r_npbuf = malloc(len);
- if (rap->r_pbuf == NULL)
- return (ENOMEM);
- (void) smb_rap_rqparam(rap, 'W', 1, fn);
- (void) smb_rap_rqparam_z(rap, rap->r_sparam);
- (void) smb_rap_rqparam_z(rap, rap->r_sdata);
- *rapp = rap;
- return (0);
-}
-
-void
-smb_rap_done(struct smb_rap *rap)
-{
- if (rap->r_sparam)
- free(rap->r_sparam);
- if (rap->r_sdata)
- free(rap->r_sdata);
- if (rap->r_pbuf)
- free(rap->r_pbuf);
-#ifdef NOTYETDEFINED
- if (rap->r_npbuf)
- free(rap->r_npbuf);
- if (rap->r_dbuf)
- free(rap->r_dbuf);
- if (rap->r_rcvbuf)
- free(rap->r_rcvbuf);
-#endif
- free(rap);
-}
-
-int
-smb_rap_setNparam(struct smb_rap *rap, int value)
-{
- char *p = rap->r_nparam;
- char ptype = *p;
- int error, plen;
-
- error = smb_rap_parserqparam(p, &p, &plen);
- if (error)
- return (error);
- switch (ptype) {
- case 'L':
- rap->r_rcvbuflen = value;
- /* FALLTHROUGH */
- case 'W':
- case 'D':
- case 'b':
- error = smb_rap_rqparam(rap, ptype, plen, value);
- break;
- default:
- return (EINVAL);
- }
- rap->r_nparam = p;
- return (0);
-}
-
-int
-smb_rap_setPparam(struct smb_rap *rap, void *value)
-{
- char *p = rap->r_nparam;
- char ptype = *p;
- int error, plen;
-
- error = smb_rap_parserqparam(p, &p, &plen);
- if (error)
- return (error);
- switch (ptype) {
- case 'r':
- rap->r_rcvbuf = value;
- break;
- default:
- return (EINVAL);
- }
- rap->r_nparam = p;
- return (0);
-}
-
-int
-smb_rap_getNparam(struct smb_rap *rap, long *value)
-{
- char *p = rap->r_nparam;
- char ptype = *p;
- int error, plen;
- uint16_t *te;
-
- error = smb_rap_parserpparam(p, &p, &plen);
- if (error)
- return (error);
- switch (ptype) {
- case 'h':
- /* LINTED */
- te = (uint16_t *)rap->r_npbuf;
- *value = letohs(*te);
- break;
- default:
- return (EINVAL);
- }
- rap->r_npbuf += plen;
- rap->r_nparam = p;
- return (0);
-}
-
-int
-smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
-{
- uint16_t *rp, conv, *tmp;
- uint32_t *p32;
- char *dp, *p = rap->r_nparam;
- char ptype;
- int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow;
-
- rdatacnt = rap->r_rcvbuflen;
- rparamcnt = rap->r_plen;
- error = smb_t2_request(ctx->ct_dev_fd,
- 0, NULL, "\\PIPE\\LANMAN",
- rap->r_plen, rap->r_pbuf, /* int tparamcnt,void *tparam */
- 0, NULL, /* int tdatacnt, void *tdata */
- &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */
- &rdatacnt, rap->r_rcvbuf, /* int *rdatacnt, void *rdata */
- &buffer_oflow);
- if (error)
- return (error);
-
- /* LINTED */
- rp = (uint16_t *)rap->r_pbuf;
-
- /*
- * Note: First is a "LanMan API" error code.
- * See: usr/src/uts/common/smbsrv/lmerr.h
- */
- if (rparamcnt < 2)
- return (EBADRPC);
- rap->r_result = letohs(*rp);
- rp++; rparamcnt -= 2;
-
- if (rap->r_result != 0) {
- /*
- * Could also return zero and let the caller
- * come get r_result via smb_rap_error(),
- * but in case they dont...
- */
- return (rap->r_result | SMB_RAP_ERROR);
- }
-
- if (rparamcnt < 2)
- return (EBADRPC);
- conv = letohs(*rp);
- rp++; rparamcnt -= 2;
-
- rap->r_npbuf = (char *)rp;
- rap->r_entries = entries = 0;
- /* Save the returned data length */
- rap->r_rcvbuflen = rdatacnt;
- done = 0;
-
- while (!done && *p) {
- ptype = *p;
- switch (ptype) {
- case 'e':
- if (rparamcnt < 2)
- return (EBADRPC);
- /* LINTED */
- tmp = (uint16_t *)rap->r_npbuf;
- rap->r_entries = entries = letohs(*tmp);
- rap->r_npbuf += 2;
- rparamcnt -= 2;
- p++;
- break;
- default:
- done = 1;
- }
-#if 0 /* commented out in Darwin. Why? */
- error = smb_rap_parserpparam(p, &p, &plen);
- if (error) {
- smb_error(dgettext(TEXT_DOMAIN,
- "reply parameter mismatch %s"), 0, p);
- return (EBADRPC);
- }
-#endif
- }
- rap->r_nparam = p;
- /*
- * In general, unpacking entries we may need to relocate
- * entries for proper aligning. For now use them as is.
- */
- dp = rap->r_rcvbuf;
- while (entries--) {
- p = rap->r_sdata;
- while (*p) {
- ptype = *p;
- error = smb_rap_parserpdata(p, &p, &dlen);
- if (error) {
- smb_error(dgettext(TEXT_DOMAIN,
- "reply data mismatch %s"), 0, p);
- return (EBADRPC);
- }
- if (rdatacnt < dlen)
- return (EBADRPC);
- switch (ptype) {
- case 'z':
- /* LINTED */
- p32 = (uint32_t *)dp;
- *p32 = (letohl(*p32) & 0xffff) - conv;
- break;
- }
- dp += dlen;
- rdatacnt -= dlen;
- }
- }
- return (error);
-}
-
-int
-smb_rap_error(struct smb_rap *rap, int error)
-{
- if (error)
- return (error);
- if (rap->r_result == 0)
- return (0);
- return (rap->r_result | SMB_RAP_ERROR);
-}
diff --git a/usr/src/lib/libsmbfs/smb/rc_scf.c b/usr/src/lib/libsmbfs/smb/rc_scf.c
new file mode 100644
index 0000000000..477982c0c8
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/rc_scf.c
@@ -0,0 +1,231 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Support functions for getting things libsmbfs needs
+ * from the SMF configuration (using libscf).
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libscf.h>
+
+#include <cflib.h>
+#include "rcfile_priv.h"
+
+#define IDMAP_SERVICE_FMRI "svc:/system/idmap"
+#define IDMAP_PG_NAME "config"
+#define MACHINE_UUID "machine_uuid"
+
+#define SMBC_DEFAULT_INSTANCE_FMRI "svc:/network/smb/client:default"
+
+scf_handle_t *_scf_handle_create_and_bind(scf_version_t ver);
+
+/*
+ * Get the "machine_uuid" from idmap, as a string (allocated)
+ */
+char *
+cf_get_client_uuid(void)
+{
+ char val_buf[64];
+ char *ret = NULL;
+
+ scf_handle_t *h = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *val = NULL;
+
+ if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)
+ goto out;
+
+ if ((svc = scf_service_create(h)) == NULL ||
+ (pg = scf_pg_create(h)) == NULL ||
+ (prop = scf_property_create(h)) == NULL ||
+ (val = scf_value_create(h)) == NULL)
+ goto out;
+
+ if (scf_handle_decode_fmri(h, IDMAP_SERVICE_FMRI,
+ NULL, svc, NULL, NULL, NULL, 0) == -1)
+ goto out;
+
+
+ if (scf_service_get_pg(svc, IDMAP_PG_NAME, pg) != 0)
+ goto out;
+ if (scf_pg_get_property(pg, MACHINE_UUID, prop) != 0)
+ goto out;
+ if (scf_property_get_value(prop, val) != 0)
+ goto out;
+ if (scf_value_get_as_string(val, val_buf, sizeof (val_buf)) < 0)
+ goto out;
+
+ ret = strdup(val_buf);
+
+out:
+ scf_value_destroy(val);
+ scf_property_destroy(prop);
+ scf_pg_destroy(pg);
+ scf_service_destroy(svc);
+
+ if (h != NULL)
+ scf_handle_destroy(h);
+
+ return (ret);
+}
+
+/*
+ * Get the output of "sharectl get smbfs" into a file, without an
+ * actual fork/exec of sharectl.
+ *
+ * Each section of the smbfs settings are represented as an SMF
+ * property group with an "S-" prefix and a UUID, and the section
+ * name itself a property which can have a more flexible name than
+ * a property group name can have.
+ */
+int
+rc_scf_get_sharectl(FILE *fp)
+{
+ char sect_name[256];
+ char prop_name[256];
+ char val_buf[1024];
+
+ scf_handle_t *h = NULL;
+ scf_service_t *svc = NULL;
+ scf_instance_t *inst = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *val = NULL;
+ scf_iter_t *pgiter = NULL;
+ scf_iter_t *propiter = NULL;
+ scf_iter_t *valiter = NULL;
+ int ret = -1;
+
+ if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)
+ goto out;
+
+ if ((svc = scf_service_create(h)) == NULL ||
+ (inst = scf_instance_create(h)) == NULL ||
+ (pgiter = scf_iter_create(h)) == NULL ||
+ (propiter = scf_iter_create(h)) == NULL ||
+ (valiter = scf_iter_create(h)) == NULL ||
+ (pg = scf_pg_create(h)) == NULL ||
+ (prop = scf_property_create(h)) == NULL ||
+ (val = scf_value_create(h)) == NULL)
+ goto out;
+
+ if (scf_handle_decode_fmri(h, SMBC_DEFAULT_INSTANCE_FMRI,
+ NULL, svc, inst, NULL, NULL, 0) == -1)
+ goto out;
+
+ if (scf_iter_instance_pgs_composed(pgiter, inst, NULL) == -1)
+ goto out;
+ while ((ret = scf_iter_next_pg(pgiter, pg)) == 1) {
+ /*
+ * Using prop_name array for pg name temporarily.
+ * Skip any property groups names other than "S-*".
+ */
+ if (scf_pg_get_name(pg, prop_name, sizeof (prop_name)) < 0)
+ continue;
+ if (strncmp(prop_name, "S-", 2) != 0)
+ continue;
+
+ /*
+ * Get the "section" name, which is a property of
+ * this property group.
+ */
+ if (scf_pg_get_property(pg, "section", prop) != 0)
+ continue;
+ if (scf_property_get_value(prop, val) != 0)
+ continue;
+ if (scf_value_get_as_string(val, sect_name,
+ sizeof (sect_name)) < 0)
+ continue;
+
+ /*
+ * Have an S-* property group with a "section" name.
+ * Print the section start.
+ */
+ fprintf(fp, "[%s]\n", sect_name);
+
+ /*
+ * Now print the remaining properties in this PG,
+ * but skip the special "section" (name) prop.
+ */
+ if (scf_iter_pg_properties(propiter, pg) == -1)
+ goto out;
+ while ((ret = scf_iter_next_property(propiter, prop)) == 1) {
+
+ if (scf_property_get_name(prop, prop_name,
+ sizeof (prop_name)) < 0)
+ continue;
+
+ /* Skip the "section" prop. now */
+ if (strcmp(prop_name, "section") == 0)
+ continue;
+
+ if (scf_property_get_value(prop, val) != 0)
+ continue;
+
+ if (scf_value_get_as_string(val, val_buf,
+ sizeof (val_buf)) < 0)
+ continue;
+
+ fprintf(fp, "%s=%s\n", prop_name, val_buf);
+ }
+ }
+ ret = 0;
+
+out:
+ fflush(fp);
+
+ scf_value_destroy(val);
+ scf_property_destroy(prop);
+ scf_pg_destroy(pg);
+ scf_iter_destroy(valiter);
+ scf_iter_destroy(propiter);
+ scf_iter_destroy(pgiter);
+ scf_instance_destroy(inst);
+ scf_service_destroy(svc);
+
+ if (h != NULL)
+ scf_handle_destroy(h);
+
+ return (ret);
+}
+
+/*
+ * Simple test wrapper. Compile with:
+ * cc -o rc_scf_test -I.. -DTEST_MAIN rc_scf.c -lscf
+ */
+#ifdef TEST_MAIN
+int
+main(int argc, char **arv)
+{
+ char *s;
+ int rc;
+
+ rc = rc_scf_get_sharectl(stdout);
+ printf("# rc=%d\n", rc);
+ return (0);
+}
+#endif /* TEST_MAIN */
diff --git a/usr/src/lib/libsmbfs/smb/rcfile.c b/usr/src/lib/libsmbfs/smb/rcfile.c
index 22ca0fc420..d7ee2d15af 100644
--- a/usr/src/lib/libsmbfs/smb/rcfile.c
+++ b/usr/src/lib/libsmbfs/smb/rcfile.c
@@ -31,6 +31,9 @@
*
* $Id: rcfile.c,v 1.1.1.2 2001/07/06 22:38:43 conrad Exp $
*/
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
#include <fcntl.h>
#include <sys/types.h>
@@ -57,7 +60,6 @@
#define SMB_CFG_FILE "/etc/nsmb.conf"
#define OLD_SMB_CFG_FILE "/usr/local/etc/nsmb.conf"
#endif
-#define SMBFS_SHARECTL_CMD "/usr/sbin/sharectl get smbfs"
extern int smb_debug;
@@ -147,37 +149,77 @@ rc_merge(const char *filename, struct rcfile **rcfile)
}
/*
- * Like rc_open, but does popen of command:
- * sharectl get smbfs
+ * Like rc_open, but creates a temporary file and
+ * reads the sharectl settings into it.
+ * The file is deleted when we close it.
*/
static int
-rc_popen_cmd(const char *command, struct rcfile **rcfile)
+rc_open_sharectl(struct rcfile **rcfile)
{
- struct rcfile *rcp;
- FILE *f;
+ static char template[24] = "/tmp/smbfsXXXXXX";
+ struct rcfile *rcp = NULL;
+ FILE *fp = NULL;
+ int err;
+ int fd = -1;
assert(MUTEX_HELD(&rcfile_mutex));
- f = popen(command, "r");
- if (f == NULL)
- return (errno);
- insecure_nsmbrc = 0;
+ fd = mkstemp(template);
+ if (fd < 0) {
+ err = errno;
+ goto errout;
+ }
+
+ fp = fdopen(fd, "w+");
+ if (fp == NULL) {
+ err = errno;
+ close(fd);
+ goto errout;
+ }
+ fd = -1; /* The fp owns this fd now. */
+
+ /*
+ * Get smbfs sharectl settings into the file.
+ */
+ if ((err = rc_scf_get_sharectl(fp)) != 0)
+ goto errout;
rcp = malloc(sizeof (struct rcfile));
if (rcp == NULL) {
- fclose(f);
- return (ENOMEM);
+ err = ENOMEM;
+ goto errout;
}
bzero(rcp, sizeof (struct rcfile));
- rcp->rf_name = strdup(command);
- rcp->rf_f = f;
+
+ rcp->rf_name = strdup(template);
+ if (rcp->rf_name == NULL) {
+ err = ENOMEM;
+ goto errout;
+ }
+ rcp->rf_f = fp;
+ rcp->rf_flags = RCFILE_DELETE_ON_CLOSE;
+
SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
+ insecure_nsmbrc = 0;
rc_parse(rcp);
*rcfile = rcp;
/* fclose(f) in rc_close */
return (0);
+
+errout:
+ if (rcp != NULL)
+ free(rcp);
+ if (fp != NULL) {
+ fclose(fp);
+ fd = -1;
+ }
+ if (fd != -1)
+ close(fd);
+
+ return (err);
}
+
static int
rc_close(struct rcfile *rcp)
{
@@ -186,6 +228,9 @@ rc_close(struct rcfile *rcp)
mutex_lock(&rcfile_mutex);
fclose(rcp->rf_f);
+ if (rcp->rf_flags & RCFILE_DELETE_ON_CLOSE)
+ (void) unlink(rcp->rf_name);
+
for (p = SLIST_FIRST(&rcp->rf_sect); p; ) {
n = p;
p = SLIST_NEXT(p, rs_next);
@@ -343,11 +388,10 @@ set_value(struct rcfile *rcp, struct rcsection *rsp, struct rckey *rkp,
{
int now, new;
#ifdef DEBUG
- char *from;
+ char *from = "SMF";
- if (smb_debug)
- from = (home_nsmbrc) ?
- "user file" : "SMF";
+ if (home_nsmbrc != 0)
+ from = "user file";
#endif
if (strcmp(rkp->rk_name, "minauth") == 0) {
@@ -485,7 +529,7 @@ rc_parse(struct rcfile *rcp)
set_value(rcp, rsp, rkp, buf);
state = stNewLine;
rkp = NULL;
- } /* while */
+ } /* while */
if (c == EOF && state == stGetValue) {
*next = 0;
set_value(rcp, rsp, rkp, buf);
@@ -661,8 +705,8 @@ smb_open_rcfile(char *home)
fn = SMB_CFG_FILE;
error = rc_open(fn, &smb_rc);
#else
- fn = SMBFS_SHARECTL_CMD;
- error = rc_popen_cmd(fn, &smb_rc);
+ fn = "(sharectl get smbfs)";
+ error = rc_open_sharectl(&smb_rc);
#endif
if (error != 0 && error != ENOENT) {
/* Error from fopen. strerror is OK. */
diff --git a/usr/src/lib/libsmbfs/smb/rcfile_priv.h b/usr/src/lib/libsmbfs/smb/rcfile_priv.h
index ef9e31d7fc..b239c77a67 100644
--- a/usr/src/lib/libsmbfs/smb/rcfile_priv.h
+++ b/usr/src/lib/libsmbfs/smb/rcfile_priv.h
@@ -30,9 +30,26 @@
* SUCH DAMAGE.
*/
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _RCFILE_PRIV_H
+#define _RCFILE_PRIV_H
+
+/*
+ * Private RC file support.
+ */
+
+#include <sys/queue.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct rckey {
SLIST_ENTRY(rckey) rk_next;
- char *rk_name;
+ char *rk_name;
char *rk_value;
};
@@ -52,3 +69,12 @@ struct rcfile {
#define RCFILE_HOME_NSMBRC 1
#define RCFILE_IS_INSECURE 2
+#define RCFILE_DELETE_ON_CLOSE 4
+
+int rc_scf_get_sharectl(FILE *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RCFILE_PRIV_H */
diff --git a/usr/src/lib/libsmbfs/smb/rq.c b/usr/src/lib/libsmbfs/smb/rq.c
deleted file mode 100644
index c4e929eff9..0000000000
--- a/usr/src/lib/libsmbfs/smb/rq.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2000, Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id: rq.c,v 1.4 2004/12/13 00:25:23 lindak Exp $
- */
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <sysexits.h>
-#include <libintl.h>
-
-#include <netsmb/smb.h>
-#include <netsmb/smb_lib.h>
-#include "private.h"
-
-#define MIN_REPLY_SIZE 4096
-
-static uint32_t smb_map_doserr(uint8_t, uint16_t);
-
-/*
- * Create and initialize a request structure, for either an
- * "internal" request (one that does not use the driver) or
- * a regular "driver" request, that uses driver ioctls.
- *
- * The two kinds are built a little differently:
- * Driver requests are composed starting with the
- * first word of the "variable word vector" section.
- * The driver prepends the SMB header and word count.
- * The driver also needs an output buffer to receive
- * the response, filled in via copyout in the ioctl.
- *
- * Internal requests are composed entirely in this library.
- * Space for the SMB header is reserved here, and later
- * filled in by smb_rq_internal before the send/receive.
- */
-int
-smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, struct smb_rq **rqpp)
-{
- struct smb_rq *rqp;
-
- rqp = malloc(sizeof (*rqp));
- if (rqp == NULL)
- goto errout;
- bzero(rqp, sizeof (*rqp));
- rqp->rq_cmd = cmd;
- rqp->rq_ctx = ctx;
-
- /*
- * Setup the request buffer.
- * Do the reply buffer later.
- */
- if (mb_init(&rqp->rq_rq))
- goto errout;
-
- /* Space for the SMB header. (filled in later) */
- mb_put_mem(&rqp->rq_rq, NULL, SMB_HDRLEN, MB_MSYSTEM);
-
- /*
- * Copy the ctx flags here, so the caller can
- * update the req flags before the OTW call.
- */
- rqp->rq_hflags = ctx->ct_hflags;
- rqp->rq_hflags2 = ctx->ct_hflags2;
-
- *rqpp = rqp;
- return (0);
-
-errout:
- if (rqp) {
- smb_rq_done(rqp);
- free(rqp);
- }
- return (ENOMEM);
-}
-
-void
-smb_rq_done(struct smb_rq *rqp)
-{
- mb_done(&rqp->rq_rp);
- mb_done(&rqp->rq_rq);
- free(rqp);
-}
-
-/*
- * Reserve space for the word count, which is filled in later by
- * smb_rq_wend(). Also initialize the counter that it uses
- * to figure out what value to fill in.
- *
- * Note that the word count happens to be 8-bits,
- * which can lead to confusion.
- */
-void
-smb_rq_wstart(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
-
- (void) mb_fit(mbp, 1, &rqp->rq_wcntp);
- rqp->rq_wcbase = mbp->mb_count;
-}
-
-/*
- * Fill in the word count, in the space reserved by
- * smb_rq_wstart().
- */
-void
-smb_rq_wend(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
- int wcnt;
-
- if (rqp->rq_wcntp == NULL) {
- DPRINT("no wcount ptr\n");
- return;
- }
- wcnt = mbp->mb_count - rqp->rq_wcbase;
- if (wcnt > 0x1ff)
- DPRINT("word count too large (%d)\n", wcnt);
- if (wcnt & 1)
- DPRINT("odd word count\n");
- wcnt >>= 1;
-
- /*
- * Fill in the word count (8-bits).
- * Also store it in the rq, in case
- * we're using the ioctl path.
- */
- *rqp->rq_wcntp = (char)wcnt;
-}
-
-/*
- * Reserve space for the byte count, which is filled in later by
- * smb_rq_bend(). Also initialize the counter that it uses
- * to figure out what value to fill in.
- *
- * Note that the byte count happens to be 16-bits,
- * which can lead to confusion.
- */
-void
-smb_rq_bstart(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
-
- (void) mb_fit(mbp, 2, &rqp->rq_bcntp);
- rqp->rq_bcbase = mbp->mb_count;
-}
-
-/*
- * Fill in the byte count, in the space reserved by
- * smb_rq_bstart().
- */
-void
-smb_rq_bend(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
- int bcnt;
-
- if (rqp->rq_bcntp == NULL) {
- DPRINT("no bcount ptr\n");
- return;
- }
- bcnt = mbp->mb_count - rqp->rq_bcbase;
- if (bcnt > 0xffff)
- DPRINT("byte count too large (%d)\n", bcnt);
- /*
- * Fill in the byte count (16-bits).
- * Also store it in the rq, in case
- * we're using the ioctl path.
- *
- * The pointer is char * type due to
- * typical off-by-one alignment.
- */
- rqp->rq_bcntp[0] = bcnt & 0xFF;
- rqp->rq_bcntp[1] = (bcnt >> 8);
-}
-
-int
-smb_rq_simple(struct smb_rq *rqp)
-{
- struct smbioc_rq krq;
- struct mbdata *mbp;
- mbuf_t *m;
- char *data;
- uint32_t len;
- size_t rpbufsz;
- int error;
-
- bzero(&krq, sizeof (krq));
- krq.ioc_cmd = rqp->rq_cmd;
-
- /*
- * Make the SMB request body contiguous,
- * and fill in the ioctl request.
- */
- mbp = smb_rq_getrequest(rqp);
- error = m_lineup(mbp->mb_top, &mbp->mb_top);
- if (error)
- return (error);
-
- data = mtod(mbp->mb_top, char *);
- len = m_totlen(mbp->mb_top);
-
- /*
- * _rq_init left space for the SMB header,
- * which makes mb_count the offset from
- * the beginning of the header (useful).
- * However, in this code path the driver
- * prepends the header, so we skip it.
- */
- krq.ioc_tbufsz = len - SMB_HDRLEN;
- krq.ioc_tbuf = data + SMB_HDRLEN;
-
- /*
- * Setup a buffer to hold the reply,
- * at least MIN_REPLY_SIZE, or larger
- * if the caller increased rq_rpbufsz.
- */
- mbp = smb_rq_getreply(rqp);
- rpbufsz = rqp->rq_rpbufsz;
- if (rpbufsz < MIN_REPLY_SIZE)
- rpbufsz = MIN_REPLY_SIZE;
- if ((error = m_get(rpbufsz, &m)) != 0)
- return (error);
- mb_initm(mbp, m);
- krq.ioc_rbufsz = rpbufsz;
- krq.ioc_rbuf = mtod(m, char *);
-
- /*
- * Call the driver
- */
- if (ioctl(rqp->rq_ctx->ct_dev_fd, SMBIOC_REQUEST, &krq) == -1)
- return (errno);
-
- /*
- * Initialize returned mbdata.
- * SMB header already parsed.
- */
- m->m_len = krq.ioc_rbufsz;
-
- return (0);
-}
-
-
-int
-smb_t2_request(int dev_fd, int setupcount, uint16_t *setup,
- const char *name,
- int tparamcnt, void *tparam,
- int tdatacnt, void *tdata,
- int *rparamcnt, void *rparam,
- int *rdatacnt, void *rdata,
- int *buffer_oflow)
-{
- smbioc_t2rq_t *krq;
- int i;
-
- krq = (smbioc_t2rq_t *)malloc(sizeof (smbioc_t2rq_t));
- bzero(krq, sizeof (*krq));
-
- if (setupcount < 0 || setupcount >= SMBIOC_T2RQ_MAXSETUP) {
- /* Bogus setup count, or too many setup words */
- return (EINVAL);
- }
- for (i = 0; i < setupcount; i++)
- krq->ioc_setup[i] = setup[i];
- krq->ioc_setupcnt = setupcount;
- strcpy(krq->ioc_name, name);
- krq->ioc_tparamcnt = tparamcnt;
- krq->ioc_tparam = tparam;
- krq->ioc_tdatacnt = tdatacnt;
- krq->ioc_tdata = tdata;
-
- krq->ioc_rparamcnt = *rparamcnt;
- krq->ioc_rdatacnt = *rdatacnt;
- krq->ioc_rparam = rparam;
- krq->ioc_rdata = rdata;
-
- if (ioctl(dev_fd, SMBIOC_T2RQ, krq) == -1) {
- return (errno);
- }
-
- *rparamcnt = krq->ioc_rparamcnt;
- *rdatacnt = krq->ioc_rdatacnt;
- *buffer_oflow = (krq->ioc_rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
- (krq->ioc_error == NT_STATUS_BUFFER_OVERFLOW);
- free(krq);
-
- return (0);
-}
-
-
-/*
- * Do an over-the-wire call without using the nsmb driver.
- * This is all "internal" to this library, and used only
- * for connection setup (negotiate protocol, etc.)
- */
-int
-smb_rq_internal(struct smb_ctx *ctx, struct smb_rq *rqp)
-{
- static const uint8_t ffsmb[4] = SMB_SIGNATURE;
- struct smb_iods *is = &ctx->ct_iods;
- uint32_t sigbuf[2];
- struct mbdata mbtmp, *mbp;
- int err, save_mlen;
- uint8_t ctmp;
-
- rqp->rq_uid = is->is_smbuid;
- rqp->rq_tid = SMB_TID_UNKNOWN;
- rqp->rq_mid = is->is_next_mid++;
-
- /*
- * Fill in the NBT and SMB headers
- * Using mbtmp so we can rewind without
- * affecting the passed request mbdata.
- */
- bcopy(&rqp->rq_rq, &mbtmp, sizeof (mbtmp));
- mbp = &mbtmp;
- mbp->mb_cur = mbp->mb_top;
- mbp->mb_pos = mbp->mb_cur->m_data;
- mbp->mb_count = 0;
- /* Have to save and restore m_len */
- save_mlen = mbp->mb_cur->m_len;
- mbp->mb_cur->m_len = 0;
-
- /*
- * rewind done; fill it in
- */
- mb_put_mem(mbp, ffsmb, SMB_SIGLEN, MB_MSYSTEM);
- mb_put_uint8(mbp, rqp->rq_cmd);
- mb_put_uint32le(mbp, 0); /* status */
- mb_put_uint8(mbp, rqp->rq_hflags);
- mb_put_uint16le(mbp, rqp->rq_hflags2);
- /* pid_hi(2), signature(8), reserved(2) */
- mb_put_mem(mbp, NULL, 12, MB_MZERO);
- mb_put_uint16le(mbp, rqp->rq_tid);
- mb_put_uint16le(mbp, 0); /* pid_lo */
- mb_put_uint16le(mbp, rqp->rq_uid);
- mb_put_uint16le(mbp, rqp->rq_mid);
-
- /* Restore original m_len */
- mbp->mb_cur->m_len = save_mlen;
-
- /*
- * Sign the message, if flags2 indicates.
- */
- if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- smb_rq_sign(rqp);
- }
-
- /*
- * Send it, wait for the reply.
- */
- if ((err = smb_ssn_send(ctx, &rqp->rq_rq)) != 0)
- return (err);
-
- if ((err = smb_ssn_recv(ctx, &rqp->rq_rp)) != 0)
- return (err);
-
- /*
- * Should have an SMB header, at least.
- */
- mbp = &rqp->rq_rp;
- if (mbp->mb_cur->m_len < SMB_HDRLEN) {
- DPRINT("len < 32");
- return (EBADRPC);
- }
-
- /*
- * If the request was signed, validate the
- * signature on the response.
- */
- if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- err = smb_rq_verify(rqp);
- if (err) {
- DPRINT("bad signature");
- return (err);
- }
- }
-
- /*
- * Decode the SMB header.
- */
- md_get_mem(mbp, (char *)sigbuf, 4, MB_MSYSTEM);
- if (0 != bcmp(sigbuf, ffsmb, 4)) {
- DPRINT("not SMB");
- return (EBADRPC);
- }
- md_get_uint8(mbp, &ctmp); /* SMB cmd */
- md_get_uint32le(mbp, &rqp->rq_status);
- md_get_uint8(mbp, &rqp->rq_hflags);
- md_get_uint16le(mbp, &rqp->rq_hflags2);
- /* pid_hi(2), signature(8), reserved(2) */
- md_get_mem(mbp, NULL, 12, MB_MSYSTEM);
- md_get_uint16le(mbp, &rqp->rq_tid);
- md_get_uint16le(mbp, NULL); /* pid_lo */
- md_get_uint16le(mbp, &rqp->rq_uid);
- md_get_uint16le(mbp, &rqp->rq_mid);
-
- /*
- * Figure out the status return.
- * Caller looks at rq_status.
- */
- if ((rqp->rq_hflags2 & SMB_FLAGS2_ERR_STATUS) == 0) {
- uint16_t serr;
- uint8_t class;
-
- class = rqp->rq_status & 0xff;
- serr = rqp->rq_status >> 16;
- rqp->rq_status = smb_map_doserr(class, serr);
- }
-
- return (0);
-}
-
-/*
- * Map old DOS errors (etc.) to NT status codes.
- * We probably don't need this anymore, since
- * the oldest server we talk to is NT. But if
- * later find we do need this, add support here
- * for the DOS errors we care about.
- */
-static uint32_t
-smb_map_doserr(uint8_t class, uint16_t serr)
-{
- if (class == 0 && serr == 0)
- return (0);
-
- DPRINT("class 0x%x serr 0x%x", (int)class, (int)serr);
- return (NT_STATUS_UNSUCCESSFUL);
-}
diff --git a/usr/src/lib/libsmbfs/smb/signing.c b/usr/src/lib/libsmbfs/smb/signing.c
deleted file mode 100644
index 0e9c826bbd..0000000000
--- a/usr/src/lib/libsmbfs/smb/signing.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Signing support, using libmd
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <strings.h>
-
-#include <sys/types.h>
-#include <sys/md5.h>
-
-#include <netsmb/mchain.h>
-#include <netsmb/smb.h>
-#include <netsmb/smb_lib.h>
-
-#include "private.h"
-
-#define SMBSIGOFF 14 /* SMB signature offset */
-#define SMBSIGLEN 8 /* SMB signature length */
-
-/*
- * Set this to a small number to debug sequence numbers
- * that seem to get out of step.
- */
-#ifdef DEBUG
-int nsmb_signing_fudge = 4;
-#endif
-
-/*
- * Compute MD5 digest of packet data, using the stored MAC key.
- *
- * See similar code in the driver:
- * uts/common/fs/smbclnt/netsmb/smb_signing.c
- * and on the server side:
- * uts/common/fs/smbsrv/smb_signing.c
- */
-static int
-smb_compute_MAC(struct smb_ctx *ctx, mbuf_t *m,
- uint32_t seqno, uchar_t *signature)
-{
- MD5_CTX md5;
- uchar_t digest[MD5_DIGEST_LENGTH];
-
- /*
- * This union is a little bit of trickery to:
- * (1) get the sequence number int aligned, and
- * (2) reduce the number of digest calls, at the
- * cost of a copying 32 bytes instead of 8.
- * Both sides of this union are 2+32 bytes.
- */
- union {
- struct {
- uint8_t skip[2]; /* not used - just alignment */
- uint8_t raw[SMB_HDRLEN]; /* header length (32) */
- } r;
- struct {
- uint8_t skip[2]; /* not used - just alignment */
- uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
- uint32_t sig[2]; /* MAC signature, aligned! */
- uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
- } s;
- } smbhdr;
-
- if (m->m_len < SMB_HDRLEN)
- return (EIO);
- if (ctx->ct_mackey == NULL)
- return (EINVAL);
-
- /*
- * Make an aligned copy of the SMB header
- * and fill in the sequence number.
- */
- bcopy(m->m_data, smbhdr.r.raw, SMB_HDRLEN);
- smbhdr.s.sig[0] = htolel(seqno);
- smbhdr.s.sig[1] = 0;
-
- /*
- * Compute the MAC: MD5(concat(Key, message))
- */
- MD5Init(&md5);
-
- /* Digest the MAC Key */
- MD5Update(&md5, ctx->ct_mackey, ctx->ct_mackeylen);
-
- /* Digest the (copied) SMB header */
- MD5Update(&md5, smbhdr.r.raw, SMB_HDRLEN);
-
- /* Digest the rest of the first mbuf */
- if (m->m_len > SMB_HDRLEN) {
- MD5Update(&md5, m->m_data + SMB_HDRLEN,
- m->m_len - SMB_HDRLEN);
- }
- m = m->m_next;
-
- /* Digest rest of the SMB message. */
- while (m) {
- MD5Update(&md5, m->m_data, m->m_len);
- m = m->m_next;
- }
-
- /* Final */
- MD5Final(digest, &md5);
-
- /*
- * Finally, store the signature.
- * (first 8 bytes of the digest)
- */
- if (signature)
- bcopy(digest, signature, SMBSIGLEN);
-
- return (0);
-}
-
-/*
- * Sign a request with HMAC-MD5.
- */
-void
-smb_rq_sign(struct smb_rq *rqp)
-{
- struct smb_ctx *ctx = rqp->rq_ctx;
- mbuf_t *m = rqp->rq_rq.mb_top;
- uint8_t *sigloc;
- int err;
-
- /*
- * Our mblk allocation ensures this,
- * but just in case...
- */
- if (m->m_len < SMB_HDRLEN)
- return;
- sigloc = (uchar_t *)m->m_data + SMBSIGOFF;
-
- if (ctx->ct_mackey == NULL) {
- /*
- * Signing is required, but we have no key yet
- * fill in with the magic fake signing value.
- * This happens with SPNEGO, NTLMSSP, ...
- */
- bcopy("BSRSPLY", sigloc, 8);
- return;
- }
-
- /*
- * This will compute the MAC and store it
- * directly into the message at sigloc.
- */
- rqp->rq_seqno = ctx->ct_mac_seqno;
- ctx->ct_mac_seqno += 2;
- err = smb_compute_MAC(ctx, m, rqp->rq_seqno, sigloc);
- if (err) {
- DPRINT("compute MAC, err %d", err);
- bzero(sigloc, SMBSIGLEN);
- }
-}
-
-/*
- * Verify reply signature.
- */
-int
-smb_rq_verify(struct smb_rq *rqp)
-{
- struct smb_ctx *ctx = rqp->rq_ctx;
- mbuf_t *m = rqp->rq_rp.mb_top;
- uint8_t sigbuf[SMBSIGLEN];
- uint8_t *sigloc;
- uint32_t rseqno;
- int err, fudge;
-
- /*
- * Note ct_mackey and ct_mackeylen gets initialized by
- * smb_smb_ssnsetup. It's normal to have a null MAC key
- * during extended security session setup.
- */
- if (ctx->ct_mackey == NULL)
- return (0);
-
- /*
- * Let caller deal with empty reply or short messages by
- * returning zero. Caller will fail later, in parsing.
- */
- if (m == NULL) {
- DPRINT("empty reply");
- return (0);
- }
- if (m->m_len < SMB_HDRLEN) {
- DPRINT("short reply");
- return (0);
- }
-
- sigloc = (uchar_t *)m->m_data + SMBSIGOFF;
- rseqno = rqp->rq_seqno + 1;
-
- DPRINT("rq_rseqno = 0x%x", rseqno);
-
- err = smb_compute_MAC(ctx, m, rseqno, sigbuf);
- if (err) {
- DPRINT("compute MAC, err %d", err);
- /*
- * If we can't compute a MAC, then there's
- * no point trying other seqno values.
- */
- return (EBADRPC);
- }
-
- /*
- * Compare the computed signature with the
- * one found in the message (at sigloc)
- */
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
- return (0);
-
- DPRINT("BAD signature, MID=0x%x", rqp->rq_mid);
-
-#ifdef DEBUG
- /*
- * For diag purposes, we check whether the client/server idea
- * of the sequence # has gotten a bit out of sync.
- */
- for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) {
- (void) smb_compute_MAC(ctx, m, rseqno + fudge, sigbuf);
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
- break;
- (void) smb_compute_MAC(ctx, m, rseqno - fudge, sigbuf);
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) {
- fudge = -fudge;
- break;
- }
- }
- if (fudge <= nsmb_signing_fudge) {
- DPRINT("rseqno=%d, but %d would have worked",
- rseqno, rseqno + fudge);
- }
-#endif
- return (EBADRPC);
-}
diff --git a/usr/src/lib/libsmbfs/smb/ssnsetup.c b/usr/src/lib/libsmbfs/smb/ssnsetup.c
deleted file mode 100644
index da7640241c..0000000000
--- a/usr/src/lib/libsmbfs/smb/ssnsetup.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * Copyright (c) 2000-2001 Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-/*
- * SMB Session Setup, and related.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <strings.h>
-#include <netdb.h>
-#include <libintl.h>
-#include <xti.h>
-#include <assert.h>
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/byteorder.h>
-#include <sys/socket.h>
-#include <sys/fcntl.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-
-#include <netsmb/mchain.h>
-#include <netsmb/netbios.h>
-#include <netsmb/smb_dev.h>
-#include <netsmb/smb.h>
-
-#include <netsmb/smb_lib.h>
-#include <netsmb/nb_lib.h>
-
-#include "private.h"
-#include "charsets.h"
-#include "ntlm.h"
-#include "smb_crypt.h"
-
-
-static int
-smb__ssnsetup(struct smb_ctx *ctx,
- struct mbdata *mbc1, struct mbdata *mbc2,
- uint32_t *statusp, uint16_t *actionp);
-
-/*
- * Session Setup: NULL session (anonymous)
- */
-int
-smb_ssnsetup_null(struct smb_ctx *ctx)
-{
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- /* Should not get here with... */
- err = EINVAL;
- goto out;
- }
-
- err = smb__ssnsetup(ctx, NULL, NULL, &ntstatus, &action);
- if (err)
- goto out;
-
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
- if (ntstatus != 0)
- err = EAUTH;
-
-out:
- return (err);
-}
-
-
-/*
- * SMB Session Setup, using NTLMv1 (and maybe LMv1)
- */
-int
-smb_ssnsetup_ntlm1(struct smb_ctx *ctx)
-{
- struct mbdata lm_mbc, nt_mbc;
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- /* Should not get here with... */
- err = EINVAL;
- goto out;
- }
-
- /* Make mb_done calls at out safe. */
- bzero(&lm_mbc, sizeof (lm_mbc));
- bzero(&nt_mbc, sizeof (nt_mbc));
-
- /* Put the LM,NTLM responses (as mbdata). */
- err = ntlm_put_v1_responses(ctx, &lm_mbc, &nt_mbc);
- if (err)
- goto out;
-
- if ((ctx->ct_vcflags & SMBV_WILL_SIGN) != 0 &&
- (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
- err = ntlm_build_mac_key(ctx, &nt_mbc);
- if (err)
- goto out;
- /* OK, start signing! */
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
- }
-
- err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
- if (err)
- goto out;
-
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
- if (ntstatus != 0)
- err = EAUTH;
-
-out:
- mb_done(&lm_mbc);
- mb_done(&nt_mbc);
-
- return (err);
-}
-
-/*
- * SMB Session Setup, using NTLMv2 (and LMv2)
- */
-int
-smb_ssnsetup_ntlm2(struct smb_ctx *ctx)
-{
- struct mbdata lm_mbc, nt_mbc, ti_mbc;
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- /* Should not get here with... */
- err = EINVAL;
- goto out;
- }
-
- /* Make mb_done calls at out safe. */
- bzero(&lm_mbc, sizeof (lm_mbc));
- bzero(&nt_mbc, sizeof (nt_mbc));
- bzero(&ti_mbc, sizeof (ti_mbc));
-
- /* Build the NTLMv2 "target info" blob (as mbdata) */
- err = ntlm_build_target_info(ctx, NULL, &ti_mbc);
- if (err)
- goto out;
-
- /* Put the LMv2, NTLMv2 responses (as mbdata). */
- err = ntlm_put_v2_responses(ctx, &ti_mbc, &lm_mbc, &nt_mbc);
- if (err)
- goto out;
-
- if ((ctx->ct_vcflags & SMBV_WILL_SIGN) != 0 &&
- (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
- err = ntlm_build_mac_key(ctx, &nt_mbc);
- if (err)
- goto out;
- /* OK, start signing! */
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
- }
-
- err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
- if (err)
- goto out;
-
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
- if (ntstatus != 0)
- err = EAUTH;
-
-out:
- mb_done(&ti_mbc);
- mb_done(&lm_mbc);
- mb_done(&nt_mbc);
-
- return (err);
-}
-
-int
-smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
-{
- struct mbdata send_mb, recv_mb;
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- err = ssp_ctx_create_client(ctx, hint_mb);
- if (err)
- goto out;
-
- bzero(&send_mb, sizeof (send_mb));
- bzero(&recv_mb, sizeof (recv_mb));
-
- /* NULL input indicates first call. */
- err = ssp_ctx_next_token(ctx, NULL, &send_mb);
- if (err)
- goto out;
-
- for (;;) {
- err = smb__ssnsetup(ctx, &send_mb, &recv_mb,
- &ntstatus, &action);
- if (err)
- goto out;
- if (ntstatus == 0)
- break; /* normal loop termination */
- if (ntstatus != NT_STATUS_MORE_PROCESSING_REQUIRED) {
- err = EAUTH;
- goto out;
- }
-
- /* middle calls get both in, out */
- err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
- if (err)
- goto out;
- }
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
-
- /* NULL output indicates last call. */
- (void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
-
-out:
- ssp_ctx_destroy(ctx);
-
- return (err);
-}
-
-/*
- * Session Setup function used for all the forms we support.
- * To allow this sharing, the crypto stuff is computed by
- * callers and passed in as mbdata chains. Also, the args
- * have different meanings for extended security vs. old.
- * Some may be used as either IN or OUT parameters.
- *
- * For NTLM (v1, v2), all parameters are inputs
- * mbc1: [in] LM password hash
- * mbc2: [in] NT password hash
- * For Extended security (spnego)
- * mbc1: [in] outgoing blob data
- * mbc2: [out] received blob data
- * For both forms, these are optional:
- * statusp: [out] NT status
- * actionp: [out] Logon Action (i.e. SMB_ACT_GUEST)
- */
-static int
-smb__ssnsetup(struct smb_ctx *ctx,
- struct mbdata *mbc1, struct mbdata *mbc2,
- uint32_t *statusp, uint16_t *actionp)
-{
- static const char NativeOS[] = "Solaris";
- static const char LanMan[] = "NETSMB";
- struct smb_sopt *sv = &ctx->ct_sopt;
- struct smb_iods *is = &ctx->ct_iods;
- struct smb_rq *rqp = NULL;
- struct mbdata *mbp;
- struct mbuf *m;
- int err, uc;
- uint32_t caps;
- uint16_t bc, len1, len2, sblen;
- uint8_t wc;
-
- caps = ctx->ct_clnt_caps;
- uc = ctx->ct_hflags2 & SMB_FLAGS2_UNICODE;
-
- err = smb_rq_init(ctx, SMB_COM_SESSION_SETUP_ANDX, &rqp);
- if (err)
- goto out;
-
- /*
- * Build the SMB request.
- */
- mbp = &rqp->rq_rq;
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, 0xff); /* 0: AndXCommand */
- mb_put_uint16le(mbp, 0); /* 1: AndXOffset */
- mb_put_uint16le(mbp, sv->sv_maxtx); /* 2: MaxBufferSize */
- mb_put_uint16le(mbp, sv->sv_maxmux); /* 3: MaxMpxCount */
- mb_put_uint16le(mbp, 1); /* 4: VcNumber */
- mb_put_uint32le(mbp, sv->sv_skey); /* 5,6: Session Key */
-
- if (caps & SMB_CAP_EXT_SECURITY) {
- len1 = mbc1 ? mbc1->mb_count : 0;
- mb_put_uint16le(mbp, len1); /* 7: Sec. Blob Len */
- mb_put_uint32le(mbp, 0); /* 8,9: reserved */
- mb_put_uint32le(mbp, caps); /* 10,11: Capabilities */
- smb_rq_wend(rqp); /* 12: Byte Count */
- smb_rq_bstart(rqp);
- if (mbc1 && mbc1->mb_top) {
- mb_put_mbuf(mbp, mbc1->mb_top); /* sec. blob */
- mbc1->mb_top = NULL; /* consumed */
- }
- /* mbc2 is required below */
- if (mbc2 == NULL) {
- err = EINVAL;
- goto out;
- }
- } else {
- len1 = mbc1 ? mbc1->mb_count : 0;
- len2 = mbc2 ? mbc2->mb_count : 0;
- mb_put_uint16le(mbp, len1); /* 7: LM pass. len */
- mb_put_uint16le(mbp, len2); /* 8: NT pass. len */
- mb_put_uint32le(mbp, 0); /* 9,10: reserved */
- mb_put_uint32le(mbp, caps); /* 11,12: Capabilities */
- smb_rq_wend(rqp); /* 13: Byte Count */
- smb_rq_bstart(rqp);
- if (mbc1 && mbc1->mb_top) {
- mb_put_mbuf(mbp, mbc1->mb_top); /* LM password */
- mbc1->mb_top = NULL; /* consumed */
- }
- if (mbc2 && mbc2->mb_top) {
- mb_put_mbuf(mbp, mbc2->mb_top); /* NT password */
- mbc2->mb_top = NULL; /* consumed */
- }
- mb_put_string(mbp, ctx->ct_user, uc);
- mb_put_string(mbp, ctx->ct_domain, uc);
- }
- mb_put_string(mbp, NativeOS, uc);
- mb_put_string(mbp, LanMan, uc);
- smb_rq_bend(rqp);
-
- err = smb_rq_internal(ctx, rqp);
- if (err)
- goto out;
-
- if (statusp)
- *statusp = rqp->rq_status;
-
- /*
- * If we have a real error, the response probably has
- * no more data, so don't try to parse any more.
- * Note: err=0, means rq_status is valid.
- */
- if (rqp->rq_status != 0 &&
- rqp->rq_status != NT_STATUS_MORE_PROCESSING_REQUIRED) {
- goto out;
- }
-
- /*
- * Parse the reply
- */
- uc = rqp->rq_hflags2 & SMB_FLAGS2_UNICODE;
- is->is_smbuid = rqp->rq_uid;
- mbp = &rqp->rq_rp;
-
- err = md_get_uint8(mbp, &wc);
- if (err)
- goto out;
-
- err = EBADRPC; /* for any problems in this section */
- if (caps & SMB_CAP_EXT_SECURITY) {
- if (wc != 4)
- goto out;
- md_get_uint16le(mbp, NULL); /* secondary cmd */
- md_get_uint16le(mbp, NULL); /* andxoffset */
- md_get_uint16le(mbp, actionp); /* action */
- md_get_uint16le(mbp, &sblen); /* sec. blob len */
- md_get_uint16le(mbp, &bc); /* byte count */
- /*
- * Get the security blob, after
- * sanity-checking the length.
- */
- if (sblen == 0 || bc < sblen)
- goto out;
- err = md_get_mbuf(mbp, sblen, &m);
- if (err)
- goto out;
- mb_initm(mbc2, m);
- mbc2->mb_count = sblen;
- } else {
- if (wc != 3)
- goto out;
- md_get_uint16le(mbp, NULL); /* secondary cmd */
- md_get_uint16le(mbp, NULL); /* andxoffset */
- md_get_uint16le(mbp, actionp); /* action */
- err = md_get_uint16le(mbp, &bc); /* byte count */
- if (err)
- goto out;
- }
-
- /*
- * Native OS, LANMGR, & Domain follow here.
- * Parse these strings and store for later.
- * If unicode, they should be aligned.
- *
- * Note that with Extended security, we may use
- * multiple calls to this function. Only parse
- * these strings on the last one (status == 0).
- * Ditto for the CAP_LARGE work-around.
- */
- if (rqp->rq_status != 0)
- goto out;
-
- /* Ignore any parsing errors for these strings. */
- err = md_get_string(mbp, &ctx->ct_srv_OS, uc);
- DPRINT("server OS: %s", err ? "?" : ctx->ct_srv_OS);
- err = md_get_string(mbp, &ctx->ct_srv_LM, uc);
- DPRINT("server LM: %s", err ? "?" : ctx->ct_srv_LM);
- /*
- * There's sometimes a server domain folloing
- * at this point, but we don't need it.
- */
-
- /* Success! (See Ignore any ... above) */
- err = 0;
-
- /*
- * MS-SMB 2.2.4.5 clarifies that when SMB signing is enabled,
- * the client should NOT use "large read/write" even though
- * the server might offer those capabilities.
- */
- if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
- DPRINT("signing, so disable CAP_LARGE_(r/w)");
- ctx->ct_sopt.sv_caps &=
- ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX);
- }
-
-out:
- if (rqp)
- smb_rq_done(rqp);
-
- return (err);
-}
diff --git a/usr/src/lib/smbclnt/Makefile b/usr/src/lib/smbclnt/Makefile
new file mode 100644
index 0000000000..4425611834
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile
@@ -0,0 +1,24 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.lib
+
+SUBDIRS = \
+ libfknsmb \
+ libfksmbfs
+
+libfksmbfs: libfknsmb
+
+include ./Makefile.subdirs
diff --git a/usr/src/lib/smbclnt/Makefile.lib b/usr/src/lib/smbclnt/Makefile.lib
new file mode 100644
index 0000000000..67528308d3
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile.lib
@@ -0,0 +1,51 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# Common Makefile definitions for smbclnt
+#
+
+# We reset the Makefile.lib macros ROOTLIBDIR to refer to usr/lib/smbfs.
+# For 64 bit, we reset ROOTLIBDIR64 to refer to usr/lib/smbfs/$(MACH64).
+# Install the userland library header files under /usr/include/netsmb
+ROOTSMBHDRDIR= $(ROOTHDRDIR)/netsmb
+ROOTSMBHDRS= $(HDRS:%=$(ROOTSMBHDRDIR)/%)
+
+ROOTLIBDIR = $(ROOT)/usr/lib/smbfs
+ROOTLIBDIR64 = $(ROOT)/usr/lib/smbfs/$(MACH64)
+
+SRCDIR= ../common
+LIBS= $(DYNLIB) $(LINTLIB)
+
+CSTD = $(CSTD_GNU99)
+
+CPPFLAGS += -I$(SRCDIR) -I.
+LDLIBS32 += -L$(ROOT)/usr/lib/smbfs
+LDLIBS64 += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
+
+CLEANFILES += $(OBJECTS:%_ndr.o=%_ndr.c)
diff --git a/usr/src/lib/smbclnt/Makefile.smbclnt b/usr/src/lib/smbclnt/Makefile.smbclnt
new file mode 100644
index 0000000000..4df97c6daa
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile.smbclnt
@@ -0,0 +1,66 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# Toplevel Makefile included by each subdirectory. Responsible for the 'check'
+# and 'install_h' targets, as well as descending into the architecture directory
+# to actually build the library.
+#
+
+include ../../Makefile.lib
+include ../Makefile.lib
+
+SUBDIRS= $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+HDRDIR= common
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber lint: $(SUBDIRS)
+
+install: install_h $(SUBDIRS)
+
+check: $(CHECKHDRS)
+
+install_h: $(ROOTSMBHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; VERSION='$(VERSION)' $(MAKE) $(TARGET)
+
+FRC:
+
+$(ROOTSMBHDRDIR)/%: common/%
+ $(INS.file)
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/smbclnt/Makefile.subdirs b/usr/src/lib/smbclnt/Makefile.subdirs
new file mode 100644
index 0000000000..66720e53ee
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile.subdirs
@@ -0,0 +1,43 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+.KEEP_STATE:
+
+all := TARGET = all
+check := TARGET = check
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+install_h := TARGET = install_h
+lint := TARGET = lint
+
+all check clean clobber install install_h lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; VERSION='$(VERSION)' $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/smbclnt/Makefile.targ b/usr/src/lib/smbclnt/Makefile.targ
new file mode 100644
index 0000000000..4c910e3565
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile.targ
@@ -0,0 +1,50 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# Common targets for smbclnt Makefiles
+#
+
+pics/%.o: $(SRC)/common/smbclnt/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: # skip
+
+$(ROOTLIBS): $(ROOTLIBDIR)
+
+$(ROOTLIBDIR):
+ $(INS.dir)
+
+$(ROOTLIBS64): $(ROOTLIBDIR64)
+
+$(ROOTLIBDIR64):
+ $(INS.dir)
diff --git a/usr/src/lib/smbclnt/libfknsmb/Makefile b/usr/src/lib/smbclnt/libfknsmb/Makefile
new file mode 100644
index 0000000000..ee4ab9faf7
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/Makefile
@@ -0,0 +1,16 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.smbclnt
diff --git a/usr/src/lib/smbclnt/libfknsmb/Makefile.com b/usr/src/lib/smbclnt/libfknsmb/Makefile.com
new file mode 100644
index 0000000000..01da52d337
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/Makefile.com
@@ -0,0 +1,109 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+#
+
+LIBRARY = libfknsmb.a
+VERS = .1
+
+OBJS_LOCAL = \
+ fksmb_sign_pkcs.o \
+ fake_ddi.o \
+ fake_fio.o \
+ fake_kmem.o \
+ fake_ktli.o \
+ fake_pkey.o \
+ fake_policy.o \
+ fake_sdt.o \
+ fake_softc.o \
+ fake_stream.o \
+ fake_strsubr.o
+
+# See also: $SRC/uts/common/Makefile.files
+# NB: Intentionally ommitted, compared w/ the above:
+# smb_dev.o smb_pass.o smb_sign_kcf.o
+#
+OBJS_NSMB = \
+ smb_dev.o \
+ smb_conn.o \
+ smb_iod.o \
+ smb_rq.o \
+ smb_sign.o \
+ smb_smb.o \
+ smb_subrs.o \
+ smb_time.o \
+ smb_tran.o \
+ smb_trantcp.o \
+ smb_usr.o \
+ smb2_rq.o \
+ smb2_sign.o \
+ smb2_smb.o \
+ subr_mchain.o
+
+OBJECTS = \
+ $(OBJS_LOCAL) \
+ $(OBJS_NSMB)
+
+include ../../../Makefile.lib
+include ../../Makefile.lib
+
+# Force SOURCEDEBUG
+CSOURCEDEBUGFLAGS = -g
+CCSOURCEDEBUGFLAGS = -g
+STRIP_STABS = :
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+# Also, like Makefile.uts, reset CPPFLAGS
+CPPFLAGS.first += -I../../../libfakekernel/common
+CPPFLAGS.first += -I../common
+CPPFLAGS= $(CPPFLAGS.first)
+
+INCS += -I$(SRC)/uts/common/fs/smbclnt
+INCS += -I$(SRC)/uts/common
+
+CPPFLAGS += $(INCS) -D_REENTRANT -D_FAKE_KERNEL
+CPPFLAGS += -D_FILE_OFFSET_BITS=64
+# Always want DEBUG here
+CPPFLAGS += -DDEBUG
+
+CERRWARN += -_gcc=-Wno-switch
+
+LDLIBS += $(MACH_LDLIBS)
+LDLIBS += -lfakekernel -lpkcs11 -lnsl -lc
+
+NSMB_DIR=$(SRC)/uts/common/fs/smbclnt/netsmb
+SRCS= $(OBJS_LOCAL:%.o=$(SRCDIR)/%.c) \
+ $(OBJS_NSMB:%.o=$(NSMB_DIR)/%.c)
+
+all:
+
+pics/%.o: $(NSMB_DIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+.KEEP_STATE:
+
+include ../../Makefile.targ
+include ../../../Makefile.targ
diff --git a/usr/src/lib/smbclnt/libfknsmb/amd64/Makefile b/usr/src/lib/smbclnt/libfknsmb/amd64/Makefile
new file mode 100644
index 0000000000..441f9285b5
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/amd64/Makefile
@@ -0,0 +1,21 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MACH_LDLIBS += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_ddi.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_ddi.c
new file mode 100644
index 0000000000..4dc0faf984
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_ddi.c
@@ -0,0 +1,133 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * UNIX Device Driver Interface functions
+ * (excerpts)
+ */
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/param.h>
+#include <sys/ddi.h>
+#include <sys/mkdev.h>
+#include <sys/debug.h>
+
+#ifndef NODEV32
+#define NODEV32 (dev32_t)(-1)
+#endif /* NODEV32 */
+
+/*
+ * return internal major number corresponding to device
+ * number (new format) argument
+ */
+major_t
+getmajor(dev_t dev)
+{
+#ifdef _LP64
+ return ((major_t)((dev >> NBITSMINOR64) & MAXMAJ64));
+#else
+ return ((major_t)((dev >> NBITSMINOR) & MAXMAJ));
+#endif
+}
+
+/*
+ * return internal minor number corresponding to device
+ * number (new format) argument
+ */
+minor_t
+getminor(dev_t dev)
+{
+#ifdef _LP64
+ return ((minor_t)(dev & MAXMIN64));
+#else
+ return ((minor_t)(dev & MAXMIN));
+#endif
+}
+
+/*
+ * encode external major and minor number arguments into a
+ * new format device number
+ */
+dev_t
+makedevice(major_t maj, minor_t minor)
+{
+#ifdef _LP64
+ return (((dev_t)maj << NBITSMINOR64) | (minor & MAXMIN64));
+#else
+ return (((dev_t)maj << NBITSMINOR) | (minor & MAXMIN));
+#endif
+}
+
+/*
+ * Compress 'long' device number encoding to 32-bit device number
+ * encoding. If it won't fit, we return failure, but set the
+ * device number to 32-bit NODEV for the sake of our callers.
+ */
+int
+cmpldev(dev32_t *dst, dev_t dev)
+{
+#if defined(_LP64)
+ if (dev == NODEV) {
+ *dst = NODEV32;
+ } else {
+ major_t major = dev >> L_BITSMINOR;
+ minor_t minor = dev & L_MAXMIN;
+
+ if (major > L_MAXMAJ32 || minor > L_MAXMIN32) {
+ *dst = NODEV32;
+ return (0);
+ }
+
+ *dst = (dev32_t)((major << L_BITSMINOR32) | minor);
+ }
+#else
+ *dst = (dev32_t)dev;
+#endif
+ return (1);
+}
+
+/*
+ * Expand 32-bit dev_t's to long dev_t's. Expansion always "fits"
+ * into the return type, but we're careful to expand NODEV explicitly.
+ */
+dev_t
+expldev(dev32_t dev32)
+{
+#ifdef _LP64
+ if (dev32 == NODEV32)
+ return (NODEV);
+ return (makedevice((dev32 >> L_BITSMINOR32) & L_MAXMAJ32,
+ dev32 & L_MAXMIN32));
+#else
+ return ((dev_t)dev32);
+#endif
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_fio.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_fio.c
new file mode 100644
index 0000000000..18f8fa2255
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_fio.c
@@ -0,0 +1,105 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent Inc.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * The kTLI "shim" over in ./fake_ktli.c uses getf(), releasef() to
+ * represent an open socket FD in "fake" vnode_t and file_t objects.
+ * This implements minimal getf()/releasef() shims for that purpose.
+ */
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/debug.h>
+#include <sys/kmem.h>
+
+#define FAKEFDS 256
+
+kmutex_t ftlock;
+file_t *ftab[FAKEFDS];
+
+file_t *
+getf(int fd)
+{
+ file_t *fp;
+ vnode_t *vp;
+
+ if (fd >= FAKEFDS)
+ return (NULL);
+
+ mutex_enter(&ftlock);
+ if ((fp = ftab[fd]) != NULL) {
+ fp->f_count++;
+ mutex_exit(&ftlock);
+ return (fp);
+ }
+
+ fp = kmem_zalloc(sizeof (*fp), KM_SLEEP);
+ vp = kmem_zalloc(sizeof (*vp), KM_SLEEP);
+ vp->v_fd = fd;
+ fp->f_vnode = vp;
+ fp->f_count = 1;
+ ftab[fd] = fp;
+
+ mutex_exit(&ftlock);
+
+ return (fp);
+}
+
+void
+releasef(int fd)
+{
+ file_t *fp;
+ vnode_t *vp;
+
+ mutex_enter(&ftlock);
+ if ((fp = ftab[fd]) == NULL) {
+ mutex_exit(&ftlock);
+ return;
+ }
+ fp->f_count--;
+ if (fp->f_count > 0) {
+ mutex_exit(&ftlock);
+ return;
+ }
+ ftab[fd] = NULL;
+ mutex_exit(&ftlock);
+
+ vp = fp->f_vnode;
+ kmem_free(vp, sizeof (*vp));
+ kmem_free(fp, sizeof (*fp));
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_kmem.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_kmem.c
new file mode 100644
index 0000000000..21453f410d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_kmem.c
@@ -0,0 +1,45 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/cred.h>
+#include <sys/kmem.h>
+#include <sys/systm.h>
+
+static size_t availmem = (1<<24);
+
+size_t
+kmem_avail(void)
+{
+ return (availmem);
+}
+
+size_t
+kmem_maxavail(void)
+{
+ return (availmem);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_ktli.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_ktli.c
new file mode 100644
index 0000000000..3011de2e77
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_ktli.c
@@ -0,0 +1,432 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Kernel TLI-like functions
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/proc.h>
+#include <sys/file.h>
+#include <sys/filio.h>
+#include <sys/user.h>
+#include <sys/vnode.h>
+#include <sys/cmn_err.h>
+#include <sys/errno.h>
+#include <sys/kmem.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/strsun.h>
+#include <sys/tihdr.h>
+#include <sys/timod.h>
+#include <sys/tiuser.h>
+#include <sys/t_kuser.h>
+
+#include <errno.h>
+#include <stropts.h>
+#include <unistd.h>
+
+#include "fake_xti.h"
+
+/* Size of mblks for tli_recv */
+#define FKTLI_RCV_SZ 4096
+
+/*
+ * Translate a TLI error into a system error as best we can.
+ */
+static const int tli_errs[] = {
+ 0, /* no error */
+ EADDRNOTAVAIL, /* TBADADDR */
+ ENOPROTOOPT, /* TBADOPT */
+ EACCES, /* TACCES */
+ EBADF, /* TBADF */
+ EADDRNOTAVAIL, /* TNOADDR */
+ EPROTO, /* TOUTSTATE */
+ EPROTO, /* TBADSEQ */
+ ENOSYS, /* TSYSERR */
+ EPROTO, /* TLOOK */
+ EMSGSIZE, /* TBADDATA */
+ EMSGSIZE, /* TBUFOVFLW */
+ EPROTO, /* TFLOW */
+ EWOULDBLOCK, /* TNODATA */
+ EPROTO, /* TNODIS */
+ EPROTO, /* TNOUDERR */
+ EINVAL, /* TBADFLAG */
+ EPROTO, /* TNOREL */
+ EOPNOTSUPP, /* TNOTSUPPORT */
+ EPROTO, /* TSTATECHNG */
+};
+
+static int
+tlitosyserr(int terr)
+{
+ if (terr < 0 || (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0]))))
+ return (EPROTO);
+ else
+ return (tli_errs[terr]);
+}
+
+/*
+ * Note: This implementation is specific to the needs of the callers in
+ * uts/common/fs/smbclnt/netsmb/smb_trantcp.c
+ */
+/* ARGSUSED */
+int
+t_kopen(file_t *fp, dev_t rdev, int flags, TIUSER **tiptr, cred_t *cr)
+{
+ boolean_t madefp = B_FALSE;
+ vnode_t *vp;
+ TIUSER *tiu;
+ int fd;
+ int rc;
+
+ *tiptr = NULL;
+
+ if (fp == NULL) {
+ /*
+ * create a socket endpoint
+ * dev is actualy AF
+ */
+ char *devnm;
+ switch (rdev) {
+ case AF_INET:
+ devnm = "/dev/tcp";
+ break;
+ case AF_INET6:
+ devnm = "/dev/tcp6";
+ break;
+ default:
+ cmn_err(CE_NOTE, "t_kopen: bad device");
+ return (EINVAL);
+ }
+
+ fd = t_open(devnm, O_RDWR, NULL);
+ if (fd < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kopen: t_open terr=%d", rc);
+ return (tlitosyserr(rc));
+ }
+
+ /*
+ * allocate a file pointer...
+ */
+ fp = getf(fd);
+ madefp = B_TRUE;
+ }
+ vp = fp->f_vnode;
+ fd = vp->v_fd;
+
+ tiu = kmem_zalloc(sizeof (*tiu), KM_SLEEP);
+ rc = t_getinfo(fd, &tiu->tp_info);
+ if (rc < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kopen: t_getinfo terr=%d", rc);
+ kmem_free(tiu, sizeof (*tiu));
+ if (madefp) {
+ releasef(fd);
+ (void) t_close(fd);
+ }
+ return (tlitosyserr(rc));
+ }
+
+ tiu->fp = fp;
+ tiu->flags = madefp ? MADE_FP : 0;
+ *tiptr = tiu;
+
+ return (0);
+}
+
+/* ARGSUSED */
+int
+t_kclose(TIUSER *tiptr, int callclosef)
+{
+ file_t *fp;
+
+ fp = (tiptr->flags & MADE_FP) ? tiptr->fp : NULL;
+
+ kmem_free(tiptr, TIUSERSZ);
+
+ if (fp != NULL) {
+ vnode_t *vp = fp->f_vnode;
+ int fd = vp->v_fd;
+ releasef(fd);
+ (void) t_close(fd);
+ }
+
+ return (0);
+}
+
+int
+t_kbind(TIUSER *tiptr, struct t_bind *req, struct t_bind *ret)
+{
+ file_t *fp = tiptr->fp;
+ vnode_t *vp = fp->f_vnode;
+ int rc;
+
+ if (t_bind(vp->v_fd, req, ret) < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kbind: t_bind terr=%d", rc);
+ return (tlitosyserr(rc));
+ }
+ return (0);
+}
+
+int
+t_kunbind(TIUSER *tiptr)
+{
+ file_t *fp = tiptr->fp;
+ vnode_t *vp = fp->f_vnode;
+ int rc;
+
+ if (t_unbind(vp->v_fd) < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kunbind: t_unbind terr=%d", rc);
+ return (tlitosyserr(rc));
+ }
+ return (0);
+}
+
+int
+t_kconnect(TIUSER *tiptr, struct t_call *sndcall, struct t_call *rcvcall)
+{
+ file_t *fp = tiptr->fp;
+ vnode_t *vp = fp->f_vnode;
+ int rc;
+
+ if (t_connect(vp->v_fd, sndcall, rcvcall) < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kconnect: t_connect terr=%d", rc);
+ if (rc == TLOOK) {
+ /* Probably got a RST. */
+ rc = ECONNREFUSED;
+ } else {
+ rc = tlitosyserr(rc);
+ }
+ return (rc);
+ }
+ return (0);
+}
+
+int
+t_koptmgmt(TIUSER *tiptr, struct t_optmgmt *req, struct t_optmgmt *ret)
+{
+ file_t *fp = tiptr->fp;
+ vnode_t *vp = fp->f_vnode;
+ int rc;
+
+ if (t_optmgmt(vp->v_fd, req, ret) < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_koptmgmt: t_optmgmt terr=%d", rc);
+ return (tlitosyserr(rc));
+ }
+ return (0);
+}
+
+/*
+ * Poll for an input event.
+ *
+ * timo is measured in ticks
+ */
+int
+t_kspoll(TIUSER *tiptr, int timo, int waitflg, int *events)
+{
+ struct pollfd pfds[1];
+ file_t *fp;
+ vnode_t *vp;
+ clock_t timout; /* milliseconds */
+ int n;
+
+ fp = tiptr->fp;
+ vp = fp->f_vnode;
+
+ if (events == NULL || ((waitflg & READWAIT) == 0))
+ return (EINVAL);
+
+ /* Convert from ticks to milliseconds */
+ if (timo < 0)
+ timout = -1;
+ else
+ timout = TICK_TO_MSEC(timo);
+
+ pfds[0].fd = vp->v_fd;
+ pfds[0].events = POLLIN;
+ pfds[0].revents = 0;
+
+ errno = 0;
+ n = poll(pfds, 1, timout);
+ if (n < 0)
+ return (errno);
+ if (n == 0)
+ return (ETIME);
+ *events = pfds[0].revents;
+ return (0);
+}
+
+/*
+ * Send the message, return zero or errno.
+ * Always free's the message, even on error.
+ */
+int
+tli_send(TIUSER *tiptr, mblk_t *bp, int fmode)
+{
+ struct strbuf ctlbuf;
+ struct strbuf databuf;
+ mblk_t *m;
+ int flg, n, rc;
+ vnode_t *vp;
+
+ if (bp == NULL)
+ return (0);
+ vp = tiptr->fp->f_vnode;
+
+ switch (bp->b_datap->db_type) {
+ case M_DATA:
+ for (m = bp; m != NULL; m = m->b_cont) {
+ n = MBLKL(m);
+ flg = (m->b_cont != NULL) ? T_MORE : 0;
+ rc = t_snd(vp->v_fd, (void *) m->b_rptr, n, flg);
+ if (rc != n) {
+ rc = EIO;
+ goto out;
+ }
+ }
+ rc = 0;
+ break;
+
+ /*
+ * May get M_PROTO/T_DISCON_REQ from nb_snddis()
+ */
+ case M_PROTO:
+ case M_PCPROTO:
+ ctlbuf.len = MBLKL(bp);
+ ctlbuf.maxlen = MBLKL(bp);
+ ctlbuf.buf = (char *)bp->b_rptr;
+ if (bp->b_cont == NULL) {
+ bzero(&databuf, sizeof (databuf));
+ } else {
+ m = bp->b_cont;
+ databuf.len = MBLKL(m);
+ databuf.maxlen = MBLKL(m);
+ databuf.buf = (char *)m->b_rptr;
+ }
+ if (putmsg(vp->v_fd, &ctlbuf, &databuf, 0) < 0) {
+ rc = errno;
+ cmn_err(CE_NOTE, "tli_send: putmsg err=%d", rc);
+ } else {
+ rc = 0;
+ }
+ break;
+
+ default:
+ rc = EIO;
+ break;
+ }
+
+out:
+ freemsg(bp);
+ return (rc);
+}
+
+int
+tli_recv(TIUSER *tiptr, mblk_t **bp, int fmode)
+{
+ mblk_t *mtop = NULL;
+ mblk_t *m;
+ vnode_t *vp;
+ int error;
+ int flags;
+ int nread;
+ int n;
+
+ vp = tiptr->fp->f_vnode;
+
+
+
+ /*
+ * Get an mblk for the data
+ */
+ nread = FKTLI_RCV_SZ;
+ m = allocb_wait(nread, 0, 0, &error);
+ ASSERT(m != NULL);
+
+ if (mtop == NULL)
+ mtop = m;
+
+again:
+ flags = 0;
+ n = t_rcv(vp->v_fd, (void *) m->b_rptr, nread, &flags);
+ if (n < 0) {
+ n = t_errno;
+ cmn_err(CE_NOTE, "tli_recv: t_rcv terr=%d", n);
+ error = tlitosyserr(n);
+ goto errout;
+ }
+ if (n == 0) {
+ error = ENOTCONN;
+ goto errout;
+ }
+ ASSERT(n > 0 && n <= nread);
+ m->b_wptr = m->b_rptr + n;
+
+ if (flags & T_MORE) {
+ mblk_t *mtail = m;
+ m = allocb_wait(nread, 0, 0, &error);
+ ASSERT(m != NULL);
+ mtail->b_cont = m;
+ goto again;
+ }
+
+ *bp = mtop;
+ return (0);
+
+errout:
+ if (m == mtop) {
+ freemsg(mtop);
+ return (error);
+ }
+
+ /* got some data, so return it. */
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_pkey.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_pkey.c
new file mode 100644
index 0000000000..b7944f8dca
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_pkey.c
@@ -0,0 +1,48 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * pkey stubs
+ */
+
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/errno.h>
+
+#include <netsmb/smb_dev.h>
+#include <netsmb/smb_pass.h>
+
+void
+smb_pkey_init()
+{
+}
+
+void
+smb_pkey_fini()
+{
+}
+
+int
+smb_pkey_idle()
+{
+ return (0);
+}
+
+/* ARGSUSED */
+int
+smb_pkey_ioctl(int cmd, intptr_t arg, int flags, cred_t *cr)
+{
+ return (ENOTTY);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_policy.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_policy.c
new file mode 100644
index 0000000000..4531e86bae
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_policy.c
@@ -0,0 +1,90 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
+ * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/errno.h>
+#include <sys/policy.h>
+
+/* ARGSUSED */
+int
+secpolicy_fs_allowed_mount(const char *fsname)
+{
+ return (0);
+}
+
+int
+secpolicy_vnode_access2(const cred_t *cr, vnode_t *vp, uid_t owner,
+ mode_t curmode, mode_t wantmode)
+{
+ mode_t mode;
+
+ mode = ~curmode & wantmode;
+
+ if (mode == 0)
+ return (0);
+ return (EACCES);
+}
+
+int
+secpolicy_vnode_owner(const cred_t *cr, uid_t owner)
+{
+ /* cr->cr_uid */
+ if (owner == crgetruid(cr))
+ return (0);
+
+ return (EPERM);
+}
+
+int
+secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap,
+ const struct vattr *ovap, int flags,
+ int unlocked_access(void *, int, cred_t *),
+ void *node)
+{
+ int mask = vap->va_mask;
+
+ if (mask & AT_SIZE) {
+ if (vp->v_type == VDIR)
+ return (EISDIR);
+ }
+ if (mask & AT_MODE)
+ return (EACCES);
+ if (mask & (AT_UID|AT_GID))
+ return (EACCES);
+
+ return (0);
+}
+
+int
+secpolicy_vnode_setdac(const cred_t *cred, uid_t owner)
+{
+ if (owner == crgetuid(cred))
+ return (0);
+
+ return (EPERM);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_sdt.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_sdt.c
new file mode 100644
index 0000000000..bc88864843
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_sdt.c
@@ -0,0 +1,50 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/cmn_err.h>
+#include <sys/sdt.h>
+
+/*
+ * See: DTRACE_PROBE... in sys/sdt.h
+ */
+
+int fknsmb_dtrace_log = 0;
+
+void
+smb_dtrace1(const char *n, long v1)
+{
+ if (fknsmb_dtrace_log) {
+ cmn_err(CE_CONT, "dtrace1: %s,"
+ " 0x%lx\n", n, v1);
+ }
+}
+
+void
+smb_dtrace2(const char *n, long v1, long v2)
+{
+ if (fknsmb_dtrace_log) {
+ cmn_err(CE_CONT, "dtrace2: %s,"
+ " 0x%lx, 0x%lx\n", n, v1, v2);
+ }
+}
+
+void
+smb_dtrace3(const char *n, long v1, long v2, long v3)
+{
+ if (fknsmb_dtrace_log) {
+ cmn_err(CE_CONT, "dtrace3: %s,"
+ " 0x%lx, 0x%lx, 0x%lx\n", n, v1, v2, v3);
+ }
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_softc.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_softc.c
new file mode 100644
index 0000000000..2d990ed3f8
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_softc.c
@@ -0,0 +1,263 @@
+
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/debug.h>
+#include <sys/sunddi.h>
+
+#define MIN_N_ITEMS 8
+
+typedef struct i_ddi_soft_state {
+ void **array; /* the array of pointers */
+ kmutex_t lock; /* serialize access to this struct */
+ size_t size; /* how many bytes per state struct */
+ size_t n_items; /* how many structs herein */
+ void *next; /* unused */
+} i_ddi_soft_state;
+
+
+void *
+ddi_get_soft_state(void *state, int item)
+{
+ i_ddi_soft_state *ss = (i_ddi_soft_state *)state;
+ void *ret = NULL;
+
+ ASSERT((ss != NULL) && (item >= 0));
+
+ mutex_enter(&ss->lock);
+
+ if (item < ss->n_items && ss->array != NULL)
+ ret = ss->array[item];
+
+ mutex_exit(&ss->lock);
+
+ return (ret);
+}
+
+
+int
+ddi_soft_state_init(void **state_p, size_t size, size_t n_items)
+{
+ i_ddi_soft_state *ss;
+
+ if (state_p == NULL || size == 0)
+ return (EINVAL);
+
+ ss = kmem_zalloc(sizeof (*ss), KM_SLEEP);
+ mutex_init(&ss->lock, NULL, MUTEX_DRIVER, NULL);
+ ss->size = size;
+
+ if (n_items < MIN_N_ITEMS)
+ ss->n_items = MIN_N_ITEMS;
+ else {
+ ss->n_items = n_items;
+ }
+
+ ASSERT(ss->n_items >= n_items);
+
+ ss->array = kmem_zalloc(ss->n_items * sizeof (void *), KM_SLEEP);
+
+ *state_p = ss;
+ return (0);
+}
+
+/*
+ * Allocate a state structure of size 'size' to be associated
+ * with item 'item'.
+ *
+ * In this implementation, the array is extended to
+ * allow the requested offset, if needed.
+ */
+int
+ddi_soft_state_zalloc(void *state, int item)
+{
+ i_ddi_soft_state *ss = (i_ddi_soft_state *)state;
+ void **array;
+ void *new_element;
+
+ if ((state == NULL) || (item < 0))
+ return (DDI_FAILURE);
+
+ mutex_enter(&ss->lock);
+ if (ss->size == 0) {
+ mutex_exit(&ss->lock);
+ cmn_err(CE_WARN, "ddi_soft_state_zalloc: bad handle: %s",
+ "fake");
+ return (DDI_FAILURE);
+ }
+
+ array = ss->array; /* NULL if ss->n_items == 0 */
+ ASSERT(ss->n_items != 0 && array != NULL);
+
+ /*
+ * refuse to tread on an existing element
+ */
+ if (item < ss->n_items && array[item] != NULL) {
+ mutex_exit(&ss->lock);
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Allocate a new element to plug in
+ */
+ new_element = kmem_zalloc(ss->size, KM_SLEEP);
+
+ /*
+ * Check if the array is big enough, if not, grow it.
+ */
+ if (item >= ss->n_items) {
+ void **new_array;
+ size_t new_n_items;
+
+ /*
+ * Allocate a new array of the right length, copy
+ * all the old pointers to the new array, then
+ * if it exists at all, put the old array on the
+ * dirty list.
+ *
+ * Note that we can't kmem_free() the old array.
+ *
+ * Why -- well the 'get' operation is 'mutex-free', so we
+ * can't easily catch a suspended thread that is just about
+ * to dereference the array we just grew out of. So we
+ * cons up a header and put it on a list of 'dirty'
+ * pointer arrays. (Dirty in the sense that there may
+ * be suspended threads somewhere that are in the middle
+ * of referencing them). Fortunately, we -can- garbage
+ * collect it all at ddi_soft_state_fini time.
+ */
+ new_n_items = ss->n_items;
+ while (new_n_items < (1 + item))
+ new_n_items <<= 1; /* double array size .. */
+
+ ASSERT(new_n_items >= (1 + item)); /* sanity check! */
+
+ new_array = kmem_zalloc(new_n_items * sizeof (void *),
+ KM_SLEEP);
+ /*
+ * Copy the pointers into the new array
+ */
+ bcopy(array, new_array, ss->n_items * sizeof (void *));
+
+ /*
+ * Free the old array now. Note that
+ * ddi_get_soft_state takes the mutex.
+ */
+ kmem_free(ss->array, ss->n_items * sizeof (void *));
+
+ ss->array = (array = new_array);
+ ss->n_items = new_n_items;
+ }
+
+ ASSERT(array != NULL && item < ss->n_items && array[item] == NULL);
+
+ array[item] = new_element;
+
+ mutex_exit(&ss->lock);
+ return (DDI_SUCCESS);
+}
+
+void
+ddi_soft_state_free(void *state, int item)
+{
+ i_ddi_soft_state *ss = (i_ddi_soft_state *)state;
+ void **array;
+ void *element;
+ static char msg[] = "ddi_soft_state_free:";
+
+ if (ss == NULL) {
+ cmn_err(CE_WARN, "%s null handle: %s",
+ msg, "fake");
+ return;
+ }
+
+ element = NULL;
+
+ mutex_enter(&ss->lock);
+
+ if ((array = ss->array) == NULL || ss->size == 0) {
+ cmn_err(CE_WARN, "%s bad handle: %s",
+ msg, "fake");
+ } else if (item < 0 || item >= ss->n_items) {
+ cmn_err(CE_WARN, "%s item %d not in range [0..%lu]: %s",
+ msg, item, (ulong_t)ss->n_items - 1, "fake");
+ } else if (array[item] != NULL) {
+ element = array[item];
+ array[item] = NULL;
+ }
+
+ mutex_exit(&ss->lock);
+
+ if (element)
+ kmem_free(element, ss->size);
+}
+
+/*
+ * Free the entire set of pointers, and any
+ * soft state structures contained therein.
+ *
+ * Note that we don't grab the ss->lock mutex, even though
+ * we're inspecting the various fields of the data structure.
+ *
+ * There is an implicit assumption that this routine will
+ * never run concurrently with any of the above on this
+ * particular state structure i.e. by the time the driver
+ * calls this routine, there should be no other threads
+ * running in the driver.
+ */
+void
+ddi_soft_state_fini(void **state_p)
+{
+ i_ddi_soft_state *ss;
+ int item;
+ static char msg[] = "ddi_soft_state_fini:";
+
+ if (state_p == NULL ||
+ (ss = (i_ddi_soft_state *)(*state_p)) == NULL) {
+ cmn_err(CE_WARN, "%s null handle: %s",
+ msg, "fake");
+ return;
+ }
+
+ if (ss->size == 0) {
+ cmn_err(CE_WARN, "%s bad handle: %s",
+ msg, "fake");
+ return;
+ }
+
+ if (ss->n_items > 0) {
+ for (item = 0; item < ss->n_items; item++)
+ ddi_soft_state_free(ss, item);
+ kmem_free(ss->array, ss->n_items * sizeof (void *));
+ }
+
+ mutex_destroy(&ss->lock);
+ kmem_free(ss, sizeof (*ss));
+
+ *state_p = NULL;
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_stream.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_stream.c
new file mode 100644
index 0000000000..d89a732d69
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_stream.c
@@ -0,0 +1,1377 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/thread.h>
+#include <sys/sysmacros.h>
+#include <sys/stropts.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/strsun.h>
+#include <sys/conf.h>
+#include <sys/debug.h>
+#include <sys/cmn_err.h>
+#include <sys/kmem.h>
+#include <sys/atomic.h>
+#include <sys/errno.h>
+#include <sys/vtrace.h>
+#include <sys/ftrace.h>
+#include <sys/ontrap.h>
+#include <sys/sdt.h>
+#include <sys/strft.h>
+
+/*
+ * This file contains selected functions from io/stream.c
+ * needed by this library, mostly unmodified.
+ */
+
+/*
+ * STREAMS message allocator: principles of operation
+ * (See usr/src/uts/common/io/stream.c)
+ */
+#define DBLK_MAX_CACHE 73728
+#define DBLK_CACHE_ALIGN 64
+#define DBLK_MIN_SIZE 8
+#define DBLK_SIZE_SHIFT 3
+
+#ifdef _BIG_ENDIAN
+#define DBLK_RTFU_SHIFT(field) \
+ (8 * (&((dblk_t *)0)->db_struioflag - &((dblk_t *)0)->field))
+#else
+#define DBLK_RTFU_SHIFT(field) \
+ (8 * (&((dblk_t *)0)->field - &((dblk_t *)0)->db_ref))
+#endif
+
+#define DBLK_RTFU(ref, type, flags, uioflag) \
+ (((ref) << DBLK_RTFU_SHIFT(db_ref)) | \
+ ((type) << DBLK_RTFU_SHIFT(db_type)) | \
+ (((flags) | (ref - 1)) << DBLK_RTFU_SHIFT(db_flags)) | \
+ ((uioflag) << DBLK_RTFU_SHIFT(db_struioflag)))
+#define DBLK_RTFU_REF_MASK (DBLK_REFMAX << DBLK_RTFU_SHIFT(db_ref))
+#define DBLK_RTFU_WORD(dbp) (*((uint32_t *)&(dbp)->db_ref))
+#define MBLK_BAND_FLAG_WORD(mp) (*((uint32_t *)&(mp)->b_band))
+
+static size_t dblk_sizes[] = {
+#ifdef _LP64
+ 16, 80, 144, 208, 272, 336, 528, 1040, 1488, 1936, 2576, 3856,
+ 8192, 12048, 16384, 20240, 24576, 28432, 32768, 36624,
+ 40960, 44816, 49152, 53008, 57344, 61200, 65536, 69392,
+#else
+ 64, 128, 320, 576, 1088, 1536, 1984, 2624, 3904,
+ 8192, 12096, 16384, 20288, 24576, 28480, 32768, 36672,
+ 40960, 44864, 49152, 53056, 57344, 61248, 65536, 69440,
+#endif
+ DBLK_MAX_CACHE, 0
+};
+
+static struct kmem_cache *dblk_cache[DBLK_MAX_CACHE / DBLK_MIN_SIZE];
+static struct kmem_cache *mblk_cache;
+static struct kmem_cache *dblk_esb_cache;
+
+static void dblk_lastfree(mblk_t *mp, dblk_t *dbp);
+static mblk_t *allocb_oversize(size_t size, int flags);
+static int allocb_tryhard_fails;
+static void frnop_func(void *arg);
+frtn_t frnop = { frnop_func };
+static void bcache_dblk_lastfree(mblk_t *mp, dblk_t *dbp);
+
+/*
+ * Patchable mblk/dblk kmem_cache flags.
+ */
+int dblk_kmem_flags = 0;
+int mblk_kmem_flags = 0;
+
+static int
+dblk_constructor(void *buf, void *cdrarg, int kmflags)
+{
+ dblk_t *dbp = buf;
+ ssize_t msg_size = (ssize_t)cdrarg;
+ size_t index;
+
+ ASSERT(msg_size != 0);
+
+ index = (msg_size - 1) >> DBLK_SIZE_SHIFT;
+
+ ASSERT(index < (DBLK_MAX_CACHE >> DBLK_SIZE_SHIFT));
+
+ if ((dbp->db_mblk = kmem_cache_alloc(mblk_cache, kmflags)) == NULL)
+ return (-1);
+ if ((msg_size & PAGEOFFSET) == 0) {
+ dbp->db_base = kmem_alloc(msg_size, kmflags);
+ if (dbp->db_base == NULL) {
+ kmem_cache_free(mblk_cache, dbp->db_mblk);
+ return (-1);
+ }
+ } else {
+ dbp->db_base = (unsigned char *)&dbp[1];
+ }
+
+ dbp->db_mblk->b_datap = dbp;
+ dbp->db_cache = dblk_cache[index];
+ dbp->db_lim = dbp->db_base + msg_size;
+ dbp->db_free = dbp->db_lastfree = dblk_lastfree;
+ dbp->db_frtnp = NULL;
+ dbp->db_fthdr = NULL;
+ dbp->db_credp = NULL;
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dblk_esb_constructor(void *buf, void *cdrarg, int kmflags)
+{
+ dblk_t *dbp = buf;
+
+ if ((dbp->db_mblk = kmem_cache_alloc(mblk_cache, kmflags)) == NULL)
+ return (-1);
+ dbp->db_mblk->b_datap = dbp;
+ dbp->db_cache = dblk_esb_cache;
+ dbp->db_fthdr = NULL;
+ dbp->db_credp = NULL;
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+ return (0);
+}
+
+static int
+bcache_dblk_constructor(void *buf, void *cdrarg, int kmflags)
+{
+ dblk_t *dbp = buf;
+ bcache_t *bcp = cdrarg;
+
+ if ((dbp->db_mblk = kmem_cache_alloc(mblk_cache, kmflags)) == NULL)
+ return (-1);
+
+ dbp->db_base = kmem_cache_alloc(bcp->buffer_cache, kmflags);
+ if (dbp->db_base == NULL) {
+ kmem_cache_free(mblk_cache, dbp->db_mblk);
+ return (-1);
+ }
+
+ dbp->db_mblk->b_datap = dbp;
+ dbp->db_cache = (void *)bcp;
+ dbp->db_lim = dbp->db_base + bcp->size;
+ dbp->db_free = dbp->db_lastfree = bcache_dblk_lastfree;
+ dbp->db_frtnp = NULL;
+ dbp->db_fthdr = NULL;
+ dbp->db_credp = NULL;
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+ return (0);
+}
+
+/*ARGSUSED*/
+static void
+dblk_destructor(void *buf, void *cdrarg)
+{
+ dblk_t *dbp = buf;
+ ssize_t msg_size = (ssize_t)cdrarg;
+
+ ASSERT(dbp->db_mblk->b_datap == dbp);
+ ASSERT(msg_size != 0);
+ ASSERT(dbp->db_struioflag == 0);
+ ASSERT(dbp->db_struioun.cksum.flags == 0);
+
+ if ((msg_size & PAGEOFFSET) == 0) {
+ kmem_free(dbp->db_base, msg_size);
+ }
+
+ kmem_cache_free(mblk_cache, dbp->db_mblk);
+}
+
+static void
+bcache_dblk_destructor(void *buf, void *cdrarg)
+{
+ dblk_t *dbp = buf;
+ bcache_t *bcp = cdrarg;
+
+ kmem_cache_free(bcp->buffer_cache, dbp->db_base);
+
+ ASSERT(dbp->db_mblk->b_datap == dbp);
+ ASSERT(dbp->db_struioflag == 0);
+ ASSERT(dbp->db_struioun.cksum.flags == 0);
+
+ kmem_cache_free(mblk_cache, dbp->db_mblk);
+}
+
+/* Needed in the ASSERT below */
+#ifdef DEBUG
+#ifdef _KERNEL
+#define KMEM_SLAB_T_SZ sizeof (kmem_slab_t)
+#else /* _KERNEL */
+#define KMEM_SLAB_T_SZ 64 /* fakekernel */
+#endif /* _KERNEL */
+#endif /* DEBUG */
+
+void
+streams_msg_init(void)
+{
+ char name[40];
+ size_t size;
+ size_t lastsize = DBLK_MIN_SIZE;
+ size_t *sizep;
+ struct kmem_cache *cp;
+ size_t tot_size;
+ int offset;
+
+ mblk_cache = kmem_cache_create("streams_mblk", sizeof (mblk_t), 32,
+ NULL, NULL, NULL, NULL, NULL, mblk_kmem_flags);
+
+ for (sizep = dblk_sizes; (size = *sizep) != 0; sizep++) {
+
+ if ((offset = (size & PAGEOFFSET)) != 0) {
+ /*
+ * We are in the middle of a page, dblk should
+ * be allocated on the same page
+ */
+ tot_size = size + sizeof (dblk_t);
+ ASSERT((offset + sizeof (dblk_t) + KMEM_SLAB_T_SZ)
+ < PAGESIZE);
+ ASSERT((tot_size & (DBLK_CACHE_ALIGN - 1)) == 0);
+
+ } else {
+
+ /*
+ * buf size is multiple of page size, dblk and
+ * buffer are allocated separately.
+ */
+
+ ASSERT((size & (DBLK_CACHE_ALIGN - 1)) == 0);
+ tot_size = sizeof (dblk_t);
+ }
+
+ (void) sprintf(name, "streams_dblk_%ld", (long)size);
+ cp = kmem_cache_create(name, tot_size, DBLK_CACHE_ALIGN,
+ dblk_constructor, dblk_destructor, NULL, (void *)(size),
+ NULL, dblk_kmem_flags);
+
+ while (lastsize <= size) {
+ dblk_cache[(lastsize - 1) >> DBLK_SIZE_SHIFT] = cp;
+ lastsize += DBLK_MIN_SIZE;
+ }
+ }
+
+ dblk_esb_cache = kmem_cache_create("streams_dblk_esb", sizeof (dblk_t),
+ DBLK_CACHE_ALIGN, dblk_esb_constructor, dblk_destructor, NULL,
+ (void *)sizeof (dblk_t), NULL, dblk_kmem_flags);
+
+ /* fthdr_cache, ftblk_cache, mmd_init... */
+}
+
+/*ARGSUSED*/
+mblk_t *
+allocb(size_t size, uint_t pri)
+{
+ dblk_t *dbp;
+ mblk_t *mp;
+ size_t index;
+
+ index = (size - 1) >> DBLK_SIZE_SHIFT;
+
+ if (index >= (DBLK_MAX_CACHE >> DBLK_SIZE_SHIFT)) {
+ if (size != 0) {
+ mp = allocb_oversize(size, KM_NOSLEEP);
+ goto out;
+ }
+ index = 0;
+ }
+
+ if ((dbp = kmem_cache_alloc(dblk_cache[index], KM_NOSLEEP)) == NULL) {
+ mp = NULL;
+ goto out;
+ }
+
+ mp = dbp->db_mblk;
+ DBLK_RTFU_WORD(dbp) = DBLK_RTFU(1, M_DATA, 0, 0);
+ mp->b_next = mp->b_prev = mp->b_cont = NULL;
+ mp->b_rptr = mp->b_wptr = dbp->db_base;
+ mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(mp) = 0;
+ STR_FTALLOC(&dbp->db_fthdr, FTEV_ALLOCB, size);
+out:
+ FTRACE_1("allocb(): mp=0x%p", (uintptr_t)mp);
+
+ return (mp);
+}
+
+/*
+ * Allocate an mblk taking db_credp and db_cpid from the template.
+ * Allow the cred to be NULL.
+ */
+mblk_t *
+allocb_tmpl(size_t size, const mblk_t *tmpl)
+{
+ mblk_t *mp = allocb(size, 0);
+
+ if (mp != NULL) {
+ dblk_t *src = tmpl->b_datap;
+ dblk_t *dst = mp->b_datap;
+ cred_t *cr;
+ pid_t cpid;
+
+ cr = msg_getcred(tmpl, &cpid);
+ if (cr != NULL)
+ crhold(dst->db_credp = cr);
+ dst->db_cpid = cpid;
+ dst->db_type = src->db_type;
+ }
+ return (mp);
+}
+
+mblk_t *
+allocb_cred(size_t size, cred_t *cr, pid_t cpid)
+{
+ mblk_t *mp = allocb(size, 0);
+
+ ASSERT(cr != NULL);
+ if (mp != NULL) {
+ dblk_t *dbp = mp->b_datap;
+
+ crhold(dbp->db_credp = cr);
+ dbp->db_cpid = cpid;
+ }
+ return (mp);
+}
+
+mblk_t *
+allocb_cred_wait(size_t size, uint_t flags, int *error, cred_t *cr, pid_t cpid)
+{
+ mblk_t *mp = allocb_wait(size, 0, flags, error);
+
+ ASSERT(cr != NULL);
+ if (mp != NULL) {
+ dblk_t *dbp = mp->b_datap;
+
+ crhold(dbp->db_credp = cr);
+ dbp->db_cpid = cpid;
+ }
+
+ return (mp);
+}
+
+/*
+ * Extract the db_cred (and optionally db_cpid) from a message.
+ * We find the first mblk which has a non-NULL db_cred and use that.
+ * If none found we return NULL.
+ * Does NOT get a hold on the cred.
+ */
+cred_t *
+msg_getcred(const mblk_t *mp, pid_t *cpidp)
+{
+ cred_t *cr = NULL;
+
+ while (mp != NULL) {
+ dblk_t *dbp = mp->b_datap;
+
+ cr = dbp->db_credp;
+ if (cr == NULL) {
+ mp = mp->b_cont;
+ continue;
+ }
+ if (cpidp != NULL)
+ *cpidp = dbp->db_cpid;
+
+ /* DEBUG check for only one db_credp */
+ return (cr);
+ }
+ if (cpidp != NULL)
+ *cpidp = NOPID;
+ return (NULL);
+}
+
+/*
+ * Variant of msg_getcred which, when a cred is found
+ * 1. Returns with a hold on the cred
+ * 2. Clears the first cred in the mblk.
+ * This is more efficient to use than a msg_getcred() + crhold() when
+ * the message is freed after the cred has been extracted.
+ *
+ * The caller is responsible for ensuring that there is no other reference
+ * on the message since db_credp can not be cleared when there are other
+ * references.
+ */
+cred_t *
+msg_extractcred(mblk_t *mp, pid_t *cpidp)
+{
+ cred_t *cr = NULL;
+
+ while (mp != NULL) {
+ dblk_t *dbp = mp->b_datap;
+
+ cr = dbp->db_credp;
+ if (cr == NULL) {
+ mp = mp->b_cont;
+ continue;
+ }
+ ASSERT(dbp->db_ref == 1);
+ dbp->db_credp = NULL;
+ if (cpidp != NULL)
+ *cpidp = dbp->db_cpid;
+
+ /* DEBUG check for only one db_credp */
+ return (cr);
+ }
+ return (NULL);
+}
+
+/* _KERNEL msg_getlabel() */
+
+void
+freeb(mblk_t *mp)
+{
+ dblk_t *dbp = mp->b_datap;
+
+ ASSERT(dbp->db_ref > 0);
+ ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
+ FTRACE_1("freeb(): mp=0x%lx", (uintptr_t)mp);
+
+ STR_FTEVENT_MBLK(mp, caller(), FTEV_FREEB, dbp->db_ref);
+
+ dbp->db_free(mp, dbp);
+}
+
+void
+freemsg(mblk_t *mp)
+{
+ FTRACE_1("freemsg(): mp=0x%lx", (uintptr_t)mp);
+ while (mp) {
+ dblk_t *dbp = mp->b_datap;
+ mblk_t *mp_cont = mp->b_cont;
+
+ ASSERT(dbp->db_ref > 0);
+ ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
+
+ STR_FTEVENT_MBLK(mp, caller(), FTEV_FREEB, dbp->db_ref);
+
+ dbp->db_free(mp, dbp);
+ mp = mp_cont;
+ }
+}
+
+/*
+ * Reallocate a block for another use. Try hard to use the old block.
+ * If the old data is wanted (copy), leave b_wptr at the end of the data,
+ * otherwise return b_wptr = b_rptr.
+ *
+ * This routine is private and unstable.
+ */
+mblk_t *
+reallocb(mblk_t *mp, size_t size, uint_t copy)
+{
+ mblk_t *mp1;
+ unsigned char *old_rptr;
+ ptrdiff_t cur_size;
+
+ if (mp == NULL)
+ return (allocb(size, BPRI_HI));
+
+ cur_size = mp->b_wptr - mp->b_rptr;
+ old_rptr = mp->b_rptr;
+
+ ASSERT(mp->b_datap->db_ref != 0);
+
+ if (mp->b_datap->db_ref == 1 && MBLKSIZE(mp) >= size) {
+ /*
+ * If the data is wanted and it will fit where it is, no
+ * work is required.
+ */
+ if (copy && mp->b_datap->db_lim - mp->b_rptr >= size)
+ return (mp);
+
+ mp->b_wptr = mp->b_rptr = mp->b_datap->db_base;
+ mp1 = mp;
+ } else if ((mp1 = allocb_tmpl(size, mp)) != NULL) {
+ /* XXX other mp state could be copied too, db_flags ... ? */
+ mp1->b_cont = mp->b_cont;
+ } else {
+ return (NULL);
+ }
+
+ if (copy) {
+ bcopy(old_rptr, mp1->b_rptr, cur_size);
+ mp1->b_wptr = mp1->b_rptr + cur_size;
+ }
+
+ if (mp != mp1)
+ freeb(mp);
+
+ return (mp1);
+}
+
+static void
+dblk_lastfree(mblk_t *mp, dblk_t *dbp)
+{
+ ASSERT(dbp->db_mblk == mp);
+ if (dbp->db_fthdr != NULL)
+ str_ftfree(dbp);
+
+ /* set credp and projid to be 'unspecified' before returning to cache */
+ if (dbp->db_credp != NULL) {
+ crfree(dbp->db_credp);
+ dbp->db_credp = NULL;
+ }
+ dbp->db_cpid = -1;
+
+ /* Reset the struioflag and the checksum flag fields */
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+
+ /* and the COOKED and/or UIOA flag(s) */
+ dbp->db_flags &= ~(DBLK_COOKED | DBLK_UIOA);
+
+ kmem_cache_free(dbp->db_cache, dbp);
+}
+
+static void
+dblk_decref(mblk_t *mp, dblk_t *dbp)
+{
+ if (dbp->db_ref != 1) {
+ uint32_t rtfu = atomic_add_32_nv(&DBLK_RTFU_WORD(dbp),
+ -(1 << DBLK_RTFU_SHIFT(db_ref)));
+ /*
+ * atomic_add_32_nv() just decremented db_ref, so we no longer
+ * have a reference to the dblk, which means another thread
+ * could free it. Therefore we cannot examine the dblk to
+ * determine whether ours was the last reference. Instead,
+ * we extract the new and minimum reference counts from rtfu.
+ * Note that all we're really saying is "if (ref != refmin)".
+ */
+ if (((rtfu >> DBLK_RTFU_SHIFT(db_ref)) & DBLK_REFMAX) !=
+ ((rtfu >> DBLK_RTFU_SHIFT(db_flags)) & DBLK_REFMIN)) {
+ kmem_cache_free(mblk_cache, mp);
+ return;
+ }
+ }
+ dbp->db_mblk = mp;
+ dbp->db_free = dbp->db_lastfree;
+ dbp->db_lastfree(mp, dbp);
+}
+
+mblk_t *
+dupb(mblk_t *mp)
+{
+ dblk_t *dbp = mp->b_datap;
+ mblk_t *new_mp;
+ uint32_t oldrtfu, newrtfu;
+
+ if ((new_mp = kmem_cache_alloc(mblk_cache, KM_NOSLEEP)) == NULL)
+ goto out;
+
+ new_mp->b_next = new_mp->b_prev = new_mp->b_cont = NULL;
+ new_mp->b_rptr = mp->b_rptr;
+ new_mp->b_wptr = mp->b_wptr;
+ new_mp->b_datap = dbp;
+ new_mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(new_mp) = MBLK_BAND_FLAG_WORD(mp);
+
+ STR_FTEVENT_MBLK(mp, caller(), FTEV_DUPB, dbp->db_ref);
+
+ dbp->db_free = dblk_decref;
+ do {
+ ASSERT(dbp->db_ref > 0);
+ oldrtfu = DBLK_RTFU_WORD(dbp);
+ newrtfu = oldrtfu + (1 << DBLK_RTFU_SHIFT(db_ref));
+ /*
+ * If db_ref is maxed out we can't dup this message anymore.
+ */
+ if ((oldrtfu & DBLK_RTFU_REF_MASK) == DBLK_RTFU_REF_MASK) {
+ kmem_cache_free(mblk_cache, new_mp);
+ new_mp = NULL;
+ goto out;
+ }
+ } while (atomic_cas_32(&DBLK_RTFU_WORD(dbp), oldrtfu, newrtfu) !=
+ oldrtfu);
+
+out:
+ FTRACE_1("dupb(): new_mp=0x%lx", (uintptr_t)new_mp);
+ return (new_mp);
+}
+
+/*ARGSUSED*/
+static void
+frnop_func(void *arg)
+{
+}
+
+/*
+ * Generic esballoc used to implement the four flavors: [d]esballoc[a].
+ * and allocb_oversize
+ */
+static mblk_t *
+gesballoc(unsigned char *base, size_t size, uint32_t db_rtfu, frtn_t *frp,
+ void (*lastfree)(mblk_t *, dblk_t *), int kmflags)
+{
+ dblk_t *dbp;
+ mblk_t *mp;
+
+ ASSERT(base != NULL && frp != NULL);
+
+ if ((dbp = kmem_cache_alloc(dblk_esb_cache, kmflags)) == NULL) {
+ mp = NULL;
+ goto out;
+ }
+
+ mp = dbp->db_mblk;
+ dbp->db_base = base;
+ dbp->db_lim = base + size;
+ dbp->db_free = dbp->db_lastfree = lastfree;
+ dbp->db_frtnp = frp;
+ DBLK_RTFU_WORD(dbp) = db_rtfu;
+ mp->b_next = mp->b_prev = mp->b_cont = NULL;
+ mp->b_rptr = mp->b_wptr = base;
+ mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(mp) = 0;
+
+out:
+ FTRACE_1("gesballoc(): mp=0x%lx", (uintptr_t)mp);
+ return (mp);
+}
+
+static void
+bcache_dblk_lastfree(mblk_t *mp, dblk_t *dbp)
+{
+ bcache_t *bcp = dbp->db_cache;
+
+ ASSERT(dbp->db_mblk == mp);
+ if (dbp->db_fthdr != NULL)
+ str_ftfree(dbp);
+
+ /* set credp and projid to be 'unspecified' before returning to cache */
+ if (dbp->db_credp != NULL) {
+ crfree(dbp->db_credp);
+ dbp->db_credp = NULL;
+ }
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+
+ mutex_enter(&bcp->mutex);
+ kmem_cache_free(bcp->dblk_cache, dbp);
+ bcp->alloc--;
+
+ if (bcp->alloc == 0 && bcp->destroy != 0) {
+ kmem_cache_destroy(bcp->dblk_cache);
+ kmem_cache_destroy(bcp->buffer_cache);
+ mutex_exit(&bcp->mutex);
+ mutex_destroy(&bcp->mutex);
+ kmem_free(bcp, sizeof (bcache_t));
+ } else {
+ mutex_exit(&bcp->mutex);
+ }
+}
+
+bcache_t *
+bcache_create(char *name, size_t size, uint_t align)
+{
+ bcache_t *bcp;
+ char buffer[255];
+
+ ASSERT((align & (align - 1)) == 0);
+
+ if ((bcp = kmem_alloc(sizeof (bcache_t), KM_NOSLEEP)) == NULL)
+ return (NULL);
+
+ bcp->size = size;
+ bcp->align = align;
+ bcp->alloc = 0;
+ bcp->destroy = 0;
+
+ mutex_init(&bcp->mutex, NULL, MUTEX_DRIVER, NULL);
+
+ (void) sprintf(buffer, "%s_buffer_cache", name);
+ bcp->buffer_cache = kmem_cache_create(buffer, size, align, NULL, NULL,
+ NULL, NULL, NULL, 0);
+ (void) sprintf(buffer, "%s_dblk_cache", name);
+ bcp->dblk_cache = kmem_cache_create(buffer, sizeof (dblk_t),
+ DBLK_CACHE_ALIGN, bcache_dblk_constructor, bcache_dblk_destructor,
+ NULL, (void *)bcp, NULL, 0);
+
+ return (bcp);
+}
+
+void
+bcache_destroy(bcache_t *bcp)
+{
+ ASSERT(bcp != NULL);
+
+ mutex_enter(&bcp->mutex);
+ if (bcp->alloc == 0) {
+ kmem_cache_destroy(bcp->dblk_cache);
+ kmem_cache_destroy(bcp->buffer_cache);
+ mutex_exit(&bcp->mutex);
+ mutex_destroy(&bcp->mutex);
+ kmem_free(bcp, sizeof (bcache_t));
+ } else {
+ bcp->destroy++;
+ mutex_exit(&bcp->mutex);
+ }
+}
+
+/*ARGSUSED*/
+mblk_t *
+bcache_allocb(bcache_t *bcp, uint_t pri)
+{
+ dblk_t *dbp;
+ mblk_t *mp = NULL;
+
+ ASSERT(bcp != NULL);
+
+ mutex_enter(&bcp->mutex);
+ if (bcp->destroy != 0) {
+ mutex_exit(&bcp->mutex);
+ goto out;
+ }
+
+ if ((dbp = kmem_cache_alloc(bcp->dblk_cache, KM_NOSLEEP)) == NULL) {
+ mutex_exit(&bcp->mutex);
+ goto out;
+ }
+ bcp->alloc++;
+ mutex_exit(&bcp->mutex);
+
+ ASSERT(((uintptr_t)(dbp->db_base) & (bcp->align - 1)) == 0);
+
+ mp = dbp->db_mblk;
+ DBLK_RTFU_WORD(dbp) = DBLK_RTFU(1, M_DATA, 0, 0);
+ mp->b_next = mp->b_prev = mp->b_cont = NULL;
+ mp->b_rptr = mp->b_wptr = dbp->db_base;
+ mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(mp) = 0;
+ STR_FTALLOC(&dbp->db_fthdr, FTEV_BCALLOCB, bcp->size);
+out:
+ FTRACE_1("bcache_allocb(): mp=0x%p", (uintptr_t)mp);
+
+ return (mp);
+}
+
+static void
+dblk_lastfree_oversize(mblk_t *mp, dblk_t *dbp)
+{
+ ASSERT(dbp->db_mblk == mp);
+ if (dbp->db_fthdr != NULL)
+ str_ftfree(dbp);
+
+ /* set credp and projid to be 'unspecified' before returning to cache */
+ if (dbp->db_credp != NULL) {
+ crfree(dbp->db_credp);
+ dbp->db_credp = NULL;
+ }
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+
+ kmem_free(dbp->db_base, dbp->db_lim - dbp->db_base);
+ kmem_cache_free(dbp->db_cache, dbp);
+}
+
+static mblk_t *
+allocb_oversize(size_t size, int kmflags)
+{
+ mblk_t *mp;
+ void *buf;
+
+ size = P2ROUNDUP(size, DBLK_CACHE_ALIGN);
+ if ((buf = kmem_alloc(size, kmflags)) == NULL)
+ return (NULL);
+ if ((mp = gesballoc(buf, size, DBLK_RTFU(1, M_DATA, 0, 0),
+ &frnop, dblk_lastfree_oversize, kmflags)) == NULL)
+ kmem_free(buf, size);
+
+ if (mp != NULL)
+ STR_FTALLOC(&DB_FTHDR(mp), FTEV_ALLOCBIG, size);
+
+ return (mp);
+}
+
+mblk_t *
+allocb_tryhard(size_t target_size)
+{
+ size_t size;
+ mblk_t *bp;
+
+ for (size = target_size; size < target_size + 512;
+ size += DBLK_CACHE_ALIGN)
+ if ((bp = allocb(size, BPRI_HI)) != NULL)
+ return (bp);
+ allocb_tryhard_fails++;
+ return (NULL);
+}
+
+/*
+ * This routine is consolidation private for STREAMS internal use
+ * This routine may only be called from sync routines (i.e., not
+ * from put or service procedures). It is located here (rather
+ * than strsubr.c) so that we don't have to expose all of the
+ * allocb() implementation details in header files.
+ */
+mblk_t *
+allocb_wait(size_t size, uint_t pri, uint_t flags, int *error)
+{
+ dblk_t *dbp;
+ mblk_t *mp;
+ size_t index;
+
+ index = (size -1) >> DBLK_SIZE_SHIFT;
+
+ if (flags & STR_NOSIG) {
+ if (index >= (DBLK_MAX_CACHE >> DBLK_SIZE_SHIFT)) {
+ if (size != 0) {
+ mp = allocb_oversize(size, KM_SLEEP);
+ FTRACE_1("allocb_wait (NOSIG): mp=0x%lx",
+ (uintptr_t)mp);
+ return (mp);
+ }
+ index = 0;
+ }
+
+ dbp = kmem_cache_alloc(dblk_cache[index], KM_SLEEP);
+ mp = dbp->db_mblk;
+ DBLK_RTFU_WORD(dbp) = DBLK_RTFU(1, M_DATA, 0, 0);
+ mp->b_next = mp->b_prev = mp->b_cont = NULL;
+ mp->b_rptr = mp->b_wptr = dbp->db_base;
+ mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(mp) = 0;
+ STR_FTALLOC(&DB_FTHDR(mp), FTEV_ALLOCBW, size);
+
+ FTRACE_1("allocb_wait (NOSIG): mp=0x%lx", (uintptr_t)mp);
+
+ } else {
+ while ((mp = allocb(size, pri)) == NULL) {
+ if ((*error = strwaitbuf(size, BPRI_HI)) != 0)
+ return (NULL);
+ }
+ }
+
+ return (mp);
+}
+
+/*
+ * Call function 'func' with 'arg' when a class zero block can
+ * be allocated with priority 'pri'.
+ */
+bufcall_id_t
+esbbcall(uint_t pri, void (*func)(void *), void *arg)
+{
+ return (bufcall(1, pri, func, arg));
+}
+
+/*
+ * Allocates an iocblk (M_IOCTL) block. Properly sets the credentials
+ * ioc_id, rval and error of the struct ioctl to set up an ioctl call.
+ * This provides consistency for all internal allocators of ioctl.
+ */
+mblk_t *
+mkiocb(uint_t cmd)
+{
+ struct iocblk *ioc;
+ mblk_t *mp;
+
+ /*
+ * Allocate enough space for any of the ioctl related messages.
+ */
+ if ((mp = allocb(sizeof (union ioctypes), BPRI_MED)) == NULL)
+ return (NULL);
+
+ bzero(mp->b_rptr, sizeof (union ioctypes));
+
+ /*
+ * Set the mblk_t information and ptrs correctly.
+ */
+ mp->b_wptr += sizeof (struct iocblk);
+ mp->b_datap->db_type = M_IOCTL;
+
+ /*
+ * Fill in the fields.
+ */
+ ioc = (struct iocblk *)mp->b_rptr;
+ ioc->ioc_cmd = cmd;
+ ioc->ioc_cr = kcred;
+ ioc->ioc_id = getiocseqno();
+ ioc->ioc_flag = IOC_NATIVE;
+ return (mp);
+}
+
+/*
+ * test if block of given size can be allocated with a request of
+ * the given priority.
+ * 'pri' is no longer used, but is retained for compatibility.
+ */
+/* ARGSUSED */
+int
+testb(size_t size, uint_t pri)
+{
+ return ((size + sizeof (dblk_t)) <= kmem_avail());
+}
+
+/* _KERNEL: bufcall, unbufcall */
+
+/*
+ * Duplicate a message block by block (uses dupb), returning
+ * a pointer to the duplicate message.
+ * Returns a non-NULL value only if the entire message
+ * was dup'd.
+ */
+mblk_t *
+dupmsg(mblk_t *bp)
+{
+ mblk_t *head, *nbp;
+
+ if (!bp || !(nbp = head = dupb(bp)))
+ return (NULL);
+
+ while (bp->b_cont) {
+ if (!(nbp->b_cont = dupb(bp->b_cont))) {
+ freemsg(head);
+ return (NULL);
+ }
+ nbp = nbp->b_cont;
+ bp = bp->b_cont;
+ }
+ return (head);
+}
+
+#define DUPB_NOLOAN(bp) \
+ ((((bp)->b_datap->db_struioflag & STRUIO_ZC) != 0) ? \
+ copyb((bp)) : dupb((bp)))
+
+mblk_t *
+dupmsg_noloan(mblk_t *bp)
+{
+ mblk_t *head, *nbp;
+
+ if (bp == NULL || DB_TYPE(bp) != M_DATA ||
+ ((nbp = head = DUPB_NOLOAN(bp)) == NULL))
+ return (NULL);
+
+ while (bp->b_cont) {
+ if ((nbp->b_cont = DUPB_NOLOAN(bp->b_cont)) == NULL) {
+ freemsg(head);
+ return (NULL);
+ }
+ nbp = nbp->b_cont;
+ bp = bp->b_cont;
+ }
+ return (head);
+}
+
+/*
+ * Copy data from message and data block to newly allocated message and
+ * data block. Returns new message block pointer, or NULL if error.
+ * The alignment of rptr (w.r.t. word alignment) will be the same in the copy
+ * as in the original even when db_base is not word aligned. (bug 1052877)
+ */
+mblk_t *
+copyb(mblk_t *bp)
+{
+ mblk_t *nbp;
+ dblk_t *dp, *ndp;
+ uchar_t *base;
+ size_t size;
+ size_t unaligned;
+
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+
+ dp = bp->b_datap;
+ if (dp->db_fthdr != NULL)
+ STR_FTEVENT_MBLK(bp, caller(), FTEV_COPYB, 0);
+
+ /*
+ * Special handling for Multidata message; this should be
+ * removed once a copy-callback routine is made available.
+ */
+ if (dp->db_type == M_MULTIDATA) {
+ /* _KERNEL mmd_copy stuff */
+ return (NULL);
+ }
+
+ size = dp->db_lim - dp->db_base;
+ unaligned = P2PHASE((uintptr_t)dp->db_base, sizeof (uint_t));
+ if ((nbp = allocb_tmpl(size + unaligned, bp)) == NULL)
+ return (NULL);
+ nbp->b_flag = bp->b_flag;
+ nbp->b_band = bp->b_band;
+ ndp = nbp->b_datap;
+
+ /*
+ * Well, here is a potential issue. If we are trying to
+ * trace a flow, and we copy the message, we might lose
+ * information about where this message might have been.
+ * So we should inherit the FT data. On the other hand,
+ * a user might be interested only in alloc to free data.
+ * So I guess the real answer is to provide a tunable.
+ */
+ STR_FTEVENT_MBLK(nbp, caller(), FTEV_COPYB, 1);
+
+ base = ndp->db_base + unaligned;
+ bcopy(dp->db_base, ndp->db_base + unaligned, size);
+
+ nbp->b_rptr = base + (bp->b_rptr - dp->db_base);
+ nbp->b_wptr = nbp->b_rptr + MBLKL(bp);
+
+ return (nbp);
+}
+
+/*
+ * Copy data from message to newly allocated message using new
+ * data blocks. Returns a pointer to the new message, or NULL if error.
+ */
+mblk_t *
+copymsg(mblk_t *bp)
+{
+ mblk_t *head, *nbp;
+
+ if (!bp || !(nbp = head = copyb(bp)))
+ return (NULL);
+
+ while (bp->b_cont) {
+ if (!(nbp->b_cont = copyb(bp->b_cont))) {
+ freemsg(head);
+ return (NULL);
+ }
+ nbp = nbp->b_cont;
+ bp = bp->b_cont;
+ }
+ return (head);
+}
+
+/*
+ * link a message block to tail of message
+ */
+void
+linkb(mblk_t *mp, mblk_t *bp)
+{
+ ASSERT(mp && bp);
+
+ for (; mp->b_cont; mp = mp->b_cont)
+ ;
+ mp->b_cont = bp;
+}
+
+/*
+ * unlink a message block from head of message
+ * return pointer to new message.
+ * NULL if message becomes empty.
+ */
+mblk_t *
+unlinkb(mblk_t *bp)
+{
+ mblk_t *bp1;
+
+ bp1 = bp->b_cont;
+ bp->b_cont = NULL;
+ return (bp1);
+}
+
+/*
+ * remove a message block "bp" from message "mp"
+ *
+ * Return pointer to new message or NULL if no message remains.
+ * Return -1 if bp is not found in message.
+ */
+mblk_t *
+rmvb(mblk_t *mp, mblk_t *bp)
+{
+ mblk_t *tmp;
+ mblk_t *lastp = NULL;
+
+ ASSERT(mp && bp);
+ for (tmp = mp; tmp; tmp = tmp->b_cont) {
+ if (tmp == bp) {
+ if (lastp)
+ lastp->b_cont = tmp->b_cont;
+ else
+ mp = tmp->b_cont;
+ tmp->b_cont = NULL;
+ return (mp);
+ }
+ lastp = tmp;
+ }
+ return ((mblk_t *)-1);
+}
+
+/*
+ * Concatenate and align first len bytes of common
+ * message type. Len == -1, means concat everything.
+ * Returns 1 on success, 0 on failure
+ * After the pullup, mp points to the pulled up data.
+ */
+int
+pullupmsg(mblk_t *mp, ssize_t len)
+{
+ mblk_t *bp, *b_cont;
+ dblk_t *dbp;
+ ssize_t n;
+
+ ASSERT(mp->b_datap->db_ref > 0);
+ ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
+
+ /*
+ * We won't handle Multidata message, since it contains
+ * metadata which this function has no knowledge of; we
+ * assert on DEBUG, and return failure otherwise.
+ */
+ ASSERT(mp->b_datap->db_type != M_MULTIDATA);
+ if (mp->b_datap->db_type == M_MULTIDATA)
+ return (0);
+
+ if (len == -1) {
+ if (mp->b_cont == NULL && str_aligned(mp->b_rptr))
+ return (1);
+ len = xmsgsize(mp);
+ } else {
+ ssize_t first_mblk_len = mp->b_wptr - mp->b_rptr;
+ ASSERT(first_mblk_len >= 0);
+ /*
+ * If the length is less than that of the first mblk,
+ * we want to pull up the message into an aligned mblk.
+ * Though not part of the spec, some callers assume it.
+ */
+ if (len <= first_mblk_len) {
+ if (str_aligned(mp->b_rptr))
+ return (1);
+ len = first_mblk_len;
+ } else if (xmsgsize(mp) < len)
+ return (0);
+ }
+
+ if ((bp = allocb_tmpl(len, mp)) == NULL)
+ return (0);
+
+ dbp = bp->b_datap;
+ *bp = *mp; /* swap mblks so bp heads the old msg... */
+ mp->b_datap = dbp; /* ... and mp heads the new message */
+ mp->b_datap->db_mblk = mp;
+ bp->b_datap->db_mblk = bp;
+ mp->b_rptr = mp->b_wptr = dbp->db_base;
+
+ do {
+ ASSERT(bp->b_datap->db_ref > 0);
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+ n = MIN(bp->b_wptr - bp->b_rptr, len);
+ ASSERT(n >= 0); /* allow zero-length mblk_t's */
+ if (n > 0)
+ bcopy(bp->b_rptr, mp->b_wptr, (size_t)n);
+ mp->b_wptr += n;
+ bp->b_rptr += n;
+ len -= n;
+ if (bp->b_rptr != bp->b_wptr)
+ break;
+ b_cont = bp->b_cont;
+ freeb(bp);
+ bp = b_cont;
+ } while (len && bp);
+
+ mp->b_cont = bp; /* tack on whatever wasn't pulled up */
+
+ return (1);
+}
+
+/*
+ * Concatenate and align at least the first len bytes of common message
+ * type. Len == -1 means concatenate everything. The original message is
+ * unaltered. Returns a pointer to a new message on success, otherwise
+ * returns NULL.
+ */
+mblk_t *
+msgpullup(mblk_t *mp, ssize_t len)
+{
+ mblk_t *newmp;
+ ssize_t totlen;
+ ssize_t n;
+
+ /*
+ * We won't handle Multidata message, since it contains
+ * metadata which this function has no knowledge of; we
+ * assert on DEBUG, and return failure otherwise.
+ */
+ ASSERT(mp->b_datap->db_type != M_MULTIDATA);
+ if (mp->b_datap->db_type == M_MULTIDATA)
+ return (NULL);
+
+ totlen = xmsgsize(mp);
+
+ if ((len > 0) && (len > totlen))
+ return (NULL);
+
+ /*
+ * Copy all of the first msg type into one new mblk, then dupmsg
+ * and link the rest onto this.
+ */
+
+ len = totlen;
+
+ if ((newmp = allocb_tmpl(len, mp)) == NULL)
+ return (NULL);
+
+ newmp->b_flag = mp->b_flag;
+ newmp->b_band = mp->b_band;
+
+ while (len > 0) {
+ n = mp->b_wptr - mp->b_rptr;
+ ASSERT(n >= 0); /* allow zero-length mblk_t's */
+ if (n > 0)
+ bcopy(mp->b_rptr, newmp->b_wptr, n);
+ newmp->b_wptr += n;
+ len -= n;
+ mp = mp->b_cont;
+ }
+
+ if (mp != NULL) {
+ newmp->b_cont = dupmsg(mp);
+ if (newmp->b_cont == NULL) {
+ freemsg(newmp);
+ return (NULL);
+ }
+ }
+
+ return (newmp);
+}
+
+/*
+ * Trim bytes from message
+ * len > 0, trim from head
+ * len < 0, trim from tail
+ * Returns 1 on success, 0 on failure.
+ */
+int
+adjmsg(mblk_t *mp, ssize_t len)
+{
+ mblk_t *bp;
+ mblk_t *save_bp = NULL;
+ mblk_t *prev_bp;
+ mblk_t *bcont;
+ unsigned char type;
+ ssize_t n;
+ int fromhead;
+ int first;
+
+ ASSERT(mp != NULL);
+ /*
+ * We won't handle Multidata message, since it contains
+ * metadata which this function has no knowledge of; we
+ * assert on DEBUG, and return failure otherwise.
+ */
+ ASSERT(mp->b_datap->db_type != M_MULTIDATA);
+ if (mp->b_datap->db_type == M_MULTIDATA)
+ return (0);
+
+ if (len < 0) {
+ fromhead = 0;
+ len = -len;
+ } else {
+ fromhead = 1;
+ }
+
+ if (xmsgsize(mp) < len)
+ return (0);
+
+ if (fromhead) {
+ first = 1;
+ while (len) {
+ ASSERT(mp->b_wptr >= mp->b_rptr);
+ n = MIN(mp->b_wptr - mp->b_rptr, len);
+ mp->b_rptr += n;
+ len -= n;
+
+ /*
+ * If this is not the first zero length
+ * message remove it
+ */
+ if (!first && (mp->b_wptr == mp->b_rptr)) {
+ bcont = mp->b_cont;
+ freeb(mp);
+ mp = save_bp->b_cont = bcont;
+ } else {
+ save_bp = mp;
+ mp = mp->b_cont;
+ }
+ first = 0;
+ }
+ } else {
+ type = mp->b_datap->db_type;
+ while (len) {
+ bp = mp;
+ save_bp = NULL;
+
+ /*
+ * Find the last message of same type
+ */
+ while (bp && bp->b_datap->db_type == type) {
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+ prev_bp = save_bp;
+ save_bp = bp;
+ bp = bp->b_cont;
+ }
+ if (save_bp == NULL)
+ break;
+ n = MIN(save_bp->b_wptr - save_bp->b_rptr, len);
+ save_bp->b_wptr -= n;
+ len -= n;
+
+ /*
+ * If this is not the first message
+ * and we have taken away everything
+ * from this message, remove it
+ */
+
+ if ((save_bp != mp) &&
+ (save_bp->b_wptr == save_bp->b_rptr)) {
+ bcont = save_bp->b_cont;
+ freeb(save_bp);
+ prev_bp->b_cont = bcont;
+ }
+ }
+ }
+ return (1);
+}
+
+/*
+ * get number of data bytes in message
+ */
+size_t
+msgdsize(mblk_t *bp)
+{
+ size_t count = 0;
+
+ for (; bp; bp = bp->b_cont)
+ if (bp->b_datap->db_type == M_DATA) {
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+ count += bp->b_wptr - bp->b_rptr;
+ }
+ return (count);
+}
+
+/* getq() etc to EOF removed */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_strsubr.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_strsubr.c
new file mode 100644
index 0000000000..e49313c37c
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_strsubr.c
@@ -0,0 +1,160 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <sys/atomic.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/cmn_err.h>
+
+#include <sys/strft.h>
+
+int str_ftnever = 0;
+
+static void mblk_free(mblk_t *);
+static void esballoc_mblk_free(mblk_t *);
+
+/*
+ * A few things from os/strsubr.c
+ */
+
+int
+strwaitbuf(size_t size, int pri)
+{
+ return (0);
+}
+
+/*
+ * Return size of message of block type (bp->b_datap->db_type)
+ */
+size_t
+xmsgsize(mblk_t *bp)
+{
+ unsigned char type;
+ size_t count = 0;
+
+ type = bp->b_datap->db_type;
+
+ for (; bp; bp = bp->b_cont) {
+ if (type != bp->b_datap->db_type)
+ break;
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+ count += bp->b_wptr - bp->b_rptr;
+ }
+ return (count);
+}
+
+/* ARGSUSED */
+bufcall_id_t
+bufcall(size_t size, uint_t pri, void (*func)(void *), void *arg)
+{
+ cmn_err(CE_NOTE, "bufcall() called!");
+ return ("fake bufcall id");
+}
+
+/* ARGSUSED */
+void
+unbufcall(bufcall_id_t id)
+{
+}
+
+/* ARGSUSED */
+void
+freebs_enqueue(mblk_t *mp, dblk_t *dbp)
+{
+ /*
+ * Won't bother with esb_queue_t async free here.
+ * Rather just free this mblk directly.
+ */
+ esballoc_mblk_free(mp);
+}
+
+static void
+esballoc_mblk_free(mblk_t *mp)
+{
+ mblk_t *nextmp;
+
+ for (; mp != NULL; mp = nextmp) {
+ nextmp = mp->b_next;
+ mp->b_next = NULL;
+ mblk_free(mp);
+ }
+}
+
+static void
+mblk_free(mblk_t *mp)
+{
+ dblk_t *dbp = mp->b_datap;
+ frtn_t *frp = dbp->db_frtnp;
+
+ mp->b_next = NULL;
+ if (dbp->db_fthdr != NULL)
+ str_ftfree(dbp);
+
+ ASSERT(dbp->db_fthdr == NULL);
+ frp->free_func(frp->free_arg);
+ ASSERT(dbp->db_mblk == mp);
+
+ if (dbp->db_credp != NULL) {
+ crfree(dbp->db_credp);
+ dbp->db_credp = NULL;
+ }
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+
+ kmem_cache_free(dbp->db_cache, dbp);
+}
+
+/* ARGSUSED */
+mblk_t *
+mmd_copy(mblk_t *bp, int flags)
+{
+ return (NULL);
+}
+
+/*
+ * A little bit from os/streamio.c
+ */
+
+static volatile uint32_t ioc_id;
+
+int
+getiocseqno(void)
+{
+ uint32_t i;
+
+ i = atomic_inc_32_nv(&ioc_id);
+
+ return ((int)i);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_xti.h b/usr/src/lib/smbclnt/libfknsmb/common/fake_xti.h
new file mode 100644
index 0000000000..d58b5454c4
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_xti.h
@@ -0,0 +1,314 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ */
+/* Copyright (c) 1996 Sun Microsystems, Inc. */
+/* All Rights Reserved */
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _XTI_H
+#define _XTI_H
+
+#include <sys/types.h>
+
+/*
+ * The following include file has declarations needed by both the kernel
+ * level transport providers and the user level library. This file includes
+ * it to expose its namespaces to XTI user level interface.
+ */
+#include <sys/tpicommon.h>
+
+/*
+ * Include XTI interface level options management declarations
+ */
+#include <sys/xti_xtiopt.h>
+
+#if !defined(_XPG5)
+
+/*
+ * Include declarations related to OSI transport and management data
+ * structures, and the Internet Protocol Suite.
+ * Note: The older Unix95/XNS4 XTI spec required these to be
+ * exposed through the generic interface header.
+ */
+#include <sys/xti_osi.h>
+#include <sys/xti_inet.h>
+
+#endif /* !defined(_XPG5) */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The following t_errno error codes are included in the namespace by
+ * inclusion of <sys/tpicommon.h> above. The english language error strings
+ * associated with the error values are reproduced here for easy reference.
+ *
+ * Error Value Error message string
+ * ---- ----- --------------------
+ * TBADADDR 1 Incorrect address format
+ * TBADOPT 2 Incorrect options format
+ * TACCES 3 Illegal permissions
+ * TBADF 4 Illegal file descriptor
+ * TNOADDR 5 Couldn't allocate address
+ * TOUTSTATE 6 Routine will place interface out of state
+ * TBADSEQ 7 Illegal called/calling sequence number
+ * TSYSERR 8 System error
+ * TLOOK 9 An event requires attention
+ * TBADDATA 10 Illegal amount of data
+ * TBUFOVFLW 11 Buffer not large enough
+ * TFLOW 12 Can't send message - (blocked)
+ * TNODATA 13 No message currently available
+ * TNODIS 14 Disconnect message not found
+ * TNOUDERR 15 Unitdata error message not found
+ * TBADFLAG 16 Incorrect flags specified
+ * TNOREL 17 Orderly release message not found
+ * TNOTSUPPORT 18 Primitive not supported by provider
+ * TSTATECHNG 19 State is in process of changing
+ * TNOSTRUCTYPE 20 Unsupported structure type requested
+ * TBADNAME 21 Invalid transport provider name
+ * TBADQLEN 22 Listener queue length limit is zero
+ * TADDRBUSY 23 Transport address is in use
+ * TINDOUT 24 Outstanding connection indications
+ * TPROVMISMATCH 25 Listener-acceptor transport provider mismatch
+ * TRESQLEN 26 Connection acceptor has listen queue length
+ * limit greater than zero
+ * TRESADDR 27 Connection acceptor-listener addresses not
+ * same but required by transport
+ * TQFULL 28 Incoming connection queue is full
+ * TPROTO 29 Protocol error on transport primitive
+ *
+ */
+
+/*
+ * The following are the events returned by t_look
+ */
+#define T_LISTEN 0x0001 /* connection indication received */
+#define T_CONNECT 0x0002 /* connect confirmation received */
+#define T_DATA 0x0004 /* normal data received */
+#define T_EXDATA 0x0008 /* expedited data received */
+#define T_DISCONNECT 0x0010 /* disconnect received */
+#define T_UDERR 0x0040 /* data gram error indication */
+#define T_ORDREL 0x0080 /* orderly release indication */
+#define T_GODATA 0x0100 /* sending normal data is again possible */
+#define T_GOEXDATA 0x0200 /* sending expedited data is again possible */
+
+/*
+ * Flags for data primitives
+ */
+#define T_MORE 0x001 /* more data */
+#define T_EXPEDITED 0x002 /* expedited data */
+#define T_PUSH 0x004 /* send data immediately */
+
+/*
+ * XTI error return
+ */
+#if defined(_REENTRANT) || defined(_TS_ERRNO)
+extern int *__t_errno();
+#define t_errno (*(__t_errno()))
+#else
+#error "extern int t_errno?"
+#endif /* defined(_REENTRANT) || defined(_TS_ERRNO) */
+
+
+/*
+ * The following are for t_sysconf()
+ */
+#ifndef T_IOV_MAX
+#define T_IOV_MAX 16 /* Maximum number of scatter/gather buffers */
+#endif /* Should be <= IOV_MAX */
+
+#ifndef _SC_T_IOV_MAX
+#define _SC_T_IOV_MAX 79 /* Should be same in <unistd.h> for use by */
+#endif /* sysconf() */
+
+struct t_iovec {
+ void *iov_base;
+ size_t iov_len;
+};
+
+/*
+ * Translate source level interface to binary entry point names.
+ *
+ * Note: This is done to maintain co-existence of TLI and XTI
+ * interfaces which have identical names for most functions but
+ * different semantics. The XTI names are moved to the different
+ * prefix space in the ABI. The #ifdef is required to make use of
+ * of the compiler feature to allow redefinition of external names
+ * where available. Otherwise a simple #define is used when this
+ * header is used with other compilers.
+ * The use of #define also has the effect of renaming all names (not
+ * just function names) to the new name. The TLI function names
+ * (e.g. t_bind) can have identical names for structure names
+ * (e.g struct t_bind). Therefore, this redefinition of names needs
+ * to be before all structure and function name declarations in the header.
+ */
+
+#ifdef __PRAGMA_REDEFINE_EXTNAME
+
+#if defined(_XOPEN_SOURCE) && !defined(_XPG5)
+#pragma redefine_extname t_accept _xti_accept
+#else
+#pragma redefine_extname t_accept _xti_xns5_accept
+#endif
+#pragma redefine_extname t_alloc _xti_alloc
+#pragma redefine_extname t_bind _xti_bind
+#pragma redefine_extname t_close _xti_close
+#pragma redefine_extname t_connect _xti_connect
+#pragma redefine_extname t_error _xti_error
+#pragma redefine_extname t_free _xti_free
+#pragma redefine_extname t_getinfo _xti_getinfo
+#pragma redefine_extname t_getstate _xti_getstate
+#pragma redefine_extname t_getprotaddr _xti_getprotaddr
+#pragma redefine_extname t_listen _xti_listen
+#pragma redefine_extname t_look _xti_look
+#pragma redefine_extname t_open _xti_open
+#pragma redefine_extname t_optmgmt _xti_optmgmt
+#pragma redefine_extname t_rcv _xti_rcv
+#pragma redefine_extname t_rcvconnect _xti_rcvconnect
+#pragma redefine_extname t_rcvdis _xti_rcvdis
+#pragma redefine_extname t_rcvrel _xti_rcvrel
+#pragma redefine_extname t_rcvreldata _xti_rcvreldata
+#pragma redefine_extname t_rcvudata _xti_rcvudata
+#pragma redefine_extname t_rcvuderr _xti_rcvuderr
+#pragma redefine_extname t_rcvv _xti_rcvv
+#pragma redefine_extname t_rcvvudata _xti_rcvvudata
+#if defined(_XOPEN_SOURCE) && !defined(_XPG5)
+#pragma redefine_extname t_snd _xti_snd
+#else
+#pragma redefine_extname t_snd _xti_xns5_snd
+#endif
+#pragma redefine_extname t_snddis _xti_snddis
+#pragma redefine_extname t_sndrel _xti_sndrel
+#pragma redefine_extname t_sndreldata _xti_sndreldata
+#pragma redefine_extname t_sndudata _xti_sndudata
+#pragma redefine_extname t_sndv _xti_sndv
+#pragma redefine_extname t_sndvudata _xti_sndvudata
+#pragma redefine_extname t_strerror _xti_strerror
+#pragma redefine_extname t_sync _xti_sync
+#pragma redefine_extname t_sysconf _xti_sysconf
+#pragma redefine_extname t_unbind _xti_unbind
+
+#else /* __PRAGMA_REDEFINE_EXTNAME */
+
+#if defined(_XOPEN_SOURCE) && !defined(_XPG5)
+#define t_accept _xti_accept
+#else
+#define t_accept _xti_xns5_accept
+#endif
+#define t_alloc _xti_alloc
+#define t_bind(a,b,c) _xti_bind(a,b,c)
+#define t_close _xti_close
+#define t_connect _xti_connect
+#define t_error _xti_error
+#define t_free _xti_free
+#define t_getinfo _xti_getinfo
+#define t_getstate _xti_getstate
+#define t_getprotaddr _xti_getprotaddr
+#define t_listen _xti_listen
+#define t_look _xti_look
+#define t_open _xti_open
+#define t_optmgmt(a,b,c) _xti_optmgmt(a,b,c)
+#define t_rcv _xti_rcv
+#define t_rcvconnect _xti_rcvconnect
+#define t_rcvdis _xti_rcvdis
+#define t_rcvrel _xti_rcvrel
+#define t_rcvreldata _xti_rcvreldata
+#define t_rcvudata _xti_rcvudata
+#define t_rcvuderr _xti_rcvuderr
+#define t_rcvv _xti_rcvv
+#define t_rcvvudata _xti_rcvvudata
+#if defined(_XOPEN_SOURCE) && !defined(_XPG5)
+#define t_snd _xti_snd
+#else
+#define t_snd _xti_xns5_snd
+#endif
+#define t_snddis _xti_snddis
+#define t_sndrel _xti_sndrel
+#define t_sndreldata _xti_sndreldata
+#define t_sndudata _xti_sndudata
+#define t_sndv _xti_sndv
+#define t_sndvudata _xti_sndvudata
+#define t_strerror _xti_strerror
+#define t_sync _xti_sync
+#define t_sysconf _xti_sysconf
+#define t_unbind _xti_unbind
+
+#endif /* __PRAGMA_REDEFINE_EXTNAME */
+
+/*
+ * All the rest of the standard xti.h removed because the structs:
+ * netbuf, t_info, t_opthdr, t_optmgmt, t_bind, t_call, ...
+ * all conflict with definitions in tiuser.h which we need
+ * for the (simulated) kernel interfaces in fake_ktli.c.
+ *
+ * The XTI library functions below would normally be defined by
+ * including tiuser.h after the defines above, which we can't.
+ */
+
+int _xti_accept(int, int, struct t_call *);
+int _xti_xns5_accept(int, int, struct t_call *);
+char *_xti_alloc(int, int, int);
+int _xti_bind(int, struct t_bind *, struct t_bind *);
+int _xti_close(int);
+int _xti_connect(int, struct t_call *, struct t_call *);
+int _xti_error(char *);
+int _xti_free(char *, int);
+int _xti_getinfo(int, struct t_info *);
+int _xti_getprotaddr(int, struct t_bind *, struct t_bind *);
+int _xti_getstate(int);
+int _xti_listen(int, struct t_call *);
+int _xti_look(int);
+int _xti_open(char *, int, struct t_info *);
+int _xti_optmgmt(int, struct t_optmgmt *, struct t_optmgmt *);
+int _xti_rcv(int, char *, unsigned int, int *);
+int _xti_rcvconnect(int, struct t_call *);
+int _xti_rcvdis(int, struct t_discon *);
+int _xti_rcvrel(int);
+int _xti_rcvreldata(int, struct t_discon *);
+int _xti_rcvudata(int, struct t_unitdata *, int *);
+int _xti_rcvuderr(int, struct t_uderr *);
+int _xti_rcvv(int, struct t_iovec *, unsigned int, int *);
+int _xti_rcvvudata(int, struct t_unitdata *, struct t_iovec *,
+ unsigned int, int *);
+int _xti_snd(int, char *, unsigned int, int);
+int _xti_xns5_snd(int, char *, unsigned int, int);
+int _xti_snddis(int, struct t_call *);
+int _xti_sndrel(int);
+int _xti_sndreldata(int, struct t_discon *);
+int _xti_sndudata(int, struct t_unitdata *);
+int _xti_sndv(int, const struct t_iovec *, unsigned int, int);
+int _xti_sndvudata(int, struct t_unitdata *, struct t_iovec *, unsigned int);
+char *_xti_strerror(int);
+int _xti_sync(int);
+int _xti_sysconf(int);
+int _xti_unbind(int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _XTI_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c b/usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
new file mode 100644
index 0000000000..24bb8fccbc
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
@@ -0,0 +1,163 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Helper functions for SMB signing using PKCS#11
+ *
+ * There are two implementations of these functions:
+ * This one (for user space) and another for kernel.
+ * See: uts/common/fs/smbclnt/netsmb/smb_sign_kcf.c
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <netsmb/smb_signing.h>
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+
+/*
+ * SMB1 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb_md5_getmech(smb_sign_mech_t *mech)
+{
+ mech->mechanism = CKM_MD5;
+ mech->pParameter = NULL;
+ mech->ulParameterLen = 0;
+ return (0);
+}
+
+/*
+ * Start PKCS#11 session.
+ */
+int
+smb_md5_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech)
+{
+ CK_RV rv;
+
+ rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
+ if (rv != CKR_OK)
+ return (-1);
+
+ rv = C_DigestInit(*ctxp, mech);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len)
+{
+ CK_RV rv;
+
+ rv = C_DigestUpdate(ctx, buf, len);
+ if (rv != CKR_OK)
+ (void) C_CloseSession(ctx);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * Get the final digest.
+ */
+int
+smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16)
+{
+ CK_ULONG len = MD5_DIGEST_LENGTH;
+ CK_RV rv;
+
+ rv = C_DigestFinal(ctx, digest16, &len);
+ (void) C_CloseSession(ctx);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * SMB2 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb2_hmac_getmech(smb_sign_mech_t *mech)
+{
+ mech->mechanism = CKM_SHA256_HMAC;
+ mech->pParameter = NULL;
+ mech->ulParameterLen = 0;
+ return (0);
+}
+
+/*
+ * Start PKCS#11 session, load the key.
+ */
+int
+smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech,
+ uint8_t *key, size_t key_len)
+{
+ CK_OBJECT_HANDLE hkey = 0;
+ CK_RV rv;
+
+ rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
+ if (rv != CKR_OK)
+ return (-1);
+
+ rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism,
+ key, key_len, &hkey);
+ if (rv != CKR_OK)
+ return (-1);
+
+ rv = C_SignInit(*ctxp, mech, hkey);
+ (void) C_DestroyObject(*ctxp, hkey);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb2_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
+{
+ CK_RV rv;
+
+ rv = C_SignUpdate(ctx, in, len);
+ if (rv != CKR_OK)
+ (void) C_CloseSession(ctx);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * Note, the SMB2 signature is the first 16 bytes of the
+ * 32-byte SHA256 HMAC digest.
+ */
+int
+smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16)
+{
+ uint8_t full_digest[SHA256_DIGEST_LENGTH];
+ CK_ULONG len = SHA256_DIGEST_LENGTH;
+ CK_RV rv;
+
+ rv = C_SignFinal(ctx, full_digest, &len);
+ if (rv == CKR_OK)
+ bcopy(full_digest, digest16, 16);
+
+ (void) C_CloseSession(ctx);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/libfknsmb.h b/usr/src/lib/smbclnt/libfknsmb/common/libfknsmb.h
new file mode 100644
index 0000000000..b3d15510be
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/libfknsmb.h
@@ -0,0 +1,45 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _LIBFKNSMB_H_
+#define _LIBFKNSMB_H_
+
+#include <sys/types.h>
+#include <sys/types32.h>
+#include <sys/cred.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct smb_share;
+
+extern const uint32_t nsmb_version;
+extern void streams_msg_init(void);
+
+int nsmb_drv_init(void);
+int nsmb_drv_fini(void);
+/* These are dev32_t because they're cast to int in user code. */
+int nsmb_drv_ioctl(dev32_t dev, int cmd, intptr_t arg, int flags);
+int nsmb_drv_open(dev32_t *dev, int flags, int otyp);
+int nsmb_drv_close(dev32_t dev, int flags, int otyp);
+int smb_dev2share(int fd, struct smb_share **sspp);
+void nsmb_drv_load(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBFKNSMB_H_ */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/llib-lfknsmb b/usr/src/lib/smbclnt/libfknsmb/common/llib-lfknsmb
new file mode 100644
index 0000000000..8ba9f62607
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/llib-lfknsmb
@@ -0,0 +1,19 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <libfknsmb.h>
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers b/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers
new file mode 100644
index 0000000000..27fbd87b4d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers
@@ -0,0 +1,134 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ global:
+ kmem_avail;
+ kmem_maxavail;
+
+ nsmb_drv_close;
+ nsmb_drv_fini;
+ nsmb_drv_init;
+ nsmb_drv_ioctl;
+ nsmb_drv_load;
+ nsmb_drv_open;
+
+ nsmb_version;
+
+ m_fixhdr;
+ mb_done;
+ mb_init;
+ mb_initm;
+ mb_put_mbchain;
+ mb_put_mbuf;
+ mb_put_mem;
+ mb_put_padbyte;
+ mb_put_uint16le;
+ mb_put_uint32le;
+ mb_put_uint64le;
+ mb_put_uint8;
+ mb_put_uio;
+ mb_reserve;
+
+ md_done;
+ md_get_mbuf;
+ md_get_mem;
+ md_get_uint16le;
+ md_get_uint32le;
+ md_get_uint64le;
+ md_get_uint8;
+ md_initm;
+
+ secpolicy_fs_allowed_mount;
+ secpolicy_vnode_access2;
+ secpolicy_vnode_owner;
+ secpolicy_vnode_setattr;
+ secpolicy_vnode_setdac;
+
+ smb_credinit;
+ smb_credrele;
+ smb_debugmsg { FLAGS = NODIRECT };
+ smb_dev2share;
+ smb_errmsg { FLAGS = NODIRECT };
+ smb_fh_close;
+ smb_fh_create;
+ smb_fh_hold;
+ smb_fh_opened;
+ smb_fh_rele;
+ smb_get_dstring;
+ smb_nt_alloc;
+ smb_nt_done;
+ smb_nt_request;
+ smb_put_dmem;
+ smb_rq_alloc;
+ smb_rq_bend;
+ smb_rq_bstart;
+ smb_rq_done;
+ smb_rq_init;
+ smb_rq_simple;
+ smb_rq_simple_timed;
+ smb_rq_wend;
+ smb_rq_wstart;
+ smb_rwuio;
+ smb_share_kill;
+ smb_share_rele;
+ smb_smb_close;
+ smb_smb_ntcreate;
+ smb_t2_alloc;
+ smb_t2_done;
+ smb_t2_request;
+ smb_time_NT2local;
+ smb_time_local2NT;
+ smb_time_local2server;
+ smb_time_server2local;
+ smb_timo_append;
+ smb_timo_open;
+ smb_timo_read;
+ smb_timo_write;
+
+ smb2_rq_simple;
+ smb2_rq_simple_timed;
+ smb2_smb_close;
+ smb2_smb_ntcreate;
+
+ local:
+ *;
+};
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/ftrace.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/ftrace.h
new file mode 100644
index 0000000000..68979ca9d4
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/ftrace.h
@@ -0,0 +1,67 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_FTRACE_H
+#define _SYS_FTRACE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Constants used by both asm and non-asm code.
+ */
+
+/*
+ * Flags determining the state of tracing -
+ * both for the "ftrace_state" variable, and for the per-CPU variable
+ * "cpu[N]->cpu_ftrace_state".
+ */
+#define FTRACE_READY 0x00000001
+#define FTRACE_ENABLED 0x00000002
+
+#include <sys/types.h>
+#include <sys/sdt.h>
+
+/*
+ * The record of a single event.
+ * ftrace_record_t;
+ */
+
+#define FTRACE_0(fmt) \
+ DTRACE_PROBE1(ftrace0, char *, fmt)
+#define FTRACE_1(fmt, d1) \
+ DTRACE_PROBE2(ftrace1, char *, fmt, uintptr_t, d1)
+
+// #define FTRACE_START() ftrace_start()
+// #define FTRACE_STOP() ftrace_stop()
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FTRACE_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/kidmap.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/kidmap.h
new file mode 100644
index 0000000000..64a48897c3
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/kidmap.h
@@ -0,0 +1,183 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Windows to Solaris Identity Mapping kernel API
+ * This header defines an API to map Windows SIDs to
+ * Solaris UID and GIDs and versa visa.
+ */
+
+#ifndef _SYS_KIDMAP_H
+#define _SYS_KIDMAP_H
+
+#include <sys/idmap.h>
+#include <sys/door.h>
+#include <sys/zone.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The ifdef's for these two accomodate duplicate definitions in
+ * lib/libidmap/common/idmap.h (the real one). In this code we
+ * simulate a kernel environment in user space using the real
+ * idmap library, so need to be able to use both headers.
+ */
+
+/* Return status */
+#ifndef _IDMAP_STAT_TYPE
+#define _IDMAP_STAT_TYPE
+typedef int32_t idmap_stat;
+#endif /* _IDMAP_STAT_TYPE */
+
+/* Opaque get handle */
+#ifndef _IDMAP_GET_HANDLE_T
+#define _IDMAP_GET_HANDLE_T
+typedef struct idmap_get_handle idmap_get_handle_t;
+#endif /* _IDMAP_GET_HANDLE_T */
+
+/*
+ * In all the routines a Windows SID is handled as a
+ * string SID prefix plus a RID. For example
+ *
+ * S-1-5-5-12-34-568 will be passed as SID prefix
+ * S-1-5-5-12-34 and RID 568
+ *
+ * Certain routines returns pointers to a SID prefix string.
+ * These strings are stored internally and should not be modified
+ * or freed.
+ */
+
+
+/*
+ * The following routines are simple get ID mapping routines.
+ */
+
+
+idmap_stat
+kidmap_getuidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
+ uid_t *uid);
+
+idmap_stat
+kidmap_getgidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
+ gid_t *gid);
+
+idmap_stat
+kidmap_getpidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
+ uid_t *pid, int *is_user);
+
+idmap_stat
+kidmap_getsidbyuid(zone_t *zone, uid_t uid, const char **sid_prefix,
+ uint32_t *rid);
+
+idmap_stat
+kidmap_getsidbygid(zone_t *zone, gid_t gid, const char **sid_prefix,
+ uint32_t *rid);
+
+
+
+/*
+ * The following routines provide a batch interface for mapping IDs.
+ */
+
+/*
+ * Create a batch "get mapping" handle for batch mappings.
+ */
+idmap_get_handle_t *
+kidmap_get_create(zone_t *zone);
+
+/*
+ * These routines queue the request to the "get mapping" handle
+ */
+
+idmap_stat
+kidmap_batch_getuidbysid(idmap_get_handle_t *get_handle,
+ const char *sid_prefix, uint32_t rid,
+ uid_t *uid, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getgidbysid(idmap_get_handle_t *get_handle,
+ const char *sid_prefix, uint32_t rid,
+ gid_t *gid, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getpidbysid(idmap_get_handle_t *get_handle,
+ const char *sid_prefix, uint32_t rid,
+ uid_t *pid, int *is_user, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getsidbyuid(idmap_get_handle_t *get_handle, uid_t uid,
+ const char **sid_prefix, uint32_t *rid, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getsidbygid(idmap_get_handle_t *get_handle, gid_t gid,
+ const char **sid_prefix, uint32_t *rid, idmap_stat *stat);
+
+/*
+ * Process the queued "get mapping" requests. The results (i.e.
+ * status and identity) will be available in the data areas
+ * provided by individual requests.
+ */
+idmap_stat
+kidmap_get_mappings(idmap_get_handle_t *get_handle);
+
+/*
+ * Destroy the "get mapping" handle
+ */
+void
+kidmap_get_destroy(idmap_get_handle_t *get_handle);
+
+#ifdef _KERNEL
+/*
+ * Functions that do the hard part of door registration/unregistration
+ * for the idmap_reg()/idmap_unreg() syscalls
+ */
+int idmap_reg_dh(zone_t *zone, door_handle_t dh);
+int idmap_unreg_dh(zone_t *zone, door_handle_t dh);
+
+/*
+ * Function needed by allocids() to ensure only the daemon that owns
+ * the door gets ephemeral IDS
+ */
+door_handle_t idmap_get_door(zone_t *zone);
+
+/*
+ * Function used by system call allocids() to purge the
+ * ID mapping cache
+ */
+void idmap_purge_cache(zone_t *zone);
+
+#endif /* _KERNEL */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_KIDMAP_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/policy.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/policy.h
new file mode 100644
index 0000000000..7ca0d9c3fa
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/policy.h
@@ -0,0 +1,50 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_POLICY_H
+#define _SYS_POLICY_H
+
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/fs/snode.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int secpolicy_fs_allowed_mount(const char *);
+int secpolicy_vnode_owner(const cred_t *, uid_t);
+int secpolicy_vnode_access2(const cred_t *, vnode_t *, uid_t, mode_t, mode_t);
+int secpolicy_vnode_setattr(cred_t *, struct vnode *, struct vattr *,
+ const struct vattr *, int, int (void *, int, cred_t *), void *);
+int secpolicy_vnode_setdac(const cred_t *, uid_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_POLICY_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/sdt.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/sdt.h
new file mode 100644
index 0000000000..c79ea68cec
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/sdt.h
@@ -0,0 +1,70 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_SDT_H
+#define _SYS_SDT_H
+
+#include <sys/stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * DTrace SDT probes have different signatures in userland than they do in
+ * kernel. If we're compiling for user mode (libfksmbsrv) define them as
+ * either no-op (for the SMB dtrace provider) or libfksmbsrv functions for
+ * the other SDT probe sites.
+ */
+#ifndef _KERNEL
+
+extern void smb_dtrace1(const char *, long);
+extern void smb_dtrace2(const char *, long, long);
+extern void smb_dtrace3(const char *, long, long, long);
+
+/*
+ * These are for the few (specialized) dtrace SDT probes sprinkled
+ * through the smbclnt code. In libfknsmb map these to functions.
+ */
+
+#undef DTRACE_PROBE1
+#define DTRACE_PROBE1(n, t1, a1) \
+ smb_dtrace1(#n, (long)a1)
+
+#undef DTRACE_PROBE2
+#define DTRACE_PROBE2(n, t1, a1, t2, a2) \
+ smb_dtrace2(#n, (long)a1, (long)a2)
+
+#undef DTRACE_PROBE3
+#define DTRACE_PROBE3(n, t1, a1, t2, a2, t3, a3) \
+ smb_dtrace3(#n, (long)a1, (long)a2, (long)a3)
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _SYS_SDT_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/strft.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/strft.h
new file mode 100644
index 0000000000..a293118e9d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/strft.h
@@ -0,0 +1,65 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_STRFT_H
+#define _SYS_STRFT_H
+
+#include <sys/sdt.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define FTEV_ALLOCB 0x0000
+#define FTEV_ESBALLOC 0x0001
+#define FTEV_DESBALLOC 0x0002
+#define FTEV_ESBALLOCA 0x0003
+#define FTEV_DESBALLOCA 0x0004
+#define FTEV_ALLOCBIG 0x0005
+#define FTEV_ALLOCBW 0x0006
+#define FTEV_BCALLOCB 0x0007
+#define FTEV_FREEB 0x0008
+#define FTEV_DUPB 0x0009
+#define FTEV_COPYB 0x000A
+
+#define STR_FTALLOC(hpp, e, d) \
+ DTRACE_PROBE3(str__ftalloc, void *, hpp, ushort_t, e, ushort_t, d)
+
+/* Skip the 2nd arg (p) which is: caller() */
+#define STR_FTEVENT_MBLK(mp, p, e, d) \
+ DTRACE_PROBE3(str__ftevent, void *, mp, ushort_t, e, ushort_t, d)
+
+#define str_ftfree(dbp) ((void)(dbp))
+
+extern int str_ftnever, str_ftstack;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_STRFT_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/sunddi.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/sunddi.h
new file mode 100644
index 0000000000..f901e79566
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/sunddi.h
@@ -0,0 +1,141 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_SUNDDI_H
+#define _SYS_SUNDDI_H
+
+/*
+ * Sun Specific DDI definitions (fakekernel version)
+ * The real sunddi.h has become a "kitchen sink" full of
+ * includes we don't want, and lots of places include it.
+ * Rather than fight that battle now, provide this one
+ * with just the str*, mem*, and kiconv* functions.
+ * Some day, re-factor: sunddi.h, systm.h
+ */
+
+#include <sys/isa_defs.h>
+#include <sys/dditypes.h>
+#include <sys/time.h>
+#include <sys/cmn_err.h>
+
+#include <sys/kmem.h>
+#include <sys/nvpair.h>
+#include <sys/thread.h>
+#include <sys/stream.h>
+
+#include <sys/u8_textprep.h>
+#include <sys/kiconv.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DDI_SUCCESS (0) /* successful return */
+#define DDI_FAILURE (-1) /* unsuccessful return */
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+extern char *ddi_strdup(const char *str, int flag);
+extern char *strdup(const char *str);
+extern void strfree(char *str);
+
+extern size_t strlen(const char *) __PURE;
+extern size_t strnlen(const char *, size_t) __PURE;
+extern char *strcpy(char *, const char *);
+extern char *strncpy(char *, const char *, size_t);
+
+/* Need to be consistent with <string.h> C++ definition for strchr() */
+#if __cplusplus >= 199711L
+extern const char *strchr(const char *, int);
+#else
+extern char *strchr(const char *, int);
+#endif /* __cplusplus >= 199711L */
+
+#define DDI_STRSAME(s1, s2) ((*(s1) == *(s2)) && (strcmp((s1), (s2)) == 0))
+extern int strcmp(const char *, const char *) __PURE;
+extern int strncmp(const char *, const char *, size_t) __PURE;
+extern char *strncat(char *, const char *, size_t);
+extern size_t strlcat(char *, const char *, size_t);
+extern size_t strlcpy(char *, const char *, size_t);
+extern size_t strspn(const char *, const char *);
+extern size_t strcspn(const char *, const char *);
+extern int bcmp(const void *, const void *, size_t) __PURE;
+extern int stoi(char **);
+extern void numtos(ulong_t, char *);
+extern void bcopy(const void *, void *, size_t);
+extern void bzero(void *, size_t);
+
+extern void *memcpy(void *, const void *, size_t);
+extern void *memset(void *, int, size_t);
+extern void *memmove(void *, const void *, size_t);
+extern int memcmp(const void *, const void *, size_t) __PURE;
+
+/* Need to be consistent with <string.h> C++ definition for memchr() */
+#if __cplusplus >= 199711L
+extern const void *memchr(const void *, int, size_t);
+#else
+extern void *memchr(const void *, int, size_t);
+#endif /* __cplusplus >= 199711L */
+
+extern int ddi_strtol(const char *, char **, int, long *);
+extern int ddi_strtoul(const char *, char **, int, unsigned long *);
+extern int ddi_strtoll(const char *, char **, int, longlong_t *);
+extern int ddi_strtoull(const char *, char **, int, u_longlong_t *);
+
+extern int ddi_copyin(const void *, void *, size_t, int);
+extern int ddi_copyout(const void *, void *, size_t, int);
+
+/*
+ * kiconv functions and their macros.
+ */
+#define KICONV_IGNORE_NULL (0x0001)
+#define KICONV_REPLACE_INVALID (0x0002)
+
+extern kiconv_t kiconv_open(const char *, const char *);
+extern size_t kiconv(kiconv_t, char **, size_t *, char **, size_t *, int *);
+extern int kiconv_close(kiconv_t);
+extern size_t kiconvstr(const char *, const char *, char *, size_t *, char *,
+ size_t *, int, int *);
+
+int
+ddi_soft_state_init(void **state_p, size_t size, size_t n_items);
+int
+ddi_soft_state_zalloc(void *state, int item);
+void *
+ddi_get_soft_state(void *state, int item);
+void
+ddi_soft_state_free(void *state, int item);
+void
+ddi_soft_state_fini(void **state_p);
+
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SUNDDI_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs.h
new file mode 100644
index 0000000000..9906f94a12
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs.h
@@ -0,0 +1,622 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Toomas Soome <tsoome@me.com>
+ * Copyright (c) 2016, 2017 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#ifndef _SYS_VFS_H
+#define _SYS_VFS_H
+
+#include <sys/zone.h>
+#include <sys/types.h>
+#include <sys/t_lock.h>
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/statvfs.h>
+#include <sys/refstr.h>
+#include <sys/avl.h>
+#include <sys/time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Data associated with mounted file systems.
+ */
+
+/*
+ * Operations vector. This is used internal to the kernel; file systems
+ * supply their list of operations via vfs_setfsops().
+ */
+
+typedef struct vfsops vfsops_t;
+
+/*
+ * File system identifier. Should be unique (at least per machine).
+ */
+typedef struct {
+ int val[2]; /* file system id type */
+} fsid_t;
+
+/*
+ * File identifier. Should be unique per filesystem on a single
+ * machine. This is typically called by a stateless file server
+ * in order to generate "file handles".
+ *
+ * Many underlying file systems cast a struct fid into other
+ * file system dependent structures which may require 4 byte alignment.
+ * Because a fid starts with a short it may not be 4 byte aligned, the
+ * fid_pad will force the alignment.
+ */
+#define MAXFIDSZ 64
+#define OLD_MAXFIDSZ 16
+
+typedef struct fid {
+ union {
+ long fid_pad;
+ struct {
+ ushort_t len; /* length of data in bytes */
+ char data[MAXFIDSZ]; /* data (variable len) */
+ } _fid;
+ } un;
+} fid_t;
+
+#ifdef _SYSCALL32
+/*
+ * Solaris 64 - use old-style cache format with 32-bit aligned fid for on-disk
+ * struct compatibility.
+ */
+typedef struct fid32 {
+ union {
+ int32_t fid_pad;
+ struct {
+ uint16_t len; /* length of data in bytes */
+ char data[MAXFIDSZ]; /* data (variable len) */
+ } _fid;
+ } un;
+} fid32_t;
+#else /* not _SYSCALL32 */
+#define fid32 fid
+typedef fid_t fid32_t;
+#endif /* _SYSCALL32 */
+
+#define fid_len un._fid.len
+#define fid_data un._fid.data
+
+/*
+ * Structure defining a mount option for a filesystem.
+ * option names are found in mntent.h
+ */
+typedef struct mntopt {
+ char *mo_name; /* option name */
+ char **mo_cancel; /* list of options cancelled by this one */
+ char *mo_arg; /* argument string for this option */
+ int mo_flags; /* flags for this mount option */
+ void *mo_data; /* filesystem specific data */
+} mntopt_t;
+
+/*
+ * Flags that apply to mount options
+ */
+
+#define MO_SET 0x01 /* option is set */
+#define MO_NODISPLAY 0x02 /* option not listed in mnttab */
+#define MO_HASVALUE 0x04 /* option takes a value */
+#define MO_IGNORE 0x08 /* option ignored by parser */
+#define MO_DEFAULT MO_SET /* option is on by default */
+#define MO_TAG 0x10 /* flags a tag set by user program */
+#define MO_EMPTY 0x20 /* empty space in option table */
+
+#define VFS_NOFORCEOPT 0x01 /* honor MO_IGNORE (don't set option) */
+#define VFS_DISPLAY 0x02 /* Turn off MO_NODISPLAY bit for opt */
+#define VFS_NODISPLAY 0x04 /* Turn on MO_NODISPLAY bit for opt */
+#define VFS_CREATEOPT 0x08 /* Create the opt if it's not there */
+
+/*
+ * Structure holding mount option strings for the mounted file system.
+ */
+typedef struct mntopts {
+ uint_t mo_count; /* number of entries in table */
+ mntopt_t *mo_list; /* list of mount options */
+} mntopts_t;
+
+/*
+ * The kstat structures associated with the vopstats are kept in an
+ * AVL tree. This is to avoid the case where a file system does not
+ * use a unique fsid_t for each vfs (e.g., namefs). In order to do
+ * this, we need a structure that the AVL tree can use that also
+ * references the kstat.
+ * Note that the vks_fsid is generated from the value reported by
+ * VFS_STATVFS().
+ */
+typedef struct vskstat_anchor vsk_anchor_t;
+
+extern avl_tree_t vskstat_tree;
+extern kmutex_t vskstat_tree_lock;
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+/*
+ * Structure per mounted file system. Each mounted file system has
+ * an array of operations and an instance record.
+ *
+ * The file systems are kept on a doubly linked circular list headed by
+ * "rootvfs".
+ * File system implementations should not access this list;
+ * it's intended for use only in the kernel's vfs layer.
+ *
+ * Each zone also has its own list of mounts, containing filesystems mounted
+ * somewhere within the filesystem tree rooted at the zone's rootpath. The
+ * list is doubly linked to match the global list.
+ *
+ * mnttab locking: the in-kernel mnttab uses the vfs_mntpt, vfs_resource and
+ * vfs_mntopts fields in the vfs_t. mntpt and resource are refstr_ts that
+ * are set at mount time and can only be modified during a remount.
+ * It is safe to read these fields if you can prevent a remount on the vfs,
+ * or through the convenience funcs vfs_getmntpoint() and vfs_getresource().
+ * The mntopts field may only be accessed through the provided convenience
+ * functions, as it is protected by the vfs list lock. Modifying a mount
+ * option requires grabbing the vfs list write lock, which can be a very
+ * high latency lock.
+ */
+struct zone; /* from zone.h */
+struct fem_head; /* from fem.h */
+
+typedef struct vfs {
+ struct vfs *vfs_next; /* next VFS in VFS list */
+ struct vfs *vfs_prev; /* prev VFS in VFS list */
+
+/* vfs_op should not be used directly. Accessor functions are provided */
+ vfsops_t *vfs_op; /* operations on VFS */
+
+ struct vnode *vfs_vnodecovered; /* vnode mounted on */
+ uint_t vfs_flag; /* flags */
+ uint_t vfs_bsize; /* native block size */
+ int vfs_fstype; /* file system type index */
+ fsid_t vfs_fsid; /* file system id */
+ void *vfs_data; /* private data */
+ dev_t vfs_dev; /* device of mounted VFS */
+ ulong_t vfs_bcount; /* I/O count (accounting) */
+ struct vfs *vfs_list; /* sync list pointer */
+ struct vfs *vfs_hash; /* hash list pointer */
+ ksema_t vfs_reflock; /* mount/unmount/sync lock */
+ uint_t vfs_count; /* vfs reference count */
+ mntopts_t vfs_mntopts; /* options mounted with */
+ refstr_t *vfs_resource; /* mounted resource name */
+ refstr_t *vfs_mntpt; /* mount point name */
+ time_t vfs_mtime; /* time we were mounted */
+ struct vfs_impl *vfs_implp; /* impl specific data */
+ /*
+ * Zones support. Note that the zone that "owns" the mount isn't
+ * necessarily the same as the zone in which the zone is visible.
+ * That is, vfs_zone and (vfs_zone_next|vfs_zone_prev) may refer to
+ * different zones.
+ */
+ struct zone *vfs_zone; /* zone that owns the mount */
+ struct vfs *vfs_zone_next; /* next VFS visible in zone */
+ struct vfs *vfs_zone_prev; /* prev VFS visible in zone */
+
+ struct fem_head *vfs_femhead; /* fs monitoring */
+ uint32_t vfs_lofi_id; /* ID if lofi mount */
+} vfs_t;
+
+#define vfs_featureset vfs_implp->vi_featureset
+#define vfs_vskap vfs_implp->vi_vskap
+#define vfs_fstypevsp vfs_implp->vi_fstypevsp
+#define vfs_vopstats vfs_implp->vi_vopstats
+#define vfs_hrctime vfs_implp->vi_hrctime
+
+#else // defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+typedef struct vfs vfs_t;
+
+#endif // defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * VFS flags.
+ */
+#define VFS_RDONLY 0x01 /* read-only vfs */
+#define VFS_NOMNTTAB 0x02 /* vfs not seen in mnttab */
+#define VFS_NOSETUID 0x08 /* setuid disallowed */
+#define VFS_REMOUNT 0x10 /* modify mount options only */
+#define VFS_NOTRUNC 0x20 /* does not truncate long file names */
+#define VFS_UNLINKABLE 0x40 /* unlink(2) can be applied to root */
+#define VFS_PXFS 0x80 /* clustering: global fs proxy vfs */
+#define VFS_UNMOUNTED 0x100 /* file system has been unmounted */
+#define VFS_NBMAND 0x200 /* allow non-blocking mandatory locks */
+#define VFS_XATTR 0x400 /* fs supports extended attributes */
+#define VFS_NODEVICES 0x800 /* device-special files disallowed */
+#define VFS_NOEXEC 0x1000 /* executables disallowed */
+#define VFS_STATS 0x2000 /* file system can collect stats */
+#define VFS_XID 0x4000 /* file system supports extended ids */
+
+#define VFS_NORESOURCE "unspecified_resource"
+#define VFS_NOMNTPT "unspecified_mountpoint"
+
+/*
+ * VFS features are implemented as bits set in the vfs_t.
+ * The vfs_feature_t typedef is a 64-bit number that will translate
+ * into an element in an array of bitmaps and a bit in that element.
+ * Developers must not depend on the implementation of this and
+ * need to use vfs_has_feature()/vfs_set_feature() routines.
+ */
+typedef uint64_t vfs_feature_t;
+
+#define VFSFT_XVATTR 0x100000001 /* Supports xvattr for attrs */
+#define VFSFT_CASEINSENSITIVE 0x100000002 /* Supports case-insensitive */
+#define VFSFT_NOCASESENSITIVE 0x100000004 /* NOT case-sensitive */
+#define VFSFT_DIRENTFLAGS 0x100000008 /* Supports dirent flags */
+#define VFSFT_ACLONCREATE 0x100000010 /* Supports ACL on create */
+#define VFSFT_ACEMASKONACCESS 0x100000020 /* Can use ACEMASK for access */
+#define VFSFT_SYSATTR_VIEWS 0x100000040 /* Supports sysattr view i/f */
+#define VFSFT_ACCESS_FILTER 0x100000080 /* dirents filtered by access */
+#define VFSFT_REPARSE 0x100000100 /* Supports reparse point */
+#define VFSFT_ZEROCOPY_SUPPORTED 0x100000200
+ /* Support loaning /returning cache buffer */
+/*
+ * Argument structure for mount(2).
+ *
+ * Flags are defined in <sys/mount.h>.
+ *
+ * Note that if the MS_SYSSPACE bit is set in flags, the pointer fields in
+ * this structure are to be interpreted as kernel addresses. File systems
+ * should be prepared for this possibility.
+ */
+struct mounta {
+ char *spec;
+ char *dir;
+ int flags;
+ char *fstype;
+ char *dataptr;
+ int datalen;
+ char *optptr;
+ int optlen;
+};
+
+/*
+ * Reasons for calling the vfs_mountroot() operation.
+ */
+enum whymountroot { ROOT_INIT, ROOT_REMOUNT, ROOT_UNMOUNT};
+typedef enum whymountroot whymountroot_t;
+
+/*
+ * Reasons for calling the VFS_VNSTATE():
+ */
+enum vntrans {
+ VNTRANS_EXISTS,
+ VNTRANS_IDLED,
+ VNTRANS_RECLAIMED,
+ VNTRANS_DESTROYED
+};
+typedef enum vntrans vntrans_t;
+
+/*
+ * VFS_OPS defines all the vfs operations. It is used to define
+ * the vfsops structure (below) and the fs_func_p union (vfs_opreg.h).
+ */
+#define VFS_OPS \
+ int (*vfs_mount)(vfs_t *, vnode_t *, struct mounta *, cred_t *); \
+ int (*vfs_unmount)(vfs_t *, int, cred_t *); \
+ int (*vfs_root)(vfs_t *, vnode_t **); \
+ int (*vfs_statvfs)(vfs_t *, statvfs64_t *); \
+ int (*vfs_sync)(vfs_t *, short, cred_t *); \
+ int (*vfs_vget)(vfs_t *, vnode_t **, fid_t *); \
+ int (*vfs_mountroot)(vfs_t *, enum whymountroot); \
+ void (*vfs_freevfs)(vfs_t *); \
+ int (*vfs_vnstate)(vfs_t *, vnode_t *, vntrans_t) /* NB: No ";" */
+
+/*
+ * Operations supported on virtual file system.
+ */
+struct vfsops {
+ VFS_OPS; /* Signature of all vfs operations (vfsops) */
+};
+
+extern int fsop_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
+extern int fsop_unmount(vfs_t *, int, cred_t *);
+extern int fsop_root(vfs_t *, vnode_t **);
+extern int fsop_statfs(vfs_t *, statvfs64_t *);
+extern int fsop_sync(vfs_t *, short, cred_t *);
+extern int fsop_vget(vfs_t *, vnode_t **, fid_t *);
+extern int fsop_mountroot(vfs_t *, enum whymountroot);
+extern void fsop_freefs(vfs_t *);
+extern int fsop_sync_by_kind(int, short, cred_t *);
+extern int fsop_vnstate(vfs_t *, vnode_t *, vntrans_t);
+
+#define VFS_MOUNT(vfsp, mvp, uap, cr) fsop_mount(vfsp, mvp, uap, cr)
+#define VFS_UNMOUNT(vfsp, flag, cr) fsop_unmount(vfsp, flag, cr)
+#define VFS_ROOT(vfsp, vpp) fsop_root(vfsp, vpp)
+#define VFS_STATVFS(vfsp, sp) fsop_statfs(vfsp, sp)
+#define VFS_SYNC(vfsp, flag, cr) fsop_sync(vfsp, flag, cr)
+#define VFS_VGET(vfsp, vpp, fidp) fsop_vget(vfsp, vpp, fidp)
+#define VFS_MOUNTROOT(vfsp, init) fsop_mountroot(vfsp, init)
+#define VFS_FREEVFS(vfsp) fsop_freefs(vfsp)
+#define VFS_VNSTATE(vfsp, vn, ns) fsop_vnstate(vfsp, vn, ns)
+
+#define VFSNAME_MOUNT "mount"
+#define VFSNAME_UNMOUNT "unmount"
+#define VFSNAME_ROOT "root"
+#define VFSNAME_STATVFS "statvfs"
+#define VFSNAME_SYNC "sync"
+#define VFSNAME_VGET "vget"
+#define VFSNAME_MOUNTROOT "mountroot"
+#define VFSNAME_FREEVFS "freevfs"
+#define VFSNAME_VNSTATE "vnstate"
+/*
+ * Filesystem type switch table.
+ */
+
+typedef struct vfssw {
+ char *vsw_name; /* type name -- max len _ST_FSTYPSZ */
+ int (*vsw_init) (int, char *);
+ /* init routine (for non-loadable fs only) */
+ int vsw_flag; /* flags */
+ mntopts_t vsw_optproto; /* mount options table prototype */
+ uint_t vsw_count; /* count of references */
+ kmutex_t vsw_lock; /* lock to protect vsw_count */
+ vfsops_t vsw_vfsops; /* filesystem operations vector */
+} vfssw_t;
+
+/*
+ * Filesystem type definition record. All file systems must export a record
+ * of this type through their modlfs structure. N.B., changing the version
+ * number requires a change in sys/modctl.h.
+ */
+
+typedef struct vfsdef_v5 {
+ int def_version; /* structure version, must be first */
+ char *name; /* filesystem type name */
+ int (*init) (int, char *); /* init routine */
+ int flags; /* filesystem flags */
+ mntopts_t *optproto; /* mount options table prototype */
+} vfsdef_v5;
+
+typedef struct vfsdef_v5 vfsdef_t;
+
+enum {
+ VFSDEF_VERSION = 5
+};
+
+/* Specific to libfksmbfs */
+int fake_installfs(vfsdef_t *);
+int fake_removefs(vfsdef_t *);
+
+/*
+ * flags for vfssw and vfsdef
+ */
+#define VSW_HASPROTO 0x01 /* struct has a mount options prototype */
+#define VSW_CANRWRO 0x02 /* file system can transition from rw to ro */
+#define VSW_CANREMOUNT 0x04 /* file system supports remounts */
+#define VSW_NOTZONESAFE 0x08 /* zone_enter(2) should fail for these files */
+#define VSW_VOLATILEDEV 0x10 /* vfs_dev can change each time fs is mounted */
+#define VSW_STATS 0x20 /* file system can collect stats */
+#define VSW_XID 0x40 /* file system supports extended ids */
+#define VSW_CANLOFI 0x80 /* file system supports lofi mounts */
+#define VSW_ZMOUNT 0x100 /* file system always allowed in a zone */
+#define VSW_MOUNTDEV 0x200 /* file system is mounted via device path */
+
+#define VSW_INSTALLED 0x8000 /* this vsw is associated with a file system */
+
+/*
+ * A flag for vfs_setpath().
+ */
+#define VFSSP_VERBATIM 0x1 /* do not prefix the supplied path */
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * Private vfs data, NOT to be used by a file system implementation.
+ */
+
+#define VFS_FEATURE_MAXSZ 4
+
+typedef struct vfs_impl {
+ /* Counted array - Bitmap of vfs features */
+ uint32_t vi_featureset[VFS_FEATURE_MAXSZ];
+ /*
+ * Support for statistics on the vnode operations
+ */
+ vsk_anchor_t *vi_vskap; /* anchor for vopstats' kstat */
+ vopstats_t *vi_fstypevsp; /* ptr to per-fstype vopstats */
+ vopstats_t vi_vopstats; /* per-mount vnode op stats */
+
+ timespec_t vi_hrctime; /* High-res creation time */
+
+ zone_ref_t vi_zone_ref; /* reference to zone */
+} vfs_impl_t;
+
+/*
+ * Public operations.
+ */
+struct umounta;
+struct statvfsa;
+struct fstatvfsa;
+
+void vfs_freevfsops(vfsops_t *);
+int vfs_freevfsops_by_type(int);
+void vfs_setops(vfs_t *, vfsops_t *);
+vfsops_t *vfs_getops(vfs_t *vfsp);
+int vfs_matchops(vfs_t *, vfsops_t *);
+int vfs_can_sync(vfs_t *vfsp);
+vfs_t *vfs_alloc(int);
+void vfs_free(vfs_t *);
+void vfs_init(vfs_t *vfsp, vfsops_t *, void *);
+void vfsimpl_setup(vfs_t *vfsp);
+void vfsimpl_teardown(vfs_t *vfsp);
+void vn_exists(vnode_t *);
+void vn_idle(vnode_t *);
+void vn_reclaim(vnode_t *);
+void vn_invalid(vnode_t *);
+
+int rootconf(void);
+int domount(char *, struct mounta *, vnode_t *, struct cred *,
+ struct vfs **);
+int dounmount(struct vfs *, int, cred_t *);
+int vfs_lock(struct vfs *);
+int vfs_rlock(struct vfs *);
+void vfs_lock_wait(struct vfs *);
+void vfs_rlock_wait(struct vfs *);
+void vfs_unlock(struct vfs *);
+int vfs_lock_held(struct vfs *);
+struct _kthread *vfs_lock_owner(struct vfs *);
+void sync(void);
+void vfs_sync(int);
+void vfs_mountroot(void);
+void vfs_add(vnode_t *, struct vfs *, int);
+void vfs_remove(struct vfs *);
+
+/* VFS feature routines */
+void vfs_set_feature(vfs_t *, vfs_feature_t);
+void vfs_clear_feature(vfs_t *, vfs_feature_t);
+int vfs_has_feature(vfs_t *, vfs_feature_t);
+void vfs_propagate_features(vfs_t *, vfs_t *);
+
+/* The following functions are not for general use by filesystems */
+
+void vfs_createopttbl(mntopts_t *, const char *);
+void vfs_copyopttbl(const mntopts_t *, mntopts_t *);
+void vfs_mergeopttbl(const mntopts_t *, const mntopts_t *, mntopts_t *);
+void vfs_freeopttbl(mntopts_t *);
+void vfs_parsemntopts(mntopts_t *, char *, int);
+int vfs_buildoptionstr(const mntopts_t *, char *, int);
+struct mntopt *vfs_hasopt(const mntopts_t *, const char *);
+void vfs_mnttab_modtimeupd(void);
+
+void vfs_clearmntopt(struct vfs *, const char *);
+void vfs_setmntopt(struct vfs *, const char *, const char *, int);
+void vfs_setresource(struct vfs *, const char *, uint32_t);
+void vfs_setmntpoint(struct vfs *, const char *, uint32_t);
+refstr_t *vfs_getresource(const struct vfs *);
+refstr_t *vfs_getmntpoint(const struct vfs *);
+int vfs_optionisset(const struct vfs *, const char *, char **);
+int vfs_settag(uint_t, uint_t, const char *, const char *, cred_t *);
+int vfs_clrtag(uint_t, uint_t, const char *, const char *, cred_t *);
+void vfs_syncall(void);
+void vfsinit(void);
+void vfs_unmountall(void);
+void vfs_make_fsid(fsid_t *, dev_t, int);
+void vfs_addmip(dev_t, struct vfs *);
+void vfs_delmip(struct vfs *);
+int vfs_devismounted(dev_t);
+int vfs_devmounting(dev_t, struct vfs *);
+int vfs_opsinuse(vfsops_t *);
+struct vfs *getvfs(fsid_t *);
+struct vfs *vfs_dev2vfsp(dev_t);
+struct vfs *vfs_mntpoint2vfsp(const char *);
+struct vfssw *allocate_vfssw(const char *);
+struct vfssw *vfs_getvfssw(const char *);
+struct vfssw *vfs_getvfsswbyname(const char *);
+struct vfssw *vfs_getvfsswbyvfsops(vfsops_t *);
+void vfs_refvfssw(struct vfssw *);
+void vfs_unrefvfssw(struct vfssw *);
+uint_t vf_to_stf(uint_t);
+void vfs_mnttab_modtime(timespec_t *);
+void vfs_mnttab_poll(timespec_t *, struct pollhead **);
+
+void vfs_list_lock(void);
+void vfs_list_read_lock(void);
+void vfs_list_unlock(void);
+void vfs_list_add(struct vfs *);
+void vfs_list_remove(struct vfs *);
+void vfs_hold(vfs_t *vfsp);
+void vfs_rele(vfs_t *vfsp);
+void fs_freevfs(vfs_t *);
+void vfs_root_redev(vfs_t *vfsp, dev_t ndev, int fstype);
+
+int vfs_zone_change_safe(vfs_t *);
+
+int vfs_get_lofi(vfs_t *, vnode_t **);
+
+#define VFSHASH(maj, min) (((int)((maj)+(min))) & (vfshsz - 1))
+#define VFS_ON_LIST(vfsp) \
+ ((vfsp)->vfs_next != (vfsp) && (vfsp)->vfs_next != NULL)
+
+/*
+ * Globals.
+ */
+
+extern struct vfssw vfssw[]; /* table of filesystem types */
+extern krwlock_t vfssw_lock;
+extern char rootfstype[]; /* name of root fstype */
+extern const int nfstype; /* # of elements in vfssw array */
+extern vfsops_t *EIO_vfsops; /* operations for vfs being torn-down */
+
+/*
+ * The following variables are private to the the kernel's vfs layer. File
+ * system implementations should not access them.
+ */
+extern struct vfs *rootvfs; /* ptr to root vfs structure */
+typedef struct {
+ struct vfs *rvfs_head; /* head vfs in chain */
+ kmutex_t rvfs_lock; /* mutex protecting this chain */
+ uint32_t rvfs_len; /* length of this chain */
+} rvfs_t;
+extern rvfs_t *rvfs_list;
+extern int vfshsz; /* # of elements in rvfs_head array */
+extern const mntopts_t vfs_mntopts; /* globally recognized options */
+
+#endif /* defined(_KERNEL) */
+
+#define VFS_HOLD(vfsp) { \
+ vfs_hold(vfsp); \
+}
+
+#define VFS_RELE(vfsp) { \
+ vfs_rele(vfsp); \
+}
+
+#define VFS_INIT(vfsp, op, data) { \
+ vfs_init((vfsp), (op), (data)); \
+}
+
+
+#define VFS_INSTALLED(vfsswp) (((vfsswp)->vsw_flag & VSW_INSTALLED) != 0)
+#define ALLOCATED_VFSSW(vswp) ((vswp)->vsw_name[0] != '\0')
+#define RLOCK_VFSSW() (rw_enter(&vfssw_lock, RW_READER))
+#define RUNLOCK_VFSSW() (rw_exit(&vfssw_lock))
+#define WLOCK_VFSSW() (rw_enter(&vfssw_lock, RW_WRITER))
+#define WUNLOCK_VFSSW() (rw_exit(&vfssw_lock))
+#define VFSSW_LOCKED() (RW_LOCK_HELD(&vfssw_lock))
+#define VFSSW_WRITE_LOCKED() (RW_WRITE_HELD(&vfssw_lock))
+/*
+ * VFS_SYNC flags.
+ */
+#define SYNC_ATTR 0x01 /* sync attributes only */
+#define SYNC_CLOSE 0x02 /* close open file */
+#define SYNC_ALL 0x04 /* force to sync all fs */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VFS_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs_opreg.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs_opreg.h
new file mode 100644
index 0000000000..cdb6c9c6c5
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs_opreg.h
@@ -0,0 +1,116 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_VFS_OPREG_H
+#define _SYS_VFS_OPREG_H
+
+#include <sys/vfs.h>
+#include <sys/fem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * The following union allows us to use C99's "designated initializer"
+ * feature so that we can have strong typechecking for the operations
+ * used in the the fs_operation_def structures.
+ */
+
+typedef union fs_func {
+ fs_generic_func_p fs_generic; /* Generic function signature */
+ int (*error)(); /* Signature of error function */
+ VFS_OPS; /* Signatures of all vfs operations (vfsops) */
+ VNODE_OPS; /* Signatures of all vnode operations (vops) */
+ FEM_OPS; /* Signatures of all FEM operations (femops) */
+ FSEM_OPS; /* Signatures of all FSEM ops (fsemops) */
+} fs_func_p;
+
+/*
+ * File systems use arrays of fs_operation_def structures to form
+ * name/value pairs of operations. These arrays get passed to:
+ *
+ * - vn_make_ops() to create vnodeops
+ * - vfs_makefsops()/vfs_setfsops() to create vfsops.
+ */
+typedef struct fs_operation_def {
+ char *name; /* name of operation (NULL at end) */
+ fs_func_p func; /* function implementing operation */
+} fs_operation_def_t;
+
+/*
+ * The operation registration mechanism uses two master tables of operations:
+ * one for vnode operations (vn_ops_table[]) and one for vfs operations
+ * (vfs_ops_table[]). These tables are arrays of fs_operation_trans_def
+ * structures. They contain all of the information necessary for the system
+ * to populate an operations structure (e.g., vnodeops, vfsops).
+ *
+ * File systems call registration routines (vfs_setfsops(), vfs_makefsops(),
+ * and vn_make_ops()) and pass in their operations specification tables
+ * (arrays of fs_operation_def structures). These routines use the master
+ * table(s) of operations to build a vnodeops or vfsops structure.
+ */
+typedef struct fs_operation_trans_def {
+ char *name; /* name of operation (NULL at end) */
+ int offset; /* byte offset within ops vector */
+ fs_generic_func_p defaultFunc; /* default function */
+ fs_generic_func_p errorFunc; /* error function */
+} fs_operation_trans_def_t;
+
+/*
+ * Generic operations vector types (used for vfs/vnode ops registration).
+ */
+
+extern int fs_default(); /* "default" function placeholder */
+extern int fs_error(); /* "error" function placeholder */
+
+int fs_build_vector(void *vector, int *unused_ops,
+ const fs_operation_trans_def_t *translation,
+ const fs_operation_def_t *operations);
+
+/*
+ * Public operations.
+ */
+
+int vn_make_ops(const char *, const struct fs_operation_def *,
+ vnodeops_t **);
+void vn_freevnodeops(vnodeops_t *);
+
+int vfs_setfsops(int, const fs_operation_def_t *, vfsops_t **);
+int vfs_makefsops(const fs_operation_def_t *, vfsops_t **);
+void vfs_freevfsops(vfsops_t *);
+int vfs_freevfsops_by_type(int);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VFS_OPREG_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/vnode.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/vnode.h
new file mode 100644
index 0000000000..33e84e68f2
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/vnode.h
@@ -0,0 +1,1452 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#ifndef _SYS_VNODE_H
+#define _SYS_VNODE_H
+
+#include <sys/types.h>
+#include <sys/t_lock.h>
+#include <sys/time_impl.h>
+#include <sys/cred.h>
+#include <sys/uio.h>
+#include <sys/resource.h>
+#include <vm/seg_enum.h>
+#include <sys/kstat.h>
+#include <sys/kmem.h>
+#include <sys/list.h>
+#include <sys/avl.h>
+#ifdef _KERNEL
+#include <sys/rwstlock.h>
+#include <sys/buf.h>
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * Statistics for all vnode operations.
+ * All operations record number of ops (since boot/mount/zero'ed).
+ * Certain I/O operations (read, write, readdir) also record number
+ * of bytes transferred.
+ * This appears in two places in the system: one is embedded in each
+ * vfs_t. There is also an array of vopstats_t structures allocated
+ * on a per-fstype basis.
+ */
+
+#define VOPSTATS_STR "vopstats_" /* Initial string for vopstat kstats */
+
+typedef struct vopstats {
+ kstat_named_t nopen; /* VOP_OPEN */
+ kstat_named_t nclose; /* VOP_CLOSE */
+ kstat_named_t nread; /* VOP_READ */
+ kstat_named_t read_bytes;
+ kstat_named_t nwrite; /* VOP_WRITE */
+ kstat_named_t write_bytes;
+ kstat_named_t nioctl; /* VOP_IOCTL */
+ kstat_named_t nsetfl; /* VOP_SETFL */
+ kstat_named_t ngetattr; /* VOP_GETATTR */
+ kstat_named_t nsetattr; /* VOP_SETATTR */
+ kstat_named_t naccess; /* VOP_ACCESS */
+ kstat_named_t nlookup; /* VOP_LOOKUP */
+ kstat_named_t ncreate; /* VOP_CREATE */
+ kstat_named_t nremove; /* VOP_REMOVE */
+ kstat_named_t nlink; /* VOP_LINK */
+ kstat_named_t nrename; /* VOP_RENAME */
+ kstat_named_t nmkdir; /* VOP_MKDIR */
+ kstat_named_t nrmdir; /* VOP_RMDIR */
+ kstat_named_t nreaddir; /* VOP_READDIR */
+ kstat_named_t readdir_bytes;
+ kstat_named_t nsymlink; /* VOP_SYMLINK */
+ kstat_named_t nreadlink; /* VOP_READLINK */
+ kstat_named_t nfsync; /* VOP_FSYNC */
+ kstat_named_t ninactive; /* VOP_INACTIVE */
+ kstat_named_t nfid; /* VOP_FID */
+ kstat_named_t nrwlock; /* VOP_RWLOCK */
+ kstat_named_t nrwunlock; /* VOP_RWUNLOCK */
+ kstat_named_t nseek; /* VOP_SEEK */
+ kstat_named_t ncmp; /* VOP_CMP */
+ kstat_named_t nfrlock; /* VOP_FRLOCK */
+ kstat_named_t nspace; /* VOP_SPACE */
+ kstat_named_t nrealvp; /* VOP_REALVP */
+ kstat_named_t ngetpage; /* VOP_GETPAGE */
+ kstat_named_t nputpage; /* VOP_PUTPAGE */
+ kstat_named_t nmap; /* VOP_MAP */
+ kstat_named_t naddmap; /* VOP_ADDMAP */
+ kstat_named_t ndelmap; /* VOP_DELMAP */
+ kstat_named_t npoll; /* VOP_POLL */
+ kstat_named_t ndump; /* VOP_DUMP */
+ kstat_named_t npathconf; /* VOP_PATHCONF */
+ kstat_named_t npageio; /* VOP_PAGEIO */
+ kstat_named_t ndumpctl; /* VOP_DUMPCTL */
+ kstat_named_t ndispose; /* VOP_DISPOSE */
+ kstat_named_t nsetsecattr; /* VOP_SETSECATTR */
+ kstat_named_t ngetsecattr; /* VOP_GETSECATTR */
+ kstat_named_t nshrlock; /* VOP_SHRLOCK */
+ kstat_named_t nvnevent; /* VOP_VNEVENT */
+ kstat_named_t nreqzcbuf; /* VOP_REQZCBUF */
+ kstat_named_t nretzcbuf; /* VOP_RETZCBUF */
+} vopstats_t;
+#endif // defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * The vnode is the focus of all file activity in UNIX.
+ * A vnode is allocated for each active file, each current
+ * directory, each mounted-on file, and the root.
+ *
+ * Each vnode is usually associated with a file-system-specific node (for
+ * UFS, this is the in-memory inode). Generally, a vnode and an fs-node
+ * should be created and destroyed together as a pair.
+ *
+ * If a vnode is reused for a new file, it should be reinitialized by calling
+ * either vn_reinit() or vn_recycle().
+ *
+ * vn_reinit() resets the entire vnode as if it was returned by vn_alloc().
+ * The caller is responsible for setting up the entire vnode after calling
+ * vn_reinit(). This is important when using kmem caching where the vnode is
+ * allocated by a constructor, for instance.
+ *
+ * vn_recycle() is used when the file system keeps some state around in both
+ * the vnode and the associated FS-node. In UFS, for example, the inode of
+ * a deleted file can be reused immediately. The v_data, v_vfsp, v_op, etc.
+ * remains the same but certain fields related to the previous instance need
+ * to be reset. In particular:
+ * v_femhead
+ * v_path
+ * v_rdcnt, v_wrcnt
+ * v_mmap_read, v_mmap_write
+ */
+
+/*
+ * vnode types. VNON means no type. These values are unrelated to
+ * values in on-disk inodes.
+ */
+typedef enum vtype {
+ VNON = 0,
+ VREG = 1,
+ VDIR = 2,
+ VBLK = 3,
+ VCHR = 4,
+ VLNK = 5,
+ VFIFO = 6,
+ VDOOR = 7,
+ VPROC = 8,
+ VSOCK = 9,
+ VPORT = 10,
+ VBAD = 11
+} vtype_t;
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * VSD - Vnode Specific Data
+ * Used to associate additional private data with a vnode.
+ */
+struct vsd_node {
+ list_node_t vs_nodes; /* list of all VSD nodes */
+ uint_t vs_nkeys; /* entries in value array */
+ void **vs_value; /* array of value/key */
+};
+
+/*
+ * Many of the fields in the vnode are read-only once they are initialized
+ * at vnode creation time. Other fields are protected by locks.
+ *
+ * IMPORTANT: vnodes should be created ONLY by calls to vn_alloc(). They
+ * may not be embedded into the file-system specific node (inode). The
+ * size of vnodes may change.
+ *
+ * The v_lock protects:
+ * v_flag
+ * v_stream
+ * v_count
+ * v_shrlocks
+ * v_path
+ * v_vsd
+ * v_xattrdir
+ *
+ * A special lock (implemented by vn_vfswlock in vnode.c) protects:
+ * v_vfsmountedhere
+ *
+ * The global flock_lock mutex (in flock.c) protects:
+ * v_filocks
+ *
+ * IMPORTANT NOTE:
+ *
+ * The following vnode fields are considered public and may safely be
+ * accessed by file systems or other consumers:
+ *
+ * v_lock
+ * v_flag
+ * v_count
+ * v_data
+ * v_vfsp
+ * v_stream
+ * v_type
+ * v_rdev
+ *
+ * ALL OTHER FIELDS SHOULD BE ACCESSED ONLY BY THE OWNER OF THAT FIELD.
+ * In particular, file systems should not access other fields; they may
+ * change or even be removed. The functionality which was once provided
+ * by these fields is available through vn_* functions.
+ */
+
+struct fem_head; /* from fem.h */
+
+typedef struct vnode {
+ kmutex_t v_lock; /* protects vnode fields */
+ uint_t v_flag; /* vnode flags (see below) */
+ uint_t v_count; /* reference count */
+ void *v_data; /* private data for fs */
+ struct vfs *v_vfsp; /* ptr to containing VFS */
+ struct stdata *v_stream; /* associated stream */
+ enum vtype v_type; /* vnode type */
+ dev_t v_rdev; /* device (VCHR, VBLK) */
+
+ /* PRIVATE FIELDS BELOW - DO NOT USE */
+
+ struct vfs *v_vfsmountedhere; /* ptr to vfs mounted here */
+ struct vnodeops *v_op; /* vnode operations */
+ krwlock_t v_nbllock; /* sync for NBMAND locks */
+ char *v_path; /* cached path */
+ uint_t v_rdcnt; /* open for read count (VREG only) */
+ uint_t v_wrcnt; /* open for write count (VREG only) */
+ struct vnode *v_xattrdir; /* unnamed extended attr dir (GFS) */
+
+ /* Private to the fake vnode impl. */
+
+ int v_fd;
+ dev_t v_st_dev;
+ ino_t v_st_ino;
+ avl_node_t v_avl_node;
+ int v_vfsrlocks;
+} vnode_t;
+
+#define IS_DEVVP(vp) \
+ ((vp)->v_type == VCHR || (vp)->v_type == VBLK || (vp)->v_type == VFIFO)
+
+#define VNODE_ALIGN 16
+
+/*
+ * vnode flags.
+ */
+#define VROOT 0x01 /* root of its file system */
+#define VNOCACHE 0x02 /* don't keep cache pages on vnode */
+#define VNOMAP 0x04 /* file cannot be mapped/faulted */
+#define VDUP 0x08 /* file should be dup'ed rather then opened */
+#define VNOSWAP 0x10 /* file cannot be used as virtual swap device */
+#define VNOMOUNT 0x20 /* file cannot be covered by mount */
+#define VISSWAP 0x40 /* vnode is being used for swap */
+#define VSWAPLIKE 0x80 /* vnode acts like swap (but may not be) */
+
+#define IS_SWAPVP(vp) (((vp)->v_flag & (VISSWAP | VSWAPLIKE)) != 0)
+
+#else // defined(_KERNEL) || defined(_FAKE_KERNEL)
+typedef struct vnode vnode_t;
+#endif // defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+#if defined(_KERNEL)
+typedef struct vn_vfslocks_entry {
+ rwstlock_t ve_lock;
+ void *ve_vpvfs;
+ struct vn_vfslocks_entry *ve_next;
+ uint32_t ve_refcnt;
+ char pad[64 - sizeof (rwstlock_t) - 2 * sizeof (void *) - \
+ sizeof (uint32_t)];
+} vn_vfslocks_entry_t;
+#endif /* _KERNEL */
+
+/*
+ * The following two flags are used to lock the v_vfsmountedhere field
+ */
+#define VVFSLOCK 0x100
+#define VVFSWAIT 0x200
+
+/*
+ * Used to serialize VM operations on a vnode
+ */
+#define VVMLOCK 0x400
+
+/*
+ * Tell vn_open() not to fail a directory open for writing but
+ * to go ahead and call VOP_OPEN() to let the filesystem check.
+ */
+#define VDIROPEN 0x800
+
+/*
+ * Flag to let the VM system know that this file is most likely a binary
+ * or shared library since it has been mmap()ed EXEC at some time.
+ */
+#define VVMEXEC 0x1000
+
+#define VPXFS 0x2000 /* clustering: global fs proxy vnode */
+
+#define IS_PXFSVP(vp) ((vp)->v_flag & VPXFS)
+
+#define V_XATTRDIR 0x4000 /* attribute unnamed directory */
+
+#define IS_XATTRDIR(vp) ((vp)->v_flag & V_XATTRDIR)
+
+#define V_LOCALITY 0x8000 /* whether locality aware */
+
+/*
+ * Flag that indicates the VM should maintain the v_pages list with all modified
+ * pages on one end and unmodified pages at the other. This makes finding dirty
+ * pages to write back to disk much faster at the expense of taking a minor
+ * fault on the first store instruction which touches a writable page.
+ */
+#define VMODSORT (0x10000)
+#define IS_VMODSORT(vp) \
+ (pvn_vmodsort_supported != 0 && ((vp)->v_flag & VMODSORT) != 0)
+
+#define VISSWAPFS 0x20000 /* vnode is being used for swapfs */
+
+/*
+ * The mdb memstat command assumes that IS_SWAPFSVP only uses the
+ * vnode's v_flag field. If this changes, cache the additional
+ * fields in mdb; see vn_get in mdb/common/modules/genunix/memory.c
+ */
+#define IS_SWAPFSVP(vp) (((vp)->v_flag & VISSWAPFS) != 0)
+
+#define V_SYSATTR 0x40000 /* vnode is a GFS system attribute */
+
+/*
+ * Vnode attributes. A bit-mask is supplied as part of the
+ * structure to indicate the attributes the caller wants to
+ * set (setattr) or extract (getattr).
+ */
+
+/*
+ * Note that va_nodeid and va_nblocks are 64bit data type.
+ * We support large files over NFSV3. With Solaris client and
+ * Server that generates 64bit ino's and sizes these fields
+ * will overflow if they are 32 bit sizes.
+ */
+
+typedef struct vattr {
+ uint_t va_mask; /* bit-mask of attributes */
+ vtype_t va_type; /* vnode type (for create) */
+ mode_t va_mode; /* file access mode */
+ uid_t va_uid; /* owner user id */
+ gid_t va_gid; /* owner group id */
+ dev_t va_fsid; /* file system id (dev for now) */
+ u_longlong_t va_nodeid; /* node id */
+ nlink_t va_nlink; /* number of references to file */
+ u_offset_t va_size; /* file size in bytes */
+ timestruc_t va_atime; /* time of last access */
+ timestruc_t va_mtime; /* time of last modification */
+ timestruc_t va_ctime; /* time of last status change */
+ dev_t va_rdev; /* device the file represents */
+ uint_t va_blksize; /* fundamental block size */
+ u_longlong_t va_nblocks; /* # of blocks allocated */
+ uint_t va_seq; /* sequence number */
+} vattr_t;
+
+#define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */
+
+/*
+ * Structure of all optional attributes.
+ */
+typedef struct xoptattr {
+ timestruc_t xoa_createtime; /* Create time of file */
+ uint8_t xoa_archive;
+ uint8_t xoa_system;
+ uint8_t xoa_readonly;
+ uint8_t xoa_hidden;
+ uint8_t xoa_nounlink;
+ uint8_t xoa_immutable;
+ uint8_t xoa_appendonly;
+ uint8_t xoa_nodump;
+ uint8_t xoa_opaque;
+ uint8_t xoa_av_quarantined;
+ uint8_t xoa_av_modified;
+ uint8_t xoa_av_scanstamp[AV_SCANSTAMP_SZ];
+ uint8_t xoa_reparse;
+ uint64_t xoa_generation;
+ uint8_t xoa_offline;
+ uint8_t xoa_sparse;
+} xoptattr_t;
+
+/*
+ * The xvattr structure is really a variable length structure that
+ * is made up of:
+ * - The classic vattr_t (xva_vattr)
+ * - a 32 bit quantity (xva_mapsize) that specifies the size of the
+ * attribute bitmaps in 32 bit words.
+ * - A pointer to the returned attribute bitmap (needed because the
+ * previous element, the requested attribute bitmap) is variable lenth.
+ * - The requested attribute bitmap, which is an array of 32 bit words.
+ * Callers use the XVA_SET_REQ() macro to set the bits corresponding to
+ * the attributes that are being requested.
+ * - The returned attribute bitmap, which is an array of 32 bit words.
+ * File systems that support optional attributes use the XVA_SET_RTN()
+ * macro to set the bits corresponding to the attributes that are being
+ * returned.
+ * - The xoptattr_t structure which contains the attribute values
+ *
+ * xva_mapsize determines how many words in the attribute bitmaps.
+ * Immediately following the attribute bitmaps is the xoptattr_t.
+ * xva_getxoptattr() is used to get the pointer to the xoptattr_t
+ * section.
+ */
+
+#define XVA_MAPSIZE 3 /* Size of attr bitmaps */
+#define XVA_MAGIC 0x78766174 /* Magic # for verification */
+
+/*
+ * The xvattr structure is an extensible structure which permits optional
+ * attributes to be requested/returned. File systems may or may not support
+ * optional attributes. They do so at their own discretion but if they do
+ * support optional attributes, they must register the VFSFT_XVATTR feature
+ * so that the optional attributes can be set/retrived.
+ *
+ * The fields of the xvattr structure are:
+ *
+ * xva_vattr - The first element of an xvattr is a legacy vattr structure
+ * which includes the common attributes. If AT_XVATTR is set in the va_mask
+ * then the entire structure is treated as an xvattr. If AT_XVATTR is not
+ * set, then only the xva_vattr structure can be used.
+ *
+ * xva_magic - 0x78766174 (hex for "xvat"). Magic number for verification.
+ *
+ * xva_mapsize - Size of requested and returned attribute bitmaps.
+ *
+ * xva_rtnattrmapp - Pointer to xva_rtnattrmap[]. We need this since the
+ * size of the array before it, xva_reqattrmap[], could change which means
+ * the location of xva_rtnattrmap[] could change. This will allow unbundled
+ * file systems to find the location of xva_rtnattrmap[] when the sizes change.
+ *
+ * xva_reqattrmap[] - Array of requested attributes. Attributes are
+ * represented by a specific bit in a specific element of the attribute
+ * map array. Callers set the bits corresponding to the attributes
+ * that the caller wants to get/set.
+ *
+ * xva_rtnattrmap[] - Array of attributes that the file system was able to
+ * process. Not all file systems support all optional attributes. This map
+ * informs the caller which attributes the underlying file system was able
+ * to set/get. (Same structure as the requested attributes array in terms
+ * of each attribute corresponding to specific bits and array elements.)
+ *
+ * xva_xoptattrs - Structure containing values of optional attributes.
+ * These values are only valid if the corresponding bits in xva_reqattrmap
+ * are set and the underlying file system supports those attributes.
+ */
+typedef struct xvattr {
+ vattr_t xva_vattr; /* Embedded vattr structure */
+ uint32_t xva_magic; /* Magic Number */
+ uint32_t xva_mapsize; /* Size of attr bitmap (32-bit words) */
+ uint32_t *xva_rtnattrmapp; /* Ptr to xva_rtnattrmap[] */
+ uint32_t xva_reqattrmap[XVA_MAPSIZE]; /* Requested attrs */
+ uint32_t xva_rtnattrmap[XVA_MAPSIZE]; /* Returned attrs */
+ xoptattr_t xva_xoptattrs; /* Optional attributes */
+} xvattr_t;
+
+#ifdef _SYSCALL32
+/*
+ * For bigtypes time_t changed to 64 bit on the 64-bit kernel.
+ * Define an old version for user/kernel interface
+ */
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+
+typedef struct vattr32 {
+ uint32_t va_mask; /* bit-mask of attributes */
+ vtype_t va_type; /* vnode type (for create) */
+ mode32_t va_mode; /* file access mode */
+ uid32_t va_uid; /* owner user id */
+ gid32_t va_gid; /* owner group id */
+ dev32_t va_fsid; /* file system id (dev for now) */
+ u_longlong_t va_nodeid; /* node id */
+ nlink_t va_nlink; /* number of references to file */
+ u_offset_t va_size; /* file size in bytes */
+ timestruc32_t va_atime; /* time of last access */
+ timestruc32_t va_mtime; /* time of last modification */
+ timestruc32_t va_ctime; /* time of last status change */
+ dev32_t va_rdev; /* device the file represents */
+ uint32_t va_blksize; /* fundamental block size */
+ u_longlong_t va_nblocks; /* # of blocks allocated */
+ uint32_t va_seq; /* sequence number */
+} vattr32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+
+#else /* not _SYSCALL32 */
+#define vattr32 vattr
+typedef vattr_t vattr32_t;
+#endif /* _SYSCALL32 */
+
+/*
+ * Attributes of interest to the caller of setattr or getattr.
+ */
+#define AT_TYPE 0x00001
+#define AT_MODE 0x00002
+#define AT_UID 0x00004
+#define AT_GID 0x00008
+#define AT_FSID 0x00010
+#define AT_NODEID 0x00020
+#define AT_NLINK 0x00040
+#define AT_SIZE 0x00080
+#define AT_ATIME 0x00100
+#define AT_MTIME 0x00200
+#define AT_CTIME 0x00400
+#define AT_RDEV 0x00800
+#define AT_BLKSIZE 0x01000
+#define AT_NBLOCKS 0x02000
+/* 0x04000 */ /* unused */
+#define AT_SEQ 0x08000
+/*
+ * If AT_XVATTR is set then there are additional bits to process in
+ * the xvattr_t's attribute bitmap. If this is not set then the bitmap
+ * MUST be ignored. Note that this bit must be set/cleared explicitly.
+ * That is, setting AT_ALL will NOT set AT_XVATTR.
+ */
+#define AT_XVATTR 0x10000
+
+#define AT_ALL (AT_TYPE|AT_MODE|AT_UID|AT_GID|AT_FSID|AT_NODEID|\
+ AT_NLINK|AT_SIZE|AT_ATIME|AT_MTIME|AT_CTIME|\
+ AT_RDEV|AT_BLKSIZE|AT_NBLOCKS|AT_SEQ)
+
+#define AT_STAT (AT_MODE|AT_UID|AT_GID|AT_FSID|AT_NODEID|AT_NLINK|\
+ AT_SIZE|AT_ATIME|AT_MTIME|AT_CTIME|AT_RDEV|AT_TYPE)
+
+#define AT_TIMES (AT_ATIME|AT_MTIME|AT_CTIME)
+
+#define AT_NOSET (AT_NLINK|AT_RDEV|AT_FSID|AT_NODEID|AT_TYPE|\
+ AT_BLKSIZE|AT_NBLOCKS|AT_SEQ)
+
+/*
+ * Attribute bits used in the extensible attribute's (xva's) attribute
+ * bitmaps. Note that the bitmaps are made up of a variable length number
+ * of 32-bit words. The convention is to use XAT{n}_{attrname} where "n"
+ * is the element in the bitmap (starting at 1). This convention is for
+ * the convenience of the maintainer to keep track of which element each
+ * attribute belongs to.
+ *
+ * NOTE THAT CONSUMERS MUST *NOT* USE THE XATn_* DEFINES DIRECTLY. CONSUMERS
+ * MUST USE THE XAT_* DEFINES.
+ */
+#define XAT0_INDEX 0LL /* Index into bitmap for XAT0 attrs */
+#define XAT0_CREATETIME 0x00000001 /* Create time of file */
+#define XAT0_ARCHIVE 0x00000002 /* Archive */
+#define XAT0_SYSTEM 0x00000004 /* System */
+#define XAT0_READONLY 0x00000008 /* Readonly */
+#define XAT0_HIDDEN 0x00000010 /* Hidden */
+#define XAT0_NOUNLINK 0x00000020 /* Nounlink */
+#define XAT0_IMMUTABLE 0x00000040 /* immutable */
+#define XAT0_APPENDONLY 0x00000080 /* appendonly */
+#define XAT0_NODUMP 0x00000100 /* nodump */
+#define XAT0_OPAQUE 0x00000200 /* opaque */
+#define XAT0_AV_QUARANTINED 0x00000400 /* anti-virus quarantine */
+#define XAT0_AV_MODIFIED 0x00000800 /* anti-virus modified */
+#define XAT0_AV_SCANSTAMP 0x00001000 /* anti-virus scanstamp */
+#define XAT0_REPARSE 0x00002000 /* FS reparse point */
+#define XAT0_GEN 0x00004000 /* object generation number */
+#define XAT0_OFFLINE 0x00008000 /* offline */
+#define XAT0_SPARSE 0x00010000 /* sparse */
+
+#define XAT0_ALL_ATTRS (XAT0_CREATETIME|XAT0_ARCHIVE|XAT0_SYSTEM| \
+ XAT0_READONLY|XAT0_HIDDEN|XAT0_NOUNLINK|XAT0_IMMUTABLE|XAT0_APPENDONLY| \
+ XAT0_NODUMP|XAT0_OPAQUE|XAT0_AV_QUARANTINED| XAT0_AV_MODIFIED| \
+ XAT0_AV_SCANSTAMP|XAT0_REPARSE|XATO_GEN|XAT0_OFFLINE|XAT0_SPARSE)
+
+/* Support for XAT_* optional attributes */
+#define XVA_MASK 0xffffffff /* Used to mask off 32 bits */
+#define XVA_SHFT 32 /* Used to shift index */
+
+/*
+ * Used to pry out the index and attribute bits from the XAT_* attributes
+ * defined below. Note that we're masking things down to 32 bits then
+ * casting to uint32_t.
+ */
+#define XVA_INDEX(attr) ((uint32_t)(((attr) >> XVA_SHFT) & XVA_MASK))
+#define XVA_ATTRBIT(attr) ((uint32_t)((attr) & XVA_MASK))
+
+/*
+ * The following defines present a "flat namespace" so that consumers don't
+ * need to keep track of which element belongs to which bitmap entry.
+ *
+ * NOTE THAT THESE MUST NEVER BE OR-ed TOGETHER
+ */
+#define XAT_CREATETIME ((XAT0_INDEX << XVA_SHFT) | XAT0_CREATETIME)
+#define XAT_ARCHIVE ((XAT0_INDEX << XVA_SHFT) | XAT0_ARCHIVE)
+#define XAT_SYSTEM ((XAT0_INDEX << XVA_SHFT) | XAT0_SYSTEM)
+#define XAT_READONLY ((XAT0_INDEX << XVA_SHFT) | XAT0_READONLY)
+#define XAT_HIDDEN ((XAT0_INDEX << XVA_SHFT) | XAT0_HIDDEN)
+#define XAT_NOUNLINK ((XAT0_INDEX << XVA_SHFT) | XAT0_NOUNLINK)
+#define XAT_IMMUTABLE ((XAT0_INDEX << XVA_SHFT) | XAT0_IMMUTABLE)
+#define XAT_APPENDONLY ((XAT0_INDEX << XVA_SHFT) | XAT0_APPENDONLY)
+#define XAT_NODUMP ((XAT0_INDEX << XVA_SHFT) | XAT0_NODUMP)
+#define XAT_OPAQUE ((XAT0_INDEX << XVA_SHFT) | XAT0_OPAQUE)
+#define XAT_AV_QUARANTINED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_QUARANTINED)
+#define XAT_AV_MODIFIED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_MODIFIED)
+#define XAT_AV_SCANSTAMP ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_SCANSTAMP)
+#define XAT_REPARSE ((XAT0_INDEX << XVA_SHFT) | XAT0_REPARSE)
+#define XAT_GEN ((XAT0_INDEX << XVA_SHFT) | XAT0_GEN)
+#define XAT_OFFLINE ((XAT0_INDEX << XVA_SHFT) | XAT0_OFFLINE)
+#define XAT_SPARSE ((XAT0_INDEX << XVA_SHFT) | XAT0_SPARSE)
+
+/*
+ * The returned attribute map array (xva_rtnattrmap[]) is located past the
+ * requested attribute map array (xva_reqattrmap[]). Its location changes
+ * when the array sizes change. We use a separate pointer in a known location
+ * (xva_rtnattrmapp) to hold the location of xva_rtnattrmap[]. This is
+ * set in xva_init()
+ */
+#define XVA_RTNATTRMAP(xvap) ((xvap)->xva_rtnattrmapp)
+
+/*
+ * XVA_SET_REQ() sets an attribute bit in the proper element in the bitmap
+ * of requested attributes (xva_reqattrmap[]).
+ */
+#define XVA_SET_REQ(xvap, attr) \
+ ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \
+ ASSERT((xvap)->xva_magic == XVA_MAGIC); \
+ (xvap)->xva_reqattrmap[XVA_INDEX(attr)] |= XVA_ATTRBIT(attr)
+/*
+ * XVA_CLR_REQ() clears an attribute bit in the proper element in the bitmap
+ * of requested attributes (xva_reqattrmap[]).
+ */
+#define XVA_CLR_REQ(xvap, attr) \
+ ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \
+ ASSERT((xvap)->xva_magic == XVA_MAGIC); \
+ (xvap)->xva_reqattrmap[XVA_INDEX(attr)] &= ~XVA_ATTRBIT(attr)
+
+/*
+ * XVA_SET_RTN() sets an attribute bit in the proper element in the bitmap
+ * of returned attributes (xva_rtnattrmap[]).
+ */
+#define XVA_SET_RTN(xvap, attr) \
+ ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \
+ ASSERT((xvap)->xva_magic == XVA_MAGIC); \
+ (XVA_RTNATTRMAP(xvap))[XVA_INDEX(attr)] |= XVA_ATTRBIT(attr)
+
+/*
+ * XVA_ISSET_REQ() checks the requested attribute bitmap (xva_reqattrmap[])
+ * to see of the corresponding attribute bit is set. If so, returns non-zero.
+ */
+#define XVA_ISSET_REQ(xvap, attr) \
+ ((((xvap)->xva_vattr.va_mask | AT_XVATTR) && \
+ ((xvap)->xva_magic == XVA_MAGIC) && \
+ ((xvap)->xva_mapsize > XVA_INDEX(attr))) ? \
+ ((xvap)->xva_reqattrmap[XVA_INDEX(attr)] & XVA_ATTRBIT(attr)) : 0)
+
+/*
+ * XVA_ISSET_RTN() checks the returned attribute bitmap (xva_rtnattrmap[])
+ * to see of the corresponding attribute bit is set. If so, returns non-zero.
+ */
+#define XVA_ISSET_RTN(xvap, attr) \
+ ((((xvap)->xva_vattr.va_mask | AT_XVATTR) && \
+ ((xvap)->xva_magic == XVA_MAGIC) && \
+ ((xvap)->xva_mapsize > XVA_INDEX(attr))) ? \
+ ((XVA_RTNATTRMAP(xvap))[XVA_INDEX(attr)] & XVA_ATTRBIT(attr)) : 0)
+
+/*
+ * Modes. Some values same as S_xxx entries from stat.h for convenience.
+ */
+#define VSUID 04000 /* set user id on execution */
+#define VSGID 02000 /* set group id on execution */
+#define VSVTX 01000 /* save swapped text even after use */
+
+/*
+ * Permissions.
+ */
+#define VREAD 00400
+#define VWRITE 00200
+#define VEXEC 00100
+
+#define MODEMASK 07777 /* mode bits plus permission bits */
+#define PERMMASK 00777 /* permission bits */
+
+/*
+ * VOP_ACCESS flags
+ */
+#define V_ACE_MASK 0x1 /* mask represents NFSv4 ACE permissions */
+#define V_APPEND 0x2 /* want to do append only check */
+
+/*
+ * Check whether mandatory file locking is enabled.
+ */
+
+#define MANDMODE(mode) (((mode) & (VSGID|(VEXEC>>3))) == VSGID)
+#define MANDLOCK(vp, mode) ((vp)->v_type == VREG && MANDMODE(mode))
+
+/*
+ * Flags for vnode operations.
+ */
+enum rm { RMFILE, RMDIRECTORY }; /* rm or rmdir (remove) */
+enum symfollow { NO_FOLLOW, FOLLOW }; /* follow symlinks (or not) */
+enum vcexcl { NONEXCL, EXCL }; /* (non)excl create */
+enum create { CRCREAT, CRMKNOD, CRMKDIR }; /* reason for create */
+
+typedef enum rm rm_t;
+typedef enum symfollow symfollow_t;
+typedef enum vcexcl vcexcl_t;
+typedef enum create create_t;
+
+/* Vnode Events - Used by VOP_VNEVENT */
+typedef enum vnevent {
+ VE_SUPPORT = 0, /* Query */
+ VE_RENAME_SRC = 1, /* Rename, with vnode as source */
+ VE_RENAME_DEST = 2, /* Rename, with vnode as target/destination */
+ VE_REMOVE = 3, /* Remove of vnode's name */
+ VE_RMDIR = 4, /* Remove of directory vnode's name */
+ VE_CREATE = 5, /* Create with vnode's name which exists */
+ VE_LINK = 6, /* Link with vnode's name as source */
+ VE_RENAME_DEST_DIR = 7, /* Rename with vnode as target dir */
+ VE_MOUNTEDOVER = 8, /* File or Filesystem got mounted over vnode */
+ VE_TRUNCATE = 9 /* Truncate */
+} vnevent_t;
+
+/*
+ * Values for checking vnode open and map counts
+ */
+enum v_mode { V_READ, V_WRITE, V_RDORWR, V_RDANDWR };
+
+typedef enum v_mode v_mode_t;
+
+#define V_TRUE 1
+#define V_FALSE 0
+
+/*
+ * Structure used on VOP_GETSECATTR and VOP_SETSECATTR operations
+ */
+
+typedef struct vsecattr {
+ uint_t vsa_mask; /* See below */
+ int vsa_aclcnt; /* ACL entry count */
+ void *vsa_aclentp; /* pointer to ACL entries */
+ int vsa_dfaclcnt; /* default ACL entry count */
+ void *vsa_dfaclentp; /* pointer to default ACL entries */
+ size_t vsa_aclentsz; /* ACE size in bytes of vsa_aclentp */
+ uint_t vsa_aclflags; /* ACE ACL flags */
+} vsecattr_t;
+
+/* vsa_mask values */
+#define VSA_ACL 0x0001
+#define VSA_ACLCNT 0x0002
+#define VSA_DFACL 0x0004
+#define VSA_DFACLCNT 0x0008
+#define VSA_ACE 0x0010
+#define VSA_ACECNT 0x0020
+#define VSA_ACE_ALLTYPES 0x0040
+#define VSA_ACE_ACLFLAGS 0x0080 /* get/set ACE ACL flags */
+
+/*
+ * Structure used by various vnode operations to determine
+ * the context (pid, host, identity) of a caller.
+ *
+ * The cc_caller_id is used to identify one or more callers who invoke
+ * operations, possibly on behalf of others. For example, the NFS
+ * server could have it's own cc_caller_id which can be detected by
+ * vnode/vfs operations or (FEM) monitors on those operations. New
+ * caller IDs are generated by fs_new_caller_id().
+ */
+typedef struct caller_context {
+ pid_t cc_pid; /* Process ID of the caller */
+ int cc_sysid; /* System ID, used for remote calls */
+ u_longlong_t cc_caller_id; /* Identifier for (set of) caller(s) */
+ ulong_t cc_flags;
+} caller_context_t;
+
+/*
+ * Flags for caller context. The caller sets CC_DONTBLOCK if it does not
+ * want to block inside of a FEM monitor. The monitor will set CC_WOULDBLOCK
+ * and return EAGAIN if the operation would have blocked.
+ */
+#define CC_WOULDBLOCK 0x01
+#define CC_DONTBLOCK 0x02
+
+/*
+ * Structure tags for function prototypes, defined elsewhere.
+ */
+struct pathname;
+struct fid;
+struct flock64;
+struct flk_callback;
+struct shrlock;
+struct page;
+struct seg;
+struct as;
+struct pollhead;
+struct taskq;
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * VNODE_OPS defines all the vnode operations. It is used to define
+ * the vnodeops structure (below) and the fs_func_p union (vfs_opreg.h).
+ */
+#define VNODE_OPS \
+ int (*vop_open)(vnode_t **, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_close)(vnode_t *, int, int, offset_t, cred_t *, \
+ caller_context_t *); \
+ int (*vop_read)(vnode_t *, uio_t *, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_write)(vnode_t *, uio_t *, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_ioctl)(vnode_t *, int, intptr_t, int, cred_t *, \
+ int *, caller_context_t *); \
+ int (*vop_setfl)(vnode_t *, int, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_getattr)(vnode_t *, vattr_t *, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_setattr)(vnode_t *, vattr_t *, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_access)(vnode_t *, int, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_lookup)(vnode_t *, char *, vnode_t **, \
+ struct pathname *, \
+ int, vnode_t *, cred_t *, \
+ caller_context_t *, int *, \
+ struct pathname *); \
+ int (*vop_create)(vnode_t *, char *, vattr_t *, vcexcl_t, \
+ int, vnode_t **, cred_t *, int, \
+ caller_context_t *, vsecattr_t *); \
+ int (*vop_remove)(vnode_t *, char *, cred_t *, \
+ caller_context_t *, int); \
+ int (*vop_link)(vnode_t *, vnode_t *, char *, cred_t *, \
+ caller_context_t *, int); \
+ int (*vop_rename)(vnode_t *, char *, vnode_t *, char *, \
+ cred_t *, caller_context_t *, int); \
+ int (*vop_mkdir)(vnode_t *, char *, vattr_t *, vnode_t **, \
+ cred_t *, caller_context_t *, int, \
+ vsecattr_t *); \
+ int (*vop_rmdir)(vnode_t *, char *, vnode_t *, cred_t *, \
+ caller_context_t *, int); \
+ int (*vop_readdir)(vnode_t *, uio_t *, cred_t *, int *, \
+ caller_context_t *, int); \
+ int (*vop_symlink)(vnode_t *, char *, vattr_t *, char *, \
+ cred_t *, caller_context_t *, int); \
+ int (*vop_readlink)(vnode_t *, uio_t *, cred_t *, \
+ caller_context_t *); \
+ int (*vop_fsync)(vnode_t *, int, cred_t *, \
+ caller_context_t *); \
+ void (*vop_inactive)(vnode_t *, cred_t *, \
+ caller_context_t *); \
+ int (*vop_fid)(vnode_t *, struct fid *, \
+ caller_context_t *); \
+ int (*vop_rwlock)(vnode_t *, int, caller_context_t *); \
+ void (*vop_rwunlock)(vnode_t *, int, caller_context_t *); \
+ int (*vop_seek)(vnode_t *, offset_t, offset_t *, \
+ caller_context_t *); \
+ int (*vop_cmp)(vnode_t *, vnode_t *, caller_context_t *); \
+ int (*vop_frlock)(vnode_t *, int, struct flock64 *, \
+ int, offset_t, \
+ struct flk_callback *, cred_t *, \
+ caller_context_t *); \
+ int (*vop_space)(vnode_t *, int, struct flock64 *, \
+ int, offset_t, \
+ cred_t *, caller_context_t *); \
+ int (*vop_realvp)(vnode_t *, vnode_t **, \
+ caller_context_t *); \
+ int (*vop_getpage)(vnode_t *, offset_t, size_t, uint_t *, \
+ struct page **, size_t, struct seg *, \
+ caddr_t, enum seg_rw, cred_t *, \
+ caller_context_t *); \
+ int (*vop_putpage)(vnode_t *, offset_t, size_t, \
+ int, cred_t *, caller_context_t *); \
+ int (*vop_map)(vnode_t *, offset_t, struct as *, \
+ caddr_t *, size_t, \
+ uchar_t, uchar_t, uint_t, cred_t *, \
+ caller_context_t *); \
+ int (*vop_addmap)(vnode_t *, offset_t, struct as *, \
+ caddr_t, size_t, \
+ uchar_t, uchar_t, uint_t, cred_t *, \
+ caller_context_t *); \
+ int (*vop_delmap)(vnode_t *, offset_t, struct as *, \
+ caddr_t, size_t, \
+ uint_t, uint_t, uint_t, cred_t *, \
+ caller_context_t *); \
+ int (*vop_poll)(vnode_t *, short, int, short *, \
+ struct pollhead **, \
+ caller_context_t *); \
+ int (*vop_dump)(vnode_t *, caddr_t, offset_t, offset_t, \
+ caller_context_t *); \
+ int (*vop_pathconf)(vnode_t *, int, ulong_t *, cred_t *, \
+ caller_context_t *); \
+ int (*vop_pageio)(vnode_t *, struct page *, \
+ u_offset_t, size_t, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_dumpctl)(vnode_t *, int, offset_t *, \
+ caller_context_t *); \
+ void (*vop_dispose)(vnode_t *, struct page *, \
+ int, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_setsecattr)(vnode_t *, vsecattr_t *, \
+ int, cred_t *, caller_context_t *); \
+ int (*vop_getsecattr)(vnode_t *, vsecattr_t *, \
+ int, cred_t *, caller_context_t *); \
+ int (*vop_shrlock)(vnode_t *, int, struct shrlock *, \
+ int, cred_t *, caller_context_t *); \
+ int (*vop_vnevent)(vnode_t *, vnevent_t, vnode_t *, \
+ char *, caller_context_t *); \
+ int (*vop_reqzcbuf)(vnode_t *, enum uio_rw, xuio_t *, \
+ cred_t *, caller_context_t *); \
+ int (*vop_retzcbuf)(vnode_t *, xuio_t *, cred_t *, \
+ caller_context_t *)
+ /* NB: No ";" */
+
+/*
+ * Operations on vnodes. Note: File systems must never operate directly
+ * on a 'vnodeops' structure -- it WILL change in future releases! They
+ * must use vn_make_ops() to create the structure.
+ */
+typedef struct vnodeops {
+ const char *vnop_name;
+ VNODE_OPS; /* Signatures of all vnode operations (vops) */
+} vnodeops_t;
+
+typedef int (*fs_generic_func_p) (); /* Generic vop/vfsop/femop/fsemop ptr */
+
+extern int fop_open(vnode_t **, int, cred_t *, caller_context_t *);
+extern int fop_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
+extern int fop_read(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
+extern int fop_write(vnode_t *, uio_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+ caller_context_t *);
+extern int fop_setfl(vnode_t *, int, int, cred_t *, caller_context_t *);
+extern int fop_getattr(vnode_t *, vattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_setattr(vnode_t *, vattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_access(vnode_t *, int, int, cred_t *, caller_context_t *);
+extern int fop_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
+ int, vnode_t *, cred_t *, caller_context_t *,
+ int *, struct pathname *);
+extern int fop_create(vnode_t *, char *, vattr_t *, vcexcl_t, int,
+ vnode_t **, cred_t *, int, caller_context_t *,
+ vsecattr_t *);
+extern int fop_remove(vnode_t *vp, char *, cred_t *, caller_context_t *,
+ int);
+extern int fop_link(vnode_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+extern int fop_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+extern int fop_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *,
+ caller_context_t *, int, vsecattr_t *);
+extern int fop_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
+extern int fop_readdir(vnode_t *, uio_t *, cred_t *, int *,
+ caller_context_t *, int);
+extern int fop_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *,
+ caller_context_t *, int);
+extern int fop_readlink(vnode_t *, uio_t *, cred_t *, caller_context_t *);
+extern int fop_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+extern void fop_inactive(vnode_t *, cred_t *, caller_context_t *);
+extern int fop_fid(vnode_t *, struct fid *, caller_context_t *);
+extern int fop_rwlock(vnode_t *, int, caller_context_t *);
+extern void fop_rwunlock(vnode_t *, int, caller_context_t *);
+extern int fop_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
+extern int fop_cmp(vnode_t *, vnode_t *, caller_context_t *);
+extern int fop_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
+ struct flk_callback *, cred_t *,
+ caller_context_t *);
+extern int fop_space(vnode_t *, int, struct flock64 *, int, offset_t,
+ cred_t *, caller_context_t *);
+extern int fop_realvp(vnode_t *, vnode_t **, caller_context_t *);
+extern int fop_getpage(vnode_t *, offset_t, size_t, uint_t *,
+ struct page **, size_t, struct seg *,
+ caddr_t, enum seg_rw, cred_t *,
+ caller_context_t *);
+extern int fop_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
+ caller_context_t *);
+extern int fop_map(vnode_t *, offset_t, struct as *, caddr_t *, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *cr,
+ caller_context_t *);
+extern int fop_addmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *,
+ caller_context_t *);
+extern int fop_delmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uint_t, uint_t, uint_t, cred_t *,
+ caller_context_t *);
+extern int fop_poll(vnode_t *, short, int, short *, struct pollhead **,
+ caller_context_t *);
+extern int fop_dump(vnode_t *, caddr_t, offset_t, offset_t,
+ caller_context_t *);
+extern int fop_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
+extern int fop_pageio(vnode_t *, struct page *, u_offset_t, size_t, int,
+ cred_t *, caller_context_t *);
+extern int fop_dumpctl(vnode_t *, int, offset_t *, caller_context_t *);
+extern void fop_dispose(vnode_t *, struct page *, int, int, cred_t *,
+ caller_context_t *);
+extern int fop_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
+ caller_context_t *);
+extern int fop_vnevent(vnode_t *, vnevent_t, vnode_t *, char *,
+ caller_context_t *);
+extern int fop_reqzcbuf(vnode_t *, enum uio_rw, xuio_t *, cred_t *,
+ caller_context_t *);
+extern int fop_retzcbuf(vnode_t *, xuio_t *, cred_t *, caller_context_t *);
+
+#endif /* _KERNEL */
+
+#define VOP_OPEN(vpp, mode, cr, ct) \
+ fop_open(vpp, mode, cr, ct)
+#define VOP_CLOSE(vp, f, c, o, cr, ct) \
+ fop_close(vp, f, c, o, cr, ct)
+#define VOP_READ(vp, uiop, iof, cr, ct) \
+ fop_read(vp, uiop, iof, cr, ct)
+#define VOP_WRITE(vp, uiop, iof, cr, ct) \
+ fop_write(vp, uiop, iof, cr, ct)
+#define VOP_IOCTL(vp, cmd, a, f, cr, rvp, ct) \
+ fop_ioctl(vp, cmd, a, f, cr, rvp, ct)
+#define VOP_SETFL(vp, f, a, cr, ct) \
+ fop_setfl(vp, f, a, cr, ct)
+#define VOP_GETATTR(vp, vap, f, cr, ct) \
+ fop_getattr(vp, vap, f, cr, ct)
+#define VOP_SETATTR(vp, vap, f, cr, ct) \
+ fop_setattr(vp, vap, f, cr, ct)
+#define VOP_ACCESS(vp, mode, f, cr, ct) \
+ fop_access(vp, mode, f, cr, ct)
+#define VOP_LOOKUP(vp, cp, vpp, pnp, f, rdir, cr, ct, defp, rpnp) \
+ fop_lookup(vp, cp, vpp, pnp, f, rdir, cr, ct, defp, rpnp)
+#define VOP_CREATE(dvp, p, vap, ex, mode, vpp, cr, flag, ct, vsap) \
+ fop_create(dvp, p, vap, ex, mode, vpp, cr, flag, ct, vsap)
+#define VOP_REMOVE(dvp, p, cr, ct, f) \
+ fop_remove(dvp, p, cr, ct, f)
+#define VOP_LINK(tdvp, fvp, p, cr, ct, f) \
+ fop_link(tdvp, fvp, p, cr, ct, f)
+#define VOP_RENAME(fvp, fnm, tdvp, tnm, cr, ct, f) \
+ fop_rename(fvp, fnm, tdvp, tnm, cr, ct, f)
+#define VOP_MKDIR(dp, p, vap, vpp, cr, ct, f, vsap) \
+ fop_mkdir(dp, p, vap, vpp, cr, ct, f, vsap)
+#define VOP_RMDIR(dp, p, cdir, cr, ct, f) \
+ fop_rmdir(dp, p, cdir, cr, ct, f)
+#define VOP_READDIR(vp, uiop, cr, eofp, ct, f) \
+ fop_readdir(vp, uiop, cr, eofp, ct, f)
+#define VOP_SYMLINK(dvp, lnm, vap, tnm, cr, ct, f) \
+ fop_symlink(dvp, lnm, vap, tnm, cr, ct, f)
+#define VOP_READLINK(vp, uiop, cr, ct) \
+ fop_readlink(vp, uiop, cr, ct)
+#define VOP_FSYNC(vp, syncflag, cr, ct) \
+ fop_fsync(vp, syncflag, cr, ct)
+#define VOP_INACTIVE(vp, cr, ct) \
+ fop_inactive(vp, cr, ct)
+#define VOP_FID(vp, fidp, ct) \
+ fop_fid(vp, fidp, ct)
+#define VOP_RWLOCK(vp, w, ct) \
+ fop_rwlock(vp, w, ct)
+#define VOP_RWUNLOCK(vp, w, ct) \
+ fop_rwunlock(vp, w, ct)
+#define VOP_SEEK(vp, ooff, noffp, ct) \
+ fop_seek(vp, ooff, noffp, ct)
+#define VOP_CMP(vp1, vp2, ct) \
+ fop_cmp(vp1, vp2, ct)
+#define VOP_FRLOCK(vp, cmd, a, f, o, cb, cr, ct) \
+ fop_frlock(vp, cmd, a, f, o, cb, cr, ct)
+#define VOP_SPACE(vp, cmd, a, f, o, cr, ct) \
+ fop_space(vp, cmd, a, f, o, cr, ct)
+#define VOP_REALVP(vp1, vp2, ct) \
+ fop_realvp(vp1, vp2, ct)
+#define VOP_GETPAGE(vp, of, sz, pr, pl, ps, sg, a, rw, cr, ct) \
+ fop_getpage(vp, of, sz, pr, pl, ps, sg, a, rw, cr, ct)
+#define VOP_PUTPAGE(vp, of, sz, fl, cr, ct) \
+ fop_putpage(vp, of, sz, fl, cr, ct)
+#define VOP_MAP(vp, of, as, a, sz, p, mp, fl, cr, ct) \
+ fop_map(vp, of, as, a, sz, p, mp, fl, cr, ct)
+#define VOP_ADDMAP(vp, of, as, a, sz, p, mp, fl, cr, ct) \
+ fop_addmap(vp, of, as, a, sz, p, mp, fl, cr, ct)
+#define VOP_DELMAP(vp, of, as, a, sz, p, mp, fl, cr, ct) \
+ fop_delmap(vp, of, as, a, sz, p, mp, fl, cr, ct)
+#define VOP_POLL(vp, events, anyyet, reventsp, phpp, ct) \
+ fop_poll(vp, events, anyyet, reventsp, phpp, ct)
+#define VOP_DUMP(vp, addr, bn, count, ct) \
+ fop_dump(vp, addr, bn, count, ct)
+#define VOP_PATHCONF(vp, cmd, valp, cr, ct) \
+ fop_pathconf(vp, cmd, valp, cr, ct)
+#define VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr, ct) \
+ fop_pageio(vp, pp, io_off, io_len, flags, cr, ct)
+#define VOP_DUMPCTL(vp, action, blkp, ct) \
+ fop_dumpctl(vp, action, blkp, ct)
+#define VOP_DISPOSE(vp, pp, flag, dn, cr, ct) \
+ fop_dispose(vp, pp, flag, dn, cr, ct)
+#define VOP_GETSECATTR(vp, vsap, f, cr, ct) \
+ fop_getsecattr(vp, vsap, f, cr, ct)
+#define VOP_SETSECATTR(vp, vsap, f, cr, ct) \
+ fop_setsecattr(vp, vsap, f, cr, ct)
+#define VOP_SHRLOCK(vp, cmd, shr, f, cr, ct) \
+ fop_shrlock(vp, cmd, shr, f, cr, ct)
+#define VOP_VNEVENT(vp, vnevent, dvp, fnm, ct) \
+ fop_vnevent(vp, vnevent, dvp, fnm, ct)
+#define VOP_REQZCBUF(vp, rwflag, xuiop, cr, ct) \
+ fop_reqzcbuf(vp, rwflag, xuiop, cr, ct)
+#define VOP_RETZCBUF(vp, xuiop, cr, ct) \
+ fop_retzcbuf(vp, xuiop, cr, ct)
+
+#define VOPNAME_OPEN "open"
+#define VOPNAME_CLOSE "close"
+#define VOPNAME_READ "read"
+#define VOPNAME_WRITE "write"
+#define VOPNAME_IOCTL "ioctl"
+#define VOPNAME_SETFL "setfl"
+#define VOPNAME_GETATTR "getattr"
+#define VOPNAME_SETATTR "setattr"
+#define VOPNAME_ACCESS "access"
+#define VOPNAME_LOOKUP "lookup"
+#define VOPNAME_CREATE "create"
+#define VOPNAME_REMOVE "remove"
+#define VOPNAME_LINK "link"
+#define VOPNAME_RENAME "rename"
+#define VOPNAME_MKDIR "mkdir"
+#define VOPNAME_RMDIR "rmdir"
+#define VOPNAME_READDIR "readdir"
+#define VOPNAME_SYMLINK "symlink"
+#define VOPNAME_READLINK "readlink"
+#define VOPNAME_FSYNC "fsync"
+#define VOPNAME_INACTIVE "inactive"
+#define VOPNAME_FID "fid"
+#define VOPNAME_RWLOCK "rwlock"
+#define VOPNAME_RWUNLOCK "rwunlock"
+#define VOPNAME_SEEK "seek"
+#define VOPNAME_CMP "cmp"
+#define VOPNAME_FRLOCK "frlock"
+#define VOPNAME_SPACE "space"
+#define VOPNAME_REALVP "realvp"
+#define VOPNAME_GETPAGE "getpage"
+#define VOPNAME_PUTPAGE "putpage"
+#define VOPNAME_MAP "map"
+#define VOPNAME_ADDMAP "addmap"
+#define VOPNAME_DELMAP "delmap"
+#define VOPNAME_POLL "poll"
+#define VOPNAME_DUMP "dump"
+#define VOPNAME_PATHCONF "pathconf"
+#define VOPNAME_PAGEIO "pageio"
+#define VOPNAME_DUMPCTL "dumpctl"
+#define VOPNAME_DISPOSE "dispose"
+#define VOPNAME_GETSECATTR "getsecattr"
+#define VOPNAME_SETSECATTR "setsecattr"
+#define VOPNAME_SHRLOCK "shrlock"
+#define VOPNAME_VNEVENT "vnevent"
+#define VOPNAME_REQZCBUF "reqzcbuf"
+#define VOPNAME_RETZCBUF "retzcbuf"
+
+/*
+ * Flags for VOP_LOOKUP
+ *
+ * Defined in file.h, but also possible, FIGNORECASE and FSEARCH
+ *
+ */
+#define LOOKUP_DIR 0x01 /* want parent dir vp */
+#define LOOKUP_XATTR 0x02 /* lookup up extended attr dir */
+#define CREATE_XATTR_DIR 0x04 /* Create extended attr dir */
+#define LOOKUP_HAVE_SYSATTR_DIR 0x08 /* Already created virtual GFS dir */
+
+/*
+ * Flags for VOP_READDIR
+ */
+#define V_RDDIR_ENTFLAGS 0x01 /* request dirent flags */
+#define V_RDDIR_ACCFILTER 0x02 /* filter out inaccessible dirents */
+
+/*
+ * Flags for VOP_RWLOCK/VOP_RWUNLOCK
+ * VOP_RWLOCK will return the flag that was actually set, or -1 if none.
+ */
+#define V_WRITELOCK_TRUE (1) /* Request write-lock on the vnode */
+#define V_WRITELOCK_FALSE (0) /* Request read-lock on the vnode */
+
+/*
+ * Flags for VOP_DUMPCTL
+ */
+#define DUMP_ALLOC 0
+#define DUMP_FREE 1
+#define DUMP_SCAN 2
+
+/*
+ * Public vnode manipulation functions.
+ */
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+vnode_t *vn_alloc(int);
+void vn_reinit(vnode_t *);
+void vn_recycle(vnode_t *);
+void vn_free(vnode_t *);
+
+int vn_is_readonly(vnode_t *);
+int vn_is_opened(vnode_t *, v_mode_t);
+int vn_is_mapped(vnode_t *, v_mode_t);
+int vn_has_other_opens(vnode_t *, v_mode_t);
+void vn_open_upgrade(vnode_t *, int);
+void vn_open_downgrade(vnode_t *, int);
+
+int vn_can_change_zones(vnode_t *vp);
+
+int vn_has_flocks(vnode_t *);
+int vn_has_mandatory_locks(vnode_t *, int);
+int vn_has_cached_data(vnode_t *);
+
+void vn_setops(vnode_t *, vnodeops_t *);
+vnodeops_t *vn_getops(vnode_t *);
+int vn_matchops(vnode_t *, vnodeops_t *);
+int vn_matchopval(vnode_t *, char *, fs_generic_func_p);
+int vn_ismntpt(vnode_t *);
+
+struct vfs *vn_mountedvfs(vnode_t *);
+
+int vn_in_dnlc(vnode_t *);
+
+void vn_create_cache(void);
+void vn_destroy_cache(void);
+
+void vn_freevnodeops(vnodeops_t *);
+
+int vn_open(char *pnamep, enum uio_seg seg, int filemode, int createmode,
+ struct vnode **vpp, enum create crwhy, mode_t umask);
+int vn_openat(char *pnamep, enum uio_seg seg, int filemode, int createmode,
+ struct vnode **vpp, enum create crwhy,
+ mode_t umask, struct vnode *startvp, int fd);
+int vn_create(char *pnamep, enum uio_seg seg, struct vattr *vap,
+ enum vcexcl excl, int mode, struct vnode **vpp,
+ enum create why, int flag, mode_t umask);
+int vn_createat(char *pnamep, enum uio_seg seg, struct vattr *vap,
+ enum vcexcl excl, int mode, struct vnode **vpp,
+ enum create why, int flag, mode_t umask, struct vnode *startvp);
+int vn_rdwr(enum uio_rw rw, struct vnode *vp, caddr_t base, ssize_t len,
+ offset_t offset, enum uio_seg seg, int ioflag, rlim64_t ulimit,
+ cred_t *cr, ssize_t *residp);
+
+void vn_hold(struct vnode *vp);
+void vn_rele(struct vnode *vp);
+void vn_rele_async(struct vnode *vp, struct taskq *taskq);
+void vn_rele_dnlc(struct vnode *vp);
+void vn_rele_stream(struct vnode *vp);
+int vn_link(char *from, char *to, enum uio_seg seg);
+int vn_linkat(vnode_t *fstartvp, char *from, enum symfollow follow,
+ vnode_t *tstartvp, char *to, enum uio_seg seg);
+int vn_rename(char *from, char *to, enum uio_seg seg);
+int vn_renameat(vnode_t *fdvp, char *fname, vnode_t *tdvp, char *tname,
+ enum uio_seg seg);
+int vn_remove(char *fnamep, enum uio_seg seg, enum rm dirflag);
+int vn_removeat(vnode_t *startvp, char *fnamep, enum uio_seg seg,
+ enum rm dirflag);
+int vn_compare(vnode_t *vp1, vnode_t *vp2);
+int vn_vfswlock(struct vnode *vp);
+int vn_vfswlock_wait(struct vnode *vp);
+int vn_vfsrlock(struct vnode *vp);
+int vn_vfsrlock_wait(struct vnode *vp);
+void vn_vfsunlock(struct vnode *vp);
+int vn_vfswlock_held(struct vnode *vp);
+vnode_t *specvp(struct vnode *vp, dev_t dev, vtype_t type, struct cred *cr);
+vnode_t *makespecvp(dev_t dev, vtype_t type);
+
+#if defined(_KERNEL)
+vn_vfslocks_entry_t *vn_vfslocks_getlock(void *);
+void vn_vfslocks_rele(vn_vfslocks_entry_t *);
+#endif
+
+boolean_t vn_is_reparse(vnode_t *, cred_t *, caller_context_t *);
+
+void vn_copypath(struct vnode *src, struct vnode *dst);
+void vn_setpath_str(struct vnode *vp, const char *str, size_t len);
+void vn_setpath(vnode_t *rootvp, struct vnode *startvp, struct vnode *vp,
+ const char *path, size_t plen);
+void vn_renamepath(vnode_t *dvp, vnode_t *vp, const char *nm, size_t len);
+
+/* Vnode event notification */
+void vnevent_rename_src(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_rename_dest(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_remove(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_rmdir(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_create(vnode_t *, caller_context_t *);
+void vnevent_link(vnode_t *, caller_context_t *);
+void vnevent_rename_dest_dir(vnode_t *, caller_context_t *ct);
+void vnevent_mountedover(vnode_t *, caller_context_t *);
+void vnevent_truncate(vnode_t *, caller_context_t *);
+int vnevent_support(vnode_t *, caller_context_t *);
+
+/* Vnode specific data */
+void vsd_create(uint_t *, void (*)(void *));
+void vsd_destroy(uint_t *);
+void *vsd_get(vnode_t *, uint_t);
+int vsd_set(vnode_t *, uint_t, void *);
+void vsd_free(vnode_t *);
+
+/*
+ * Extensible vnode attribute (xva) routines:
+ * xva_init() initializes an xvattr_t (zero struct, init mapsize, set AT_XATTR)
+ * xva_getxoptattr() returns a ponter to the xoptattr_t section of xvattr_t
+ */
+void xva_init(xvattr_t *);
+xoptattr_t *xva_getxoptattr(xvattr_t *); /* Get ptr to xoptattr_t */
+
+void xattr_init(void); /* Initialize vnodeops for xattrs */
+
+/* GFS tunnel for xattrs */
+int xattr_dir_lookup(vnode_t *, vnode_t **, int, cred_t *);
+
+/* Reparse Point */
+void reparse_point_init(void);
+
+/* Context identification */
+u_longlong_t fs_new_caller_id();
+
+int vn_vmpss_usepageio(vnode_t *);
+
+/* Empty v_path placeholder */
+extern char *vn_vpath_empty;
+
+/*
+ * Needed for use of IS_VMODSORT() in kernel.
+ */
+extern uint_t pvn_vmodsort_supported;
+
+#define VN_HOLD(vp) { \
+ vn_hold(vp); \
+}
+
+#define VN_RELE(vp) { \
+ vn_rele(vp); \
+}
+
+#define VN_RELE_ASYNC(vp, taskq) { \
+ vn_rele_async(vp, taskq); \
+}
+
+#define VN_RELE_LOCKED(vp) { \
+ (vp)->v_count--; \
+}
+
+#define VN_SET_VFS_TYPE_DEV(vp, vfsp, type, dev) { \
+ (vp)->v_vfsp = (vfsp); \
+ (vp)->v_type = (type); \
+ (vp)->v_rdev = (dev); \
+}
+
+/*
+ * Compare two vnodes for equality. In general this macro should be used
+ * in preference to calling VOP_CMP directly.
+ */
+#if defined(_FAKE_KERNEL)
+#define VN_CMP(VP1, VP2) \
+ (((VP1) == (VP2)) ? 1 : VOP_CMP(VP1, VP2, NULL))
+#else
+#define VN_CMP(VP1, VP2) ((VP1) == (VP2) ? 1 : \
+ ((VP1) && (VP2) && (vn_getops(VP1) == vn_getops(VP2)) ? \
+ VOP_CMP(VP1, VP2, NULL) : 0))
+#endif
+
+/*
+ * Some well-known global vnodes used by the VM system to name pages.
+ */
+extern struct vnode kvps[];
+
+typedef enum {
+ KV_KVP, /* vnode for all segkmem pages */
+ KV_ZVP, /* vnode for all ZFS pages */
+#if defined(__sparc)
+ KV_MPVP, /* vnode for all page_t meta-pages */
+ KV_PROMVP, /* vnode for all PROM pages */
+#endif /* __sparc */
+ KV_MAX /* total number of vnodes in kvps[] */
+} kvps_index_t;
+
+#define VN_ISKAS(vp) ((vp) >= &kvps[0] && (vp) < &kvps[KV_MAX])
+
+#endif /* _KERNEL */
+
+/*
+ * Flags to VOP_SETATTR/VOP_GETATTR.
+ */
+#define ATTR_UTIME 0x01 /* non-default utime(2) request */
+#define ATTR_EXEC 0x02 /* invocation from exec(2) */
+#define ATTR_COMM 0x04 /* yield common vp attributes */
+#define ATTR_HINT 0x08 /* information returned will be `hint' */
+#define ATTR_REAL 0x10 /* yield attributes of the real vp */
+#define ATTR_NOACLCHECK 0x20 /* Don't check ACL when checking permissions */
+#define ATTR_TRIGGER 0x40 /* Mount first if vnode is a trigger mount */
+/*
+ * Generally useful macros.
+ */
+#define VBSIZE(vp) ((vp)->v_vfsp->vfs_bsize)
+
+#define VTOZONE(vp) ((vp)->v_vfsp->vfs_zone)
+
+#define NULLVP ((struct vnode *)0)
+#define NULLVPP ((struct vnode **)0)
+
+#ifdef _KERNEL
+
+/*
+ * Structure used while handling asynchronous VOP_PUTPAGE operations.
+ */
+struct async_reqs {
+ struct async_reqs *a_next; /* pointer to next arg struct */
+ struct vnode *a_vp; /* vnode pointer */
+ u_offset_t a_off; /* offset in file */
+ uint_t a_len; /* size of i/o request */
+ int a_flags; /* flags to indicate operation type */
+ struct cred *a_cred; /* cred pointer */
+ ushort_t a_prealloced; /* set if struct is pre-allocated */
+};
+
+/*
+ * VN_DISPOSE() -- given a page pointer, safely invoke VOP_DISPOSE().
+ * Note that there is no guarantee that the page passed in will be
+ * freed. If that is required, then a check after calling VN_DISPOSE would
+ * be necessary to ensure the page was freed.
+ */
+#define VN_DISPOSE(pp, flag, dn, cr) { \
+ if ((pp)->p_vnode != NULL && !VN_ISKAS((pp)->p_vnode)) \
+ VOP_DISPOSE((pp)->p_vnode, (pp), (flag), (dn), (cr), NULL); \
+ else if ((flag) == B_FREE) \
+ page_free((pp), (dn)); \
+ else \
+ page_destroy((pp), (dn)); \
+ }
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VNODE_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/i386/Makefile b/usr/src/lib/smbclnt/libfknsmb/i386/Makefile
new file mode 100644
index 0000000000..40b7e3bf5d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbclnt/libfknsmb/sparc/Makefile b/usr/src/lib/smbclnt/libfknsmb/sparc/Makefile
new file mode 100644
index 0000000000..40b7e3bf5d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/sparc/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbclnt/libfknsmb/sparcv9/Makefile b/usr/src/lib/smbclnt/libfknsmb/sparcv9/Makefile
new file mode 100644
index 0000000000..de1ec045d8
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/sparcv9/Makefile
@@ -0,0 +1,23 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MACH_LDLIBS += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+sparcv9_C_PICFLAGS= $(sparcv9_C_BIGPICFLAGS)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbclnt/libfksmbfs/Makefile b/usr/src/lib/smbclnt/libfksmbfs/Makefile
new file mode 100644
index 0000000000..ee4ab9faf7
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/Makefile
@@ -0,0 +1,16 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.smbclnt
diff --git a/usr/src/lib/smbclnt/libfksmbfs/Makefile.com b/usr/src/lib/smbclnt/libfksmbfs/Makefile.com
new file mode 100644
index 0000000000..abc12a9464
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/Makefile.com
@@ -0,0 +1,139 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+#
+
+LIBRARY = libfksmbfs.a
+VERS = .1
+
+OBJS_LOCAL = \
+ fksmbfs_rwlock.o \
+ fake_fssub.o \
+ fake_getdents.o \
+ fake_lookup.o \
+ fake_misc.o \
+ fake_modconf.o \
+ fake_nbmlock.o \
+ fake_open.o \
+ fake_rename.o \
+ fake_rw.o \
+ fake_stat.o \
+ fake_unlink.o \
+ fake_vfs.o \
+ fake_vnode.o \
+ fake_zone.o
+
+# See also: $SRC/uts/common/Makefile.files
+# NB: Intentionally ommitted, compared w/ the above:
+# smbfs_rwlock.o
+#
+OBJS_FS_SMBFS = \
+ smbfs_vfsops.o \
+ smbfs_vnops.o \
+ smbfs_client.o \
+ smbfs_node.o \
+ smbfs_smb.o \
+ smbfs_smb1.o \
+ smbfs_smb2.o \
+ smbfs_subr.o \
+ smbfs_subr2.o \
+ smbfs_acl.o \
+ smbfs_xattr.o
+
+OBJS_CMN_SMBFS = \
+ smbfs_ntacl.o
+
+OBJS_MISC = \
+ acl_common.o \
+ pathname.o \
+ refstr.o
+
+OBJECTS = \
+ $(OBJS_LOCAL) \
+ $(OBJS_FS_SMBFS) \
+ $(OBJS_CMN_SMBFS) \
+ $(OBJS_MISC)
+
+include ../../../Makefile.lib
+include ../../Makefile.lib
+
+# Force SOURCEDEBUG
+CSOURCEDEBUGFLAGS = -g
+CCSOURCEDEBUGFLAGS = -g
+STRIP_STABS = :
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+# Also, like Makefile.uts, reset CPPFLAGS
+CPPFLAGS.first += -I../../../libfakekernel/common
+CPPFLAGS.first += -I../../libfknsmb/common
+CPPFLAGS.first += -I../common
+CPPFLAGS= $(CPPFLAGS.first)
+
+INCS += -I$(SRC)/uts/common/fs/smbclnt
+INCS += -I$(SRC)/uts/common
+INCS += -I$(SRC)/common/smbclnt
+INCS += -I$(SRC)/common
+
+CPPFLAGS += $(INCS) -D_REENTRANT -D_FAKE_KERNEL
+CPPFLAGS += -D_FILE_OFFSET_BITS=64
+# Always want DEBUG here
+CPPFLAGS += -DDEBUG
+
+CERRWARN += -_gcc=-Wno-switch
+CERRWARN += -_gcc=-Wno-parentheses
+
+LDLIBS += $(MACH_LDLIBS)
+LDLIBS += -lfknsmb -lfakekernel -lidmap -lcmdutils -lavl -lc
+
+FS_SMBFS_DIR=$(SRC)/uts/common/fs/smbclnt/smbfs
+CMN_SMBFS_DIR=$(SRC)/common/smbclnt
+SRCS= $(OBJS_LOCAL:%.o=$(SRCDIR)/%.c) \
+ $(OBJS_FS_SMBFS:%.o=$(FS_SMBFS_DIR)/%.c) \
+ $(OBJS_CMN_SMBFS:%.o=$(CMN_SMBFS_DIR)/%.c)
+
+all:
+
+pics/%.o: $(FS_SMBFS_DIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+# pathname.o
+pics/%.o: $(SRC)/uts/common/fs/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+# refstr.o
+pics/%.o: $(SRC)/uts/common/os/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/acl_common.o: $(SRC)/common/acl/acl_common.c
+ $(COMPILE.c) -o $@ $(SRC)/common/acl/acl_common.c
+ $(POST_PROCESS_O)
+
+.KEEP_STATE:
+
+include ../../Makefile.targ
+include ../../../Makefile.targ
diff --git a/usr/src/lib/smbclnt/libfksmbfs/amd64/Makefile b/usr/src/lib/smbclnt/libfksmbfs/amd64/Makefile
new file mode 100644
index 0000000000..8b52fdf7af
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/amd64/Makefile
@@ -0,0 +1,23 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MACH_LDLIBS += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+DYNFLAGS += -R/usr/lib/smbfs/$(MACH64)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_fssub.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_fssub.c
new file mode 100644
index 0000000000..336406f095
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_fssub.c
@@ -0,0 +1,432 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Joyent, Inc.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Generic vnode operations.
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/flock.h>
+#include <sys/statvfs.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/cred.h>
+#include <sys/poll.h>
+#include <sys/debug.h>
+#include <sys/cmn_err.h>
+#include <sys/share.h>
+#include <sys/file.h>
+#include <sys/kmem.h>
+#include <sys/nbmlock.h>
+#include <sys/acl.h>
+
+#include <acl/acl_common.h>
+#include <fs/fs_subr.h>
+
+/*
+ * Tunable to limit the number of retry to recover from STALE error.
+ */
+int fs_estale_retry = 5;
+
+/*
+ * The associated operation is not supported by the file system.
+ */
+int
+fs_nosys()
+{
+ return (ENOSYS);
+}
+
+/*
+ * The associated operation is invalid (on this vnode).
+ */
+int
+fs_inval()
+{
+ return (EINVAL);
+}
+
+/*
+ * The associated operation is valid only for directories.
+ */
+int
+fs_notdir()
+{
+ return (ENOTDIR);
+}
+
+/*
+ * Free the file system specific resources. For the file systems that
+ * do not support the forced unmount, it will be a nop function.
+ */
+
+/*ARGSUSED*/
+void
+fs_freevfs(vfs_t *vfsp)
+{
+}
+
+/* ARGSUSED */
+int
+fs_nosys_map(struct vnode *vp, offset_t off, struct as *as, caddr_t *addrp,
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr,
+ caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+/* ARGSUSED */
+int
+fs_nosys_addmap(struct vnode *vp, offset_t off, struct as *as, caddr_t addr,
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr,
+ caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+/* ARGSUSED */
+int
+fs_nosys_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
+ struct pollhead **phpp, caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+
+/*
+ * The file system has nothing to sync to disk. However, the
+ * VFS_SYNC operation must not fail.
+ */
+/* ARGSUSED */
+int
+fs_sync(struct vfs *vfspp, short flag, cred_t *cr)
+{
+ return (0);
+}
+
+/*
+ * Does nothing but VOP_FSYNC must not fail.
+ */
+/* ARGSUSED */
+int
+fs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
+{
+ return (0);
+}
+
+/*
+ * Does nothing but VOP_PUTPAGE must not fail.
+ */
+/* ARGSUSED */
+int
+fs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ctp)
+{
+ return (0);
+}
+
+/*
+ * Does nothing but VOP_IOCTL must not fail.
+ */
+/* ARGSUSED */
+int
+fs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred,
+ int *rvalp)
+{
+ return (0);
+}
+
+/*
+ * Read/write lock/unlock. Does nothing.
+ */
+/* ARGSUSED */
+int
+fs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
+{
+ return (-1);
+}
+
+/* ARGSUSED */
+void
+fs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
+{
+}
+
+/*
+ * Compare two vnodes.
+ */
+/*ARGSUSED2*/
+int
+fs_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
+{
+ return (vp1 == vp2);
+}
+
+/*
+ * No-op seek operation.
+ */
+/* ARGSUSED */
+int
+fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
+{
+ return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
+}
+
+/*
+ * File and record locking.
+ */
+/* ARGSUSED */
+int
+fs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, offset_t offset,
+ flk_callback_t *flk_cbp, cred_t *cr, caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+/*
+ * Allow any flags.
+ */
+/* ARGSUSED */
+int
+fs_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr, caller_context_t *ct)
+{
+ return (0);
+}
+
+/*
+ * Return the answer requested to poll() for non-device files.
+ * Only POLLIN, POLLRDNORM, and POLLOUT are recognized.
+ */
+struct pollhead fs_pollhd;
+
+/* ARGSUSED */
+int
+fs_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
+ struct pollhead **phpp, caller_context_t *ct)
+{
+ if (events & POLLET) {
+ return (EPERM);
+ }
+
+ *reventsp = 0;
+ if (events & POLLIN)
+ *reventsp |= POLLIN;
+ if (events & POLLRDNORM)
+ *reventsp |= POLLRDNORM;
+ if (events & POLLRDBAND)
+ *reventsp |= POLLRDBAND;
+ if (events & POLLOUT)
+ *reventsp |= POLLOUT;
+ if (events & POLLWRBAND)
+ *reventsp |= POLLWRBAND;
+ if (*reventsp == 0 && !anyyet) {
+ *phpp = &fs_pollhd;
+ }
+ return (0);
+}
+
+/*
+ * POSIX pathconf() support.
+ */
+/* ARGSUSED */
+int
+fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
+{
+ /* not called */
+ return (EINVAL);
+}
+
+/*
+ * Dispose of a page.
+ */
+/* ARGSUSED */
+void
+fs_dispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
+ caller_context_t *ct)
+{
+}
+
+/* ARGSUSED */
+void
+fs_nodispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
+ caller_context_t *ct)
+{
+ cmn_err(CE_PANIC, "fs_nodispose invoked");
+}
+
+/*
+ * fabricate acls for file systems that do not support acls.
+ */
+/* ARGSUSED */
+int
+fs_fab_acl(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
+{
+ struct vattr vattr;
+ int error;
+
+ vsecattr->vsa_aclcnt = 0;
+ vsecattr->vsa_aclentsz = 0;
+ vsecattr->vsa_aclentp = NULL;
+ vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */
+ vsecattr->vsa_dfaclentp = NULL;
+
+ vattr.va_mask = AT_MODE | AT_UID | AT_GID;
+ if (error = VOP_GETATTR(vp, &vattr, 0, cr, ct))
+ return (error);
+
+ if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) {
+ return (ENOSYS);
+ }
+
+ if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) {
+ VERIFY(0 == acl_trivial_create(vattr.va_mode,
+ (vp->v_type == VDIR), (ace_t **)&vsecattr->vsa_aclentp,
+ &vsecattr->vsa_aclcnt));
+ vsecattr->vsa_aclentsz = vsecattr->vsa_aclcnt * sizeof (ace_t);
+ }
+
+ return (error);
+}
+
+/*
+ * Common code for implementing DOS share reservations
+ */
+/* ARGSUSED */
+int
+fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
+ caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+/*ARGSUSED1*/
+int
+fs_vnevent_nosupport(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
+ caller_context_t *ct)
+{
+ ASSERT(vp != NULL);
+ return (ENOTSUP);
+}
+
+/*ARGSUSED1*/
+int
+fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
+ caller_context_t *ct)
+{
+ ASSERT(vp != NULL);
+ return (0);
+}
+
+// fs_acl_nontrivial
+
+/*
+ * Check whether we need a retry to recover from STALE error.
+ */
+int
+fs_need_estale_retry(int retry_count)
+{
+ if (retry_count < fs_estale_retry)
+ return (1);
+ else
+ return (0);
+}
+
+// fs_vscan...
+// reparse...
+
+/*
+ * A few things from os/flock.c
+ */
+
+/* ARGSUSED */
+void
+cleanlocks(vnode_t *vp, pid_t pid, int sysid)
+{
+}
+
+/* ARGSUSED */
+void
+cleanshares(struct vnode *vp, pid_t pid)
+{
+}
+
+/*
+ * convoff - converts the given data (start, whence) to the
+ * given whence.
+ */
+int
+convoff(struct vnode *vp, struct flock64 *lckdat, int whence, offset_t offset)
+{
+ int error;
+ struct vattr vattr;
+
+ if ((lckdat->l_whence == 2) || (whence == 2)) {
+ vattr.va_mask = AT_SIZE;
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
+ return (error);
+ }
+
+ switch (lckdat->l_whence) {
+ case 1:
+ lckdat->l_start += offset;
+ break;
+ case 2:
+ lckdat->l_start += vattr.va_size;
+ /* FALLTHRU */
+ case 0:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ if (lckdat->l_start < 0)
+ return (EINVAL);
+
+ switch (whence) {
+ case 1:
+ lckdat->l_start -= offset;
+ break;
+ case 2:
+ lckdat->l_start -= vattr.va_size;
+ /* FALLTHRU */
+ case 0:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ lckdat->l_whence = (short)whence;
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_getdents.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_getdents.c
new file mode 100644
index 0000000000..afa4eb1c0f
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_getdents.c
@@ -0,0 +1,96 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#include <sys/param.h>
+#include <sys/isa_defs.h>
+#include <sys/types.h>
+#include <sys/inttypes.h>
+#include <sys/sysmacros.h>
+#include <sys/cred.h>
+#include <sys/dirent.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/mode.h>
+#include <sys/uio.h>
+#include <sys/filio.h>
+#include <sys/debug.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+
+/*
+ * Returns count of dir entries, or -errno
+ */
+int
+fake_getdents(vnode_t *vp, offset_t *offp, void *buf, size_t count)
+{
+ struct uio auio;
+ struct iovec aiov;
+ register int error;
+ int sink;
+
+ if (count < sizeof (struct dirent64))
+ return (-EINVAL);
+
+ /*
+ * Don't let the user overcommit kernel resources.
+ */
+ if (count > MAXGETDENTS_SIZE)
+ count = MAXGETDENTS_SIZE;
+
+ if (vp->v_type != VDIR) {
+ return (-ENOTDIR);
+ }
+
+ aiov.iov_base = buf;
+ aiov.iov_len = count;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_loffset = *offp;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_resid = count;
+ auio.uio_fmode = 0;
+ auio.uio_extflg = UIO_COPY_CACHED;
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
+ error = VOP_READDIR(vp, &auio, CRED(), &sink, NULL, 0);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
+ if (error) {
+ return (-error);
+ }
+ count = count - auio.uio_resid;
+ *offp = auio.uio_loffset;
+
+ return (count);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_lookup.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_lookup.c
new file mode 100644
index 0000000000..8072a91b3b
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_lookup.c
@@ -0,0 +1,173 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/pathname.h>
+#include <sys/proc.h>
+#include <sys/vtrace.h>
+#include <sys/sysmacros.h>
+#include <sys/debug.h>
+#include <sys/dirent.h>
+#include <sys/zone.h>
+#include <sys/fs/snode.h>
+
+#include <libfksmbfs.h>
+
+extern vnode_t *rootdir;
+
+/*
+ * Simplified variation on lookuppnvp()
+ */
+int
+fake_lookup(vnode_t *dvp, char *path, vnode_t **vpp)
+{
+ char component[MAXNAMELEN]; /* buffer for component */
+ pathname_t pn;
+ cred_t *cr;
+ vnode_t *cvp; /* current component vp */
+ vnode_t *nvp; /* next component vp */
+ char *p;
+ int flags = 0;
+ int error, len;
+
+ bzero(&pn, sizeof (pn));
+ pn.pn_buf = path;
+ pn.pn_path = path;
+ pn.pn_pathlen = strlen(path);
+ pn.pn_bufsize = pn.pn_pathlen + 1;
+ p = path;
+
+ cr = CRED();
+ cvp = (dvp != NULL) ? dvp : rootdir;
+ VN_HOLD(cvp);
+ nvp = NULL;
+
+ while (*p != '\0') {
+ if (*p == '/') {
+ p++;
+ continue;
+ }
+
+ len = strcspn(p, "/");
+ ASSERT(len > 0);
+ if (len >= MAXNAMELEN)
+ return (EINVAL);
+ (void) strncpy(component, p, len);
+ component[len] = '\0';
+ pn.pn_path = p;
+ pn.pn_pathlen = strlen(p);
+
+ error = VOP_LOOKUP(cvp, component, &nvp, &pn, flags,
+ rootdir, cr, NULL, NULL, NULL);
+ VN_RELE(cvp);
+ if (error != 0)
+ return (error);
+
+ /* Lookup gave us a hold on nvp */
+ cvp = nvp;
+ nvp = NULL;
+ p += len;
+ }
+
+ *vpp = cvp;
+ return (0);
+}
+
+/*
+ * Lookup the directory and find the start of the
+ * last component of the given path.
+ */
+int
+fake_lookup_dir(char *path, vnode_t **vpp, char **lastcomp)
+{
+ vnode_t *dvp;
+ char *last;
+ char *tpn = NULL;
+ int tpn_sz;
+ int lc_off;
+ int error;
+
+ *vpp = NULL;
+ *lastcomp = NULL;
+
+ tpn_sz = strlen(path) + 1;
+ tpn = kmem_alloc(tpn_sz, KM_SLEEP);
+
+ /*
+ * Get a copy of the path, and zap the last /
+ */
+ bcopy(path, tpn, tpn_sz);
+ last = strrchr(tpn, '/');
+ if (last == NULL) {
+ lc_off = 0;
+ dvp = rootdir;
+ VN_HOLD(dvp);
+ error = 0;
+ } else {
+ *last++ = '\0';
+ if (*last == '\0') {
+ error = EINVAL;
+ goto out;
+ }
+ error = fake_lookup(rootdir, tpn, &dvp);
+ if (error != 0) {
+ /* dir not found */
+ goto out;
+ }
+ lc_off = last - tpn;
+ ASSERT(lc_off >= 0 && lc_off < tpn_sz);
+ }
+ *vpp = dvp;
+ *lastcomp = path + lc_off;
+
+out:
+ if (tpn != NULL)
+ kmem_free(tpn, tpn_sz);
+
+ return (error);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_misc.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_misc.c
new file mode 100644
index 0000000000..e5ab8973b4
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_misc.c
@@ -0,0 +1,108 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/cred.h>
+#include <sys/kmem.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+
+volatile int ncsize = 500; /* dnlc.h */
+
+static major_t devcnt = 0x280;
+static kmutex_t udevlock;
+
+/* os/subr.c */
+major_t
+getudev()
+{
+ static major_t next = 0;
+ major_t ret;
+
+ mutex_enter(&udevlock);
+ if (next == 0)
+ next = devcnt;
+ if (next <= L_MAXMAJ32 && next >= devcnt)
+ ret = next++;
+ else {
+ cmn_err(CE_WARN, "out of major numbers");
+ ret = ((major_t)-1);
+ }
+ mutex_exit(&udevlock);
+ return (ret);
+}
+
+/*
+ * Compress 'long' device number encoding to 32-bit device number
+ * encoding. If it won't fit, we return failure, but set the
+ * device number to 32-bit NODEV for the sake of our callers.
+ */
+int
+cmpldev(dev32_t *dst, dev_t dev)
+{
+#if defined(_LP64)
+ if (dev == NODEV) {
+ *dst = (dev32_t)(-1);
+ } else {
+ major_t major = dev >> L_BITSMINOR;
+ minor_t minor = dev & L_MAXMIN;
+
+ if (major > L_MAXMAJ32 || minor > L_MAXMIN32) {
+ *dst = (dev32_t)(-1);
+ return (0);
+ }
+
+ *dst = (dev32_t)((major << L_BITSMINOR32) | minor);
+ }
+#else
+ *dst = (dev32_t)dev;
+#endif
+ return (1);
+}
+
+/* os/cred.c */
+int
+groupmember(gid_t gid, const cred_t *cr)
+{
+ if (gid == 0 || gid == 1)
+ return (1);
+ return (0);
+}
+
+/* os/sig.c */
+
+/* ARGSUSED */
+void
+sigintr(k_sigset_t *smask, int intable)
+{
+}
+
+/* ARGSUSED */
+void
+sigunintr(k_sigset_t *smask)
+{
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_modconf.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_modconf.c
new file mode 100644
index 0000000000..d5482f9cc5
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_modconf.c
@@ -0,0 +1,195 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/cmn_err.h>
+#include <sys/debug.h>
+
+#if 0 // XXX
+
+#include <sys/user.h>
+#include <sys/vm.h>
+#include <sys/conf.h>
+#include <sys/class.h>
+#include <sys/systm.h>
+#include <sys/modctl.h>
+#include <sys/exec.h>
+#include <sys/exechdr.h>
+#include <sys/devops.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/hwconf.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/autoconf.h>
+#include <sys/disp.h>
+#include <sys/kmem.h>
+#include <sys/instance.h>
+#include <sys/modhash.h>
+#include <sys/dacf.h>
+#include <ipp/ipp.h>
+#include <sys/strsubr.h>
+#include <sys/kcpc.h>
+#include <sys/brand.h>
+#include <sys/cpc_pcbe.h>
+#include <sys/kstat.h>
+#include <sys/socketvar.h>
+#include <sys/kiconv.h>
+
+#endif // XXX
+
+#include <libfksmbfs.h>
+
+/*
+ * Install a filesystem.
+ */
+/*ARGSUSED1*/
+int
+fake_installfs(vfsdef_t *def)
+{
+ struct vfssw *vswp;
+ char *fsname = def->name;
+ int fstype; /* index into vfssw[] and vsanchor_fstype[] */
+ int allocated;
+ int err;
+
+ if (def->def_version != VFSDEF_VERSION) {
+ cmn_err(CE_WARN, "file system '%s' version mismatch", fsname);
+ return (ENXIO);
+ }
+
+ allocated = 0;
+
+ WLOCK_VFSSW();
+ if ((vswp = vfs_getvfsswbyname(fsname)) == NULL) {
+ if ((vswp = allocate_vfssw(fsname)) == NULL) {
+ WUNLOCK_VFSSW();
+ /*
+ * See 1095689. If this message appears, then
+ * we either need to make the vfssw table bigger
+ * statically, or make it grow dynamically.
+ */
+ cmn_err(CE_WARN, "no room for '%s' in vfssw!", fsname);
+ return (ENXIO);
+ }
+ allocated = 1;
+ }
+ ASSERT(vswp != NULL);
+
+ fstype = vswp - vfssw; /* Pointer arithmetic to get the fstype */
+
+ /* Turn on everything by default *except* VSW_STATS */
+ vswp->vsw_flag = def->flags & ~(VSW_STATS);
+
+ if (def->flags & VSW_HASPROTO) {
+ vfs_mergeopttbl(&vfs_mntopts, def->optproto,
+ &vswp->vsw_optproto);
+ } else {
+ vfs_copyopttbl(&vfs_mntopts, &vswp->vsw_optproto);
+ }
+
+ if (def->flags & VSW_CANRWRO) {
+ /*
+ * This obviously implies VSW_CANREMOUNT.
+ */
+ vswp->vsw_flag |= VSW_CANREMOUNT;
+ }
+
+ /* vopstats ... */
+
+ if (def->init == NULL)
+ err = EFAULT;
+ else
+ err = (*(def->init))(fstype, fsname);
+
+ if (err != 0) {
+ if (allocated) {
+ kmem_free(vswp->vsw_name, strlen(vswp->vsw_name)+1);
+ vswp->vsw_name = "";
+ }
+ vswp->vsw_flag = 0;
+ vswp->vsw_init = NULL;
+ }
+
+ vfs_unrefvfssw(vswp);
+ WUNLOCK_VFSSW();
+
+ /* ... vopstats */
+
+ return (err);
+}
+
+int fake_removefs_allowed = 1;
+
+/*
+ * Remove a filesystem
+ */
+int
+fake_removefs(vfsdef_t *def)
+{
+ struct vfssw *vswp;
+
+ if (fake_removefs_allowed == 0)
+ return (EBUSY);
+
+ WLOCK_VFSSW();
+ if ((vswp = vfs_getvfsswbyname(def->name)) == NULL) {
+ WUNLOCK_VFSSW();
+ cmn_err(CE_WARN, "fake_removefs: %s not in vfssw",
+ def->name);
+ return (EINVAL);
+ }
+ if (vswp->vsw_count != 1) {
+ vfs_unrefvfssw(vswp);
+ WUNLOCK_VFSSW();
+ return (EBUSY);
+ }
+
+ /*
+ * A mounted filesystem could still have vsw_count = 0
+ * so we must check whether anyone is actually using our ops
+ */
+ if (vfs_opsinuse(&vswp->vsw_vfsops)) {
+ vfs_unrefvfssw(vswp);
+ WUNLOCK_VFSSW();
+ return (EBUSY);
+ }
+
+ vfs_freeopttbl(&vswp->vsw_optproto);
+ vswp->vsw_optproto.mo_count = 0;
+
+ vswp->vsw_flag = 0;
+ vswp->vsw_init = NULL;
+ vfs_unrefvfssw(vswp);
+ WUNLOCK_VFSSW();
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_nbmlock.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_nbmlock.c
new file mode 100644
index 0000000000..c1b5ef63e8
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_nbmlock.c
@@ -0,0 +1,124 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Utility routines and top-level conflict detection code for NBMAND
+ * locks.
+ */
+
+#include <sys/nbmlock.h>
+#include <sys/rwlock.h>
+#include <sys/vnode.h>
+#include <sys/cmn_err.h>
+#include <sys/debug.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/vfs.h>
+
+/*
+ * Enter the critical region for synchronizing I/O requests with lock/share
+ * requests. "mode" specifies whether the caller intends to update
+ * lock/share state (as opposed to just query it).
+ */
+
+void
+nbl_start_crit(vnode_t *vp, krw_t mode)
+{
+ rw_enter(&vp->v_nbllock, mode);
+}
+
+/*
+ * Leave the critical region.
+ */
+
+void
+nbl_end_crit(vnode_t *vp)
+{
+ rw_exit(&vp->v_nbllock);
+}
+
+/*
+ * Return non-zero if some thread is in the critical region.
+ * Note that this is appropriate for use in ASSERT()s only.
+ */
+
+int
+nbl_in_crit(vnode_t *vp)
+{
+ return (RW_LOCK_HELD(&vp->v_nbllock));
+}
+
+/*
+ * Returns non-zero if we need to look further for an NBMAND lock or
+ * share conflict.
+ */
+int
+nbl_need_check(vnode_t *vp)
+{
+ /*
+ * Currently we only check if NBMAND locks/shares are allowed on
+ * the filesystem. An option for the future would be to have a
+ * flag on the vnode, though the locking for that can get tricky.
+ */
+ return ((vp->v_vfsp) && (vp->v_vfsp->vfs_flag & VFS_NBMAND));
+}
+
+/* No locks, so no conflicts. */
+int
+nbl_conflict(vnode_t *vp,
+ nbl_op_t op, /* attempted operation */
+ u_offset_t offset, /* ignore if not I/O */
+ ssize_t length, /* ignore if not I/O */
+ int svmand, /* System V mandatory locking */
+ caller_context_t *ct) /* caller context */
+{
+ ASSERT(nbl_in_crit(vp));
+
+ return (0);
+}
+
+/*
+ * Determine if the given file has mode bits for System V mandatory locks.
+ * If there was an error, the errno value is returned. Otherwise, zero is
+ * returned and *svp is set appropriately (non-zero for mandatory locks,
+ * zero for no mandatory locks).
+ */
+
+int
+nbl_svmand(vnode_t *vp, cred_t *cr, int *svp)
+{
+ struct vattr va;
+ int error;
+
+ va.va_mask = AT_MODE;
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
+ if (error != 0)
+ return (error);
+
+ *svp = MANDLOCK(vp, va.va_mode);
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_open.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_open.c
new file mode 100644
index 0000000000..169197ae03
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_open.c
@@ -0,0 +1,340 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017, Joyent, Inc.
+ * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/*
+ * Portions of code from both of:
+ * syscall/open.c
+ * fs/vnode.c
+ * heavily modified for this use.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/t_lock.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/pathname.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/vnode.h>
+#include <sys/rwstlock.h>
+#include <sys/fem.h>
+#include <sys/stat.h>
+#include <sys/mode.h>
+#include <sys/conf.h>
+#include <sys/sysmacros.h>
+#include <sys/cmn_err.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/acl.h>
+#include <sys/nbmlock.h>
+#include <sys/fcntl.h>
+#include <fs/fs_subr.h>
+#include <sys/taskq.h>
+#include <fs/fs_reparse.h>
+#include <sys/time.h>
+
+#include <libfksmbfs.h>
+
+/* close and release */
+int
+vn_close_rele(vnode_t *vp, int flag)
+{
+ int error;
+
+ error = VOP_CLOSE(vp, flag, 0, 0, CRED(), NULL);
+ vn_rele(vp);
+
+ return (error);
+}
+
+/*
+ * Open/create a vnode.
+ * This may be callable by the kernel, the only known use
+ * of user context being that the current user credentials
+ * are used for permissions. crwhy is defined iff filemode & FCREAT.
+ */
+int
+vn_open(
+ char *pnamep,
+ enum uio_seg seg,
+ int filemode,
+ int createmode,
+ struct vnode **vpp,
+ enum create crwhy,
+ mode_t umask)
+{
+ struct vnode *vp;
+ int mode;
+ int accessflags;
+ int error;
+ int open_done = 0;
+ struct vattr vattr;
+ int estale_retry = 0;
+
+ mode = 0;
+ accessflags = 0;
+ if (filemode & FREAD)
+ mode |= VREAD;
+ if (filemode & (FWRITE|FTRUNC))
+ mode |= VWRITE;
+ if (filemode & (FSEARCH|FEXEC|FXATTRDIROPEN))
+ mode |= VEXEC;
+
+ if (filemode & FAPPEND)
+ accessflags |= V_APPEND;
+
+top:
+ if (filemode & FCREAT) {
+ enum vcexcl excl;
+
+ /*
+ * Wish to create a file.
+ */
+ vattr.va_type = VREG;
+ vattr.va_mode = createmode;
+ vattr.va_mask = AT_TYPE|AT_MODE;
+ if (filemode & FTRUNC) {
+ vattr.va_size = 0;
+ vattr.va_mask |= AT_SIZE;
+ }
+ if (filemode & FEXCL)
+ excl = EXCL;
+ else
+ excl = NONEXCL;
+
+ if ((error =
+ vn_create(pnamep, seg, &vattr, excl, mode, &vp, crwhy,
+ (filemode & ~(FTRUNC|FEXCL)), umask)) != 0)
+ return (error);
+ } else {
+ /*
+ * Wish to open a file. Just look it up.
+ * Was lookupnameat()
+ */
+ if ((error = fake_lookup(NULL, pnamep, &vp)) != 0) {
+ if ((error == ESTALE) &&
+ fs_need_estale_retry(estale_retry++))
+ goto top;
+ return (error);
+ }
+
+ /*
+ * Want the XATTRDIR under it?
+ */
+ if (filemode & FXATTRDIROPEN) {
+ vnode_t *xvp = NULL;
+ error = VOP_LOOKUP(vp, NULL, &xvp, NULL,
+ LOOKUP_XATTR, rootdir, CRED(), NULL,
+ NULL, NULL);
+ VN_RELE(vp);
+ vp = xvp;
+ /* continue with vp */
+ }
+
+ /*
+ * Can't write directories, active texts, or
+ * read-only filesystems. Can't truncate files
+ * on which mandatory locking is in effect.
+ */
+ if (filemode & (FWRITE|FTRUNC)) {
+ if (vp->v_type == VDIR) {
+ error = EISDIR;
+ goto out;
+ }
+ }
+ /*
+ * Check permissions.
+ */
+ if (error = VOP_ACCESS(vp, mode, accessflags, CRED(), NULL))
+ goto out;
+ /*
+ * Require FSEARCH to return a directory.
+ * Require FEXEC to return a regular file.
+ */
+ if ((filemode & FSEARCH) && vp->v_type != VDIR) {
+ error = ENOTDIR;
+ goto out;
+ }
+ if ((filemode & FEXEC) && vp->v_type != VREG) {
+ error = ENOEXEC;
+ goto out;
+ }
+ }
+
+ /*
+ * Do remaining checks for FNOFOLLOW and FNOLINKS.
+ */
+ if ((filemode & FNOFOLLOW) && vp->v_type == VLNK) {
+ error = ELOOP;
+ goto out;
+ }
+ if (filemode & FNOLINKS) {
+ vattr.va_mask = AT_NLINK;
+ if ((error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))) {
+ goto out;
+ }
+ if (vattr.va_nlink != 1) {
+ error = EMLINK;
+ goto out;
+ }
+ }
+
+ /*
+ * Opening a socket corresponding to the AF_UNIX pathname
+ * in the filesystem name space is not supported...
+ */
+ if (vp->v_type == VSOCK) {
+ error = EOPNOTSUPP;
+ goto out;
+ }
+
+ /*
+ * Do opening protocol.
+ */
+ error = VOP_OPEN(&vp, filemode, CRED(), NULL);
+ if (error)
+ goto out;
+ open_done = 1;
+
+ /*
+ * Truncate if required.
+ */
+ if ((filemode & FTRUNC) && !(filemode & FCREAT)) {
+ vattr.va_size = 0;
+ vattr.va_mask = AT_SIZE;
+ if ((error = VOP_SETATTR(vp, &vattr, 0, CRED(), NULL)) != 0)
+ goto out;
+ }
+out:
+ ASSERT(vp->v_count > 0);
+
+ if (error) {
+ if (open_done) {
+ (void) VOP_CLOSE(vp, filemode, 1, (offset_t)0, CRED(),
+ NULL);
+ open_done = 0;
+ }
+ VN_RELE(vp);
+ } else
+ *vpp = vp;
+ return (error);
+}
+
+
+/*
+ * Create a vnode (makenode).
+ */
+int
+vn_create(
+ char *pnamep,
+ enum uio_seg seg,
+ struct vattr *vap,
+ enum vcexcl excl,
+ int mode,
+ struct vnode **vpp,
+ enum create why,
+ int flag,
+ mode_t umask)
+{
+ struct vnode *dvp = NULL; /* ptr to parent dir vnode */
+ char *lastcomp = NULL;
+ int error;
+
+ ASSERT((vap->va_mask & (AT_TYPE|AT_MODE)) == (AT_TYPE|AT_MODE));
+
+ flag &= ~(FNOFOLLOW|FNOLINKS);
+
+ *vpp = NULL;
+
+ /*
+ * Lookup directory and last component
+ */
+ error = fake_lookup_dir(pnamep, &dvp, &lastcomp);
+ if (error != 0) {
+ /* dir not found */
+ return (error);
+ }
+
+ /*
+ * If default ACLs are defined for the directory don't apply the
+ * umask if umask is passed.
+ */
+
+ if (umask) {
+ /*
+ * Apply the umask if no default ACLs...
+ */
+ vap->va_mode &= ~umask;
+ }
+
+ if (dvp->v_vfsp->vfs_flag & VFS_RDONLY) {
+ error = EROFS;
+ goto out;
+ }
+
+ /*
+ * Call mkdir() if specified, otherwise create().
+ */
+ if (why == CRMKDIR) {
+ /*
+ * N.B., if vn_createat() ever requests
+ * case-insensitive behavior then it will need
+ * to be passed to VOP_MKDIR(). VOP_CREATE()
+ * will already get it via "flag"
+ */
+ error = VOP_MKDIR(dvp, lastcomp, vap, vpp, CRED(),
+ NULL, 0, NULL);
+ } else {
+ error = VOP_CREATE(dvp, lastcomp, vap,
+ excl, mode, vpp, CRED(), flag, NULL, NULL);
+ }
+
+out:
+ if (dvp != NULL)
+ VN_RELE(dvp);
+
+ return (error);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_rename.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_rename.c
new file mode 100644
index 0000000000..5ff428593d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_rename.c
@@ -0,0 +1,123 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017, Joyent, Inc.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/*
+ * Portions of code from both of:
+ * syscall/rename.c
+ * fs/vnode.c
+ * heavily modified for this use.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/t_lock.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/pathname.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/vnode.h>
+#include <sys/rwstlock.h>
+#include <sys/fem.h>
+#include <sys/stat.h>
+#include <sys/mode.h>
+#include <sys/conf.h>
+#include <sys/sysmacros.h>
+#include <sys/cmn_err.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/acl.h>
+#include <sys/nbmlock.h>
+#include <sys/fcntl.h>
+#include <fs/fs_subr.h>
+#include <sys/taskq.h>
+#include <fs/fs_reparse.h>
+#include <sys/time.h>
+
+#include <libfksmbfs.h>
+
+int
+fake_rename(char *frompath, char *topath)
+{
+ vnode_t *fdvp = NULL;
+ vnode_t *tdvp = NULL;
+ char *fname = NULL;
+ char *tname = NULL;
+ int error;
+
+ /*
+ * Lookup to and from directories.
+ */
+ if ((error = fake_lookup_dir(frompath, &fdvp, &fname)) != 0)
+ goto out;
+ if ((error = fake_lookup_dir(topath, &tdvp, &tname)) != 0)
+ goto out;
+
+ /*
+ * Make sure both the from vnode directory and the to directory
+ * are in the same vfs and the to directory is writable.
+ */
+ if (fdvp != tdvp && fdvp->v_vfsp != tdvp->v_vfsp) {
+ error = EXDEV;
+ goto out;
+ }
+ if (tdvp->v_vfsp->vfs_flag & VFS_RDONLY) {
+ error = EROFS;
+ goto out;
+ }
+
+ /*
+ * Do the rename.
+ */
+ error = VOP_RENAME(fdvp, fname, tdvp, tname, CRED(), NULL, 0);
+
+out:
+ if (fdvp)
+ VN_RELE(fdvp);
+ if (tdvp)
+ VN_RELE(tdvp);
+
+ return (error);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_rw.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_rw.c
new file mode 100644
index 0000000000..33a63a16dc
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_rw.c
@@ -0,0 +1,203 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/inttypes.h>
+#include <sys/sysmacros.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <sys/uio.h>
+#include <sys/debug.h>
+
+#include <libfksmbfs.h>
+
+#define set_errno(e) (-(e))
+
+ssize_t
+fake_pread(vnode_t *vp, void *cbuf, size_t count, off_t offset)
+{
+ struct uio auio;
+ struct iovec aiov;
+ int fflag, ioflag, rwflag;
+ ssize_t bcount;
+ int error = 0;
+ u_offset_t fileoff = (u_offset_t)(ulong_t)offset;
+ const u_offset_t maxoff = MAXOFF32_T;
+
+ if ((bcount = (ssize_t)count) < 0)
+ return (set_errno(EINVAL));
+ fflag = FREAD;
+
+ rwflag = 0;
+
+ if (vp->v_type == VREG) {
+
+ if (bcount == 0)
+ goto out;
+
+ /*
+ * Return EINVAL if an invalid offset comes to pread.
+ * Negative offset from user will cause this error.
+ */
+
+ if (fileoff > maxoff) {
+ error = EINVAL;
+ goto out;
+ }
+ /*
+ * Limit offset such that we don't read or write
+ * a file beyond the maximum offset representable in
+ * an off_t structure.
+ */
+ if (fileoff + bcount > maxoff)
+ bcount = (ssize_t)((offset_t)maxoff - fileoff);
+ } else if (vp->v_type == VFIFO) {
+ error = ESPIPE;
+ goto out;
+ }
+
+ aiov.iov_base = cbuf;
+ aiov.iov_len = bcount;
+ (void) VOP_RWLOCK(vp, rwflag, NULL);
+ auio.uio_loffset = fileoff;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_resid = bcount;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_llimit = MAXOFFSET_T;
+ auio.uio_fmode = fflag;
+ auio.uio_extflg = UIO_COPY_CACHED;
+
+ ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC);
+
+ /* If read sync is not asked for, filter sync flags */
+ if ((ioflag & FRSYNC) == 0)
+ ioflag &= ~(FSYNC|FDSYNC);
+ error = VOP_READ(vp, &auio, ioflag, CRED(), NULL);
+ bcount -= auio.uio_resid;
+ VOP_RWUNLOCK(vp, rwflag, NULL);
+
+ if (error == EINTR && bcount != 0)
+ error = 0;
+out:
+ if (error)
+ return (set_errno(error));
+ return (bcount);
+}
+
+ssize_t
+fake_pwrite(vnode_t *vp, void *cbuf, size_t count, off_t offset)
+{
+ struct uio auio;
+ struct iovec aiov;
+ int fflag, ioflag, rwflag;
+ ssize_t bcount;
+ int error = 0;
+ u_offset_t fileoff = (u_offset_t)(ulong_t)offset;
+ const u_offset_t maxoff = MAXOFF32_T;
+
+ if ((bcount = (ssize_t)count) < 0)
+ return (set_errno(EINVAL));
+ fflag = FREAD | FWRITE;
+
+ rwflag = 1;
+
+ if (vp->v_type == VREG) {
+
+ if (bcount == 0)
+ goto out;
+
+ /*
+ * return EINVAL for offsets that cannot be
+ * represented in an off_t.
+ */
+ if (fileoff > maxoff) {
+ error = EINVAL;
+ goto out;
+ }
+ /*
+ * Don't allow pwrite to cause file sizes to exceed
+ * maxoff.
+ */
+ if (fileoff == maxoff) {
+ error = EFBIG;
+ goto out;
+ }
+ if (fileoff + count > maxoff)
+ bcount = (ssize_t)((u_offset_t)maxoff - fileoff);
+ } else if (vp->v_type == VFIFO) {
+ error = ESPIPE;
+ goto out;
+ }
+
+ aiov.iov_base = cbuf;
+ aiov.iov_len = bcount;
+ (void) VOP_RWLOCK(vp, rwflag, NULL);
+ auio.uio_loffset = fileoff;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_resid = bcount;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_llimit = MAXOFFSET_T;
+ auio.uio_fmode = fflag;
+ auio.uio_extflg = UIO_COPY_CACHED;
+
+ /*
+ * The SUSv4 POSIX specification states:
+ * The pwrite() function shall be equivalent to write(), except
+ * that it writes into a given position and does not change
+ * the file offset (regardless of whether O_APPEND is set).
+ * To make this be true, we omit the FAPPEND flag from ioflag.
+ */
+ ioflag = auio.uio_fmode & (FSYNC|FDSYNC|FRSYNC);
+
+ error = VOP_WRITE(vp, &auio, ioflag, CRED(), NULL);
+ bcount -= auio.uio_resid;
+ VOP_RWUNLOCK(vp, rwflag, NULL);
+
+ if (error == EINTR && bcount != 0)
+ error = 0;
+out:
+ if (error)
+ return (set_errno(error));
+ return (bcount);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_stat.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_stat.c
new file mode 100644
index 0000000000..5b074e2be9
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_stat.c
@@ -0,0 +1,96 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+/*
+ * Get file attribute information through a file name or a file descriptor.
+ */
+
+#include <sys/param.h>
+#include <sys/isa_defs.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/cred.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/pathname.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/mode.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <sys/uio.h>
+#include <sys/debug.h>
+#include <sys/cmn_err.h>
+#include <fs/fs_subr.h>
+
+#include <libfksmbfs.h>
+
+int
+fake_stat(vnode_t *vp, struct stat64 *ubp, int flag)
+{
+ cred_t *cr = CRED();
+ struct vfssw *vswp;
+ struct stat64 lsb;
+ vattr_t vattr;
+ int error;
+
+ vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
+ if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL))
+ return (error);
+
+ bzero(&lsb, sizeof (lsb));
+ lsb.st_dev = vattr.va_fsid;
+ lsb.st_ino = vattr.va_nodeid;
+ lsb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode;
+ lsb.st_nlink = vattr.va_nlink;
+ lsb.st_uid = vattr.va_uid;
+ lsb.st_gid = vattr.va_gid;
+ lsb.st_rdev = vattr.va_rdev;
+ lsb.st_size = vattr.va_size;
+ lsb.st_atim = vattr.va_atime;
+ lsb.st_mtim = vattr.va_mtime;
+ lsb.st_ctim = vattr.va_ctime;
+ lsb.st_blksize = vattr.va_blksize;
+ lsb.st_blocks = vattr.va_nblocks;
+ if (vp->v_vfsp != NULL) {
+ vswp = &vfssw[vp->v_vfsp->vfs_fstype];
+ if (vswp->vsw_name && *vswp->vsw_name)
+ (void) strcpy(lsb.st_fstype, vswp->vsw_name);
+ }
+ if (copyout(&lsb, ubp, sizeof (lsb)))
+ return (EFAULT);
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_unlink.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_unlink.c
new file mode 100644
index 0000000000..4c35620d29
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_unlink.c
@@ -0,0 +1,91 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+/*
+ * Modified version of syscall/unlink.c
+ */
+
+#include <sys/param.h>
+#include <sys/isa_defs.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+#include <sys/uio.h>
+#include <sys/debug.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+
+#include <libfksmbfs.h>
+
+/*
+ * Unlink a file from a directory
+ * Like syscall/unlinkat.c
+ */
+int
+fake_unlink(char *path, int flags)
+{
+ vnode_t *dvp = NULL;
+ char *lastcomp = NULL;
+ int error;
+
+ if (path == NULL)
+ return (EFAULT);
+
+ error = fake_lookup_dir(path, &dvp, &lastcomp);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Some logic from vn_removeat() here
+ */
+ if (dvp->v_vfsp->vfs_flag & VFS_RDONLY) {
+ error = EROFS;
+ goto out;
+ }
+
+ if (flags == AT_REMOVEDIR) {
+ error = VOP_RMDIR(dvp, lastcomp, NULL, CRED(), NULL, 0);
+ } else {
+ error = VOP_REMOVE(dvp, lastcomp, CRED(), NULL, 0);
+ }
+
+out:
+ if (dvp != NULL)
+ VN_RELE(dvp);
+
+ return (error);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_vfs.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_vfs.c
new file mode 100644
index 0000000000..cc63b01ee1
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_vfs.c
@@ -0,0 +1,2155 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
+ * Copyright 2016 Toomas Soome <tsoome@me.com>
+ * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 RackTop Systems.
+ * Copyright 2018 Nexenta Systems, Inc.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/*
+ * This file contains those functions from fs/vfs.c that can be
+ * used with relatively little change. Functions that differ
+ * significantly from that are in other files.
+ */
+
+#include <sys/types.h>
+#include <sys/t_lock.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/user.h>
+#include <sys/fstyp.h>
+#include <sys/kmem.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/fem.h>
+#include <sys/mntent.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/statfs.h>
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/rwstlock.h>
+#include <sys/dnlc.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/atomic.h>
+#include <sys/cmn_err.h>
+#include <sys/buf.h>
+#include <sys/debug.h>
+#include <sys/vnode.h>
+#include <sys/ddi.h>
+#include <sys/pathname.h>
+#include <sys/poll.h>
+#include <sys/sunddi.h>
+#include <sys/sysmacros.h>
+#include <sys/zone.h>
+#include <sys/policy.h>
+#include <sys/attr.h>
+#include <fs/fs_subr.h>
+
+#include <libfksmbfs.h>
+
+static void vfs_clearmntopt_nolock(mntopts_t *, const char *, int);
+static void vfs_setmntopt_nolock(mntopts_t *, const char *,
+ const char *, int, int);
+static int vfs_optionisset_nolock(const mntopts_t *, const char *, char **);
+// static void vfs_freemnttab(struct vfs *);
+static void vfs_freeopt(mntopt_t *);
+static void vfs_swapopttbl_nolock(mntopts_t *, mntopts_t *);
+static void vfs_swapopttbl(mntopts_t *, mntopts_t *);
+static void vfs_copyopttbl_extend(const mntopts_t *, mntopts_t *, int);
+// static void vfs_createopttbl_extend(mntopts_t *, const char *,
+// const mntopts_t *);
+// static char **vfs_copycancelopt_extend(char **const, int);
+static void vfs_freecancelopt(char **);
+
+/*
+ * VFS global data.
+ */
+vnode_t *rootdir; /* pointer to root inode vnode. */
+struct vfs *rootvfs = NULL; /* pointer to root vfs; head of VFS list. */
+static krwlock_t vfslist;
+struct vfs *zone_vfslist; /* list of FS's mounted in zone */
+
+/* from os/vfs_conf.c */
+const int nfstype = 5;
+struct vfssw vfssw[10] = {
+ { "BADVFS" }, /* 0:invalid */
+ { "" }, /* reserved for loadable fs */
+ { "" },
+ { "" },
+ { "" },
+};
+
+/*
+ * Table for generic options recognized in the VFS layer and acted
+ * on at this level before parsing file system specific options.
+ * The nosuid option is stronger than any of the devices and setuid
+ * options, so those are canceled when nosuid is seen.
+ *
+ * All options which are added here need to be added to the
+ * list of standard options in usr/src/cmd/fs.d/fslib.c as well.
+ */
+/*
+ * VFS Mount options table
+ */
+static char *ro_cancel[] = { MNTOPT_RW, NULL };
+static char *rw_cancel[] = { MNTOPT_RO, NULL };
+static char *suid_cancel[] = { MNTOPT_NOSUID, NULL };
+static char *nosuid_cancel[] = { MNTOPT_SUID, MNTOPT_DEVICES, MNTOPT_NODEVICES,
+ MNTOPT_NOSETUID, MNTOPT_SETUID, NULL };
+static char *devices_cancel[] = { MNTOPT_NODEVICES, NULL };
+static char *nodevices_cancel[] = { MNTOPT_DEVICES, NULL };
+static char *setuid_cancel[] = { MNTOPT_NOSETUID, NULL };
+static char *nosetuid_cancel[] = { MNTOPT_SETUID, NULL };
+static char *nbmand_cancel[] = { MNTOPT_NONBMAND, NULL };
+static char *nonbmand_cancel[] = { MNTOPT_NBMAND, NULL };
+static char *exec_cancel[] = { MNTOPT_NOEXEC, NULL };
+static char *noexec_cancel[] = { MNTOPT_EXEC, NULL };
+
+static const mntopt_t mntopts[] = {
+/*
+ * option name cancel options default arg flags
+ */
+ { MNTOPT_REMOUNT, NULL, NULL,
+ MO_NODISPLAY, (void *)0 },
+ { MNTOPT_RO, ro_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_RW, rw_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_SUID, suid_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NOSUID, nosuid_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_DEVICES, devices_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NODEVICES, nodevices_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_SETUID, setuid_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NOSETUID, nosetuid_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NBMAND, nbmand_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NONBMAND, nonbmand_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_EXEC, exec_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NOEXEC, noexec_cancel, NULL, 0,
+ (void *)0 },
+};
+
+const mntopts_t vfs_mntopts = {
+ sizeof (mntopts) / sizeof (mntopt_t),
+ (mntopt_t *)&mntopts[0]
+};
+
+/*
+ * File system operation dispatch functions.
+ */
+
+int
+fsop_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
+{
+ return (*(vfsp)->vfs_op->vfs_mount)(vfsp, mvp, uap, cr);
+}
+
+int
+fsop_unmount(vfs_t *vfsp, int flag, cred_t *cr)
+{
+ return (*(vfsp)->vfs_op->vfs_unmount)(vfsp, flag, cr);
+}
+
+int
+fsop_root(vfs_t *vfsp, vnode_t **vpp)
+{
+ return ((*(vfsp)->vfs_op->vfs_root)(vfsp, vpp));
+}
+
+int
+fsop_statfs(vfs_t *vfsp, statvfs64_t *sp)
+{
+ return (*(vfsp)->vfs_op->vfs_statvfs)(vfsp, sp);
+}
+
+int
+fsop_sync(vfs_t *vfsp, short flag, cred_t *cr)
+{
+ return (*(vfsp)->vfs_op->vfs_sync)(vfsp, flag, cr);
+}
+
+int
+fsop_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
+{
+ return (*(vfsp)->vfs_op->vfs_vget)(vfsp, vpp, fidp);
+}
+
+int
+fsop_mountroot(vfs_t *vfsp, enum whymountroot reason)
+{
+ return (*(vfsp)->vfs_op->vfs_mountroot)(vfsp, reason);
+}
+
+void
+fsop_freefs(vfs_t *vfsp)
+{
+ (*(vfsp)->vfs_op->vfs_freevfs)(vfsp);
+}
+
+int
+fsop_vnstate(vfs_t *vfsp, vnode_t *vp, vntrans_t nstate)
+{
+ return ((*(vfsp)->vfs_op->vfs_vnstate)(vfsp, vp, nstate));
+}
+
+int
+fsop_sync_by_kind(int fstype, short flag, cred_t *cr)
+{
+ ASSERT((fstype >= 0) && (fstype < nfstype));
+
+ if (ALLOCATED_VFSSW(&vfssw[fstype]) && VFS_INSTALLED(&vfssw[fstype]))
+ return (*vfssw[fstype].vsw_vfsops.vfs_sync) (NULL, flag, cr);
+ else
+ return (ENOTSUP);
+}
+
+/*
+ * File system initialization. vfs_setfsops() must be called from a file
+ * system's init routine.
+ */
+
+static int
+fs_copyfsops(const fs_operation_def_t *template, vfsops_t *actual,
+ int *unused_ops)
+{
+ static const fs_operation_trans_def_t vfs_ops_table[] = {
+ VFSNAME_MOUNT, offsetof(vfsops_t, vfs_mount),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_UNMOUNT, offsetof(vfsops_t, vfs_unmount),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_ROOT, offsetof(vfsops_t, vfs_root),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_STATVFS, offsetof(vfsops_t, vfs_statvfs),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_SYNC, offsetof(vfsops_t, vfs_sync),
+ (fs_generic_func_p) fs_sync,
+ (fs_generic_func_p) fs_sync, /* No errors allowed */
+
+ VFSNAME_VGET, offsetof(vfsops_t, vfs_vget),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_MOUNTROOT, offsetof(vfsops_t, vfs_mountroot),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_FREEVFS, offsetof(vfsops_t, vfs_freevfs),
+ (fs_generic_func_p)fs_freevfs,
+ (fs_generic_func_p)fs_freevfs, /* Shouldn't fail */
+
+ VFSNAME_VNSTATE, offsetof(vfsops_t, vfs_vnstate),
+ (fs_generic_func_p)fs_nosys,
+ (fs_generic_func_p)fs_nosys,
+
+ NULL, 0, NULL, NULL
+ };
+
+ return (fs_build_vector(actual, unused_ops, vfs_ops_table, template));
+}
+
+/* zfs_boot_init() */
+
+int
+vfs_setfsops(int fstype, const fs_operation_def_t *template, vfsops_t **actual)
+{
+ int error;
+ int unused_ops;
+
+ /*
+ * Verify that fstype refers to a valid fs. Note that
+ * 0 is valid since it's used to set "stray" ops.
+ */
+ if ((fstype < 0) || (fstype >= nfstype))
+ return (EINVAL);
+
+ if (!ALLOCATED_VFSSW(&vfssw[fstype]))
+ return (EINVAL);
+
+ /* Set up the operations vector. */
+
+ error = fs_copyfsops(template, &vfssw[fstype].vsw_vfsops, &unused_ops);
+
+ if (error != 0)
+ return (error);
+
+ vfssw[fstype].vsw_flag |= VSW_INSTALLED;
+
+ if (actual != NULL)
+ *actual = &vfssw[fstype].vsw_vfsops;
+
+#if DEBUG
+ if (unused_ops != 0)
+ cmn_err(CE_WARN, "vfs_setfsops: %s: %d operations supplied "
+ "but not used", vfssw[fstype].vsw_name, unused_ops);
+#endif
+
+ return (0);
+}
+
+int
+vfs_makefsops(const fs_operation_def_t *template, vfsops_t **actual)
+{
+ int error;
+ int unused_ops;
+
+ *actual = (vfsops_t *)kmem_alloc(sizeof (vfsops_t), KM_SLEEP);
+
+ error = fs_copyfsops(template, *actual, &unused_ops);
+ if (error != 0) {
+ kmem_free(*actual, sizeof (vfsops_t));
+ *actual = NULL;
+ return (error);
+ }
+
+ return (0);
+}
+
+/*
+ * Free a vfsops structure created as a result of vfs_makefsops().
+ * NOTE: For a vfsops structure initialized by vfs_setfsops(), use
+ * vfs_freevfsops_by_type().
+ */
+void
+vfs_freevfsops(vfsops_t *vfsops)
+{
+ kmem_free(vfsops, sizeof (vfsops_t));
+}
+
+/*
+ * Since the vfsops structure is part of the vfssw table and wasn't
+ * really allocated, we're not really freeing anything. We keep
+ * the name for consistency with vfs_freevfsops(). We do, however,
+ * need to take care of a little bookkeeping.
+ * NOTE: For a vfsops structure created by vfs_setfsops(), use
+ * vfs_freevfsops_by_type().
+ */
+int
+vfs_freevfsops_by_type(int fstype)
+{
+
+ /* Verify that fstype refers to a loaded fs (and not fsid 0). */
+ if ((fstype <= 0) || (fstype >= nfstype))
+ return (EINVAL);
+
+ WLOCK_VFSSW();
+ if ((vfssw[fstype].vsw_flag & VSW_INSTALLED) == 0) {
+ WUNLOCK_VFSSW();
+ return (EINVAL);
+ }
+
+ vfssw[fstype].vsw_flag &= ~VSW_INSTALLED;
+ WUNLOCK_VFSSW();
+
+ return (0);
+}
+
+/* Support routines used to reference vfs_op */
+
+/* Set the operations vector for a vfs */
+void
+vfs_setops(vfs_t *vfsp, vfsops_t *vfsops)
+{
+
+ ASSERT(vfsp != NULL);
+ ASSERT(vfsops != NULL);
+
+ vfsp->vfs_op = vfsops;
+}
+
+/* Retrieve the operations vector for a vfs */
+vfsops_t *
+vfs_getops(vfs_t *vfsp)
+{
+
+ ASSERT(vfsp != NULL);
+
+ return (vfsp->vfs_op);
+}
+
+/*
+ * Returns non-zero (1) if the vfsops matches that of the vfs.
+ * Returns zero (0) if not.
+ */
+int
+vfs_matchops(vfs_t *vfsp, vfsops_t *vfsops)
+{
+ return (vfs_getops(vfsp) == vfsops);
+}
+
+/*
+ * Returns non-zero (1) if the file system has installed a non-default,
+ * non-error vfs_sync routine. Returns zero (0) otherwise.
+ */
+int
+vfs_can_sync(vfs_t *vfsp)
+{
+ /* vfs_sync() routine is not the default/error function */
+ return (vfs_getops(vfsp)->vfs_sync != fs_sync);
+}
+
+/*
+ * Initialize a vfs structure.
+ */
+void
+vfs_init(vfs_t *vfsp, vfsops_t *op, void *data)
+{
+ /* Always do full init, like vfs_alloc() */
+ bzero(vfsp, sizeof (vfs_t));
+ vfsp->vfs_count = 0;
+ vfsp->vfs_next = vfsp;
+ vfsp->vfs_prev = vfsp;
+ vfsp->vfs_zone_next = vfsp;
+ vfsp->vfs_zone_prev = vfsp;
+ vfsp->vfs_lofi_id = 0;
+ sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL);
+ vfsimpl_setup(vfsp);
+ vfsp->vfs_data = (data);
+ vfs_setops((vfsp), (op));
+}
+
+/*
+ * Allocate and initialize the vfs implementation private data
+ * structure, vfs_impl_t.
+ */
+void
+vfsimpl_setup(vfs_t *vfsp)
+{
+ int i;
+
+ if (vfsp->vfs_implp != NULL) {
+ return;
+ }
+
+ vfsp->vfs_implp = kmem_alloc(sizeof (vfs_impl_t), KM_SLEEP);
+ /* Note that these are #define'd in vfs.h */
+ vfsp->vfs_vskap = NULL;
+ vfsp->vfs_fstypevsp = NULL;
+
+ /* Set size of counted array, then zero the array */
+ vfsp->vfs_featureset[0] = VFS_FEATURE_MAXSZ - 1;
+ for (i = 1; i < VFS_FEATURE_MAXSZ; i++) {
+ vfsp->vfs_featureset[i] = 0;
+ }
+}
+
+/*
+ * Release the vfs_impl_t structure, if it exists. Some unbundled
+ * filesystems may not use the newer version of vfs and thus
+ * would not contain this implementation private data structure.
+ */
+void
+vfsimpl_teardown(vfs_t *vfsp)
+{
+ vfs_impl_t *vip = vfsp->vfs_implp;
+
+ if (vip == NULL)
+ return;
+
+ kmem_free(vfsp->vfs_implp, sizeof (vfs_impl_t));
+ vfsp->vfs_implp = NULL;
+}
+
+/*
+ * VFS system calls: mount, umount, syssync, statfs, fstatfs, statvfs,
+ * fstatvfs, and sysfs moved to common/syscall.
+ */
+
+// vfs_sync, sync
+
+/*
+ * External routines.
+ */
+
+krwlock_t vfssw_lock; /* lock accesses to vfssw */
+
+/*
+ * Lock for accessing the vfs linked list. Initialized in vfs_mountroot(),
+ * but otherwise should be accessed only via vfs_list_lock() and
+ * vfs_list_unlock(). Also used to protect the timestamp for mods to the list.
+ */
+static krwlock_t vfslist;
+
+// vfs_mountdevices(void)
+// vfs_mountdev1(void)
+// vfs_mountfs()
+// vfs_mountroot()
+// lofi_add, lofi_remove
+
+
+/*
+ * Mount the FS for the test jig. Based on domount()
+ */
+int
+fake_domount(char *fsname, struct mounta *uap, struct vfs **vfspp)
+{
+ vnode_t *vp;
+ struct cred *credp;
+ struct vfssw *vswp;
+ vfsops_t *vfsops;
+ struct vfs *vfsp = NULL;
+ mntopts_t mnt_mntopts;
+ int error = 0;
+ int copyout_error = 0;
+ char *opts = uap->optptr;
+ char *inargs = opts;
+ int optlen = uap->optlen;
+
+ credp = CRED();
+
+ /*
+ * Test jig specific: mount on rootdir
+ */
+ if (rootvfs != NULL)
+ return (EBUSY);
+ vp = rootdir;
+
+ /*
+ * The v_flag value for the mount point vp is permanently set
+ * to VVFSLOCK so that no one bypasses the vn_vfs*locks routine
+ * for mount point locking.
+ */
+ mutex_enter(&vp->v_lock);
+ vp->v_flag |= VVFSLOCK;
+ mutex_exit(&vp->v_lock);
+
+ mnt_mntopts.mo_count = 0;
+
+ /*
+ * Find the ops vector to use to invoke the file system-specific mount
+ * method. If the fsname argument is non-NULL, use it directly.
+ */
+ if ((vswp = vfs_getvfssw(fsname)) == NULL) {
+ return (EINVAL);
+ }
+ if (!VFS_INSTALLED(vswp))
+ return (EINVAL);
+
+ // secpolicy_fs_allowed_mount(fsname)
+
+ vfsops = &vswp->vsw_vfsops;
+
+ vfs_copyopttbl(&vswp->vsw_optproto, &mnt_mntopts);
+
+ /*
+ * Fetch mount options and parse them for generic vfs options
+ */
+ if (uap->flags & MS_OPTIONSTR) {
+ /*
+ * Limit the buffer size
+ */
+ if (optlen < 0 || optlen > MAX_MNTOPT_STR) {
+ error = EINVAL;
+ goto errout;
+ }
+ if ((uap->flags & MS_SYSSPACE) == 0) {
+ inargs = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP);
+ inargs[0] = '\0';
+ if (optlen) {
+ error = copyinstr(opts, inargs, (size_t)optlen,
+ NULL);
+ if (error) {
+ goto errout;
+ }
+ }
+ }
+ vfs_parsemntopts(&mnt_mntopts, inargs, 0);
+ }
+ /*
+ * Flag bits override the options string.
+ */
+ if (uap->flags & MS_REMOUNT)
+ vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_REMOUNT, NULL, 0, 0);
+ if (uap->flags & MS_RDONLY)
+ vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_RO, NULL, 0, 0);
+ if (uap->flags & MS_NOSUID)
+ vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
+
+ /*
+ * Check if this is a remount; must be set in the option string and
+ * the file system must support a remount option.
+ */
+ if (vfs_optionisset_nolock(&mnt_mntopts,
+ MNTOPT_REMOUNT, NULL)) {
+ /* disallow here */
+ error = ENOTSUP;
+ goto errout;
+ }
+
+ /*
+ * uap->flags and vfs_optionisset() should agree.
+ */
+ if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_RO, NULL)) {
+ uap->flags |= MS_RDONLY;
+ }
+ if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL)) {
+ uap->flags |= MS_NOSUID;
+ }
+ // nbmand ...
+
+ /*
+ * If we are splicing the fs into the namespace,
+ * perform mount point checks...
+ * (always splice=0 here)
+ */
+
+ if ((uap->flags & (MS_DATA | MS_OPTIONSTR)) == 0) {
+ uap->dataptr = NULL;
+ uap->datalen = 0;
+ }
+
+ /*
+ * If this is a remount, ... (never here)
+ */
+ vfsp = vfs_alloc(KM_SLEEP);
+ VFS_INIT(vfsp, vfsops, NULL);
+
+ VFS_HOLD(vfsp);
+
+ // lofi_add(fsname, vfsp, &mnt_mntopts, uap)
+
+ /*
+ * PRIV_SYS_MOUNT doesn't mean you can become root.
+ */
+ uap->flags |= MS_NOSUID;
+ vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
+
+ /*
+ * The vfs_reflock...
+ */
+
+ /*
+ * Lock the vfs...
+ */
+ if ((error = vfs_lock(vfsp)) != 0) {
+ vfs_free(vfsp);
+ vfsp = NULL;
+ goto errout;
+ }
+
+ /*
+ * Add device to mount in progress table...
+ */
+ /*
+ * Invalidate cached entry for the mount point.
+ */
+
+ /*
+ * If have an option string but the filesystem doesn't supply a
+ * prototype options table, create a table...
+ */
+
+ /*
+ * Serialize with zone state transitions...
+ */
+
+ // mount_in_progress(zone);
+
+ /*
+ * Instantiate (or reinstantiate) the file system...
+ */
+ vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts);
+
+ vfs_setresource(vfsp, uap->spec, 0);
+ vfs_setmntpoint(vfsp, uap->dir, 0);
+
+ /*
+ * going to mount on this vnode, so notify.
+ */
+ // vnevent_mountedover(vp, NULL);
+ error = VFS_MOUNT(vfsp, vp, uap, credp);
+
+ if (uap->flags & MS_RDONLY)
+ vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
+ if (uap->flags & MS_NOSUID)
+ vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0);
+ if (uap->flags & MS_GLOBAL)
+ vfs_setmntopt(vfsp, MNTOPT_GLOBAL, NULL, 0);
+
+ if (error) {
+ // lofi_remove(vfsp);
+
+ // (remount == 0)
+ vfs_unlock(vfsp);
+ // vfs_freemnttab(vfsp);
+ vfs_free(vfsp);
+ vfsp = NULL;
+ } else {
+ /*
+ * Set the mount time to now
+ */
+ // vfsp->vfs_mtime = ddi_get_time();
+ // if (remount) ...
+ // else if (splice) vfs_add(vp, vfsp, flags)
+ // else VFS_HOLD(vfsp);
+
+ /*
+ * Test jig specific:
+ * Do sort of like vfs_add for vp=rootdir
+ * Already have hold on vp.
+ */
+ vfsp->vfs_vnodecovered = vp;
+ vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES);
+ VFS_HOLD(vfsp);
+ rootvfs = vfsp;
+
+ /*
+ * Set flags for global options encountered
+ */
+ if (vfs_optionisset(vfsp, MNTOPT_RO, NULL))
+ vfsp->vfs_flag |= VFS_RDONLY;
+ else
+ vfsp->vfs_flag &= ~VFS_RDONLY;
+ if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) {
+ vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES);
+ } else {
+ if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL))
+ vfsp->vfs_flag |= VFS_NODEVICES;
+ else
+ vfsp->vfs_flag &= ~VFS_NODEVICES;
+ if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))
+ vfsp->vfs_flag |= VFS_NOSETUID;
+ else
+ vfsp->vfs_flag &= ~VFS_NOSETUID;
+ }
+ if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL))
+ vfsp->vfs_flag |= VFS_NBMAND;
+ else
+ vfsp->vfs_flag &= ~VFS_NBMAND;
+
+ if (vfs_optionisset(vfsp, MNTOPT_XATTR, NULL))
+ vfsp->vfs_flag |= VFS_XATTR;
+ else
+ vfsp->vfs_flag &= ~VFS_XATTR;
+
+ if (vfs_optionisset(vfsp, MNTOPT_NOEXEC, NULL))
+ vfsp->vfs_flag |= VFS_NOEXEC;
+ else
+ vfsp->vfs_flag &= ~VFS_NOEXEC;
+
+ /*
+ * Now construct the output option string of options
+ * we recognized.
+ */
+ if (uap->flags & MS_OPTIONSTR) {
+ vfs_list_read_lock();
+ copyout_error = vfs_buildoptionstr(
+ &vfsp->vfs_mntopts, inargs, optlen);
+ vfs_list_unlock();
+ if (copyout_error == 0 &&
+ (uap->flags & MS_SYSSPACE) == 0) {
+ copyout_error = copyout(inargs, opts, optlen);
+ }
+ }
+
+ /*
+ * If this isn't a remount, set up the vopstats...
+ */
+ if (vswp->vsw_flag & VSW_XID)
+ vfsp->vfs_flag |= VFS_XID;
+
+ vfs_unlock(vfsp);
+
+ /*
+ * Test jig specicific:
+ * Replace rootdir with the mounted root.
+ */
+ error = VFS_ROOT(vfsp, &rootdir);
+ if (error != 0) {
+ panic("fake_domount, get root %d\n", error);
+ }
+ }
+ // mount_completed(zone);
+ // zone_rele(zone);
+
+ // if (splice)
+ // vn_vfsunlock(vp);
+
+ if ((error == 0) && (copyout_error == 0)) {
+ /* get_vskstat_anchor() */
+ /* Return vfsp to caller. */
+ *vfspp = vfsp;
+ }
+errout:
+ vfs_freeopttbl(&mnt_mntopts);
+ /* resource, mountpt not allocated */
+ /* no addmip, delmip */
+ ASSERT(vswp != NULL);
+ vfs_unrefvfssw(vswp);
+ if (inargs != opts)
+ kmem_free(inargs, MAX_MNTOPT_STR);
+ if (copyout_error) {
+ if (vfsp != NULL) {
+ // lofi_remove(vfsp);
+ VFS_RELE(vfsp);
+ }
+ error = copyout_error;
+ }
+ return (error);
+}
+
+
+static void
+vfs_setpath(
+ struct vfs *vfsp, /* vfs being updated */
+ refstr_t **refp, /* Ref-count string to contain the new path */
+ const char *newpath, /* Path to add to refp (above) */
+ uint32_t flag) /* flag */
+{
+ // size_t len;
+ refstr_t *ref;
+ // char *sp;
+ int have_list_lock = 0;
+
+ ASSERT(!VFS_ON_LIST(vfsp) || vfs_lock_held(vfsp));
+
+ /*
+ * New path must be less than MAXPATHLEN because mntfs
+ * will only display up to MAXPATHLEN bytes. This is currently
+ * safe, because domount() uses pn_get(), and other callers
+ * similarly cap the size to fewer than MAXPATHLEN bytes.
+ */
+
+ ASSERT(strlen(newpath) < MAXPATHLEN);
+
+ /* mntfs requires consistency while vfs list lock is held */
+
+ if (VFS_ON_LIST(vfsp)) {
+ have_list_lock = 1;
+ vfs_list_lock();
+ }
+
+ if (*refp != NULL)
+ refstr_rele(*refp);
+
+ /*
+ * If we are in a non-global zone... (do something else)
+ */
+ ref = refstr_alloc(newpath);
+ *refp = ref;
+
+ if (have_list_lock) {
+ vfs_mnttab_modtimeupd();
+ vfs_list_unlock();
+ }
+}
+
+/*
+ * Record a mounted resource name in a vfs structure.
+ * If vfsp is already mounted, caller must hold the vfs lock.
+ */
+void
+vfs_setresource(struct vfs *vfsp, const char *resource, uint32_t flag)
+{
+ if (resource == NULL || resource[0] == '\0')
+ resource = VFS_NORESOURCE;
+ vfs_setpath(vfsp, &vfsp->vfs_resource, resource, flag);
+}
+
+/*
+ * Record a mount point name in a vfs structure.
+ * If vfsp is already mounted, caller must hold the vfs lock.
+ */
+void
+vfs_setmntpoint(struct vfs *vfsp, const char *mntpt, uint32_t flag)
+{
+ if (mntpt == NULL || mntpt[0] == '\0')
+ mntpt = VFS_NOMNTPT;
+ vfs_setpath(vfsp, &vfsp->vfs_mntpt, mntpt, flag);
+}
+
+/* Returns the vfs_resource. Caller must call refstr_rele() when finished. */
+
+refstr_t *
+vfs_getresource(const struct vfs *vfsp)
+{
+ refstr_t *resource;
+
+ vfs_list_read_lock();
+ resource = vfsp->vfs_resource;
+ refstr_hold(resource);
+ vfs_list_unlock();
+
+ return (resource);
+}
+
+/* Returns the vfs_mntpt. Caller must call refstr_rele() when finished. */
+
+refstr_t *
+vfs_getmntpoint(const struct vfs *vfsp)
+{
+ refstr_t *mntpt;
+
+ vfs_list_read_lock();
+ mntpt = vfsp->vfs_mntpt;
+ refstr_hold(mntpt);
+ vfs_list_unlock();
+
+ return (mntpt);
+}
+
+// vfs_createopttbl_extend
+// vfs_createopttbl
+
+/*
+ * Swap two mount options tables
+ */
+static void
+vfs_swapopttbl_nolock(mntopts_t *optbl1, mntopts_t *optbl2)
+{
+ uint_t tmpcnt;
+ mntopt_t *tmplist;
+
+ tmpcnt = optbl2->mo_count;
+ tmplist = optbl2->mo_list;
+ optbl2->mo_count = optbl1->mo_count;
+ optbl2->mo_list = optbl1->mo_list;
+ optbl1->mo_count = tmpcnt;
+ optbl1->mo_list = tmplist;
+}
+
+static void
+vfs_swapopttbl(mntopts_t *optbl1, mntopts_t *optbl2)
+{
+ vfs_list_lock();
+ vfs_swapopttbl_nolock(optbl1, optbl2);
+ vfs_mnttab_modtimeupd();
+ vfs_list_unlock();
+}
+
+static char **
+vfs_copycancelopt_extend(char **const moc, int extend)
+{
+ int i = 0;
+ int j;
+ char **result;
+
+ if (moc != NULL) {
+ for (; moc[i] != NULL; i++)
+ /* count number of options to cancel */;
+ }
+
+ if (i + extend == 0)
+ return (NULL);
+
+ result = kmem_alloc((i + extend + 1) * sizeof (char *), KM_SLEEP);
+
+ for (j = 0; j < i; j++) {
+ result[j] = kmem_alloc(strlen(moc[j]) + 1, KM_SLEEP);
+ (void) strcpy(result[j], moc[j]);
+ }
+ for (; j <= i + extend; j++)
+ result[j] = NULL;
+
+ return (result);
+}
+
+static void
+vfs_copyopt(const mntopt_t *s, mntopt_t *d)
+{
+ char *sp, *dp;
+
+ d->mo_flags = s->mo_flags;
+ d->mo_data = s->mo_data;
+ sp = s->mo_name;
+ if (sp != NULL) {
+ dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
+ (void) strcpy(dp, sp);
+ d->mo_name = dp;
+ } else {
+ d->mo_name = NULL; /* should never happen */
+ }
+
+ d->mo_cancel = vfs_copycancelopt_extend(s->mo_cancel, 0);
+
+ sp = s->mo_arg;
+ if (sp != NULL) {
+ dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
+ (void) strcpy(dp, sp);
+ d->mo_arg = dp;
+ } else {
+ d->mo_arg = NULL;
+ }
+}
+
+// vfs_copyopttbl_extend
+// vfs_copyopttbl
+
+/*
+ * Copy a mount options table, possibly allocating some spare
+ * slots at the end. It is permissible to copy_extend the NULL table.
+ */
+static void
+vfs_copyopttbl_extend(const mntopts_t *smo, mntopts_t *dmo, int extra)
+{
+ uint_t i, count;
+ mntopt_t *motbl;
+
+ /*
+ * Clear out any existing stuff in the options table being initialized
+ */
+ vfs_freeopttbl(dmo);
+ count = (smo == NULL) ? 0 : smo->mo_count;
+ if ((count + extra) == 0) /* nothing to do */
+ return;
+ dmo->mo_count = count + extra;
+ motbl = kmem_zalloc((count + extra) * sizeof (mntopt_t), KM_SLEEP);
+ dmo->mo_list = motbl;
+ for (i = 0; i < count; i++) {
+ vfs_copyopt(&smo->mo_list[i], &motbl[i]);
+ }
+ for (i = count; i < count + extra; i++) {
+ motbl[i].mo_flags = MO_EMPTY;
+ }
+}
+
+/*
+ * Copy a mount options table.
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect smo and dmo.
+ */
+void
+vfs_copyopttbl(const mntopts_t *smo, mntopts_t *dmo)
+{
+ vfs_copyopttbl_extend(smo, dmo, 0);
+}
+
+static char **
+vfs_mergecancelopts(const mntopt_t *mop1, const mntopt_t *mop2)
+{
+ int c1 = 0;
+ int c2 = 0;
+ char **result;
+ char **sp1, **sp2, **dp;
+
+ /*
+ * First we count both lists of cancel options.
+ * If either is NULL or has no elements, we return a copy of
+ * the other.
+ */
+ if (mop1->mo_cancel != NULL) {
+ for (; mop1->mo_cancel[c1] != NULL; c1++)
+ /* count cancel options in mop1 */;
+ }
+
+ if (c1 == 0)
+ return (vfs_copycancelopt_extend(mop2->mo_cancel, 0));
+
+ if (mop2->mo_cancel != NULL) {
+ for (; mop2->mo_cancel[c2] != NULL; c2++)
+ /* count cancel options in mop2 */;
+ }
+
+ result = vfs_copycancelopt_extend(mop1->mo_cancel, c2);
+
+ if (c2 == 0)
+ return (result);
+
+ /*
+ * When we get here, we've got two sets of cancel options;
+ * we need to merge the two sets. We know that the result
+ * array has "c1+c2+1" entries and in the end we might shrink
+ * it.
+ * Result now has a copy of the c1 entries from mop1; we'll
+ * now lookup all the entries of mop2 in mop1 and copy it if
+ * it is unique.
+ * This operation is O(n^2) but it's only called once per
+ * filesystem per duplicate option. This is a situation
+ * which doesn't arise with the filesystems in ON and
+ * n is generally 1.
+ */
+
+ dp = &result[c1];
+ for (sp2 = mop2->mo_cancel; *sp2 != NULL; sp2++) {
+ for (sp1 = mop1->mo_cancel; *sp1 != NULL; sp1++) {
+ if (strcmp(*sp1, *sp2) == 0)
+ break;
+ }
+ if (*sp1 == NULL) {
+ /*
+ * Option *sp2 not found in mop1, so copy it.
+ * The calls to vfs_copycancelopt_extend()
+ * guarantee that there's enough room.
+ */
+ *dp = kmem_alloc(strlen(*sp2) + 1, KM_SLEEP);
+ (void) strcpy(*dp++, *sp2);
+ }
+ }
+ if (dp != &result[c1+c2]) {
+ size_t bytes = (dp - result + 1) * sizeof (char *);
+ char **nres = kmem_alloc(bytes, KM_SLEEP);
+
+ bcopy(result, nres, bytes);
+ kmem_free(result, (c1 + c2 + 1) * sizeof (char *));
+ result = nres;
+ }
+ return (result);
+}
+
+/*
+ * Merge two mount option tables (outer and inner) into one. This is very
+ * similar to "merging" global variables and automatic variables in C.
+ *
+ * This isn't (and doesn't have to be) fast.
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect omo, imo & dmo.
+ */
+void
+vfs_mergeopttbl(const mntopts_t *omo, const mntopts_t *imo, mntopts_t *dmo)
+{
+ uint_t i, count;
+ mntopt_t *mop, *motbl;
+ uint_t freeidx;
+
+ /*
+ * First determine how much space we need to allocate.
+ */
+ count = omo->mo_count;
+ for (i = 0; i < imo->mo_count; i++) {
+ if (imo->mo_list[i].mo_flags & MO_EMPTY)
+ continue;
+ if (vfs_hasopt(omo, imo->mo_list[i].mo_name) == NULL)
+ count++;
+ }
+ ASSERT(count >= omo->mo_count &&
+ count <= omo->mo_count + imo->mo_count);
+ motbl = kmem_alloc(count * sizeof (mntopt_t), KM_SLEEP);
+ for (i = 0; i < omo->mo_count; i++)
+ vfs_copyopt(&omo->mo_list[i], &motbl[i]);
+ freeidx = omo->mo_count;
+ for (i = 0; i < imo->mo_count; i++) {
+ if (imo->mo_list[i].mo_flags & MO_EMPTY)
+ continue;
+ if ((mop = vfs_hasopt(omo, imo->mo_list[i].mo_name)) != NULL) {
+ char **newcanp;
+ uint_t index = mop - omo->mo_list;
+
+ newcanp = vfs_mergecancelopts(mop, &motbl[index]);
+
+ vfs_freeopt(&motbl[index]);
+ vfs_copyopt(&imo->mo_list[i], &motbl[index]);
+
+ vfs_freecancelopt(motbl[index].mo_cancel);
+ motbl[index].mo_cancel = newcanp;
+ } else {
+ /*
+ * If it's a new option, just copy it over to the first
+ * free location.
+ */
+ vfs_copyopt(&imo->mo_list[i], &motbl[freeidx++]);
+ }
+ }
+ dmo->mo_count = count;
+ dmo->mo_list = motbl;
+}
+
+/*
+ * Functions to set and clear mount options in a mount options table.
+ */
+
+/*
+ * Clear a mount option, if it exists.
+ *
+ * The update_mnttab arg indicates whether mops is part of a vfs that is on
+ * the vfs list.
+ */
+static void
+vfs_clearmntopt_nolock(mntopts_t *mops, const char *opt, int update_mnttab)
+{
+ struct mntopt *mop;
+ uint_t i, count;
+
+ ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist));
+
+ count = mops->mo_count;
+ for (i = 0; i < count; i++) {
+ mop = &mops->mo_list[i];
+
+ if (mop->mo_flags & MO_EMPTY)
+ continue;
+ if (strcmp(opt, mop->mo_name))
+ continue;
+ mop->mo_flags &= ~MO_SET;
+ if (mop->mo_arg != NULL) {
+ kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
+ }
+ mop->mo_arg = NULL;
+ if (update_mnttab)
+ vfs_mnttab_modtimeupd();
+ break;
+ }
+}
+
+void
+vfs_clearmntopt(struct vfs *vfsp, const char *opt)
+{
+ int gotlock = 0;
+
+ if (VFS_ON_LIST(vfsp)) {
+ gotlock = 1;
+ vfs_list_lock();
+ }
+ vfs_clearmntopt_nolock(&vfsp->vfs_mntopts, opt, gotlock);
+ if (gotlock)
+ vfs_list_unlock();
+}
+
+
+/*
+ * Set a mount option on...
+ */
+static void
+vfs_setmntopt_nolock(mntopts_t *mops, const char *opt,
+ const char *arg, int flags, int update_mnttab)
+{
+ mntopt_t *mop;
+ uint_t i, count;
+ char *sp;
+
+ ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist));
+
+ if (flags & VFS_CREATEOPT) {
+ if (vfs_hasopt(mops, opt) != NULL) {
+ flags &= ~VFS_CREATEOPT;
+ }
+ }
+ count = mops->mo_count;
+ for (i = 0; i < count; i++) {
+ mop = &mops->mo_list[i];
+
+ if (mop->mo_flags & MO_EMPTY) {
+ if ((flags & VFS_CREATEOPT) == 0)
+ continue;
+ sp = kmem_alloc(strlen(opt) + 1, KM_SLEEP);
+ (void) strcpy(sp, opt);
+ mop->mo_name = sp;
+ if (arg != NULL)
+ mop->mo_flags = MO_HASVALUE;
+ else
+ mop->mo_flags = 0;
+ } else if (strcmp(opt, mop->mo_name)) {
+ continue;
+ }
+ if ((mop->mo_flags & MO_IGNORE) && (flags & VFS_NOFORCEOPT))
+ break;
+ if (arg != NULL && (mop->mo_flags & MO_HASVALUE) != 0) {
+ sp = kmem_alloc(strlen(arg) + 1, KM_SLEEP);
+ (void) strcpy(sp, arg);
+ } else {
+ sp = NULL;
+ }
+ if (mop->mo_arg != NULL)
+ kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
+ mop->mo_arg = sp;
+ if (flags & VFS_DISPLAY)
+ mop->mo_flags &= ~MO_NODISPLAY;
+ if (flags & VFS_NODISPLAY)
+ mop->mo_flags |= MO_NODISPLAY;
+ mop->mo_flags |= MO_SET;
+ if (mop->mo_cancel != NULL) {
+ char **cp;
+
+ for (cp = mop->mo_cancel; *cp != NULL; cp++)
+ vfs_clearmntopt_nolock(mops, *cp, 0);
+ }
+ if (update_mnttab)
+ vfs_mnttab_modtimeupd();
+ break;
+ }
+}
+
+void
+vfs_setmntopt(struct vfs *vfsp, const char *opt, const char *arg, int flags)
+{
+ int gotlock = 0;
+
+ if (VFS_ON_LIST(vfsp)) {
+ gotlock = 1;
+ vfs_list_lock();
+ }
+ vfs_setmntopt_nolock(&vfsp->vfs_mntopts, opt, arg, flags, gotlock);
+ if (gotlock)
+ vfs_list_unlock();
+}
+
+// vfs_addtag
+// vfs_settag
+// vfs_clrtag
+
+/*
+ * Function to parse an option string and fill in a mount options table.
+ * Unknown options are silently ignored. The input option string is modified
+ * by replacing separators with nulls. If the create flag is set, options
+ * not found in the table are just added on the fly. The table must have
+ * an option slot marked MO_EMPTY to add an option on the fly.
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect mops..
+ */
+void
+vfs_parsemntopts(mntopts_t *mops, char *osp, int create)
+{
+ char *s = osp, *p, *nextop, *valp, *cp, *ep = NULL;
+ int setflg = VFS_NOFORCEOPT;
+
+ if (osp == NULL)
+ return;
+ while (*s != '\0') {
+ p = strchr(s, ','); /* find next option */
+ if (p == NULL) {
+ cp = NULL;
+ p = s + strlen(s);
+ } else {
+ cp = p; /* save location of comma */
+ *p++ = '\0'; /* mark end and point to next option */
+ }
+ nextop = p;
+ p = strchr(s, '='); /* look for value */
+ if (p == NULL) {
+ valp = NULL; /* no value supplied */
+ ep = NULL;
+ } else {
+ ep = p; /* save location of equals */
+ *p++ = '\0'; /* end option and point to value */
+ valp = p;
+ }
+ /*
+ * set option into options table
+ */
+ if (create)
+ setflg |= VFS_CREATEOPT;
+ vfs_setmntopt_nolock(mops, s, valp, setflg, 0);
+ if (cp != NULL)
+ *cp = ','; /* restore the comma */
+ if (valp != NULL)
+ *ep = '='; /* restore the equals */
+ s = nextop;
+ }
+}
+
+/*
+ * Function to inquire if an option exists in a mount options table.
+ * Returns a pointer to the option if it exists, else NULL.
+ */
+struct mntopt *
+vfs_hasopt(const mntopts_t *mops, const char *opt)
+{
+ struct mntopt *mop;
+ uint_t i, count;
+
+ count = mops->mo_count;
+ for (i = 0; i < count; i++) {
+ mop = &mops->mo_list[i];
+
+ if (mop->mo_flags & MO_EMPTY)
+ continue;
+ if (strcmp(opt, mop->mo_name) == 0)
+ return (mop);
+ }
+ return (NULL);
+}
+
+/*
+ * Function to inquire if an option is set in a mount options table.
+ * Returns non-zero if set and fills in the arg pointer with a pointer to
+ * the argument string or NULL if there is no argument string.
+ */
+static int
+vfs_optionisset_nolock(const mntopts_t *mops, const char *opt, char **argp)
+{
+ struct mntopt *mop;
+ uint_t i, count;
+
+ count = mops->mo_count;
+ for (i = 0; i < count; i++) {
+ mop = &mops->mo_list[i];
+
+ if (mop->mo_flags & MO_EMPTY)
+ continue;
+ if (strcmp(opt, mop->mo_name))
+ continue;
+ if ((mop->mo_flags & MO_SET) == 0)
+ return (0);
+ if (argp != NULL && (mop->mo_flags & MO_HASVALUE) != 0)
+ *argp = mop->mo_arg;
+ return (1);
+ }
+ return (0);
+}
+
+
+int
+vfs_optionisset(const struct vfs *vfsp, const char *opt, char **argp)
+{
+ int ret;
+
+ vfs_list_read_lock();
+ ret = vfs_optionisset_nolock(&vfsp->vfs_mntopts, opt, argp);
+ vfs_list_unlock();
+ return (ret);
+}
+
+
+/*
+ * Construct a comma separated string of the options set in the given
+ * mount table, return the string in the given buffer. Return non-zero if
+ * the buffer would overflow.
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect mp.
+ */
+int
+vfs_buildoptionstr(const mntopts_t *mp, char *buf, int len)
+{
+ char *cp;
+ uint_t i;
+
+ buf[0] = '\0';
+ cp = buf;
+ for (i = 0; i < mp->mo_count; i++) {
+ struct mntopt *mop;
+
+ mop = &mp->mo_list[i];
+ if (mop->mo_flags & MO_SET) {
+ int optlen, comma = 0;
+
+ if (buf[0] != '\0')
+ comma = 1;
+ optlen = strlen(mop->mo_name);
+ if (strlen(buf) + comma + optlen + 1 > len)
+ goto err;
+ if (comma)
+ *cp++ = ',';
+ (void) strcpy(cp, mop->mo_name);
+ cp += optlen;
+ /*
+ * Append option value if there is one
+ */
+ if (mop->mo_arg != NULL) {
+ int arglen;
+
+ arglen = strlen(mop->mo_arg);
+ if (strlen(buf) + arglen + 2 > len)
+ goto err;
+ *cp++ = '=';
+ (void) strcpy(cp, mop->mo_arg);
+ cp += arglen;
+ }
+ }
+ }
+ return (0);
+err:
+ return (EOVERFLOW);
+}
+
+static void
+vfs_freecancelopt(char **moc)
+{
+ if (moc != NULL) {
+ int ccnt = 0;
+ char **cp;
+
+ for (cp = moc; *cp != NULL; cp++) {
+ kmem_free(*cp, strlen(*cp) + 1);
+ ccnt++;
+ }
+ kmem_free(moc, (ccnt + 1) * sizeof (char *));
+ }
+}
+
+static void
+vfs_freeopt(mntopt_t *mop)
+{
+ if (mop->mo_name != NULL)
+ kmem_free(mop->mo_name, strlen(mop->mo_name) + 1);
+
+ vfs_freecancelopt(mop->mo_cancel);
+
+ if (mop->mo_arg != NULL)
+ kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
+}
+
+/*
+ * Free a mount options table
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect mp.
+ */
+void
+vfs_freeopttbl(mntopts_t *mp)
+{
+ uint_t i, count;
+
+ count = mp->mo_count;
+ for (i = 0; i < count; i++) {
+ vfs_freeopt(&mp->mo_list[i]);
+ }
+ if (count) {
+ kmem_free(mp->mo_list, sizeof (mntopt_t) * count);
+ mp->mo_count = 0;
+ mp->mo_list = NULL;
+ }
+}
+
+// vfs_mntdummyread
+// vfs_mntdummywrite
+// vfs_mntdummygetattr
+// vfs_mnttabvp_setup
+// vfs_mnttab_rwop
+// vfs_mnttab_writeop
+// vfs_mnttab_readop
+// vfs_freemnttab
+// vfs_mnttab_modtime
+// vfs_mnttab_poll
+// vfs_mono_time
+
+/*
+ * Update the mnttab modification time...
+ */
+void
+vfs_mnttab_modtimeupd()
+{
+}
+
+/*
+ * Unlike the real dounmount, we don't have
+ * vn_vfswlock_held(coveredvp)
+ */
+int
+fake_dounmount(struct vfs *vfsp, int flag)
+{
+ cred_t *cr = CRED();
+ vnode_t *coveredvp;
+ int error;
+
+ /*
+ * Get covered vnode. This will be NULL if the vfs is not linked
+ * into the file system name space (i.e., domount() with MNT_NOSPICE).
+ */
+ coveredvp = vfsp->vfs_vnodecovered;
+
+ /* For forcible umount, skip VFS_SYNC() since it may hang */
+ if ((flag & MS_FORCE) == 0)
+ (void) VFS_SYNC(vfsp, 0, cr);
+
+ /*
+ * Test-jig specific:
+ * Need to release rootdir before unmount or VFS_UNMOUNT
+ * may fail due to that node being active.
+ */
+ if (rootdir != NULL) {
+ ASSERT(rootdir != coveredvp);
+ VN_RELE(rootdir);
+ rootdir = NULL;
+ }
+
+ /*
+ * Lock the vfs to maintain fs status quo during unmount. This
+ * has to be done after the sync because ufs_update tries to acquire
+ * the vfs_reflock.
+ */
+ vfs_lock_wait(vfsp);
+
+ if ((error = VFS_UNMOUNT(vfsp, flag, cr)) != 0) {
+ int err2;
+ vfs_unlock(vfsp);
+ /* Get rootdir back */
+ err2 = VFS_ROOT(vfsp, &rootdir);
+ if (err2 != 0) {
+ panic("fake_dounmount, get root %d\n", err2);
+ }
+ } else {
+ /*
+ * Real dounmount does vfs_remove.
+ *
+ * Test-jig specific:
+ * Restore the covered rootdir,
+ * release the rootvfs hold and clear.
+ */
+ if (coveredvp != NULL) {
+ // vfs_list_remove(vfsp);
+ vfsp->vfs_vnodecovered = NULL;
+ rootdir = coveredvp;
+ }
+ if (rootvfs == vfsp) {
+ VFS_RELE(vfsp);
+ rootvfs = NULL;
+ }
+
+ /*
+ * Release the (final) reference to vfs
+ */
+ vfs_unlock(vfsp);
+ VFS_RELE(vfsp);
+ }
+ return (error);
+}
+
+// vfs_unmountall(void)
+// vfs_addmip
+// vfs_delmip
+// vfs_add
+// vfs_remove
+
+static krwlock_t vpvfsentry_ve_lock;
+
+/*
+ * Lock a filesystem to prevent access to it while mounting,
+ * unmounting and syncing. Return EBUSY immediately if lock
+ * can't be acquired.
+ */
+int
+vfs_lock(vfs_t *vfsp)
+{
+
+ if (rw_tryenter(&vpvfsentry_ve_lock, RW_WRITER))
+ return (0);
+
+ return (EBUSY);
+}
+
+int
+vfs_rlock(vfs_t *vfsp)
+{
+
+ if (rw_tryenter(&vpvfsentry_ve_lock, RW_READER))
+ return (0);
+
+ return (EBUSY);
+}
+
+void
+vfs_lock_wait(vfs_t *vfsp)
+{
+
+ rw_enter(&vpvfsentry_ve_lock, RW_WRITER);
+}
+
+void
+vfs_rlock_wait(vfs_t *vfsp)
+{
+ rw_enter(&vpvfsentry_ve_lock, RW_READER);
+}
+
+/*
+ * Unlock a locked filesystem.
+ */
+void
+vfs_unlock(vfs_t *vfsp)
+{
+
+ rw_exit(&vpvfsentry_ve_lock);
+}
+
+/*
+ * Utility routine that allows a filesystem to construct its
+ * fsid in "the usual way" - by munging some underlying dev_t and
+ * the filesystem type number into the 64-bit fsid. ...
+ */
+void
+vfs_make_fsid(fsid_t *fsi, dev_t dev, int val)
+{
+ if (!cmpldev((dev32_t *)&fsi->val[0], dev))
+ panic("device number too big for fsid!");
+ fsi->val[1] = val;
+}
+
+int
+vfs_lock_held(vfs_t *vfsp)
+{
+ int held;
+
+ held = rw_write_held(&vpvfsentry_ve_lock);
+
+ return (held);
+}
+
+// vfs_lock_owner
+
+/*
+ * vfs list locking.
+ */
+
+void
+vfs_list_lock()
+{
+ rw_enter(&vfslist, RW_WRITER);
+}
+
+void
+vfs_list_read_lock()
+{
+ rw_enter(&vfslist, RW_READER);
+}
+
+void
+vfs_list_unlock()
+{
+ rw_exit(&vfslist);
+}
+
+/*
+ * Low level worker routines for adding entries to and removing entries from
+ * the vfs list.
+ */
+
+// vfs_hash_add
+// vfs_hash_remove
+// vfs_list_add
+// vfs_list_remove
+// getvfs
+// vfs_devmounting
+
+/*
+ * Search the vfs list for a specified device. Returns 1, if entry is found
+ * or 0 if no suitable entry is found.
+ */
+
+int
+vfs_devismounted(dev_t dev)
+{
+ return (0);
+}
+
+// vfs_dev2vfsp
+// vfs_mntpoint2vfsp
+
+/*
+ * Search the vfs list for a specified vfsops.
+ * if vfs entry is found then return 1, else 0.
+ */
+int
+vfs_opsinuse(vfsops_t *ops)
+{
+ return (0);
+}
+
+/*
+ * Allocate an entry in vfssw for a file system type
+ */
+struct vfssw *
+allocate_vfssw(const char *type)
+{
+ struct vfssw *vswp;
+
+ if (type[0] == '\0' || strlen(type) + 1 > _ST_FSTYPSZ) {
+ /*
+ * The vfssw table uses the empty string to identify an
+ * available entry; we cannot add any type which has
+ * a leading NUL. The string length is limited to
+ * the size of the st_fstype array in struct stat.
+ */
+ return (NULL);
+ }
+
+ ASSERT(VFSSW_WRITE_LOCKED());
+ for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++)
+ if (!ALLOCATED_VFSSW(vswp)) {
+ vswp->vsw_name = kmem_alloc(strlen(type) + 1, KM_SLEEP);
+ (void) strcpy(vswp->vsw_name, type);
+ ASSERT(vswp->vsw_count == 0);
+ vswp->vsw_count = 1;
+ mutex_init(&vswp->vsw_lock, NULL, MUTEX_DEFAULT, NULL);
+ return (vswp);
+ }
+ return (NULL);
+}
+
+// vfs_to_modname
+// vfs_getvfssw
+
+/*
+ * Find a vfssw entry given a file system type name.
+ */
+struct vfssw *
+vfs_getvfssw(const char *type)
+{
+ struct vfssw *vswp;
+
+ if (type == NULL || *type == '\0')
+ return (NULL);
+
+ for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
+ if (strcmp(type, vswp->vsw_name) == 0) {
+ return (vswp);
+ }
+ }
+
+ return (NULL);
+
+}
+
+/*
+ * Find a vfssw entry given a file system type name.
+ */
+struct vfssw *
+vfs_getvfsswbyname(const char *type)
+{
+ struct vfssw *vswp;
+
+ ASSERT(VFSSW_LOCKED());
+ if (type == NULL || *type == '\0')
+ return (NULL);
+
+ for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
+ if (strcmp(type, vswp->vsw_name) == 0) {
+ vfs_refvfssw(vswp);
+ return (vswp);
+ }
+ }
+
+ return (NULL);
+}
+
+// vfs_getvfsswbyvfsops
+
+/*
+ * Reference a vfssw entry.
+ */
+void
+vfs_refvfssw(struct vfssw *vswp)
+{
+
+ mutex_enter(&vswp->vsw_lock);
+ vswp->vsw_count++;
+ mutex_exit(&vswp->vsw_lock);
+}
+
+/*
+ * Unreference a vfssw entry.
+ */
+void
+vfs_unrefvfssw(struct vfssw *vswp)
+{
+
+ mutex_enter(&vswp->vsw_lock);
+ vswp->vsw_count--;
+ mutex_exit(&vswp->vsw_lock);
+}
+
+// vfs_syncall
+
+/*
+ * Map VFS flags to statvfs flags. These shouldn't really be separate
+ * flags at all.
+ */
+uint_t
+vf_to_stf(uint_t vf)
+{
+ uint_t stf = 0;
+
+ if (vf & VFS_RDONLY)
+ stf |= ST_RDONLY;
+ if (vf & VFS_NOSETUID)
+ stf |= ST_NOSUID;
+ if (vf & VFS_NOTRUNC)
+ stf |= ST_NOTRUNC;
+
+ return (stf);
+}
+
+// vfsstray_sync
+// vfsstray
+// vfs_EIO
+// vfs_EIO_sync
+// EIO_vfs
+// EIO_vfsops
+
+#pragma init(vfsinit)
+
+/*
+ * Called from startup() to initialize all loaded vfs's
+ */
+void
+vfsinit(void)
+{
+ vn_create_cache();
+
+ /* Temporary, until we mount root */
+ rootdir = vn_alloc(KM_SLEEP);
+ rootdir->v_type = VDIR;
+}
+
+vfs_t *
+vfs_alloc(int kmflag)
+{
+ vfs_t *vfsp;
+
+ vfsp = kmem_alloc(sizeof (struct vfs), kmflag);
+
+ /*
+ * Do the simplest initialization here.
+ * Everything else gets done in vfs_init()
+ */
+ bzero(vfsp, sizeof (vfs_t));
+ return (vfsp);
+}
+
+void
+vfs_free(vfs_t *vfsp)
+{
+ /*
+ * One would be tempted to assert that "vfsp->vfs_count == 0".
+ * Don't. See fs/vfs.c
+ */
+
+ /* If FEM was in use, make sure everything gets cleaned up */
+
+ if (vfsp->vfs_implp)
+ vfsimpl_teardown(vfsp);
+ sema_destroy(&vfsp->vfs_reflock);
+ kmem_free(vfsp, sizeof (struct vfs));
+}
+
+/*
+ * Increments the vfs reference count by one atomically.
+ */
+void
+vfs_hold(vfs_t *vfsp)
+{
+ atomic_inc_32(&vfsp->vfs_count);
+ ASSERT(vfsp->vfs_count != 0);
+}
+
+/*
+ * Decrements the vfs reference count by one atomically. When
+ * vfs reference count becomes zero, it calls the file system
+ * specific vfs_freevfs() to free up the resources.
+ */
+void
+vfs_rele(vfs_t *vfsp)
+{
+ ASSERT(vfsp->vfs_count != 0);
+ if (atomic_dec_32_nv(&vfsp->vfs_count) == 0) {
+ VFS_FREEVFS(vfsp);
+ // lofi_remove(vfsp);
+ // zone_rele_ref...
+ // vfs_freemnttab(vfsp);
+ vfs_free(vfsp);
+ }
+}
+
+/*
+ * Generic operations vector support.
+ */
+
+int
+fs_build_vector(void *vector, int *unused_ops,
+ const fs_operation_trans_def_t *translation,
+ const fs_operation_def_t *operations)
+{
+ int i, num_trans, num_ops, used;
+
+ /*
+ * Count the number of translations and the number of supplied
+ * operations.
+ */
+
+ {
+ const fs_operation_trans_def_t *p;
+
+ for (num_trans = 0, p = translation;
+ p->name != NULL;
+ num_trans++, p++)
+ ;
+ }
+
+ {
+ const fs_operation_def_t *p;
+
+ for (num_ops = 0, p = operations;
+ p->name != NULL;
+ num_ops++, p++)
+ ;
+ }
+
+ /* Walk through each operation known to our caller. There will be */
+ /* one entry in the supplied "translation table" for each. */
+
+ used = 0;
+
+ for (i = 0; i < num_trans; i++) {
+ int j, found;
+ char *curname;
+ fs_generic_func_p result;
+ fs_generic_func_p *location;
+
+ curname = translation[i].name;
+
+ /* Look for a matching operation in the list supplied by the */
+ /* file system. */
+
+ found = 0;
+
+ for (j = 0; j < num_ops; j++) {
+ if (strcmp(operations[j].name, curname) == 0) {
+ used++;
+ found = 1;
+ break;
+ }
+ }
+
+ /*
+ * If the file system is using a "placeholder" for default
+ * or error functions, grab the appropriate function out of
+ * the translation table. If the file system didn't supply
+ * this operation at all, use the default function.
+ */
+
+ if (found) {
+ result = operations[j].func.fs_generic;
+ if (result == fs_default) {
+ result = translation[i].defaultFunc;
+ } else if (result == fs_error) {
+ result = translation[i].errorFunc;
+ } else if (result == NULL) {
+ /* Null values are PROHIBITED */
+ return (EINVAL);
+ }
+ } else {
+ result = translation[i].defaultFunc;
+ }
+
+ /* Now store the function into the operations vector. */
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ location = (fs_generic_func_p *)
+ (((char *)vector) + translation[i].offset);
+
+ *location = result;
+ }
+
+ *unused_ops = num_ops - used;
+
+ return (0);
+}
+
+/* Placeholder functions, should never be called. */
+
+int
+fs_error(void)
+{
+ cmn_err(CE_PANIC, "fs_error called");
+ return (0);
+}
+
+int
+fs_default(void)
+{
+ cmn_err(CE_PANIC, "fs_default called");
+ return (0);
+}
+
+// rootconf
+// getfsname
+// getrootfs
+
+/*
+ * VFS feature routines
+ */
+
+#define VFTINDEX(feature) (((feature) >> 32) & 0xFFFFFFFF)
+#define VFTBITS(feature) ((feature) & 0xFFFFFFFFLL)
+
+/* Register a feature in the vfs */
+void
+vfs_set_feature(vfs_t *vfsp, vfs_feature_t feature)
+{
+ /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
+ if (vfsp->vfs_implp == NULL)
+ return;
+
+ vfsp->vfs_featureset[VFTINDEX(feature)] |= VFTBITS(feature);
+}
+
+void
+vfs_clear_feature(vfs_t *vfsp, vfs_feature_t feature)
+{
+ /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
+ if (vfsp->vfs_implp == NULL)
+ return;
+ vfsp->vfs_featureset[VFTINDEX(feature)] &= VFTBITS(~feature);
+}
+
+/*
+ * Query a vfs for a feature.
+ * Returns 1 if feature is present, 0 if not
+ */
+int
+vfs_has_feature(vfs_t *vfsp, vfs_feature_t feature)
+{
+ int ret = 0;
+
+ /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
+ if (vfsp->vfs_implp == NULL)
+ return (ret);
+
+ if (vfsp->vfs_featureset[VFTINDEX(feature)] & VFTBITS(feature))
+ ret = 1;
+
+ return (ret);
+}
+
+// vfs_propagate_features
+// vfs_get_lofi
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_vnode.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_vnode.c
new file mode 100644
index 0000000000..07eb5bc18d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_vnode.c
@@ -0,0 +1,2026 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017, Joyent, Inc.
+ * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/*
+ * This file contains those functions from fs/vnode.c that can be
+ * used with relatively little change. Functions that differ
+ * significantly from that are in other files.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/t_lock.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/pathname.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/vnode.h>
+#include <sys/rwstlock.h>
+#include <sys/fem.h>
+#include <sys/stat.h>
+#include <sys/mode.h>
+#include <sys/conf.h>
+#include <sys/sysmacros.h>
+#include <sys/cmn_err.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/atomic.h>
+#include <sys/debug.h>
+#include <sys/acl.h>
+#include <sys/nbmlock.h>
+#include <sys/fcntl.h>
+#include <sys/time.h>
+#include <fs/fs_subr.h>
+#include <fs/fs_reparse.h>
+
+#include <libfksmbfs.h>
+
+/* Determine if this vnode is a file that is read-only */
+#define ISROFILE(vp) \
+ ((vp)->v_type != VCHR && (vp)->v_type != VBLK && \
+ (vp)->v_type != VFIFO && vn_is_readonly(vp))
+
+#define VOPSTATS_UPDATE(vp, counter) ((void)vp)
+#define VOPSTATS_UPDATE_IO(vp, counter, bytecounter, bytesval) \
+ ((void)vp, (void)bytesval)
+#define VOPXID_MAP_CR(vp, cr) ((void)vp)
+
+/*
+ * Excerpts from fs/vnode.c
+ */
+
+/* Global used for empty/invalid v_path */
+char *vn_vpath_empty = "";
+
+static int fs_reparse_mark(char *target, vattr_t *vap, xvattr_t *xvattr);
+
+/*
+ * Convert stat(2) formats to vnode types and vice versa. (Knows about
+ * numerical order of S_IFMT and vnode types.)
+ */
+enum vtype iftovt_tab[] = {
+ VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
+ VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON
+};
+
+ushort_t vttoif_tab[] = {
+ 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO,
+ S_IFDOOR, 0, S_IFSOCK, S_IFPORT, 0
+};
+
+/*
+ * The system vnode cache.
+ */
+
+kmem_cache_t *vn_cache;
+
+
+/*
+ * Vnode operations vector.
+ */
+
+static const fs_operation_trans_def_t vn_ops_table[] = {
+ VOPNAME_OPEN, offsetof(struct vnodeops, vop_open),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_CLOSE, offsetof(struct vnodeops, vop_close),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_READ, offsetof(struct vnodeops, vop_read),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_WRITE, offsetof(struct vnodeops, vop_write),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_IOCTL, offsetof(struct vnodeops, vop_ioctl),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_SETFL, offsetof(struct vnodeops, vop_setfl),
+ fs_setfl, fs_nosys,
+
+ VOPNAME_GETATTR, offsetof(struct vnodeops, vop_getattr),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_SETATTR, offsetof(struct vnodeops, vop_setattr),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_ACCESS, offsetof(struct vnodeops, vop_access),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_LOOKUP, offsetof(struct vnodeops, vop_lookup),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_CREATE, offsetof(struct vnodeops, vop_create),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_REMOVE, offsetof(struct vnodeops, vop_remove),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_LINK, offsetof(struct vnodeops, vop_link),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_RENAME, offsetof(struct vnodeops, vop_rename),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_MKDIR, offsetof(struct vnodeops, vop_mkdir),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_RMDIR, offsetof(struct vnodeops, vop_rmdir),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_READDIR, offsetof(struct vnodeops, vop_readdir),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_SYMLINK, offsetof(struct vnodeops, vop_symlink),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_READLINK, offsetof(struct vnodeops, vop_readlink),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_FSYNC, offsetof(struct vnodeops, vop_fsync),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_INACTIVE, offsetof(struct vnodeops, vop_inactive),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_FID, offsetof(struct vnodeops, vop_fid),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_RWLOCK, offsetof(struct vnodeops, vop_rwlock),
+ fs_rwlock, fs_rwlock,
+
+ VOPNAME_RWUNLOCK, offsetof(struct vnodeops, vop_rwunlock),
+ (fs_generic_func_p) fs_rwunlock,
+ (fs_generic_func_p) fs_rwunlock, /* no errors allowed */
+
+ VOPNAME_SEEK, offsetof(struct vnodeops, vop_seek),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_CMP, offsetof(struct vnodeops, vop_cmp),
+ fs_cmp, fs_cmp, /* no errors allowed */
+
+ VOPNAME_FRLOCK, offsetof(struct vnodeops, vop_frlock),
+ fs_frlock, fs_nosys,
+
+ VOPNAME_SPACE, offsetof(struct vnodeops, vop_space),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_REALVP, offsetof(struct vnodeops, vop_realvp),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_GETPAGE, offsetof(struct vnodeops, vop_getpage),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_PUTPAGE, offsetof(struct vnodeops, vop_putpage),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_MAP, offsetof(struct vnodeops, vop_map),
+ (fs_generic_func_p) fs_nosys_map,
+ (fs_generic_func_p) fs_nosys_map,
+
+ VOPNAME_ADDMAP, offsetof(struct vnodeops, vop_addmap),
+ (fs_generic_func_p) fs_nosys_addmap,
+ (fs_generic_func_p) fs_nosys_addmap,
+
+ VOPNAME_DELMAP, offsetof(struct vnodeops, vop_delmap),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_POLL, offsetof(struct vnodeops, vop_poll),
+ (fs_generic_func_p) fs_poll, (fs_generic_func_p) fs_nosys_poll,
+
+ VOPNAME_DUMP, offsetof(struct vnodeops, vop_dump),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_PATHCONF, offsetof(struct vnodeops, vop_pathconf),
+ fs_pathconf, fs_nosys,
+
+ VOPNAME_PAGEIO, offsetof(struct vnodeops, vop_pageio),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_DUMPCTL, offsetof(struct vnodeops, vop_dumpctl),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_DISPOSE, offsetof(struct vnodeops, vop_dispose),
+ (fs_generic_func_p) fs_dispose,
+ (fs_generic_func_p) fs_nodispose,
+
+ VOPNAME_SETSECATTR, offsetof(struct vnodeops, vop_setsecattr),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_GETSECATTR, offsetof(struct vnodeops, vop_getsecattr),
+ fs_fab_acl, fs_nosys,
+
+ VOPNAME_SHRLOCK, offsetof(struct vnodeops, vop_shrlock),
+ fs_shrlock, fs_nosys,
+
+ VOPNAME_VNEVENT, offsetof(struct vnodeops, vop_vnevent),
+ (fs_generic_func_p) fs_vnevent_nosupport,
+ (fs_generic_func_p) fs_vnevent_nosupport,
+
+ VOPNAME_REQZCBUF, offsetof(struct vnodeops, vop_reqzcbuf),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_RETZCBUF, offsetof(struct vnodeops, vop_retzcbuf),
+ fs_nosys, fs_nosys,
+
+ NULL, 0, NULL, NULL
+};
+
+/* Extensible attribute (xva) routines. */
+
+/*
+ * Zero out the structure, set the size of the requested/returned bitmaps,
+ * set AT_XVATTR in the embedded vattr_t's va_mask, and set up the pointer
+ * to the returned attributes array.
+ */
+void
+xva_init(xvattr_t *xvap)
+{
+ bzero(xvap, sizeof (xvattr_t));
+ xvap->xva_mapsize = XVA_MAPSIZE;
+ xvap->xva_magic = XVA_MAGIC;
+ xvap->xva_vattr.va_mask = AT_XVATTR;
+ xvap->xva_rtnattrmapp = &(xvap->xva_rtnattrmap)[0];
+}
+
+/*
+ * If AT_XVATTR is set, returns a pointer to the embedded xoptattr_t
+ * structure. Otherwise, returns NULL.
+ */
+xoptattr_t *
+xva_getxoptattr(xvattr_t *xvap)
+{
+ xoptattr_t *xoap = NULL;
+ if (xvap->xva_vattr.va_mask & AT_XVATTR)
+ xoap = &xvap->xva_xoptattrs;
+ return (xoap);
+}
+
+// vska_compar
+// create_vopstats_template
+// new_vskstat
+// vopstats_startup
+// initialize_vopstats
+// get_fstype_vopstats
+// get_vskstat_anchor
+// teardown_vopstats
+
+/*
+ * Read or write a vnode. Called from kernel code.
+ */
+int
+vn_rdwr(
+ enum uio_rw rw,
+ struct vnode *vp,
+ caddr_t base,
+ ssize_t len,
+ offset_t offset,
+ enum uio_seg seg,
+ int ioflag,
+ rlim64_t ulimit, /* meaningful only if rw is UIO_WRITE */
+ cred_t *cr,
+ ssize_t *residp)
+{
+ struct uio uio;
+ struct iovec iov;
+ int error;
+ int in_crit = 0;
+
+ if (rw == UIO_WRITE && ISROFILE(vp))
+ return (EROFS);
+
+ if (len < 0)
+ return (EIO);
+
+ VOPXID_MAP_CR(vp, cr);
+
+ iov.iov_base = base;
+ iov.iov_len = len;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_loffset = offset;
+ uio.uio_segflg = (short)seg;
+ uio.uio_resid = len;
+ uio.uio_llimit = ulimit;
+
+ /*
+ * We have to enter the critical region before calling VOP_RWLOCK
+ * to avoid a deadlock with ufs.
+ */
+ if (nbl_need_check(vp)) {
+ int svmand;
+
+ nbl_start_crit(vp, RW_READER);
+ in_crit = 1;
+ error = nbl_svmand(vp, cr, &svmand);
+ if (error != 0)
+ goto done;
+ if (nbl_conflict(vp, rw == UIO_WRITE ? NBL_WRITE : NBL_READ,
+ uio.uio_offset, uio.uio_resid, svmand, NULL)) {
+ error = EACCES;
+ goto done;
+ }
+ }
+
+ (void) VOP_RWLOCK(vp,
+ rw == UIO_WRITE ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE, NULL);
+ if (rw == UIO_WRITE) {
+ uio.uio_fmode = FWRITE;
+ uio.uio_extflg = UIO_COPY_DEFAULT;
+ error = VOP_WRITE(vp, &uio, ioflag, cr, NULL);
+ } else {
+ uio.uio_fmode = FREAD;
+ uio.uio_extflg = UIO_COPY_CACHED;
+ error = VOP_READ(vp, &uio, ioflag, cr, NULL);
+ }
+ VOP_RWUNLOCK(vp,
+ rw == UIO_WRITE ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE, NULL);
+ if (residp)
+ *residp = uio.uio_resid;
+ else if (uio.uio_resid)
+ error = EIO;
+
+done:
+ if (in_crit)
+ nbl_end_crit(vp);
+ return (error);
+}
+
+/*
+ * Incremend the hold on a vnode
+ * (Real kernel uses a macro)
+ */
+void
+vn_hold(struct vnode *vp)
+{
+ mutex_enter(&vp->v_lock);
+ (vp)->v_count++;
+ mutex_exit(&vp->v_lock);
+}
+
+/*
+ * Release a vnode. Call VOP_INACTIVE on last reference or
+ * decrement reference count...
+ */
+void
+vn_rele(vnode_t *vp)
+{
+ VERIFY(vp->v_count > 0);
+ mutex_enter(&vp->v_lock);
+ if (vp->v_count == 1) {
+ mutex_exit(&vp->v_lock);
+ VOP_INACTIVE(vp, CRED(), NULL);
+ return;
+ }
+ VN_RELE_LOCKED(vp);
+ mutex_exit(&vp->v_lock);
+}
+
+// vn_rele_dnlc
+// vn_rele_stream
+// vn_rele_inactive
+// vn_rele_async
+// vn_open, vn_openat
+// vn_open_upgrade
+// vn_open_downgrade
+// vn_create, vn_createat
+// vn_link, vn_linkat
+// vn_rename, vn_renameat
+// vn_remove, vn_removeat
+
+
+/*
+ * Utility function to compare equality of vnodes.
+ * Compare the underlying real vnodes, if there are underlying vnodes.
+ * This is a more thorough comparison than the VN_CMP() macro provides.
+ */
+int
+vn_compare(vnode_t *vp1, vnode_t *vp2)
+{
+ vnode_t *realvp;
+
+ if (vp1 != NULL && VOP_REALVP(vp1, &realvp, NULL) == 0)
+ vp1 = realvp;
+ if (vp2 != NULL && VOP_REALVP(vp2, &realvp, NULL) == 0)
+ vp2 = realvp;
+ return (VN_CMP(vp1, vp2));
+}
+
+// vn_vfslocks_buckets
+// vn_vfslocks_getlock
+// vn_vfslocks_rele
+
+static krwlock_t vfsentry_ve_lock;
+
+/*
+ * vn_vfswlock_wait is used to implement a lock which is logically a
+ * writers lock protecting the v_vfsmountedhere field.
+ * vn_vfswlock_wait has been modified to be similar to vn_vfswlock,
+ * except that it blocks to acquire the lock VVFSLOCK.
+ *
+ * traverse() and routines re-implementing part of traverse (e.g. autofs)
+ * need to hold this lock. mount(), vn_rename(), vn_remove() and so on
+ * need the non-blocking version of the writers lock i.e. vn_vfswlock
+ */
+int
+vn_vfswlock_wait(vnode_t *vp)
+{
+
+ ASSERT(vp != NULL);
+
+ rw_enter(&vfsentry_ve_lock, RW_WRITER);
+
+ return (0);
+}
+
+int
+vn_vfsrlock_wait(vnode_t *vp)
+{
+
+ ASSERT(vp != NULL);
+
+ rw_enter(&vfsentry_ve_lock, RW_READER);
+
+ return (0);
+}
+
+/*
+ * vn_vfswlock is used to implement a lock which is logically a writers lock
+ * protecting the v_vfsmountedhere field.
+ */
+int
+vn_vfswlock(vnode_t *vp)
+{
+
+ if (vp == NULL)
+ return (EBUSY);
+
+ if (rw_tryenter(&vfsentry_ve_lock, RW_WRITER))
+ return (0);
+
+ return (EBUSY);
+}
+
+int
+vn_vfsrlock(vnode_t *vp)
+{
+
+ if (vp == NULL)
+ return (EBUSY);
+
+ if (rw_tryenter(&vfsentry_ve_lock, RW_READER))
+ return (0);
+
+ return (EBUSY);
+}
+
+void
+vn_vfsunlock(vnode_t *vp)
+{
+
+ rw_exit(&vfsentry_ve_lock);
+}
+
+int
+vn_vfswlock_held(vnode_t *vp)
+{
+ int held;
+
+ ASSERT(vp != NULL);
+
+ held = rw_write_held(&vfsentry_ve_lock);
+
+ return (held);
+}
+
+
+int
+vn_make_ops(
+ const char *name, /* Name of file system */
+ const fs_operation_def_t *templ, /* Operation specification */
+ vnodeops_t **actual) /* Return the vnodeops */
+{
+ int unused_ops;
+ int error;
+
+ *actual = (vnodeops_t *)kmem_alloc(sizeof (vnodeops_t), KM_SLEEP);
+
+ (*actual)->vnop_name = name;
+
+ error = fs_build_vector(*actual, &unused_ops, vn_ops_table, templ);
+ if (error) {
+ kmem_free(*actual, sizeof (vnodeops_t));
+ }
+
+#if DEBUG
+ if (unused_ops != 0)
+ cmn_err(CE_WARN, "vn_make_ops: %s: %d operations supplied "
+ "but not used", name, unused_ops);
+#endif
+
+ return (error);
+}
+
+/*
+ * Free the vnodeops created as a result of vn_make_ops()
+ */
+void
+vn_freevnodeops(vnodeops_t *vnops)
+{
+ kmem_free(vnops, sizeof (vnodeops_t));
+}
+
+/*
+ * Vnode cache.
+ */
+
+/* ARGSUSED */
+static int
+vn_cache_constructor(void *buf, void *cdrarg, int kmflags)
+{
+ struct vnode *vp = buf;
+
+ bzero(vp, sizeof (*vp));
+ mutex_init(&vp->v_lock, NULL, MUTEX_DEFAULT, NULL);
+ rw_init(&vp->v_nbllock, NULL, RW_DEFAULT, NULL);
+ vp->v_path = vn_vpath_empty;
+ vp->v_fd = -1;
+ vp->v_st_dev = NODEV;
+
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+vn_cache_destructor(void *buf, void *cdrarg)
+{
+ struct vnode *vp;
+
+ vp = buf;
+
+ rw_destroy(&vp->v_nbllock);
+ mutex_destroy(&vp->v_lock);
+}
+
+void
+vn_create_cache(void)
+{
+ vn_cache = kmem_cache_create("vn_cache", sizeof (struct vnode),
+ VNODE_ALIGN, vn_cache_constructor, vn_cache_destructor, NULL, NULL,
+ NULL, 0);
+}
+
+void
+vn_destroy_cache(void)
+{
+ kmem_cache_destroy(vn_cache);
+}
+
+/*
+ * Used by file systems when fs-specific nodes (e.g., ufs inodes) are
+ * cached by the file system and vnodes remain associated.
+ */
+void
+vn_recycle(vnode_t *vp)
+{
+ VERIFY(vp->v_path != NULL);
+
+ /*
+ * XXX - This really belongs in vn_reinit(), but we have some issues
+ * with the counts. Best to have it here for clean initialization.
+ */
+ vp->v_rdcnt = 0;
+ vp->v_wrcnt = 0;
+
+ /*
+ * If FEM was in use...
+ */
+
+ if (vp->v_path != vn_vpath_empty) {
+ kmem_free(vp->v_path, strlen(vp->v_path) + 1);
+ vp->v_path = vn_vpath_empty;
+ }
+ // vsd_free(vp);
+}
+
+/*
+ * Used to reset the vnode fields including those that are directly accessible
+ * as well as those which require an accessor function.
+ */
+void
+vn_reinit(vnode_t *vp)
+{
+ vp->v_count = 1;
+ // vp->v_count_dnlc = 0;
+ vp->v_vfsp = NULL;
+ vp->v_stream = NULL;
+ vp->v_vfsmountedhere = NULL;
+ vp->v_flag = 0;
+ vp->v_type = VNON;
+ vp->v_rdev = NODEV;
+
+ vp->v_xattrdir = NULL;
+
+ /*
+ * In a few specific instances, vn_reinit() is used to initialize
+ * locally defined vnode_t instances. Lacking the construction offered
+ * by vn_alloc(), these vnodes require v_path initialization.
+ */
+ if (vp->v_path == NULL) {
+ vp->v_path = vn_vpath_empty;
+ }
+
+ /* Handles v_femhead, v_path, and the r/w/map counts */
+ vn_recycle(vp);
+}
+
+vnode_t *
+vn_alloc(int kmflag)
+{
+ vnode_t *vp;
+
+ vp = kmem_cache_alloc(vn_cache, kmflag);
+
+ if (vp != NULL) {
+ // vp->v_femhead = NULL; /* Must be done before vn_reinit() */
+ // vp->v_fopdata = NULL;
+ vn_reinit(vp);
+ }
+
+ return (vp);
+}
+
+void
+vn_free(vnode_t *vp)
+{
+ extern vnode_t *rootdir;
+ ASSERT(vp != rootdir);
+
+ /*
+ * Some file systems call vn_free() with v_count of zero,
+ * some with v_count of 1. In any case, the value should
+ * never be anything else.
+ */
+ ASSERT((vp->v_count == 0) || (vp->v_count == 1));
+ VERIFY(vp->v_path != NULL);
+ if (vp->v_path != vn_vpath_empty) {
+ kmem_free(vp->v_path, strlen(vp->v_path) + 1);
+ vp->v_path = vn_vpath_empty;
+ }
+
+ /* If FEM was in use... */
+
+ // vsd_free(vp);
+ kmem_cache_free(vn_cache, vp);
+}
+
+/*
+ * vnode status changes, should define better states than 1, 0.
+ */
+void
+vn_reclaim(vnode_t *vp)
+{
+ vfs_t *vfsp = vp->v_vfsp;
+
+ if (vfsp == NULL ||
+ vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) {
+ return;
+ }
+ (void) VFS_VNSTATE(vfsp, vp, VNTRANS_RECLAIMED);
+}
+
+void
+vn_idle(vnode_t *vp)
+{
+ vfs_t *vfsp = vp->v_vfsp;
+
+ if (vfsp == NULL ||
+ vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) {
+ return;
+ }
+ (void) VFS_VNSTATE(vfsp, vp, VNTRANS_IDLED);
+}
+void
+vn_exists(vnode_t *vp)
+{
+ vfs_t *vfsp = vp->v_vfsp;
+
+ if (vfsp == NULL ||
+ vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) {
+ return;
+ }
+ (void) VFS_VNSTATE(vfsp, vp, VNTRANS_EXISTS);
+}
+
+void
+vn_invalid(vnode_t *vp)
+{
+}
+
+/* Vnode event notification */
+// vnevent_support()
+// vnevent_...
+
+/*
+ * Vnode accessors.
+ */
+
+int
+vn_is_readonly(vnode_t *vp)
+{
+ return (vp->v_vfsp->vfs_flag & VFS_RDONLY);
+}
+
+int
+vn_has_flocks(vnode_t *vp)
+{
+ return (0);
+}
+
+int
+vn_has_mandatory_locks(vnode_t *vp, int mode)
+{
+ return (0);
+}
+
+int
+vn_has_cached_data(vnode_t *vp)
+{
+ return (0);
+}
+
+// vn_can_change_zones
+
+/*
+ * Return nonzero if the vnode is a mount point, zero if not.
+ */
+int
+vn_ismntpt(vnode_t *vp)
+{
+ return (vp->v_vfsmountedhere != NULL);
+}
+
+/* Retrieve the vfs (if any) mounted on this vnode */
+vfs_t *
+vn_mountedvfs(vnode_t *vp)
+{
+ return (vp->v_vfsmountedhere);
+}
+
+/*
+ * Return nonzero if the vnode is referenced by the dnlc, zero if not.
+ * (no DNLC here)
+ */
+int
+vn_in_dnlc(vnode_t *vp)
+{
+ return (0);
+}
+
+
+/*
+ * vn_has_other_opens() checks whether a particular file is opened by more than
+ * just the caller and whether the open is for read and/or write.
+ * This routine is for calling after the caller has already called VOP_OPEN()
+ * and the caller wishes to know if they are the only one with it open for
+ * the mode(s) specified.
+ *
+ * Vnode counts are only kept on regular files (v_type=VREG).
+ */
+int
+vn_has_other_opens(
+ vnode_t *vp,
+ v_mode_t mode)
+{
+
+ ASSERT(vp != NULL);
+
+ switch (mode) {
+ case V_WRITE:
+ if (vp->v_wrcnt > 1)
+ return (V_TRUE);
+ break;
+ case V_RDORWR:
+ if ((vp->v_rdcnt > 1) || (vp->v_wrcnt > 1))
+ return (V_TRUE);
+ break;
+ case V_RDANDWR:
+ if ((vp->v_rdcnt > 1) && (vp->v_wrcnt > 1))
+ return (V_TRUE);
+ break;
+ case V_READ:
+ if (vp->v_rdcnt > 1)
+ return (V_TRUE);
+ break;
+ }
+
+ return (V_FALSE);
+}
+
+/*
+ * vn_is_opened() checks whether a particular file is opened and
+ * whether the open is for read and/or write.
+ *
+ * Vnode counts are only kept on regular files (v_type=VREG).
+ */
+int
+vn_is_opened(
+ vnode_t *vp,
+ v_mode_t mode)
+{
+
+ ASSERT(vp != NULL);
+
+ switch (mode) {
+ case V_WRITE:
+ if (vp->v_wrcnt)
+ return (V_TRUE);
+ break;
+ case V_RDANDWR:
+ if (vp->v_rdcnt && vp->v_wrcnt)
+ return (V_TRUE);
+ break;
+ case V_RDORWR:
+ if (vp->v_rdcnt || vp->v_wrcnt)
+ return (V_TRUE);
+ break;
+ case V_READ:
+ if (vp->v_rdcnt)
+ return (V_TRUE);
+ break;
+ }
+
+ return (V_FALSE);
+}
+
+/*
+ * vn_is_mapped() checks whether a particular file is mapped and whether
+ * the file is mapped read and/or write. (no mmap here)
+ */
+int
+vn_is_mapped(
+ vnode_t *vp,
+ v_mode_t mode)
+{
+ return (V_FALSE);
+}
+
+/*
+ * Set the operations vector for a vnode.
+ */
+void
+vn_setops(vnode_t *vp, vnodeops_t *vnodeops)
+{
+
+ ASSERT(vp != NULL);
+ ASSERT(vnodeops != NULL);
+
+ vp->v_op = vnodeops;
+}
+
+/*
+ * Retrieve the operations vector for a vnode
+ */
+vnodeops_t *
+vn_getops(vnode_t *vp)
+{
+
+ ASSERT(vp != NULL);
+
+ return (vp->v_op);
+}
+
+/*
+ * Returns non-zero (1) if the vnodeops matches that of the vnode.
+ * Returns zero (0) if not.
+ */
+int
+vn_matchops(vnode_t *vp, vnodeops_t *vnodeops)
+{
+ return (vn_getops(vp) == vnodeops);
+}
+
+// vn_matchopval
+// fs_new_caller_id
+
+// vn_clearpath
+// vn_setpath_common
+
+/* ARGSUSED */
+void
+vn_updatepath(vnode_t *pvp, vnode_t *vp, const char *name)
+{
+}
+
+// vn_setpath...
+// vn_renamepath
+// vn_copypath
+
+// vn_vmpss_usepageio
+
+/* VOP_XXX() macros call the corresponding fop_xxx() function */
+
+int
+fop_open(
+ vnode_t **vpp,
+ int mode,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int ret;
+ vnode_t *vp = *vpp;
+
+ VN_HOLD(vp);
+ /*
+ * Adding to the vnode counts before calling open
+ * avoids the need for a mutex...
+ */
+ if ((*vpp)->v_type == VREG) {
+ if (mode & FREAD)
+ atomic_inc_32(&(*vpp)->v_rdcnt);
+ if (mode & FWRITE)
+ atomic_inc_32(&(*vpp)->v_wrcnt);
+ }
+
+ VOPXID_MAP_CR(vp, cr);
+
+ ret = (*(*(vpp))->v_op->vop_open)(vpp, mode, cr, ct);
+
+ if (ret) {
+ /*
+ * Use the saved vp just in case the vnode ptr got trashed
+ * by the error.
+ */
+ VOPSTATS_UPDATE(vp, open);
+ if ((vp->v_type == VREG) && (mode & FREAD))
+ atomic_dec_32(&vp->v_rdcnt);
+ if ((vp->v_type == VREG) && (mode & FWRITE))
+ atomic_dec_32(&vp->v_wrcnt);
+ } else {
+ /*
+ * Some filesystems will return a different vnode,
+ * but the same path was still used to open it.
+ * So if we do change the vnode and need to
+ * copy over the path, do so here, rather than special
+ * casing each filesystem. Adjust the vnode counts to
+ * reflect the vnode switch.
+ */
+ VOPSTATS_UPDATE(*vpp, open);
+ if (*vpp != vp && *vpp != NULL) {
+ // vn_copypath(vp, *vpp);
+ if (((*vpp)->v_type == VREG) && (mode & FREAD))
+ atomic_inc_32(&(*vpp)->v_rdcnt);
+ if ((vp->v_type == VREG) && (mode & FREAD))
+ atomic_dec_32(&vp->v_rdcnt);
+ if (((*vpp)->v_type == VREG) && (mode & FWRITE))
+ atomic_inc_32(&(*vpp)->v_wrcnt);
+ if ((vp->v_type == VREG) && (mode & FWRITE))
+ atomic_dec_32(&vp->v_wrcnt);
+ }
+ }
+ VN_RELE(vp);
+ return (ret);
+}
+
+int
+fop_close(
+ vnode_t *vp,
+ int flag,
+ int count,
+ offset_t offset,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_close)(vp, flag, count, offset, cr, ct);
+ VOPSTATS_UPDATE(vp, close);
+ /*
+ * Check passed in count to handle possible dups. Vnode counts are only
+ * kept on regular files
+ */
+ if ((vp->v_type == VREG) && (count == 1)) {
+ if (flag & FREAD) {
+ ASSERT(vp->v_rdcnt > 0);
+ atomic_dec_32(&vp->v_rdcnt);
+ }
+ if (flag & FWRITE) {
+ ASSERT(vp->v_wrcnt > 0);
+ atomic_dec_32(&vp->v_wrcnt);
+ }
+ }
+ return (err);
+}
+
+int
+fop_read(
+ vnode_t *vp,
+ uio_t *uiop,
+ int ioflag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+ ssize_t resid_start = uiop->uio_resid;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_read)(vp, uiop, ioflag, cr, ct);
+ VOPSTATS_UPDATE_IO(vp, read,
+ read_bytes, (resid_start - uiop->uio_resid));
+ return (err);
+}
+
+int
+fop_write(
+ vnode_t *vp,
+ uio_t *uiop,
+ int ioflag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+ ssize_t resid_start = uiop->uio_resid;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_write)(vp, uiop, ioflag, cr, ct);
+ VOPSTATS_UPDATE_IO(vp, write,
+ write_bytes, (resid_start - uiop->uio_resid));
+ return (err);
+}
+
+int
+fop_ioctl(
+ vnode_t *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_ioctl)(vp, cmd, arg, flag, cr, rvalp, ct);
+ VOPSTATS_UPDATE(vp, ioctl);
+ return (err);
+}
+
+int
+fop_setfl(
+ vnode_t *vp,
+ int oflags,
+ int nflags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_setfl)(vp, oflags, nflags, cr, ct);
+ VOPSTATS_UPDATE(vp, setfl);
+ return (err);
+}
+
+int
+fop_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ /*
+ * If this file system doesn't understand the xvattr extensions
+ * then turn off the xvattr bit.
+ */
+ if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0) {
+ vap->va_mask &= ~AT_XVATTR;
+ }
+
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flags & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+ err = (*(vp)->v_op->vop_getattr)(vp, vap, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, getattr);
+ return (err);
+}
+
+int
+fop_setattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ /*
+ * If this file system doesn't understand the xvattr extensions
+ * then turn off the xvattr bit.
+ */
+ if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0) {
+ vap->va_mask &= ~AT_XVATTR;
+ }
+
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flags & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+ err = (*(vp)->v_op->vop_setattr)(vp, vap, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, setattr);
+ return (err);
+}
+
+int
+fop_access(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ if ((flags & V_ACE_MASK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, access);
+ return (err);
+}
+
+int
+fop_lookup(
+ vnode_t *dvp,
+ char *nm,
+ vnode_t **vpp,
+ pathname_t *pnp,
+ int flags,
+ vnode_t *rdir,
+ cred_t *cr,
+ caller_context_t *ct,
+ int *deflags, /* Returned per-dirent flags */
+ pathname_t *ppnp) /* Returned case-preserved name in directory */
+{
+ int ret;
+
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly. It is required
+ * that if the vfs supports case-insensitive lookup, it also
+ * supports extended dirent flags.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ /*
+ * The real vnode.c would call xattr_dir_lookup here,
+ * which inserts the special "System Attribute" files:
+ * (SUNWattr_rw, SUNWattr_ro) into the xattr list.
+ * Here the main focus is on testing xattr support,
+ * so the system attribute stuff is ommitted.
+ */
+#if 0
+ if ((flags & LOOKUP_XATTR) && (flags & LOOKUP_HAVE_SYSATTR_DIR) == 0) {
+ // Don't need xattr support in libfksmbfs.
+ // ret = xattr_dir_lookup(dvp, vpp, flags, cr);
+ ret = EINVAL;
+ } else
+#endif
+ {
+ ret = (*(dvp)->v_op->vop_lookup)
+ (dvp, nm, vpp, pnp, flags, rdir, cr, ct, deflags, ppnp);
+ }
+ if (ret == 0 && *vpp) {
+ VOPSTATS_UPDATE(*vpp, lookup);
+ vn_updatepath(dvp, *vpp, nm);
+ }
+
+ return (ret);
+}
+
+int
+fop_create(
+ vnode_t *dvp,
+ char *name,
+ vattr_t *vap,
+ vcexcl_t excl,
+ int mode,
+ vnode_t **vpp,
+ cred_t *cr,
+ int flags,
+ caller_context_t *ct,
+ vsecattr_t *vsecp) /* ACL to set during create */
+{
+ int ret;
+
+ if (vsecp != NULL &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_ACLONCREATE) == 0) {
+ return (EINVAL);
+ }
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ ret = (*(dvp)->v_op->vop_create)
+ (dvp, name, vap, excl, mode, vpp, cr, flags, ct, vsecp);
+ if (ret == 0 && *vpp) {
+ VOPSTATS_UPDATE(*vpp, create);
+ vn_updatepath(dvp, *vpp, name);
+ }
+
+ return (ret);
+}
+
+int
+fop_remove(
+ vnode_t *dvp,
+ char *nm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ err = (*(dvp)->v_op->vop_remove)(dvp, nm, cr, ct, flags);
+ VOPSTATS_UPDATE(dvp, remove);
+ return (err);
+}
+
+int
+fop_link(
+ vnode_t *tdvp,
+ vnode_t *svp,
+ char *tnm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+
+ /*
+ * If the target file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(tdvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(tdvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(tdvp, cr);
+
+ err = (*(tdvp)->v_op->vop_link)(tdvp, svp, tnm, cr, ct, flags);
+ VOPSTATS_UPDATE(tdvp, link);
+ return (err);
+}
+
+int
+fop_rename(
+ vnode_t *sdvp,
+ char *snm,
+ vnode_t *tdvp,
+ char *tnm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+
+ /*
+ * If the file system involved does not support
+ * case-insensitive access and said access is requested, fail
+ * quickly.
+ */
+ if (flags & FIGNORECASE &&
+ ((vfs_has_feature(sdvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(sdvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0)))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(tdvp, cr);
+
+ err = (*(sdvp)->v_op->vop_rename)(sdvp, snm, tdvp, tnm, cr, ct, flags);
+ VOPSTATS_UPDATE(sdvp, rename);
+ return (err);
+}
+
+int
+fop_mkdir(
+ vnode_t *dvp,
+ char *dirname,
+ vattr_t *vap,
+ vnode_t **vpp,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp) /* ACL to set during create */
+{
+ int ret;
+
+ if (vsecp != NULL &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_ACLONCREATE) == 0) {
+ return (EINVAL);
+ }
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ ret = (*(dvp)->v_op->vop_mkdir)
+ (dvp, dirname, vap, vpp, cr, ct, flags, vsecp);
+ if (ret == 0 && *vpp) {
+ VOPSTATS_UPDATE(*vpp, mkdir);
+ vn_updatepath(dvp, *vpp, dirname);
+ }
+
+ return (ret);
+}
+
+int
+fop_rmdir(
+ vnode_t *dvp,
+ char *nm,
+ vnode_t *cdir,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ err = (*(dvp)->v_op->vop_rmdir)(dvp, nm, cdir, cr, ct, flags);
+ VOPSTATS_UPDATE(dvp, rmdir);
+ return (err);
+}
+
+int
+fop_readdir(
+ vnode_t *vp,
+ uio_t *uiop,
+ cred_t *cr,
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+ ssize_t resid_start = uiop->uio_resid;
+
+ /*
+ * If this file system doesn't support retrieving directory
+ * entry flags and said access is requested, fail quickly.
+ */
+ if (flags & V_RDDIR_ENTFLAGS &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS) == 0)
+ return (EINVAL);
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_readdir)(vp, uiop, cr, eofp, ct, flags);
+ VOPSTATS_UPDATE_IO(vp, readdir,
+ readdir_bytes, (resid_start - uiop->uio_resid));
+ return (err);
+}
+
+int
+fop_symlink(
+ vnode_t *dvp,
+ char *linkname,
+ vattr_t *vap,
+ char *target,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+ xvattr_t xvattr;
+
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ /* check for reparse point */
+ if ((vfs_has_feature(dvp->v_vfsp, VFSFT_REPARSE)) &&
+ (strncmp(target, FS_REPARSE_TAG_STR,
+ strlen(FS_REPARSE_TAG_STR)) == 0)) {
+ if (!fs_reparse_mark(target, vap, &xvattr))
+ vap = (vattr_t *)&xvattr;
+ }
+
+ err = (*(dvp)->v_op->vop_symlink)
+ (dvp, linkname, vap, target, cr, ct, flags);
+ VOPSTATS_UPDATE(dvp, symlink);
+ return (err);
+}
+
+int
+fop_readlink(
+ vnode_t *vp,
+ uio_t *uiop,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_readlink)(vp, uiop, cr, ct);
+ VOPSTATS_UPDATE(vp, readlink);
+ return (err);
+}
+
+int
+fop_fsync(
+ vnode_t *vp,
+ int syncflag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_fsync)(vp, syncflag, cr, ct);
+ VOPSTATS_UPDATE(vp, fsync);
+ return (err);
+}
+
+void
+fop_inactive(
+ vnode_t *vp,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ /* Need to update stats before vop call since we may lose the vnode */
+ VOPSTATS_UPDATE(vp, inactive);
+
+ VOPXID_MAP_CR(vp, cr);
+
+ (*(vp)->v_op->vop_inactive)(vp, cr, ct);
+}
+
+int
+fop_fid(
+ vnode_t *vp,
+ fid_t *fidp,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_fid)(vp, fidp, ct);
+ VOPSTATS_UPDATE(vp, fid);
+ return (err);
+}
+
+int
+fop_rwlock(
+ vnode_t *vp,
+ int write_lock,
+ caller_context_t *ct)
+{
+ int ret;
+
+ ret = ((*(vp)->v_op->vop_rwlock)(vp, write_lock, ct));
+ VOPSTATS_UPDATE(vp, rwlock);
+ return (ret);
+}
+
+void
+fop_rwunlock(
+ vnode_t *vp,
+ int write_lock,
+ caller_context_t *ct)
+{
+ (*(vp)->v_op->vop_rwunlock)(vp, write_lock, ct);
+ VOPSTATS_UPDATE(vp, rwunlock);
+}
+
+int
+fop_seek(
+ vnode_t *vp,
+ offset_t ooff,
+ offset_t *noffp,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_seek)(vp, ooff, noffp, ct);
+ VOPSTATS_UPDATE(vp, seek);
+ return (err);
+}
+
+int
+fop_cmp(
+ vnode_t *vp1,
+ vnode_t *vp2,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp1)->v_op->vop_cmp)(vp1, vp2, ct);
+ VOPSTATS_UPDATE(vp1, cmp);
+ return (err);
+}
+
+int
+fop_frlock(
+ vnode_t *vp,
+ int cmd,
+ flock64_t *bfp,
+ int flag,
+ offset_t offset,
+ struct flk_callback *flk_cbp,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_frlock)
+ (vp, cmd, bfp, flag, offset, flk_cbp, cr, ct);
+ VOPSTATS_UPDATE(vp, frlock);
+ return (err);
+}
+
+int
+fop_space(
+ vnode_t *vp,
+ int cmd,
+ flock64_t *bfp,
+ int flag,
+ offset_t offset,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_space)(vp, cmd, bfp, flag, offset, cr, ct);
+ VOPSTATS_UPDATE(vp, space);
+ return (err);
+}
+
+int
+fop_realvp(
+ vnode_t *vp,
+ vnode_t **vpp,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_realvp)(vp, vpp, ct);
+ VOPSTATS_UPDATE(vp, realvp);
+ return (err);
+}
+
+int
+fop_getpage(
+ vnode_t *vp,
+ offset_t off,
+ size_t len,
+ uint_t *protp,
+ page_t **plarr,
+ size_t plsz,
+ struct seg *seg,
+ caddr_t addr,
+ enum seg_rw rw,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_getpage)
+ (vp, off, len, protp, plarr, plsz, seg, addr, rw, cr, ct);
+ VOPSTATS_UPDATE(vp, getpage);
+ return (err);
+}
+
+int
+fop_putpage(
+ vnode_t *vp,
+ offset_t off,
+ size_t len,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_putpage)(vp, off, len, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, putpage);
+ return (err);
+}
+
+int
+fop_map(
+ vnode_t *vp,
+ offset_t off,
+ struct as *as,
+ caddr_t *addrp,
+ size_t len,
+ uchar_t prot,
+ uchar_t maxprot,
+ uint_t flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_map)
+ (vp, off, as, addrp, len, prot, maxprot, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, map);
+ return (err);
+}
+
+int
+fop_addmap(
+ vnode_t *vp,
+ offset_t off,
+ struct as *as,
+ caddr_t addr,
+ size_t len,
+ uchar_t prot,
+ uchar_t maxprot,
+ uint_t flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int error;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ error = (*(vp)->v_op->vop_addmap)
+ (vp, off, as, addr, len, prot, maxprot, flags, cr, ct);
+
+ VOPSTATS_UPDATE(vp, addmap);
+ return (error);
+}
+
+int
+fop_delmap(
+ vnode_t *vp,
+ offset_t off,
+ struct as *as,
+ caddr_t addr,
+ size_t len,
+ uint_t prot,
+ uint_t maxprot,
+ uint_t flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int error;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ error = (*(vp)->v_op->vop_delmap)
+ (vp, off, as, addr, len, prot, maxprot, flags, cr, ct);
+
+ VOPSTATS_UPDATE(vp, delmap);
+ return (error);
+}
+
+
+int
+fop_poll(
+ vnode_t *vp,
+ short events,
+ int anyyet,
+ short *reventsp,
+ struct pollhead **phpp,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_poll)(vp, events, anyyet, reventsp, phpp, ct);
+ VOPSTATS_UPDATE(vp, poll);
+ return (err);
+}
+
+int
+fop_dump(
+ vnode_t *vp,
+ caddr_t addr,
+ offset_t lbdn,
+ offset_t dblks,
+ caller_context_t *ct)
+{
+ int err;
+
+ /* ensure lbdn and dblks can be passed safely to bdev_dump */
+ if ((lbdn != (daddr_t)lbdn) || (dblks != (int)dblks))
+ return (EIO);
+
+ err = (*(vp)->v_op->vop_dump)(vp, addr, lbdn, dblks, ct);
+ VOPSTATS_UPDATE(vp, dump);
+ return (err);
+}
+
+int
+fop_pathconf(
+ vnode_t *vp,
+ int cmd,
+ ulong_t *valp,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_pathconf)(vp, cmd, valp, cr, ct);
+ VOPSTATS_UPDATE(vp, pathconf);
+ return (err);
+}
+
+int
+fop_pageio(
+ vnode_t *vp,
+ struct page *pp,
+ u_offset_t io_off,
+ size_t io_len,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_pageio)(vp, pp, io_off, io_len, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, pageio);
+ return (err);
+}
+
+int
+fop_dumpctl(
+ vnode_t *vp,
+ int action,
+ offset_t *blkp,
+ caller_context_t *ct)
+{
+ int err;
+ err = (*(vp)->v_op->vop_dumpctl)(vp, action, blkp, ct);
+ VOPSTATS_UPDATE(vp, dumpctl);
+ return (err);
+}
+
+void
+fop_dispose(
+ vnode_t *vp,
+ page_t *pp,
+ int flag,
+ int dn,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ /* Must do stats first since it's possible to lose the vnode */
+ VOPSTATS_UPDATE(vp, dispose);
+
+ VOPXID_MAP_CR(vp, cr);
+
+ (*(vp)->v_op->vop_dispose)(vp, pp, flag, dn, cr, ct);
+}
+
+int
+fop_setsecattr(
+ vnode_t *vp,
+ vsecattr_t *vsap,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flag & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+ err = (*(vp)->v_op->vop_setsecattr) (vp, vsap, flag, cr, ct);
+ VOPSTATS_UPDATE(vp, setsecattr);
+ return (err);
+}
+
+int
+fop_getsecattr(
+ vnode_t *vp,
+ vsecattr_t *vsap,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flag & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_getsecattr) (vp, vsap, flag, cr, ct);
+ VOPSTATS_UPDATE(vp, getsecattr);
+ return (err);
+}
+
+int
+fop_shrlock(
+ vnode_t *vp,
+ int cmd,
+ struct shrlock *shr,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_shrlock)(vp, cmd, shr, flag, cr, ct);
+ VOPSTATS_UPDATE(vp, shrlock);
+ return (err);
+}
+
+int
+fop_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *fnm,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_vnevent)(vp, vnevent, dvp, fnm, ct);
+ VOPSTATS_UPDATE(vp, vnevent);
+ return (err);
+}
+
+// fop_reqzcbuf
+// fop_retzcbuf
+
+// vsd_defaultdestructor
+// vsd_create, vsd_destroy
+// vsd_get, vsd_set
+// vsd_free, vsd_realloc
+
+static int
+fs_reparse_mark(char *target, vattr_t *vap, xvattr_t *xvattr)
+{
+ return (-1);
+}
+
+/*
+ * Function to check whether a symlink is a reparse point.
+ * Return B_TRUE if it is a reparse point, else return B_FALSE
+ */
+boolean_t
+vn_is_reparse(vnode_t *vp, cred_t *cr, caller_context_t *ct)
+{
+ xvattr_t xvattr;
+ xoptattr_t *xoap;
+
+ if ((vp->v_type != VLNK) ||
+ !(vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR)))
+ return (B_FALSE);
+
+ xva_init(&xvattr);
+ xoap = xva_getxoptattr(&xvattr);
+ ASSERT(xoap);
+ XVA_SET_REQ(&xvattr, XAT_REPARSE);
+
+ if (VOP_GETATTR(vp, &xvattr.xva_vattr, 0, cr, ct))
+ return (B_FALSE);
+
+ if ((!(xvattr.xva_vattr.va_mask & AT_XVATTR)) ||
+ (!(XVA_ISSET_RTN(&xvattr, XAT_REPARSE))))
+ return (B_FALSE);
+
+ return (xoap->xoa_reparse ? B_TRUE : B_FALSE);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_zone.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_zone.c
new file mode 100644
index 0000000000..5593a8d542
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_zone.c
@@ -0,0 +1,76 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent Inc. All rights reserved.
+ * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Simulating just one zone here (the global zone)
+ */
+
+#include <sys/types.h>
+#include <sys/zone.h>
+#include <sys/debug.h>
+
+static void *zone_specific_val;
+static void *(*zkey_create)(zoneid_t);
+// static void (*zkey_shutdown)(zoneid_t, void *);
+// static void (*zkey_destroy)(zoneid_t, void *);
+
+/* ARGSUSED */
+void
+zone_key_create(zone_key_t *keyp, void *(*create)(zoneid_t),
+ void (*shutdown)(zoneid_t, void *), void (*destroy)(zoneid_t, void *))
+{
+
+ zkey_create = create;
+ // zkey_shutdown = shutdown;
+ // zkey_destroy = destroy;
+ *keyp = 1;
+}
+
+/* ARGSUSED */
+int
+zone_key_delete(zone_key_t key)
+{
+ return (-1);
+}
+
+/* ARGSUSED */
+int
+zone_setspecific(zone_key_t key, zone_t *zone, const void *data)
+{
+ return (-1);
+}
+
+/* ARGSUSED */
+void *
+zone_getspecific(zone_key_t key, zone_t *zone)
+{
+ ASSERT(key == 1);
+ if (zone_specific_val == NULL)
+ zone_specific_val = (*zkey_create)(zone->zone_id);
+ return (zone_specific_val);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fksmbfs_rwlock.c b/usr/src/lib/smbclnt/libfksmbfs/common/fksmbfs_rwlock.c
new file mode 100644
index 0000000000..ee92e3ed67
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fksmbfs_rwlock.c
@@ -0,0 +1,235 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
+ * All rights reserved.
+ */
+
+/*
+ * A homegrown reader/writer lock implementation. It addresses
+ * two requirements not addressed by the system primitives. They
+ * are that the `enter" operation is optionally interruptible and
+ * that that they can be re`enter'ed by writers without deadlock.
+ *
+ * All of this was borrowed from NFS.
+ * See: uts/common/fs/nfs/nfs_subr.c
+ *
+ * XXX: Could we make this serve our needs instead?
+ * See: uts/common/os/rwstlock.c
+ * (and then use it for NFS too)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+
+/*
+ * Only can return non-zero if intr != 0.
+ */
+int
+smbfs_rw_enter_sig(smbfs_rwlock_t *l, krw_t rw, int intr)
+{
+
+ mutex_enter(&l->lock);
+
+ /*
+ * If this is a nested enter, then allow it. There
+ * must be as many exits as enters through.
+ */
+ if (l->owner == curthread) {
+ /* lock is held for writing by current thread */
+ ASSERT(rw == RW_READER || rw == RW_WRITER);
+ l->count--;
+ } else if (rw == RW_READER) {
+ /*
+ * While there is a writer active or writers waiting,
+ * then wait for them to finish up and move on. Then,
+ * increment the count to indicate that a reader is
+ * active.
+ */
+ while (l->count < 0 || l->waiters > 0) {
+ if (intr) {
+ // lwp_nostop stuff...
+ (void) cv_wait_sig(&l->cv, &l->lock);
+ } else
+ cv_wait(&l->cv, &l->lock);
+ }
+ ASSERT(l->count < INT_MAX);
+#ifdef SMBDEBUG
+ if ((l->count % 10000) == 9999)
+ cmn_err(CE_WARN, "smbfs_rw_enter_sig: count %d on"
+ "rwlock @ %p\n", l->count, (void *)&l);
+#endif
+ l->count++;
+ } else {
+ ASSERT(rw == RW_WRITER);
+ /*
+ * While there are readers active or a writer
+ * active, then wait for all of the readers
+ * to finish or for the writer to finish.
+ * Then, set the owner field to curthread and
+ * decrement count to indicate that a writer
+ * is active.
+ */
+ while (l->count > 0 || l->owner != NULL) {
+ l->waiters++;
+ if (intr) {
+ // lwp_nostop stuff...
+ if (!cv_wait_sig(&l->cv, &l->lock)) {
+ l->waiters--;
+ cv_broadcast(&l->cv);
+ mutex_exit(&l->lock);
+ return (EINTR);
+ }
+ } else
+ cv_wait(&l->cv, &l->lock);
+ l->waiters--;
+ }
+ l->owner = curthread;
+ l->count--;
+ }
+
+ mutex_exit(&l->lock);
+
+ return (0);
+}
+
+/*
+ * If the lock is available, obtain it and return non-zero. If there is
+ * already a conflicting lock, return 0 immediately.
+ */
+
+int
+smbfs_rw_tryenter(smbfs_rwlock_t *l, krw_t rw)
+{
+ mutex_enter(&l->lock);
+
+ /*
+ * If this is a nested enter, then allow it. There
+ * must be as many exits as enters through.
+ */
+ if (l->owner == curthread) {
+ /* lock is held for writing by current thread */
+ ASSERT(rw == RW_READER || rw == RW_WRITER);
+ l->count--;
+ } else if (rw == RW_READER) {
+ /*
+ * If there is a writer active or writers waiting, deny the
+ * lock. Otherwise, bump the count of readers.
+ */
+ if (l->count < 0 || l->waiters > 0) {
+ mutex_exit(&l->lock);
+ return (0);
+ }
+ l->count++;
+ } else {
+ ASSERT(rw == RW_WRITER);
+ /*
+ * If there are readers active or a writer active, deny the
+ * lock. Otherwise, set the owner field to curthread and
+ * decrement count to indicate that a writer is active.
+ */
+ if (l->count > 0 || l->owner != NULL) {
+ mutex_exit(&l->lock);
+ return (0);
+ }
+ l->owner = curthread;
+ l->count--;
+ }
+
+ mutex_exit(&l->lock);
+
+ return (1);
+}
+
+void
+smbfs_rw_exit(smbfs_rwlock_t *l)
+{
+
+ mutex_enter(&l->lock);
+ /*
+ * If this is releasing a writer lock, then increment count to
+ * indicate that there is one less writer active. If this was
+ * the last of possibly nested writer locks, then clear the owner
+ * field as well to indicate that there is no writer active
+ * and wakeup any possible waiting writers or readers.
+ *
+ * If releasing a reader lock, then just decrement count to
+ * indicate that there is one less reader active. If this was
+ * the last active reader and there are writer(s) waiting,
+ * then wake up the first.
+ */
+ if (l->owner != NULL) {
+ ASSERT(l->owner == curthread);
+ l->count++;
+ if (l->count == 0) {
+ l->owner = NULL;
+ cv_broadcast(&l->cv);
+ }
+ } else {
+ ASSERT(l->count > 0);
+ l->count--;
+ if (l->count == 0 && l->waiters > 0)
+ cv_broadcast(&l->cv);
+ }
+ mutex_exit(&l->lock);
+}
+
+int
+smbfs_rw_lock_held(smbfs_rwlock_t *l, krw_t rw)
+{
+
+ if (rw == RW_READER)
+ return (l->count > 0);
+ ASSERT(rw == RW_WRITER);
+ return (l->count < 0);
+}
+
+/* ARGSUSED */
+void
+smbfs_rw_init(smbfs_rwlock_t *l, char *name, krw_type_t type, void *arg)
+{
+
+ l->count = 0;
+ l->waiters = 0;
+ l->owner = NULL;
+ mutex_init(&l->lock, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&l->cv, NULL, CV_DEFAULT, NULL);
+}
+
+void
+smbfs_rw_destroy(smbfs_rwlock_t *l)
+{
+
+ mutex_destroy(&l->lock);
+ cv_destroy(&l->cv);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/libfksmbfs.h b/usr/src/lib/smbclnt/libfksmbfs/common/libfksmbfs.h
new file mode 100644
index 0000000000..e168b008af
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/libfksmbfs.h
@@ -0,0 +1,73 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _LIBFKSMBFS_H_
+#define _LIBFKSMBFS_H_
+
+/*
+ * Declarations for exports in fake_vfs.c
+ */
+
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+
+#ifndef MAXOFF32_T
+#define MAXOFF32_T 0x7fffffff
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Need these visible outside _FAKE_KERNEL for the test CLI.
+ * In the kmod/lib build these duplicate declarations in vfs.h or
+ * vnode.h but that's OK as long as the declarations are identical.
+ */
+struct mounta;
+struct stat64;
+int fake_installfs(vfsdef_t *);
+int fake_removefs(vfsdef_t *);
+int fake_domount(char *, struct mounta *, struct vfs **);
+int fake_dounmount(struct vfs *, int);
+int fake_lookup(vnode_t *, char *, vnode_t **);
+int fake_lookup_dir(char *, vnode_t **, char **);
+int fake_stat(vnode_t *, struct stat64 *, int);
+int fake_getdents(vnode_t *, offset_t *, void *, size_t);
+ssize_t fake_pread(vnode_t *, void *, size_t, off_t);
+ssize_t fake_pwrite(vnode_t *, void *, size_t, off_t);
+int fake_unlink(char *, int);
+int fake_rename(char *, char *);
+
+int vn_close_rele(vnode_t *vp, int flag);
+int vn_open(char *pnamep, enum uio_seg seg, int filemode, int createmode,
+ struct vnode **vpp, enum create crwhy, mode_t umask);
+int vn_create(char *pnamep, enum uio_seg seg, struct vattr *vap,
+ enum vcexcl excl, int mode, struct vnode **vpp,
+ enum create why, int flag, mode_t umask);
+
+void vn_rele(struct vnode *vp);
+
+/* In the real smbfs, these are _init(), _fini() */
+int fksmbfs_init(void);
+int fksmbfs_fini(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBFKSMBFS_H_ */
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/llib-lfksmbfs b/usr/src/lib/smbclnt/libfksmbfs/common/llib-lfksmbfs
new file mode 100644
index 0000000000..6e7f55f31d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/llib-lfksmbfs
@@ -0,0 +1,19 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <libfksmbfs.h>
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/mapfile-vers b/usr/src/lib/smbclnt/libfksmbfs/common/mapfile-vers
new file mode 100644
index 0000000000..6e8b11a4ef
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/mapfile-vers
@@ -0,0 +1,68 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ global:
+ fake_domount;
+ fake_dounmount;
+ fake_lookup;
+ fake_lookup_dir;
+ fake_getdents;
+ fake_pread;
+ fake_pwrite;
+ fake_rename;
+ fake_stat;
+ fake_unlink;
+
+ fksmbfs_fini;
+ fksmbfs_init;
+
+ fsop_root;
+ fsop_statfs;
+ fsop_sync;
+
+ vn_close_rele;
+ vn_create;
+ vn_open;
+ vn_rele;
+ local:
+ *;
+};
diff --git a/usr/src/lib/smbclnt/libfksmbfs/i386/Makefile b/usr/src/lib/smbclnt/libfksmbfs/i386/Makefile
new file mode 100644
index 0000000000..6e1eb18522
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/i386/Makefile
@@ -0,0 +1,20 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+DYNFLAGS += -R/usr/lib/smbfs
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbclnt/libfksmbfs/sparc/Makefile b/usr/src/lib/smbclnt/libfksmbfs/sparc/Makefile
new file mode 100644
index 0000000000..6e1eb18522
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/sparc/Makefile
@@ -0,0 +1,20 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+DYNFLAGS += -R/usr/lib/smbfs
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbclnt/libfksmbfs/sparcv9/Makefile b/usr/src/lib/smbclnt/libfksmbfs/sparcv9/Makefile
new file mode 100644
index 0000000000..151660294b
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/sparcv9/Makefile
@@ -0,0 +1,24 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MACH_LDLIBS += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+DYNFLAGS += -R/usr/lib/smbfs/$(MACH64)
+sparcv9_C_PICFLAGS= $(sparcv9_C_BIGPICFLAGS)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c b/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c
index 7524e2db55..b6b669cd27 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -36,7 +36,7 @@
#include <smbsrv/libsmb.h>
#include <smbsrv/libmlsvc.h>
#include <smbsrv/smbinfo.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
#include <smbsrv/ntlocale.h>
#include <smbsrv/string.h>
#include <lsalib.h>
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
index 956fbbad15..942650545f 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -41,7 +41,7 @@
#include <smbsrv/libsmb.h>
#include <smbsrv/libsmbns.h>
#include <smbsrv/libmlsvc.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
#include <smbsrv/smbinfo.h>
#include <smbsrv/netrauth.h>
#include <libsmbrdr.h>
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
index 8b0c4e3fbd..edf6952a8d 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -37,7 +37,7 @@
#include <smbsrv/libsmb.h>
#include <smbsrv/libmlsvc.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
#include <lsalib.h>
#include <samlib.h>
@@ -47,8 +47,8 @@
#define letohl(x) ((uint32_t)(x))
#else /* (BYTE_ORDER == LITTLE_ENDIAN) */
/* little-endian values on big-endian (swap) */
-#define letohl(x) BSWAP_32(x)
-#define htolel(x) BSWAP_32(x)
+#define letohl(x) BSWAP_32(x)
+#define htolel(x) BSWAP_32(x)
#endif /* (BYTE_ORDER == LITTLE_ENDIAN) */
/*
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c b/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c
index dd15469c15..38dc21b712 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -48,7 +48,7 @@
#include <smbsrv/libsmb.h>
#include <smbsrv/libmlsvc.h>
#include <smbsrv/smbinfo.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
#include <smbsrv/smb_sid.h>
#include <samlib.h>