diff options
Diffstat (limited to 'fs/cifs/cifsacl.c')
-rw-r--r-- | fs/cifs/cifsacl.c | 135 |
1 files changed, 83 insertions, 52 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 */ |
1081 | static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, | 1073 | static 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 | ||
1195 | static 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) | 1226 | int 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 */ | ||
1232 | int 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 */ |
1243 | int | 1269 | int |
1244 | cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, | 1270 | 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, | |||
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 */ |
1273 | int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode) | 1299 | int |
1300 | id_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 | ||