[CIFS] CIFS ACL support part 3
Steve French [Fri, 12 Oct 2007 04:11:59 +0000 (04:11 +0000)]
Signed-off-by: Shirish Pargaonkar <shirishp@us.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>

fs/cifs/CHANGES
fs/cifs/cifsacl.c
fs/cifs/cifsacl.h
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifssmb.c
fs/cifs/export.c

index c8ad87d..13071fa 100644 (file)
@@ -6,7 +6,10 @@ which support the current POSIX Extensions to provide better semantics
 (e.g. delete for open files opened with posix open).  Take into
 account umask on posix mkdir not just older style mkdir.  Add
 ability to mount to IPC$ share (which allows CIFS named pipes to be
-opened, read and written as if they were files).
+opened, read and written as if they were files).  When 1st tree
+connect fails (e.g. due to signing negotiation failure) fix
+leak that causes cifsd not to stop and rmmod to fail to cleanup
+cifs_request_buffers pool.
 
 Version 1.50
 ------------
index 52f9cb8..43ab26f 100644 (file)
 #include "cifsproto.h"
 #include "cifs_debug.h"
 
+
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+
+struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
+       {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"},
+       {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"},
+       {{1, 1, {0, 0, 0, 0, 0, 5}, {11, 0, 0, 0, 0} }, "net-users"},
+       {{1, 1, {0, 0, 0, 0, 0, 5}, {18, 0, 0, 0, 0} }, "sys"},
+       {{1, 2, {0, 0, 0, 0, 0, 5}, {32, 544, 0, 0, 0} }, "root"},
+       {{1, 2, {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0, 0} }, "users"},
+       {{1, 2, {0, 0, 0, 0, 0, 5}, {32, 546, 0, 0, 0} }, "guest"}
+};
+
+
 /* security id for everyone */
 static const struct cifs_sid sid_everyone =
                {1, 1, {0, 0, 0, 0, 0, 0}, {} };
@@ -35,33 +49,113 @@ static const struct cifs_sid sid_everyone =
 static const struct cifs_sid sid_user =
                {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
 
+
+int match_sid(struct cifs_sid *ctsid)
+{
+       int i, j;
+       int num_subauth, num_sat, num_saw;
+       struct cifs_sid *cwsid;
+
+       if (!ctsid)
+               return (-1);
+
+       for (i = 0; i < NUM_WK_SIDS; ++i) {
+               cwsid = &(wksidarr[i].cifssid);
+
+               /* compare the revision */
+               if (ctsid->revision != cwsid->revision)
+                       continue;
+
+               /* compare all of the six auth values */
+               for (j = 0; j < 6; ++j) {
+                       if (ctsid->authority[j] != cwsid->authority[j])
+                               break;
+               }
+               if (j < 6)
+                       continue; /* all of the auth values did not match */
+
+               /* compare all of the subauth values if any */
+               num_sat = cpu_to_le32(ctsid->num_subauth);
+               num_saw = cpu_to_le32(cwsid->num_subauth);
+               num_subauth = num_sat < num_saw ? num_sat : num_saw;
+               if (num_subauth) {
+                       for (j = 0; j < num_subauth; ++j) {
+                               if (ctsid->sub_auth[j] != cwsid->sub_auth[j])
+                                       break;
+                       }
+                       if (j < num_subauth)
+                               continue; /* all sub_auth values do not match */
+               }
+
+               cFYI(1, ("matching sid: %s\n", wksidarr[i].sidname));
+               return (0); /* sids compare/match */
+       }
+
+       cFYI(1, ("No matching sid"));
+       return (-1);
+}
+
+
+int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid)
+{
+       int i;
+       int num_subauth, num_sat, num_saw;
+
+       if ((!ctsid) || (!cwsid))
+               return (-1);
+
+       /* compare the revision */
+       if (ctsid->revision != cwsid->revision)
+               return (-1);
+
+       /* compare all of the six auth values */
+       for (i = 0; i < 6; ++i) {
+               if (ctsid->authority[i] != cwsid->authority[i])
+                       return (-1);
+       }
+
+       /* compare all of the subauth values if any */
+       num_sat = cpu_to_le32(ctsid->num_subauth);
+       num_saw = cpu_to_le32(cwsid->num_subauth);
+       num_subauth = num_sat < num_saw ? num_sat : num_saw;
+       if (num_subauth) {
+               for (i = 0; i < num_subauth; ++i) {
+                       if (ctsid->sub_auth[i] != cwsid->sub_auth[i])
+                               return (-1);
+               }
+       }
+
+       return (0); /* sids compare/match */
+}
+
+
 static void parse_ace(struct cifs_ace *pace, char *end_of_acl)
 {
        int i;
        int num_subauth;
-        __u32 *psub_auth;
 
        /* validate that we do not go past end of acl */
+
+       /* XXX this if statement can be removed
        if (end_of_acl < (char *)pace + sizeof(struct cifs_ace)) {
                cERROR(1, ("ACL too small to parse ACE"));
                return;
-       }
+       } */
 
        num_subauth = cpu_to_le32(pace->num_subauth);
        if (num_subauth) {
-               psub_auth = (__u32 *)((char *)pace + sizeof(struct cifs_ace));
 #ifdef CONFIG_CIFS_DEBUG2
                cFYI(1, ("ACE revision %d num_subauth %d",
                        pace->revision, pace->num_subauth));
                for (i = 0; i < num_subauth; ++i) {
                        cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
-                               le32_to_cpu(psub_auth[i])));
+                               le32_to_cpu(pace->sub_auth[i])));
                }
 
                /* BB add length check to make sure that we do not have huge
                        num auths and therefore go off the end */
 
