Print this page
NEX-19378 Access problem with SMB server
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-19152 MacOS HighSierra Finder crashes...
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-13644 File access audit logging
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-17779 Creating named streams on existing files is not quite right
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-17289 Minimal SMB 3.0.2 support
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-2807 Restoring previous versions from snapshots doesn't work with nested folders.
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-13653 Obsolete SMB server work-around for ZFS read-only
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-6276 SMB sparse file support
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5844 want SMB2 ioctl FSCTL_SRV_COPYCHUNK
NEX-6124 smb_fsop_read/write should allow file != sr->fid_ofile
NEX-6125 smbtorture invalid response with smb2.ioctl
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-6041 Should pass the smbtorture lock tests
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-4474 SMB open with access=MAXIMUM_ALLOWED fails after NEX-3232
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
SMB-58 smbsrv should be immune to its own FEM hooks
SMB-50 User-mode SMB server
 Includes work by these authors:
 Thomas Keiser <thomas.keiser@nexenta.com>
 Albert Lee <trisk@nexenta.com>
SMB-65 SMB server in non-global zones (use zone_kcred())
SMB-63 taskq_create_proc ... TQ_DYNAMIC puts tasks in p0
re #11974 CIFS Share - Tree connect fails from Windows 7 Clients
SUS-172 Excel 2003 warning dialog when re-saving a file
SUS-173 Open fails if the client does not ask for read_attribute permission
re #7815 SMB server delivers old modification time...
re #11215 rb3676 sesctl to SGI JBOD hangs in biowait() with a command stuck in mptsas driver
re #10734 NT Trans. Notify returning too quickly

