summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
authorGordon Ross <gwr@nexenta.com>2018-03-16 14:17:36 -0400
committerGordon Ross <gwr@nexenta.com>2019-03-14 10:38:30 -0400
commitadee678425979226b2b55d1a0b39ce4c989382e9 (patch)
treec4605d064fb3ce4fb587287ebee92838bc4d9b58 /usr
parent40c0e2317898b8c774791bdc2b30bd50111ab1fa (diff)
downloadillumos-joyent-adee678425979226b2b55d1a0b39ce4c989382e9.tar.gz
9735 Need to provide SMB 2.1 Client
Reviewed by: Evan Layton <evan.layton@nexenta.com> Reviewed by: Matt Barden <matt.barden@nexenta.com> Reviewed by: Rick McNeal <rick.mcneal@nexenta.com> Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com> Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com> Approved by: Joshua M. Clulow <josh@sysmgr.org>
Diffstat (limited to 'usr')
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d19
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c14
-rw-r--r--usr/src/cmd/mdb/common/modules/nsmb/nsmb.c88
-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.com3
-rw-r--r--usr/src/lib/libsmbfs/cflib.h4
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smb_lib.h5
-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/connect.c75
-rw-r--r--usr/src/lib/libsmbfs/smb/ctx.c147
-rw-r--r--usr/src/lib/libsmbfs/smb/file.c3
-rw-r--r--usr/src/lib/libsmbfs/smb/iod_wk.c17
-rw-r--r--usr/src/lib/libsmbfs/smb/mapfile-vers5
-rw-r--r--usr/src/lib/libsmbfs/smb/print.c24
-rw-r--r--usr/src/lib/libsmbfs/smb/rc_scf.c231
-rw-r--r--usr/src/lib/libsmbfs/smb/rcfile.c76
-rw-r--r--usr/src/lib/libsmbfs/smb/rcfile_priv.h28
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/Makefile.com5
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers21
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/Makefile.com4
-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
-rw-r--r--usr/src/man/man4/nsmbrc.435
-rw-r--r--usr/src/uts/common/Makefile.files4
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple22
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip1
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov29
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip1
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/offsets.in20
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c382
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h44
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c253
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c1325
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c139
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h130
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c18
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c1389
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c286
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h38
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c40
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c383
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h96
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c236
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c215
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h4
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c104
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c268
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c54
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c36
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c47
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h7
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c2508
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c926
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c896
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c294
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h184
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c4
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c310
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c186
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_ioctl.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_transact.c6
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_dfs.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_opipe.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_vss.c2
-rw-r--r--usr/src/uts/common/netsmb/mchain.h7
-rw-r--r--usr/src/uts/common/netsmb/smb.h62
-rw-r--r--usr/src/uts/common/netsmb/smb2.h465
-rw-r--r--usr/src/uts/common/netsmb/smb_dev.h26
-rw-r--r--usr/src/uts/common/smb/Makefile4
-rw-r--r--usr/src/uts/common/smb/ntaccess.h (renamed from usr/src/uts/common/smbsrv/ntaccess.h)4
-rw-r--r--usr/src/uts/common/smb/winioctl.h (renamed from usr/src/uts/common/smbsrv/winioctl.h)8
-rw-r--r--usr/src/uts/common/smbsrv/Makefile4
-rw-r--r--usr/src/uts/common/smbsrv/smb.h4
-rw-r--r--usr/src/uts/intel/nsmb/ioc_check.ref32
-rw-r--r--usr/src/uts/sparc/nsmb/ioc_check.ref32
84 files changed, 8394 insertions, 4045 deletions
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d
index 823115bf9c..b36fd13d6f 100644
--- a/usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d
@@ -11,7 +11,7 @@
*/
/*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -19,21 +19,6 @@
* Usage: dtrace -s Watch-fksmbcl.d -p $PID
*/
-self int trace;
-
-/*
- * Trace almost everything
- */
-pid$target:fksmbcl::entry
-{
- self->trace++;
-}
-
-pid$target:fksmbcl::return
-{
- self->trace--;
-}
-
/*
* If traced, print entry/return
*/
@@ -42,7 +27,6 @@ pid$target:libsmbfs.so.1::entry,
pid$target:libfksmbfs.so.1::entry,
pid$target:libfknsmb.so.1::entry,
pid$target:libfakekernel.so.1::entry
-/self->trace > 0/
{
printf("\t0x%x", arg0);
printf("\t0x%x", arg1);
@@ -57,7 +41,6 @@ pid$target:libsmbfs.so.1::return,
pid$target:libfksmbfs.so.1::return,
pid$target:libfknsmb.so.1::return,
pid$target:libfakekernel.so.1::entry
-/self->trace > 0/
{
printf("\t0x%x", arg1);
}
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c
index 65b0312558..8b1757ea62 100644
--- a/usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -33,6 +33,7 @@
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <unistd.h>
#include <sys/fs/smbfs_mount.h>
@@ -911,6 +912,17 @@ fakekernel_putlog(char *msg, size_t len, int flags)
}
/*
+ * Print nsmb debug messages via driver smb_debugmsg()
+ */
+void
+smb_debugmsg(const char *func, char *msg)
+{
+ if (smb_debug < 2)
+ return;
+ printf("[kmod] %s: %s\n", func, msg);
+}
+
+/*
* Enable libumem debugging
*/
const char *
diff --git a/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c b/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c
index 8b3b76c38a..24e690f98a 100644
--- a/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c
+++ b/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c
@@ -20,9 +20,10 @@
*/
/*
- * Copyright 2017 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.
*/
@@ -72,12 +73,13 @@ print_str(uintptr_t addr)
*/
typedef struct smb_co_walk_data {
uintptr_t pp;
- int level; /* SMBL_SM, SMBL_VC, SMBL_SHARE */
+ int level; /* SMBL_SM, SMBL_VC, SMBL_SHARE, ... */
int size; /* sizeof (union member) */
union co_u {
smb_connobj_t co; /* copy of the list element */
smb_vc_t vc;
smb_share_t ss;
+ smb_fh_t fh;
} u;
} smb_co_walk_data_t;
@@ -114,6 +116,9 @@ smb_co_walk_init(mdb_walk_state_t *wsp, int level)
case SMBL_SHARE:
smbw->size = sizeof (smbw->u.ss);
break;
+ case SMBL_FH:
+ smbw->size = sizeof (smbw->u.fh);
+ break;
default:
smbw->size = sizeof (smbw->u);
break;
@@ -180,6 +185,24 @@ smb_ss_walk_init(mdb_walk_state_t *wsp)
}
/*
+ * Walk the file hande list below some share.
+ */
+int
+smb_fh_walk_init(mdb_walk_state_t *wsp)
+{
+
+ /*
+ * Initial walk_addr is address of parent (share)
+ */
+ if (wsp->walk_addr == 0) {
+ mdb_warn("::walk smb_fh does not support global walks\n");
+ return (WALK_ERR);
+ }
+
+ return (smb_co_walk_init(wsp, SMBL_FH));
+}
+
+/*
* Common walk_step for walking structs inherited
* from smb_connobj_t (smb_vc_t, smb_share_t)
*/
@@ -221,6 +244,30 @@ typedef struct smb_co_cbdata {
} smb_co_cbdata_t;
/*
+ * Call-back function for walking a file handle list.
+ */
+/* ARGSUSED */
+int
+smb_fh_cb(uintptr_t addr, const void *data, void *arg)
+{
+ const smb_fh_t *fhp = data;
+ // smb_co_cbdata_t *cbd = arg;
+
+ mdb_inc_indent(2);
+ mdb_printf(" %-p", addr);
+ if (fhp->fh_fid2.fid_volatile != 0) {
+ mdb_printf("\t0x%llx\n",
+ (long long) fhp->fh_fid2.fid_volatile);
+ } else {
+ mdb_printf("\t0x%x\n", fhp->fh_fid1);
+ }
+
+ mdb_dec_indent(2);
+
+ return (WALK_NEXT);
+}
+
+/*
* Call-back function for walking a share list.
*/
int
@@ -228,12 +275,20 @@ smb_ss_cb(uintptr_t addr, const void *data, void *arg)
{
const smb_share_t *ssp = data;
smb_co_cbdata_t *cbd = arg;
+ uint32_t tid;
- mdb_printf(" %-p\t%s\n", addr, ssp->ss_name);
+ tid = ssp->ss2_tree_id;
+ if (tid == 0)
+ tid = ssp->ss_tid;
- if (cbd->flags & OPT_VERBOSE) {
+ mdb_printf(" %-p\t0x%x\t%s\n", addr, tid, ssp->ss_name);
+
+ if (cbd->flags & OPT_RECURSE) {
mdb_inc_indent(2);
- /* Anything wanted here? */
+ if (mdb_pwalk("nsmb_fh", smb_fh_cb, cbd, addr) < 0) {
+ mdb_warn("failed to walk 'nsmb_fh'");
+ /* Don't: return (WALK_ERR); */
+ }
mdb_dec_indent(2);
}
@@ -414,6 +469,7 @@ rqlist_walk_step(mdb_walk_state_t *wsp)
typedef struct rqlist_cbdata {
int printed_header;
+ int vcflags;
uintptr_t uid; /* optional filtering by UID */
} rqlist_cbdata_t;
@@ -429,8 +485,13 @@ rqlist_cb(uintptr_t addr, const void *data, void *arg)
}
mdb_printf(" %-p", addr); /* smb_rq_t */
- mdb_printf(" x%04x", rq->sr_mid);
- mdb_printf(" x%02x", rq->sr_cmd);
+ if ((cbd->vcflags & SMBV_SMB2) != 0) {
+ mdb_printf(" x%04llx", (long long)rq->sr2_messageid);
+ mdb_printf(" x%02x", rq->sr2_command);
+ } else {
+ mdb_printf(" x%04x", rq->sr_mid);
+ mdb_printf(" x%02x", rq->sr_cmd);
+ }
mdb_printf(" %d", rq->sr_state);
mdb_printf(" x%x", rq->sr_flags);
mdb_printf("\n");
@@ -443,9 +504,20 @@ int
rqlist_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
rqlist_cbdata_t cbd;
+ smb_vc_t *vcp;
+ size_t vcsz;
memset(&cbd, 0, sizeof (cbd));
+ /* Need the VC again to get */
+ vcsz = sizeof (*vcp);
+ vcp = mdb_alloc(vcsz, UM_SLEEP | UM_GC);
+ if (mdb_vread(vcp, vcsz, addr) != vcsz) {
+ mdb_warn("cannot read VC from %p", addr);
+ return (DCMD_ERR);
+ }
+ cbd.vcflags = vcp->vc_flags;
+
/*
* Initial walk_addr is address of parent (VC)
*/
@@ -606,6 +678,8 @@ static const mdb_walker_t walkers[] = {
smb_vc_walk_init, smb_co_walk_step, NULL },
{ "nsmb_ss", "walk nsmb share list for some VC",
smb_ss_walk_init, smb_co_walk_step, NULL },
+ { "nsmb_fh", "walk nsmb share list for some VC",
+ smb_fh_walk_init, smb_co_walk_step, NULL },
{ "nsmb_rqlist", "walk request list for some VC",
rqlist_walk_init, rqlist_walk_step, NULL },
{ "nsmb_pwtree", "walk passord AVL tree",
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 e69b199ad0..be5ad05c42 100644
--- a/usr/src/lib/libsmbfs/Makefile.com
+++ b/usr/src/lib/libsmbfs/Makefile.com
@@ -64,6 +64,7 @@ OBJ_LIB=\
ntlmssp.o \
print.o \
rcfile.o \
+ rc_scf.o \
spnego.o \
spnegoparse.o \
ssp.o \
@@ -89,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)
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 c9aa810c91..ae71332e97 100644
--- a/usr/src/lib/libsmbfs/netsmb/smb_lib.h
+++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
@@ -126,6 +126,8 @@ 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
@@ -194,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/connect.c b/usr/src/lib/libsmbfs/smb/connect.c
index a45fa90958..c231fe0e8a 100644
--- a/usr/src/lib/libsmbfs/smb/connect.c
+++ b/usr/src/lib/libsmbfs/smb/connect.c
@@ -51,6 +51,7 @@
#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>
@@ -59,6 +60,8 @@
#include <netsmb/nb_lib.h>
#include <netsmb/smb_dev.h>
+#include <cflib.h>
+
#include "charsets.h"
#include "private.h"
#include "smb_crypt.h"
@@ -115,12 +118,18 @@ smb_iod_state_name(enum smbiod_state st)
/*
* 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)
{
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;
@@ -151,6 +160,20 @@ 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.
*/
@@ -227,6 +250,13 @@ out:
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)
{
@@ -249,25 +279,39 @@ smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
}
for (;;) {
err = smb__ssnsetup(ctx, &send_mb, &recv_mb);
- if (err != 0 && err != EINPROGRESS) {
- DPRINT("smb__ssnsetup, err=%d", err);
- goto out;
- }
- DPRINT("smb__ssnsetup, new state=%s",
+ DPRINT("smb__ssnsetup rc=%d, new state=%s", err,
smb_iod_state_name(work->wk_out_state));
- if (work->wk_out_state == SMBIOD_ST_AUTHOK) {
- err = 0;
+
+ 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 (work->wk_out_state == SMBIOD_ST_AUTHFAIL) {
- err = EAUTH;
+
+ if (err != EINPROGRESS) {
+ /*
+ * Session setup complete w/ failure.
+ * Should have state AUTHFAIL
+ */
+ 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) {
- err = EPROTO;
- goto out;
+ DPRINT("Wrong state (expected AUTHCONT)");
}
- /* state == SMBIOD_ST_AUTHCONT */
/* middle calls get both in, out */
err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
@@ -277,7 +321,12 @@ smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
}
}
- /* NULL output indicates last call. */
+ /*
+ * 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);
/*
diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c
index 43ca516f81..3aa67fd5f5 100644
--- a/usr/src/lib/libsmbfs/smb/ctx.c
+++ b/usr/src/lib/libsmbfs/smb/ctx.c
@@ -165,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:");
@@ -259,6 +261,7 @@ smb_ctx_init(struct smb_ctx *ctx)
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, ...
@@ -856,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)
{
@@ -1120,8 +1154,12 @@ 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.
*/
@@ -1362,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:
@@ -1374,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) {
@@ -1392,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 1c4e2dc236..3d2a431142 100644
--- a/usr/src/lib/libsmbfs/smb/file.c
+++ b/usr/src/lib/libsmbfs/smb/file.c
@@ -217,7 +217,6 @@ 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;
@@ -234,7 +233,6 @@ 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;
@@ -262,7 +260,6 @@ smb_fh_xactnp(int fd,
/* this gets copyin & copyout */
bzero(&ioc, sizeof (ioc));
- ioc.ioc_fh = -1; /* tell driver to supply this */
ioc.ioc_tdlen = tdlen;
ioc.ioc_rdlen = *rdlen;
ioc.ioc_more = 0;
diff --git a/usr/src/lib/libsmbfs/smb/iod_wk.c b/usr/src/lib/libsmbfs/smb/iod_wk.c
index b19f1f3f0f..38e9d5e0de 100644
--- a/usr/src/lib/libsmbfs/smb/iod_wk.c
+++ b/usr/src/lib/libsmbfs/smb/iod_wk.c
@@ -104,6 +104,7 @@ smb_iod_work(smb_ctx_t *ctx)
DPRINT("ioc_idle: err %d", err);
goto out;
}
+ DPRINT("Ret. from _ioc_idle");
continue;
case SMBIOD_ST_RECONNECT:
@@ -119,16 +120,14 @@ 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;
- continue;
-
- case SMBIOD_ST_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.
*/
DPRINT("Call _iod_rcfail...");
if (nsmb_ioctl(ctx->ct_dev_fd,
@@ -152,9 +151,11 @@ smb_iod_work(smb_ctx_t *ctx)
DPRINT("iod_work: err %d", err);
goto out;
}
+ DPRINT("Ret. from _ioc_work");
continue;
case SMBIOD_ST_DEAD:
+ DPRINT("got state=DEAD");
err = 0;
goto out;
diff --git a/usr/src/lib/libsmbfs/smb/mapfile-vers b/usr/src/lib/libsmbfs/smb/mapfile-vers
index 73ab2504f5..a94b3bc6e1 100644
--- a/usr/src/lib/libsmbfs/smb/mapfile-vers
+++ b/usr/src/lib/libsmbfs/smb/mapfile-vers
@@ -68,6 +68,9 @@ SYMBOL_VERSION SUNWprivate {
nsmb_close { FLAGS = NODIRECT };
nsmb_ioctl { FLAGS = NODIRECT };
+ smb_cf_minauth_from_str;
+ smb_cf_version_from_str;
+
smb_close_rcfile;
smb_ctx_alloc;
@@ -91,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;
diff --git a/usr/src/lib/libsmbfs/smb/print.c b/usr/src/lib/libsmbfs/smb/print.c
index 80fcab7d10..698dd8359f 100644
--- a/usr/src/lib/libsmbfs/smb/print.c
+++ b/usr/src/lib/libsmbfs/smb/print.c
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -57,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);
@@ -91,6 +103,14 @@ smb_open_printer(struct smb_ctx *ctx, const char *title,
ioc.ioc_prmode = mode;
strlcpy(ioc.ioc_title, title, SMBIOC_MAX_NAME);
+ /*
+ * 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;
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 56335d0954..d7ee2d15af 100644
--- a/usr/src/lib/libsmbfs/smb/rcfile.c
+++ b/usr/src/lib/libsmbfs/smb/rcfile.c
@@ -32,7 +32,7 @@
* $Id: rcfile.c,v 1.1.1.2 2001/07/06 22:38:43 conrad Exp $
*/
/*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <fcntl.h>
@@ -60,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;
@@ -150,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)
{
@@ -189,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);
@@ -663,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/smbclnt/libfknsmb/Makefile.com b/usr/src/lib/smbclnt/libfknsmb/Makefile.com
index 3c79d72974..01da52d337 100644
--- a/usr/src/lib/smbclnt/libfknsmb/Makefile.com
+++ b/usr/src/lib/smbclnt/libfknsmb/Makefile.com
@@ -22,7 +22,7 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
#
LIBRARY = libfknsmb.a
@@ -57,6 +57,9 @@ OBJS_NSMB = \
smb_tran.o \
smb_trantcp.o \
smb_usr.o \
+ smb2_rq.o \
+ smb2_sign.o \
+ smb2_smb.o \
subr_mchain.o
OBJECTS = \
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers b/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers
index 1123cc1e85..27fbd87b4d 100644
--- a/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers
+++ b/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers
@@ -20,7 +20,7 @@
#
#
# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
#
#
@@ -57,12 +57,15 @@ SYMBOL_VERSION SUNWprivate {
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;
@@ -82,9 +85,15 @@ SYMBOL_VERSION SUNWprivate {
smb_credinit;
smb_credrele;
+ smb_debugmsg { FLAGS = NODIRECT };
smb_dev2share;
- smb_dos2unixtime;
- smb_errmsg;
+ 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;
@@ -110,12 +119,16 @@ SYMBOL_VERSION SUNWprivate {
smb_time_local2NT;
smb_time_local2server;
smb_time_server2local;
- smb_time_unix2dos;
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/libfksmbfs/Makefile.com b/usr/src/lib/smbclnt/libfksmbfs/Makefile.com
index 5eb9728c12..abc12a9464 100644
--- a/usr/src/lib/smbclnt/libfksmbfs/Makefile.com
+++ b/usr/src/lib/smbclnt/libfksmbfs/Makefile.com
@@ -22,7 +22,7 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
#
LIBRARY = libfksmbfs.a
@@ -55,6 +55,8 @@ OBJS_FS_SMBFS = \
smbfs_client.o \
smbfs_node.o \
smbfs_smb.o \
+ smbfs_smb1.o \
+ smbfs_smb2.o \
smbfs_subr.o \
smbfs_subr2.o \
smbfs_acl.o \
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>
diff --git a/usr/src/man/man4/nsmbrc.4 b/usr/src/man/man4/nsmbrc.4
index 2468be8f28..5eaffa9f63 100644
--- a/usr/src/man/man4/nsmbrc.4
+++ b/usr/src/man/man4/nsmbrc.4
@@ -3,7 +3,8 @@
.\" 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]
-.TH NSMBRC 4 "Dec 8, 2008"
+.\" Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+.TH NSMBRC 4 "May 8, 2018"
.SH NAME
nsmbrc \- configuration file for Solaris CIFS client requests
.SH SYNOPSIS
@@ -13,7 +14,6 @@ nsmbrc \- configuration file for Solaris CIFS client requests
.fi
.SH DESCRIPTION
-.sp
.LP
Global behavior of the Solaris CIFS client is defined by property values that
are stored in the Service Management Facility (SMF). The \fB\&.nsmbrc\fR file
@@ -137,6 +137,32 @@ value is \fBntlm\fR.
.sp
.ne 2
.na
+\fB\fBmin_protocol\fR\fR
+.ad
+.sp .6
+.RS 4n
+Is the minimum SMB protocol level that will be negotiated,
+which must be one of: \fB1\fR, \fB2.1\fR
+This property can only be set in the default and server sections.
+The default value is \fB1\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBmax_protocol\fR\fR
+.ad
+.sp .6
+.RS 4n
+Is the maximum SMB protocol level that will be negotiated,
+which must be one of: \fB1\fR, \fB2.1\fR
+This property can only be set in the default and server sections.
+The default value is \fB2.1\fR.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fBnbns\fR\fR
.ad
.sp .6
@@ -254,7 +280,6 @@ property. Use the \fBdomain\fR property instead.
.RE
.SH EXAMPLES
-.sp
.LP
The examples in this section show how to use the \fB\&.nsmbrc\fR file and the
\fBsmbutil\fR command to configure the \fBex.com\fR environment.
@@ -360,7 +385,6 @@ shown are those set by the previous example.
.sp
.SH FILES
-.sp
.ne 2
.na
\fB\fB$HOME/.nsmbrc\fR\fR
@@ -372,7 +396,6 @@ connection.
.RE
.SH ATTRIBUTES
-.sp
.LP
See \fBattributes\fR(5) for descriptions of the following attributes:
.sp
@@ -388,13 +411,11 @@ Interface Stability Committed
.TE
.SH SEE ALSO
-.sp
.LP
\fBsmbutil\fR(1), \fBmount_smbfs\fR(1M), \fBsharectl\fR(1M),
\fBnsswitch.conf\fR(4), \fBuser_attr\fR(4), \fBattributes\fR(5), \fBrbac\fR(5),
\fBsmbfs\fR(7FS)
.SH NOTES
-.sp
.LP
By default, passwords stored in the \fB\&.nsmbrc\fR file are ignored unless
\fBonly\fR the file owner has read and write permission.
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 98a01e9993..7469b797d0 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1272,11 +1272,13 @@ VSCAN_OBJS += vscan_drv.o vscan_svc.o vscan_door.o
NSMB_OBJS += smb_conn.o smb_dev.o smb_iod.o smb_pass.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 \
- subr_mchain.o nsmb_sign_kcf.o
+ smb2_rq.o smb2_sign.o smb2_smb.o subr_mchain.o \
+ nsmb_sign_kcf.o
SMBFS_COMMON_OBJS += smbfs_ntacl.o
SMBFS_OBJS += smbfs_vfsops.o smbfs_vnops.o smbfs_node.o \
smbfs_acl.o smbfs_client.o smbfs_smb.o \
+ smbfs_smb1.o smbfs_smb2.o \
smbfs_subr.o smbfs_subr2.o \
smbfs_rwlock.o smbfs_xattr.o \
$(SMBFS_COMMON_OBJS)
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple
new file mode 100644
index 0000000000..a42fec94d8
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2001 - 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip
new file mode 100644
index 0000000000..96b9771514
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip
@@ -0,0 +1 @@
+PORTIONS OF NSMB DRIVER IN SMB CLIENT
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov
new file mode 100644
index 0000000000..583923c355
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov
@@ -0,0 +1,29 @@
+ 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.
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip
new file mode 100644
index 0000000000..96b9771514
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip
@@ -0,0 +1 @@
+PORTIONS OF NSMB DRIVER IN SMB CLIENT
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
index 1d3bc3e6f5..a78b08bba0 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
@@ -52,8 +52,10 @@ smbioc_ssn_ident
id_user
smbioc_ossn
- ssn_vopt
ssn_owner
+ ssn_vopt
+ ssn_minver
+ ssn_maxver
ssn_id
ssn_srvname
@@ -76,22 +78,22 @@ smbioc_ssn_work
wk_u_auth_wlen
wk_u_auth_rbuf
wk_u_auth_wbuf
- wk_ssn_key
+ wk_cl_guid
+
+smbioc_rw SIZEOF_SMBIOC_RW
+ ioc_cnt
+ ioc_flags
+ _ioc_offset
+ _ioc_base
smbioc_xnp SIZEOF_SMBIOC_XNP
- ioc_fh
ioc_tdlen
ioc_rdlen
ioc_more
+ ioc_pad1
_ioc_tdata
_ioc_rdata
-smbioc_rw SIZEOF_SMBIOC_RW
- ioc_fh
- ioc_cnt
- _ioc_offset
- _ioc_base
-
smbioc_ntcreate SIZEOF_NTCREATE
ioc_req_acc
ioc_efattr
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c
new file mode 100644
index 0000000000..44041ad975
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/kmem.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <sys/atomic.h>
+#include <sys/sdt.h>
+
+#include <netsmb/smb_osdep.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_tran.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
+
+static const uint8_t SMB2_SIGNATURE[4] = SMB2_PROTOCOL_ID;
+
+static int smb2_rq_enqueue(struct smb_rq *rqp);
+static int smb2_rq_reply(struct smb_rq *rqp);
+
+/*
+ * Given a request with it's body already composed,
+ * rewind to the start and fill in the SMB2 header.
+ * This is called when the request is enqueued,
+ * so we have the final message ID etc.
+ */
+void
+smb2_rq_fillhdr(struct smb_rq *rqp)
+{
+ struct mbchain mbtmp, *mbp = &mbtmp;
+ uint16_t creditcharge, creditrequest;
+ size_t len;
+ mblk_t *m;
+
+ ASSERT((rqp->sr2_nextcmd & 7) == 0);
+ if (rqp->sr2_nextcmd != 0) {
+ len = msgdsize(rqp->sr_rq.mb_top);
+ ASSERT((len & 7) == 0);
+ }
+
+ /*
+ * When sending negotiate, we don't technically know yet
+ * if the server handles SMB 2.1 or later and credits.
+ * Negotiate is supposed to set these to zero.
+ */
+ if (rqp->sr2_command == SMB2_NEGOTIATE) {
+ creditcharge = creditrequest = 0;
+ } else {
+ creditcharge = rqp->sr2_creditcharge;
+ creditrequest = rqp->sr2_creditsrequested;
+ }
+
+ /*
+ * Fill in the SMB2 header using a dup of the first mblk,
+ * which points at the same data but has its own wptr,
+ * so we can rewind without trashing the message.
+ */
+ m = dupb(rqp->sr_rq.mb_top);
+ m->b_wptr = m->b_rptr; /* rewind */
+ mb_initm(mbp, m);
+
+ mb_put_mem(mbp, SMB2_SIGNATURE, 4, MB_MSYSTEM);
+ mb_put_uint16le(mbp, SMB2_HDR_SIZE); /* Struct Size */
+ mb_put_uint16le(mbp, creditcharge);
+ mb_put_uint32le(mbp, 0); /* Status */
+ mb_put_uint16le(mbp, rqp->sr2_command);
+ mb_put_uint16le(mbp, creditrequest);
+ mb_put_uint32le(mbp, rqp->sr2_rqflags);
+ mb_put_uint32le(mbp, rqp->sr2_nextcmd);
+ mb_put_uint64le(mbp, rqp->sr2_messageid);
+
+ mb_put_uint32le(mbp, rqp->sr_pid); /* Process ID */
+ mb_put_uint32le(mbp, rqp->sr2_rqtreeid); /* Tree ID */
+ mb_put_uint64le(mbp, rqp->sr2_rqsessionid); /* Session ID */
+ /* The MAC signature is filled in by smb2_vc_sign() */
+
+ /* This will free the mblk from dupb. */
+ mb_done(mbp);
+}
+
+int
+smb2_rq_simple(struct smb_rq *rqp)
+{
+ return (smb2_rq_simple_timed(rqp, smb2_timo_default));
+}
+
+/*
+ * Simple request-reply exchange
+ */
+int
+smb2_rq_simple_timed(struct smb_rq *rqp, int timeout)
+{
+ int error;
+
+ rqp->sr_flags &= ~SMBR_RESTART;
+ rqp->sr_timo = timeout; /* in seconds */
+ rqp->sr_state = SMBRQ_NOTSENT;
+
+ error = smb2_rq_enqueue(rqp);
+ if (error == 0)
+ error = smb2_rq_reply(rqp);
+
+ return (error);
+}
+
+
+static int
+smb2_rq_enqueue(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ struct smb_share *ssp = rqp->sr_share;
+ int error = 0;
+
+ ASSERT((vcp->vc_flags & SMBV_SMB2) != 0);
+
+ /*
+ * Normal requests may initiate a reconnect,
+ * and/or wait for state changes to finish.
+ * Some requests set the NORECONNECT flag
+ * to avoid all that (i.e. tree discon)
+ */
+ if (rqp->sr_flags & SMBR_NORECONNECT) {
+ if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ SMBSDEBUG("bad vc_state=%d\n", vcp->vc_state);
+ return (ENOTCONN);
+ }
+ if (ssp != NULL &&
+ ((ssp->ss_flags & SMBS_CONNECTED) == 0))
+ return (ENOTCONN);
+ goto ok_out;
+ }
+
+ /*
+ * If we're not connected, initiate a reconnect
+ * and/or wait for an existing one to finish.
+ */
+ if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ error = smb_iod_reconnect(vcp);
+ if (error != 0)
+ return (error);
+ }
+
+ /*
+ * If this request has a "share" object
+ * that needs a tree connect, do it now.
+ */
+ if (ssp != NULL && (ssp->ss_flags & SMBS_CONNECTED) == 0) {
+ error = smb_share_tcon(ssp, rqp->sr_cred);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * We now know what UID + TID to use.
+ * Store them in the request.
+ */
+ok_out:
+ rqp->sr2_rqsessionid = vcp->vc2_session_id;
+ rqp->sr2_rqtreeid = ssp ? ssp->ss2_tree_id : SMB2_TID_UNKNOWN;
+ error = smb2_iod_addrq(rqp);
+
+ return (error);
+}
+
+/*
+ * Used by the IOD thread during connection setup,
+ * and for smb2_echo after network timeouts. Note that
+ * unlike smb2_rq_simple, callers must check sr_error.
+ */
+int
+smb2_rq_internal(struct smb_rq *rqp, int timeout)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ int error;
+
+ ASSERT((vcp->vc_flags & SMBV_SMB2) != 0);
+
+ rqp->sr_flags &= ~SMBR_RESTART;
+ rqp->sr_timo = timeout; /* in seconds */
+ rqp->sr_state = SMBRQ_NOTSENT;
+
+ /*
+ * In-line smb2_rq_enqueue(rqp) here, as we don't want it
+ * trying to reconnect etc. for an internal request.
+ */
+ rqp->sr2_rqsessionid = vcp->vc2_session_id;
+ rqp->sr2_rqtreeid = SMB2_TID_UNKNOWN;
+ rqp->sr_flags |= SMBR_INTERNAL;
+ error = smb2_iod_addrq(rqp);
+ if (error != 0)
+ return (error);
+
+ /*
+ * In-line a variant of smb2_rq_reply(rqp) here as we may
+ * need to do custom parsing for SMB1-to-SMB2 negotiate.
+ */
+ if (rqp->sr_timo == SMBNOREPLYWAIT) {
+ smb_iod_removerq(rqp);
+ return (0);
+ }
+
+ error = smb_iod_waitrq_int(rqp);
+ if (error)
+ return (error);
+
+ /*
+ * If the request was signed, validate the
+ * signature on the response.
+ */
+ if (rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) {
+ error = smb2_rq_verify(rqp);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * Parse the SMB2 header.
+ */
+ error = smb2_rq_parsehdr(rqp);
+
+ /*
+ * Skip the error translation smb2_rq_reply does.
+ * Callers of this expect "raw" NT status.
+ */
+
+ return (error);
+}
+
+/*
+ * Wait for a reply to this request, then parse it.
+ */
+static int
+smb2_rq_reply(struct smb_rq *rqp)
+{
+ int error;
+
+ if (rqp->sr_timo == SMBNOREPLYWAIT) {
+ smb_iod_removerq(rqp);
+ return (0);
+ }
+
+ error = smb_iod_waitrq(rqp);
+ if (error)
+ return (error);
+
+ /*
+ * If the request was signed, validate the
+ * signature on the response.
+ */
+ if (rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) {
+ error = smb2_rq_verify(rqp);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * Parse the SMB2 header
+ */
+ error = smb2_rq_parsehdr(rqp);
+ if (error != 0)
+ return (error);
+
+ if (rqp->sr_error != 0) {
+ error = smb_maperr32(rqp->sr_error);
+ }
+
+ if (error != 0) {
+ /*
+ * Do a special check for STATUS_BUFFER_OVERFLOW;
+ * it's not an error.
+ */
+ if (rqp->sr_error == NT_STATUS_BUFFER_OVERFLOW) {
+ /*
+ * Don't report it as an error to our caller;
+ * they can look at rqp->sr_error if they
+ * need to know whether we got a
+ * STATUS_BUFFER_OVERFLOW.
+ */
+ rqp->sr_flags |= SMBR_MOREDATA;
+ error = 0;
+ }
+ } else {
+ rqp->sr_flags &= ~SMBR_MOREDATA;
+ }
+
+ return (error);
+}
+
+/*
+ * Parse the SMB 2+ Header
+ */
+int
+smb2_rq_parsehdr(struct smb_rq *rqp)
+{
+ struct mdchain *mdp = &rqp->sr_rp;
+ uint32_t protocol_id;
+ uint16_t length = 0;
+ uint16_t credit_charge;
+ uint16_t command;
+ uint64_t message_id = 0;
+ int error = 0;
+
+ /* Get Protocol ID */
+ md_get_uint32le(mdp, &protocol_id);
+
+ /* Get/Check structure size is 64 */
+ md_get_uint16le(mdp, &length);
+ if (length != 64)
+ return (EBADRPC);
+
+ md_get_uint16le(mdp, &credit_charge);
+ md_get_uint32le(mdp, &rqp->sr_error);
+ md_get_uint16le(mdp, &command);
+ md_get_uint16le(mdp, &rqp->sr2_rspcreditsgranted);
+ md_get_uint32le(mdp, &rqp->sr2_rspflags);
+ md_get_uint32le(mdp, &rqp->sr2_rspnextcmd);
+ md_get_uint64le(mdp, &message_id);
+
+ if ((rqp->sr2_rspflags & SMB2_FLAGS_ASYNC_COMMAND) == 0) {
+ /*
+ * Sync Header
+ */
+
+ /* Get Process ID */
+ md_get_uint32le(mdp, &rqp->sr2_rsppid);
+
+ /* Get Tree ID */
+ md_get_uint32le(mdp, &rqp->sr2_rsptreeid);
+ } else {
+ /*
+ * Async Header
+ */
+
+ /* Get Async ID */
+ md_get_uint64le(mdp, &rqp->sr2_rspasyncid);
+ }
+
+ /* Get Session ID */
+ error = md_get_uint64le(mdp, &rqp->sr2_rspsessionid);
+ if (error)
+ return (error);
+
+ /* Skip MAC Signature */
+ error = md_get_mem(mdp, NULL, 16, MB_MSYSTEM);
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h
new file mode 100644
index 0000000000..812c679b2f
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011 - 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _NETSMB_SMB2_RQ_H_
+#define _NETSMB_SMB2_RQ_H_
+
+#include <sys/types.h>
+
+/*
+ * Note: Pad all structures to 8 byte boundaries
+ */
+
+int smb2_rq_parsehdr(struct smb_rq *rqp);
+void smb2_rq_fillhdr(struct smb_rq *rqp);
+
+int smb2_rq_simple(struct smb_rq *rqp);
+int smb2_rq_simple_timed(struct smb_rq *rqp, int timeout);
+int smb2_rq_internal(struct smb_rq *rqp, int timeout);
+
+#endif /* _NETSMB_SMB2_RQ_H_ */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c
new file mode 100644
index 0000000000..46bf28c370
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c
@@ -0,0 +1,253 @@
+/*
+ * 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.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Support for SMB2 "signing" (message integrity)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <sys/md4.h>
+#include <sys/md5.h>
+#include <sys/des.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/sdt.h>
+
+#include <netsmb/smb_osdep.h>
+#include <netsmb/smb2.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_dev.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb_signing.h>
+
+#define SMB2_SIG_OFF 48
+#define SMB2_SIG_LEN 16
+
+/*
+ * smb2_sign_init
+ *
+ * Get the mechanism info and initilize SMB2 signing.
+ */
+int
+smb2_sign_init(smb_vc_t *vcp)
+{
+ uint_t copysize;
+ int rc;
+
+ ASSERT(vcp->vc_ssnkey != NULL);
+ ASSERT(vcp->vc_mackey == NULL);
+
+ rc = smb2_hmac_getmech(&vcp->vc_signmech);
+ if (rc != 0) {
+ cmn_err(CE_NOTE, "smb2 can't get signing mechanism");
+ return (EAUTH);
+ }
+
+ /*
+ * Convert the session key to the MAC key.
+ *
+ * For SMB2, the signing key is just the first 16 bytes
+ * of the session key (truncated or padded with zeros).
+ * [MS-SMB2] 3.2.5.3.1
+ *
+ * SMB3 would do KDF here.
+ */
+ vcp->vc_mackeylen = SMB2_SIG_LEN;
+ vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP);
+ copysize = vcp->vc_ssnkeylen;
+ if (copysize > vcp->vc_mackeylen)
+ copysize = vcp->vc_mackeylen;
+ bcopy(vcp->vc_ssnkey, vcp->vc_mackey, copysize);
+
+ return (0);
+}
+
+
+/*
+ * Compute MAC signature of packet data, using the stored MAC key.
+ *
+ * The signature is in the last 16 bytes of the SMB2 header.
+ * The signature algorighm is to compute HMAC SHA256 over the
+ * entire command, with the signature field set to zeros.
+ *
+ * See similar code for the server side:
+ * uts/common/fs/smbsrv/smb2_signing.c : smb2_sign_calc
+ */
+static int
+smb2_compute_MAC(struct smb_vc *vcp, mblk_t *mp, uchar_t *signature)
+{
+ uint8_t tmp_hdr[SMB2_HDR_SIZE];
+ smb_sign_ctx_t ctx = 0;
+ mblk_t *m = mp;
+ int size;
+ int rc;
+
+ if (vcp->vc_mackey == NULL)
+ return (-1);
+
+ rc = smb2_hmac_init(&ctx, &vcp->vc_signmech,
+ vcp->vc_mackey, vcp->vc_mackeylen);
+ if (rc != 0)
+ return (rc);
+
+ /* Our caller should ensure mp has a contiguous header */
+ ASSERT(m != NULL);
+ ASSERT(MBLKL(m) >= SMB2_HDRLEN);
+
+ /*
+ * Copy of the SMB2 header, zero out the signature, and digest.
+ */
+ size = SMB2_HDRLEN;
+ bcopy(m->b_rptr, tmp_hdr, size);
+ bzero(tmp_hdr + SMB2_SIG_OFF, SMB2_SIG_LEN);
+ rc = smb2_hmac_update(ctx, tmp_hdr, size);
+ if (rc != 0)
+ return (rc);
+
+ /*
+ * Digest the rest of the SMB2 header packet, starting at
+ * the data just after the SMB2 header.
+ */
+ size = MBLKL(m) - SMB2_HDRLEN;
+ rc = smb2_hmac_update(ctx, m->b_rptr + SMB2_HDRLEN, size);
+ if (rc != 0)
+ return (rc);
+ m = m->b_cont;
+
+ /* Digest rest of the SMB2 message. */
+ while (m != NULL) {
+ size = MBLKL(m);
+ if (size > 0) {
+ rc = smb2_hmac_update(ctx, m->b_rptr, size);
+ if (rc != 0)
+ return (rc);
+ }
+ m = m->b_cont;
+ }
+ rc = smb2_hmac_final(ctx, signature);
+
+ return (rc);
+}
+
+/*
+ * Sign a request with HMAC-MD5.
+ */
+void
+smb2_rq_sign(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ mblk_t *mp = rqp->sr_rq.mb_top;
+ uint8_t *sigloc;
+ int rc;
+
+ /*
+ * smb_rq_new() ensures this,
+ * but just in case..
+ */
+ ASSERT(MBLKL(mp) >= SMB2_HDRLEN);
+ sigloc = mp->b_rptr + SMB2_SIG_OFF;
+
+ if (vcp->vc_mackey == NULL)
+ return;
+
+ /*
+ * This will compute the MAC and store it
+ * directly into the message at sigloc.
+ */
+ rc = smb2_compute_MAC(vcp, mp, sigloc);
+ if (rc != 0) {
+ SMBSDEBUG("Crypto error %d", rc);
+ bzero(sigloc, SMB2_SIG_LEN);
+ }
+}
+
+/*
+ * Verify reply signature.
+ */
+int
+smb2_rq_verify(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ mblk_t *mp = rqp->sr_rp.md_top;
+ uint8_t sigbuf[SMB2_SIG_LEN];
+ uint8_t *sigloc;
+ int rc;
+
+ /*
+ * Note vc_mackey and vc_mackeylen gets filled in by
+ * smb_usr_iod_work as the connection comes in.
+ */
+ if (vcp->vc_mackey == NULL) {
+ SMBSDEBUG("no mac key\n");
+ return (0);
+ }
+
+ /*
+ * Let caller deal with empty reply or short messages by
+ * returning zero. Caller will fail later, in parsing.
+ */
+ if (mp == NULL) {
+ SMBSDEBUG("empty reply\n");
+ return (0);
+ }
+
+ /* smb2_iod_process ensures this */
+ ASSERT(MBLKL(mp) >= SMB2_HDRLEN);
+ sigloc = mp->b_rptr + SMB2_SIG_OFF;
+
+ /*
+ * Compute the expected signature in sigbuf.
+ */
+ rc = smb2_compute_MAC(vcp, mp, sigbuf);
+ if (rc != 0) {
+ SMBSDEBUG("Crypto error %d", rc);
+ /*
+ * 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, SMB2_SIG_LEN) == 0)
+ return (0);
+
+ SMBERROR("BAD signature, Server=%s MID=0x%llx\n",
+ vcp->vc_srvname, (long long)rqp->sr2_messageid);
+
+ return (EBADRPC);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c
new file mode 100644
index 0000000000..c3df18faa9
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c
@@ -0,0 +1,1325 @@
+/*
+ * Copyright (c) 2011 - 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/random.h>
+#include <sys/note.h>
+#include <sys/errno.h>
+#include <sys/cmn_err.h>
+
+#include <smb/ntaccess.h>
+#include <smb/winioctl.h>
+
+#include <netsmb/smb_osdep.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_tran.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
+
+#define NDIALECTS 1
+static const uint16_t smb2_dialects[1] = {
+ SMB2_DIALECT_0210
+};
+
+/* Optional capabilities we advertise (none yet). */
+uint32_t smb2_clnt_caps = 0;
+
+/* How many credits to ask for during ssn. setup. */
+uint16_t smb2_ss_req_credits = 64;
+
+/*
+ * Default timeout values, all in seconds.
+ * Make these tunable (only via mdb for now).
+ */
+int smb2_timo_notice = 15;
+int smb2_timo_default = 30;
+int smb2_timo_logon = 45;
+int smb2_timo_open = 45;
+int smb2_timo_read = 45;
+int smb2_timo_write = 60;
+int smb2_timo_append = 90;
+
+/*
+ * This is a special handler for the odd SMB1-to-SMB2 negotiate
+ * response, where an SMB1 request gets an SMB2 response.
+ *
+ * Unlike most parse functions here, this needs to parse both
+ * the SMB2 header and the nego. response body. Note that
+ * the only "SMB2" dialect our SMB1 negotiate offered was
+ * { SMB_DIALECT_SMB2_FF, "SMB 2.???"} so the only valid
+ * SMB2 dialect we should get is: SMB2_DIALECT_02ff
+ */
+int
+smb2_parse_smb1nego_resp(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ struct smb_sopt *sp = &vcp->vc_sopt;
+ struct mdchain *mdp;
+ uint16_t length = 0;
+ int error;
+
+ /* Get pointer to response data */
+ smb_rq_getreply(rqp, &mdp);
+
+ error = smb2_rq_parsehdr(rqp);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Parse SMB 2/3 Negotiate Response
+ * We are already pointing to begining of Response data
+ */
+
+ /* Check structure size is 65 */
+ md_get_uint16le(mdp, &length);
+ if (length != 65)
+ return (EBADRPC);
+
+ /* Get Security Mode */
+ md_get_uint16le(mdp, &sp->sv2_security_mode);
+
+ /* Get Dialect. */
+ error = md_get_uint16le(mdp, &sp->sv2_dialect);
+ if (error != 0)
+ return (error);
+
+ /* What dialect did we get? */
+ if (sp->sv2_dialect != SMB2_DIALECT_02ff) {
+ SMBERROR("Unknown dialect 0x%x\n", sp->sv2_dialect);
+ return (EINVAL);
+ }
+ /* Set our (internal) SMB1 dialect also. */
+ sp->sv_proto = SMB_DIALECT_SMB2_FF;
+
+ /*
+ * This request did not go through smb2_iod_addrq and
+ * smb2_iod_process() so the SMB2 message ID state is
+ * behind what we need it to be. Fix that.
+ */
+ vcp->vc2_next_message_id = 1;
+ vcp->vc2_limit_message_id = 2;
+
+ /*
+ * Skip parsing the rest. We'll get a normal
+ * SMB2 negotiate next and do negotiate then.
+ */
+ return (0);
+}
+
+int
+smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ smb_sopt_t *sp = &vcp->vc_sopt;
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp = NULL;
+ struct mdchain *mdp = NULL;
+ uint16_t ndialects = NDIALECTS;
+ boolean_t will_sign = B_FALSE;
+ uint16_t length = 0;
+ uint16_t security_mode;
+ uint16_t sec_buf_off;
+ uint16_t sec_buf_len;
+ int err, i;
+
+ /*
+ * Compute security mode
+ */
+ if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
+ security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ } else {
+ security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+ }
+
+ err = smb_rq_alloc(VCTOCP(vcp), SMB2_NEGOTIATE, scred, &rqp);
+ if (err)
+ return (err);
+
+ /*
+ * Build the SMB2 negotiate request.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 36); /* Struct Size */
+ mb_put_uint16le(mbp, ndialects); /* Dialect Count */
+ mb_put_uint16le(mbp, security_mode);
+ mb_put_uint16le(mbp, 0); /* Reserved */
+ mb_put_uint32le(mbp, smb2_clnt_caps);
+ mb_put_mem(mbp, vcp->vc_cl_guid, 16, MB_MSYSTEM);
+ mb_put_uint64le(mbp, 0); /* Start Time */
+ for (i = 0; i < ndialects; i++) { /* Dialects */
+ mb_put_uint16le(mbp, smb2_dialects[i]);
+ }
+
+ /*
+ * Do the OTW call.
+ */
+ err = smb2_rq_internal(rqp, smb2_timo_default);
+ if (err) {
+ goto errout;
+ }
+ /* Should only get status success. */
+ if (rqp->sr_error != NT_STATUS_SUCCESS) {
+ err = ENOTSUP;
+ goto errout;
+ }
+
+ /*
+ * Decode the negotiate response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ md_get_uint16le(mdp, &length); /* Struct size */
+ if (length != 65) {
+ err = EBADRPC;
+ goto errout;
+ }
+
+ md_get_uint16le(mdp, &sp->sv2_security_mode);
+ md_get_uint16le(mdp, &sp->sv2_dialect);
+ md_get_uint16le(mdp, NULL); /* reserved */
+ md_get_mem(mdp, sp->sv2_guid, 16, MB_MSYSTEM);
+ md_get_uint32le(mdp, &sp->sv2_capabilities);
+ md_get_uint32le(mdp, &sp->sv2_maxtransact);
+ md_get_uint32le(mdp, &sp->sv2_maxread);
+ md_get_uint32le(mdp, &sp->sv2_maxwrite);
+ md_get_uint64le(mdp, NULL); /* curr_time */
+ md_get_uint64le(mdp, NULL); /* boot_time */
+
+ /* Get Security Blob offset and length */
+ md_get_uint16le(mdp, &sec_buf_off);
+ err = md_get_uint16le(mdp, &sec_buf_len);
+ if (err != 0)
+ goto errout;
+ md_get_uint32le(mdp, NULL); /* reserved */
+
+ /*
+ * Security buffer offset is from the beginning of SMB 2 Header
+ * Calculate how much further we have to go to get to it.
+ * Current offset is: SMB2_HDRLEN + 64
+ */
+ if (sec_buf_len != 0) {
+ int skip = (int)sec_buf_off - (SMB2_HDRLEN + 64);
+ if (skip < 0) {
+ err = EBADRPC;
+ goto errout;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+
+ /*
+ * Copy the security blob out to user space.
+ * Buffer addr,size in vc_auth_rbuf,rlen
+ */
+ if (wk->wk_u_auth_rlen < sec_buf_len) {
+ SMBSDEBUG("vc_auth_rbuf too small");
+ /* Give caller required size. */
+ wk->wk_u_auth_rlen = sec_buf_len;
+ err = EMSGSIZE;
+ goto errout;
+ }
+ wk->wk_u_auth_rlen = sec_buf_len;
+ err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
+ sec_buf_len, MB_MUSER);
+ if (err) {
+ goto errout;
+ }
+ }
+
+ /*
+ * Decoded everything. Now decisions.
+ */
+
+ /*
+ * Turn on signing if either Server or client requires it,
+ * except: anonymous sessions can't sign.
+ */
+ if ((sp->sv2_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
+ (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED))
+ will_sign = B_TRUE;
+ if (vcp->vc_vopt & SMBVOPT_ANONYMOUS)
+ will_sign = B_FALSE;
+ SMBSDEBUG("Security signatures: %d", (int)will_sign);
+ if (will_sign)
+ vcp->vc_flags |= SMBV_SIGNING;
+
+ /*
+ * ToDo - too many places are looking at sv_caps, so for now
+ * set the SMB1 capabilities too. Later we should use the
+ * sv2_capabilities for SMB 2+.
+ */
+ sp->sv_caps = (SMB_CAP_UNICODE |
+ SMB_CAP_LARGE_FILES |
+ SMB_CAP_STATUS32 |
+ SMB_CAP_LARGE_READX |
+ SMB_CAP_LARGE_WRITEX |
+ SMB_CAP_EXT_SECURITY);
+ if (sp->sv2_capabilities & SMB2_CAP_DFS)
+ sp->sv_caps |= SMB_CAP_DFS;
+
+ /*
+ * 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 (sp->sv2_maxread < 0x8000) {
+ SMBSDEBUG("maxread too small\n");
+ err = ENOTSUP;
+ goto errout;
+ }
+ if (sp->sv2_maxwrite < 0x8000) {
+ SMBSDEBUG("maxwrite too small\n");
+ err = ENOTSUP;
+ goto errout;
+ }
+ if (sp->sv2_maxtransact < 0x4000) {
+ SMBSDEBUG("maxtransact too small\n");
+ err = ENOTSUP;
+ goto errout;
+ }
+
+ /* Here too, fill SMB1 fields */
+ vcp->vc_rxmax = sp->sv2_maxread;
+ vcp->vc_wxmax = sp->sv2_maxwrite;
+ vcp->vc_txmax = sp->sv2_maxtransact;
+
+ smb_rq_done(rqp);
+ return (0);
+
+errout:
+ smb_rq_done(rqp);
+ if (err == 0)
+ err = EBADRPC;
+ return (err);
+}
+
+int
+smb2_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ // smb_sopt_t *sv = &vcp->vc_sopt;
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp = NULL;
+ struct mdchain *mdp = NULL;
+ char *sb;
+ int err, ret;
+ uint16_t sblen;
+ uint16_t length = 0;
+ uint16_t session_flags;
+ uint16_t sec_buf_off;
+ uint16_t sec_buf_len;
+ uint8_t security_mode;
+
+ /*
+ * Compute security mode
+ */
+ if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
+ security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ } else {
+ security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+ }
+
+ sb = wk->wk_u_auth_wbuf.lp_ptr;
+ sblen = (uint16_t)wk->wk_u_auth_wlen;
+
+ err = smb_rq_alloc(VCTOCP(vcp), SMB2_SESSION_SETUP, scred, &rqp);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+
+ /*
+ * Always ask for some credits. The server usually will
+ * only grant these credits once we've authenticated.
+ */
+ rqp->sr2_creditsrequested = smb2_ss_req_credits;
+
+ /*
+ * Build the SMB Session Setup request.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+
+ mb_put_uint16le(mbp, 25); /* Struct size */
+ mb_put_uint8(mbp, 0); /* VcNumber */
+ mb_put_uint8(mbp, security_mode);
+ mb_put_uint32le(mbp, smb2_clnt_caps); /* Capabilities */
+ mb_put_uint32le(mbp, 0); /* Channel - always 0 */
+
+ /*
+ * Security buffer offset and length. Normally would use
+ * ptr = mb_reserve() and fill in later, but since only a
+ * small amount of fixed-size stuff follows (12 bytes)
+ * we can just compute the offset now.
+ */
+ mb_put_uint16le(mbp, mbp->mb_count + 12);
+ mb_put_uint16le(mbp, sblen);
+ mb_put_uint64le(mbp, vcp->vc2_prev_session_id);
+ err = mb_put_mem(mbp, sb, sblen, MB_MUSER);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+
+ /*
+ * Run the request. The return value here should be the
+ * return from this function, unless we fail decoding.
+ * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and
+ * the caller expects EINPROGRESS for that case.
+ */
+ ret = smb2_rq_internal(rqp, smb2_timo_logon);
+ if (ret != 0)
+ goto out;
+ switch (rqp->sr_error) {
+ case NT_STATUS_SUCCESS:
+ break;
+ case NT_STATUS_MORE_PROCESSING_REQUIRED:
+ /* Keep going, but return... */
+ ret = EINPROGRESS;
+ break;
+ default:
+ ret = EAUTH;
+ goto out;
+ }
+
+ /*
+ * After the first Session Setup Response,
+ * save the session ID.
+ */
+ if (vcp->vc2_session_id == 0)
+ vcp->vc2_session_id = rqp->sr2_rspsessionid;
+
+ /*
+ * Decode the session setup response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ md_get_uint16le(mdp, &length); /* Struct size */
+ if (length != 9) {
+ ret = EBADRPC;
+ goto out;
+ }
+
+ md_get_uint16le(mdp, &session_flags);
+ md_get_uint16le(mdp, &sec_buf_off);
+ err = md_get_uint16le(mdp, &sec_buf_len);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+
+ /*
+ * Security buffer offset is from the beginning of SMB 2 Header
+ * Calculate how much further we have to go to get to it.
+ * Current offset is: SMB2_HDRLEN + 8
+ */
+ if (sec_buf_len != 0) {
+ int skip = (int)sec_buf_off - (SMB2_HDRLEN + 8);
+ if (skip < 0) {
+ ret = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+
+ /*
+ * Copy the security blob out to user space.
+ * Buffer addr,size in vc_auth_rbuf,rlen
+ */
+ if (wk->wk_u_auth_rlen < sec_buf_len) {
+ SMBSDEBUG("vc_auth_rbuf too small");
+ /* Give caller required size. */
+ wk->wk_u_auth_rlen = sec_buf_len;
+ ret = EMSGSIZE;
+ goto out;
+ }
+ wk->wk_u_auth_rlen = sec_buf_len;
+ err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
+ sec_buf_len, MB_MUSER);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+ }
+
+out:
+ if (err != 0 && err != EINPROGRESS) {
+ /* Session ID no longer valid. */
+ vcp->vc2_session_id = 0;
+ }
+ if (rqp)
+ smb_rq_done(rqp);
+
+ return (ret);
+}
+
+int
+smb2_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ if (vcp->vc2_session_id == 0)
+ return (0);
+
+ error = smb_rq_alloc(VCTOCP(vcp), SMB2_LOGOFF, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Fill in Logoff part
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 4); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+
+ /*
+ * Run this with a relatively short timeout. (5 sec.)
+ * We don't really care about the result here.
+ * Also, don't reconnect for this, of course!
+ */
+ rqp->sr_flags |= SMBR_NORECONNECT;
+ error = smb2_rq_internal(rqp, 5);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+int
+smb2_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
+{
+ struct smb_vc *vcp;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ char *unc_name = NULL;
+ int error, unc_len;
+ uint16_t plen, *plenp;
+ uint16_t options = 0;
+ uint_t cnt0;
+ uint32_t net_stype;
+ uint16_t structure_size = 0;
+ uint8_t smb2stype;
+
+ vcp = SSTOVC(ssp);
+
+ /*
+ * Make this a "VC-level" request, so it will have
+ * rqp->sr_share == NULL, and smb_iod_sendrq()
+ * will send it with TID = SMB_TID_UNKNOWN
+ *
+ * This also serves to bypass the wait for
+ * share state changes, which this call is
+ * trying to carry out.
+ */
+ error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_CONNECT, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the UNC name, i.e. "//server/share"
+ * but with backslashes of course.
+ * size math: three slashes, one null.
+ */
+ unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name);
+ unc_name = kmem_alloc(unc_len, KM_SLEEP);
+ (void) snprintf(unc_name, unc_len, "\\\\%s\\%s",
+ vcp->vc_srvname, ssp->ss_name);
+ SMBSDEBUG("unc_name: \"%s\"", unc_name);
+
+ /*
+ * Build the request.
+ */
+ mbp = &rqp->sr_rq;
+
+ mb_put_uint16le(mbp, 9); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+ mb_put_uint16le(mbp, 72); /* Path Offset */
+
+ /*
+ * Fill in path length after we put the string, so we know
+ * the length after conversion from UTF-8 to UCS-2.
+ */
+ plenp = mb_reserve(mbp, 2);
+ cnt0 = mbp->mb_count;
+
+ /* UNC resource name (without the null) */
+ error = smb_put_dmem(mbp, vcp, unc_name, unc_len - 1,
+ SMB_CS_NONE, NULL);
+ if (error)
+ goto out;
+
+ /* Now go back and fill in the path length. */
+ plen = (uint16_t)(mbp->mb_count - cnt0);
+ *plenp = htoles(plen);
+
+ /*
+ * Run the request.
+ *
+ * Using NOINTR_RECV because we don't want to risk
+ * missing a successful tree connect response,
+ * which would "leak" Tree IDs.
+ */
+ rqp->sr_flags |= SMBR_NOINTR_RECV;
+ error = smb2_rq_simple(rqp);
+ SMBSDEBUG("%d\n", error);
+ if (error) {
+ /*
+ * If we get the server name wrong, i.e. due to
+ * mis-configured name services, this will be
+ * NT_STATUS_DUPLICATE_NAME. Log this error.
+ */
+ SMBERROR("(%s) failed, status=0x%x",
+ unc_name, rqp->sr_error);
+ goto out;
+ }
+
+ /*
+ * Parse the tree connect response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 16 */
+ md_get_uint16le(mdp, &structure_size);
+ if (structure_size != 16) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ md_get_uint8(mdp, &smb2stype);
+ md_get_uint8(mdp, NULL); /* reserved */
+ md_get_uint32le(mdp, &ssp->ss2_share_flags);
+ md_get_uint32le(mdp, &ssp->ss2_share_caps);
+ error = md_get_uint32le(mdp, NULL); /* maxAccessRights */
+ if (error)
+ goto out;
+
+ /*
+ * Convert SMB2 share type to NetShareEnum share type
+ */
+ switch (smb2stype) {
+ case SMB2_SHARE_TYPE_DISK:
+ net_stype = STYPE_DISKTREE;
+ break;
+ case SMB2_SHARE_TYPE_PIPE:
+ net_stype = STYPE_IPC;
+ break;
+ case SMB2_SHARE_TYPE_PRINT:
+ net_stype = STYPE_PRINTQ;
+ break;
+ default:
+ net_stype = STYPE_UNKNOWN;
+ break;
+ }
+ ssp->ss_type = net_stype;
+
+ /*
+ * Map SMB 2/3 capabilities to SMB 1 options,
+ * for common code that looks there.
+ */
+ if (ssp->ss2_share_caps & SMB2_SHARE_CAP_DFS)
+ options |= SMB_SHARE_IS_IN_DFS;
+
+ /* Update share state */
+ SMB_SS_LOCK(ssp);
+ ssp->ss2_tree_id = rqp->sr2_rsptreeid;
+ ssp->ss_vcgenid = vcp->vc_genid;
+ ssp->ss_options = options;
+ ssp->ss_flags |= SMBS_CONNECTED;
+ SMB_SS_UNLOCK(ssp);
+
+out:
+ if (unc_name)
+ kmem_free(unc_name, unc_len);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+int
+smb2_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
+{
+ struct smb_vc *vcp;
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ if (ssp->ss2_tree_id == SMB2_TID_UNKNOWN)
+ return (0);
+
+ /*
+ * Build this as a "VC-level" request, so it will
+ * avoid testing the _GONE flag on the share,
+ * which has already been set at this point.
+ * Add the share pointer "by hand" below, so
+ * smb_iod_sendrq will plug in the TID.
+ */
+ vcp = SSTOVC(ssp);
+ error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_DISCONNECT, scred, &rqp);
+ if (error)
+ return (error);
+ rqp->sr_share = ssp; /* See "by hand" above. */
+
+ /*
+ * Fill in SMB2 Tree Disconnect part
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 4); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+
+ /*
+ * Run this with a relatively short timeout. (5 sec.)
+ * We don't really care about the result here, but we
+ * do need to make sure we send this out, or we could
+ * "leak" active tree IDs on interrupt or timeout.
+ * The NOINTR_SEND flag makes this request immune to
+ * interrupt or timeout until the send is done.
+ * Also, don't reconnect for this, of course!
+ */
+ rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
+ error = smb2_rq_simple_timed(rqp, 5);
+
+ smb_rq_done(rqp);
+
+ /* Whether we get an error or not... */
+ ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
+
+ return (error);
+}
+
+/*
+ * Put the name, first skipping a leading slash.
+ */
+static int
+put_name_skip_slash(struct mbchain *mbp, struct mbchain *name_mbp)
+{
+ mblk_t *m;
+
+ if (name_mbp == NULL)
+ return (0);
+ m = name_mbp->mb_top;
+ if (m == NULL)
+ return (0);
+
+ /* Use a dup of the message to leave the passed one untouched. */
+ m = dupmsg(m);
+ if (m == NULL)
+ return (ENOSR);
+
+ if (MBLKL(m) >= 2 &&
+ m->b_rptr[0] == '\\' &&
+ m->b_rptr[1] == '\0')
+ m->b_rptr += 2;
+
+ return (mb_put_mbuf(mbp, m));
+}
+
+/*
+ * Modern create/open of file or directory.
+ *
+ * The passed name is a full path relative to the share root.
+ * Callers prepare paths with a leading slash (backslash)
+ * because that's what SMB1 expected. SMB2 does not allow the
+ * leading slash here. To make life simpler for callers skip a
+ * leading slash here. That allows callers use use common logic
+ * for building paths without needing to know if the connection
+ * is using SMB1 or SMB2 (just build paths with a leading slash).
+ */
+int
+smb2_smb_ntcreate(
+ struct smb_share *ssp,
+ struct mbchain *name_mb,
+ struct mbchain *cctx_in,
+ struct mdchain *cctx_out,
+ uint32_t cr_flags, /* create flags */
+ uint32_t req_acc, /* requested access */
+ uint32_t efa, /* ext. file attrs (DOS attr +) */
+ uint32_t share_acc,
+ uint32_t open_disp, /* open disposition */
+ uint32_t createopt, /* NTCREATEX_OPTIONS_ */
+ uint32_t impersonate, /* NTCREATEX_IMPERSONATION_... */
+ struct smb_cred *scrp,
+ smb2fid_t *fidp, /* returned FID */
+ uint32_t *cr_act_p, /* optional create action */
+ struct smbfattr *fap) /* optional attributes */
+{
+ struct smbfattr fa;
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint16_t *name_offp;
+ uint16_t *name_lenp;
+ uint32_t *cctx_offp;
+ uint32_t *cctx_lenp;
+ uint32_t rcc_off, rcc_len;
+ smb2fid_t smb2_fid;
+ uint64_t llongint;
+ uint32_t longint, createact;
+ uint_t off, len;
+ int error;
+ uint16_t StructSize = 57; // [MS-SMB2]
+
+ bzero(&fa, sizeof (fa));
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_CREATE, scrp, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Todo: Assemble creat contexts (if needed)
+ * into an mbchain.
+ */
+
+ /*
+ * Build the SMB 2/3 Create Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, StructSize);
+ mb_put_uint8(mbp, 0); /* Security flags */
+ mb_put_uint8(mbp, SMB2_OPLOCK_LEVEL_NONE); /* Oplock level */
+ mb_put_uint32le(mbp, impersonate); /* Impersonation Level */
+ mb_put_uint64le(mbp, cr_flags);
+ mb_put_uint64le(mbp, 0); /* Reserved */
+ mb_put_uint32le(mbp, req_acc);
+ mb_put_uint32le(mbp, efa); /* File attributes */
+ mb_put_uint32le(mbp, share_acc); /* Share access */
+ mb_put_uint32le(mbp, open_disp); /* Create disposition */
+ mb_put_uint32le(mbp, createopt); /* Create options */
+
+ name_offp = mb_reserve(mbp, 2); /* Name offset */
+ name_lenp = mb_reserve(mbp, 2); /* Name len */
+
+ cctx_offp = mb_reserve(mbp, 4); /* Context offset */
+ cctx_lenp = mb_reserve(mbp, 4); /* Context len */
+
+ /*
+ * Put the file name, which is provided in an mbchain.
+ * If there's a leading slash, skip it (see above).
+ */
+ off = mbp->mb_count;
+ *name_offp = htoles((uint16_t)off);
+ error = put_name_skip_slash(mbp, name_mb);
+ if (error)
+ goto out;
+ len = mbp->mb_count - off;
+ *name_lenp = htoles((uint16_t)len);
+
+ /*
+ * Now the create contexts (if provided)
+ */
+ if (cctx_in != NULL) {
+ off = mbp->mb_count;
+ *cctx_offp = htolel((uint32_t)off);
+ mb_put_mbchain(mbp, cctx_in);
+ len = mbp->mb_count - off;
+ *cctx_lenp = htolel((uint32_t)len);
+ } else {
+ *cctx_offp = 0;
+ *cctx_lenp = 0;
+ }
+
+ /*
+ * If we didn't put any variable-sized data, we'll have
+ * put exactly 56 bytes of data, and we need to pad out
+ * this request to the 57 bytes StructSize indicated.
+ */
+ if (mbp->mb_count < (StructSize + SMB2_HDRLEN))
+ mb_put_uint8(mbp, 0);
+
+ /*
+ * Don't want to risk missing a successful
+ * open response, or we could "leak" FIDs.
+ */
+ rqp->sr_flags |= SMBR_NOINTR_RECV;
+ error = smb2_rq_simple_timed(rqp, smb2_timo_open);
+ if (error)
+ goto out;
+
+ /*
+ * Parse SMB 2/3 Create Response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 89 */
+ error = md_get_uint16le(mdp, &StructSize);
+ if (StructSize != 89) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ md_get_uint8(mdp, NULL); /* oplock lvl granted */
+ md_get_uint8(mdp, NULL); /* mbz */
+ md_get_uint32le(mdp, &createact); /* create_action */
+ md_get_uint64le(mdp, &llongint); /* creation time */
+ smb_time_NT2local(llongint, &fa.fa_createtime);
+ md_get_uint64le(mdp, &llongint); /* access time */
+ smb_time_NT2local(llongint, &fa.fa_atime);
+ md_get_uint64le(mdp, &llongint); /* write time */
+ smb_time_NT2local(llongint, &fa.fa_mtime);
+ md_get_uint64le(mdp, &llongint); /* change time */
+ smb_time_NT2local(llongint, &fa.fa_ctime);
+ md_get_uint64le(mdp, &llongint); /* allocation size */
+ fa.fa_allocsz = llongint;
+ md_get_uint64le(mdp, &llongint); /* EOF position */
+ fa.fa_size = llongint;
+ md_get_uint32le(mdp, &longint); /* attributes */
+ fa.fa_attr = longint;
+ md_get_uint32le(mdp, NULL); /* reserved */
+
+ /* Get SMB 2/3 File ID and create user fid to return */
+ md_get_uint64le(mdp, &smb2_fid.fid_persistent);
+ error = md_get_uint64le(mdp, &smb2_fid.fid_volatile);
+ if (error)
+ goto out;
+
+ /* Get Context Offset */
+ error = md_get_uint32le(mdp, &rcc_off);
+ if (error)
+ goto out;
+ /* Get Context Length */
+ error = md_get_uint32le(mdp, &rcc_len);
+ if (error)
+ goto out;
+
+ /*
+ * If the caller wants the returned create contexts, parse.
+ * Context offset is from the beginning of SMB 2/3 Header
+ * Calculate how much further we have to go to get to it.
+ * Current offset is: SMB2_HDRLEN + 88
+ */
+ if (rcc_len != 0) {
+ int skip = (int)rcc_off - (SMB2_HDRLEN + 88);
+ if (skip < 0) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+ if (cctx_out != NULL) {
+ mblk_t *m = NULL;
+ error = md_get_mbuf(mdp, rcc_len, &m);
+ if (error)
+ goto out;
+ md_initm(cctx_out, m);
+ }
+ }
+
+out:
+ smb_rq_done(rqp);
+ if (error)
+ return (error);
+
+ *fidp = smb2_fid;
+ if (cr_act_p)
+ *cr_act_p = createact;
+ if (fap)
+ *fap = fa; /* struct copy */
+
+ return (0);
+}
+
+int
+smb2_smb_close(struct smb_share *ssp, smb2fid_t *fid, struct smb_cred *scrp)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_CLOSE, scrp, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2/3 Close Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 24); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Flags */
+ mb_put_uint32le(mbp, 0); /* Reserved */
+
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ /* Make sure we send, but only if already connected */
+ rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
+ error = smb2_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+int
+smb2_smb_ioctl(
+ struct smb_share *ssp,
+ smb2fid_t *fid,
+ struct mbchain *data_in,
+ struct mdchain *data_out,
+ uint32_t *data_out_sz, /* max / returned */
+ uint32_t ctl_code,
+ struct smb_cred *scrp)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint32_t *data_in_offp;
+ uint32_t *data_in_lenp;
+ uint32_t data_out_off;
+ uint32_t data_out_len;
+ uint16_t length = 0;
+ uint_t off, len;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_IOCTL, scrp, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 IOCTL Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 57); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+ mb_put_uint32le(mbp, ctl_code);
+
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ data_in_offp = mb_reserve(mbp, 4);
+ data_in_lenp = mb_reserve(mbp, 4);
+ mb_put_uint32le(mbp, 0); /* Max input resp */
+
+ mb_put_uint32le(mbp, 0); /* Output offset */
+ mb_put_uint32le(mbp, 0); /* Output count */
+ mb_put_uint32le(mbp, *data_out_sz);
+
+ mb_put_uint32le(mbp, SMB2_IOCTL_IS_FSCTL); /* Flags */
+ mb_put_uint32le(mbp, 0); /* Reserved2 */
+
+ /*
+ * Now data_in (if provided)
+ */
+ if (data_in != NULL) {
+ off = mbp->mb_count;
+ *data_in_offp = htolel((uint32_t)off);
+ mb_put_mbchain(mbp, data_in);
+ len = mbp->mb_count - off;
+ *data_in_lenp = htolel((uint32_t)len);
+ } else {
+ *data_in_offp = 0;
+ *data_in_lenp = 0;
+ }
+
+ /*
+ * Run the request
+ */
+ error = smb2_rq_simple_timed(rqp, smb2_timo_default);
+ if (error)
+ goto out;
+
+ /*
+ * Parse SMB 2 Ioctl Response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 49 */
+ md_get_uint16le(mdp, &length);
+ if (length != 49) {
+ error = EBADRPC;
+ goto out;
+ }
+ md_get_uint16le(mdp, NULL); /* reserved */
+ md_get_uint32le(mdp, NULL); /* Get CtlCode */
+ md_get_uint64le(mdp, NULL); /* fid_persistent */
+ md_get_uint64le(mdp, NULL); /* fid_volatile */
+ md_get_uint32le(mdp, NULL); /* Get Input offset */
+ md_get_uint32le(mdp, NULL); /* Get Input count */
+
+ error = md_get_uint32le(mdp, &data_out_off);
+ if (error)
+ goto out;
+ error = md_get_uint32le(mdp, &data_out_len);
+ if (error)
+ goto out;
+
+ md_get_uint32le(mdp, NULL); /* Flags */
+ md_get_uint32le(mdp, NULL); /* reserved */
+
+ /*
+ * If the caller wants the ioctl output data, parse.
+ * Current offset is: SMB2_HDRLEN + 48
+ * Always return the received length.
+ */
+ *data_out_sz = data_out_len;
+ if (data_out_len != 0) {
+ int skip = (int)data_out_off - (SMB2_HDRLEN + 48);
+ if (skip < 0) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+ if (data_out != NULL) {
+ mblk_t *m = NULL;
+ error = md_get_mbuf(mdp, data_out_len, &m);
+ if (error)
+ goto out;
+ md_initm(data_out, m);
+ }
+ }
+
+out:
+ smb_rq_done(rqp);
+
+ return (error);
+}
+
+int
+smb2_smb_read(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo)
+{
+ struct smb_share *ssp = FHTOSS(fhp);
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ int error;
+ uint64_t off64 = uiop->uio_loffset;
+ uint32_t rlen;
+ uint16_t length = 0;
+ uint8_t data_offset;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_READ, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 Read Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 49); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Padding and Reserved */
+
+ mb_put_uint32le(mbp, *lenp); /* Length of read */
+ mb_put_uint64le(mbp, off64); /* Offset */
+
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
+
+ mb_put_uint32le(mbp, 1); /* MinCount */
+ /* (only indicates blocking) */
+
+ mb_put_uint32le(mbp, 0); /* Channel */
+ mb_put_uint32le(mbp, 0); /* Remaining */
+ mb_put_uint32le(mbp, 0); /* Channel offset/len */
+ mb_put_uint8(mbp, 0); /* data "blob" (pad) */
+
+ if (timo == 0)
+ timo = smb2_timo_read;
+ error = smb2_rq_simple_timed(rqp, timo);
+ if (error)
+ goto out;
+
+ /*
+ * Parse SMB 2 Read Response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 17 */
+ md_get_uint16le(mdp, &length);
+ if (length != 17) {
+ error = EBADRPC;
+ goto out;
+ }
+ md_get_uint8(mdp, &data_offset);
+ md_get_uint8(mdp, NULL); /* reserved */
+
+ /* Get Data Length read */
+ error = md_get_uint32le(mdp, &rlen);
+ if (error)
+ goto out;
+
+ md_get_uint32le(mdp, NULL); /* Data Remaining (always 0) */
+ md_get_uint32le(mdp, NULL); /* Get Reserved2 (always 0) */
+
+ /*
+ * Data offset is from the beginning of SMB 2/3 Header
+ * Calculate how much further we have to go to get to it.
+ */
+ if (data_offset < (SMB2_HDRLEN + 16)) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (data_offset > (SMB2_HDRLEN + 16)) {
+ int skip = data_offset - (SMB2_HDRLEN + 16);
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+
+ /*
+ * Get the data
+ */
+ if (rlen == 0) {
+ *lenp = rlen;
+ goto out;
+ }
+ /* paranoid */
+ if (rlen > *lenp) {
+ SMBSDEBUG("bad server! rlen %d, len %d\n",
+ rlen, *lenp);
+ rlen = *lenp;
+ }
+
+ error = md_get_uio(mdp, uiop, rlen);
+ if (error)
+ goto out;
+
+ /* Success */
+ *lenp = rlen;
+
+out:
+ smb_rq_done(rqp);
+ return (error);
+}
+
+int
+smb2_smb_write(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo)
+{
+ struct smb_share *ssp = FHTOSS(fhp);
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ int error;
+ uint64_t off64 = uiop->uio_loffset;
+ uint32_t rlen;
+ uint16_t data_offset;
+ uint16_t length = 0;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_WRITE, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 Write Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 49); /* Struct size */
+ data_offset = SMB2_HDRLEN + 48;
+ mb_put_uint16le(mbp, data_offset); /* Data Offset */
+ mb_put_uint32le(mbp, *lenp); /* Length of write */
+ mb_put_uint64le(mbp, off64); /* Offset */
+
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
+
+ mb_put_uint32le(mbp, 0); /* Channel */
+ mb_put_uint32le(mbp, 0); /* Remaining */
+ mb_put_uint32le(mbp, 0); /* Channel offset/len */
+ mb_put_uint32le(mbp, 0); /* Write flags */
+
+ error = mb_put_uio(mbp, uiop, *lenp);
+ if (error)
+ goto out;
+
+ if (timo == 0)
+ timo = smb2_timo_write;
+ error = smb2_rq_simple_timed(rqp, timo);
+ if (error)
+ goto out;
+
+ /*
+ * Parse SMB 2/3 Write Response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 17 */
+ md_get_uint16le(mdp, &length);
+ if (length != 17) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ md_get_uint16le(mdp, NULL); /* Get Reserved */
+
+ /* Get Data Length written */
+ error = md_get_uint32le(mdp, &rlen);
+ if (error)
+ goto out;
+
+ /* Get Data Remaining (always 0) */
+ md_get_uint32le(mdp, NULL);
+
+ /* Get Reserved2 (always 0) */
+ md_get_uint32le(mdp, NULL);
+
+ /* Success */
+ *lenp = rlen;
+
+out:
+ smb_rq_done(rqp);
+ return (error);
+}
+
+/*
+ * Note: the IOD calls this, so this request must not wait for
+ * connection state changes, etc. (uses smb2_rq_internal)
+ */
+int
+smb2_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_alloc(VCTOCP(vcp), SMB2_ECHO, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 Echo Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 4); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+
+ rqp->sr_flags |= SMBR_NORECONNECT;
+ error = smb2_rq_internal(rqp, timo);
+
+ smb_rq_done(rqp);
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
index 41405c314d..398be59709 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
@@ -63,6 +63,7 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_tran.h>
@@ -82,6 +83,9 @@ static void smb_vc_gone(struct smb_connobj *cp);
static void smb_share_free(struct smb_connobj *cp);
static void smb_share_gone(struct smb_connobj *cp);
+static void smb_fh_free(struct smb_connobj *cp);
+static void smb_fh_gone(struct smb_connobj *cp);
+
int
smb_sm_init(void)
{
@@ -183,6 +187,16 @@ smb_co_rele(struct smb_connobj *co)
int old_flags;
SMB_CO_LOCK(co);
+
+ /*
+ * When VC usecount goes from 2 to 1, signal the iod_idle CV.
+ * It's unfortunate to have object type-specific logic here,
+ * but it's hard to do this anywhere else.
+ */
+ if (co->co_level == SMBL_VC && co->co_usecount == 2) {
+ smb_vc_t *vcp = CPTOVC(co);
+ cv_signal(&vcp->iod_idle);
+ }
if (co->co_usecount > 1) {
co->co_usecount--;
SMB_CO_UNLOCK(co);
@@ -370,9 +384,9 @@ smb_vc_free(struct smb_connobj *cp)
if (vcp->vc_ssnkey != NULL)
kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen);
+ cv_destroy(&vcp->iod_muxwait);
cv_destroy(&vcp->iod_idle);
rw_destroy(&vcp->iod_rqlock);
- sema_destroy(&vcp->vc_sendlock);
cv_destroy(&vcp->vc_statechg);
smb_co_done(VCTOCP(vcp));
kmem_free(vcp, sizeof (*vcp));
@@ -396,9 +410,9 @@ smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
vcp->vc_co.co_gone = smb_vc_gone;
cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL);
- sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL);
rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL);
cv_init(&vcp->iod_idle, objtype, CV_DRIVER, NULL);
+ cv_init(&vcp->iod_muxwait, objtype, CV_DRIVER, NULL);
/* Expanded TAILQ_HEAD_INITIALIZER */
vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first;
@@ -617,10 +631,14 @@ smb_share_gone(struct smb_connobj *cp)
{
struct smb_cred scred;
struct smb_share *ssp = CPTOSS(cp);
+ smb_vc_t *vcp = SSTOVC(ssp);
smb_credinit(&scred, NULL);
smb_iod_shutdown_share(ssp);
- (void) smb_smb_treedisconnect(ssp, &scred);
+ if (vcp->vc_flags & SMBV_SMB2)
+ (void) smb2_smb_treedisconnect(ssp, &scred);
+ else
+ (void) smb_smb_treedisconnect(ssp, &scred);
smb_credrele(&scred);
}
@@ -660,6 +678,7 @@ smb_share_create(smbioc_tcon_t *tcon, struct smb_vc *vcp,
cv_init(&ssp->ss_conn_done, objtype, CV_DRIVER, NULL);
ssp->ss_tid = SMB_TID_UNKNOWN;
+ ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
bcopy(&tcon->tc_sh, &ssp->ss_ioc,
sizeof (smbioc_oshare_t));
@@ -775,6 +794,7 @@ smb_share_invalidate(struct smb_share *ssp)
int
smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred)
{
+ smb_vc_t *vcp = SSTOVC(ssp);
clock_t tmo;
int error;
@@ -818,7 +838,10 @@ smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred)
* and ss_flags |= SMBS_CONNECTED;
*/
SMB_SS_UNLOCK(ssp);
- error = smb_smb_treeconnect(ssp, scred);
+ if (vcp->vc_flags & SMBV_SMB2)
+ error = smb2_smb_treeconnect(ssp, scred);
+ else
+ error = smb_smb_treeconnect(ssp, scred);
SMB_SS_LOCK(ssp);
ssp->ss_flags &= ~SMBS_RECONNECTING;
@@ -834,6 +857,114 @@ out:
}
/*
+ * File handle level functions
+ */
+
+void
+smb_fh_hold(struct smb_fh *fhp)
+{
+ smb_co_hold(FHTOCP(fhp));
+}
+
+void
+smb_fh_rele(struct smb_fh *fhp)
+{
+ smb_co_rele(FHTOCP(fhp));
+}
+
+void
+smb_fh_close(struct smb_fh *fhp)
+{
+ smb_co_kill(FHTOCP(fhp));
+}
+
+/*
+ * Normally called via smb_fh_rele()
+ * after co_usecount drops to zero.
+ * Also called via: smb_fh_kill()
+ */
+static void
+smb_fh_gone(struct smb_connobj *cp)
+{
+ struct smb_cred scred;
+ struct smb_fh *fhp = CPTOFH(cp);
+ smb_share_t *ssp = FHTOSS(fhp);
+ int err;
+
+ if ((fhp->fh_flags & SMBFH_VALID) == 0)
+ return;
+
+ /*
+ * We have no durable handles (yet) so if there has been a
+ * reconnect, don't bother to close this handle.
+ */
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+ return;
+
+ smb_credinit(&scred, NULL);
+ err = smb_smb_close(ssp, fhp, &scred);
+ smb_credrele(&scred);
+ if (err) {
+ SMBSDEBUG("close err=%d\n", err);
+ }
+}
+
+/*
+ * Normally called via smb_fh_rele()
+ * after co_usecount drops to zero.
+ */
+static void
+smb_fh_free(struct smb_connobj *cp)
+{
+ struct smb_fh *fhp = CPTOFH(cp);
+
+ smb_co_done(FHTOCP(fhp));
+ kmem_free(fhp, sizeof (*fhp));
+}
+
+/*
+ * Allocate fh structure and attach it to the given share.
+ * Share expected to be locked on entry.
+ */
+/*ARGSUSED*/
+int
+smb_fh_create(smb_share_t *ssp, struct smb_fh **fhpp)
+{
+ static char objtype[] = "smb_fh";
+ struct smb_fh *fhp;
+
+ fhp = kmem_zalloc(sizeof (struct smb_fh), KM_SLEEP);
+ smb_co_init(FHTOCP(fhp), SMBL_FH, objtype);
+ fhp->fh_co.co_free = smb_fh_free;
+ fhp->fh_co.co_gone = smb_fh_gone;
+
+ SMB_SS_LOCK(ssp);
+ if ((ssp->ss_flags & SMBS_GONE) != 0) {
+ SMB_SS_UNLOCK(ssp);
+ smb_fh_free(FHTOCP(fhp));
+ return (ENOTCONN);
+ }
+
+ smb_co_addchild(SSTOCP(ssp), FHTOCP(fhp));
+ *fhpp = fhp;
+ SMB_SS_UNLOCK(ssp);
+
+ return (0);
+}
+
+void
+smb_fh_opened(struct smb_fh *fhp)
+{
+ smb_share_t *ssp = FHTOSS(fhp);
+
+ SMB_FH_LOCK(fhp);
+ fhp->fh_vcgenid = ssp->ss_vcgenid;
+ fhp->fh_flags |= SMBFH_VALID;
+ SMB_FH_UNLOCK(fhp);
+}
+
+
+/*
* Solaris zones support
*/
/*ARGSUSED*/
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
index 7b2b6a4690..d0a8a1dca0 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
@@ -36,6 +36,7 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
+ * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
* Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
@@ -47,6 +48,7 @@
#include <sys/queue.h> /* for SLIST below */
#include <sys/uio.h>
#include <netsmb/smb_dev.h>
+#include "smb_signing.h"
/*
* Credentials of user/process for processing in the connection procedures
@@ -66,7 +68,10 @@ typedef struct smb_cred {
*/
#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 */
+#define SMBV_SIGNING 0x0100 /* negotiated signing */
+#define SMBV_SMB2 0x0200 /* VC using SMB 2 or 3 */
+#define SMBV_HAS_FILEIDS 0x0400 /* Use File IDs for hash and inode numbers */
+#define SMBV_NO_WRITE_THRU 0x0800 /* Can't use ... */
/*
* Note: the common "obj" level uses this GONE flag by
@@ -87,6 +92,16 @@ typedef struct smb_cred {
*/
#define SMBS_GONE SMBO_GONE
+/*
+ * bits in smb_fh fh_flags (a.k.a. ss_co.co_flags)
+ */
+#define SMBFH_VALID 0x0002 /* FID is valid */
+/*
+ * Note: the common "obj" level uses this GONE flag by
+ * the name SMBO_GONE. Keep this alias as a reminder.
+ */
+#define SMBFH_GONE SMBO_GONE
+
struct smb_rq;
/* This declares struct smb_rqhead */
TAILQ_HEAD(smb_rqhead, smb_rq);
@@ -139,9 +154,12 @@ typedef struct smb_connobj smb_connobj_t;
/*
* "Level" in the connection object hierarchy
*/
-#define SMBL_SM 0
-#define SMBL_VC 1
-#define SMBL_SHARE 2
+enum smbco_level {
+ SMBL_SM = 0,
+ SMBL_VC = 1,
+ SMBL_SHARE = 2,
+ SMBL_FH = 3
+};
/*
* SMB1 Negotiated protocol parameters
@@ -157,6 +175,16 @@ struct smb_sopt {
uint32_t sv_maxraw; /* maximum raw-buffer size */
uint32_t sv_skey; /* session key */
uint32_t sv_caps; /* capabilites SMB_CAP_ */
+
+ /* SMB2+ fields */
+ uint32_t sv2_sessflags; /* final session setup reply flags */
+ uint16_t sv2_dialect; /* dialect (non zero for SMB 2/3 */
+ uint32_t sv2_capabilities; /* capabilities */
+ uint32_t sv2_maxtransact; /* max transact size */
+ uint32_t sv2_maxread; /* max read size */
+ uint32_t sv2_maxwrite; /* max write size */
+ uint8_t sv2_guid[16]; /* GUID */
+ uint16_t sv2_security_mode; /* security mode */
};
typedef struct smb_sopt smb_sopt_t;
@@ -197,18 +225,28 @@ typedef struct smb_vc {
int vc_ssnkeylen; /* session key length */
uint8_t *vc_mackey; /* MAC key buffer */
uint8_t *vc_ssnkey; /* session key buffer */
+ smb_sign_mech_t vc_signmech;
- ksema_t vc_sendlock;
struct smb_tran_desc *vc_tdesc; /* transport ops. vector */
void *vc_tdata; /* transport control block */
+ /* SMB2+ fields */
+ uint64_t vc2_oldest_message_id;
+ uint64_t vc2_next_message_id;
+ uint64_t vc2_limit_message_id;
+ uint64_t vc2_session_id; /* session id */
+ uint64_t vc2_prev_session_id; /* for reconnect */
+ uint32_t vc2_lease_key; /* lease key gen */
+
kcondvar_t iod_idle; /* IOD thread idle CV */
krwlock_t iod_rqlock; /* iod_rqlist */
- struct smb_rqhead iod_rqlist; /* list of outstanding reqs */
+ struct smb_rqhead iod_rqlist; /* list of active reqs */
struct _kthread *iod_thr; /* the IOD (reader) thread */
int iod_flags; /* see SMBIOD_* below */
- int iod_newrq; /* send needed (iod_rqlock) */
- int iod_muxfull; /* maxmux limit reached */
+ uint_t iod_muxcnt; /* num. active requests */
+ uint_t iod_muxwant; /* waiting to be active */
+ kcondvar_t iod_muxwait;
+ boolean_t iod_noresp; /* Logged "not responding" */
smb_iods_t vc_iods;
smb_sopt_t vc_sopt;
@@ -225,13 +263,16 @@ typedef struct smb_vc {
/* defines for members in vc_ssn */
#define vc_owner vc_ssn.ssn_owner
+#define vc_vopt vc_ssn.ssn_vopt
+#define vc_minver vc_ssn.ssn_minver
+#define vc_maxver vc_ssn.ssn_maxver
#define vc_srvname vc_ssn.ssn_srvname
#define vc_srvaddr vc_ssn.ssn_id.id_srvaddr
#define vc_domain vc_ssn.ssn_id.id_domain
#define vc_username vc_ssn.ssn_id.id_user
-#define vc_vopt vc_ssn.ssn_vopt
/* defines for members in vc_work */
+#define vc_cl_guid vc_work.wk_cl_guid
/* defines for members in vc_sopt ? */
#define vc_maxmux vc_sopt.sv_maxmux
@@ -250,7 +291,12 @@ typedef struct smb_vc {
#define SMB_VC_LOCK(vcp) mutex_enter(&(vcp)->vc_lock)
#define SMB_VC_UNLOCK(vcp) mutex_exit(&(vcp)->vc_lock)
-#define SMB_UNICODE_STRINGS(vcp) ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE)
+#define CPTOVC(cp) ((struct smb_vc *)((void *)(cp)))
+#define VCTOCP(vcp) (&(vcp)->vc_co)
+
+#define SMB_UNICODE_STRINGS(vcp) \
+ (((vcp)->vc_flags & SMBV_SMB2) != 0 || \
+ ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) != 0)
/* Bits in iod_flags */
#define SMBIOD_RUNNING 0x0001
@@ -268,6 +314,9 @@ typedef struct smb_share {
int ss_vcgenid; /* check VC generation ID */
uint16_t ss_tid; /* TID */
uint16_t ss_options; /* option support bits */
+ uint32_t ss2_tree_id;
+ uint32_t ss2_share_flags;
+ uint32_t ss2_share_caps;
smbioc_oshare_t ss_ioc;
} smb_share_t;
@@ -282,27 +331,47 @@ typedef struct smb_share {
#define SMB_SS_LOCK(ssp) mutex_enter(&(ssp)->ss_lock)
#define SMB_SS_UNLOCK(ssp) mutex_exit(&(ssp)->ss_lock)
-#define CPTOVC(cp) ((struct smb_vc *)((void *)(cp)))
-#define VCTOCP(vcp) (&(vcp)->vc_co)
-
#define CPTOSS(cp) ((struct smb_share *)((void *)(cp)))
-#define SSTOVC(ssp) CPTOVC(((ssp)->ss_co.co_parent))
#define SSTOCP(ssp) (&(ssp)->ss_co)
+#define SSTOVC(ssp) CPTOVC(((ssp)->ss_co.co_parent))
+
+typedef struct smb2fid {
+ uint64_t fid_persistent;
+ uint64_t fid_volatile;
+} smb2fid_t;
+
+/*
+ * smb_fh struct describes an open file handle under some share.
+ */
+typedef struct smb_fh {
+ struct smb_connobj fh_co; /* keep first! See CPTOSS */
+ int fh_vcgenid; /* check VC generation ID */
+ uint32_t fh_rights; /* granted access */
+ smb2fid_t fh_fid2;
+ uint16_t fh_fid1;
+} smb_fh_t;
+
+#define fh_lock fh_co.co_lock
+#define fh_flags fh_co.co_flags
+
+#define SMB_FH_LOCK(fhp) mutex_enter(&(fhp)->fh_lock)
+#define SMB_FH_UNLOCK(fhp) mutex_exit(&(fhp)->fh_lock)
+
+#define CPTOFH(cp) ((struct smb_fh *)((void *)(cp)))
+#define FHTOCP(fhp) (&(fhp)->fh_co)
+#define FHTOSS(fhp) CPTOSS(((fhp)->fh_co.co_parent))
/*
* Call-back operations vector, so the netsmb module
* can notify smbfs about events affecting mounts.
* Installed in netsmb after smbfs loads.
+ * Note: smbfs only uses the fscb_discon hook.
*/
typedef struct smb_fscb {
/* Called when the VC has disconnected. */
void (*fscb_disconn)(smb_share_t *);
/* Called when the VC has reconnected. */
void (*fscb_connect)(smb_share_t *);
- /* Called when the server becomes unresponsive. */
- void (*fscb_down)(smb_share_t *);
- /* Called when the server is responding again. */
- void (*fscb_up)(smb_share_t *);
} smb_fscb_t;
/* Install the above vector, or pass NULL to clear it. */
void smb_fscb_set(smb_fscb_t *);
@@ -315,14 +384,14 @@ typedef struct smb_dev {
kmutex_t sd_lock;
struct smb_vc *sd_vc; /* Reference to VC */
struct smb_share *sd_share; /* Reference to share if any */
+ struct smb_fh *sd_fh; /* Reference to FH, if any */
int sd_level; /* SMBL_VC, ... */
int sd_vcgenid; /* Generation of share or VC */
int sd_poll; /* Future use */
int sd_flags; /* State of connection */
-#define NSMBFL_OPEN 0x0001
-#define NSMBFL_IOD 0x0002
-#define NSMBFL_IOCTL 0x0004
- int sd_smbfid; /* library read/write */
+#define NSMBFL_OPEN 0x0001 /* Device minor is open */
+#define NSMBFL_IOD 0x0004 /* Open by IOD */
+#define NSMBFL_IOCTL 0x0010 /* Serialize ioctl calls */
zoneid_t zoneid; /* Zone id */
} smb_dev_t;
@@ -370,9 +439,11 @@ int smb_pkey_ioctl(int, intptr_t, int, cred_t *);
int smb_iod_create(smb_vc_t *vcp);
int smb_iod_destroy(smb_vc_t *vcp);
void smb_iod_disconnect(smb_vc_t *vcp);
-int smb_iod_addrq(struct smb_rq *rqp);
-int smb_iod_multirq(struct smb_rq *rqp);
+int smb2_iod_addrq(struct smb_rq *rqp);
+int smb1_iod_addrq(struct smb_rq *rqp);
+int smb1_iod_multirq(struct smb_rq *rqp);
int smb_iod_waitrq(struct smb_rq *rqp);
+int smb_iod_waitrq_int(struct smb_rq *rqp);
void smb_iod_removerq(struct smb_rq *rqp);
int smb_iod_sendrecv(struct smb_rq *, int);
void smb_iod_shutdown_share(smb_share_t *ssp);
@@ -380,7 +451,7 @@ void smb_iod_shutdown_share(smb_share_t *ssp);
void smb_iod_sendall(smb_vc_t *);
int smb_iod_recvall(smb_vc_t *, boolean_t);
-int nsmb_iod_connect(smb_vc_t *vcp);
+int nsmb_iod_connect(smb_vc_t *vcp, cred_t *cr);
int nsmb_iod_negotiate(smb_vc_t *vcp, cred_t *cr);
int nsmb_iod_ssnsetup(smb_vc_t *vcp, cred_t *cr);
int smb_iod_vc_work(smb_vc_t *, int, cred_t *);
@@ -426,4 +497,13 @@ void smb_share_kill(smb_share_t *ssp);
void smb_share_invalidate(smb_share_t *ssp);
int smb_share_tcon(smb_share_t *, smb_cred_t *);
+/*
+ * File handle level functions
+ */
+int smb_fh_create(smb_share_t *ssp, struct smb_fh **fhpp);
+void smb_fh_opened(struct smb_fh *fhp);
+void smb_fh_close(struct smb_fh *fhp);
+void smb_fh_hold(struct smb_fh *fhp);
+void smb_fh_rele(struct smb_fh *fhp);
+
#endif /* _SMB_CONN_H */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
index b2788bb194..3f00ec24ed 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
@@ -69,6 +69,7 @@
#include <netsmb/mchain.h> /* for "htoles()" */
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_dev.h>
@@ -196,12 +197,6 @@ _init(void)
/* Initialize password Key chain DB. */
smb_pkey_init();
- /* Time conversion stuff. */
- smb_time_init();
-
- /* Initialize crypto mechanisms. */
- smb_crypto_mech_init();
-
#ifdef _KERNEL
zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown,
nsmb_zone_destroy);
@@ -259,9 +254,6 @@ _fini(void)
(void) zone_key_delete(nsmb_zone_key);
#endif /* _KERNEL */
- /* Time conversion stuff. */
- smb_time_fini();
-
/* Destroy password Key chain DB. */
smb_pkey_fini();
@@ -498,7 +490,6 @@ found:
*dev = makedevice(nsmb_major, m);
mutex_exit(&dev_lck);
- sdp->sd_smbfid = -1;
sdp->sd_flags |= NSMBFL_OPEN;
sdp->zoneid = crgetzoneid(cr);
mutex_init(&sdp->sd_lock, NULL, MUTEX_DRIVER, NULL);
@@ -536,14 +527,17 @@ nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
return (err);
}
+/*ARGSUSED*/
static int
nsmb_close2(smb_dev_t *sdp, cred_t *cr)
{
struct smb_vc *vcp;
struct smb_share *ssp;
+ struct smb_fh *fhp;
- if (sdp->sd_smbfid != -1)
- (void) smb_usr_closefh(sdp, cr);
+ fhp = sdp->sd_fh;
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
ssp = sdp->sd_share;
if (ssp != NULL)
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
index 4c547df25b..48c8ef591d 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
@@ -36,6 +36,7 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
+ * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
* Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
@@ -69,25 +70,26 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_tran.h>
#include <netsmb/smb_trantcp.h>
/*
- * SMB messages are up to 64K.
- * Let's leave room for two.
+ * SMB messages are up to 64K. Let's leave room for two.
+ * If we negotiate up to SMB2, increase these. XXX todo
*/
static int smb_tcpsndbuf = 0x20000;
static int smb_tcprcvbuf = 0x20000;
static int smb_connect_timeout = 10; /* seconds */
-int smb_iod_send_echo(smb_vc_t *);
-
-#ifdef _FAKE_KERNEL
-extern void tsignal(kthread_t *, int);
-#endif
+static int smb1_iod_process(smb_vc_t *, mblk_t *);
+static int smb2_iod_process(smb_vc_t *, mblk_t *);
+static int smb_iod_send_echo(smb_vc_t *, cred_t *cr);
+static int smb_iod_logoff(struct smb_vc *vcp, cred_t *cr);
/*
* This is set/cleared when smbfs loads/unloads
@@ -107,7 +109,10 @@ smb_iod_share_disconnected(smb_share_t *ssp)
smb_share_invalidate(ssp);
- /* smbfs_dead() */
+ /*
+ * This is the only fscb hook smbfs currently uses.
+ * Replaces smbfs_dead() from Darwin.
+ */
if (fscb && fscb->fscb_disconn) {
fscb->fscb_disconn(ssp);
}
@@ -156,19 +161,22 @@ smb_iod_invrq(struct smb_vc *vcp)
/*
* Invalidate all outstanding requests for this connection
+ * Also wakeup iod_muxwant waiters.
*/
rw_enter(&vcp->iod_rqlock, RW_READER);
TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
smb_iod_rqprocessed(rqp, ENOTCONN, SMBR_RESTART);
}
rw_exit(&vcp->iod_rqlock);
+ cv_broadcast(&vcp->iod_muxwait);
}
/*
- * Called by smb_vc_rele, smb_vc_kill, and by the driver
- * close entry point if the IOD closes its dev handle.
+ * Called by smb_vc_rele/smb_vc_kill on last ref, and by
+ * the driver close function if the IOD closes its minor.
+ * In those cases, the caller should be the IOD thread.
*
- * Forcibly kill the connection and IOD.
+ * Forcibly kill the connection.
*/
void
smb_iod_disconnect(struct smb_vc *vcp)
@@ -184,31 +192,29 @@ smb_iod_disconnect(struct smb_vc *vcp)
}
SMB_VC_UNLOCK(vcp);
- /*
- * Let's be safe here and avoid doing any
- * call across the network while trying to
- * shut things down. If we just disconnect,
- * the server will take care of the logoff.
- */
SMB_TRAN_DISCONNECT(vcp);
}
/*
* Send one request.
*
+ * SMB1 only
+ *
* Called by _addrq (for internal requests)
* and _sendall (via _addrq, _multirq, _waitrq)
+ * Errors are reported via the smb_rq, using:
+ * smb_iod_rqprocessed(rqp, ...)
*/
-static int
-smb_iod_sendrq(struct smb_rq *rqp)
+static void
+smb1_iod_sendrq(struct smb_rq *rqp)
{
struct smb_vc *vcp = rqp->sr_vc;
mblk_t *m;
int error;
ASSERT(vcp);
- ASSERT(SEMA_HELD(&vcp->vc_sendlock));
- ASSERT(RW_READ_HELD(&vcp->iod_rqlock));
+ ASSERT(RW_WRITE_HELD(&vcp->iod_rqlock));
+ ASSERT((vcp->vc_flags & SMBV_SMB2) == 0);
/*
* Internal requests are allowed in any state;
@@ -217,101 +223,178 @@ smb_iod_sendrq(struct smb_rq *rqp)
if ((rqp->sr_flags & SMBR_INTERNAL) == 0 &&
vcp->vc_state != SMBIOD_ST_VCACTIVE) {
SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
- return (ENOTCONN);
+ smb_iod_rqprocessed(rqp, ENOTCONN, SMBR_RESTART);
+ return;
}
/*
- * On the first send, set the MID and (maybe)
- * the signing sequence numbers. The increments
- * here are serialized by vc_sendlock
+ * Overwrite the SMB header with the assigned MID and
+ * (if we're signing) sign it.
*/
- if (rqp->sr_sendcnt == 0) {
+ smb_rq_fillhdr(rqp);
+ if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
+ smb_rq_sign(rqp);
+ }
- rqp->sr_mid = vcp->vc_next_mid++;
+ /*
+ * The transport send consumes the message and we'd
+ * prefer to keep a copy, so dupmsg() before sending.
+ */
+ m = dupmsg(rqp->sr_rq.mb_top);
+ if (m == NULL) {
+ error = ENOBUFS;
+ goto fatal;
+ }
- if (vcp->vc_mackey != NULL && (rqp->sr_rqflags2 &
- SMB_FLAGS2_SECURITY_SIGNATURE) != 0) {
- /*
- * We're signing requests and verifying
- * signatures on responses. Set the
- * sequence numbers of the request and
- * response here, used in smb_rq_verify.
- * Note we have the signing flag during
- * session setup but no key yet, and
- * don't want sequence numbers there.
- */
- rqp->sr_seqno = vcp->vc_next_seq++;
- rqp->sr_rseqno = vcp->vc_next_seq++;
- }
+#ifdef DTRACE_PROBE2
+ DTRACE_PROBE2(iod_sendrq,
+ (smb_rq_t *), rqp, (mblk_t *), m);
+#endif
- /* Fill in UID, TID, MID, etc. */
- smb_rq_fillhdr(rqp);
+ error = SMB_TRAN_SEND(vcp, m);
+ m = 0; /* consumed by SEND */
- /*
- * Sign the message now that we're finally done
- * filling in the SMB header fields, etc.
- */
- if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- smb_rq_sign(rqp);
- }
+ rqp->sr_lerror = error;
+ if (error == 0) {
+ SMBRQ_LOCK(rqp);
+ rqp->sr_flags |= SMBR_SENT;
+ rqp->sr_state = SMBRQ_SENT;
+ SMBRQ_UNLOCK(rqp);
+ return;
}
- if (rqp->sr_sendcnt++ >= 60/SMBSBTIMO) { /* one minute */
- smb_iod_rqprocessed(rqp, rqp->sr_lerror, SMBR_RESTART);
+ /*
+ * Transport send returned an error.
+ * Was it a fatal one?
+ */
+ if (SMB_TRAN_FATAL(vcp, error)) {
/*
- * If all attempts to send a request failed, then
- * something is seriously hosed.
+ * No further attempts should be made
*/
- return (ENOTCONN);
+ fatal:
+ SMBSDEBUG("TRAN_SEND returned fatal error %d\n", error);
+ smb_iod_rqprocessed(rqp, error, SMBR_RESTART);
+ return;
}
+}
+
+/*
+ * Send one request.
+ *
+ * SMB2 only
+ *
+ * Called by _addrq (for internal requests)
+ * and _sendall (via _addrq, _multirq, _waitrq)
+ * Errors are reported via the smb_rq, using:
+ * smb_iod_rqprocessed(rqp, ...)
+ */
+static void
+smb2_iod_sendrq(struct smb_rq *rqp)
+{
+ struct smb_rq *c_rqp; /* compound */
+ struct smb_vc *vcp = rqp->sr_vc;
+ mblk_t *top_m;
+ mblk_t *cur_m;
+ int error;
+
+ ASSERT(vcp);
+ ASSERT(RW_WRITE_HELD(&vcp->iod_rqlock));
+ ASSERT((vcp->vc_flags & SMBV_SMB2) != 0);
/*
- * Replaced m_copym() with Solaris copymsg() which does the same
- * work when we want to do a M_COPYALL.
- * m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, 0);
+ * Internal requests are allowed in any state;
+ * otherwise should be active.
*/
- m = copymsg(rqp->sr_rq.mb_top);
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0 &&
+ vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+ smb_iod_rqprocessed(rqp, ENOTCONN, SMBR_RESTART);
+ return;
+ }
- DTRACE_PROBE2(smb_iod_sendrq,
- (smb_rq_t *), rqp, (mblk_t *), m);
- m_dumpm(m);
+ /*
+ * Overwrite the SMB header with the assigned MID and
+ * (if we're signing) sign it. If there are compounded
+ * requests after the top one, do those too.
+ */
+ smb2_rq_fillhdr(rqp);
+ if (rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) {
+ smb2_rq_sign(rqp);
+ }
+ c_rqp = rqp->sr2_compound_next;
+ while (c_rqp != NULL) {
+ smb2_rq_fillhdr(c_rqp);
+ if (c_rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) {
+ smb2_rq_sign(c_rqp);
+ }
+ c_rqp = c_rqp->sr2_compound_next;
+ }
- if (m != NULL) {
- error = SMB_TRAN_SEND(vcp, m);
- m = 0; /* consumed by SEND */
- } else
+ /*
+ * The transport send consumes the message and we'd
+ * prefer to keep a copy, so dupmsg() before sending.
+ * We also need this to build the compound message
+ * that we'll actually send. The message offset at
+ * the start of each compounded message should be
+ * eight-byte aligned. The caller preparing the
+ * compounded request has to take care of that
+ * before we get here and sign messages etc.
+ */
+ top_m = dupmsg(rqp->sr_rq.mb_top);
+ if (top_m == NULL) {
error = ENOBUFS;
+ goto fatal;
+ }
+ c_rqp = rqp->sr2_compound_next;
+ while (c_rqp != NULL) {
+ size_t len = msgdsize(top_m);
+ ASSERT((len & 7) == 0);
+ cur_m = dupmsg(c_rqp->sr_rq.mb_top);
+ if (cur_m == NULL) {
+ freemsg(top_m);
+ error = ENOBUFS;
+ goto fatal;
+ }
+ linkb(top_m, cur_m);
+ }
+
+ DTRACE_PROBE2(iod_sendrq,
+ (smb_rq_t *), rqp, (mblk_t *), top_m);
+
+ error = SMB_TRAN_SEND(vcp, top_m);
+ top_m = 0; /* consumed by SEND */
rqp->sr_lerror = error;
if (error == 0) {
SMBRQ_LOCK(rqp);
rqp->sr_flags |= SMBR_SENT;
rqp->sr_state = SMBRQ_SENT;
- if (rqp->sr_flags & SMBR_SENDWAIT)
- cv_broadcast(&rqp->sr_cond);
SMBRQ_UNLOCK(rqp);
- return (0);
+ return;
}
/*
- * Check for fatal errors
+ * Transport send returned an error.
+ * Was it a fatal one?
*/
if (SMB_TRAN_FATAL(vcp, error)) {
/*
* No further attempts should be made
*/
+ fatal:
SMBSDEBUG("TRAN_SEND returned fatal error %d\n", error);
- return (ENOTCONN);
+ smb_iod_rqprocessed(rqp, error, SMBR_RESTART);
+ return;
}
- if (error)
- SMBSDEBUG("TRAN_SEND returned non-fatal error %d\n", error);
-
- return (0);
}
+/*
+ * Receive one NetBIOS (or NBT over TCP) message. If none have arrived,
+ * wait up to SMB_NBTIMO (15 sec.) for one to arrive, and then if still
+ * none have arrived, return ETIME.
+ */
static int
-smb_iod_recv1(struct smb_vc *vcp, mblk_t **mpp)
+smb_iod_recvmsg(struct smb_vc *vcp, mblk_t **mpp)
{
mblk_t *m;
- uchar_t *hp;
int error;
top:
@@ -321,27 +404,29 @@ top:
goto top;
if (error)
return (error);
- ASSERT(m);
+ ASSERT(m != NULL);
- m = m_pullup(m, SMB_HDRLEN);
+ m = m_pullup(m, 4);
if (m == NULL) {
return (ENOSR);
}
- /*
- * Check the SMB header
- */
- hp = mtod(m, uchar_t *);
- if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) {
- m_freem(m);
- return (EPROTO);
- }
-
*mpp = m;
return (0);
}
/*
+ * How long should we keep around an unused VC (connection)?
+ * There's usually a good chance connections will be reused,
+ * so the default is to keep such connections for 5 min.
+ */
+#ifdef DEBUG
+int smb_iod_idle_keep_time = 60; /* seconds */
+#else
+int smb_iod_idle_keep_time = 300; /* seconds */
+#endif
+
+/*
* Process incoming packets
*
* This is the "reader" loop, run by the IOD thread. Normally we're in
@@ -353,19 +438,16 @@ top:
int
smb_iod_recvall(struct smb_vc *vcp, boolean_t poll)
{
- struct smb_rq *rqp;
mblk_t *m;
- uchar_t *hp;
- ushort_t mid;
int error = 0;
- int etime_count = 0; /* for "server not responding", etc. */
+ int etime_idle = 0; /* How many 15 sec. "ticks" idle. */
+ int etime_count = 0; /* ... and when we have requests. */
for (;;) {
/*
* Check whether someone "killed" this VC,
* or is asking the IOD to terminate.
*/
-
if (vcp->iod_flags & SMBIOD_SHUTDOWN) {
SMBIODEBUG("SHUTDOWN set\n");
/* This IOD thread will terminate. */
@@ -378,7 +460,7 @@ smb_iod_recvall(struct smb_vc *vcp, boolean_t poll)
}
m = NULL;
- error = smb_iod_recv1(vcp, &m);
+ error = smb_iod_recvmsg(vcp, &m);
/*
* Internal requests (reconnecting) call this in a loop
@@ -389,49 +471,77 @@ smb_iod_recvall(struct smb_vc *vcp, boolean_t poll)
if (error == ETIME &&
vcp->iod_rqlist.tqh_first != NULL) {
+
/*
- * Nothing received for 15 seconds and
- * we have requests in the queue.
+ * Nothing received and requests waiting.
+ * Increment etime_count. If we were idle,
+ * skip the 1st tick, because we started
+ * waiting before there were any requests.
*/
- etime_count++;
+ if (etime_idle != 0) {
+ etime_idle = 0;
+ } else if (etime_count < INT16_MAX) {
+ etime_count++;
+ }
/*
- * Once, at 15 sec. notify callbacks
- * and print the warning message.
+ * ETIME and requests in the queue.
+ * The first time (at 15 sec.)
+ * Log an error (just once).
*/
- if (etime_count == 1) {
- /* Was: smb_iod_notify_down(vcp); */
- if (fscb && fscb->fscb_down)
- smb_vc_walkshares(vcp,
- fscb->fscb_down);
+ if (etime_count > 0 &&
+ vcp->iod_noresp == B_FALSE) {
+ vcp->iod_noresp = B_TRUE;
zprintf(vcp->vc_zoneid,
"SMB server %s not responding\n",
vcp->vc_srvname);
}
-
/*
- * At 30 sec. try sending an echo, and then
- * once a minute thereafter.
+ * At 30 sec. try sending an echo, which
+ * should cause some response.
*/
- if ((etime_count & 3) == 2) {
- (void) smb_iod_send_echo(vcp);
+ if (etime_count == 2) {
+ SMBIODEBUG("send echo\n");
+ (void) smb_iod_send_echo(vcp, CRED());
+ }
+ /*
+ * At 45 sec. give up on the connection
+ * and try to reconnect.
+ */
+ if (etime_count == 3) {
+ SMB_VC_LOCK(vcp);
+ smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT);
+ SMB_VC_UNLOCK(vcp);
+ SMB_TRAN_DISCONNECT(vcp);
+ break;
}
-
continue;
- } /* ETIME && requests in queue */
+ } /* ETIME and requests in the queue */
- if (error == ETIME) { /* and req list empty */
+ if (error == ETIME) {
/*
- * If the IOD thread holds the last reference
- * to this VC, let it become IDLE, and then
- * let it be destroyed if not used.
+ * Nothing received and no active requests.
+ *
+ * If we've received nothing from the server for
+ * smb_iod_idle_keep_time seconds, and the IOD
+ * thread holds the last reference to this VC,
+ * move to state IDLE and drop the TCP session.
+ * The IDLE handler will destroy the VC unless
+ * vc_state goes to RECONNECT before then.
*/
- if (vcp->vc_co.co_usecount > 1)
+ etime_count = 0;
+ if (etime_idle < INT16_MAX)
+ etime_idle++;
+ if ((etime_idle * SMB_NBTIMO) <
+ smb_iod_idle_keep_time)
continue;
SMB_VC_LOCK(vcp);
if (vcp->vc_co.co_usecount == 1) {
smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
SMB_VC_UNLOCK(vcp);
+ SMBIODEBUG("logoff & disconnect\n");
+ (void) smb_iod_logoff(vcp, CRED());
+ SMB_TRAN_DISCONNECT(vcp);
error = 0;
break;
}
@@ -441,97 +551,327 @@ smb_iod_recvall(struct smb_vc *vcp, boolean_t poll)
if (error) {
/*
- * The recv. above returned some error
- * we can't continue from i.e. ENOTCONN.
- * It's dangerous to continue here.
- * (possible infinite loop!)
- *
- * If this VC has shares, try reconnect;
- * otherwise let this VC die now.
+ * The recv above returned an error indicating
+ * that our TCP session is no longer usable.
+ * Disconnect the session and get ready to
+ * reconnect. If we have pending requests,
+ * move to state reconnect immediately;
+ * otherwise move to state IDLE until a
+ * request is issued on this VC.
*/
SMB_VC_LOCK(vcp);
- if (vcp->vc_co.co_usecount > 1)
+ if (vcp->iod_rqlist.tqh_first != NULL)
smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT);
else
- smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
+ smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
cv_broadcast(&vcp->vc_statechg);
SMB_VC_UNLOCK(vcp);
+ SMB_TRAN_DISCONNECT(vcp);
break;
}
/*
* Received something. Yea!
*/
- if (etime_count) {
- etime_count = 0;
+ etime_count = 0;
+ etime_idle = 0;
+ /*
+ * If we just completed a reconnect after logging
+ * "SMB server %s not responding" then log OK now.
+ */
+ if (vcp->iod_noresp) {
+ vcp->iod_noresp = B_FALSE;
zprintf(vcp->vc_zoneid, "SMB server %s OK\n",
vcp->vc_srvname);
+ }
- /* Was: smb_iod_notify_up(vcp); */
- if (fscb && fscb->fscb_up)
- smb_vc_walkshares(vcp, fscb->fscb_up);
+ if ((vcp->vc_flags & SMBV_SMB2) != 0) {
+ error = smb2_iod_process(vcp, m);
+ } else {
+ error = smb1_iod_process(vcp, m);
}
/*
- * Have an SMB packet. The SMB header was
- * checked in smb_iod_recv1().
- * Find the request...
+ * Reconnect calls this in a loop with poll=TRUE
+ * We've received a response, so break now.
*/
- hp = mtod(m, uchar_t *);
- /*LINTED*/
- mid = letohs(SMB_HDRMID(hp));
- SMBIODEBUG("mid %04x\n", (uint_t)mid);
+ if (poll) {
+ error = 0;
+ break;
+ }
+ }
- rw_enter(&vcp->iod_rqlock, RW_READER);
- TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+ return (error);
+}
- if (rqp->sr_mid != mid)
- continue;
+/*
+ * Have what should be an SMB1 reply. Check and parse the header,
+ * then use the message ID to find the request this belongs to and
+ * post it on that request.
+ *
+ * Returns an error if the reader should give up.
+ * To be safe, error if we read garbage.
+ */
+static int
+smb1_iod_process(smb_vc_t *vcp, mblk_t *m)
+{
+ struct mdchain md;
+ struct smb_rq *rqp;
+ uint8_t cmd, sig[4];
+ uint16_t mid;
+ int err, skip;
- DTRACE_PROBE2(smb_iod_recvrq,
- (smb_rq_t *), rqp, (mblk_t *), m);
- m_dumpm(m);
+ m = m_pullup(m, SMB_HDRLEN);
+ if (m == NULL)
+ return (ENOMEM);
- SMBRQ_LOCK(rqp);
- if (rqp->sr_rp.md_top == NULL) {
- md_initm(&rqp->sr_rp, m);
- } else {
- if (rqp->sr_flags & SMBR_MULTIPACKET) {
- md_append_record(&rqp->sr_rp, m);
- } else {
- SMBRQ_UNLOCK(rqp);
- SMBSDEBUG("duplicate response %d "
- "(ignored)\n", mid);
- break;
- }
- }
- smb_iod_rqprocessed_LH(rqp, 0, 0);
- SMBRQ_UNLOCK(rqp);
+ /*
+ * Note: Intentionally do NOT md_done(&md)
+ * because that would free the message and
+ * we just want to peek here.
+ */
+ md_initm(&md, m);
+
+ /*
+ * Check the SMB header version and get the MID.
+ *
+ * The header version should be SMB1 except when we're
+ * doing SMB1-to-SMB2 negotiation, in which case we may
+ * see an SMB2 header with message ID=0 (only allowed in
+ * vc_state == SMBIOD_ST_CONNECTED -- negotiationg).
+ */
+ err = md_get_mem(&md, sig, 4, MB_MSYSTEM);
+ if (err)
+ return (err);
+ if (sig[1] != 'S' || sig[2] != 'M' || sig[3] != 'B') {
+ goto bad_hdr;
+ }
+ switch (sig[0]) {
+ case SMB_HDR_V1: /* SMB1 */
+ md_get_uint8(&md, &cmd);
+ /* Skip to and get the MID. At offset 5 now. */
+ skip = SMB_HDR_OFF_MID - 5;
+ md_get_mem(&md, NULL, skip, MB_MSYSTEM);
+ err = md_get_uint16le(&md, &mid);
+ if (err)
+ return (err);
+ break;
+ case SMB_HDR_V2: /* SMB2+ */
+ if (vcp->vc_state == SMBIOD_ST_CONNECTED) {
+ /*
+ * No need to look, can only be
+ * MID=0, cmd=negotiate
+ */
+ cmd = SMB_COM_NEGOTIATE;
+ mid = 0;
break;
}
+ /* FALLTHROUGH */
+ bad_hdr:
+ default:
+ SMBIODEBUG("Bad SMB hdr\n");
+ m_freem(m);
+ return (EPROTO);
+ }
- if (rqp == NULL) {
- int cmd = SMB_HDRCMD(hp);
+ /*
+ * Find the reqeuest and post the reply
+ */
+ rw_enter(&vcp->iod_rqlock, RW_READER);
+ TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
- if (cmd != SMB_COM_ECHO)
- SMBSDEBUG("drop resp: mid %d, cmd %d\n",
- (uint_t)mid, cmd);
- m_freem(m);
+ if (rqp->sr_mid != mid)
+ continue;
+
+ DTRACE_PROBE2(iod_post_reply,
+ (smb_rq_t *), rqp, (mblk_t *), m);
+ m_dumpm(m);
+
+ SMBRQ_LOCK(rqp);
+ if (rqp->sr_rp.md_top == NULL) {
+ md_initm(&rqp->sr_rp, m);
+ } else {
+ if (rqp->sr_flags & SMBR_MULTIPACKET) {
+ md_append_record(&rqp->sr_rp, m);
+ } else {
+ SMBRQ_UNLOCK(rqp);
+ rqp = NULL;
+ break;
+ }
}
- rw_exit(&vcp->iod_rqlock);
+ smb_iod_rqprocessed_LH(rqp, 0, 0);
+ SMBRQ_UNLOCK(rqp);
+ break;
+ }
+ rw_exit(&vcp->iod_rqlock);
+ if (rqp == NULL) {
+ if (cmd != SMB_COM_ECHO) {
+ SMBSDEBUG("drop resp: MID 0x%04x\n", (uint_t)mid);
+ }
+ m_freem(m);
/*
- * Reconnect calls this in a loop with poll=TRUE
- * We've received a response, so break now.
+ * Keep going. It's possible this reply came
+ * after the request timed out and went away.
*/
- if (poll) {
- error = 0;
+ }
+ return (0);
+}
+
+/*
+ * Have what should be an SMB2 reply. Check and parse the header,
+ * then use the message ID to find the request this belongs to and
+ * post it on that request.
+ *
+ * We also want to apply any credit grant in this reply now,
+ * rather than waiting for the owner to wake up.
+ */
+static int
+smb2_iod_process(smb_vc_t *vcp, mblk_t *m)
+{
+ struct mdchain md;
+ struct smb_rq *rqp;
+ uint8_t sig[4];
+ mblk_t *next_m = NULL;
+ uint64_t message_id, async_id;
+ uint32_t flags, next_cmd_off, status;
+ uint16_t command, credits_granted;
+ int err;
+
+top:
+ m = m_pullup(m, SMB2_HDRLEN);
+ if (m == NULL)
+ return (ENOMEM);
+
+ /*
+ * Note: Intentionally do NOT md_done(&md)
+ * because that would free the message and
+ * we just want to peek here.
+ */
+ md_initm(&md, m);
+
+ /*
+ * Check the SMB header. Must be SMB2
+ * (and later, could be SMB3 encrypted)
+ */
+ err = md_get_mem(&md, sig, 4, MB_MSYSTEM);
+ if (err)
+ return (err);
+ if (sig[1] != 'S' || sig[2] != 'M' || sig[3] != 'B') {
+ goto bad_hdr;
+ }
+ switch (sig[0]) {
+ case SMB_HDR_V2:
+ break;
+ case SMB_HDR_V3E:
+ /*
+ * Todo: If encryption enabled, decrypt the message
+ * and restart processing on the cleartext.
+ */
+ /* FALLTHROUGH */
+ bad_hdr:
+ default:
+ SMBIODEBUG("Bad SMB2 hdr\n");
+ m_freem(m);
+ return (EPROTO);
+ }
+
+ /*
+ * Parse the rest of the SMB2 header,
+ * skipping what we don't need.
+ */
+ md_get_uint32le(&md, NULL); /* length, credit_charge */
+ md_get_uint32le(&md, &status);
+ md_get_uint16le(&md, &command);
+ md_get_uint16le(&md, &credits_granted);
+ md_get_uint32le(&md, &flags);
+ md_get_uint32le(&md, &next_cmd_off);
+ md_get_uint64le(&md, &message_id);
+ if (flags & SMB2_FLAGS_ASYNC_COMMAND) {
+ md_get_uint64le(&md, &async_id);
+ } else {
+ /* PID, TID (not needed) */
+ async_id = 0;
+ }
+
+ /*
+ * If this is a compound reply, split it.
+ * Next must be 8-byte aligned.
+ */
+ if (next_cmd_off != 0) {
+ if ((next_cmd_off & 7) != 0)
+ SMBIODEBUG("Misaligned next cmd\n");
+ else
+ next_m = m_split(m, next_cmd_off, 1);
+ }
+
+ /*
+ * Apply the credit grant
+ */
+ rw_enter(&vcp->iod_rqlock, RW_WRITER);
+ vcp->vc2_limit_message_id += credits_granted;
+
+ /*
+ * Find the reqeuest and post the reply
+ */
+ rw_downgrade(&vcp->iod_rqlock);
+ TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+
+ if (rqp->sr2_messageid != message_id)
+ continue;
+
+ DTRACE_PROBE2(iod_post_reply,
+ (smb_rq_t *), rqp, (mblk_t *), m);
+ m_dumpm(m);
+
+ /*
+ * If this is an interim response, just save the
+ * async ID but don't wakup the request.
+ * Don't need SMBRQ_LOCK for this.
+ */
+ if (status == NT_STATUS_PENDING && async_id != 0) {
+ rqp->sr2_rspasyncid = async_id;
+ m_freem(m);
+ break;
+ }
+
+ SMBRQ_LOCK(rqp);
+ if (rqp->sr_rp.md_top == NULL) {
+ md_initm(&rqp->sr_rp, m);
+ } else {
+ SMBRQ_UNLOCK(rqp);
+ rqp = NULL;
break;
}
+ smb_iod_rqprocessed_LH(rqp, 0, 0);
+ SMBRQ_UNLOCK(rqp);
+ break;
}
+ rw_exit(&vcp->iod_rqlock);
- return (error);
+ if (rqp == NULL) {
+ if (command != SMB2_ECHO) {
+ SMBSDEBUG("drop resp: MID %lld\n",
+ (long long)message_id);
+ }
+ m_freem(m);
+ /*
+ * Keep going. It's possible this reply came
+ * after the request timed out and went away.
+ */
+ }
+
+ /*
+ * If we split a compound reply, continue with the
+ * next part of the compound.
+ */
+ if (next_m != NULL) {
+ m = next_m;
+ goto top;
+ }
+
+ return (0);
}
/*
@@ -545,125 +885,256 @@ smb_iod_recvall(struct smb_vc *vcp, boolean_t poll)
* The smb_smb_echo call uses SMBR_INTERNAL
* to avoid calling smb_iod_sendall().
*/
-int
-smb_iod_send_echo(smb_vc_t *vcp)
+static int
+smb_iod_send_echo(smb_vc_t *vcp, cred_t *cr)
{
smb_cred_t scred;
- int err;
+ int err, tmo = SMBNOREPLYWAIT;
+
+ ASSERT(vcp->iod_thr == curthread);
- smb_credinit(&scred, NULL);
- err = smb_smb_echo(vcp, &scred, SMBNOREPLYWAIT);
+ smb_credinit(&scred, cr);
+ if ((vcp->vc_flags & SMBV_SMB2) != 0) {
+ err = smb2_smb_echo(vcp, &scred, tmo);
+ } else {
+ err = smb_smb_echo(vcp, &scred, tmo);
+ }
smb_credrele(&scred);
return (err);
}
/*
- * The IOD thread is now just a "reader",
- * so no more smb_iod_request(). Yea!
+ * Helper for smb1_iod_addrq, smb2_iod_addrq
+ * Returns zero if interrupted, else 1.
*/
+static int
+smb_iod_muxwait(smb_vc_t *vcp, boolean_t sig_ok)
+{
+ int rc;
+
+ SMB_VC_LOCK(vcp);
+ vcp->iod_muxwant++;
+ if (sig_ok) {
+ rc = cv_wait_sig(&vcp->iod_muxwait, &vcp->vc_lock);
+ } else {
+ cv_wait(&vcp->iod_muxwait, &vcp->vc_lock);
+ rc = 1;
+ }
+ vcp->iod_muxwant--;
+ SMB_VC_UNLOCK(vcp);
+
+ return (rc);
+}
/*
- * Place request in the queue, and send it now if possible.
+ * Place request in the queue, and send it.
* Called with no locks held.
+ *
+ * Called for SMB1 only
+ *
+ * The logic for how we limit active requests differs between
+ * SMB1 and SMB2. With SMB1 it's a simple counter ioc_muxcnt.
*/
int
-smb_iod_addrq(struct smb_rq *rqp)
+smb1_iod_addrq(struct smb_rq *rqp)
{
struct smb_vc *vcp = rqp->sr_vc;
- int error, save_newrq;
+ uint16_t need;
+ boolean_t sig_ok =
+ (rqp->sr_flags & SMBR_NOINTR_SEND) == 0;
ASSERT(rqp->sr_cred);
+ ASSERT((vcp->vc_flags & SMBV_SMB2) == 0);
+
+ rqp->sr_owner = curthread;
+
+ rw_enter(&vcp->iod_rqlock, RW_WRITER);
+recheck:
/*
- * Requests from the IOD itself are marked _INTERNAL,
- * and get some special treatment to avoid blocking
- * the reader thread (so we don't deadlock).
- * The request is not yet on the queue, so we can
- * modify it's state here without locks.
+ * Internal requests can be added in any state,
+ * but normal requests only in state active.
*/
- rqp->sr_owner = curthread;
- if (rqp->sr_owner == vcp->iod_thr) {
- rqp->sr_flags |= SMBR_INTERNAL;
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0 &&
+ vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+ rw_exit(&vcp->iod_rqlock);
+ return (ENOTCONN);
+ }
- /*
- * This is a request from the IOD thread.
- * Always send directly from this thread.
- * Note lock order: iod_rqlist, vc_sendlock
- */
+ /*
+ * If we're at the limit of active requests, block until
+ * enough requests complete so we can make ours active.
+ * Wakeup in smb_iod_removerq().
+ *
+ * Normal callers leave one slot free, so internal
+ * callers can have the last slot if needed.
+ */
+ need = 1;
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0)
+ need++;
+ if ((vcp->iod_muxcnt + need) > vcp->vc_maxmux) {
+ rw_exit(&vcp->iod_rqlock);
+ if (rqp->sr_flags & SMBR_INTERNAL)
+ return (EBUSY);
+ if (smb_iod_muxwait(vcp, sig_ok) == 0)
+ return (EINTR);
rw_enter(&vcp->iod_rqlock, RW_WRITER);
- TAILQ_INSERT_HEAD(&vcp->iod_rqlist, rqp, sr_link);
- rw_downgrade(&vcp->iod_rqlock);
+ goto recheck;
+ }
- /*
- * Note: iod_sendrq expects vc_sendlock,
- * so take that here, but carefully:
- * Never block the IOD thread here.
- */
- if (sema_tryp(&vcp->vc_sendlock) == 0) {
- SMBIODEBUG("sendlock busy\n");
- error = EAGAIN;
- } else {
- /* Have vc_sendlock */
- error = smb_iod_sendrq(rqp);
- sema_v(&vcp->vc_sendlock);
- }
+ /*
+ * Add this request to the active list and send it.
+ * For SMB2 we may have a sequence of compounded
+ * requests, in which case we must add them all.
+ * They're sent as a compound in smb2_iod_sendrq.
+ */
+ rqp->sr_mid = vcp->vc_next_mid++;
+ /* If signing, set the signing sequence numbers. */
+ if (vcp->vc_mackey != NULL && (rqp->sr_rqflags2 &
+ SMB_FLAGS2_SECURITY_SIGNATURE) != 0) {
+ rqp->sr_seqno = vcp->vc_next_seq++;
+ rqp->sr_rseqno = vcp->vc_next_seq++;
+ }
+ vcp->iod_muxcnt++;
+ TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link);
+ smb1_iod_sendrq(rqp);
- rw_exit(&vcp->iod_rqlock);
+ rw_exit(&vcp->iod_rqlock);
+ return (0);
+}
- /*
- * In the non-error case, _removerq
- * is done by either smb_rq_reply
- * or smb_iod_waitrq.
- */
- if (error)
- smb_iod_removerq(rqp);
+/*
+ * Place request in the queue, and send it.
+ * Called with no locks held.
+ *
+ * Called for SMB2 only.
+ *
+ * With SMB2 we have a range of valid message IDs, and we may
+ * only send requests when we can assign a message ID within
+ * the valid range. We may need to wait here for some active
+ * request to finish (and update vc2_limit_message_id) before
+ * we can get message IDs for our new request(s). Another
+ * difference is that the request sequence we're waiting to
+ * add here may require multipe message IDs, either due to
+ * either compounding or multi-credit requests. Therefore
+ * we need to wait for the availibility of how ever many
+ * message IDs are required by our request sequence.
+ */
+int
+smb2_iod_addrq(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ struct smb_rq *c_rqp; /* compound req */
+ uint16_t charge;
+ boolean_t sig_ok =
+ (rqp->sr_flags & SMBR_NOINTR_SEND) == 0;
- return (error);
- } else {
- /*
- * State should be correct after the check in
- * smb_rq_enqueue(), but we dropped locks...
- */
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
- return (ENOTCONN);
+ ASSERT(rqp->sr_cred != NULL);
+ ASSERT((vcp->vc_flags & SMBV_SMB2) != 0);
+
+ /*
+ * Figure out the credit charges
+ * No multi-credit messages yet.
+ */
+ rqp->sr2_totalcreditcharge = rqp->sr2_creditcharge;
+ c_rqp = rqp->sr2_compound_next;
+ while (c_rqp != NULL) {
+ rqp->sr2_totalcreditcharge += c_rqp->sr2_creditcharge;
+ c_rqp = c_rqp->sr2_compound_next;
+ }
+
+ /*
+ * Internal request must not be compounded
+ * and should use exactly one credit.
+ */
+ if (rqp->sr_flags & SMBR_INTERNAL) {
+ if (rqp->sr2_compound_next != NULL) {
+ ASSERT(0);
+ return (EINVAL);
}
}
+ rqp->sr_owner = curthread;
+
rw_enter(&vcp->iod_rqlock, RW_WRITER);
- TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link);
- /* iod_rqlock/WRITER protects iod_newrq */
- save_newrq = vcp->iod_newrq;
- vcp->iod_newrq++;
+recheck:
+ /*
+ * Internal requests can be added in any state,
+ * but normal requests only in state active.
+ */
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0 &&
+ vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+ rw_exit(&vcp->iod_rqlock);
+ return (ENOTCONN);
+ }
- rw_exit(&vcp->iod_rqlock);
+ /*
+ * If we're at the limit of active requests, block until
+ * enough requests complete so we can make ours active.
+ * Wakeup in smb_iod_removerq().
+ *
+ * Normal callers leave one slot free, so internal
+ * callers can have the last slot if needed.
+ */
+ charge = rqp->sr2_totalcreditcharge;
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0)
+ charge++;
+ if ((vcp->vc2_next_message_id + charge) >
+ vcp->vc2_limit_message_id) {
+ rw_exit(&vcp->iod_rqlock);
+ if (rqp->sr_flags & SMBR_INTERNAL)
+ return (EBUSY);
+ if (smb_iod_muxwait(vcp, sig_ok) == 0)
+ return (EINTR);
+ rw_enter(&vcp->iod_rqlock, RW_WRITER);
+ goto recheck;
+ }
/*
- * Now send any requests that need to be sent,
- * including the one we just put on the list.
- * Only the thread that found iod_newrq==0
- * needs to run the send loop.
+ * Add this request to the active list and send it.
+ * For SMB2 we may have a sequence of compounded
+ * requests, in which case we must add them all.
+ * They're sent as a compound in smb2_iod_sendrq.
*/
- if (save_newrq == 0)
- smb_iod_sendall(vcp);
+ rqp->sr2_messageid = vcp->vc2_next_message_id;
+ vcp->vc2_next_message_id += rqp->sr2_creditcharge;
+ TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link);
+
+ c_rqp = rqp->sr2_compound_next;
+ while (c_rqp != NULL) {
+ c_rqp->sr2_messageid = vcp->vc2_next_message_id;
+ vcp->vc2_next_message_id += c_rqp->sr2_creditcharge;
+ TAILQ_INSERT_TAIL(&vcp->iod_rqlist, c_rqp, sr_link);
+ c_rqp = c_rqp->sr2_compound_next;
+ }
+ smb2_iod_sendrq(rqp);
+
+ rw_exit(&vcp->iod_rqlock);
return (0);
}
/*
* Mark an SMBR_MULTIPACKET request as
* needing another send. Similar to the
- * "normal" part of smb_iod_addrq.
+ * "normal" part of smb1_iod_addrq.
+ * Only used by SMB1
*/
int
-smb_iod_multirq(struct smb_rq *rqp)
+smb1_iod_multirq(struct smb_rq *rqp)
{
struct smb_vc *vcp = rqp->sr_vc;
- int save_newrq;
ASSERT(rqp->sr_flags & SMBR_MULTIPACKET);
+ if (vcp->vc_flags & SMBV_SMB2) {
+ ASSERT("!SMB2?");
+ return (EINVAL);
+ }
+
if (rqp->sr_flags & SMBR_INTERNAL)
return (EINVAL);
@@ -676,32 +1147,36 @@ smb_iod_multirq(struct smb_rq *rqp)
/* Already on iod_rqlist, just reset state. */
rqp->sr_state = SMBRQ_NOTSENT;
-
- /* iod_rqlock/WRITER protects iod_newrq */
- save_newrq = vcp->iod_newrq;
- vcp->iod_newrq++;
+ smb1_iod_sendrq(rqp);
rw_exit(&vcp->iod_rqlock);
- /*
- * Now send any requests that need to be sent,
- * including the one we just marked NOTSENT.
- * Only the thread that found iod_newrq==0
- * needs to run the send loop.
- */
- if (save_newrq == 0)
- smb_iod_sendall(vcp);
-
return (0);
}
-
+/*
+ * Remove a request from the active list, and
+ * wake up requests waiting to go active.
+ *
+ * Shared by SMB1 + SMB2
+ *
+ * The logic for how we limit active requests differs between
+ * SMB1 and SMB2. With SMB1 it's a simple counter ioc_muxcnt.
+ * With SMB2 we have a range of valid message IDs, and when we
+ * retire the oldest request we need to keep track of what is
+ * now the oldest message ID. In both cases, after we take a
+ * request out of the list here, we should be able to wake up
+ * a request waiting to get in the active list.
+ */
void
smb_iod_removerq(struct smb_rq *rqp)
{
+ struct smb_rq *rqp2;
struct smb_vc *vcp = rqp->sr_vc;
+ boolean_t was_head = B_FALSE;
rw_enter(&vcp->iod_rqlock, RW_WRITER);
+
#ifdef QUEUEDEBUG
/*
* Make sure we have not already removed it.
@@ -710,45 +1185,47 @@ smb_iod_removerq(struct smb_rq *rqp)
*/
ASSERT(rqp->sr_link.tqe_next != (void *)1L);
#endif
+
+ if (TAILQ_FIRST(&vcp->iod_rqlist) == rqp)
+ was_head = B_TRUE;
TAILQ_REMOVE(&vcp->iod_rqlist, rqp, sr_link);
- rw_exit(&vcp->iod_rqlock);
-}
+ if (vcp->vc_flags & SMBV_SMB2) {
+ rqp2 = TAILQ_FIRST(&vcp->iod_rqlist);
+ if (was_head && rqp2 != NULL) {
+ /* Do we still need this? */
+ vcp->vc2_oldest_message_id =
+ rqp2->sr2_messageid;
+ }
+ } else {
+ ASSERT(vcp->iod_muxcnt > 0);
+ vcp->iod_muxcnt--;
+ }
+ rw_exit(&vcp->iod_rqlock);
+ /*
+ * If there are requests waiting for "mux" slots,
+ * wake one.
+ */
+ SMB_VC_LOCK(vcp);
+ if (vcp->iod_muxwant != 0)
+ cv_signal(&vcp->iod_muxwait);
+ SMB_VC_UNLOCK(vcp);
+}
/*
* Wait for a request to complete.
- *
- * For normal requests, we need to deal with
- * ioc_muxcnt dropping below vc_maxmux by
- * making arrangements to send more...
*/
int
smb_iod_waitrq(struct smb_rq *rqp)
{
struct smb_vc *vcp = rqp->sr_vc;
clock_t tr, tmo1, tmo2;
- int error, rc;
+ int error;
if (rqp->sr_flags & SMBR_INTERNAL) {
- int timeleft = rqp->sr_timo;
-
- ASSERT((rqp->sr_flags & SMBR_MULTIPACKET) == 0);
- again:
- smb_iod_sendall(vcp);
- error = smb_iod_recvall(vcp, B_TRUE);
- if (error == ETIME) {
- /* We waited SMB_NBTIMO sec. */
- timeleft -= SMB_NBTIMO;
- if (timeleft > 0)
- goto again;
- }
-
- smb_iod_removerq(rqp);
- if (rqp->sr_state != SMBRQ_NOTIFIED)
- error = ETIME;
-
- return (error);
+ /* XXX - Do we ever take this path now? */
+ return (smb_iod_waitrq_int(rqp));
}
/*
@@ -760,35 +1237,6 @@ smb_iod_waitrq(struct smb_rq *rqp)
SMBRQ_LOCK(rqp);
/*
- * First, wait for the request to be sent. Normally the send
- * has already happened by the time we get here. However, if
- * we have more than maxmux entries in the request list, our
- * request may not be sent until other requests complete.
- * The wait in this case is due to local I/O demands, so
- * we don't want the server response timeout to apply.
- *
- * If a request is allowed to interrupt this wait, then the
- * request is cancelled and never sent OTW. Some kinds of
- * requests should never be cancelled (i.e. close) and those
- * are marked SMBR_NOINTR_SEND so they either go eventually,
- * or a connection close will terminate them with ENOTCONN.
- */
- while (rqp->sr_state == SMBRQ_NOTSENT) {
- rqp->sr_flags |= SMBR_SENDWAIT;
- if (rqp->sr_flags & SMBR_NOINTR_SEND) {
- cv_wait(&rqp->sr_cond, &rqp->sr_lock);
- rc = 1;
- } else
- rc = cv_wait_sig(&rqp->sr_cond, &rqp->sr_lock);
- rqp->sr_flags &= ~SMBR_SENDWAIT;
- if (rc == 0) {
- SMBIODEBUG("EINTR in sendwait, rq=%p\n", (void *)rqp);
- error = EINTR;
- goto out;
- }
- }
-
- /*
* The request has been sent. Now wait for the response,
* with the timeout specified for this request.
* Compute all the deadlines now, so we effectively
@@ -861,13 +1309,34 @@ out:
if ((rqp->sr_flags & SMBR_MULTIPACKET) == 0)
smb_iod_removerq(rqp);
- /*
- * Some request has been completed.
- * If we reached the mux limit,
- * re-run the send loop...
- */
- if (vcp->iod_muxfull)
- smb_iod_sendall(vcp);
+ return (error);
+}
+
+/*
+ * Internal variant of smb_iod_waitrq(), for use in
+ * requests run by the IOD (reader) thread itself.
+ * Block only long enough to receive one reply.
+ */
+int
+smb_iod_waitrq_int(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ int timeleft = rqp->sr_timo;
+ int error;
+
+ ASSERT((rqp->sr_flags & SMBR_MULTIPACKET) == 0);
+again:
+ error = smb_iod_recvall(vcp, B_TRUE);
+ if (error == ETIME) {
+ /* We waited SMB_NBTIMO sec. */
+ timeleft -= SMB_NBTIMO;
+ if (timeleft > 0)
+ goto again;
+ }
+
+ smb_iod_removerq(rqp);
+ if (rqp->sr_state != SMBRQ_NOTIFIED)
+ error = ETIME;
return (error);
}
@@ -897,77 +1366,15 @@ smb_iod_shutdown_share(struct smb_share *ssp)
}
/*
- * Send all requests that need sending.
- * Called from _addrq, _multirq, _waitrq
- */
-void
-smb_iod_sendall(smb_vc_t *vcp)
-{
- struct smb_rq *rqp;
- int error, muxcnt;
-
- /*
- * Clear "newrq" to make sure threads adding
- * new requests will run this function again.
- */
- rw_enter(&vcp->iod_rqlock, RW_WRITER);
- vcp->iod_newrq = 0;
-
- /*
- * We only read iod_rqlist, so downgrade rwlock.
- * This allows the IOD to handle responses while
- * some requesting thread may be blocked in send.
- */
- rw_downgrade(&vcp->iod_rqlock);
-
- /*
- * Serialize to prevent multiple senders.
- * Note lock order: iod_rqlock, vc_sendlock
- */
- sema_p(&vcp->vc_sendlock);
-
- /*
- * Walk the list of requests and send when possible.
- * We avoid having more than vc_maxmux requests
- * outstanding to the server by traversing only
- * vc_maxmux entries into this list. Simple!
- */
- ASSERT(vcp->vc_maxmux > 0);
- error = muxcnt = 0;
- TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
-
- if (rqp->sr_state == SMBRQ_NOTSENT) {
- error = smb_iod_sendrq(rqp);
- if (error)
- break;
- }
-
- if (++muxcnt == vcp->vc_maxmux) {
- SMBIODEBUG("muxcnt == vc_maxmux\n");
- break;
- }
-
- }
-
- /*
- * If we have vc_maxmux requests outstanding,
- * arrange for _waitrq to call _sendall as
- * requests are completed.
- */
- vcp->iod_muxfull =
- (muxcnt < vcp->vc_maxmux) ? 0 : 1;
-
- sema_v(&vcp->vc_sendlock);
- rw_exit(&vcp->iod_rqlock);
-}
-
-/*
* Ioctl functions called by the user-level I/O Deamon (IOD)
* to bring up and service a connection to some SMB server.
*/
+/*
+ * Handle ioctl SMBIOC_IOD_CONNECT
+ */
int
-nsmb_iod_connect(struct smb_vc *vcp)
+nsmb_iod_connect(struct smb_vc *vcp, cred_t *cr)
{
int err, val;
@@ -979,6 +1386,22 @@ nsmb_iod_connect(struct smb_vc *vcp)
}
/*
+ * Putting a TLI endpoint back in the right state for a new
+ * connection is a bit tricky. In theory, this could be:
+ * SMB_TRAN_DISCONNECT(vcp);
+ * SMB_TRAN_UNBIND(vcp);
+ * but that method often results in TOUTSTATE errors.
+ * It's easier to just close it and open a new endpoint.
+ */
+ SMB_VC_LOCK(vcp);
+ if (vcp->vc_tdata)
+ SMB_TRAN_DONE(vcp);
+ err = SMB_TRAN_CREATE(vcp, cr);
+ SMB_VC_UNLOCK(vcp);
+ if (err != 0)
+ return (err);
+
+ /*
* Set various options on this endpoint.
* Keep going in spite of errors.
*/
@@ -1032,7 +1455,21 @@ nsmb_iod_connect(struct smb_vc *vcp)
}
/*
+ * Handle ioctl SMBIOC_IOD_NEGOTIATE
* Do the whole SMB1/SMB2 negotiate
+ *
+ * This is where we send our first request to the server.
+ * If this is the first time we're talking to this server,
+ * (meaning not a reconnect) then we don't know whether
+ * the server supports SMB2, so we need to use the weird
+ * SMB1-to-SMB2 negotiation. That's where we send an SMB1
+ * negotiate including dialect "SMB 2.???" and if the
+ * server supports SMB2 we get an SMB2 reply -- Yes, an
+ * SMB2 reply to an SMB1 request. A strange protocol...
+ *
+ * If on the other hand we already know the server supports
+ * SMB2 (because this is a reconnect) or if the client side
+ * has disabled SMB1 entirely, we'll skip the SMB1 part.
*/
int
nsmb_iod_negotiate(struct smb_vc *vcp, cred_t *cr)
@@ -1043,15 +1480,26 @@ nsmb_iod_negotiate(struct smb_vc *vcp, cred_t *cr)
ASSERT(vcp->iod_thr == curthread);
+ smb_credinit(&scred, cr);
+
if (vcp->vc_state != SMBIOD_ST_CONNECTED) {
cmn_err(CE_NOTE, "iod_negotiate: bad state %d", vcp->vc_state);
- return (EINVAL);
+ err = EINVAL;
+ goto out;
+ }
+
+ if (vcp->vc_maxver == 0 || vcp->vc_minver > vcp->vc_maxver) {
+ err = EINVAL;
+ goto out;
}
/*
* (Re)init negotiated values
*/
bzero(sv, sizeof (*sv));
+ vcp->vc2_next_message_id = 0;
+ vcp->vc2_limit_message_id = 1;
+ vcp->vc2_session_id = 0;
vcp->vc_next_seq = 0;
/*
@@ -1071,10 +1519,54 @@ nsmb_iod_negotiate(struct smb_vc *vcp, cred_t *cr)
}
SMB_VC_UNLOCK(vcp);
- smb_credinit(&scred, cr);
- err = smb_smb_negotiate(vcp, &scred);
- smb_credrele(&scred);
+ /*
+ * If this is not an SMB2 reconect (SMBV_SMB2 not set),
+ * and if SMB1 is enabled, do SMB1 neogotiate. Then
+ * if either SMB1-to-SMB2 negotiate tells us we should
+ * switch to SMB2, or the local configuration has
+ * disabled SMB1, set the SMBV_SMB2 flag.
+ *
+ * Note that vc_maxver is handled in smb_smb_negotiate
+ * so we never get sv_proto == SMB_DIALECT_SMB2_FF when
+ * the local configuration disables SMB2, and therefore
+ * we won't set the SMBV_SMB2 flag.
+ */
+ if ((vcp->vc_flags & SMBV_SMB2) == 0) {
+ if (vcp->vc_minver < SMB2_DIALECT_BASE) {
+ /*
+ * SMB1 is enabled
+ */
+ err = smb_smb_negotiate(vcp, &scred);
+ if (err != 0)
+ goto out;
+ }
+ /*
+ * If SMB1-to-SMB2 negotiate told us we should
+ * switch to SMB2, or if the local configuration
+ * disables SMB1, set the SMB2 flag.
+ */
+ if (sv->sv_proto == SMB_DIALECT_SMB2_FF ||
+ vcp->vc_minver >= SMB2_DIALECT_BASE) {
+ /*
+ * Switch this VC to SMB2.
+ */
+ SMB_VC_LOCK(vcp);
+ vcp->vc_flags |= SMBV_SMB2;
+ SMB_VC_UNLOCK(vcp);
+ }
+ }
+ /*
+ * If this is an SMB2 reconnect (SMBV_SMB2 was set before this
+ * function was called), or SMB1-to-SMB2 negotiate indicated
+ * we should switch to SMB2, or we have SMB1 disabled (both
+ * cases set SMBV_SMB2 above), then do SMB2 negotiate.
+ */
+ if ((vcp->vc_flags & SMBV_SMB2) != 0) {
+ err = smb2_smb_negotiate(vcp, &scred);
+ }
+
+out:
if (err == 0) {
SMB_VC_LOCK(vcp);
smb_iod_newstate(vcp, SMBIOD_ST_NEGOTIATED);
@@ -1082,15 +1574,18 @@ nsmb_iod_negotiate(struct smb_vc *vcp, cred_t *cr)
}
/*
* (else) leave state as it was.
- * User-level will report this error
- * and close this device handle.
+ * User-level will either close this handle (if connecting
+ * for the first time) or call rcfail and then try again.
*/
+ smb_credrele(&scred);
+
return (err);
}
/*
- * Do either SMB1 or SMB2 session setup.
+ * Handle ioctl SMBIOC_IOD_SSNSETUP
+ * Do either SMB1 or SMB2 session setup (one call/reply)
*/
int
nsmb_iod_ssnsetup(struct smb_vc *vcp, cred_t *cr)
@@ -1109,8 +1604,10 @@ nsmb_iod_ssnsetup(struct smb_vc *vcp, cred_t *cr)
}
smb_credinit(&scred, cr);
- // XXX if SMB1 else ...
- err = smb_smb_ssnsetup(vcp, &scred);
+ if (vcp->vc_flags & SMBV_SMB2)
+ err = smb2_smb_ssnsetup(vcp, &scred);
+ else
+ err = smb_smb_ssnsetup(vcp, &scred);
smb_credrele(&scred);
SMB_VC_LOCK(vcp);
@@ -1130,6 +1627,32 @@ nsmb_iod_ssnsetup(struct smb_vc *vcp, cred_t *cr)
return (err);
}
+static int
+smb_iod_logoff(struct smb_vc *vcp, cred_t *cr)
+{
+ smb_cred_t scred;
+ int err;
+
+ ASSERT(vcp->iod_thr == curthread);
+
+ smb_credinit(&scred, cr);
+ if (vcp->vc_flags & SMBV_SMB2)
+ err = smb2_smb_logoff(vcp, &scred);
+ else
+ err = smb_smb_logoff(vcp, &scred);
+ smb_credrele(&scred);
+
+ return (err);
+}
+
+/*
+ * Handle ioctl SMBIOC_IOD_WORK
+ *
+ * The smbiod agent calls this after authentication to become
+ * the reader for this session, so long as that's possible.
+ * This should only return non-zero if we want that agent to
+ * give up on this VC permanently.
+ */
/* ARGSUSED */
int
smb_iod_vc_work(struct smb_vc *vcp, int flags, cred_t *cr)
@@ -1185,7 +1708,10 @@ smb_iod_vc_work(struct smb_vc *vcp, int flags, cred_t *cr)
*/
ASSERT(vcp->vc_mackey == NULL);
if (vcp->vc_ssnkey != NULL) {
- err = smb_sign_init(vcp);
+ if (vcp->vc_flags & SMBV_SMB2)
+ err = smb2_sign_init(vcp);
+ else
+ err = smb_sign_init(vcp);
if (err != 0)
return (err);
}
@@ -1210,9 +1736,11 @@ smb_iod_vc_work(struct smb_vc *vcp, int flags, cred_t *cr)
smb_vc_walkshares(vcp, fscb->fscb_connect);
/*
- * Run the "reader" loop.
+ * Run the "reader" loop. An error return here is normal
+ * (i.e. when we need to reconnect) so ignore errors.
+ * Note: This call updates the vc_state.
*/
- err = smb_iod_recvall(vcp, B_FALSE);
+ (void) smb_iod_recvall(vcp, B_FALSE);
/*
* The reader loop returned, so we must have a
@@ -1237,15 +1765,20 @@ smb_iod_vc_work(struct smb_vc *vcp, int flags, cred_t *cr)
}
/*
- * Wait around for someone to ask to use this VC.
- * If the VC has only the IOD reference, then
- * wait only a minute or so, then drop it.
+ * Handle ioctl SMBIOC_IOD_IDLE
+ *
+ * Wait around for someone to ask to use this VC again after the
+ * TCP session has closed. When one of the connected trees adds a
+ * request, smb_iod_reconnect will set vc_state to RECONNECT and
+ * wake this cv_wait. When a VC ref. goes away in smb_vc_rele,
+ * that also signals this wait so we can re-check whether we
+ * now hold the last ref. on this VC (and can destroy it).
*/
int
smb_iod_vc_idle(struct smb_vc *vcp)
{
- clock_t tr, delta = SEC_TO_TICK(15);
int err = 0;
+ boolean_t destroy = B_FALSE;
/*
* This is called by the one-and-only
@@ -1253,30 +1786,50 @@ smb_iod_vc_idle(struct smb_vc *vcp)
*/
ASSERT(vcp->iod_thr == curthread);
+ /*
+ * Should be in state...
+ */
+ if (vcp->vc_state != SMBIOD_ST_IDLE &&
+ vcp->vc_state != SMBIOD_ST_RECONNECT) {
+ cmn_err(CE_NOTE, "iod_vc_idle: bad state %d", vcp->vc_state);
+ return (EINVAL);
+ }
+
SMB_VC_LOCK(vcp);
- while (vcp->vc_state == SMBIOD_ST_IDLE) {
- tr = cv_reltimedwait_sig(&vcp->iod_idle, &vcp->vc_lock,
- delta, TR_CLOCK_TICK);
- if (tr == 0) {
+
+ while (vcp->vc_state == SMBIOD_ST_IDLE &&
+ vcp->vc_co.co_usecount > 1) {
+ if (cv_wait_sig(&vcp->iod_idle, &vcp->vc_lock) == 0) {
err = EINTR;
break;
}
- if (tr < 0) {
- /* timeout */
- if (vcp->vc_co.co_usecount == 1) {
- /* Let this IOD terminate. */
- smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
- /* nobody to cv_broadcast */
- break;
- }
- }
}
+ if (vcp->vc_state == SMBIOD_ST_IDLE &&
+ vcp->vc_co.co_usecount == 1) {
+ /*
+ * We were woken because we now have the last ref.
+ * Arrange for this VC to be destroyed now.
+ * Set the "GONE" flag while holding the lock,
+ * to prevent a race with new references.
+ * The destroy happens after unlock.
+ */
+ vcp->vc_flags |= SMBV_GONE;
+ destroy = B_TRUE;
+ }
+
SMB_VC_UNLOCK(vcp);
+ if (destroy) {
+ /* This sets vc_state = DEAD */
+ smb_iod_disconnect(vcp);
+ }
+
return (err);
}
/*
+ * Handle ioctl SMBIOC_IOD_RCFAIL
+ *
* After a failed reconnect attempt, smbiod will
* call this to make current requests error out.
*/
@@ -1307,13 +1860,17 @@ smb_iod_vc_rcfail(struct smb_vc *vcp)
err = EINTR;
/*
- * While we were waiting on the CV, the state might have
- * changed to reconnect. If so, leave that; otherwise
- * go to state idle until the next request.
+ * Normally we'll switch to state IDLE here. However,
+ * if something called smb_iod_reconnect() while we were
+ * waiting above, we'll be in in state reconnect already.
+ * In that case, keep state RECONNECT, so we essentially
+ * skip transition through state IDLE that would normally
+ * happen next.
*/
- if (vcp->vc_state == SMBIOD_ST_RCFAILED)
+ if (vcp->vc_state != SMBIOD_ST_RECONNECT) {
smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
- cv_broadcast(&vcp->vc_statechg);
+ cv_broadcast(&vcp->vc_statechg);
+ }
SMB_VC_UNLOCK(vcp);
@@ -1334,6 +1891,7 @@ again:
switch (vcp->vc_state) {
case SMBIOD_ST_IDLE:
+ /* Tell the IOD thread it's no longer IDLE. */
smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT);
cv_signal(&vcp->iod_idle);
/* FALLTHROUGH */
@@ -1343,6 +1901,7 @@ again:
case SMBIOD_ST_NEGOTIATED:
case SMBIOD_ST_AUTHCONT:
case SMBIOD_ST_AUTHOK:
+ /* Wait for the VC state to become ACTIVE. */
rv = cv_wait_sig(&vcp->vc_statechg, &vcp->vc_lock);
if (rv == 0) {
err = EINTR;
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
index 2301965762..1c62850599 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
@@ -34,6 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
* Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
@@ -52,10 +53,12 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_tran.h>
#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
/*
* How long to wait before restarting a request (after reconnect)
@@ -70,9 +73,8 @@
static int smb_rq_reply(struct smb_rq *rqp);
+static int smb_rq_parsehdr(struct smb_rq *rqp);
static int smb_rq_enqueue(struct smb_rq *rqp);
-static int smb_rq_getenv(struct smb_connobj *layer,
- struct smb_vc **vcpp, struct smb_share **sspp);
static int smb_rq_new(struct smb_rq *rqp, uchar_t cmd);
static int smb_t2_reply(struct smb_t2rq *t2p);
static int smb_nt_reply(struct smb_ntrq *ntp);
@@ -148,7 +150,6 @@ smb_rq_init(struct smb_rq *rqp, struct smb_connobj *co, uchar_t cmd,
rqp->sr_rexmit = SMBMAXRESTARTS;
rqp->sr_cred = scred; /* Note: ref hold done by caller. */
- rqp->sr_pid = (uint16_t)ddi_get_pid();
error = smb_rq_new(rqp, cmd);
return (error);
@@ -164,7 +165,6 @@ smb_rq_new(struct smb_rq *rqp, uchar_t cmd)
ASSERT(rqp != NULL);
rqp->sr_sendcnt = 0;
- rqp->sr_cmd = cmd;
mb_done(mbp);
md_done(&rqp->sr_rp);
@@ -172,18 +172,42 @@ smb_rq_new(struct smb_rq *rqp, uchar_t cmd)
if (error)
return (error);
- /*
- * Is this the right place to save the flags?
- */
- rqp->sr_rqflags = vcp->vc_hflags;
- rqp->sr_rqflags2 = vcp->vc_hflags2;
+ if (vcp->vc_flags & SMBV_SMB2) {
+ /*
+ * SMB2 request initialization
+ */
+ rqp->sr2_command = cmd;
+ rqp->sr2_creditcharge = 1;
+ rqp->sr2_creditsrequested = 1;
+ rqp->sr_pid = 0xFEFF; /* Made up, just like Windows */
+ rqp->sr2_rqflags = 0;
+ if ((vcp->vc_flags & SMBV_SIGNING) != 0 &&
+ vcp->vc_mackey != NULL) {
+ rqp->sr2_rqflags |= SMB2_FLAGS_SIGNED;
+ }
- /*
- * The SMB header is filled in later by
- * smb_rq_fillhdr (see below)
- * Just reserve space here.
- */
- mb_put_mem(mbp, NULL, SMB_HDRLEN, MB_MZERO);
+ /*
+ * The SMB2 header is filled in later by
+ * smb2_rq_fillhdr (see smb2_rq.c)
+ * Just reserve space here.
+ */
+ mb_put_mem(mbp, NULL, SMB2_HDRLEN, MB_MZERO);
+ } else {
+ /*
+ * SMB1 request initialization
+ */
+ rqp->sr_cmd = cmd;
+ rqp->sr_pid = (uint32_t)ddi_get_pid();
+ rqp->sr_rqflags = vcp->vc_hflags;
+ rqp->sr_rqflags2 = vcp->vc_hflags2;
+
+ /*
+ * The SMB header is filled in later by
+ * smb_rq_fillhdr (see below)
+ * Just reserve space here.
+ */
+ mb_put_mem(mbp, NULL, SMB_HDRLEN, MB_MZERO);
+ }
return (0);
}
@@ -191,7 +215,7 @@ smb_rq_new(struct smb_rq *rqp, uchar_t cmd)
/*
* Given a request with it's body already composed,
* rewind to the start and fill in the SMB header.
- * This is called after the request is enqueued,
+ * This is called when the request is enqueued,
* so we have the final MID, seq num. etc.
*/
void
@@ -218,7 +242,7 @@ smb_rq_fillhdr(struct smb_rq *rqp)
mb_put_mem(mbp, NULL, 8, MB_MZERO); /* MAC sig. (later) */
mb_put_uint16le(mbp, 0); /* reserved */
mb_put_uint16le(mbp, rqp->sr_rqtid);
- mb_put_uint16le(mbp, rqp->sr_pid);
+ mb_put_uint16le(mbp, (uint16_t)rqp->sr_pid);
mb_put_uint16le(mbp, rqp->sr_rquid);
mb_put_uint16le(mbp, rqp->sr_mid);
@@ -282,6 +306,8 @@ smb_rq_enqueue(struct smb_rq *rqp)
struct smb_share *ssp = rqp->sr_share;
int error = 0;
+ ASSERT((vcp->vc_flags & SMBV_SMB2) == 0);
+
/*
* Normal requests may initiate a reconnect,
* and/or wait for state changes to finish.
@@ -326,37 +352,73 @@ smb_rq_enqueue(struct smb_rq *rqp)
ok_out:
rqp->sr_rquid = vcp->vc_smbuid;
rqp->sr_rqtid = ssp ? ssp->ss_tid : SMB_TID_UNKNOWN;
- error = smb_iod_addrq(rqp);
+ error = smb1_iod_addrq(rqp);
return (error);
}
/*
- * Used by the IOD thread during connection setup.
+ * Used by the IOD thread during connection setup,
+ * and for smb_echo after network timeouts. Note that
+ * unlike smb_rq_simple, callers must check sr_error.
*/
int
smb_rq_internal(struct smb_rq *rqp, int timeout)
{
struct smb_vc *vcp = rqp->sr_vc;
- int err;
+ int error;
+
+ ASSERT((vcp->vc_flags & SMBV_SMB2) == 0);
rqp->sr_flags &= ~SMBR_RESTART;
rqp->sr_timo = timeout; /* in seconds */
rqp->sr_state = SMBRQ_NOTSENT;
/*
- * Skip smb_rq_enqueue(rqp) here, as we don't want it
- * trying to reconnect etc. We're doing that.
+ * In-line smb_rq_enqueue(rqp) here, as we don't want it
+ * trying to reconnect etc. for an internal request.
*/
rqp->sr_rquid = vcp->vc_smbuid;
rqp->sr_rqtid = SMB_TID_UNKNOWN;
- err = smb_iod_addrq(rqp);
- if (err != 0)
- return (err);
+ rqp->sr_flags |= SMBR_INTERNAL;
+ error = smb1_iod_addrq(rqp);
+ if (error != 0)
+ return (error);
- err = smb_rq_reply(rqp);
+ /*
+ * In-line a variant of smb_rq_reply(rqp) here as we may
+ * need to do custom parsing for SMB1-to-SMB2 negotiate.
+ */
+ if (rqp->sr_timo == SMBNOREPLYWAIT) {
+ smb_iod_removerq(rqp);
+ return (0);
+ }
- return (err);
+ error = smb_iod_waitrq_int(rqp);
+ if (error)
+ return (error);
+
+ /*
+ * If the request was signed, validate the
+ * signature on the response.
+ */
+ if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
+ error = smb_rq_verify(rqp);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * Parse the SMB header.
+ */
+ error = smb_rq_parsehdr(rqp);
+
+ /*
+ * Skip the error translation smb_rq_reply does.
+ * Callers of this expect "raw" NT status.
+ */
+
+ return (error);
}
/*
@@ -427,15 +489,6 @@ smb_rq_bend(struct smb_rq *rqp)
}
int
-smb_rq_intr(struct smb_rq *rqp)
-{
- if (rqp->sr_flags & SMBR_INTR)
- return (EINTR);
-
- return (0);
-}
-
-static int
smb_rq_getenv(struct smb_connobj *co,
struct smb_vc **vcpp, struct smb_share **sspp)
{
@@ -486,14 +539,12 @@ out:
}
/*
- * Wait for reply on the request
+ * Wait for a reply to this request, then parse it.
*/
static int
smb_rq_reply(struct smb_rq *rqp)
{
- struct mdchain *mdp = &rqp->sr_rp;
- u_int8_t tb;
- int error, rperror = 0;
+ int error;
if (rqp->sr_timo == SMBNOREPLYWAIT) {
smb_iod_removerq(rqp);
@@ -517,27 +568,23 @@ smb_rq_reply(struct smb_rq *rqp)
/*
* Parse the SMB header
*/
- error = md_get_uint32le(mdp, NULL);
- if (error)
+ error = smb_rq_parsehdr(rqp);
+ if (error != 0)
return (error);
- error = md_get_uint8(mdp, &tb);
- error = md_get_uint32le(mdp, &rqp->sr_error);
- error = md_get_uint8(mdp, &rqp->sr_rpflags);
- error = md_get_uint16le(mdp, &rqp->sr_rpflags2);
if (rqp->sr_error != 0) {
if (rqp->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) {
- rperror = smb_maperr32(rqp->sr_error);
+ error = smb_maperr32(rqp->sr_error);
} else {
uint8_t errClass = rqp->sr_error & 0xff;
uint16_t errCode = rqp->sr_error >> 16;
/* Convert to NT status */
rqp->sr_error = smb_doserr2status(errClass, errCode);
- rperror = smb_maperror(errClass, errCode);
+ error = smb_maperror(errClass, errCode);
}
}
- if (rperror) {
+ if (error != 0) {
/*
* Do a special check for STATUS_BUFFER_OVERFLOW;
* it's not an error.
@@ -550,22 +597,63 @@ smb_rq_reply(struct smb_rq *rqp)
* STATUS_BUFFER_OVERFLOW.
*/
rqp->sr_flags |= SMBR_MOREDATA;
- rperror = 0;
+ error = 0;
}
} else {
rqp->sr_flags &= ~SMBR_MOREDATA;
}
- error = md_get_uint32le(mdp, NULL);
- error = md_get_uint32le(mdp, NULL);
- error = md_get_uint32le(mdp, NULL);
+ return (error);
+}
+
+/*
+ * Parse the SMB header
+ */
+static int
+smb_rq_parsehdr(struct smb_rq *rqp)
+{
+ struct mdchain mdp_save;
+ struct mdchain *mdp = &rqp->sr_rp;
+ u_int8_t tb, sig[4];
+ int error;
- error = md_get_uint16le(mdp, &rqp->sr_rptid);
- error = md_get_uint16le(mdp, &rqp->sr_rppid);
- error = md_get_uint16le(mdp, &rqp->sr_rpuid);
+ /*
+ * Parse the signature. The reader already checked that
+ * the signature is valid. Here we just have to check
+ * for SMB1-to-SMB2 negotiate. Caller handles an EPROTO
+ * as a signal that we got an SMB2 reply. If we return
+ * EPROTO, rewind the mdchain back where it was.
+ */
+ mdp_save = *mdp;
+ error = md_get_mem(mdp, sig, 4, MB_MSYSTEM);
+ if (error)
+ return (error);
+ if (sig[0] != SMB_HDR_V1) {
+ if (rqp->sr_cmd == SMB_COM_NEGOTIATE) {
+ *mdp = mdp_save;
+ return (EPROTO);
+ }
+ return (EBADRPC);
+ }
+
+ /* Check cmd */
+ error = md_get_uint8(mdp, &tb);
+ if (tb != rqp->sr_cmd)
+ return (EBADRPC);
+
+ md_get_uint32le(mdp, &rqp->sr_error);
+ md_get_uint8(mdp, &rqp->sr_rpflags);
+ md_get_uint16le(mdp, &rqp->sr_rpflags2);
+
+ /* Skip: pid-high(2), MAC sig(8), reserved(2) */
+ md_get_mem(mdp, NULL, 12, MB_MSYSTEM);
+
+ md_get_uint16le(mdp, &rqp->sr_rptid);
+ md_get_uint16le(mdp, &rqp->sr_rppid);
+ md_get_uint16le(mdp, &rqp->sr_rpuid);
error = md_get_uint16le(mdp, &rqp->sr_rpmid);
- return ((error) ? error : rperror);
+ return (error);
}
@@ -1166,7 +1254,7 @@ smb_t2_request_int(struct smb_t2rq *t2p)
mb_put_mbuf(mbp, m);
}
smb_rq_bend(rqp);
- error = smb_iod_multirq(rqp);
+ error = smb1_iod_multirq(rqp);
if (error)
goto bad;
} /* while left params or data */
@@ -1377,7 +1465,7 @@ smb_nt_request_int(struct smb_ntrq *ntp)
mb_put_mbuf(mbp, m);
}
smb_rq_bend(rqp);
- error = smb_iod_multirq(rqp);
+ error = smb1_iod_multirq(rqp);
if (error)
goto bad;
} /* while left params or data */
@@ -1470,3 +1558,83 @@ smb_nt_request(struct smb_ntrq *ntp)
}
return (error);
}
+
+/*
+ * Run an SMB transact named pipe.
+ * Note: send_mb is consumed.
+ */
+int
+smb_t2_xnp(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *send_mb, struct mdchain *recv_md,
+ uint32_t *data_out_sz, /* max / returned */
+ uint32_t *more, struct smb_cred *scrp)
+{
+ struct smb_t2rq *t2p = NULL;
+ mblk_t *m;
+ uint16_t setup[2];
+ int err;
+
+ setup[0] = TRANS_TRANSACT_NAMED_PIPE;
+ setup[1] = fid;
+
+ t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
+ err = smb_t2_init(t2p, SSTOCP(ssp), setup, 2, scrp);
+ if (err) {
+ *data_out_sz = 0;
+ goto out;
+ }
+
+ t2p->t2_setupcount = 2;
+ t2p->t2_setupdata = setup;
+
+ t2p->t_name = "\\PIPE\\";
+ t2p->t_name_len = 6;
+
+ t2p->t2_maxscount = 0;
+ t2p->t2_maxpcount = 0;
+ t2p->t2_maxdcount = (uint16_t)*data_out_sz;
+
+ /* Transmit parameters (none) */
+
+ /*
+ * Transmit data
+ *
+ * Copy the mb, and clear the source so we
+ * don't end up with a double free.
+ */
+ t2p->t2_tdata = *send_mb;
+ bzero(send_mb, sizeof (*send_mb));
+
+ /*
+ * Run the request
+ */
+ err = smb_t2_request(t2p);
+
+ /* No returned parameters. */
+
+ if (err == 0 && (m = t2p->t2_rdata.md_top) != NULL) {
+ /*
+ * Received data
+ *
+ * Copy the mdchain, and clear the source so we
+ * don't end up with a double free.
+ */
+ *data_out_sz = msgdsize(m);
+ md_initm(recv_md, m);
+ t2p->t2_rdata.md_top = NULL;
+ } else {
+ *data_out_sz = 0;
+ }
+
+ if (t2p->t2_sr_error == NT_STATUS_BUFFER_OVERFLOW)
+ *more = 1;
+
+out:
+ if (t2p != NULL) {
+ /* Note: t2p->t_name no longer allocated */
+ smb_t2_done(t2p);
+ kmem_free(t2p, sizeof (*t2p));
+ }
+
+ return (err);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
index 4d6dbb1fe0..7c3106612c 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
@@ -34,6 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Portions Copyright (C) 2001 - 2012 Apple Inc. All rights reserved.
* Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
@@ -57,6 +58,10 @@
#define SMBR_NORECONNECT 0x0800 /* do not reconnect for this */
/* SMBR_VCREF 0x4000 * took vc reference (obsolete) */
#define SMBR_MOREDATA 0x8000 /* our buffer was too small */
+#define SMBR_COMPOUND_RQ 0x10000 /* SMB 2/3 compound request */
+#define SMBR_ASYNC 0x20000 /* got async response */
+#define SMBR_RECONNECTED 0x40000 /* reconnected during request */
+
#define SMBT2_ALLSENT 0x0001 /* all data and params are sent */
#define SMBT2_ALLRECV 0x0002 /* all data and params are received */
@@ -92,11 +97,24 @@ struct smb_rq {
uint8_t sr_rqflags;
uint16_t sr_rqflags2;
uint16_t sr_rqtid;
- uint16_t sr_pid;
+ uint32_t sr_pid;
uint16_t sr_rquid;
uint16_t sr_mid;
uchar_t *sr_wcount;
uchar_t *sr_bcount;
+
+ /* SMB 2/3 request fields */
+ struct smb_rq *sr2_compound_next;
+ uint16_t sr2_command;
+ uint16_t sr2_totalcreditcharge;
+ uint16_t sr2_creditcharge;
+ uint16_t sr2_creditsrequested;
+ uint32_t sr2_rqflags;
+ uint32_t sr2_nextcmd;
+ uint64_t sr2_messageid; /* local copy of message id */
+ uint64_t sr2_rqsessionid;
+ uint32_t sr2_rqtreeid;
+
struct mdchain sr_rp;
int sr_rpgen;
int sr_rplast;
@@ -117,6 +135,15 @@ struct smb_rq {
uint16_t sr_rppid;
uint16_t sr_rpuid;
uint16_t sr_rpmid;
+
+ /* SMB2 response fields */
+ uint16_t sr2_rspcreditsgranted;
+ uint32_t sr2_rspflags;
+ uint32_t sr2_rspnextcmd;
+ uint32_t sr2_rsppid;
+ uint32_t sr2_rsptreeid;
+ uint64_t sr2_rspasyncid;
+ uint64_t sr2_rspsessionid;
};
typedef struct smb_rq smb_rq_t;
@@ -185,17 +212,20 @@ int smb_rq_alloc(struct smb_connobj *layer, uchar_t cmd,
struct smb_cred *scred, struct smb_rq **rqpp);
int smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer,
uchar_t cmd, struct smb_cred *scred);
+int smb_rq_getenv(struct smb_connobj *layer,
+ struct smb_vc **vcpp, struct smb_share **sspp);
void smb_rq_fillhdr(struct smb_rq *rqp);
void smb_rq_wstart(struct smb_rq *rqp);
void smb_rq_wend(struct smb_rq *rqp);
void smb_rq_bstart(struct smb_rq *rqp);
void smb_rq_bend(struct smb_rq *rqp);
-int smb_rq_intr(struct smb_rq *rqp);
int smb_rq_simple(struct smb_rq *rqp);
int smb_rq_simple_timed(struct smb_rq *rqp, int timeout);
int smb_rq_internal(struct smb_rq *rqp, int timeout);
+int smb2_parse_smb1nego_resp(struct smb_rq *rqp);
+
int smb_t2_alloc(struct smb_connobj *layer, ushort_t setup,
struct smb_cred *scred, struct smb_t2rq **rqpp);
int smb_t2_init(struct smb_t2rq *rqp, struct smb_connobj *layer,
@@ -203,6 +233,10 @@ int smb_t2_init(struct smb_t2rq *rqp, struct smb_connobj *layer,
void smb_t2_done(struct smb_t2rq *t2p);
int smb_t2_request(struct smb_t2rq *t2p);
+int smb_t2_xnp(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *send_mb, struct mdchain *recv_md,
+ uint32_t *data_out_sz, uint32_t *more, struct smb_cred *scrp);
+
int smb_nt_alloc(struct smb_connobj *layer, ushort_t fn,
struct smb_cred *scred, struct smb_ntrq **rqpp);
int smb_nt_init(struct smb_ntrq *rqp, struct smb_connobj *layer,
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
index 0d3b21a888..bec61e4392 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
@@ -59,16 +59,6 @@
int nsmb_signing_fudge = 0;
#endif
-/* Mechanism definitions */
-static smb_sign_mech_t smb_mech_md5;
-
-void
-smb_crypto_mech_init(void)
-{
- if (smb_md5_getmech(&smb_mech_md5) != 0)
- cmn_err(CE_NOTE, "nsmb can't get md5 mech");
-}
-
/*
* This is called just after session setup completes,
* at the top of smb_iod_vc_work(). Initialize signing.
@@ -76,10 +66,17 @@ smb_crypto_mech_init(void)
int
smb_sign_init(smb_vc_t *vcp)
{
+ int rc;
ASSERT(vcp->vc_ssnkey != NULL);
ASSERT(vcp->vc_mackey == NULL);
+ rc = smb_md5_getmech(&vcp->vc_signmech);
+ if (rc != 0) {
+ cmn_err(CE_NOTE, "smb can't get signing mechanism");
+ return (EAUTH);
+ }
+
/*
* Convert the session key to the MAC key.
* SMB1 uses the whole session key.
@@ -134,11 +131,10 @@ smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
} s;
} smbhdr;
- /* Later: check vcp->sign_mech == NULL */
if (vcp->vc_mackey == NULL)
return (-1);
- if ((rc = smb_md5_init(&ctx, &smb_mech_md5)) != 0)
+ if ((rc = smb_md5_init(&ctx, &vcp->vc_signmech)) != 0)
return (rc);
/* Digest the MAC Key */
@@ -146,6 +142,7 @@ smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
if (rc != 0)
return (rc);
+ /* Our caller should ensure mp has a contiguous header */
ASSERT(m != NULL);
ASSERT(MBLKL(m) >= SMB_HDRLEN);
@@ -154,8 +151,6 @@ smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
* fill in the sequence number, and digest.
*/
size = SMB_HDRLEN;
- if (MBLKL(m) < size)
- (void) pullupmsg(m, size);
bcopy(m->b_rptr, smbhdr.r.raw, size);
smbhdr.s.sig[0] = htolel(seqno);
smbhdr.s.sig[1] = 0;
@@ -192,7 +187,7 @@ smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
* Finally, store the signature.
* (first 8 bytes of the mac)
*/
- if (signature)
+ if (signature != NULL)
bcopy(digest, signature, SMBSIGLEN);
return (0);
@@ -210,13 +205,10 @@ smb_rq_sign(struct smb_rq *rqp)
int status;
/*
- * Our mblk allocation ensures this,
- * but just in case...
+ * smb_rq_new() ensures this,
+ * but just in case..
*/
- if (MBLKL(mp) < SMB_HDRLEN) {
- if (!pullupmsg(mp, SMB_HDRLEN))
- return;
- }
+ ASSERT(MBLKL(mp) >= SMB_HDRLEN);
sigloc = mp->b_rptr + SMBSIGOFF;
if (vcp->vc_mackey == NULL) {
@@ -269,10 +261,8 @@ smb_rq_verify(struct smb_rq *rqp)
SMBSDEBUG("empty reply\n");
return (0);
}
- if (MBLKL(mp) < SMB_HDRLEN) {
- if (!pullupmsg(mp, SMB_HDRLEN))
- return (0);
- }
+
+ ASSERT(MBLKL(mp) >= SMB_HDRLEN);
sigloc = mp->b_rptr + SMBSIGOFF;
/*
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
index 47f9a201cc..566f131316 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
@@ -63,32 +63,18 @@
#define STYPE_LEN 8 /* share type strings */
-/*
- * Largest size to use with LARGE_READ/LARGE_WRITE.
- * Specs say up to 64k data bytes, but Windows traffic
- * uses 60k... no doubt for some good reason.
- * (Probably to keep 4k block alignment.)
- * XXX: Move to smb.h maybe?
- */
-#define SMB_MAX_LARGE_RW_SIZE (60*1024)
-
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_COREPLUS, "MICROSOFT NETWORKS 1.03"},
- {SMB_DIALECT_LANMAN1_0, "MICROSOFT NETWORKS 3.0"},
- {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"},
- {SMB_DIALECT_LANMAN2_0, "LM1.2X002"},
- {SMB_DIALECT_LANMAN2_1, "LANMAN2.1"},
+static struct smb_dialect smb_dialects[3] = {
{SMB_DIALECT_NTLM0_12, "NT LANMAN 1.0"},
{SMB_DIALECT_NTLM0_12, "NT LM 0.12"},
+#define NDIALECT_SMB1 2
+ {SMB_DIALECT_SMB2_FF, "SMB 2.???"},
+#define NDIALECT_SMB2 3
};
-static uint_t smb_ndialect =
- sizeof (smb_dialects) / sizeof (smb_dialects[0]);
static const uint32_t smb_clnt_caps_mask =
SMB_CAP_UNICODE |
@@ -109,16 +95,6 @@ int smb_timo_read = 45;
int smb_timo_write = 60; /* was SMBWRTTIMO */
int smb_timo_append = 90;
-static int smb_smb_read(struct smb_share *ssp, uint16_t fid,
- uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
-static int smb_smb_write(struct smb_share *ssp, uint16_t fid,
- uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
-
-static int smb_smb_readx(struct smb_share *ssp, uint16_t fid,
- uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
-static int smb_smb_writex(struct smb_share *ssp, uint16_t fid,
- uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
-
int
smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
{
@@ -131,6 +107,7 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
int err, sblen, tlen;
uint8_t wc, eklen;
uint16_t dindex, bc;
+ uint16_t ndialects;
boolean_t will_sign = B_FALSE;
/*
@@ -168,6 +145,14 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
sv->sv_maxvcs = 1;
sv->sv_maxtx = 1024;
+ /*
+ * Should we offer the magic SMB2 dialect?
+ */
+ if (vcp->vc_ssn.ssn_maxver >= SMB2_DIALECT_BASE)
+ ndialects = NDIALECT_SMB2;
+ else
+ ndialects = NDIALECT_SMB1;
+
err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp);
if (err)
return (err);
@@ -179,7 +164,7 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
smb_rq_wstart(rqp);
smb_rq_wend(rqp);
smb_rq_bstart(rqp);
- for (dindex = 0; dindex < smb_ndialect; dindex++) {
+ for (dindex = 0; dindex < ndialects; dindex++) {
dp = &smb_dialects[dindex];
mb_put_uint8(mbp, SMB_DT_DIALECT);
tlen = strlen(dp->d_name) + 1;
@@ -191,10 +176,25 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
* Do the OTW call.
*/
err = smb_rq_internal(rqp, smb_timo_default);
+ /*
+ * If it's an SMB1-to-SMB2 negotiate response,
+ * call the special handler and then skip the
+ * whole rest of this function.
+ */
+ if (err == EPROTO) {
+ err = smb2_parse_smb1nego_resp(rqp);
+ smb_rq_done(rqp);
+ return (err);
+ }
if (err) {
SMBSDEBUG("smb_rq_internal, err %d", err);
goto errout;
}
+ /* Should only get status success. */
+ if (rqp->sr_error != NT_STATUS_SUCCESS) {
+ err = ENOTSUP;
+ goto errout;
+ }
/*
* Decode the response
@@ -208,7 +208,7 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
err = md_get_uint16le(mdp, &dindex);
if (err != 0)
goto errout;
- if (dindex >= smb_ndialect) {
+ if (dindex >= ndialects) {
SMBERROR("Invalid dialect index from server: %s\n",
vcp->vc_srvname);
err = EBADRPC;
@@ -299,7 +299,7 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
SMBSDEBUG("Security signatures: %d", (int)will_sign);
if (will_sign) {
- vcp->vc_flags |= SMBV_WILL_SIGN;
+ vcp->vc_flags |= SMBV_SIGNING;
vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
/*
@@ -322,6 +322,15 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
}
/*
+ * Warn if they don't support SMB_CAP_NT_SMBS
+ * (We'll try to use NtCreate anyway)
+ */
+ if ((sv->sv_caps & SMB_CAP_NT_SMBS) == 0) {
+ cmn_err(CE_NOTE, "%s does not support SMB_CAP_NT_SMBS",
+ vcp->vc_srvname);
+ }
+
+ /*
* The rest of the message varies depending on
* whether we've negotiated "extended security".
*
@@ -495,13 +504,21 @@ smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
/*
* Run the request. The return value here should be the
* return from this function, unless we fail decoding.
- * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK.
+ * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and
+ * the caller expects EINPROGRESS for that case.
*/
ret = smb_rq_internal(rqp, smb_timo_logon);
- if (ret != 0 && rqp->sr_error !=
- NT_STATUS_MORE_PROCESSING_REQUIRED) {
- /* UID no longer valid. */
- vcp->vc_smbuid = 0;
+ if (ret != 0)
+ goto out;
+ switch (rqp->sr_error) {
+ case NT_STATUS_SUCCESS:
+ break;
+ case NT_STATUS_MORE_PROCESSING_REQUIRED:
+ /* Keep going, but return... */
+ ret = EINPROGRESS;
+ break;
+ default:
+ ret = EAUTH;
goto out;
}
@@ -550,12 +567,49 @@ smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
*/
out:
+ if (err != 0 && err != EINPROGRESS) {
+ /* UID no longer valid. */
+ vcp->vc_smbuid = 0;
+ }
if (rqp)
smb_rq_done(rqp);
return (ret);
}
+int
+smb_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
+ return (0);
+
+ error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
+ if (error)
+ return (error);
+ mbp = &rqp->sr_rq;
+ smb_rq_wstart(rqp);
+ mb_put_uint8(mbp, 0xff);
+ mb_put_uint8(mbp, 0);
+ mb_put_uint16le(mbp, 0);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ smb_rq_bend(rqp);
+
+ /*
+ * Run this with a relatively short timeout. (5 sec.)
+ * We don't really care about the result here.
+ * Also, don't reconnect for this, of course!
+ */
+ rqp->sr_flags |= SMBR_NORECONNECT;
+ error = smb_rq_internal(rqp, 5);
+ smb_rq_done(rqp);
+ return (error);
+}
+
/*
* Get the string representation of a share "use" type,
* as needed for the "service" in tree connect.
@@ -817,7 +871,7 @@ smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
* Modern create/open of file or directory.
*/
int
-smb_smb_ntcreate(
+smb1_smb_ntcreate(
struct smb_share *ssp,
struct mbchain *name_mb,
uint32_t cr_flags, /* create flags */
@@ -940,7 +994,7 @@ done:
}
int
-smb_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
+smb1_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
struct smb_cred *scrp)
{
struct smb_rq rq, *rqp = &rq;
@@ -1065,101 +1119,11 @@ smb_smb_close_prjob(struct smb_share *ssp, uint16_t fid,
return (error);
}
-/*
- * Common function for read/write with UIO.
- * Called by netsmb smb_usr_rw,
- * smbfs_readvnode, smbfs_writevnode
- */
int
-smb_rwuio(struct smb_share *ssp, uint16_t fid, uio_rw_t rw,
- uio_t *uiop, smb_cred_t *scred, int timo)
-{
- struct smb_vc *vcp = SSTOVC(ssp);
- ssize_t save_resid;
- uint32_t len, rlen, maxlen;
- int error = 0;
- int (*iofun)(struct smb_share *, uint16_t, uint32_t *,
- uio_t *, smb_cred_t *, int);
-
- /*
- * Determine which function to use,
- * and the transfer size per call.
- */
- if (SMB_DIALECT(vcp) >= SMB_DIALECT_NTLM0_12) {
- /*
- * Using NT LM 0.12, so readx, writex.
- * Make sure we can represent the offset.
- */
- if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 &&
- (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
- return (EFBIG);
-
- if (rw == UIO_READ) {
- iofun = smb_smb_readx;
- if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
- maxlen = SMB_MAX_LARGE_RW_SIZE;
- else
- maxlen = vcp->vc_rxmax;
- } else { /* UIO_WRITE */
- iofun = smb_smb_writex;
- if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
- maxlen = SMB_MAX_LARGE_RW_SIZE;
- else
- maxlen = vcp->vc_wxmax;
- }
- } else {
- /*
- * Using the old SMB_READ and SMB_WRITE so
- * we're limited to 32-bit offsets, etc.
- * XXX: Someday, punt the old dialects.
- */
- if ((uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
- return (EFBIG);
-
- if (rw == UIO_READ) {
- iofun = smb_smb_read;
- maxlen = vcp->vc_rxmax;
- } else { /* UIO_WRITE */
- iofun = smb_smb_write;
- maxlen = vcp->vc_wxmax;
- }
- }
-
- save_resid = uiop->uio_resid;
- while (uiop->uio_resid > 0) {
- /* Lint: uio_resid may be 64-bits */
- rlen = len = (uint32_t)min(maxlen, uiop->uio_resid);
- error = (*iofun)(ssp, fid, &rlen, uiop, scred, timo);
-
- /*
- * Note: the iofun called uio_update, so
- * not doing that here as one might expect.
- *
- * Quit the loop either on error, or if we
- * transferred less then requested.
- */
- if (error || (rlen < len))
- break;
-
- timo = 0; /* only first I/O should wait */
- }
- if (error && (save_resid != uiop->uio_resid)) {
- /*
- * Stopped on an error after having
- * successfully transferred data.
- * Suppress this error.
- */
- SMBSDEBUG("error %d suppressed\n", error);
- error = 0;
- }
-
- return (error);
-}
-
-static int
-smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
+smb_smb_readx(smb_fh_t *fhp, uint32_t *lenp,
uio_t *uiop, smb_cred_t *scred, int timo)
{
+ struct smb_share *ssp = FHTOSS(fhp);
struct smb_rq *rqp;
struct mbchain *mbp;
struct mdchain *mdp;
@@ -1181,7 +1145,7 @@ smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
mb_put_uint8(mbp, 0xff); /* no secondary command */
mb_put_uint8(mbp, 0); /* MBZ */
mb_put_uint16le(mbp, 0); /* offset to secondary */
- mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, fhp->fh_fid1);
mb_put_uint32le(mbp, offlo); /* offset (low part) */
mb_put_uint16le(mbp, lenlo); /* MaxCount */
mb_put_uint16le(mbp, 1); /* MinCount */
@@ -1251,10 +1215,11 @@ out:
return (error);
}
-static int
-smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
+int
+smb_smb_writex(smb_fh_t *fhp, uint32_t *lenp,
uio_t *uiop, smb_cred_t *scred, int timo)
{
+ struct smb_share *ssp = FHTOSS(fhp);
struct smb_rq *rqp;
struct mbchain *mbp;
struct mdchain *mdp;
@@ -1276,7 +1241,7 @@ smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
mb_put_uint8(mbp, 0xff); /* no secondary command */
mb_put_uint8(mbp, 0); /* MBZ */
mb_put_uint16le(mbp, 0); /* offset to secondary */
- mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, fhp->fh_fid1);
mb_put_uint32le(mbp, offlo); /* offset (low part) */
mb_put_uint32le(mbp, 0); /* MBZ (timeout) */
mb_put_uint16le(mbp, 0); /* !write-thru */
@@ -1324,148 +1289,13 @@ out:
return (error);
}
-static int
-smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
- uio_t *uiop, smb_cred_t *scred, int timo)
-{
- struct smb_rq *rqp;
- struct mbchain *mbp;
- struct mdchain *mdp;
- int error;
- uint32_t off32;
- uint16_t bc, cnt, dlen, rcnt, todo;
- uint8_t wc;
-
- ASSERT(uiop->uio_loffset <= UINT32_MAX);
- off32 = (uint32_t)uiop->uio_loffset;
- ASSERT(*lenp <= UINT16_MAX);
- cnt = (uint16_t)*lenp;
- /* This next is an "estimate" of planned reads. */
- todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX);
-
- error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, cnt);
- mb_put_uint32le(mbp, off32);
- mb_put_uint16le(mbp, todo);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
-
- if (timo == 0)
- timo = smb_timo_read;
- error = smb_rq_simple_timed(rqp, timo);
- if (error)
- goto out;
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto out;
- if (wc != 5) {
- error = EBADRPC;
- goto out;
- }
- md_get_uint16le(mdp, &rcnt); /* ret. count */
- md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); /* res. */
- md_get_uint16le(mdp, &bc); /* byte count */
- md_get_uint8(mdp, NULL); /* buffer format */
- error = md_get_uint16le(mdp, &dlen); /* data len */
- if (error)
- goto out;
- if (dlen < rcnt) {
- SMBSDEBUG("oops: dlen=%d rcnt=%d\n",
- (int)dlen, (int)rcnt);
- rcnt = dlen;
- }
- if (rcnt == 0) {
- *lenp = 0;
- goto out;
- }
- /* paranoid */
- if (rcnt > cnt) {
- SMBSDEBUG("bad server! rcnt %d, cnt %d\n",
- (int)rcnt, (int)cnt);
- rcnt = cnt;
- }
- error = md_get_uio(mdp, uiop, (int)rcnt);
- if (error)
- goto out;
-
- /* success */
- *lenp = (int)rcnt;
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-static int
-smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
- uio_t *uiop, smb_cred_t *scred, int timo)
-{
- struct smb_rq *rqp;
- struct mbchain *mbp;
- struct mdchain *mdp;
- int error;
- uint32_t off32;
- uint16_t cnt, rcnt, todo;
- uint8_t wc;
-
- ASSERT(uiop->uio_loffset <= UINT32_MAX);
- off32 = (uint32_t)uiop->uio_loffset;
- ASSERT(*lenp <= UINT16_MAX);
- cnt = (uint16_t)*lenp;
- /* This next is an "estimate" of planned writes. */
- todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX);
-
- error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, cnt);
- mb_put_uint32le(mbp, off32);
- mb_put_uint16le(mbp, todo);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_DATA);
- mb_put_uint16le(mbp, cnt);
-
- error = mb_put_uio(mbp, uiop, *lenp);
- if (error)
- goto out;
- smb_rq_bend(rqp);
- if (timo == 0)
- timo = smb_timo_write;
- error = smb_rq_simple_timed(rqp, timo);
- if (error)
- goto out;
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto out;
- if (wc != 1) {
- error = EBADRPC;
- goto out;
- }
- error = md_get_uint16le(mdp, &rcnt);
- if (error)
- goto out;
- *lenp = rcnt;
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
static u_int32_t smbechoes = 0;
+/*
+ * Note: the IOD calls this, so this request must not wait for
+ * connection state changes, etc. (uses smb_rq_internal)
+ */
int
smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
{
@@ -1483,13 +1313,8 @@ smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
smb_rq_bstart(rqp);
mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes));
smb_rq_bend(rqp);
- /*
- * Note: the IOD calls this, so
- * this request must not wait for
- * connection state changes, etc.
- */
rqp->sr_flags |= SMBR_NORECONNECT;
- error = smb_rq_simple_timed(rqp, timo);
+ error = smb_rq_internal(rqp, timo);
SMBSDEBUG("%d\n", error);
smb_rq_done(rqp);
return (error);
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
index 48815ff709..b780f9b21b 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
@@ -43,8 +43,16 @@
#include <sys/cmn_err.h>
#include <sys/lock.h>
#include <sys/note.h>
+#include <netsmb/mchain.h>
#include <netsmb/smb_conn.h>
+/*
+ * Possible lock commands
+ */
+#define SMB_LOCK_EXCL 0
+#define SMB_LOCK_SHARED 1
+#define SMB_LOCK_RELEASE 2
+
struct msgb; /* avoiding sys/stream.h here */
/* Helper function for SMBERROR */
@@ -120,29 +128,42 @@ extern int smb_timo_append;
extern dev_t nsmb_dev_tcp;
extern dev_t nsmb_dev_tcp6;
-#define EMOREDATA (0x7fff)
+/*
+ * Tunable timeout values. See: smb2_smb.c
+ */
+extern int smb2_timo_notice;
+extern int smb2_timo_default;
+extern int smb2_timo_open;
+extern int smb2_timo_read;
+extern int smb2_timo_write;
+extern int smb2_timo_append;
void smb_credinit(struct smb_cred *scred, cred_t *cr);
void smb_credrele(struct smb_cred *scred);
-void smb_oldlm_hash(const char *apwd, uchar_t *hash);
-void smb_ntlmv1hash(const char *apwd, uchar_t *hash);
-void smb_ntlmv2hash(const uchar_t *v1hash, const char *user,
- const char *destination, uchar_t *v2hash);
-
-int smb_lmresponse(const uchar_t *hash, const uchar_t *C8, uchar_t *RN);
-int smb_ntlmv2response(const uchar_t *hash, const uchar_t *C8,
- const uchar_t *blob, size_t bloblen, uchar_t **RN, size_t *RNlen);
int smb_maperror(int eclass, int eno);
int smb_maperr32(uint32_t eno);
uint_t smb_doserr2status(int, int);
+int smb_get_dstring(struct mdchain *mdc, struct smb_vc *vcp,
+ char *outbuf, size_t *outlen, int inlen);
int smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp,
const char *src, int len, int caseopt, int *lenp);
int smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp,
const char *src, int caseopt);
int smb_put_string(struct smb_rq *rqp, const char *src);
int smb_put_asunistring(struct smb_rq *rqp, const char *src);
-int smb_checksmp(void);
+
+int smb_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
+ uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc,
+ uint32_t disp, uint32_t createopt, uint32_t impersonate,
+ struct smb_cred *scrp, smb_fh_t *fhp,
+ uint32_t *cr_act_p, struct smbfattr *fap);
+
+int smb_smb_close(struct smb_share *ssp, smb_fh_t *fhp,
+ struct smb_cred *scrp);
+
+int smb_rwuio(smb_fh_t *fhp, uio_rw_t rw,
+ uio_t *uiop, smb_cred_t *scred, int timo);
int smb_cmp_sockaddr(struct sockaddr *, struct sockaddr *);
struct sockaddr *smb_dup_sockaddr(struct sockaddr *sa);
@@ -155,53 +176,80 @@ int smb_calcv2mackey(struct smb_vc *, const uchar_t *,
const uchar_t *, size_t);
int smb_calcmackey(struct smb_vc *, const uchar_t *,
const uchar_t *, size_t);
-void smb_crypto_mech_init(void);
+int smb2_sign_init(struct smb_vc *);
+void smb2_rq_sign(struct smb_rq *);
+int smb2_rq_verify(struct smb_rq *);
/*
* SMB protocol level functions
*/
int smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred);
int smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred);
+int smb_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred);
int smb_smb_echo(smb_vc_t *vcp, smb_cred_t *scred, int timo);
int smb_smb_treeconnect(smb_share_t *ssp, smb_cred_t *scred);
int smb_smb_treedisconnect(smb_share_t *ssp, smb_cred_t *scred);
-int
-smb_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
+int smb1_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc,
uint32_t disp, uint32_t createopt, uint32_t impersonate,
struct smb_cred *scrp, uint16_t *fidp,
uint32_t *cr_act_p, struct smbfattr *fap);
-int smb_smb_close(struct smb_share *ssp, uint16_t fid,
+int smb1_smb_close(struct smb_share *ssp, uint16_t fid,
struct timespec *mtime, struct smb_cred *scrp);
-int
-smb_smb_open_prjob(struct smb_share *ssp, char *title,
+int smb_smb_open_prjob(struct smb_share *ssp, char *title,
uint16_t setuplen, uint16_t mode,
struct smb_cred *scrp, uint16_t *fidp);
int smb_smb_close_prjob(struct smb_share *ssp, uint16_t fid,
struct smb_cred *scrp);
-int smb_rwuio(smb_share_t *ssp, uint16_t fid, uio_rw_t rw,
+int smb_smb_readx(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo);
+int smb_smb_writex(smb_fh_t *fhp, uint32_t *lenp,
uio_t *uiop, smb_cred_t *scred, int timo);
/*
- * time conversions
+ * SMB2 protocol level functions
*/
+int smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred);
+int smb2_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred);
+int smb2_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred);
+int smb2_smb_echo(smb_vc_t *vcp, smb_cred_t *scred, int timo);
+int smb2_smb_treeconnect(smb_share_t *ssp, smb_cred_t *scred);
+int smb2_smb_treedisconnect(smb_share_t *ssp, smb_cred_t *scred);
+
+int
+smb2_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
+ struct mbchain *cctx_in, struct mdchain *cctx_out,
+ uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc,
+ uint32_t disp, uint32_t createopt, uint32_t impersonate,
+ struct smb_cred *scrp, smb2fid_t *fidp,
+ uint32_t *cr_act_p, struct smbfattr *fap);
+
+int smb2_smb_close(struct smb_share *ssp, smb2fid_t *fid,
+ struct smb_cred *scrp);
+
+int smb2_smb_ioctl(struct smb_share *ssp, smb2fid_t *fid,
+ struct mbchain *data_in, struct mdchain *data_out,
+ uint32_t *data_out_sz, /* max / returned */
+ uint32_t ctl_code, struct smb_cred *scrp);
+
+int smb2_smb_read(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo);
+int smb2_smb_write(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo);
-void smb_time_init(void);
-void smb_time_fini(void);
+/*
+ * time conversions
+ */
void smb_time_local2server(struct timespec *tsp, int tzoff, long *seconds);
void smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp);
void smb_time_NT2local(uint64_t nsec, struct timespec *tsp);
void smb_time_local2NT(struct timespec *tsp, uint64_t *nsec);
-void smb_time_unix2dos(struct timespec *tsp, int tzoff, uint16_t *ddp,
- uint16_t *dtp, uint8_t *dhp);
-void smb_dos2unixtime(uint_t dd, uint_t dt, uint_t dh, int tzoff,
- struct timespec *tsp);
#endif /* !_NETSMB_SMB_SUBR_H_ */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
index dc0e824e5e..bf1e605187 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
@@ -86,6 +86,14 @@ smb_credrele(struct smb_cred *scred)
}
}
+#ifndef _KERNEL
+/* ARGSUSED */
+void
+smb_debugmsg(const char *func, char *msg)
+{
+}
+#endif /* _KERNEL */
+
/*
* Helper for the SMBERROR macro, etc.
* This is also a good place for a breakpoint
@@ -108,6 +116,9 @@ smb_errmsg(int cel, const char *func_name, const char *fmt, ...)
DTRACE_PROBE2(debugmsg2,
(char *), func_name,
(char *), buf);
+#ifndef _KERNEL
+ smb_debugmsg(func_name, buf);
+#endif
} else {
/*
* This is one of our xxxERROR macros.
@@ -161,6 +172,9 @@ m_dumpm(mblk_t *m)
#ifndef ETIME
#define ETIME ETIMEDOUT
#endif
+#ifndef EMOREDATA
+#define EMOREDATA (0x7fff)
+#endif
/*
* Log any un-handled NT or DOS errors we encounter.
@@ -597,14 +611,6 @@ static const nt2doserr_t nt2doserr[] = {
{ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION},
{ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE},
{ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR},
{ERRHRD, ERRgeneral, NT_STATUS_NO_LDT},
{ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE},
{ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET},
@@ -1013,13 +1019,90 @@ smb_maperror(int eclass, int eno)
return (EIO);
}
-#if defined(NOICONVSUPPORT) || defined(lint)
-extern int iconv_conv(void *handle, const char **inbuf,
- size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
-#endif
-
#define SMALL_CONV 256
+/*
+ * Decode an SMB OTW string (Unicode or OEM chars)
+ * converting to UTF-8 in the output buffer.
+ * outlen is in/out (max size on input)
+ * insize is the wire size (2 * chars if unicode)
+ * The output string is null terminated.
+ * Output length does not include the null.
+ */
+int
+smb_get_dstring(struct mdchain *mdc, struct smb_vc *vcp,
+ char *outbuf, size_t *outlen, int insize)
+{
+ uint16_t convbuf[SMALL_CONV];
+ uint16_t *cbuf;
+ size_t cbufalloc, inlen, outsize;
+ int error;
+
+ if (insize <= 0)
+ return (0);
+ /* Note: inlen is UTF-16 symbols. */
+ inlen = insize / 2;
+
+ if (*outlen < 2)
+ return (EINVAL);
+ outsize = *outlen - 1; /* room for null */
+
+ /*
+ * Get a buffer for the conversion and fill it.
+ * Use stack buffer if the string is
+ * small enough, else allocate.
+ */
+ if (insize < sizeof (convbuf)) {
+ cbufalloc = 0;
+ cbuf = convbuf;
+ } else {
+ cbufalloc = insize + 2;
+ cbuf = kmem_alloc(cbufalloc, KM_SLEEP);
+ }
+ error = md_get_mem(mdc, cbuf, insize, MB_MSYSTEM);
+ if (error != 0)
+ goto out;
+ cbuf[inlen] = 0;
+
+ /*
+ * Handle the easy case (non-unicode).
+ * XXX: Technically, we should convert
+ * the string to OEM codeset first...
+ * Modern servers all use Unicode, so
+ * this is good enough.
+ */
+ if (SMB_UNICODE_STRINGS(vcp) == 0) {
+ *outlen = strlcpy(outbuf, (char *)cbuf, outsize);
+ if (*outlen > outsize) {
+ *outlen = outsize;
+ error = E2BIG;
+ }
+ } else {
+ /*
+ * Convert from UTF-16 to UTF-8
+ */
+ error = uconv_u16tou8(cbuf, &inlen,
+ (uchar_t *)outbuf, outlen,
+ UCONV_IN_LITTLE_ENDIAN);
+ if (error == 0) {
+ outbuf[*outlen] = '\0';
+ }
+ }
+
+ ASSERT(*outlen == strlen(outbuf));
+
+out:
+ if (cbufalloc != 0)
+ kmem_free(cbuf, cbufalloc);
+
+ return (error);
+}
+
+/*
+ * It's surprising that this function does utf8-ucs2 conversion.
+ * One would expect only smb_put_dstring to do that.
+ * Fixing that will require changing a bunch of callers. XXX
+ */
/*ARGSUSED*/
int
smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
@@ -1097,3 +1180,130 @@ smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
return (error);
}
+int
+smb_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
+ uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc,
+ uint32_t disp, uint32_t createopt, uint32_t impersonate,
+ struct smb_cred *scrp, smb_fh_t *fhp,
+ uint32_t *cr_act_p, struct smbfattr *fap)
+{
+ int err;
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smb2_smb_ntcreate(ssp, name_mb, NULL, NULL,
+ crflag, req_acc, efa, sh_acc, disp, createopt,
+ impersonate, scrp, &fhp->fh_fid2, cr_act_p, fap);
+ } else {
+ err = smb1_smb_ntcreate(ssp, name_mb, crflag, req_acc,
+ efa, sh_acc, disp, createopt, impersonate, scrp,
+ &fhp->fh_fid1, cr_act_p, fap);
+ }
+ return (err);
+}
+
+int
+smb_smb_close(struct smb_share *ssp, smb_fh_t *fhp,
+ struct smb_cred *scrp)
+{
+ int err;
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smb2_smb_close(ssp, &fhp->fh_fid2, scrp);
+ } else {
+ err = smb1_smb_close(ssp, fhp->fh_fid1, NULL, scrp);
+ }
+
+ return (err);
+}
+
+/*
+ * Largest size to use with LARGE_READ/LARGE_WRITE.
+ * Specs say up to 64k data bytes, but Windows traffic
+ * uses 60k... no doubt for some good reason.
+ * (Probably to keep 4k block alignment.)
+ */
+uint32_t smb1_large_io_max = (60*1024);
+
+/*
+ * Common function for read/write with UIO.
+ * Called by netsmb smb_usr_rw,
+ * smbfs_readvnode, smbfs_writevnode
+ */
+int
+smb_rwuio(smb_fh_t *fhp, uio_rw_t rw,
+ uio_t *uiop, smb_cred_t *scred, int timo)
+{
+ struct smb_share *ssp = FHTOSS(fhp);
+ struct smb_vc *vcp = SSTOVC(ssp);
+ ssize_t save_resid;
+ uint32_t len, rlen, maxlen;
+ int error = 0;
+ int (*iofun)(smb_fh_t *, uint32_t *,
+ uio_t *, smb_cred_t *, int);
+
+ /* After reconnect, the fid is invalid. */
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ if (rw == UIO_READ) {
+ iofun = smb2_smb_read;
+ maxlen = vcp->vc_sopt.sv2_maxread;
+ } else { /* UIO_WRITE */
+ iofun = smb2_smb_write;
+ maxlen = vcp->vc_sopt.sv2_maxwrite;
+ }
+ } else {
+ /*
+ * Using NT LM 0.12, so readx, writex.
+ * Make sure we can represent the offset.
+ */
+ if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 &&
+ (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
+ return (EFBIG);
+
+ if (rw == UIO_READ) {
+ iofun = smb_smb_readx;
+ if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
+ maxlen = smb1_large_io_max;
+ else
+ maxlen = vcp->vc_rxmax;
+ } else { /* UIO_WRITE */
+ iofun = smb_smb_writex;
+ if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
+ maxlen = smb1_large_io_max;
+ else
+ maxlen = vcp->vc_wxmax;
+ }
+ }
+
+ save_resid = uiop->uio_resid;
+ while (uiop->uio_resid > 0) {
+ /* Lint: uio_resid may be 64-bits */
+ rlen = len = (uint32_t)min(maxlen, uiop->uio_resid);
+ error = (*iofun)(fhp, &rlen, uiop, scred, timo);
+
+ /*
+ * Note: the iofun called uio_update, so
+ * not doing that here as one might expect.
+ *
+ * Quit the loop either on error, or if we
+ * transferred less then requested.
+ */
+ if (error || (rlen < len))
+ break;
+
+ timo = 0; /* only first I/O should wait */
+ }
+ if (error && (save_resid != uiop->uio_resid)) {
+ /*
+ * Stopped on an error after having
+ * successfully transferred data.
+ * Suppress this error.
+ */
+ SMBSDEBUG("error %d suppressed\n", error);
+ error = 0;
+ }
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c
index e984ded911..0116d6ea6e 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c
@@ -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.
*/
/*
@@ -55,61 +57,6 @@
#include <netsmb/smb_subr.h>
/*
- * Time & date conversion routines taken from msdosfs. Although leap
- * year calculation is bogus, it's sufficient before 2100 :)
- */
-/*
- * This is the format of the contents of the deTime field in the direntry
- * structure.
- * We don't use bitfields because we don't know how compilers for
- * arbitrary machines will lay them out.
- */
-#define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */
-#define DT_2SECONDS_SHIFT 0
-#define DT_MINUTES_MASK 0x7E0 /* minutes */
-#define DT_MINUTES_SHIFT 5
-#define DT_HOURS_MASK 0xF800 /* hours */
-#define DT_HOURS_SHIFT 11
-
-/*
- * This is the format of the contents of the deDate field in the direntry
- * structure.
- */
-#define DD_DAY_MASK 0x1F /* day of month */
-#define DD_DAY_SHIFT 0
-#define DD_MONTH_MASK 0x1E0 /* month */
-#define DD_MONTH_SHIFT 5
-#define DD_YEAR_MASK 0xFE00 /* year - 1980 */
-#define DD_YEAR_SHIFT 9
-/*
- * Total number of days that have passed for each month in a regular year.
- */
-static ushort_t regyear[] = {
- 31, 59, 90, 120, 151, 181,
- 212, 243, 273, 304, 334, 365
-};
-
-/*
- * Total number of days that have passed for each month in a leap year.
- */
-static ushort_t leapyear[] = {
- 31, 60, 91, 121, 152, 182,
- 213, 244, 274, 305, 335, 366
-};
-
-/*
- * Variables used to remember parts of the last time conversion. Maybe we
- * can avoid a full conversion.
- */
-static ulong_t lasttime;
-static ulong_t lastday;
-static ushort_t lastddate;
-static ushort_t lastdtime;
-
-/* Lock for the lastxxx variables */
-static kmutex_t lastdt_lock;
-
-/*
* Number of seconds between 1970 and 1601 year
* (134774 days)
*/
@@ -193,161 +140,3 @@ smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp)
tsp->tv_sec = seconds + tzoff * 60;
tsp->tv_nsec = 0;
}
-
-/*
- * Time conversions to/from DOS format, for old dialects.
- */
-
-void
-smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp,
- u_int16_t *dtp, u_int8_t *dhp)
-{
- long t;
- ulong_t days, year, month, inc;
- ushort_t *months;
-
- mutex_enter(&lastdt_lock);
-
- /*
- * If the time from the last conversion is the same as now, then
- * skip the computations and use the saved result.
- */
- smb_time_local2server(tsp, tzoff, &t);
- t &= ~1;
- if (lasttime != t) {
- lasttime = t;
- if (t < 0) {
- /*
- * This is before 1970, so it's before 1980,
- * and can't be represented as a DOS time.
- * Just represent it as the DOS epoch.
- */
- lastdtime = 0;
- lastddate = (1 << DD_DAY_SHIFT)
- + (1 << DD_MONTH_SHIFT)
- + ((1980 - 1980) << DD_YEAR_SHIFT);
- } else {
- lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
- + (((t / 60) % 60) << DT_MINUTES_SHIFT)
- + (((t / 3600) % 24) << DT_HOURS_SHIFT);
-
- /*
- * If the number of days since 1970 is the same as
- * the last time we did the computation then skip
- * all this leap year and month stuff.
- */
- days = t / (24 * 60 * 60);
- if (days != lastday) {
- lastday = days;
- for (year = 1970; ; year++) {
- /*
- * XXX - works in 2000, but won't
- * work in 2100.
- */
- inc = year & 0x03 ? 365 : 366;
- if (days < inc)
- break;
- days -= inc;
- }
- /*
- * XXX - works in 2000, but won't work in 2100.
- */
- months = year & 0x03 ? regyear : leapyear;
- for (month = 0; days >= months[month]; month++)
- ;
- if (month > 0)
- days -= months[month - 1];
- lastddate = ((days + 1) << DD_DAY_SHIFT)
- + ((month + 1) << DD_MONTH_SHIFT);
- /*
- * Remember DOS's idea of time is relative
- * to 1980, but UN*X's is relative to 1970.
- * If somehow we get a time before 1980 then
- * don't give totally crazy results.
- */
- if (year > 1980)
- lastddate += (year - 1980) <<
- DD_YEAR_SHIFT;
- }
- }
- }
- if (dhp)
- *dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000;
-
- *ddp = lastddate;
- *dtp = lastdtime;
-
- mutex_exit(&lastdt_lock);
-}
-
-/*
- * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
- * interval there were 8 regular years and 2 leap years.
- */
-#define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
-
-static ushort_t lastdosdate;
-static ulong_t lastseconds;
-
-void
-smb_dos2unixtime(uint_t dd, uint_t dt, uint_t dh, int tzoff,
- struct timespec *tsp)
-{
- ulong_t seconds;
- ulong_t month;
- ulong_t year;
- ulong_t days;
- ushort_t *months;
-
- if (dd == 0) {
- tsp->tv_sec = 0;
- tsp->tv_nsec = 0;
- return;
- }
- seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1)
- + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
- + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
- + dh / 100;
-
- /*
- * If the year, month, and day from the last conversion are the
- * same then use the saved value.
- */
- mutex_enter(&lastdt_lock);
- if (lastdosdate != dd) {
- lastdosdate = (ushort_t)dd;
- days = 0;
- year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT;
- days = year * 365;
- days += year / 4 + 1; /* add in leap days */
- /*
- * XXX - works in 2000, but won't work in 2100.
- */
- if ((year & 0x03) == 0)
- days--; /* if year is a leap year */
- months = year & 0x03 ? regyear : leapyear;
- month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
- if (month < 1 || month > 12) {
- month = 1;
- }
- if (month > 1)
- days += months[month - 2];
- days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1;
- lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
- }
- smb_time_server2local(seconds + lastseconds, tzoff, tsp);
- tsp->tv_nsec = (dh % 100) * 10000000;
- mutex_exit(&lastdt_lock);
-}
-
-void
-smb_time_init(void)
-{
- mutex_init(&lastdt_lock, NULL, MUTEX_DEFAULT, NULL);
-}
-
-void
-smb_time_fini(void)
-{
- mutex_destroy(&lastdt_lock);
-}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
index dc44fcc755..1060139491 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
@@ -70,12 +70,12 @@ struct smb_tran_desc {
int (*tr_create)(struct smb_vc *vcp, cred_t *cr);
int (*tr_done)(struct smb_vc *vcp);
int (*tr_bind)(struct smb_vc *vcp, struct sockaddr *sap);
+ int (*tr_unbind)(struct smb_vc *vcp);
int (*tr_connect)(struct smb_vc *vcp, struct sockaddr *sap);
int (*tr_disconnect)(struct smb_vc *vcp);
int (*tr_send)(struct smb_vc *vcp, mblk_t *m);
int (*tr_recv)(struct smb_vc *vcp, mblk_t **mpp);
int (*tr_poll)(struct smb_vc *vcp, int ticks);
- int (*tr_loan_fp)(struct smb_vc *, struct file *, cred_t *cr);
int (*tr_getparam)(struct smb_vc *vcp, int param, void *data);
int (*tr_setparam)(struct smb_vc *vcp, int param, void *data);
int (*tr_fatal)(struct smb_vc *vcp, int error);
@@ -86,12 +86,12 @@ typedef struct smb_tran_desc smb_tran_desc_t;
#define SMB_TRAN_CREATE(vcp, cr) (vcp)->vc_tdesc->tr_create(vcp, cr)
#define SMB_TRAN_DONE(vcp) (vcp)->vc_tdesc->tr_done(vcp)
#define SMB_TRAN_BIND(vcp, sap) (vcp)->vc_tdesc->tr_bind(vcp, sap)
+#define SMB_TRAN_UNBIND(vcp) (vcp)->vc_tdesc->tr_unbind(vcp)
#define SMB_TRAN_CONNECT(vcp, sap) (vcp)->vc_tdesc->tr_connect(vcp, sap)
#define SMB_TRAN_DISCONNECT(vcp) (vcp)->vc_tdesc->tr_disconnect(vcp)
#define SMB_TRAN_SEND(vcp, m) (vcp)->vc_tdesc->tr_send(vcp, m)
#define SMB_TRAN_RECV(vcp, m) (vcp)->vc_tdesc->tr_recv(vcp, m)
#define SMB_TRAN_POLL(vcp, t) (vcp)->vc_tdesc->tr_poll(vcp, t)
-#define SMB_TRAN_LOAN_FP(vcp, f, cr) (vcp)->vc_tdesc->tr_loan_fp(vcp, f, cr)
#define SMB_TRAN_GETPARAM(vcp, par, data) \
(vcp)->vc_tdesc->tr_getparam(vcp, par, data)
#define SMB_TRAN_SETPARAM(vcp, par, data) \
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
index 733ff9d078..849e91637e 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
@@ -558,110 +558,30 @@ smb_nbst_done(struct smb_vc *vcp)
return (0);
}
-/*
- * XXX - Later, get rid of nb_loan_fp, nb_unloan_fp
- *
- * Loan a transport file pointer (from user space) to this
- * IOD endpoint. There should be no other thread using this
- * endpoint when we do this, but lock for consistency.
- */
-static int
-nb_loan_fp(struct nbpcb *nbp, struct file *fp, cred_t *cr)
-{
- TIUSER *tiptr;
- int err;
-
- err = t_kopen(fp, 0, 0, &tiptr, cr);
- if (err != 0)
- return (err);
-
- mutex_enter(&nbp->nbp_lock);
-
- nbp->nbp_tiptr = tiptr;
- nbp->nbp_fmode = tiptr->fp->f_flag;
- nbp->nbp_flags |= NBF_CONNECTED;
- nbp->nbp_state = NBST_SESSION;
-
- mutex_exit(&nbp->nbp_lock);
-
- return (0);
-}
-
-/*
- * Take back the transport file pointer we previously loaned.
- * It's possible there may be another thread in here, so let
- * others get out of the way before we pull the rug out.
- *
- * Some notes about the locking here: The higher-level IOD code
- * serializes activity such that at most one reader and writer
- * thread can be active in this code (and possibly both).
- * Keeping nbp_lock held during the activities of these two
- * threads would lead to the possibility of nbp_lock being
- * held by a blocked thread, so this instead sets one of the
- * flags (NBF_SENDLOCK | NBF_RECVLOCK) when a sender or a
- * receiver is active (respectively). Lastly, tear-down is
- * the only tricky bit (here) where we must wait for any of
- * these activities to get out of current calls so they will
- * notice that we've turned off the NBF_CONNECTED flag.
- */
-static void
-nb_unloan_fp(struct nbpcb *nbp)
-{
-
- mutex_enter(&nbp->nbp_lock);
-
- nbp->nbp_flags &= ~NBF_CONNECTED;
- while (nbp->nbp_flags & (NBF_SENDLOCK | NBF_RECVLOCK)) {
- nbp->nbp_flags |= NBF_LOCKWAIT;
- cv_wait(&nbp->nbp_cv, &nbp->nbp_lock);
- }
- if (nbp->nbp_frag != NULL) {
- freemsg(nbp->nbp_frag);
- nbp->nbp_frag = NULL;
- }
- if (nbp->nbp_tiptr != NULL) {
- (void) t_kclose(nbp->nbp_tiptr, 0);
- nbp->nbp_tiptr = NULL;
- }
- nbp->nbp_state = NBST_CLOSED;
-
- mutex_exit(&nbp->nbp_lock);
-}
-
static int
-smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr)
+smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
{
struct nbpcb *nbp = vcp->vc_tdata;
- int error = 0;
+ TIUSER *tiptr = nbp->nbp_tiptr;
+ int err;
- /*
- * Un-loan the existing one, if any.
- */
- (void) nb_disconnect(nbp);
- nb_unloan_fp(nbp);
+ /* Only default bind supported. */
+ if (sap != NULL)
+ return (ENOTSUP);
- /*
- * Loan the new one passed in.
- */
- if (fp != NULL) {
- error = nb_loan_fp(nbp, fp, cr);
- }
+ err = t_kbind(tiptr, NULL, NULL);
- return (error);
+ return (err);
}
static int
-smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
+smb_nbst_unbind(struct smb_vc *vcp)
{
struct nbpcb *nbp = vcp->vc_tdata;
TIUSER *tiptr = nbp->nbp_tiptr;
int err;
- /* Only default bind supported. */
- if (sap != NULL)
- return (ENOTSUP);
-
- err = t_kbind(tiptr, NULL, NULL);
+ err = t_kunbind(tiptr);
return (err);
}
@@ -956,7 +876,7 @@ smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
return (EPROTO);
}
- if (ores.flags != T_SUCCESS) {
+ if ((ores.flags & T_SUCCESS) == 0) {
cmn_err(CE_NOTE, "smb_nbst_setparam: "
"flags 0x%x, status 0x%x",
(int)ores.flags, (int)opts.oh.status);
@@ -989,12 +909,12 @@ struct smb_tran_desc smb_tran_nbtcp_desc = {
smb_nbst_create,
smb_nbst_done,
smb_nbst_bind,
+ smb_nbst_unbind,
smb_nbst_connect,
smb_nbst_disconnect,
smb_nbst_send,
smb_nbst_recv,
smb_nbst_poll,
- smb_nbst_loan_fp,
smb_nbst_getparam,
smb_nbst_setparam,
smb_nbst_fatal,
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
index 5209732a1e..d83c3a086c 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
@@ -53,6 +53,7 @@
#include <netsmb/smb_osdep.h>
+#include <smb/winioctl.h>
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_rq.h>
@@ -102,96 +103,83 @@ smb_usr_xnp(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
{
struct smb_cred scred;
struct smb_share *ssp;
+ struct smb_fh *fhp;
smbioc_xnp_t *ioc = NULL;
- struct smb_t2rq *t2p = NULL;
- struct mdchain *mdp;
- int err, len, mbseg;
- uint16_t setup[2];
+ struct mbchain send_mb;
+ struct mdchain recv_md;
+ uint32_t rdlen;
+ int err, mbseg;
- /* This ioctl requires a share. */
- if ((ssp = sdp->sd_share) == NULL)
- return (ENOTCONN);
+ /* This ioctl requires a file handle. */
+ if ((fhp = sdp->sd_fh) == NULL)
+ return (EINVAL);
+ ssp = FHTOSS(fhp);
+
+ /* After reconnect, force close+reopen */
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
+ bzero(&send_mb, sizeof (send_mb));
+ bzero(&recv_md, sizeof (recv_md));
- smb_credinit(&scred, cr);
ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
err = EFAULT;
goto out;
}
- /* See ddi_copyin, ddi_copyout */
- mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
-
/*
- * Fill in the FID for libsmbfs transact named pipe.
+ * Copyin the send data, into an mbchain,
+ * save output buffer size.
*/
- if (ioc->ioc_fh == -1) {
- if (sdp->sd_vcgenid != ssp->ss_vcgenid) {
- err = ESTALE;
- goto out;
- }
- ioc->ioc_fh = sdp->sd_smbfid;
- }
-
- setup[0] = TRANS_TRANSACT_NAMED_PIPE;
- setup[1] = (uint16_t)ioc->ioc_fh;
-
- t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
- err = smb_t2_init(t2p, SSTOCP(ssp), setup, 2, &scred);
- if (err)
- goto out;
- t2p->t2_setupcount = 2;
- t2p->t2_setupdata = setup;
-
- t2p->t_name = "\\PIPE\\";
- t2p->t_name_len = 6;
-
- t2p->t2_maxscount = 0;
- t2p->t2_maxpcount = 0;
- t2p->t2_maxdcount = ioc->ioc_rdlen;
-
- /* Transmit parameters (none) */
-
- /* Transmit data */
- err = smb_cpdatain(&t2p->t2_tdata,
- ioc->ioc_tdlen, ioc->ioc_tdata, mbseg);
+ mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
+ err = smb_cpdatain(&send_mb, ioc->ioc_tdlen, ioc->ioc_tdata, mbseg);
if (err)
goto out;
+ rdlen = ioc->ioc_rdlen;
- err = smb_t2_request(t2p);
-
- /* No returned parameters. */
+ /*
+ * Run the SMB2 ioctl or SMB1 trans2
+ */
+ smb_credinit(&scred, cr);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smb2_smb_ioctl(ssp, &fhp->fh_fid2,
+ &send_mb, &recv_md, &rdlen,
+ FSCTL_PIPE_TRANSCEIVE, &scred);
+ } else {
+ err = smb_t2_xnp(ssp, fhp->fh_fid1,
+ &send_mb, &recv_md, &rdlen,
+ &ioc->ioc_more, &scred);
+ }
+ smb_credrele(&scred);
/* Copyout returned data. */
- mdp = &t2p->t2_rdata;
- if (err == 0 && mdp->md_top != NULL) {
- /* User's buffer large enough? */
- len = m_fixhdr(mdp->md_top);
+ if (err == 0 && recv_md.md_top != NULL) {
+ /* User's buffer large enough for copyout? */
+ size_t len = m_fixhdr(recv_md.md_top);
if (len > ioc->ioc_rdlen) {
err = EMSGSIZE;
goto out;
}
- ioc->ioc_rdlen = (ushort_t)len;
- err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg);
+ err = md_get_mem(&recv_md, ioc->ioc_rdata, len, mbseg);
if (err)
goto out;
} else
ioc->ioc_rdlen = 0;
- if (t2p->t2_sr_error == NT_STATUS_BUFFER_OVERFLOW)
+ /* Tell caller received length */
+ if (rdlen <= ioc->ioc_rdlen) {
+ /* Normal case */
+ ioc->ioc_rdlen = rdlen;
+ } else {
+ /* Buffer overlow. Leave ioc_rdlen */
ioc->ioc_more = 1;
+ }
(void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
-
out:
- if (t2p != NULL) {
- /* Note: t2p->t_name no longer allocated */
- smb_t2_done(t2p);
- kmem_free(t2p, sizeof (*t2p));
- }
kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
return (err);
}
@@ -219,22 +207,22 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
{
struct smb_cred scred;
struct smb_share *ssp;
+ struct smb_fh *fhp;
smbioc_rw_t *ioc = NULL;
struct iovec aiov[1];
struct uio auio;
- uint16_t fh;
int err;
uio_rw_t rw;
- /* This ioctl requires a share. */
- if ((ssp = sdp->sd_share) == NULL)
- return (ENOTCONN);
+ /* This ioctl requires a file handle. */
+ if ((fhp = sdp->sd_fh) == NULL)
+ return (EINVAL);
+ ssp = FHTOSS(fhp);
/* After reconnect, force close+reopen */
- if (sdp->sd_vcgenid != ssp->ss_vcgenid)
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
return (ESTALE);
- smb_credinit(&scred, cr);
ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
err = EFAULT;
@@ -253,15 +241,6 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
goto out;
}
- /*
- * If caller passes -1 in ioc_fh, then
- * use the FID from SMBIOC_NTCREATE.
- */
- if (ioc->ioc_fh == -1)
- fh = (uint16_t)sdp->sd_smbfid;
- else
- fh = (uint16_t)ioc->ioc_fh;
-
aiov[0].iov_base = ioc->ioc_base;
aiov[0].iov_len = (size_t)ioc->ioc_cnt;
@@ -273,7 +252,9 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
auio.uio_fmode = 0;
auio.uio_resid = (size_t)ioc->ioc_cnt;
- err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0);
+ smb_credinit(&scred, cr);
+ err = smb_rwuio(fhp, rw, &auio, &scred, 0);
+ smb_credrele(&scred);
/*
* On return ioc_cnt holds the
@@ -285,7 +266,6 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
out:
kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
return (err);
}
@@ -300,20 +280,20 @@ smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
struct smb_cred scred;
struct mbchain name_mb;
struct smb_share *ssp;
+ struct smb_fh *fhp = NULL;
smbioc_ntcreate_t *ioc = NULL;
- uint16_t fid;
int err, nmlen;
+ mb_init(&name_mb);
+
/* This ioctl requires a share. */
if ((ssp = sdp->sd_share) == NULL)
return (ENOTCONN);
- /* Must not be already open. */
- if (sdp->sd_smbfid != -1)
+ /* Must not already have a file handle. */
+ if (sdp->sd_fh != NULL)
return (EINVAL);
- mb_init(&name_mb);
- smb_credinit(&scred, cr);
ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
err = EFAULT;
@@ -329,7 +309,14 @@ smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
if (err != 0)
goto out;
- /* Do the OtW open, save the FID. */
+ err = smb_fh_create(ssp, &fhp);
+ if (err != 0)
+ goto out;
+
+ /*
+ * Do the OtW open, save the FID.
+ */
+ smb_credinit(&scred, cr);
err = smb_smb_ntcreate(ssp, &name_mb,
0, /* create flags */
ioc->ioc_req_acc,
@@ -339,18 +326,22 @@ smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
ioc->ioc_creat_opts,
NTCREATEX_IMPERSONATION_IMPERSONATION,
&scred,
- &fid,
+ fhp,
NULL,
NULL);
+ smb_credrele(&scred);
if (err != 0)
goto out;
- sdp->sd_smbfid = fid;
- sdp->sd_vcgenid = ssp->ss_vcgenid;
+ fhp->fh_rights = ioc->ioc_req_acc;
+ smb_fh_opened(fhp);
+ sdp->sd_fh = fhp;
+ fhp = NULL;
out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
mb_done(&name_mb);
return (err);
@@ -363,11 +354,17 @@ out:
int
smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
{
+ static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS;
struct smb_cred scred;
+ struct mbchain name_mb;
struct smb_share *ssp;
+ struct smb_fh *fhp = NULL;
smbioc_printjob_t *ioc = NULL;
- uint16_t fid;
- int err;
+ int err, cklen, nmlen;
+ uint32_t access = SA_RIGHT_FILE_WRITE_DATA |
+ SA_RIGHT_FILE_READ_ATTRIBUTES;
+
+ mb_init(&name_mb);
/* This ioctl requires a share. */
if ((ssp = sdp->sd_share) == NULL)
@@ -377,8 +374,8 @@ smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
if (ssp->ss_type != STYPE_PRINTQ)
return (EINVAL);
- /* Must not be already open. */
- if (sdp->sd_smbfid != -1)
+ /* Must not already have a file handle. */
+ if (sdp->sd_fh != NULL)
return (EINVAL);
smb_credinit(&scred, cr);
@@ -387,21 +384,68 @@ smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
err = EFAULT;
goto out;
}
+
+ /*
+ * Use the print job title as the file name to open, but
+ * check for invalid characters first. See the notes in
+ * libsmbfs/smb/print.c about job name sanitizing.
+ */
ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0';
+ nmlen = strnlen(ioc->ioc_title, SMBIOC_MAX_NAME-1);
+ cklen = strcspn(ioc->ioc_title, invalid_chars);
+ if (cklen < nmlen) {
+ err = EINVAL;
+ goto out;
+ }
- /* Do the OtW open, save the FID. */
- err = smb_smb_open_prjob(ssp, ioc->ioc_title,
- ioc->ioc_setuplen, ioc->ioc_prmode,
- &scred, &fid);
+ /* Build name_mb */
+ err = smb_put_dmem(&name_mb, SSTOVC(ssp),
+ ioc->ioc_title, nmlen,
+ SMB_CS_NONE, NULL);
if (err != 0)
goto out;
- sdp->sd_smbfid = fid;
- sdp->sd_vcgenid = ssp->ss_vcgenid;
+ err = smb_fh_create(ssp, &fhp);
+ if (err != 0)
+ goto out;
+
+ /*
+ * Do the OtW open, save the FID.
+ */
+ smb_credinit(&scred, cr);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smb2_smb_ntcreate(ssp, &name_mb,
+ NULL, NULL, /* cctx in, out */
+ 0, /* create flags */
+ access,
+ SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
+ NTCREATEX_IMPERSONATION_IMPERSONATION,
+ &scred,
+ &fhp->fh_fid2,
+ NULL,
+ NULL);
+ } else {
+ err = smb_smb_open_prjob(ssp, ioc->ioc_title,
+ ioc->ioc_setuplen, ioc->ioc_prmode,
+ &scred, &fhp->fh_fid1);
+ }
+ smb_credrele(&scred);
+ if (err != 0)
+ goto out;
+
+ fhp->fh_rights = access;
+ smb_fh_opened(fhp);
+ sdp->sd_fh = fhp;
+ fhp = NULL;
out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
+ mb_done(&name_mb);
return (err);
}
@@ -410,31 +454,21 @@ out:
* Helper for nsmb_ioctl case
* SMBIOC_CLOSEFH
*/
+/*ARGSUSED*/
int
smb_usr_closefh(smb_dev_t *sdp, cred_t *cr)
{
- struct smb_cred scred;
- struct smb_share *ssp;
- uint16_t fid;
- int err;
-
- /* This ioctl requires a share. */
- if ((ssp = sdp->sd_share) == NULL)
- return (ENOTCONN);
+ struct smb_fh *fhp;
- if (sdp->sd_smbfid == -1)
- return (0);
- fid = (uint16_t)sdp->sd_smbfid;
- sdp->sd_smbfid = -1;
+ /* This ioctl requires a file handle. */
+ if ((fhp = sdp->sd_fh) == NULL)
+ return (EINVAL);
+ sdp->sd_fh = NULL;
- smb_credinit(&scred, cr);
- if (ssp->ss_type == STYPE_PRINTQ)
- err = smb_smb_close_prjob(ssp, fid, &scred);
- else
- err = smb_smb_close(ssp, fid, NULL, &scred);
- smb_credrele(&scred);
+ smb_fh_close(fhp);
+ smb_fh_rele(fhp);
- return (err);
+ return (0);
}
/*
@@ -732,7 +766,7 @@ smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
switch (cmd) {
case SMBIOC_IOD_CONNECT:
- err = nsmb_iod_connect(vcp);
+ err = nsmb_iod_connect(vcp, cr);
break;
case SMBIOC_IOD_NEGOTIATE:
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c
index 47b2783c58..b7f6bd8570 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.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>
@@ -63,9 +64,9 @@
* m_data ... (m_data + m_len)
* In Unix STREAMS, the mblk payload is:
* b_rptr ... b_wptr
- *
+ *
* Here are some handy conversion notes:
- *
+ *
* struct mbuf struct mblk
* m->m_next m->b_cont
* m->m_nextpkt m->b_next
@@ -75,7 +76,7 @@
* &m->m_dat[MLEN] m->b_datap->db_lim
* M_TRAILINGSPACE(m) MBLKTAIL(m)
* m_freem(m) freemsg(m)
- *
+ *
* Note that mbufs chains also have a special "packet" header,
* which has the length of the whole message. In STREAMS one
* typically just calls msgdsize(m) to get that.
@@ -113,6 +114,9 @@
*/
#define MLEN 4096
+#if (MLEN < SMB2_HDRLEN)
+#error "MLEN can't fit a contiguous SMB2 header"
+#endif
/*
* Some UIO routines.
@@ -420,6 +424,22 @@ mb_put_padbyte(struct mbchain *mbp)
return (0);
}
+/*
+ * Adds padding to 8 byte boundary
+ */
+int
+mb_put_align8(struct mbchain *mbp)
+{
+ static const char zeros[8] = { 0 };
+ int pad_len = 0;
+
+ if ((mbp->mb_count % 8) != 0) {
+ pad_len = 8 - (mbp->mb_count % 8);
+ MB_PUT_INLINE(mbp, zeros, pad_len);
+ }
+ return (0);
+}
+
int
mb_put_uint8(struct mbchain *mbp, u_int8_t x)
{
@@ -537,6 +557,7 @@ mb_put_mem(struct mbchain *mbp, const void *vsrc, int size, int type)
/*
* Append an mblk to the chain.
+ * Note: The mblk_t *m is consumed.
*/
int
mb_put_mbuf(struct mbchain *mbp, mblk_t *m)
@@ -576,6 +597,29 @@ mb_put_mbuf(struct mbchain *mbp, mblk_t *m)
}
/*
+ * Put an mbchain into another mbchain
+ * Leave sub_mbp untouched.
+ */
+int
+mb_put_mbchain(struct mbchain *mbp, struct mbchain *sub_mbp)
+{
+ mblk_t *m;
+
+ if (sub_mbp == NULL)
+ return (0);
+
+ m = sub_mbp->mb_top;
+ if (m == NULL)
+ return (0);
+
+ m = dupmsg(m);
+ if (m == NULL)
+ return (ENOSR);
+
+ return (mb_put_mbuf(mbp, m));
+}
+
+/*
* copies a uio scatter/gather list to an mbuf chain.
*/
int
@@ -875,6 +919,7 @@ md_get_mem(struct mdchain *mdp, void *vdst, int size, int type)
/*
* Get the next SIZE bytes as a separate mblk.
+ * Advances position in mdp by SIZE.
*/
int
md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret)
@@ -898,6 +943,7 @@ md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret)
rm = m_copym(m, off, size, M_WAITOK);
if (rm == NULL)
return (EBADRPC);
+ (void) md_get_mem(mdp, NULL, size, MB_MSYSTEM);
*ret = rm;
return (0);
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c
index c5af3391c6..1e16e95d18 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c
@@ -22,6 +22,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -69,12 +71,12 @@ static int
smbfs_getsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
{
struct smb_cred scred;
- int error, cerror;
smbmntinfo_t *smi;
smbnode_t *np;
- u_int16_t fid = SMB_FID_UNUSED;
+ smb_fh_t *fid = NULL;
uint32_t sdlen = SMALL_SD_SIZE;
uint32_t rights = STD_RIGHT_READ_CONTROL_ACCESS;
+ int error;
if (selector & SACL_SECURITY_INFORMATION)
rights |= SEC_RIGHT_SYSTEM_SECURITY;
@@ -82,9 +84,6 @@ smbfs_getsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
np = VTOSMB(vp);
smi = VTOSMI(vp);
- /* Shared lock for (possible) n_fid use. */
- if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
- return (EINTR);
smb_credinit(&scred, cr);
error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
@@ -95,8 +94,8 @@ again:
/*
* This does the OTW Get
*/
- error = smbfs_smb_getsec_m(smi->smi_share, fid,
- &scred, selector, mp, &sdlen);
+ error = smbfs_smb_getsec(smi->smi_share, fid,
+ selector, mp, &sdlen, &scred);
/*
* Server may give us an error indicating that we
* need a larger data buffer to receive the SD,
@@ -115,14 +114,10 @@ again:
sdlen <= MAX_RAW_SD_SIZE)
goto again;
- cerror = smbfs_smb_tmpclose(np, fid, &scred);
- if (cerror)
- SMBVDEBUG("error %d closing file %s\n",
- cerror, np->n_rpath);
+ smbfs_smb_tmpclose(np, fid);
out:
smb_credrele(&scred);
- smbfs_rw_exit(&np->r_lkserlock);
return (error);
}
@@ -139,11 +134,11 @@ static int
smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
{
struct smb_cred scred;
- int error, cerror;
smbmntinfo_t *smi;
smbnode_t *np;
uint32_t rights;
- u_int16_t fid = SMB_FID_UNUSED;
+ smb_fh_t *fid = NULL;
+ int error;
np = VTOSMB(vp);
smi = VTOSMI(vp);
@@ -164,9 +159,6 @@ smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
if (selector & SACL_SECURITY_INFORMATION)
rights |= SEC_RIGHT_SYSTEM_SECURITY;
- /* Shared lock for (possible) n_fid use. */
- if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
- return (EINTR);
smb_credinit(&scred, cr);
error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
@@ -185,17 +177,13 @@ smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
/*
* This does the OTW Set
*/
- error = smbfs_smb_setsec_m(smi->smi_share, fid,
- &scred, selector, mp);
+ error = smbfs_smb_setsec(smi->smi_share, fid,
+ selector, mp, &scred);
- cerror = smbfs_smb_tmpclose(np, fid, &scred);
- if (cerror)
- SMBVDEBUG("error %d closing file %s\n",
- cerror, np->n_rpath);
+ smbfs_smb_tmpclose(np, fid);
out:
smb_credrele(&scred);
- smbfs_rw_exit(&np->r_lkserlock);
return (error);
}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
index b9226e56d0..41a6f41a2b 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
@@ -25,7 +25,7 @@
* Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
* All rights reserved.
*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -398,11 +398,23 @@ smbfs_getattr_cache(vnode_t *vp, struct smbfattr *fap)
static int
smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr)
{
- struct smbnode *np;
struct smb_cred scred;
+ smbnode_t *np = VTOSMB(vp);
+ smb_share_t *ssp = np->n_mount->smi_share;
+ smb_fh_t *fhp = NULL;
int error;
- np = VTOSMB(vp);
+ bzero(fap, sizeof (*fap));
+
+ /*
+ * Special case the XATTR directory here (all fake).
+ * OK to leave a,c,m times zero (expected).
+ */
+ if (vp->v_flag & V_XATTRDIR) {
+ fap->fa_attr = SMB_FA_DIR;
+ fap->fa_size = DEV_BSIZE;
+ return (0);
+ }
/*
* Here NFS uses the ACL RPC (if smi_flags & SMI_ACL)
@@ -416,8 +428,28 @@ smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr)
return (EINTR);
smb_credinit(&scred, cr);
- bzero(fap, sizeof (*fap));
- error = smbfs_smb_getfattr(np, fap, &scred);
+// Does the attr. open code path work for streams?
+// Trying that, and if it doesn't work enable this.
+#if 0 // XXX
+ /*
+ * Extended attribute files
+ */
+ if (np->n_flag & N_XATTR) {
+ error = smbfs_xa_getfattr(np, fap, scrp);
+ goto out;
+ }
+#endif // XXX
+
+ if (np->n_fidrefs > 0 &&
+ (fhp = np->n_fid) != NULL &&
+ (fhp->fh_vcgenid == ssp->ss_vcgenid)) {
+ /* Use the FID we have. */
+ error = smbfs_smb_getfattr(np, fhp, fap, &scred);
+
+ } else {
+ /* This will do an attr open */
+ error = smbfs_smb_getpattr(np, fap, &scred);
+ }
smb_credrele(&scred);
smbfs_rw_exit(&np->r_lkserlock);
@@ -820,9 +852,8 @@ static void smbfs_cb_nop(smb_share_t *ss)
smb_fscb_t smbfs_cb = {
.fscb_disconn = smbfs_dead,
- .fscb_connect = smbfs_cb_nop,
- .fscb_down = smbfs_cb_nop,
- .fscb_up = smbfs_cb_nop };
+ .fscb_connect = smbfs_cb_nop
+};
#endif /* NEED_SMBFS_CALLBACKS */
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h
index 2fe7476814..62d47e9b20 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _FS_SMBFS_NODE_H_
@@ -221,10 +222,8 @@ typedef struct smbnode {
struct smbfs_fctx *n_dirseq; /* ff context */
int n_dirofs; /* last ff offset */
int n_fidrefs;
- uint16_t n_fid; /* file handle */
+ smb_fh_t *n_fid; /* file handle */
enum vtype n_ovtype; /* vnode type opened */
- uint32_t n_rights; /* granted rights */
- int n_vcgenid; /* gereration no. (reconnect) */
/*
* Misc. bookkeeping
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c
index b8a91ef94a..9a44867521 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c
@@ -28,15 +28,13 @@
* 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: smbfs_smb.c,v 1.73.38.1 2005/05/27 02:35:28 lindak Exp $
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -50,6 +48,7 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_rq.h>
@@ -64,375 +63,70 @@
*/
const uint64_t NT1980 = 11960035200ULL*10000000ULL;
-/*
- * Local functions.
- * Not static, to aid debugging.
- */
-
-int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
- struct smbfattr *fap, struct smb_cred *scrp);
-int smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
- struct smb_cred *scrp, uint16_t infolevel);
-
-int smbfs_smb_statfsLM1(struct smb_share *ssp,
- statvfs64_t *sbp, struct smb_cred *scrp);
-int smbfs_smb_statfsLM2(struct smb_share *ssp,
- statvfs64_t *sbp, struct smb_cred *scrp);
-
-int smbfs_smb_setfattrNT(struct smbnode *np, int fid,
- uint32_t attr, struct timespec *mtime, struct timespec *atime,
- struct smb_cred *scrp);
-
-int smbfs_smb_setftime1(struct smbnode *np, uint16_t fid,
- struct timespec *mtime, struct timespec *atime,
- struct smb_cred *scrp);
-
-int smbfs_smb_setpattr1(struct smbnode *np,
- const char *name, int len, uint32_t attr,
- struct timespec *mtime, struct smb_cred *scrp);
-
-
-/*
- * Todo: locking over-the-wire
- */
-#ifdef APPLE
-
-static int
-smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid,
- offset_t start, uint64_t len, int largelock,
- struct smb_cred *scrp, uint32_t timeout)
-{
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- uint8_t ltype = 0;
- int error;
-
- /* Shared lock for n_fid use below. */
- ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
-
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- return (ESTALE);
-
- if (op == SMB_LOCK_SHARED)
- ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
- /* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */
- if (largelock)
- ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint8(mbp, 0xff); /* secondary command */
- mb_put_uint8(mbp, 0); /* MBZ */
- mb_put_uint16le(mbp, 0);
- mb_put_uint16le(mbp, np->n_fid);
- mb_put_uint8(mbp, ltype); /* locktype */
- mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
- mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */
- mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
- mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint16le(mbp, pid);
- if (!largelock) {
- mb_put_uint32le(mbp, start);
- mb_put_uint32le(mbp, len);
- } else {
- mb_put_uint16le(mbp, 0); /* pad */
- mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
- mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
- mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
- mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
- }
- smb_rq_bend(rqp);
- /*
- * Don't want to risk missing a successful
- * unlock send or lock response, or we could
- * lose track of an outstanding lock.
- */
- if (op == SMB_LOCK_RELEASE)
- rqp->sr_flags |= SMBR_NOINTR_SEND;
- else
- rqp->sr_flags |= SMBR_NOINTR_RECV;
-
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
- return (error);
-}
-
-int
-smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
- offset_t start, uint64_t len, int largelock,
- struct smb_cred *scrp, uint32_t timeout)
-{
- struct smb_share *ssp = np->n_mount->smi_share;
-
- if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
- /*
- * TODO: use LOCK_BYTE_RANGE here.
- */
- return (EINVAL);
-
- /*
- * XXX: compute largelock via:
- * (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)?
- */
- return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len,
- largelock, scrp, timeout));
-}
-
-#endif /* APPLE */
/*
- * Helper for smbfs_getattr
- * Something like nfs_getattr_otw
+ * Helper for smbfs_getattr_otw
+ * used when we have an open FID
*/
int
smbfs_smb_getfattr(
struct smbnode *np,
+ smb_fh_t *fhp,
struct smbfattr *fap,
struct smb_cred *scrp)
{
+ struct smb_share *ssp = np->n_mount->smi_share;
int error;
- /*
- * This lock is necessary for FID-based calls.
- * Lock may be writer (via open) or reader.
- */
- ASSERT(np->r_lkserlock.count != 0);
-
- /*
- * Extended attribute directory or file.
- */
- if (np->n_flag & N_XATTR) {
- error = smbfs_xa_getfattr(np, fap, scrp);
- return (error);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_qfileinfo(ssp, &fhp->fh_fid2, fap, scrp);
+ } else {
+ error = smbfs_smb1_trans2_query(np, fhp->fh_fid1, fap, scrp);
}
- error = smbfs_smb_trans2_query(np, fap, scrp, 0);
- if (error != EINVAL)
- return (error);
-
- /* fallback */
- error = smbfs_smb_query_info(np, NULL, 0, fap, scrp);
-
return (error);
}
/*
- * Common function for QueryFileInfo, QueryPathInfo.
+ * Helper for smbfs_getattr_otw
+ * used when we don't have an open FID
+ *
+ * For SMB1 we can just use the path form of trans2 query.
+ * For SMB2 we need to do an attribute-only open.
+ * See smbfs_smb2_getpattr()
*/
int
-smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
- struct smb_cred *scrp, uint16_t infolevel)
+smbfs_smb_getpattr(
+ struct smbnode *np,
+ struct smbfattr *fap,
+ struct smb_cred *scrp)
{
struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct smb_t2rq *t2p;
- int error, svtz, timesok = 1;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint16_t cmd, date, time, wattr;
- uint64_t llongint, lsize;
- uint32_t size, dattr;
-
- /*
- * Shared lock for n_fid use below.
- * See smbfs_smb_getfattr()
- */
- ASSERT(np->r_lkserlock.count != 0);
-
- /*
- * If we have a valid open FID, use it.
- */
- if ((np->n_fidrefs > 0) &&
- (np->n_fid != SMB_FID_UNUSED) &&
- (np->n_vcgenid == ssp->ss_vcgenid))
- cmd = SMB_TRANS2_QUERY_FILE_INFORMATION;
- else
- cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
-
-top:
- error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- if (!infolevel) {
- if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
- infolevel = SMB_QFILEINFO_STANDARD;
- else
- infolevel = SMB_QFILEINFO_ALL_INFO;
- }
-
- if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION)
- mb_put_uint16le(mbp, np->n_fid);
-
- mb_put_uint16le(mbp, infolevel);
-
- if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) {
- mb_put_uint32le(mbp, 0);
- /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
- error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
- if (error) {
- smb_t2_done(t2p);
- return (error);
- }
- }
+ int error;
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = vcp->vc_txmax;
- error = smb_t2_request(t2p);
- if (error) {
- smb_t2_done(t2p);
- /* Invalid info level? Try fallback. */
- if (error == EINVAL &&
- infolevel == SMB_QFILEINFO_ALL_INFO) {
- infolevel = SMB_QFILEINFO_STANDARD;
- goto top;
- }
- return (error);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_getpattr(np, fap, scrp);
+ } else {
+ uint16_t fid = SMB_FID_UNUSED;
+ error = smbfs_smb1_trans2_query(np, fid, fap, scrp);
}
- mdp = &t2p->t2_rdata;
- svtz = vcp->vc_sopt.sv_tz;
- switch (infolevel) {
- case SMB_QFILEINFO_STANDARD:
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* creation time */
- smb_dos2unixtime(date, time, 0, svtz, &fap->fa_createtime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* access time */
- smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* modify time */
- smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
- md_get_uint32le(mdp, &size); /* EOF position */
- fap->fa_size = size;
- md_get_uint32le(mdp, &size); /* allocation size */
- fap->fa_allocsz = size;
- error = md_get_uint16le(mdp, &wattr);
- fap->fa_attr = wattr;
- timesok = 1;
- break;
- case SMB_QFILEINFO_ALL_INFO:
- timesok = 0;
- /* creation time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_createtime);
-
- /* last access time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_atime);
-
- /* last write time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_mtime);
-
- /* last change time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_ctime);
-
- /* attributes */
- md_get_uint32le(mdp, &dattr);
- fap->fa_attr = dattr;
- /*
- * 4-Byte alignment - discard
- * Specs don't talk about this.
- */
- md_get_uint32le(mdp, NULL);
- /* allocation size */
- md_get_uint64le(mdp, &lsize);
- fap->fa_allocsz = lsize;
- /* File size */
- error = md_get_uint64le(mdp, &lsize);
- fap->fa_size = lsize;
- break;
- default:
- SMBVDEBUG("unexpected info level %d\n", infolevel);
- error = EINVAL;
- }
- smb_t2_done(t2p);
- /*
- * if all times are zero (observed with FAT on NT4SP6)
- * then fall back to older info level
- */
- if (!timesok) {
- if (infolevel == SMB_QFILEINFO_ALL_INFO) {
- infolevel = SMB_QFILEINFO_STANDARD;
- goto top;
- }
- error = EINVAL;
- }
return (error);
}
/*
- * Support functions for _qstreaminfo
- * Moved to smbfs_xattr.c
+ * Get and parse FileFsAttributeInformation
*/
-
int
smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
struct smb_cred *scrp)
{
- struct smb_t2rq *t2p;
- struct mbchain *mbp;
- struct mdchain *mdp;
int error;
- uint32_t nlen;
-
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
- scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO);
- t2p->t2_maxpcount = 4;
- t2p->t2_maxdcount = 4 * 3 + 512;
- error = smb_t2_request(t2p);
- if (error)
- goto out;
-
- mdp = &t2p->t2_rdata;
- md_get_uint32le(mdp, &fsa->fsa_aflags);
- md_get_uint32le(mdp, &fsa->fsa_maxname);
- error = md_get_uint32le(mdp, &nlen); /* fs name length */
- if (error)
- goto out;
- /*
- * Get the FS type name.
- */
- bzero(fsa->fsa_tname, FSTYPSZ);
- if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
- uint16_t tmpbuf[FSTYPSZ];
- size_t tmplen, outlen;
-
- if (nlen > sizeof (tmpbuf))
- nlen = sizeof (tmpbuf);
- error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
- tmplen = nlen / 2; /* UCS-2 chars */
- outlen = FSTYPSZ - 1;
- (void) uconv_u16tou8(tmpbuf, &tmplen,
- (uchar_t *)fsa->fsa_tname, &outlen,
- UCONV_IN_LITTLE_ENDIAN);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_qfsattr(ssp, fsa, scrp);
} else {
- if (nlen > (FSTYPSZ - 1))
- nlen = FSTYPSZ - 1;
- error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
+ error = smbfs_smb1_qfsattr(ssp, fsa, scrp);
}
/*
@@ -444,651 +138,113 @@ smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
SMB_SS_UNLOCK(ssp);
}
-out:
- smb_t2_done(t2p);
- return (0);
+ return (error);
}
int
smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
struct smb_cred *scp)
{
- int error;
-
- if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
- error = smbfs_smb_statfsLM2(ssp, sbp, scp);
- else
- error = smbfs_smb_statfsLM1(ssp, sbp, scp);
-
- return (error);
-}
-
-int
-smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp,
- struct smb_cred *scrp)
-{
- struct smb_t2rq *t2p;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint16_t bsize;
- uint32_t units, bpu, funits;
- uint64_t s, t, f;
- int error;
-
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
- scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, SMB_QFS_ALLOCATION);
- t2p->t2_maxpcount = 4;
- t2p->t2_maxdcount = 4 * 4 + 2;
- error = smb_t2_request(t2p);
- if (error)
- goto out;
-
- mdp = &t2p->t2_rdata;
- md_get_uint32le(mdp, NULL); /* fs id */
- md_get_uint32le(mdp, &bpu);
- md_get_uint32le(mdp, &units);
- md_get_uint32le(mdp, &funits);
- error = md_get_uint16le(mdp, &bsize);
- if (error)
- goto out;
- s = bsize;
- s *= bpu;
- t = units;
- f = funits;
- /*
- * Don't allow over-large blocksizes as they determine
- * Finder List-view size granularities. On the other
- * hand, we mustn't let the block count overflow the
- * 31 bits available.
- */
- while (s > 16 * 1024) {
- if (t > LONG_MAX)
- break;
- s /= 2;
- t *= 2;
- f *= 2;
- }
- while (t > LONG_MAX) {
- t /= 2;
- f /= 2;
- s *= 2;
- }
- sbp->f_bsize = (ulong_t)s; /* file system block size */
- sbp->f_blocks = t; /* total data blocks in file system */
- sbp->f_bfree = f; /* free blocks in fs */
- sbp->f_bavail = f; /* free blocks avail to non-superuser */
- sbp->f_files = (-1); /* total file nodes in file system */
- sbp->f_ffree = (-1); /* free file nodes in fs */
-
-out:
- smb_t2_done(t2p);
- return (0);
-}
-
-int
-smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp,
- struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct mdchain *mdp;
- uint16_t units, bpu, bsize, funits;
- uint64_t s, t, f;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
- scrp);
- if (error)
- return (error);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- if (error)
- goto out;
-
- smb_rq_getreply(rqp, &mdp);
- md_get_uint16le(mdp, &units);
- md_get_uint16le(mdp, &bpu);
- md_get_uint16le(mdp, &bsize);
- error = md_get_uint16le(mdp, &funits);
- if (error)
- goto out;
- s = bsize;
- s *= bpu;
- t = units;
- f = funits;
- /*
- * Don't allow over-large blocksizes as they determine
- * Finder List-view size granularities. On the other
- * hand, we mustn't let the block count overflow the
- * 31 bits available.
- */
- while (s > 16 * 1024) {
- if (t > LONG_MAX)
- break;
- s /= 2;
- t *= 2;
- f *= 2;
- }
- while (t > LONG_MAX) {
- t /= 2;
- f /= 2;
- s *= 2;
- }
- sbp->f_bsize = (ulong_t)s; /* file system block size */
- sbp->f_blocks = t; /* total data blocks in file system */
- sbp->f_bfree = f; /* free blocks in fs */
- sbp->f_bavail = f; /* free blocks avail to non-superuser */
- sbp->f_files = (-1); /* total file nodes in file system */
- sbp->f_ffree = (-1); /* free file nodes in fs */
-
-out:
- smb_rq_done(rqp);
- return (0);
-}
-
-int
-smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
- struct smb_cred *scrp)
-{
- struct smb_t2rq *t2p;
+ struct smb_fs_size_info info;
struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
+ uint32_t bps, spu;
int error;
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
- scrp, &t2p);
+ if (vcp->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_statfs(ssp, &info, scp);
+ } else {
+ error = smbfs_smb1_statfs(ssp, &info, scp);
+ }
if (error)
return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
- mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION);
- else
- mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO);
- mb_put_uint16le(mbp, 0); /* pad */
- mbp = &t2p->t2_tdata;
- mb_init(mbp);
- mb_put_uint64le(mbp, newsize);
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
- smb_t2_done(t2p);
- return (error);
-}
-
-int
-smbfs_smb_setdisp(struct smbnode *np, uint16_t fid, uint8_t newdisp,
- struct smb_cred *scrp)
-{
- struct smb_t2rq *t2p;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- int error;
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
- scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
- mb_put_uint16le(mbp, SMB_SFILEINFO_DISPOSITION_INFORMATION);
- else
- mb_put_uint16le(mbp, SMB_SFILEINFO_DISPOSITION_INFO);
- mb_put_uint16le(mbp, 0); /* pad */
- mbp = &t2p->t2_tdata;
- mb_init(mbp);
- mb_put_uint8(mbp, newdisp);
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
- smb_t2_done(t2p);
- return (error);
-}
+ /* A bit of paranoia. */
+ bps = info.bytes_per_sect;
+ if (bps < DEV_BSIZE)
+ bps = DEV_BSIZE;
+ spu = info.sect_per_unit;
+ if (spu == 0)
+ spu = 1;
-/*
- * On SMB1, the trans2 rename only allows a rename where the
- * source and target are in the same directory. If you give
- * the server any separators, you get "status not supported".
- */
+ /* preferred file system block size */
+ sbp->f_bsize = bps * spu;
-/*ARGSUSED*/
-int
-smbfs_smb_t2rename(struct smbnode *np,
- const char *tname, int tnlen, struct smb_cred *scrp,
- uint16_t fid, int overwrite)
-{
- struct smb_t2rq *t2p;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- int32_t *ucslenp;
- int error;
+ /* file system block size ("fragment size") */
+ sbp->f_frsize = bps;
- if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU))
- return (ENOTSUP);
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
- scrp, &t2p);
- if (error)
- return (error);
+ /* total blocks of f_frsize */
+ sbp->f_blocks = info.total_units * spu;
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
- mb_put_uint16le(mbp, 0); /* reserved, nowadays */
+ /* free blocks of f_frsize */
+ sbp->f_bfree = info.actual_avail * spu;
- mbp = &t2p->t2_tdata;
- mb_init(mbp);
- mb_put_uint32le(mbp, overwrite); /* one or zero */
- mb_put_uint32le(mbp, 0); /* obsolete target dir fid */
+ /* free blocks avail to non-superuser */
+ sbp->f_bavail = info.caller_avail * spu;
- ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t));
- mbp->mb_count = 0;
- error = smb_put_dmem(mbp, vcp, tname, tnlen, SMB_CS_NONE, NULL);
- if (error)
- goto out;
- *ucslenp = htolel(mbp->mb_count);
+ sbp->f_files = (-1); /* total file nodes in file system */
+ sbp->f_ffree = (-1); /* free file nodes in fs */
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
-out:
- smb_t2_done(t2p);
return (error);
}
int
-smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp)
+smbfs_smb_setdisp(struct smb_share *ssp, smb_fh_t *fhp,
+ uint8_t disp, struct smb_cred *scrp)
{
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- int error;
-
- /* Shared lock for n_fid use below. */
- ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
-
- if (!(np->n_flag & NFLUSHWIRE))
- return (0);
- if (np->n_fidrefs == 0)
- return (0); /* not open */
-
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- return (ESTALE);
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, np->n_fid);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
- if (!error) {
- mutex_enter(&np->r_statelock);
- np->n_flag &= ~NFLUSHWIRE;
- mutex_exit(&np->r_statelock);
- }
- return (error);
-}
-
-int
-smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
- struct smb_cred *scrp)
-{
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- int error;
+ int err;
- if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- /*
- * This call knows about 64-bit offsets.
- */
- error = smbfs_smb_seteof(ssp, fid, newsize, scrp);
- if (!error) {
- mutex_enter(&np->r_statelock);
- np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
- mutex_exit(&np->r_statelock);
- return (0);
- }
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smbfs_smb2_setdisp(ssp, &fhp->fh_fid2, disp, scrp);
+ } else {
+ err = smbfs_smb1_setdisp(ssp, fhp->fh_fid1, disp, scrp);
}
- /*
- * OK, so fallback to SMB_COM_WRITE, but note:
- * it only supports 32-bit file offsets.
- */
- if (newsize > UINT32_MAX)
- return (EFBIG);
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, 0);
- mb_put_uint32le(mbp, newsize);
- mb_put_uint16le(mbp, 0);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_DATA);
- mb_put_uint16le(mbp, 0);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
- mutex_enter(&np->r_statelock);
- np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
- mutex_exit(&np->r_statelock);
- return (error);
+ return (err);
}
-/*
- * Old method for getting file attributes.
- */
int
-smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
- struct smbfattr *fap, struct smb_cred *scrp)
+smbfs_smb_setfsize(struct smb_share *ssp, smb_fh_t *fhp,
+ uint64_t size, struct smb_cred *scrp)
{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint8_t wc;
int error;
- uint16_t wattr;
- uint32_t longint;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np,
- name, nmlen, '\\');
- if (error)
- goto out;
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- if (error)
- goto out;
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto out;
- if (wc != 10) {
- error = EBADRPC;
- goto out;
- }
- md_get_uint16le(mdp, &wattr);
- fap->fa_attr = wattr;
- /*
- * Be careful using the time returned here, as
- * with FAT on NT4SP6, at least, the time returned is low
- * 32 bits of 100s of nanoseconds (since 1601) so it rolls
- * over about every seven minutes!
- */
- md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
- smb_time_server2local(longint,
- SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime);
- error = md_get_uint32le(mdp, &longint);
- fap->fa_size = longint;
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-/*
- * Set DOS file attributes. mtime should be NULL for dialects above lm10
- */
-int
-smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len,
- uint32_t attr, struct timespec *mtime,
- struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- long time;
- int error, svtz;
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp);
- if (error)
- return (error);
- svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, (uint16_t)attr);
- if (mtime) {
- smb_time_local2server(mtime, svtz, &time);
- } else
- time = 0;
- mb_put_uint32le(mbp, time); /* mtime */
- mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len, '\\');
- if (error)
- goto out;
- mb_put_uint8(mbp, SMB_DT_ASCII);
- if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
- mb_put_padbyte(mbp);
- mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_seteof(ssp, &fhp->fh_fid2, size, scrp);
+ } else {
+ error = smbfs_smb1_seteof(ssp, fhp->fh_fid1, size, scrp);
}
- mb_put_uint8(mbp, 0);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-int
-smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
- struct smb_cred *scrp)
-{
- struct smbfattr fa;
- int error;
- uint32_t attr;
- error = smbfs_smb_query_info(np, name, len, &fa, scrp);
- attr = fa.fa_attr;
- if (!error && !(attr & SMB_FA_HIDDEN)) {
- attr |= SMB_FA_HIDDEN;
- error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
- }
return (error);
}
-int
-smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
- struct smb_cred *scrp)
-{
- struct smbfattr fa;
- uint32_t attr;
- int error;
-
- error = smbfs_smb_query_info(np, name, len, &fa, scrp);
- attr = fa.fa_attr;
- if (!error && (attr & SMB_FA_HIDDEN)) {
- attr &= ~SMB_FA_HIDDEN;
- error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
- }
- return (error);
-}
-
/*
* Set file attributes (optionally: DOS attr, atime, mtime)
- * either by open FID or by path name (FID == -1).
+ * Always have an open FID with set attr rights.
*/
int
smbfs_smb_setfattr(
- struct smbnode *np,
- int fid,
+ struct smb_share *ssp,
+ smb_fh_t *fhp,
uint32_t attr,
struct timespec *mtime,
struct timespec *atime,
struct smb_cred *scrp)
{
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
+ struct mbchain mb_info;
+ struct mbchain *mbp = &mb_info;
+ uint64_t tm;
int error;
/*
- * Normally can use the trans2 call.
- */
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- error = smbfs_smb_setfattrNT(np, fid,
- attr, mtime, atime, scrp);
- return (error);
- }
-
- /*
- * Fall-back for older protocols.
+ * Build a struct FILE_BASIC_INFORMATION in mbp
+ * LARGE_INTEGER CreationTime;
+ * LARGE_INTEGER LastAccessTime;
+ * LARGE_INTEGER LastWriteTime;
+ * LARGE_INTEGER ChangeTime;
+ * ULONG FileAttributes;
+ * Zero in times means "no change".
*/
- if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) {
- error = smbfs_smb_setftime1(np, fid,
- mtime, atime, scrp);
- return (error);
- }
- error = smbfs_smb_setpattr1(np, NULL, 0,
- attr, mtime, scrp);
- return (error);
-}
-
-/*
- * Set file atime and mtime. Isn't supported by core dialect.
- */
-int
-smbfs_smb_setftime1(
- struct smbnode *np,
- uint16_t fid,
- struct timespec *mtime,
- struct timespec *atime,
- struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- uint16_t date, time;
- int error, tzoff;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp);
- if (error)
- return (error);
-
- tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint32le(mbp, 0); /* creation time */
-
- if (atime)
- smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
- else
- time = date = 0;
- mb_put_uint16le(mbp, date);
- mb_put_uint16le(mbp, time);
- if (mtime)
- smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
- else
- time = date = 0;
- mb_put_uint16le(mbp, date);
- mb_put_uint16le(mbp, time);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- SMBVDEBUG("%d\n", error);
- smb_rq_done(rqp);
- return (error);
-}
-
-/*
- * Set DOS file attributes, either via open FID or by path name.
- * Looks like this call can be used only if CAP_NT_SMBS bit is on.
- *
- * When setting via path (fid == -1):
- * *BASIC_INFO works with Samba, but Win2K servers say it is an
- * invalid information level on a SET_PATH_INFO. Note Win2K does
- * support *BASIC_INFO on a SET_FILE_INFO, and they support the
- * equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure.
- */
-int
-smbfs_smb_setfattrNT(
- struct smbnode *np,
- int fid, /* if fid == -1, set by path */
- uint32_t attr,
- struct timespec *mtime,
- struct timespec *atime,
- struct smb_cred *scrp)
-{
- struct smb_t2rq *t2p;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- uint64_t tm;
- int error;
- uint16_t cmd, level;
-
- if (fid == -1) {
- cmd = SMB_TRANS2_SET_PATH_INFORMATION;
- } else {
- if (fid > UINT16_MAX)
- return (EINVAL);
- cmd = SMB_TRANS2_SET_FILE_INFORMATION;
- }
- if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
- level = SMB_SFILEINFO_BASIC_INFORMATION;
- else
- level = SMB_SFILEINFO_BASIC_INFO;
-
- error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
- if (error)
- return (error);
-
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
-
- if (cmd == SMB_TRANS2_SET_FILE_INFORMATION)
- mb_put_uint16le(mbp, fid);
-
- mb_put_uint16le(mbp, level);
- mb_put_uint32le(mbp, 0); /* MBZ */
-
- if (cmd == SMB_TRANS2_SET_PATH_INFORMATION) {
- error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
- if (error != 0)
- goto out;
- }
-
- /* FAT file systems don't support dates earlier than 1980. */
-
- mbp = &t2p->t2_tdata;
mb_init(mbp);
mb_put_uint64le(mbp, 0); /* creation time */
if (atime) {
@@ -1098,7 +254,7 @@ smbfs_smb_setfattrNT(
tm = NT1980;
} else
tm = 0;
- mb_put_uint64le(mbp, tm); /* access time */
+ mb_put_uint64le(mbp, tm); /* last access time */
if (mtime) {
smb_time_local2NT(mtime, &tm);
if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
@@ -1107,19 +263,35 @@ smbfs_smb_setfattrNT(
} else
tm = 0;
mb_put_uint64le(mbp, tm); /* last write time */
- mb_put_uint64le(mbp, 0); /* ctime (no change) */
+ mb_put_uint64le(mbp, 0); /* change time */
mb_put_uint32le(mbp, attr);
- mb_put_uint32le(mbp, 0); /* padding */
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
-out:
- smb_t2_done(t2p);
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_setfattr(ssp, &fhp->fh_fid2, mbp, scrp);
+ } else {
+ error = smbfs_smb1_setfattr(ssp, fhp->fh_fid1, mbp, scrp);
+ }
+
+ return (error);
+}
+
+int
+smbfs_smb_flush(struct smb_share *ssp, smb_fh_t *fhp,
+ struct smb_cred *scrp)
+{
+ int error;
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_flush(ssp, &fhp->fh_fid2, scrp);
+ } else {
+ error = smbfs_smb1_flush(ssp, fhp->fh_fid1, scrp);
+ }
return (error);
}
/*
* Modern create/open of file or directory.
+ * On success, fills in fhp->fh_fid* and fhp->fh_rights
*/
int
smbfs_smb_ntcreatex(
@@ -1133,7 +305,7 @@ smbfs_smb_ntcreatex(
uint32_t disp, /* open disposition */
uint32_t createopt, /* NTCREATEX_OPTIONS_ */
struct smb_cred *scrp,
- uint16_t *fidp, /* returned FID */
+ smb_fh_t *fhp, /* pre-made file handle to fill in */
uint32_t *cr_act_p, /* optional returned create action */
struct smbfattr *fap) /* optional returned attributes */
{
@@ -1154,7 +326,7 @@ smbfs_smb_ntcreatex(
0, /* NTCREATEX_FLAGS... */
req_acc, efa, share_acc, disp, createopt,
NTCREATEX_IMPERSONATION_IMPERSONATION,
- scrp, fidp, cr_act_p, fap);
+ scrp, fhp, cr_act_p, fap);
out:
mb_done(&name_mb);
@@ -1162,233 +334,68 @@ out:
return (err);
}
-static uint32_t
-smb_mode2rights(int mode)
-{
- mode = mode & SMB_AM_OPENMODE;
- uint32_t rights =
- STD_RIGHT_SYNCHRONIZE_ACCESS |
- STD_RIGHT_READ_CONTROL_ACCESS;
-
- if ((mode == SMB_AM_OPENREAD) ||
- (mode == SMB_AM_OPENRW)) {
- rights |=
- SA_RIGHT_FILE_READ_ATTRIBUTES |
- SA_RIGHT_FILE_READ_DATA;
- }
-
- if ((mode == SMB_AM_OPENWRITE) ||
- (mode == SMB_AM_OPENRW)) {
- rights |=
- SA_RIGHT_FILE_WRITE_ATTRIBUTES |
- SA_RIGHT_FILE_APPEND_DATA |
- SA_RIGHT_FILE_WRITE_DATA;
- }
-
- if (mode == SMB_AM_OPENEXEC) {
- rights |=
- SA_RIGHT_FILE_READ_ATTRIBUTES |
- SA_RIGHT_FILE_EXECUTE;
- }
-
- return (rights);
-}
-
-static int
-smb_rights2mode(uint32_t rights)
-{
- int accmode = SMB_AM_OPENEXEC; /* our fallback */
-
- if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD |
- SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES |
- SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS |
- STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS))
- accmode = SMB_AM_OPENWRITE;
- if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES |
- SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS))
- accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD
- : SMB_AM_OPENRW;
- return (accmode);
-}
-
-static int
-smbfs_smb_oldopen(
- struct smbnode *np,
- const char *name,
- int nmlen,
- int xattr,
- int accmode,
- struct smb_cred *scrp,
- uint16_t *fidp,
- uint16_t *granted_mode_p,
- smbfattr_t *fap)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- struct mdchain *mdp;
- struct smbfattr fa;
- uint8_t wc;
- uint16_t wattr;
- uint32_t longint;
- int error;
-
- bzero(&fa, sizeof (fa));
-
- /*
- * XXX: move to callers...
- *
- * Use DENYNONE to give unixy semantics of permitting
- * everything not forbidden by permissions. Ie denial
- * is up to server with clients/openers needing to use
- * advisory locks for further control.
- */
- accmode |= SMB_SM_DENYNONE;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, accmode);
- mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY |
- SMB_FA_DIR);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, vcp, np, name, nmlen,
- xattr ? ':' : '\\');
- if (error)
- goto done;
- smb_rq_bend(rqp);
- /*
- * Don't want to risk missing a successful
- * open response, or we could "leak" FIDs.
- */
- rqp->sr_flags |= SMBR_NOINTR_RECV;
- error = smb_rq_simple_timed(rqp, smb_timo_open);
- if (error)
- goto done;
- smb_rq_getreply(rqp, &mdp);
- /*
- * 8/2002 a DAVE server returned wc of 15 so we ignore that.
- * (the actual packet length and data was correct)
- */
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto done;
- if (wc != 7 && wc != 15) {
- error = EBADRPC;
- goto done;
- }
- md_get_uint16le(mdp, fidp);
- md_get_uint16le(mdp, &wattr);
- fa.fa_attr = wattr;
- /*
- * Be careful using the time returned here, as
- * with FAT on NT4SP6, at least, the time returned is low
- * 32 bits of 100s of nanoseconds (since 1601) so it rolls
- * over about every seven minutes!
- */
- md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
- smb_time_server2local(longint, vcp->vc_sopt.sv_tz, &fa.fa_mtime);
- md_get_uint32le(mdp, &longint);
- fa.fa_size = longint;
- error = md_get_uint16le(mdp, granted_mode_p);
-
-done:
- smb_rq_done(rqp);
- if (error)
- return (error);
-
- if (fap)
- *fap = fa; /* struct copy */
-
- return (0);
-}
-
+/*
+ * Get a file handle with (at least) the specified rights.
+ *
+ * We'll try to borrow the node ->n_fid if we can. When we
+ * borrow n_fid, just take a hold on the smb_fh_t, and don't
+ * bump n_fidrefs as that tracks VFS-level opens. Similarly
+ * in _tmpclose we just release the smb_fh_t, not n_fidrefs.
+ */
int
smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
- uint16_t *fidp)
+ smb_fh_t **fhpp)
{
struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- int accmode, error;
-
- /* Shared lock for n_fid use below. */
- ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+ smb_fh_t *fhp = NULL;
+ int error;
/* Can we re-use n_fid? or must we open anew? */
mutex_enter(&np->r_statelock);
if (np->n_fidrefs > 0 &&
- np->n_vcgenid == ssp->ss_vcgenid &&
- (rights & np->n_rights) == rights) {
- np->n_fidrefs++;
- *fidp = np->n_fid;
+ (fhp = np->n_fid) != NULL &&
+ fhp->fh_vcgenid == ssp->ss_vcgenid &&
+ (fhp->fh_rights & rights) == rights) {
+ smb_fh_hold(fhp);
+ *fhpp = fhp;
mutex_exit(&np->r_statelock);
return (0);
}
mutex_exit(&np->r_statelock);
+ error = smb_fh_create(ssp, &fhp);
+ if (error != 0)
+ goto out;
+
/* re-open an existing file. */
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- error = smbfs_smb_ntcreatex(np,
- NULL, 0, 0, /* name nmlen xattr */
- rights, SMB_EFA_NORMAL,
- NTCREATEX_SHARE_ACCESS_ALL,
- NTCREATEX_DISP_OPEN,
- 0, /* create options */
- scrp, fidp,
- NULL, NULL); /* cr_act_p fa_p */
- return (error);
- }
+ error = smbfs_smb_ntcreatex(np,
+ NULL, 0, 0, /* name nmlen xattr */
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ scrp, fhp,
+ NULL, NULL); /* cr_act_p fa_p */
+ if (error != 0)
+ goto out;
+
+ fhp->fh_rights = rights;
+ smb_fh_opened(fhp);
+ *fhpp = fhp;
+ fhp = NULL;
- accmode = smb_rights2mode(rights);
- error = smbfs_smb_oldopen(np,
- NULL, 0, 0, /* name nmlen xattr */
- accmode, scrp,
- fidp,
- NULL, /* granted mode p */
- NULL); /* fa p */
+out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
return (error);
}
-int
-smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp)
+/* ARGSUSED */
+void
+smbfs_smb_tmpclose(struct smbnode *np, smb_fh_t *fhp)
{
- struct smb_share *ssp = np->n_mount->smi_share;
- int error = 0;
- uint16_t oldfid = SMB_FID_UNUSED;
-
- /* Shared lock for n_fid use below. */
- ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
-
- mutex_enter(&np->r_statelock);
- if (fid == np->n_fid) {
- ASSERT(np->n_fidrefs > 0);
- if (--np->n_fidrefs == 0) {
- /*
- * Don't expect to find the last reference
- * here in tmpclose. Hard to deal with as
- * we don't have r_lkserlock exclusive.
- * Will close oldfid below.
- */
- oldfid = np->n_fid;
- np->n_fid = SMB_FID_UNUSED;
- }
- } else {
- /* Will close the passed fid. */
- oldfid = fid;
- }
- mutex_exit(&np->r_statelock);
-
- if (oldfid != SMB_FID_UNUSED)
- error = smbfs_smb_close(ssp, oldfid, NULL, scrp);
-
- return (error);
+ smb_fh_rele(fhp);
}
int
@@ -1399,124 +406,47 @@ smbfs_smb_open(
int xattr,
uint32_t rights,
struct smb_cred *scrp,
- uint16_t *fidp,
- uint32_t *rightsp,
+ smb_fh_t **fhpp,
smbfattr_t *fap)
{
struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- int accmode, error;
- uint16_t grantedmode;
-
- /* open an existing file */
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- error = smbfs_smb_ntcreatex(np,
- name, nmlen, xattr,
- rights, SMB_EFA_NORMAL,
- NTCREATEX_SHARE_ACCESS_ALL,
- NTCREATEX_DISP_OPEN,
- 0, /* create options */
- scrp, fidp,
- NULL, fap); /* cr_act_p fa_p */
- if (error != 0)
- return (error);
- *rightsp = rights;
- return (0);
- }
+ // struct smb_vc *vcp = SSTOVC(ssp);
+ smb_fh_t *fhp = NULL;
+ int error;
- accmode = smb_rights2mode(rights);
- error = smbfs_smb_oldopen(np,
- name, nmlen, xattr, accmode, scrp,
- fidp, &grantedmode, fap);
+ error = smb_fh_create(ssp, &fhp);
if (error != 0)
- return (error);
- *rightsp = smb_mode2rights(grantedmode);
- (void) smbfs_smb_getfattr(np, fap, scrp);
+ goto out;
- return (0);
-}
+ /* open an existing file */
+ error = smbfs_smb_ntcreatex(np,
+ name, nmlen, xattr,
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ scrp, fhp, NULL, fap);
+ if (error != 0)
+ goto out;
-int
-smbfs_smb_close(struct smb_share *ssp, uint16_t fid,
- struct timespec *mtime, struct smb_cred *scrp)
-{
- int error;
+ fhp->fh_rights = rights;
+ smb_fh_opened(fhp);
+ *fhpp = fhp;
+ fhp = NULL;
- error = smb_smb_close(ssp, fid, mtime, scrp);
+out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
- /*
- * ENOTCONN isn't interesting - if the connection is closed,
- * so are all our FIDs - and EIO is also not interesting,
- * as it means a forced unmount was done. (was ENXIO)
- * Also ETIME, which means we sent the request but gave up
- * waiting before the response came back.
- *
- * Don't clog up the system log with warnings about these
- * uninteresting failures on closes.
- */
- switch (error) {
- case ENOTCONN:
- case ENXIO:
- case EIO:
- case ETIME:
- error = 0;
- }
- return (error);
+ return (0);
}
-static int
-smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen,
- int xattr, struct smb_cred *scrp, uint16_t *fidp)
+void
+smbfs_smb_close(smb_fh_t *fhp)
{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = dnp->n_mount->smi_share;
- struct mbchain *mbp;
- struct mdchain *mdp;
- struct timespec ctime;
- uint8_t wc;
- long tm;
- int error;
- uint16_t attr = SMB_FA_ARCHIVE;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- if (name && *name == '.')
- attr |= SMB_FA_HIDDEN;
- mb_put_uint16le(mbp, attr); /* attributes */
- gethrestime(&ctime);
- smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
- mb_put_uint32le(mbp, tm);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen,
- xattr ? ':' : '\\');
- if (error)
- goto out;
- smb_rq_bend(rqp);
- /*
- * Don't want to risk missing a successful
- * open response, or we could "leak" FIDs.
- */
- rqp->sr_flags |= SMBR_NOINTR_RECV;
- error = smb_rq_simple_timed(rqp, smb_timo_open);
- if (error)
- goto out;
- smb_rq_getreply(rqp, &mdp);
- md_get_uint8(mdp, &wc);
- if (wc != 1) {
- error = EBADRPC;
- goto out;
- }
- error = md_get_uint16le(mdp, fidp);
-
-out:
- smb_rq_done(rqp);
- return (error);
+ smb_fh_close(fhp);
+ smb_fh_rele(fhp);
}
int
@@ -1527,759 +457,127 @@ smbfs_smb_create(
int xattr,
uint32_t disp,
struct smb_cred *scrp,
- uint16_t *fidp)
+ smb_fh_t **fhpp)
{
struct smb_share *ssp = dnp->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
+ // struct smb_vc *vcp = SSTOVC(ssp);
+ smb_fh_t *fhp = NULL;
uint32_t efa, rights;
int error;
+ error = smb_fh_create(ssp, &fhp);
+ if (error != 0)
+ goto out;
+
/*
* At present the only access we might need is to WRITE data,
* and that only if we are creating a "symlink". When/if the
* access needed gets more complex it should made a parameter
* and be set upstream.
*/
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- rights = SA_RIGHT_FILE_WRITE_DATA;
- efa = SMB_EFA_NORMAL;
- if (!xattr && name && *name == '.')
- efa = SMB_EFA_HIDDEN;
- error = smbfs_smb_ntcreatex(dnp,
- name, nmlen, xattr, rights, efa,
- NTCREATEX_SHARE_ACCESS_ALL,
- disp, /* != NTCREATEX_DISP_OPEN */
- NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
- scrp, fidp, NULL, NULL); /* cr_act_p fa_p */
- return (error);
- }
+ rights = SA_RIGHT_FILE_WRITE_DATA;
+ efa = SMB_EFA_NORMAL;
+ if (!xattr && name && *name == '.')
+ efa = SMB_EFA_HIDDEN;
+ error = smbfs_smb_ntcreatex(dnp,
+ name, nmlen, xattr, rights, efa,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ disp, /* != NTCREATEX_DISP_OPEN */
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
+ scrp, fhp, NULL, NULL);
+ if (error != 0)
+ goto out;
- error = smbfs_smb_oldcreate(dnp, name, nmlen, xattr, scrp, fidp);
- return (error);
-}
+ fhp->fh_rights = rights;
+ smb_fh_opened(fhp);
+ *fhpp = fhp;
+ fhp = NULL;
-int
-smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name,
- int nmlen, int xattr)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
+out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, nmlen,
- xattr ? ':' : '\\');
- if (!error) {
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- }
- smb_rq_done(rqp);
return (error);
}
int
-smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
- const char *tname, int tnmlen, struct smb_cred *scrp)
+smbfs_smb_rename(struct smbnode *sdnp, struct smbnode *np,
+ struct smbnode *tdnp, const char *tname, int tnlen,
+ smb_fh_t *fhp, struct smb_cred *scrp)
{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = src->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
- uint16_t fa;
- char sep;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- /* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
- fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
- fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
- mb_put_uint16le(mbp, fa);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ int err;
- /*
- * When we're not adding any component name, the
- * passed sep is ignored, so just pass sep=0.
- */
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0);
- if (error)
- goto out;
+ if (vcp->vc_flags & SMBV_SMB2) {
+ err = smbfs_smb2_rename(np, tdnp, tname, tnlen, 0,
+ &fhp->fh_fid2, scrp);
+ return (err);
+ }
/*
- * After XATTR directories, separator is ":"
+ * SMB1 -- Want to use _t2rename if we can
+ * (rename in same dir and cap pass-through)
+ * Most SMB1 servers have cap pass-through.
*/
- sep = (src->n_flag & N_XATTR) ? ':' : '\\';
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, sep);
- if (error)
- goto out;
-
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-int
-smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
- const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = src->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
- mb_put_uint16le(mbp, 0x20); /* delete target file */
- mb_put_uint16le(mbp, flags);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, '\\');
- if (error)
- goto out;
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, '\\');
- if (error)
- goto out;
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-static int
-smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len,
- struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = dnp->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len, '\\');
- if (!error) {
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
+ if (sdnp == tdnp &&
+ (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) != 0) {
+ err = smbfs_smb1_t2rename(np, tname, tnlen, fhp->fh_fid1, scrp);
+ } else {
+ err = smbfs_smb1_oldrename(np, tdnp, tname, tnlen, scrp);
}
- smb_rq_done(rqp);
- return (error);
+
+ return (err);
}
int
smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen,
struct smb_cred *scrp)
{
+ smb_fh_t tmp_fh;
struct smb_share *ssp = dnp->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- uint32_t rights;
- uint16_t fid;
+ uint32_t efa, rights;
int error;
/*
+ * Using a faked-up handle here to avoid the work of
+ * creating and destroying a real "conn obj".
+ */
+ bzero(&tmp_fh, sizeof (tmp_fh));
+
+ /*
* We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
* just to be asking for something. The rights==0 case could
* easily be broken on some old or unusual servers.
*/
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- rights = SA_RIGHT_FILE_READ_DATA;
- error = smbfs_smb_ntcreatex(dnp,
- name, nmlen, 0, /* xattr */
- rights, SMB_EFA_DIRECTORY,
- NTCREATEX_SHARE_ACCESS_ALL,
- NTCREATEX_DISP_CREATE,
- NTCREATEX_OPTIONS_DIRECTORY,
- scrp, &fid, NULL, NULL); /* cr_act_p fa_p */
- if (error)
- return (error);
- (void) smbfs_smb_close(ssp, fid, NULL, scrp);
- return (0);
+ rights = SA_RIGHT_FILE_READ_DATA;
+ efa = SMB_EFA_NORMAL;
+ if (name && *name == '.')
+ efa |= SMB_EFA_HIDDEN;
+ error = smbfs_smb_ntcreatex(dnp,
+ name, nmlen, 0, /* xattr */
+ rights, SMB_EFA_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_DIRECTORY,
+ scrp, &tmp_fh, NULL, NULL);
+ if (error == 0) {
+ (void) smb_smb_close(ssp, &tmp_fh, scrp);
}
- error = smbfs_smb_oldmkdir(dnp, name, nmlen, scrp);
- return (error);
-}
-
-int
-smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0, '\\');
- if (!error) {
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- }
- smb_rq_done(rqp);
return (error);
}
-static int
-smbfs_smb_search(struct smbfs_fctx *ctx)
-{
- struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
- struct smb_rq *rqp;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint8_t wc, bt;
- uint16_t ec, dlen, bc;
- int maxent, error, iseof = 0;
-
- maxent = min(ctx->f_left,
- (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN);
- if (ctx->f_rq) {
- smb_rq_done(ctx->f_rq);
- ctx->f_rq = NULL;
- }
- error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH,
- ctx->f_scred, &rqp);
- if (error)
- return (error);
- ctx->f_rq = rqp;
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, maxent); /* max entries to return */
- mb_put_uint16le(mbp, ctx->f_attrmask);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */
- if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
- error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
- ctx->f_wildcard, ctx->f_wclen, '\\');
- if (error)
- return (error);
- mb_put_uint8(mbp, SMB_DT_VARIABLE);
- mb_put_uint16le(mbp, 0); /* context length */
- ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
- } else {
- if (SMB_UNICODE_STRINGS(vcp)) {
- mb_put_padbyte(mbp);
- mb_put_uint8(mbp, 0);
- }
- mb_put_uint8(mbp, 0);
- mb_put_uint8(mbp, SMB_DT_VARIABLE);
- mb_put_uint16le(mbp, SMB_SKEYLEN);
- mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
- }
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
- error = 0;
- iseof = 1;
- ctx->f_flags |= SMBFS_RDD_EOF;
- } else if (error)
- return (error);
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- return (error);
- if (wc != 1)
- return (iseof ? ENOENT : EBADRPC);
- md_get_uint16le(mdp, &ec);
- md_get_uint16le(mdp, &bc);
- md_get_uint8(mdp, &bt);
- error = md_get_uint16le(mdp, &dlen);
- if (error)
- return (error);
- if (ec == 0)
- return (ENOENT);
- ctx->f_ecnt = ec;
- if (bc < 3)
- return (EBADRPC);
- bc -= 3;
- if (bt != SMB_DT_VARIABLE)
- return (EBADRPC);
- if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
- return (EBADRPC);
- return (0);
-}
-
-
-/*ARGSUSED*/
-static int
-smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
- const char *wildcard, int wclen, uint16_t attr)
-{
-
- ctx->f_type = ft_LM1;
- ctx->f_attrmask = attr;
- if (wildcard) {
- if (wclen == 1 && wildcard[0] == '*') {
- ctx->f_wildcard = "*.*";
- ctx->f_wclen = 3;
- } else {
- ctx->f_wildcard = wildcard;
- ctx->f_wclen = wclen;
- }
- } else {
- ctx->f_wildcard = NULL;
- ctx->f_wclen = 0;
- }
- ctx->f_name = (char *)ctx->f_fname;
- ctx->f_namesz = 0;
- return (0);
-}
-
-static int
-smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit)
-{
- struct mdchain *mdp;
- struct smb_rq *rqp;
- char *cp;
- uint8_t battr;
- uint16_t date, time;
- uint32_t size;
- int error;
- struct timespec ts;
-
- if (ctx->f_ecnt == 0) {
- if (ctx->f_flags & SMBFS_RDD_EOF)
- return (ENOENT);
- ctx->f_left = ctx->f_limit = limit;
- gethrestime(&ts);
- error = smbfs_smb_search(ctx);
- if (error)
- return (error);
- }
- rqp = ctx->f_rq;
- smb_rq_getreply(rqp, &mdp);
- md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
- md_get_uint8(mdp, &battr);
- md_get_uint16le(mdp, &time);
- md_get_uint16le(mdp, &date);
- md_get_uint32le(mdp, &size);
- cp = ctx->f_name;
- error = md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM);
- cp[sizeof (ctx->f_fname) - 1] = 0;
- cp += strlen(cp) - 1;
- while (*cp == ' ' && cp >= ctx->f_name)
- *cp-- = 0;
- ctx->f_attr.fa_attr = battr;
- smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
- &ctx->f_attr.fa_mtime);
- ctx->f_attr.fa_size = size;
- ctx->f_nmlen = strlen(ctx->f_name);
- ctx->f_ecnt--;
- ctx->f_left--;
- return (0);
-}
-
-static int
-smbfs_smb_findcloseLM1(struct smbfs_fctx *ctx)
-{
- if (ctx->f_rq)
- smb_rq_done(ctx->f_rq);
- return (0);
-}
-
/*
- * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
+ * Protocol-level directory open
*/
-static int
-smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
-{
- struct smb_t2rq *t2p;
- struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint16_t ecnt, eos, lno, flags;
- int error;
-
- if (ctx->f_t2) {
- smb_t2_done(ctx->f_t2);
- ctx->f_t2 = NULL;
- }
- flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
- if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
- flags |= FIND2_CLOSE_AFTER_REQUEST;
- ctx->f_flags |= SMBFS_RDD_NOCLOSE;
- }
- if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
- error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
- ctx->f_scred, &t2p);
- if (error)
- return (error);
- ctx->f_t2 = t2p;
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, ctx->f_attrmask);
- mb_put_uint16le(mbp, ctx->f_limit);
- mb_put_uint16le(mbp, flags);
- mb_put_uint16le(mbp, ctx->f_infolevel);
- mb_put_uint32le(mbp, 0);
- error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
- ctx->f_wildcard, ctx->f_wclen, '\\');
- if (error)
- return (error);
- } else {
- error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
- ctx->f_scred, &t2p);
- if (error)
- return (error);
- ctx->f_t2 = t2p;
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, ctx->f_Sid);
- mb_put_uint16le(mbp, ctx->f_limit);
- mb_put_uint16le(mbp, ctx->f_infolevel);
- /* Send whatever resume key we received... */
- mb_put_uint32le(mbp, ctx->f_rkey);
- mb_put_uint16le(mbp, flags);
- /* ... and the resume name if we have one. */
- if (ctx->f_rname) {
- /* resume file name */
- mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
- MB_MSYSTEM);
- }
- /* Add trailing null - 1 byte if ASCII, 2 if Unicode */
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
- mb_put_uint8(mbp, 0);
- }
- t2p->t2_maxpcount = 5 * 2;
- t2p->t2_maxdcount = 0xF000; /* 64K less some overhead */
- error = smb_t2_request(t2p);
- if (error)
- return (error);
-
- /*
- * This is the "resume name" we just sent.
- * We want the new one (if any) that may be
- * found in the response we just received and
- * will now begin parsing. Free the old one
- * now so we'll know if we found a new one.
- */
- if (ctx->f_rname) {
- kmem_free(ctx->f_rname, ctx->f_rnamelen);
- ctx->f_rname = NULL;
- ctx->f_rnamelen = 0;
- }
-
- mdp = &t2p->t2_rparam;
- if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
- if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0)
- goto nodata;
- ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
- }
- md_get_uint16le(mdp, &ecnt); /* entry count */
- md_get_uint16le(mdp, &eos); /* end of search */
- md_get_uint16le(mdp, NULL); /* EA err. off. */
- error = md_get_uint16le(mdp, &lno); /* last name off. */
- if (error != 0)
- goto nodata;
-
- /*
- * The "end of search" flag from an XP server sometimes
- * comes back zero when the prior find_next returned exactly
- * the number of entries requested. in which case we'd try again
- * but the search has in fact been closed so an EBADF results.
- * our circumvention is to check here for a zero entry count.
- */
- ctx->f_ecnt = ecnt;
- if (eos || ctx->f_ecnt == 0)
- ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
- if (ctx->f_ecnt == 0)
- return (ENOENT);
-
- /* Last Name Off (LNO) is the entry with the resume name. */
- ctx->f_rnameofs = lno;
- ctx->f_eofs = 0;
- return (0);
-
-nodata:
- /*
- * Failed parsing the FindFirst or FindNext response.
- * Force this directory listing closed, otherwise the
- * calling process may hang in an infinite loop.
- */
- ctx->f_ecnt = 0; /* Force closed. */
- ctx->f_flags |= SMBFS_RDD_EOF;
- return (EIO);
-}
-
-static int
-smbfs_smb_findclose2(struct smbfs_fctx *ctx)
-{
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
- ctx->f_scred);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, ctx->f_Sid);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- /* Ditto comments at _smb_close */
- rqp->sr_flags |= SMBR_NOINTR_SEND;
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
- return (error);
-}
-
-/*ARGSUSED*/
-static int
-smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
- const char *wildcard, int wclen, uint16_t attr)
-{
-
- ctx->f_type = ft_LM2;
- ctx->f_namesz = SMB_MAXFNAMELEN + 1;
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- ctx->f_namesz *= 2;
- ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
- ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp))
- < SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD :
- SMB_FIND_BOTH_DIRECTORY_INFO;
- ctx->f_attrmask = attr;
- ctx->f_wildcard = wildcard;
- ctx->f_wclen = wclen;
- return (0);
-}
-
-static int
-smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
-{
- struct mdchain *mdp;
- struct smb_t2rq *t2p;
- char *cp;
- uint8_t tb;
- uint16_t date, time, wattr;
- uint32_t size, next, dattr, resumekey = 0;
- uint64_t llongint;
- int error, svtz, cnt, fxsz, nmlen, recsz;
- struct timespec ts;
-
- if (ctx->f_ecnt == 0) {
- if (ctx->f_flags & SMBFS_RDD_EOF)
- return (ENOENT);
- ctx->f_left = ctx->f_limit = limit;
- gethrestime(&ts);
- error = smbfs_smb_trans2find2(ctx);
- if (error)
- return (error);
- ctx->f_otws++;
- }
- t2p = ctx->f_t2;
- mdp = &t2p->t2_rdata;
- svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
- switch (ctx->f_infolevel) {
- case SMB_FIND_STANDARD:
- next = 0;
- fxsz = 0;
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* creation time */
- smb_dos2unixtime(date, time, 0, svtz,
- &ctx->f_attr.fa_createtime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* access time */
- smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* modify time */
- smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
- md_get_uint32le(mdp, &size);
- ctx->f_attr.fa_size = size;
- md_get_uint32le(mdp, &size); /* allocation size */
- ctx->f_attr.fa_allocsz = size;
- md_get_uint16le(mdp, &wattr);
- ctx->f_attr.fa_attr = wattr;
- error = md_get_uint8(mdp, &tb);
- if (error)
- goto nodata;
- size = nmlen = tb;
- fxsz = 23;
- recsz = next = 24 + nmlen; /* docs misses zero byte @end */
- break;
- case SMB_FIND_DIRECTORY_INFO:
- case SMB_FIND_BOTH_DIRECTORY_INFO:
- md_get_uint32le(mdp, &next);
- md_get_uint32le(mdp, &resumekey); /* file index (resume key) */
- md_get_uint64le(mdp, &llongint); /* creation time */
- smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime);
- md_get_uint64le(mdp, &llongint);
- smb_time_NT2local(llongint, &ctx->f_attr.fa_atime);
- md_get_uint64le(mdp, &llongint);
- smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime);
- md_get_uint64le(mdp, &llongint);
- smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime);
- md_get_uint64le(mdp, &llongint); /* file size */
- ctx->f_attr.fa_size = llongint;
- md_get_uint64le(mdp, &llongint); /* alloc. size */
- ctx->f_attr.fa_allocsz = llongint;
- md_get_uint32le(mdp, &dattr); /* ext. file attributes */
- ctx->f_attr.fa_attr = dattr;
- error = md_get_uint32le(mdp, &size); /* name len */
- if (error)
- goto nodata;
- fxsz = 64; /* size ofinfo up to filename */
- if (ctx->f_infolevel == SMB_FIND_BOTH_DIRECTORY_INFO) {
- /*
- * Skip EaSize(4 bytes), a byte of ShortNameLength,
- * a reserved byte, and ShortName(8.3 means 24 bytes,
- * as Leach defined it to always be Unicode)
- */
- error = md_get_mem(mdp, NULL, 30, MB_MSYSTEM);
- if (error)
- goto nodata;
- fxsz += 30;
- }
- recsz = next ? next : fxsz + size;
- break;
- default:
- SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
- return (EINVAL);
- }
-
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- nmlen = min(size, SMB_MAXFNAMELEN * 2);
- else
- nmlen = min(size, SMB_MAXFNAMELEN);
-
- /* Allocated f_name in findopen */
- ASSERT(nmlen < ctx->f_namesz);
- cp = ctx->f_name;
-
- error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM);
- if (error)
- goto nodata;
- if (next) {
- /* How much data to skip? */
- cnt = next - nmlen - fxsz;
- if (cnt < 0) {
- SMBVDEBUG("out of sync\n");
- goto nodata;
- }
- if (cnt > 0)
- md_get_mem(mdp, NULL, cnt, MB_MSYSTEM);
- }
- /* Don't count any trailing null in the name. */
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
- if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
- nmlen -= 2;
- } else {
- if (nmlen && cp[nmlen - 1] == 0)
- nmlen--;
- }
- if (nmlen == 0)
- goto nodata;
-
- /*
- * On a find-next we expect that the server will:
- * 1) if the continue bit is set, use the server's offset,
- * 2) else if the resume key is non-zero, use that offset,
- * 3) else if the resume name is set, use that offset,
- * 4) else use the server's idea of current offset.
- *
- * We always set the resume key flag. If the server returns
- * a resume key then we should always send it back to them.
- */
- ctx->f_rkey = resumekey;
-
- next = ctx->f_eofs + recsz;
- if (ctx->f_rnameofs &&
- ctx->f_rnameofs >= ctx->f_eofs &&
- ctx->f_rnameofs < (int)next) {
- /*
- * This entry is the "resume name".
- * Save it for the next request.
- */
- if (ctx->f_rnamelen != nmlen) {
- if (ctx->f_rname)
- kmem_free(ctx->f_rname, ctx->f_rnamelen);
- ctx->f_rname = kmem_alloc(nmlen, KM_SLEEP);
- ctx->f_rnamelen = nmlen;
- }
- bcopy(ctx->f_name, ctx->f_rname, nmlen);
- }
- ctx->f_nmlen = nmlen;
- ctx->f_eofs = next;
- ctx->f_ecnt--;
- ctx->f_left--;
-
- smbfs_fname_tolocal(ctx);
- return (0);
-
-nodata:
- /*
- * Something bad has happened and we ran out of data
- * before we could parse all f_ecnt entries expected.
- * Force this directory listing closed, otherwise the
- * calling process may hang in an infinite loop.
- */
- SMBVDEBUG("ran out of data\n");
- ctx->f_ecnt = 0; /* Force closed. */
- ctx->f_flags |= SMBFS_RDD_EOF;
- return (EIO);
-}
-
-static int
-smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
-{
- int error = 0;
- if (ctx->f_name)
- kmem_free(ctx->f_name, ctx->f_namesz);
- if (ctx->f_t2)
- smb_t2_done(ctx->f_t2);
- /*
- * If SMBFS_RDD_FINDFIRST is still set, we were opened
- * but never saw a findfirst, so we don't have any
- * search handle to close.
- */
- if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0)
- error = smbfs_smb_findclose2(ctx);
- return (error);
-}
-
int
smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
int attr, struct smb_cred *scrp,
struct smbfs_fctx **ctxpp)
{
+ struct smb_share *ssp = dnp->n_mount->smi_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
struct smbfs_fctx *ctx;
int error;
@@ -2288,50 +586,56 @@ smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
ctx->f_flags = SMBFS_RDD_FINDFIRST;
ctx->f_dnp = dnp;
ctx->f_scred = scrp;
- ctx->f_ssp = dnp->n_mount->smi_share;
+ ctx->f_ssp = ssp;
if (dnp->n_flag & N_XATTR) {
error = smbfs_xa_findopen(ctx, dnp, wild, wlen);
goto out;
}
- if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0) {
- error = smbfs_smb_findopenLM1(ctx, dnp, wild, wlen, attr);
+ if (vcp->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_findopen(ctx, dnp, wild, wlen, attr);
} else {
error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr);
}
out:
- if (error)
- (void) smbfs_smb_findclose(ctx, scrp);
- else
+ ctx->f_scred = NULL;
+ if (error) {
+ kmem_free(ctx, sizeof (*ctx));
+ } else {
*ctxpp = ctx;
+ }
+
return (error);
}
int
smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
{
- int error;
+ int error = 0;
+ uint16_t lim;
/*
* Note: "limit" (maxcount) needs to fit in a short!
*/
if (limit > 0xffff)
limit = 0xffff;
+ lim = (uint16_t)limit;
ctx->f_scred = scrp;
for (;;) {
bzero(&ctx->f_attr, sizeof (ctx->f_attr));
switch (ctx->f_type) {
- case ft_LM1:
- error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit);
+
+ case ft_SMB2:
+ error = smbfs_smb2_findnext(ctx, lim);
break;
case ft_LM2:
- error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit);
+ error = smbfs_smb_findnextLM2(ctx, lim);
break;
case ft_XA:
- error = smbfs_xa_findnext(ctx, (uint16_t)limit);
+ error = smbfs_xa_findnext(ctx, lim);
break;
default:
ASSERT(0);
@@ -2339,7 +643,7 @@ smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
break;
}
if (error)
- return (error);
+ break;
/*
* Skip "." or ".." - easy now that ctx->f_name
* has already been converted to utf-8 format.
@@ -2350,14 +654,18 @@ smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
continue;
break;
}
+ ctx->f_scred = NULL;
+ if (error != 0)
+ return (error);
- /*
- * Moved the smbfs_fname_tolocal(ctx) call into
- * the ..._findnext functions above.
- */
+ ctx->f_inum = smbfs_getino(ctx->f_dnp,
+ ctx->f_name, ctx->f_nmlen);
- ctx->f_inum = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
- return (0);
+#ifdef DEBUG
+ SMBVDEBUG("findnext: (%s)\n", ctx->f_name);
+#endif
+
+ return (error);
}
@@ -2368,8 +676,8 @@ smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
ctx->f_scred = scrp;
switch (ctx->f_type) {
- case ft_LM1:
- error = smbfs_smb_findcloseLM1(ctx);
+ case ft_SMB2:
+ error = smbfs_smb2_findclose(ctx);
break;
case ft_LM2:
error = smbfs_smb_findcloseLM2(ctx);
@@ -2381,6 +689,7 @@ smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
error = ENOSYS;
break;
}
+ ctx->f_scred = NULL;
if (ctx->f_rname)
kmem_free(ctx->f_rname, ctx->f_rnamelen);
if (ctx->f_firstnm)
@@ -2420,25 +729,12 @@ smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
}
/*
- * XXX: Should use _qpathinfo here instead.
- * (if SMB_CAP_NT_SMBS)
- */
-
- /*
* Shared lock for n_fid use (smb_flush).
*/
intr = dnp->n_mount->smi_flags & SMI_INT;
if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr))
return (EINTR);
- /*
- * This hides a server bug observable in Win98:
- * size changes may not show until a CLOSE or a FLUSH op
- * XXX: Make this conditional on !NTSMBs
- */
- error = smbfs_smb_flush(dnp, scrp);
- if (error)
- goto out;
error = smbfs_smb_findopen(dnp, name, nmlen,
SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx);
if (error)
@@ -2472,148 +768,49 @@ out:
* which the caller should free.
*/
int
-smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
- struct smb_cred *scrp, uint32_t selector,
- mblk_t **res, uint32_t *reslen)
+smbfs_smb_getsec(struct smb_share *ssp, smb_fh_t *fhp,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp)
{
- struct smb_ntrq *ntp;
- struct mbchain *mbp;
- struct mdchain *mdp;
+ struct smb_vc *vcp = SSTOVC(ssp);
int error, len;
- error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
- scrp, &ntp);
- if (error)
- return (error);
-
- /* Parameters part */
- mbp = &ntp->nt_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, 0); /* reserved */
- mb_put_uint32le(mbp, selector);
- /* Data part (none) */
-
- /* Max. returned parameters and data. */
- ntp->nt_maxpcount = 4;
- ntp->nt_maxdcount = *reslen;
-
- error = smb_nt_request(ntp);
- if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
- goto done;
*res = NULL;
- /*
- * if there's more data than we said we could receive, here
- * is where we pick up the length of it
- */
- mdp = &ntp->nt_rparam;
- md_get_uint32le(mdp, reslen);
- if (error)
- goto done;
+ if (vcp->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_getsec(ssp, &fhp->fh_fid2,
+ selector, res, reslen, scrp);
+ } else {
+ error = smbfs_smb1_getsec(ssp, fhp->fh_fid1,
+ selector, res, reslen, scrp);
+ }
/*
* get the data part.
*/
- mdp = &ntp->nt_rdata;
- if (mdp->md_top == NULL) {
- SMBVDEBUG("null md_top? fid 0x%x\n", fid);
+ if (*res == NULL) {
error = EBADRPC;
goto done;
}
/*
- * The returned parameter SD_length should match
- * the length of the returned data. Unfortunately,
- * we have to work around server bugs here.
- */
- len = m_fixhdr(mdp->md_top);
- if (len != *reslen) {
- SMBVDEBUG("len %d *reslen %d fid 0x%x\n",
- len, *reslen, fid);
- }
-
- /*
- * Actual data provided is < returned SD_length.
- *
- * The following "if (len < *reslen)" handles a Windows bug
- * observed when the underlying filesystem is FAT32. In that
- * case a 32 byte security descriptor comes back (S-1-1-0, ie
- * "Everyone") but the Parameter Block claims 44 is the length
- * of the security descriptor. (The Data Block length
- * claimed is 32. This server bug was reported against NT
- * first and I've personally observed it with W2K.
+ * If message length is < returned SD_length,
+ * correct *reslen (reduce it). It greater,
+ * just ignore the extra data.
*/
+ len = m_fixhdr(*res);
if (len < *reslen)
*reslen = len;
- /*
- * Actual data provided is > returned SD_length.
- * (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0)
- * Narrow work-around for returned SD_length==0.
- */
- if (len > *reslen) {
- /*
- * Increase *reslen, but carefully.
- */
- if (*reslen == 0 && len <= ntp->nt_maxdcount)
- *reslen = len;
- }
- error = md_get_mbuf(mdp, len, res);
-
done:
if (error == 0 && *res == NULL) {
ASSERT(*res);
error = EBADRPC;
}
- smb_nt_done(ntp);
return (error);
}
-#ifdef APPLE
-/*
- * Wrapper for _getsd() compatible with darwin code.
- */
-int
-smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
- uint32_t selector, struct ntsecdesc **res)
-{
- int error;
- uint32_t len, olen;
- struct mdchain *mdp, md_store;
- struct mbuf *m;
-
- bzero(mdp, sizeof (*mdp));
- len = 500; /* "overlarge" values => server errors */
-again:
- olen = len;
- error = smbfs_smb_getsec_m(ssp, fid, scrp, selector, &m, &len);
- /*
- * Server may give us an error indicating that we
- * need a larger data buffer to receive the SD,
- * and the size we'll need. Use the given size,
- * but only after a sanity check.
- *
- * XXX: Check for specific error values here?
- * XXX: also ... && len <= MAX_RAW_SD_SIZE
- */
- if (error && len > olen)
- goto again;
-
- if (error)
- return (error);
-
- mdp = &md_store;
- md_initm(mdp, m);
- MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK);
- error = md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM);
- md_done(mdp);
-
- return (error);
-}
-#endif /* APPLE */
-
/*
* OTW function to Set a security descriptor (SD).
* Caller data are carried in an mbchain_t.
@@ -2621,108 +818,21 @@ again:
* Note: This normally consumes mbp->mb_top, and clears
* that pointer when it does.
*/
-int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
- struct smb_cred *scrp, uint32_t selector, mblk_t **mp)
-{
- struct smb_ntrq *ntp;
- struct mbchain *mbp;
- int error;
-
- error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
- scrp, &ntp);
- if (error)
- return (error);
-
- /* Parameters part */
- mbp = &ntp->nt_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, 0); /* reserved */
- mb_put_uint32le(mbp, selector);
-
- /* Data part */
- mbp = &ntp->nt_tdata;
- mb_initm(mbp, *mp);
- *mp = NULL; /* consumed */
-
- /* No returned parameters or data. */
- ntp->nt_maxpcount = 0;
- ntp->nt_maxdcount = 0;
-
- error = smb_nt_request(ntp);
- smb_nt_done(ntp);
-
- return (error);
-}
-
-#ifdef APPLE
-/*
- * This function builds the SD given the various parts.
- */
int
-smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
- uint32_t selector, uint16_t flags, struct ntsid *owner,
- struct ntsid *group, struct ntacl *sacl, struct ntacl *dacl)
+smbfs_smb_setsec(struct smb_share *ssp, smb_fh_t *fhp,
+ uint32_t selector, mblk_t **mp,
+ struct smb_cred *scrp)
{
- struct mbchain *mbp, mb_store;
- struct ntsecdesc ntsd;
- int error, off;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ int error;
- /*
- * Build the SD as its own mbuf chain and pass it to
- * smbfs_smb_setsec_m()
- */
- mbp = &mb_store;
- mb_init(mbp);
- bzero(&ntsd, sizeof (ntsd));
- wset_sdrevision(&ntsd);
- /*
- * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN)
- * We set here only those bits we can be sure must be set. The rest
- * are up to the caller. In particular, the caller may intentionally
- * set an acl PRESENT bit while giving us a null pointer for the
- * acl - that sets a null acl, giving access to everyone. Note also
- * that the AUTO_INHERITED bits should probably always be set unless
- * the server is NT.
- */
- flags |= SD_SELF_RELATIVE;
- off = sizeof (ntsd);
- if (owner) {
- wset_sdowneroff(&ntsd, off);
- off += sidlen(owner);
- }
- if (group) {
- wset_sdgroupoff(&ntsd, off);
- off += sidlen(group);
- }
- if (sacl) {
- flags |= SD_SACL_PRESENT;
- wset_sdsacloff(&ntsd, off);
- off += acllen(sacl);
- }
- if (dacl) {
- flags |= SD_DACL_PRESENT;
- wset_sddacloff(&ntsd, off);
+ if (vcp->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_setsec(ssp, &fhp->fh_fid2,
+ selector, mp, scrp);
+ } else {
+ error = smbfs_smb1_setsec(ssp, fhp->fh_fid1,
+ selector, mp, scrp);
}
- wset_sdflags(&ntsd, flags);
- mb_put_mem(mbp, (caddr_t)&ntsd, sizeof (ntsd), MB_MSYSTEM);
- if (owner)
- mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM);
- if (group)
- mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM);
- if (sacl)
- mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM);
- if (dacl)
- mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM);
-
- /*
- * Just pass the mbuf to _setsec_m
- * It will clear mb_top if consumed.
- */
- error = smbfs_smb_setsec_m(ssp, fid, scrp, selector, &mbp->mb_top);
- mb_done(mbp);
return (error);
}
-
-#endif /* APPLE */
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c
new file mode 100644
index 0000000000..6c00816133
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c
@@ -0,0 +1,926 @@
+/*
+ * 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 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>
+#include <sys/systm.h>
+#include <sys/inttypes.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+
+#include <netsmb/smb_osdep.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_rq.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+
+/*
+ * Todo: locking over-the-wire
+ */
+#if 0 // todo
+
+int
+smbfs_smb1_lockandx(struct smbnode *np, int op, uint32_t pid,
+ offset_t start, uint64_t len, int largelock,
+ struct smb_cred *scrp, uint32_t timeout)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct smb_rq rq, *rqp = &rq;
+ struct mbchain *mbp;
+ uint8_t ltype = 0;
+ int error;
+
+ /* Shared lock for n_fid use below. */
+ ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+
+ /* After reconnect, n_fid is invalid */
+ if (np->n_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
+ if (op == SMB_LOCK_SHARED)
+ ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
+ /* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */
+ if (largelock)
+ ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
+ if (error)
+ return (error);
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ mb_put_uint8(mbp, 0xff); /* secondary command */
+ mb_put_uint8(mbp, 0); /* MBZ */
+ mb_put_uint16le(mbp, 0);
+ mb_put_uint16le(mbp, np->n_fid);
+ mb_put_uint8(mbp, ltype); /* locktype */
+ mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
+ mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */
+ mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
+ mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ mb_put_uint16le(mbp, pid);
+ if (!largelock) {
+ mb_put_uint32le(mbp, start);
+ mb_put_uint32le(mbp, len);
+ } else {
+ mb_put_uint16le(mbp, 0); /* pad */
+ mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
+ mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
+ mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
+ mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
+ }
+ smb_rq_bend(rqp);
+ /*
+ * Don't want to risk missing a successful
+ * unlock send or lock response, or we could
+ * lose track of an outstanding lock.
+ */
+ if (op == SMB_LOCK_RELEASE)
+ rqp->sr_flags |= SMBR_NOINTR_SEND;
+ else
+ rqp->sr_flags |= SMBR_NOINTR_RECV;
+
+ error = smb_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+#endif // todo
+
+/*
+ * Common function for QueryFileInfo, QueryPathInfo.
+ */
+int
+smbfs_smb1_trans2_query(struct smbnode *np, uint16_t fid,
+ struct smbfattr *fap, struct smb_cred *scrp)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ struct smb_t2rq *t2p;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint16_t cmd;
+ uint16_t infolevel = SMB_QFILEINFO_ALL_INFO;
+ int error;
+
+ /*
+ * If we have a valid open FID, use it.
+ */
+ if (fid != SMB_FID_UNUSED)
+ cmd = SMB_TRANS2_QUERY_FILE_INFORMATION;
+ else
+ cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
+
+ error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
+ if (error)
+ return (error);
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+
+ if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION)
+ mb_put_uint16le(mbp, fid);
+
+ mb_put_uint16le(mbp, infolevel);
+
+ if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) {
+ mb_put_uint32le(mbp, 0);
+ /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
+ error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
+ if (error)
+ goto out;
+ }
+
+ t2p->t2_maxpcount = 2;
+ t2p->t2_maxdcount = vcp->vc_txmax;
+ error = smb_t2_request(t2p);
+ if (error)
+ goto out;
+
+ /*
+ * Parse the SMB_QFILEINFO_ALL_INFO
+ */
+ mdp = &t2p->t2_rdata;
+ error = smbfs_decode_file_all_info(ssp, mdp, fap);
+
+out:
+ smb_t2_done(t2p);
+
+ return (error);
+}
+
+/*
+ * Get some FS information
+ */
+static int
+smbfs_smb1_query_fs_info(struct smb_share *ssp, struct mdchain *info_mdp,
+ uint16_t level, struct smb_cred *scrp)
+{
+ struct smb_t2rq *t2p;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ int error;
+
+ error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
+ scrp, &t2p);
+ if (error)
+ return (error);
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, level);
+ t2p->t2_maxpcount = 4;
+ t2p->t2_maxdcount = 1024;
+ error = smb_t2_request(t2p);
+ if (error)
+ goto out;
+
+ mdp = &t2p->t2_rdata;
+ *info_mdp = *mdp;
+ bzero(mdp, sizeof (*mdp));
+
+out:
+ smb_t2_done(t2p);
+ return (error);
+}
+
+/*
+ * Get FILE_FS_ATTRIBUTE_INFORMATION
+ */
+int
+smbfs_smb1_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb1_query_fs_info(ssp, mdp,
+ SMB_QFS_ATTRIBUTE_INFO, scrp);
+ if (error)
+ goto out;
+ error = smbfs_decode_fs_attr_info(ssp, mdp, fsa);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+/*
+ * Get FileFsFullSizeInformation and
+ * parse into *info
+ */
+int
+smbfs_smb1_statfs(struct smb_share *ssp,
+ struct smb_fs_size_info *info,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ uint16_t level;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+ level = SMB_QFS_FULL_SIZE_INFORMATION;
+ else
+ level = SMB_QFS_SIZE_INFO;
+ error = smbfs_smb1_query_fs_info(ssp, mdp, level, scrp);
+ if (error)
+ goto out;
+
+ md_get_uint64le(mdp, &info->total_units);
+ md_get_uint64le(mdp, &info->caller_avail);
+ if (level == SMB_QFS_FULL_SIZE_INFORMATION)
+ md_get_uint64le(mdp, &info->actual_avail);
+ else
+ info->actual_avail = info->caller_avail;
+
+ md_get_uint32le(mdp, &info->sect_per_unit);
+ error = md_get_uint32le(mdp, &info->bytes_per_sect);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+int
+smbfs_smb1_flush(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
+ if (error)
+ return (error);
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, fid);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+/*
+ * Set file info via an open handle.
+ * Caller provides payload, info level.
+ */
+static int
+smbfs_smb1_setinfo_file(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *info_mbp, uint16_t level, struct smb_cred *scrp)
+{
+ struct smb_t2rq *t2p = NULL;
+ struct mbchain *mbp;
+ uint16_t cmd = SMB_TRANS2_SET_FILE_INFORMATION;
+ int error;
+
+ ASSERT(fid != SMB_FID_UNUSED);
+
+ error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
+ if (error)
+ return (error);
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, level);
+ mb_put_uint16le(mbp, 0); /* pad */
+
+ /* put the payload */
+ mbp = &t2p->t2_tdata;
+ mb_init(mbp);
+ error = mb_put_mbchain(mbp, info_mbp);
+ if (error)
+ goto out;
+
+ t2p->t2_maxpcount = 2;
+ t2p->t2_maxdcount = 0;
+ error = smb_t2_request(t2p);
+
+out:
+ smb_t2_done(t2p);
+
+ return (error);
+}
+
+int
+smbfs_smb1_seteof(struct smb_share *ssp, uint16_t fid,
+ uint64_t newsize, struct smb_cred *scrp)
+{
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint16_t level;
+ int error;
+
+ if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+ level = SMB_SFILEINFO_END_OF_FILE_INFORMATION;
+ else
+ level = SMB_SFILEINFO_END_OF_FILE_INFO;
+
+ mb_init(mbp);
+ error = mb_put_uint64le(mbp, newsize);
+ if (error)
+ goto out;
+ error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
+
+out:
+ mb_done(mbp);
+ return (error);
+}
+
+int
+smbfs_smb1_setdisp(struct smb_share *ssp, uint16_t fid,
+ uint8_t newdisp, struct smb_cred *scrp)
+{
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint16_t level;
+ int error;
+
+ if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+ level = SMB_SFILEINFO_DISPOSITION_INFORMATION;
+ else
+ level = SMB_SFILEINFO_DISPOSITION_INFO;
+
+ mb_init(mbp);
+ error = mb_put_uint8(mbp, newdisp);
+ if (error)
+ goto out;
+ error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
+
+out:
+ mb_done(mbp);
+
+ return (error);
+}
+
+/*
+ * Set FileBasicInformation on an open handle
+ * Caller builds the mbchain.
+ * Always have a FID here.
+ */
+int
+smbfs_smb1_setfattr(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *mbp, struct smb_cred *scrp)
+{
+ uint16_t level;
+ int error;
+
+ if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+ level = SMB_SFILEINFO_BASIC_INFORMATION;
+ else
+ level = SMB_SFILEINFO_BASIC_INFO;
+ error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
+
+ return (error);
+}
+
+/*
+ * On SMB1, the trans2 rename only allows a rename where the
+ * source and target are in the same directory. If you give
+ * the server any separators, you get "status not supported".
+ *
+ * Why bother using this instead of smbfs_smb1_oldrename?
+ * Because it works with an open file, and some servers don't
+ * allow oldrename of a file that's currently open. We call
+ * this when deleting an open file in smbfsremove(), where
+ * the rename is always in the same directory.
+ */
+/*ARGSUSED*/
+int
+smbfs_smb1_t2rename(struct smbnode *np,
+ const char *tname, int tnlen,
+ uint16_t fid, struct smb_cred *scrp)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct mbchain data_mb, *mbp = &data_mb;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ uint32_t *name_lenp;
+ uint16_t level = SMB_SFILEINFO_RENAME_INFORMATION;
+ int base, len;
+ int error;
+
+ mb_init(mbp);
+ mb_put_uint32le(mbp, 0); /* don't overwrite */
+ mb_put_uint32le(mbp, 0); /* obsolete target dir fid */
+ name_lenp = mb_reserve(mbp, 4); /* name len */
+
+ /* New name */
+ base = mbp->mb_count;
+ error = smb_put_dmem(mbp, vcp, tname, tnlen, SMB_CS_NONE, NULL);
+ if (error)
+ goto out;
+ len = mbp->mb_count - base;
+ *name_lenp = htolel(len);
+
+ error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
+
+out:
+ mb_done(mbp);
+ return (error);
+}
+
+/*
+ * Do an SMB1 (old style) rename using a full dest. path.
+ * This is used when renaming to a different directory,
+ * because the (preferred) t2rename can't do that.
+ */
+int
+smbfs_smb1_oldrename(struct smbnode *src, struct smbnode *tdnp,
+ const char *tname, int tnmlen, struct smb_cred *scrp)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct smb_share *ssp = src->n_mount->smi_share;
+ struct mbchain *mbp;
+ int error;
+ uint16_t fa;
+ char sep;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
+ if (error)
+ return (error);
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ /* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
+ fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
+ fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
+ mb_put_uint16le(mbp, fa);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+
+ /*
+ * When we're not adding any component name, the
+ * passed sep is ignored, so just pass sep=0.
+ */
+ mb_put_uint8(mbp, SMB_DT_ASCII);
+ error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0);
+ if (error)
+ goto out;
+
+ /*
+ * After XATTR directories, separator is ":"
+ */
+ sep = (src->n_flag & N_XATTR) ? ':' : '\\';
+ mb_put_uint8(mbp, SMB_DT_ASCII);
+ error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, sep);
+ if (error)
+ goto out;
+
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+out:
+ smb_rq_done(rqp);
+ return (error);
+}
+
+
+/*
+ * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
+ */
+static int
+smbfs_smb1_trans2find2(struct smbfs_fctx *ctx)
+{
+ struct smb_t2rq *t2p;
+ struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint16_t ecnt, eos, lno, flags;
+ uint16_t amask, limit;
+ int error;
+
+ /* smbfs_smb_findnextLM2 sets this */
+ limit = ctx->f_limit;
+ amask = (uint16_t)ctx->f_attrmask;
+
+ if (ctx->f_t2) {
+ smb_t2_done(ctx->f_t2);
+ ctx->f_t2 = NULL;
+ }
+ flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
+ if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
+ flags |= FIND2_CLOSE_AFTER_REQUEST;
+ ctx->f_flags |= SMBFS_RDD_NOCLOSE;
+ }
+ if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
+ error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
+ ctx->f_scred, &t2p);
+ if (error)
+ return (error);
+ ctx->f_t2 = t2p;
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, amask);
+ mb_put_uint16le(mbp, limit);
+ mb_put_uint16le(mbp, flags);
+ mb_put_uint16le(mbp, ctx->f_infolevel);
+ mb_put_uint32le(mbp, 0);
+ error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
+ ctx->f_wildcard, ctx->f_wclen, '\\');
+ if (error)
+ return (error);
+ } else {
+ error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
+ ctx->f_scred, &t2p);
+ if (error)
+ return (error);
+ ctx->f_t2 = t2p;
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, ctx->f_Sid);
+ mb_put_uint16le(mbp, limit);
+ mb_put_uint16le(mbp, ctx->f_infolevel);
+ /* Send whatever resume key we received... */
+ mb_put_uint32le(mbp, ctx->f_rkey);
+ mb_put_uint16le(mbp, flags);
+ /* ... and the resume name if we have one. */
+ if (ctx->f_rname) {
+ /* resume file name */
+ mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
+ MB_MSYSTEM);
+ }
+ /* Add trailing null - 1 byte if ASCII, 2 if Unicode */
+ if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
+ mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
+ mb_put_uint8(mbp, 0);
+ }
+ t2p->t2_maxpcount = 5 * 2;
+ t2p->t2_maxdcount = 0xF000; /* 64K less some overhead */
+ error = smb_t2_request(t2p);
+ if (error)
+ return (error);
+
+ /*
+ * This is the "resume name" we just sent.
+ * We want the new one (if any) that may be
+ * found in the response we just received and
+ * will now begin parsing. Free the old one
+ * now so we'll know if we found a new one.
+ */
+ if (ctx->f_rname) {
+ kmem_free(ctx->f_rname, ctx->f_rnamelen);
+ ctx->f_rname = NULL;
+ ctx->f_rnamelen = 0;
+ }
+
+ mdp = &t2p->t2_rparam;
+ if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
+ if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0)
+ goto nodata;
+ ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
+ }
+ md_get_uint16le(mdp, &ecnt); /* entry count */
+ md_get_uint16le(mdp, &eos); /* end of search */
+ md_get_uint16le(mdp, NULL); /* EA err. off. */
+ error = md_get_uint16le(mdp, &lno); /* last name off. */
+ if (error != 0)
+ goto nodata;
+
+ /*
+ * The "end of search" flag from an XP server sometimes
+ * comes back zero when the prior find_next returned exactly
+ * the number of entries requested. in which case we'd try again
+ * but the search has in fact been closed so an EBADF results.
+ * our circumvention is to check here for a zero entry count.
+ */
+ ctx->f_ecnt = ecnt;
+ if (eos || ctx->f_ecnt == 0)
+ ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
+ if (ctx->f_ecnt == 0)
+ return (ENOENT);
+
+ /* Last Name Off (LNO) is the entry with the resume name. */
+ ctx->f_rnameofs = lno;
+ ctx->f_eofs = 0;
+
+ /*
+ * Have data. Put the payload in ctx->f_mdchain
+ * Note struct assignments here.
+ */
+ mdp = &t2p->t2_rdata;
+ md_done(&ctx->f_mdchain);
+ ctx->f_mdchain = *mdp;
+ ctx->f_left = m_fixhdr(mdp->md_top);
+ bzero(mdp, sizeof (*mdp));
+
+ return (0);
+
+nodata:
+ /*
+ * Failed parsing the FindFirst or FindNext response.
+ * Force this directory listing closed, otherwise the
+ * calling process may hang in an infinite loop.
+ */
+ ctx->f_ecnt = 0; /* Force closed. */
+ ctx->f_flags |= SMBFS_RDD_EOF;
+ return (EIO);
+}
+
+static int
+smbfs_smb1_findclose2(struct smbfs_fctx *ctx)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
+ ctx->f_scred);
+ if (error)
+ return (error);
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, ctx->f_Sid);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ smb_rq_bend(rqp);
+ /* Ditto comments at _smb_close */
+ rqp->sr_flags |= SMBR_NOINTR_SEND;
+ error = smb_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen, uint32_t attr)
+{
+
+ ctx->f_type = ft_LM2;
+ ctx->f_namesz = SMB_MAXFNAMELEN + 1;
+ ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
+ ctx->f_infolevel = SMB_FIND_FULL_DIRECTORY_INFO;
+ ctx->f_attrmask = attr;
+ ctx->f_wildcard = wildcard;
+ ctx->f_wclen = wclen;
+ return (0);
+}
+
+int
+smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
+{
+ int error = 0;
+ if (ctx->f_name)
+ kmem_free(ctx->f_name, ctx->f_namesz);
+ if (ctx->f_t2)
+ smb_t2_done(ctx->f_t2);
+ md_done(&ctx->f_mdchain);
+
+ /*
+ * If SMBFS_RDD_FINDFIRST is still set, we were opened
+ * but never saw a findfirst, so we don't have any
+ * search handle to close.
+ */
+ if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0)
+ error = smbfs_smb1_findclose2(ctx);
+ return (error);
+}
+
+/*
+ * Get a buffer of directory entries (if we don't already have
+ * some remaining in the current buffer) then decode one.
+ */
+int
+smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
+{
+ int error;
+
+ /*
+ * If we've scanned to the end of the current buffer
+ * try to read anohther buffer of dir entries.
+ * Treat anything less than 8 bytes as an "empty"
+ * buffer to ensure we can read something.
+ * (There may be up to 8 bytes of padding.)
+ */
+ if ((ctx->f_eofs + 8) > ctx->f_left) {
+ /* Scanned the whole buffer. */
+ if (ctx->f_flags & SMBFS_RDD_EOF)
+ return (ENOENT);
+ ctx->f_limit = limit;
+ error = smbfs_smb1_trans2find2(ctx);
+ if (error)
+ return (error);
+ ctx->f_otws++;
+ }
+
+ /*
+ * Decode one entry, advance f_eofs
+ */
+ error = smbfs_decode_dirent(ctx);
+
+ return (error);
+}
+
+/*
+ * Helper for smbfs_xa_get_streaminfo
+ * Query stream info
+ */
+int
+smbfs_smb1_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
+ struct smb_cred *scrp)
+{
+ smb_share_t *ssp = np->n_mount->smi_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ struct smb_t2rq *t2p = NULL;
+ struct mbchain *mbp;
+ mblk_t *m;
+ uint16_t cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
+ int error;
+
+ error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
+ if (error)
+ return (error);
+
+ mbp = &t2p->t2_tparam;
+ (void) mb_init(mbp);
+ (void) mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO);
+ (void) mb_put_uint32le(mbp, 0);
+ error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, 0);
+ if (error)
+ goto out;
+
+ t2p->t2_maxpcount = 2;
+ t2p->t2_maxdcount = INT16_MAX;
+ error = smb_t2_request(t2p);
+ if (error) {
+ if (t2p->t2_sr_error == NT_STATUS_INVALID_PARAMETER)
+ error = ENOTSUP;
+ goto out;
+ }
+
+ /*
+ * Have data. Move it to *mdp
+ */
+ m = t2p->t2_rdata.md_top;
+ if (m == NULL) {
+ error = EBADRPC;
+ goto out;
+ }
+ t2p->t2_rdata.md_top = NULL;
+ md_initm(mdp, m);
+
+out:
+ smb_t2_done(t2p);
+ return (error);
+}
+
+/*
+ * OTW function to Get a security descriptor (SD).
+ *
+ * The *reslen param is bufsize(in) / length(out)
+ * Note: On success, this fills in mdp->md_top,
+ * which the caller should free.
+ */
+int
+smbfs_smb1_getsec(struct smb_share *ssp, uint16_t fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp)
+{
+ struct smb_ntrq *ntp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint32_t dlen;
+ int error;
+
+ *res = NULL;
+
+ error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
+ scrp, &ntp);
+ if (error)
+ return (error);
+
+ /* Parameters part */
+ mbp = &ntp->nt_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, 0); /* reserved */
+ mb_put_uint32le(mbp, selector);
+ /* Data part (none) */
+
+ /* Max. returned parameters and data. */
+ ntp->nt_maxpcount = 4;
+ ntp->nt_maxdcount = *reslen; // out buf size
+
+ error = smb_nt_request(ntp);
+ if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
+ goto done;
+
+ /* Get data len */
+ mdp = &ntp->nt_rparam;
+ error = md_get_uint32le(mdp, &dlen);
+ if (error)
+ goto done;
+
+ /*
+ * if there's more data than we said we could receive,
+ * here is where we pick up the length of it
+ */
+ *reslen = dlen;
+ if (dlen == 0) {
+ error = EBADRPC;
+ goto done;
+ }
+
+ /*
+ * get the SD data part.
+ */
+ mdp = &ntp->nt_rdata;
+ error = md_get_mbuf(mdp, dlen, res);
+
+done:
+ if (error == 0 && *res == NULL) {
+ ASSERT(*res);
+ error = EBADRPC;
+ }
+
+ smb_nt_done(ntp);
+ return (error);
+}
+
+
+/*
+ * OTW function to Set a security descriptor (SD).
+ * Caller data are carried in an mbchain_t.
+ *
+ * Note: This normally consumes mbp->mb_top, and clears
+ * that pointer when it does.
+ */
+int
+smbfs_smb1_setsec(struct smb_share *ssp, uint16_t fid,
+ uint32_t selector, mblk_t **mp, struct smb_cred *scrp)
+{
+ struct smb_ntrq *ntp;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
+ scrp, &ntp);
+ if (error)
+ return (error);
+
+ /* Parameters part */
+ mbp = &ntp->nt_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, 0); /* reserved */
+ mb_put_uint32le(mbp, selector);
+
+ /* Data part */
+ mbp = &ntp->nt_tdata;
+ mb_initm(mbp, *mp);
+ *mp = NULL; /* consumed */
+
+ /* No returned parameters or data. */
+ ntp->nt_maxpcount = 0;
+ ntp->nt_maxdcount = 0;
+
+ error = smb_nt_request(ntp);
+ smb_nt_done(ntp);
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c
new file mode 100644
index 0000000000..80afc327c3
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c
@@ -0,0 +1,896 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 2011 - 2013 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/inttypes.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+
+#include <netsmb/smb_osdep.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+
+/*
+ * Todo: locking over-the-wire
+ */
+#if 0 // todo
+
+int
+smbfs_smb2_locking(struct smbnode *np, int op, uint32_t pid,
+ offset_t start, uint64_t len, int largelock,
+ struct smb_cred *scrp, uint32_t timeout)
+{
+ return (ENOTSUP);
+}
+
+#endif // todo
+
+/*
+ * Helper for smbfs_getattr_otw
+ * used when we don't have an open FID
+ *
+ * For SMB2 we need to do an attribute-only open. The
+ * data returned by open gets us everything we need, so
+ * just close the handle and we're done.
+ */
+int
+smbfs_smb2_getpattr(
+ struct smbnode *np,
+ struct smbfattr *fap,
+ struct smb_cred *scrp)
+{
+ smb_fh_t tmp_fh;
+ struct smb_share *ssp = np->n_mount->smi_share;
+ uint32_t rights = (STD_RIGHT_READ_CONTROL_ACCESS |
+ SA_RIGHT_FILE_READ_ATTRIBUTES);
+ int error;
+
+ bzero(&tmp_fh, sizeof (tmp_fh));
+ error = smbfs_smb_ntcreatex(np,
+ NULL, 0, 0, /* name nmlen xattr */
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ scrp, &tmp_fh,
+ NULL, fap);
+ if (error == 0) {
+ (void) smb_smb_close(ssp, &tmp_fh, scrp);
+ }
+
+ return (error);
+}
+
+/*
+ * Common SMB2 query file info
+ */
+static int
+smbfs_smb2_query_info(struct smb_share *ssp, smb2fid_t *fid,
+ struct mdchain *info_mdp, uint32_t *iolen,
+ uint8_t type, uint8_t level, uint32_t addl_info,
+ struct smb_cred *scrp)
+{
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint32_t dlen = 0;
+ uint16_t doff = 0;
+ uint16_t ssize = 0;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_QUERY_INFO, scrp, &rqp);
+ if (error)
+ goto out;
+
+ /*
+ * Build the SMB 2 Query Info req.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 41); // struct size
+ mb_put_uint8(mbp, type);
+ mb_put_uint8(mbp, level);
+ mb_put_uint32le(mbp, *iolen); // out buf len
+ mb_put_uint16le(mbp, 0); // in buf off
+ mb_put_uint16le(mbp, 0); // reserved
+ mb_put_uint32le(mbp, 0); // in buf len
+ mb_put_uint32le(mbp, addl_info);
+ mb_put_uint32le(mbp, 0); // flags
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ error = smb2_rq_simple(rqp);
+ if (error) {
+ if (rqp->sr_error == NT_STATUS_INVALID_PARAMETER)
+ error = ENOTSUP;
+ goto out;
+ }
+
+ /*
+ * Parse SMB 2 Query Info response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 9 */
+ md_get_uint16le(mdp, &ssize);
+ if (ssize != 9) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ /* Get data off, len */
+ md_get_uint16le(mdp, &doff);
+ md_get_uint32le(mdp, &dlen);
+ *iolen = dlen;
+
+ /*
+ * Skip ahead to the payload, as needed.
+ * Current offset is SMB2_HDRLEN + 8.
+ */
+ if (dlen != 0) {
+ mblk_t *m = NULL;
+ int skip = (int)doff - (SMB2_HDRLEN + 8);
+ if (skip < 0) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+ error = md_get_mbuf(mdp, dlen, &m);
+ if (error)
+ goto out;
+ md_initm(info_mdp, m);
+ }
+
+out:
+ smb_rq_done(rqp);
+
+ return (error);
+}
+
+
+/*
+ * Get FileAllInformation for an open file
+ * and parse into *fap
+ */
+int
+smbfs_smb2_qfileinfo(struct smb_share *ssp, smb2fid_t *fid,
+ struct smbfattr *fap, struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ uint32_t iolen = 1024;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb2_query_info(ssp, fid, mdp, &iolen,
+ SMB2_0_INFO_FILE, FileAllInformation, 0, scrp);
+ if (error)
+ goto out;
+
+ error = smbfs_decode_file_all_info(ssp, mdp, fap);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+/*
+ * Get some SMB2_0_INFO_FILESYSTEM info
+ *
+ * Note: This can be called during mount. We don't have any
+ * smbfs_node_t or pathname, so do our own attr. open on
+ * the root of the share to get a handle for this request.
+ */
+static int
+smbfs_smb2_query_fs_info(struct smb_share *ssp, struct mdchain *mdp,
+ uint8_t level, struct smb_cred *scrp)
+{
+ smb2fid_t fid;
+ uint32_t iolen = 1024;
+ boolean_t opened = B_FALSE;
+ int error;
+
+ /*
+ * Need a FID for smb2, and this is called during mount
+ * so "go behind" the usual open/close functions.
+ */
+ error = smb2_smb_ntcreate(
+ ssp, NULL, // name
+ NULL, NULL, // create ctx in, out
+ 0, /* NTCREATEX_FLAGS... */
+ SA_RIGHT_FILE_READ_ATTRIBUTES,
+ SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ NTCREATEX_IMPERSONATION_IMPERSONATION,
+ scrp, &fid, NULL, NULL);
+ if (error != 0)
+ goto out;
+ opened = B_TRUE;
+
+ error = smbfs_smb2_query_info(ssp, &fid, mdp, &iolen,
+ SMB2_0_INFO_FILESYSTEM, level, 0, scrp);
+
+out:
+ if (opened)
+ (void) smb2_smb_close(ssp, &fid, scrp);
+
+ return (error);
+}
+
+/*
+ * Get FileFsAttributeInformation and
+ * parse into *info
+ */
+int
+smbfs_smb2_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *info,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb2_query_fs_info(ssp, mdp,
+ FileFsAttributeInformation, scrp);
+ if (error)
+ goto out;
+ error = smbfs_decode_fs_attr_info(ssp, mdp, info);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+/*
+ * Get FileFsFullSizeInformation and
+ * parse into *info
+ */
+int
+smbfs_smb2_statfs(struct smb_share *ssp,
+ struct smb_fs_size_info *info,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb2_query_fs_info(ssp, mdp,
+ FileFsFullSizeInformation, scrp);
+ if (error)
+ goto out;
+
+ md_get_uint64le(mdp, &info->total_units);
+ md_get_uint64le(mdp, &info->caller_avail);
+ md_get_uint64le(mdp, &info->actual_avail);
+
+ md_get_uint32le(mdp, &info->sect_per_unit);
+ error = md_get_uint32le(mdp, &info->bytes_per_sect);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+int
+smbfs_smb2_flush(struct smb_share *ssp, smb2fid_t *fid,
+ struct smb_cred *scrp)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_FLUSH, scrp, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 Flush Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 24); /* struct size */
+ mb_put_uint16le(mbp, 0); /* reserved */
+ mb_put_uint32le(mbp, 0); /* reserved */
+
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ rqp->sr_flags |= SMBR_NORECONNECT;
+ error = smb2_rq_simple(rqp);
+ smb_rq_done(rqp);
+
+ return (error);
+}
+
+/*
+ * Set file info via an open handle.
+ * Caller provides payload, info level.
+ */
+static int
+smbfs_smb2_set_info(struct smb_share *ssp, smb2fid_t *fid,
+ struct mbchain *info_mbp, uint8_t type, uint8_t level,
+ uint32_t addl_info, struct smb_cred *scrp)
+{
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp;
+ uint32_t *buffer_lenp;
+ int base, len;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_SET_INFO, scrp, &rqp);
+ if (error)
+ goto out;
+
+ /*
+ * Build the SMB 2 Set Info req.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 33); // struct size
+ mb_put_uint8(mbp, type);
+ mb_put_uint8(mbp, level);
+ buffer_lenp = mb_reserve(mbp, sizeof (uint32_t));
+ mb_put_uint16le(mbp, SMB2_HDRLEN + 32); // Buffer Offset
+ mb_put_uint16le(mbp, 0); // Reserved
+ mb_put_uint32le(mbp, addl_info); // Additional Info
+
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ /*
+ * Now the payload
+ */
+ base = mbp->mb_count;
+ error = mb_put_mbchain(mbp, info_mbp);
+ if (error)
+ goto out;
+ len = mbp->mb_count - base;
+ *buffer_lenp = htolel(len);
+ if (error)
+ goto out;
+
+ /*
+ * Run the request.
+ * Don't care about the (empty) reply.
+ */
+ error = smb2_rq_simple(rqp);
+
+out:
+ smb_rq_done(rqp);
+
+ return (error);
+}
+
+int
+smbfs_smb2_seteof(struct smb_share *ssp, smb2fid_t *fid,
+ uint64_t newsize, struct smb_cred *scrp)
+{
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint8_t level = FileEndOfFileInformation;
+ int error;
+
+ mb_init(mbp);
+ mb_put_uint64le(mbp, newsize);
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_FILE, level, 0, scrp);
+ mb_done(mbp);
+
+ return (error);
+}
+
+int
+smbfs_smb2_setdisp(struct smb_share *ssp, smb2fid_t *fid,
+ uint8_t newdisp, struct smb_cred *scrp)
+{
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint8_t level = FileDispositionInformation;
+ int error;
+
+ mb_init(mbp);
+ mb_put_uint8(mbp, newdisp);
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_FILE, level, 0, scrp);
+ mb_done(mbp);
+
+ return (error);
+}
+
+/*
+ * Set FileBasicInformation on an open handle
+ * Caller builds the mbchain.
+ */
+int
+smbfs_smb2_setfattr(struct smb_share *ssp, smb2fid_t *fid,
+ struct mbchain *mbp, struct smb_cred *scrp)
+{
+ uint8_t level = FileBasicInformation;
+ int error;
+
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_FILE, level, 0, scrp);
+ return (error);
+}
+
+/*
+ * Build a FileRenameInformation and call setinfo
+ */
+int
+smbfs_smb2_rename(struct smbnode *np, struct smbnode *tdnp,
+ const char *tname, int tnlen, int overwrite,
+ smb2fid_t *fid, struct smb_cred *scrp)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint32_t *name_lenp;
+ uint8_t level = FileRenameInformation;
+ int base, len;
+ int error;
+
+ mb_init(mbp);
+
+ mb_put_uint32le(mbp, (overwrite & 1));
+ mb_put_uint32le(mbp, 0); // reserved
+ mb_put_uint64le(mbp, 0); // Root Dir
+ name_lenp = mb_reserve(mbp, 4);
+
+ /* Target name (full path) */
+ base = mbp->mb_count;
+ if (tnlen > 0) {
+ error = smbfs_fullpath(mbp, SSTOVC(ssp),
+ tdnp, tname, tnlen, '\\');
+ if (error)
+ goto out;
+ }
+ len = mbp->mb_count - base;
+ *name_lenp = htolel(len);
+
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_FILE, level, 0, scrp);
+
+out:
+ mb_done(mbp);
+
+ return (error);
+}
+
+/*
+ * Later servers have maxtransact at a megabyte or more,
+ * but we don't want to buffer up that much data, so use
+ * the lesser of that or 64k.
+ */
+#define SMBFS_QDIR_MAX_BUF (1<<16)
+
+/*
+ * SMB2 query directory
+ */
+static int
+smbfs_smb2_qdir(struct smbfs_fctx *ctx)
+{
+ smb_fh_t *fhp = ctx->f_fhp;
+ smb_share_t *ssp = ctx->f_ssp;
+ smb_vc_t *vcp = SSTOVC(ssp);
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint16_t *name_lenp;
+ uint8_t level, flags;
+ uint16_t ssize = 0;
+ uint16_t obuf_off = 0;
+ uint32_t obuf_len = 0;
+ uint32_t obuf_req;
+ int error;
+
+ level = (uint8_t)ctx->f_infolevel;
+ flags = 0;
+ if (ctx->f_flags & SMBFS_RDD_FINDSINGLE)
+ flags |= SMB2_QDIR_FLAG_SINGLE;
+ if (ctx->f_flags & SMBFS_RDD_FINDFIRST)
+ ctx->f_rkey = 0;
+ else
+ flags |= SMB2_QDIR_FLAG_INDEX;
+
+ obuf_req = SMBFS_QDIR_MAX_BUF;
+ if (obuf_req > vcp->vc_sopt.sv2_maxtransact)
+ obuf_req = vcp->vc_sopt.sv2_maxtransact;
+
+ if (ctx->f_rq) {
+ smb_rq_done(ctx->f_rq);
+ ctx->f_rq = NULL;
+ }
+ error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB2_QUERY_DIRECTORY,
+ ctx->f_scred, &rqp);
+ if (error)
+ return (error);
+ ctx->f_rq = rqp;
+
+ /*
+ * Build an SMB2 Query Dir req.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+
+ mb_put_uint16le(mbp, 33); /* Struct size */
+ mb_put_uint8(mbp, level);
+ mb_put_uint8(mbp, flags);
+ mb_put_uint32le(mbp, ctx->f_rkey); /* FileIndex */
+
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
+
+ mb_put_uint16le(mbp, 96);
+ name_lenp = mb_reserve(mbp, sizeof (uint16_t)); /* FileNameLen */
+ mb_put_uint32le(mbp, obuf_req); /* Output Buf Len */
+
+ /* Add in the name if any */
+ if (ctx->f_wclen > 0) {
+ int base, len;
+
+ /* Put the match pattern. */
+ base = mbp->mb_count;
+ error = smb_put_dmem(mbp, vcp,
+ ctx->f_wildcard, ctx->f_wclen,
+ SMB_CS_NONE, NULL);
+ if (error)
+ return (error);
+
+ /* Update the FileNameLen */
+ len = mbp->mb_count - base;
+ *name_lenp = htoles(len);
+ } else {
+ /* Empty string */
+ mb_put_uint16le(mbp, 0);
+ *name_lenp = 0;
+ }
+
+ error = smb2_rq_simple(rqp);
+ if (error != 0)
+ goto out;
+
+ /*
+ * Parse the SMB2 Query Dir response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 9 */
+ md_get_uint16le(mdp, &ssize);
+ if (ssize != 9) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ /* Get output buffer offset, length */
+ md_get_uint16le(mdp, &obuf_off);
+ md_get_uint32le(mdp, &obuf_len);
+
+ /*
+ * After read at EOF we'll have just one word:
+ * NextEntryOffset == 0 Allow some padding.
+ */
+ if (obuf_len < 8) {
+ error = ENOENT;
+ goto out;
+ }
+
+ /*
+ * If this reply is shorter than requested by 1k
+ * or more, we must have reached EOF.
+ */
+ if ((obuf_len + 1024) < obuf_req)
+ ctx->f_flags |= SMBFS_RDD_EOF;
+
+ /*
+ * Have data. Put the payload in ctx->f_mdchain
+ * Current offset is SMB2_HDRLEN + 8.
+ */
+ {
+ mblk_t *m = NULL;
+ int skip = (int)obuf_off - (SMB2_HDRLEN + 8);
+ if (skip < 0) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+ error = md_get_mbuf(mdp, obuf_len, &m);
+ if (error)
+ goto out;
+ md_done(&ctx->f_mdchain);
+ md_initm(&ctx->f_mdchain, m);
+ }
+
+ /*
+ * SMB2 Query Directory does not provie an EntryCount.
+ * Instead, we'll advance f_eofs (entry offset)
+ * through the range [0..f_left]
+ */
+ ctx->f_left = obuf_len;
+ ctx->f_eofs = 0;
+ return (0);
+
+out:
+ if (error != 0) {
+ /*
+ * Failed parsing the FindFirst or FindNext response.
+ * Force this directory listing closed, otherwise the
+ * calling process may hang in an infinite loop.
+ */
+ ctx->f_left = 0;
+ ctx->f_eofs = 0;
+ ctx->f_flags |= SMBFS_RDD_EOF;
+ }
+
+ return (error);
+}
+
+int
+smbfs_smb2_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen, uint32_t attr)
+{
+ smb_fh_t *fhp = NULL;
+ uint32_t rights =
+ STD_RIGHT_READ_CONTROL_ACCESS |
+ SA_RIGHT_FILE_READ_ATTRIBUTES |
+ SA_RIGHT_FILE_READ_DATA;
+ int error;
+
+ /*
+ * Set f_type no matter what, so cleanup will call
+ * smbfs_smb2_findclose, error or not.
+ */
+ ctx->f_type = ft_SMB2;
+ ASSERT(ctx->f_dnp == dnp);
+
+ /*
+ * Get a file handle on the directory
+ */
+ error = smb_fh_create(ctx->f_ssp, &fhp);
+ if (error != 0)
+ goto errout;
+
+ error = smbfs_smb_ntcreatex(dnp,
+ NULL, 0, 0, /* name nmlen xattr */
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ ctx->f_scred, fhp,
+ NULL, NULL); /* cr_act_p fa_p */
+ if (error != 0)
+ goto errout;
+
+ fhp->fh_rights = rights;
+ smb_fh_opened(fhp);
+ ctx->f_fhp = fhp;
+
+ ctx->f_namesz = SMB_MAXFNAMELEN + 1;
+ ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
+ ctx->f_infolevel = FileFullDirectoryInformation;
+ ctx->f_attrmask = attr;
+ ctx->f_wildcard = wildcard;
+ ctx->f_wclen = wclen;
+
+ return (0);
+
+errout:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
+ return (error);
+}
+
+int
+smbfs_smb2_findclose(struct smbfs_fctx *ctx)
+{
+ smb_fh_t *fhp = NULL;
+
+ if ((fhp = ctx->f_fhp) != NULL) {
+ ctx->f_fhp = NULL;
+ smb_fh_rele(fhp);
+ }
+ if (ctx->f_name)
+ kmem_free(ctx->f_name, ctx->f_namesz);
+ if (ctx->f_rq)
+ smb_rq_done(ctx->f_rq);
+ md_done(&ctx->f_mdchain);
+
+ return (0);
+}
+
+/*
+ * Get a buffer of directory entries (if we don't already have
+ * some remaining in the current buffer) then decode one.
+ */
+int
+smbfs_smb2_findnext(struct smbfs_fctx *ctx, uint16_t limit)
+{
+ int error;
+
+ /*
+ * If we've scanned to the end of the current buffer
+ * try to read anohther buffer of dir entries.
+ * Treat anything less than 8 bytes as an "empty"
+ * buffer to ensure we can read something.
+ * (There may be up to 8 bytes of padding.)
+ */
+ if ((ctx->f_eofs + 8) > ctx->f_left) {
+ /* Scanned the whole buffer. */
+ if (ctx->f_flags & SMBFS_RDD_EOF)
+ return (ENOENT);
+ ctx->f_limit = limit;
+ error = smbfs_smb2_qdir(ctx);
+ if (error)
+ return (error);
+ ctx->f_otws++;
+ }
+
+ /*
+ * Decode one entry
+ */
+ error = smbfs_decode_dirent(ctx);
+
+ return (error);
+}
+
+
+/*
+ * Helper for smbfs_xa_get_streaminfo
+ * Query stream info
+ */
+int
+smbfs_smb2_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
+ struct smb_cred *scrp)
+{
+ smb_share_t *ssp = np->n_mount->smi_share;
+ smb_fh_t *fhp = NULL;
+ uint32_t rights =
+ STD_RIGHT_READ_CONTROL_ACCESS |
+ SA_RIGHT_FILE_READ_ATTRIBUTES;
+ uint32_t iolen = INT16_MAX;
+ int error;
+
+ /*
+ * Get a file handle on the object
+ * with read attr. rights.
+ */
+ error = smb_fh_create(ssp, &fhp);
+ if (error != 0)
+ goto out;
+ error = smbfs_smb_ntcreatex(np,
+ NULL, 0, 0, /* name nmlen xattr */
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ scrp, fhp, NULL, NULL);
+ if (error != 0)
+ goto out;
+
+ smb_fh_opened(fhp);
+
+ /*
+ * Query stream info
+ */
+ error = smbfs_smb2_query_info(ssp, &fhp->fh_fid2, mdp, &iolen,
+ SMB2_0_INFO_FILE, FileStreamInformation, 0, scrp);
+
+out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
+ return (error);
+}
+
+
+/*
+ * OTW function to Get a security descriptor (SD).
+ *
+ * The *reslen param is bufsize(in) / length(out)
+ * Note: On success, this fills in mdp->md_top,
+ * which the caller should free.
+ */
+int
+smbfs_smb2_getsec(struct smb_share *ssp, smb2fid_t *fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb2_query_info(ssp, fid, mdp, reslen,
+ SMB2_0_INFO_SECURITY, 0, selector, scrp);
+ if (error)
+ goto out;
+
+ if (mdp->md_top == NULL) {
+ error = EBADRPC;
+ goto out;
+ }
+ *res = mdp->md_top;
+ mdp->md_top = NULL;
+
+out:
+ md_done(mdp);
+ return (error);
+}
+
+
+/*
+ * OTW function to Set a security descriptor (SD).
+ * Caller data are carried in an mbchain_t.
+ *
+ * Note: This normally consumes mbp->mb_top, and clears
+ * that pointer when it does.
+ */
+int
+smbfs_smb2_setsec(struct smb_share *ssp, smb2fid_t *fid,
+ uint32_t selector, mblk_t **mp, struct smb_cred *scrp)
+{
+ struct mbchain info_mbp, *mbp = &info_mbp;
+ int error;
+
+ ASSERT(*mp != NULL);
+ mb_initm(mbp, *mp);
+ *mp = NULL; /* consumed */
+
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_SECURITY, 0, selector, scrp);
+
+ mb_done(mbp);
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
index 71d49c49b4..0b5eb411f1 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.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>
@@ -47,6 +48,7 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_rq.h>
@@ -73,10 +75,11 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
int unicode = (SMB_UNICODE_STRINGS(vcp)) ? 1 : 0;
int error;
- if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0)
- caseopt |= SMB_CS_UPPER;
-
- if (unicode) {
+ /*
+ * SMB1 may need an alignment pad before (not SMB2)
+ */
+ if (((vcp)->vc_flags & SMBV_SMB2) == 0 &&
+ ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) != 0) {
error = mb_put_padbyte(mbp);
if (error)
return (error);
@@ -122,11 +125,14 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
if (error)
return (error);
}
- /* Put NULL termination. */
- if (unicode)
- error = mb_put_uint16le(mbp, 0);
- else
- error = mb_put_uint8(mbp, 0);
+
+ /* SMB1 wants NULL termination. */
+ if (((vcp)->vc_flags & SMBV_SMB2) == 0) {
+ if (unicode)
+ error = mb_put_uint16le(mbp, 0);
+ else
+ error = mb_put_uint8(mbp, 0);
+ }
return (error);
}
@@ -183,3 +189,271 @@ errout:
*/
(void) strlcpy(ctx->f_name, "?", ctx->f_namesz);
}
+
+/*
+ * Decode a directory entry from OtW form into ctx->f_attr
+ *
+ * Caller already put some (wire-format) directory entries
+ * into ctx->f_mdchain and we expect to find one.
+ *
+ * Advancing correctly through the buffer can be tricky if one
+ * tries to add up the size of an entry as you go (which is how
+ * the darwin code this is derived from did it). The easiest way
+ * to correctly advance the position is to get a whole dirent
+ * into another mdchain (entry_mdc) based on NextEntryOffset,
+ * and then scan the data from that mdchain. On the last entry,
+ * we don't know the entire length, so just scan directly from
+ * what remains of the multi-entry buffer instead of trying to
+ * figure out the length to copy into a separate mdchain.
+ */
+int
+smbfs_decode_dirent(struct smbfs_fctx *ctx)
+{
+ struct mdchain entry_mdc;
+ struct mdchain *mdp = &ctx->f_mdchain;
+ size_t nmlen;
+ uint64_t llongint;
+ uint32_t nmsize, dattr;
+ uint32_t nextoff = 0;
+ int error;
+
+ /* In case we error out... */
+ ctx->f_nmlen = 0;
+ ctx->f_rkey = (uint32_t)-1;
+ bzero(&entry_mdc, sizeof (entry_mdc));
+
+ /*
+ * Setup mdp to point to an mbchain holding
+ * what should be a single directory entry.
+ */
+ error = md_get_uint32le(mdp, &nextoff);
+ if (error != 0)
+ goto errout;
+ if (nextoff >= 4) {
+ /*
+ * More entries follow. Make a new mbchain
+ * holding just this one entry, then advance.
+ */
+ mblk_t *m = NULL;
+ error = md_get_mbuf(mdp, nextoff - 4, &m);
+ if (error != 0)
+ goto errout;
+ md_initm(&entry_mdc, m);
+ mdp = &entry_mdc;
+ ctx->f_eofs += nextoff;
+ } else {
+ /* Scan directly from ctx->f_mdchain */
+ ctx->f_eofs = ctx->f_left;
+ }
+
+ /*
+ * Decode the fixed-size parts
+ */
+ switch (ctx->f_infolevel) {
+ case FileFullDirectoryInformation:
+ case SMB_FIND_FULL_DIRECTORY_INFO:
+ md_get_uint32le(mdp, &ctx->f_rkey); /* resume key (idx) */
+ md_get_uint64le(mdp, &llongint); /* creation time */
+ smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime);
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &ctx->f_attr.fa_atime);
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime);
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime);
+ md_get_uint64le(mdp, &llongint); /* file size */
+ ctx->f_attr.fa_size = llongint;
+ md_get_uint64le(mdp, &llongint); /* alloc. size */
+ ctx->f_attr.fa_allocsz = llongint;
+ md_get_uint32le(mdp, &dattr); /* ext. file attributes */
+ ctx->f_attr.fa_attr = dattr;
+ error = md_get_uint32le(mdp, &nmsize); /* name size (otw) */
+ if (error)
+ goto errout;
+ md_get_uint32le(mdp, NULL); /* Ea size */
+ break;
+
+ case FileStreamInformation:
+ error = md_get_uint32le(mdp, &nmsize); /* name size (otw) */
+ md_get_uint64le(mdp, &llongint); /* file size */
+ ctx->f_attr.fa_size = llongint;
+ md_get_uint64le(mdp, &llongint); /* alloc. size */
+ ctx->f_attr.fa_allocsz = llongint;
+ /*
+ * Stream names start with a ':' that we want to skip.
+ * This is the easiest place to take care of that.
+ * Always unicode here.
+ */
+ if (nmsize >= 2) {
+ struct mdchain save_mdc;
+ uint16_t wch;
+ save_mdc = *mdp;
+ md_get_uint16le(mdp, &wch);
+ if (wch == ':') {
+ /* OK, we skipped the ':' */
+ nmsize -= 2;
+ } else {
+ SMBVDEBUG("No leading : in stream?\n");
+ /* restore position */
+ *mdp = save_mdc;
+ }
+ }
+ break;
+
+ default:
+ SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
+ error = EINVAL;
+ goto errout;
+ }
+
+ /*
+ * Get the filename, and convert to utf-8
+ * Allocated f_name in findopen
+ */
+ nmlen = ctx->f_namesz;
+ error = smb_get_dstring(mdp, SSTOVC(ctx->f_ssp),
+ ctx->f_name, &nmlen, nmsize);
+ if (error != 0)
+ goto errout;
+ ctx->f_nmlen = (int)nmlen;
+ md_done(&entry_mdc);
+ return (0);
+
+errout:
+ /*
+ * Something bad has happened and we ran out of data
+ * before we could parse all f_ecnt entries expected.
+ * Give up on the current buffer.
+ */
+ SMBVDEBUG("ran out of data\n");
+ ctx->f_eofs = ctx->f_left;
+ md_done(&entry_mdc);
+ return (error);
+}
+
+/*
+ * Decode FileAllInformation
+ *
+ * The data is a concatenation of:
+ * FileBasicInformation
+ * FileStandardInformation
+ * FileInternalInformation
+ * FileEaInformation
+ * FilePositionInformation
+ * FileModeInformation
+ * FileAlignmentInformation
+ * FileNameInformation
+ */
+/*ARGSUSED*/
+int
+smbfs_decode_file_all_info(struct smb_share *ssp,
+ struct mdchain *mdp, struct smbfattr *fap)
+{
+ uint64_t llongint, lsize;
+ uint32_t dattr;
+ int error;
+
+ /*
+ * This part is: FileBasicInformation
+ */
+
+ /* creation time */
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &fap->fa_createtime);
+
+ /* last access time */
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &fap->fa_atime);
+
+ /* last write time */
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &fap->fa_mtime);
+
+ /* last change time */
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &fap->fa_ctime);
+
+ /* attributes */
+ md_get_uint32le(mdp, &dattr);
+ fap->fa_attr = dattr;
+
+ /* reserved */
+ md_get_uint32le(mdp, NULL);
+
+ /*
+ * This part is: FileStandardInformation
+ */
+
+ /* allocation size */
+ md_get_uint64le(mdp, &lsize);
+ fap->fa_allocsz = lsize;
+
+ /* File size */
+ error = md_get_uint64le(mdp, &lsize);
+ fap->fa_size = lsize;
+
+ /*
+ * There's more after this but we don't need it:
+ * Remainder of FileStandardInformation
+ * NumLlinks, DeletOnClose, IsDir, reserved.
+ * Then:
+ * FileInternalInformation
+ * FileEaInformation
+ * FilePositionInformation
+ * FileModeInformation
+ * FileAlignmentInformation
+ * FileNameInformation
+ */
+
+ return (error);
+}
+
+/*
+ * Decode FileFsAttributeInformation
+ *
+ * ULONG FileSystemAttributes;
+ * LONG MaximumComponentNameLength;
+ * ULONG FileSystemNameLength;
+ * WCHAR FileSystemName[1];
+ */
+int
+smbfs_decode_fs_attr_info(struct smb_share *ssp,
+ struct mdchain *mdp, struct smb_fs_attr_info *fsa)
+{
+ struct smb_vc *vcp = SSTOVC(ssp);
+ uint32_t nlen;
+ int error;
+
+ md_get_uint32le(mdp, &fsa->fsa_aflags);
+ md_get_uint32le(mdp, &fsa->fsa_maxname);
+ error = md_get_uint32le(mdp, &nlen); /* fs name length */
+ if (error)
+ goto out;
+
+ /*
+ * Get the FS type name.
+ */
+ bzero(fsa->fsa_tname, FSTYPSZ);
+ if (SMB_UNICODE_STRINGS(vcp)) {
+ uint16_t tmpbuf[FSTYPSZ];
+ size_t tmplen, outlen;
+
+ if (nlen > sizeof (tmpbuf))
+ nlen = sizeof (tmpbuf);
+ error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
+ if (error != 0)
+ goto out;
+ tmplen = nlen / 2; /* UCS-2 chars */
+ outlen = FSTYPSZ - 1;
+ error = uconv_u16tou8(tmpbuf, &tmplen,
+ (uchar_t *)fsa->fsa_tname, &outlen,
+ UCONV_IN_LITTLE_ENDIAN);
+ } else {
+ if (nlen > (FSTYPSZ - 1))
+ nlen = FSTYPSZ - 1;
+ error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
+ }
+
+out:
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h
index fc7a4ffa26..f8d708b5a3 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _FS_SMBFS_SMBFS_SUBR_H_
@@ -85,6 +86,7 @@ struct timespec;
typedef enum {
ft_LM1 = 1,
ft_LM2,
+ ft_SMB2,
ft_XA
} smbfs_fctx_type_t;
@@ -120,31 +122,33 @@ struct smbfs_fctx {
/*
* Internal variables
*/
+ uint16_t f_infolevel;
uint16_t f_limit; /* maximum number of entries */
- uint16_t f_attrmask; /* SMB_FA_ */
+ uint32_t f_attrmask; /* SMB_FA_ */
int f_wclen;
const char *f_wildcard;
struct smbnode *f_dnp;
struct smb_cred *f_scred;
struct smb_share *f_ssp;
+ struct smb_fh *f_fhp;
union {
struct smb_rq *uf_rq;
struct smb_t2rq *uf_t2;
- } f_urq;
+ } f_urq; // XXX remove and use...
+ struct mdchain f_mdchain;
int f_left; /* entries left */
int f_ecnt; /* entries left in current response */
int f_eofs; /* entry offset in data block */
uchar_t f_skey[SMB_SKEYLEN]; /* server side search context */
uchar_t f_fname[8 + 1 + 3 + 1]; /* for 8.3 filenames */
uint16_t f_Sid; /* Search handle (like a FID) */
- uint16_t f_infolevel;
int f_rnamelen;
char *f_rname; /* resume name */
int f_rnameofs;
int f_otws; /* # over-the-wire ops so far */
char *f_firstnm; /* first filename we got back */
int f_firstnmlen;
- int f_rkey; /* resume key */
+ uint32_t f_rkey; /* resume key */
};
typedef struct smbfs_fctx smbfs_fctx_t;
@@ -152,73 +156,163 @@ typedef struct smbfs_fctx smbfs_fctx_t;
#define f_t2 f_urq.uf_t2
/*
- * smb level (smbfs_smb.c)
+ * Internal form of FileFsFullSizeInformation
+ * [MS-FSCC] 2.5.4 FileFsFullSizeInformation
+ * for the _statfs functions.
+ */
+struct smb_fs_size_info {
+ uint64_t total_units;
+ uint64_t caller_avail;
+ uint64_t actual_avail;
+ uint32_t sect_per_unit;
+ uint32_t bytes_per_sect;
+};
+
+/*
+ * smb common functions (smbfs_smbx.c)
*/
int smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
offset_t start, uint64_t len, int largelock,
struct smb_cred *scrp, uint32_t timeout);
+int smbfs_smb_getfattr(struct smbnode *np, smb_fh_t *fhp,
+ struct smbfattr *fap, struct smb_cred *scrp);
+int smbfs_smb_getpattr(struct smbnode *np, struct smbfattr *fap,
+ struct smb_cred *scrp);
int smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *,
struct smb_cred *scrp);
int smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
struct smb_cred *scrp);
-
-int smbfs_smb_setdisp(struct smbnode *np, uint16_t fid, uint8_t newdisp,
- struct smb_cred *scrp);
-int smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
+int smbfs_smb_setdisp(struct smb_share *ssp, smb_fh_t *fid, uint8_t newdisp,
struct smb_cred *scrp);
-
-int smbfs_smb_getfattr(struct smbnode *np, struct smbfattr *fap,
+int smbfs_smb_setfsize(struct smb_share *ssp, smb_fh_t *fid, uint64_t newsize,
struct smb_cred *scrp);
-
-int smbfs_smb_setfattr(struct smbnode *np, int fid,
+int smbfs_smb_setfattr(struct smb_share *ssp, smb_fh_t *fid,
uint32_t attr, struct timespec *mtime, struct timespec *atime,
struct smb_cred *scrp);
+int smbfs_smb_flush(struct smb_share *ssp, smb_fh_t *fid,
+ struct smb_cred *scrp);
+
+int smbfs_smb_ntcreatex(
+ struct smbnode *np, const char *name, int nmlen, int xattr,
+ uint32_t req_acc, uint32_t efa, uint32_t share_acc,
+ uint32_t disp, uint32_t createopt, struct smb_cred *scrp,
+ smb_fh_t *fhpp, uint32_t *cr_act_p, struct smbfattr *fap);
+int smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights,
+ struct smb_cred *scrp, smb_fh_t **fidpp);
+void smbfs_smb_tmpclose(struct smbnode *ssp, smb_fh_t *fid);
int smbfs_smb_open(struct smbnode *np, const char *name, int nmlen,
int xattr, uint32_t rights, struct smb_cred *scrp,
- uint16_t *fidp, uint32_t *rightsp, struct smbfattr *fap);
-int smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights,
- struct smb_cred *scrp, uint16_t *fidp);
-int smbfs_smb_close(struct smb_share *ssp, uint16_t fid,
- struct timespec *mtime, struct smb_cred *scrp);
-int smbfs_smb_tmpclose(struct smbnode *ssp, uint16_t fid,
- struct smb_cred *scrp);
+ smb_fh_t **fidpp, struct smbfattr *fap);
+void smbfs_smb_close(smb_fh_t *fid);
int smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
- int xattr, uint32_t disp, struct smb_cred *scrp, uint16_t *fidp);
-int smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp,
- const char *name, int len, int xattr);
-int smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
- const char *tname, int tnmlen, struct smb_cred *scrp);
-int smbfs_smb_t2rename(struct smbnode *np, const char *tname, int tnmlen,
- struct smb_cred *scrp, uint16_t fid, int replace);
-int smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
- const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp);
+ int xattr, uint32_t disp, struct smb_cred *scrp, smb_fh_t **fidpp);
+int smbfs_smb_rename(struct smbnode *sdnp, struct smbnode *src,
+ struct smbnode *tdnp, const char *tname, int tnmlen,
+ smb_fh_t *fid, struct smb_cred *scrp);
int smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
struct smb_cred *scrp);
-int smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp);
+
int smbfs_smb_findopen(struct smbnode *dnp, const char *wildcard, int wclen,
int attr, struct smb_cred *scrp, struct smbfs_fctx **ctxpp);
int smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit,
struct smb_cred *scrp);
int smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp);
-int smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp,
- struct smbnode *dnp, const char *name, int nmlen, uint8_t sep);
+
int smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
struct smbfattr *fap, struct smb_cred *scrp);
-int smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
- struct smb_cred *scrp);
-int smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
- struct smb_cred *scrp);
-int smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp);
-int smbfs_0extend(vnode_t *vp, uint16_t fid, len_t from, len_t to,
- struct smb_cred *scredp, int timo);
/* get/set security descriptor */
-int smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
- struct smb_cred *scrp, uint32_t selector,
- mblk_t **res, uint32_t *reslen);
-int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
- struct smb_cred *scrp, uint32_t selector, mblk_t **mp);
+int smbfs_smb_getsec(struct smb_share *ssp, smb_fh_t *fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp);
+int smbfs_smb_setsec(struct smb_share *ssp, smb_fh_t *fid,
+ uint32_t selector, mblk_t **mp, struct smb_cred *scrp);
+
+/*
+ * SMB1 functions
+ */
+int smbfs_smb1_trans2_query(struct smbnode *np, uint16_t fid,
+ struct smbfattr *fap, struct smb_cred *scrp);
+int smbfs_smb1_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *,
+ struct smb_cred *scrp);
+int smbfs_smb1_statfs(struct smb_share *ssp,
+ struct smb_fs_size_info *info, struct smb_cred *scrp);
+int smbfs_smb1_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
+ struct smb_cred *scrp);
+int smbfs_smb1_setdisp(struct smb_share *ssp, uint16_t fid, uint8_t newdisp,
+ struct smb_cred *scrp);
+int smbfs_smb1_setfattr(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *, struct smb_cred *);
+int smbfs_smb1_flush(struct smb_share *ssp, uint16_t fid,
+ struct smb_cred *scrp);
+int smbfs_smb1_t2rename(struct smbnode *np, const char *tname, int tnmlen,
+ uint16_t fid, struct smb_cred *scrp);
+int smbfs_smb1_oldrename(struct smbnode *src, struct smbnode *tdnp,
+ const char *tname, int tnmlen, struct smb_cred *scrp);
+
+int smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen, uint32_t attr);
+int smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit);
+int smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx);
+int smbfs_smb1_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
+ struct smb_cred *scrp);
+
+int smbfs_smb1_getsec(struct smb_share *ssp, uint16_t fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp);
+int smbfs_smb1_setsec(struct smb_share *ssp, uint16_t fid,
+ uint32_t selector, mblk_t **mp,
+ struct smb_cred *scrp);
+
+/*
+ * SMB2 functions
+ */
+
+int smbfs_smb2_getpattr(struct smbnode *np, struct smbfattr *fap,
+ struct smb_cred *scrp);
+int smbfs_smb2_qfileinfo(struct smb_share *ssp, smb2fid_t *fid,
+ struct smbfattr *fap, struct smb_cred *scrp);
+int smbfs_smb2_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *,
+ struct smb_cred *scrp);
+int smbfs_smb2_statfs(struct smb_share *ssp,
+ struct smb_fs_size_info *info, struct smb_cred *scrp);
+int smbfs_smb2_seteof(struct smb_share *ssp, smb2fid_t *fid, uint64_t newsize,
+ struct smb_cred *scrp);
+int smbfs_smb2_setdisp(struct smb_share *ssp, smb2fid_t *fid, uint8_t newdisp,
+ struct smb_cred *scrp);
+int smbfs_smb2_flush(struct smb_share *ssp, smb2fid_t *fid,
+ struct smb_cred *scrp);
+int smbfs_smb2_setfattr(struct smb_share *ssp, smb2fid_t *fid,
+ struct mbchain *, struct smb_cred *);
+int smbfs_smb2_rename(struct smbnode *np, struct smbnode *tdnp,
+ const char *tname, int tnlen, int overwrite,
+ smb2fid_t *fid, struct smb_cred *scrp);
+
+int smbfs_smb2_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen, uint32_t attr);
+int smbfs_smb2_findnext(struct smbfs_fctx *ctx, uint16_t limit);
+int smbfs_smb2_findclose(struct smbfs_fctx *ctx);
+int smbfs_smb2_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
+ struct smb_cred *scrp);
+
+int smbfs_smb2_getsec(struct smb_share *ssp, smb2fid_t *fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp);
+int smbfs_smb2_setsec(struct smb_share *ssp, smb2fid_t *fid,
+ uint32_t selector, mblk_t **mp,
+ struct smb_cred *scrp);
+
+
+/* smbfs_subr.c */
+
+int smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp,
+ struct smbnode *dnp, const char *name, int nmlen, uint8_t sep);
+int smbfs_decode_dirent(struct smbfs_fctx *ctx);
+int smbfs_decode_file_all_info(struct smb_share *ssp,
+ struct mdchain *mdp, struct smbfattr *fap);
+int smbfs_decode_fs_attr_info(struct smb_share *ssp,
+ struct mdchain *mdp, struct smb_fs_attr_info *fsa);
/*
* VFS-level init, fini stuff
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c
index deb8d8f182..768664b610 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c
@@ -27,7 +27,7 @@
*/
/*
* Copyright (c) 2017 by Delphix. All rights reserved.
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -433,7 +433,7 @@ start:
np->r_vnode = vp;
np->n_mount = mi;
- np->n_fid = SMB_FID_UNUSED;
+ np->n_fid = NULL;
np->n_uid = mi->smi_uid;
np->n_gid = mi->smi_gid;
/* Leave attributes "stale." */
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
index 707238e5ad..3fca806155 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -144,6 +144,7 @@ static int smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
static int smbfs_accessx(void *, int, cred_t *);
static int smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
caller_context_t *);
+static int smbfsflush(smbnode_t *, struct smb_cred *);
static void smbfs_rele_fid(smbnode_t *, struct smb_cred *);
static uint32_t xvattr_to_dosattr(smbnode_t *, struct vattr *);
@@ -201,14 +202,13 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
smbnode_t *np;
vnode_t *vp;
smbfattr_t fa;
- u_int32_t rights, rightsrcvd;
- u_int16_t fid, oldfid;
- int oldgenid;
+ smb_fh_t *fid = NULL;
+ smb_fh_t *oldfid;
+ uint32_t rights;
struct smb_cred scred;
smbmntinfo_t *smi;
smb_share_t *ssp;
cred_t *oldcr;
- int tmperror;
int error = 0;
vp = *vpp;
@@ -280,14 +280,15 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
* check whether the rights are sufficient for FID reuse.
*/
if (np->n_fidrefs > 0 &&
- np->n_vcgenid == ssp->ss_vcgenid) {
+ (fid = np->n_fid) != NULL &&
+ fid->fh_vcgenid == ssp->ss_vcgenid) {
int upgrade = 0;
if ((flag & FWRITE) &&
- !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA))
+ !(fid->fh_rights & SA_RIGHT_FILE_WRITE_DATA))
upgrade = 1;
if ((flag & FREAD) &&
- !(np->n_rights & SA_RIGHT_FILE_READ_DATA))
+ !(fid->fh_rights & SA_RIGHT_FILE_READ_DATA))
upgrade = 1;
if (!upgrade) {
/*
@@ -296,8 +297,9 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
np->n_fidrefs++;
goto have_fid;
}
+ fid = NULL;
}
- rights = np->n_fidrefs ? np->n_rights : 0;
+ rights = (fid != NULL) ? fid->fh_rights : 0;
/*
* we always ask for READ_CONTROL so we can always get the
@@ -316,7 +318,7 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
error = smbfs_smb_open(np,
NULL, 0, 0, /* name nmlen xattr */
rights, &scred,
- &fid, &rightsrcvd, &fa);
+ &fid, &fa);
if (error)
goto out;
smbfs_attrcache_fa(vp, &fa);
@@ -325,24 +327,10 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
* We have a new FID and access rights.
*/
oldfid = np->n_fid;
- oldgenid = np->n_vcgenid;
np->n_fid = fid;
- np->n_vcgenid = ssp->ss_vcgenid;
- np->n_rights = rightsrcvd;
np->n_fidrefs++;
- if (np->n_fidrefs > 1 &&
- oldgenid == ssp->ss_vcgenid) {
- /*
- * We already had it open (presumably because
- * it was open with insufficient rights.)
- * Close old wire-open.
- */
- tmperror = smbfs_smb_close(ssp,
- oldfid, NULL, &scred);
- if (tmperror)
- SMBVDEBUG("error %d closing %s\n",
- tmperror, np->n_rpath);
- }
+ if (oldfid != NULL)
+ smb_fh_rele(oldfid);
/*
* This thread did the open.
@@ -488,13 +476,11 @@ smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
static void
smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
{
- smb_share_t *ssp;
cred_t *oldcr;
struct smbfs_fctx *fctx;
int error;
- uint16_t ofid;
+ smb_fh_t *ofid;
- ssp = np->n_mount->smi_share;
error = 0;
/* Make sure we serialize for n_dirseq use. */
@@ -523,13 +509,9 @@ smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
ASSERT(np->n_fidrefs > 0);
if (--np->n_fidrefs)
return;
- if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
- np->n_fid = SMB_FID_UNUSED;
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid == ssp->ss_vcgenid) {
- error = smbfs_smb_close(
- ssp, ofid, NULL, scred);
- }
+ if ((ofid = np->n_fid) != NULL) {
+ np->n_fid = NULL;
+ smb_fh_rele(ofid);
}
break;
@@ -567,14 +549,12 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
struct vattr va;
smbnode_t *np;
smbmntinfo_t *smi;
- smb_share_t *ssp;
offset_t endoff;
ssize_t past_eof;
int error;
np = VTOSMB(vp);
smi = VTOSMI(vp);
- ssp = smi->smi_share;
if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
return (EIO);
@@ -636,12 +616,8 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
return (EINTR);
smb_credinit(&scred, cr);
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- error = ESTALE;
- else
- error = smb_rwuio(ssp, np->n_fid, UIO_READ,
- uiop, &scred, smb_timo_read);
+ error = smb_rwuio(np->n_fid, UIO_READ,
+ uiop, &scred, smb_timo_read);
smb_credrele(&scred);
smbfs_rw_exit(&np->r_lkserlock);
@@ -729,7 +705,6 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
struct vattr va;
smbnode_t *np;
smbmntinfo_t *smi;
- smb_share_t *ssp;
offset_t endoff, limit;
ssize_t past_limit;
int error, timo;
@@ -741,7 +716,6 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
np = VTOSMB(vp);
smi = VTOSMI(vp);
- ssp = smi->smi_share;
if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
return (EIO);
@@ -852,12 +826,8 @@ smbfs_fwrite:
return (EINTR);
smb_credinit(&scred, cr);
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- error = ESTALE;
- else
- error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
- uiop, &scred, timo);
+ error = smb_rwuio(np->n_fid, UIO_WRITE,
+ uiop, &scred, timo);
if (error == 0) {
mutex_enter(&np->r_statelock);
@@ -867,7 +837,7 @@ smbfs_fwrite:
mutex_exit(&np->r_statelock);
if (ioflag & (FSYNC | FDSYNC)) {
/* Don't error the I/O if this fails. */
- (void) smbfs_smb_flush(np, &scred);
+ (void) smbfsflush(np, &scred);
}
}
@@ -1274,7 +1244,6 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
struct smb_cred scred;
smbnode_t *np = VTOSMB(bp->b_vp);
smbmntinfo_t *smi = np->n_mount;
- smb_share_t *ssp = smi->smi_share;
offset_t offset;
offset_t endoff;
size_t count;
@@ -1330,12 +1299,8 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
if (bp->b_flags & B_READ) {
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- error = ESTALE;
- else
- error = smb_rwuio(ssp, np->n_fid, UIO_READ,
- &auio, &scred, smb_timo_read);
+ error = smb_rwuio(np->n_fid, UIO_READ,
+ &auio, &scred, smb_timo_read);
/* Like NFS, only set b_error here. */
bp->b_error = error;
@@ -1349,12 +1314,8 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
}
} else {
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- error = ESTALE;
- else
- error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
- &auio, &scred, smb_timo_write);
+ error = smb_rwuio(np->n_fid, UIO_WRITE,
+ &auio, &scred, smb_timo_write);
/* Like NFS, only set b_error here. */
bp->b_error = error;
@@ -1363,7 +1324,7 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
if (!error && auio.uio_resid != 0)
error = EIO;
if (!error && sync) {
- (void) smbfs_smb_flush(np, &scred);
+ (void) smbfsflush(np, &scred);
}
}
@@ -1618,12 +1579,12 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
{
int error = 0;
smbnode_t *np = VTOSMB(vp);
+ smbmntinfo_t *smi = np->n_mount;
uint_t mask = vap->va_mask;
struct timespec *mtime, *atime;
struct smb_cred scred;
- int cerror, modified = 0;
- unsigned short fid;
- int have_fid = 0;
+ int modified = 0;
+ smb_fh_t *fid = NULL;
uint32_t rights = 0;
uint32_t dosattr = 0;
@@ -1675,9 +1636,6 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
* with a partially complete request.
*/
- /* Shared lock for (possible) n_fid use. */
- if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
- return (EINTR);
smb_credinit(&scred, cr);
/*
@@ -1715,7 +1673,7 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
error, np->n_rpath);
goto out;
}
- have_fid = 1;
+ ASSERT(fid != NULL);
}
/*
@@ -1734,8 +1692,9 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
/*
* Set the file size to vap->va_size.
*/
- ASSERT(have_fid);
- error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
+ ASSERT(fid != NULL);
+ error = smbfs_smb_setfsize(smi->smi_share, fid,
+ vap->va_size, &scred);
if (error) {
SMBVDEBUG("setsize error %d file %s\n",
error, np->n_rpath);
@@ -1747,6 +1706,7 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
*/
mutex_enter(&np->r_statelock);
np->r_size = vap->va_size;
+ np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
mutex_exit(&np->r_statelock);
modified = 1;
}
@@ -1763,8 +1723,8 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
/*
* Always use the handle-based set attr call now.
*/
- ASSERT(have_fid);
- error = smbfs_smb_setfattr(np, fid,
+ ASSERT(fid != NULL);
+ error = smbfs_smb_setfattr(smi->smi_share, fid,
dosattr, mtime, atime, &scred);
if (error) {
SMBVDEBUG("set times error %d file %s\n",
@@ -1775,15 +1735,10 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
}
out:
- if (have_fid) {
- cerror = smbfs_smb_tmpclose(np, fid, &scred);
- if (cerror)
- SMBVDEBUG("error %d closing %s\n",
- cerror, np->n_rpath);
- }
+ if (fid != NULL)
+ smbfs_smb_tmpclose(np, fid);
smb_credrele(&scred);
- smbfs_rw_exit(&np->r_lkserlock);
if (modified) {
/*
@@ -2052,7 +2007,7 @@ smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
return (EINTR);
smb_credinit(&scred, cr);
- error = smbfs_smb_flush(np, &scred);
+ error = smbfsflush(np, &scred);
smb_credrele(&scred);
smbfs_rw_exit(&np->r_lkserlock);
@@ -2060,6 +2015,37 @@ smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
return (error);
}
+static int
+smbfsflush(smbnode_t *np, struct smb_cred *scrp)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ smb_fh_t *fhp;
+ int error;
+
+ /* Shared lock for n_fid use below. */
+ ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+
+ if (!(np->n_flag & NFLUSHWIRE))
+ return (0);
+ if (np->n_fidrefs == 0)
+ return (0); /* not open */
+ if ((fhp = np->n_fid) == NULL)
+ return (0);
+
+ /* After reconnect, n_fid is invalid */
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
+ error = smbfs_smb_flush(ssp, fhp, scrp);
+
+ if (!error) {
+ mutex_enter(&np->r_statelock);
+ np->n_flag &= ~NFLUSHWIRE;
+ mutex_exit(&np->r_statelock);
+ }
+ return (error);
+}
+
/*
* Last reference to vnode went away.
*/
@@ -2149,8 +2135,8 @@ smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
case VREG:
if (np->n_fidrefs == 0)
break;
- SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
- np->n_fidrefs, np->n_fid, np->n_rpath);
+ SMBVDEBUG("open file: refs %d path %s\n",
+ np->n_fidrefs, np->n_rpath);
/* Force last close. */
np->n_fidrefs = 1;
smbfs_rele_fid(np, &scred);
@@ -2228,6 +2214,14 @@ smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
smbfs_rw_exit(&dnp->r_rwlock);
+ /*
+ * If the caller passes an invalid name here, we'll have
+ * error == EINVAL but want to return ENOENT. This is
+ * common with things like "ls foo*" with no matches.
+ */
+ if (error == EINVAL)
+ error = ENOENT;
+
return (error);
}
@@ -2255,14 +2249,7 @@ smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
-#ifdef NOT_YET
- vcp = SSTOVC(smi->smi_share);
-
- /* XXX: Should compute this once and store it in smbmntinfo_t */
- supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
-#else
supplen = 255;
-#endif
/*
* RWlock must be held, either reader or writer.
@@ -2549,7 +2536,6 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
vsecattr_t *vsecp)
{
int error;
- int cerror;
vfs_t *vfsp;
vnode_t *vp;
smbnode_t *np;
@@ -2561,7 +2547,7 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
const char *name = (const char *)nm;
int nmlen = strlen(nm);
uint32_t disp;
- uint16_t fid;
+ smb_fh_t *fid = NULL;
int xattr;
vfsp = dvp->v_vfsp;
@@ -2723,11 +2709,7 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
* Should use the fid to get/set the size
* while we have it opened here. See above.
*/
-
- cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
- if (cerror)
- SMBVDEBUG("error %d closing %s\\%s\n",
- cerror, dnp->n_rpath, name);
+ smbfs_smb_close(fid);
/*
* In the open case, the name may differ a little
@@ -2796,14 +2778,30 @@ smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
/* Lookup the file to remove. */
error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
- if (error == 0) {
- /*
- * Do the real remove work
- */
- error = smbfsremove(dvp, vp, &scred, flags);
- VN_RELE(vp);
+ if (error != 0)
+ goto out;
+
+ /* Don't allow unlink of a directory. */
+ if (vp->v_type == VDIR) {
+ error = EPERM;
+ goto out;
}
+ /*
+ * Do the real remove work
+ */
+ error = smbfsremove(dvp, vp, &scred, flags);
+ if (error != 0)
+ goto out;
+
+#ifdef SMBFS_VNEVENT
+ vnevent_remove(vp, dvp, nm, ct);
+#endif
+
+out:
+ if (vp != NULL)
+ VN_RELE(vp);
+
smb_credrele(&scred);
smbfs_rw_exit(&dnp->r_rwlock);
@@ -2838,11 +2836,11 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
{
smbnode_t *dnp = VTOSMB(dvp);
smbnode_t *np = VTOSMB(vp);
+ smbmntinfo_t *smi = np->n_mount;
char *tmpname = NULL;
int tnlen;
int error;
- unsigned short fid;
- boolean_t have_fid = B_FALSE;
+ smb_fh_t *fid = NULL;
boolean_t renamed = B_FALSE;
/*
@@ -2850,10 +2848,6 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
*/
ASSERT(dnp->r_rwlock.owner == curthread);
- /* Never allow link/unlink directories on SMB. */
- if (vp->v_type == VDIR)
- return (EPERM);
-
/*
* We need to flush any dirty pages which happen to
* be hanging around before removing the file. This
@@ -2872,10 +2866,6 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
}
}
- /* Shared lock for n_fid use in smbfs_smb_setdisp etc. */
- if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
- return (EINTR);
-
/*
* Get a file handle with delete access.
* Close this FID before return.
@@ -2887,16 +2877,18 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
error, np->n_rpath);
goto out;
}
- have_fid = B_TRUE;
+ ASSERT(fid != NULL);
/*
* If we have the file open, try to rename it to a temporary name.
* If we can't rename, continue on and try setting DoC anyway.
+ * Unnecessary for directories.
*/
- if ((vp->v_count > 1) && (np->n_fidrefs > 0)) {
+ if (vp->v_type != VDIR && vp->v_count > 1 && np->n_fidrefs > 0) {
tmpname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
tnlen = smbfs_newname(tmpname, MAXNAMELEN);
- error = smbfs_smb_t2rename(np, tmpname, tnlen, scred, fid, 0);
+ error = smbfs_smb_rename(dnp, np, dnp, tmpname, tnlen,
+ fid, scred);
if (error != 0) {
SMBVDEBUG("error %d renaming %s -> %s\n",
error, np->n_rpath, tmpname);
@@ -2910,7 +2902,7 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
* Mark the file as delete-on-close. If we can't,
* undo what we did and err out.
*/
- error = smbfs_smb_setdisp(np, fid, 1, scred);
+ error = smbfs_smb_setdisp(smi->smi_share, fid, 1, scred);
if (error != 0) {
SMBVDEBUG("error %d setting DoC on %s\n",
error, np->n_rpath);
@@ -2927,8 +2919,8 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
oldname = np->n_rpath + (dnp->n_rplen + 1);
oldnlen = np->n_rplen - (dnp->n_rplen + 1);
- err2 = smbfs_smb_t2rename(np, oldname, oldnlen,
- scred, fid, 0);
+ err2 = smbfs_smb_rename(dnp, np, dnp, oldname, oldnlen,
+ fid, scred);
SMBVDEBUG("error %d un-renaming %s -> %s\n",
err2, tmpname, np->n_rpath);
}
@@ -2936,19 +2928,14 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
goto out;
}
/* Done! */
+ smbfs_attrcache_remove(np);
smbfs_attrcache_prune(np);
-#ifdef SMBFS_VNEVENT
- vnevent_remove(vp, dvp, nm, ct);
-#endif
-
out:
if (tmpname != NULL)
kmem_free(tmpname, MAXNAMELEN);
-
- if (have_fid)
- (void) smbfs_smb_tmpclose(np, fid, scred);
- smbfs_rw_exit(&np->r_lkserlock);
+ if (fid != NULL)
+ smbfs_smb_tmpclose(np, fid);
if (error == 0) {
/* Keep lookup from finding this node anymore. */
@@ -3080,6 +3067,7 @@ smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp, char *nnm,
vnode_t *nvp = NULL;
int error;
int nvp_locked = 0;
+ smb_fh_t *fid = NULL;
/* Things our caller should have checked. */
ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone);
@@ -3160,8 +3148,23 @@ smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp, char *nnm,
nvp = NULL;
} /* nvp */
+ /*
+ * Get a file handle with delete access.
+ * Close this FID before return.
+ */
+ error = smbfs_smb_tmpopen(onp, STD_RIGHT_DELETE_ACCESS,
+ scred, &fid);
+ if (error) {
+ SMBVDEBUG("error %d opening %s\n",
+ error, onp->n_rpath);
+ goto out;
+ }
+
smbfs_attrcache_remove(onp);
- error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), scred);
+ error = smbfs_smb_rename(odnp, onp, ndnp, nnm, strlen(nnm),
+ fid, scred);
+
+ smbfs_smb_tmpclose(onp, fid);
/*
* If the old name should no longer exist,
@@ -3202,7 +3205,7 @@ smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
struct smbfattr fattr;
const char *name = (const char *) nm;
int nmlen = strlen(name);
- int error, hiderr;
+ int error;
if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
return (EPERM);
@@ -3243,10 +3246,6 @@ smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
if (error)
goto out;
- if (name[0] == '.')
- if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
- SMBVDEBUG("hide failure %d\n", hiderr);
-
/* Success! */
*vpp = vp;
error = 0;
@@ -3270,12 +3269,12 @@ static int
smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
caller_context_t *ct, int flags)
{
+ struct smb_cred scred;
vnode_t *vp = NULL;
int vp_locked = 0;
struct smbmntinfo *smi = VTOSMI(dvp);
struct smbnode *dnp = VTOSMB(dvp);
struct smbnode *np;
- struct smb_cred scred;
int error;
if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
@@ -3284,17 +3283,16 @@ smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
return (EIO);
- if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
- return (EINTR);
- smb_credinit(&scred, cr);
-
/*
- * Require w/x access in the containing directory.
- * Server handles all other access checks.
+ * Verify access to the dirctory.
*/
- error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
+ error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
if (error)
- goto out;
+ return (error);
+
+ if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
+ return (EINTR);
+ smb_credinit(&scred, cr);
/*
* First lookup the entry to be removed.
@@ -3327,23 +3325,17 @@ smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
goto out;
}
- smbfs_attrcache_remove(np);
- error = smbfs_smb_rmdir(np, &scred);
-
/*
- * Similar to smbfs_remove
+ * Do the real rmdir work
*/
- switch (error) {
- case 0:
- case ENOENT:
- case ENOTDIR:
- smbfs_attrcache_prune(np);
- break;
- }
-
+ error = smbfsremove(dvp, vp, &scred, flags);
if (error)
goto out;
+#ifdef SMBFS_VNEVENT
+ vnevent_rmdir(vp, dvp, nm, ct);
+#endif
+
mutex_enter(&np->r_statelock);
dnp->n_flag |= NMODIFIED;
mutex_exit(&np->r_statelock);
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c
index 5a36306283..323b8c8d10 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -45,7 +45,9 @@
#include <sys/u8_textprep.h>
#include <netsmb/smb_osdep.h>
+
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_rq.h>
@@ -291,32 +293,20 @@ smbfs_xa_getfattr(struct smbnode *xnp, struct smbfattr *fap,
}
/*
- * Fetch the entire attribute list here in findopen.
- * Will parse the results in findnext.
+ * Actually go OtW to get the list of "streams".
*
* This is called on the XATTR directory, so we
* have to get the (real) parent object first.
*/
-/* ARGSUSED */
-int
-smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
- const char *wildcard, int wclen)
+static int
+smbfs_xa_get_streaminfo(struct smbfs_fctx *ctx)
{
vnode_t *pvp; /* parent */
smbnode_t *pnp;
- struct smb_t2rq *t2p;
- struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
- struct mbchain *mbp;
+ smbnode_t *dnp = ctx->f_dnp;
+ struct mdchain *mdp;
int error;
- ASSERT(dnp->n_flag & N_XATTR);
-
- ctx->f_type = ft_XA;
- ctx->f_namesz = SMB_MAXFNAMELEN + 1;
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- ctx->f_namesz *= 2;
- ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
-
error = smbfs_xa_parent(SMBTOV(dnp), &pvp);
if (error)
return (error);
@@ -324,40 +314,31 @@ smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
/* Note: pvp has a VN_HOLD */
pnp = VTOSMB(pvp);
- if (ctx->f_t2) {
- smb_t2_done(ctx->f_t2);
- ctx->f_t2 = NULL;
- }
+ /*
+ * Get stream info into f_mdchain
+ */
+ mdp = &ctx->f_mdchain;
+ md_done(mdp);
- error = smb_t2_alloc(SSTOCP(ctx->f_ssp),
- SMB_TRANS2_QUERY_PATH_INFORMATION,
- ctx->f_scred, &t2p);
+ if (SSTOVC(ctx->f_ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_get_streaminfo(pnp, mdp, ctx->f_scred);
+ } else {
+ error = smbfs_smb1_get_streaminfo(pnp, mdp, ctx->f_scred);
+ }
if (error)
goto out;
- ctx->f_t2 = t2p;
- mbp = &t2p->t2_tparam;
- (void) mb_init(mbp);
- (void) mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO);
- (void) mb_put_uint32le(mbp, 0);
- error = smbfs_fullpath(mbp, vcp, pnp, NULL, NULL, 0);
- if (error)
- goto out;
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = INT16_MAX;
- error = smb_t2_request(t2p);
- if (error) {
- if (t2p->t2_sr_error == NT_STATUS_INVALID_PARAMETER)
- error = ENOTSUP;
- }
/*
- * No returned parameters to parse.
- * Returned data are in t2_rdata,
- * which we'll parse in _findnext.
- * However, save the wildcard.
+ * Have stream info in ctx->f_mdchain
+ * Initialize buffer length, position.
*/
- ctx->f_wildcard = wildcard;
- ctx->f_wclen = wclen;
+ ctx->f_left = m_fixhdr(mdp->md_top);
+ ctx->f_eofs = 0;
+
+ /*
+ * After one successful call, we're at EOF.
+ */
+ ctx->f_flags |= SMBFS_RDD_EOF;
out:
VN_RELE(pvp);
@@ -365,83 +346,62 @@ out:
}
/*
- * Get the next name in an XATTR directory into f_name
+ * Get a buffer of directory entries (if we don't already have
+ * some remaining in the current buffer) then decode one.
*/
-/* ARGSUSED */
int
-smbfs_xa_findnext(struct smbfs_fctx *ctx, uint16_t limit)
+smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen)
{
- struct mdchain *mdp;
- struct smb_t2rq *t2p;
- uint32_t size, next;
- uint64_t llongint;
- int error, skip, used, nmlen;
- t2p = ctx->f_t2;
- mdp = &t2p->t2_rdata;
+ ASSERT(dnp->n_flag & N_XATTR);
- if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
- ASSERT(ctx->f_wildcard);
- SMBVDEBUG("wildcard: %s\n", ctx->f_wildcard);
- }
+ ctx->f_type = ft_XA;
+ ctx->f_namesz = SMB_MAXFNAMELEN + 1;
+ ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
+ ctx->f_infolevel = FileStreamInformation;
+ ctx->f_wildcard = wildcard;
+ ctx->f_wclen = wclen;
-again:
- if (ctx->f_flags & SMBFS_RDD_EOF)
- return (ENOENT);
-
- /* Parse FILE_STREAM_INFORMATION */
- if ((error = md_get_uint32le(mdp, &next)) != 0) /* offset to */
- return (ENOENT);
- if ((error = md_get_uint32le(mdp, &size)) != 0) /* name len */
- return (ENOENT);
- (void) md_get_uint64le(mdp, &llongint); /* file size */
- ctx->f_attr.fa_size = llongint;
- (void) md_get_uint64le(mdp, NULL); /* alloc. size */
- used = 4 + 4 + 8 + 8; /* how much we consumed */
+ return (0);
+}
- /*
- * Copy the string, but skip the first char (":")
- * Watch out for zero-length strings here.
- */
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
- if (size >= 2) {
- size -= 2; used += 2;
- (void) md_get_uint16le(mdp, NULL);
- }
- nmlen = min(size, SMB_MAXFNAMELEN * 2);
- } else {
- if (size >= 1) {
- size -= 1; used += 1;
- (void) md_get_uint8(mdp, NULL);
- }
- nmlen = min(size, SMB_MAXFNAMELEN);
- }
- ASSERT(nmlen < ctx->f_namesz);
- ctx->f_nmlen = nmlen;
- error = md_get_mem(mdp, ctx->f_name, nmlen, MB_MSYSTEM);
- if (error)
- return (error);
- used += nmlen;
+/*
+ * Get the next name in an XATTR directory
+ */
+/* ARGSUSED */
+int
+smbfs_xa_findnext(struct smbfs_fctx *ctx, uint16_t limit)
+{
+ int error;
/*
- * Convert UCS-2 to UTF-8
+ * If we've scanned to the end of the current buffer
+ * try to read anohther buffer of dir entries.
+ * Treat anything less than 8 bytes as an "empty"
+ * buffer to ensure we can read something.
+ * (There may be up to 8 bytes of padding.)
*/
- smbfs_fname_tolocal(ctx);
- if (nmlen)
- SMBVDEBUG("name: %s\n", ctx->f_name);
- else
- SMBVDEBUG("null name!\n");
+again:
+ if ((ctx->f_eofs + 8) > ctx->f_left) {
+ /* Scanned the whole buffer. */
+ if (ctx->f_flags & SMBFS_RDD_EOF)
+ return (ENOENT);
+ ctx->f_limit = limit;
+ error = smbfs_xa_get_streaminfo(ctx);
+ if (error)
+ return (error);
+ ctx->f_otws++;
+ }
/*
- * Skip padding until next offset
+ * Decode one entry, advance f_eofs
*/
- if (next > used) {
- skip = next - used;
- (void) md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
- }
- if (next == 0)
- ctx->f_flags |= SMBFS_RDD_EOF;
+ error = smbfs_decode_dirent(ctx);
+ if (error)
+ return (error);
+ SMBVDEBUG("name: %s\n", ctx->f_name);
/*
* Chop off the trailing ":$DATA"
@@ -464,8 +424,10 @@ again:
goto again;
/*
- * If this is a lookup of a specific name,
- * skip past any non-matching names.
+ * When called by lookup, we'll have the "single" flag,
+ * and a name with no wildcards. We need to filter here
+ * because smbfs_xa_get_streaminfo() gets ALL the names
+ * (not just those matching our pattern).
*/
if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
if (ctx->f_wclen != ctx->f_nmlen)
@@ -490,8 +452,6 @@ smbfs_xa_findclose(struct smbfs_fctx *ctx)
if (ctx->f_name)
kmem_free(ctx->f_name, ctx->f_namesz);
- if (ctx->f_t2)
- smb_t2_done(ctx->f_t2);
return (0);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c b/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c
index f4a9f9a948..4ed5cba79c 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c
@@ -22,7 +22,7 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -31,7 +31,7 @@
*/
#include <smbsrv/smb2_kproto.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
struct smb2_ioctbl_ent {
uint32_t te_code;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
index ffe230f888..6176a8b002 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2007, 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.
*/
#include <smbsrv/smb_kproto.h>
@@ -30,7 +30,7 @@
#include <smbsrv/string.h>
#include <smbsrv/nmpipes.h>
#include <smbsrv/mailslot.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
/*
* count of bytes in server response packet
@@ -943,7 +943,7 @@ smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa)
data_off, /* Data offset from header start */
data_disp, /* Data displacement */
n_setup, /* suwcnt */
- &xa->rep_setup_mb, /* setup[] */
+ &xa->rep_setup_mb, /* setup[] */
tot_packet_bytes, /* Total data bytes */
param_pad,
&xa->rep_param_mb,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_dfs.c b/usr/src/uts/common/fs/smbsrv/smb_dfs.c
index 495965859b..03c565e9e4 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_dfs.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_dfs.c
@@ -22,13 +22,13 @@
* Copyright 2010 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.
*/
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_dfs.h>
#include <smbsrv/smb_door.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
/*
* Get Referral response header flags
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
index c0ab285bd5..f355e314bc 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
@@ -20,11 +20,11 @@
*/
/*
* Copyright (c) 2007, 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.
*/
#include <smbsrv/smb_kproto.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
static uint32_t smb_nt_trans_ioctl_noop(smb_request_t *, smb_xa_t *);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_opipe.c b/usr/src/uts/common/fs/smbsrv/smb_opipe.c
index 273a2f7297..c08cba0ac6 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_opipe.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_opipe.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.
*/
/*
@@ -35,7 +35,7 @@
#include <sys/filio.h>
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_xdr.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
static uint32_t smb_opipe_transceive(smb_request_t *, smb_fsctl_t *);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c
index df874ffe1d..918bf78727 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c
@@ -22,11 +22,11 @@
* Copyright 2010 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.
*/
#include <smbsrv/smb_kproto.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
/*
* [MS-CIFS]
diff --git a/usr/src/uts/common/fs/smbsrv/smb_vss.c b/usr/src/uts/common/fs/smbsrv/smb_vss.c
index 211bc467a8..72657ae3be 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_vss.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_vss.c
@@ -41,7 +41,7 @@
#include <smbsrv/smb_kproto.h>
#include <smbsrv/string.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
#include <smbsrv/smb_door.h>
/* Size of the token on the wire due to encoding */
diff --git a/usr/src/uts/common/netsmb/mchain.h b/usr/src/uts/common/netsmb/mchain.h
index 4f236d6b52..156671999b 100644
--- a/usr/src/uts/common/netsmb/mchain.h
+++ b/usr/src/uts/common/netsmb/mchain.h
@@ -36,7 +36,7 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _MCHAIN_H_
@@ -105,6 +105,7 @@
*/
#include <sys/stream.h> /* mblk_t */
+#include <sys/strsun.h> /* MBLKL */
typedef mblk_t mbuf_t;
/* BEGIN CSTYLED */
@@ -226,6 +227,7 @@ void mb_initm(mbchain_t *, mbuf_t *);
void mb_done(mbchain_t *);
void *mb_reserve(mbchain_t *, int size);
+int mb_put_align8(mbchain_t *mbp);
int mb_put_padbyte(mbchain_t *mbp);
int mb_put_uint8(mbchain_t *, uint8_t);
int mb_put_uint16be(mbchain_t *, uint16_t);
@@ -236,6 +238,7 @@ int mb_put_uint64be(mbchain_t *, uint64_t);
int mb_put_uint64le(mbchain_t *, uint64_t);
int mb_put_mem(mbchain_t *, const void *, int, int);
int mb_put_mbuf(mbchain_t *, mbuf_t *);
+int mb_put_mbchain(mbchain_t *, mbchain_t *);
int md_init(mdchain_t *mdp);
void md_initm(mdchain_t *mbp, mbuf_t *m);
@@ -250,5 +253,7 @@ int md_get_uint64be(mdchain_t *, uint64_t *);
int md_get_uint64le(mdchain_t *, uint64_t *);
int md_get_mem(mdchain_t *, void *, int, int);
int md_get_mbuf(mdchain_t *, int, mbuf_t **);
+int md_seek(mdchain_t *, uint32_t);
+uint32_t md_tell(mdchain_t *);
#endif /* !_MCHAIN_H_ */
diff --git a/usr/src/uts/common/netsmb/smb.h b/usr/src/uts/common/netsmb/smb.h
index e3bfc5144c..b57be5bbfe 100644
--- a/usr/src/uts/common/netsmb/smb.h
+++ b/usr/src/uts/common/netsmb/smb.h
@@ -40,6 +40,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_H_
@@ -66,8 +67,8 @@ enum smb_dialects {
SMB_DIALECT_LANMAN1_0, /* MICROSOFT NETWORKS 3.0, LANMAN1.0 */
SMB_DIALECT_LANMAN2_0, /* LM1.2X002, DOS LM1.2X002, Samba */
SMB_DIALECT_LANMAN2_1, /* DOS LANMAN2.1, LANMAN2.1 */
- SMB_DIALECT_NTLM0_12 /* NT LM 0.12, Windows for Workgroups */
- /* 3.1a, * NT LANMAN 1.0 */
+ SMB_DIALECT_NTLM0_12, /* NT LM 0.12, etc. */
+ SMB_DIALECT_SMB2_FF /* SMB1 negotiate to SMB2 */
};
/*
@@ -82,11 +83,18 @@ enum smb_dialects {
/*
* SMB header
*/
+
#define SMB_SIGNATURE "\xFFSMB"
#define SMB_SIGLEN 4
#define SMB_HDRCMD(p) (*((uchar_t *)(p) + SMB_SIGLEN))
#define SMB_HDRMID(p) (*(ushort_t *)((uchar_t *)(p) + 30))
+#define SMB_HDR_OFF_MID 30
#define SMB_HDRLEN 32
+
+#define SMB_HDR_V1 0xFF
+#define SMB_HDR_V2 0xFE
+#define SMB_HDR_V3E 0xFD /* SMB3 encrypted */
+
/*
* bits in the smb_flags field
*/
@@ -151,6 +159,25 @@ enum smb_dialects {
#define SMB_CAP_COMPRESSED_DATA 0x40000000
#define SMB_CAP_EXT_SECURITY 0x80000000
+/* SMB_COM_TREE_CONNECT_ANDX flags. See [MS-SMB] for a complete description. */
+#define TREE_CONNECT_ANDX_DISCONNECT_TID 0x0001
+#define TREE_CONNECT_ANDX_EXTENDED_SIGNATURES 0x0004
+#define TREE_CONNECT_ANDX_EXTENDED_RESPONSE 0x0008
+
+/*
+ * SMB_COM_TREE_CONNECT_ANDX optional support flags. See [MS-SMB] for a
+ * complete description.
+ */
+#define SMB_SUPPORT_SEARCH_BITS 0x0001 /* supports SearchAttributes */
+#define SMB_SHARE_IS_IN_DFS 0x0002 /* share is managed by DFS */
+#define SMB_CSC_MASK 0x000C /* Offline-caching bits. */
+#define SMB_UNIQUE_FILE_NAME 0x0010 /* Long file names only */
+#define SMB_EXTENDED_SIGNATURES 0x0020 /* Signing key protection. */
+/* See [MS-SMB] for a complete description of SMB_CSC_MASK bits. */
+#define SMB_CSC_CACHE_MANUAL_REINT 0x0000
+#define SMB_CSC_CACHE_AUTO_REINT 0x0004
+#define SMB_CSC_CACHE_VDO 0x0008
+
/*
* File attributes
*/
@@ -372,6 +399,7 @@ enum smb_dialects {
#define SMB_QFS_DEVICE_INFO 0x104
#define SMB_QFS_ATTRIBUTE_INFO 0x105
#define SMB_QFS_UNIX_INFO 0x200
+#define SMB_QFS_POSIX_WHOAMI 0x202
#define SMB_QFS_MAC_FS_INFO 0x301
#define SMB_QFS_VOLUME_INFORMATION 1001
#define SMB_QFS_SIZE_INFORMATION 1003
@@ -381,6 +409,11 @@ enum smb_dialects {
#define SMB_QFS_FULL_SIZE_INFORMATION 1007
#define SMB_QFS_OBJECTID_INFORMATION 1008
+/*
+ * NT Notify Change Compeletion Filter
+ * NT Notify Actions
+ * (We don't use these.)
+ */
/*
* SMB_QFS_ATTRIBUTE_INFO bits.
@@ -403,6 +436,7 @@ enum smb_dialects {
#define FILE_SUPPORTS_OBJECT_IDS 0x00010000
#define FILE_SUPPORTS_ENCRYPTION 0x00020000
#define FILE_NAMED_STREAMS 0x00040000
+#define FILE_READ_ONLY_VOLUME 0x00080000
/*
* SMB_TRANS2_QUERY_PATH levels
@@ -424,9 +458,12 @@ enum smb_dialects {
#define SMB_QFILEINFO_COMPRESSION_INFO 0x10b
#define SMB_QFILEINFO_UNIX_BASIC 0x200
#define SMB_QFILEINFO_UNIX_LINK 0x201
+#define SMB_QFILEINFO_POSIX_ACL 0x204
+#define SMB_QFILEINFO_UNIX_INFO2 0x20B
#define SMB_QFILEINFO_MAC_DT_GET_APPL 0x306
#define SMB_QFILEINFO_MAC_DT_GET_ICON 0x307
#define SMB_QFILEINFO_MAC_DT_GET_ICON_INFO 0x308
+#define SMB_QFILEINFO_MAC_SPOTLIGHT 0x310
#define SMB_QFILEINFO_BASIC_INFORMATION 1004
#define SMB_QFILEINFO_STANDARD_INFORMATION 1005
#define SMB_QFILEINFO_INTERNAL_INFORMATION 1006
@@ -454,6 +491,9 @@ enum smb_dialects {
#define SMB_FIND_NAME_INFO 0x103
#define SMB_FIND_BOTH_DIRECTORY_INFO 0x104
#define SMB_FIND_UNIX_INFO 0x200
+/* Transact 2 Find First levels */
+#define SMB_FIND_FILE_UNIX 0x202
+#define SMB_FIND_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */
/*
* Selectors for NT_TRANSACT_QUERY_SECURITY_DESC and
@@ -707,6 +747,9 @@ typedef struct ntsid ntsid_t;
#define SMB_SFILEINFO_UNIX_BASIC 0x200
#define SMB_SFILEINFO_UNIX_LINK 0x201
#define SMB_SFILEINFO_UNIX_HLINK 0x203
+#define SMB_SFILEINFO_POSIX_ACL 0x204
+#define SMB_SFILEINFO_POSIX_UNLINK 0x20A
+#define SMB_SFILEINFO_UNIX_INFO2 0x20B
#define SMB_SFILEINFO_DIRECTORY_INFORMATION 1001
#define SMB_SFILEINFO_FULL_DIRECTORY_INFORMATION 1002
#define SMB_SFILEINFO_BOTH_DIRECTORY_INFORMATION 1003
@@ -816,4 +859,19 @@ typedef struct ntlmv2_namehdr ntlmv2_namehdr_t;
#define STYPE_TEMPORARY 0x40000000
#define STYPE_HIDDEN 0x80000000
+/*
+ * Characters that are not allowed in an SMB file name component.
+ * From MSDN: Naming Files, Paths, ...
+ * < (less than)
+ * > (greater than)
+ * : (colon)
+ * " (double quote)
+ * / (forward slash)
+ * \ (backslash)
+ * | (vertical bar or pipe)
+ * ? (question mark)
+ * * (asterisk)
+ */
+#define SMB_FILENAME_INVALID_CHARS "<>:\"/\\|?*"
+
#endif /* _NETSMB_SMB_H_ */
diff --git a/usr/src/uts/common/netsmb/smb2.h b/usr/src/uts/common/netsmb/smb2.h
new file mode 100644
index 0000000000..abae5e8063
--- /dev/null
+++ b/usr/src/uts/common/netsmb/smb2.h
@@ -0,0 +1,465 @@
+/*
+ * 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.
+ */
+
+#ifndef _NETSMB_SMB2_H
+#define _NETSMB_SMB2_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SMB2_PROTOCOL_ID { 0xFE, 'S', 'M', 'B' }
+#define SMB2_HDR_SIZE 64
+#define SMB2_HDRLEN SMB2_HDR_SIZE
+
+/*
+ * SMB2 header command codes.
+ * These are uint16_t on the wire.
+ */
+typedef enum {
+ SMB2_NEGOTIATE = 0,
+ SMB2_SESSION_SETUP,
+ SMB2_LOGOFF,
+ SMB2_TREE_CONNECT,
+ SMB2_TREE_DISCONNECT,
+ SMB2_CREATE,
+ SMB2_CLOSE,
+ SMB2_FLUSH,
+ SMB2_READ,
+ SMB2_WRITE,
+ SMB2_LOCK,
+ SMB2_IOCTL,
+ SMB2_CANCEL,
+ SMB2_ECHO,
+ SMB2_QUERY_DIRECTORY,
+ SMB2_CHANGE_NOTIFY,
+ SMB2_QUERY_INFO,
+ SMB2_SET_INFO,
+ SMB2_OPLOCK_BREAK,
+ /*
+ * The above (oplock break) is the last real SMB2 op-code.
+ * We use one more slot to represent invalid commands, and
+ * the final enum value is used for array sizes. Keep last!
+ */
+ SMB2_INVALID_CMD,
+ SMB2__NCMDS
+} SMB2_cmd_code;
+
+/*
+ * SMB2 header flags.
+ */
+
+/*
+ * SERVER_TO_REDIR
+ * When set, indicates the message is a response rather than
+ * a request. This MUST be set on responses sent from the
+ * server to the client, and MUST NOT be set on requests
+ * sent from the client to the server.
+ */
+#define SMB2_FLAGS_SERVER_TO_REDIR 0x00000001
+
+/*
+ * ASYNC_COMMAND
+ * When set, indicates that this is an ASYNC SMB2 header.
+ * Always set for headers of the form described in this
+ * section.
+ */
+#define SMB2_FLAGS_ASYNC_COMMAND 0x00000002
+
+/*
+ * RELATED_OPERATIONS
+ * When set in an SMB2 request, indicates that this request
+ * is a related operation in a compounded request chain.
+ * [MS-SMB2 sec. 3.2.4.1.4]
+ *
+ * When set in an SMB2 compound response, indicates that
+ * the request corresponding to this response was part of a
+ * related operation in a compounded request chain.
+ * [MS-SMB2 sec. 3.3.5.2.7.2]
+ */
+#define SMB2_FLAGS_RELATED_OPERATIONS 0x00000004
+
+/*
+ * SIGNED
+ * When set, indicates that this packet has been signed.
+ * [MS-SMB2 3.1.5.1]
+ */
+#define SMB2_FLAGS_SIGNED 0x00000008
+
+/*
+ * [MS-SMB2] 3.2.5.3.1 The SessionKey MUST be set to the
+ * first 16 bytes of the cryptographic key from GSSAPI.
+ * (Padded with zeros if the GSSAPI key is shorter.)
+ */
+#define SMB2_SESSION_KEY_LEN 16
+
+/*
+ * DFS_OPERATIONS
+ * When set, indicates that this command is a Distributed
+ * File System (DFS) operation. [MS-SMB2 3.3.5.9]
+ */
+#define SMB2_FLAGS_DFS_OPERATIONS 0x10000000
+
+/*
+ * REPLAY_OPERATION
+ * This flag is only valid for the SMB 3.0 dialect. When set,
+ * it indicates that this command is a replay operation.
+ * The client MUST ignore this bit on receipt.
+ */
+#define SMB2_FLAGS_REPLAY_OPERATION 0x20000000
+
+/*
+ * SMB2 Netgotiate [MS-SMB2 2.2.3]
+ */
+
+#define SMB2_NEGOTIATE_SIGNING_ENABLED 0x01
+#define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x02
+
+#define SMB2_CAP_DFS 0x00000001
+
+/* Added with SMB2.1 */
+#define SMB2_CAP_DFS 0x00000001
+#define SMB2_CAP_LEASING 0x00000002
+/*
+ * LARGE_MTU:
+ * When set, indicates that the client supports multi-credit operations.
+ */
+#define SMB2_CAP_LARGE_MTU 0x00000004
+
+/* Added with SMB3.0 */
+#define SMB2_CAP_MULTI_CHANNEL 0x00000008
+#define SMB2_CAP_PERSISTENT_HANDLES 0x00000010
+#define SMB2_CAP_DIRECTORY_LEASING 0x00000020
+#define SMB2_CAP_ENCRYPTION 0x00000040
+
+/* SMB2 session flags */
+#define SMB2_SESSION_FLAG_IS_GUEST 0x0001
+#define SMB2_SESSION_FLAG_IS_NULL 0x0002
+#define SMB2_SESSION_FLAG_ENCRYPT_DATA 0x0004
+
+/*
+ * SMB2 Tree connect, disconnect
+ */
+
+/* SMB2 sharetype flags */
+#define SMB2_SHARE_TYPE_DISK 0x1
+#define SMB2_SHARE_TYPE_PIPE 0x2
+#define SMB2_SHARE_TYPE_PRINT 0x3
+
+/* SMB2 share flags */
+#define SMB2_SHAREFLAG_MANUAL_CACHING 0x00000000
+#define SMB2_SHAREFLAG_AUTO_CACHING 0x00000010
+#define SMB2_SHAREFLAG_VDO_CACHING 0x00000020
+#define SMB2_SHAREFLAG_NO_CACHING 0x00000030
+#define SMB2_SHAREFLAG_DFS 0x00000001
+#define SMB2_SHAREFLAG_DFS_ROOT 0x00000002
+#define SMB2_SHAREFLAG_RESTRICT_EXCLUSIVE_OPENS 0x00000100
+#define SMB2_SHAREFLAG_FORCE_SHARED_DELETE 0x00000200
+#define SMB2_SHAREFLAG_ALLOW_NAMESPACE_CACHING 0x00000400
+#define SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM 0x00000800
+#define SMB2_SHAREFLAG_FORCE_LEVELII_OPLOCK 0x00001000
+/* SMB 3.0 */
+#define SMB2_SHAREFLAG_ENABLE_HASH_V1 0x00002000
+#define SMB2_SHAREFLAG_ENABLE_HASH_V2 0x00004000
+#define SMB2_SHAREFLAG_ENCRYPT_DATA 0x00008000
+
+/* SMB2 share capabilities */
+#define SMB2_SHARE_CAP_DFS 0x00000008
+/* SMB 3.0 */
+#define SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY 0x00000010
+#define SMB2_SHARE_CAP_SCALEOUT 0x00000020
+#define SMB2_SHARE_CAP_CLUSTER 0x00000040
+
+/*
+ * SMB2 Create (open)
+ */
+
+/* SMB2 requested oplock levels */
+#define SMB2_OPLOCK_LEVEL_NONE 0x00
+#define SMB2_OPLOCK_LEVEL_II 0x01
+#define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08
+#define SMB2_OPLOCK_LEVEL_BATCH 0x09
+#define SMB2_OPLOCK_LEVEL_LEASE 0xFF
+
+/* SMB2 impersonation levels */
+#define SMB2_IMPERSONATION_ANONYMOUS 0x00
+#define SMB2_IMPERSONATION_IDENTIFICATION 0x01
+#define SMB2_IMPERSONATION_IMPERSONATION 0x02
+#define SMB2_IMPERSONATION_DELEGATE 0x03
+
+/*
+ * Note: ShareAccess, CreateDispositon, CreateOptions,
+ * all use the same definitions as SMB1 (from MS-FSA).
+ * Ditto FileAccess flags (as with ACLs)
+ */
+
+/* SMB2 Create Context tags */
+
+#define SMB2_CREATE_EA_BUFFER 0x45787441 /* ("ExtA") */
+/*
+ * The data contains the extended attributes
+ * that MUST be stored on the created file.
+ * This value MUST NOT be set for named
+ * pipes and print files.
+ */
+
+#define SMB2_CREATE_SD_BUFFER 0x53656344 /* ("SecD") */
+/*
+ * The data contains a security descriptor that
+ * MUST be stored on the created file.
+ * This value MUST NOT be set for named
+ * pipes and print files.
+ */
+
+#define SMB2_CREATE_DURABLE_HANDLE_REQUEST 0x44486e51 /* ("DHnQ") */
+/* The client is requesting the open to be durable */
+
+#define SMB2_CREATE_DURABLE_HANDLE_RECONNECT 0x44486e43 /* ("DHnC") */
+/*
+ * The client is requesting to reconnect to a
+ * durable open after being disconnected
+ */
+
+#define SMB2_CREATE_ALLOCATION_SIZE 0x416c5369 /* ("AISi") */
+/*
+ * The data contains the required allocation
+ * size of the newly created file.
+ */
+
+#define SMB2_CREATE_QUERY_MAXIMAL_ACCESS 0x4d784163 /* ("MxAc") */
+/*
+ * The client is requesting that the server
+ * return maximal access information.
+ */
+
+#define SMB2_CREATE_TIMEWARP_TOKEN 0x54577270 /* ("TWrp") */
+/*
+ * The client is requesting that the server
+ * open an earlier version of the file identified
+ * by the provided time stamp.
+ */
+
+#define SMB2_CREATE_QUERY_ON_DISK_ID 0x51466964 /* ("QFid") */
+/*
+ * The client is requesting that the server return a 32-byte
+ * opaque BLOB that uniquely identifies the file being opened
+ * on disk. No data is passed to the server by the client.
+ */
+
+#define SMB2_CREATE_REQUEST_LEASE 0x52714c73 /* ("RqLs") */
+/*
+ * The client is requesting that the server return a lease.
+ * This value is only supported for the SMB 2.1 and 3.0 dialects.
+ */
+
+/* SMB2 create request lease */
+#define SMB2_LEASE_NONE 0x00
+#define SMB2_LEASE_READ_CACHING 0x01
+#define SMB2_LEASE_HANDLE_CACHING 0x02
+#define SMB2_LEASE_WRITE_CACHING 0x04
+
+/* SMB2 lease break notification flags */
+#define SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED 0x01
+
+/*
+ * SMB2 Close
+ */
+#define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB 0x0001
+
+/*
+ * SMB2 Write
+ */
+#define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001
+
+/*
+ * SMB2 Lock Request
+ */
+
+/* SMB2 lock flags */
+
+/*
+ * SMB2_LOCKFLAG_SHARED_LOCK
+ * The range MUST be locked shared, allowing other opens
+ * to read from or take a shared lock on the range. All opens
+ * MUST NOT be allowed to write within the range. Other
+ * locks can be requested and taken on this range.
+ */
+#define SMB2_LOCKFLAG_SHARED_LOCK 0x00000001
+
+/*
+ * SMB2_LOCKFLAG_EXCLUSIVE_LOCK
+ * The range MUST be locked exclusive, not allowing other
+ * opens to read, write, or lock within the range.
+ */
+#define SMB2_LOCKFLAG_EXCLUSIVE_LOCK 0x00000002
+
+/*
+ * SMB2_LOCKFLAG_UNLOCK
+ * The range MUST be unlocked from a previous lock taken
+ * on this range. The unlock range MUST be identical to the
+ * lock range. Sub-ranges cannot be unlocked.
+ */
+#define SMB2_LOCKFLAG_UNLOCK 0x00000004
+
+/*
+ * SMB2_LOCKFLAG_FAIL_IMMEDIATELY
+ * The lock operation MUST fail immediately if it conflicts
+ * with an existing lock, instead of waiting for the range to
+ * become available. This can be OR'ed with either of
+ * shared_lock, exclusive_lock (nothing else).
+ */
+#define SMB2_LOCKFLAG_FAIL_IMMEDIATELY 0x00000010
+
+/*
+ * SMB2 Ioctl Request
+ */
+#define SMB2_IOCTL_IS_FSCTL 0x00000001
+
+
+/*
+ * SMB2 Query Directory
+ */
+
+/*
+ * SMB2 query directory info levels
+ * Same as SMB1 (see ntifs.h)
+ */
+
+/*
+ * SMB2 Query Directory Flags
+ * (our own names for these - spec. used poor names)
+ */
+#define SMB2_QDIR_FLAG_RESTART 0x01 /* SMB2_RESTART_SCANS */
+#define SMB2_QDIR_FLAG_SINGLE 0x02 /* SMB2_RETURN_SINGLE_ENTRY */
+#define SMB2_QDIR_FLAG_INDEX 0x04 /* SMB2_INDEX_SPECIFIED */
+#define SMB2_QDIR_FLAG_REOPEN 0x10 /* SMB2_REOPEN */
+
+/*
+ * SMB2 Query Info Request
+ */
+
+/* info type */
+#define SMB2_0_INFO_FILE 0x01
+/* The file information is requested. */
+#define SMB2_0_INFO_FILESYSTEM 0x02
+/* The underlying object store information is requested. */
+#define SMB2_0_INFO_SECURITY 0x03
+/* The security information is requested. */
+#define SMB2_0_INFO_QUOTA 0x04
+/* The underlying object store quota information is requested. */
+
+/*
+ * MS-FSCC 2.5 FileSystem Information Classes.
+ * Also see MSDN for ZwQueryVolumeInformationFile.
+ */
+typedef enum _FS_INFORMATION_CLASS
+{
+ FileFsVolumeInformation = 1, /* Query */
+ FileFsLabelInformation = 2, /* Set */
+ FileFsSizeInformation = 3, /* Query */
+ FileFsDeviceInformation = 4, /* Query */
+ FileFsAttributeInformation = 5, /* Query */
+ FileFsControlInformation = 6, /* Query, Set */
+ FileFsFullSizeInformation = 7, /* Query */
+ FileFsObjectIdInformation = 8, /* Query, Set */
+ FileFsDriverPathInformation = 9 /* Query */
+} FS_INFORMATION_CLASS;
+
+/*
+ * MS-FSCC 2.4 File Information Classes
+ */
+typedef enum _FILE_INFORMATION_CLASS
+{
+ FileDirectoryInformation = 1,
+ FileFullDirectoryInformation = 2,
+ FileBothDirectoryInformation = 3,
+ FileBasicInformation = 4,
+ FileStandardInformation = 5,
+ FileInternalInformation = 6,
+ FileEaInformation = 7,
+ FileAccessInformation = 8,
+ FileNameInformation = 9,
+ FileRenameInformation = 10,
+ FileLinkInformation = 11,
+ FileNamesInformation = 12,
+ FileDispositionInformation = 13,
+ FilePositionInformation = 14,
+ FileFullEaInformation = 15,
+ FileModeInformation = 16,
+ FileAlignmentInformation = 17,
+ FileAllInformation = 18,
+ FileAllocationInformation = 19,
+ FileEndOfFileInformation = 20,
+ FileAlternateNameInformation = 21,
+ FileStreamInformation = 22,
+ FilePipeInformation = 23,
+ FilePipeLocalInformation = 24,
+ FilePipeRemoteInformation = 25,
+ FileMailslotQueryInformation = 26,
+ FileMailslotSetInformation = 27,
+ FileCompressionInformation = 28,
+ FileObjectIdInformation = 29,
+ FileMoveClusterInformation = 31,
+ FileQuotaInformation = 32,
+ FileReparsePointInformation = 33,
+ FileNetworkOpenInformation = 34,
+ FileAttributeTagInformation = 35,
+ FileTrackingInformation = 36,
+ FileIdBothDirectoryInformation = 37,
+ FileIdFullDirectoryInformation = 38,
+ FileValidDataLengthInformation = 39,
+ FileShortNameInformation = 40,
+ FileSfioReserveInformation = 44,
+ FileSfioVolumeInformation = 45,
+ FileHardLinkInformation = 46,
+ FileNormalizedNameInformation = 48,
+ FileIdGlobalTxDirectoryInformation = 50,
+ FileStandardLinkInformation = 54
+} FILE_INFORMATION_CLASS;
+
+/*
+ * SMB2 Change Nofity Request
+ */
+#define SMB2_WATCH_TREE 0x00000001
+
+/*
+ * After here, added stuff from darwin
+ */
+#define SMB2_TID_UNKNOWN 0
+#define SMB2_FID_UNUSED 0xffffffffffffffff
+
+/* smb2_durable_handle flags */
+typedef enum _SMB2_DURABLE_HANDLE_FLAGS
+{
+ SMB2_DURABLE_HANDLE_REQUEST = 0x0001,
+ SMB2_DURABLE_HANDLE_RECONNECT = 0x0002,
+ SMB2_DURABLE_HANDLE_GRANTED = 0x0004,
+ SMB2_LEASE_GRANTED = 0x0008
+} _SMB2_DURABLE_HANDLE_FLAGS;
+
+struct smb2_durable_handle {
+ uint64_t fid; /* SMBFID to reconnect in durable handle reconnect */
+ uint64_t flags;
+ uint64_t lease_key_hi; /* atomic increment number */
+ uint64_t lease_key_low; /* node hash value */
+ uint32_t lease_state;
+ uint32_t pad;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NETSMB_SMB2_H */
diff --git a/usr/src/uts/common/netsmb/smb_dev.h b/usr/src/uts/common/netsmb/smb_dev.h
index fb20b9c753..817d214b3e 100644
--- a/usr/src/uts/common/netsmb/smb_dev.h
+++ b/usr/src/uts/common/netsmb/smb_dev.h
@@ -114,9 +114,19 @@
#define SMBVOPT_PERMANENT 0x0010 /* object will keep last reference */
#define SMBVOPT_ANONYMOUS 0x0020 /* using a NULL session */
-#define SMBVOPT_SIGNING_ENABLED 0x0100 /* sign if server agrees */
-#define SMBVOPT_SIGNING_REQUIRED 0x0200 /* signing required */
-#define SMBVOPT_SIGNING_MASK 0x0300 /* all signing bits */
+#define SMBVOPT_SIGNING_ENABLED 0x10000 /* sign if server agrees */
+#define SMBVOPT_SIGNING_REQUIRED 0x20000 /* signing required */
+#define SMBVOPT_SIGNING_MASK 0x30000 /* all signing bits */
+
+#define SMB2_DIALECT_BASE 0x0200
+#define SMB2_DIALECT_0202 0x0202
+#define SMB2_DIALECT_02ff 0x02ff
+#define SMB2_DIALECT_0210 0x0210
+#define SMB2_DIALECT_0300 0x0300
+#define SMB2_DIALECT_0302 0x0302
+
+/* Maximum supported dialect (for ssn_maxver) */
+#define SMB2_DIALECT_MAX SMB2_DIALECT_0210
/*
* Option flags in smbioc_oshare.ioc_opt
@@ -208,8 +218,10 @@ typedef struct smbioc_ssn_ident smbioc_ssn_ident_t;
* Structure used with SMBIOC_SSN_FIND, _CREATE
*/
struct smbioc_ossn {
- uint32_t ssn_vopt; /* i.e. SMBVOPT_CREATE */
uint32_t ssn_owner; /* Unix owner (UID) */
+ uint32_t ssn_vopt; /* i.e. SMBVOPT_CREATE */
+ uint16_t ssn_minver; /* Min SMB version. */
+ uint16_t ssn_maxver; /* Max SMB version. */
smbioc_ssn_ident_t ssn_id;
char ssn_srvname[SMBIOC_MAX_NAME];
};
@@ -248,7 +260,7 @@ struct smbioc_ssn_work {
uint32_t wk_u_auth_wlen; /* send auth tok len */
lptr_t wk_u_auth_rbuf; /* recv auth tok buf */
lptr_t wk_u_auth_wbuf; /* send auth tok buf */
- uint8_t wk_ssn_key[SMBIOC_HASH_SZ]; /* session key */
+ uint8_t wk_cl_guid[16]; /* client GUID */
};
typedef struct smbioc_ssn_work smbioc_ssn_work_t;
@@ -257,8 +269,8 @@ typedef struct smbioc_ssn_work smbioc_ssn_work_t;
*/
typedef struct smbioc_rw {
- int32_t ioc_fh;
uint32_t ioc_cnt;
+ uint32_t ioc_flags;
lloff_t _ioc_offset;
lptr_t _ioc_base;
} smbioc_rw_t;
@@ -267,10 +279,10 @@ typedef struct smbioc_rw {
/* Transact on named pipe (send/recv) */
typedef struct smbioc_xnp {
- int32_t ioc_fh;
uint32_t ioc_tdlen; /* transmit len */
uint32_t ioc_rdlen; /* recv maxlen */
uint32_t ioc_more; /* more data to read */
+ uint32_t ioc_pad1;
lptr_t _ioc_tdata;
lptr_t _ioc_rdata;
} smbioc_xnp_t;
diff --git a/usr/src/uts/common/smb/Makefile b/usr/src/uts/common/smb/Makefile
index 74ac618565..afa0837b2b 100644
--- a/usr/src/uts/common/smb/Makefile
+++ b/usr/src/uts/common/smb/Makefile
@@ -21,7 +21,7 @@
#
# Copyright (c) 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 ../../../Makefile.master
@@ -29,8 +29,10 @@ include ../../../Makefile.master
HDRS= \
doserror.h \
lmerr.h \
+ ntaccess.h \
nterror.h \
ntstatus.h \
+ winioctl.h \
wintypes.h
diff --git a/usr/src/uts/common/smbsrv/ntaccess.h b/usr/src/uts/common/smb/ntaccess.h
index 114150baa9..77d48b48ad 100644
--- a/usr/src/uts/common/smbsrv/ntaccess.h
+++ b/usr/src/uts/common/smb/ntaccess.h
@@ -21,13 +21,13 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMBSRV_NTACCESS_H
#define _SMBSRV_NTACCESS_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* This file defines the NT compatible access control masks and values.
* An access mask as a 32-bit value arranged as shown below.
diff --git a/usr/src/uts/common/smbsrv/winioctl.h b/usr/src/uts/common/smb/winioctl.h
index bbde2e4a6f..a18d7853ce 100644
--- a/usr/src/uts/common/smbsrv/winioctl.h
+++ b/usr/src/uts/common/smb/winioctl.h
@@ -22,10 +22,10 @@
* 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 _SMBSRV_WINIOCTL_H
-#define _SMBSRV_WINIOCTL_H
+#ifndef _SMB_WINIOCTL_H
+#define _SMB_WINIOCTL_H
/*
* Standard Windows NT IOCTL/FSCTL definitions (derived from the VC++
@@ -544,4 +544,4 @@ extern "C" {
}
#endif
-#endif /* _SMBSRV_WINIOCTL_H */
+#endif /* _SMB_WINIOCTL_H */
diff --git a/usr/src/uts/common/smbsrv/Makefile b/usr/src/uts/common/smbsrv/Makefile
index 4664c09cfb..a80be7497f 100644
--- a/usr/src/uts/common/smbsrv/Makefile
+++ b/usr/src/uts/common/smbsrv/Makefile
@@ -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.
#
include ../../../Makefile.master
@@ -36,7 +36,6 @@ HDRS= alloc.h \
netbios.h \
netrauth.h \
nmpipes.h \
- ntaccess.h \
ntifs.h \
ntlocale.h \
smb_sid.h \
@@ -61,7 +60,6 @@ HDRS= alloc.h \
smb2_kproto.h \
string.h \
svrapi.h \
- winioctl.h \
winsvc.h
NDLHDRS= dssetup.ndl \
diff --git a/usr/src/uts/common/smbsrv/smb.h b/usr/src/uts/common/smbsrv/smb.h
index a4986bea78..65e2708569 100644
--- a/usr/src/uts/common/smbsrv/smb.h
+++ b/usr/src/uts/common/smbsrv/smb.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2007, 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 _SMBSRV_SMB_H
@@ -39,7 +39,7 @@
#include <smb/nterror.h>
#include <smb/lmerr.h>
#include <smb/doserror.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
/*
* Macintosh Extensions for CIFS
diff --git a/usr/src/uts/intel/nsmb/ioc_check.ref b/usr/src/uts/intel/nsmb/ioc_check.ref
index e966bfdef5..7476bc696d 100644
--- a/usr/src/uts/intel/nsmb/ioc_check.ref
+++ b/usr/src/uts/intel/nsmb/ioc_check.ref
@@ -3,10 +3,12 @@
#define ID_DOMAIN_INCR 0x1
#define ID_USER 0x120
#define ID_USER_INCR 0x1
-#define SSN_VOPT 0x0
-#define SSN_OWNER 0x4
-#define SSN_ID 0x8
-#define SSN_SRVNAME 0x228
+#define SSN_OWNER 0x0
+#define SSN_VOPT 0x4
+#define SSN_MINVER 0x8
+#define SSN_MAXVER 0xa
+#define SSN_ID 0xc
+#define SSN_SRVNAME 0x22c
#define SSN_SRVNAME_INCR 0x1
#define SH_USE 0x0
#define SH_TYPE 0x4
@@ -24,20 +26,20 @@
#define WK_U_AUTH_WLEN 0x14
#define WK_U_AUTH_RBUF 0x18
#define WK_U_AUTH_WBUF 0x20
-#define WK_SSN_KEY 0x28
-#define WK_SSN_KEY_INCR 0x1
-#define SIZEOF_SMBIOC_XNP 0x20
-#define IOC_FH 0x0
-#define IOC_TDLEN 0x4
-#define IOC_RDLEN 0x8
-#define IOC_MORE 0xc
-#define _IOC_TDATA 0x10
-#define _IOC_RDATA 0x18
+#define WK_CL_GUID 0x28
+#define WK_CL_GUID_INCR 0x1
#define SIZEOF_SMBIOC_RW 0x18
-#define IOC_FH 0x0
-#define IOC_CNT 0x4
+#define IOC_CNT 0x0
+#define IOC_FLAGS 0x4
#define _IOC_OFFSET 0x8
#define _IOC_BASE 0x10
+#define SIZEOF_SMBIOC_XNP 0x20
+#define IOC_TDLEN 0x0
+#define IOC_RDLEN 0x4
+#define IOC_MORE 0x8
+#define IOC_PAD1 0xc
+#define _IOC_TDATA 0x10
+#define _IOC_RDATA 0x18
#define SIZEOF_NTCREATE 0x114
#define IOC_REQ_ACC 0x0
#define IOC_EFATTR 0x4
diff --git a/usr/src/uts/sparc/nsmb/ioc_check.ref b/usr/src/uts/sparc/nsmb/ioc_check.ref
index e966bfdef5..7476bc696d 100644
--- a/usr/src/uts/sparc/nsmb/ioc_check.ref
+++ b/usr/src/uts/sparc/nsmb/ioc_check.ref
@@ -3,10 +3,12 @@
#define ID_DOMAIN_INCR 0x1
#define ID_USER 0x120
#define ID_USER_INCR 0x1
-#define SSN_VOPT 0x0
-#define SSN_OWNER 0x4
-#define SSN_ID 0x8
-#define SSN_SRVNAME 0x228
+#define SSN_OWNER 0x0
+#define SSN_VOPT 0x4
+#define SSN_MINVER 0x8
+#define SSN_MAXVER 0xa
+#define SSN_ID 0xc
+#define SSN_SRVNAME 0x22c
#define SSN_SRVNAME_INCR 0x1
#define SH_USE 0x0
#define SH_TYPE 0x4
@@ -24,20 +26,20 @@
#define WK_U_AUTH_WLEN 0x14
#define WK_U_AUTH_RBUF 0x18
#define WK_U_AUTH_WBUF 0x20
-#define WK_SSN_KEY 0x28
-#define WK_SSN_KEY_INCR 0x1
-#define SIZEOF_SMBIOC_XNP 0x20
-#define IOC_FH 0x0
-#define IOC_TDLEN 0x4
-#define IOC_RDLEN 0x8
-#define IOC_MORE 0xc
-#define _IOC_TDATA 0x10
-#define _IOC_RDATA 0x18
+#define WK_CL_GUID 0x28
+#define WK_CL_GUID_INCR 0x1
#define SIZEOF_SMBIOC_RW 0x18
-#define IOC_FH 0x0
-#define IOC_CNT 0x4
+#define IOC_CNT 0x0
+#define IOC_FLAGS 0x4
#define _IOC_OFFSET 0x8
#define _IOC_BASE 0x10
+#define SIZEOF_SMBIOC_XNP 0x20
+#define IOC_TDLEN 0x0
+#define IOC_RDLEN 0x4
+#define IOC_MORE 0x8
+#define IOC_PAD1 0xc
+#define _IOC_TDATA 0x10
+#define _IOC_RDATA 0x18
#define SIZEOF_NTCREATE 0x114
#define IOC_REQ_ACC 0x0
#define IOC_EFATTR 0x4