Skip to content

Commit d413eab

Browse files
slowfranklinSteve French
authored andcommitted
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 <[email protected]> Cc: [email protected] Signed-off-by: Steve French <[email protected]>
1 parent 128630e commit d413eab

File tree

4 files changed

+37
-23
lines changed

4 files changed

+37
-23
lines changed

fs/smb/client/cifsacl.c

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -885,12 +885,17 @@ unsigned int setup_authusers_ACE(struct smb_ace *pntace)
885885
* Fill in the special SID based on the mode. See
886886
* https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
887887
*/
888-
unsigned int setup_special_mode_ACE(struct smb_ace *pntace, __u64 nmode)
888+
unsigned int setup_special_mode_ACE(struct smb_ace *pntace,
889+
bool posix,
890+
__u64 nmode)
889891
{
890892
int i;
891893
unsigned int ace_size = 28;
892894

893-
pntace->type = ACCESS_DENIED_ACE_TYPE;
895+
if (posix)
896+
pntace->type = ACCESS_ALLOWED_ACE_TYPE;
897+
else
898+
pntace->type = ACCESS_DENIED_ACE_TYPE;
894899
pntace->flags = 0x0;
895900
pntace->access_req = 0;
896901
pntace->sid.num_subauth = 3;
@@ -933,7 +938,8 @@ static void populate_new_aces(char *nacl_base,
933938
struct smb_sid *pownersid,
934939
struct smb_sid *pgrpsid,
935940
__u64 *pnmode, u32 *pnum_aces, u16 *pnsize,
936-
bool modefromsid)
941+
bool modefromsid,
942+
bool posix)
937943
{
938944
__u64 nmode;
939945
u32 num_aces = 0;
@@ -950,13 +956,15 @@ static void populate_new_aces(char *nacl_base,
950956
num_aces = *pnum_aces;
951957
nsize = *pnsize;
952958

953-
if (modefromsid) {
954-
pnntace = (struct smb_ace *) (nacl_base + nsize);
955-
nsize += setup_special_mode_ACE(pnntace, nmode);
956-
num_aces++;
959+
if (modefromsid || posix) {
957960
pnntace = (struct smb_ace *) (nacl_base + nsize);
958-
nsize += setup_authusers_ACE(pnntace);
961+
nsize += setup_special_mode_ACE(pnntace, posix, nmode);
959962
num_aces++;
963+
if (modefromsid) {
964+
pnntace = (struct smb_ace *) (nacl_base + nsize);
965+
nsize += setup_authusers_ACE(pnntace);
966+
num_aces++;
967+
}
960968
goto set_size;
961969
}
962970

@@ -1076,7 +1084,7 @@ static __u16 replace_sids_and_copy_aces(struct smb_acl *pdacl, struct smb_acl *p
10761084

10771085
static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
10781086
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
1079-
__u64 *pnmode, bool mode_from_sid)
1087+
__u64 *pnmode, bool mode_from_sid, bool posix)
10801088
{
10811089
int i;
10821090
u16 size = 0;
@@ -1094,11 +1102,11 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
10941102
nsize = sizeof(struct smb_acl);
10951103

10961104
/* If pdacl is NULL, we don't have a src. Simply populate new ACL. */
1097-
if (!pdacl) {
1105+
if (!pdacl || posix) {
10981106
populate_new_aces(nacl_base,
10991107
pownersid, pgrpsid,
11001108
pnmode, &num_aces, &nsize,
1101-
mode_from_sid);
1109+
mode_from_sid, posix);
11021110
goto finalize_dacl;
11031111
}
11041112

@@ -1115,7 +1123,7 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
11151123
populate_new_aces(nacl_base,
11161124
pownersid, pgrpsid,
11171125
pnmode, &num_aces, &nsize,
1118-
mode_from_sid);
1126+
mode_from_sid, posix);
11191127

11201128
new_aces_set = true;
11211129
}
@@ -1144,7 +1152,7 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
11441152
populate_new_aces(nacl_base,
11451153
pownersid, pgrpsid,
11461154
pnmode, &num_aces, &nsize,
1147-
mode_from_sid);
1155+
mode_from_sid, posix);
11481156