*** 18,43 **** * * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2015 Nexenta Systems, Inc. All rights reserved. */ #include <sys/sid.h> #include <sys/nbmlock.h> #include <smbsrv/smb_fsops.h> #include <smbsrv/smb_kproto.h> #include <acl/acl_common.h> #include <sys/fcntl.h> #include <sys/flock.h> #include <fs/fs_subr.h> extern caller_context_t smb_ct; ! static int smb_fsop_create_stream(smb_request_t *, cred_t *, smb_node_t *, ! char *, char *, int, smb_attr_t *, smb_node_t **); static int smb_fsop_create_file(smb_request_t *, cred_t *, smb_node_t *, char *, int, smb_attr_t *, smb_node_t **); #ifdef _KERNEL --- 18,44 ---- * * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include <sys/sid.h> #include <sys/nbmlock.h> #include <smbsrv/smb_fsops.h> #include <smbsrv/smb_kproto.h> #include <acl/acl_common.h> #include <sys/fcntl.h> + #include <sys/filio.h> #include <sys/flock.h> #include <fs/fs_subr.h> extern caller_context_t smb_ct; ! static int smb_fsop_create_file_with_stream(smb_request_t *, cred_t *, ! smb_node_t *, char *, char *, int, smb_attr_t *, smb_node_t **); static int smb_fsop_create_file(smb_request_t *, cred_t *, smb_node_t *, char *, int, smb_attr_t *, smb_node_t **); #ifdef _KERNEL
*** 131,142 **** --- 132,145 ---- cred_t *kcr = zone_kcred(); int aclbsize = 0; /* size of acl list in bytes */ int flags = 0; int rc; boolean_t is_dir; + boolean_t do_audit; ASSERT(fs_sd); + ASSERT(ret_snode != NULL); if (SMB_TREE_IS_CASEINSENSITIVE(sr)) flags = SMB_IGNORE_CASE; if (SMB_TREE_SUPPORTS_CATIA(sr)) flags |= SMB_CATIA;
*** 143,152 **** --- 146,156 ---- ASSERT(cr); is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0); + do_audit = smb_audit_init(sr); if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACLONCREATE)) { if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { dacl = fs_sd->sd_zdacl; sacl = fs_sd->sd_zsacl; ASSERT(dacl || sacl);
*** 181,190 **** --- 185,200 ---- if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_FILE) != 0) rc = smb_vop_create(dnode->vp, name, attr, &vp, flags, cr, vsap); } + if (do_audit) { + smb_audit_fini(sr, + is_dir ? ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE, + dnode, rc == 0); + } + if (vsap != NULL) kmem_free(vsap->vsa_aclentp, aclbsize); if (rc != 0) return (rc);
*** 235,244 **** --- 245,260 ---- } else { rc = smb_vop_create(dnode->vp, name, attr, &vp, flags, cr, NULL); } + if (do_audit) { + smb_audit_fini(sr, + is_dir ? ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE, + dnode, rc == 0); + } + if (rc != 0) return (rc); *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, name, dnode, NULL);
*** 317,327 **** if (smb_is_stream_name(name)) { fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); smb_stream_parse_name(name, fname, sname); ! rc = smb_fsop_create_stream(sr, cr, dnode, fname, sname, flags, attr, ret_snode); kmem_free(fname, MAXNAMELEN); kmem_free(sname, MAXNAMELEN); return (rc); --- 333,343 ---- if (smb_is_stream_name(name)) { fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); smb_stream_parse_name(name, fname, sname); ! rc = smb_fsop_create_file_with_stream(sr, cr, dnode, fname, sname, flags, attr, ret_snode); kmem_free(fname, MAXNAMELEN); kmem_free(sname, MAXNAMELEN); return (rc);
*** 346,385 **** } /* ! * smb_fsop_create_stream * ! * Create NTFS named stream file (sname) on unnamed stream ! * file (fname), creating the unnamed stream file if it * doesn't exist. ! * If we created the unnamed stream file and then creation ! * of the named stream file fails, we delete the unnamed stream. * Since we use the real file name for the smb_vop_remove we * clear the SMB_IGNORE_CASE flag to ensure a case sensitive * match. * ! * The second parameter of smb_vop_setattr() is set to ! * NULL, even though an unnamed stream exists. This is ! * because we want to set the UID and GID on the named ! * stream in this case for consistency with the (unnamed ! * stream) file (see comments for smb_vop_setattr()). */ static int ! smb_fsop_create_stream(smb_request_t *sr, cred_t *cr, smb_node_t *dnode, char *fname, char *sname, int flags, smb_attr_t *attr, smb_node_t **ret_snode) { - smb_attr_t fattr; smb_node_t *fnode; - vnode_t *xattrdvp; - vnode_t *vp; cred_t *kcr = zone_kcred(); int rc = 0; boolean_t fcreate = B_FALSE; /* Look up / create the unnamed stream, fname */ rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, sr->tid_tree->t_snode, dnode, fname, &fnode); if (rc == ENOENT) { fcreate = B_TRUE; --- 362,399 ---- } /* ! * smb_fsop_create_file_with_stream * ! * Create named stream (sname) on file (fname), creating the file if it * doesn't exist. ! * If we created the file and then creation of the named stream fails, ! * we delete the file. * Since we use the real file name for the smb_vop_remove we * clear the SMB_IGNORE_CASE flag to ensure a case sensitive * match. * ! * Note that some stream "types" are "restricted" and only ! * internal callers (cr == kcred) can create those. */ static int ! smb_fsop_create_file_with_stream(smb_request_t *sr, cred_t *cr, smb_node_t *dnode, char *fname, char *sname, int flags, smb_attr_t *attr, smb_node_t **ret_snode) { smb_node_t *fnode; cred_t *kcr = zone_kcred(); int rc = 0; boolean_t fcreate = B_FALSE; + ASSERT(ret_snode != NULL); + + if (cr != kcr && smb_strname_restricted(sname)) + return (EACCES); + /* Look up / create the unnamed stream, fname */ rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, sr->tid_tree->t_snode, dnode, fname, &fnode); if (rc == ENOENT) { fcreate = B_TRUE;
*** 387,438 **** attr, &fnode); } if (rc != 0) return (rc); ! fattr.sa_mask = SMB_AT_UID | SMB_AT_GID; ! rc = smb_vop_getattr(fnode->vp, NULL, &fattr, 0, kcr); - if (rc == 0) { - /* create the named stream, sname */ - rc = smb_vop_stream_create(fnode->vp, sname, attr, - &vp, &xattrdvp, flags, cr); - } if (rc != 0) { if (fcreate) { flags &= ~SMB_IGNORE_CASE; (void) smb_vop_remove(dnode->vp, fnode->od_name, flags, cr); } smb_node_release(fnode); return (rc); } attr->sa_vattr.va_uid = fattr.sa_vattr.va_uid; attr->sa_vattr.va_gid = fattr.sa_vattr.va_gid; attr->sa_mask = SMB_AT_UID | SMB_AT_GID; rc = smb_vop_setattr(vp, NULL, attr, 0, kcr); if (rc != 0) { ! smb_node_release(fnode); return (rc); } *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdvp, vp, sname); - smb_node_release(fnode); VN_RELE(xattrdvp); VN_RELE(vp); if (*ret_snode == NULL) rc = ENOMEM; /* notify change to the unnamed stream */ if (rc == 0) smb_node_notify_change(dnode, ! FILE_ACTION_ADDED_STREAM, fname); return (rc); } /* --- 401,491 ---- attr, &fnode); } if (rc != 0) return (rc); ! rc = smb_fsop_create_stream(sr, cr, dnode, fnode, sname, flags, attr, ! ret_snode); if (rc != 0) { if (fcreate) { flags &= ~SMB_IGNORE_CASE; (void) smb_vop_remove(dnode->vp, fnode->od_name, flags, cr); } + } + smb_node_release(fnode); return (rc); + } + + /* + * smb_fsop_create_stream + * + * Create named stream (sname) on existing file (fnode). + * + * The second parameter of smb_vop_setattr() is set to + * NULL, even though an unnamed stream exists. This is + * because we want to set the UID and GID on the named + * stream in this case for consistency with the (unnamed + * stream) file (see comments for smb_vop_setattr()). + * + * Note that some stream "types" are "restricted" and only + * internal callers (cr == kcred) can create those. + */ + int + smb_fsop_create_stream(smb_request_t *sr, cred_t *cr, + smb_node_t *dnode, smb_node_t *fnode, char *sname, int flags, + smb_attr_t *attr, smb_node_t **ret_snode) + { + smb_attr_t fattr; + vnode_t *xattrdvp; + vnode_t *vp; + cred_t *kcr = zone_kcred(); + int rc = 0; + + ASSERT(ret_snode != NULL); + + if (cr != kcr && smb_strname_restricted(sname)) + return (EACCES); + + bzero(&fattr, sizeof (fattr)); + fattr.sa_mask = SMB_AT_UID | SMB_AT_GID; + rc = smb_vop_getattr(fnode->vp, NULL, &fattr, 0, kcr); + + if (rc == 0) { + /* create the named stream, sname */ + rc = smb_vop_stream_create(fnode->vp, sname, + attr, &vp, &xattrdvp, flags, cr); } + if (rc != 0) + return (rc); attr->sa_vattr.va_uid = fattr.sa_vattr.va_uid; attr->sa_vattr.va_gid = fattr.sa_vattr.va_gid; attr->sa_mask = SMB_AT_UID | SMB_AT_GID; rc = smb_vop_setattr(vp, NULL, attr, 0, kcr); if (rc != 0) { ! VN_RELE(xattrdvp); ! VN_RELE(vp); return (rc); } *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdvp, vp, sname); VN_RELE(xattrdvp); VN_RELE(vp); if (*ret_snode == NULL) rc = ENOMEM; /* notify change to the unnamed stream */ if (rc == 0) smb_node_notify_change(dnode, ! FILE_ACTION_ADDED_STREAM, fnode->od_name); return (rc); } /*
*** 445,454 **** --- 498,509 ---- { smb_arg_open_t *op = &sr->sr_open; vnode_t *vp; int rc; + ASSERT(ret_snode != NULL); + #ifdef _KERNEL smb_fssd_t fs_sd; uint32_t secinfo; uint32_t status;
*** 486,499 **** --- 541,563 ---- #endif /* _KERNEL */ { /* * No incoming SD and filesystem is not ZFS * let the filesystem handles the inheritance. + * + * fsop_create_with_sd handles auditing in the other cases. + * Handle it explicitly here. */ + boolean_t do_audit = smb_audit_init(sr); + rc = smb_vop_create(dnode->vp, name, attr, &vp, flags, cr, NULL); + if (do_audit) { + smb_audit_fini(sr, ACE_ADD_FILE, dnode, rc == 0); + } + if (rc == 0) { *ret_snode = smb_node_lookup(sr, op, cr, vp, name, dnode, NULL); if (*ret_snode == NULL)
*** 625,637 **** --- 689,712 ---- smb_fssd_term(&fs_sd); } else #endif /* _KERNEL */ { + /* + * fsop_create_with_sd handles auditing in the other cases. + * Handle it explicitly here. + */ + boolean_t do_audit = smb_audit_init(sr); + rc = smb_vop_mkdir(dnode->vp, name, attr, &vp, flags, cr, NULL); + if (do_audit) { + smb_audit_fini(sr, ACE_ADD_SUBDIRECTORY, dnode, + rc == 0); + } + if (rc == 0) { *ret_snode = smb_node_lookup(sr, op, cr, vp, name, dnode, NULL); if (*ret_snode == NULL)
*** 656,665 **** --- 731,743 ---- * for avoiding this wrapper. * * It is assumed that a reference exists on snode coming into this routine. * * A null smb_request might be passed to this function. + * + * Note that some stream "types" are "restricted" and only + * internal callers (cr == kcred) can remove those. */ int smb_fsop_remove( smb_request_t *sr, cred_t *cr,
*** 691,700 **** --- 769,783 ---- fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); if (dnode->flags & NODE_XATTR_DIR) { + if (cr != zone_kcred() && smb_strname_restricted(name)) { + rc = EACCES; + goto out; + } + fnode = dnode->n_dnode; rc = smb_vop_stream_remove(fnode->vp, name, flags, cr); /* notify change to the unnamed stream */ if ((rc == 0) && fnode->n_dnode) {
*** 702,711 **** --- 785,799 ---- FILE_ACTION_REMOVED_STREAM, fnode->od_name); } } else if (smb_is_stream_name(name)) { smb_stream_parse_name(name, fname, sname); + if (cr != zone_kcred() && smb_strname_restricted(sname)) { + rc = EACCES; + goto out; + } + /* * Look up the unnamed stream (i.e. fname). * Unmangle processing will be done on fname * as well as any link target. */
*** 712,724 **** rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, sr->tid_tree->t_snode, dnode, fname, &fnode); if (rc != 0) { ! kmem_free(fname, MAXNAMELEN); ! kmem_free(sname, MAXNAMELEN); ! return (rc); } /* * XXX * Need to find out what permission is required by NTFS --- 800,810 ---- rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, sr->tid_tree->t_snode, dnode, fname, &fnode); if (rc != 0) { ! goto out; } /* * XXX * Need to find out what permission is required by NTFS
*** 737,749 **** rc = smb_vop_remove(dnode->vp, name, flags, cr); if (rc == ENOENT) { if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) || !smb_maybe_mangled(name)) { ! kmem_free(fname, MAXNAMELEN); ! kmem_free(sname, MAXNAMELEN); ! return (rc); } longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); if (SMB_TREE_SUPPORTS_ABE(sr)) flags |= SMB_ABE; --- 823,833 ---- rc = smb_vop_remove(dnode->vp, name, flags, cr); if (rc == ENOENT) { if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) || !smb_maybe_mangled(name)) { ! goto out; } longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); if (SMB_TREE_SUPPORTS_ABE(sr)) flags |= SMB_ABE;
*** 769,778 **** --- 853,863 ---- smb_node_notify_change(dnode, FILE_ACTION_REMOVED, name); } } + out: kmem_free(fname, MAXNAMELEN); kmem_free(sname, MAXNAMELEN); return (rc); }
*** 814,823 **** --- 899,909 ---- status = smb_odir_openat(sr, fnode, &od); switch (status) { case 0: break; + case NT_STATUS_OBJECT_NAME_NOT_FOUND: case NT_STATUS_NO_SUCH_FILE: case NT_STATUS_NOT_SUPPORTED: /* No streams to remove. */ return (0); default:
*** 1112,1123 **** --- 1198,1214 ---- /* * XXX: Lock required through smb_node_release() below? */ + /* + * Don't audit the lookup + */ + smb_audit_save(); rc = smb_vop_lookup(from_dnode->vp, from_name, &from_vp, NULL, flags, &ret_flags, NULL, &from_attr, cr); + smb_audit_load(); if (rc != 0) return (rc); if (from_attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) {
*** 1153,1162 **** --- 1244,1254 ---- if (rc != NT_STATUS_SUCCESS) { VN_RELE(from_vp); return (EACCES); } + /* TODO: rename drops ATTR_NOACLCHECK, so this is a no-op. */ if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) flags = ATTR_NOACLCHECK; }
*** 1237,1265 **** if (SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_ATTRIBUTES | ACE_WRITE_NAMED_ATTRS) == 0) return (EACCES); /* - * The file system cannot detect pending READDONLY - * (i.e. if the file has been opened readonly but - * not yet closed) so we need to test READONLY here. - * - * Note that file handle that were opened before the - * READONLY flag was set in the node (or the FS) are - * immune to that change, and remain writable. - */ - if (sr && (set_attr->sa_mask & SMB_AT_SIZE)) { - if (sr->fid_ofile) { - if (SMB_OFILE_IS_READONLY(sr->fid_ofile)) - return (EACCES); - } else { - if (SMB_PATHFILE_IS_READONLY(sr, snode)) - return (EACCES); - } - } - - /* * SMB checks access on open and retains an access granted * mask for use while the file is open. ACL changes should * not affect access to an open file. * * If the setattr is being performed on an ofile: --- 1329,1338 ----
*** 1311,1335 **** return (rc); } /* * Support for SMB2 setinfo FileValidDataLengthInformation. ! * Free data from the specified offset to EoF. ! * ! * This can effectively truncate data. It truncates the data ! * leaving the file size as it was, leaving zeros after the ! * offset specified here. That is effectively modifying the ! * file content, so for access control this is a write. */ int ! smb_fsop_set_data_length( smb_request_t *sr, cred_t *cr, ! smb_node_t *node, ! offset_t end_of_data) { flock64_t flk; uint32_t status; uint32_t access = FILE_WRITE_DATA; int rc; ASSERT(cr); --- 1384,1405 ---- return (rc); } /* * Support for SMB2 setinfo FileValidDataLengthInformation. ! * Free (zero out) data in the range off, off+len */ int ! smb_fsop_freesp( smb_request_t *sr, cred_t *cr, ! smb_ofile_t *ofile, ! off64_t off, ! off64_t len) { flock64_t flk; + smb_node_t *node = ofile->f_node; uint32_t status; uint32_t access = FILE_WRITE_DATA; int rc; ASSERT(cr);
*** 1345,1371 **** if (SMB_TREE_HAS_ACCESS(sr, access) == 0) return (EACCES); /* - * The file system cannot detect pending READDONLY - * (i.e. if the file has been opened readonly but - * not yet closed) so we need to test READONLY here. - * - * Note that file handle that were opened before the - * READONLY flag was set in the node (or the FS) are - * immune to that change, and remain writable. - */ - if (sr->fid_ofile) { - if (SMB_OFILE_IS_READONLY(sr->fid_ofile)) - return (EACCES); - } else { - /* This requires an open file. */ - return (EACCES); - } - - /* * SMB checks access on open and retains an access granted * mask for use while the file is open. ACL changes should * not affect access to an open file. * * If the setattr is being performed on an ofile: --- 1415,1424 ----
*** 1375,1385 **** status = smb_ofile_access(sr->fid_ofile, cr, access); if (status != NT_STATUS_SUCCESS) return (EACCES); bzero(&flk, sizeof (flk)); ! flk.l_start = end_of_data; rc = smb_vop_space(node->vp, F_FREESP, &flk, FWRITE, 0LL, cr); return (rc); } --- 1428,1439 ---- status = smb_ofile_access(sr->fid_ofile, cr, access); if (status != NT_STATUS_SUCCESS) return (EACCES); bzero(&flk, sizeof (flk)); ! flk.l_start = off; ! flk.l_len = len; rc = smb_vop_space(node->vp, F_FREESP, &flk, FWRITE, 0LL, cr); return (rc); }
*** 1390,1426 **** * the the calls are performed with the appropriate credentials. * Please document any direct call to explain the reason * for avoiding this wrapper. * * It is assumed that a reference exists on snode coming into this routine. */ int ! smb_fsop_read(smb_request_t *sr, cred_t *cr, smb_node_t *snode, uio_t *uio) { caller_context_t ct; cred_t *kcr = zone_kcred(); int svmand; int rc; ASSERT(cr); ASSERT(snode); ASSERT(snode->n_magic == SMB_NODE_MAGIC); ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); ASSERT(sr); - ASSERT(sr->fid_ofile); ! if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_DATA) == 0) return (EACCES); ! rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA); ! if ((rc != NT_STATUS_SUCCESS) && ! (sr->smb_flg2 & SMB_FLAGS2_READ_IF_EXECUTE)) ! rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE); ! ! if (rc != NT_STATUS_SUCCESS) return (EACCES); /* * Streams permission are checked against the unnamed stream, * but in FS level they have their own permissions. To avoid * rejection by FS due to lack of permission on the actual --- 1444,1491 ---- * the the calls are performed with the appropriate credentials. * Please document any direct call to explain the reason * for avoiding this wrapper. * * It is assumed that a reference exists on snode coming into this routine. + * Note that ofile may be different from sr->fid_ofile, or may be NULL. */ int ! smb_fsop_read(smb_request_t *sr, cred_t *cr, smb_node_t *snode, ! smb_ofile_t *ofile, uio_t *uio, int ioflag) { caller_context_t ct; cred_t *kcr = zone_kcred(); + uint32_t amask; int svmand; int rc; ASSERT(cr); ASSERT(snode); ASSERT(snode->n_magic == SMB_NODE_MAGIC); ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); ASSERT(sr); ! if (ofile != NULL) { ! /* ! * Check tree access. Not SMB_TREE_HAS_ACCESS ! * because we need to use ofile->f_tree ! */ ! if ((ofile->f_tree->t_access & ACE_READ_DATA) == 0) return (EACCES); ! /* ! * Check ofile access. Use in-line smb_ofile_access ! * so we can check both amask bits at the same time. ! * If any bit in amask is granted, allow this read. ! */ ! amask = FILE_READ_DATA; ! if (sr->smb_flg2 & SMB_FLAGS2_READ_IF_EXECUTE) ! amask |= FILE_EXECUTE; ! if (cr != kcr && (ofile->f_granted_access & amask) == 0) return (EACCES); + } /* * Streams permission are checked against the unnamed stream, * but in FS level they have their own permissions. To avoid * rejection by FS due to lack of permission on the actual
*** 1434,1507 **** if (rc) { smb_node_end_crit(snode); return (rc); } ct = smb_ct; ! ct.cc_pid = sr->fid_ofile->f_uniqid; rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset, ! uio->uio_iov->iov_len, svmand, &ct); ! ! if (rc) { smb_node_end_crit(snode); return (ERANGE); } ! rc = smb_vop_read(snode->vp, uio, cr); smb_node_end_crit(snode); return (rc); } /* * smb_fsop_write * - * This is a wrapper function used for smb_write and smb_write_raw operations. - * * It is assumed that a reference exists on snode coming into this routine. */ int smb_fsop_write( smb_request_t *sr, cred_t *cr, smb_node_t *snode, uio_t *uio, uint32_t *lcount, int ioflag) { caller_context_t ct; smb_attr_t attr; smb_node_t *u_node; vnode_t *u_vp = NULL; - smb_ofile_t *of; vnode_t *vp; ! cred_t *kcr = zone_kcred(); int svmand; int rc; ASSERT(cr); ASSERT(snode); ASSERT(snode->n_magic == SMB_NODE_MAGIC); ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); ASSERT(sr); - ASSERT(sr->tid_tree); - of = sr->fid_ofile; vp = snode->vp; ! if (SMB_TREE_IS_READONLY(sr)) return (EROFS); ! if (SMB_OFILE_IS_READONLY(of) || ! SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_DATA | ACE_APPEND_DATA) == 0) return (EACCES); - - rc = smb_ofile_access(of, cr, FILE_WRITE_DATA); - if (rc != NT_STATUS_SUCCESS) { - rc = smb_ofile_access(of, cr, FILE_APPEND_DATA); - if (rc != NT_STATUS_SUCCESS) - return (EACCES); } /* * Streams permission are checked against the unnamed stream, * but in FS level they have their own permissions. To avoid --- 1499,1580 ---- if (rc) { smb_node_end_crit(snode); return (rc); } + /* + * Note: SMB allows a zero-byte read, which should not + * conflict with any locks. However nbl_lock_conflict + * takes a zero-byte length as lock to EOF, so we must + * special case that here. + */ + if (uio->uio_resid > 0) { ct = smb_ct; ! if (ofile != NULL) ! ct.cc_pid = ofile->f_uniqid; rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset, ! uio->uio_resid, svmand, &ct); ! if (rc != 0) { smb_node_end_crit(snode); return (ERANGE); } + } ! rc = smb_vop_read(snode->vp, uio, ioflag, cr); smb_node_end_crit(snode); return (rc); } /* * smb_fsop_write * * It is assumed that a reference exists on snode coming into this routine. + * Note that ofile may be different from sr->fid_ofile, or may be NULL. */ int smb_fsop_write( smb_request_t *sr, cred_t *cr, smb_node_t *snode, + smb_ofile_t *ofile, uio_t *uio, uint32_t *lcount, int ioflag) { caller_context_t ct; smb_attr_t attr; + cred_t *kcr = zone_kcred(); smb_node_t *u_node; vnode_t *u_vp = NULL; vnode_t *vp; ! uint32_t amask; int svmand; int rc; ASSERT(cr); ASSERT(snode); ASSERT(snode->n_magic == SMB_NODE_MAGIC); ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); ASSERT(sr); vp = snode->vp; ! if (ofile != NULL) { ! amask = FILE_WRITE_DATA | FILE_APPEND_DATA; ! ! /* Check tree access. */ ! if ((ofile->f_tree->t_access & amask) == 0) return (EROFS); ! /* ! * Check ofile access. Use in-line smb_ofile_access ! * so we can check both amask bits at the same time. ! * If any bit in amask is granted, allow this write. ! */ ! if (cr != kcr && (ofile->f_granted_access & amask) == 0) return (EACCES); } /* * Streams permission are checked against the unnamed stream, * but in FS level they have their own permissions. To avoid
*** 1521,1539 **** if (rc) { smb_node_end_crit(snode); return (rc); } ct = smb_ct; ! ct.cc_pid = of->f_uniqid; rc = nbl_lock_conflict(vp, NBL_WRITE, uio->uio_loffset, ! uio->uio_iov->iov_len, svmand, &ct); ! ! if (rc) { smb_node_end_crit(snode); return (ERANGE); } rc = smb_vop_write(vp, uio, ioflag, lcount, cr); /* * Once the mtime has been set via this ofile, the --- 1594,1620 ---- if (rc) { smb_node_end_crit(snode); return (rc); } + /* + * Note: SMB allows a zero-byte write, which should not + * conflict with any locks. However nbl_lock_conflict + * takes a zero-byte length as lock to EOF, so we must + * special case that here. + */ + if (uio->uio_resid > 0) { ct = smb_ct; ! if (ofile != NULL) ! ct.cc_pid = ofile->f_uniqid; rc = nbl_lock_conflict(vp, NBL_WRITE, uio->uio_loffset, ! uio->uio_resid, svmand, &ct); ! if (rc != 0) { smb_node_end_crit(snode); return (ERANGE); } + } rc = smb_vop_write(vp, uio, ioflag, lcount, cr); /* * Once the mtime has been set via this ofile, the
*** 1544,1555 **** * The VFS interface does not offer a way to ask it to * skip the mtime updates, so we simulate the desired * behavior by re-setting the mtime after writes on a * handle where the mtime has been set. */ ! if (of->f_pending_attr.sa_mask & SMB_AT_MTIME) { ! bcopy(&of->f_pending_attr, &attr, sizeof (attr)); attr.sa_mask = SMB_AT_MTIME; (void) smb_vop_setattr(vp, u_vp, &attr, 0, kcr); } smb_node_end_crit(snode); --- 1625,1637 ---- * The VFS interface does not offer a way to ask it to * skip the mtime updates, so we simulate the desired * behavior by re-setting the mtime after writes on a * handle where the mtime has been set. */ ! if (ofile != NULL && ! (ofile->f_pending_attr.sa_mask & SMB_AT_MTIME) != 0) { ! bcopy(&ofile->f_pending_attr, &attr, sizeof (attr)); attr.sa_mask = SMB_AT_MTIME; (void) smb_vop_setattr(vp, u_vp, &attr, 0, kcr); } smb_node_end_crit(snode);
*** 1556,1565 **** --- 1638,1671 ---- return (rc); } /* + * Find the next allocated range starting at or after + * the offset (*datap), returning the start/end of + * that range in (*datap, *holep) + */ + int + smb_fsop_next_alloc_range( + cred_t *cr, + smb_node_t *node, + off64_t *datap, + off64_t *holep) + { + int err; + + err = smb_vop_ioctl(node->vp, _FIO_SEEK_DATA, datap, cr); + if (err != 0) + return (err); + + *holep = *datap; + err = smb_vop_ioctl(node->vp, _FIO_SEEK_HOLE, holep, cr); + + return (err); + } + + /* * smb_fsop_statfs * * This is a wrapper function used for stat operations. */ int
*** 1587,1596 **** --- 1693,1705 ---- * separate from that on the unnamed stream. If READ or EXECUTE * access has been requested on a named stream, an additional access * check is performed on the named stream in case it has been * quarantined. kcred is used to avoid issues with the permissions * set on the extended attribute file representing the named stream. + * + * Note that some stream "types" are "restricted" and only + * internal callers (cr == kcred) can access those. */ int smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode, uint32_t faccess) {
*** 1617,1637 **** if (smb_node_is_reparse(snode) && (faccess & DELETE)) return (NT_STATUS_ACCESS_DENIED); unnamed_node = SMB_IS_STREAM(snode); if (unnamed_node) { ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); /* * Perform VREAD access check on the named stream in case it * is quarantined. kcred is passed to smb_vop_access so it * doesn't fail due to lack of permission. */ if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) { error = smb_vop_access(snode->vp, VREAD, ! 0, NULL, zone_kcred()); if (error) return (NT_STATUS_ACCESS_DENIED); } /* --- 1726,1751 ---- if (smb_node_is_reparse(snode) && (faccess & DELETE)) return (NT_STATUS_ACCESS_DENIED); unnamed_node = SMB_IS_STREAM(snode); if (unnamed_node) { + cred_t *kcr = zone_kcred(); + ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); + if (cr != kcr && smb_strname_restricted(snode->od_name)) + return (NT_STATUS_ACCESS_DENIED); + /* * Perform VREAD access check on the named stream in case it * is quarantined. kcred is passed to smb_vop_access so it * doesn't fail due to lack of permission. */ if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) { error = smb_vop_access(snode->vp, VREAD, ! 0, NULL, kcr); if (error) return (NT_STATUS_ACCESS_DENIED); } /*
*** 1690,1702 **** --- 1804,1820 ---- } /* * smb_fsop_lookup_name() * + * Lookup both the file and stream specified in 'name'. * If name indicates that the file is a stream file, perform * stream specific lookup, otherwise call smb_fsop_lookup. * + * On success, returns the found node in *ret_snode. This will be either a named + * or unnamed stream node, depending on the name specified. + * * Return an error if the looked-up file is in outside the tree. * (Required when invoked from open path.) * * Case sensitivity flags (SMB_IGNORE_CASE, SMB_CASE_SENSITIVE): * if SMB_CASE_SENSITIVE is set, the SMB_IGNORE_CASE flag will NOT be set
*** 1714,1735 **** smb_node_t *root_node, smb_node_t *dnode, char *name, smb_node_t **ret_snode) { ! smb_node_t *fnode; ! vnode_t *xattrdirvp; ! vnode_t *vp; ! char *od_name; char *fname; - char *sname; int rc; ASSERT(cr); ASSERT(dnode); ASSERT(dnode->n_magic == SMB_NODE_MAGIC); ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING); /* * The following check is required for streams processing, below */ --- 1832,1899 ---- smb_node_t *root_node, smb_node_t *dnode, char *name, smb_node_t **ret_snode) { ! char *sname = NULL; ! int rc; ! smb_node_t *tmp_node; ! ! ASSERT(ret_snode != NULL); ! ! rc = smb_fsop_lookup_file(sr, cr, flags, root_node, dnode, name, ! &sname, ret_snode); ! ! if (rc != 0 || sname == NULL) ! return (rc); ! ! tmp_node = *ret_snode; ! rc = smb_fsop_lookup_stream(sr, cr, flags, root_node, tmp_node, sname, ! ret_snode); ! kmem_free(sname, MAXNAMELEN); ! smb_node_release(tmp_node); ! ! return (rc); ! } ! ! /* ! * smb_fsop_lookup_file() ! * ! * Look up of the file portion of 'name'. If a Stream is specified, ! * return the stream name in 'sname', which this allocates. ! * The caller must free 'sname'. ! * ! * Return an error if the looked-up file is outside the tree. ! * (Required when invoked from open path.) ! * ! * Case sensitivity flags (SMB_IGNORE_CASE, SMB_CASE_SENSITIVE): ! * if SMB_CASE_SENSITIVE is set, the SMB_IGNORE_CASE flag will NOT be set ! * based on the tree's case sensitivity. However, if the SMB_IGNORE_CASE ! * flag is set in the flags value passed as a parameter, a case insensitive ! * lookup WILL be done (regardless of whether SMB_CASE_SENSITIVE is set ! * or not). ! */ ! ! int ! smb_fsop_lookup_file( ! smb_request_t *sr, ! cred_t *cr, ! int flags, ! smb_node_t *root_node, ! smb_node_t *dnode, ! char *name, ! char **sname, ! smb_node_t **ret_snode) ! { char *fname; int rc; ASSERT(cr); ASSERT(dnode); ASSERT(dnode->n_magic == SMB_NODE_MAGIC); ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING); + ASSERT(ret_snode != NULL); /* * The following check is required for streams processing, below */
*** 1736,1817 **** if (!(flags & SMB_CASE_SENSITIVE)) { if (SMB_TREE_IS_CASEINSENSITIVE(sr)) flags |= SMB_IGNORE_CASE; } fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); ! sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); - if (smb_is_stream_name(name)) { - smb_stream_parse_name(name, fname, sname); - /* * Look up the unnamed stream (i.e. fname). * Unmangle processing will be done on fname * as well as any link target. */ rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, ! fname, &fnode); ! ! if (rc != 0) { kmem_free(fname, MAXNAMELEN); ! kmem_free(sname, MAXNAMELEN); return (rc); } od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); /* * od_name is the on-disk name of the stream, except * without the prepended stream prefix (SMB_STREAM_PREFIX) */ - /* - * XXX - * What permissions NTFS requires for stream lookup if any? - */ rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name, &xattrdirvp, flags, root_node->vp, cr); if (rc != 0) { - smb_node_release(fnode); - kmem_free(fname, MAXNAMELEN); - kmem_free(sname, MAXNAMELEN); kmem_free(od_name, MAXNAMELEN); return (rc); } *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, vp, od_name); kmem_free(od_name, MAXNAMELEN); - smb_node_release(fnode); VN_RELE(xattrdirvp); VN_RELE(vp); ! if (*ret_snode == NULL) { ! kmem_free(fname, MAXNAMELEN); ! kmem_free(sname, MAXNAMELEN); return (ENOMEM); - } - } else { - rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, name, - ret_snode); - } - if (rc == 0) { - ASSERT(ret_snode); - if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) { - smb_node_release(*ret_snode); - *ret_snode = NULL; - rc = EACCES; - } - } - - kmem_free(fname, MAXNAMELEN); - kmem_free(sname, MAXNAMELEN); - return (rc); } /* * smb_fsop_lookup --- 1900,1998 ---- if (!(flags & SMB_CASE_SENSITIVE)) { if (SMB_TREE_IS_CASEINSENSITIVE(sr)) flags |= SMB_IGNORE_CASE; } + *sname = NULL; + if (smb_is_stream_name(name)) { + *sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); ! smb_stream_parse_name(name, fname, *sname); /* * Look up the unnamed stream (i.e. fname). * Unmangle processing will be done on fname * as well as any link target. */ rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, ! fname, ret_snode); kmem_free(fname, MAXNAMELEN); ! } else { ! rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, name, ! ret_snode); ! } ! ! if (rc == 0) { ! ASSERT(ret_snode); ! if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) { ! smb_node_release(*ret_snode); ! *ret_snode = NULL; ! rc = EACCES; ! } ! } ! ! if (rc != 0 && *sname != NULL) { ! kmem_free(*sname, MAXNAMELEN); ! *sname = NULL; ! } return (rc); + } + + /* + * smb_fsop_lookup_stream + * + * The file exists, see if the stream exists. + */ + int + smb_fsop_lookup_stream( + smb_request_t *sr, + cred_t *cr, + int flags, + smb_node_t *root_node, + smb_node_t *fnode, + char *sname, + smb_node_t **ret_snode) + { + char *od_name; + vnode_t *xattrdirvp; + vnode_t *vp; + int rc; + + /* + * The following check is required for streams processing, below + */ + + if (!(flags & SMB_CASE_SENSITIVE)) { + if (SMB_TREE_IS_CASEINSENSITIVE(sr)) + flags |= SMB_IGNORE_CASE; } od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); /* * od_name is the on-disk name of the stream, except * without the prepended stream prefix (SMB_STREAM_PREFIX) */ rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name, &xattrdirvp, flags, root_node->vp, cr); if (rc != 0) { kmem_free(od_name, MAXNAMELEN); return (rc); } *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, vp, od_name); kmem_free(od_name, MAXNAMELEN); VN_RELE(xattrdirvp); VN_RELE(vp); ! if (*ret_snode == NULL) return (ENOMEM); return (rc); } /* * smb_fsop_lookup
*** 1879,1890 **** if (SMB_TREE_SUPPORTS_CATIA(sr)) flags |= SMB_CATIA; if (SMB_TREE_SUPPORTS_ABE(sr)) flags |= SMB_ABE; ! od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); rc = smb_vop_lookup(dnode->vp, name, &vp, od_name, flags, &ret_flags, root_node ? root_node->vp : NULL, &attr, cr); if (rc != 0) { if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) || --- 2060,2080 ---- if (SMB_TREE_SUPPORTS_CATIA(sr)) flags |= SMB_CATIA; 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_zalloc(MAXNAMELEN, KM_SLEEP); + rc = smb_vop_lookup(dnode->vp, name, &vp, od_name, flags, &ret_flags, root_node ? root_node->vp : NULL, &attr, cr); if (rc != 0) { if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
*** 1925,1935 **** } if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK) && ((attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)) { rc = smb_pathname(sr, od_name, FOLLOW, root_node, dnode, ! &lnk_dnode, &lnk_target_node, cr); if (rc != 0) { /* * The link is assumed to be for the last component * of a path. Hence any ENOTDIR error will be returned --- 2115,2125 ---- } if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK) && ((attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)) { rc = smb_pathname(sr, od_name, FOLLOW, root_node, dnode, ! &lnk_dnode, &lnk_target_node, cr, NULL); if (rc != 0) { /* * The link is assumed to be for the last component * of a path. Hence any ENOTDIR error will be returned
*** 2034,2047 **** { int error = 0; int flags = 0; int access = 0; acl_t *acl; - smb_node_t *unnamed_node; ASSERT(cr); if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_ACL) == 0) return (EACCES); if (sr->fid_ofile) { if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) --- 2224,2240 ---- { int error = 0; int flags = 0; int access = 0; acl_t *acl; ASSERT(cr); + /* Can't query security on named streams */ + if (SMB_IS_STREAM(snode) != NULL) + return (EINVAL); + if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_ACL) == 0) return (EACCES); if (sr->fid_ofile) { if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
*** 2054,2073 **** if (error != NT_STATUS_SUCCESS) { return (EACCES); } } - unnamed_node = SMB_IS_STREAM(snode); - if (unnamed_node) { - ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); - ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); - /* - * Streams don't have ACL, any read ACL attempt on a stream - * should be performed on the unnamed stream. - */ - snode = unnamed_node; - } if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) flags = ATTR_NOACLCHECK; error = smb_vop_acl_read(snode->vp, &acl, flags, --- 2247,2256 ----
*** 2100,2118 **** int target_flavor; int error = 0; int flags = 0; int access = 0; acl_t *acl, *dacl, *sacl; - smb_node_t *unnamed_node; ASSERT(cr); ASSERT(sr); ASSERT(sr->tid_tree); if (SMB_TREE_IS_READONLY(sr)) return (EROFS); if (SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_ACL) == 0) return (EACCES); if (sr->fid_ofile) { if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) --- 2283,2304 ---- int target_flavor; int error = 0; int flags = 0; int access = 0; acl_t *acl, *dacl, *sacl; ASSERT(cr); ASSERT(sr); ASSERT(sr->tid_tree); if (SMB_TREE_IS_READONLY(sr)) return (EROFS); + /* Can't set security on named streams */ + if (SMB_IS_STREAM(snode) != NULL) + return (EINVAL); + if (SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_ACL) == 0) return (EACCES); if (sr->fid_ofile) { if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
*** 2136,2156 **** break; default: return (EINVAL); } - unnamed_node = SMB_IS_STREAM(snode); - if (unnamed_node) { - ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); - ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); - /* - * Streams don't have ACL, any write ACL attempt on a stream - * should be performed on the unnamed stream. - */ - snode = unnamed_node; - } - dacl = fs_sd->sd_zdacl; sacl = fs_sd->sd_zsacl; ASSERT(dacl || sacl); if ((dacl == NULL) && (sacl == NULL)) --- 2322,2331 ----
*** 2201,2210 **** --- 2376,2389 ---- smb_attr_t attr; ASSERT(cr); ASSERT(fs_sd); + /* Can't query security on named streams */ + if (SMB_IS_STREAM(snode) != NULL) + return (EINVAL); + /* * File's uid/gid is fetched in two cases: * * 1. it's explicitly requested *
*** 2366,2375 **** --- 2545,2558 ---- ASSERT(sr); ASSERT(sr->tid_tree); if (SMB_TREE_IS_READONLY(sr)) return (EROFS); + /* Can't set security on named streams */ + if (SMB_IS_STREAM(snode) != NULL) + return (EINVAL); + bzero(&set_attr, sizeof (smb_attr_t)); if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { set_attr.sa_vattr.va_uid = fs_sd->sd_uid; set_attr.sa_mask |= SMB_AT_UID;
*** 2556,2565 **** --- 2739,2757 ---- *eaccess |= FILE_EXECUTE; if (access & VWRITE) *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD; + + if (access & (VREAD | VWRITE)) + *eaccess |= SYNCHRONIZE; + + #ifdef _FAKE_KERNEL + /* Should be: if (we are the owner)... */ + if (access & VWRITE) + *eaccess |= DELETE | WRITE_DAC | WRITE_OWNER; + #endif } /* * smb_fsop_shrlock *
*** 2636,2645 **** --- 2828,2845 ---- * incompatibilities between POSIX and Windows. In the Windows world, * if a client submits such a lock, the server will not lock any * bytes. Interestingly if the same lock (same offset and length) is * resubmitted Windows will consider that there is an overlap and * the granting rules will then apply. + * + * 3) The SMB-level process IDs (smb_pid) are not passed down to the + * POSIX level in l_pid because (a) the rules about lock PIDs are + * different in SMB, and (b) we're putting our ofile f_uniqid in + * the POSIX l_pid field to segregate locks per SMB ofile. + * (We're also using a "remote" system ID in l_sysid.) + * All SMB locking PIDs are handled at the SMB level and + * not exposed in POSIX locking. */ if ((lock->l_length == 0) || ((lock->l_start + lock->l_length - 1) < lock->l_start)) return (0);