|
@@ -904,7 +904,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
|
|
acl_size = sizeof(struct cifs_acl);
|
|
|
|
|
|
num_aces = le32_to_cpu(pdacl->num_aces);
|
|
|
- if (num_aces > 0) {
|
|
|
+ if (num_aces > 0) {
|
|
|
umode_t user_mask = S_IRWXU;
|
|
|
umode_t group_mask = S_IRWXG;
|
|
|
umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
|
|
@@ -1066,52 +1066,82 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
|
|
else
|
|
|
cFYI(1, "no ACL"); /* BB grant all or default perms? */
|
|
|
|
|
|
-/* cifscred->uid = owner_sid_ptr->rid;
|
|
|
- cifscred->gid = group_sid_ptr->rid;
|
|
|
- memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
|
|
|
- sizeof(struct cifs_sid));
|
|
|
- memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
|
|
|
- sizeof(struct cifs_sid)); */
|
|
|
-
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/* Convert permission bits from mode to equivalent CIFS ACL */
|
|
|
static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
|
|
|
- struct inode *inode, __u64 nmode)
|
|
|
+ __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
|
|
|
{
|
|
|
int rc = 0;
|
|
|
__u32 dacloffset;
|
|
|
__u32 ndacloffset;
|
|
|
__u32 sidsoffset;
|
|
|
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
|
|
|
+ struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
|
|
|
struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
|
|
|
struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
|
|
|
|
|
|
- if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
|
|
|
- return -EIO;
|
|
|
-
|
|
|
- owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
|
|
+ if (nmode != NO_CHANGE_64) { /* chmod */
|
|
|
+ owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
|
|
le32_to_cpu(pntsd->osidoffset));
|
|
|
- group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
|
|
+ group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
|
|
le32_to_cpu(pntsd->gsidoffset));
|
|
|
-
|
|
|
- dacloffset = le32_to_cpu(pntsd->dacloffset);
|
|
|
- dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
|
|
|
-
|
|
|
- ndacloffset = sizeof(struct cifs_ntsd);
|
|
|
- ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
|
|
|
- ndacl_ptr->revision = dacl_ptr->revision;
|
|
|
- ndacl_ptr->size = 0;
|
|
|
- ndacl_ptr->num_aces = 0;
|
|
|
-
|
|
|
- rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
|
|
|
-
|
|
|
- sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
|
|
|
-
|
|
|
- /* copy security descriptor control portion and owner and group sid */
|
|
|
- copy_sec_desc(pntsd, pnntsd, sidsoffset);
|
|
|
+ dacloffset = le32_to_cpu(pntsd->dacloffset);
|
|
|
+ dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
|
|
|
+ ndacloffset = sizeof(struct cifs_ntsd);
|
|
|
+ ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
|
|
|
+ ndacl_ptr->revision = dacl_ptr->revision;
|
|
|
+ ndacl_ptr->size = 0;
|
|
|
+ ndacl_ptr->num_aces = 0;
|
|
|
+
|
|
|
+ rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
|
|
|
+ nmode);
|
|
|
+ sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
|
|
|
+ /* copy sec desc control portion & owner and group sids */
|
|
|
+ copy_sec_desc(pntsd, pnntsd, sidsoffset);
|
|
|
+ *aclflag = CIFS_ACL_DACL;
|
|
|
+ } else {
|
|
|
+ memcpy(pnntsd, pntsd, secdesclen);
|
|
|
+ if (uid != NO_CHANGE_32) { /* chown */
|
|
|
+ owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
|
|
|
+ le32_to_cpu(pnntsd->osidoffset));
|
|
|
+ nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!nowner_sid_ptr)
|
|
|
+ return -ENOMEM;
|
|
|
+ rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
|
|
|
+ if (rc) {
|
|
|
+ cFYI(1, "%s: Mapping error %d for owner id %d",
|
|
|
+ __func__, rc, uid);
|
|
|
+ kfree(nowner_sid_ptr);
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+ memcpy(owner_sid_ptr, nowner_sid_ptr,
|
|
|
+ sizeof(struct cifs_sid));
|
|
|
+ kfree(nowner_sid_ptr);
|
|
|
+ *aclflag = CIFS_ACL_OWNER;
|
|
|
+ }
|
|
|
+ if (gid != NO_CHANGE_32) { /* chgrp */
|
|
|
+ group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
|
|
|
+ le32_to_cpu(pnntsd->gsidoffset));
|
|
|
+ ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!ngroup_sid_ptr)
|
|
|
+ return -ENOMEM;
|
|
|
+ rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
|
|
|
+ if (rc) {
|
|
|
+ cFYI(1, "%s: Mapping error %d for group id %d",
|
|
|
+ __func__, rc, gid);
|
|
|
+ kfree(ngroup_sid_ptr);
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+ memcpy(group_sid_ptr, ngroup_sid_ptr,
|
|
|
+ sizeof(struct cifs_sid));
|
|
|
+ kfree(ngroup_sid_ptr);
|
|
|
+ *aclflag = CIFS_ACL_GROUP;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
return rc;
|
|
|
}
|
|
@@ -1192,13 +1222,15 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
|
|
|
return pntsd;
|
|
|
}
|
|
|
|
|
|
-static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
|
|
|
- struct cifs_ntsd *pnntsd, u32 acllen)
|
|
|
+ /* Set an ACL on the server */
|
|
|
+int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
|
|
+ struct inode *inode, const char *path, int aclflag)
|
|
|
{
|
|
|
int oplock = 0;
|
|
|
- int xid, rc, create_options = 0;
|
|
|
+ int xid, rc, access_flags, create_options = 0;
|
|
|
__u16 fid;
|
|
|
struct cifs_tcon *tcon;
|
|
|
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
|
|
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
|
|
|
|
|
if (IS_ERR(tlink))
|
|
@@ -1210,15 +1242,20 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
|
|
|
if (backup_cred(cifs_sb))
|
|
|
create_options |= CREATE_OPEN_BACKUP_INTENT;
|
|
|
|
|
|
- rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, create_options,
|
|
|
- &fid, &oplock, NULL, cifs_sb->local_nls,
|
|
|
- cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
|
|
+ if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
|
|
|
+ access_flags = WRITE_OWNER;
|
|
|
+ else
|
|
|
+ access_flags = WRITE_DAC;
|
|
|
+
|
|
|
+ rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
|
|
|
+ create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
|
|
|
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
|
|
if (rc) {
|
|
|
cERROR(1, "Unable to open file to set ACL");
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
|
|
|
+ rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
|
|
|
cFYI(DBG2, "SetCIFSACL rc = %d", rc);
|
|
|
|
|
|
CIFSSMBClose(xid, tcon, fid);
|
|
@@ -1228,17 +1265,6 @@ out:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-/* Set an ACL on the server */
|
|
|
-int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
|
|
- struct inode *inode, const char *path)
|
|
|
-{
|
|
|
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
|
|
-
|
|
|
- cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
|
|
|
-
|
|
|
- return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
|
|
|
-}
|
|
|
-
|
|
|
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
|
|
|
int
|
|
|
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
|
@@ -1270,9 +1296,12 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
|
|
}
|
|
|
|
|
|
/* Convert mode bits to an ACL so we can update the ACL on the server */
|
|
|
-int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
|
|
|
+int
|
|
|
+id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
|
|
|
+ uid_t uid, gid_t gid)
|
|
|
{
|
|
|
int rc = 0;
|
|
|
+ int aclflag = CIFS_ACL_DACL; /* default flag to set */
|
|
|
__u32 secdesclen = 0;
|
|
|
struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
|
|
|
struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
|
|
@@ -1302,13 +1331,15 @@ int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
- rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
|
|
|
+ rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
|
|
|
+ &aclflag);
|
|
|
|
|
|
cFYI(DBG2, "build_sec_desc rc: %d", rc);
|
|
|
|
|
|
if (!rc) {
|
|
|
/* Set the security descriptor */
|
|
|
- rc = set_cifs_acl(pnntsd, secdesclen, inode, path);
|
|
|
+ rc = set_cifs_acl(pnntsd, secdesclen, inode,
|
|
|
+ path, aclflag);
|
|
|
cFYI(DBG2, "set_cifs_acl rc: %d", rc);
|
|
|
}
|
|
|
|