diff options
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; |