diff options
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/cifsacl.c | 77 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 23 | ||||
-rw-r--r-- | fs/cifs/connect.c | 2 |
3 files changed, 79 insertions, 23 deletions
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index f1215df7fbee..bd75a3b8caff 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -223,6 +223,17 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, le32_to_cpu(pdacl->num_aces))); #endif + /* reset rwx permissions for user/group/other. + Also, if num_aces is 0 i.e. DACL has no ACEs, + user/group/other have no permissions */ + inode->i_mode &= ~(S_IRWXUGO); + + if (!pdacl) { + /* no DACL in the security descriptor, set + all the permissions for user/group/other */ + inode->i_mode |= S_IRWXUGO; + return; + } acl_base = (char *)pdacl; acl_size = sizeof(struct cifs_acl); @@ -235,9 +246,6 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, cifscred->aces = kmalloc(num_aces * sizeof(struct cifs_ace *), GFP_KERNEL);*/ - /* reset rwx permissions for user/group/other */ - inode->i_mode &= ~(S_IRWXUGO); - for (i = 0; i < num_aces; ++i) { ppace[i] = (struct cifs_ace *) (acl_base + acl_size); #ifdef CONFIG_CIFS_DEBUG2 @@ -309,6 +317,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, struct cifs_sid *owner_sid_ptr, *group_sid_ptr; struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ char *end_of_acl = ((char *)pntsd) + acl_len; + __u32 dacloffset; if ((inode == NULL) || (pntsd == NULL)) return -EIO; @@ -317,15 +326,14 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, le32_to_cpu(pntsd->osidoffset)); group_sid_ptr = (struct cifs_sid *)((char *)pntsd + le32_to_cpu(pntsd->gsidoffset)); - dacl_ptr = (struct cifs_acl *)((char *)pntsd + - le32_to_cpu(pntsd->dacloffset)); + dacloffset = le32_to_cpu(pntsd->dacloffset); + dacl_ptr = (struct cifs_acl *)(char *)pntsd + dacloffset; #ifdef CONFIG_CIFS_DEBUG2 cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x " "sacloffset 0x%x dacloffset 0x%x", pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset), le32_to_cpu(pntsd->gsidoffset), - le32_to_cpu(pntsd->sacloffset), - le32_to_cpu(pntsd->dacloffset))); + le32_to_cpu(pntsd->sacloffset), dacloffset)); #endif /* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */ rc = parse_sid(owner_sid_ptr, end_of_acl); @@ -336,7 +344,11 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, if (rc) return rc; - parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, group_sid_ptr, inode); + if (dacloffset) + parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, + group_sid_ptr, inode); + else + cFYI(1, ("no ACL")); /* BB grant all or default perms? */ /* cifscred->uid = owner_sid_ptr->rid; cifscred->gid = group_sid_ptr->rid; @@ -350,9 +362,9 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, } -/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ - -void acl_to_uid_mode(struct inode *inode, const char *path) +/* Retrieve an ACL from the server */ +static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, + const char *path) { struct cifsFileInfo *open_file; int unlock_file = FALSE; @@ -362,19 +374,18 @@ void acl_to_uid_mode(struct inode *inode, const char *path) struct super_block *sb; struct cifs_sb_info *cifs_sb; struct cifs_ntsd *pntsd = NULL; - __u32 acllen; cFYI(1, ("get mode from ACL for %s", path)); if (inode == NULL) - return; + return NULL; xid = GetXid(); open_file = find_readable_file(CIFS_I(inode)); sb = inode->i_sb; if (sb == NULL) { FreeXid(xid); - return; + return NULL; } cifs_sb = CIFS_SB(sb); @@ -391,25 +402,44 @@ void acl_to_uid_mode(struct inode *inode, const char *path) if (rc != 0) { cERROR(1, ("Unable to open file to get ACL")); FreeXid(xid); - return; + return NULL; } } - rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, &acllen); - cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, acllen)); + rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); + cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen)); if (unlock_file == TRUE) atomic_dec(&open_file->wrtPending); else CIFSSMBClose(xid, cifs_sb->tcon, fid); - /* parse ACEs */ - if (!rc) + FreeXid(xid); + return pntsd; +} + +/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ +void acl_to_uid_mode(struct inode *inode, const char *path) +{ + struct cifs_ntsd *pntsd = NULL; + u32 acllen = 0; + int rc = 0; + +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("converting ACL to mode for %s", path)); +#endif + pntsd = get_cifs_acl(&acllen, inode, path); + + /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ + if (pntsd) rc = parse_sec_desc(pntsd, acllen, inode); + if (rc) + cFYI(1, ("parse sec desc failed rc = %d", rc)); + kfree(pntsd); - FreeXid(xid); return; } +/* Convert mode bits to an ACL so we can update the ACL on the server */ int mode_to_acl(struct inode *inode, const char *path) { int rc = 0; @@ -419,12 +449,15 @@ int mode_to_acl(struct inode *inode, const char *path) cFYI(1, ("set ACL from mode for %s", path)); /* Get the security descriptor */ + pntsd = get_cifs_acl(&acllen, inode, path); - /* Add/Modify the three ACEs for owner, group, everyone */ + /* Add/Modify the three ACEs for owner, group, everyone + while retaining the other ACEs */ /* Set the security descriptor */ - kfree(pntsd); + + kfree(pntsd); return rc; } #endif /* CONFIG_CIFS_EXPERIMENTAL */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 07464b6ac129..dbe6b846f37f 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1228,6 +1228,29 @@ typedef struct smb_com_transaction_qsec_req { __le32 AclFlags; } __attribute__((packed)) QUERY_SEC_DESC_REQ; + +typedef struct smb_com_transaction_ssec_req { + struct smb_hdr hdr; /* wct = 19 */ + __u8 MaxSetupCount; + __u16 Reserved; + __le32 TotalParameterCount; + __le32 TotalDataCount; + __le32 MaxParameterCount; + __le32 MaxDataCount; + __le32 ParameterCount; + __le32 ParameterOffset; + __le32 DataCount; + __le32 DataOffset; + __u8 SetupCount; /* no setup words follow subcommand */ + /* SNIA spec incorrectly included spurious pad here */ + __le16 SubCommand; /* 3 = SET_SECURITY_DESC */ + __le16 ByteCount; /* bcc = 3 + 8 */ + __u8 Pad[3]; + __u16 Fid; + __u16 Reserved2; + __le32 AclFlags; +} __attribute__((packed)) SET_SEC_DESC_REQ; + typedef struct smb_com_transaction_change_notify_req { struct smb_hdr hdr; /* wct = 23 */ __u8 MaxSetupCount; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 19ee11f7f35a..380ee9991f20 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -793,7 +793,7 @@ cifs_parse_mount_options(char *options, const char *devname, vol->linux_gid = current->gid; vol->dir_mode = S_IRWXUGO; /* 2767 perms indicate mandatory locking support */ - vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); + vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP); /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ vol->rw = TRUE; |