aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/cifsacl.c
diff options
context:
space:
mode:
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>2011-10-13 11:26:03 -0400
committerSteve French <smfrench@gmail.com>2011-10-17 10:11:11 -0400
commita5ff376966c079bd2f078524eff11b0c63cc2507 (patch)
treef0a6576a0987ba73589caaadc2b4fde1b24650b5 /fs/cifs/cifsacl.c
parentd59dad2be038132259ac99a2837d65a87fd90588 (diff)
cifs: Call id to SID mapping functions to change owner/group (try #4 repost)
Now build security descriptor to change either owner or group at the server. Initially security descriptor was built to change only (D)ACL, that functionality has been extended. When either an Owner or a Group of a file object at the server is changed, rest of security descriptor remains same (DACL etc.). To set security descriptor, it is necessary to open that file with permission bits of either WRITE_DAC if DACL is being modified or WRITE_OWNER (Take Ownership) if Owner or Group is being changed. It is the server that decides whether a set security descriptor with either owner or group change succeeds or not. Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/cifsacl.c')
-rw-r--r--fs/cifs/cifsacl.c135
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 */
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