aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/cifsacl.c
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2007-12-31 02:47:21 -0500
committerSteve French <sfrench@us.ibm.com>2007-12-31 02:47:21 -0500
commit97837582bc1e191d2792af74c1f3762ed01243b9 (patch)
treec472591913d02cc4fb107815c53221044fdc9a6c /fs/cifs/cifsacl.c
parent28c5a02a11f70bb1fd8dd3b633206e2db3220308 (diff)
[CIFS] Allow setting mode via cifs acl
Requires cifsacl mount flag to be on and CIFS_EXPERIMENTAL enabled CC: Shirish Pargaonkar <shirishp@us.ibm.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/cifsacl.c')
-rw-r--r--fs/cifs/cifsacl.c240
1 files changed, 232 insertions, 8 deletions
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index c312adcba4fc..a7035bd18e4e 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -129,6 +129,54 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
129 return (1); /* sids compare/match */ 129 return (1); /* sids compare/match */
130} 130}
131 131
132
133/* copy ntsd, owner sid, and group sid from a security descriptor to another */
134static void copy_sec_desc(const struct cifs_ntsd *pntsd,
135 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
136{
137 int i;
138
139 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
140 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
141
142 /* copy security descriptor control portion */
143 pnntsd->revision = pntsd->revision;
144 pnntsd->type = pntsd->type;
145 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
146 pnntsd->sacloffset = 0;
147 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
148 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
149
150 /* copy owner sid */
151 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
152 le32_to_cpu(pntsd->osidoffset));
153 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
154
155 nowner_sid_ptr->revision = owner_sid_ptr->revision;
156 nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
157 for (i = 0; i < 6; i++)
158 nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
159 for (i = 0; i < 5; i++)
160 nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
161
162 /* copy group sid */
163 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
164 le32_to_cpu(pntsd->gsidoffset));
165 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
166 sizeof(struct cifs_sid));
167
168 ngroup_sid_ptr->revision = group_sid_ptr->revision;
169 ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
170 for (i = 0; i < 6; i++)
171 ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
172 for (i = 0; i < 5; i++)
173 ngroup_sid_ptr->sub_auth[i] =
174 cpu_to_le32(group_sid_ptr->sub_auth[i]);
175
176 return;
177}
178
179
132/* 180/*
133 change posix mode to reflect permissions 181 change posix mode to reflect permissions
134 pmode is the existing mode (we only want to overwrite part of this 182 pmode is the existing mode (we only want to overwrite part of this
@@ -220,6 +268,33 @@ static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
220 return; 268 return;
221} 269}
222 270
271static __le16 fill_ace_for_sid(struct cifs_ace *pntace,
272 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
273{
274 int i;
275 __u16 size = 0;
276 __u32 access_req = 0;
277
278 pntace->type = ACCESS_ALLOWED;
279 pntace->flags = 0x0;
280 mode_to_access_flags(nmode, bits, &access_req);
281 if (!access_req)
282 access_req = SET_MINIMUM_RIGHTS;
283 pntace->access_req = cpu_to_le32(access_req);
284
285 pntace->sid.revision = psid->revision;
286 pntace->sid.num_subauth = psid->num_subauth;
287 for (i = 0; i < 6; i++)
288 pntace->sid.authority[i] = psid->authority[i];
289 for (i = 0; i < psid->num_subauth; i++)
290 pntace->sid.sub_auth[i] = psid->sub_auth[i];
291
292 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
293 pntace->size = cpu_to_le16(size);
294
295 return (size);
296}
297
223 298
224#ifdef CONFIG_CIFS_DEBUG2 299#ifdef CONFIG_CIFS_DEBUG2
225static void dump_ace(struct cifs_ace *pace, char *end_of_acl) 300static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
@@ -243,7 +318,7 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
243 int i; 318 int i;
244 cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d", 319 cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d",
245 pace->sid.revision, pace->sid.num_subauth, pace->type, 320 pace->sid.revision, pace->sid.num_subauth, pace->type,
246 pace->flags, pace->size)); 321 pace->flags, le16_to_cpu(pace->size)));
247 for (i = 0; i < num_subauth; ++i) { 322 for (i = 0; i < num_subauth; ++i) {
248 cFYI(1, ("ACE sub_auth[%d]: 0x%x", i, 323 cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
249 le32_to_cpu(pace->sid.sub_auth[i]))); 324 le32_to_cpu(pace->sid.sub_auth[i])));
@@ -346,6 +421,28 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
346} 421}
347 422
348 423
424static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
425 struct cifs_sid *pgrpsid, __u64 nmode)
426{
427 __le16 size = 0;
428 struct cifs_acl *pnndacl;
429
430 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
431
432 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
433 pownersid, nmode, S_IRWXU);
434 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
435 pgrpsid, nmode, S_IRWXG);
436 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
437 &sid_everyone, nmode, S_IRWXO);
438
439 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
440 pndacl->num_aces = 3;
441
442 return (0);
443}
444
445
349static int parse_sid(struct cifs_sid *psid, char *end_of_acl) 446static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
350{ 447{
351 /* BB need to add parm so we can store the SID BB */ 448 /* BB need to add parm so we can store the SID BB */
@@ -432,6 +529,46 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
432} 529}
433 530
434 531
532/* Convert permission bits from mode to equivalent CIFS ACL */
533static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
534 int acl_len, struct inode *inode, __u64 nmode)
535{
536 int rc = 0;
537 __u32 dacloffset;
538 __u32 ndacloffset;
539 __u32 sidsoffset;
540 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
541 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
542 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
543
544 if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
545 return (-EIO);
546
547 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
548 le32_to_cpu(pntsd->osidoffset));
549 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
550 le32_to_cpu(pntsd->gsidoffset));
551
552 dacloffset = le32_to_cpu(pntsd->dacloffset);
553 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
554
555 ndacloffset = sizeof(struct cifs_ntsd);
556 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
557 ndacl_ptr->revision = dacl_ptr->revision;
558 ndacl_ptr->size = 0;
559 ndacl_ptr->num_aces = 0;
560
561 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
562
563 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
564
565 /* copy security descriptor control portion and owner and group sid */
566 copy_sec_desc(pntsd, pnntsd, sidsoffset);
567
568 return (rc);
569}
570
571
435/* Retrieve an ACL from the server */ 572/* Retrieve an ACL from the server */
436static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, 573static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
437 const char *path) 574 const char *path)
@@ -487,6 +624,64 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
487 return pntsd; 624 return pntsd;
488} 625}
489 626
627/* Set an ACL on the server */
628static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
629 struct inode *inode, const char *path)
630{
631 struct cifsFileInfo *open_file;
632 int unlock_file = FALSE;
633 int xid;
634 int rc = -EIO;
635 __u16 fid;
636 struct super_block *sb;
637 struct cifs_sb_info *cifs_sb;
638
639#ifdef CONFIG_CIFS_DEBUG2
640 cFYI(1, ("set ACL for %s from mode 0x%x", path, inode->i_mode));
641#endif
642
643 if (!inode)
644 return (rc);
645
646 sb = inode->i_sb;
647 if (sb == NULL)
648 return (rc);
649
650 cifs_sb = CIFS_SB(sb);
651 xid = GetXid();
652
653 open_file = find_readable_file(CIFS_I(inode));
654 if (open_file) {
655 unlock_file = TRUE;
656 fid = open_file->netfid;
657 } else {
658 int oplock = FALSE;
659 /* open file */
660 rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
661 WRITE_DAC, 0, &fid, &oplock, NULL,
662 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
663 CIFS_MOUNT_MAP_SPECIAL_CHR);
664 if (rc != 0) {
665 cERROR(1, ("Unable to open file to set ACL"));
666 FreeXid(xid);
667 return (rc);
668 }
669 }
670
671 rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
672#ifdef CONFIG_CIFS_DEBUG2
673 cFYI(1, ("SetCIFSACL rc = %d", rc));
674#endif
675 if (unlock_file == TRUE)
676 atomic_dec(&open_file->wrtPending);
677 else
678 CIFSSMBClose(xid, cifs_sb->tcon, fid);
679
680 FreeXid(xid);
681
682 return (rc);
683}
684
490/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ 685/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
491void acl_to_uid_mode(struct inode *inode, const char *path) 686void acl_to_uid_mode(struct inode *inode, const char *path)
492{ 687{
@@ -510,24 +705,53 @@ void acl_to_uid_mode(struct inode *inode, const char *path)
510} 705}
511 706
512/* Convert mode bits to an ACL so we can update the ACL on the server */ 707/* Convert mode bits to an ACL so we can update the ACL on the server */
513int mode_to_acl(struct inode *inode, const char *path) 708int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
514{ 709{
515 int rc = 0; 710 int rc = 0;
516 __u32 acllen = 0; 711 __u32 acllen = 0;
517 struct cifs_ntsd *pntsd = NULL; 712 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
713 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
518 714
715#ifdef CONFIG_CIFS_DEBUG2
519 cFYI(1, ("set ACL from mode for %s", path)); 716 cFYI(1, ("set ACL from mode for %s", path));
717#endif
520 718
521 /* Get the security descriptor */ 719 /* Get the security descriptor */
522 pntsd = get_cifs_acl(&acllen, inode, path); 720 pntsd = get_cifs_acl(&acllen, inode, path);
523 721
524 /* Add/Modify the three ACEs for owner, group, everyone 722 /* Add three ACEs for owner, group, everyone getting rid of
525 while retaining the other ACEs */ 723 other ACEs as chmod disables ACEs and set the security descriptor */
526 724
527 /* Set the security descriptor */ 725 if (pntsd) {
726 /* allocate memory for the smb header,
727 set security descriptor request security descriptor
728 parameters, and secuirty descriptor itself */
528 729
730 pnntsd = kmalloc(acllen, GFP_KERNEL);
731 if (!pnntsd) {
732 cERROR(1, ("Unable to allocate security descriptor"));
733 kfree(pntsd);
734 return (-ENOMEM);
735 }
529 736
530 kfree(pntsd); 737 rc = build_sec_desc(pntsd, pnntsd, acllen, inode, nmode);
531 return rc; 738
739#ifdef CONFIG_CIFS_DEBUG2
740 cFYI(1, ("build_sec_desc rc: %d", rc));
741#endif
742
743 if (!rc) {
744 /* Set the security descriptor */
745 rc = set_cifs_acl(pnntsd, acllen, inode, path);
746#ifdef CONFIG_CIFS_DEBUG2
747 cFYI(1, ("set_cifs_acl rc: %d", rc));
748#endif
749 }
750
751 kfree(pnntsd);
752 kfree(pntsd);
753 }
754
755 return (rc);
532} 756}
533#endif /* CONFIG_CIFS_EXPERIMENTAL */ 757#endif /* CONFIG_CIFS_EXPERIMENTAL */