/*
- * DEBUG: section 28 Access Control
- * AUTHOR: Duane Wessels
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
*
- * SQUID Web Proxy Cache http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from
- * the Internet community; see the CONTRIBUTORS file for full
- * details. Many organizations have provided support for Squid's
- * development; see the SPONSORS file for full details. Squid is
- * Copyrighted (C) 2001 by the Regents of the University of
- * California; see the COPYRIGHT file for full details. Squid
- * incorporates software developed and/or copyrighted by other
- * sources; see the CREDITS file for full details.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- *
- * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
*/
+/* DEBUG: section 28 Access Control */
+
#include "squid.h"
-#include "acl/UserData.h"
#include "acl/Checklist.h"
-#include "Debug.h"
-#include "wordlist.h"
+#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)
-{
- 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)
+const Acl::ParameterFlags &
+ACLUserData::supportedFlags() const
{
- return strcmp ((char *)l,(char *)r);
+ static const Acl::ParameterFlags flagNames = { "-i", "+i" };
+ return flagNames;
}
bool
ACLUserData::match(char const *user)
{
- SplayNode<char *> *Top = names;
-
- debugs(28, 7, "aclMatchUser: user is " << user << ", case_insensitive is " << flags.case_insensitive);
- debugs(28, 8, "Top is " << Top << ", Top->data is " << ((char *) (Top != NULL ? (Top)->data : "Unavailable")));
+ debugs(28, 7, "user is " << user << ", case_insensitive is " << flags.case_insensitive);
if (user == NULL || strcmp(user, "-") == 0)
return 0;
return 1;
}
- if (flags.case_insensitive)
- Top = Top->splay((char *)user, splaystrcasecmp);
- else
- Top = Top->splay((char *)user, splaystrcmp);
+ bool result = (userDataNames.find(SBuf(user)) != userDataNames.end());
+ debugs(28, 7, "returning " << result);
+ return result;
+}
- /* Top=splay_splay(user,Top,(splayNode::SPLAYCMP *)dumping_strcmp); */
- debugs(28, 7, "aclMatchUser: returning " << !splayLastResult << ",Top is " <<
- Top << ", Top->data is " << ((char *) (Top ? Top->data : "Unavailable")));
+SBufList
+ACLUserData::dump() const
+{
+ SBufList sl;
- names = Top;
+ if (flags.required) {
+ sl.push_back(SBuf("REQUIRED"));
+ return sl;
+ }
- return !splayLastResult;
+ 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 void
-aclDumpUserListWalkee(char * const & node_data, void *outlist)
+static bool
+CaseSensitiveSBufCompare(const SBuf &lhs, const SBuf &rhs)
{
- /* outlist is really a wordlist ** */
- wordlistAdd((wordlist **)outlist, (char const *)node_data);
+ return (lhs.cmp(rhs) < 0);
}
-wordlist *
-ACLUserData::dump()
+static bool
+CaseInsensitveSBufCompare(const SBuf &lhs, const SBuf &rhs)
{
- wordlist *wl = NULL;
-
- if (flags.case_insensitive)
- wordlistAdd(&wl, "-i");
-
- /* damn this is VERY inefficient for long ACL lists... filling
- * a wordlist this way costs Sum(1,N) iterations. For instance
- * a 1000-elements list will be filled in 499500 iterations.
- */
- if (flags.required)
- wordlistAdd(&wl, "REQUIRED");
- else if (names)
- names->walk(aclDumpUserListWalkee, &wl);
+ return (lhs.caseCmp(rhs) < 0);
+}
- return wl;
+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);
-
- if (strcmp("-i", t) == 0) {
- debugs(28, 5, "aclParseUserList: Going case-insensitive");
- flags.case_insensitive = 1;
- } else if (strcmp("REQUIRED", t) == 0) {
- debugs(28, 5, "aclParseUserList: REQUIRED-type enabled");
- flags.required = 1;
+ SBuf s(t);
+ debugs(28, 5, "first token is " << s);
+
+ if (s.cmp("-i",2) == 0) {
+ debugs(28, 5, "Going case-insensitive");
+ flags.case_insensitive = true;
+ // 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 = 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();
- names = names->insert(xstrdup(t), splaystrcmp);
+ debugs(28, 6, "Adding user " << s);
+ userDataNames.insert(s);
}
+
+ 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;
}
+