fs/smb/client: implement chmod() for SMB3 POSIX Extensions
The NT ACL format for an SMB3 POSIX Extensions chmod() is a single ACE with the
magic S-1-5-88-3-mode SID:
NT Security Descriptor
Revision: 1
Type: 0x8004, Self Relative, DACL Present
Offset to owner SID: 56
Offset to group SID: 124
Offset to SACL: 0
Offset to DACL: 20
Owner: S-1-5-21-3177838999-3893657415-1037673384-1000
Group: S-1-22-2-1000
NT User (DACL) ACL
Revision: NT4 (2)
Size: 36
Num ACEs: 1
NT ACE: S-1-5-88-3-438, flags 0x00, Access Allowed, mask 0x00000000
Type: Access Allowed
NT ACE Flags: 0x00
Size: 28
Access required: 0x00000000
SID: S-1-5-88-3-438
Owner and Group should be NULL, but the server is not required to fail the
request if they are present.
Signed-off-by: Ralph Boehme <slow@samba.org>
Cc: stable@vger.kernel.org
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
committed by
Steve French
parent
128630e1db
commit
d413eabff1
+30
-20
@@ -885,12 +885,17 @@ unsigned int setup_authusers_ACE(struct smb_ace *pntace)
|
|||||||
* Fill in the special SID based on the mode. See
|
* Fill in the special SID based on the mode. See
|
||||||
* https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
|
* https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
|
||||||
*/
|
*/
|
||||||
unsigned int setup_special_mode_ACE(struct smb_ace *pntace, __u64 nmode)
|
unsigned int setup_special_mode_ACE(struct smb_ace *pntace,
|
||||||
|
bool posix,
|
||||||
|
__u64 nmode)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned int ace_size = 28;
|
unsigned int ace_size = 28;
|
||||||
|
|
||||||
pntace->type = ACCESS_DENIED_ACE_TYPE;
|
if (posix)
|
||||||
|
pntace->type = ACCESS_ALLOWED_ACE_TYPE;
|
||||||
|
else
|
||||||
|
pntace->type = ACCESS_DENIED_ACE_TYPE;
|
||||||
pntace->flags = 0x0;
|
pntace->flags = 0x0;
|
||||||
pntace->access_req = 0;
|
pntace->access_req = 0;
|
||||||
pntace->sid.num_subauth = 3;
|
pntace->sid.num_subauth = 3;
|
||||||
@@ -933,7 +938,8 @@ static void populate_new_aces(char *nacl_base,
|
|||||||
struct smb_sid *pownersid,
|
struct smb_sid *pownersid,
|
||||||
struct smb_sid *pgrpsid,
|
struct smb_sid *pgrpsid,
|
||||||
__u64 *pnmode, u32 *pnum_aces, u16 *pnsize,
|
__u64 *pnmode, u32 *pnum_aces, u16 *pnsize,
|
||||||
bool modefromsid)
|
bool modefromsid,
|
||||||
|
bool posix)
|
||||||
{
|
{
|
||||||
__u64 nmode;
|
__u64 nmode;
|
||||||
u32 num_aces = 0;
|
u32 num_aces = 0;
|
||||||
@@ -950,13 +956,15 @@ static void populate_new_aces(char *nacl_base,
|
|||||||
num_aces = *pnum_aces;
|
num_aces = *pnum_aces;
|
||||||
nsize = *pnsize;
|
nsize = *pnsize;
|
||||||
|
|
||||||
if (modefromsid) {
|
if (modefromsid || posix) {
|
||||||
pnntace = (struct smb_ace *) (nacl_base + nsize);
|
pnntace = (struct smb_ace *) (nacl_base + nsize);
|
||||||
nsize += setup_special_mode_ACE(pnntace, nmode);
|
nsize += setup_special_mode_ACE(pnntace, posix, nmode);
|
||||||
num_aces++;
|
|
||||||
pnntace = (struct smb_ace *) (nacl_base + nsize);
|
|
||||||
nsize += setup_authusers_ACE(pnntace);
|
|
||||||
num_aces++;
|
num_aces++;
|
||||||
|
if (modefromsid) {
|
||||||
|
pnntace = (struct smb_ace *) (nacl_base + nsize);
|
||||||
|
nsize += setup_authusers_ACE(pnntace);
|
||||||
|
num_aces++;
|
||||||
|
}
|
||||||
goto set_size;
|
goto set_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1076,7 +1084,7 @@ static __u16 replace_sids_and_copy_aces(struct smb_acl *pdacl, struct smb_acl *p
|
|||||||
|
|
||||||
static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
|
static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
|
||||||
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
|
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
|
||||||
__u64 *pnmode, bool mode_from_sid)
|
__u64 *pnmode, bool mode_from_sid, bool posix)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
u16 size = 0;
|
u16 size = 0;
|
||||||
@@ -1094,11 +1102,11 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
|
|||||||
nsize = sizeof(struct smb_acl);
|
nsize = sizeof(struct smb_acl);
|
||||||
|
|
||||||
/* If pdacl is NULL, we don't have a src. Simply populate new ACL. */
|
/* If pdacl is NULL, we don't have a src. Simply populate new ACL. */
|
||||||
if (!pdacl) {
|
if (!pdacl || posix) {
|
||||||
populate_new_aces(nacl_base,
|
populate_new_aces(nacl_base,
|
||||||
pownersid, pgrpsid,
|
pownersid, pgrpsid,
|
||||||
pnmode, &num_aces, &nsize,
|
pnmode, &num_aces, &nsize,
|
||||||
mode_from_sid);
|
mode_from_sid, posix);
|
||||||
goto finalize_dacl;
|
goto finalize_dacl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1115,7 +1123,7 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
|
|||||||
populate_new_aces(nacl_base,
|
populate_new_aces(nacl_base,
|
||||||
pownersid, pgrpsid,
|
pownersid, pgrpsid,
|
||||||
pnmode, &num_aces, &nsize,
|
pnmode, &num_aces, &nsize,
|
||||||
mode_from_sid);
|
mode_from_sid, posix);
|
||||||
|
|
||||||
new_aces_set = true;
|
new_aces_set = true;
|
||||||
}
|
}
|
||||||
@@ -1144,7 +1152,7 @@ next_ace:
|
|||||||
populate_new_aces(nacl_base,
|
populate_new_aces(nacl_base,
|
||||||
pownersid, pgrpsid,
|
pownersid, pgrpsid,
|
||||||
pnmode, &num_aces, &nsize,
|
pnmode, &num_aces, &nsize,
|
||||||
mode_from_sid);
|
mode_from_sid, posix);
|
||||||
|
|
||||||
new_aces_set = true;
|
new_aces_set = true;
|
||||||
}
|
}
|
||||||
@@ -1251,7 +1259,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
|||||||
/* Convert permission bits from mode to equivalent CIFS ACL */
|
/* Convert permission bits from mode to equivalent CIFS ACL */
|
||||||
static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
|
static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
|
||||||
__u32 secdesclen, __u32 *pnsecdesclen, __u64 *pnmode, kuid_t uid, kgid_t gid,
|
__u32 secdesclen, __u32 *pnsecdesclen, __u64 *pnmode, kuid_t uid, kgid_t gid,
|
||||||
bool mode_from_sid, bool id_from_sid, int *aclflag)
|
bool mode_from_sid, bool id_from_sid, bool posix, int *aclflag)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
__u32 dacloffset;
|
__u32 dacloffset;
|
||||||
@@ -1288,7 +1296,7 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
|
|||||||
ndacl_ptr->num_aces = cpu_to_le32(0);
|
ndacl_ptr->num_aces = cpu_to_le32(0);
|
||||||
|
|
||||||
rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
|
rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
|
||||||
pnmode, mode_from_sid);
|
pnmode, mode_from_sid, posix);
|
||||||
|
|
||||||
sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
|
sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
|
||||||
/* copy the non-dacl portion of secdesc */
|
/* copy the non-dacl portion of secdesc */
|
||||||
@@ -1587,6 +1595,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
|
|||||||
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
||||||
struct smb_version_operations *ops;
|
struct smb_version_operations *ops;
|
||||||
bool mode_from_sid, id_from_sid;
|
bool mode_from_sid, id_from_sid;
|
||||||
|
bool posix = tlink_tcon(tlink)->posix_extensions;
|
||||||
const u32 info = 0;
|
const u32 info = 0;
|
||||||
|
|
||||||
if (IS_ERR(tlink))
|
if (IS_ERR(tlink))
|
||||||
@@ -1622,12 +1631,13 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
|
|||||||
id_from_sid = false;
|
id_from_sid = false;
|
||||||
|
|
||||||
/* Potentially, five new ACEs can be added to the ACL for U,G,O mapping */
|
/* Potentially, five new ACEs can be added to the ACL for U,G,O mapping */
|
||||||
nsecdesclen = secdesclen;
|
|
||||||
if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */
|
if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */
|
||||||
if (mode_from_sid)
|
if (posix)
|
||||||
nsecdesclen += 2 * sizeof(struct smb_ace);
|
nsecdesclen = 1 * sizeof(struct smb_ace);
|
||||||
|
else if (mode_from_sid)
|
||||||
|
nsecdesclen = secdesclen + (2 * sizeof(struct smb_ace));
|
||||||
else /* cifsacl */
|
else /* cifsacl */
|
||||||
nsecdesclen += 5 * sizeof(struct smb_ace);
|
nsecdesclen = secdesclen + (5 * sizeof(struct smb_ace));
|
||||||
} else { /* chown */
|
} else { /* chown */
|
||||||
/* When ownership changes, changes new owner sid length could be different */
|
/* When ownership changes, changes new owner sid length could be different */
|
||||||
nsecdesclen = sizeof(struct smb_ntsd) + (sizeof(struct smb_sid) * 2);
|
nsecdesclen = sizeof(struct smb_ntsd) + (sizeof(struct smb_sid) * 2);
|
||||||
@@ -1657,7 +1667,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
rc = build_sec_desc(pntsd, pnntsd, secdesclen, &nsecdesclen, pnmode, uid, gid,
|
rc = build_sec_desc(pntsd, pnntsd, secdesclen, &nsecdesclen, pnmode, uid, gid,
|
||||||
mode_from_sid, id_from_sid, &aclflag);
|
mode_from_sid, id_from_sid, posix, &aclflag);
|
||||||
|
|
||||||
cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
|
cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
|
||||||
|
|
||||||
|
|||||||
@@ -244,7 +244,9 @@ extern int cifs_set_acl(struct mnt_idmap *idmap,
|
|||||||
extern int set_cifs_acl(struct smb_ntsd *pntsd, __u32 len, struct inode *ino,
|
extern int set_cifs_acl(struct smb_ntsd *pntsd, __u32 len, struct inode *ino,
|
||||||
const char *path, int flag);
|
const char *path, int flag);
|
||||||
extern unsigned int setup_authusers_ACE(struct smb_ace *pace);
|
extern unsigned int setup_authusers_ACE(struct smb_ace *pace);
|
||||||
extern unsigned int setup_special_mode_ACE(struct smb_ace *pace, __u64 nmode);
|
extern unsigned int setup_special_mode_ACE(struct smb_ace *pace,
|
||||||
|
bool posix,
|
||||||
|
__u64 nmode);
|
||||||
extern unsigned int setup_special_user_owner_ACE(struct smb_ace *pace);
|
extern unsigned int setup_special_user_owner_ACE(struct smb_ace *pace);
|
||||||
|
|
||||||
extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
|
extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
|
||||||
|
|||||||
@@ -3062,6 +3062,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
|||||||
int rc = -EACCES;
|
int rc = -EACCES;
|
||||||
__u32 dosattr = 0;
|
__u32 dosattr = 0;
|
||||||
__u64 mode = NO_CHANGE_64;
|
__u64 mode = NO_CHANGE_64;
|
||||||
|
bool posix = cifs_sb_master_tcon(cifs_sb)->posix_extensions;
|
||||||
|
|
||||||
xid = get_xid();
|
xid = get_xid();
|
||||||
|
|
||||||
@@ -3152,7 +3153,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
|||||||
mode = attrs->ia_mode;
|
mode = attrs->ia_mode;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
|
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
|
||||||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
|
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) ||
|
||||||
|
posix) {
|
||||||
rc = id_mode_to_cifs_acl(inode, full_path, &mode,
|
rc = id_mode_to_cifs_acl(inode, full_path, &mode,
|
||||||
INVALID_UID, INVALID_GID);
|
INVALID_UID, INVALID_GID);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
|||||||
@@ -2683,7 +2683,7 @@ create_sd_buf(umode_t mode, bool set_owner, unsigned int *len)
|
|||||||
ptr += sizeof(struct smb3_acl);
|
ptr += sizeof(struct smb3_acl);
|
||||||
|
|
||||||
/* create one ACE to hold the mode embedded in reserved special SID */
|
/* create one ACE to hold the mode embedded in reserved special SID */
|
||||||
acelen = setup_special_mode_ACE((struct smb_ace *)ptr, (__u64)mode);
|
acelen = setup_special_mode_ACE((struct smb_ace *)ptr, false, (__u64)mode);
|
||||||
ptr += acelen;
|
ptr += acelen;
|
||||||
acl_size = acelen + sizeof(struct smb3_acl);
|
acl_size = acelen + sizeof(struct smb3_acl);
|
||||||
ace_count = 1;
|
ace_count = 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user