summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/boot/Makefile.version2
-rw-r--r--usr/src/boot/lib/libstand/dosfs.c4
-rw-r--r--usr/src/boot/lib/libstand/zfs/zfsimpl.c4
-rw-r--r--usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c113
-rw-r--r--usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c113
-rw-r--r--usr/src/lib/smbsrv/libfksmbsrv/Makefile.com1
-rw-r--r--usr/src/lib/smbsrv/libfksmbsrv/common/fake_vop.c117
-rw-r--r--usr/src/pkg/manifests/service-file-system-smb.mf2
-rw-r--r--usr/src/pkg/manifests/system-test-zfstest.mf3
-rw-r--r--usr/src/uts/common/Makefile.files1
-rw-r--r--usr/src/uts/common/fs/smbsrv/THIRDPARTYLICENSE.apple22
-rw-r--r--usr/src/uts/common/fs/smbsrv/THIRDPARTYLICENSE.apple.descrip1
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_aapl.c241
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_create.c41
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_qinfo_file.c11
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_query_dir.c117
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_open.c48
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_fsops.c9
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c136
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c131
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_open_andx.c129
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_opipe.c17
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_pathname.c38
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c5
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_find.c17
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree_connect.c40
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_vops.c27
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_scan.c7
-rw-r--r--usr/src/uts/common/smbsrv/ntifs.h4
-rw-r--r--usr/src/uts/common/smbsrv/smb.h27
-rw-r--r--usr/src/uts/common/smbsrv/smb2.h5
-rw-r--r--usr/src/uts/common/smbsrv/smb2_aapl.h253
-rw-r--r--usr/src/uts/common/smbsrv/smb2_kproto.h5
-rw-r--r--usr/src/uts/common/smbsrv/smb_ktypes.h4
34 files changed, 1423 insertions, 272 deletions
diff --git a/usr/src/boot/Makefile.version b/usr/src/boot/Makefile.version
index d3fafb7152..5febd80a06 100644
--- a/usr/src/boot/Makefile.version
+++ b/usr/src/boot/Makefile.version
@@ -33,4 +33,4 @@ LOADER_VERSION = 1.1
# Use date like formatting here, YYYY.MM.DD.XX, without leading zeroes.
# The version is processed from left to right, the version number can only
# be increased.
-BOOT_VERSION = $(LOADER_VERSION)-2019.05.14.1
+BOOT_VERSION = $(LOADER_VERSION)-2019.05.17.1
diff --git a/usr/src/boot/lib/libstand/dosfs.c b/usr/src/boot/lib/libstand/dosfs.c
index 1732511b07..d4bc2c9834 100644
--- a/usr/src/boot/lib/libstand/dosfs.c
+++ b/usr/src/boot/lib/libstand/dosfs.c
@@ -152,7 +152,7 @@ dos_read_fatblk(DOS_FS *fs, struct open_file *fd, uint_t blknum)
daddr_t offset_in_fat, max_offset_in_fat;
offset_in_fat = ((daddr_t)blknum) * FATBLKSZ;
- max_offset_in_fat = secbyt(fs->spf);
+ max_offset_in_fat = secbyt((daddr_t)fs->spf);
io_size = FATBLKSZ;
if (offset_in_fat > max_offset_in_fat)
offset_in_fat = max_offset_in_fat;
@@ -692,7 +692,7 @@ cp_xdnm(uchar_t *lfn, DOS_XDE *xde)
return;
}
if (xde->seq & 0x40)
- *lfn = 0;
+ *lfn = 0;
}
/*
diff --git a/usr/src/boot/lib/libstand/zfs/zfsimpl.c b/usr/src/boot/lib/libstand/zfs/zfsimpl.c
index b3edf4653a..23632e98c0 100644
--- a/usr/src/boot/lib/libstand/zfs/zfsimpl.c
+++ b/usr/src/boot/lib/libstand/zfs/zfsimpl.c
@@ -1708,7 +1708,7 @@ fzap_list(const spa_t *spa, const dnode_phys_t *dnode, int (*callback)(const cha
zap_leaf_t zl;
zl.l_bs = z.zap_block_shift;
for (i = 0; i < zh.zap_num_leafs; i++) {
- off_t off = (i + 1) << zl.l_bs;
+ off_t off = ((off_t)(i + 1)) << zl.l_bs;
char name[256], *p;
uint64_t value;
@@ -1871,7 +1871,7 @@ fzap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t v
zap_leaf_t zl;
zl.l_bs = z.zap_block_shift;
for (i = 0; i < zh.zap_num_leafs; i++) {
- off_t off = (i + 1) << zl.l_bs;
+ off_t off = ((off_t)(i + 1)) << zl.l_bs;
if (dnode_read(spa, dnode, off, zap_scratch, bsize))
return (EIO);
diff --git a/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c b/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c
index 254ccf5af1..b19498b96e 100644
--- a/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c
+++ b/usr/src/cmd/mdb/intel/mdb/proc_amd64dep.c
@@ -25,6 +25,7 @@
*/
/*
* Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2019 Doma Gergő Mihály <doma.gergo.mihaly@gmail.com>
*/
/*
@@ -287,48 +288,110 @@ fpcw2str(uint32_t cw, char *buf, size_t nbytes)
buf[0] = '\0';
/*
- * Decode all masks in the 80387 control word.
+ * Decode all exception masks in the x87 FPU Control Word.
+ *
+ * See here:
+ * Intel® 64 and IA-32 Architectures Software Developer’s Manual,
+ * Volume 1: Basic Architecture, 8.1.5 x87 FPU Control Word
*/
- if (cw & FPIM)
+ if (cw & FPIM) /* Invalid operation mask. */
p += mdb_snprintf(p, (size_t)(end - p), "|IM");
- if (cw & FPDM)
+ if (cw & FPDM) /* Denormalized operand mask. */
p += mdb_snprintf(p, (size_t)(end - p), "|DM");
- if (cw & FPZM)
+ if (cw & FPZM) /* Zero divide mask. */
p += mdb_snprintf(p, (size_t)(end - p), "|ZM");
- if (cw & FPOM)
+ if (cw & FPOM) /* Overflow mask. */
p += mdb_snprintf(p, (size_t)(end - p), "|OM");
- if (cw & FPUM)
+ if (cw & FPUM) /* Underflow mask. */
p += mdb_snprintf(p, (size_t)(end - p), "|UM");
- if (cw & FPPM)
+ if (cw & FPPM) /* Precision mask. */
p += mdb_snprintf(p, (size_t)(end - p), "|PM");
- if (cw & FPPC)
- p += mdb_snprintf(p, (size_t)(end - p), "|PC");
- if (cw & FPRC)
- p += mdb_snprintf(p, (size_t)(end - p), "|RC");
- if (cw & FPIC)
- p += mdb_snprintf(p, (size_t)(end - p), "|IC");
/*
- * Decode precision, rounding, and infinity options in control word.
+ * Decode precision control options.
*/
- if (cw & FPSIG53)
+ switch (cw & FPPC) {
+ case FPSIG24:
+ /* 24-bit significand, single precision. */
+ p += mdb_snprintf(p, (size_t)(end - p), "|SIG24");
+ break;
+ case FPSIG53:
+ /* 53-bit significand, double precision. */
p += mdb_snprintf(p, (size_t)(end - p), "|SIG53");
- if (cw & FPSIG64)
+ break;
+ case FPSIG64:
+ /* 64-bit significand, double extended precision. */
p += mdb_snprintf(p, (size_t)(end - p), "|SIG64");
+ break;
+ default:
+ /*
+ * Should never happen.
+ * Value 0x00000100 is 'Reserved'.
+ */
+ break;
+ }
- if ((cw & FPRC) == (FPRD|FPRU))
- p += mdb_snprintf(p, (size_t)(end - p), "|RTZ");
- else if (cw & FPRD)
+ /*
+ * Decode rounding control options.
+ */
+ switch (cw & FPRC) {
+ case FPRTN:
+ /* Round to nearest, or to even if equidistant. */
+ p += mdb_snprintf(p, (size_t)(end - p), "|RTN");
+ break;
+ case FPRD:
+ /* Round down. */
p += mdb_snprintf(p, (size_t)(end - p), "|RD");
- else if (cw & FPRU)
+ break;
+ case FPRU:
+ /* Round up. */
p += mdb_snprintf(p, (size_t)(end - p), "|RU");
- else
- p += mdb_snprintf(p, (size_t)(end - p), "|RTN");
+ break;
+ case FPCHOP:
+ /* Truncate. */
+ p += mdb_snprintf(p, (size_t)(end - p), "|RTZ");
+ break;
+ default:
+ /*
+ * This is a two-bit field.
+ * No other options left.
+ */
+ break;
+ }
- if (cw & FPA)
- p += mdb_snprintf(p, (size_t)(end - p), "|A");
- else
+ /*
+ * Decode infinity control options.
+ *
+ * This field has been retained for compatibility with
+ * the 287 and earlier co-processors.
+ * In the more modern FPUs, this bit is disregarded and
+ * both -infinity and +infinity are respected.
+ * Comment source: SIMPLY FPU by Raymond Filiatreault
+ */
+ switch (cw & FPIC) {
+ case FPP:
+ /*
+ * Projective infinity.
+ * Both -infinity and +infinity are treated as
+ * unsigned infinity.
+ */
p += mdb_snprintf(p, (size_t)(end - p), "|P");
+ break;
+ case FPA:
+ /*
+ * Affine infinity.
+ * Respects both -infinity and +infinity.
+ */
+ p += mdb_snprintf(p, (size_t)(end - p), "|A");
+ break;
+ default:
+ /*
+ * This is a one-bit field.
+ * No other options left.
+ */
+ break;
+ }
+
if (cw & WFPB17)
p += mdb_snprintf(p, (size_t)(end - p), "|WFPB17");
if (cw & WFPB24)
diff --git a/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c b/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c
index 4efba18e4b..728ece57a8 100644
--- a/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c
+++ b/usr/src/cmd/mdb/intel/mdb/proc_ia32dep.c
@@ -25,6 +25,7 @@
*/
/*
* Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2019 Doma Gergő Mihály <doma.gergo.mihaly@gmail.com>
*/
/*
@@ -228,48 +229,110 @@ fpcw2str(uint32_t cw, char *buf, size_t nbytes)
buf[0] = '\0';
/*
- * Decode all masks in the 80387 control word.
+ * Decode all exception masks in the x87 FPU Control Word.
+ *
+ * See here:
+ * Intel® 64 and IA-32 Architectures Software Developer’s Manual,
+ * Volume 1: Basic Architecture, 8.1.5 x87 FPU Control Word
*/
- if (cw & FPIM)
+ if (cw & FPIM) /* Invalid operation mask. */
p += mdb_snprintf(p, (size_t)(end - p), "|IM");
- if (cw & FPDM)
+ if (cw & FPDM) /* Denormalized operand mask. */
p += mdb_snprintf(p, (size_t)(end - p), "|DM");
- if (cw & FPZM)
+ if (cw & FPZM) /* Zero divide mask. */
p += mdb_snprintf(p, (size_t)(end - p), "|ZM");
- if (cw & FPOM)
+ if (cw & FPOM) /* Overflow mask. */
p += mdb_snprintf(p, (size_t)(end - p), "|OM");
- if (cw & FPUM)
+ if (cw & FPUM) /* Underflow mask. */
p += mdb_snprintf(p, (size_t)(end - p), "|UM");
- if (cw & FPPM)
+ if (cw & FPPM) /* Precision mask. */
p += mdb_snprintf(p, (size_t)(end - p), "|PM");
- if (cw & FPPC)
- p += mdb_snprintf(p, (size_t)(end - p), "|PC");
- if (cw & FPRC)
- p += mdb_snprintf(p, (size_t)(end - p), "|RC");
- if (cw & FPIC)
- p += mdb_snprintf(p, (size_t)(end - p), "|IC");
/*
- * Decode precision, rounding, and infinity options in control word.
+ * Decode precision control options.
*/
- if (cw & FPSIG53)
+ switch (cw & FPPC) {
+ case FPSIG24:
+ /* 24-bit significand, single precision. */
+ p += mdb_snprintf(p, (size_t)(end - p), "|SIG24");
+ break;
+ case FPSIG53:
+ /* 53-bit significand, double precision. */
p += mdb_snprintf(p, (size_t)(end - p), "|SIG53");
- if (cw & FPSIG64)
+ break;
+ case FPSIG64:
+ /* 64-bit significand, double extended precision. */
p += mdb_snprintf(p, (size_t)(end - p), "|SIG64");
+ break;
+ default:
+ /*
+ * Should never happen.
+ * Value 0x00000100 is 'Reserved'.
+ */
+ break;
+ }
- if ((cw & FPRC) == (FPRD|FPRU))
- p += mdb_snprintf(p, (size_t)(end - p), "|RTZ");
- else if (cw & FPRD)
+ /*
+ * Decode rounding control options.
+ */
+ switch (cw & FPRC) {
+ case FPRTN:
+ /* Round to nearest, or to even if equidistant. */
+ p += mdb_snprintf(p, (size_t)(end - p), "|RTN");
+ break;
+ case FPRD:
+ /* Round down. */
p += mdb_snprintf(p, (size_t)(end - p), "|RD");
- else if (cw & FPRU)
+ break;
+ case FPRU:
+ /* Round up. */
p += mdb_snprintf(p, (size_t)(end - p), "|RU");
- else
- p += mdb_snprintf(p, (size_t)(end - p), "|RTN");
+ break;
+ case FPCHOP:
+ /* Truncate. */
+ p += mdb_snprintf(p, (size_t)(end - p), "|RTZ");
+ break;
+ default:
+ /*
+ * This is a two-bit field.
+ * No other options left.
+ */
+ break;
+ }
- if (cw & FPA)
- p += mdb_snprintf(p, (size_t)(end - p), "|A");
- else
+ /*
+ * Decode infinity control options.
+ *
+ * This field has been retained for compatibility with
+ * the 287 and earlier co-processors.
+ * In the more modern FPUs, this bit is disregarded and
+ * both -infinity and +infinity are respected.
+ * Comment source: SIMPLY FPU by Raymond Filiatreault
+ */
+ switch (cw & FPIC) {
+ case FPP:
+ /*
+ * Projective infinity.
+ * Both -infinity and +infinity are treated as
+ * unsigned infinity.
+ */
p += mdb_snprintf(p, (size_t)(end - p), "|P");
+ break;
+ case FPA:
+ /*
+ * Affine infinity.
+ * Respects both -infinity and +infinity.
+ */
+ p += mdb_snprintf(p, (size_t)(end - p), "|A");
+ break;
+ default:
+ /*
+ * This is a one-bit field.
+ * No other options left.
+ */
+ break;
+ }
+
if (cw & WFPB17)
p += mdb_snprintf(p, (size_t)(end - p), "|WFPB17");
if (cw & WFPB24)
diff --git a/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com b/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com
index 168343801b..8512488b42 100644
--- a/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com
+++ b/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com
@@ -122,6 +122,7 @@ OBJS_FS_SMBSRV = \
smb_vss.o \
smb_write.o \
\
+ smb2_aapl.o \
smb2_dispatch.o \
smb2_cancel.o \
smb2_change_notify.o \
diff --git a/usr/src/lib/smbsrv/libfksmbsrv/common/fake_vop.c b/usr/src/lib/smbsrv/libfksmbsrv/common/fake_vop.c
index 41c301fbaa..fdb1d82f5c 100644
--- a/usr/src/lib/smbsrv/libfksmbsrv/common/fake_vop.c
+++ b/usr/src/lib/smbsrv/libfksmbsrv/common/fake_vop.c
@@ -10,11 +10,12 @@
*/
/*
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/t_lock.h>
#include <sys/errno.h>
#include <sys/cred.h>
@@ -27,9 +28,11 @@
#include <sys/stat.h>
#include <sys/mode.h>
#include <sys/kmem.h>
+#include <sys/cmn_err.h>
#include <sys/debug.h>
#include <sys/atomic.h>
#include <sys/acl.h>
+#include <sys/filio.h>
#include <sys/flock.h>
#include <sys/nbmlock.h>
#include <sys/fcntl.h>
@@ -50,6 +53,7 @@ int stat_to_vattr(const struct stat *, vattr_t *);
int fop__getxvattr(vnode_t *, xvattr_t *);
int fop__setxvattr(vnode_t *, xvattr_t *);
+static void fake_inactive_xattrdir(vnode_t *);
/* ARGSUSED */
int
@@ -305,6 +309,75 @@ fop_access(
return (0);
}
+/*
+ * Conceptually like xattr_dir_lookup()
+ */
+static int
+fake_lookup_xattrdir(
+ vnode_t *dvp,
+ vnode_t **vpp)
+{
+ int len, fd;
+ int omode = O_RDWR | O_NOFOLLOW;
+ vnode_t *vp;
+
+ *vpp = NULL;
+
+ if (dvp->v_type != VDIR && dvp->v_type != VREG)
+ return (EINVAL);
+
+ /*
+ * If we're already in sysattr space, don't allow creation
+ * of another level of sysattrs.
+ */
+ if (dvp->v_flag & V_SYSATTR)
+ return (EINVAL);
+
+ mutex_enter(&dvp->v_lock);
+ if (dvp->v_xattrdir != NULL) {
+ *vpp = dvp->v_xattrdir;
+ VN_HOLD(*vpp);
+ mutex_exit(&dvp->v_lock);
+ return (0);
+ }
+ mutex_exit(&dvp->v_lock);
+
+ omode = O_RDONLY|O_XATTR;
+ fd = openat(dvp->v_fd, ".", omode);
+ if (fd < 0)
+ return (errno);
+
+ vp = vn_alloc(KM_SLEEP);
+ vp->v_fd = fd;
+ vp->v_flag = V_XATTRDIR|V_SYSATTR;
+ vp->v_type = VDIR;
+ vp->v_vfsp = dvp->v_vfsp;
+
+ /* Set v_path to parent path + "/@" (like NFS) */
+ len = strlen(dvp->v_path) + 3;
+ vp->v_path = kmem_alloc(len, KM_SLEEP);
+ (void) snprintf(vp->v_path, len, "%s/@", dvp->v_path);
+
+ /*
+ * Keep a pointer to the parent and a hold on it.
+ * Both are cleaned up in fake_inactive_xattrdir
+ */
+ vp->v_data = dvp;
+ vn_hold(dvp);
+
+ mutex_enter(&dvp->v_lock);
+ if (dvp->v_xattrdir == NULL) {
+ *vpp = dvp->v_xattrdir = vp;
+ mutex_exit(&dvp->v_lock);
+ } else {
+ *vpp = dvp->v_xattrdir;
+ mutex_exit(&dvp->v_lock);
+ fake_inactive_xattrdir(vp);
+ }
+
+ return (0);
+}
+
/* ARGSUSED */
int
fop_lookup(
@@ -325,7 +398,7 @@ fop_lookup(
struct stat st;
if (flags & LOOKUP_XATTR)
- return (ENOENT);
+ return (fake_lookup_xattrdir(dvp, vpp));
/*
* If lookup is for "", just return dvp.
@@ -681,7 +754,43 @@ fop_inactive(
cred_t *cr,
caller_context_t *ct)
{
- vncache_inactive(vp);
+ if (vp->v_flag & V_XATTRDIR) {
+ fake_inactive_xattrdir(vp);
+ } else {
+ vncache_inactive(vp);
+ }
+}
+
+/*
+ * The special xattr directories are not in the vncache AVL, but
+ * hang off the parent's v_xattrdir field. When vn_rele finds
+ * an xattr dir at v_count == 1 it calls here, but until we
+ * take locks on both the parent and the xattrdir, we don't
+ * know if we're really at the last reference. So in here we
+ * take both locks, re-check the count, and either bail out
+ * or proceed with "inactive" vnode cleanup. Part of that
+ * cleanup includes releasing the hold on the parent and
+ * clearing the parent's v_xattrdir field, which were
+ * setup in fake_lookup_xattrdir()
+ */
+static void
+fake_inactive_xattrdir(vnode_t *vp)
+{
+ vnode_t *dvp = vp->v_data; /* parent */
+ mutex_enter(&dvp->v_lock);
+ mutex_enter(&vp->v_lock);
+ if (vp->v_count > 1) {
+ /* new ref. via v_xattrdir */
+ mutex_exit(&vp->v_lock);
+ mutex_exit(&dvp->v_lock);
+ return;
+ }
+ ASSERT(dvp->v_xattrdir == vp);
+ dvp->v_xattrdir = NULL;
+ mutex_exit(&vp->v_lock);
+ mutex_exit(&dvp->v_lock);
+ vn_rele(dvp);
+ vn_free(vp);
}
/* ARGSUSED */
@@ -1267,7 +1376,7 @@ vn_rele(vnode_t *vp)
mutex_enter(&vp->v_lock);
if (vp->v_count == 1) {
mutex_exit(&vp->v_lock);
- vncache_inactive(vp);
+ fop_inactive(vp, NULL, NULL);
} else {
vp->v_count--;
mutex_exit(&vp->v_lock);
diff --git a/usr/src/pkg/manifests/service-file-system-smb.mf b/usr/src/pkg/manifests/service-file-system-smb.mf
index ba5dedcd6d..bb8f384499 100644
--- a/usr/src/pkg/manifests/service-file-system-smb.mf
+++ b/usr/src/pkg/manifests/service-file-system-smb.mf
@@ -106,5 +106,7 @@ legacy pkg=SUNWsmbsu desc="SMB Server libraries and commands" \
name="SMB Server (Usr)"
license cr_Sun license=cr_Sun
license lic_CDDL license=lic_CDDL
+license usr/src/uts/common/fs/smbsrv/THIRDPARTYLICENSE.apple \
+ license=usr/src/uts/common/fs/smbsrv/THIRDPARTYLICENSE.apple
link path=usr/lib/reparse/libreparse_smb.so target=libreparse_smb.so.1
link path=usr/lib/security/pam_smb_passwd.so target=pam_smb_passwd.so.1
diff --git a/usr/src/pkg/manifests/system-test-zfstest.mf b/usr/src/pkg/manifests/system-test-zfstest.mf
index aeb7288efc..febf7ac38c 100644
--- a/usr/src/pkg/manifests/system-test-zfstest.mf
+++ b/usr/src/pkg/manifests/system-test-zfstest.mf
@@ -374,6 +374,8 @@ file path=opt/zfs-tests/tests/functional/bootfs/bootfs_005_neg mode=0555
file path=opt/zfs-tests/tests/functional/bootfs/bootfs_006_pos mode=0555
file path=opt/zfs-tests/tests/functional/bootfs/bootfs_007_pos mode=0555
file path=opt/zfs-tests/tests/functional/bootfs/bootfs_008_pos mode=0555
+file path=opt/zfs-tests/tests/functional/bootfs/cleanup mode=0555
+file path=opt/zfs-tests/tests/functional/bootfs/setup mode=0555
file path=opt/zfs-tests/tests/functional/cache/cache.cfg mode=0444
file path=opt/zfs-tests/tests/functional/cache/cache.kshlib mode=0444
file path=opt/zfs-tests/tests/functional/cache/cache_001_pos mode=0555
@@ -2426,6 +2428,7 @@ file path=opt/zfs-tests/tests/functional/pool_names/pool_names_001_pos \
file path=opt/zfs-tests/tests/functional/pool_names/pool_names_002_neg \
mode=0555
file path=opt/zfs-tests/tests/functional/poolversion/cleanup mode=0555
+file path=opt/zfs-tests/tests/functional/poolversion/poolversion.cfg mode=0444
file path=opt/zfs-tests/tests/functional/poolversion/poolversion_001_pos \
mode=0555
file path=opt/zfs-tests/tests/functional/poolversion/poolversion_002_pos \
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 895cfeeff7..f69c7e42cd 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1225,6 +1225,7 @@ SMBSRV_OBJS += $(SMBSRV_SHARED_OBJS) \
smb_vss.o \
smb_write.o \
\
+ smb2_aapl.o \
smb2_dispatch.o \
smb2_cancel.o \
smb2_change_notify.o \
diff --git a/usr/src/uts/common/fs/smbsrv/THIRDPARTYLICENSE.apple b/usr/src/uts/common/fs/smbsrv/THIRDPARTYLICENSE.apple
new file mode 100644
index 0000000000..e2af52745c
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/THIRDPARTYLICENSE.apple
@@ -0,0 +1,22 @@
+/*
+ * 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@
+ */
diff --git a/usr/src/uts/common/fs/smbsrv/THIRDPARTYLICENSE.apple.descrip b/usr/src/uts/common/fs/smbsrv/THIRDPARTYLICENSE.apple.descrip
new file mode 100644
index 0000000000..a3cf7a4a77
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/THIRDPARTYLICENSE.apple.descrip
@@ -0,0 +1 @@
+PORTIONS OF SMBSRV IN SMB SERVER
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_aapl.c b/usr/src/uts/common/fs/smbsrv/smb2_aapl.c
new file mode 100644
index 0000000000..0989fdaf6e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb2_aapl.c
@@ -0,0 +1,241 @@
+/*
+ * 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 2015 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Create context handler for "AAPL" extensions.
+ * See: smbsrv/smb2_aapl.h for documentation.
+ */
+
+#include <smbsrv/smb2_kproto.h>
+#include <smbsrv/smb2_aapl.h>
+#include <smbsrv/smb_fsops.h>
+
+/* SMB2 AAPL extensions: enabled? */
+int smb2_aapl_extensions = 1;
+uint64_t smb2_aapl_server_caps =
+ kAAPL_SUPPORTS_READ_DIR_ATTR;
+ /* | kAAPL_SUPPORTS_OSX_COPYFILE; (not yet) */
+ /* | kAAPL_UNIX_BASED; */
+/*
+ * We could turn on kAAPL_UNIX_BASED above and report UNIX modes in
+ * directory listings (see smb2_aapl_get_macinfo below) but don't
+ * because the modes ZFS presents with non-trivial ACLs cause mac
+ * clients to misbehave when copying files from the share to local.
+ * For example, we may have a file that we can read, but which has
+ * mode 0200. When the mac copies such a file to the local disk,
+ * the copy cannot be opened for read. For now just turn off the
+ * kAAPL_UNIX_BASED flag. Later we might set this flag and return
+ * modes only when we have a trivial ACL.
+ */
+
+/*
+ * Normally suppress file IDs for MacOS because it
+ * requires them to be unique per share, and ours
+ * can have duplicates under .zfs or sub-mounts.
+ */
+int smb2_aapl_use_file_ids = 0;
+
+static uint32_t smb2_aapl_srv_query(smb_request_t *,
+ mbuf_chain_t *, mbuf_chain_t *);
+
+static int smb_aapl_ext_maxlen = 512;
+
+/*
+ * Decode an AAPL create context (command code) and build the
+ * corresponding AAPL c.c. response.
+ */
+uint32_t
+smb2_aapl_crctx(smb_request_t *sr,
+ mbuf_chain_t *mbcin,
+ mbuf_chain_t *mbcout)
+{
+ uint32_t cmdcode;
+ uint32_t status;
+ int rc;
+
+ if (smb2_aapl_extensions == 0)
+ return (NT_STATUS_NOT_SUPPORTED);
+
+ rc = smb_mbc_decodef(mbcin, "l4.", &cmdcode);
+ if (rc != 0)
+ return (NT_STATUS_INFO_LENGTH_MISMATCH);
+ mbcout->max_bytes = smb_aapl_ext_maxlen;
+ (void) smb_mbc_encodef(mbcout, "ll", cmdcode, 0);
+
+ switch (cmdcode) {
+ case kAAPL_SERVER_QUERY:
+ status = smb2_aapl_srv_query(sr, mbcin, mbcout);
+ break;
+ case kAAPL_RESOLVE_ID:
+ default:
+ status = NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ return (status);
+}
+
+/*
+ * Handle an AAPL c.c. kAAPL_SERVER_QUERY
+ * Return our Mac-ish capabilities. We also need to remember
+ * that this client wants AAPL readdir etc.
+ * Typically see: client_bitmap=7, client_caps=7
+ */
+static uint32_t
+smb2_aapl_srv_query(smb_request_t *sr,
+ mbuf_chain_t *mbcin, mbuf_chain_t *mbcout)
+{
+ uint64_t client_bitmap;
+ uint64_t client_caps;
+ uint64_t server_bitmap;
+ int rc;
+
+ rc = smb_mbc_decodef(
+ mbcin, "qq",
+ &client_bitmap,
+ &client_caps);
+ if (rc != 0)
+ return (NT_STATUS_INFO_LENGTH_MISMATCH);
+
+ smb_rwx_rwenter(&sr->session->s_lock, RW_WRITER);
+
+ /* Remember that this is a MacOS client. */
+ sr->session->native_os = NATIVE_OS_MACOS;
+ sr->session->s_flags |= SMB_SSN_AAPL_CCEXT;
+
+ /*
+ * Select which parts of the bitmap we use.
+ */
+ server_bitmap = client_bitmap &
+ (kAAPL_SERVER_CAPS | kAAPL_VOLUME_CAPS);
+ (void) smb_mbc_encodef(mbcout, "q", server_bitmap);
+
+ if ((server_bitmap & kAAPL_SERVER_CAPS) != 0) {
+ uint64_t server_caps =
+ smb2_aapl_server_caps & client_caps;
+ if (server_caps & kAAPL_SUPPORTS_READ_DIR_ATTR)
+ sr->session->s_flags |= SMB_SSN_AAPL_READDIR;
+ (void) smb_mbc_encodef(mbcout, "q", server_caps);
+ }
+ if ((server_bitmap & kAAPL_VOLUME_CAPS) != 0) {
+ (void) smb_mbc_encodef(mbcout, "q", 0);
+ }
+
+ /* Pad2, null model string. */
+ (void) smb_mbc_encodef(mbcout, "ll", 0, 0);
+
+ smb_rwx_rwexit(&sr->session->s_lock);
+
+ return (0);
+}
+
+/*
+ * Get additional information about a directory entry
+ * needed when MacOS is using the AAPL extensions.
+ * This is called after smb_odir_read_fileinfo has
+ * filled in the fileinfo. This fills in macinfo.
+ *
+ * This does a couple FS operations per directory entry.
+ * That has some cost, but if we don't do it for them here,
+ * the client has to make two more round trips for each
+ * directory entry, which is much worse.
+ */
+int
+smb2_aapl_get_macinfo(smb_request_t *sr, smb_odir_t *od,
+ smb_fileinfo_t *fileinfo, smb_macinfo_t *mi,
+ char *tbuf, size_t tbuflen)
+{
+ int rc;
+ cred_t *kcr = zone_kcred();
+ smb_node_t *fnode, *snode;
+ smb_attr_t attr;
+ uint32_t AfpInfo[15];
+
+ bzero(mi, sizeof (*mi));
+
+ rc = smb_fsop_lookup(sr, od->d_cred, SMB_CASE_SENSITIVE,
+ od->d_tree->t_snode, od->d_dnode, fileinfo->fi_name, &fnode);
+ if (rc != 0)
+ return (rc);
+ /* Note: hold ref on fnode, must release */
+
+ smb_fsop_eaccess(sr, od->d_cred, fnode, &mi->mi_maxaccess);
+
+ /*
+ * mi_rforksize
+ * Get length of stream: "AFP_Resource"
+ * Return size=zero if not found.
+ */
+ (void) snprintf(tbuf, tbuflen, "%s:AFP_Resource", fileinfo->fi_name);
+ rc = smb_fsop_lookup_name(sr, kcr, 0, sr->tid_tree->t_snode,
+ od->d_dnode, tbuf, &snode);
+ if (rc == 0) {
+ bzero(&attr, sizeof (attr));
+ attr.sa_mask = SMB_AT_SIZE | SMB_AT_ALLOCSZ;
+ rc = smb_node_getattr(NULL, snode, kcr, NULL, &attr);
+ if (rc == 0) {
+ mi->mi_rforksize = attr.sa_vattr.va_size;
+ }
+ smb_node_release(snode);
+ snode = NULL;
+ }
+
+ /*
+ * mi_finder
+ * Get contents of stream: "AFP_AfpInfo"
+ * read 60 bytes, copy 32 bytes at off 16
+ */
+ (void) snprintf(tbuf, tbuflen, "%s:AFP_AfpInfo", fileinfo->fi_name);
+ rc = smb_fsop_lookup_name(sr, kcr, 0, sr->tid_tree->t_snode,
+ od->d_dnode, tbuf, &snode);
+ if (rc == 0) {
+ iovec_t iov;
+ uio_t uio;
+
+ bzero(&AfpInfo, sizeof (AfpInfo));
+ bzero(&uio, sizeof (uio));
+
+ iov.iov_base = (void *) &AfpInfo;
+ iov.iov_len = sizeof (AfpInfo);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_resid = sizeof (AfpInfo);
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_extflg = UIO_COPY_DEFAULT;
+ rc = smb_fsop_read(sr, kcr, snode, &uio);
+ if (rc == 0 && uio.uio_resid == 0) {
+ bcopy(&AfpInfo[4], &mi->mi_finderinfo,
+ sizeof (mi->mi_finderinfo));
+ }
+ smb_node_release(snode);
+ snode = NULL;
+ }
+
+ /*
+ * Later: Fill in the mode if we have a trivial ACL
+ * (otherwise leaving it zero as we do now).
+ */
+ if (smb2_aapl_server_caps & kAAPL_UNIX_BASED) {
+ bzero(&attr, sizeof (attr));
+ attr.sa_mask = SMB_AT_MODE;
+ rc = smb_node_getattr(NULL, fnode, kcr, NULL, &attr);
+ if (rc == 0) {
+ mi->mi_unixmode = (uint16_t)attr.sa_vattr.va_mode;
+ }
+ }
+
+ smb_node_release(fnode);
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_create.c b/usr/src/uts/common/fs/smbsrv/smb2_create.c
index 870ac656b4..8e9801c151 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_create.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_create.c
@@ -34,7 +34,7 @@
#define CCTX_TIMEWARP_TOKEN 0x40
#define CCTX_QUERY_ON_DISK_ID 0x80
#define CCTX_REQUEST_LEASE 0x100
-
+#define CCTX_AAPL_EXT 0x200
typedef struct smb2_create_ctx_elem {
uint32_t cce_len;
@@ -52,9 +52,11 @@ typedef struct smb2_create_ctx {
smb2_create_ctx_elem_t cc_in_alloc_size;
smb2_create_ctx_elem_t cc_in_time_warp;
smb2_create_ctx_elem_t cc_in_req_lease;
+ smb2_create_ctx_elem_t cc_in_aapl;
/* Elements we my place in the response */
smb2_create_ctx_elem_t cc_out_max_access;
smb2_create_ctx_elem_t cc_out_file_id;
+ smb2_create_ctx_elem_t cc_out_aapl;
} smb2_create_ctx_t;
static uint32_t smb2_decode_create_ctx(
@@ -362,6 +364,24 @@ smb2_create(smb_request_t *sr)
/* reserved (16 bytes) .15. */
cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID;
}
+ if ((cctx.cc_in_flags & CCTX_AAPL_EXT) != 0) {
+ cce = &cctx.cc_out_aapl;
+ /*
+ * smb2_aapl_crctx has a variable response depending on
+ * what the incoming context looks like, so it does all
+ * the work of building cc_out_aapl, including setting
+ * cce_len, cce_mbc.max_bytes, and smb_mbc_encode.
+ * If we see errors getting this, simply omit it from
+ * the collection of returned create contexts.
+ */
+ status = smb2_aapl_crctx(sr,
+ &cctx.cc_in_aapl.cce_mbc, &cce->cce_mbc);
+ if (status == 0) {
+ cce->cce_len = cce->cce_mbc.chain_offset;
+ cctx.cc_out_flags |= CCTX_AAPL_EXT;
+ }
+ status = 0;
+ }
if (cctx.cc_out_flags) {
sr->raw_data.max_bytes = smb2_max_trans;
status = smb2_encode_create_ctx(&sr->raw_data, &cctx);
@@ -520,6 +540,10 @@ smb2_decode_create_ctx(mbuf_chain_t *in_mbc, smb2_create_ctx_t *cc)
cc->cc_in_flags |= CCTX_REQUEST_LEASE;
cce = &cc->cc_in_req_lease;
break;
+ case SMB2_CREATE_CTX_AAPL: /* ("AAPL") */
+ cc->cc_in_flags |= CCTX_AAPL_EXT;
+ cce = &cc->cc_in_aapl;
+ break;
default:
/*
* Unknown create context values are normal, and
@@ -598,6 +622,17 @@ smb2_encode_create_ctx(mbuf_chain_t *mbc, smb2_create_ctx_t *cc)
mbc->chain_offset - last_top);
}
+ if (cc->cc_out_flags & CCTX_AAPL_EXT) {
+ cce = &cc->cc_out_aapl;
+ last_top = mbc->chain_offset;
+ rc = smb2_encode_create_ctx_elem(mbc, cce,
+ SMB2_CREATE_CTX_AAPL);
+ if (rc)
+ return (NT_STATUS_INTERNAL_ERROR);
+ (void) smb_mbc_poke(mbc, last_top, "l",
+ mbc->chain_offset - last_top);
+ }
+
if (last_top >= 0)
(void) smb_mbc_poke(mbc, last_top, "l", 0);
@@ -665,4 +700,8 @@ smb2_free_create_ctx(smb2_create_ctx_t *cc)
cce = &cc->cc_out_file_id;
MBC_FLUSH(&cce->cce_mbc);
}
+ if (cc->cc_out_flags & CCTX_AAPL_EXT) {
+ cce = &cc->cc_out_aapl;
+ MBC_FLUSH(&cce->cce_mbc);
+ }
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_qinfo_file.c b/usr/src/uts/common/fs/smbsrv/smb2_qinfo_file.c
index e4242c72e6..ab682b7966 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_qinfo_file.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_qinfo_file.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -86,6 +86,7 @@ smb2_qinfo_file(smb_request_t *sr, smb_queryinfo_t *qi)
case FileStreamInformation:
mask = SMB_AT_STANDARD;
+ getstd = B_TRUE;
break;
case FileCompressionInformation:
@@ -288,12 +289,18 @@ static uint32_t
smb2_qif_internal(smb_request_t *sr, smb_queryinfo_t *qi)
{
smb_attr_t *sa = &qi->qi_attr;
+ u_longlong_t nodeid;
ASSERT((sa->sa_mask & SMB_AT_NODEID) == SMB_AT_NODEID);
+ nodeid = sa->sa_vattr.va_nodeid;
+
+ if (smb2_aapl_use_file_ids == 0 &&
+ (sr->session->s_flags & SMB_SSN_AAPL_CCEXT) != 0)
+ nodeid = 0;
(void) smb_mbc_encodef(
&sr->raw_data, "q",
- sa->sa_vattr.va_nodeid); /* q */
+ nodeid); /* q */
return (0);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_query_dir.c b/usr/src/uts/common/fs/smbsrv/smb2_query_dir.c
index 03d4382862..98f2dc4ad1 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_query_dir.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_query_dir.c
@@ -22,7 +22,7 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -32,6 +32,14 @@
*/
#include <smbsrv/smb2_kproto.h>
+#include <smbsrv/smb2_aapl.h>
+
+/*
+ * Internally defined info. level for MacOS support.
+ * Make sure this does not conflict with real values in
+ * FILE_INFORMATION_CLASS, and that it fits in 8-bits.
+ */
+#define FileIdMacOsDirectoryInformation (FileMaximumInformation + 10)
/*
* Args (and other state) that we carry around among the
@@ -46,12 +54,17 @@ typedef struct smb2_find_args {
uint16_t fa_fixedsize; /* size of fixed part of a returned entry */
uint32_t fa_lastkey; /* Last resume key */
int fa_last_entry; /* offset of last entry */
+
+ /* Normal info, per dir. entry */
+ smb_fileinfo_t fa_fi;
+
+ /* MacOS AAPL extension stuff. */
+ smb_macinfo_t fa_mi;
} smb2_find_args_t;
static uint32_t smb2_find_entries(smb_request_t *,
smb_odir_t *, smb2_find_args_t *);
-static uint32_t smb2_find_mbc_encode(smb_request_t *,
- smb_fileinfo_t *, smb2_find_args_t *);
+static uint32_t smb2_find_mbc_encode(smb_request_t *, smb2_find_args_t *);
/*
* Tunable parameter to limit the maximum
@@ -62,8 +75,8 @@ uint16_t smb2_find_max = 128;
smb_sdrc_t
smb2_query_dir(smb_request_t *sr)
{
- smb2_find_args_t args;
- smb_odir_resume_t odir_resume;
+ smb2_find_args_t args;
+ smb_odir_resume_t odir_resume;
smb_ofile_t *of = NULL;
smb_odir_t *od = NULL;
char *pattern = NULL;
@@ -142,10 +155,8 @@ smb2_query_dir(smb_request_t *sr)
sr->raw_data.max_bytes = args.fa_maxdata;
/*
- * Get the mininum size of entries we will return, which
+ * Get the fixed size of entries we will return, which
* lets us estimate the number of entries we'll need.
- * This should be the size with a one character name.
- * Compare w/ smb2_find_get_maxdata().
*
* Also use this opportunity to validate fa_infoclass.
*/
@@ -174,6 +185,19 @@ smb2_query_dir(smb_request_t *sr)
goto errout;
}
+ /*
+ * MacOS, when using the AAPL CreateContext extensions
+ * and the "read dir attr" feature, uses a non-standard
+ * information format for directory entries. Internally
+ * we'll use a fake info level to represent this case.
+ * (Wish they had just defined a new info level.)
+ */
+ if ((sr->session->s_flags & SMB_SSN_AAPL_READDIR) != 0 &&
+ args.fa_infoclass == FileIdBothDirectoryInformation) {
+ args.fa_infoclass = FileIdMacOsDirectoryInformation;
+ args.fa_fixedsize = 96; /* yes, same size */
+ }
+
args.fa_maxcount = args.fa_maxdata / (args.fa_fixedsize + 4);
if (args.fa_maxcount == 0)
args.fa_maxcount = 1;
@@ -279,8 +303,9 @@ errout:
static uint32_t
smb2_find_entries(smb_request_t *sr, smb_odir_t *od, smb2_find_args_t *args)
{
- smb_fileinfo_t fileinfo;
smb_odir_resume_t odir_resume;
+ char *tbuf = NULL;
+ size_t tbuflen = 0;
uint16_t count;
uint16_t minsize;
uint32_t status = 0;
@@ -293,6 +318,16 @@ smb2_find_entries(smb_request_t *sr, smb_odir_t *od, smb2_find_args_t *args)
*/
minsize = args->fa_fixedsize + 2;
+ /*
+ * FileIdMacOsDirectoryInformation needs some buffer space
+ * for composing directory entry + stream name for lookup.
+ * Get the buffer now to avoid alloc/free per entry.
+ */
+ if (args->fa_infoclass == FileIdMacOsDirectoryInformation) {
+ tbuflen = 2 * MAXNAMELEN;
+ tbuf = kmem_alloc(tbuflen, KM_SLEEP);
+ }
+
count = 0;
while (count < args->fa_maxcount) {
@@ -301,7 +336,8 @@ smb2_find_entries(smb_request_t *sr, smb_odir_t *od, smb2_find_args_t *args)
break;
}
- rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &args->fa_eos);
+ rc = smb_odir_read_fileinfo(sr, od,
+ &args->fa_fi, &args->fa_eos);
if (rc == ENOENT) {
status = NT_STATUS_NO_MORE_FILES;
break;
@@ -316,7 +352,15 @@ smb2_find_entries(smb_request_t *sr, smb_odir_t *od, smb2_find_args_t *args)
break;
}
- status = smb2_find_mbc_encode(sr, &fileinfo, args);
+ if (args->fa_infoclass == FileIdMacOsDirectoryInformation)
+ (void) smb2_aapl_get_macinfo(sr, od,
+ &args->fa_fi, &args->fa_mi, tbuf, tbuflen);
+
+ if (smb2_aapl_use_file_ids == 0 &&
+ (sr->session->s_flags & SMB_SSN_AAPL_CCEXT) != 0)
+ args->fa_fi.fi_nodeid = 0;
+
+ status = smb2_find_mbc_encode(sr, args);
if (status) {
/*
* We read a directory entry but failed to
@@ -335,7 +379,7 @@ smb2_find_entries(smb_request_t *sr, smb_odir_t *od, smb2_find_args_t *args)
* Save the offset of the next entry we'll read.
* If we fail copying, we'll need this offset.
*/
- args->fa_lastkey = fileinfo.fi_cookie;
+ args->fa_lastkey = args->fa_fi.fi_cookie;
++count;
}
@@ -355,6 +399,9 @@ smb2_find_entries(smb_request_t *sr, smb_odir_t *od, smb2_find_args_t *args)
status = 0;
}
+ if (tbuf != NULL)
+ kmem_free(tbuf, tbuflen);
+
return (status);
}
@@ -379,9 +426,10 @@ smb2_find_entries(smb_request_t *sr, smb_odir_t *od, smb2_find_args_t *args)
* NT status
*/
static uint32_t
-smb2_find_mbc_encode(smb_request_t *sr, smb_fileinfo_t *fileinfo,
- smb2_find_args_t *args)
+smb2_find_mbc_encode(smb_request_t *sr, smb2_find_args_t *args)
{
+ smb_fileinfo_t *fileinfo = &args->fa_fi;
+ smb_macinfo_t *macinfo = &args->fa_mi;
uint8_t buf83[26];
smb_msgbuf_t mb;
int namelen, padsz;
@@ -524,6 +572,47 @@ smb2_find_mbc_encode(smb_request_t *sr, smb_fileinfo_t *fileinfo,
smb_msgbuf_term(&mb);
break;
+ /*
+ * MacOS, when using the AAPL extensions (see smb2_create)
+ * uses modified directory listing responses where the
+ * "EA size" field is replaced with "maximum access".
+ * This avoids the need for MacOS Finder to come back
+ * N times to get the maximum access for every file.
+ */
+ case FileIdMacOsDirectoryInformation:
+ rc = smb_mbc_encodef(
+ &sr->raw_data, "llTTTTqqll",
+ 0, /* NextEntryOffset (set later) */
+ resume_key, /* a.k.a. file index */
+ &fileinfo->fi_crtime,
+ &fileinfo->fi_atime,
+ &fileinfo->fi_mtime,
+ &fileinfo->fi_ctime,
+ fileinfo->fi_size, /* q */
+ fileinfo->fi_alloc_size, /* q */
+ fileinfo->fi_dosattr, /* l */
+ namelen); /* l */
+ if (rc != 0)
+ break;
+ /*
+ * This where FileIdMacOsDirectoryInformation
+ * differs from FileIdBothDirectoryInformation
+ * Instead of: EaSize, ShortNameLen, ShortName;
+ * MacOS wants: MaxAccess, ResourceForkSize, and
+ * 16 bytes of "compressed finder info".
+ * mi_rforksize + mi_finderinfo falls where
+ * the 24 byte shortname would normally be.
+ */
+ rc = smb_mbc_encodef(
+ &sr->raw_data, "l..q16cwq",
+ macinfo->mi_maxaccess, /* l */
+ /* short_name_len, reserved (..) */
+ macinfo->mi_rforksize, /* q */
+ macinfo->mi_finderinfo, /* 16c */
+ macinfo->mi_unixmode, /* w */
+ fileinfo->fi_nodeid); /* q */
+ break;
+
/* See also: SMB_FIND_FILE_NAMES_INFO */
case FileNamesInformation: /* 12 */
rc = smb_mbc_encodef(
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_open.c b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
index 695a2c062c..194e3a1331 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
@@ -109,7 +109,7 @@ smb_omode_to_amask(uint32_t desired_access)
return (FILE_GENERIC_READ | FILE_GENERIC_WRITE);
case SMB_DA_ACCESS_EXECUTE:
- return (FILE_GENERIC_EXECUTE);
+ return (FILE_GENERIC_READ | FILE_GENERIC_EXECUTE);
default:
return (FILE_GENERIC_ALL);
@@ -397,36 +397,11 @@ smb_open_subr(smb_request_t *sr)
cur_node = op->fqi.fq_dnode ?
op->fqi.fq_dnode : sr->tid_tree->t_snode;
- /*
- * if no path or filename are specified the stream should be
- * created on cur_node
- */
- if (!is_dir && !pn->pn_pname && !pn->pn_fname && pn->pn_sname) {
- /*
- * Can't currently handle a stream on the tree root.
- * If a stream is being opened return "not found", otherwise
- * return "access denied".
- */
- if (cur_node == sr->tid_tree->t_snode) {
- if (op->create_disposition == FILE_OPEN) {
- return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
- }
- return (NT_STATUS_ACCESS_DENIED);
- }
-
- (void) snprintf(op->fqi.fq_last_comp,
- sizeof (op->fqi.fq_last_comp),
- "%s%s", cur_node->od_name, pn->pn_sname);
-
- op->fqi.fq_dnode = cur_node->n_dnode;
- smb_node_ref(op->fqi.fq_dnode);
- } else {
- rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path,
- sr->tid_tree->t_snode, cur_node, &op->fqi.fq_dnode,
- op->fqi.fq_last_comp);
- if (rc != 0) {
- return (smb_errno2status(rc));
- }
+ rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path,
+ sr->tid_tree->t_snode, cur_node, &op->fqi.fq_dnode,
+ op->fqi.fq_last_comp);
+ if (rc != 0) {
+ return (smb_errno2status(rc));
}
/*
@@ -743,9 +718,16 @@ smb_open_subr(smb_request_t *sr)
/*
* We set alloc_size = op->dsize later,
- * after we have an ofile. See:
- * smb_set_open_attributes
+ * (in smb_set_open_attributes) after we
+ * have an ofile on which to save that.
+ *
+ * Legacy Open&X sets size to alloc_size
+ * when creating a new file.
*/
+ if (sr->smb_com == SMB_COM_OPEN_ANDX) {
+ new_attr.sa_vattr.va_size = op->dsize;
+ new_attr.sa_mask |= SMB_AT_SIZE;
+ }
rc = smb_fsop_create(sr, sr->user_cr, dnode,
op->fqi.fq_last_comp, &new_attr, &op->fqi.fq_fnode);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_fsops.c b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
index e58b065d6e..8e4bcc2939 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
@@ -1885,6 +1885,15 @@ smb_fsop_lookup(
if (SMB_TREE_SUPPORTS_ABE(sr))
flags |= SMB_ABE;
+ /*
+ * Can have "" or "." when opening named streams on a directory.
+ */
+ if (name[0] == '\0' || (name[0] == '.' && name[1] == '\0')) {
+ smb_node_ref(dnode);
+ *ret_snode = dnode;
+ return (0);
+ }
+
od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
rc = smb_vop_lookup(dnode->vp, name, &vp, od_name, flags,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
index 5b28b0778a..a787b9ed27 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -32,6 +32,8 @@
#include <smbsrv/smb_fsops.h>
#include <smbsrv/smb_vops.h>
+int smb_nt_create_enable_extended_response = 1;
+
/*
* smb_com_nt_create_andx
*
@@ -227,6 +229,9 @@ smb_post_nt_create_andx(smb_request_t *sr)
}
}
+/*
+ * A lot like smb_nt_transact_create
+ */
smb_sdrc_t
smb_com_nt_create_andx(struct smb_request *sr)
{
@@ -234,9 +239,21 @@ smb_com_nt_create_andx(struct smb_request *sr)
smb_attr_t *ap = &op->fqi.fq_fattr;
smb_ofile_t *of;
int rc;
- unsigned char DirFlag;
+ uint8_t DirFlag;
uint32_t status;
+ if (op->create_options & ~SMB_NTCREATE_VALID_OPTIONS) {
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (SDRC_ERROR);
+ }
+
+ if (op->create_options & FILE_OPEN_BY_FILE_ID) {
+ smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
+ ERRDOS, ERROR_NOT_SUPPORTED);
+ return (SDRC_ERROR);
+ }
+
if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
!(op->desired_access & DELETE)) {
smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
@@ -294,47 +311,11 @@ smb_com_nt_create_andx(struct smb_request *sr)
case STYPE_PRINTQ:
if (op->create_options & FILE_DELETE_ON_CLOSE)
smb_ofile_set_delete_on_close(of);
-
DirFlag = smb_node_is_dir(of->f_node) ? 1 : 0;
- rc = smbsr_encode_result(sr, 34, 0, "bb.wbwlTTTTlqqwwbw",
- 34,
- sr->andx_com,
- 0x67,
- op->op_oplock_level,
- sr->smb_fid,
- op->action_taken,
- &ap->sa_crtime,
- &ap->sa_vattr.va_atime,
- &ap->sa_vattr.va_mtime,
- &ap->sa_vattr.va_ctime,
- op->dattr & FILE_ATTRIBUTE_MASK,
- ap->sa_allocsz,
- ap->sa_vattr.va_size,
- op->ftype,
- op->devstate,
- DirFlag,
- 0);
break;
case STYPE_IPC:
- rc = smbsr_encode_result(sr, 34, 0, "bb.wbwlqqqqlqqwwbw",
- 34,
- sr->andx_com,
- 0x67,
- 0,
- sr->smb_fid,
- op->action_taken,
- 0LL,
- 0LL,
- 0LL,
- 0LL,
- FILE_ATTRIBUTE_NORMAL,
- 0x1000LL,
- 0LL,
- op->ftype,
- op->devstate,
- 0,
- 0);
+ DirFlag = 0;
break;
default:
@@ -342,6 +323,83 @@ smb_com_nt_create_andx(struct smb_request *sr)
ERRDOS, ERROR_INVALID_FUNCTION);
goto errout;
}
+
+ if ((op->nt_flags & NT_CREATE_FLAG_EXTENDED_RESPONSE) != 0 &&
+ smb_nt_create_enable_extended_response != 0) {
+ uint32_t MaxAccess = 0;
+ if (of->f_node != NULL) {
+ smb_fsop_eaccess(sr, of->f_cr, of->f_node, &MaxAccess);
+ }
+ MaxAccess |= of->f_granted_access;
+
+ /*
+ * Here is a really ugly protocol wart in SMB1:
+ *
+ * [MS-SMB] Sec. 2.2.4.9.2: Windows-based SMB servers
+ * send 50 (0x32) words in the extended response although
+ * they set the WordCount field to 0x2A.
+ *
+ * In other words, THEY LIE! We really do need to encode
+ * 50 words here, but lie and say we encoded 42 words.
+ * This means we can't use smbsr_encode_result() to
+ * build this response, because the rules it breaks
+ * would cause errors in smbsr_check_result().
+ *
+ * And that's not all (it gets worse...)
+ * Because of the bogus word count, some clients will
+ * read the byte count from within what should be the
+ * fileid field below. Leave that zero, like Win7.
+ *
+ * Apparently the only really useful thing in this
+ * extended response is MaxAccess.
+ */
+ sr->smb_wct = 50; /* real word count */
+ sr->smb_bcc = 0;
+ rc = smb_mbc_encodef(&sr->reply,
+ "bb.wbwlTTTTlqqwwb16.qllw",
+ 42, /* fake word count (b) */
+ sr->andx_com, /* (b.) */
+ 0x87, /* andx offset (w) */
+ op->op_oplock_level, /* (b) */
+ sr->smb_fid, /* (w) */
+ op->action_taken, /* (l) */
+ &ap->sa_crtime, /* (T) */
+ &ap->sa_vattr.va_atime, /* (T) */
+ &ap->sa_vattr.va_mtime, /* (T) */
+ &ap->sa_vattr.va_ctime, /* (T) */
+ op->dattr & FILE_ATTRIBUTE_MASK, /* (l) */
+ ap->sa_allocsz, /* (q) */
+ ap->sa_vattr.va_size, /* (q) */
+ op->ftype, /* (w) */
+ op->devstate, /* (w) */
+ DirFlag, /* (b) */
+ /* volume guid (16.) */
+ 0, /* file ID (see above) (q) */
+ MaxAccess, /* (l) */
+ 0, /* guest access (l) */
+ 0); /* byte count (w) */
+ } else {
+ rc = smbsr_encode_result(
+ sr, 34, 0, "bb.wbwlTTTTlqqwwbw",
+ 34, /* word count (b) */
+ sr->andx_com, /* (b.) */
+ 0x67, /* andx offset (w) */
+ op->op_oplock_level, /* (b) */
+ sr->smb_fid, /* (w) */
+ op->action_taken, /* (l) */
+ &ap->sa_crtime, /* (T) */
+ &ap->sa_vattr.va_atime, /* (T) */
+ &ap->sa_vattr.va_mtime, /* (T) */
+ &ap->sa_vattr.va_ctime, /* (T) */
+ op->dattr & FILE_ATTRIBUTE_MASK, /* (l) */
+ ap->sa_allocsz, /* (q) */
+ ap->sa_vattr.va_size, /* (q) */
+ op->ftype, /* (w) */
+ op->devstate, /* (w) */
+ DirFlag, /* (b) */
+ 0); /* byte count (w) */
+ }
+
if (rc == 0)
return (SDRC_SUCCESS);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
index 7a04ba2b6a..34bf2d25c9 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -36,6 +36,8 @@
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_fsops.h>
+extern int smb_nt_create_enable_extended_response;
+
/*
* smb_nt_transact_create
*
@@ -83,9 +85,9 @@ smb_pre_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
if (rc == 0) {
if (NameLength == 0) {
op->fqi.fq_path.pn_path = "\\";
- } else if (NameLength >= MAXPATHLEN) {
- smbsr_error(sr, NT_STATUS_OBJECT_PATH_NOT_FOUND,
- ERRDOS, ERROR_PATH_NOT_FOUND);
+ } else if (NameLength >= SMB_MAXPATHLEN) {
+ smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
+ ERRDOS, ERROR_INVALID_NAME);
rc = -1;
} else {
rc = smb_mbc_decodef(&xa->req_param_mb, "%#u",
@@ -132,19 +134,36 @@ smb_post_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
kmem_free(sd, sizeof (smb_sd_t));
}
- if (sr->arg.open.dir != NULL)
+ if (sr->arg.open.dir != NULL) {
smb_ofile_release(sr->arg.open.dir);
+ sr->arg.open.dir = NULL;
+ }
}
+/*
+ * A lot like smb_com_nt_create_andx
+ */
smb_sdrc_t
smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
{
- struct open_param *op = &sr->arg.open;
- uint8_t DirFlag;
- smb_attr_t attr;
+ struct open_param *op = &sr->arg.open;
+ smb_attr_t *ap = &op->fqi.fq_fattr;
smb_ofile_t *of;
- uint32_t status;
int rc;
+ uint8_t DirFlag;
+ uint32_t status;
+
+ if (op->create_options & ~SMB_NTCREATE_VALID_OPTIONS) {
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (SDRC_ERROR);
+ }
+
+ if (op->create_options & FILE_OPEN_BY_FILE_ID) {
+ smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
+ ERRDOS, ERROR_NOT_SUPPORTED);
+ return (SDRC_ERROR);
+ }
if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
!(op->desired_access & DELETE)) {
@@ -203,50 +222,11 @@ smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
case STYPE_PRINTQ:
if (op->create_options & FILE_DELETE_ON_CLOSE)
smb_ofile_set_delete_on_close(of);
-
DirFlag = smb_node_is_dir(of->f_node) ? 1 : 0;
- bzero(&attr, sizeof (attr));
- attr.sa_mask = SMB_AT_ALL;
- rc = smb_node_getattr(sr, of->f_node, of->f_cr, of, &attr);
- if (rc != 0) {
- smbsr_errno(sr, rc);
- goto errout;
- }
-
- rc = smb_mbc_encodef(&xa->rep_param_mb, "b.wllTTTTlqqwwb",
- op->op_oplock_level,
- sr->smb_fid,
- op->action_taken,
- 0, /* EaErrorOffset */
- &attr.sa_crtime,
- &attr.sa_vattr.va_atime,
- &attr.sa_vattr.va_mtime,
- &attr.sa_vattr.va_ctime,
- op->dattr & FILE_ATTRIBUTE_MASK,
- attr.sa_allocsz,
- attr.sa_vattr.va_size,
- op->ftype,
- op->devstate,
- DirFlag);
break;
case STYPE_IPC:
- bzero(&attr, sizeof (smb_attr_t));
- rc = smb_mbc_encodef(&xa->rep_param_mb, "b.wllTTTTlqqwwb",
- 0,
- sr->smb_fid,
- op->action_taken,
- 0, /* EaErrorOffset */
- &attr.sa_crtime,
- &attr.sa_vattr.va_atime,
- &attr.sa_vattr.va_mtime,
- &attr.sa_vattr.va_ctime,
- op->dattr,
- 0x1000LL,
- 0LL,
- op->ftype,
- op->devstate,
- 0);
+ DirFlag = 0;
break;
default:
@@ -254,7 +234,58 @@ smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
ERRDOS, ERROR_INVALID_FUNCTION);
goto errout;
}
- return (SDRC_SUCCESS);
+
+ if ((op->nt_flags & NT_CREATE_FLAG_EXTENDED_RESPONSE) != 0 &&
+ smb_nt_create_enable_extended_response != 0) {
+ uint32_t MaxAccess = 0;
+ if (of->f_node != NULL) {
+ smb_fsop_eaccess(sr, of->f_cr, of->f_node, &MaxAccess);
+ }
+ MaxAccess |= of->f_granted_access;
+
+ rc = smb_mbc_encodef(
+ &xa->rep_param_mb, "bbwllTTTTlqqwwb16.qll",
+ op->op_oplock_level, /* (b) */
+ 1, /* ResponseType (b) */
+ sr->smb_fid, /* (w) */
+ op->action_taken, /* (l) */
+ 0, /* EaErrorOffset (l) */
+ &ap->sa_crtime, /* (T) */
+ &ap->sa_vattr.va_atime, /* (T) */
+ &ap->sa_vattr.va_mtime, /* (T) */
+ &ap->sa_vattr.va_ctime, /* (T) */
+ op->dattr & FILE_ATTRIBUTE_MASK, /* (l) */
+ ap->sa_allocsz, /* (q) */
+ ap->sa_vattr.va_size, /* (q) */
+ op->ftype, /* (w) */
+ op->devstate, /* (w) */
+ DirFlag, /* (b) */
+ /* volume guid (16.) */
+ op->fileid, /* (q) */
+ MaxAccess, /* (l) */
+ 0); /* guest access (l) */
+ } else {
+ rc = smb_mbc_encodef(
+ &xa->rep_param_mb, "bbwllTTTTlqqwwb",
+ op->op_oplock_level, /* (b) */
+ 0, /* ResponseType (b) */
+ sr->smb_fid, /* (w) */
+ op->action_taken, /* (l) */
+ 0, /* EaErrorOffset (l) */
+ &ap->sa_crtime, /* (T) */
+ &ap->sa_vattr.va_atime, /* (T) */
+ &ap->sa_vattr.va_mtime, /* (T) */
+ &ap->sa_vattr.va_ctime, /* (T) */
+ op->dattr & FILE_ATTRIBUTE_MASK, /* (l) */
+ ap->sa_allocsz, /* (q) */
+ ap->sa_vattr.va_size, /* (q) */
+ op->ftype, /* (w) */
+ op->devstate, /* (w) */
+ DirFlag); /* (b) */
+ }
+
+ if (rc == 0)
+ return (SDRC_SUCCESS);
errout:
smb_ofile_close(of, 0);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
index e370f74747..ff26c61119 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
@@ -20,10 +20,11 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
+#include <smbsrv/smb_fsops.h>
#include <smbsrv/smb_vops.h>
int smb_open_dsize_check = 0;
@@ -316,6 +317,8 @@ errout:
return (SDRC_ERROR);
}
+int smb_openx_enable_extended_response = 1;
+
/*
* smb_pre_open_andx
* For compatibility with windows servers, the search attributes
@@ -325,7 +328,7 @@ smb_sdrc_t
smb_pre_open_andx(smb_request_t *sr)
{
struct open_param *op = &sr->arg.open;
- uint16_t flags;
+ uint16_t openx_flags;
uint32_t alloc_size;
uint32_t creation_time;
uint16_t file_attr, sattr;
@@ -334,7 +337,7 @@ smb_pre_open_andx(smb_request_t *sr)
bzero(op, sizeof (sr->arg.open));
rc = smbsr_decode_vwv(sr, "b.wwwwwlwll4.", &sr->andx_com,
- &sr->andx_off, &flags, &op->omode, &sattr,
+ &sr->andx_off, &openx_flags, &op->omode, &sattr,
&file_attr, &creation_time, &op->ofun, &alloc_size, &op->timeo);
if (rc == 0) {
@@ -343,12 +346,18 @@ smb_pre_open_andx(smb_request_t *sr)
op->dattr = file_attr;
op->dsize = alloc_size;
- if (flags & 2)
+ /*
+ * The openx_flags use some "extended" flags that
+ * happen to match some of the NtCreateX flags.
+ */
+ if (openx_flags & NT_CREATE_FLAG_REQUEST_OPLOCK)
op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
- else if (flags & 4)
+ else if (openx_flags & NT_CREATE_FLAG_REQUEST_OPBATCH)
op->op_oplock_level = SMB_OPLOCK_BATCH;
else
op->op_oplock_level = SMB_OPLOCK_NONE;
+ if (openx_flags & NT_CREATE_FLAG_EXTENDED_RESPONSE)
+ op->nt_flags |= NT_CREATE_FLAG_EXTENDED_RESPONSE;
if ((creation_time != 0) && (creation_time != UINT_MAX))
op->crtime.tv_sec =
@@ -374,10 +383,11 @@ smb_sdrc_t
smb_com_open_andx(smb_request_t *sr)
{
struct open_param *op = &sr->arg.open;
+ smb_attr_t *ap = &op->fqi.fq_fattr;
smb_ofile_t *of;
uint32_t status;
+ uint32_t mtime_sec;
uint16_t file_attr;
- smb_attr_t attr;
int rc;
op->desired_access = smb_omode_to_amask(op->omode);
@@ -414,50 +424,20 @@ smb_com_open_andx(smb_request_t *sr)
of = sr->fid_ofile;
if (op->op_oplock_level != SMB_OPLOCK_NONE)
- op->action_taken |= SMB_OACT_LOCK;
+ op->action_taken |= SMB_OACT_OPLOCK;
else
- op->action_taken &= ~SMB_OACT_LOCK;
+ op->action_taken &= ~SMB_OACT_OPLOCK;
file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
- bzero(&attr, sizeof (attr));
+ mtime_sec = smb_time_gmt_to_local(sr, ap->sa_vattr.va_mtime.tv_sec);
switch (sr->tid_tree->t_res_type & STYPE_MASK) {
case STYPE_DISKTREE:
case STYPE_PRINTQ:
- attr.sa_mask = SMB_AT_MTIME;
- rc = smb_node_getattr(sr, of->f_node, of->f_cr, of, &attr);
- if (rc != 0) {
- smbsr_errno(sr, rc);
- goto errout;
- }
-
- rc = smbsr_encode_result(sr, 15, 0,
- "bb.wwwllwwwwl2.w",
- 15,
- sr->andx_com, VAR_BCC,
- sr->smb_fid,
- file_attr,
- smb_time_gmt_to_local(sr, attr.sa_vattr.va_mtime.tv_sec),
- (uint32_t)op->dsize,
- op->omode, op->ftype,
- op->devstate,
- op->action_taken, op->fileid,
- 0);
break;
case STYPE_IPC:
- rc = smbsr_encode_result(sr, 15, 0,
- "bb.wwwllwwwwl2.w",
- 15,
- sr->andx_com, VAR_BCC,
- sr->smb_fid,
- file_attr,
- 0L,
- 0L,
- op->omode, op->ftype,
- op->devstate,
- op->action_taken, op->fileid,
- 0);
+ mtime_sec = 0;
break;
default:
@@ -466,6 +446,52 @@ smb_com_open_andx(smb_request_t *sr)
goto errout;
}
+ if ((op->nt_flags & NT_CREATE_FLAG_EXTENDED_RESPONSE) != 0 &&
+ smb_openx_enable_extended_response != 0) {
+ uint32_t MaxAccess = 0;
+ if (of->f_node != NULL) {
+ smb_fsop_eaccess(sr, of->f_cr, of->f_node, &MaxAccess);
+ }
+ MaxAccess |= of->f_granted_access;
+
+ rc = smbsr_encode_result(
+ sr, 19, 0, "bb.wwwllwwwwl2.llw",
+ 19, /* word count (b) */
+ sr->andx_com, /* (b.) */
+ VAR_BCC, /* andx offset (w) */
+ sr->smb_fid, /* (w) */
+ file_attr, /* (w) */
+ mtime_sec, /* (l) */
+ (uint32_t)op->dsize, /* (l) */
+ op->omode, /* (w) */
+ op->ftype, /* (w) */
+ op->devstate, /* (w) */
+ op->action_taken, /* (w) */
+ 0, /* legacy fileid (l) */
+ /* reserved (2.) */
+ MaxAccess, /* (l) */
+ 0, /* guest access (l) */
+ 0); /* byte count (w) */
+
+ } else {
+ rc = smbsr_encode_result(
+ sr, 15, 0, "bb.wwwllwwwwl2.w",
+ 15, /* word count (b) */
+ sr->andx_com, /* (b.) */
+ VAR_BCC, /* andx offset (w) */
+ sr->smb_fid, /* (w) */
+ file_attr, /* (w) */
+ mtime_sec, /* (l) */
+ (uint32_t)op->dsize, /* (l) */
+ op->omode, /* (w) */
+ op->ftype, /* (w) */
+ op->devstate, /* (w) */
+ op->action_taken, /* (w) */
+ 0, /* legacy fileid (l) */
+ /* reserved (2.) */
+ 0); /* byte count (w) */
+ }
+
if (rc == 0)
return (SDRC_SUCCESS);
@@ -480,6 +506,7 @@ smb_com_trans2_open2(smb_request_t *sr, smb_xa_t *xa)
struct open_param *op = &sr->arg.open;
uint32_t creation_time;
uint32_t alloc_size;
+ uint32_t ea_list_size;
uint16_t flags;
uint16_t file_attr;
uint32_t status;
@@ -493,6 +520,24 @@ smb_com_trans2_open2(smb_request_t *sr, smb_xa_t *xa)
if (rc != 0)
return (SDRC_ERROR);
+ /*
+ * The data part of this transaction may contain an EA list.
+ * See: SMB_FEA_LIST ExtendedAttributeList
+ *
+ * If we find a non-empty EA list payload, return the special
+ * error that tells the caller this FS does not suport EAs.
+ *
+ * Note: the first word is the size of the whole data segment,
+ * INCLUDING the size of that length word. That means if
+ * the length word specifies a size less than four, it's
+ * invalid (and probably a client trying something fishy).
+ */
+ rc = smb_mbc_decodef(&xa->req_data_mb, "l", &ea_list_size);
+ if (rc == 0 && ea_list_size > 4) {
+ smbsr_status(sr, NT_STATUS_EAS_NOT_SUPPORTED, 0, 0);
+ return (SDRC_ERROR);
+ }
+
if ((creation_time != 0) && (creation_time != UINT_MAX))
op->crtime.tv_sec = smb_time_local_to_gmt(sr, creation_time);
op->crtime.tv_nsec = 0;
@@ -529,9 +574,9 @@ smb_com_trans2_open2(smb_request_t *sr, smb_xa_t *xa)
}
if (op->op_oplock_level != SMB_OPLOCK_NONE)
- op->action_taken |= SMB_OACT_LOCK;
+ op->action_taken |= SMB_OACT_OPLOCK;
else
- op->action_taken &= ~SMB_OACT_LOCK;
+ op->action_taken &= ~SMB_OACT_OPLOCK;
file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_opipe.c b/usr/src/uts/common/fs/smbsrv/smb_opipe.c
index c08cba0ac6..f46ff659a8 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_opipe.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_opipe.c
@@ -212,6 +212,7 @@ int
smb_opipe_open(smb_request_t *sr, uint32_t uniqid)
{
smb_arg_open_t *op = &sr->sr_open;
+ smb_attr_t *ap = &op->fqi.fq_fattr;
smb_ofile_t *ofile;
smb_opipe_t *opipe;
smb_error_t err;
@@ -248,14 +249,19 @@ smb_opipe_open(smb_request_t *sr, uint32_t uniqid)
/* An "up" pointer, for debug. */
opipe->p_ofile = ofile;
- op->dsize = 0x01000;
- op->dattr = FILE_ATTRIBUTE_NORMAL;
+ /*
+ * Caller expects attributes in op->fqi
+ */
+ (void) smb_opipe_getattr(ofile, &op->fqi.fq_fattr);
+
+ op->dsize = 0;
+ op->dattr = ap->sa_dosattr;
+ op->fileid = ap->sa_vattr.va_nodeid;
op->ftype = SMB_FTYPE_MESG_PIPE;
- op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */
+ op->action_taken = SMB_OACT_OPLOCK | SMB_OACT_OPENED;
op->devstate = SMB_PIPE_READMODE_MESSAGE
| SMB_PIPE_TYPE_MESSAGE
| SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
- op->fileid = ofile->f_fid;
sr->smb_fid = ofile->f_fid;
sr->fid_ofile = ofile;
@@ -440,8 +446,9 @@ smb_opipe_getattr(smb_ofile_t *of, smb_attr_t *ap)
ap->sa_vattr.va_type = VFIFO;
ap->sa_vattr.va_nlink = 1;
+ ap->sa_vattr.va_nodeid = (uintptr_t)of->f_pipe;
ap->sa_dosattr = FILE_ATTRIBUTE_NORMAL;
- ap->sa_allocsz = 0x1000LL;
+ ap->sa_allocsz = SMB_PIPE_MAX_MSGSIZE;
return (0);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_pathname.c b/usr/src/uts/common/fs/smbsrv/smb_pathname.c
index 599698b78c..a8f5ae3aa4 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_pathname.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_pathname.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 2016 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
@@ -907,10 +907,10 @@ smb_pathname_validate(smb_request_t *sr, smb_pathname_t *pn)
return (B_FALSE);
}
- /* If fname is "." -> INVALID_OBJECT_NAME */
+ /* If fname is "." -> OBJECT_NAME_INVALID */
if (pn->pn_fname && (strcmp(pn->pn_fname, ".") == 0)) {
smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
- ERRDOS, ERROR_PATH_NOT_FOUND);
+ ERRDOS, ERROR_INVALID_NAME);
return (B_FALSE);
}
@@ -984,19 +984,23 @@ smb_validate_object_name(smb_request_t *sr, smb_pathname_t *pn)
*
* smb_stream_parse_name should only be called for a path that
* contains a valid named stream. Path validation should have
- * been performed before this function is called.
+ * been performed before this function is called, typically by
+ * calling smb_is_stream_name() just before this.
*
* Find the last component of path and split it into filename
* and stream name.
*
* On return the named stream type will be present. The stream
* type defaults to ":$DATA", if it has not been defined
- * For exmaple, 'stream' contains :<sname>:$DATA
+ * For example, 'stream' contains :<sname>:$DATA
+ *
+ * Output args: filename, stream both MAXNAMELEN
*/
void
smb_stream_parse_name(char *path, char *filename, char *stream)
{
char *fname, *sname, *stype;
+ size_t flen, slen;
ASSERT(path);
ASSERT(filename);
@@ -1004,12 +1008,24 @@ smb_stream_parse_name(char *path, char *filename, char *stream)
fname = strrchr(path, '\\');
fname = (fname == NULL) ? path : fname + 1;
- (void) strlcpy(filename, fname, MAXNAMELEN);
-
- sname = strchr(filename, ':');
- (void) strlcpy(stream, sname, MAXNAMELEN);
- *sname = '\0';
-
+ sname = strchr(fname, ':');
+ /* Caller makes sure there is a ':' in path. */
+ VERIFY(sname != NULL);
+ /* LINTED: possible ptrdiff_t overflow */
+ flen = sname - fname;
+ slen = strlen(sname);
+
+ if (flen > (MAXNAMELEN-1))
+ flen = (MAXNAMELEN-1);
+ (void) strncpy(filename, fname, flen);
+ filename[flen] = '\0';
+
+ if (slen > (MAXNAMELEN-1))
+ slen = (MAXNAMELEN-1);
+ (void) strncpy(stream, sname, slen);
+ stream[slen] = '\0';
+
+ /* Add a "stream type" if there isn't one. */
stype = strchr(stream + 1, ':');
if (stype == NULL)
(void) strlcat(stream, ":$DATA", MAXNAMELEN);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c b/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c
index 8f24e1e053..4405230319 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -341,8 +341,7 @@ smb_set_fileinfo(smb_request_t *sr, smb_setinfo_t *sinfo, int infolev)
break;
case SMB_INFO_SET_EAS:
- /* EAs not supported */
- status = 0;
+ status = NT_STATUS_EAS_NOT_SUPPORTED;
break;
case SMB_SET_FILE_BASIC_INFO:
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
index 6efcbf7385..cdfaf0c8ee 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
@@ -538,6 +538,21 @@ smb_trans2_find_entries(smb_request_t *sr, smb_xa_t *xa, smb_odir_t *od,
int rc = -1;
boolean_t need_rewind = B_FALSE;
+ /*
+ * EAs are not current supported, so a search for level
+ * SMB_INFO_QUERY_EAS_FROM_LIST should always return an
+ * empty list. Returning zero for this case gives the
+ * client an empty response, which is better than an
+ * NT_STATUS_INVALID_LEVEL return (and test failures).
+ *
+ * If and when we do support EAs, this level will modify
+ * the search here, and then return results just like
+ * SMB_INFO_QUERY_EA_SIZE, but only including files
+ * that have an EA in the provided list.
+ */
+ if (args->fa_infolev == SMB_INFO_QUERY_EAS_FROM_LIST)
+ return (0);
+
if ((maxcount = args->fa_maxcount) == 0)
maxcount = 1;
@@ -629,6 +644,7 @@ smb_trans2_find_get_maxdata(smb_request_t *sr, uint16_t infolev, uint16_t fflag)
break;
case SMB_INFO_QUERY_EA_SIZE:
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
maxdata += sizeof (int32_t);
maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1;
@@ -774,6 +790,7 @@ smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
break;
case SMB_INFO_QUERY_EA_SIZE:
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
resume_key);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c b/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c
index f1bb880c43..94d8be4978 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
@@ -307,17 +307,27 @@ smb_sdrc_t
smb_com_tree_connect_andx(smb_request_t *sr)
{
smb_arg_tcon_t *tcon = &sr->sr_tcon;
+ smb_tree_t *tree;
char *service;
uint32_t status;
int rc;
+ if (tcon->flags & SMB_TCONX_DISCONECT_TID) {
+ tree = smb_session_lookup_tree(sr->session, sr->smb_tid);
+ if (tree != NULL) {
+ smb_session_cancel_requests(sr->session, tree, sr);
+ smb_tree_disconnect(tree, B_TRUE);
+ }
+ }
+
status = smb_tree_connect(sr);
if (status) {
smb_tcon_puterror(sr, status);
return (SDRC_ERROR);
}
+ tree = sr->tid_tree;
- switch (sr->tid_tree->t_res_type & STYPE_MASK) {
+ switch (tree->t_res_type & STYPE_MASK) {
case STYPE_IPC:
service = "IPC";
break;
@@ -330,23 +340,37 @@ smb_com_tree_connect_andx(smb_request_t *sr)
}
if (sr->session->dialect < NT_LM_0_12) {
- rc = smbsr_encode_result(sr, 2, VAR_BCC, "bb.wwss",
+ rc = smbsr_encode_result(sr, 2, VAR_BCC, "bb.ww%ss",
(char)2, /* wct */
sr->andx_com,
VAR_BCC,
VAR_BCC,
+ sr,
service,
- sr->tid_tree->t_typename);
- } else {
- rc = smbsr_encode_result(sr, 3, VAR_BCC, "bb.wwws%u",
+ tree->t_typename);
+ } else if ((tcon->flags & SMB_TCONX_EXTENDED_RESPONSE) == 0) {
+ rc = smbsr_encode_result(sr, 3, VAR_BCC, "bb.www%su",
(char)3, /* wct */
sr->andx_com,
(short)64,
tcon->optional_support,
VAR_BCC,
- service,
sr,
- sr->tid_tree->t_typename);
+ service,
+ tree->t_typename);
+
+ } else {
+ rc = smbsr_encode_result(sr, 7, VAR_BCC, "bb.wwllw%su",
+ (char)7, /* wct (b) */
+ sr->andx_com, /* AndXcmd (b) */
+ (short)72, /* AndXoff (w) */
+ tcon->optional_support, /* (w) */
+ tree->t_access, /* (l) */
+ 0, /* guest_access (l) */
+ VAR_BCC, /* (w) */
+ sr, /* (%) */
+ service, /* (s) */
+ tree->t_typename); /* (u) */
}
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_vops.c b/usr/src/uts/common/fs/smbsrv/smb_vops.c
index 49b83a0cee..a0b38bfb7c 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_vops.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_vops.c
@@ -620,14 +620,23 @@ smb_vop_lookup(
pn_alloc(&rpn);
+ /*
+ * Easier to not have junk in rpn, as not every FS type
+ * will necessarily fill that in for us.
+ */
+ bzero(rpn.pn_buf, rpn.pn_bufsize);
+
error = VOP_LOOKUP(dvp, np, vpp, NULL, option_flags, NULL, cr,
&smb_ct, direntflags, &rpn);
if (error == 0) {
if (od_name) {
bzero(od_name, MAXNAMELEN);
- np = (option_flags == FIGNORECASE) ? rpn.pn_buf : name;
-
+ if ((option_flags & FIGNORECASE) != 0 &&
+ rpn.pn_buf[0] != '\0')
+ np = rpn.pn_buf;
+ else
+ np = name;
if (flags & SMB_CATIA)
smb_vop_catia_v4tov5(np, od_name, MAXNAMELEN);
else
@@ -678,6 +687,20 @@ smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
error = VOP_CREATE(dvp, np, vap, EXCL, attr->sa_vattr.va_mode,
vpp, cr, option_flags, &smb_ct, vsap);
+ /*
+ * One could argue that filesystems should obey the size
+ * if specified in the create attributes. Unfortunately,
+ * they only appear to let you truncate the size to zero.
+ * SMB needs to set a non-zero size, so work-around.
+ */
+ if (error == 0 && *vpp != NULL &&
+ (vap->va_mask & AT_SIZE) != 0 &&
+ vap->va_size > 0) {
+ vattr_t ta = *vap;
+ ta.va_mask = AT_SIZE;
+ (void) VOP_SETATTR(*vpp, &ta, 0, cr, &smb_ct);
+ }
+
return (error);
}
diff --git a/usr/src/uts/common/fs/zfs/dsl_scan.c b/usr/src/uts/common/fs/zfs/dsl_scan.c
index ca82195178..78c8c2a581 100644
--- a/usr/src/uts/common/fs/zfs/dsl_scan.c
+++ b/usr/src/uts/common/fs/zfs/dsl_scan.c
@@ -3432,6 +3432,13 @@ count_block(dsl_scan_t *scn, zfs_all_blkstats_t *zab, const blkptr_t *bp)
int i;
/*
+ * Don't count embedded bp's, since we already did the work of
+ * scanning these when we scanned the containing block.
+ */
+ if (BP_IS_EMBEDDED(bp))
+ return;
+
+ /*
* Update the spa's stats on how many bytes we have issued.
* Sequential scrubs create a zio for each DVA of the bp. Each
* of these will include all DVAs for repair purposes, but the
diff --git a/usr/src/uts/common/smbsrv/ntifs.h b/usr/src/uts/common/smbsrv/ntifs.h
index 79dcbf91da..bb3d7146c1 100644
--- a/usr/src/uts/common/smbsrv/ntifs.h
+++ b/usr/src/uts/common/smbsrv/ntifs.h
@@ -21,6 +21,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
*/
@@ -190,7 +192,7 @@ extern "C" {
#define FILE_RESERVED1 0x00400000
#define FILE_RESERVED2 0x00800000
-#define FILE_VALID_OPTION_FLAGS 0x007fffff
+#define FILE_VALID_OPTION_FLAGS 0x00ffffff
#define FILE_VALID_PIPE_OPTION_FLAGS 0x00000032
#define FILE_VALID_MAILSLOT_OPTION_FLAGS 0x00000032
#define FILE_VALID_SET_FLAGS 0x00000036
diff --git a/usr/src/uts/common/smbsrv/smb.h b/usr/src/uts/common/smbsrv/smb.h
index 65e2708569..c151a2a388 100644
--- a/usr/src/uts/common/smbsrv/smb.h
+++ b/usr/src/uts/common/smbsrv/smb.h
@@ -202,7 +202,15 @@ typedef uint32_t smb_utime_t;
#define NT_CREATE_FLAG_REQUEST_OPLOCK 0x02
#define NT_CREATE_FLAG_REQUEST_OPBATCH 0x04
#define NT_CREATE_FLAG_OPEN_TARGET_DIR 0x08
+#define NT_CREATE_FLAG_EXTENDED_RESPONSE 0x10
+/*
+ * The option flags valid in the SMB nt_create_andx call are a subset of
+ * those defined in ntifs.h (ditto SMB nt_transact_create)
+ */
+#define SMB_NTCREATE_VALID_OPTIONS (FILE_VALID_OPTION_FLAGS & ~( \
+ FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT |\
+ FILE_RESERVE_OPFILTER))
/*
* Define the filter flags for NtNotifyChangeDirectoryFile
@@ -417,6 +425,23 @@ typedef uint32_t smb_utime_t;
#define DIALECT_SMB2XXX 13 /* SMB 2.??? (switch to SMB2) */
/*
+ * SMB_TREE_CONNECT_ANDX request flags
+ *
+ * The tree specified by TID in the SMB header
+ * should be disconnected - disconnect errors
+ * should be ignored.
+ */
+#define SMB_TCONX_DISCONECT_TID 0x0001
+/*
+ * Client request for signing key protection.
+ */
+#define SMB_TCONX_EXTENDED_SIGNATURES 0x0004
+/*
+ * Client request for extended information.
+ */
+#define SMB_TCONX_EXTENDED_RESPONSE 0x0008
+
+/*
* SMB_TREE_CONNECT_ANDX OptionalSupport flags
*
* SMB_SUPPORT_SEARCH_BITS The server supports SearchAttributes.
@@ -637,11 +662,9 @@ typedef uint32_t smb_utime_t;
* 3 - The file existed and was truncated
*/
-#define SMB_OACT_LOCK 0x8000
#define SMB_OACT_OPENED 0x01
#define SMB_OACT_CREATED 0x02
#define SMB_OACT_TRUNCATED 0x03
-
#define SMB_OACT_OPLOCK 0x8000
#define SMB_FTYPE_DISK 0
diff --git a/usr/src/uts/common/smbsrv/smb2.h b/usr/src/uts/common/smbsrv/smb2.h
index c072f8233c..1a16c15cd3 100644
--- a/usr/src/uts/common/smbsrv/smb2.h
+++ b/usr/src/uts/common/smbsrv/smb2.h
@@ -263,6 +263,11 @@ typedef enum {
* This value is only supported for the SMB 2.1 and 3.0 dialects.
*/
+#define SMB2_CREATE_CTX_AAPL 0x4141504c /* ("AAPL") */
+/*
+ * Client is MacOS X looking for MacOS-specific extensions.
+ */
+
/* SMB2 create request lease */
#define SMB2_LEASE_NONE 0x00
#define SMB2_LEASE_READ_CACHING 0x01
diff --git a/usr/src/uts/common/smbsrv/smb2_aapl.h b/usr/src/uts/common/smbsrv/smb2_aapl.h
new file mode 100644
index 0000000000..c3dcf9c518
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb2_aapl.h
@@ -0,0 +1,253 @@
+/*
+ * 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@
+ */
+
+/*
+ * This content was published as: smb-759.0/kernel/netsmb/smb_2.h
+ * in http://opensource.apple.com/source/smb/smb-759.0.tar.gz
+ */
+
+#ifndef _SMB2AAPL_H
+#define _SMB2AAPL_H
+
+#include <sys/types.h>
+
+/*
+ * Apple SMB 2/3 "AAPL" Create Context extensions
+ */
+
+/* Define "AAPL" Context Command Codes */
+enum {
+ kAAPL_SERVER_QUERY = 1,
+ kAAPL_RESOLVE_ID = 2
+};
+
+/*
+ * Server Query Request
+ *
+ * uint32_t command_code = kAAPL_SERVER_QUERY;
+ * uint32_t reserved = 0;
+ * uint64_t request_bitmap;
+ * uint64_t client_capabilities;
+ *
+ * Server Query Response
+ *
+ * uint32_t command_code = kAAPL_SERVER_QUERY;
+ * uint32_t reserved = 0;
+ * uint64_t reply_bitmap;
+ * <reply specific data>
+ *
+ * The reply data is packed in the response block in the order specified
+ * by the reply_bitmap.
+ *
+ * Server Query request/reply bitmap
+ * Bit 0 - kAAPL_SERVER_CAPS returns uint64_t bitmap of server capabilities
+ * Bit 1 - kAAPL_VOLUME_CAPS returns uint64_t bitmap of volume capabilities
+ * Bit 2 - kAAPL_MODEL_INFO returns uint32_t Pad2 followed by uint32_t length
+ * followed by the Unicode model string. The Unicode string is padded with
+ * zeros to end on an 8 byte boundary.
+ *
+ * Example Server Query Context Response Buffer:
+ * uint32_t Next = 0;
+ * uint16_t NameOffset = 16;
+ * uint16_t NameLength = 4;
+ * uint16_t Reserved = 0;
+ * uint16_t DataOffset = 24;
+ * uint32_t DataLength = variable based on ModelString length;
+ * uint32_t ContextName = "AAPL";
+ * uint32_t Pad = 0;
+ * uint32_t CommandCode = kAAPL_SERVER_QUERY
+ * uint32_t Reserved = 0;
+ * uint64_t ReplyBitmap = kAAPL_SERVER_CAPS | kAAPL_VOLUME_CAPS |
+ * kAAPL_MODEL_INFO;
+ * uint64_t ServerCaps = kAAPL_SUPPORTS_READ_DIR_ATTR |
+ * kAAPL_SUPPORTS_OSX_COPYFILE;
+ * uint64_t VolumeCaps = kAAPL_SUPPORT_RESOLVE_ID | kAAPL_CASE_SENSITIVE;
+ * uint32_t Pad2 = 0;
+ * uint32_t ModelStringLen = variable;
+ * char * ModelString;
+ * char PadBytes = variable to end on 8 byte boundary;
+ *
+ * kAAPL_SUPPORTS_NFS_ACE - Uses to set Posix permission when ACLs are off
+ * on the server. The server must allow the client to get the current
+ * ACL and then the client will return it with the desired Posix
+ * permissions in the NFS ACE in the ACL.
+ */
+
+/* Define Server Query request/response bitmap */
+enum {
+ kAAPL_SERVER_CAPS = 0x01,
+ kAAPL_VOLUME_CAPS = 0x02,
+ kAAPL_MODEL_INFO = 0x04
+};
+
+/* Define Client/Server Capabilities bitmap */
+enum {
+ kAAPL_SUPPORTS_READ_DIR_ATTR = 0x01,
+ kAAPL_SUPPORTS_OSX_COPYFILE = 0x02,
+ kAAPL_UNIX_BASED = 0x04,
+ kAAPL_SUPPORTS_NFS_ACE = 0x08
+};
+
+/* Define Volume Capabilities bitmap */
+enum {
+ kAAPL_SUPPORT_RESOLVE_ID = 0x01,
+ kAAPL_CASE_SENSITIVE = 0x02
+};
+
+/*
+ * Resolve ID Request
+ *
+ * uint32_t command_code = kAAPL_RESOLVE_ID;
+ * uint32_t reserved = 0;
+ * uint64_t file_id;
+ *
+ * Resolve ID Response
+ *
+ * uint32_t command_code = kAAPL_RESOLVE_ID;
+ * uint32_t reserved = 0;
+ * uint32_t resolve_id_ntstatus;
+ * uint32_t path_string_len = variable;
+ * char * path_string;
+ *
+ * Example Resolve ID Context Response Buffer:
+ * uint32_t Next = 0;
+ * uint16_t NameOffset = 16;
+ * uint16_t NameLength = 4;
+ * uint16_t Reserved = 0;
+ * uint16_t DataOffset = 24;
+ * uint32_t DataLength = variable based on PathString length;
+ * uint32_t ContextName = "AAPL";
+ * uint32_t Pad = 0;
+ * uint32_t CommandCode = kAAPL_RESOLVE_ID;
+ * uint32_t Reserved = 0;
+ * uint32_t ResolveID_NTStatus = 0;
+ * uint32_t ServerPathLen = variable;
+ * char * ServerPath;
+ * char PadBytes = variable to end on 8 byte boundary;
+ */
+
+/*
+ * ReadDirAttr Support
+ *
+ * Server has to support AAPL Create Context and support the
+ * command of kAAPL_SERVER_QUERY. In the ReplyBitMap, kAAPL_SERVER_CAPS
+ * has to be set and in the ServerCaps field, kAAPL_SUPPORTS_READ_DIR_ATTR
+ * must be set.
+ *
+ * Client uses FILE_ID_BOTH_DIR_INFORMATION for QueryDir
+ *
+ * In the Server reply for FILE_ID_BOTH_DIR_INFORMATION, fields are defined as:
+ * uint32_t ea_size;
+ * uint8_t short_name_len;
+ * uint8_t reserved;
+ * uint8_t short_name[24];
+ * uint16_t reserved2;
+ *
+ * If kAAPL_SUPPORTS_READ_DIR_ATTR is set, the fields will be filled in as:
+ * uint32_t max_access;
+ * uint8_t short_name_len = 0;
+ * uint8_t reserved = 0;
+ * uint64_t rsrc_fork_len;
+ * uint8_t compressed_finder_info[16];
+ * uint16_t unix_mode; (only if kAAPL_UNIX_BASED is set)
+ *
+ * Notes:
+ * (1) ea_size is the max access if SMB_EFA_REPARSE_POINT is NOT set in
+ * the file attributes. For a reparse point, the SMB Client will assume
+ * full access.
+ * (2) short_name is now the Resource Fork logical length and minimal
+ * Finder Info.
+ * (3) SMB Cient will calculate the resource fork allocation size based on
+ * block size. This will be done in all places resource fork allocation
+ * size is returned by the SMB Client so we return consistent answers.
+ * (4) Compressed Finder Info will be only the fields actually still in
+ * use in the regular Finder Info and in the Ext Finder Info. SMB client
+ * will build a normal Finder Info and Ext Finder Info and fill in the
+ * other fields in with zeros.
+ * (5) If kAAPL_UNIX_BASED is set, then reserved2 is the entire Posix mode
+ *
+ * struct smb_finder_file_info {
+ * uint32_t finder_type;
+ * uint32_t finder_creator;
+ * uint16_t finder_flags;
+ * uint16_t finder_ext_flags;
+ * uint32_t finder_date_added;
+ * }
+ *
+ * struct smb_finder_folder_info {
+ * uint64_t reserved1;
+ * uint16_t finder_flags;
+ * uint16_t finder_ext_flags;
+ * uint32_t finder_date_added;
+ * }
+ *
+ *
+ * Normal Finder Info and Extended Finder Info definitions
+ * struct finder_file_info {
+ * uint32_t finder_type;
+ * uint32_t finder_creator;
+ * uint16_t finder_flags;
+ * uint32_t finder_old_location = 0;
+ * uint16_t reserved = 0;
+ *
+ * uint32_t reserved2 = 0;
+ * uint32_t finder_date_added;
+ * uint16_t finder_ext_flags;
+ * uint16_t reserved3 = 0;
+ * uint32_t reserved4 = 0;
+ * }
+ *
+ * struct finder_folder_info {
+ * uint64_t reserved1;
+ * uint16_t finder_flags;
+ * uint32_t finder_old_location = 0;
+ * uint16_t finder_old_view_flags = 0;
+ *
+ * uint32_t finder_old_scroll_position = 0;
+ * uint32_t finder_date_added;
+ * uint16_t finder_ext_flags;
+ * uint16_t reserved3 = 0;
+ * uint32_t reserved4 = 0;
+ * }
+ */
+
+/*
+ * Note: If you use the above smb_finder_* structs, they must be "packed".
+ * (no alignment padding). On the server side, all of these can be
+ * opaque, so for simplicity we use smb_macinfo_t below.
+ */
+
+/*
+ * Implementation specific:
+ */
+typedef struct smb_macinfo {
+ uint64_t mi_rforksize;
+ uint32_t mi_finderinfo[4];
+ uint32_t mi_maxaccess;
+ uint16_t mi_unixmode;
+} smb_macinfo_t;
+
+int smb2_aapl_get_macinfo(smb_request_t *, smb_odir_t *,
+ smb_fileinfo_t *, smb_macinfo_t *, char *, size_t);
+
+#endif /* _SMB2AAPL_H */
diff --git a/usr/src/uts/common/smbsrv/smb2_kproto.h b/usr/src/uts/common/smbsrv/smb2_kproto.h
index 17ac24ed36..5714438cc6 100644
--- a/usr/src/uts/common/smbsrv/smb2_kproto.h
+++ b/usr/src/uts/common/smbsrv/smb2_kproto.h
@@ -27,6 +27,8 @@ extern uint32_t smb2_tcp_rcvbuf;
extern uint32_t smb2_max_rwsize;
extern uint32_t smb2_max_trans;
+extern int smb2_aapl_use_file_ids;
+
void smb2_dispatch_stats_init(smb_server_t *);
void smb2_dispatch_stats_fini(smb_server_t *);
void smb2_dispatch_stats_update(smb_server_t *,
@@ -73,6 +75,9 @@ smb_sdrc_t smb2_oplock_break_ack(smb_request_t *);
int smb2_newrq_negotiate(smb_request_t *);
+uint32_t smb2_aapl_crctx(smb_request_t *,
+ mbuf_chain_t *, mbuf_chain_t *);
+
uint32_t smb2_ofile_getattr(smb_request_t *, smb_ofile_t *, smb_attr_t *);
uint32_t smb2_ofile_getstd(smb_ofile_t *, smb_queryinfo_t *);
uint32_t smb2_ofile_getname(smb_ofile_t *, smb_queryinfo_t *);
diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h
index c6a22a6406..e765ec5614 100644
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h
@@ -849,6 +849,10 @@ typedef enum {
SMB_SESSION_STATE_SENTINEL
} smb_session_state_t;
+/* Bits in s_flags below */
+#define SMB_SSN_AAPL_CCEXT 1 /* Saw "AAPL" create ctx. ext. */
+#define SMB_SSN_AAPL_READDIR 2 /* Wants MacOS ext. readdir */
+
typedef struct smb_session {
list_node_t s_lnd;
uint32_t s_magic;