11491157
new_aces_set = true;
11501158
}
@@ -1251,7 +1259,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
12511259
/* Convert permission bits from mode to equivalent CIFS ACL */
12521260
static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
12531261
__u32 secdesclen, __u32 *pnsecdesclen, __u64 *pnmode, kuid_t uid, kgid_t gid,
1254-
bool mode_from_sid, bool id_from_sid, int *aclflag)
1262+
bool mode_from_sid, bool id_from_sid, bool posix, int *aclflag)
12551263
{
12561264
int rc = 0;
12571265
__u32 dacloffset;
@@ -1288,7 +1296,7 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
12881296
ndacl_ptr->num_aces = cpu_to_le32(0);
12891297

12901298
rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
1291-
pnmode, mode_from_sid);
1299+
pnmode, mode_from_sid, posix);
12921300

12931301
sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
12941302
/* copy the non-dacl portion of secdesc */
@@ -1587,6 +1595,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
15871595
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
15881596
struct smb_version_operations *ops;
15891597
bool mode_from_sid, id_from_sid;
1598+
bool posix = tlink_tcon(tlink)->posix_extensions;
15901599
const u32 info = 0;
15911600

15921601
if (IS_ERR(tlink))
@@ -1622,12 +1631,13 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
16221631
id_from_sid = false;
16231632

16241633
/* Potentially, five new ACEs can be added to the ACL for U,G,O mapping */
1625-
nsecdesclen = secdesclen;
16261634
if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */
1627-
if (mode_from_sid)
1628-
nsecdesclen += 2 * sizeof(struct smb_ace);
1635+
if (posix)
1636+
nsecdesclen = 1 * sizeof(struct smb_ace);
1637+
else if (mode_from_sid)
1638+
nsecdesclen = secdesclen + (2 * sizeof(struct smb_ace));
16291639
else /* cifsacl */
1630-
nsecdesclen += 5 * sizeof(struct smb_ace);
1640+
nsecdesclen = secdesclen + (5 * sizeof(struct smb_ace));
16311641
} else { /* chown */
16321642
/* When ownership changes, changes new owner sid length could be different */
16331643
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,
16571667
}
16581668

16591669
rc = build_sec_desc(pntsd, pnntsd, secdesclen, &nsecdesclen, pnmode, uid, gid,
1660-
mode_from_sid, id_from_sid, &aclflag);
1670+
mode_from_sid, id_from_sid, posix, &aclflag);
16611671

16621672
cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
16631673

fs/smb/client/cifsproto.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,9 @@ extern int cifs_set_acl(struct mnt_idmap *idmap,
244244
extern int set_cifs_acl(struct smb_ntsd *pntsd, __u32 len, struct inode *ino,
245245
const char *path, int flag);
246246
extern unsigned int setup_authusers_ACE(struct smb_ace *pace);
247-
extern unsigned int setup_special_mode_ACE(struct smb_ace *pace, __u64 nmode);
247+
extern unsigned int setup_special_mode_ACE(struct smb_ace *pace,
248+
bool posix,
249+
__u64 nmode);
248250
extern unsigned int setup_special_user_owner_ACE(struct smb_ace *pace);
249251

250252
extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);

fs/smb/client/inode.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3062,6 +3062,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
30623062
int rc = -EACCES;
30633063
__u32 dosattr = 0;
30643064
__u64 mode = NO_CHANGE_64;
3065+
bool posix = cifs_sb_master_tcon(cifs_sb)->posix_extensions;
30653066

30663067
xid = get_xid();
30673068

@@ -3152,7 +3153,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
31523153
mode = attrs->ia_mode;
31533154
rc = 0;
31543155
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
3155-
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
3156+
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) ||
3157+
posix) {
31563158
rc = id_mode_to_cifs_acl(inode, full_path, &mode,
31573159
INVALID_UID, INVALID_GID);
31583160
if (rc) {

fs/smb/client/smb2pdu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2683,7 +2683,7 @@ create_sd_buf(umode_t mode, bool set_owner, unsigned int *len)
26832683
ptr += sizeof(struct smb3_acl);
26842684

26852685
/* create one ACE to hold the mode embedded in reserved special SID */
2686-
acelen = setup_special_mode_ACE((struct smb_ace *)ptr, (__u64)mode);
2686+
acelen = setup_special_mode_ACE((struct smb_ace *)ptr, false, (__u64)mode);
26872687
ptr += acelen;
26882688
acl_size = acelen + sizeof(struct smb3_acl);
26892689
ace_count = 1;

0 commit comments

Comments
 (0)