-               cFYI(1, ("RID %d", le32_to_cpu(psub_auth[num_subauth-1])));
+               cFYI(1, ("RID %d", le32_to_cpu(pace->sub_auth[num_subauth-1])));
 #endif
        }
 
@@ -132,7 +226,13 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl)
                                        sizeof(struct cifs_ntace));
 
                        parse_ntace(ppntace[i], end_of_acl);
-                       parse_ace(ppace[i], end_of_acl);
+                       if (end_of_acl < ((char *)ppace[i] +
+                                       (ppntace[i]->size -
+                                       sizeof(struct cifs_ntace)))) {
+                               cERROR(1, ("ACL too small to parse ACE"));
+                               break;
+                       } else
+                               parse_ace(ppace[i], end_of_acl);
 
 /*                     memcpy((void *)(&(cifscred->ntaces[i])),
                                (void *)ppntace[i],
@@ -157,7 +257,6 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
 {
        int i;
        int num_subauth;
-       __u32 *psub_auth;
 
        /* BB need to add parm so we can store the SID BB */
 
@@ -169,20 +268,19 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
 
        num_subauth = cpu_to_le32(psid->num_subauth);
        if (num_subauth) {
-               psub_auth = (__u32 *)((char *)psid + sizeof(struct cifs_sid));
 #ifdef CONFIG_CIFS_DEBUG2
                cFYI(1, ("SID revision %d num_auth %d First subauth 0x%x",
                        psid->revision, psid->num_subauth, psid->sub_auth[0]));
 
                for (i = 0; i < num_subauth; ++i) {
                        cFYI(1, ("SID sub_auth[%d]: 0x%x ", i,
-                               le32_to_cpu(psub_auth[i])));
+                               le32_to_cpu(psid->sub_auth[i])));
                }
 
                /* BB add length check to make sure that we do not have huge
                        num auths and therefore go off the end */
                cFYI(1, ("RID 0x%x",
-                       le32_to_cpu(psid->sub_auth[psid->num_subauth])));
+                       le32_to_cpu(psid->sub_auth[num_subauth-1])));
 #endif
        }
 
@@ -228,5 +326,7 @@ int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len)
        memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
                        sizeof (struct cifs_sid)); */
 
+
        return (0);
 }
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
index bf297ea..1b11564 100644 (file)
 #ifndef _CIFSACL_H
 #define _CIFSACL_H
 
+
+#define NUM_WK_SIDS 7 /* number of well known sids */
+#define SIDNAMELENGTH 20 /* long enough for the ones we care about */
+
 struct cifs_ntsd {
        __u16 revision; /* revision level */
        __u16 type;
@@ -35,7 +39,7 @@ struct cifs_sid {
        __u8 revision; /* revision level */
        __u8 num_subauth;
        __u8 authority[6];
-       __u32 sub_auth[0]; /* sub_auth[num_subauth] */
+       __u32 sub_auth[5]; /* sub_auth[num_subauth] */
 } __attribute__((packed));
 
 struct cifs_acl {
@@ -55,12 +59,20 @@ struct cifs_ace { /* last part of ACE which includes user info */
        __u8 revision; /* revision level */
        __u8 num_subauth;
        __u8 authority[6];
-       __u32 sub_auth[0];
+       __u32 sub_auth[5];
+} __attribute__((packed));
+
+struct cifs_wksid {
+       struct cifs_sid cifssid;
+       char sidname[SIDNAMELENGTH];
 } __attribute__((packed));
 
-/* everyone */
-/* extern const struct cifs_sid sid_everyone;*/
-/* group users */
-/* extern const struct cifs_sid sid_user;*/
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+
+extern struct cifs_wksid wksidarr[NUM_WK_SIDS];
+extern int match_sid(struct cifs_sid *);
+extern int compare_sids(struct cifs_sid *, struct cifs_sid *);
+
+#endif /*  CONFIG_CIFS_EXPERIMENTAL */
 
 #endif /* _CIFSACL_H */
index c7c3521..abca6b0 100644 (file)
 static struct quotactl_ops cifs_quotactl_ops;
 #endif /* QUOTA */
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-extern struct export_operations cifs_export_ops;
-#endif /* EXPERIMENTAL */
-
 int cifsFYI = 0;
 int cifsERROR = 1;
 int traceSMB = 0;
index 13c53a4..0a3ee5a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsfs.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002, 2005
+ *   Copyright (c) International Business Machines  Corp., 2002, 2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -101,5 +101,10 @@ extern ssize_t     cifs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
 extern int cifs_ioctl(struct inode *inode, struct file *filep,
                       unsigned int command, unsigned long arg);
+
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+extern struct export_operations cifs_export_ops;
+#endif /* EXPERIMENTAL */
+
 #define CIFS_VERSION   "1.51"
 #endif                         /* _CIFSFS_H */
index fda8b24..eff3226 100644 (file)
@@ -3058,6 +3058,7 @@ GetExtAttrOut:
 
 #endif /* CONFIG_POSIX */
 
+#ifdef CONFIG_CIFS_EXPERIMENTAL
 /* Get Security Descriptor (by handle) from remote server for a file or dir */
 int
 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
@@ -3129,6 +3130,7 @@ qsec_out:
 /*     cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
        return rc;
 }
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
 
 /* Legacy Query Path Information call for lookup to old servers such
    as Win9x/WinME */
index 893fd0a..d614b91 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/exportfs.h>
 #include "cifsglob.h"
 #include "cifs_debug.h"
+#include "cifsfs.h"
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 static struct dentry *cifs_get_parent(struct dentry *dentry)