mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-18 21:41:52 -04:00
cifs: get mode bits from special sid on stat
When mounting with "modefromsid" retrieve mode bits from
special SID (S-1-5-88-3) on stat. Subsequent patch will fix
setattr (chmod) to save mode bits in S-1-5-88-3-<mode>
Note that when an ACE matching S-1-5-88-3 is not found, we
default the mode to an approximation based on the owner, group
and everyone permissions (as with the "cifsacl" mount option).
See See e.g.
https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/hh509017(v=ws.10)
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
@@ -701,10 +701,9 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
||||||
struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
|
struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
|
||||||
struct cifs_fattr *fattr)
|
struct cifs_fattr *fattr, bool mode_from_special_sid)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int num_aces = 0;
|
int num_aces = 0;
|
||||||
@@ -757,22 +756,34 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
|||||||
#ifdef CONFIG_CIFS_DEBUG2
|
#ifdef CONFIG_CIFS_DEBUG2
|
||||||
dump_ace(ppace[i], end_of_acl);
|
dump_ace(ppace[i], end_of_acl);
|
||||||
#endif
|
#endif
|
||||||
if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
|
if (mode_from_special_sid &&
|
||||||
|
(compare_sids(&(ppace[i]->sid),
|
||||||
|
&sid_unix_NFS_mode) == 0)) {
|
||||||
|
/*
|
||||||
|
* Full permissions are:
|
||||||
|
* 07777 = S_ISUID | S_ISGID | S_ISVTX |
|
||||||
|
* S_IRWXU | S_IRWXG | S_IRWXO
|
||||||
|
*/
|
||||||
|
fattr->cf_mode &= ~07777;
|
||||||
|
fattr->cf_mode |=
|
||||||
|
le32_to_cpu(ppace[i]->sid.sub_auth[2]);
|
||||||
|
break;
|
||||||
|
} else if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
|
||||||
access_flags_to_mode(ppace[i]->access_req,
|
access_flags_to_mode(ppace[i]->access_req,
|
||||||
ppace[i]->type,
|
ppace[i]->type,
|
||||||
&fattr->cf_mode,
|
&fattr->cf_mode,
|
||||||
&user_mask);
|
&user_mask);
|
||||||
if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
|
else if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
|
||||||
access_flags_to_mode(ppace[i]->access_req,
|
access_flags_to_mode(ppace[i]->access_req,
|
||||||
ppace[i]->type,
|
ppace[i]->type,
|
||||||
&fattr->cf_mode,
|
&fattr->cf_mode,
|
||||||
&group_mask);
|
&group_mask);
|
||||||
if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
|
else if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
|
||||||
access_flags_to_mode(ppace[i]->access_req,
|
access_flags_to_mode(ppace[i]->access_req,
|
||||||
ppace[i]->type,
|
ppace[i]->type,
|
||||||
&fattr->cf_mode,
|
&fattr->cf_mode,
|
||||||
&other_mask);
|
&other_mask);
|
||||||
if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
|
else if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
|
||||||
access_flags_to_mode(ppace[i]->access_req,
|
access_flags_to_mode(ppace[i]->access_req,
|
||||||
ppace[i]->type,
|
ppace[i]->type,
|
||||||
&fattr->cf_mode,
|
&fattr->cf_mode,
|
||||||
@@ -851,7 +862,8 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
|
|||||||
|
|
||||||
/* Convert CIFS ACL to POSIX form */
|
/* Convert CIFS ACL to POSIX form */
|
||||||
static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
||||||
struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
|
struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr,
|
||||||
|
bool get_mode_from_special_sid)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
|
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
|
||||||
@@ -900,7 +912,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
|||||||
|
|
||||||
if (dacloffset)
|
if (dacloffset)
|
||||||
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
|
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
|
||||||
group_sid_ptr, fattr);
|
group_sid_ptr, fattr, get_mode_from_special_sid);
|
||||||
else
|
else
|
||||||
cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
|
cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
|
||||||
|
|
||||||
@@ -1128,8 +1140,8 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
|||||||
/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */
|
/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */
|
||||||
int
|
int
|
||||||
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
||||||
struct inode *inode, const char *path,
|
struct inode *inode, bool mode_from_special_sid,
|
||||||
const struct cifs_fid *pfid)
|
const char *path, const struct cifs_fid *pfid)
|
||||||
{
|
{
|
||||||
struct cifs_ntsd *pntsd = NULL;
|
struct cifs_ntsd *pntsd = NULL;
|
||||||
u32 acllen = 0;
|
u32 acllen = 0;
|
||||||
@@ -1156,8 +1168,11 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
|||||||
if (IS_ERR(pntsd)) {
|
if (IS_ERR(pntsd)) {
|
||||||
rc = PTR_ERR(pntsd);
|
rc = PTR_ERR(pntsd);
|
||||||
cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
|
cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
|
||||||
|
} else if (mode_from_special_sid) {
|
||||||
|
rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true);
|
||||||
} else {
|
} else {
|
||||||
rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
|
/* get approximated mode from ACL */
|
||||||
|
rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false);
|
||||||
kfree(pntsd);
|
kfree(pntsd);
|
||||||
if (rc)
|
if (rc)
|
||||||
cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
|
cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
|
||||||
|
|||||||
@@ -197,6 +197,7 @@ extern int cifs_rename_pending_delete(const char *full_path,
|
|||||||
const unsigned int xid);
|
const unsigned int xid);
|
||||||
extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
|
extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||||
struct cifs_fattr *fattr, struct inode *inode,
|
struct cifs_fattr *fattr, struct inode *inode,
|
||||||
|
bool get_mode_from_special_sid,
|
||||||
const char *path, const struct cifs_fid *pfid);
|
const char *path, const struct cifs_fid *pfid);
|
||||||
extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64,
|
extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64,
|
||||||
kuid_t, kgid_t);
|
kuid_t, kgid_t);
|
||||||
|
|||||||
@@ -893,8 +893,17 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* fill in 0777 bits from ACL */
|
/* fill in 0777 bits from ACL */
|
||||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) {
|
||||||
rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, full_path, fid);
|
rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, true,
|
||||||
|
full_path, fid);
|
||||||
|
if (rc) {
|
||||||
|
cifs_dbg(FYI, "%s: Get mode from SID failed. rc=%d\n",
|
||||||
|
__func__, rc);
|
||||||
|
goto cgii_exit;
|
||||||
|
}
|
||||||
|
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
||||||
|
rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, false,
|
||||||
|
full_path, fid);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(FYI, "%s: Getting ACL failed with error: %d\n",
|
cifs_dbg(FYI, "%s: Getting ACL failed with error: %d\n",
|
||||||
__func__, rc);
|
__func__, rc);
|
||||||
|
|||||||
Reference in New Issue
Block a user