/*
- * 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);
- delete names;
- }
-}
-
-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;
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 || 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;
}