diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index a7035bd..1a0f558 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -268,11 +268,11 @@ #endif return; } -static __le16 fill_ace_for_sid(struct cifs_ace *pntace, +static short fill_ace_for_sid(struct cifs_ace *pntace, const struct cifs_sid *psid, __u64 nmode, umode_t bits) { int i; - __u16 size = 0; + short size = 0; __u32 access_req = 0; pntace->type = ACCESS_ALLOWED; @@ -295,6 +295,24 @@ static __le16 fill_ace_for_sid(struct ci return (size); } +static void copy_ace(struct cifs_ace *psace, struct cifs_ace *pdace) +{ + int i; + + pdace->type = psace->type; + pdace->flags = psace->flags; + pdace->access_req = psace->access_req; + pdace->sid.revision = psace->sid.revision; + pdace->sid.num_subauth = psace->sid.num_subauth; + for (i = 0; i < 6; i++) + pdace->sid.authority[i] = psace->sid.authority[i]; + for (i = 0; i < pdace->sid.num_subauth; i++) + pdace->sid.sub_auth[i] = psace->sid.sub_auth[i]; + pdace->size = psace->size; + + return; +} + #ifdef CONFIG_CIFS_DEBUG2 static void dump_ace(struct cifs_ace *pace, char *end_of_acl) @@ -421,23 +439,57 @@ #endif } -static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid, - struct cifs_sid *pgrpsid, __u64 nmode) +static int set_chmod_dacl(struct cifs_acl *psdacl, struct cifs_acl *pddacl, + struct cifs_sid *pownersid, + struct cifs_sid *pgrpsid, + __u64 nmode) { - __le16 size = 0; - struct cifs_acl *pnndacl; - - pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl)); - - size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size), - pownersid, nmode, S_IRWXU); - size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), - pgrpsid, nmode, S_IRWXG); - size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), - &sid_everyone, nmode, S_IRWXO); + short soffset = 0; /* ace offsets in source dacl */ + short acesize = 0; /* size of a source ace */ + short size = 0; /* size of destination dacl */ + int num_aces_rcvd = 0; /* number of aces in source dacl */ + int num_aces = 0; /* number of aces in destination dacl */ + int i; /* just an index */ + struct cifs_acl *pbsdacl; /* ptr to begining of source dacl */ + struct cifs_acl *pbddacl; /* ptr begining of destination dacl */ + struct cifs_ace *psace; /* ptr to source ace */ + struct cifs_ace *pdace; /* ptr to destination ace */ + + pbsdacl = (struct cifs_acl *)((char *)psdacl + sizeof(struct cifs_acl)); + pbddacl = (struct cifs_acl *)((char *)pddacl + sizeof(struct cifs_acl)); + + size += fill_ace_for_sid((struct cifs_ace *) ((char *)pbddacl + size), + pownersid, nmode, S_IRWXU); + size += fill_ace_for_sid((struct cifs_ace *) ((char *)pbddacl + size), + pgrpsid, nmode, S_IRWXG); + size += fill_ace_for_sid((struct cifs_ace *) ((char *)pbddacl + size), + &sid_everyone, nmode, S_IRWXO); + num_aces = 3; + + /* For every ace in source dacl, if the ace does not match to that + of owner, group, and everyone, copy it in the destination dacl. + Update the size and increment the number of aces count */ + + num_aces_rcvd = le32_to_cpu(psdacl->num_aces); + for (i = 0; i < num_aces_rcvd; i++) { + psace = (struct cifs_ace *) ((char *)pbsdacl + soffset); + pdace = (struct cifs_ace *) ((char *)pbddacl + size); + + acesize = le16_to_cpu(psace->size); + soffset += acesize; + + if ((compare_sids(&(psace->sid), pownersid)) || + (compare_sids(&(psace->sid), pgrpsid)) || + (compare_sids(&(psace->sid), &sid_everyone))) + continue; /* skip ace copy */ + + copy_ace(psace, pdace); + size += acesize; + num_aces += 1; + } - pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl)); - pndacl->num_aces = 3; + pddacl->size = cpu_to_le16(size + sizeof(struct cifs_acl)); + pddacl->num_aces = cpu_to_le16(num_aces); return (0); } @@ -558,7 +610,8 @@ static int build_sec_desc(struct cifs_nt ndacl_ptr->size = 0; ndacl_ptr->num_aces = 0; - rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode); + rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr, + nmode); sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size); @@ -626,7 +679,7 @@ static struct cifs_ntsd *get_cifs_acl(u3 /* Set an ACL on the server */ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, - struct inode *inode, const char *path) + struct inode *inode, const char *path) { struct cifsFileInfo *open_file; int unlock_file = FALSE;