]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/acl/UserData.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / acl / UserData.cc
index 638f05e72b87df1230add4faa1934a3992b42f4d..13c639b64a94d5ef7962e5c443c941aa461684ac 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
 #include "acl/UserData.h"
 #include "ConfigParser.h"
 #include "Debug.h"
+#include "globals.h"
+#include "sbuf/Algorithms.h"
 #include "util.h"
 
-template<class T>
-inline void
-xRefFree(T &thing)
+const Acl::ParameterFlags &
+ACLUserData::supportedFlags() const
 {
-    xfree (thing);
-}
-
-ACLUserData::~ACLUserData()
-{
-    if (names)
-        names->destroy(xRefFree);
-}
-
-static int
-splaystrcasecmp (char * const &l, char * const &r)
-{
-    return strcasecmp ((char *)l,(char *)r);
-}
-
-static int
-splaystrcmp (char * const &l, char * const &r)
-{
-    return strcmp ((char *)l,(char *)r);
+    static const Acl::ParameterFlags flagNames = { "-i", "+i" };
+    return flagNames;
 }
 
 bool
 ACLUserData::match(char const *user)
 {
-    debugs(28, 7, "aclMatchUser: user is " << user << ", case_insensitive is " << flags.case_insensitive);
+    debugs(28, 7, "user is " << user << ", case_insensitive is " << flags.case_insensitive);
 
     if (user == NULL || strcmp(user, "-") == 0)
         return 0;
@@ -53,98 +37,117 @@ ACLUserData::match(char const *user)
         return 1;
     }
 
-    char * const *result;
-
-    if (flags.case_insensitive)
-        result = names->find(const_cast<char *>(user), splaystrcasecmp);
-    else
-        result = names->find(const_cast<char *>(user), splaystrcmp);
-
-    /* Top=splay_splay(user,Top,(splayNode::SPLAYCMP *)dumping_strcmp); */
-    debugs(28, 7, "aclMatchUser: returning " << (result != NULL));
-
-    return (result != NULL);
+    bool result = (userDataNames.find(SBuf(user)) != userDataNames.end());
+    debugs(28, 7, "returning " << result);
+    return result;
 }
 
-struct UserDataAclDumpVisitor {
-    SBufList contents;
-    void operator() (char * const & node_data) {
-       contents.push_back(SBuf(node_data));
-    }
-};
-
 SBufList
 ACLUserData::dump() const
 {
     SBufList sl;
 
-    if (flags.case_insensitive)
-        sl.push_back(SBuf("-i"));
-
-    /* damn this is VERY inefficient for long ACL lists... filling
-     * a SBufList this way costs Sum(1,N) iterations. For instance
-     * a 1000-elements list will be filled in 499500 iterations.
-     */
     if (flags.required) {
         sl.push_back(SBuf("REQUIRED"));
-    } else if (names) {
-        UserDataAclDumpVisitor visitor;
-        names->visit(visitor);
-        sl.splice(sl.end(),visitor.contents);
+        return sl;
     }
 
+    if (flags.case_insensitive)
+        sl.push_back(SBuf("-i"));
+
+    sl.insert(sl.end(), userDataNames.begin(), userDataNames.end());
+
+    debugs(28,5, "ACLUserData dump output: " <<
+           JoinContainerToSBuf(userDataNames.begin(), userDataNames.end(),
+                               SBuf(" ")));
     return sl;
 }
 
+static bool
+CaseSensitiveSBufCompare(const SBuf &lhs, const SBuf &rhs)
+{
+    return (lhs.cmp(rhs) < 0);
+}
+
+static bool
+CaseInsensitveSBufCompare(const SBuf &lhs, const SBuf &rhs)
+{
+    return (lhs.caseCmp(rhs) < 0);
+}
+
+ACLUserData::ACLUserData() :
+    userDataNames(CaseSensitiveSBufCompare)
+{
+    flags.case_insensitive = false;
+    flags.required = false;
+}
+
 void
 ACLUserData::parse()
 {
-    debugs(28, 2, "aclParseUserList: parsing user list");
-    char *t = NULL;
+    debugs(28, 2, "parsing user list");
 
+    char *t = NULL;
     if ((t = ConfigParser::strtokFile())) {
-        debugs(28, 5, "aclParseUserList: First token is " << t);
+        SBuf s(t);
+        debugs(28, 5, "first token is " << s);
 
-        if (strcmp("-i", t) == 0) {
-            debugs(28, 5, "aclParseUserList: Going case-insensitive");
+        if (s.cmp("-i",2) == 0) {
+            debugs(28, 5, "Going case-insensitive");
             flags.case_insensitive = true;
-        } else if (strcmp("REQUIRED", t) == 0) {
-            debugs(28, 5, "aclParseUserList: REQUIRED-type enabled");
+            // due to how the std::set API work, if we want to change
+            // the comparison function we have to create a new std::set
+            UserDataNames_t newUdn(CaseInsensitveSBufCompare);
+            newUdn.insert(userDataNames.begin(), userDataNames.end());
+            swap(userDataNames,newUdn);
+        } else if (s.cmp("REQUIRED") == 0) {
+            debugs(28, 5, "REQUIRED-type enabled");
             flags.required = true;
         } else {
             if (flags.case_insensitive)
-                Tolower(t);
+                s.toLower();
 
-            names->insert(xstrdup(t), splaystrcmp);
+            debugs(28, 6, "Adding user " << s);
+            userDataNames.insert(s);
         }
     }
 
-    debugs(28, 3, "aclParseUserList: Case-insensitive-switch is " << flags.case_insensitive);
+    debugs(28, 3, "Case-insensitive-switch is " << flags.case_insensitive);
     /* we might inherit from a previous declaration */
 
-    debugs(28, 4, "aclParseUserList: parsing user list");
+    debugs(28, 4, "parsing following tokens");
 
     while ((t = ConfigParser::strtokFile())) {
-        debugs(28, 6, "aclParseUserList: Got token: " << t);
+        SBuf s(t);
+        debugs(28, 6, "Got token: " << s);
 
         if (flags.case_insensitive)
-            Tolower(t);
+            s.toLower();
+
+        debugs(28, 6, "Adding user " << s);
+        userDataNames.insert(s);
+    }
 
-        names->insert(xstrdup(t), splaystrcmp);
+    if (flags.required && !userDataNames.empty()) {
+        debugs(28, DBG_PARSE_NOTE(1), "WARNING: detected attempt to add usernames to an acl of type REQUIRED");
+        userDataNames.clear();
     }
+
+    debugs(28,4, "ACL contains " << userDataNames.size() << " users");
 }
 
 bool
 ACLUserData::empty() const
 {
-    return names->empty() && !flags.required;
+    debugs(28,6,"required: " << flags.required << ", number of users: " << userDataNames.size());
+    if (flags.required)
+        return false;
+    return userDataNames.empty();
 }
 
 ACLData<char const *> *
 ACLUserData::clone() const
 {
-    /* Splay trees don't clone yet. */
-    assert (!names);
     return new ACLUserData;
 }