summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/fs')
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_acl.c1571
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_open.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_create.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_fsops.c245
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_init.c12
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_lock_svc.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c30
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c440
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_ofile.c16
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_open_andx.c6
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c28
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_read.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_rpc.c7
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_sd.c812
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_find.c8
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c20
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_fs_information.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c18
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree.c17
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_vops.c221
-rwxr-xr-xusr/src/uts/common/fs/smbsrv/smb_winpipe.c50
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_write.c10
25 files changed, 1612 insertions, 1919 deletions
diff --git a/usr/src/uts/common/fs/smbsrv/smb_acl.c b/usr/src/uts/common/fs/smbsrv/smb_acl.c
index 2617268d9e..5491e927f1 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_acl.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_acl.c
@@ -25,68 +25,15 @@
#pragma ident "%Z%%M% %I% %E% SMI"
-/*
- * Platform SDK: Security
- *
- * ACE Inheritance Rules
- *
- * The system propagates inheritable ACEs to child objects according to a
- * set of inheritance rules. The system places inherited ACEs in the child's
- * DACL according to the preferred order of ACEs in a DACL. For Windows
- * 2000 or later, the system sets the INHERITED_ACE flag in all inherited ACEs.
- *
- * The following table shows the ACEs inherited by container and noncontainer
- * child objects for different combinations of inheritance flags. These
- * inheritance rules work the same for both DACLs and SACLs.
- *
- * Parent ACE type Effect on Child ACL
- * ----------------------- -------------------
- * OBJECT_INHERIT_ACE only Noncontainer child objects:
- * Inherited as an effective ACE.
- * Container child objects:
- * Containers inherit an inherit-only ACE
- * unless the NO_PROPAGATE_INHERIT_ACE bit
- * flag is also set.
- *
- * CONTAINER_INHERIT_ACE only Noncontainer child objects:
- * No effect on the child object.
- * Container child objects:
- * The child object inherits an effective ACE.
- * The inherited ACE is inheritable unless the
- * NO_PROPAGATE_INHERIT_ACE bit flag is also set.
- *
- * CONTAINER_INHERIT_ACE and
- * OBJECT_INHERIT_ACE Noncontainer child objects:
- * Inherited as an effective ACE.
- * Container child objects:
- * The child object inherits an effective ACE.
- * The inherited ACE is inheritable unless the
- * NO_PROPAGATE_INHERIT_ACE bit flag is also set
- *
- * No inheritance flags set No effect on child container or noncontainer
- * objects.
- *
- * If an inherited ACE is an effective ACE for the child object, the system
- * maps any generic rights to the specific rights for the child object.
- * Similarly, the system maps generic SIDs, such as CREATOR_OWNER, to the
- * appropriate SID. If an inherited ACE is an inherit-only ACE, any generic
- * rights or generic SIDs are left unchanged so that they can be mapped
- * appropriately when the ACE is inherited by the next generation of child
- * objects.
- *
- * For a case in which a container object inherits an ACE that is both
- * effective on the container and inheritable by its descendants, the
- * container may inherit two ACEs. This occurs if the inheritable ACE
- * contains generic information. The container inherits an inherit-only
- * ACE containing the generic information and an effective-only ACE in
- * which the generic information has been mapped.
- */
-
#include <sys/acl.h>
-#include <smbsrv/smb_incl.h>
+#include <acl/acl_common.h>
#include <smbsrv/ntsid.h>
#include <smbsrv/smb_fsops.h>
#include <smbsrv/smb_idmap.h>
+#include <smbsrv/smb_kproto.h>
+#include <smbsrv/smbvar.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/ntaccess.h>
#define ACE_FD_INHERIT_ACE (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE)
@@ -111,195 +58,143 @@
#define ZACE_IS_CREATOR(zace) \
(ZACE_IS_CREATOR_OWNER(zace) || ZACE_IS_CREATOR_GROUP(zace))
-static int smb_ace_isvalid(smb_ace_hdr_t *ace, int which_acl);
-static int smb_ace_append_generic(smb_acl_t *acl, void *generic_ace);
-
-static int smb_ace_common_add(
- smb_acl_t *acl,
- uint8_t type,
- uint8_t flags,
- uint32_t access_mask,
- nt_sid_t *sid);
-
-static void smb_ace_inherit(ace_t *dir_zace, ace_t *zace, int is_dir);
-static uint16_t smb_ace_flags_tozfs(uint8_t c_flags, int isdir);
-static uint8_t smb_ace_flags_fromzfs(uint16_t z_flags);
-static void smb_acl_init(smb_acl_t *acl, uint16_t size, uint8_t rev);
-
-static int
-smb_ace_isvalid(smb_ace_hdr_t *ace, int which_acl)
-{
- uint16_t min_len;
- smb_ace_t *p;
+/*
+ * ACE groups within a DACL
+ *
+ * This is from lower to higher ACE order priority
+ */
+#define SMB_AG_START 0
+#define SMB_AG_ALW_INHRT 0
+#define SMB_AG_DNY_INHRT 1
+#define SMB_AG_ALW_DRCT 2
+#define SMB_AG_DNY_DRCT 3
+#define SMB_AG_NUM 4
- min_len = sizeof (smb_ace_hdr_t);
+/*
+ * SID for Everyone group: S-1-1-0.
+ */
+nt_sid_t everyone_sid = {
+ NT_SID_REVISION,
+ 1,
+ NT_SECURITY_WORLD_AUTH,
+ { 0 }
+};
- if (ace->se_size < min_len)
- return (0);
+#define DEFAULT_DACL_ACENUM 2
+/*
+ * Default ACL:
+ * owner: full access
+ * SYSTEM: full access
+ */
+static ace_t default_dacl[DEFAULT_DACL_ACENUM] = {
+ { (uid_t)-1, ACE_ALL_PERMS, 0, ACE_ACCESS_ALLOWED_ACE_TYPE },
+ { IDMAP_WK_LOCAL_SYSTEM_GID, ACE_ALL_PERMS, ACE_IDENTIFIER_GROUP,
+ ACE_ACCESS_ALLOWED_ACE_TYPE }
+};
- if (smb_ace_is_access(ace->se_type) &&
- (which_acl != SMB_DACL_SECINFO)) {
- return (0);
- }
+/*
+ * Note:
+ *
+ * smb_acl_xxx functions work with smb_acl_t which represents the CIFS format
+ * smb_fsacl_xxx functions work with acl_t which represents the Solaris native
+ * format
+ */
- if (smb_ace_is_audit(ace->se_type) &&
- (which_acl != SMB_SACL_SECINFO)) {
- return (0);
- }
+static idmap_stat smb_acl_getsids(smb_idmap_batch_t *, acl_t *, uid_t, gid_t);
+static acl_t *smb_acl_null_empty(boolean_t null);
- if (smb_ace_is_generic(ace->se_type)) {
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- p = (smb_ace_t *)ace;
+static int smb_fsacl_inheritable(acl_t *, int);
- if (ace->se_size < sizeof (*p))
- return (0); /* won't handle empty SubAuthority[] */
- if (nt_sid_is_valid(&p->se_sid) == 0)
- return (0);
+static void smb_ace_inherit(ace_t *, ace_t *, int);
+static boolean_t smb_ace_isvalid(smb_ace_t *, int);
+static uint16_t smb_ace_len(smb_ace_t *);
+static uint32_t smb_ace_mask_g2s(uint32_t);
+static uint16_t smb_ace_flags_tozfs(uint8_t, int);
+static uint8_t smb_ace_flags_fromzfs(uint16_t);
- min_len += sizeof (p->se_mask);
- min_len += nt_sid_length(&p->se_sid);
+smb_acl_t *
+smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt)
+{
+ smb_acl_t *acl;
+ int size;
- if (ace->se_size < min_len)
- return (0);
- }
+ size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t));
+ acl = kmem_zalloc(size, KM_SLEEP);
+ acl->sl_revision = revision;
+ acl->sl_bsize = bsize;
+ acl->sl_acecnt = acecnt;
+ acl->sl_aces = (smb_ace_t *)(acl + 1);
- /*
- * XXX object-specific ACE validation will be added later.
- */
- return (1);
+ list_create(&acl->sl_sorted, sizeof (smb_ace_t),
+ offsetof(smb_ace_t, se_sln));
+ return (acl);
}
-int
-smb_acl_isvalid(smb_acl_t *acl, int which_acl)
+void
+smb_acl_free(smb_acl_t *acl)
{
- uint16_t min_len;
- unsigned char *scan;
- unsigned char *scan_end;
- smb_ace_hdr_t *ace;
- uint16_t count = 0;
-
- min_len = sizeof (smb_acl_t);
-
- if (acl->sl_size < min_len)
- return (0);
-
- if (acl->sl_revision != ACL_REVISION) {
- /*
- * XXX we are rejecting ACLs with object-specific ACEs for now
- */
- return (0);
- }
+ int i, size;
+ void *ace;
- scan = (unsigned char *) &acl[0];
- scan_end = scan + acl->sl_size;
- scan = (unsigned char *) &acl[1]; /* skip Acl header */
+ if (acl == NULL)
+ return;
- while (count < acl->sl_acecnt && scan < scan_end) {
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- ace = (smb_ace_hdr_t *)scan;
-
- if (scan + sizeof (smb_ace_hdr_t) >= scan_end)
- return (0);
-
- if (scan + ace->se_size > scan_end)
- return (0); /* overflow */
-
- if (!smb_ace_isvalid(ace, which_acl))
- return (0);
-
- scan += ace->se_size;
- count++;
+ for (i = 0; i < acl->sl_acecnt; i++) {
+ MEM_FREE("smbsrv", acl->sl_aces[i].se_sid);
}
- return (1);
-}
-
+ while ((ace = list_head(&acl->sl_sorted)) != NULL)
+ list_remove(&acl->sl_sorted, ace);
+ list_destroy(&acl->sl_sorted);
-static void
-smb_acl_init(smb_acl_t *acl, uint16_t size, uint8_t rev)
-{
- bzero(acl, size);
- acl->sl_revision = rev;
- acl->sl_size = size;
+ size = sizeof (smb_acl_t) + (acl->sl_acecnt * sizeof (smb_ace_t));
+ kmem_free(acl, size);
}
+/*
+ * smb_acl_len
+ *
+ * Returns the size of given ACL in bytes. Note that this
+ * is not an in-memory size, it's the ACL's size as it would
+ * appear on the wire
+ */
uint16_t
smb_acl_len(smb_acl_t *acl)
{
- smb_ace_hdr_t *ace;
- unsigned char *scan_beg;
- unsigned char *scan_end;
- unsigned char *scan;
- uint16_t length;
- uint16_t count;
-
- scan_beg = (unsigned char *) &acl[0];
- scan_end = scan_beg + acl->sl_size;
- scan = (unsigned char *) &acl[1];
- length = sizeof (smb_acl_t);
- count = 0;
-
- while ((count < acl->sl_acecnt) && (scan < scan_end)) {
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- ace = (smb_ace_hdr_t *)scan;
- length += ace->se_size;
- scan += ace->se_size;
- count++;
- }
+ if (acl == NULL)
+ return (0);
- return (length);
+ return (acl->sl_bsize);
}
-/*
- * Append the generic ACE to the ACL. This is used to put any
- * kind of ACE on the ACL so the argument is declared as a void*. We cast it
- * to an ACCESS_ALLOWED_ACE just because there is no sense of a generic ACE.
- */
-static int
-smb_ace_append_generic(smb_acl_t *acl, void *generic_ace)
+boolean_t
+smb_acl_isvalid(smb_acl_t *acl, int which_acl)
{
- smb_ace_t *ace = (smb_ace_t *)generic_ace;
- uint16_t acl_len = smb_acl_len(acl);
- unsigned char *scan = (uchar_t *)acl;
+ int i;
- if ((acl_len + ace->se_header.se_size) > acl->sl_size) {
- /* no room in the acl for this ace */
- return (0);
+ if (acl->sl_bsize < SMB_ACL_HDRSIZE)
+ return (B_FALSE);
+
+ if (acl->sl_revision != ACL_REVISION) {
+ /*
+ * we are rejecting ACLs with object-specific ACEs for now
+ */
+ return (B_FALSE);
}
- /* append the ace to the acl and inc ace count */
- bcopy(ace, &scan[acl_len], ace->se_header.se_size);
- acl->sl_acecnt++;
+ for (i = 0; i < acl->sl_acecnt; i++) {
+ if (!smb_ace_isvalid(&acl->sl_aces[i], which_acl))
+ return (B_FALSE);
+ }
- return (1);
+ return (B_TRUE);
}
/*
- * Helper for the ACL sort routine
- */
-typedef struct smb_ace_entry {
- smb_ace_t *e_ace;
- list_node_t e_node;
-} smb_ace_entry_t;
-
-/*
- * ACE groups within a DACL
- *
- * This is from lower to higher ACE order priority
- */
-#define SMB_AG_START 0
-#define SMB_AG_ALW_INHRT 0
-#define SMB_AG_DNY_INHRT 1
-#define SMB_AG_ALW_DRCT 2
-#define SMB_AG_DNY_DRCT 3
-#define SMB_AG_NUM 4
-
-/*
- * smb_acl_do_sort
+ * smb_acl_sort
*
- * Sorts the given ACL, acl, and returns the result
- * in a newly allocated memory.
+ * Sorts the given ACL in place if it needs to be sorted.
*
* The following is an excerpt from MSDN website.
*
@@ -327,82 +222,20 @@ typedef struct smb_ace_entry {
* . Access-allowed ACEs that apply to the object itself
* . Access-allowed ACEs that apply to a subobject of the object
*
- * Of course, not all ACE types are required in an ACL.
- */
-static smb_acl_t *
-smb_acl_do_sort(smb_acl_t *acl, list_t *ace_grps)
-{
- smb_acl_t *sorted_acl;
- smb_ace_entry_t *nae;
- int i;
-
- sorted_acl = kmem_alloc(acl->sl_size, KM_SLEEP);
- *sorted_acl = *acl;
-
- /* start with no ACE in the sorted ACL */
- sorted_acl->sl_acecnt = 0;
-
- /*
- * start with highest priority ACE group and append
- * the ACEs to the ACL.
- */
- for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
- nae = list_head(&ace_grps[i]);
- while (nae) {
- if (!smb_ace_append_generic(sorted_acl, nae->e_ace)) {
- kmem_free(sorted_acl, acl->sl_size);
- return (NULL);
- }
- nae = list_next(&ace_grps[i], nae);
- }
- }
-
- return (sorted_acl);
-}
-
-/*
- * smb_acl_need_sort
- *
- * Here is the desired ACE order
+ * So, here is the desired ACE order
*
* deny-direct, allow-direct, deny-inherited, allow-inherited
*
- * If any ace has been encountered which belongs to a group
- * with lower priority of the specified ace_grp then the acl
- * should be sorted.
- */
-static int
-smb_acl_need_sort(list_t *ace_grps, int ace_grp)
-{
- int i;
-
- for (i = SMB_AG_START; i < ace_grp; i++)
- if (!list_is_empty(&ace_grps[i]))
- return (1);
-
- return (0);
-}
-
-/*
- * smb_acl_sort
- *
- * Returns NULL upon failure.
- * Returns pointer to the passed (original) acl if no sort is required.
- * Returns pointer to a new acl upon successful sort in which case the
- * caller is responsible for freeing the allocated memory.
+ * Of course, not all ACE types are required in an ACL.
*/
-smb_acl_t *
+void
smb_acl_sort(smb_acl_t *acl)
{
- smb_acl_t *sorted_acl;
- smb_ace_t *ace;
- smb_ace_entry_t *ace_list;
- int ace_list_size;
list_t ace_grps[SMB_AG_NUM];
- int ag;
- int do_sort = 0;
- uint16_t i;
+ list_t *alist;
+ smb_ace_t *ace;
uint8_t ace_flags;
+ int ag, i;
ASSERT(acl);
@@ -411,46 +244,26 @@ smb_acl_sort(smb_acl_t *acl)
* ACL with no entry is a valid ACL and it means
* no access for anybody.
*/
- return (acl);
+ return;
}
for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
- list_create(&ace_grps[i], sizeof (smb_ace_entry_t),
- offsetof(smb_ace_entry_t, e_node));
+ list_create(&ace_grps[i], sizeof (smb_ace_t),
+ offsetof(smb_ace_t, se_sln));
}
- /*
- * Allocate the helper entries to group the ACEs based on
- * the desired priorities.
- */
- ace_list_size = sizeof (smb_ace_entry_t) * acl->sl_acecnt;
- ace_list = kmem_alloc(ace_list_size, KM_SLEEP);
-
- for (i = 0; i < acl->sl_acecnt; ++i) {
- ace_list[i].e_ace = smb_ace_get(acl, i);
- ace = ace_list[i].e_ace;
- ASSERT(ace);
+ for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) {
+ ace_flags = ace->se_hdr.se_flags;
- ace_flags = ace->se_header.se_flags;
-
- switch (ace->se_header.se_type) {
+ switch (ace->se_hdr.se_type) {
case ACCESS_DENIED_ACE_TYPE:
- if (ace_flags & INHERITED_ACE) {
- ag = SMB_AG_DNY_INHRT;
- do_sort |= smb_acl_need_sort(ace_grps, ag);
- } else {
- ag = SMB_AG_DNY_DRCT;
- do_sort |= smb_acl_need_sort(ace_grps, ag);
- }
+ ag = (ace_flags & INHERITED_ACE) ?
+ SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT;
break;
case ACCESS_ALLOWED_ACE_TYPE:
- if (ace_flags & INHERITED_ACE) {
- ag = SMB_AG_ALW_INHRT;
- } else {
- ag = SMB_AG_ALW_DRCT;
- do_sort |= smb_acl_need_sort(ace_grps, ag);
- }
+ ag = (ace_flags & INHERITED_ACE) ?
+ SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT;
break;
default:
@@ -462,185 +275,177 @@ smb_acl_sort(smb_acl_t *acl)
break;
}
- /* Put the element on the appropriate list */
- list_insert_tail(&ace_grps[ag], &ace_list[i]);
+ /* Add the ACE to the selected group */
+ list_insert_tail(&ace_grps[ag], ace);
}
- if (do_sort)
- sorted_acl = smb_acl_do_sort(acl, ace_grps);
- else
- sorted_acl = acl;
-
- for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
- void *ent;
- list_t *alist = &ace_grps[i];
-
- while ((ent = list_head(alist)) != NULL)
- list_remove(alist, ent);
+ /*
+ * start with highest priority ACE group and append
+ * the ACEs to the ACL.
+ */
+ for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
+ alist = &ace_grps[i];
+ while ((ace = list_head(alist)) != NULL) {
+ list_remove(alist, ace);
+ list_insert_tail(&acl->sl_sorted, ace);
+ }
list_destroy(alist);
}
-
- kmem_free(ace_list, ace_list_size);
-
- return (sorted_acl);
}
-static int
-smb_ace_common_add(
- smb_acl_t *acl,
- uint8_t type,
- uint8_t flags,
- uint32_t access_mask,
- nt_sid_t *sid)
+/*
+ * smb_acl_from_zfs
+ *
+ * Converts given ZFS ACL to a Windows ACL.
+ *
+ * A pointer to allocated memory for the Win ACL will be
+ * returned upon successful conversion.
+ */
+smb_acl_t *
+smb_acl_from_zfs(acl_t *zacl, uid_t uid, gid_t gid)
{
+ ace_t *zace;
+ int numaces;
+ smb_acl_t *acl;
smb_ace_t *ace;
- unsigned char *scan = (unsigned char *) acl;
- uint16_t used = smb_acl_len(acl);
- uint16_t sid_len = nt_sid_length(sid);
- uint16_t size;
+ smb_idmap_batch_t sib;
+ smb_idmap_t *sim;
+ idmap_stat idm_stat;
- size = sizeof (ace->se_header) + sizeof (ace->se_mask) + sid_len;
+ idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
+ SMB_IDMAP_ID2SID);
+ if (idm_stat != IDMAP_SUCCESS)
+ return (NULL);
- if (size + used > acl->sl_size) {
- /* won't fit */
- return (0);
+ if (smb_acl_getsids(&sib, zacl, uid, gid) != IDMAP_SUCCESS) {
+ smb_idmap_batch_destroy(&sib);
+ return (NULL);
}
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- ace = (smb_ace_t *)&scan[used];
+ acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);
+
+ sim = sib.sib_maps;
+ for (numaces = 0, zace = zacl->acl_aclp;
+ numaces < zacl->acl_cnt;
+ zace++, numaces++, sim++) {
+ ASSERT(sim->sim_sid);
+ if (sim->sim_sid == NULL) {
+ smb_acl_free(acl);
+ acl = NULL;
+ break;
+ }
- ace->se_header.se_type = type;
- ace->se_header.se_flags = flags;
- ace->se_header.se_size = size;
- ace->se_mask = access_mask;
- bcopy(sid, &ace->se_sid, sid_len);
+ ace = &acl->sl_aces[numaces];
+ ace->se_hdr.se_type = zace->a_type;
+ ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags);
+ ace->se_mask = zace->a_access_mask;
+ ace->se_sid = nt_sid_dup(sim->sim_sid);
+ ace->se_hdr.se_bsize = smb_ace_len(ace);
- acl->sl_acecnt++;
+ acl->sl_bsize += ace->se_hdr.se_bsize;
+ }
- return (1);
+ smb_idmap_batch_destroy(&sib);
+ return (acl);
}
-smb_ace_t *
-smb_ace_get(smb_acl_t *acl, uint16_t idx)
+/*
+ * smb_acl_to_zfs
+ *
+ * Converts given Windows ACL to a ZFS ACL.
+ *
+ * fs_acl will contain a pointer to the created ZFS ACL.
+ * The allocated memory should be freed by calling
+ * smb_fsacl_free().
+ *
+ * Since the output parameter, fs_acl, is allocated in this
+ * function, the caller has to make sure *fs_acl is NULL which
+ * means it's not pointing to any memory.
+ */
+uint32_t
+smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
{
smb_ace_t *ace;
- unsigned char *scan_beg = (unsigned char *) &acl[0];
- unsigned char *scan_end = scan_beg + acl->sl_size;
- unsigned char *scan = (unsigned char *) &acl[1];
- uint16_t count = 0;
+ acl_t *zacl;
+ ace_t *zace;
+ smb_idmap_batch_t sib;
+ smb_idmap_t *sim;
+ idmap_stat idm_stat;
+ int i, isdir;
- if (idx >= acl->sl_acecnt)
- return (NULL);
+ ASSERT(fs_acl);
+ ASSERT(*fs_acl == NULL);
- while (count <= idx && scan < scan_end) {
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- ace = (smb_ace_t *)scan;
+ if (acl && !smb_acl_isvalid(acl, which_acl))
+ return (NT_STATUS_INVALID_ACL);
- if (count == idx) {
- return (ace);
+ if ((acl == NULL) || (acl->sl_acecnt == 0)) {
+ if (which_acl == SMB_DACL_SECINFO) {
+ *fs_acl = smb_acl_null_empty(acl == NULL);
}
- scan += ace->se_header.se_size;
- count++;
+ return (NT_STATUS_SUCCESS);
}
- return (NULL);
-}
-
-int
-smb_acl_copy(uint16_t buflen, smb_acl_t *dst_acl, smb_acl_t *src_acl)
-{
- smb_ace_hdr_t *dst_ace;
- smb_ace_hdr_t *src_ace;
- unsigned char *scan = (unsigned char *) &src_acl[1];
- unsigned char *dest_beg = (unsigned char *) &dst_acl[0];
- unsigned char *dest_end;
- unsigned char *dest = (unsigned char *) &dst_acl[1];
- uint16_t count = 0;
- uint16_t n_bytes;
-
- n_bytes = smb_acl_len(src_acl);
- if (n_bytes > buflen)
- return (0);
+ idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
+ SMB_IDMAP_SID2ID);
+ if (idm_stat != IDMAP_SUCCESS)
+ return (NT_STATUS_INTERNAL_ERROR);
- dest_end = dest_beg + n_bytes;
-
- dst_acl->sl_revision = src_acl->sl_revision;
- dst_acl->sl_sbz1 = 0;
- dst_acl->sl_size = n_bytes;
- dst_acl->sl_acecnt = 0;
- dst_acl->sl_sbz2 = 0;
-
- while (count < src_acl->sl_acecnt && dest < dest_end) {
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- src_ace = (smb_ace_hdr_t *)scan;
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- dst_ace = (smb_ace_hdr_t *)dest;
- bcopy(src_ace, dst_ace, src_ace->se_size);
- dest += dst_ace->se_size;
- dst_acl->sl_acecnt++;
- scan += src_ace->se_size;
- count++;
- }
+ isdir = ((flags & ACL_IS_DIR) == ACL_IS_DIR);
- /*LINTED E_PTRDIFF_OVERFLOW*/
- return (dest - dest_beg);
-}
+ zacl = smb_fsacl_alloc(acl->sl_acecnt, flags);
-/*
- * smb_ace_len
- *
- * Returns the length of an ACE with the given SID
- *
- * struct smb_ace {
- * smb_ace_hdr_t se_header;
- * uint32_t se_mask;
- * nt_sid_t se_sid;
- * };
- */
-uint16_t
-smb_ace_len(nt_sid_t *sid)
-{
- ASSERT(sid);
+ zace = zacl->acl_aclp;
+ ace = acl->sl_aces;
+ sim = sib.sib_maps;
- return (sizeof (smb_ace_hdr_t)
- + sizeof (uint32_t) + nt_sid_length(sid));
-}
+ for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
+ zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES;
+ zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
+ zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags,
+ isdir);
-/*
- * smb_ace_mask_g2s
- *
- * Converts generic access bits in the given mask (if any)
- * to file specific bits. Generic access masks shouldn't be
- * stored in filesystem ACEs.
- */
-uint32_t
-smb_ace_mask_g2s(DWORD mask)
-{
- if (mask & GENERIC_ALL) {
- mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
- | GENERIC_EXECUTE);
+ if (nt_sid_is_equal(ace->se_sid, &everyone_sid))
+ zace->a_flags |= ACE_EVERYONE;
+ else {
+ sim->sim_id = &zace->a_who;
+ idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
+ ace->se_sid, -1);
- mask |= FILE_ALL_ACCESS;
- return (mask);
+ if (idm_stat != IDMAP_SUCCESS) {
+ smb_fsacl_free(zacl);
+ smb_idmap_batch_destroy(&sib);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ }
}
- if (mask & GENERIC_READ) {
- mask &= ~GENERIC_READ;
- mask |= FILE_GENERIC_READ;
+ idm_stat = smb_idmap_batch_getmappings(&sib);
+ if (idm_stat != IDMAP_SUCCESS) {
+ smb_fsacl_free(zacl);
+ smb_idmap_batch_destroy(&sib);
+ return (NT_STATUS_NONE_MAPPED);
}
- if (mask & GENERIC_WRITE) {
- mask &= ~GENERIC_WRITE;
- mask |= FILE_GENERIC_WRITE;
- }
+ /*
+ * Set the ACEs group flag based on the type of ID returned.
+ */
+ zace = zacl->acl_aclp;
+ ace = acl->sl_aces;
+ sim = sib.sib_maps;
+ for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
+ if (zace->a_flags & ACE_EVERYONE)
+ continue;
- if (mask & GENERIC_EXECUTE) {
- mask &= ~GENERIC_EXECUTE;
- mask |= FILE_GENERIC_EXECUTE;
+ if (sim->sim_idtype == SMB_IDMAP_GROUP)
+ zace->a_flags |= ACE_IDENTIFIER_GROUP;
}
- return (mask);
+ smb_idmap_batch_destroy(&sib);
+
+ *fs_acl = zacl;
+ return (NT_STATUS_SUCCESS);
}
/*
@@ -702,239 +507,488 @@ smb_acl_getsids(smb_idmap_batch_t *sib, acl_t *zacl, uid_t uid, gid_t gid)
}
/*
- * smb_acl_grow
+ * smb_acl_null_empty
+ *
+ * NULL DACL means everyone full-access
+ * Empty DACL means everyone full-deny
*
- * Grow the acl size by given number of bytes in 'grow'
- * Returns pointer to the newly allocated memory.
+ * ZFS ACL must have at least one entry so smb server has
+ * to simulate the aforementioned expected behavior by adding
+ * an entry in case the requested DACL is null or empty. Adding
+ * a everyone full-deny entry has proved to be problematic in
+ * tests since a deny entry takes precedence over allow entries.
+ * So, instead of adding a everyone full-deny, an owner ACE with
+ * owner implicit permissions will be set.
*/
-static smb_acl_t *
-smb_acl_grow(smb_acl_t *acl, uint16_t grow)
+static acl_t *
+smb_acl_null_empty(boolean_t null)
{
- smb_acl_t *new_acl;
- uint16_t smb_aclsz;
+ acl_t *zacl;
+ ace_t *zace;
- ASSERT(acl);
+ zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT);
+ zace = zacl->acl_aclp;
- smb_aclsz = acl->sl_size;
- new_acl = kmem_alloc(smb_aclsz + grow, KM_SLEEP);
- (void) memcpy(new_acl, acl, smb_aclsz);
- kmem_free(acl, smb_aclsz);
- new_acl->sl_size = smb_aclsz + grow;
+ zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+ if (null) {
+ zace->a_access_mask = ACE_ALL_PERMS;
+ zace->a_flags = ACE_EVERYONE;
+ } else {
+ zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
+ ACE_READ_ATTRIBUTES;
+ zace->a_flags = ACE_OWNER;
+ }
- return (new_acl);
+ return (zacl);
}
/*
- * smb_acl_from_zfs
+ * FS ACL (acl_t) Functions
+ */
+acl_t *
+smb_fsacl_alloc(int acenum, int flags)
+{
+ acl_t *acl;
+
+ acl = acl_alloc(ACE_T);
+ acl->acl_cnt = acenum;
+ acl->acl_aclp = kmem_zalloc(acl->acl_entry_size * acenum, KM_SLEEP);
+ acl->acl_flags = flags;
+ return (acl);
+}
+
+void
+smb_fsacl_free(acl_t *acl)
+{
+ if (acl)
+ acl_free(acl);
+}
+
+/*
+ * smb_fsop_aclmerge
*
- * Converts given ZFS ACL to a Windows ACL.
+ * smb_fsop_aclread/write routines which interact with filesystem
+ * work with single ACL. This routine merges given DACL and SACL
+ * which might have been created during CIFS to FS conversion into
+ * one single ACL.
+ */
+acl_t *
+smb_fsacl_merge(acl_t *dacl, acl_t *sacl)
+{
+ acl_t *acl;
+ int dacl_size;
+
+ ASSERT(dacl);
+ ASSERT(sacl);
+
+ acl = smb_fsacl_alloc(dacl->acl_cnt + sacl->acl_cnt, dacl->acl_flags);
+ dacl_size = dacl->acl_cnt * dacl->acl_entry_size;
+ bcopy(dacl->acl_aclp, acl->acl_aclp, dacl_size);
+ bcopy(sacl->acl_aclp, (char *)acl->acl_aclp + dacl_size,
+ sacl->acl_cnt * sacl->acl_entry_size);
+
+ return (acl);
+}
+
+/*
+ * smb_fsacl_split
*
- * A pointer to allocated memory for the Win ACL will be
- * returned upon successful conversion.
+ * splits the given ACE_T ACL (zacl) to one or two ACLs (DACL/SACL) based on
+ * the 'which_acl' parameter. Note that output dacl/sacl parameters could be
+ * NULL even if they're specified in 'which_acl', which means the target
+ * doesn't have any access and/or audit ACEs.
*/
-smb_acl_t *
-smb_acl_from_zfs(acl_t *zacl, uid_t uid, gid_t gid)
+void
+smb_fsacl_split(acl_t *zacl, acl_t **dacl, acl_t **sacl, int which_acl)
{
ace_t *zace;
+ ace_t *access_ace;
+ ace_t *audit_ace;
+ int naccess, naudit;
+ int get_dacl, get_sacl;
+ int i;
+
+ *dacl = *sacl = NULL;
+ naccess = naudit = 0;
+ get_dacl = (which_acl & SMB_DACL_SECINFO);
+ get_sacl = (which_acl & SMB_SACL_SECINFO);
+
+ for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
+ if (get_dacl && smb_ace_is_access(zace->a_type))
+ naccess++;
+ else if (get_sacl && smb_ace_is_audit(zace->a_type))
+ naudit++;
+ }
+
+ if (naccess) {
+ *dacl = smb_fsacl_alloc(naccess, zacl->acl_flags);
+ access_ace = (*dacl)->acl_aclp;
+ }
+
+ if (naudit) {
+ *sacl = smb_fsacl_alloc(naudit, zacl->acl_flags);
+ audit_ace = (*sacl)->acl_aclp;
+ }
+
+ for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
+ if (get_dacl && smb_ace_is_access(zace->a_type)) {
+ *access_ace = *zace;
+ access_ace++;
+ } else if (get_sacl && smb_ace_is_audit(zace->a_type)) {
+ *audit_ace = *zace;
+ audit_ace++;
+ }
+ }
+}
+
+/*
+ * ACE Inheritance Rules
+ *
+ * The system propagates inheritable ACEs to child objects according to a
+ * set of inheritance rules. The system places inherited ACEs in the child's
+ * DACL according to the preferred order of ACEs in a DACL. For Windows
+ * 2000 or later, the system sets the INHERITED_ACE flag in all inherited ACEs.
+ *
+ * The following table shows the ACEs inherited by container and noncontainer
+ * child objects for different combinations of inheritance flags. These
+ * inheritance rules work the same for both DACLs and SACLs.
+ *
+ * Parent ACE type Effect on Child ACL
+ * ----------------------- -------------------
+ * OBJECT_INHERIT_ACE only Noncontainer child objects:
+ * Inherited as an effective ACE.
+ * Container child objects:
+ * Containers inherit an inherit-only ACE
+ * unless the NO_PROPAGATE_INHERIT_ACE bit
+ * flag is also set.
+ *
+ * CONTAINER_INHERIT_ACE only Noncontainer child objects:
+ * No effect on the child object.
+ * Container child objects:
+ * The child object inherits an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * NO_PROPAGATE_INHERIT_ACE bit flag is also set.
+ *
+ * CONTAINER_INHERIT_ACE and
+ * OBJECT_INHERIT_ACE Noncontainer child objects:
+ * Inherited as an effective ACE.
+ * Container child objects:
+ * The child object inherits an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * NO_PROPAGATE_INHERIT_ACE bit flag is also set
+ *
+ * No inheritance flags set No effect on child container or noncontainer
+ * objects.
+ *
+ * If an inherited ACE is an effective ACE for the child object, the system
+ * maps any generic rights to the specific rights for the child object.
+ * Similarly, the system maps generic SIDs, such as CREATOR_OWNER, to the
+ * appropriate SID. If an inherited ACE is an inherit-only ACE, any generic
+ * rights or generic SIDs are left unchanged so that they can be mapped
+ * appropriately when the ACE is inherited by the next generation of child
+ * objects.
+ *
+ * For a case in which a container object inherits an ACE that is both
+ * effective on the container and inheritable by its descendants, the
+ * container may inherit two ACEs. This occurs if the inheritable ACE
+ * contains generic information. The container inherits an inherit-only
+ * ACE containing the generic information and an effective-only ACE in
+ * which the generic information has been mapped.
+ */
+
+/*
+ * smb_fsacl_inherit
+ *
+ * Manufacture the inherited ACL from the given ACL considering
+ * the new object type (file/dir) specified by 'is_dir'. The
+ * returned ACL is used in smb_fsop_create/smb_fsop_mkdir functions.
+ * This function implements Windows inheritance rules explained above.
+ *
+ * Note that the in/out ACLs are ZFS ACLs not Windows ACLs
+ */
+acl_t *
+smb_fsacl_inherit(acl_t *dir_zacl, int is_dir, int which_acl, uid_t owner_uid)
+{
+ boolean_t use_default = B_FALSE;
+ int num_inheritable = 0;
int numaces;
- smb_acl_t *acl;
- uint16_t smb_aclsz;
- smb_idmap_batch_t sib;
- smb_idmap_t *sim;
- idmap_stat idm_stat;
- int status;
+ ace_t *dir_zace;
+ acl_t *new_zacl;
+ ace_t *new_zace;
- idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
- SMB_IDMAP_ID2SID);
- if (idm_stat != IDMAP_SUCCESS)
- return (NULL);
+ num_inheritable = smb_fsacl_inheritable(dir_zacl, is_dir);
- if (smb_acl_getsids(&sib, zacl, uid, gid) != IDMAP_SUCCESS) {
- smb_idmap_batch_destroy(&sib);
- return (NULL);
+ if (num_inheritable == 0) {
+ if (which_acl == SMB_DACL_SECINFO) {
+ /* No inheritable access ACEs -> default DACL */
+ num_inheritable = DEFAULT_DACL_ACENUM;
+ use_default = B_TRUE;
+ } else {
+ return (NULL);
+ }
}
- smb_aclsz = sizeof (smb_acl_t);
+ new_zacl = smb_fsacl_alloc(num_inheritable, ACL_AUTO_INHERIT);
+ new_zace = new_zacl->acl_aclp;
- acl = kmem_alloc(smb_aclsz, KM_SLEEP);
- smb_acl_init(acl, smb_aclsz, ACL_REVISION);
+ if (use_default) {
+ bcopy(default_dacl, new_zacl->acl_aclp, sizeof (default_dacl));
+ new_zace->a_who = owner_uid;
+ return (new_zacl);
+ }
- sim = sib.sib_maps;
- for (numaces = 0, zace = zacl->acl_aclp;
- numaces < zacl->acl_cnt;
- zace++, numaces++, sim++) {
- ASSERT(sim->sim_sid);
- if (sim->sim_sid == NULL) {
- kmem_free(acl, acl->sl_size);
- acl = NULL;
+ for (numaces = 0, dir_zace = dir_zacl->acl_aclp;
+ numaces < dir_zacl->acl_cnt;
+ dir_zace++, numaces++) {
+ switch (dir_zace->a_flags & ACE_FD_INHERIT_ACE) {
+ case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
+ /*
+ * Files inherit an effective ACE.
+ *
+ * Dirs inherit an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
+ */
+ smb_ace_inherit(dir_zace, new_zace, is_dir);
+ new_zace++;
+
+ if (is_dir && ZACE_IS_CREATOR(dir_zace) &&
+ (ZACE_IS_PROPAGATE(dir_zace))) {
+ *new_zace = *dir_zace;
+ new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
+ ACE_INHERITED_ACE);
+ new_zace++;
+ }
break;
- }
- /* Make room for this ACE */
- acl = smb_acl_grow(acl, smb_ace_len(sim->sim_sid));
+ case ACE_FILE_INHERIT_ACE:
+ /*
+ * Files inherit as an effective ACE.
+ *
+ * Dirs inherit an inherit-only ACE
+ * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
+ * flag is also set.
+ */
+ if (is_dir == 0) {
+ smb_ace_inherit(dir_zace, new_zace, is_dir);
+ new_zace++;
+ } else if (ZACE_IS_PROPAGATE(dir_zace)) {
+ *new_zace = *dir_zace;
+ new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
+ ACE_INHERITED_ACE);
+ new_zace++;
+ }
+ break;
- status = smb_ace_common_add(acl,
- zace->a_type,
- smb_ace_flags_fromzfs(zace->a_flags),
- zace->a_access_mask,
- sim->sim_sid);
+ case ACE_DIRECTORY_INHERIT_ACE:
+ /*
+ * No effect on files
+ *
+ * Dirs inherit an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
+ */
+ if (is_dir == 0)
+ break;
- if (status == 0) {
- kmem_free(acl, acl->sl_size);
- acl = NULL;
+ smb_ace_inherit(dir_zace, new_zace, is_dir);
+ new_zace++;
+
+ if (ZACE_IS_CREATOR(dir_zace) &&
+ (ZACE_IS_PROPAGATE(dir_zace))) {
+ *new_zace = *dir_zace;
+ new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
+ ACE_INHERITED_ACE);
+ new_zace++;
+ }
+
+ break;
+
+ default:
break;
}
}
- smb_idmap_batch_destroy(&sib);
- return (acl);
+ return (new_zacl);
}
/*
- * SID for Everyone group: S-1-1-0.
- */
-nt_sid_t everyone_sid = {
- NT_SID_REVISION,
- 1,
- NT_SECURITY_WORLD_AUTH,
- { 0 }
-};
-
-/*
- * smb_acl_null_empty
+ * smb_fsacl_from_vsa
*
- * NULL DACL means everyone full-access
- * Empty DACL means everyone full-deny
+ * Converts given vsecattr_t structure to a acl_t structure.
*
- * ZFS ACL must have at least one entry so smb server has
- * to simulate the aforementioned expected behavior by adding
- * an entry in case the requested DACL is null or empty. Adding
- * a everyone full-deny entry has proved to be problematic in
- * tests since a deny entry takes precedence over allow entries.
- * So, instead of adding a everyone full-deny, an owner ACE with
- * owner implicit permissions will be set.
+ * The allocated memory for retuned acl_t should be freed by
+ * calling acl_free().
*/
acl_t *
-smb_acl_null_empty(int null)
+smb_fsacl_from_vsa(vsecattr_t *vsecattr, acl_type_t acl_type)
{
- acl_t *zacl;
- ace_t *zace;
+ int aclbsize = 0; /* size of acl list in bytes */
+ int dfaclbsize = 0; /* size of default acl list in bytes */
+ int numacls;
+ acl_t *acl_info;
- zacl = smb_fsop_aclalloc(1, ACL_AUTO_INHERIT);
- zace = zacl->acl_aclp;
+ ASSERT(vsecattr);
- zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
- if (null) {
- zace->a_access_mask = ACE_ALL_PERMS;
- zace->a_flags = ACE_EVERYONE;
- } else {
- zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
- ACE_READ_ATTRIBUTES;
- zace->a_flags = ACE_OWNER;
+ acl_info = acl_alloc(acl_type);
+ if (acl_info == NULL)
+ return (NULL);
+
+ acl_info->acl_flags = 0;
+
+ switch (acl_type) {
+
+ case ACLENT_T:
+ numacls = vsecattr->vsa_aclcnt + vsecattr->vsa_dfaclcnt;
+ aclbsize = vsecattr->vsa_aclcnt * sizeof (aclent_t);
+ dfaclbsize = vsecattr->vsa_dfaclcnt * sizeof (aclent_t);
+
+ acl_info->acl_cnt = numacls;
+ acl_info->acl_aclp = kmem_alloc(aclbsize + dfaclbsize,
+ KM_SLEEP);
+ (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
+ aclbsize);
+ (void) memcpy((char *)acl_info->acl_aclp + aclbsize,
+ vsecattr->vsa_dfaclentp, dfaclbsize);
+
+ if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
+ acl_info->acl_flags |= ACL_IS_TRIVIAL;
+
+ break;
+
+ case ACE_T:
+ aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
+ acl_info->acl_cnt = vsecattr->vsa_aclcnt;
+ acl_info->acl_flags = vsecattr->vsa_aclflags;
+ acl_info->acl_aclp = kmem_alloc(aclbsize, KM_SLEEP);
+ (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
+ aclbsize);
+ if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
+ acl_info->acl_flags |= ACL_IS_TRIVIAL;
+
+ break;
+
+ default:
+ acl_free(acl_info);
+ return (NULL);
}
- return (zacl);
+ if (aclbsize && vsecattr->vsa_aclentp)
+ kmem_free(vsecattr->vsa_aclentp, aclbsize);
+ if (dfaclbsize && vsecattr->vsa_dfaclentp)
+ kmem_free(vsecattr->vsa_dfaclentp, dfaclbsize);
+
+ return (acl_info);
}
/*
- * smb_acl_to_zfs
+ * smb_fsacl_to_vsa
*
- * Converts given Windows ACL to a ZFS ACL.
+ * Converts given acl_t structure to a vsecattr_t structure.
*
- * fs_acl will contain a pointer to the created ZFS ACL.
- * The allocated memory should be freed by calling
- * smb_fsop_aclfree().
- *
- * Since the output parameter, fs_acl, is allocated in this
- * function, the caller has to make sure *fs_acl is NULL which
- * means it's not pointing to any memory.
+ * IMPORTANT:
+ * Upon successful return the memory allocated for vsa_aclentp
+ * should be freed by calling kmem_free(). The size is returned
+ * in aclbsize.
*/
-uint32_t
-smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
+int
+smb_fsacl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, int *aclbsize)
{
- smb_ace_t *ace;
- acl_t *zacl;
- ace_t *zace;
- smb_idmap_batch_t sib;
- smb_idmap_t *sim;
- idmap_stat idm_stat;
- int i, isdir;
+ int error = 0;
+ int numacls;
+ aclent_t *aclp;
- ASSERT(fs_acl);
- ASSERT(*fs_acl == NULL);
+ ASSERT(acl_info);
+ ASSERT(vsecattr);
+ ASSERT(aclbsize);
- if (acl && !smb_acl_isvalid(acl, which_acl))
- return (NT_STATUS_INVALID_ACL);
+ bzero(vsecattr, sizeof (vsecattr_t));
+ *aclbsize = 0;
- if ((acl == NULL) || (acl->sl_acecnt == 0)) {
- if (which_acl == SMB_DACL_SECINFO) {
- *fs_acl = smb_acl_null_empty(acl == NULL);
+ switch (acl_info->acl_type) {
+ case ACLENT_T:
+ numacls = acl_info->acl_cnt;
+ /*
+ * Minimum ACL size is three entries so might as well
+ * bail out here. Also limit request size to prevent user
+ * from allocating too much kernel memory. Maximum size
+ * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES
+ * for the default ACL part.
+ */
+ if (numacls < 3 || numacls > (MAX_ACL_ENTRIES * 2)) {
+ error = EINVAL;
+ break;
}
- return (NT_STATUS_SUCCESS);
- }
+ vsecattr->vsa_mask = VSA_ACL;
- idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
- SMB_IDMAP_SID2ID);
- if (idm_stat != IDMAP_SUCCESS)
- return (NT_STATUS_INTERNAL_ERROR);
+ vsecattr->vsa_aclcnt = numacls;
+ *aclbsize = numacls * sizeof (aclent_t);
+ vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
+ (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
+ *aclbsize);
- isdir = ((flags & ACL_IS_DIR) == ACL_IS_DIR);
+ /* Sort the acl list */
+ ksort((caddr_t)vsecattr->vsa_aclentp,
+ vsecattr->vsa_aclcnt, sizeof (aclent_t), cmp2acls);
- zacl = smb_fsop_aclalloc(acl->sl_acecnt, flags);
+ /* Break into acl and default acl lists */
+ for (numacls = 0, aclp = vsecattr->vsa_aclentp;
+ numacls < vsecattr->vsa_aclcnt;
+ aclp++, numacls++) {
+ if (aclp->a_type & ACL_DEFAULT)
+ break;
+ }
- zace = zacl->acl_aclp;
- sim = sib.sib_maps;
+ /* Find where defaults start (if any) */
+ if (numacls < vsecattr->vsa_aclcnt) {
+ vsecattr->vsa_mask |= VSA_DFACL;
+ vsecattr->vsa_dfaclcnt = vsecattr->vsa_aclcnt - numacls;
+ vsecattr->vsa_dfaclentp = aclp;
+ vsecattr->vsa_aclcnt = numacls;
+ }
- for (i = 0; ace = smb_ace_get(acl, i); i++, zace++, sim++) {
- zace->a_type = ace->se_header.se_type & ACE_ALL_TYPES;
- zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
- zace->a_flags = smb_ace_flags_tozfs(ace->se_header.se_flags,
- isdir);
+ /* Adjust if they're all defaults */
+ if (vsecattr->vsa_aclcnt == 0) {
+ vsecattr->vsa_mask &= ~VSA_ACL;
+ vsecattr->vsa_aclentp = NULL;
+ }
- if (nt_sid_is_equal(&ace->se_sid, &everyone_sid))
- zace->a_flags |= ACE_EVERYONE;
- else {
- sim->sim_id = &zace->a_who;
- idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
- &ace->se_sid, -1);
+ /* Only directories can have defaults */
+ if (vsecattr->vsa_dfaclcnt &&
+ (acl_info->acl_flags & ACL_IS_DIR)) {
+ error = ENOTDIR;
+ }
- if (idm_stat != IDMAP_SUCCESS) {
- smb_fsop_aclfree(zacl);
- smb_idmap_batch_destroy(&sib);
- return (NT_STATUS_INTERNAL_ERROR);
- }
+ break;
+
+ case ACE_T:
+ if (acl_info->acl_cnt < 1 ||
+ acl_info->acl_cnt > MAX_ACL_ENTRIES) {
+ error = EINVAL;
+ break;
}
- }
- idm_stat = smb_idmap_batch_getmappings(&sib);
- if (idm_stat != IDMAP_SUCCESS) {
- smb_fsop_aclfree(zacl);
- smb_idmap_batch_destroy(&sib);
- return (NT_STATUS_NONE_MAPPED);
- }
+ vsecattr->vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
+ vsecattr->vsa_aclcnt = acl_info->acl_cnt;
+ vsecattr->vsa_aclflags = acl_info->acl_flags & ACL_FLAGS_ALL;
+ *aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
+ vsecattr->vsa_aclentsz = *aclbsize;
+ vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
+ (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
+ *aclbsize);
- /*
- * Set the ACEs group flag based on the type of ID returned.
- */
- zace = zacl->acl_aclp;
- sim = sib.sib_maps;
- for (i = 0; i < acl->sl_acecnt; i++, zace++, sim++) {
- if (zace->a_flags & ACE_EVERYONE)
- continue;
+ break;
- if (sim->sim_idtype == SMB_IDMAP_GROUP)
- zace->a_flags |= ACE_IDENTIFIER_GROUP;
+ default:
+ error = EINVAL;
}
- smb_idmap_batch_destroy(&sib);
-
- *fs_acl = zacl;
- return (NT_STATUS_SUCCESS);
+ return (error);
}
/*
- * smb_acl_inheritable
+ * smb_fsacl_inheritable
*
* Checks to see if there are any inheritable ACEs in the
* given ZFS ACL. Returns the number of inheritable ACEs.
@@ -984,7 +1038,7 @@ smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
* 1c: one creator owner/group ACE
*/
static int
-smb_acl_inheritable(acl_t *zacl, int is_dir)
+smb_fsacl_inheritable(acl_t *zacl, int is_dir)
{
int numaces;
int num_inheritable = 0;
@@ -1053,132 +1107,92 @@ smb_acl_inheritable(acl_t *zacl, int is_dir)
return (num_inheritable);
}
-#define DEFAULT_DACL_ACENUM 2
+
/*
- * Default ACL:
- * owner: full access
- * SYSTEM: full access
+ * ACE Functions
*/
-static ace_t default_dacl[DEFAULT_DACL_ACENUM] = {
- { (uid_t)-1, ACE_ALL_PERMS, 0, ACE_ACCESS_ALLOWED_ACE_TYPE },
- { IDMAP_WK_LOCAL_SYSTEM_GID, ACE_ALL_PERMS, ACE_IDENTIFIER_GROUP,
- ACE_ACCESS_ALLOWED_ACE_TYPE }
-};
/*
- * smb_acl_inherit
- *
- * Manufacture the inherited ACL from the given ACL considering
- * the new object type (file/dir) specified by 'is_dir'. The
- * returned ACL is used in smb_fsop_create/smb_fsop_mkdir functions.
- * This function implements Windows inheritance rules.
- *
- * Note that the in/our ACLs are ZFS ACLs not Windows ACLs
+ * This is generic (ACL version 2) vs. object-specific
+ * (ACL version 4) ACE types.
*/
-acl_t *
-smb_acl_inherit(acl_t *dir_zacl, int is_dir, int which_acl, uid_t owner_uid)
+boolean_t
+smb_ace_is_generic(int type)
{
- boolean_t use_default = B_FALSE;
- int num_inheritable = 0;
- int numaces;
- ace_t *dir_zace;
- acl_t *new_zacl;
- ace_t *new_zace;
-
- num_inheritable = smb_acl_inheritable(dir_zacl, is_dir);
+ switch (type) {
+ case ACE_ACCESS_ALLOWED_ACE_TYPE:
+ case ACE_ACCESS_DENIED_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
+ case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE:
+ return (B_TRUE);
- if (num_inheritable == 0) {
- if (which_acl == SMB_DACL_SECINFO) {
- /* No inheritable access ACEs -> default DACL */
- num_inheritable = DEFAULT_DACL_ACENUM;
- use_default = B_TRUE;
- } else {
- return (NULL);
- }
+ default:
+ break;
}
- new_zacl = smb_fsop_aclalloc(num_inheritable, ACL_AUTO_INHERIT);
- new_zace = new_zacl->acl_aclp;
-
- if (use_default) {
- bcopy(default_dacl, new_zacl->acl_aclp, sizeof (default_dacl));
- new_zace->a_who = owner_uid;
- return (new_zacl);
- }
+ return (B_FALSE);
+}
- for (numaces = 0, dir_zace = dir_zacl->acl_aclp;
- numaces < dir_zacl->acl_cnt;
- dir_zace++, numaces++) {
- switch (dir_zace->a_flags & ACE_FD_INHERIT_ACE) {
- case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
- /*
- * Files inherit an effective ACE.
- *
- * Dirs inherit an effective ACE.
- * The inherited ACE is inheritable unless the
- * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
- */
- smb_ace_inherit(dir_zace, new_zace, is_dir);
- new_zace++;
+boolean_t
+smb_ace_is_access(int type)
+{
+ switch (type) {
+ case ACE_ACCESS_ALLOWED_ACE_TYPE:
+ case ACE_ACCESS_DENIED_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
+ case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
+ return (B_TRUE);
- if (is_dir && ZACE_IS_CREATOR(dir_zace) &&
- (ZACE_IS_PROPAGATE(dir_zace))) {
- *new_zace = *dir_zace;
- new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
- ACE_INHERITED_ACE);
- new_zace++;
- }
- break;
+ default:
+ break;
+ }
- case ACE_FILE_INHERIT_ACE:
- /*
- * Files inherit as an effective ACE.
- *
- * Dirs inherit an inherit-only ACE
- * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
- * flag is also set.
- */
- if (is_dir == 0) {
- smb_ace_inherit(dir_zace, new_zace, is_dir);
- new_zace++;
- } else if (ZACE_IS_PROPAGATE(dir_zace)) {
- *new_zace = *dir_zace;
- new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
- ACE_INHERITED_ACE);
- new_zace++;
- }
- break;
+ return (B_FALSE);
+}
- case ACE_DIRECTORY_INHERIT_ACE:
- /*
- * No effect on files
- *
- * Dirs inherit an effective ACE.
- * The inherited ACE is inheritable unless the
- * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
- */
- if (is_dir == 0)
- break;
+boolean_t
+smb_ace_is_audit(int type)
+{
+ switch (type) {
+ case ACE_SYSTEM_AUDIT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
+ return (B_TRUE);
- smb_ace_inherit(dir_zace, new_zace, is_dir);
- new_zace++;
+ default:
+ break;
+ }
- if (ZACE_IS_CREATOR(dir_zace) &&
- (ZACE_IS_PROPAGATE(dir_zace))) {
- *new_zace = *dir_zace;
- new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
- ACE_INHERITED_ACE);
- new_zace++;
- }
+ return (B_FALSE);
+}
- break;
+/*
+ * smb_ace_len
+ *
+ * Returns the length of the given ACE as it appears in an
+ * ACL on the wire (i.e. a flat buffer which contains the SID)
+ */
+static uint16_t
+smb_ace_len(smb_ace_t *ace)
+{
+ ASSERT(ace);
+ ASSERT(ace->se_sid);
- default:
- break;
- }
- }
+ if (ace == NULL)
+ return (0);
- return (new_zacl);
+ return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) +
+ nt_sid_length(ace->se_sid));
}
static void
@@ -1202,6 +1216,42 @@ smb_ace_inherit(ace_t *dir_zace, ace_t *zace, int is_dir)
}
}
+/*
+ * smb_ace_mask_g2s
+ *
+ * Converts generic access bits in the given mask (if any)
+ * to file specific bits. Generic access masks shouldn't be
+ * stored in filesystem ACEs.
+ */
+static uint32_t
+smb_ace_mask_g2s(uint32_t mask)
+{
+ if (mask & GENERIC_ALL) {
+ mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
+ | GENERIC_EXECUTE);
+
+ mask |= FILE_ALL_ACCESS;
+ return (mask);
+ }
+
+ if (mask & GENERIC_READ) {
+ mask &= ~GENERIC_READ;
+ mask |= FILE_GENERIC_READ;
+ }
+
+ if (mask & GENERIC_WRITE) {
+ mask &= ~GENERIC_WRITE;
+ mask |= FILE_GENERIC_WRITE;
+ }
+
+ if (mask & GENERIC_EXECUTE) {
+ mask &= ~GENERIC_EXECUTE;
+ mask |= FILE_GENERIC_EXECUTE;
+ }
+
+ return (mask);
+}
+
static uint16_t
smb_ace_flags_tozfs(uint8_t c_flags, int isdir)
{
@@ -1245,66 +1295,37 @@ smb_ace_flags_fromzfs(uint16_t z_flags)
return (c_flags);
}
-/*
- * This is generic (ACL version 2) vs. object-specific
- * (ACL version 4) ACE types.
- */
-int
-smb_ace_is_generic(int type)
+static boolean_t
+smb_ace_isvalid(smb_ace_t *ace, int which_acl)
{
- switch (type) {
- case ACE_ACCESS_ALLOWED_ACE_TYPE:
- case ACE_ACCESS_DENIED_ACE_TYPE:
- case ACE_SYSTEM_AUDIT_ACE_TYPE:
- case ACE_SYSTEM_ALARM_ACE_TYPE:
- case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
- case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
- case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
- case ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE:
- return (1);
+ uint16_t min_len;
- default:
- break;
- }
+ min_len = sizeof (smb_acehdr_t);
- return (0);
-}
+ if (ace->se_hdr.se_bsize < min_len)
+ return (B_FALSE);
-int
-smb_ace_is_access(int type)
-{
- switch (type) {
- case ACE_ACCESS_ALLOWED_ACE_TYPE:
- case ACE_ACCESS_DENIED_ACE_TYPE:
- case ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
- case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
- case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
- case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
- case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
- case ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
- case ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
- return (1);
+ if (smb_ace_is_access(ace->se_hdr.se_type) &&
+ (which_acl != SMB_DACL_SECINFO))
+ return (B_FALSE);
- default:
- break;
- }
+ if (smb_ace_is_audit(ace->se_hdr.se_type) &&
+ (which_acl != SMB_SACL_SECINFO))
+ return (B_FALSE);
- return (0);
-}
+ if (smb_ace_is_generic(ace->se_hdr.se_type)) {
+ if (nt_sid_is_valid(ace->se_sid) == 0)
+ return (B_FALSE);
-int
-smb_ace_is_audit(int type)
-{
- switch (type) {
- case ACE_SYSTEM_AUDIT_ACE_TYPE:
- case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
- case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
- case ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
- return (1);
+ min_len += sizeof (ace->se_mask);
+ min_len += nt_sid_length(ace->se_sid);
- default:
- break;
+ if (ace->se_hdr.se_bsize < min_len)
+ return (B_FALSE);
}
- return (0);
+ /*
+ * object-specific ACE validation will be added later.
+ */
+ return (B_TRUE);
}
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 30058e8f82..d3a462fbc5 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
@@ -879,7 +879,7 @@ smb_open_subr(struct smb_request *sr)
op->dattr &= ~SMB_FA_READONLY;
}
smb_node_set_dosattr(node, op->dattr | SMB_FA_ARCHIVE);
- if (op->utime.tv_sec == 0 || op->utime.tv_sec == 0xffffffff)
+ if (op->utime.tv_sec == 0 || op->utime.tv_sec == UINT_MAX)
(void) microtime(&op->utime);
smb_node_set_time(node, NULL, &op->utime, 0, 0, SMB_AT_MTIME);
(void) smb_sync_fsattr(sr, sr->user_cr, node);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_create.c b/usr/src/uts/common/fs/smbsrv/smb_create.c
index fccdf5ba9e..8fd289bb75 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_create.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_create.c
@@ -176,7 +176,7 @@ smb_com_create_temporary(struct smb_request *sr)
break;
}
- smbsr_encode_result(sr, 1, 0, "bwwwbs", 1, sr->smb_fid, bcc, 4, name);
+ smbsr_encode_result(sr, 1, 0, "bwwbs", 1, sr->smb_fid, bcc, 4, name);
return (SDRC_NORMAL_REPLY);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_fsops.c b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
index 655e5ad3ff..3d7292961e 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
@@ -26,29 +26,19 @@
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sid.h>
-#include <smbsrv/smb_incl.h>
#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_kproto.h>
+#include <smbsrv/smbvar.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/ntaccess.h>
#include <acl/acl_common.h>
u_longlong_t smb_caller_id;
static int smb_fsop_amask_to_omode(uint32_t granted_access);
-
-extern uint32_t smb_sd_tofs(smb_sdbuf_t *sr_sd, smb_fssd_t *fs_sd);
-
-extern uint32_t smb_sd_write(smb_request_t *sr, smb_sdbuf_t *sr_sd,
- uint32_t secinfo);
-
-extern int smb_vop_acl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr,
- int *aclbsize);
-
static int smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode,
smb_fssd_t *fs_sd);
-static void smb_fsop_aclsplit(acl_t *zacl, acl_t **dacl, acl_t **sacl,
- int which_acl);
-static acl_t *smb_fsop_aclmerge(acl_t *dacl, acl_t *sacl);
-
/*
* The smb_fsop_* functions have knowledge of CIFS semantics.
*
@@ -161,6 +151,7 @@ smb_fsop_create_with_sd(
int flags = 0;
int is_dir;
int rc;
+ boolean_t no_xvattr = B_FALSE;
ASSERT(fs_sd);
@@ -178,14 +169,14 @@ smb_fsop_create_with_sd(
sacl = fs_sd->sd_zsacl;
ASSERT(dacl || sacl);
if (dacl && sacl) {
- acl = smb_fsop_aclmerge(dacl, sacl);
+ acl = smb_fsacl_merge(dacl, sacl);
} else if (dacl) {
acl = dacl;
} else {
acl = sacl;
}
- rc = smb_vop_acl_to_vsa(acl, &vsecattr, &aclbsize);
+ rc = smb_fsacl_to_vsa(acl, &vsecattr, &aclbsize);
if (dacl && sacl)
acl_free(acl);
@@ -231,8 +222,11 @@ smb_fsop_create_with_sd(
}
if (set_attr.sa_mask) {
+ if (sr && sr->tid_tree)
+ if (sr->tid_tree->t_flags & SMB_TREE_FLAG_UFS)
+ no_xvattr = B_TRUE;
rc = smb_vop_setattr(snode->vp, NULL, &set_attr,
- 0, kcred, &ct);
+ 0, kcred, no_xvattr, &ct);
}
} else {
@@ -253,7 +247,10 @@ smb_fsop_create_with_sd(
cr, &ct, NULL);
}
- if (rc == 0)
+ if (rc != 0)
+ return (rc);
+
+ if ((sr->tid_tree->t_flags & SMB_TREE_FLAG_NFS_MOUNTED) == 0)
rc = smb_fsop_sdwrite(sr, kcred, snode, fs_sd, 1);
}
@@ -267,6 +264,14 @@ smb_fsop_create_with_sd(
}
}
+ if (rc != 0) {
+ if (is_dir) {
+ (void) smb_vop_rmdir(snode->vp, name, flags, cr, &ct);
+ } else {
+ (void) smb_vop_remove(snode->vp, name, flags, cr, &ct);
+ }
+ }
+
return (rc);
}
@@ -417,36 +422,36 @@ smb_fsop_create(
return (ENOMEM);
}
} else {
- if (op->sd_buf) {
+ if (op->sd) {
/*
* SD sent by client in Windows format. Needs to be
* converted to FS format. No inheritance.
*/
- secinfo = smb_sd_get_secinfo((smb_sdbuf_t *)op->sd_buf);
- smb_fsop_sdinit(&fs_sd, secinfo, 0);
+ secinfo = smb_sd_get_secinfo(op->sd);
+ smb_fssd_init(&fs_sd, secinfo, 0);
- status = smb_sd_tofs(op->sd_buf, &fs_sd);
+ status = smb_sd_tofs(op->sd, &fs_sd);
if (status == NT_STATUS_SUCCESS) {
rc = smb_fsop_create_with_sd(sr, cr, dir_snode,
name, attr, ret_snode, ret_attr, &fs_sd);
}
else
rc = EINVAL;
- smb_fsop_sdterm(&fs_sd);
+ smb_fssd_term(&fs_sd);
} else if (sr->tid_tree->t_acltype == ACE_T) {
/*
* No incoming SD and filesystem is ZFS
* Server applies Windows inheritance rules,
* see smb_fsop_sdinherit() comments as to why.
*/
- smb_fsop_sdinit(&fs_sd, SMB_ACL_SECINFO, 0);
+ smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, 0);
rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd);
if (rc == 0) {
rc = smb_fsop_create_with_sd(sr, cr, dir_snode,
name, attr, ret_snode, ret_attr, &fs_sd);
}
- smb_fsop_sdterm(&fs_sd);
+ smb_fssd_term(&fs_sd);
} else {
/*
* No incoming SD and filesystem is not ZFS
@@ -554,36 +559,36 @@ smb_fsop_mkdir(
smb_get_caller_context(sr, &ct);
- if (op->sd_buf) {
+ if (op->sd) {
/*
* SD sent by client in Windows format. Needs to be
* converted to FS format. No inheritance.
*/
- secinfo = smb_sd_get_secinfo((smb_sdbuf_t *)op->sd_buf);
- smb_fsop_sdinit(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR);
+ secinfo = smb_sd_get_secinfo(op->sd);
+ smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR);
- status = smb_sd_tofs(op->sd_buf, &fs_sd);
+ status = smb_sd_tofs(op->sd, &fs_sd);
if (status == NT_STATUS_SUCCESS) {
rc = smb_fsop_create_with_sd(sr, cr, dir_snode,
name, attr, ret_snode, ret_attr, &fs_sd);
}
else
rc = EINVAL;
- smb_fsop_sdterm(&fs_sd);
+ smb_fssd_term(&fs_sd);
} else if (sr->tid_tree->t_acltype == ACE_T) {
/*
* No incoming SD and filesystem is ZFS
* Server applies Windows inheritance rules,
* see smb_fsop_sdinherit() comments as to why.
*/
- smb_fsop_sdinit(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR);
+ smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR);
rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd);
if (rc == 0) {
rc = smb_fsop_create_with_sd(sr, cr, dir_snode,
name, attr, ret_snode, ret_attr, &fs_sd);
}
- smb_fsop_sdterm(&fs_sd);
+ smb_fssd_term(&fs_sd);
} else {
rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, flags, cr,
@@ -1242,6 +1247,7 @@ smb_fsop_setattr(
uint32_t access = 0;
int rc = 0;
int flags = 0;
+ boolean_t no_xvattr = B_FALSE;
ASSERT(cr);
ASSERT(snode);
@@ -1281,8 +1287,12 @@ smb_fsop_setattr(
ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
unnamed_vp = unnamed_node->vp;
}
+ if (sr && sr->tid_tree)
+ if (sr->tid_tree->t_flags & SMB_TREE_FLAG_UFS)
+ no_xvattr = B_TRUE;
- rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr, &ct);
+ rc = smb_vop_setattr(snode->vp, unnamed_vp,
+ set_attr, flags, cr, no_xvattr, &ct);
if ((rc == 0) && ret_attr) {
/*
@@ -1930,34 +1940,6 @@ smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode)
}
/*
- * smb_fsop_sdinit
- *
- * Initializes the given FS SD structure.
- */
-void
-smb_fsop_sdinit(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
-{
- bzero(fs_sd, sizeof (smb_fssd_t));
- fs_sd->sd_secinfo = secinfo;
- fs_sd->sd_flags = flags;
-}
-
-/*
- * smb_fsop_sdterm
- *
- * Frees allocated memory for acl fields.
- */
-void
-smb_fsop_sdterm(smb_fssd_t *fs_sd)
-{
- ASSERT(fs_sd);
-
- smb_fsop_aclfree(fs_sd->sd_zdacl);
- smb_fsop_aclfree(fs_sd->sd_zsacl);
- bzero(fs_sd, sizeof (smb_fssd_t));
-}
-
-/*
* smb_fsop_aclread
*
* Retrieve filesystem ACL. Depends on requested ACLs in
@@ -1969,7 +1951,7 @@ smb_fsop_sdterm(smb_fssd_t *fs_sd)
*
* Returned ACL is always in ACE_T (aka ZFS) format.
* If successful the allocated memory for the ACL should be freed
- * using smb_fsop_aclfree() or smb_fsop_sdterm()
+ * using smb_fsacl_free() or smb_fssd_term()
*/
int
smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
@@ -2022,7 +2004,7 @@ smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
(snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid);
if (error == 0) {
- smb_fsop_aclsplit(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl,
+ smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl,
fs_sd->sd_secinfo);
}
@@ -2097,7 +2079,7 @@ smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
return (EINVAL);
if (dacl && sacl)
- acl = smb_fsop_aclmerge(dacl, sacl);
+ acl = smb_fsacl_merge(dacl, sacl);
else if (dacl)
acl = dacl;
else
@@ -2119,102 +2101,6 @@ smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
return (error);
}
-acl_t *
-smb_fsop_aclalloc(int acenum, int flags)
-{
- acl_t *acl;
-
- acl = acl_alloc(ACE_T);
- acl->acl_cnt = acenum;
- acl->acl_aclp = kmem_zalloc(acl->acl_entry_size * acenum, KM_SLEEP);
- acl->acl_flags = flags;
- return (acl);
-}
-
-void
-smb_fsop_aclfree(acl_t *acl)
-{
- if (acl)
- acl_free(acl);
-}
-
-/*
- * smb_fsop_aclmerge
- *
- * smb_fsop_aclread/write routines which interact with filesystem
- * work with single ACL. This routine merges given DACL and SACL
- * which might have been created during CIFS to FS conversion into
- * one single ACL.
- */
-static acl_t *
-smb_fsop_aclmerge(acl_t *dacl, acl_t *sacl)
-{
- acl_t *acl;
- int dacl_size;
-
- ASSERT(dacl);
- ASSERT(sacl);
-
- acl = smb_fsop_aclalloc(dacl->acl_cnt + sacl->acl_cnt, dacl->acl_flags);
- dacl_size = dacl->acl_cnt * dacl->acl_entry_size;
- bcopy(dacl->acl_aclp, acl->acl_aclp, dacl_size);
- bcopy(sacl->acl_aclp, (char *)acl->acl_aclp + dacl_size,
- sacl->acl_cnt * sacl->acl_entry_size);
-
- return (acl);
-}
-
-/*
- * smb_fsop_aclsplit
- *
- * splits the given ACE_T ACL (zacl) to one or two ACLs (DACL/SACL) based on
- * the 'which_acl' parameter. Note that output dacl/sacl parameters could be
- * NULL even if they're specified in 'which_acl', which means the target
- * doesn't have any access and/or audit ACEs.
- */
-static void
-smb_fsop_aclsplit(acl_t *zacl, acl_t **dacl, acl_t **sacl, int which_acl)
-{
- ace_t *zace;
- ace_t *access_ace;
- ace_t *audit_ace;
- int naccess, naudit;
- int get_dacl, get_sacl;
- int i;
-
- *dacl = *sacl = NULL;
- naccess = naudit = 0;
- get_dacl = (which_acl & SMB_DACL_SECINFO);
- get_sacl = (which_acl & SMB_SACL_SECINFO);
-
- for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
- if (get_dacl && smb_ace_is_access(zace->a_type))
- naccess++;
- else if (get_sacl && smb_ace_is_audit(zace->a_type))
- naudit++;
- }
-
- if (naccess) {
- *dacl = smb_fsop_aclalloc(naccess, zacl->acl_flags);
- access_ace = (*dacl)->acl_aclp;
- }
-
- if (naudit) {
- *sacl = smb_fsop_aclalloc(naudit, zacl->acl_flags);
- audit_ace = (*sacl)->acl_aclp;
- }
-
- for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
- if (get_dacl && smb_ace_is_access(zace->a_type)) {
- *access_ace = *zace;
- access_ace++;
- } else if (get_sacl && smb_ace_is_audit(zace->a_type)) {
- *audit_ace = *zace;
- audit_ace++;
- }
- }
-}
-
acl_type_t
smb_fsop_acltype(smb_node_t *snode)
{
@@ -2328,7 +2214,7 @@ smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd)
/*
* Don't overwrite existing audit entries
*/
- smb_fsop_sdinit(&cur_sd, SMB_SACL_SECINFO,
+ smb_fssd_init(&cur_sd, SMB_SACL_SECINFO,
fs_sd->sd_flags);
error = smb_fsop_sdread(sr, kcred, snode, &cur_sd);
@@ -2343,7 +2229,7 @@ smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd)
/*
* Don't overwrite existing access entries
*/
- smb_fsop_sdinit(&cur_sd, SMB_DACL_SECINFO,
+ smb_fssd_init(&cur_sd, SMB_DACL_SECINFO,
fs_sd->sd_flags);
error = smb_fsop_sdread(sr, kcred, snode, &cur_sd);
@@ -2357,7 +2243,7 @@ smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd)
}
if (error)
- smb_fsop_sdterm(&cur_sd);
+ smb_fssd_term(&cur_sd);
}
return (error);
@@ -2460,15 +2346,6 @@ smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
return (error);
}
-/*ARGSUSED*/
-void
-smb_get_caller_context(smb_request_t *sr, caller_context_t *ct)
-{
- ct->cc_caller_id = smb_caller_id;
- ct->cc_pid = 0; /* TBD */
- ct->cc_sysid = 0; /* TBD */
-}
-
/*
* smb_fsop_sdinherit
*
@@ -2498,8 +2375,8 @@ static int
smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd)
{
int is_dir;
- acl_t *dacl;
- acl_t *sacl;
+ acl_t *dacl = NULL;
+ acl_t *sacl = NULL;
ksid_t *owner_sid;
int error;
@@ -2523,13 +2400,16 @@ smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd)
is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR);
owner_sid = crgetsid(sr->user_cr, KSID_OWNER);
ASSERT(owner_sid);
- dacl = smb_acl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO,
+ dacl = smb_fsacl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO,
owner_sid->ks_id);
- sacl = smb_acl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO,
+ sacl = smb_fsacl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO,
(uid_t)-1);
- smb_fsop_aclfree(fs_sd->sd_zdacl);
- smb_fsop_aclfree(fs_sd->sd_zsacl);
+ if (sacl == NULL)
+ fs_sd->sd_secinfo &= ~SMB_SACL_SECINFO;
+
+ smb_fsacl_free(fs_sd->sd_zdacl);
+ smb_fsacl_free(fs_sd->sd_zsacl);
fs_sd->sd_zdacl = dacl;
fs_sd->sd_zsacl = sacl;
@@ -2593,3 +2473,12 @@ smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
*eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES |
FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD;
}
+
+/*ARGSUSED*/
+void
+smb_get_caller_context(smb_request_t *sr, caller_context_t *ct)
+{
+ ct->cc_caller_id = smb_caller_id;
+ ct->cc_pid = 0; /* TBD */
+ ct->cc_sysid = 0; /* TBD */
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_init.c b/usr/src/uts/common/fs/smbsrv/smb_init.c
index 1d3d8f39cb..897f09bded 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_init.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_init.c
@@ -292,21 +292,29 @@ smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred,
int *retval)
{
int gmtoff;
+ int door_id;
switch (cmd) {
-
case SMB_IOC_GMTOFF:
if (ddi_copyin((int *)argp, &gmtoff, sizeof (int), flag))
return (EFAULT);
(void) smb_set_gmtoff((uint32_t)gmtoff);
break;
- case SMB_IOC_CONFIG_REFRESH:
+ case SMB_IOC_CONFIG:
#if 0
smb_svcstate_event(SMB_SVCEVT_CONFIG, NULL);
#endif
break;
+ case SMB_IOC_WINPIPE:
+ if (ddi_copyin((int *)argp, &door_id, sizeof (int), flag))
+ return (EFAULT);
+
+ if (smb_winpipe_open(door_id) != 0)
+ return (EPIPE);
+ break;
+
default:
break;
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c b/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c
index 53e8d0326e..cb5aa042ee 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c
@@ -88,7 +88,7 @@ smb_com_lock_byte_range(struct smb_request *sr)
* normal lock (write lock).
*/
result = smb_lock_range(sr, sr->fid_ofile,
- (off_t)off, (uint64_t)count, 0, SMB_LOCK_TYPE_READWRITE);
+ (u_offset_t)off, (uint64_t)count, 0, SMB_LOCK_TYPE_READWRITE);
if (result != NT_STATUS_SUCCESS) {
smb_lock_range_raise_error(sr, result);
/* NOT REACHED */
diff --git a/usr/src/uts/common/fs/smbsrv/smb_lock_svc.c b/usr/src/uts/common/fs/smbsrv/smb_lock_svc.c
index e043472af5..7326d5a12c 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_lock_svc.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_lock_svc.c
@@ -571,7 +571,7 @@ smb_lock_create(
* in cv_timedwait.
*/
lock->l_end_time = lbolt + MSEC_TO_TICK(timeout);
- if (timeout == 0xffffffff) {
+ if (timeout == UINT_MAX) {
lock->l_flags |= SMB_LOCK_FLAG_INDEFINITE;
}
mutex_init(&lock->l_mutex, NULL, MUTEX_DEFAULT, NULL);
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 63f1f81440..00d648cc32 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
@@ -35,9 +35,15 @@
* support them at this time.
*/
-#include <smbsrv/smb_incl.h>
+#include <smbsrv/smbvar.h>
+#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_fsops.h>
-#include <smbsrv/smb_vops.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/ntaccess.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/ntifs.h>
+#include <smbsrv/cifs.h>
+#include <smbsrv/doserror.h>
/*
* smb_nt_transact_create
@@ -68,6 +74,7 @@ smb_nt_transact_create(struct smb_request *sr, struct smb_xa *xa)
uint32_t NameLength;
smb_attr_t new_attr;
smb_node_t *node;
+ smb_sd_t sd;
DWORD status;
int rc;
@@ -112,18 +119,15 @@ smb_nt_transact_create(struct smb_request *sr, struct smb_xa *xa)
/* NOTREACHED */
}
- if (sd_len >= sizeof (smb_sdbuf_t)) {
- /* ignore security setting for files on Unix volumes */
- op->sd_buf = kmem_alloc(sd_len, KM_SLEEP);
-
- if ((smb_decode_mbc(&xa->req_data_mb, "#c", sd_len,
- (char *)op->sd_buf)) != 0) {
- kmem_free(op->sd_buf, sd_len);
- smbsr_raise_nt_error(sr, NT_STATUS_BUFFER_TOO_SMALL);
+ if (sd_len) {
+ status = smb_decode_sd(xa, &sd);
+ if (status != NT_STATUS_SUCCESS) {
+ smbsr_raise_nt_error(sr, status);
/* NOTREACHED */
}
+ op->sd = &sd;
} else {
- op->sd_buf = 0;
+ op->sd = NULL;
}
op->fqi.srch_attr = 0;
@@ -168,8 +172,8 @@ smb_nt_transact_create(struct smb_request *sr, struct smb_xa *xa)
}
status = smb_open_subr(sr);
- if (op->sd_buf)
- kmem_free(op->sd_buf, sd_len);
+ if (op->sd)
+ smb_sd_term(op->sd);
if (status != NT_STATUS_SUCCESS) {
if (status == NT_STATUS_SHARING_VIOLATION)
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c
index 70d8437cdf..fec95a2835 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c
@@ -25,14 +25,21 @@
#pragma ident "%Z%%M% %I% %E% SMI"
-#include <smbsrv/smb_secdesc.h>
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smbvar.h>
+#include <smbsrv/smb_kproto.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/doserror.h>
+#include <smbsrv/cifs.h>
-extern uint32_t smb_sd_read(smb_request_t *sr, smb_sdbuf_t **sr_sd,
- uint32_t secinfo, uint32_t *buflen);
-extern uint32_t smb_sd_write(smb_request_t *sr, smb_sdbuf_t *sr_sd,
- uint32_t secinfo);
+static void smb_encode_sd(struct smb_xa *, smb_sd_t *, uint32_t);
+static void smb_encode_sid(struct smb_xa *, nt_sid_t *);
+static void smb_encode_sacl(struct smb_xa *, smb_acl_t *);
+static void smb_encode_dacl(struct smb_xa *, smb_acl_t *);
+
+uint32_t smb_decode_sd(struct smb_xa *, smb_sd_t *);
+static nt_sid_t *smb_decode_sid(struct smb_xa *, uint32_t);
+static smb_acl_t *smb_decode_acl(struct smb_xa *, uint32_t);
/*
* smb_nt_transact_query_security_info
@@ -63,20 +70,15 @@ extern uint32_t smb_sd_write(smb_request_t *sr, smb_sdbuf_t *sr_sd,
int
smb_nt_transact_query_security_info(struct smb_request *sr, struct smb_xa *xa)
{
- smb_sdbuf_t *sr_sd;
- uint32_t secinfo;
- uint32_t sr_sdlen;
- uint32_t status;
+ smb_sd_t sd;
+ uint32_t secinfo;
+ uint32_t sdlen;
+ uint32_t status;
+
if (smb_decode_mbc(&xa->req_param_mb, "w2.l",
&sr->smb_fid, &secinfo) != 0) {
- /*
- * It's not clear why ERRnomem is returned here.
- * This should rarely happen and we're not sure if
- * it's going to break something if we change this
- * error code, so we're going to keep it for now.
- */
- smbsr_raise_error(sr, ERRSRV, ERRnomem);
+ smbsr_raise_nt_error(sr, NT_STATUS_INVALID_PARAMETER);
/* NOTREACHED */
}
@@ -90,7 +92,8 @@ smb_nt_transact_query_security_info(struct smb_request *sr, struct smb_xa *xa)
if ((sr->fid_ofile->f_node == NULL) ||
(sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
- smbsr_raise_nt_error(sr, NT_STATUS_ACCESS_DENIED);
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
/* NOTREACHED */
}
@@ -102,31 +105,36 @@ smb_nt_transact_query_security_info(struct smb_request *sr, struct smb_xa *xa)
secinfo &= ~SMB_SACL_SECINFO;
}
- sr_sdlen = xa->smb_mdrcnt;
- status = smb_sd_read(sr, &sr_sd, secinfo, &sr_sdlen);
-
+ status = smb_sd_read(sr, &sd, secinfo);
if (status != NT_STATUS_SUCCESS) {
- if (status == NT_STATUS_BUFFER_TOO_SMALL) {
- /*
- * The maximum data return count specified by the
- * client is not big enough to hold the security
- * descriptor. We have to return an error but we
- * can provide a buffer size hint for the client.
- */
- (void) smb_encode_mbc(&xa->rep_param_mb, "l", sr_sdlen);
- smbsr_setup_nt_status(sr, ERROR_SEVERITY_ERROR,
- NT_STATUS_BUFFER_TOO_SMALL);
- return (SDRC_NORMAL_REPLY);
- }
-
smbsr_raise_nt_error(sr, status);
/* NOTREACHED */
}
- (void) smb_encode_mbc(&xa->rep_data_mb, "#c", (int)sr_sdlen, sr_sd);
- (void) smb_encode_mbc(&xa->rep_param_mb, "l", sr_sdlen);
+ sdlen = smb_sd_len(&sd, secinfo);
+ if (sdlen == 0) {
+ smb_sd_term(&sd);
+ smbsr_raise_nt_error(sr, NT_STATUS_INVALID_SECURITY_DESCR);
+ /* NOTREACHED */
+ }
+
+ if (sdlen > xa->smb_mdrcnt) {
+ /*
+ * The maximum data return count specified by the
+ * client is not big enough to hold the security
+ * descriptor. We have to return an error but we
+ * should provide a buffer size hint for the client.
+ */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "l", sdlen);
+ smbsr_setup_nt_status(sr, ERROR_SEVERITY_ERROR,
+ NT_STATUS_BUFFER_TOO_SMALL);
+ smb_sd_term(&sd);
+ return (SDRC_NORMAL_REPLY);
+ }
- kmem_free(sr_sd, sr_sdlen);
+ smb_encode_sd(xa, &sd, secinfo);
+ (void) smb_encode_mbc(&xa->rep_param_mb, "l", sdlen);
+ smb_sd_term(&sd);
return (SDRC_NORMAL_REPLY);
}
@@ -152,12 +160,12 @@ smb_nt_transact_query_security_info(struct smb_request *sr, struct smb_xa *xa)
int
smb_nt_transact_set_security_info(struct smb_request *sr, struct smb_xa *xa)
{
- smb_sdbuf_t *sd_buf;
- uint32_t sec_info;
+ smb_sd_t sd;
+ uint32_t secinfo;
uint32_t status;
if (smb_decode_mbc(&xa->req_param_mb, "w2.l",
- &sr->smb_fid, &sec_info) != 0) {
+ &sr->smb_fid, &secinfo) != 0) {
smbsr_raise_nt_error(sr, NT_STATUS_INVALID_PARAMETER);
/* NOTREACHED */
}
@@ -185,25 +193,27 @@ smb_nt_transact_set_security_info(struct smb_request *sr, struct smb_xa *xa)
* If target filesystem doesn't support ACE_T acls then
* don't process SACL
*/
- sec_info &= ~SMB_SACL_SECINFO;
+ secinfo &= ~SMB_SACL_SECINFO;
}
- if ((sec_info & SMB_ALL_SECINFO) == 0) {
+ if ((secinfo & SMB_ALL_SECINFO) == 0) {
return (NT_STATUS_SUCCESS);
}
- sd_buf = kmem_alloc(xa->smb_tdscnt, KM_SLEEP);
-
- if ((smb_decode_mbc(&xa->req_data_mb, "#c",
- xa->smb_tdscnt, (char *)sd_buf)) != 0) {
- kmem_free(sd_buf, xa->smb_tdscnt);
- smbsr_raise_nt_error(sr, NT_STATUS_BUFFER_TOO_SMALL);
+ status = smb_decode_sd(xa, &sd);
+ if (status != NT_STATUS_SUCCESS) {
+ smbsr_raise_nt_error(sr, status);
/* NOTREACHED */
}
- status = smb_sd_write(sr, sd_buf, sec_info);
- kmem_free(sd_buf, xa->smb_tdscnt);
+ if (((secinfo & SMB_OWNER_SECINFO) && (sd.sd_owner == NULL)) ||
+ ((secinfo & SMB_GROUP_SECINFO) && (sd.sd_group == NULL))) {
+ smbsr_raise_nt_error(sr, NT_STATUS_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+ status = smb_sd_write(sr, &sd, secinfo);
+ smb_sd_term(&sd);
if (status != NT_STATUS_SUCCESS) {
smbsr_raise_nt_error(sr, status);
/* NOTREACHED */
@@ -211,3 +221,331 @@ smb_nt_transact_set_security_info(struct smb_request *sr, struct smb_xa *xa)
return (SDRC_NORMAL_REPLY);
}
+
+/*
+ * smb_encode_sd
+ *
+ * Encodes given security descriptor in the reply buffer.
+ */
+static void
+smb_encode_sd(struct smb_xa *xa, smb_sd_t *sd, uint32_t secinfo)
+{
+ uint32_t offset = SMB_SD_HDRSIZE;
+
+ /* encode header */
+ (void) smb_encode_mbc(&xa->rep_data_mb, "b.w",
+ sd->sd_revision, sd->sd_control | SE_SELF_RELATIVE);
+
+ /* owner offset */
+ if (secinfo & SMB_OWNER_SECINFO) {
+ ASSERT(sd->sd_owner);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", offset);
+ offset += nt_sid_length(sd->sd_owner);
+ } else {
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", 0);
+ }
+
+ /* group offset */
+ if (secinfo & SMB_GROUP_SECINFO) {
+ ASSERT(sd->sd_group);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", offset);
+ offset += nt_sid_length(sd->sd_group);
+ } else {
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", 0);
+ }
+
+ /* SACL offset */
+ if ((secinfo & SMB_SACL_SECINFO) && (sd->sd_sacl)) {
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", offset);
+ offset += smb_acl_len(sd->sd_sacl);
+ } else {
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", 0);
+ }
+
+ /* DACL offset */
+ if ((secinfo & SMB_DACL_SECINFO) && (sd->sd_dacl))
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", offset);
+ else
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", 0);
+
+ if (secinfo & SMB_OWNER_SECINFO)
+ smb_encode_sid(xa, sd->sd_owner);
+
+ if (secinfo & SMB_GROUP_SECINFO)
+ smb_encode_sid(xa, sd->sd_group);
+
+ if (secinfo & SMB_SACL_SECINFO)
+ smb_encode_sacl(xa, sd->sd_sacl);
+
+ if (secinfo & SMB_DACL_SECINFO)
+ smb_encode_dacl(xa, sd->sd_dacl);
+}
+
+/*
+ * smb_encode_sid
+ *
+ * Encodes given SID in the reply buffer.
+ */
+static void
+smb_encode_sid(struct smb_xa *xa, nt_sid_t *sid)
+{
+ int i;
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "bb",
+ sid->Revision, sid->SubAuthCount);
+
+ for (i = 0; i < NT_SID_AUTH_MAX; i++) {
+ (void) smb_encode_mbc(&xa->rep_data_mb, "b",
+ sid->Authority[i]);
+ }
+
+ for (i = 0; i < sid->SubAuthCount; i++) {
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l",
+ sid->SubAuthority[i]);
+ }
+}
+
+/*
+ * smb_encode_sacl
+ *
+ * Encodes given SACL in the reply buffer.
+ */
+static void
+smb_encode_sacl(struct smb_xa *xa, smb_acl_t *acl)
+{
+ smb_ace_t *ace;
+ int i;
+
+ if (acl == NULL)
+ return;
+
+ /* encode header */
+ (void) smb_encode_mbc(&xa->rep_data_mb, "b.ww2.", acl->sl_revision,
+ acl->sl_bsize, acl->sl_acecnt);
+
+ for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; i++, ace++) {
+ (void) smb_encode_mbc(&xa->rep_data_mb, "bbwl",
+ ace->se_hdr.se_type, ace->se_hdr.se_flags,
+ ace->se_hdr.se_bsize, ace->se_mask);
+
+ smb_encode_sid(xa, ace->se_sid);
+ }
+}
+
+/*
+ * smb_encode_dacl
+ *
+ * Encodes given DACL in the reply buffer.
+ */
+static void
+smb_encode_dacl(struct smb_xa *xa, smb_acl_t *acl)
+{
+ smb_ace_t *ace;
+
+ if (acl == NULL)
+ return;
+
+ /* encode header */
+ (void) smb_encode_mbc(&xa->rep_data_mb, "b.ww2.", acl->sl_revision,
+ acl->sl_bsize, acl->sl_acecnt);
+
+ ace = list_head(&acl->sl_sorted);
+ while (ace) {
+ (void) smb_encode_mbc(&xa->rep_data_mb, "bbwl",
+ ace->se_hdr.se_type, ace->se_hdr.se_flags,
+ ace->se_hdr.se_bsize, ace->se_mask);
+
+ smb_encode_sid(xa, ace->se_sid);
+ ace = list_next(&acl->sl_sorted, ace);
+ }
+}
+
+/*
+ * smb_decode_sd
+ *
+ * Decodes the security descriptor in the request buffer
+ * and set the fields of 'sd' appropraitely. Upon successful
+ * return, caller must free allocated memories by calling
+ * smb_sd_term().
+ */
+uint32_t
+smb_decode_sd(struct smb_xa *xa, smb_sd_t *sd)
+{
+ struct mbuf_chain sdbuf;
+ uint32_t owner_offs;
+ uint32_t group_offs;
+ uint32_t sacl_offs;
+ uint32_t dacl_offs;
+
+ smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
+
+ (void) MBC_SHADOW_CHAIN(&sdbuf, &xa->req_data_mb,
+ xa->req_data_mb.chain_offset,
+ xa->req_data_mb.max_bytes - xa->req_data_mb.chain_offset);
+
+ if (smb_decode_mbc(&sdbuf, "b.wllll",
+ &sd->sd_revision, &sd->sd_control,
+ &owner_offs, &group_offs, &sacl_offs, &dacl_offs))
+ goto decode_error;
+
+ sd->sd_control &= ~SE_SELF_RELATIVE;
+
+ if (owner_offs != 0) {
+ if (owner_offs < SMB_SD_HDRSIZE)
+ goto decode_error;
+
+ sd->sd_owner = smb_decode_sid(xa, owner_offs);
+ if (sd->sd_owner == NULL)
+ goto decode_error;
+ }
+
+ if (group_offs != 0) {
+ if (group_offs < SMB_SD_HDRSIZE)
+ goto decode_error;
+
+ sd->sd_group = smb_decode_sid(xa, group_offs);
+ if (sd->sd_group == NULL)
+ goto decode_error;
+ }
+
+ if (sacl_offs != 0) {
+ if ((sd->sd_control & SE_SACL_PRESENT) == 0)
+ goto decode_error;
+
+ if (sacl_offs < SMB_SD_HDRSIZE)
+ goto decode_error;
+
+ sd->sd_sacl = smb_decode_acl(xa, sacl_offs);
+ if (sd->sd_sacl == NULL)
+ goto decode_error;
+ }
+
+ if (dacl_offs != 0) {
+ if ((sd->sd_control & SE_DACL_PRESENT) == 0)
+ goto decode_error;
+
+ if (dacl_offs < SMB_SD_HDRSIZE)
+ goto decode_error;
+
+ sd->sd_dacl = smb_decode_acl(xa, dacl_offs);
+ if (sd->sd_dacl == NULL)
+ goto decode_error;
+ }
+
+ return (NT_STATUS_SUCCESS);
+
+decode_error:
+ smb_sd_term(sd);
+ return (NT_STATUS_INVALID_SECURITY_DESCR);
+}
+
+/*
+ * smb_decode_sid
+ *
+ * Allocates memory and decodes the SID in the request buffer
+ * Upon successful return, caller must free the allocated memory
+ * by calling MEM_FREE()
+ */
+static nt_sid_t *
+smb_decode_sid(struct smb_xa *xa, uint32_t offset)
+{
+ uint8_t revision;
+ uint8_t subauth_cnt;
+ struct mbuf_chain sidbuf;
+ nt_sid_t *sid;
+ int sidlen;
+ int bytes_left;
+ int i;
+
+ offset += xa->req_data_mb.chain_offset;
+ bytes_left = xa->req_data_mb.max_bytes - offset;
+ if (bytes_left < sizeof (nt_sid_t))
+ return (NULL);
+
+ (void) MBC_SHADOW_CHAIN(&sidbuf, &xa->req_data_mb, offset, bytes_left);
+
+ if (smb_decode_mbc(&sidbuf, "bb", &revision, &subauth_cnt))
+ return (NULL);
+
+ sidlen = sizeof (nt_sid_t) - sizeof (uint32_t) +
+ (subauth_cnt * sizeof (uint32_t));
+ sid = MEM_MALLOC("smbsrv", sidlen);
+
+ sid->Revision = revision;
+ sid->SubAuthCount = subauth_cnt;
+
+ for (i = 0; i < NT_SID_AUTH_MAX; i++) {
+ if (smb_decode_mbc(&sidbuf, "b", &sid->Authority[i]))
+ goto decode_err;
+ }
+
+ for (i = 0; i < sid->SubAuthCount; i++) {
+ if (smb_decode_mbc(&sidbuf, "l", &sid->SubAuthority[i]))
+ goto decode_err;
+ }
+
+ return (sid);
+
+decode_err:
+ MEM_FREE("smbsrv", sid);
+ return (NULL);
+}
+
+/*
+ * smb_decode_acl
+ *
+ * Allocates memory and decodes the ACL in the request buffer
+ * Upon successful return, caller must free the allocated memory
+ * by calling smb_acl_free().
+ */
+static smb_acl_t *
+smb_decode_acl(struct smb_xa *xa, uint32_t offset)
+{
+ struct mbuf_chain aclbuf;
+ smb_acl_t *acl;
+ smb_ace_t *ace;
+ uint8_t revision;
+ uint16_t size;
+ uint16_t acecnt;
+ int bytes_left;
+ uint32_t sid_offs = offset;
+ int sidlen;
+ int i;
+
+ offset += xa->req_data_mb.chain_offset;
+ bytes_left = xa->req_data_mb.max_bytes - offset;
+ if (bytes_left < SMB_ACL_HDRSIZE)
+ return (NULL);
+
+ (void) MBC_SHADOW_CHAIN(&aclbuf, &xa->req_data_mb, offset, bytes_left);
+
+ if (smb_decode_mbc(&aclbuf, "b.ww2.", &revision, &size, &acecnt))
+ return (NULL);
+
+ if (size == 0)
+ return (NULL);
+
+ acl = smb_acl_alloc(revision, size, acecnt);
+
+ sid_offs += SMB_ACL_HDRSIZE;
+ for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; i++, ace++) {
+ if (smb_decode_mbc(&aclbuf, "bbwl",
+ &ace->se_hdr.se_type, &ace->se_hdr.se_flags,
+ &ace->se_hdr.se_bsize, &ace->se_mask))
+ goto decode_error;
+
+ sid_offs += SMB_ACE_HDRSIZE + sizeof (ace->se_mask);
+ ace->se_sid = smb_decode_sid(xa, sid_offs);
+ if (ace->se_sid == NULL)
+ goto decode_error;
+ sidlen = nt_sid_length(ace->se_sid);
+ aclbuf.chain_offset += sidlen;
+ sid_offs += sidlen;
+ }
+
+ return (acl);
+
+decode_error:
+ smb_acl_free(acl);
+ return (NULL);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_ofile.c b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
index 150262e28b..e8eb106291 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
@@ -498,7 +498,7 @@ smb_ofile_seek(
int32_t off,
uint32_t *retoff)
{
- off_t newoff = 0;
+ u_offset_t newoff = 0;
int rc = 0;
ASSERT(of);
@@ -511,21 +511,22 @@ smb_ofile_seek(
if (off < 0)
newoff = 0;
else
- newoff = (off_t)off;
+ newoff = (u_offset_t)off;
break;
case SMB_SEEK_CUR:
if (off < 0 && (-off) > of->f_seek_pos)
newoff = 0;
else
- newoff = of->f_seek_pos + (off_t)off;
+ newoff = of->f_seek_pos + (u_offset_t)off;
break;
case SMB_SEEK_END:
if (off < 0 && (-off) > of->f_node->attr.sa_vattr.va_size)
newoff = 0;
else
- newoff = of->f_node->attr.sa_vattr.va_size + (off_t)off;
+ newoff = of->f_node->attr.sa_vattr.va_size +
+ (u_offset_t)off;
break;
default:
@@ -533,7 +534,12 @@ smb_ofile_seek(
return (EINVAL);
}
- if (newoff > ULONG_MAX) {
+ /*
+ * See comments at the beginning of smb_seek.c.
+ * If the offset is greater than UINT_MAX, we will return an error.
+ */
+
+ if (newoff > UINT_MAX) {
rc = EOVERFLOW;
} else {
of->f_seek_pos = newoff;
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 aa02274224..b195ed6353 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
@@ -280,7 +280,7 @@ smb_com_open(struct smb_request *sr)
~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY);
}
- if (op->dsize > 0xffffffff)
+ if (op->dsize > UINT_MAX)
smbsr_raise_error(sr, ERRDOS, ERRbadfunc);
file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
@@ -350,7 +350,7 @@ smb_com_open_andx(struct smb_request *sr)
else if (flags & 4)
op->my_flags = MYF_BATCH_OPLOCK;
- if ((CreationTime != 0) && (CreationTime != 0xffffffff))
+ if ((CreationTime != 0) && (CreationTime != UINT_MAX))
op->utime.tv_sec = smb_local_time_to_gmt(CreationTime);
op->utime.tv_nsec = 0;
@@ -385,7 +385,7 @@ smb_com_open_andx(struct smb_request *sr)
/* NOTREACHED */
}
- if (op->dsize > 0xffffffff)
+ if (op->dsize > UINT_MAX)
smbsr_raise_error(sr, ERRDOS, ERRbadfunc);
if (MYF_OPLOCK_TYPE(op->my_flags) != MYF_OPLOCK_NONE) {
diff --git a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
index cacbbb3e9d..cc203a7315 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
@@ -391,19 +391,17 @@ smb_pathname(
rootvp = (vnode_t *)root_node->vp;
/*
- * Instead of passing the FOLLOW flag to lookuppnvp(), process links in
- * this routine. This allows smb_nodes to be created for each component
- * of a link.
- */
- local_flags = flags & FIGNORECASE;
-
- /*
* Path components are processed one at a time so that smb_nodes
* can be created for each component. This allows the dir_snode
* field in the smb_node to be properly populated.
*
- * Mangle checking is also done on each component.
+ * Because of the above, links are also processed in this routine
+ * (i.e., we do not pass the FOLLOW flag to lookuppnvp()). This
+ * will allow smb_nodes to be created for each component of a link.
+ *
+ * Mangle checking is per component.
*/
+
while ((pathleft = pn_pathleft(&upn)) != 0) {
if (fnode) {
smb_node_release(dnode);
@@ -419,10 +417,24 @@ smb_pathname(
component, real_name, MAXNAMELEN, 0, 0,
1)) != 0)
break;
+ /*
+ * Do not pass FIGNORECASE to lookuppnvp().
+ * This is because we would like to do a lookup
+ * on the real name just obtained (which
+ * corresponds to the mangled name).
+ */
namep = real_name;
+ local_flags = 0;
} else {
+ /*
+ * Pass FIGNORECASE to lookuppnvp().
+ * This will cause the file system to
+ * return "first match" in the event of
+ * a case collision.
+ */
namep = component;
+ local_flags = flags & FIGNORECASE;
}
if ((err = pn_set(&pn, namep)) != 0)
diff --git a/usr/src/uts/common/fs/smbsrv/smb_read.c b/usr/src/uts/common/fs/smbsrv/smb_read.c
index 6554c07014..8542a1a1f9 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_read.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_read.c
@@ -145,7 +145,7 @@ smb_com_lock_and_read(struct smb_request *sr)
}
result = smb_lock_range(sr, sr->fid_ofile, param.r_offset,
- (uint64_t)param.r_count, 0xffffffff, SMB_LOCK_TYPE_READWRITE);
+ (uint64_t)param.r_count, UINT_MAX, SMB_LOCK_TYPE_READWRITE);
if (result != NT_STATUS_SUCCESS) {
smb_lock_range_raise_error(sr, result);
}
@@ -370,7 +370,7 @@ smb_common_read(struct smb_request *sr, smb_read_param_t *param)
vdb->uio.uio_iov = &vdb->iovec[0];
vdb->uio.uio_iovcnt = MAX_IOVEC;
vdb->uio.uio_resid = param->r_count;
- vdb->uio.uio_offset = param->r_offset;
+ vdb->uio.uio_loffset = (offset_t)param->r_offset;
vdb->uio.uio_segflg = UIO_SYSSPACE;
switch (sr->tid_tree->t_res_type & STYPE_MASK) {
diff --git a/usr/src/uts/common/fs/smbsrv/smb_rpc.c b/usr/src/uts/common/fs/smbsrv/smb_rpc.c
index 394c5addbe..5059c909b4 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_rpc.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_rpc.c
@@ -171,9 +171,6 @@ smb_rpc_open(struct smb_request *sr)
char *pipe_name;
int status;
- if (smb_winpipe_open() != 0)
- return (NT_STATUS_INTERNAL_ERROR);
-
op = &sr->arg.open;
if ((pipe_name = smb_rpc_lookup(op->fqi.path)) != 0) {
@@ -278,7 +275,7 @@ smb_rpc_transact(struct smb_request *sr, struct uio *uio)
streamin = &pipe_info->input;
streamin->uio.uio_iov = uio->uio_iov;
streamin->uio.uio_iovcnt = uio->uio_iovcnt;
- streamin->uio.uio_offset = 0;
+ streamin->uio.uio_loffset = 0;
streamin->uio.uio_resid = uio->uio_resid;
streamin->uio.uio_segflg = UIO_SYSSPACE;
@@ -446,7 +443,7 @@ smb_rpc_write(struct smb_request *sr, struct uio *uio)
streamin = &pipe_info->input;
streamin->uio.uio_iov = uio->uio_iov;
streamin->uio.uio_iovcnt = uio->uio_iovcnt;
- streamin->uio.uio_offset = 0;
+ streamin->uio.uio_loffset = 0;
streamin->uio.uio_resid = uio->uio_resid;
streamin->uio.uio_segflg = UIO_SYSSPACE;
mdrcnt = (uint32_t)uio->uio_resid;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_sd.c b/usr/src/uts/common/fs/smbsrv/smb_sd.c
index 4afa258b9a..fa2bf223d7 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_sd.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_sd.c
@@ -29,20 +29,21 @@
* This module provides Security Descriptor handling functions.
*/
-#include <smbsrv/smb_incl.h>
+#include <smbsrv/smbvar.h>
+#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_fsops.h>
#include <smbsrv/smb_idmap.h>
+#include <smbsrv/ntstatus.h>
-#define AS_DWORD(X) (*(uint32_t *)&(X))
-#define SELF_REL(P, M, T) (T *)(((char *)(P)) + AS_DWORD((P)->M))
-
-void smb_fmt_sid(char *buf, nt_sid_t *sid);
+static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
+static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
+static uint32_t smb_sd_fromfs(smb_fssd_t *, smb_sd_t *);
void
smb_sd_init(smb_sd_t *sd, uint8_t revision)
{
bzero(sd, sizeof (smb_sd_t));
- sd->sd_hdr.sd_revision = revision;
+ sd->sd_revision = revision;
}
/*
@@ -55,7 +56,7 @@ void
smb_sd_term(smb_sd_t *sd)
{
ASSERT(sd);
- ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
+ ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
if (sd->sd_owner)
MEM_FREE("libnt", sd->sd_owner);
@@ -63,219 +64,28 @@ smb_sd_term(smb_sd_t *sd)
if (sd->sd_group)
MEM_FREE("libnt", sd->sd_group);
- if (sd->sd_dacl)
- kmem_free(sd->sd_dacl, sd->sd_dacl->sl_size);
-
- if (sd->sd_sacl)
- kmem_free(sd->sd_sacl, sd->sd_sacl->sl_size);
+ smb_acl_free(sd->sd_dacl);
+ smb_acl_free(sd->sd_sacl);
bzero(sd, sizeof (smb_sd_t));
}
-/*
- * Hmmm. For all of these smb_sd_set_xxx() functions,
- * what do we do if the affected member is already set?
- * Should we free() it? For now, punt and risk a memory leak.
- */
-
-void
-smb_sd_set_owner(smb_sd_t *sd, nt_sid_t *owner, int defaulted)
-{
- ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
-
- sd->sd_owner = owner;
- if (defaulted)
- sd->sd_hdr.sd_control |= SE_OWNER_DEFAULTED;
- else
- sd->sd_hdr.sd_control &= ~SE_OWNER_DEFAULTED;
-}
-
-void
-smb_sd_set_group(smb_sd_t *sd, nt_sid_t *group, int defaulted)
-{
- ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
-
- sd->sd_group = group;
- if (defaulted)
- sd->sd_hdr.sd_control |= SE_GROUP_DEFAULTED;
- else
- sd->sd_hdr.sd_control &= ~SE_GROUP_DEFAULTED;
-}
-
-void
-smb_sd_set_dacl(smb_sd_t *sd, int present, smb_acl_t *acl, int flags)
-{
- ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
-
- sd->sd_dacl = acl;
-
- if (flags & ACL_DEFAULTED)
- sd->sd_hdr.sd_control |= SE_DACL_DEFAULTED;
- if (flags & ACL_AUTO_INHERIT)
- sd->sd_hdr.sd_control |= SE_DACL_AUTO_INHERITED;
- if (flags & ACL_PROTECTED)
- sd->sd_hdr.sd_control |= SE_DACL_PROTECTED;
-
- if (present)
- sd->sd_hdr.sd_control |= SE_DACL_PRESENT;
-}
-
-void
-smb_sd_set_sacl(smb_sd_t *sd, int present, smb_acl_t *acl, int flags)
-{
- ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
-
- sd->sd_sacl = acl;
-
- if (flags & ACL_DEFAULTED)
- sd->sd_hdr.sd_control |= SE_SACL_DEFAULTED;
- if (flags & ACL_AUTO_INHERIT)
- sd->sd_hdr.sd_control |= SE_SACL_AUTO_INHERITED;
- if (flags & ACL_PROTECTED)
- sd->sd_hdr.sd_control |= SE_SACL_PROTECTED;
-
- if (present)
- sd->sd_hdr.sd_control |= SE_SACL_PRESENT;
-}
-
-nt_sid_t *
-smb_sd_get_owner(void *sd, int *defaulted)
-{
- smb_sdbuf_t *sr_sd;
- smb_sd_hdr_t *sd_hdr;
- nt_sid_t *sid;
-
- sd_hdr = (smb_sd_hdr_t *)sd;
- if (defaulted != NULL)
- *defaulted = (sd_hdr->sd_control & SE_OWNER_DEFAULTED) ? 1 : 0;
-
- if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
- sr_sd = ((smb_sdbuf_t *)sd);
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- sid = SELF_REL(sr_sd, sd_owner_offs, nt_sid_t);
- }
- else
- sid = ((smb_sd_t *)sd)->sd_owner;
-
- return (sid);
-}
-
-nt_sid_t *
-smb_sd_get_group(void *sd, int *defaulted)
-{
- smb_sdbuf_t *sr_sd;
- smb_sd_hdr_t *sd_hdr;
- nt_sid_t *sid;
-
- sd_hdr = (smb_sd_hdr_t *)sd;
- if (defaulted != NULL)
- *defaulted = (sd_hdr->sd_control & SE_GROUP_DEFAULTED) ? 1 : 0;
-
- if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
- sr_sd = ((smb_sdbuf_t *)sd);
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- sid = SELF_REL(sr_sd, sd_group_offs, nt_sid_t);
- }
- else
- sid = ((smb_sd_t *)sd)->sd_group;
-
- return (sid);
-}
-
-smb_acl_t *
-smb_sd_get_dacl(void *sd, int *present, int *defaulted)
-{
- smb_sdbuf_t *sr_sd;
- smb_sd_hdr_t *sd_hdr;
- smb_acl_t *acl = NULL;
-
- sd_hdr = (smb_sd_hdr_t *)sd;
- if (present != NULL)
- *present = (sd_hdr->sd_control & SE_DACL_PRESENT) ? 1 : 0;
-
- if (defaulted != NULL)
- *defaulted = (sd_hdr->sd_control & SE_DACL_DEFAULTED) ? 1 : 0;
-
- if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
- sr_sd = ((smb_sdbuf_t *)sd);
- if (sr_sd->sd_dacl_offs) {
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- acl = SELF_REL(sr_sd, sd_dacl_offs, smb_acl_t);
- }
- }
- else
- acl = ((smb_sd_t *)sd)->sd_dacl;
-
- return (acl);
-}
-
-smb_acl_t *
-smb_sd_get_sacl(void *sd, int *present, int *defaulted)
-{
- smb_sdbuf_t *sr_sd;
- smb_sd_hdr_t *sd_hdr;
- smb_acl_t *acl = NULL;
-
- sd_hdr = (smb_sd_hdr_t *)sd;
- if (present != NULL)
- *present = (sd_hdr->sd_control & SE_SACL_PRESENT) ? 1 : 0;
-
- if (defaulted != NULL)
- *defaulted = (sd_hdr->sd_control & SE_SACL_DEFAULTED) ? 1 : 0;
-
- if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
- sr_sd = ((smb_sdbuf_t *)sd);
- if (sr_sd->sd_sacl_offs) {
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- acl = SELF_REL(sr_sd, sd_sacl_offs, smb_acl_t);
- }
- }
- else
- acl = ((smb_sd_t *)sd)->sd_sacl;
-
- return (acl);
-}
-
uint32_t
-smb_sd_len(void *sd, uint32_t secinfo)
+smb_sd_len(smb_sd_t *sd, uint32_t secinfo)
{
- uint32_t length = 0;
- nt_sid_t *sid;
- smb_acl_t *acl;
- int present;
-
- /* SD Header */
- length += sizeof (smb_sdbuf_t);
+ uint32_t length = SMB_SD_HDRSIZE;
- /* Owner */
- if (secinfo & SMB_OWNER_SECINFO) {
- sid = smb_sd_get_owner(sd, NULL);
- if (sid)
- length += nt_sid_length(sid);
- }
+ if (secinfo & SMB_OWNER_SECINFO)
+ length += nt_sid_length(sd->sd_owner);
+ if (secinfo & SMB_GROUP_SECINFO)
+ length += nt_sid_length(sd->sd_group);
- /* Group */
- if (secinfo & SMB_GROUP_SECINFO) {
- sid = smb_sd_get_group(sd, NULL);
- if (sid)
- length += nt_sid_length(sid);
- }
+ if (secinfo & SMB_DACL_SECINFO)
+ length += smb_acl_len(sd->sd_dacl);
-
- /* DACL */
- if (secinfo & SMB_DACL_SECINFO) {
- acl = smb_sd_get_dacl(sd, &present, NULL);
- if (present && acl)
- length += smb_acl_len(acl);
- }
-
- /* SACL */
- if (secinfo & SMB_SACL_SECINFO) {
- acl = smb_sd_get_sacl(sd, &present, NULL);
- if (present && acl)
- length += smb_acl_len(acl);
- }
+ if (secinfo & SMB_SACL_SECINFO)
+ length += smb_acl_len(sd->sd_sacl);
return (length);
}
@@ -287,273 +97,103 @@ smb_sd_len(void *sd, uint32_t secinfo)
* descriptor.
*/
uint32_t
-smb_sd_get_secinfo(void *sd)
+smb_sd_get_secinfo(smb_sd_t *sd)
{
uint32_t sec_info = 0;
- smb_acl_t *acl;
- int present;
- if (sd == 0)
+ if (sd == NULL)
return (0);
- if (smb_sd_get_owner(sd, NULL) != 0)
+ if (sd->sd_owner)
sec_info |= SMB_OWNER_SECINFO;
- if (smb_sd_get_group(sd, NULL) != 0)
+ if (sd->sd_group)
sec_info |= SMB_GROUP_SECINFO;
- acl = smb_sd_get_dacl(sd, &present, NULL);
- if (acl && present)
+ if (sd->sd_dacl)
sec_info |= SMB_DACL_SECINFO;
- acl = smb_sd_get_sacl(sd, &present, NULL);
- if (acl && present)
+ if (sd->sd_sacl)
sec_info |= SMB_SACL_SECINFO;
return (sec_info);
}
/*
- * smb_sd_abs2selfrel
- *
- * This function takes an absolute SD (sd) and make a self relative
- * SD which will be returned in srel_sd.
- *
- * srel_sdsz contains the size of buffer which srel_sd points to.
+ * smb_sd_read
*
- * Do not add new error codes here without checking the impact on
- * all callers of this function.
+ * Read uid, gid and ACL from filesystem. The returned ACL from read
+ * routine is always in ZFS format. Convert the ZFS acl to a Win acl
+ * and return the Win SD in absolute form.
*
- * Returns NT status codes:
- * NT_STATUS_SUCCESS
- * NT_STATUS_BUFFER_TOO_SMALL
- * NT_STATUS_INVALID_SECURITY_DESCR
+ * NOTE: upon successful return caller MUST free the memory allocated
+ * for the returned SD by calling smb_sd_term().
*/
-static uint32_t
-smb_sd_abs2selfrel(
- smb_sd_t *sd,
- uint32_t secinfo,
- smb_sdbuf_t *srel_sd,
- uint32_t srel_sdsz)
+uint32_t
+smb_sd_read(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
{
- uint32_t avail_len = srel_sdsz;
- uint32_t length = 0;
- unsigned char *scan_beg = (unsigned char *) srel_sd;
- unsigned char *scan = scan_beg;
- unsigned char *scan_end;
- nt_sid_t *sid;
- smb_acl_t *acl;
- int present, defaulted;
-
- length = smb_sd_len(sd, secinfo);
-
- if (length == 0)
- return (NT_STATUS_INVALID_SECURITY_DESCR);
-
- if (avail_len < length)
- return (NT_STATUS_BUFFER_TOO_SMALL);
-
- bzero(srel_sd, length);
- scan_end = scan_beg + length;
-
- /* SD Header */
- length = sizeof (smb_sdbuf_t);
- srel_sd->sd_hdr.sd_revision = sd->sd_hdr.sd_revision;
- srel_sd->sd_hdr.sd_control = SE_SELF_RELATIVE;
- scan += length;
-
- if (secinfo & SMB_OWNER_SECINFO) {
- /* Owner */
- sid = smb_sd_get_owner(sd, &defaulted);
-
- if (defaulted)
- srel_sd->sd_hdr.sd_control |= SE_OWNER_DEFAULTED;
-
- if (sid) {
- /*LINTED E_PTRDIFF_OVERFLOW*/
- length = nt_sid_copy((void*)scan, sid, scan_end - scan);
- if (length == 0)
- goto fail;
- /*LINTED E_PTRDIFF_OVERFLOW*/
- srel_sd->sd_owner_offs = scan - scan_beg;
- scan += length;
- }
- }
-
- if (secinfo & SMB_GROUP_SECINFO) {
- /* Group */
- sid = smb_sd_get_group(sd, &defaulted);
-
- if (defaulted)
- srel_sd->sd_hdr.sd_control |= SE_GROUP_DEFAULTED;
-
- if (sid) {
- /*LINTED E_PTRDIFF_OVERFLOW*/
- length = nt_sid_copy((void*)scan, sid, scan_end - scan);
- if (length == 0)
- goto fail;
- /*LINTED E_PTRDIFF_OVERFLOW*/
- srel_sd->sd_group_offs = scan - scan_beg;
- scan += length;
- }
- }
-
-
- if (secinfo & SMB_DACL_SECINFO) {
- /* Dacl */
- acl = smb_sd_get_dacl(sd, &present, &defaulted);
-
- srel_sd->sd_hdr.sd_control |=
- (sd->sd_hdr.sd_control & SE_DACL_INHERITANCE_MASK);
-
- if (defaulted)
- srel_sd->sd_hdr.sd_control |= SE_DACL_DEFAULTED;
+ smb_fssd_t fs_sd;
+ smb_error_t smb_err;
+ smb_node_t *node;
+ uint32_t status = NT_STATUS_SUCCESS;
+ uint32_t sd_flags;
+ int error;
- if (present)
- srel_sd->sd_hdr.sd_control |= SE_DACL_PRESENT;
+ node = sr->fid_ofile->f_node;
+ sd_flags = (node->vp->v_type == VDIR) ? SMB_FSSD_FLAGS_DIR : 0;
+ smb_fssd_init(&fs_sd, secinfo, sd_flags);
- if (present && acl) {
- /*LINTED E_PTRDIFF_OVERFLOW*/
- length = smb_acl_copy(scan_end - scan,
- (void*) scan, acl);
- if (length == 0)
- goto fail;
- /*LINTED E_PTRDIFF_OVERFLOW*/
- srel_sd->sd_dacl_offs = scan - scan_beg;
- /*LINTED E_PTRDIFF_OVERFLOW*/
- acl = (smb_acl_t *)scan;
- acl->sl_size = (WORD)length; /* set the size */
- scan += length;
- }
+ error = smb_fsop_sdread(sr, sr->user_cr, node, &fs_sd);
+ if (error) {
+ smb_errmap_unix2smb(error, &smb_err);
+ return (smb_err.status);
}
- if (secinfo & SMB_SACL_SECINFO) {
- /* Sacl */
- acl = smb_sd_get_sacl(sd, &present, &defaulted);
-
- srel_sd->sd_hdr.sd_control |=
- (sd->sd_hdr.sd_control & SE_SACL_INHERITANCE_MASK);
-
- if (defaulted)
- srel_sd->sd_hdr.sd_control |= SE_SACL_DEFAULTED;
-
- if (present)
- srel_sd->sd_hdr.sd_control |= SE_SACL_PRESENT;
-
- if (present && acl) {
- /*LINTED E_PTRDIFF_OVERFLOW*/
- length = smb_acl_copy(scan_end - scan,
- (void*) scan, acl);
- if (length == 0)
- goto fail;
- /*LINTED E_PTRDIFF_OVERFLOW*/
- srel_sd->sd_sacl_offs = scan - scan_beg;
- /*LINTED E_PTRDIFF_OVERFLOW*/
- acl = (smb_acl_t *)scan;
- acl->sl_size = (WORD)length; /* set the size */
- scan += length;
- }
- }
+ status = smb_sd_fromfs(&fs_sd, sd);
+ smb_fssd_term(&fs_sd);
- return (NT_STATUS_SUCCESS);
-
-fail:
- return (NT_STATUS_INVALID_SECURITY_DESCR);
+ return (status);
}
/*
- * smb_sd_fromfs
- *
- * Makes an Windows style security descriptor in absolute form
- * based on the given filesystem security information.
+ * smb_sd_write
*
- * Should call smb_sd_term() for the returned sd to free allocated
- * members.
+ * Takes a Win SD in absolute form, converts it to
+ * ZFS format and write it to filesystem. The write routine
+ * converts ZFS acl to Posix acl if required.
*/
-static uint32_t
-smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
+uint32_t
+smb_sd_write(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
{
- uint32_t status = NT_STATUS_SUCCESS;
- smb_acl_t *acl = NULL;
- smb_acl_t *sorted_acl;
- nt_sid_t *sid;
- idmap_stat idm_stat;
-
- ASSERT(fs_sd);
- ASSERT(sd);
-
- smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
-
- /* Owner */
- if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
- idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
- SMB_IDMAP_USER, &sid);
-
- if (idm_stat != IDMAP_SUCCESS) {
- return (NT_STATUS_NONE_MAPPED);
- }
-
- smb_sd_set_owner(sd, sid, 0);
- }
-
- /* Group */
- if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
- idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
- SMB_IDMAP_GROUP, &sid);
-
- if (idm_stat != IDMAP_SUCCESS) {
- smb_sd_term(sd);
- return (NT_STATUS_NONE_MAPPED);
- }
-
- smb_sd_set_group(sd, sid, 0);
- }
+ smb_node_t *node;
+ smb_fssd_t fs_sd;
+ smb_error_t smb_err;
+ uint32_t status;
+ uint32_t sd_flags;
+ int error;
- /* DACL */
- if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
- if (fs_sd->sd_zdacl != NULL) {
- acl = smb_acl_from_zfs(fs_sd->sd_zdacl, fs_sd->sd_uid,
- fs_sd->sd_gid);
- if (acl == NULL) {
- smb_sd_term(sd);
- return (NT_STATUS_INTERNAL_ERROR);
- }
+ node = sr->fid_ofile->f_node;
+ sd_flags = (node->vp->v_type == VDIR) ? SMB_FSSD_FLAGS_DIR : 0;
+ smb_fssd_init(&fs_sd, secinfo, sd_flags);
- /*
- * Need to sort the ACL before send it to Windows
- * clients. Winodws GUI is sensitive about the order
- * of ACEs.
- */
- sorted_acl = smb_acl_sort(acl);
- if (sorted_acl && (sorted_acl != acl)) {
- kmem_free(acl, acl->sl_size);
- acl = sorted_acl;
- }
- smb_sd_set_dacl(sd, 1, acl, fs_sd->sd_zdacl->acl_flags);
- } else {
- smb_sd_set_dacl(sd, 0, NULL, 0);
- }
+ status = smb_sd_tofs(sd, &fs_sd);
+ if (status != NT_STATUS_SUCCESS) {
+ smb_fssd_term(&fs_sd);
+ return (status);
}
- /* SACL */
- if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
- if (fs_sd->sd_zsacl != NULL) {
- acl = smb_acl_from_zfs(fs_sd->sd_zsacl, fs_sd->sd_uid,
- fs_sd->sd_gid);
- if (acl == NULL) {
- smb_sd_term(sd);
- return (NT_STATUS_INTERNAL_ERROR);
- }
+ error = smb_fsop_sdwrite(sr, sr->user_cr, node, &fs_sd, 0);
+ smb_fssd_term(&fs_sd);
- smb_sd_set_sacl(sd, 1, acl, fs_sd->sd_zsacl->acl_flags);
- } else {
- smb_sd_set_sacl(sd, 0, NULL, 0);
- }
+ if (error) {
+ smb_errmap_unix2smb(error, &smb_err);
+ return (smb_err.status);
}
- return (status);
+ return (NT_STATUS_SUCCESS);
}
+
/*
* smb_sd_tofs
*
@@ -561,18 +201,16 @@ smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
* Windows security descriptor.
*/
uint32_t
-smb_sd_tofs(smb_sdbuf_t *sr_sd, smb_fssd_t *fs_sd)
+smb_sd_tofs(smb_sd_t *sd, smb_fssd_t *fs_sd)
{
nt_sid_t *sid;
- smb_acl_t *acl;
uint32_t status = NT_STATUS_SUCCESS;
uint16_t sd_control;
idmap_stat idm_stat;
- int present;
int idtype;
int flags = 0;
- sd_control = sr_sd->sd_hdr.sd_control;
+ sd_control = sd->sd_control;
/*
* ZFS only has one set of flags so for now only
@@ -590,7 +228,7 @@ smb_sd_tofs(smb_sdbuf_t *sr_sd, smb_fssd_t *fs_sd)
/* Owner */
if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
- sid = smb_sd_get_owner(sr_sd, NULL);
+ sid = sd->sd_owner;
if (nt_sid_is_valid(sid) == 0) {
return (NT_STATUS_INVALID_SID);
}
@@ -604,7 +242,7 @@ smb_sd_tofs(smb_sdbuf_t *sr_sd, smb_fssd_t *fs_sd)
/* Group */
if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
- sid = smb_sd_get_group(sr_sd, NULL);
+ sid = sd->sd_group;
if (nt_sid_is_valid(sid) == 0) {
return (NT_STATUS_INVALID_SID);
}
@@ -618,9 +256,8 @@ smb_sd_tofs(smb_sdbuf_t *sr_sd, smb_fssd_t *fs_sd)
/* DACL */
if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
- acl = smb_sd_get_dacl(sr_sd, &present, NULL);
- if (present) {
- status = smb_acl_to_zfs(acl, flags,
+ if (sd->sd_control & SE_DACL_PRESENT) {
+ status = smb_acl_to_zfs(sd->sd_dacl, flags,
SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
if (status != NT_STATUS_SUCCESS)
return (status);
@@ -631,9 +268,8 @@ smb_sd_tofs(smb_sdbuf_t *sr_sd, smb_fssd_t *fs_sd)
/* SACL */
if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
- acl = smb_sd_get_sacl(sr_sd, &present, NULL);
- if (present) {
- status = smb_acl_to_zfs(acl, flags,
+ if (sd->sd_control & SE_SACL_PRESENT) {
+ status = smb_acl_to_zfs(sd->sd_sacl, flags,
SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
if (status != NT_STATUS_SUCCESS) {
return (status);
@@ -647,216 +283,156 @@ smb_sd_tofs(smb_sdbuf_t *sr_sd, smb_fssd_t *fs_sd)
}
/*
- * smb_sd_read
+ * smb_sd_fromfs
*
- * Read uid, gid and ACL from filesystem. The returned ACL from read
- * routine is always in ZFS format. Convert the ZFS acl to a Win acl
- * and return the Win SD in relative form.
+ * Makes an Windows style security descriptor in absolute form
+ * based on the given filesystem security information.
*
- * NOTE: upon successful return caller MUST free the memory allocated
- * for the returned SD by calling kmem_free(). The length of the allocated
- * buffer is returned in 'buflen'.
+ * Should call smb_sd_term() for the returned sd to free allocated
+ * members.
*/
-uint32_t
-smb_sd_read(smb_request_t *sr, smb_sdbuf_t **sr_sd,
- uint32_t secinfo, uint32_t *buflen)
+static uint32_t
+smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
{
- smb_sd_t sd;
- smb_fssd_t fs_sd;
- smb_error_t smb_err;
- smb_sdbuf_t *sdbuf;
- smb_node_t *node;
- uint32_t sdlen;
uint32_t status = NT_STATUS_SUCCESS;
- uint32_t sd_flags;
- int error;
+ smb_acl_t *acl = NULL;
+ nt_sid_t *sid;
+ idmap_stat idm_stat;
- *sr_sd = NULL;
+ ASSERT(fs_sd);
+ ASSERT(sd);
- node = sr->fid_ofile->f_node;
- sd_flags = (node->vp->v_type == VDIR) ? SMB_FSSD_FLAGS_DIR : 0;
- smb_fsop_sdinit(&fs_sd, secinfo, sd_flags);
+ smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
- error = smb_fsop_sdread(sr, sr->user_cr, node, &fs_sd);
- if (error) {
- smb_errmap_unix2smb(error, &smb_err);
- return (smb_err.status);
+ /* Owner */
+ if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
+ idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
+ SMB_IDMAP_USER, &sid);
+
+ if (idm_stat != IDMAP_SUCCESS) {
+ smb_sd_term(sd);
+ return (NT_STATUS_NONE_MAPPED);
+ }
+
+ sd->sd_owner = sid;
}
- status = smb_sd_fromfs(&fs_sd, &sd);
- smb_fsop_sdterm(&fs_sd);
+ /* Group */
+ if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
+ idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
+ SMB_IDMAP_GROUP, &sid);
- if (status != NT_STATUS_SUCCESS)
- return (status);
+ if (idm_stat != IDMAP_SUCCESS) {
+ smb_sd_term(sd);
+ return (NT_STATUS_NONE_MAPPED);
+ }
- sdlen = smb_sd_len(&sd, secinfo);
+ sd->sd_group = sid;
+ }
- if (*buflen < sdlen) {
- /* return the required size */
- *buflen = sdlen;
- smb_sd_term(&sd);
- return (NT_STATUS_BUFFER_TOO_SMALL);
+ /* DACL */
+ if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
+ if (fs_sd->sd_zdacl != NULL) {
+ acl = smb_acl_from_zfs(fs_sd->sd_zdacl, fs_sd->sd_uid,
+ fs_sd->sd_gid);
+ if (acl == NULL) {
+ smb_sd_term(sd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ /*
+ * Need to sort the ACL before send it to Windows
+ * clients. Winodws GUI is sensitive about the order
+ * of ACEs.
+ */
+ smb_acl_sort(acl);
+ smb_sd_set_dacl(sd, acl, B_TRUE,
+ fs_sd->sd_zdacl->acl_flags);
+ } else {
+ smb_sd_set_dacl(sd, NULL, B_FALSE, 0);
+ }
}
- sdbuf = kmem_alloc(sdlen, KM_SLEEP);
- status = smb_sd_abs2selfrel(&sd, secinfo, sdbuf, sdlen);
- smb_sd_term(&sd);
+ /* SACL */
+ if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
+ if (fs_sd->sd_zsacl != NULL) {
+ acl = smb_acl_from_zfs(fs_sd->sd_zsacl, fs_sd->sd_uid,
+ fs_sd->sd_gid);
+ if (acl == NULL) {
+ smb_sd_term(sd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
- if (status == NT_STATUS_SUCCESS) {
- *sr_sd = sdbuf;
- *buflen = sdlen;
+ smb_sd_set_sacl(sd, acl, B_TRUE,
+ fs_sd->sd_zsacl->acl_flags);
+ } else {
+ smb_sd_set_sacl(sd, NULL, B_FALSE, 0);
+ }
}
- else
- kmem_free(sdbuf, sdlen);
return (status);
}
-/*
- * smb_sd_write
- *
- * Takes a Win SD in self-relative form, convert it to
- * ZFS format and write it to filesystem. The write routine
- * converts ZFS acl to Posix acl if required.
- */
-uint32_t
-smb_sd_write(smb_request_t *sr, smb_sdbuf_t *sr_sd, uint32_t secinfo)
+static void
+smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
{
- smb_node_t *node;
- smb_fssd_t fs_sd;
- smb_error_t smb_err;
- uint32_t status;
- uint32_t sd_flags;
- int error;
+ ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
- node = sr->fid_ofile->f_node;
- sd_flags = (node->vp->v_type == VDIR) ? SMB_FSSD_FLAGS_DIR : 0;
- smb_fsop_sdinit(&fs_sd, secinfo, sd_flags);
+ sd->sd_dacl = acl;
- status = smb_sd_tofs(sr_sd, &fs_sd);
- if (status != NT_STATUS_SUCCESS) {
- smb_fsop_sdterm(&fs_sd);
- return (status);
- }
+ if (flags & ACL_DEFAULTED)
+ sd->sd_control |= SE_DACL_DEFAULTED;
+ if (flags & ACL_AUTO_INHERIT)
+ sd->sd_control |= SE_DACL_AUTO_INHERITED;
+ if (flags & ACL_PROTECTED)
+ sd->sd_control |= SE_DACL_PROTECTED;
- error = smb_fsop_sdwrite(sr, sr->user_cr, node, &fs_sd, 0);
- smb_fsop_sdterm(&fs_sd);
+ if (present)
+ sd->sd_control |= SE_DACL_PRESENT;
+}
- if (error) {
- smb_errmap_unix2smb(error, &smb_err);
- return (smb_err.status);
- }
+static void
+smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
+{
+ ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
- return (NT_STATUS_SUCCESS);
+ sd->sd_sacl = acl;
+
+ if (flags & ACL_DEFAULTED)
+ sd->sd_control |= SE_SACL_DEFAULTED;
+ if (flags & ACL_AUTO_INHERIT)
+ sd->sd_control |= SE_SACL_AUTO_INHERITED;
+ if (flags & ACL_PROTECTED)
+ sd->sd_control |= SE_SACL_PROTECTED;
+
+ if (present)
+ sd->sd_control |= SE_SACL_PRESENT;
}
/*
- * smb_fmt_sid
+ * smb_fssd_init
*
- * Make an string SID and copy the result into the specified buffer.
+ * Initializes the given FS SD structure.
*/
void
-smb_fmt_sid(char *buf, nt_sid_t *sid)
+smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
{
- char *sid_str;
-
- sid_str = nt_sid_format(sid);
- if (sid_str) {
- (void) strcpy(buf, sid_str);
- MEM_FREE("smb", sid_str);
- } else {
- (void) strcpy(buf, "<invalid SID>");
- }
+ bzero(fs_sd, sizeof (smb_fssd_t));
+ fs_sd->sd_secinfo = secinfo;
+ fs_sd->sd_flags = flags;
}
/*
- * smb_sd_log
+ * smb_fssd_term
*
- * log the given Windows style security descriptor information
- * in system log. This is for debugging purposes.
+ * Frees allocated memory for acl fields.
*/
void
-smb_sd_log(void *sd)
+smb_fssd_term(smb_fssd_t *fs_sd)
{
- smb_acl_t *acl;
- smb_ace_t *ace;
- nt_sid_t *sid;
- int present, defaulted;
- char entry[128];
- char *inherit;
- char *type;
- int ix_dacl;
-
- sid = smb_sd_get_owner(sd, &defaulted);
- if (sid)
- smb_fmt_sid(entry, sid);
- else
- (void) strcpy(entry, "NULL");
-
- cmn_err(CE_NOTE, " Owner: %s", entry);
-
- sid = smb_sd_get_group(sd, &defaulted);
- if (sid)
- smb_fmt_sid(entry, sid);
- else
- (void) strcpy(entry, "NULL");
-
- cmn_err(CE_NOTE, " Primary Group: %s", entry);
-
- acl = smb_sd_get_dacl(sd, &present, &defaulted);
-
- if (!present || !acl) {
- cmn_err(CE_NOTE, " No DACL");
- return;
- }
-
- for (ix_dacl = 0;
- ace = smb_ace_get(acl, ix_dacl);
- ix_dacl++) {
- /*
- * Make sure the ACE type is something we grok.
- * All ACE, now and in the future, have a valid
- * header. Can't access fields passed the Header
- * until we're sure it's right.
- */
- switch (ace->se_header.se_type) {
- case ACCESS_ALLOWED_ACE_TYPE:
- type = "(Allow)";
- break;
- case ACCESS_DENIED_ACE_TYPE:
- type = "(Deny)";
- break;
-
- case SYSTEM_AUDIT_ACE_TYPE:
- default:
- /* Ignore unrecognized/misplaced ACE */
- continue;
- }
-
- smb_fmt_sid(entry, &ace->se_sid);
-
- switch (ace->se_header.se_flags & INHERIT_MASK_ACE) {
- case OBJECT_INHERIT_ACE:
- inherit = "(OI)";
- break;
- case CONTAINER_INHERIT_ACE:
- inherit = "(CI)";
- break;
- case INHERIT_ONLY_ACE:
- inherit = "(IO)";
- break;
- case NO_PROPOGATE_INHERIT_ACE:
- inherit = "(NP)";
- break;
- default:
- inherit = "";
- }
-
- (void) snprintf(entry + strlen(entry), sizeof (entry),
- ":%s 0x%X %s", inherit, ace->se_mask, type);
-
- cmn_err(CE_NOTE, " %s", entry);
- }
+ ASSERT(fs_sd);
- cmn_err(CE_NOTE, " %d ACE(s)", ix_dacl);
+ smb_fsacl_free(fs_sd->sd_zdacl);
+ smb_fsacl_free(fs_sd->sd_zsacl);
+ bzero(fs_sd, sizeof (smb_fssd_t));
}
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 3ab7076102..c92a248a93 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
@@ -637,7 +637,7 @@ int smb_trans2_find_get_dents(
ihdr->uio.uio_iovcnt = maxcount;
ihdr->uio.uio_resid = dent_buf_size;
ihdr->uio.uio_iov = ihdr->iov;
- ihdr->uio.uio_offset = 0;
+ ihdr->uio.uio_loffset = 0;
rc = smb_get_dents(sr, cookie, dir_snode, wildcards, ihdr, more);
if (rc != 0) {
@@ -839,9 +839,9 @@ smb_gather_dents_info(
* Each entry needs to be properly aligned or we may get an alignment
* fault on sparc.
*/
- ihdr->uio.uio_offset = (off_t)PTRALIGN(ihdr->uio.uio_offset);
+ ihdr->uio.uio_loffset = (offset_t)PTRALIGN(ihdr->uio.uio_loffset);
/*LINTED E_BAD_PTR_CAST_ALIGN*/
- ient = (smb_dent_info_t *)&ihdr->iov->iov_base[ihdr->uio.uio_offset];
+ ient = (smb_dent_info_t *)&ihdr->iov->iov_base[ihdr->uio.uio_loffset];
ient->cookie = cookie;
ient->attr = *attr;
@@ -856,7 +856,7 @@ smb_gather_dents_info(
ihdr->uio.uio_iov++;
ihdr->uio.uio_iovcnt--;
ihdr->uio.uio_resid -= reclen;
- ihdr->uio.uio_offset += reclen;
+ ihdr->uio.uio_loffset += reclen;
kmem_free(v5_name, MAXNAMELEN-1);
return (0);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
index 2d488b7f2c..e6d4dbeccf 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
@@ -78,7 +78,7 @@ smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
{
static smb_attr_t pipe_attr;
unsigned short infolev, dattr = 0;
- off_t dsize = 0, dused = 0;
+ u_offset_t dsize = 0, dused = 0;
smb_attr_t *ap = NULL;
char *namep = NULL;
char *filename = NULL, *alt_nm_ptr = NULL;
@@ -194,10 +194,10 @@ smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
break;
case SMB_INFO_STANDARD:
- if (dsize > 0xffffffff)
- dsize = 0xffffffff;
- if (dused > 0xffffffff)
- dused = 0xffffffff;
+ if (dsize > UINT_MAX)
+ dsize = UINT_MAX;
+ if (dused > UINT_MAX)
+ dused = UINT_MAX;
(void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
(void) smb_encode_mbc(&xa->rep_data_mb,
@@ -212,10 +212,10 @@ smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
break;
case SMB_INFO_QUERY_EA_SIZE:
- if (dsize > 0xffffffff)
- dsize = 0xffffffff;
- if (dused > 0xffffffff)
- dused = 0xffffffff;
+ if (dsize > UINT_MAX)
+ dsize = UINT_MAX;
+ if (dused > UINT_MAX)
+ dused = UINT_MAX;
(void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
(void) smb_encode_mbc(&xa->rep_data_mb,
@@ -449,7 +449,7 @@ smb_encode_stream_info(
uint32_t next_offset;
uint32_t stream_nlen;
uint32_t pad;
- off_t dsize;
+ u_offset_t dsize;
int is_dir;
uint32_t cookie = 0;
struct fs_stream_info *stream_info;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_fs_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_fs_information.c
index aa7cc15343..509c4094f0 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_fs_information.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_fs_information.c
@@ -294,7 +294,7 @@ smb_com_trans2_query_fs_information(struct smb_request *sr, struct smb_xa *xa)
/* NOTREACHED */
}
- max_int = 0xffffffffLL;
+ max_int = (uint64_t)UINT_MAX;
if (df.f_blocks > max_int)
df.f_blocks = max_int;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
index 1a80d6a2c4..374a6de2bd 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
@@ -329,7 +329,7 @@ smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa)
{
char *path, *alt_nm_ptr;
int rc;
- off_t dsize, dused;
+ u_offset_t dsize, dused;
unsigned short infolev, dattr;
smb_attr_t *ap, ret_attr;
struct smb_node *dir_node;
@@ -415,10 +415,10 @@ smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa)
switch (infolev) {
case SMB_INFO_STANDARD:
- if (dsize > 0xffffffff)
- dsize = 0xffffffff;
- if (dused > 0xffffffff)
- dused = 0xffffffff;
+ if (dsize > UINT_MAX)
+ dsize = UINT_MAX;
+ if (dused > UINT_MAX)
+ dused = UINT_MAX;
(void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
(void) smb_encode_mbc(&xa->rep_data_mb,
@@ -433,10 +433,10 @@ smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa)
break;
case SMB_INFO_QUERY_EA_SIZE:
- if (dsize > 0xffffffff)
- dsize = 0xffffffff;
- if (dused > 0xffffffff)
- dused = 0xffffffff;
+ if (dsize > UINT_MAX)
+ dsize = UINT_MAX;
+ if (dused > UINT_MAX)
+ dused = UINT_MAX;
(void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
(void) smb_encode_mbc(&xa->rep_data_mb,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c
index b41e1c426d..8c4368f93f 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c
@@ -197,7 +197,7 @@ smb_set_standard_info(
if (DataSize != 0) {
node->flags |= NODE_FLAGS_SET_SIZE;
- node->n_size = DataSize;
+ node->n_size = (u_offset_t)DataSize;
}
/*
@@ -331,7 +331,7 @@ smb_set_alloc_info(
if (node->attr.sa_vattr.va_size != DataSize) {
node->flags |= NODE_FLAGS_SET_SIZE;
- node->n_size = (off_t)DataSize;
+ node->n_size = (u_offset_t)DataSize;
/*
* Ensure that the FS is consistent with the node cache
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree.c b/usr/src/uts/common/fs/smbsrv/smb_tree.c
index 85d663c88c..d17c7dfade 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c
@@ -164,6 +164,7 @@
* being queued in that list is NOT registered by incrementing the
* reference count.
*/
+#include <sys/fsid.h>
#include <smbsrv/smb_incl.h>
#include <smbsrv/smb_fsops.h>
@@ -243,17 +244,21 @@ smb_tree_connect(
tree->t_acltype = smb_fsop_acltype(snode);
- if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_ACLONCREATE)) {
+ if (strncasecmp(tree->t_typename, NFS, sizeof (NFS)) == 0)
+ tree->t_flags |= SMB_TREE_FLAG_NFS_MOUNTED;
+
+ if (strncasecmp(tree->t_typename, "UFS", sizeof ("UFS")) == 0)
+ tree->t_flags |= SMB_TREE_FLAG_UFS;
+
+ if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_ACLONCREATE))
tree->t_flags |= SMB_TREE_FLAG_ACLONCREATE;
- }
- if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_ACEMASKONACCESS)) {
+ if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_ACEMASKONACCESS))
tree->t_flags |= SMB_TREE_FLAG_ACEMASKONACCESS;
- }
- if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_CASEINSENSITIVE)) {
+ if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_CASEINSENSITIVE))
tree->t_flags |= SMB_TREE_FLAG_IGNORE_CASE;
- }
+
break;
case STYPE_IPC:
diff --git a/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c b/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c
index 420c26a250..fef432d9fc 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c
@@ -75,7 +75,7 @@ smb_com_unlock_byte_range(struct smb_request *sr)
}
result = smb_unlock_range(sr, sr->fid_ofile->f_node,
- (off_t)Offset, (uint64_t)Length);
+ (u_offset_t)Offset, (uint64_t)Length);
if (result != NT_STATUS_SUCCESS) {
smb_unlock_range_raise_error(sr, result);
/* NOT REACHED */
diff --git a/usr/src/uts/common/fs/smbsrv/smb_vops.c b/usr/src/uts/common/fs/smbsrv/smb_vops.c
index b71174e9d5..538c9cfc91 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_vops.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_vops.c
@@ -34,13 +34,15 @@
#include <sys/pathname.h>
#include <sys/cred.h>
#include <sys/extdirent.h>
-#include <acl/acl_common.h>
+
#include <smbsrv/smb_vops.h>
#include <smbsrv/string.h>
-#include <smbsrv/lmshare.h>
+
#include <smbsrv/smbtrans.h>
-#include <smbsrv/smb_incl.h>
#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_kproto.h>
+#include <smbsrv/smb_incl.h>
+
static int
smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count,
@@ -324,7 +326,7 @@ smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr,
int
smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr,
- int flags, cred_t *cr, caller_context_t *ct)
+ int flags, cred_t *cr, boolean_t no_xvattr, caller_context_t *ct)
{
int error = 0;
int at_size = 0;
@@ -350,7 +352,8 @@ smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr,
set_attr->sa_vattr.va_mask = 0;
- if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
+ if ((no_xvattr == B_FALSE) &&
+ vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
/*
* Initialize xvattr, including bzero
*/
@@ -361,8 +364,8 @@ smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr,
/*
* Copy caller-specified classic attributes to tmp_xvattr.
- * First save tmp_xvattr's mask (set in xva_init()).
- * This is |'d in later.
+ * First save tmp_xvattr's mask (set in xva_init()), which
+ * contains AT_XVATTR. This is |'d in later if needed.
*/
xva_mask = tmp_xvattr.xva_vattr.va_mask;
@@ -372,12 +375,20 @@ smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr,
&tmp_xvattr.xva_vattr.va_mask);
/*
- * "|" in the original xva_mask.
+ * Do not set ctime (only the file system can do it)
*/
- tmp_xvattr.xva_vattr.va_mask |= xva_mask;
+ tmp_xvattr.xva_vattr.va_mask &= ~AT_CTIME;
if (set_attr->sa_mask & SMB_AT_DOSATTR) {
+
+ /*
+ * "|" in the original xva_mask, which contains
+ * AT_XVATTR
+ */
+
+ tmp_xvattr.xva_vattr.va_mask |= xva_mask;
+
XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE);
XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM);
XVA_SET_REQ(&tmp_xvattr, XAT_READONLY);
@@ -404,6 +415,12 @@ smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr,
}
if (set_attr->sa_mask & SMB_AT_CRTIME) {
+ /*
+ * "|" in the original xva_mask, which contains
+ * AT_XVATTR
+ */
+
+ tmp_xvattr.xva_vattr.va_mask |= xva_mask;
XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME);
xoap->xoa_createtime = set_attr->sa_crtime;
}
@@ -431,16 +448,12 @@ smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr,
error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags,
cr, ct);
}
-
return (error);
}
-
/*
- * Support for file systems without VFSFT_XVATTR
+ * Support for file systems without VFSFT_XVATTR or no_xvattr == B_TRUE
*/
-
smb_sa_to_va_mask(set_attr->sa_mask, &set_attr->sa_vattr.va_mask);
-
/*
* set_attr->sa_vattr already contains new values
* as set by the caller
@@ -463,7 +476,6 @@ smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr,
set_attr->sa_vattr.va_mask = AT_SIZE;
error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr, ct);
}
-
return (error);
}
@@ -1538,181 +1550,6 @@ smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr)
}
/*
- * smb_vop_acl_from_vsa
- *
- * Converts given vsecattr_t structure to a acl_t structure.
- *
- * The allocated memory for retuned acl_t should be freed by
- * calling acl_free().
- */
-static acl_t *
-smb_vop_acl_from_vsa(vsecattr_t *vsecattr, acl_type_t acl_type)
-{
- int aclbsize = 0; /* size of acl list in bytes */
- int dfaclbsize = 0; /* size of default acl list in bytes */
- int numacls;
- acl_t *acl_info;
-
- ASSERT(vsecattr);
-
- acl_info = acl_alloc(acl_type);
- if (acl_info == NULL)
- return (NULL);
-
- acl_info->acl_flags = 0;
-
- switch (acl_type) {
-
- case ACLENT_T:
- numacls = vsecattr->vsa_aclcnt + vsecattr->vsa_dfaclcnt;
- aclbsize = vsecattr->vsa_aclcnt * sizeof (aclent_t);
- dfaclbsize = vsecattr->vsa_dfaclcnt * sizeof (aclent_t);
-
- acl_info->acl_cnt = numacls;
- acl_info->acl_aclp = kmem_alloc(aclbsize + dfaclbsize,
- KM_SLEEP);
- (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
- aclbsize);
- (void) memcpy((char *)acl_info->acl_aclp + aclbsize,
- vsecattr->vsa_dfaclentp, dfaclbsize);
-
- if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
- acl_info->acl_flags |= ACL_IS_TRIVIAL;
-
- break;
-
- case ACE_T:
- aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
- acl_info->acl_cnt = vsecattr->vsa_aclcnt;
- acl_info->acl_flags = vsecattr->vsa_aclflags;
- acl_info->acl_aclp = kmem_alloc(aclbsize, KM_SLEEP);
- (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
- aclbsize);
- if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
- acl_info->acl_flags |= ACL_IS_TRIVIAL;
-
- break;
-
- default:
- acl_free(acl_info);
- return (NULL);
- }
-
- if (aclbsize && vsecattr->vsa_aclentp)
- kmem_free(vsecattr->vsa_aclentp, aclbsize);
- if (dfaclbsize && vsecattr->vsa_dfaclentp)
- kmem_free(vsecattr->vsa_dfaclentp, dfaclbsize);
-
- return (acl_info);
-}
-
-/*
- * smb_vop_acl_to_vsa
- *
- * Converts given acl_t structure to a vsecattr_t structure.
- *
- * IMPORTANT:
- * Upon successful return the memory allocated for vsa_aclentp
- * should be freed by calling kmem_free(). The size is returned
- * in aclbsize.
- */
-int
-smb_vop_acl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, int *aclbsize)
-{
- int error = 0;
- int numacls;
- aclent_t *aclp;
-
- ASSERT(acl_info);
- ASSERT(vsecattr);
- ASSERT(aclbsize);
-
- bzero(vsecattr, sizeof (vsecattr_t));
- *aclbsize = 0;
-
- switch (acl_info->acl_type) {
- case ACLENT_T:
- numacls = acl_info->acl_cnt;
- /*
- * Minimum ACL size is three entries so might as well
- * bail out here. Also limit request size to prevent user
- * from allocating too much kernel memory. Maximum size
- * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES
- * for the default ACL part.
- */
- if (numacls < 3 || numacls > (MAX_ACL_ENTRIES * 2)) {
- error = EINVAL;
- break;
- }
-
- vsecattr->vsa_mask = VSA_ACL;
-
- vsecattr->vsa_aclcnt = numacls;
- *aclbsize = numacls * sizeof (aclent_t);
- vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
- (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
- *aclbsize);
-
- /* Sort the acl list */
- ksort((caddr_t)vsecattr->vsa_aclentp,
- vsecattr->vsa_aclcnt, sizeof (aclent_t), cmp2acls);
-
- /* Break into acl and default acl lists */
- for (numacls = 0, aclp = vsecattr->vsa_aclentp;
- numacls < vsecattr->vsa_aclcnt;
- aclp++, numacls++) {
- if (aclp->a_type & ACL_DEFAULT)
- break;
- }
-
- /* Find where defaults start (if any) */
- if (numacls < vsecattr->vsa_aclcnt) {
- vsecattr->vsa_mask |= VSA_DFACL;
- vsecattr->vsa_dfaclcnt = vsecattr->vsa_aclcnt - numacls;
- vsecattr->vsa_dfaclentp = aclp;
- vsecattr->vsa_aclcnt = numacls;
- }
-
- /* Adjust if they're all defaults */
- if (vsecattr->vsa_aclcnt == 0) {
- vsecattr->vsa_mask &= ~VSA_ACL;
- vsecattr->vsa_aclentp = NULL;
- }
-
- /* Only directories can have defaults */
- if (vsecattr->vsa_dfaclcnt &&
- (acl_info->acl_flags & ACL_IS_DIR)) {
- error = ENOTDIR;
- }
-
- break;
-
- case ACE_T:
- if (acl_info->acl_cnt < 1 ||
- acl_info->acl_cnt > MAX_ACL_ENTRIES) {
- error = EINVAL;
- break;
- }
-
- vsecattr->vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
- vsecattr->vsa_aclcnt = acl_info->acl_cnt;
- vsecattr->vsa_aclflags = acl_info->acl_flags & ACL_FLAGS_ALL;
- *aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
- vsecattr->vsa_aclentsz = *aclbsize;
- vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
- (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
- *aclbsize);
-
- break;
-
- default:
- error = EINVAL;
- }
-
- return (error);
-}
-
-/*
* smb_vop_acl_read
*
* Reads the ACL of the specified file into 'aclp'.
@@ -1751,7 +1588,7 @@ smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type,
if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, ct))
return (error);
- *aclp = smb_vop_acl_from_vsa(&vsecattr, acl_type);
+ *aclp = smb_fsacl_from_vsa(&vsecattr, acl_type);
if (vp->v_type == VDIR)
(*aclp)->acl_flags |= ACL_IS_DIR;
@@ -1774,7 +1611,7 @@ smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr,
ASSERT(vp);
ASSERT(aclp);
- error = smb_vop_acl_to_vsa(aclp, &vsecattr, &aclbsize);
+ error = smb_fsacl_to_vsa(aclp, &vsecattr, &aclbsize);
if (error == 0) {
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_winpipe.c b/usr/src/uts/common/fs/smbsrv/smb_winpipe.c
index 361485783c..cf4c3beda0 100755
--- a/usr/src/uts/common/fs/smbsrv/smb_winpipe.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_winpipe.c
@@ -26,8 +26,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
/*
- * This file contain routines to initialize the doors interfaces for
- * CIFS winpipe calls.
+ * Winpipe door interface to MSRPC services.
*/
#define START_UPDOOR_SIZE 16384
@@ -46,7 +45,8 @@
#include <sys/uio.h>
-static door_handle_t *smb_winpipe_dh = NULL;
+static door_handle_t smb_winpipe_dh = NULL;
+static int smb_winpipe_door_id = -1;
static uint64_t smb_winpipe_ncall = 0;
static kmutex_t smb_winpipe_mutex;
static kcondvar_t smb_winpipe_cv;
@@ -74,43 +74,41 @@ smb_winpipe_fini(void)
mutex_destroy(&smb_winpipe_mutex);
}
+/*
+ * Open the winpipe (user space) door. If the door is already
+ * open, close it because the door-id has probably changed.
+ * Returns 0 on success. Otherwise -1 to indicate a lookup failure.
+ */
int
-smb_winpipe_open(void)
+smb_winpipe_open(int door_id)
{
- door_handle_t *dh;
- int rc;
+ smb_winpipe_close();
mutex_enter(&smb_winpipe_mutex);
+ smb_winpipe_ncall = 0;
if (smb_winpipe_dh == NULL) {
- dh = kmem_zalloc(sizeof (door_handle_t), KM_SLEEP);
-
- rc = door_ki_open(SMB_WINPIPE_DOOR_UP_PATH, dh);
- if (rc) {
- kmem_free(dh, sizeof (door_handle_t));
- mutex_exit(&smb_winpipe_mutex);
- cmn_err(CE_WARN, "smb_winpipe_open: rc=%d", rc);
- return (-1);
- }
-
- smb_winpipe_ncall = 0;
- smb_winpipe_dh = dh;
+ smb_winpipe_door_id = door_id;
+ smb_winpipe_dh = door_ki_lookup(door_id);
}
mutex_exit(&smb_winpipe_mutex);
- return (0);
+ return ((smb_winpipe_dh == NULL) ? -1 : 0);
}
+/*
+ * Close the winpipe (user space) door.
+ */
void
smb_winpipe_close(void)
{
mutex_enter(&smb_winpipe_mutex);
- while (smb_winpipe_ncall > 0)
- cv_wait(&smb_winpipe_cv, &smb_winpipe_mutex);
+ if (smb_winpipe_dh != NULL) {
+ while (smb_winpipe_ncall > 0)
+ cv_wait(&smb_winpipe_cv, &smb_winpipe_mutex);
- if (smb_winpipe_dh) {
- kmem_free(smb_winpipe_dh, sizeof (door_handle_t));
+ door_ki_rele(smb_winpipe_dh);
smb_winpipe_dh = NULL;
}
@@ -140,7 +138,9 @@ smb_winpipe_call(struct smb_request *sr,
if (smb_winpipe_dh == NULL) {
mutex_exit(&smb_winpipe_mutex);
- return (-1);
+
+ if (smb_winpipe_open(smb_winpipe_door_id) != 0)
+ return (-1);
}
++smb_winpipe_ncall;
@@ -284,7 +284,7 @@ smb_winpipe_upcall(mlsvc_pipe_t *pipe_info,
da.rbuf = (char *)lbuf;
da.rsize = START_UPDOOR_SIZE;
- if (door_ki_upcall(*smb_winpipe_dh, &da) != 0) {
+ if (door_ki_upcall(smb_winpipe_dh, &da) != 0) {
return (-1);
}
/* RPC_WRITE just queues the data and returns */
diff --git a/usr/src/uts/common/fs/smbsrv/smb_write.c b/usr/src/uts/common/fs/smbsrv/smb_write.c
index e6874397b4..93b9f6e758 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_write.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_write.c
@@ -84,7 +84,7 @@ smb_com_write(struct smb_request *sr)
}
param->w_offset = (uint64_t)off;
- param->w_vdb.uio.uio_offset = param->w_offset;
+ param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
if (param->w_count == 0) {
rc = smb_write_truncate(sr, param);
@@ -97,7 +97,7 @@ smb_com_write(struct smb_request *sr)
/* NOTREACHED */
}
- param->w_vdb.uio.uio_offset = param->w_offset;
+ param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
rc = smb_write_common(sr, param);
}
@@ -173,7 +173,7 @@ smb_com_write_and_close(struct smb_request *sr)
/* NOTREACHED */
}
- param->w_vdb.uio.uio_offset = param->w_offset;
+ param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
rc = smb_write_common(sr, param);
}
@@ -255,7 +255,7 @@ smb_com_write_and_unlock(struct smb_request *sr)
}
param->w_offset = (uint64_t)off;
- param->w_vdb.uio.uio_offset = (off_t)param->w_offset;
+ param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
if ((rc = smb_write_common(sr, param)) != 0) {
kmem_free(param, sizeof (smb_write_param_t));
@@ -344,7 +344,7 @@ smb_com_write_andx(struct smb_request *sr)
/* NOTREACHED */
}
- param->w_vdb.uio.uio_offset = param->w_offset;
+ param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
if (param->w_count != 0) {
if ((rc = smb_write_common(sr, param)) != 0) {