diff options
Diffstat (limited to 'usr/src/uts/common/fs')
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) { |