aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsacl.c135
-rw-r--r--fs/cifs/cifsproto.h7
-rw-r--r--fs/cifs/cifssmb.c4
-rw-r--r--fs/cifs/inode.c35
-rw-r--r--fs/cifs/xattr.c2
5 files changed, 113 insertions, 70 deletions
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 992f1fb299d1..72ddf23ef6f7 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -904,7 +904,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
904 acl_size = sizeof(struct cifs_acl); 904 acl_size = sizeof(struct cifs_acl);
905 905
906 num_aces = le32_to_cpu(pdacl->num_aces); 906 num_aces = le32_to_cpu(pdacl->num_aces);
907 if (num_aces > 0) { 907 if (num_aces > 0) {
908 umode_t user_mask = S_IRWXU; 908 umode_t user_mask = S_IRWXU;
909 umode_t group_mask = S_IRWXG; 909 umode_t group_mask = S_IRWXG;
910 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO; 910 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,
1066 else 1066 else
1067 cFYI(1, "no ACL"); /* BB grant all or default perms? */ 1067 cFYI(1, "no ACL"); /* BB grant all or default perms? */
1068 1068
1069/* cifscred->uid = owner_sid_ptr->rid;
1070 cifscred->gid = group_sid_ptr->rid;
1071 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
1072 sizeof(struct cifs_sid));
1073 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
1074 sizeof(struct cifs_sid)); */
1075
1076 return rc; 1069 return rc;
1077} 1070}
1078 1071
1079
1080/* Convert permission bits from mode to equivalent CIFS ACL */ 1072/* Convert permission bits from mode to equivalent CIFS ACL */
1081static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, 1073static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
1082 struct inode *inode, __u64 nmode) 1074 __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
1083{ 1075{
1084 int rc = 0; 1076 int rc = 0;
1085 __u32 dacloffset; 1077 __u32 dacloffset;
1086 __u32 ndacloffset; 1078 __u32 ndacloffset;
1087 __u32 sidsoffset; 1079 __u32 sidsoffset;
1088 struct cifs_sid *owner_sid_ptr, *group_sid_ptr; 1080 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
1081 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
1089 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */ 1082 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
1090 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */ 1083 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
1091 1084
1092 if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL)) 1085 if (nmode != NO_CHANGE_64) { /* chmod */
1093 return -EIO; 1086 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
1094
1095 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
1096 le32_to_cpu(pntsd->osidoffset)); 1087 le32_to_cpu(pntsd->osidoffset));
1097 group_sid_ptr = (struct cifs_sid *)((char *)pntsd + 1088 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
1098 le32_to_cpu(pntsd->gsidoffset)); 1089 le32_to_cpu(pntsd->gsidoffset));
1099 1090 dacloffset = le32_to_cpu(pntsd->dacloffset);
1100 dacloffset = le32_to_cpu(pntsd->dacloffset); 1091 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
1101 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset); 1092 ndacloffset = sizeof(struct cifs_ntsd);
1102 1093 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
1103 ndacloffset = sizeof(struct cifs_ntsd); 1094 ndacl_ptr->revision = dacl_ptr->revision;
1104 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset); 1095 ndacl_ptr->size = 0;
1105 ndacl_ptr->revision = dacl_ptr->revision; 1096 ndacl_ptr->num_aces = 0;
1106 ndacl_ptr->size = 0; 1097
1107 ndacl_ptr->num_aces = 0; 1098 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
1108 1099 nmode);
1109 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode); 1100 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
1110 1101 /* copy sec desc control portion & owner and group sids */
1111 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size); 1102 copy_sec_desc(pntsd, pnntsd, sidsoffset);
1112 1103 *aclflag = CIFS_ACL_DACL;
1113 /* copy security descriptor control portion and owner and group sid */ 1104 } else {
1114 copy_sec_desc(pntsd, pnntsd, sidsoffset); 1105 memcpy(pnntsd, pntsd, secdesclen);
1106 if (uid != NO_CHANGE_32) { /* chown */
1107 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1108 le32_to_cpu(pnntsd->osidoffset));
1109 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1110 GFP_KERNEL);
1111 if (!nowner_sid_ptr)
1112 return -ENOMEM;
1113 rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
1114 if (rc) {
1115 cFYI(1, "%s: Mapping error %d for owner id %d",
1116 __func__, rc, uid);
1117 kfree(nowner_sid_ptr);
1118 return rc;
1119 }
1120 memcpy(owner_sid_ptr, nowner_sid_ptr,
1121 sizeof(struct cifs_sid));
1122 kfree(nowner_sid_ptr);
1123 *aclflag = CIFS_ACL_OWNER;
1124 }
1125 if (gid != NO_CHANGE_32) { /* chgrp */
1126 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1127 le32_to_cpu(pnntsd->gsidoffset));
1128 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1129 GFP_KERNEL);
1130 if (!ngroup_sid_ptr)
1131 return -ENOMEM;
1132 rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
1133 if (rc) {
1134 cFYI(1, "%s: Mapping error %d for group id %d",
1135 __func__, rc, gid);
1136 kfree(ngroup_sid_ptr);
1137 return rc;
1138 }
1139 memcpy(group_sid_ptr, ngroup_sid_ptr,
1140 sizeof(struct cifs_sid));
1141 kfree(ngroup_sid_ptr);
1142 *aclflag = CIFS_ACL_GROUP;
1143 }
1144 }
1115 1145
1116 return rc; 1146 return rc;
1117} 1147}
@@ -1192,13 +1222,15 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
1192 return pntsd; 1222 return pntsd;
1193} 1223}
1194 1224
1195static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, 1225 /* Set an ACL on the server */
1196 struct cifs_ntsd *pnntsd, u32 acllen) 1226int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1227 struct inode *inode, const char *path, int aclflag)
1197{ 1228{
1198 int oplock = 0; 1229 int oplock = 0;
1199 int xid, rc, create_options = 0; 1230 int xid, rc, access_flags, create_options = 0;
1200 __u16 fid; 1231 __u16 fid;
1201 struct cifs_tcon *tcon; 1232 struct cifs_tcon *tcon;
1233 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1202 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); 1234 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1203 1235
1204 if (IS_ERR(tlink)) 1236 if (IS_ERR(tlink))
@@ -1210,15 +1242,20 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
1210 if (backup_cred(cifs_sb)) 1242 if (backup_cred(cifs_sb))
1211 create_options |= CREATE_OPEN_BACKUP_INTENT; 1243 create_options |= CREATE_OPEN_BACKUP_INTENT;
1212 1244
1213 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, create_options, 1245 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1214 &fid, &oplock, NULL, cifs_sb->local_nls, 1246 access_flags = WRITE_OWNER;
1215 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 1247 else
1248 access_flags = WRITE_DAC;
1249
1250 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
1251 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
1252 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
1216 if (rc) { 1253 if (rc) {
1217 cERROR(1, "Unable to open file to set ACL"); 1254 cERROR(1, "Unable to open file to set ACL");
1218 goto out; 1255 goto out;
1219 } 1256 }
1220 1257
1221 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen); 1258 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
1222 cFYI(DBG2, "SetCIFSACL rc = %d", rc); 1259 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
1223 1260
1224 CIFSSMBClose(xid, tcon, fid); 1261 CIFSSMBClose(xid, tcon, fid);
@@ -1228,17 +1265,6 @@ out:
1228 return rc; 1265 return rc;
1229} 1266}
1230 1267
1231/* Set an ACL on the server */
1232int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1233 struct inode *inode, const char *path)
1234{
1235 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1236
1237 cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
1238
1239 return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
1240}
1241
1242/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ 1268/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
1243int 1269int
1244cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, 1270cifs_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,
1270} 1296}
1271 1297
1272/* Convert mode bits to an ACL so we can update the ACL on the server */ 1298/* Convert mode bits to an ACL so we can update the ACL on the server */
1273int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode) 1299int
1300id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
1301 uid_t uid, gid_t gid)
1274{ 1302{
1275 int rc = 0; 1303 int rc = 0;
1304 int aclflag = CIFS_ACL_DACL; /* default flag to set */
1276 __u32 secdesclen = 0; 1305 __u32 secdesclen = 0;
1277 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */ 1306 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1278 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */ 1307 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)
1302 return -ENOMEM; 1331 return -ENOMEM;
1303 } 1332 }
1304 1333
1305 rc = build_sec_desc(pntsd, pnntsd, inode, nmode); 1334 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1335 &aclflag);
1306 1336
1307 cFYI(DBG2, "build_sec_desc rc: %d", rc); 1337 cFYI(DBG2, "build_sec_desc rc: %d", rc);
1308 1338
1309 if (!rc) { 1339 if (!rc) {
1310 /* Set the security descriptor */ 1340 /* Set the security descriptor */
1311 rc = set_cifs_acl(pnntsd, secdesclen, inode, path); 1341 rc = set_cifs_acl(pnntsd, secdesclen, inode,
1342 path, aclflag);
1312 cFYI(DBG2, "set_cifs_acl rc: %d", rc); 1343 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
1313 } 1344 }
1314 1345
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 94834dbb46da..a1fa9cec05d6 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -146,11 +146,12 @@ extern int cifs_get_inode_info_unix(struct inode **pinode,
146extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, 146extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
147 struct cifs_fattr *fattr, struct inode *inode, 147 struct cifs_fattr *fattr, struct inode *inode,
148 const char *path, const __u16 *pfid); 148 const char *path, const __u16 *pfid);
149extern int mode_to_cifs_acl(struct inode *inode, const char *path, __u64); 149extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64,
150 uid_t, gid_t);
150extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, 151extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
151 const char *, u32 *); 152 const char *, u32 *);
152extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, 153extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
153 const char *); 154 const char *, int);
154 155
155extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, 156extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
156 struct cifs_sb_info *cifs_sb); 157 struct cifs_sb_info *cifs_sb);
@@ -420,7 +421,7 @@ extern int CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon,
420extern int CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, 421extern int CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon,
421 __u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen); 422 __u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
422extern int CIFSSMBSetCIFSACL(const int, struct cifs_tcon *, __u16, 423extern int CIFSSMBSetCIFSACL(const int, struct cifs_tcon *, __u16,
423 struct cifs_ntsd *, __u32); 424 struct cifs_ntsd *, __u32, int);
424extern int CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon, 425extern int CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
425 const unsigned char *searchName, 426 const unsigned char *searchName,
426 char *acl_inf, const int buflen, const int acl_type, 427 char *acl_inf, const int buflen, const int acl_type,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index e33093f7ef0d..c824c106b2b7 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3463,7 +3463,7 @@ qsec_out:
3463 3463
3464int 3464int
3465CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid, 3465CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
3466 struct cifs_ntsd *pntsd, __u32 acllen) 3466 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
3467{ 3467{
3468 __u16 byte_count, param_count, data_count, param_offset, data_offset; 3468 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3469 int rc = 0; 3469 int rc = 0;
@@ -3500,7 +3500,7 @@ setCifsAclRetry:
3500 3500
3501 pSMB->Fid = fid; /* file handle always le */ 3501 pSMB->Fid = fid; /* file handle always le */
3502 pSMB->Reserved2 = 0; 3502 pSMB->Reserved2 = 0;
3503 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL); 3503 pSMB->AclFlags = cpu_to_le32(aclflag);
3504 3504
3505 if (pntsd && acllen) { 3505 if (pntsd && acllen) {
3506 memcpy((char *) &pSMBr->hdr.Protocol + data_offset, 3506 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index a7b2dcd4a53e..663c4e313be4 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -2096,6 +2096,8 @@ static int
2096cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) 2096cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
2097{ 2097{
2098 int xid; 2098 int xid;
2099 uid_t uid = NO_CHANGE_32;
2100 gid_t gid = NO_CHANGE_32;
2099 struct inode *inode = direntry->d_inode; 2101 struct inode *inode = direntry->d_inode;
2100 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 2102 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
2101 struct cifsInodeInfo *cifsInode = CIFS_I(inode); 2103 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
@@ -2146,13 +2148,25 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
2146 goto cifs_setattr_exit; 2148 goto cifs_setattr_exit;
2147 } 2149 }
2148 2150
2149 /* 2151 if (attrs->ia_valid & ATTR_UID)
2150 * Without unix extensions we can't send ownership changes to the 2152 uid = attrs->ia_uid;
2151 * server, so silently ignore them. This is consistent with how 2153
2152 * local DOS/Windows filesystems behave (VFAT, NTFS, etc). With 2154 if (attrs->ia_valid & ATTR_GID)
2153 * CIFSACL support + proper Windows to Unix idmapping, we may be 2155 gid = attrs->ia_gid;
2154 * able to support this in the future. 2156
2155 */ 2157#ifdef CONFIG_CIFS_ACL
2158 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
2159 if (uid != NO_CHANGE_32 || gid != NO_CHANGE_32) {
2160 rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64,
2161 uid, gid);
2162 if (rc) {
2163 cFYI(1, "%s: Setting id failed with error: %d",
2164 __func__, rc);
2165 goto cifs_setattr_exit;
2166 }
2167 }
2168 } else
2169#endif /* CONFIG_CIFS_ACL */
2156 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) 2170 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
2157 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); 2171 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
2158 2172
@@ -2161,15 +2175,12 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
2161 attrs->ia_valid &= ~ATTR_MODE; 2175 attrs->ia_valid &= ~ATTR_MODE;
2162 2176
2163 if (attrs->ia_valid & ATTR_MODE) { 2177 if (attrs->ia_valid & ATTR_MODE) {
2164 cFYI(1, "Mode changed to 0%o", attrs->ia_mode);
2165 mode = attrs->ia_mode; 2178 mode = attrs->ia_mode;
2166 }
2167
2168 if (attrs->ia_valid & ATTR_MODE) {
2169 rc = 0; 2179 rc = 0;
2170#ifdef CONFIG_CIFS_ACL 2180#ifdef CONFIG_CIFS_ACL
2171 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { 2181 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
2172 rc = mode_to_cifs_acl(inode, full_path, mode); 2182 rc = id_mode_to_cifs_acl(inode, full_path, mode,
2183 NO_CHANGE_32, NO_CHANGE_32);
2173 if (rc) { 2184 if (rc) {
2174 cFYI(1, "%s: Setting ACL failed with error: %d", 2185 cFYI(1, "%s: Setting ACL failed with error: %d",
2175 __func__, rc); 2186 __func__, rc);
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 2a22fb2989e4..fde15b1a1eb5 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -178,7 +178,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
178#ifdef CONFIG_CIFS_ACL 178#ifdef CONFIG_CIFS_ACL
179 memcpy(pacl, ea_value, value_size); 179 memcpy(pacl, ea_value, value_size);
180 rc = set_cifs_acl(pacl, value_size, 180 rc = set_cifs_acl(pacl, value_size,
181 direntry->d_inode, full_path); 181 direntry->d_inode, full_path, CIFS_ACL_DACL);
182 if (rc == 0) /* force revalidate of the inode */ 182 if (rc == 0) /* force revalidate of the inode */
183 CIFS_I(direntry->d_inode)->time = 0; 183 CIFS_I(direntry->d_inode)->time = 0;
184 kfree(pacl); 184 kfree(pacl);