summaryrefslogtreecommitdiff
path: root/usr/src/uts
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts')
-rw-r--r--usr/src/uts/common/Makefile.files4
-rw-r--r--usr/src/uts/common/fs/fs_subr.h2
-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/nsmb_sign_kcf.c180
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/offsets.in85
-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.c148
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h231
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c269
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c1597
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h39
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h7
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c322
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h50
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c171
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h73
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c810
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h105
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c349
-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.h20
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c262
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h3
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c622
-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.c49
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c3
-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.c2514
-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.c9
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c112
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c396
-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/io/aac/aac.c10
-rw-r--r--usr/src/uts/common/netsmb/mchain.h25
-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.h178
-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/common/sys/conf.h10
-rw-r--r--usr/src/uts/common/sys/debug.h4
-rw-r--r--usr/src/uts/common/sys/dirent.h2
-rw-r--r--usr/src/uts/common/sys/dnlc.h6
-rw-r--r--usr/src/uts/common/sys/file.h15
-rw-r--r--usr/src/uts/common/sys/model.h2
-rw-r--r--usr/src/uts/common/sys/modhash.h2
-rw-r--r--usr/src/uts/common/sys/poll.h2
-rw-r--r--usr/src/uts/common/sys/share.h2
-rw-r--r--usr/src/uts/common/sys/signal.h2
-rw-r--r--usr/src/uts/common/sys/stream.h6
-rw-r--r--usr/src/uts/common/sys/strsubr.h17
-rw-r--r--usr/src/uts/common/sys/t_kuser.h1
-rw-r--r--usr/src/uts/intel/nsmb/ioc_check.ref89
-rw-r--r--usr/src/uts/intel/pcbe/core_pcbe.c3
-rw-r--r--usr/src/uts/sparc/nsmb/ioc_check.ref89
77 files changed, 9556 insertions, 4775 deletions
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 8b236155fb..1ddfacb0cd 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1301,11 +1301,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
+ 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/fs_subr.h b/usr/src/uts/common/fs/fs_subr.h
index d25bf0213f..877dc36f9c 100644
--- a/usr/src/uts/common/fs/fs_subr.h
+++ b/usr/src/uts/common/fs/fs_subr.h
@@ -49,7 +49,7 @@ extern "C" {
* Utilities shared among file system implementations.
*/
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
extern int fs_nosys();
extern int fs_inval();
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/nsmb_sign_kcf.c b/usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c
new file mode 100644
index 0000000000..2be033a8fc
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c
@@ -0,0 +1,180 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Helper functions for SMB signing using the
+ * Kernel Cryptographic Framework (KCF)
+ *
+ * There are two implementations of these functions:
+ * This one (for kernel) and another for user space:
+ * See: lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
+ */
+
+#include <sys/types.h>
+#include <sys/kmem.h>
+#include <sys/sunddi.h>
+#include <sys/crypto/api.h>
+#include <netsmb/smb_signing.h>
+
+/*
+ * SMB1 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb_md5_getmech(smb_sign_mech_t *mech)
+{
+ crypto_mech_type_t t;
+
+ t = crypto_mech2id(SUN_CKM_MD5);
+ if (t == CRYPTO_MECH_INVALID)
+ return (-1);
+ mech->cm_type = t;
+ return (0);
+}
+
+/*
+ * Start the KCF session, load the key
+ */
+int
+smb_md5_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech)
+{
+ int rv;
+
+ rv = crypto_digest_init(mech, ctxp, NULL);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len)
+{
+ crypto_data_t data;
+ int rv;
+
+ bzero(&data, sizeof (data));
+ data.cd_format = CRYPTO_DATA_RAW;
+ data.cd_length = len;
+ data.cd_raw.iov_base = buf;
+ data.cd_raw.iov_len = len;
+
+ rv = crypto_digest_update(ctx, &data, 0);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * Get the final digest.
+ */
+int
+smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16)
+{
+ crypto_data_t out;
+ int rv;
+
+ bzero(&out, sizeof (out));
+ out.cd_format = CRYPTO_DATA_RAW;
+ out.cd_length = MD5_DIGEST_LENGTH;
+ out.cd_raw.iov_len = MD5_DIGEST_LENGTH;
+ out.cd_raw.iov_base = (void *)digest16;
+
+ rv = crypto_digest_final(ctx, &out, 0);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * SMB2 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb2_hmac_getmech(smb_sign_mech_t *mech)
+{
+ crypto_mech_type_t t;
+
+ t = crypto_mech2id(SUN_CKM_SHA256_HMAC);
+ if (t == CRYPTO_MECH_INVALID)
+ return (-1);
+ mech->cm_type = t;
+ return (0);
+}
+
+/*
+ * Start the KCF session, load the key
+ */
+int
+smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech,
+ uint8_t *key, size_t key_len)
+{
+ crypto_key_t ckey;
+ int rv;
+
+ bzero(&ckey, sizeof (ckey));
+ ckey.ck_format = CRYPTO_KEY_RAW;
+ ckey.ck_data = key;
+ ckey.ck_length = key_len * 8; /* in bits */
+
+ rv = crypto_mac_init(mech, &ckey, NULL, ctxp, NULL);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb2_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
+{
+ crypto_data_t data;
+ int rv;
+
+ bzero(&data, sizeof (data));
+ data.cd_format = CRYPTO_DATA_RAW;
+ data.cd_length = len;
+ data.cd_raw.iov_base = (void *)in;
+ data.cd_raw.iov_len = len;
+
+ rv = crypto_mac_update(ctx, &data, 0);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * Note, the SMB2 signature is the first 16 bytes of the
+ * 32-byte SHA256 HMAC digest.
+ */
+int
+smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16)
+{
+ uint8_t full_digest[SHA256_DIGEST_LENGTH];
+ crypto_data_t out;
+ int rv;
+
+ bzero(&out, sizeof (out));
+ out.cd_format = CRYPTO_DATA_RAW;
+ out.cd_length = SHA256_DIGEST_LENGTH;
+ out.cd_raw.iov_len = SHA256_DIGEST_LENGTH;
+ out.cd_raw.iov_base = (void *)full_digest;
+
+ rv = crypto_mac_final(ctx, &out, 0);
+ if (rv == CRYPTO_SUCCESS)
+ bcopy(full_digest, digest16, 16);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
index 993bdd61a8..a78b08bba0 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
@@ -20,7 +20,7 @@
\
\
-\ Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+\ Copyright 2018 Nexenta Systems, Inc. All rights reserved.
\ Copyright 2009 Sun Microsystems, Inc. All rights reserved.
\ Use is subject to license terms.
\
@@ -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
@@ -68,77 +70,30 @@ smbioc_tcon
tc_opt
tc_sh
-smb_sopt
- sv_proto
- sv_sm
- sv_tz
- sv_maxmux
- sv_maxvcs
- sv_rawmode
- sv_maxtx
- sv_maxraw
- sv_skey
- sv_caps
-
-smb_iods
- is_tran_fd
- is_vcflags
- is_hflags
- is_hflags2
- is_smbuid
- is_next_mid
- is_txmax
- is_rwmax
- is_rxmax
- is_wxmax
- is_ssn_key
- is_next_seq
- is_u_maclen
- is_u_mackey
-
smbioc_ssn_work
- wk_iods
- wk_sopt
wk_out_state
-
-smbioc_rq SIZEOF_SMBIOC_RQ
- ioc_cmd
- ioc_errclass IOC_RQ_ERRCLASS
- ioc_serror IOC_RQ_SERROR
- ioc_error IOC_RQ_ERROR
- ioc_tbufsz
- ioc_rbufsz
- _ioc_tbuf
- _ioc_rbuf
-
-smbioc_t2rq SIZEOF_SMBIOC_T2RQ
- ioc_setup
- ioc_setupcnt
- ioc_name IOC_T2_NAME
- ioc_tparamcnt
- ioc_tdatacnt
- ioc_rparamcnt
- ioc_rdatacnt
- ioc_errclass IOC_T2_ERRCLASS
- ioc_serror IOC_T2_SERROR
- ioc_error IOC_T2_ERROR
- ioc_rpflags2
- _ioc_tparam
- _ioc_tdata
- _ioc_rparam
- _ioc_rdata
-
-smbioc_flags SIZEOF_SMBIOC_FLAGS
- ioc_level
- ioc_mask
- ioc_flags
+ wk_u_ssnkey_len
+ wk_u_ssnkey_buf
+ wk_u_auth_rlen
+ wk_u_auth_wlen
+ wk_u_auth_rbuf
+ wk_u_auth_wbuf
+ wk_cl_guid
smbioc_rw SIZEOF_SMBIOC_RW
- ioc_fh
ioc_cnt
+ ioc_flags
_ioc_offset
_ioc_base
+smbioc_xnp SIZEOF_SMBIOC_XNP
+ ioc_tdlen
+ ioc_rdlen
+ ioc_more
+ ioc_pad1
+ _ioc_tdata
+ _ioc_rdata
+
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 d1e7efd60a..398be59709 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
@@ -34,6 +34,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -61,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>
@@ -80,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)
{
@@ -105,7 +111,7 @@ void
smb_sm_done(void)
{
/*
- * XXX Q4BP why are we not iterating on smb_vclist here?
+ * Why are we not iterating on smb_vclist here?
* Because the caller has just called smb_sm_idle() to
* make sure we have no VCs before calling this.
*/
@@ -181,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);
@@ -365,10 +381,12 @@ smb_vc_free(struct smb_connobj *cp)
if (vcp->vc_mackey != NULL)
kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
+ 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));
@@ -392,14 +410,15 @@ 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;
- vcp->vc_state = SMBIOD_ST_IDLE;
+ /* A brand new VC should connect. */
+ vcp->vc_state = SMBIOD_ST_RECONNECT;
/*
* These identify the connection.
@@ -612,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);
}
@@ -655,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));
@@ -770,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;
@@ -813,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;
@@ -829,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 42dfd687f9..d0a8a1dca0 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
@@ -33,9 +33,11 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* 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.
*/
#ifndef _SMB_CONN_H
@@ -46,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
@@ -61,14 +64,14 @@ typedef struct smb_cred {
/*
* Bits in vc_flags (a.k.a. vc_co.co_flags)
- * Many of these were duplicates of SMBVOPT_ flags
- * and we now keep those too instead of merging
- * them into vc_flags.
+ * Note: SMBO_GONE is also in vc_flags
*/
-
-#define SMBV_WIN95 0x0010 /* used to apply bugfixes for this OS */
-#define SMBV_NT4 0x0020 /* used when NT4 issues invalid resp */
#define SMBV_UNICODE 0x0040 /* conn configured to use Unicode */
+#define SMBV_EXT_SEC 0x0080 /* conn to use extended security */
+#define SMBV_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
@@ -89,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);
@@ -141,9 +154,57 @@ 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
+ */
+struct smb_sopt {
+ int16_t sv_proto; /* protocol dialect */
+ uchar_t sv_sm; /* security mode */
+ int16_t sv_tz; /* offset in min relative to UTC */
+ uint16_t sv_maxmux; /* max number of outstanding rq's */
+ uint16_t sv_maxvcs; /* max number of VCs */
+ uint16_t sv_rawmode;
+ uint32_t sv_maxtx; /* maximum transmit buf size */
+ 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;
+
+/*
+ * SMB1 I/O Deamon state
+ */
+struct smb_iods {
+ uint8_t is_hflags; /* SMB header flags */
+ uint16_t is_hflags2; /* SMB header flags2 */
+ uint16_t is_smbuid; /* SMB header UID */
+ uint16_t is_next_mid; /* SMB header MID */
+ uint32_t is_txmax; /* max tx/rx packet size */
+ uint32_t is_rwmax; /* max read/write data size */
+ uint32_t is_rxmax; /* max readx data size */
+ uint32_t is_wxmax; /* max writex data size */
+ /* Signing state */
+ uint32_t is_next_seq; /* my next sequence number */
+
+};
+typedef struct smb_iods smb_iods_t;
/*
* Virtual Circuit to a server (really connection + session).
@@ -160,20 +221,35 @@ typedef struct smb_vc {
uid_t vc_owner; /* Unix owner */
int vc_genid; /* "generation" ID */
- int vc_mackeylen; /* length of MAC key */
- uint8_t *vc_mackey; /* MAC key */
+ int vc_mackeylen; /* MAC key length */
+ 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 */
- kcondvar_t iod_idle; /* IOD thread idle CV */
+ /* 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 _kthread *iod_thr; /* the IOD (reader) thread */
+ 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;
/* This is copied in/out when IOD enters/returns */
smbioc_ssn_work_t vc_work;
@@ -187,33 +263,40 @@ 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_sopt vc_work.wk_sopt
-#define vc_maxmux vc_work.wk_sopt.sv_maxmux
-#define vc_tran_fd vc_work.wk_iods.is_tran_fd
-#define vc_hflags vc_work.wk_iods.is_hflags
-#define vc_hflags2 vc_work.wk_iods.is_hflags2
-#define vc_smbuid vc_work.wk_iods.is_smbuid
-#define vc_next_mid vc_work.wk_iods.is_next_mid
-#define vc_txmax vc_work.wk_iods.is_txmax
-#define vc_rwmax vc_work.wk_iods.is_rwmax
-#define vc_rxmax vc_work.wk_iods.is_rxmax
-#define vc_wxmax vc_work.wk_iods.is_wxmax
-#define vc_ssn_key vc_work.wk_iods.is_ssn_key
-#define vc_next_seq vc_work.wk_iods.is_next_seq
-#define vc_u_mackey vc_work.wk_iods.is_u_mackey
-#define vc_u_maclen vc_work.wk_iods.is_u_maclen
+#define vc_cl_guid vc_work.wk_cl_guid
+
+/* defines for members in vc_sopt ? */
+#define vc_maxmux vc_sopt.sv_maxmux
+
+/* defines for members in vc_iods */
+#define vc_hflags vc_iods.is_hflags
+#define vc_hflags2 vc_iods.is_hflags2
+#define vc_smbuid vc_iods.is_smbuid
+#define vc_next_mid vc_iods.is_next_mid
+#define vc_txmax vc_iods.is_txmax
+#define vc_rwmax vc_iods.is_rwmax
+#define vc_rxmax vc_iods.is_rxmax
+#define vc_wxmax vc_iods.is_wxmax
+#define vc_next_seq vc_iods.is_next_seq
#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
@@ -231,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;
@@ -245,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 *);
@@ -278,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;
@@ -300,6 +406,8 @@ int smb_dev2share(int fd, struct smb_share **sspp);
/*
* smb_usr.c
*/
+int smb_usr_ioctl(smb_dev_t *, int, intptr_t, int, cred_t *);
+
int smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags);
int smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags);
int smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags);
@@ -319,7 +427,10 @@ int smb_usr_get_tree(smb_dev_t *, int, intptr_t, int, cred_t *);
int smb_usr_drop_tree(smb_dev_t *sdp, int cmd);
int smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr);
-int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags);
+int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags,
+ cred_t *cr);
+
+int smb_pkey_ioctl(int, intptr_t, int, cred_t *);
/*
@@ -327,18 +438,23 @@ int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags);
*/
int smb_iod_create(smb_vc_t *vcp);
int smb_iod_destroy(smb_vc_t *vcp);
-int smb_iod_connect(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);
void smb_iod_sendall(smb_vc_t *);
-int smb_iod_recvall(smb_vc_t *);
+int smb_iod_recvall(smb_vc_t *, boolean_t);
-int smb_iod_vc_work(smb_vc_t *, cred_t *);
+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 *);
int smb_iod_vc_idle(smb_vc_t *);
int smb_iod_vc_rcfail(smb_vc_t *);
int smb_iod_reconnect(smb_vc_t *);
@@ -381,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 489a1756ec..3f00ec24ed 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
@@ -31,9 +31,10 @@
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -61,35 +62,42 @@
#include <sys/modctl.h>
#include <sys/devops.h>
#include <sys/thread.h>
-#include <sys/types.h>
+#include <sys/socket.h>
#include <sys/zone.h>
#include <netsmb/smb_osdep.h>
#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>
#include <netsmb/smb_pass.h>
+#ifndef _KERNEL
+#include <libfknsmb.h>
+
+#define _init(v) nsmb_drv_init(v)
+#define _fini(v) nsmb_drv_fini(v)
+
+#endif /* _KERNEL */
+
#define NSMB_MIN_MINOR 1
#define NSMB_MAX_MINOR L_MAXMIN32
/* for version checks */
const uint32_t nsmb_version = NSMB_VERSION;
+/* for smb_nbst_create() */
+dev_t nsmb_dev_tcp = NODEV;
+dev_t nsmb_dev_tcp6 = NODEV;
+
static void *statep;
static major_t nsmb_major;
static minor_t last_minor = NSMB_MIN_MINOR;
-static dev_info_t *nsmb_dip;
static kmutex_t dev_lck;
-/* Zone support */
-zone_key_t nsmb_zone_key;
-extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
-extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
-
/*
* cb_ops device operations.
*/
@@ -99,6 +107,15 @@ static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
cred_t *credp, int *rvalp);
static int nsmb_close2(smb_dev_t *sdp, cred_t *cr);
+#ifdef _KERNEL
+
+static dev_info_t *nsmb_dip;
+
+/* Zone support */
+zone_key_t nsmb_zone_key;
+extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
+extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
+
/* smbfs cb_ops */
static struct cb_ops nsmb_cbops = {
nsmb_open, /* open */
@@ -160,10 +177,14 @@ static struct modlinkage nsmb_modlinkage = {
NULL
};
+#endif /* _KERNEL */
+
int
_init(void)
{
+#ifdef _KERNEL
int error;
+#endif /* _KERNEL */
(void) ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1);
@@ -176,12 +197,7 @@ _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);
@@ -200,6 +216,14 @@ _init(void)
return (error);
}
+#else /* _KERNEL */
+ streams_msg_init();
+ /* No attach, so need to set major. */
+ nsmb_major = 1;
+ /* And these, for smb_nbst_create() */
+ nsmb_dev_tcp = AF_INET;
+ nsmb_dev_tcp6 = AF_INET6;
+#endif /* _KERNEL */
return (0);
}
@@ -218,6 +242,7 @@ _fini(void)
if ((status = smb_pkey_idle()) != 0)
return (status);
+#ifdef _KERNEL
/*
* Remove the module. Do this before destroying things,
* to prevent new entrances while we're destorying.
@@ -227,9 +252,7 @@ _fini(void)
}
(void) zone_key_delete(nsmb_zone_key);
-
- /* Time conversion stuff. */
- smb_time_fini();
+#endif /* _KERNEL */
/* Destroy password Key chain DB. */
smb_pkey_fini();
@@ -242,6 +265,8 @@ _fini(void)
return (status);
}
+#ifdef _KERNEL
+
int
_info(struct modinfo *modinfop)
{
@@ -270,6 +295,7 @@ nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
static int
nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
+ major_t tmaj;
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
@@ -294,6 +320,20 @@ nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
*/
nsmb_major = ddi_name_to_major(NSMB_NAME);
+ /*
+ * We also need major numbers for t_kopen
+ */
+ tmaj = ddi_name_to_major("tcp");
+ if (tmaj == DDI_MAJOR_T_NONE)
+ cmn_err(CE_NOTE, "no tcp major?");
+ else
+ nsmb_dev_tcp = makedevice(tmaj, 0);
+ tmaj = ddi_name_to_major("tcp6");
+ if (tmaj == DDI_MAJOR_T_NONE)
+ cmn_err(CE_NOTE, "no tcp6 major?");
+ else
+ nsmb_dev_tcp6 = makedevice(tmaj, 0);
+
nsmb_dip = dip;
ddi_report_dev(dip);
return (DDI_SUCCESS);
@@ -315,6 +355,65 @@ nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
return (DDI_SUCCESS);
}
+#else /* _KERNEL */
+
+/*
+ * Wrappers for libfknsmb: ioctl, open, close, load
+ */
+
+/*ARGSUSED*/
+int
+nsmb_drv_ioctl(dev32_t dev32, int cmd, intptr_t arg, int flags)
+{
+ dev_t dev = expldev(dev32);
+ cred_t *cr = CRED();
+ int err;
+
+ err = nsmb_ioctl(dev, cmd, arg, flags, cr, NULL);
+ return (err);
+}
+
+/*ARGSUSED*/
+int
+nsmb_drv_open(dev32_t *dev32p, int flags, int otyp)
+{
+ dev_t dev = expldev(*dev32p);
+ int err;
+
+ err = nsmb_open(&dev, flags, otyp, CRED());
+ if (err == 0) {
+ /*
+ * We have NSMB_MAX_MINOR == L_MAXMIN32
+ * therefore cmpldev never fails.
+ */
+ VERIFY(cmpldev(dev32p, dev) != 0);
+ }
+ return (err);
+}
+
+/*ARGSUSED*/
+int
+nsmb_drv_close(dev32_t dev32, int flags, int otyp)
+{
+ dev_t dev = expldev(dev32);
+ int err;
+
+ err = nsmb_close(dev, flags, otyp, CRED());
+ return (err);
+}
+
+/*
+ * This function intentionally does nothing. It's used only to
+ * force libfknsmb to load at program start so one can set
+ * breakpoints etc. without debugger "force load" tricks.
+ */
+void
+nsmb_drv_load(void)
+{
+}
+
+#endif /* _KERNEL */
+
/*ARGSUSED*/
static int
nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */
@@ -325,7 +424,7 @@ nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */
sdp = ddi_get_soft_state(statep, getminor(dev));
if (sdp == NULL) {
- return (DDI_FAILURE);
+ return (EBADF);
}
if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
return (EBADF);
@@ -346,107 +445,7 @@ nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */
* check the zone status here on every ioctl call.
*/
- /*
- * Serialize ioctl calls. The smb_usr_... functions
- * don't expect concurrent calls on a given sdp.
- */
- mutex_enter(&sdp->sd_lock);
- if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
- mutex_exit(&sdp->sd_lock);
- return (EBUSY);
- }
- sdp->sd_flags |= NSMBFL_IOCTL;
- mutex_exit(&sdp->sd_lock);
-
- err = 0;
- switch (cmd) {
- case SMBIOC_GETVERS:
- (void) ddi_copyout(&nsmb_version, (void *)arg,
- sizeof (nsmb_version), flags);
- break;
-
- case SMBIOC_FLAGS2:
- err = smb_usr_get_flags2(sdp, arg, flags);
- break;
-
- case SMBIOC_GETSSNKEY:
- err = smb_usr_get_ssnkey(sdp, arg, flags);
- break;
-
- case SMBIOC_DUP_DEV:
- err = smb_usr_dup_dev(sdp, arg, flags);
- break;
-
- case SMBIOC_REQUEST:
- err = smb_usr_simplerq(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_T2RQ:
- err = smb_usr_t2request(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_READ:
- case SMBIOC_WRITE:
- err = smb_usr_rw(sdp, cmd, arg, flags, cr);
- break;
-
- case SMBIOC_NTCREATE:
- err = smb_usr_ntcreate(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_PRINTJOB:
- err = smb_usr_printjob(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_CLOSEFH:
- err = smb_usr_closefh(sdp, cr);
- break;
-
- case SMBIOC_SSN_CREATE:
- case SMBIOC_SSN_FIND:
- err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
- break;
-
- case SMBIOC_SSN_KILL:
- case SMBIOC_SSN_RELE:
- err = smb_usr_drop_ssn(sdp, cmd);
- break;
-
- case SMBIOC_TREE_CONNECT:
- case SMBIOC_TREE_FIND:
- err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
- break;
-
- case SMBIOC_TREE_KILL:
- case SMBIOC_TREE_RELE:
- err = smb_usr_drop_tree(sdp, cmd);
- break;
-
- case SMBIOC_IOD_WORK:
- err = smb_usr_iod_work(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_IOD_IDLE:
- case SMBIOC_IOD_RCFAIL:
- err = smb_usr_iod_ioctl(sdp, cmd, arg, flags);
- break;
-
- case SMBIOC_PK_ADD:
- case SMBIOC_PK_DEL:
- case SMBIOC_PK_CHK:
- case SMBIOC_PK_DEL_OWNER:
- case SMBIOC_PK_DEL_EVERYONE:
- err = smb_pkey_ioctl(cmd, arg, flags, cr);
- break;
-
- default:
- err = ENOTTY;
- break;
- }
-
- mutex_enter(&sdp->sd_lock);
- sdp->sd_flags &= ~NSMBFL_IOCTL;
- mutex_exit(&sdp->sd_lock);
+ err = smb_usr_ioctl(sdp, cmd, arg, flags, cr);
return (err);
}
@@ -491,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);
@@ -529,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)
@@ -566,8 +567,10 @@ nsmb_close2(smb_dev_t *sdp, cred_t *cr)
int
smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
{
+#ifdef _KERNEL
file_t *fp = NULL;
vnode_t *vp;
+#endif /* _KERNEL */
smb_dev_t *from_sdp;
dev_t dev;
int32_t ufd;
@@ -582,16 +585,24 @@ smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
*/
if (ddi_copyin((void *) arg, &ufd, sizeof (ufd), flags))
return (EFAULT);
+#ifdef _KERNEL
if ((fp = getf(ufd)) == NULL)
return (EBADF);
/* rele fp below */
vp = fp->f_vnode;
dev = vp->v_rdev;
+#else /* _KERNEL */
+ /*
+ * No getf(ufd) -- ufd is really a dev32_t
+ */
+ dev = expldev((dev32_t)ufd);
+#endif /* _KERNEL */
if (dev == 0 || dev == NODEV ||
getmajor(dev) != nsmb_major) {
err = EINVAL;
goto out;
}
+
from_sdp = ddi_get_soft_state(statep, getminor(dev));
if (from_sdp == NULL) {
err = EINVAL;
@@ -609,8 +620,10 @@ smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
err = 0;
out:
+#ifdef _KERNEL
if (fp)
releasef(ufd);
+#endif /* _KERNEL */
return (err);
}
@@ -621,19 +634,27 @@ out:
int
smb_dev2share(int fd, struct smb_share **sspp)
{
+#ifdef _KERNEL
file_t *fp = NULL;
vnode_t *vp;
+#endif /* _KERNEL */
smb_dev_t *sdp;
smb_share_t *ssp;
dev_t dev;
int err;
+#ifdef _KERNEL
if ((fp = getf(fd)) == NULL)
return (EBADF);
/* rele fp below */
-
vp = fp->f_vnode;
dev = vp->v_rdev;
+#else /* _KERNEL */
+ /*
+ * No getf(ufd) -- fd is really a dev32_t
+ */
+ dev = expldev((dev32_t)fd);
+#endif /* _KERNEL */
if (dev == 0 || dev == NODEV ||
getmajor(dev) != nsmb_major) {
err = EINVAL;
@@ -660,7 +681,9 @@ smb_dev2share(int fd, struct smb_share **sspp)
err = 0;
out:
+#ifdef _KERNEL
if (fp)
releasef(fd);
+#endif /* _KERNEL */
return (err);
}
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 db82fa0958..48c8ef591d 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
@@ -35,6 +35,9 @@
/*
* 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.
*/
#ifdef DEBUG
@@ -67,13 +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>
-int smb_iod_send_echo(smb_vc_t *);
+/*
+ * 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 */
+
+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
@@ -93,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);
}
@@ -142,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)
@@ -170,139 +192,209 @@ 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);
/*
- * Note: Anything special for SMBR_INTERNAL here?
+ * Internal requests are allowed in any state;
+ * otherwise should be active.
*/
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ 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 (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- /*
- * We're signing requests and verifying
- * signatures on responses. Set the
- * sequence numbers of the request and
- * response here, used in smb_rq_verify.
- */
- 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;
+ }
-#ifdef DTRACE_PROBE
- DTRACE_PROBE2(smb_iod_sendrq,
- (smb_rq_t *), rqp, (mblk_t *), m);
-#else
- SMBIODEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0);
-#endif
- 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);
-
-#ifdef APPLE
- /* If proc waiting on rqp was signaled... */
- if (smb_rq_intr(rqp))
- smb_iod_rqprocessed(rqp, EINTR, 0);
-#endif
-
- 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:
@@ -312,58 +404,50 @@ 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
- * while in state SMBIOD_ST_VCACTIVE. The loop now
- * simply blocks in the socket recv until either a
- * message arrives, or a disconnect.
+ * This is the "reader" loop, run by the IOD thread. Normally we're in
+ * state SMBIOD_ST_VCACTIVE here, but during reconnect we're called in
+ * other states with poll==TRUE
*
- * Any non-zero error means the IOD should terminate.
+ * A non-zero error return here causes the IOD work loop to terminate.
*/
int
-smb_iod_recvall(struct smb_vc *vcp)
+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->vc_state != SMBIOD_ST_VCACTIVE) {
- SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
- error = 0;
- break;
- }
-
if (vcp->iod_flags & SMBIOD_SHUTDOWN) {
SMBIODEBUG("SHUTDOWN set\n");
/* This IOD thread will terminate. */
@@ -376,52 +460,88 @@ smb_iod_recvall(struct smb_vc *vcp)
}
m = NULL;
- error = smb_iod_recv1(vcp, &m);
+ error = smb_iod_recvmsg(vcp, &m);
+
+ /*
+ * Internal requests (reconnecting) call this in a loop
+ * (with poll==TRUE) until the request completes.
+ */
+ if (error == ETIME && poll)
+ break;
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) {
/*
- * If the IOD thread holds the last reference
- * to this VC, let the IOD thread terminate.
+ * 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_DEAD);
+ 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;
}
@@ -431,91 +551,327 @@ smb_iod_recvall(struct smb_vc *vcp)
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 we have requests enqueued, next
- * state is reconnecting, else idle.
+ * 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.
*/
- int state;
SMB_VC_LOCK(vcp);
- state = (vcp->iod_rqlist.tqh_first != NULL) ?
- SMBIOD_ST_RECONNECT : SMBIOD_ST_IDLE;
- smb_iod_newstate(vcp, state);
+ if (vcp->iod_rqlist.tqh_first != NULL)
+ smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT);
+ else
+ smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
cv_broadcast(&vcp->vc_statechg);
SMB_VC_UNLOCK(vcp);
- error = 0;
+ 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;
+
+ m = m_pullup(m, SMB_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);
- DTRACE_PROBE2(smb_iod_recvrq,
- (smb_rq_t *), rqp, (mblk_t *), m);
- m_dumpm(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);
+ }
- SMBRQ_LOCK(rqp);
- if (rqp->sr_rp.md_top == NULL) {
- md_initm(&rqp->sr_rp, m);
+ /*
+ * Find the reqeuest and post the reply
+ */
+ rw_enter(&vcp->iod_rqlock, RW_READER);
+ TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+
+ 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 {
- 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;
- }
+ SMBRQ_UNLOCK(rqp);
+ rqp = NULL;
+ break;
}
- smb_iod_rqprocessed_LH(rqp, 0, 0);
- SMBRQ_UNLOCK(rqp);
- break;
}
+ 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);
+ /*
+ * Keep going. It's possible this reply came
+ * after the request timed out and went away.
+ */
+ }
+ 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;
- if (rqp == NULL) {
- int cmd = SMB_HDRCMD(hp);
+top:
+ m = m_pullup(m, SMB2_HDRLEN);
+ if (m == NULL)
+ return (ENOMEM);
- if (cmd != SMB_COM_ECHO)
- SMBSDEBUG("drop resp: mid %d, cmd %d\n",
- (uint_t)mid, cmd);
-/* smb_printrqlist(vcp); */
+ /*
+ * 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;
}
- rw_exit(&vcp->iod_rqlock);
+ 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);
}
/*
@@ -529,126 +885,256 @@ smb_iod_recvall(struct smb_vc *vcp)
* 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;
- smb_credinit(&scred, NULL);
- err = smb_smb_echo(vcp, &scred, SMBNOREPLYWAIT);
+ ASSERT(vcp->iod_thr == curthread);
+
+ 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:
/*
- * State should be correct after the check in
- * smb_rq_enqueue(), but we dropped locks...
+ * Internal requests can be added in any state,
+ * but normal requests only in state active.
*/
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ 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);
}
/*
- * 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.
- * Only thing using this now is ECHO.
+ * 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.
*/
- rqp->sr_owner = curthread;
- if (rqp->sr_owner == vcp->iod_thr) {
- rqp->sr_flags |= SMBR_INTERNAL;
-
- /*
- * This is a request from the IOD thread.
- * Always send directly from this thread.
- * Note lock order: iod_rqlist, vc_sendlock
- */
+ 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);
+ 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);
@@ -661,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.
@@ -695,30 +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) {
- ASSERT((rqp->sr_flags & SMBR_MULTIPACKET) == 0);
- smb_iod_removerq(rqp);
- return (EAGAIN);
+ /* XXX - Do we ever take this path now? */
+ return (smb_iod_waitrq_int(rqp));
}
/*
@@ -730,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, rqp=%p\n", 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
@@ -791,17 +1269,8 @@ smb_iod_waitrq(struct smb_rq *rqp)
goto out;
}
if (tr < 0) {
-#ifdef DTRACE_PROBE
DTRACE_PROBE1(smb_iod_waitrq1,
(smb_rq_t *), rqp);
-#endif
-#ifdef NOT_YET
- /* Want this to go ONLY to the user. */
- uprintf("SMB server %s has not responded"
- " to request %d after %d seconds..."
- " (still waiting).\n", vcp->vc_srvname,
- rqp->sr_mid, smb_timo_notice);
-#endif
}
}
@@ -820,17 +1289,8 @@ smb_iod_waitrq(struct smb_rq *rqp)
goto out;
}
if (tr < 0) {
-#ifdef DTRACE_PROBE
DTRACE_PROBE1(smb_iod_waitrq2,
(smb_rq_t *), rqp);
-#endif
-#ifdef NOT_YET
- /* Want this to go ONLY to the user. */
- uprintf("SMB server %s has not responded"
- " to request %d after %d seconds..."
- " (giving up).\n", vcp->vc_srvname,
- rqp->sr_mid, rqp->sr_timo);
-#endif
error = ETIME;
goto out;
}
@@ -849,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);
}
@@ -885,79 +1366,298 @@ smb_iod_shutdown_share(struct smb_share *ssp)
}
/*
- * Send all requests that need sending.
- * Called from _addrq, _multirq, _waitrq
+ * Ioctl functions called by the user-level I/O Deamon (IOD)
+ * to bring up and service a connection to some SMB server.
*/
-void
-smb_iod_sendall(smb_vc_t *vcp)
+
+/*
+ * Handle ioctl SMBIOC_IOD_CONNECT
+ */
+int
+nsmb_iod_connect(struct smb_vc *vcp, cred_t *cr)
{
- struct smb_rq *rqp;
- int error, muxcnt;
+ int err, val;
+
+ ASSERT(vcp->iod_thr == curthread);
+
+ if (vcp->vc_state != SMBIOD_ST_RECONNECT) {
+ cmn_err(CE_NOTE, "iod_connect: bad state %d", vcp->vc_state);
+ return (EINVAL);
+ }
/*
- * Clear "newrq" to make sure threads adding
- * new requests will run this function again.
+ * 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.
*/
- rw_enter(&vcp->iod_rqlock, RW_WRITER);
- vcp->iod_newrq = 0;
+ 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);
/*
- * We only read iod_rqlist, so downgrade rwlock.
- * This allows the IOD to handle responses while
- * some requesting thread may be blocked in send.
+ * Set various options on this endpoint.
+ * Keep going in spite of errors.
*/
- rw_downgrade(&vcp->iod_rqlock);
+ val = smb_tcpsndbuf;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_SNDBUF, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt SNDBUF, err=%d", err);
+ }
+ val = smb_tcprcvbuf;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_RCVBUF, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt RCVBUF, err=%d", err);
+ }
+ val = 1;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_KEEPALIVE, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt KEEPALIVE, err=%d", err);
+ }
+ val = 1;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_TCP_NODELAY, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt TCP_NODELAY, err=%d", err);
+ }
+ val = smb_connect_timeout * 1000;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_TCP_CON_TMO, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt TCP con tmo, err=%d", err);
+ }
/*
- * Serialize to prevent multiple senders.
- * Note lock order: iod_rqlock, vc_sendlock
+ * Bind and connect
*/
- sema_p(&vcp->vc_sendlock);
+ err = SMB_TRAN_BIND(vcp, NULL);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: t_kbind: err=%d", err);
+ /* Continue on and try connect. */
+ }
+ err = SMB_TRAN_CONNECT(vcp, &vcp->vc_srvaddr.sa);
+ /*
+ * No cmn_err here, as connect failures are normal, i.e.
+ * when a server has multiple addresses and only some are
+ * routed for us. (libsmbfs tries them all)
+ */
+ if (err == 0) {
+ SMB_VC_LOCK(vcp);
+ smb_iod_newstate(vcp, SMBIOD_ST_CONNECTED);
+ SMB_VC_UNLOCK(vcp);
+ } /* else stay in state reconnect */
+
+ return (err);
+}
+
+/*
+ * 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)
+{
+ struct smb_sopt *sv = &vcp->vc_sopt;
+ smb_cred_t scred;
+ int err = 0;
+
+ 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);
+ err = EINVAL;
+ goto out;
+ }
+
+ if (vcp->vc_maxver == 0 || vcp->vc_minver > vcp->vc_maxver) {
+ err = EINVAL;
+ goto out;
+ }
/*
- * 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!
+ * (Re)init negotiated values
*/
- ASSERT(vcp->vc_maxmux > 0);
- error = muxcnt = 0;
- TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+ 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;
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- error = ENOTCONN; /* stop everything! */
- break;
- }
+ /*
+ * If this was reconnect, get rid of the old MAC key
+ * and session key.
+ */
+ SMB_VC_LOCK(vcp);
+ if (vcp->vc_mackey != NULL) {
+ kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
+ vcp->vc_mackey = NULL;
+ vcp->vc_mackeylen = 0;
+ }
+ if (vcp->vc_ssnkey != NULL) {
+ kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen);
+ vcp->vc_ssnkey = NULL;
+ vcp->vc_ssnkeylen = 0;
+ }
+ SMB_VC_UNLOCK(vcp);
- if (rqp->sr_state == SMBRQ_NOTSENT) {
- error = smb_iod_sendrq(rqp);
- if (error)
- break;
+ /*
+ * 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 (++muxcnt == vcp->vc_maxmux) {
- SMBIODEBUG("muxcnt == vc_maxmux\n");
- break;
+ /*
+ * 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);
+ SMB_VC_UNLOCK(vcp);
+ }
/*
- * If we have vc_maxmux requests outstanding,
- * arrange for _waitrq to call _sendall as
- * requests are completed.
+ * (else) leave state as it was.
+ * User-level will either close this handle (if connecting
+ * for the first time) or call rcfail and then try again.
*/
- vcp->iod_muxfull =
- (muxcnt < vcp->vc_maxmux) ? 0 : 1;
- sema_v(&vcp->vc_sendlock);
- rw_exit(&vcp->iod_rqlock);
+ smb_credrele(&scred);
+
+ return (err);
}
+/*
+ * Handle ioctl SMBIOC_IOD_SSNSETUP
+ * Do either SMB1 or SMB2 session setup (one call/reply)
+ */
int
-smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
+nsmb_iod_ssnsetup(struct smb_vc *vcp, cred_t *cr)
{
- struct file *fp = NULL;
+ smb_cred_t scred;
+ int err;
+
+ ASSERT(vcp->iod_thr == curthread);
+
+ switch (vcp->vc_state) {
+ case SMBIOD_ST_NEGOTIATED:
+ case SMBIOD_ST_AUTHCONT:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ smb_credinit(&scred, cr);
+ 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);
+ switch (err) {
+ case 0:
+ smb_iod_newstate(vcp, SMBIOD_ST_AUTHOK);
+ break;
+ case EINPROGRESS: /* MORE_PROCESSING_REQUIRED */
+ smb_iod_newstate(vcp, SMBIOD_ST_AUTHCONT);
+ break;
+ default:
+ smb_iod_newstate(vcp, SMBIOD_ST_AUTHFAIL);
+ break;
+ }
+ SMB_VC_UNLOCK(vcp);
+
+ 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)
+{
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
int err = 0;
/*
@@ -967,19 +1667,57 @@ smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
ASSERT(vcp->iod_thr == curthread);
/*
- * Get the network transport file pointer,
- * and "loan" it to our transport module.
+ * Should be in state...
*/
- if ((fp = getf(vcp->vc_tran_fd)) == NULL) {
- err = EBADF;
- goto out;
+ if (vcp->vc_state != SMBIOD_ST_AUTHOK) {
+ cmn_err(CE_NOTE, "iod_vc_work: bad state %d", vcp->vc_state);
+ return (EINVAL);
}
- if ((err = SMB_TRAN_LOAN_FP(vcp, fp, cr)) != 0)
- goto out;
/*
- * In case of reconnect, tell any enqueued requests
- * then can GO!
+ * Update the session key and initialize SMB signing.
+ *
+ * This implementation does not use multiple SMB sessions per
+ * TCP connection (where only the first session key is used)
+ * so we always have a new session key here. Sanity check the
+ * length from user space. Normally 16 or 32.
+ */
+ if (wk->wk_u_ssnkey_len > 1024) {
+ cmn_err(CE_NOTE, "iod_vc_work: ssn key too long");
+ return (EINVAL);
+ }
+
+ ASSERT(vcp->vc_ssnkey == NULL);
+ SMB_VC_LOCK(vcp);
+ if (wk->wk_u_ssnkey_len != 0 &&
+ wk->wk_u_ssnkey_buf.lp_ptr != NULL) {
+ vcp->vc_ssnkeylen = wk->wk_u_ssnkey_len;
+ vcp->vc_ssnkey = kmem_alloc(vcp->vc_ssnkeylen, KM_SLEEP);
+ if (ddi_copyin(wk->wk_u_ssnkey_buf.lp_ptr,
+ vcp->vc_ssnkey, vcp->vc_ssnkeylen, flags) != 0) {
+ err = EFAULT;
+ }
+ }
+ SMB_VC_UNLOCK(vcp);
+ if (err)
+ return (err);
+
+ /*
+ * If we have a session key, derive the MAC key for SMB signing.
+ * If this was a NULL session, we might have no session key.
+ */
+ ASSERT(vcp->vc_mackey == NULL);
+ if (vcp->vc_ssnkey != NULL) {
+ if (vcp->vc_flags & SMBV_SMB2)
+ err = smb2_sign_init(vcp);
+ else
+ err = smb_sign_init(vcp);
+ if (err != 0)
+ return (err);
+ }
+
+ /*
+ * Tell any enqueued requests they can start.
*/
SMB_VC_LOCK(vcp);
vcp->vc_genid++; /* possibly new connection */
@@ -998,9 +1736,11 @@ smb_iod_vc_work(struct smb_vc *vcp, 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);
+ (void) smb_iod_recvall(vcp, B_FALSE);
/*
* The reader loop returned, so we must have a
@@ -1021,26 +1761,24 @@ smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
*/
smb_iod_invrq(vcp);
-out:
- /* Recall the file descriptor loan. */
- (void) SMB_TRAN_LOAN_FP(vcp, NULL, cr);
- if (fp != NULL) {
- releasef(vcp->vc_tran_fd);
- }
-
return (err);
}
/*
- * 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
@@ -1048,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.
*/
@@ -1086,10 +1844,6 @@ smb_iod_vc_rcfail(struct smb_vc *vcp)
* IOD thread for this VC.
*/
ASSERT(vcp->iod_thr == curthread);
-
- if (vcp->vc_state != SMBIOD_ST_RECONNECT)
- return (EINVAL);
-
SMB_VC_LOCK(vcp);
smb_iod_newstate(vcp, SMBIOD_ST_RCFAILED);
@@ -1105,8 +1859,18 @@ smb_iod_vc_rcfail(struct smb_vc *vcp)
if (tr == 0)
err = EINTR;
- smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
- cv_broadcast(&vcp->vc_statechg);
+ /*
+ * 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_RECONNECT) {
+ smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
+ cv_broadcast(&vcp->vc_statechg);
+ }
SMB_VC_UNLOCK(vcp);
@@ -1127,11 +1891,17 @@ 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 */
case SMBIOD_ST_RECONNECT:
+ case SMBIOD_ST_CONNECTED:
+ 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;
@@ -1143,6 +1913,7 @@ again:
err = 0; /* success! */
break;
+ case SMBIOD_ST_AUTHFAIL:
case SMBIOD_ST_RCFAILED:
case SMBIOD_ST_DEAD:
default:
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h
index 712acb6f3b..aef9e70e27 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h
@@ -1,16 +1,35 @@
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * 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@
+ */
/*
* Code corresponding to smb_apple.h
- * XXX: Could merge this into smb_subr.h
- * as long as that doesn't break smbfs
*/
#ifndef _NETSMB_SMB_OSDEP_H_
#define _NETSMB_SMB_OSDEP_H_
#ifndef PRIVSYM
-#define PRIVSYM
+#define PRIVSYM
#endif
#ifndef min
@@ -65,8 +84,14 @@ typedef uint32_t u_int32_t;
typedef uint16_t u_int16_t;
typedef uint8_t u_int8_t;
-typedef const char * c_caddr_t;
-typedef uint64_t user_addr_t;
+typedef const char *c_caddr_t;
+typedef uint64_t user_addr_t;
+typedef ssize_t user_ssize_t;
+typedef size_t user_size_t;
+
+#ifdef _FAKE_KERNEL
+#define ddi_get_cred() CRED()
+#endif
/*
* Time related calls.
@@ -75,7 +100,7 @@ typedef uint64_t user_addr_t;
/* BEGIN CSTYLED */
#define timespeccmp(tvp, uvp, cmp) \
(((tvp)->tv_sec == (uvp)->tv_sec) ? \
- ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \
+ ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \
((tvp)->tv_sec cmp (uvp)->tv_sec))
/* END CSTYLED */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
index f4ebf9a573..4a44e36e89 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
@@ -22,6 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMB_PASS_H
@@ -44,14 +46,13 @@ typedef struct smb_passid {
zoneid_t zoneid; /* Future Use */
char *srvdom; /* Windows Domain (or server) */
char *username; /* Windows User name */
- uchar_t lmhash[SMBIOC_HASH_SZ];
- uchar_t nthash[SMBIOC_HASH_SZ];
+ uchar_t lmhash[SMBIOC_HASH_SZ];
+ uchar_t nthash[SMBIOC_HASH_SZ];
} smb_passid_t;
/* Called from smb_dev.c */
void smb_pkey_init(void);
void smb_pkey_fini(void);
int smb_pkey_idle(void);
-int smb_pkey_ioctl(int, intptr_t, int, cred_t *);
#endif /* _SMB_PASS_H */
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 997b7318dd..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,8 @@
/*
* 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.
*/
#include <sys/param.h>
@@ -51,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)
@@ -69,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);
@@ -147,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);
@@ -163,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);
@@ -171,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);
}
@@ -190,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
@@ -217,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);
@@ -281,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.
@@ -325,7 +352,71 @@ 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,
+ * 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 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 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;
+ rqp->sr_flags |= SMBR_INTERNAL;
+ error = smb1_iod_addrq(rqp);
+ if (error != 0)
+ return (error);
+
+ /*
+ * 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);
+ }
+
+ 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);
}
@@ -398,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)
{
@@ -457,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);
@@ -488,14 +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_rpflags2 & SMB_FLAGS2_ERR_STATUS) {
+
+ if (rqp->sr_error != 0) {
+ if (rqp->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) {
+ 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);
+ error = smb_maperror(errClass, errCode);
+ }
+ }
+
+ if (error != 0) {
/*
* Do a special check for STATUS_BUFFER_OVERFLOW;
* it's not an error.
@@ -506,34 +595,65 @@ smb_rq_reply(struct smb_rq *rqp)
* they can look at rqp->sr_error if they
* need to know whether we got a
* STATUS_BUFFER_OVERFLOW.
- * XXX - should we do that for all errors
- * where (error & 0xC0000000) is 0x80000000,
- * i.e. all warnings?
*/
- rperror = 0;
- } else
- rperror = smb_maperr32(rqp->sr_error);
+ rqp->sr_flags |= SMBR_MOREDATA;
+ error = 0;
+ }
} else {
- rqp->sr_errclass = rqp->sr_error & 0xff;
- rqp->sr_serror = rqp->sr_error >> 16;
- rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror);
- }
- if (rperror == EMOREDATA) {
- rperror = E2BIG;
- rqp->sr_flags |= SMBR_MOREDATA;
- } else
rqp->sr_flags &= ~SMBR_MOREDATA;
+ }
+
+ 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_uint32le(mdp, NULL);
- error = md_get_uint32le(mdp, NULL);
- error = md_get_uint32le(mdp, NULL);
+ /*
+ * 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);
- error = md_get_uint16le(mdp, &rqp->sr_rptid);
- error = md_get_uint16le(mdp, &rqp->sr_rppid);
- error = md_get_uint16le(mdp, &rqp->sr_rpuid);
+ /* 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);
}
@@ -1134,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 */
@@ -1345,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 */
@@ -1438,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 0184022a65..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,8 @@
/*
* 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.
*/
#ifndef _NETSMB_SMB_RQ_H_
@@ -54,8 +56,12 @@
#define SMBR_NOINTR_RECV 0x0200 /* no interrupt in recv wait */
#define SMBR_SENDWAIT 0x0400 /* waiting for send to complete */
#define SMBR_NORECONNECT 0x0800 /* do not reconnect for this */
-/* SMBR_VCREF 0x4000 * took vc reference (obsolete) */
+/* 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 */
@@ -64,7 +70,7 @@
#define SMBT2_NORESTART 0x0010
#define SMBT2_MOREDATA 0x8000 /* our buffer was too small */
-#define SMBRQ_LOCK(rqp) mutex_enter(&(rqp)->sr_lock)
+#define SMBRQ_LOCK(rqp) mutex_enter(&(rqp)->sr_lock)
#define SMBRQ_UNLOCK(rqp) mutex_exit(&(rqp)->sr_lock)
enum smbrq_state {
@@ -83,7 +89,7 @@ struct smb_rq {
enum smbrq_state sr_state;
struct smb_vc *sr_vc;
struct smb_share *sr_share;
- struct _kthread *sr_owner;
+ struct _kthread *sr_owner;
uint32_t sr_seqno; /* Seq. no. of request */
uint32_t sr_rseqno; /* Seq. no. of reply */
struct mbchain sr_rq;
@@ -91,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;
@@ -105,7 +124,7 @@ struct smb_rq {
int sr_timo;
int sr_rexmit; /* how many more retries. dflt 0 */
int sr_sendcnt;
- struct timespec sr_timesent;
+ struct timespec sr_timesent;
int sr_lerror;
uint8_t sr_errclass;
uint16_t sr_serror;
@@ -116,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;
@@ -124,7 +152,7 @@ struct smb_t2rq {
kcondvar_t t2_cond;
uint16_t t2_setupcount;
uint16_t *t2_setupdata;
- uint16_t t2_setup[SMBIOC_T2RQ_MAXSETUP];
+ uint16_t t2_setup[4];
uint8_t t2_maxscount; /* max setup words to return */
uint16_t t2_maxpcount; /* max param bytes to return */
uint16_t t2_maxdcount; /* max data bytes to return */
@@ -184,15 +212,19 @@ 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);
@@ -201,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 cf06e75767..bec61e4392 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -37,8 +38,6 @@
#include <sys/md5.h>
#include <sys/des.h>
#include <sys/kmem.h>
-#include <sys/crypto/api.h>
-#include <sys/crypto/common.h>
#include <sys/cmn_err.h>
#include <sys/stream.h>
#include <sys/strsun.h>
@@ -50,6 +49,7 @@
#include <netsmb/smb_subr.h>
#include <netsmb/smb_dev.h>
#include <netsmb/smb_rq.h>
+#include <netsmb/smb_signing.h>
#ifdef DEBUG
/*
@@ -59,15 +59,37 @@
int nsmb_signing_fudge = 0;
#endif
-/* Mechanism definitions */
-static crypto_mechanism_t crypto_mech_md5 = { CRYPTO_MECH_INVALID };
-
-void
-smb_crypto_mech_init(void)
+/*
+ * This is called just after session setup completes,
+ * at the top of smb_iod_vc_work(). Initialize signing.
+ */
+int
+smb_sign_init(smb_vc_t *vcp)
{
- crypto_mech_md5.cm_type = crypto_mech2id(SUN_CKM_MD5);
-}
+ 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.
+ */
+ vcp->vc_mackeylen = vcp->vc_ssnkeylen;
+ vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP);
+ bcopy(vcp->vc_ssnkey, vcp->vc_mackey, vcp->vc_mackeylen);
+
+ /* The initial sequence number is two. */
+ vcp->vc_next_seq = 2;
+
+ return (0);
+}
#define SMBSIGLEN 8 /* SMB signature length */
@@ -83,12 +105,12 @@ static int
smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
uint32_t seqno, uchar_t *signature)
{
- crypto_context_t crypto_ctx;
- crypto_data_t key;
- crypto_data_t data;
- crypto_data_t digest;
- uchar_t mac[16];
- int status;
+ uchar_t digest[MD5_DIGEST_LENGTH];
+ smb_sign_ctx_t ctx = 0;
+ mblk_t *m = mp;
+ int size;
+ int rc;
+
/*
* This union is a little bit of trickery to:
* (1) get the sequence number int aligned, and
@@ -109,78 +131,64 @@ smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
} s;
} smbhdr;
- ASSERT(mp != NULL);
- ASSERT(MBLKL(mp) >= SMB_HDRLEN);
- ASSERT(vcp->vc_mackey != NULL);
+ if (vcp->vc_mackey == NULL)
+ return (-1);
+
+ if ((rc = smb_md5_init(&ctx, &vcp->vc_signmech)) != 0)
+ return (rc);
+
+ /* Digest the MAC Key */
+ rc = smb_md5_update(ctx, 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) >= SMB_HDRLEN);
/*
- * Make an aligned copy of the SMB header
- * and fill in the sequence number.
+ * Make an aligned copy of the SMB header,
+ * fill in the sequence number, and digest.
*/
- bcopy(mp->b_rptr, smbhdr.r.raw, SMB_HDRLEN);
+ size = SMB_HDRLEN;
+ bcopy(m->b_rptr, smbhdr.r.raw, size);
smbhdr.s.sig[0] = htolel(seqno);
smbhdr.s.sig[1] = 0;
+ rc = smb_md5_update(ctx, &smbhdr.r.raw, size);
+ if (rc != 0)
+ return (rc);
+
/*
- * Compute the MAC: MD5(concat(Key, message))
+ * Digest the rest of the SMB header packet, starting at
+ * the data just after the SMB header.
*/
- if (crypto_mech_md5.cm_type == CRYPTO_MECH_INVALID) {
- SMBSDEBUG("crypto_mech_md5 invalid\n");
- return (CRYPTO_MECHANISM_INVALID);
- }
- status = crypto_digest_init(&crypto_mech_md5, &crypto_ctx, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
-
- /* Digest the MAC Key */
- key.cd_format = CRYPTO_DATA_RAW;
- key.cd_offset = 0;
- key.cd_length = vcp->vc_mackeylen;
- key.cd_miscdata = 0;
- key.cd_raw.iov_base = (char *)vcp->vc_mackey;
- key.cd_raw.iov_len = vcp->vc_mackeylen;
- status = crypto_digest_update(crypto_ctx, &key, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
-
- /* Digest the (copied) SMB header */
- data.cd_format = CRYPTO_DATA_RAW;
- data.cd_offset = 0;
- data.cd_length = SMB_HDRLEN;
- data.cd_miscdata = 0;
- data.cd_raw.iov_base = (char *)smbhdr.r.raw;
- data.cd_raw.iov_len = SMB_HDRLEN;
- status = crypto_digest_update(crypto_ctx, &data, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
+ size = MBLKL(m) - SMB_HDRLEN;
+ rc = smb_md5_update(ctx, m->b_rptr + SMB_HDRLEN, size);
+ if (rc != 0)
+ return (rc);
+ m = m->b_cont;
/* Digest rest of the SMB message. */
- data.cd_format = CRYPTO_DATA_MBLK;
- data.cd_offset = SMB_HDRLEN;
- data.cd_length = msgdsize(mp) - SMB_HDRLEN;
- data.cd_miscdata = 0;
- data.cd_mp = mp;
- status = crypto_digest_update(crypto_ctx, &data, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
-
- /* Final */
- digest.cd_format = CRYPTO_DATA_RAW;
- digest.cd_offset = 0;
- digest.cd_length = sizeof (mac);
- digest.cd_miscdata = 0;
- digest.cd_raw.iov_base = (char *)mac;
- digest.cd_raw.iov_len = sizeof (mac);
- status = crypto_digest_final(crypto_ctx, &digest, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
+ while (m != NULL) {
+ size = MBLKL(m);
+ if (size > 0) {
+ rc = smb_md5_update(ctx, m->b_rptr, size);
+ if (rc != 0)
+ return (rc);
+ }
+ m = m->b_cont;
+ }
+ rc = smb_md5_final(ctx, digest);
+ if (rc != 0)
+ return (rc);
/*
* Finally, store the signature.
* (first 8 bytes of the mac)
*/
- if (signature)
- bcopy(mac, signature, SMBSIGLEN);
+ if (signature != NULL)
+ bcopy(digest, signature, SMBSIGLEN);
return (0);
}
@@ -197,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) {
@@ -221,7 +226,7 @@ smb_rq_sign(struct smb_rq *rqp)
* directly into the message at sigloc.
*/
status = smb_compute_MAC(vcp, mp, rqp->sr_seqno, sigloc);
- if (status != CRYPTO_SUCCESS) {
+ if (status != 0) {
SMBSDEBUG("Crypto error %d", status);
bzero(sigloc, SMBSIGLEN);
}
@@ -256,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;
/*
@@ -267,7 +270,7 @@ smb_rq_verify(struct smb_rq *rqp)
*/
rsn = rqp->sr_rseqno;
status = smb_compute_MAC(vcp, mp, rsn, sigbuf);
- if (status != CRYPTO_SUCCESS) {
+ if (status != 0) {
SMBSDEBUG("Crypto error %d", status);
/*
* If we can't compute a MAC, then there's
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h
new file mode 100644
index 0000000000..e1799e3383
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h
@@ -0,0 +1,73 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SMB_SIGNING_H_
+#define _SMB_SIGNING_H_
+
+/*
+ * SMB signing routines used in {smb,smb2}_sign.c
+ * Two implementations of these (kernel/user) in:
+ * uts/common/fs/smbclnt/netsmb/smb_sign_kcf.c
+ * lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
+ */
+
+#ifdef _KERNEL
+#include <sys/crypto/api.h>
+#else
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MD5_DIGEST_LENGTH 16 /* MD5 digest length in bytes */
+#define SHA256_DIGEST_LENGTH 32 /* SHA256 digest length in bytes */
+#define SMB2_SIG_SIZE 16
+
+#ifdef _KERNEL
+/* KCF variant */
+typedef crypto_mechanism_t smb_sign_mech_t;
+typedef crypto_context_t smb_sign_ctx_t;
+#else /* _KERNEL */
+/* PKCS11 variant */
+typedef CK_MECHANISM smb_sign_mech_t;
+typedef CK_SESSION_HANDLE smb_sign_ctx_t;
+#endif /* _KERNEL */
+
+/*
+ * SMB signing routines used in smb_signing.c
+ */
+
+int smb_md5_getmech(smb_sign_mech_t *);
+int smb_md5_init(smb_sign_ctx_t *, smb_sign_mech_t *);
+int smb_md5_update(smb_sign_ctx_t, void *, size_t);
+int smb_md5_final(smb_sign_ctx_t, uint8_t *);
+
+/*
+ * SMB2 signing routines used in smb2_signing.c
+ */
+
+int smb2_hmac_getmech(smb_sign_mech_t *);
+int smb2_hmac_init(smb_sign_ctx_t *, smb_sign_mech_t *, uint8_t *, size_t);
+int smb2_hmac_update(smb_sign_ctx_t, uint8_t *, size_t);
+int smb2_hmac_final(smb_sign_ctx_t, uint8_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_SIGNING_H_ */
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 6016f5061a..566f131316 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
@@ -33,8 +33,9 @@
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Portions Copyright (C) 2001 - 2014 Apple Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -49,6 +50,7 @@
#include <sys/uio.h>
#include <sys/random.h>
#include <sys/note.h>
+#include <sys/errno.h>
#include <sys/cmn_err.h>
#include <netsmb/smb_osdep.h>
@@ -61,14 +63,25 @@
#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[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 const uint32_t smb_clnt_caps_mask =
+ SMB_CAP_UNICODE |
+ SMB_CAP_LARGE_FILES |
+ SMB_CAP_NT_SMBS |
+ SMB_CAP_STATUS32 |
+ SMB_CAP_EXT_SECURITY;
/*
* Default timeout values, all in seconds.
@@ -76,20 +89,526 @@
*/
int smb_timo_notice = 15;
int smb_timo_default = 30; /* was SMB_DEFRQTIMO */
+int smb_timo_logon = 45;
int smb_timo_open = 45;
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);
+int
+smb_smb_negotiate(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;
+ struct smb_dialect *dp;
+ int err, sblen, tlen;
+ uint8_t wc, eklen;
+ uint16_t dindex, bc;
+ uint16_t ndialects;
+ boolean_t will_sign = B_FALSE;
+
+ /*
+ * Initialize: vc_hflags and vc_hflags2.
+ * Note: vcp->vc_hflags* are copied into the
+ * (per request) rqp->rq_hflags* by smb_rq_init.
+ *
+ * Like Windows, set FLAGS2_UNICODE in our first request,
+ * even though technically we don't yet know whether the
+ * server supports Unicode. Will clear this flag below
+ * if we find out it doesn't. Need to do this because
+ * some servers reject all non-Unicode requests.
+ */
+ vcp->vc_hflags =
+ SMB_FLAGS_CASELESS |
+ SMB_FLAGS_CANONICAL_PATHNAMES;
+ vcp->vc_hflags2 =
+ SMB_FLAGS2_KNOWS_LONG_NAMES |
+ SMB_FLAGS2_KNOWS_EAS |
+ SMB_FLAGS2_IS_LONG_NAME |
+ SMB_FLAGS2_EXT_SEC |
+ SMB_FLAGS2_ERR_STATUS |
+ SMB_FLAGS2_UNICODE;
+
+ /*
+ * The initial UID needs to be zero,
+ */
+ vcp->vc_smbuid = 0;
+
+ /*
+ * (Re)init negotiated values
+ */
+ bzero(sv, sizeof (*sv));
+ sv->sv_maxmux = 1;
+ 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);
+
+ /*
+ * Build the SMB request.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ for (dindex = 0; dindex < ndialects; dindex++) {
+ dp = &smb_dialects[dindex];
+ mb_put_uint8(mbp, SMB_DT_DIALECT);
+ tlen = strlen(dp->d_name) + 1;
+ mb_put_mem(mbp, dp->d_name, tlen, MB_MSYSTEM);
+ }
+ smb_rq_bend(rqp);
+
+ /*
+ * 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
+ *
+ * Comments to right show names as described in
+ * The Microsoft SMB Protocol spec. [MS-SMB]
+ * section 2.2.3
+ */
+ smb_rq_getreply(rqp, &mdp);
+ (void) md_get_uint8(mdp, &wc);
+ err = md_get_uint16le(mdp, &dindex);
+ if (err != 0)
+ goto errout;
+ if (dindex >= ndialects) {
+ SMBERROR("Invalid dialect index from server: %s\n",
+ vcp->vc_srvname);
+ err = EBADRPC;
+ goto errout;
+ }
+ dp = smb_dialects + dindex;
+ sv->sv_proto = dp->d_id;
+ SMBSDEBUG("Dialect %s", dp->d_name);
+ if (dp->d_id < SMB_DIALECT_NTLM0_12) {
+ SMBSDEBUG("old dialect %s", dp->d_name);
+ goto errout;
+ }
+ if (wc != 17) {
+ SMBSDEBUG("bad wc %d", (int)wc);
+ goto errout;
+ }
+ md_get_uint8(mdp, &sv->sv_sm); /* SecurityMode */
+ md_get_uint16le(mdp, &sv->sv_maxmux); /* MaxMpxCount */
+ md_get_uint16le(mdp, &sv->sv_maxvcs); /* MaxCountVCs */
+ md_get_uint32le(mdp, &sv->sv_maxtx); /* MaxBufferSize */
+ md_get_uint32le(mdp, &sv->sv_maxraw); /* MaxRawSize */
+ md_get_uint32le(mdp, &sv->sv_skey); /* SessionKey */
+ md_get_uint32le(mdp, &sv->sv_caps); /* Capabilities */
+ md_get_mem(mdp, NULL, 8, MB_MSYSTEM); /* SystemTime(s) */
+ md_get_uint16le(mdp, (uint16_t *)&sv->sv_tz);
+ md_get_uint8(mdp, &eklen); /* EncryptionKeyLength */
+ err = md_get_uint16le(mdp, &bc); /* ByteCount */
+ if (err)
+ goto errout;
+
+ /* BEGIN CSTYLED */
+ /*
+ * Will we do SMB signing? Or block the connection?
+ * The table below describes this logic. References:
+ * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3]
+ * http://msdn.microsoft.com/en-us/library/cc212511.aspx
+ * http://msdn.microsoft.com/en-us/library/cc212929.aspx
+ *
+ * Srv/Cli | Required | Enabled | If Required | Disabled
+ * ------------+----------+------------+-------------+-----------
+ * Required | Signed | Signed | Signed | Blocked [1]
+ * ------------+----------+------------+-------------+-----------
+ * Enabled | Signed | Signed | Not Signed | Not Signed
+ * ------------+----------+------------+-------------+-----------
+ * If Required | Signed | Not Signed | Not Signed | Not Signed
+ * ------------+----------+------------+-------------+-----------
+ * Disabled | Blocked | Not Signed | Not Signed | Not Signed
+ *
+ * [1] Like Windows 2003 and later, we don't really implement
+ * the "Disabled" setting. Instead we implement "If Required",
+ * so we always sign if the server requires signing.
+ */
+ /* END CSTYLED */
+
+ if (sv->sv_sm & SMB_SM_SIGS_REQUIRE) {
+ /*
+ * Server requires signing. We will sign,
+ * even if local setting is "disabled".
+ */
+ will_sign = B_TRUE;
+ } else if (sv->sv_sm & SMB_SM_SIGS) {
+ /*
+ * Server enables signing (client's option).
+ * If enabled locally, do signing.
+ */
+ if (vcp->vc_vopt & SMBVOPT_SIGNING_ENABLED)
+ will_sign = B_TRUE;
+ /* else not signing. */
+ } else {
+ /*
+ * Server does not support signing.
+ * If we "require" it, bail now.
+ */
+ if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
+ SMBERROR("Client requires signing "
+ "but server has it disabled.");
+ err = EBADRPC;
+ goto errout;
+ }
+ }
+
+ /*
+ * Anonymous sessions can't sign.
+ */
+ 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;
+ vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
+
+ /*
+ * MS-SMB 2.2.4.5 says that when SMB signing is enabled,
+ * we should NOT use "large read/write" even though the
+ * server might offer those capabilities.
+ */
+ sv->sv_caps &= ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX);
+ }
+
+ /* See comment above re. FLAGS2_UNICODE */
+ if ((sv->sv_caps & SMB_CAP_UNICODE) != 0)
+ vcp->vc_flags |= SMBV_UNICODE;
+ else
+ vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
+
+ if ((sv->sv_caps & SMB_CAP_STATUS32) == 0) {
+ /* They don't do NT error codes. */
+ vcp->vc_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
+ }
+
+ /*
+ * 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".
+ *
+ * With extended security, we have:
+ * Server_GUID (length 16)
+ * Security_BLOB
+ * Otherwise we have:
+ * EncryptionKey (length is eklen)
+ * PrimaryDomain
+ */
+ if (sv->sv_caps & SMB_CAP_EXT_SECURITY) {
+ SMBSDEBUG("Ext.Security: yes");
+
+ /*
+ * Skip the server GUID.
+ */
+ err = md_get_mem(mdp, NULL, SMB_GUIDLEN, MB_MSYSTEM);
+ if (err)
+ goto errout;
+ /*
+ * Remainder is the security blob.
+ * Note: eklen "must be ignored" [MS-SMB]
+ */
+ sblen = (int)bc - SMB_GUIDLEN;
+ if (sblen < 0)
+ goto errout;
+ /* Security blob (hint) is next */
+ } else {
+ SMBSDEBUG("Ext.Security: no");
+ err = ENOTSUP;
+ goto errout;
+ }
+
+ /*
+ * Copy the security blob out to user space.
+ * Buffer addr,size in vc_auth_rbuf,rlen
+ */
+ if (wk->wk_u_auth_rlen < sblen) {
+ SMBSDEBUG("vc_auth_rbuf too small");
+ /* Give caller required size. */
+ wk->wk_u_auth_rlen = sblen;
+ err = EMSGSIZE;
+ goto errout;
+ }
+ wk->wk_u_auth_rlen = sblen;
+ err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr, sblen, MB_MUSER);
+ if (err)
+ goto errout;
+
+ /*
+ * A few sanity checks on what we received,
+ * becuse we will send these in ssnsetup.
+ *
+ * Maximum outstanding requests (we care),
+ * and Max. VCs (we only use one). Also,
+ * MaxBufferSize lower limit per spec.
+ */
+ if (sv->sv_maxmux < 1)
+ sv->sv_maxmux = 1;
+ if (sv->sv_maxvcs < 1)
+ sv->sv_maxvcs = 1;
+ if (sv->sv_maxtx < 1024)
+ sv->sv_maxtx = 1024;
+
+ /*
+ * Maximum transfer size.
+ * Sanity checks:
+ *
+ * Let's be conservative about an upper limit here.
+ * Win2k uses 16644 (and others) so 32k should be a
+ * reasonable sanity limit for this value.
+ *
+ * Note that this limit does NOT affect READX/WRITEX
+ * with CAP_LARGE_..., which we nearly always use.
+ */
+ vcp->vc_txmax = sv->sv_maxtx;
+ if (vcp->vc_txmax > 0x8000)
+ vcp->vc_txmax = 0x8000;
+
+ /*
+ * Max read/write sizes, WITHOUT overhead.
+ * This is just the payload size, so we must
+ * leave room for the SMB headers, etc.
+ * This is just the ct_txmax value, but
+ * reduced and rounded down. Tricky bit:
+ *
+ * Servers typically give us a value that's
+ * some nice "round" number, i.e 0x4000 plus
+ * some overhead, i.e. Win2k: 16644==0x4104
+ * Subtract for the SMB header (32) and the
+ * SMB command word and byte vectors (34?),
+ * then round down to a 512 byte multiple.
+ */
+ tlen = vcp->vc_txmax - 68;
+ tlen &= 0xFE00;
+
+ vcp->vc_rwmax = tlen;
+ vcp->vc_rxmax = tlen;
+ vcp->vc_wxmax = tlen;
+
+ /*
+ * Most of the "capability" bits we offer in session setup
+ * are just copied from those offered by the server.
+ */
+ sv->sv_caps &= smb_clnt_caps_mask;
+
+ smb_rq_done(rqp);
+ return (0);
+
+errout:
+ smb_rq_done(rqp);
+ if (err == 0)
+ err = EBADRPC;
+ return (err);
+}
+
+static const char NativeOS[] = "illumos";
+static const char LanMan[] = "NETSMB";
+
+int
+smb_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;
+ uint32_t caps;
+ uint16_t action, bc, sblen;
+ uint8_t wc;
+
+ caps = sv->sv_caps;
+ sb = wk->wk_u_auth_wbuf.lp_ptr;
+ sblen = (uint16_t)wk->wk_u_auth_wlen;
+
+ err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX,
+ scred, &rqp);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+
+ /*
+ * Build the SMB Session Setup request.
+ * Always extended security form.
+ */
+ mbp = &rqp->sr_rq;
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, 0xff); /* 0: AndXCommand */
+ mb_put_uint16le(mbp, 0); /* 1: AndXOffset */
+ mb_put_uint16le(mbp, sv->sv_maxtx); /* 2: MaxBufferSize */
+ mb_put_uint16le(mbp, sv->sv_maxmux); /* 3: MaxMpxCount */
+ mb_put_uint16le(mbp, 1); /* 4: VcNumber */
+ mb_put_uint32le(mbp, sv->sv_skey); /* 5,6: Session Key */
+ mb_put_uint16le(mbp, sblen); /* 7: Sec. Blob Len */
+ mb_put_uint32le(mbp, 0); /* 8,9: reserved */
+ mb_put_uint32le(mbp, caps); /* 10,11: Capabilities */
+ smb_rq_wend(rqp); /* 12: Byte Count */
+ smb_rq_bstart(rqp);
+ err = mb_put_mem(mbp, sb, sblen, MB_MUSER);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+ (void) smb_put_dstring(mbp, vcp, NativeOS, SMB_CS_NONE);
+ (void) smb_put_dstring(mbp, vcp, LanMan, SMB_CS_NONE);
+ smb_rq_bend(rqp);
+
+ /*
+ * 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 = smb_rq_internal(rqp, smb_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;
+ }
+
+ if (vcp->vc_smbuid == 0)
+ vcp->vc_smbuid = rqp->sr_rpuid;
+
+ /*
+ * Parse the reply
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ err = md_get_uint8(mdp, &wc);
+ if (err != 0)
+ wc = 0;
+ if (wc != 4) {
+ ret = EBADRPC;
+ goto out;
+ }
+ md_get_uint16le(mdp, NULL); /* secondary cmd */
+ md_get_uint16le(mdp, NULL); /* andxoffset */
+ md_get_uint16le(mdp, &action); /* action XXX */
+ md_get_uint16le(mdp, &sblen); /* sec. blob len */
+ md_get_uint16le(mdp, &bc); /* byte count */
+ /*
+ * Get the security blob, after
+ * sanity-checking the length.
+ */
+ if (sblen == 0 || sblen > bc) {
+ ret = EBADRPC;
+ goto out;
+ }
+ if (sblen > wk->wk_u_auth_rlen) {
+ ret = EBADRPC;
+ goto out;
+ }
+ sb = wk->wk_u_auth_rbuf.lp_ptr;
+ err = md_get_mem(mdp, sb, sblen, MB_MUSER);
+ if (err) {
+ ret = EBADRPC;
+ goto out;
+ }
+
+ /*
+ * Native OS, LANMGR, & Domain follow here.
+ * We don't need them and don't parse them.
+ */
+
+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);
-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);
+ /*
+ * 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,
@@ -352,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 */
@@ -475,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;
@@ -600,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;
@@ -716,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 */
@@ -786,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;
@@ -811,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 */
@@ -859,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)
{
@@ -1018,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 df0f28ec05..b780f9b21b 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
@@ -33,8 +33,8 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _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 */
@@ -117,86 +125,131 @@ extern int smb_timo_open;
extern int smb_timo_read;
extern int smb_timo_write;
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);
void smb_free_sockaddr(struct sockaddr *sa);
-int smb_toupper(const char *, char *, size_t);
+int smb_sign_init(struct smb_vc *);
void smb_rq_sign(struct smb_rq *);
int smb_rq_verify(struct smb_rq *);
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 e29a96631a..bf1e605187 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
@@ -34,6 +34,8 @@
/*
* 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.
*/
#include <sys/param.h>
@@ -57,50 +59,19 @@
#include <netsmb/smb_rq.h>
#include <netsmb/smb_subr.h>
-/*
- * XXX:This conversion might not be fully MS-Compatible
- * for calculating hashes. The output length may differ
- * for some locales and needs to be handled from where
- * the call is made.
- */
-int
-smb_toupper(const char *inbuf, char *outbuf, size_t outlen)
-{
- int err = 0;
- size_t inlen, inrem, outrem;
-
- inrem = inlen = strlen(inbuf);
- outrem = outlen;
- (void) u8_textprep_str((char *)inbuf, &inrem, outbuf, &outrem,
- U8_TEXTPREP_TOUPPER, U8_UNICODE_LATEST, &err);
- /* inrem, outrem are bytes unused, remaining */
- if (inrem) {
- SMBSDEBUG("input %d remains: %s\n", (int)inrem, inbuf);
- inlen -= inrem;
- }
- if (outrem) {
- outlen -= outrem;
- outbuf[outlen] = '\0';
- }
- if (outlen > inlen) {
- SMBSDEBUG("outlen > inlen! (%d > %d)\n",
- (int)outlen, (int)inlen);
- /* Truncate to inlen here? */
- }
-
- return (err);
-}
-
void
smb_credinit(struct smb_cred *scred, cred_t *cr)
{
/* cr arg is optional */
if (cr == NULL)
cr = ddi_get_cred();
+#ifdef _KERNEL
if (is_system_labeled()) {
cr = crdup(cr);
(void) setpflags(NET_MAC_AWARE, 1, cr);
- } else {
+ } else
+#endif
+ {
crhold(cr);
}
scred->scr_cred = cr;
@@ -115,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
@@ -137,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.
@@ -190,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.
@@ -219,7 +204,9 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_ACCOUNT_RESTRICTION, EACCES},
{NT_STATUS_ADDRESS_ALREADY_EXISTS, EADDRINUSE},
{NT_STATUS_BAD_NETWORK_NAME, ENOENT},
- {NT_STATUS_BUFFER_TOO_SMALL, EMOREDATA},
+ {NT_STATUS_BAD_NETWORK_PATH, ENOENT},
+ {NT_STATUS_BUFFER_TOO_SMALL, E2BIG},
+ {NT_STATUS_CANCELLED, ECANCELED},
{NT_STATUS_CANNOT_DELETE, EACCES},
{NT_STATUS_CONFLICTING_ADDRESSES, EADDRINUSE},
{NT_STATUS_CONNECTION_ABORTED, ECONNABORTED},
@@ -233,59 +220,87 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_DISK_FULL, ENOSPC},
{NT_STATUS_DLL_NOT_FOUND, ELIBACC},
{NT_STATUS_DUPLICATE_NAME, EINVAL},
+ {NT_STATUS_EAS_NOT_SUPPORTED, ENOTSUP},
+ {NT_STATUS_EA_TOO_LARGE, E2BIG},
{NT_STATUS_END_OF_FILE, ENODATA},
+ {NT_STATUS_FILE_CLOSED, EBADF},
+ {NT_STATUS_FILE_DELETED, ENOENT},
+ {NT_STATUS_FILE_INVALID, EIO},
{NT_STATUS_FILE_IS_A_DIRECTORY, EISDIR},
{NT_STATUS_FILE_LOCK_CONFLICT, EAGAIN},
+ {NT_STATUS_FILE_RENAMED, ENOENT},
{NT_STATUS_FLOAT_INEXACT_RESULT, ERANGE},
{NT_STATUS_FLOAT_OVERFLOW, ERANGE},
{NT_STATUS_FLOAT_UNDERFLOW, ERANGE},
{NT_STATUS_HOST_UNREACHABLE, EHOSTUNREACH},
- {NT_STATUS_ILL_FORMED_PASSWORD, EACCES},
+ {NT_STATUS_ILL_FORMED_PASSWORD, EAUTH},
+ {NT_STATUS_INFO_LENGTH_MISMATCH, EINVAL},
+ {NT_STATUS_INSUFFICIENT_RESOURCES, EAGAIN},
+ {NT_STATUS_INSUFF_SERVER_RESOURCES, EAGAIN},
{NT_STATUS_INTEGER_OVERFLOW, ERANGE},
- {NT_STATUS_INVALID_ACCOUNT_NAME, EACCES},
+ {NT_STATUS_INVALID_ACCOUNT_NAME, EAUTH},
+ {NT_STATUS_INVALID_BUFFER_SIZE, EIO},
+ {NT_STATUS_INVALID_DEVICE_REQUEST, EINVAL},
{NT_STATUS_INVALID_HANDLE, EBADF},
+ {NT_STATUS_INVALID_INFO_CLASS, EINVAL},
{NT_STATUS_INVALID_LEVEL, ENOTSUP},
- {NT_STATUS_INVALID_LOGON_HOURS, EACCES},
+ {NT_STATUS_INVALID_LOCK_SEQUENCE, EINVAL},
+ {NT_STATUS_INVALID_LOGON_HOURS, EAUTH},
{NT_STATUS_INVALID_OWNER, EINVAL},
{NT_STATUS_INVALID_PARAMETER, EINVAL},
{NT_STATUS_INVALID_PIPE_STATE, EPIPE},
{NT_STATUS_INVALID_PRIMARY_GROUP, EINVAL},
{NT_STATUS_INVALID_WORKSTATION, EACCES},
{NT_STATUS_IN_PAGE_ERROR, EFAULT},
+ {NT_STATUS_IO_DEVICE_ERROR, EIO},
{NT_STATUS_IO_TIMEOUT, ETIMEDOUT},
- {NT_STATUS_IP_ADDRESS_CONFLICT1, ENOTUNIQ},
- {NT_STATUS_IP_ADDRESS_CONFLICT2, ENOTUNIQ},
+ {NT_STATUS_IP_ADDRESS_CONFLICT1, EADDRINUSE},
+ {NT_STATUS_IP_ADDRESS_CONFLICT2, EADDRINUSE},
{NT_STATUS_LICENSE_QUOTA_EXCEEDED, EDQUOT},
{NT_STATUS_LOCK_NOT_GRANTED, EAGAIN},
- {NT_STATUS_LOGIN_TIME_RESTRICTION, EACCES},
- {NT_STATUS_LOGON_FAILURE, EACCES},
+ {NT_STATUS_LOGIN_TIME_RESTRICTION, EAUTH},
+ {NT_STATUS_LOGON_FAILURE, EAUTH},
+ {NT_STATUS_LOGON_TYPE_NOT_GRANTED, EAUTH},
{NT_STATUS_MEDIA_WRITE_PROTECTED, EROFS},
{NT_STATUS_MEMORY_NOT_ALLOCATED, EFAULT},
+ {NT_STATUS_MORE_PROCESSING_REQUIRED, EINPROGRESS},
{NT_STATUS_NAME_TOO_LONG, ENAMETOOLONG},
{NT_STATUS_NETWORK_ACCESS_DENIED, EACCES},
{NT_STATUS_NETWORK_BUSY, EBUSY},
+ {NT_STATUS_NETWORK_NAME_DELETED, ENOENT},
{NT_STATUS_NETWORK_UNREACHABLE, ENETUNREACH},
{NT_STATUS_NET_WRITE_FAULT, ECOMM},
+ {NT_STATUS_NONEXISTENT_EA_ENTRY, ENOENT},
{NT_STATUS_NONEXISTENT_SECTOR, ESPIPE},
{NT_STATUS_NONE_MAPPED, EINVAL},
{NT_STATUS_NOT_A_DIRECTORY, ENOTDIR},
+ {NT_STATUS_NOT_FOUND, ENOENT},
{NT_STATUS_NOT_IMPLEMENTED, ENOTSUP},
+ {NT_STATUS_NOT_LOCKED, ENOLCK},
{NT_STATUS_NOT_MAPPED_VIEW, EINVAL},
{NT_STATUS_NOT_SUPPORTED, ENOTSUP},
+ {NT_STATUS_NO_EAS_ON_FILE, ENOENT},
+ {NT_STATUS_NO_LOGON_SERVERS, EAUTH},
{NT_STATUS_NO_MEDIA, ENOMEDIUM},
{NT_STATUS_NO_MEDIA_IN_DEVICE, ENOMEDIUM},
{NT_STATUS_NO_MEMORY, ENOMEM},
{NT_STATUS_NO_SUCH_DEVICE, ENODEV},
{NT_STATUS_NO_SUCH_FILE, ENOENT},
+ {NT_STATUS_NO_SUCH_LOGON_SESSION, EAUTH},
+ {NT_STATUS_NO_SUCH_USER, EAUTH},
+ {NT_STATUS_NO_TRUST_LSA_SECRET, EAUTH},
+ {NT_STATUS_NO_TRUST_SAM_ACCOUNT, EAUTH},
{NT_STATUS_OBJECT_NAME_COLLISION, EEXIST},
{NT_STATUS_OBJECT_NAME_INVALID, EINVAL},
{NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT},
{NT_STATUS_OBJECT_PATH_INVALID, ENOTDIR},
{NT_STATUS_OBJECT_PATH_NOT_FOUND, ENOENT},
+ {NT_STATUS_OBJECT_PATH_SYNTAX_BAD, EINVAL},
+ {NT_STATUS_OBJECT_TYPE_MISMATCH, EBADF},
{NT_STATUS_PAGEFILE_QUOTA, EDQUOT},
- {NT_STATUS_PASSWORD_EXPIRED, EACCES},
- {NT_STATUS_PASSWORD_MUST_CHANGE, EACCES},
- {NT_STATUS_PASSWORD_RESTRICTION, EACCES},
+ {NT_STATUS_PASSWORD_EXPIRED, EAUTH},
+ {NT_STATUS_PASSWORD_MUST_CHANGE, EAUTH},
+ {NT_STATUS_PASSWORD_RESTRICTION, EAUTH},
{NT_STATUS_PATH_NOT_COVERED, ENOENT},
{NT_STATUS_PIPE_BROKEN, EPIPE},
{NT_STATUS_PIPE_BUSY, EPIPE},
@@ -293,11 +308,12 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_PIPE_DISCONNECTED, EPIPE},
{NT_STATUS_PIPE_NOT_AVAILABLE, EBUSY},
{NT_STATUS_PORT_CONNECTION_REFUSED, ECONNREFUSED},
+ {NT_STATUS_PORT_DISCONNECTED, EBADF},
{NT_STATUS_PORT_MESSAGE_TOO_LONG, EMSGSIZE},
{NT_STATUS_PORT_UNREACHABLE, EHOSTUNREACH},
{NT_STATUS_PROTOCOL_UNREACHABLE, ENOPROTOOPT},
{NT_STATUS_QUOTA_EXCEEDED, EDQUOT},
- {NT_STATUS_RANGE_NOT_LOCKED, EIO},
+ {NT_STATUS_RANGE_NOT_LOCKED, EAGAIN}, /* like F_SETLK */
{NT_STATUS_REGISTRY_QUOTA_LIMIT, EDQUOT},
{NT_STATUS_REMOTE_DISCONNECT, ESHUTDOWN},
{NT_STATUS_REMOTE_NOT_LISTENING, ECONNREFUSED},
@@ -307,9 +323,11 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_TIMER_NOT_CANCELED, ETIME},
{NT_STATUS_TOO_MANY_LINKS, EMLINK},
{NT_STATUS_TOO_MANY_OPENED_FILES, EMFILE},
+ {NT_STATUS_TRUSTED_DOMAIN_FAILURE, EAUTH},
+ {NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE, EAUTH},
{NT_STATUS_UNABLE_TO_FREE_VM, EADDRINUSE},
{NT_STATUS_UNSUCCESSFUL, EINVAL},
- {NT_STATUS_WRONG_PASSWORD, EACCES},
+ {NT_STATUS_WRONG_PASSWORD, EAUTH},
{0, 0}
};
@@ -593,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},
@@ -868,6 +878,19 @@ smb_maperr32(uint32_t nterr)
return (EIO);
}
+uint_t
+smb_doserr2status(int dclass, int derr)
+{
+ const nt2doserr_t *nt2d;
+
+ if (dclass == 0 && derr == 0)
+ return (0);
+
+ for (nt2d = nt2doserr; nt2d->nterr; nt2d++)
+ if (nt2d->dclass == dclass && nt2d->derr == derr)
+ return (nt2d->nterr);
+ return (NT_STATUS_UNSUCCESSFUL);
+}
int
smb_maperror(int eclass, int eno)
@@ -996,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,
@@ -1080,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 f954056a79..1060139491 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.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 _NETSMB_SMB_TRAN_H_
@@ -42,6 +44,9 @@
#include <sys/socket.h>
#include <sys/stream.h>
+#ifndef _KERNEL
+struct file;
+#endif
/*
* Known transports
@@ -49,11 +54,14 @@
#define SMBT_NBTCP 1
/*
- * Transport parameters
+ * Transport parameters, for tr_getparam/tr_setparam
*/
-#define SMBTP_SNDSZ 1 /* R - int */
-#define SMBTP_RCVSZ 2 /* R - int */
-#define SMBTP_TIMEOUT 3 /* RW - struct timespec */
+#define SMBTP_TCP_NODELAY 0x01 /* RW - int */
+#define SMBTP_TCP_CON_TMO 0x13 /* RW - int */
+#define SMBTP_KEEPALIVE SO_KEEPALIVE /* RW - int */
+#define SMBTP_SNDBUF SO_SNDBUF /* RW - int */
+#define SMBTP_RCVBUF SO_RCVBUF /* RW - int */
+#define SMBTP_RCVTIMEO SO_RCVTIMEO /* RW - int? */
struct smb_tran_ops;
@@ -62,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);
@@ -78,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 4f101a4f5f..849e91637e 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
@@ -34,7 +34,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.
*/
#include <sys/param.h>
@@ -73,13 +74,6 @@
#include <netsmb/smb_tran.h>
#include <netsmb/smb_trantcp.h>
-/*
- * SMB messages are up to 64K.
- * Let's leave room for two.
- */
-static int smb_tcpsndbuf = 0x20000;
-static int smb_tcprcvbuf = 0x20000;
-
static int nb_disconnect(struct nbpcb *nbp);
@@ -163,7 +157,7 @@ nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen)
case T_DISCON_IND:
/* Peer disconnected. */
NBDEBUG("T_DISCON_IND: reason=%d",
- pptr->discon_ind.DISCON_reason);
+ (int)pptr->discon_ind.DISCON_reason);
goto discon;
case T_ORDREL_IND:
/* Peer disconnecting. */
@@ -176,11 +170,11 @@ nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen)
goto discon;
default:
NBDEBUG("T_OK_ACK/prim=%d",
- pptr->ok_ack.CORRECT_prim);
+ (int)pptr->ok_ack.CORRECT_prim);
goto discon;
}
default:
- NBDEBUG("M_PROTO/type=%d", pptr->type);
+ NBDEBUG("M_PROTO/type=%d", (int)pptr->type);
goto discon;
}
break; /* M_PROTO, M_PCPROTO */
@@ -485,22 +479,45 @@ out:
* This is called only by the thread creating this endpoint,
* so we're single-threaded here.
*/
-/*ARGSUSED*/
static int
smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
{
- struct nbpcb *nbp;
+ TIUSER *tiptr = NULL;
+ struct nbpcb *nbp = NULL;
+ dev_t dev;
+ int rc;
+ ushort_t fmode;
+
+ switch (vcp->vc_srvaddr.sa.sa_family) {
+ case AF_INET:
+ dev = nsmb_dev_tcp;
+ break;
+ case AF_INET6:
+ dev = nsmb_dev_tcp6;
+ break;
+ default:
+ return (EAFNOSUPPORT);
+ }
+
+ fmode = FREAD|FWRITE;
+ rc = t_kopen(NULL, dev, fmode, &tiptr, cr);
+ if (rc != 0) {
+ cmn_err(CE_NOTE, "t_kopen failed, rc=%d", rc);
+ return (rc);
+ }
+ ASSERT(tiptr != NULL);
nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
nbp->nbp_timo.tv_sec = SMB_NBTIMO;
- nbp->nbp_state = NBST_CLOSED; /* really IDLE */
+ nbp->nbp_state = NBST_IDLE;
nbp->nbp_vc = vcp;
- nbp->nbp_sndbuf = smb_tcpsndbuf;
- nbp->nbp_rcvbuf = smb_tcprcvbuf;
+ nbp->nbp_tiptr = tiptr;
+ nbp->nbp_fmode = fmode;
nbp->nbp_cred = cr;
crhold(cr);
mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
+
vcp->vc_tdata = nbp;
return (0);
@@ -541,111 +558,74 @@ smb_nbst_done(struct smb_vc *vcp)
return (0);
}
-/*
- * 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)
+smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
{
- TIUSER *tiptr;
+ struct nbpcb *nbp = vcp->vc_tdata;
+ TIUSER *tiptr = nbp->nbp_tiptr;
int err;
- err = t_kopen(fp, 0, 0, &tiptr, cr);
- if (err != 0)
- return (err);
+ /* Only default bind supported. */
+ if (sap != NULL)
+ return (ENOTSUP);
- 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);
+ err = t_kbind(tiptr, NULL, NULL);
- return (0);
+ return (err);
}
-/*
- * 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)
+static int
+smb_nbst_unbind(struct smb_vc *vcp)
{
+ struct nbpcb *nbp = vcp->vc_tdata;
+ TIUSER *tiptr = nbp->nbp_tiptr;
+ int err;
- 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;
+ err = t_kunbind(tiptr);
- mutex_exit(&nbp->nbp_lock);
+ return (err);
}
static int
-smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr)
+smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
{
- struct nbpcb *nbp = vcp->vc_tdata;
- int error = 0;
+ struct t_call call;
+ struct nbpcb *nbp = vcp->vc_tdata;
+ TIUSER *tiptr = nbp->nbp_tiptr;
+ int alen, err;
+
+ /* Need the address length */
+ switch (sap->sa_family) {
+ case AF_INET:
+ alen = sizeof (struct sockaddr_in);
+ break;
+ case AF_INET6:
+ alen = sizeof (struct sockaddr_in6);
+ break;
+ default:
+ return (EAFNOSUPPORT);
+ }
- /*
- * Un-loan the existing one, if any.
- */
- (void) nb_disconnect(nbp);
- nb_unloan_fp(nbp);
+ /* sockaddr goes in the "addr" netbuf */
+ bzero(&call, sizeof (call));
+ call.addr.buf = (char *)sap;
+ call.addr.len = alen;
+ call.addr.maxlen = alen;
- /*
- * Loan the new one passed in.
- */
- if (fp != NULL) {
- error = nb_loan_fp(nbp, fp, cr);
- }
+ err = t_kconnect(tiptr, &call, NULL);
+ if (err != 0)
+ return (err);
- return (error);
-}
+ mutex_enter(&nbp->nbp_lock);
-/*ARGSUSED*/
-static int
-smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
-{
- return (ENOTSUP);
-}
+ nbp->nbp_flags |= NBF_CONNECTED;
+ nbp->nbp_state = NBST_SESSION;
-/*ARGSUSED*/
-static int
-smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
-{
- return (ENOTSUP);
+ mutex_exit(&nbp->nbp_lock);
+
+ return (0);
}
-/*ARGSUSED*/
static int
smb_nbst_disconnect(struct smb_vc *vcp)
{
@@ -832,42 +812,78 @@ smb_nbst_poll(struct smb_vc *vcp, int ticks)
return (ENOTSUP);
}
+/*ARGSUSED*/
static int
smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
{
+ return (EINVAL);
+}
+
+static int
+smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
+{
+ struct t_optmgmt oreq, ores;
+ struct {
+ struct T_opthdr oh;
+ int ival;
+ } opts;
struct nbpcb *nbp = vcp->vc_tdata;
+ int level, name, err;
switch (param) {
- case SMBTP_SNDSZ:
- *(int *)data = nbp->nbp_sndbuf;
+ case SMBTP_TCP_NODELAY:
+ level = IPPROTO_TCP;
+ name = TCP_NODELAY;
break;
- case SMBTP_RCVSZ:
- *(int *)data = nbp->nbp_rcvbuf;
- break;
- case SMBTP_TIMEOUT:
- *(struct timespec *)data = nbp->nbp_timo;
- break;
-#ifdef SMBTP_SELECTID
- case SMBTP_SELECTID:
- *(void **)data = nbp->nbp_selectid;
+
+ case SMBTP_TCP_CON_TMO: /* int mSec */
+ level = IPPROTO_TCP;
+ name = TCP_CONN_ABORT_THRESHOLD;
break;
-#endif
-#ifdef SMBTP_UPCALL
- case SMBTP_UPCALL:
- *(void **)data = nbp->nbp_upcall;
+
+ case SMBTP_KEEPALIVE: // SO_KEEPALIVE
+ case SMBTP_SNDBUF: // SO_SNDBUF
+ case SMBTP_RCVBUF: // SO_RCVBUF
+ case SMBTP_RCVTIMEO: // SO_RCVTIMEO
+ level = SOL_SOCKET;
+ name = param;
break;
-#endif
+
default:
return (EINVAL);
}
- return (0);
-}
-/*ARGSUSED*/
-static int
-smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
-{
- return (EINVAL);
+ /* opt header */
+ opts.oh.len = sizeof (opts);
+ opts.oh.level = level;
+ opts.oh.name = name;
+ opts.oh.status = 0;
+ opts.ival = *(int *)data;
+
+ oreq.flags = T_NEGOTIATE;
+ oreq.opt.buf = (void *)&opts;
+ oreq.opt.len = sizeof (opts);
+ oreq.opt.maxlen = oreq.opt.len;
+
+ ores.flags = 0;
+ ores.opt.buf = NULL;
+ ores.opt.len = 0;
+ ores.opt.maxlen = 0;
+
+ err = t_koptmgmt(nbp->nbp_tiptr, &oreq, &ores);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "t_opgmgnt, err = %d", err);
+ return (EPROTO);
+ }
+
+ 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);
+ return (EPROTO);
+ }
+
+ return (0);
}
/*
@@ -893,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_trantcp.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h
index f810a538cd..3c5e86639e 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h
@@ -32,13 +32,14 @@
* $Id: smb_trantcp.h,v 1.8 2004/08/03 23:50:01 lindak Exp $
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_TRANTCP_H_
#define _NETSMB_SMB_TRANTCP_H_
enum nbstate {
NBST_CLOSED,
+ NBST_IDLE,
NBST_RQSENT,
NBST_SESSION,
NBST_RETARGET,
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 fb587cd79e..d83c3a086c 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.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>
@@ -52,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>
@@ -61,28 +63,6 @@
static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg);
/*
- * Ioctl function for SMBIOC_FLAGS2
- */
-int
-smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags)
-{
- struct smb_vc *vcp = NULL;
-
- /* This ioctl requires a session. */
- if ((vcp = sdp->sd_vc) == NULL)
- return (ENOTCONN);
-
- /*
- * Return the flags2 value.
- */
- if (ddi_copyout(&vcp->vc_hflags2, (void *)arg,
- sizeof (u_int16_t), flags))
- return (EFAULT);
-
- return (0);
-}
-
-/*
* Ioctl function for SMBIOC_GETSSNKEY
* Size copied out is SMBIOC_HASH_SZ.
*
@@ -105,7 +85,10 @@ smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
/*
* Return the session key.
*/
- if (ddi_copyout(vcp->vc_ssn_key, (void *)arg,
+ if (vcp->vc_ssnkey == NULL ||
+ vcp->vc_ssnkeylen < SMBIOC_HASH_SZ)
+ return (EINVAL);
+ if (ddi_copyout(vcp->vc_ssnkey, (void *)arg,
SMBIOC_HASH_SZ, flags))
return (EFAULT);
@@ -113,224 +96,90 @@ smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
}
/*
- * Ioctl function for SMBIOC_REQUEST
+ * Ioctl function for SMBIOC_XACTNP (transact named pipe)
*/
int
-smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
+smb_usr_xnp(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
{
struct smb_cred scred;
struct smb_share *ssp;
- smbioc_rq_t *ioc = NULL;
- struct smb_rq *rqp = NULL;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint32_t rsz;
+ struct smb_fh *fhp;
+ smbioc_xnp_t *ioc = NULL;
+ 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);
-
- 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;
-
- /*
- * Lots of SMB commands could be safe, but
- * these are the only ones used by libsmbfs.
- */
- switch (ioc->ioc_cmd) {
- /* These are OK */
- case SMB_COM_CLOSE:
- case SMB_COM_FLUSH:
- case SMB_COM_NT_CREATE_ANDX:
- case SMB_COM_OPEN_PRINT_FILE:
- case SMB_COM_CLOSE_PRINT_FILE:
- break;
-
- default:
- err = EPERM;
- goto out;
- }
-
- err = smb_rq_alloc(SSTOCP(ssp), ioc->ioc_cmd, &scred, &rqp);
- if (err)
- goto out;
-
- mbp = &rqp->sr_rq;
- err = mb_put_mem(mbp, ioc->ioc_tbuf, ioc->ioc_tbufsz, mbseg);
-
- err = smb_rq_simple(rqp);
- if (err == 0) {
- /*
- * This may have been an open, so save the
- * generation ID of the share, which we
- * check before trying read or write.
- */
- sdp->sd_vcgenid = ssp->ss_vcgenid;
-
- /*
- * Have reply data. to copyout.
- * SMB header already parsed.
- */
- mdp = &rqp->sr_rp;
- rsz = msgdsize(mdp->md_top) - SMB_HDRLEN;
- if (ioc->ioc_rbufsz < rsz) {
- err = EOVERFLOW;
- goto out;
- }
- ioc->ioc_rbufsz = rsz;
- err = md_get_mem(mdp, ioc->ioc_rbuf, rsz, mbseg);
- if (err)
- goto out;
-
- }
-
- ioc->ioc_errclass = rqp->sr_errclass;
- ioc->ioc_serror = rqp->sr_serror;
- ioc->ioc_error = rqp->sr_error;
- (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
-
-out:
- if (rqp != NULL)
- smb_rq_done(rqp); /* free rqp */
- kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
-
- return (err);
-
-}
+ /* This ioctl requires a file handle. */
+ if ((fhp = sdp->sd_fh) == NULL)
+ return (EINVAL);
+ ssp = FHTOSS(fhp);
-/*
- * Ioctl function for SMBIOC_T2RQ
- */
-int
-smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
-{
- struct smb_cred scred;
- struct smb_share *ssp;
- smbioc_t2rq_t *ioc = NULL;
- struct smb_t2rq *t2p = NULL;
- struct mdchain *mdp;
- int err, len, mbseg;
+ /* After reconnect, force close+reopen */
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
- /* This ioctl requires a share. */
- if ((ssp = sdp->sd_share) == NULL)
- return (ENOTCONN);
+ 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 */
+ /*
+ * Copyin the send data, into an mbchain,
+ * save output buffer size.
+ */
mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
-
- if (ioc->ioc_setupcnt > SMBIOC_T2RQ_MAXSETUP) {
- err = EINVAL;
+ err = smb_cpdatain(&send_mb, ioc->ioc_tdlen, ioc->ioc_tdata, mbseg);
+ if (err)
goto out;
- }
+ rdlen = ioc->ioc_rdlen;
/*
- * Fill in the FID for libsmbfs transact named pipe.
+ * Run the SMB2 ioctl or SMB1 trans2
*/
- if (ioc->ioc_setupcnt > 1 && ioc->ioc_setup[1] == 0xFFFF) {
- if (sdp->sd_vcgenid != ssp->ss_vcgenid) {
- err = ESTALE;
- goto out;
- }
- ioc->ioc_setup[1] = (uint16_t)sdp->sd_smbfid;
- }
-
- t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
- err = smb_t2_init(t2p, SSTOCP(ssp),
- ioc->ioc_setup, ioc->ioc_setupcnt, &scred);
- if (err)
- goto out;
- t2p->t2_setupcount = ioc->ioc_setupcnt;
- t2p->t2_setupdata = ioc->ioc_setup;
-
- /* This ioc member is a fixed-size array. */
- if (ioc->ioc_name[0]) {
- /* Get the name length - carefully! */
- ioc->ioc_name[SMBIOC_T2RQ_MAXNAME-1] = '\0';
- t2p->t_name_len = strlen(ioc->ioc_name);
- t2p->t_name = ioc->ioc_name;
+ 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);
}
- t2p->t2_maxscount = 0;
- t2p->t2_maxpcount = ioc->ioc_rparamcnt;
- t2p->t2_maxdcount = ioc->ioc_rdatacnt;
-
- /* Transmit parameters */
- err = smb_cpdatain(&t2p->t2_tparam,
- ioc->ioc_tparamcnt, ioc->ioc_tparam, mbseg);
- if (err)
- goto out;
-
- /* Transmit data */
- err = smb_cpdatain(&t2p->t2_tdata,
- ioc->ioc_tdatacnt, ioc->ioc_tdata, mbseg);
- if (err)
- goto out;
-
- err = smb_t2_request(t2p);
-
- /* Copyout returned parameters. */
- mdp = &t2p->t2_rparam;
- if (err == 0 && mdp->md_top != NULL) {
- /* User's buffer large enough? */
- len = m_fixhdr(mdp->md_top);
- if (len > ioc->ioc_rparamcnt) {
- err = EMSGSIZE;
- goto out;
- }
- ioc->ioc_rparamcnt = (ushort_t)len;
- err = md_get_mem(mdp, ioc->ioc_rparam, len, mbseg);
- if (err)
- goto out;
- } else
- ioc->ioc_rparamcnt = 0;
+ 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 (len > ioc->ioc_rdatacnt) {
+ 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_rdatacnt = (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_rdatacnt = 0;
+ ioc->ioc_rdlen = 0;
- ioc->ioc_errclass = t2p->t2_sr_errclass;
- ioc->ioc_serror = t2p->t2_sr_serror;
- ioc->ioc_error = t2p->t2_sr_error;
- ioc->ioc_rpflags2 = t2p->t2_sr_rpflags2;
+ /* 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);
}
@@ -358,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;
@@ -392,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;
@@ -412,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
@@ -424,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);
}
@@ -439,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;
@@ -468,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,
@@ -478,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);
@@ -502,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)
@@ -516,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);
@@ -526,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);
}
@@ -549,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;
+ struct smb_fh *fhp;
- /* 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);
+ sdp->sd_fh = NULL;
- if (sdp->sd_smbfid == -1)
- return (0);
- fid = (uint16_t)sdp->sd_smbfid;
- sdp->sd_smbfid = -1;
+ smb_fh_close(fhp);
+ smb_fh_rele(fhp);
- 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);
-
- return (err);
+ return (0);
}
/*
@@ -825,24 +720,22 @@ smb_usr_drop_tree(smb_dev_t *sdp, int cmd)
return (0);
}
-
/*
- * Ioctl function: SMBIOC_IOD_WORK
- *
- * Become the reader (IOD) thread, until either the connection is
- * reset by the server, or until the connection is idle longer than
- * some max time. (max idle time not yet implemented)
+ * Ioctl handler for all SMBIOC_IOD_...
*/
int
-smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
+smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
{
- struct smb_vc *vcp = NULL;
+ struct smb_vc *vcp;
int err = 0;
- /* Must have a valid session. */
+ /* Must be the IOD. */
+ if ((sdp->sd_flags & NSMBFL_IOD) == 0)
+ return (EINVAL);
+ /* Must have a VC and no share. */
if ((vcp = sdp->sd_vc) == NULL)
return (EINVAL);
- if (vcp->vc_flags & SMBV_GONE)
+ if (sdp->sd_share != NULL)
return (EINVAL);
/*
@@ -859,39 +752,53 @@ smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
return (err);
/*
- * Copy the "work" state, etc. into the VC
- * The MAC key is copied separately.
+ * Copy the "work" state, etc. into the VC,
+ * and back to the caller on the way out.
+ * Clear the "out only" part.
*/
if (ddi_copyin((void *)arg, &vcp->vc_work,
sizeof (smbioc_ssn_work_t), flags)) {
err = EFAULT;
goto out;
}
- if (vcp->vc_u_maclen) {
- vcp->vc_mackeylen = vcp->vc_u_maclen;
- vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP);
- if (ddi_copyin(vcp->vc_u_mackey.lp_ptr, vcp->vc_mackey,
- vcp->vc_mackeylen, flags)) {
- err = EFAULT;
- goto out;
- }
- }
+ vcp->vc_work.wk_out_state = 0;
- err = smb_iod_vc_work(vcp, cr);
+ switch (cmd) {
- /* Caller wants state here. */
- vcp->vc_work.wk_out_state = vcp->vc_state;
+ case SMBIOC_IOD_CONNECT:
+ err = nsmb_iod_connect(vcp, cr);
+ break;
- (void) ddi_copyout(&vcp->vc_work, (void *)arg,
- sizeof (smbioc_ssn_work_t), flags);
+ case SMBIOC_IOD_NEGOTIATE:
+ err = nsmb_iod_negotiate(vcp, cr);
+ break;
-out:
- if (vcp->vc_mackey) {
- kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
- vcp->vc_mackey = NULL;
- vcp->vc_mackeylen = 0;
+ case SMBIOC_IOD_SSNSETUP:
+ err = nsmb_iod_ssnsetup(vcp, cr);
+ break;
+
+ case SMBIOC_IOD_WORK:
+ err = smb_iod_vc_work(vcp, flags, cr);
+ break;
+
+ case SMBIOC_IOD_IDLE:
+ err = smb_iod_vc_idle(vcp);
+ break;
+
+ case SMBIOC_IOD_RCFAIL:
+ err = smb_iod_vc_rcfail(vcp);
+ break;
+
+ default:
+ err = ENOTTY;
+ break;
}
+out:
+ vcp->vc_work.wk_out_state = vcp->vc_state;
+ (void) ddi_copyout(&vcp->vc_work, (void *)arg,
+ sizeof (smbioc_ssn_work_t), flags);
+
/*
* The IOD thread is leaving the driver. Clear iod_thr,
* and wake up anybody waiting for us to quit.
@@ -904,67 +811,104 @@ out:
return (err);
}
-/*
- * Ioctl functions: SMBIOC_IOD_IDLE, SMBIOC_IOD_RCFAIL
- *
- * Wait for user-level requests to be enqueued on this session,
- * and then return to the user-space helper, which will then
- * initiate a reconnect, etc.
- */
int
-smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags)
+smb_usr_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
{
- struct smb_vc *vcp = NULL;
- int err = 0;
-
- /* Must have a valid session. */
- if ((vcp = sdp->sd_vc) == NULL)
- return (EINVAL);
- if (vcp->vc_flags & SMBV_GONE)
- return (EINVAL);
+ int err;
/*
- * Is there already an IOD for this VC?
- * (Should never happen.)
+ * Serialize ioctl calls. The smb_usr_... functions
+ * don't expect concurrent calls on a given sdp.
*/
- SMB_VC_LOCK(vcp);
- if (vcp->iod_thr == NULL)
- vcp->iod_thr = curthread;
- else
- err = EEXIST;
- SMB_VC_UNLOCK(vcp);
- if (err)
- return (err);
-
- /* nothing to copyin */
+ mutex_enter(&sdp->sd_lock);
+ if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
+ mutex_exit(&sdp->sd_lock);
+ return (EBUSY);
+ }
+ sdp->sd_flags |= NSMBFL_IOCTL;
+ mutex_exit(&sdp->sd_lock);
+ err = 0;
switch (cmd) {
- case SMBIOC_IOD_IDLE:
- err = smb_iod_vc_idle(vcp);
+ case SMBIOC_GETVERS:
+ (void) ddi_copyout(&nsmb_version, (void *)arg,
+ sizeof (nsmb_version), flags);
+ break;
+
+ case SMBIOC_GETSSNKEY:
+ err = smb_usr_get_ssnkey(sdp, arg, flags);
+ break;
+
+ case SMBIOC_DUP_DEV:
+ err = smb_usr_dup_dev(sdp, arg, flags);
+ break;
+
+ case SMBIOC_XACTNP:
+ err = smb_usr_xnp(sdp, arg, flags, cr);
break;
+ case SMBIOC_READ:
+ case SMBIOC_WRITE:
+ err = smb_usr_rw(sdp, cmd, arg, flags, cr);
+ break;
+
+ case SMBIOC_NTCREATE:
+ err = smb_usr_ntcreate(sdp, arg, flags, cr);
+ break;
+
+ case SMBIOC_PRINTJOB:
+ err = smb_usr_printjob(sdp, arg, flags, cr);
+ break;
+
+ case SMBIOC_CLOSEFH:
+ err = smb_usr_closefh(sdp, cr);
+ break;
+
+ case SMBIOC_SSN_CREATE:
+ case SMBIOC_SSN_FIND:
+ err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
+ break;
+
+ case SMBIOC_SSN_KILL:
+ case SMBIOC_SSN_RELE:
+ err = smb_usr_drop_ssn(sdp, cmd);
+ break;
+
+ case SMBIOC_TREE_CONNECT:
+ case SMBIOC_TREE_FIND:
+ err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
+ break;
+
+ case SMBIOC_TREE_KILL:
+ case SMBIOC_TREE_RELE:
+ err = smb_usr_drop_tree(sdp, cmd);
+ break;
+
+ case SMBIOC_IOD_CONNECT:
+ case SMBIOC_IOD_NEGOTIATE:
+ case SMBIOC_IOD_SSNSETUP:
+ case SMBIOC_IOD_WORK:
+ case SMBIOC_IOD_IDLE:
case SMBIOC_IOD_RCFAIL:
- err = smb_iod_vc_rcfail(vcp);
+ err = smb_usr_iod_ioctl(sdp, cmd, arg, flags, cr);
+ break;
+
+ case SMBIOC_PK_ADD:
+ case SMBIOC_PK_DEL:
+ case SMBIOC_PK_CHK:
+ case SMBIOC_PK_DEL_OWNER:
+ case SMBIOC_PK_DEL_EVERYONE:
+ err = smb_pkey_ioctl(cmd, arg, flags, cr);
break;
default:
err = ENOTTY;
- goto out;
+ break;
}
- /* Both of these ioctls copy out the new state. */
- (void) ddi_copyout(&vcp->vc_state, (void *)arg,
- sizeof (int), flags);
-
-out:
- /*
- * The IOD thread is leaving the driver. Clear iod_thr,
- * and wake up anybody waiting for us to quit.
- */
- SMB_VC_LOCK(vcp);
- vcp->iod_thr = NULL;
- cv_broadcast(&vcp->vc_statechg);
- SMB_VC_UNLOCK(vcp);
+ mutex_enter(&sdp->sd_lock);
+ sdp->sd_flags &= ~NSMBFL_IOCTL;
+ mutex_exit(&sdp->sd_lock);
return (err);
}
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 44319e6682..41a6f41a2b 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
@@ -24,6 +24,8 @@
*
* Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
* All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -60,6 +62,7 @@
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
+#ifdef _KERNEL
#include <vm/hat.h>
#include <vm/as.h>
#include <vm/page.h>
@@ -67,6 +70,7 @@
#include <vm/seg.h>
#include <vm/seg_map.h>
#include <vm/seg_vn.h>
+#endif // _KERNEL
#define ATTRCACHE_VALID(vp) (gethrtime() < VTOSMB(vp)->r_attrtime)
@@ -394,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)
@@ -412,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);
@@ -816,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.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c
index 5bbbae860e..163a5a4504 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c
@@ -35,11 +35,14 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/cred.h>
+#include <sys/errno.h>
#include <sys/time.h>
#include <sys/vfs.h>
#include <sys/vnode.h>
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 db920f21b8..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,18 +28,18 @@
* 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 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>
#include <sys/systm.h>
+#include <sys/inttypes.h>
#include <sys/time.h>
#include <sys/vnode.h>
#include <sys/sunddi.h>
@@ -48,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>
@@ -62,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);
}
/*
@@ -442,652 +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_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_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);
-}
-
-/*
- * 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".
- */
-
-/*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_fs_size_info info;
struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- int32_t *ucslenp;
+ uint32_t bps, spu;
int error;
- 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 (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);
- mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
- mb_put_uint16le(mbp, 0); /* reserved, nowadays */
-
- mbp = &t2p->t2_tdata;
- mb_init(mbp);
- mb_put_uint32le(mbp, overwrite); /* one or zero */
- mb_put_uint32le(mbp, 0); /* obsolete target dir fid */
+ /* 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;
- 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);
+ /* preferred file system block size */
+ sbp->f_bsize = bps * spu;
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
-out:
- smb_t2_done(t2p);
- return (error);
-}
+ /* file system block size ("fragment size") */
+ sbp->f_frsize = bps;
-int
-smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp)
-{
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- int error;
+ /* total blocks of f_frsize */
+ sbp->f_blocks = info.total_units * spu;
- /* Shared lock for n_fid use below. */
- ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+ /* free blocks of f_frsize */
+ sbp->f_bfree = info.actual_avail * spu;
- if (!(np->n_flag & NFLUSHWIRE))
- return (0);
- if (np->n_fidrefs == 0)
- return (0); /* not open */
+ /* free blocks avail to non-superuser */
+ sbp->f_bavail = info.caller_avail * spu;
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- return (ESTALE);
+ sbp->f_files = (-1); /* total file nodes in file system */
+ sbp->f_ffree = (-1); /* free file nodes in fs */
- 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)
+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;
+ 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) {
@@ -1097,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) &&
@@ -1106,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(
@@ -1132,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 */
{
@@ -1153,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);
@@ -1161,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
@@ -1398,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
@@ -1526,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;
@@ -2287,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);
@@ -2338,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.
@@ -2349,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);
}
@@ -2367,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);
@@ -2376,7 +685,11 @@ smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
case ft_XA:
error = smbfs_xa_findclose(ctx);
break;
+ default:
+ error = ENOSYS;
+ break;
}
+ ctx->f_scred = NULL;
if (ctx->f_rname)
kmem_free(ctx->f_rname, ctx->f_rnamelen);
if (ctx->f_firstnm)
@@ -2416,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)
@@ -2468,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.
@@ -2617,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 798c26a09b..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,6 +27,7 @@
*/
/*
* Copyright (c) 2017 by Delphix. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -39,7 +40,9 @@
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/vnode.h>
+#include <sys/atomic.h>
#include <sys/bitmap.h>
+#include <sys/buf.h>
#include <sys/dnlc.h>
#include <sys/kmem.h>
#include <sys/sunddi.h>
@@ -430,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." */
@@ -1231,7 +1234,7 @@ smbfs_subrinit(void)
nsmbnode_max = (ulong_t)((kmem_maxavail() >> 2) /
sizeof (struct smbnode));
if (nsmbnode > nsmbnode_max || (nsmbnode == 0 && ncsize == 0)) {
- zcmn_err(GLOBAL_ZONEID, CE_NOTE,
+ cmn_err(CE_NOTE,
"setting nsmbnode to max value of %ld", nsmbnode_max);
nsmbnode = nsmbnode_max;
}
@@ -1249,7 +1252,7 @@ smbfs_subrinit(void)
* Assign unique major number for all smbfs mounts
*/
if ((smbfs_major = getudev()) == -1) {
- zcmn_err(GLOBAL_ZONEID, CE_WARN,
+ cmn_err(CE_WARN,
"smbfs: init: can't get unique device number");
smbfs_major = 0;
}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c
index 0122d52115..7dad8d2a70 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c
@@ -34,9 +34,9 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/systm.h>
@@ -76,6 +76,17 @@
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
+#ifndef _KERNEL
+
+#include <libfksmbfs.h>
+
+#define STRUCT_DECL(s, a) struct s a
+#define STRUCT_FGET(handle, field) ((handle).field)
+#define _init(v) fksmbfs_init(v)
+#define _fini(v) fksmbfs_fini(v)
+
+#endif /* !_KERNEL */
+
/*
* Should smbfs mount enable "-o acl" by default? There are good
* arguments for both. The most common use case is individual users
@@ -98,7 +109,10 @@ int smbfs_tq_nthread = 1;
*/
int smbfsinit(int fstyp, char *name);
void smbfsfini();
+
+#ifdef _KERNEL
static int smbfs_mount_label_policy(vfs_t *, void *, int, cred_t *);
+#endif /* _KERNEL */
/*
* SMBFS Mount options table for MS_OPTIONSTR
@@ -123,7 +137,11 @@ static mntopt_t mntopts[] = {
{ MNTOPT_ACL, acl_cancel, NULL, 0, 0 },
{ MNTOPT_NOACL, noacl_cancel, NULL, 0, 0 },
{ MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, 0 },
- { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 0 }
+ { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 0 },
+#ifndef _KERNEL
+ /* See vfs_optionisset MNTOPT_NOAC below. */
+ { MNTOPT_NOAC, NULL, NULL, 0, 0 },
+#endif /* !_KERNEL */
};
static mntopts_t smbfs_mntopts = {
@@ -141,6 +159,7 @@ static vfsdef_t vfw = {
&smbfs_mntopts /* mount options table prototype */
};
+#ifdef _KERNEL
static struct modlfs modlfs = {
&mod_fsops,
"SMBFS filesystem",
@@ -150,6 +169,7 @@ static struct modlfs modlfs = {
static struct modlinkage modlinkage = {
MODREV_1, (void *)&modlfs, NULL
};
+#endif /* _KERNEL */
/*
* Mutex to protect the following variables:
@@ -222,7 +242,12 @@ _init(void)
return (error);
}
+#ifdef _KERNEL
error = mod_install((struct modlinkage *)&modlinkage);
+#else /* _KERNEL */
+ error = fake_installfs(&vfw);
+#endif /* _KERNEL */
+
return (error);
}
@@ -244,7 +269,11 @@ _fini(void)
if (smbfs_mountcount)
return (EBUSY);
+#ifdef _KERNEL
error = mod_remove(&modlinkage);
+#else /* _KERNEL */
+ error = fake_removefs(&vfw);
+#endif /* _KERNEL */
if (error)
return (error);
@@ -267,17 +296,19 @@ _fini(void)
/*
* Return information about the module
*/
+#ifdef _KERNEL
int
_info(struct modinfo *modinfop)
{
return (mod_info((struct modlinkage *)&modlinkage, modinfop));
}
+#endif /* _KERNEL */
/*
* Initialize the vfs structure
*/
-int smbfsfstyp;
+int smbfs_fstyp;
vfsops_t *smbfs_vfsops = NULL;
static const fs_operation_def_t smbfs_vfsops_template[] = {
@@ -292,6 +323,10 @@ static const fs_operation_def_t smbfs_vfsops_template[] = {
{ NULL, NULL }
};
+/*
+ * This is the VFS switch initialization routine, normally called
+ * via vfssw[x].vsw_init by vfsinit() or mod_install
+ */
int
smbfsinit(int fstyp, char *name)
{
@@ -299,7 +334,7 @@ smbfsinit(int fstyp, char *name)
error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops);
if (error != 0) {
- zcmn_err(GLOBAL_ZONEID, CE_WARN,
+ cmn_err(CE_WARN,
"smbfsinit: bad vfs ops template");
return (error);
}
@@ -307,12 +342,12 @@ smbfsinit(int fstyp, char *name)
error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops);
if (error != 0) {
(void) vfs_freevfsops_by_type(fstyp);
- zcmn_err(GLOBAL_ZONEID, CE_WARN,
+ cmn_err(CE_WARN,
"smbfsinit: bad vnode ops template");
return (error);
}
- smbfsfstyp = fstyp;
+ smbfs_fstyp = fstyp;
return (0);
}
@@ -321,7 +356,7 @@ void
smbfsfini()
{
if (smbfs_vfsops) {
- (void) vfs_freevfsops_by_type(smbfsfstyp);
+ (void) vfs_freevfsops_by_type(smbfs_fstyp);
smbfs_vfsops = NULL;
}
if (smbfs_vnodeops) {
@@ -336,8 +371,10 @@ smbfs_free_smi(smbmntinfo_t *smi)
if (smi == NULL)
return;
+#ifdef _KERNEL
if (smi->smi_zone_ref.zref_zone != NULL)
zone_rele_ref(&smi->smi_zone_ref, ZONE_REF_SMBFS);
+#endif /* _KERNEL */
if (smi->smi_share != NULL)
smb_share_rele(smi->smi_share);
@@ -364,16 +401,21 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
dev_t smbfs_dev;
int version;
int devfd;
- zone_t *zone = curproc->p_zone;
+ zone_t *zone = curzone;
+#ifdef _KERNEL
zone_t *mntzone = NULL;
+#else /* _KERNEL */
+ short minclsyspri = MINCLSYSPRI;
+#endif /* _KERNEL */
smb_share_t *ssp = NULL;
smb_cred_t scred;
int flags, sec;
-
STRUCT_DECL(smbfs_args, args); /* smbfs mount arguments */
+#ifdef _KERNEL
if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
return (error);
+#endif /* _KERNEL */
if (mvp->v_type != VDIR)
return (ENOTDIR);
@@ -384,11 +426,17 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
* uap->datalen might be different from sizeof (args)
* in a compatible situation.
*/
+#ifdef _KERNEL
STRUCT_INIT(args, get_udatamodel());
bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE));
if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen,
SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE))))
return (EFAULT);
+#else /* _KERNEL */
+ bzero(&args, sizeof (args));
+ if (copyin(data, &args, MIN(uap->datalen, sizeof (args))))
+ return (EFAULT);
+#endif /* _KERNEL */
/*
* Check mount program version
@@ -439,6 +487,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
* See: ssp, smi, rtnp, mntzone
*/
+#ifdef _KERNEL
/*
* Determine the zone we're being mounted into.
*/
@@ -482,6 +531,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
}
}
+#endif /* _KERNEL */
/* Prevent unload. */
atomic_inc_32(&smbfs_mountcount);
@@ -504,6 +554,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
smi->smi_share = ssp;
ssp = NULL;
+#ifdef _KERNEL
/*
* Convert the anonymous zone hold acquired via zone_hold() above
* into a zone reference.
@@ -512,15 +563,22 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
zone_hold_ref(mntzone, &smi->smi_zone_ref, ZONE_REF_SMBFS);
zone_rele(mntzone);
mntzone = NULL;
+#else /* _KERNEL */
+ smi->smi_zone_ref.zref_zone = curzone;
+#endif /* _KERNEL */
/*
* Initialize option defaults
*/
- smi->smi_flags = SMI_LLOCK;
smi->smi_acregmin = SEC2HR(SMBFS_ACREGMIN);
smi->smi_acregmax = SEC2HR(SMBFS_ACREGMAX);
smi->smi_acdirmin = SEC2HR(SMBFS_ACDIRMIN);
smi->smi_acdirmax = SEC2HR(SMBFS_ACDIRMAX);
+ smi->smi_flags = SMI_LLOCK;
+#ifndef _KERNEL
+ /* Always direct IO with fakekernel */
+ smi->smi_flags |= SMI_DIRECTIO;
+#endif /* _KERNEL */
/*
* All "generic" mount options have already been
@@ -541,10 +599,30 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
* starting with args.flags (SMBFS_MF_xxx)
*/
flags = STRUCT_FGET(args, flags);
- smi->smi_uid = STRUCT_FGET(args, uid);
- smi->smi_gid = STRUCT_FGET(args, gid);
smi->smi_fmode = STRUCT_FGET(args, file_mode) & 0777;
smi->smi_dmode = STRUCT_FGET(args, dir_mode) & 0777;
+#ifdef _KERNEL
+ smi->smi_uid = STRUCT_FGET(args, uid);
+ smi->smi_gid = STRUCT_FGET(args, gid);
+#else /* _KERNEL */
+ /*
+ * Need uid/gid to match our fake cred we'll fail in
+ * smbfs_access_rwx later.
+ */
+ smi->smi_uid = crgetuid(cr);
+ smi->smi_gid = crgetgid(cr);
+
+ /*
+ * Our user-level do_mount() passes the mount options sting
+ * as-is, where the real mount program would convert some
+ * of those options to bits set in smbfs_args.flags.
+ * To avoid replicating all that conversion code, this
+ * uses the generic vfs option support to handle those
+ * option flag bits we need, i.e.: "noac"
+ */
+ if (vfs_optionisset(vfsp, MNTOPT_NOAC, NULL))
+ flags |= SMBFS_MF_NOAC;
+#endif /* _KERNEL */
/*
* Hande the SMBFS_MF_xxx flags.
@@ -615,9 +693,9 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
mutex_exit(&smbfs_minor_lock);
vfsp->vfs_dev = smbfs_dev;
- vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfsfstyp);
+ vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfs_fstyp);
vfsp->vfs_data = (caddr_t)smi;
- vfsp->vfs_fstype = smbfsfstyp;
+ vfsp->vfs_fstype = smbfs_fstyp;
vfsp->vfs_bsize = MAXBSIZE;
vfsp->vfs_bcount = 0;
@@ -657,6 +735,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
*/
return (0);
+#ifdef _KERNEL
errout:
vfsp->vfs_data = NULL;
if (smi != NULL)
@@ -669,6 +748,7 @@ errout:
smb_share_rele(ssp);
return (error);
+#endif /* _KERNEL */
}
/*
@@ -682,8 +762,10 @@ smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
smi = VFTOSMI(vfsp);
+#ifdef _KERNEL
if (secpolicy_fs_unmount(cr, vfsp) != 0)
return (EPERM);
+#endif /* _KERNEL */
if ((flag & MS_FORCE) == 0) {
smbfs_rflush(vfsp, cr);
@@ -976,6 +1058,7 @@ smbfs_freevfs(vfs_t *vfsp)
atomic_dec_32(&smbfs_mountcount);
}
+#ifdef _KERNEL
/*
* smbfs_mount_label_policy:
* Determine whether the mount is allowed according to MAC check,
@@ -1066,3 +1149,4 @@ out:
label_rele(zlabel);
return (retv);
}
+#endif /* _KERNEL */
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 23c9f8f15d..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,6 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -60,8 +61,9 @@
#include <sys/sdt.h>
#include <sys/taskq_impl.h>
#include <sys/zone.h>
-#include <sys/vmsystm.h>
+#ifdef _KERNEL
+#include <sys/vmsystm.h> // for desfree
#include <vm/hat.h>
#include <vm/as.h>
#include <vm/page.h>
@@ -70,6 +72,7 @@
#include <vm/seg_map.h>
#include <vm/seg_kpm.h>
#include <vm/seg_vn.h>
+#endif // _KERNEL
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
@@ -83,6 +86,10 @@
#include <sys/fs/smbfs_ioctl.h>
#include <fs/fs_subr.h>
+#ifndef MAXOFF32_T
+#define MAXOFF32_T 0x7fffffff
+#endif
+
/*
* We assign directory offsets like the NFS client, where the
* offset increments by _one_ after each directory entry.
@@ -137,18 +144,15 @@ 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 *);
-static int smbfs_rdwrlbn(vnode_t *, page_t *, u_offset_t, size_t, int,
- cred_t *);
-static int smbfs_bio(struct buf *, int, cred_t *);
-static int smbfs_writenp(smbnode_t *np, caddr_t base, int tcount,
- struct uio *uiop, int pgcreated);
-
static int smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+
static int smbfs_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
caller_context_t *);
+#ifdef _KERNEL
static int smbfs_getapage(vnode_t *, u_offset_t, size_t, uint_t *,
page_t *[], size_t, struct seg *, caddr_t,
enum seg_rw, cred_t *);
@@ -156,6 +160,13 @@ static int smbfs_putapage(vnode_t *, page_t *, u_offset_t *, size_t *,
int, cred_t *);
static void smbfs_delmap_async(void *);
+static int smbfs_rdwrlbn(vnode_t *, page_t *, u_offset_t, size_t, int,
+ cred_t *);
+static int smbfs_bio(struct buf *, int, cred_t *);
+static int smbfs_writenp(smbnode_t *np, caddr_t base, int tcount,
+ struct uio *uiop, int pgcreated);
+#endif // _KERNEL
+
/*
* Error flags used to pass information about certain special errors
* which need to be handled specially.
@@ -191,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;
@@ -270,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) {
/*
@@ -286,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
@@ -306,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);
@@ -315,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.
@@ -478,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. */
@@ -513,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;
@@ -557,20 +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;
- caddr_t base;
- u_offset_t off;
- size_t n;
- int on;
- uint_t flags;
-
np = VTOSMB(vp);
smi = VTOSMI(vp);
- ssp = smi->smi_share;
if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
return (EIO);
@@ -632,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);
@@ -648,8 +628,15 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
return (error);
}
+#ifdef _KERNEL
/* (else) Do I/O through segmap. */
do {
+ caddr_t base;
+ u_offset_t off;
+ size_t n;
+ int on;
+ uint_t flags;
+
off = uiop->uio_loffset & MAXBMASK; /* mapping offset */
on = uiop->uio_loffset & MAXBOFFSET; /* Relative offset */
n = MIN(MAXBSIZE - on, uiop->uio_resid);
@@ -698,6 +685,9 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
}
}
} while (!error && uiop->uio_resid > 0);
+#else // _KERNEL
+ error = ENOSYS;
+#endif // _KERNEL
/* undo adjustment of resid */
uiop->uio_resid += past_eof;
@@ -715,22 +705,17 @@ 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;
- caddr_t base;
- u_offset_t off;
- size_t n;
- int on;
- uint_t flags;
u_offset_t last_off;
size_t last_resid;
+#ifdef _KERNEL
uint_t bsize;
+#endif
np = VTOSMB(vp);
smi = VTOSMI(vp);
- ssp = smi->smi_share;
if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
return (EIO);
@@ -789,12 +774,14 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
limit = MAXOFFSET_T;
if (uiop->uio_loffset >= limit) {
+#ifdef _KERNEL
proc_t *p = ttoproc(curthread);
mutex_enter(&p->p_lock);
(void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE],
p->p_rctls, p, RCA_UNSAFE_SIGINFO);
mutex_exit(&p->p_lock);
+#endif // _KERNEL
return (EFBIG);
}
if (endoff > limit) {
@@ -813,7 +800,9 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
np->r_mapcnt == 0 && np->r_inmap == 0 &&
!vn_has_cached_data(vp))) {
+#ifdef _KERNEL
smbfs_fwrite:
+#endif // _KERNEL
if (np->r_flags & RSTALE) {
last_resid = uiop->uio_resid;
last_off = uiop->uio_loffset;
@@ -837,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);
@@ -852,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);
}
}
@@ -865,10 +850,17 @@ smbfs_fwrite:
return (error);
}
+#ifdef _KERNEL
/* (else) Do I/O through segmap. */
bsize = vp->v_vfsp->vfs_bsize;
do {
+ caddr_t base;
+ u_offset_t off;
+ size_t n;
+ int on;
+ uint_t flags;
+
off = uiop->uio_loffset & MAXBMASK; /* mapping offset */
on = uiop->uio_loffset & MAXBOFFSET; /* Relative offset */
n = MIN(MAXBSIZE - on, uiop->uio_resid);
@@ -993,6 +985,11 @@ smbfs_fwrite:
goto smbfs_fwrite;
}
} while (!error && uiop->uio_resid > 0);
+#else // _KERNEL
+ last_resid = uiop->uio_resid;
+ last_off = uiop->uio_loffset;
+ error = ENOSYS;
+#endif // _KERNEL
bottom:
/* undo adjustment of resid */
@@ -1006,6 +1003,8 @@ bottom:
return (error);
}
+#ifdef _KERNEL
+
/*
* Like nfs_client.c: writerp()
*
@@ -1245,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;
@@ -1301,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;
@@ -1320,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;
@@ -1334,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);
}
}
@@ -1361,6 +1351,7 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
return (error);
}
+#endif // _KERNEL
/*
* Here NFS has: nfs3write, nfs3read
@@ -1588,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;
@@ -1645,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);
/*
@@ -1685,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);
}
/*
@@ -1704,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);
@@ -1717,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;
}
@@ -1733,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",
@@ -1745,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) {
/*
@@ -2022,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);
@@ -2030,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.
*/
@@ -2119,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);
@@ -2198,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);
}
@@ -2225,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.
@@ -2519,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;
@@ -2531,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;
@@ -2693,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
@@ -2766,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);
@@ -2808,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;
/*
@@ -2820,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
@@ -2842,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.
@@ -2857,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);
@@ -2880,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);
@@ -2897,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);
}
@@ -2906,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. */
@@ -3050,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);
@@ -3130,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,
@@ -3172,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);
@@ -3213,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;
@@ -3240,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)
@@ -3254,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.
@@ -3297,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);
@@ -3692,6 +3714,8 @@ smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
/* mmap support ******************************************************** */
+#ifdef _KERNEL
+
#ifdef DEBUG
static int smbfs_lostpage = 0; /* number of times we lost original page */
#endif
@@ -4011,6 +4035,8 @@ again:
* No read-ahead in smbfs yet.
*/
+#endif // _KERNEL
+
/*
* Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE}
* If len == 0, do from off to EOF.
@@ -4026,6 +4052,7 @@ static int
smbfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
caller_context_t *ct)
{
+#ifdef _KERNEL
smbnode_t *np;
smbmntinfo_t *smi;
page_t *pp;
@@ -4157,8 +4184,14 @@ smbfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
}
return (error);
+
+#else // _KERNEL
+ return (ENOSYS);
+#endif // _KERNEL
}
+#ifdef _KERNEL
+
/*
* Write out a single page, possibly klustering adjacent dirty pages.
*
@@ -4331,6 +4364,9 @@ smbfs_putapage(vnode_t *vp, page_t *pp, u_offset_t *offp, size_t *lenp,
return (error);
}
+#endif // _KERNEL
+
+
/*
* NFS has this in nfs_client.c (shared by v2,v3,...)
* We have it here so smbfs_putapage can be file scope.
@@ -4355,8 +4391,10 @@ smbfs_invalidate_pages(vnode_t *vp, u_offset_t off, cred_t *cr)
/* Here NFSv3 has np->r_truncaddr = off; */
mutex_exit(&np->r_statelock);
+#ifdef _KERNEL
(void) pvn_vplist_dirty(vp, off, smbfs_putapage,
B_INVAL | B_TRUNC, cr);
+#endif // _KERNEL
mutex_enter(&np->r_statelock);
np->r_flags &= ~RTRUNCATE;
@@ -4364,6 +4402,8 @@ smbfs_invalidate_pages(vnode_t *vp, u_offset_t off, cred_t *cr)
mutex_exit(&np->r_statelock);
}
+#ifdef _KERNEL
+
/* Like nfs3_map */
/* ARGSUSED */
@@ -4659,6 +4699,8 @@ smbfs_delmap_async(void *varg)
/* No smbfs_pageio() or smbfs_dispose() ops. */
+#endif // _KERNEL
+
/* misc. ******************************************************** */
@@ -4961,11 +5003,13 @@ const fs_operation_def_t smbfs_vnodeops_template[] = {
VOPNAME_FRLOCK, { .vop_frlock = smbfs_frlock },
VOPNAME_SPACE, { .vop_space = smbfs_space },
VOPNAME_REALVP, { .vop_realvp = smbfs_realvp },
+#ifdef _KERNEL
VOPNAME_GETPAGE, { .vop_getpage = smbfs_getpage },
VOPNAME_PUTPAGE, { .vop_putpage = smbfs_putpage },
VOPNAME_MAP, { .vop_map = smbfs_map },
VOPNAME_ADDMAP, { .vop_addmap = smbfs_addmap },
VOPNAME_DELMAP, { .vop_delmap = smbfs_delmap },
+#endif // _KERNEL
VOPNAME_PATHCONF, { .vop_pathconf = smbfs_pathconf },
VOPNAME_SETSECATTR, { .vop_setsecattr = smbfs_setsecattr },
VOPNAME_GETSECATTR, { .vop_getsecattr = smbfs_getsecattr },
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 75241cc1f0..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,6 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -29,6 +30,7 @@
*/
#include <sys/systm.h>
+#include <sys/inttypes.h>
#include <sys/cred.h>
#include <sys/vnode.h>
#include <sys/vfs.h>
@@ -43,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>
@@ -289,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);
@@ -322,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);
@@ -363,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"
@@ -462,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)
@@ -488,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/io/aac/aac.c b/usr/src/uts/common/io/aac/aac.c
index 36c48d96e6..f9d3672963 100644
--- a/usr/src/uts/common/io/aac/aac.c
+++ b/usr/src/uts/common/io/aac/aac.c
@@ -255,8 +255,8 @@ static int aac_add_intrs(struct aac_softstate *);
static void aac_remove_intrs(struct aac_softstate *);
static int aac_enable_intrs(struct aac_softstate *);
static int aac_disable_intrs(struct aac_softstate *);
-static uint_t aac_intr_old(caddr_t);
-static uint_t aac_intr_new(caddr_t);
+static uint_t aac_intr_old(caddr_t, caddr_t);
+static uint_t aac_intr_new(caddr_t, caddr_t);
static uint_t aac_softintr(caddr_t);
/*
@@ -1416,7 +1416,7 @@ aac_process_intr_new(struct aac_softstate *softs)
}
static uint_t
-aac_intr_new(caddr_t arg)
+aac_intr_new(caddr_t arg, caddr_t arg1 __unused)
{
struct aac_softstate *softs = (void *)arg;
uint_t rval;
@@ -1555,7 +1555,7 @@ aac_process_intr_old(struct aac_softstate *softs)
}
static uint_t
-aac_intr_old(caddr_t arg)
+aac_intr_old(caddr_t arg, caddr_t arg1 __unused)
{
struct aac_softstate *softs = (void *)arg;
int rval;
@@ -1674,7 +1674,7 @@ aac_add_intrs(struct aac_softstate *softs)
ddi_intr_handler_t *aac_intr;
actual = softs->intr_cnt;
- aac_intr = (ddi_intr_handler_t *)((softs->flags & AAC_FLAGS_NEW_COMM) ?
+ aac_intr = ((softs->flags & AAC_FLAGS_NEW_COMM) ?
aac_intr_new : aac_intr_old);
/* Call ddi_intr_add_handler() */
diff --git a/usr/src/uts/common/netsmb/mchain.h b/usr/src/uts/common/netsmb/mchain.h
index c5c8512fd7..156671999b 100644
--- a/usr/src/uts/common/netsmb/mchain.h
+++ b/usr/src/uts/common/netsmb/mchain.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 _MCHAIN_H_
@@ -70,10 +72,10 @@
#else /* (BYTE_ORDER == LITTLE_ENDIAN) */
/* little-endian values on big-endian (swap) */
-#define letohs(x) BSWAP_16(x)
-#define htoles(x) BSWAP_16(x)
-#define letohl(x) BSWAP_32(x)
-#define htolel(x) BSWAP_32(x)
+#define letohs(x) BSWAP_16(x)
+#define htoles(x) BSWAP_16(x)
+#define letohl(x) BSWAP_32(x)
+#define htolel(x) BSWAP_32(x)
#define letohq(x) BSWAP_64(x)
#define htoleq(x) BSWAP_64(x)
@@ -93,7 +95,7 @@
* wrappers for streams functions. See: subr_mchain.c
*/
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* BSD-style mbuf "shim" for kernel code. Note, this
@@ -103,6 +105,7 @@
*/
#include <sys/stream.h> /* mblk_t */
+#include <sys/strsun.h> /* MBLKL */
typedef mblk_t mbuf_t;
/* BEGIN CSTYLED */
@@ -112,9 +115,9 @@ typedef mblk_t mbuf_t;
* 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
@@ -124,7 +127,7 @@ typedef mblk_t mbuf_t;
* &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.
@@ -177,7 +180,7 @@ void m_freem(mbuf_t *);
#define MB_MZERO 3 /* bzero(), mb_put_mem only */
#define MB_MCUSTOM 4 /* use an user defined function */
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
struct mbchain {
mblk_t *mb_top;
@@ -224,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);
@@ -234,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);
@@ -248,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 d2e7690062..817d214b3e 100644
--- a/usr/src/uts/common/netsmb/smb_dev.h
+++ b/usr/src/uts/common/netsmb/smb_dev.h
@@ -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.
*/
#ifndef _NETSMB_DEV_H_
@@ -71,9 +72,9 @@
* associated structures change in ways that would
* make them incompatible with an old driver.
*/
-#define NSMB_VERMAJ 1
-#define NSMB_VERMIN 4000
-#define NSMB_VERSION (NSMB_VERMAJ * 100000 + NSMB_VERMIN)
+#define NSMB_VERMAJ 2
+#define NSMB_VERMIN 0x100
+#define NSMB_VERSION ((NSMB_VERMAJ << 16) | NSMB_VERMIN)
/*
* Some errno values we need to expose to the library.
@@ -84,7 +85,7 @@
* EAUTH is used for CIFS authentication errors.
*/
#ifndef EBADRPC
-#define EBADRPC 113
+#define EBADRPC 113
#endif
#ifndef EAUTH
#define EAUTH 114
@@ -111,13 +112,21 @@
#define SMBVOPT_PRIVATE 0x0002 /* connection should be private */
#define SMBVOPT_SINGLESHARE 0x0004 /* keep only one share at this VC */
#define SMBVOPT_PERMANENT 0x0010 /* object will keep last reference */
-#define SMBVOPT_EXT_SEC 0x0020 /* extended security negotiation */
-#define SMBVOPT_USE_KEYCHAIN 0x0040 /* get p/w from keychain */
-#define SMBVOPT_KC_DOMAIN 0x0080 /* keychain lookup uses domain */
+#define SMBVOPT_ANONYMOUS 0x0020 /* using a NULL session */
+
+#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 SMBVOPT_SIGNING_ENABLED 0x0100 /* sign if server agrees */
-#define SMBVOPT_SIGNING_REQUIRED 0x0200 /* signing required */
-#define SMBVOPT_SIGNING_MASK 0x0300 /* 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
@@ -137,13 +146,18 @@
/*
* network IO daemon states
- * really connection states.
*/
enum smbiod_state {
- SMBIOD_ST_IDLE = 0, /* no user requests enqueued yet */
- SMBIOD_ST_RECONNECT, /* a [re]connect attempt is in progress */
+ SMBIOD_ST_UNINIT = 0, /* uninitialized */
+ SMBIOD_ST_RECONNECT, /* a [re]connect attempt requested */
SMBIOD_ST_RCFAILED, /* a reconnect attempt has failed */
- SMBIOD_ST_VCACTIVE, /* session established */
+ SMBIOD_ST_CONNECTED, /* Transport (TCP) connected */
+ SMBIOD_ST_NEGOTIATED, /* Negotiated SMB/SMB2+ */
+ SMBIOD_ST_AUTHCONT, /* Session setup continuing */
+ SMBIOD_ST_AUTHFAIL, /* Session setup failed */
+ SMBIOD_ST_AUTHOK, /* Session setup success */
+ SMBIOD_ST_VCACTIVE, /* iod_work running */
+ SMBIOD_ST_IDLE, /* no trees, will go DEAD */
SMBIOD_ST_DEAD /* connection gone, no IOD */
};
@@ -204,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];
};
@@ -232,55 +248,19 @@ typedef struct smbioc_tcon {
smbioc_oshare_t tc_sh;
} smbioc_tcon_t;
-
-/*
- * Negotiated protocol parameters
- */
-struct smb_sopt {
- int16_t sv_proto; /* protocol dialect */
- uchar_t sv_sm; /* security mode */
- int16_t sv_tz; /* offset in min relative to UTC */
- uint16_t sv_maxmux; /* max number of outstanding rq's */
- uint16_t sv_maxvcs; /* max number of VCs */
- uint16_t sv_rawmode;
- uint32_t sv_maxtx; /* maximum transmit buf size */
- uint32_t sv_maxraw; /* maximum raw-buffer size */
- uint32_t sv_skey; /* session key */
- uint32_t sv_caps; /* capabilites SMB_CAP_ */
-};
-typedef struct smb_sopt smb_sopt_t;
-
-/*
- * State carried in/out of the driver by the IOD thread.
- * Inside the driver, these are members of the "VC" object.
- */
-struct smb_iods {
- int32_t is_tran_fd; /* transport FD */
- uint32_t is_vcflags; /* SMBV_... */
- uint8_t is_hflags; /* SMB header flags */
- uint16_t is_hflags2; /* SMB header flags2 */
- uint16_t is_smbuid; /* SMB header UID */
- uint16_t is_next_mid; /* SMB header MID */
- uint32_t is_txmax; /* max tx/rx packet size */
- uint32_t is_rwmax; /* max read/write data size */
- uint32_t is_rxmax; /* max readx data size */
- uint32_t is_wxmax; /* max writex data size */
- uint8_t is_ssn_key[SMBIOC_HASH_SZ]; /* session key */
- /* Signing state */
- uint32_t is_next_seq; /* my next sequence number */
- uint32_t is_u_maclen; /* MAC key length */
- lptr_t is_u_mackey; /* user-space ptr! */
-};
-typedef struct smb_iods smb_iods_t;
-
/*
* This is the operational state information passed
* in and out of the driver for SMBIOC_SSN_WORK
*/
struct smbioc_ssn_work {
- smb_iods_t wk_iods;
- smb_sopt_t wk_sopt;
- int wk_out_state;
+ uint32_t wk_out_state; /* out-only */
+ uint32_t wk_u_ssnkey_len; /* ssn key length */
+ lptr_t wk_u_ssnkey_buf; /* user-space ptr! */
+ uint32_t wk_u_auth_rlen; /* recv auth tok len */
+ 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_cl_guid[16]; /* client GUID */
};
typedef struct smbioc_ssn_work smbioc_ssn_work_t;
@@ -288,66 +268,27 @@ typedef struct smbioc_ssn_work smbioc_ssn_work_t;
* User-level SMB requests
*/
-/*
- * SMBIOC_REQUEST (simple SMB request)
- */
-typedef struct smbioc_rq {
- uchar_t ioc_cmd;
- uint8_t ioc_errclass;
- uint16_t ioc_serror;
- uint32_t ioc_error;
- uint32_t ioc_tbufsz; /* transmit */
- uint32_t ioc_rbufsz; /* receive */
- lptr_t _ioc_tbuf;
- lptr_t _ioc_rbuf;
-} smbioc_rq_t;
-#define ioc_tbuf _ioc_tbuf.lp_ptr
-#define ioc_rbuf _ioc_rbuf.lp_ptr
-
-
-#define SMBIOC_T2RQ_MAXSETUP 4
-#define SMBIOC_T2RQ_MAXNAME 128
-
-typedef struct smbioc_t2rq {
- uint16_t ioc_setup[SMBIOC_T2RQ_MAXSETUP];
- int32_t ioc_setupcnt;
- char ioc_name[SMBIOC_T2RQ_MAXNAME];
- ushort_t ioc_tparamcnt;
- ushort_t ioc_tdatacnt;
- ushort_t ioc_rparamcnt;
- ushort_t ioc_rdatacnt;
- uint8_t ioc__pad1;
- uint8_t ioc_errclass;
- uint16_t ioc_serror;
- uint32_t ioc_error;
- uint16_t ioc_rpflags2;
- uint16_t ioc__pad2;
- lptr_t _ioc_tparam;
- lptr_t _ioc_tdata;
- lptr_t _ioc_rparam;
- lptr_t _ioc_rdata;
-} smbioc_t2rq_t;
-#define ioc_tparam _ioc_tparam.lp_ptr
-#define ioc_tdata _ioc_tdata.lp_ptr
-#define ioc_rparam _ioc_rparam.lp_ptr
-#define ioc_rdata _ioc_rdata.lp_ptr
-
-
-typedef struct smbioc_flags {
- int32_t ioc_level; /* 0 - session, 1 - share */
- int32_t ioc_flags;
- int32_t ioc_mask;
-} smbioc_flags_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;
#define ioc_offset _ioc_offset._f
#define ioc_base _ioc_base.lp_ptr
+/* Transact on named pipe (send/recv) */
+typedef struct smbioc_xnp {
+ 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;
+#define ioc_tdata _ioc_tdata.lp_ptr
+#define ioc_rdata _ioc_rdata.lp_ptr
+
typedef struct smbioc_ntcreate {
uint32_t ioc_req_acc;
uint32_t ioc_efattr;
@@ -383,18 +324,16 @@ typedef struct smbioc_pk {
* Keep GETVERS first and use it to verify
* driver compatibility with the library.
*/
-#define SMBIOC_BASE ((('n' << 8) | 's') << 8)
+#define SMBIOC_BASE ((('n' << 8) | 's') << 8)
typedef enum nsmb_ioc {
SMBIOC_GETVERS = SMBIOC_BASE, /* keep first */
- SMBIOC_FLAGS2, /* get hflags2 */
+ SMBIOC_FLAGS2, /* obsolete */
SMBIOC_GETSSNKEY, /* get SMB session key */
SMBIOC_DUP_DEV, /* duplicate dev handle */
- SMBIOC_REQUEST, /* simple request */
- SMBIOC_T2RQ, /* trans2 request */
-
SMBIOC_READ, /* read (pipe) */
SMBIOC_WRITE, /* write (pipe) */
+ SMBIOC_XACTNP, /* "transact" (pipe) */
SMBIOC_NTCREATE, /* open or create */
SMBIOC_PRINTJOB, /* open print job */
SMBIOC_CLOSEFH, /* from ntcreate or printjob */
@@ -409,9 +348,12 @@ typedef enum nsmb_ioc {
SMBIOC_TREE_KILL,
SMBIOC_TREE_RELE,
+ SMBIOC_IOD_CONNECT, /* Setup connection */
+ SMBIOC_IOD_NEGOTIATE, /* SMB/SMB2 negotiate */
+ SMBIOC_IOD_SSNSETUP, /* SMB/SMB2 session setup */
SMBIOC_IOD_WORK, /* work on session requests */
SMBIOC_IOD_IDLE, /* wait for requests on this session */
- SMBIOC_IOD_RCFAIL, /* notify that reconnect failed */
+ SMBIOC_IOD_RCFAIL, /* tell driver reconnect failed */
/* Password Keychain (PK) support. */
SMBIOC_PK_ADD, /* Add/Modify a password entry */
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/common/sys/conf.h b/usr/src/uts/common/sys/conf.h
index 4bf3d5c7e3..148104f83a 100644
--- a/usr/src/uts/common/sys/conf.h
+++ b/usr/src/uts/common/sys/conf.h
@@ -41,11 +41,11 @@
extern "C" {
#endif
-#define FMNAMESZ 8 /* used by struct fmodsw */
+#define FMNAMESZ 8 /* used by struct fmodsw */
#if !defined(_XPG4_2) || defined(__EXTENSIONS__)
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* XXX Given that drivers need to include this file,
@@ -53,10 +53,14 @@ extern "C" {
* it legitimizes (aka provides prototypes for)
* all sorts of functions that aren't in the DKI/SunDDI
*/
+#include <sys/types.h>
#include <sys/systm.h>
+
+#endif /* _KERNEL || _FAKE_KERNEL */
+#ifdef _KERNEL
+
#include <sys/devops.h>
#include <sys/model.h>
-#include <sys/types.h>
#include <sys/buf.h>
#include <sys/cred.h>
#include <sys/uio.h>
diff --git a/usr/src/uts/common/sys/debug.h b/usr/src/uts/common/sys/debug.h
index e4a959205a..9c91905af2 100644
--- a/usr/src/uts/common/sys/debug.h
+++ b/usr/src/uts/common/sys/debug.h
@@ -138,12 +138,12 @@ _NOTE(CONSTCOND) } while (0)
#define __CTASSERT(x, y) \
typedef char __compile_time_assertion__ ## y [(x) ? 1 : -1] __unused
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
extern void abort_sequence_enter(char *);
extern void debug_enter(char *);
-#endif /* _KERNEL */
+#endif /* _KERNEL || _FAKE_KERNEL */
#if defined(DEBUG) && !defined(__sun)
/* CSTYLED */
diff --git a/usr/src/uts/common/sys/dirent.h b/usr/src/uts/common/sys/dirent.h
index 114fcf6e30..c079fb983a 100644
--- a/usr/src/uts/common/sys/dirent.h
+++ b/usr/src/uts/common/sys/dirent.h
@@ -76,7 +76,7 @@ typedef struct dirent64 {
#endif /* _LARGEFILE64_SOURCE */
#if !defined(__XOPEN_OR_POSIX) || defined(__EXTENSIONS__)
-#if defined(_KERNEL)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#define DIRENT64_RECLEN(namelen) \
((offsetof(dirent64_t, d_name[0]) + 1 + (namelen) + 7) & ~ 7)
#define DIRENT64_NAMELEN(reclen) \
diff --git a/usr/src/uts/common/sys/dnlc.h b/usr/src/uts/common/sys/dnlc.h
index bf947659d0..4a5c20d6d0 100644
--- a/usr/src/uts/common/sys/dnlc.h
+++ b/usr/src/uts/common/sys/dnlc.h
@@ -76,7 +76,7 @@ extern "C" {
* storing full names, then we are ok. The space savings are worth it.
*/
typedef struct ncache {
- struct ncache *hash_next; /* hash chain, MUST BE FIRST */
+ struct ncache *hash_next; /* hash chain, MUST BE FIRST */
struct ncache *hash_prev;
struct vnode *vp; /* vnode the name refers to */
struct vnode *dp; /* vnode of parent of name */
@@ -169,7 +169,7 @@ struct nc_stats {
(namlen) = Xcp - (name); \
}
-#if defined(_KERNEL)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/vfs.h>
#include <sys/vnode.h>
@@ -205,7 +205,7 @@ void dnlc_reduce_cache(void *);
*/
typedef struct dcfree {
uint64_t df_handle; /* fs supplied handle */
- struct dcfree *df_next; /* link to next free entry in bucket */
+ struct dcfree *df_next; /* link to next free entry in bucket */
uint_t df_len; /* length of free entry */
} dcfree_t;
diff --git a/usr/src/uts/common/sys/file.h b/usr/src/uts/common/sys/file.h
index eb1328f38d..b0914cfb45 100644
--- a/usr/src/uts/common/sys/file.h
+++ b/usr/src/uts/common/sys/file.h
@@ -119,7 +119,7 @@ typedef struct fpollinfo {
#define FCLOEXEC 0x800000 /* O_CLOEXEC = 0x800000 */
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* Fake flags for driver ioctl calls to inform them of the originating
@@ -183,7 +183,7 @@ typedef struct fpollinfo {
extern int flock(int, int);
#endif
-#if defined(_KERNEL)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* Routines dealing with user per-open file flags and
@@ -192,15 +192,16 @@ extern int flock(int, int);
struct proc; /* forward reference for function prototype */
struct vnodeops;
struct vattr;
+struct uf_info;
extern file_t *getf(int);
extern file_t *getf_gen(int, uf_entry_gen_t *);
extern void releasef(int);
-extern void areleasef(int, uf_info_t *);
+extern void areleasef(int, struct uf_info *);
#ifndef _BOOT
-extern void closeall(uf_info_t *);
+extern void closeall(struct uf_info *);
#endif
-extern void flist_fork(uf_info_t *, uf_info_t *);
+extern void flist_fork(struct uf_info *, struct uf_info *);
extern int closef(file_t *);
extern int closeandsetf(int, file_t *);
extern int ufalloc_file(int, file_t *);
@@ -217,8 +218,8 @@ extern void f_setfd(int, char);
extern int f_getfl(int, int *);
extern int f_badfd(int, int *, int);
extern int fassign(struct vnode **, int, int *);
-extern void fcnt_add(uf_info_t *, int);
-extern void close_exec(uf_info_t *);
+extern void fcnt_add(struct uf_info *, int);
+extern void close_exec(struct uf_info *);
extern void clear_stale_fd(void);
extern void clear_active_fd(int);
extern void set_active_fd(int);
diff --git a/usr/src/uts/common/sys/model.h b/usr/src/uts/common/sys/model.h
index fab96bbe00..0569c086f5 100644
--- a/usr/src/uts/common/sys/model.h
+++ b/usr/src/uts/common/sys/model.h
@@ -37,7 +37,7 @@ extern "C" {
#include <sys/isa_defs.h>
-#if defined(_KERNEL) || defined(_KMEMUSER)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL) || defined(_KMEMUSER)
/*
* These bits are used in various places to specify the data model
diff --git a/usr/src/uts/common/sys/modhash.h b/usr/src/uts/common/sys/modhash.h
index 68d1c4dedd..7f7103ecb9 100644
--- a/usr/src/uts/common/sys/modhash.h
+++ b/usr/src/uts/common/sys/modhash.h
@@ -34,7 +34,7 @@
extern "C" {
#endif
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/types.h>
diff --git a/usr/src/uts/common/sys/poll.h b/usr/src/uts/common/sys/poll.h
index 4434a8551a..558edbfba9 100644
--- a/usr/src/uts/common/sys/poll.h
+++ b/usr/src/uts/common/sys/poll.h
@@ -96,7 +96,7 @@ typedef unsigned long nfds_t;
#endif /* _KERNEL */
-#if defined(_KERNEL) || defined(_KMEMUSER)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL) || defined(_KMEMUSER)
#include <sys/thread.h>
diff --git a/usr/src/uts/common/sys/share.h b/usr/src/uts/common/sys/share.h
index 4de5f5ce65..1a8aead065 100644
--- a/usr/src/uts/common/sys/share.h
+++ b/usr/src/uts/common/sys/share.h
@@ -63,7 +63,7 @@ struct shrlocklist {
struct shrlocklist *next;
};
-#if defined(_KERNEL)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
struct flock64;
extern int add_share(struct vnode *, struct shrlock *);
diff --git a/usr/src/uts/common/sys/signal.h b/usr/src/uts/common/sys/signal.h
index 1818665b45..b12dff6034 100644
--- a/usr/src/uts/common/sys/signal.h
+++ b/usr/src/uts/common/sys/signal.h
@@ -246,7 +246,7 @@ struct sigstack {
#include <sys/ucontext.h>
#endif /* defined(_XPG4_2) */
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/t_lock.h>
extern const k_sigset_t nullsmask; /* a null signal mask */
diff --git a/usr/src/uts/common/sys/stream.h b/usr/src/uts/common/sys/stream.h
index efcd2a9194..7488d3dee8 100644
--- a/usr/src/uts/common/sys/stream.h
+++ b/usr/src/uts/common/sys/stream.h
@@ -36,7 +36,7 @@
* For source compatibility
*/
#include <sys/isa_defs.h>
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/kmem.h>
#include <sys/uio.h>
#endif
@@ -641,7 +641,7 @@ struct stroptions {
#define SO_MAXBLK 0x100000 /* set maximum message block size */
#define SO_TAIL 0x200000 /* set the extra allocated space */
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* Structure for rw (read/write) procedure calls. A pointer
* to a struiod_t is passed as a parameter to the rwnext() call.
@@ -766,7 +766,7 @@ typedef struct cmdblk {
*/
#define bpsize(bp) ((unsigned int)(bp->b_datap->db_lim - bp->b_datap->db_base))
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* For two-byte M_ERROR messages: indication that a side does not have an error
diff --git a/usr/src/uts/common/sys/strsubr.h b/usr/src/uts/common/sys/strsubr.h
index 0f29dd3675..f3bc1ed407 100644
--- a/usr/src/uts/common/sys/strsubr.h
+++ b/usr/src/uts/common/sys/strsubr.h
@@ -40,6 +40,7 @@
*/
#include <sys/stream.h>
#include <sys/stropts.h>
+#include <sys/vnode.h>
#include <sys/kstat.h>
#include <sys/uio.h>
#include <sys/proc.h>
@@ -115,7 +116,7 @@ extern "C" {
/*
* Function types for the parameterized stream head.
* The msgfunc_t takes the parameters:
- * msgfunc(vnode_t *vp, mblk_t *mp, strwakeup_t *wakeups,
+ * msgfunc(vnode_t *vp, mblk_t *mp, strwakeup_t *wakeups,
* strsigset_t *firstmsgsigs, strsigset_t *allmsgsigs,
* strpollset_t *pollwakeups);
* It returns an optional message to be processed by the stream head.
@@ -130,7 +131,7 @@ typedef short strpollset_t;
typedef uintptr_t callbparams_id_t;
typedef mblk_t *(*msgfunc_t)(vnode_t *, mblk_t *, strwakeup_t *,
strsigset_t *, strsigset_t *, strpollset_t *);
-typedef int (*errfunc_t)(vnode_t *, int, int *);
+typedef int (*errfunc_t)(vnode_t *, int, int *);
/*
* Per stream sd_lock in putnext may be replaced by per cpu stream_putlocks
@@ -276,7 +277,7 @@ typedef struct stdata {
/* 0x00020000 unused */
/* 0x00040000 unused */
#define STRTOSTOP 0x00080000 /* block background writes */
-#define STRCMDWAIT 0x00100000 /* someone is doing an _I_CMD */
+#define STRCMDWAIT 0x00100000 /* someone is doing an _I_CMD */
/* 0x00200000 unused */
#define STRMOUNT 0x00400000 /* stream is mounted */
#define STRNOTATMARK 0x00800000 /* Not at mark (when empty read q) */
@@ -410,7 +411,7 @@ typedef struct stdata {
*
* The new way is:
*
- * mutex_enter(SQLOCK(sq));
+ * mutex_enter(SQLOCK(sq));
* count = sq->sq_count;
* SQ_PUTLOCKS_ENTER(sq);
* SUM_SQ_PUTCOUNTS(sq, count);
@@ -459,8 +460,8 @@ struct syncq {
*/
uint16_t sq_type; /* type (concurrency) of syncq */
uint16_t sq_rmqcount; /* # threads inside removeq() */
- kcondvar_t sq_wait; /* block on this sync queue */
- kcondvar_t sq_exitwait; /* waiting for thread to leave the */
+ kcondvar_t sq_wait; /* block on this sync queue */
+ kcondvar_t sq_exitwait; /* waiting for thread to leave the */
/* inner perimeter */
/*
* Handling synchronous callbacks such as qtimeout and qbufcall
@@ -1024,7 +1025,7 @@ typedef struct str_stack str_stack_t;
/*
* Copy modes for tty and I_STR ioctls
*/
-#define U_TO_K 01 /* User to Kernel */
+#define U_TO_K 01 /* User to Kernel */
#define K_TO_K 02 /* Kernel to Kernel */
/*
@@ -1077,7 +1078,7 @@ typedef struct str_stack str_stack_t;
#define STRUNLOCKMATES(X) mutex_exit(&((X)->sd_lock)); \
mutex_exit(&(((X)->sd_mate)->sd_lock))
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
extern void strinit(void);
extern int strdoioctl(struct stdata *, struct strioctl *, int, int,
diff --git a/usr/src/uts/common/sys/t_kuser.h b/usr/src/uts/common/sys/t_kuser.h
index 7aac9d94d2..b3c4da657c 100644
--- a/usr/src/uts/common/sys/t_kuser.h
+++ b/usr/src/uts/common/sys/t_kuser.h
@@ -98,6 +98,7 @@ extern int t_kconnect(TIUSER *, struct t_call *, struct t_call *);
extern int t_kfree(TIUSER *, char *, int);
extern int t_kgetstate(TIUSER *, int *);
extern int t_kopen(struct file *, dev_t, int, TIUSER **, struct cred *);
+extern int t_koptmgmt(TIUSER *, struct t_optmgmt *, struct t_optmgmt *);
extern int t_krcvudata(TIUSER *, struct t_kunitdata *, int *, int *);
extern int t_ksndudata(TIUSER *, struct t_kunitdata *, frtn_t *);
extern int t_kspoll(TIUSER *, int, int, int *);
diff --git a/usr/src/uts/intel/nsmb/ioc_check.ref b/usr/src/uts/intel/nsmb/ioc_check.ref
index 9d670f24c3..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
@@ -17,70 +19,27 @@
#define TC_FLAGS 0x0
#define TC_OPT 0x4
#define TC_SH 0x8
-#define SV_PROTO 0x0
-#define SV_SM 0x2
-#define SV_TZ 0x4
-#define SV_MAXMUX 0x6
-#define SV_MAXVCS 0x8
-#define SV_RAWMODE 0xa
-#define SV_MAXTX 0xc
-#define SV_MAXRAW 0x10
-#define SV_SKEY 0x14
-#define SV_CAPS 0x18
-#define IS_TRAN_FD 0x0
-#define IS_VCFLAGS 0x4
-#define IS_HFLAGS 0x8
-#define IS_HFLAGS2 0xa
-#define IS_SMBUID 0xc
-#define IS_NEXT_MID 0xe
-#define IS_TXMAX 0x10
-#define IS_RWMAX 0x14
-#define IS_RXMAX 0x18
-#define IS_WXMAX 0x1c
-#define IS_SSN_KEY 0x20
-#define IS_SSN_KEY_INCR 0x1
-#define IS_NEXT_SEQ 0x30
-#define IS_U_MACLEN 0x34
-#define IS_U_MACKEY 0x38
-#define WK_IODS 0x0
-#define WK_SOPT 0x40
-#define WK_OUT_STATE 0x5c
-#define SIZEOF_SMBIOC_RQ 0x20
-#define IOC_CMD 0x0
-#define IOC_RQ_ERRCLASS 0x1
-#define IOC_RQ_SERROR 0x2
-#define IOC_RQ_ERROR 0x4
-#define IOC_TBUFSZ 0x8
-#define IOC_RBUFSZ 0xc
-#define _IOC_TBUF 0x10
-#define _IOC_RBUF 0x18
-#define SIZEOF_SMBIOC_T2RQ 0xc0
-#define IOC_SETUP 0x0
-#define IOC_SETUP_INCR 0x2
-#define IOC_SETUPCNT 0x8
-#define IOC_T2_NAME 0xc
-#define IOC_T2_NAME_INCR 0x1
-#define IOC_TPARAMCNT 0x8c
-#define IOC_TDATACNT 0x8e
-#define IOC_RPARAMCNT 0x90
-#define IOC_RDATACNT 0x92
-#define IOC_T2_ERRCLASS 0x95
-#define IOC_T2_SERROR 0x96
-#define IOC_T2_ERROR 0x98
-#define IOC_RPFLAGS2 0x9c
-#define _IOC_TPARAM 0xa0
-#define _IOC_TDATA 0xa8
-#define _IOC_RPARAM 0xb0
-#define _IOC_RDATA 0xb8
-#define SIZEOF_SMBIOC_FLAGS 0xc
-#define IOC_LEVEL 0x0
-#define IOC_MASK 0x8
-#define IOC_FLAGS 0x4
+#define WK_OUT_STATE 0x0
+#define WK_U_SSNKEY_LEN 0x4
+#define WK_U_SSNKEY_BUF 0x8
+#define WK_U_AUTH_RLEN 0x10
+#define WK_U_AUTH_WLEN 0x14
+#define WK_U_AUTH_RBUF 0x18
+#define WK_U_AUTH_WBUF 0x20
+#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/intel/pcbe/core_pcbe.c b/usr/src/uts/intel/pcbe/core_pcbe.c
index 7424e2526b..ad92c2f62f 100644
--- a/usr/src/uts/intel/pcbe/core_pcbe.c
+++ b/usr/src/uts/intel/pcbe/core_pcbe.c
@@ -994,7 +994,8 @@ core_pcbe_event_coverage(char *event)
} else {
if (find_generic_events(event, cmn_generic_events) != NULL) {
bitmap |= BITMASK_XBITS(num_gpc);
- } if (find_generic_events(event, generic_events_pic0) != NULL) {
+ } else if (find_generic_events(event,
+ generic_events_pic0) != NULL) {
bitmap |= 1ULL;
} else if (find_gpcevent_core_uarch(event,
cmn_gpc_events_core_uarch) != NULL) {
diff --git a/usr/src/uts/sparc/nsmb/ioc_check.ref b/usr/src/uts/sparc/nsmb/ioc_check.ref
index 9d670f24c3..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
@@ -17,70 +19,27 @@
#define TC_FLAGS 0x0
#define TC_OPT 0x4
#define TC_SH 0x8
-#define SV_PROTO 0x0
-#define SV_SM 0x2
-#define SV_TZ 0x4
-#define SV_MAXMUX 0x6
-#define SV_MAXVCS 0x8
-#define SV_RAWMODE 0xa
-#define SV_MAXTX 0xc
-#define SV_MAXRAW 0x10
-#define SV_SKEY 0x14
-#define SV_CAPS 0x18
-#define IS_TRAN_FD 0x0
-#define IS_VCFLAGS 0x4
-#define IS_HFLAGS 0x8
-#define IS_HFLAGS2 0xa
-#define IS_SMBUID 0xc
-#define IS_NEXT_MID 0xe
-#define IS_TXMAX 0x10
-#define IS_RWMAX 0x14
-#define IS_RXMAX 0x18
-#define IS_WXMAX 0x1c
-#define IS_SSN_KEY 0x20
-#define IS_SSN_KEY_INCR 0x1
-#define IS_NEXT_SEQ 0x30
-#define IS_U_MACLEN 0x34
-#define IS_U_MACKEY 0x38
-#define WK_IODS 0x0
-#define WK_SOPT 0x40
-#define WK_OUT_STATE 0x5c
-#define SIZEOF_SMBIOC_RQ 0x20
-#define IOC_CMD 0x0
-#define IOC_RQ_ERRCLASS 0x1
-#define IOC_RQ_SERROR 0x2
-#define IOC_RQ_ERROR 0x4
-#define IOC_TBUFSZ 0x8
-#define IOC_RBUFSZ 0xc
-#define _IOC_TBUF 0x10
-#define _IOC_RBUF 0x18
-#define SIZEOF_SMBIOC_T2RQ 0xc0
-#define IOC_SETUP 0x0
-#define IOC_SETUP_INCR 0x2
-#define IOC_SETUPCNT 0x8
-#define IOC_T2_NAME 0xc
-#define IOC_T2_NAME_INCR 0x1
-#define IOC_TPARAMCNT 0x8c
-#define IOC_TDATACNT 0x8e
-#define IOC_RPARAMCNT 0x90
-#define IOC_RDATACNT 0x92
-#define IOC_T2_ERRCLASS 0x95
-#define IOC_T2_SERROR 0x96
-#define IOC_T2_ERROR 0x98
-#define IOC_RPFLAGS2 0x9c
-#define _IOC_TPARAM 0xa0
-#define _IOC_TDATA 0xa8
-#define _IOC_RPARAM 0xb0
-#define _IOC_RDATA 0xb8
-#define SIZEOF_SMBIOC_FLAGS 0xc
-#define IOC_LEVEL 0x0
-#define IOC_MASK 0x8
-#define IOC_FLAGS 0x4
+#define WK_OUT_STATE 0x0
+#define WK_U_SSNKEY_LEN 0x4
+#define WK_U_SSNKEY_BUF 0x8
+#define WK_U_AUTH_RLEN 0x10
+#define WK_U_AUTH_WLEN 0x14
+#define WK_U_AUTH_RBUF 0x18
+#define WK_U_AUTH_WBUF 0x20
+#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