*/
#include "squid.h"
-#include "CacheManager.h"
-#include "ExternalACL.h"
-#include "ExternalACLEntry.h"
-#include "auth/UserRequest.h"
-#include "SquidTime.h"
-#include "Store.h"
-#include "fde.h"
-#include "acl/FilledChecklist.h"
#include "acl/Acl.h"
-#if USE_IDENT
-#include "ident/AclIdent.h"
-#endif
+#include "acl/FilledChecklist.h"
#include "client_side.h"
-#include "HttpRequest.h"
-#include "HttpReply.h"
-#include "auth/Acl.h"
-#include "auth/Gadgets.h"
+#include "comm/Connection.h"
+#include "ExternalACLEntry.h"
+#include "ExternalACL.h"
+#include "fde.h"
#include "helper.h"
+#include "HttpReply.h"
+#include "HttpRequest.h"
+#include "ip/tools.h"
#include "MemBuf.h"
+#include "mgr/Registration.h"
+#include "protos.h"
#include "rfc1738.h"
+#include "SquidTime.h"
+#include "Store.h"
#include "URLScheme.h"
#include "wordlist.h"
+#if USE_SSL
+#include "ssl/support.h"
+#endif
+#if USE_AUTH
+#include "auth/Acl.h"
+#include "auth/Gadgets.h"
+#include "auth/UserRequest.h"
+#endif
+#if USE_IDENT
+#include "ident/AclIdent.h"
+#endif
#ifndef DEFAULT_EXTERNAL_ACL_TTL
#define DEFAULT_EXTERNAL_ACL_TTL 1 * 60 * 60
public:
external_acl *next;
- void add
- (ExternalACLEntry *);
+ void add(ExternalACLEntry *);
void trimCache();
dlink_list queue;
+#if USE_AUTH
/**
* Configuration flag. May only be altered by the configuration parser.
*
* details to be processed. If none are available its a fail match.
*/
bool require_auth;
+#endif
enum {
QUOTE_METHOD_SHELL = 1,
struct _external_acl_format {
enum format_type {
EXT_ACL_UNKNOWN,
+#if USE_AUTH
EXT_ACL_LOGIN,
+#endif
#if USE_IDENT
EXT_ACL_IDENT,
#endif
EXT_ACL_USER_CERT_RAW,
EXT_ACL_USER_CERTCHAIN_RAW,
#endif
+#if USE_AUTH
EXT_ACL_EXT_USER,
+#endif
+ EXT_ACL_EXT_LOG,
+ EXT_ACL_TAG,
+ EXT_ACL_PERCENT,
EXT_ACL_END
} type;
external_acl_format *next;
if (member) {
/* Split in header and member */
- *member++ = '\0';
+ *member = '\0';
+ ++member;
- if (!xisalnum(*member))
- format->separator = *member++;
- else
+ if (!xisalnum(*member)) {
+ format->separator = *member;
+ ++member;
+ } else {
format->separator = ',';
+ }
format->member = xstrdup(member);
a->negative_ttl = atoi(token + 13);
} else if (strncmp(token, "children=", 9) == 0) {
a->children.n_max = atoi(token + 9);
- debugs(0, 0, "WARNING: external_acl_type option children=N has been deprecated in favor of children-max=N and children-startup=N");
+ debugs(0, DBG_CRITICAL, "WARNING: external_acl_type option children=N has been deprecated in favor of children-max=N and children-startup=N");
} else if (strncmp(token, "children-max=", 13) == 0) {
a->children.n_max = atoi(token + 13);
} else if (strncmp(token, "children-startup=", 17) == 0) {
bind to IPv4/v6 localhost port. */
} else if (strcmp(token, "ipv4") == 0) {
if ( !a->local_addr.SetIPv4() ) {
- debugs(3, 0, "WARNING: Error converting " << a->local_addr << " to IPv4 in " << a->name );
+ debugs(3, DBG_CRITICAL, "WARNING: Error converting " << a->local_addr << " to IPv4 in " << a->name );
}
} else if (strcmp(token, "ipv6") == 0) {
-#if !USE_IPV6
- debugs(3, 0, "WARNING: --enable-ipv6 required for external ACL helpers to use IPv6: " << a->name );
-#else
- (void)0;
-#endif
+ if (!Ip::EnableIpv6)
+ debugs(3, DBG_CRITICAL, "WARNING: --enable-ipv6 required for external ACL helpers to use IPv6: " << a->name );
+ // else nothing to do.
} else {
break;
}
parse_header_token(format, (token+3), _external_acl_format::EXT_ACL_HEADER_REQUEST);
} else if (strncmp(token, "%<{", 3) == 0) {
parse_header_token(format, (token+3), _external_acl_format::EXT_ACL_HEADER_REPLY);
+#if USE_AUTH
} else if (strcmp(token, "%LOGIN") == 0) {
format->type = _external_acl_format::EXT_ACL_LOGIN;
a->require_auth = true;
+#endif
}
#if USE_IDENT
format->header = xstrdup(token + 11);
}
#endif
+#if USE_AUTH
else if (strcmp(token, "%EXT_USER") == 0)
format->type = _external_acl_format::EXT_ACL_EXT_USER;
+#endif
+ else if (strcmp(token, "%EXT_LOG") == 0)
+ format->type = _external_acl_format::EXT_ACL_EXT_LOG;
+ else if (strcmp(token, "%TAG") == 0)
+ format->type = _external_acl_format::EXT_ACL_TAG;
+ else if (strcmp(token, "%%") == 0)
+ format->type = _external_acl_format::EXT_ACL_PERCENT;
else {
- debugs(0,0, "ERROR: Unknown Format token " << token);
+ debugs(0, DBG_CRITICAL, "ERROR: Unknown Format token " << token);
self_destruct();
}
case _external_acl_format::EXT_ACL_##a: \
storeAppendPrintf(sentry, " %%%s", #a); \
break
-
+#define DUMP_EXT_ACL_TYPE_FMT(a, fmt, ...) \
+ case _external_acl_format::EXT_ACL_##a: \
+ storeAppendPrintf(sentry, fmt, ##__VA_ARGS__); \
+ break
+#if USE_AUTH
DUMP_EXT_ACL_TYPE(LOGIN);
+#endif
#if USE_IDENT
DUMP_EXT_ACL_TYPE(IDENT);
DUMP_EXT_ACL_TYPE(PATH);
DUMP_EXT_ACL_TYPE(METHOD);
#if USE_SSL
-
- case _external_acl_format::EXT_ACL_USER_CERT_RAW:
- storeAppendPrintf(sentry, " %%USER_CERT");
- break;
-
- case _external_acl_format::EXT_ACL_USER_CERTCHAIN_RAW:
- storeAppendPrintf(sentry, " %%USER_CERTCHAIN");
- break;
-
- case _external_acl_format::EXT_ACL_USER_CERT:
- storeAppendPrintf(sentry, " %%USER_CERT_%s", format->header);
- break;
-
- case _external_acl_format::EXT_ACL_CA_CERT:
- storeAppendPrintf(sentry, " %%USER_CERT_%s", format->header);
- break;
+ DUMP_EXT_ACL_TYPE_FMT(USER_CERT_RAW, " %%USER_CERT_RAW");
+ DUMP_EXT_ACL_TYPE_FMT(USER_CERTCHAIN_RAW, " %%USER_CERTCHAIN_RAW");
+ DUMP_EXT_ACL_TYPE_FMT(USER_CERT, " %%USER_CERT_%s", format->header);
+ DUMP_EXT_ACL_TYPE_FMT(CA_CERT, " %%CA_CERT_%s", format->header);
#endif
-
+#if USE_AUTH
DUMP_EXT_ACL_TYPE(EXT_USER);
-
+#endif
+ DUMP_EXT_ACL_TYPE(EXT_LOG);
+ DUMP_EXT_ACL_TYPE(TAG);
+ DUMP_EXT_ACL_TYPE_FMT(PERCENT, " %%%%");
default:
fatal("unknown external_acl format error");
break;
}
void
-
-external_acl::add
-(ExternalACLEntry *anEntry)
+external_acl::add(ExternalACLEntry *anEntry)
{
trimCache();
assert (anEntry->def == NULL);
anEntry->def = this;
hash_join(cache, anEntry);
dlinkAdd(anEntry, &anEntry->lru, &lru_list);
- cache_entries++;
+ ++cache_entries;
}
void
external_acl_cache_delete(this, static_cast<external_acl_entry *>(lru_list.tail->data));
}
-
/******************************************************************
* external acl type
*/
bool
ACLExternal::valid () const
{
+#if USE_AUTH
if (data->def->require_auth) {
if (authenticateSchemeCount() == 0) {
- debugs(28, 0, "Can't use proxy auth because no authentication schemes were compiled.");
+ debugs(28, DBG_CRITICAL, "Can't use proxy auth because no authentication schemes were compiled.");
return false;
}
if (authenticateActiveSchemeCount() == 0) {
- debugs(28, 0, "Can't use proxy auth because no authentication schemes are fully configured.");
+ debugs(28, DBG_CRITICAL, "Can't use proxy auth because no authentication schemes are fully configured.");
return false;
}
}
+#endif
return true;
}
safe_free (class_);
}
-static int
+static void
+copyResultsFromEntry(HttpRequest *req, external_acl_entry *entry)
+{
+ if (req) {
+#if USE_AUTH
+ if (entry->user.size())
+ req->extacl_user = entry->user;
+
+ if (entry->password.size())
+ req->extacl_passwd = entry->password;
+#endif
+ if (!req->tag.size())
+ req->tag = entry->tag;
+
+ if (entry->log.size())
+ req->extacl_log = entry->log;
+
+ if (entry->message.size())
+ req->extacl_message = entry->message;
+ }
+}
+
+static allow_t
aclMatchExternal(external_acl_data *acl, ACLFilledChecklist *ch)
{
- int result;
- external_acl_entry *entry;
const char *key = "";
- debugs(82, 9, "aclMatchExternal: acl=\"" << acl->def->name << "\"");
- entry = ch->extacl_entry;
+ debugs(82, 9, HERE << "acl=\"" << acl->def->name << "\"");
+ external_acl_entry *entry = ch->extacl_entry;
if (entry) {
- if (cbdataReferenceValid(entry) && entry->def == acl->def &&
- strcmp((char *)entry->key, key) == 0) {
- /* Ours, use it.. */
+ if (cbdataReferenceValid(entry) && entry->def == acl->def) {
+ /* Ours, use it.. if the key matches */
+ key = makeExternalAclKey(ch, acl);
+ if (strcmp(key, (char*)entry->key) != 0) {
+ debugs(82, 9, HERE << "entry key='" << (char *)entry->key << "', our key='" << key << "' dont match. Discarded.");
+ // too bad. need a new lookup.
+ cbdataReferenceDone(ch->extacl_entry);
+ entry = NULL;
+ }
} else {
/* Not valid, or not ours.. get rid of it */
+ debugs(82, 9, HERE << "entry " << entry << " not valid or not ours. Discarded.");
+ if (entry) {
+ debugs(82, 9, HERE << "entry def=" << entry->def << ", our def=" << acl->def);
+ key = makeExternalAclKey(ch, acl);
+ debugs(82, 9, HERE << "entry key='" << (char *)entry->key << "', our key='" << key << "'");
+ }
cbdataReferenceDone(ch->extacl_entry);
entry = NULL;
}
external_acl_message = "MISSING REQUIRED INFORMATION";
if (!entry) {
+ debugs(82, 9, HERE << "No helper entry available");
+#if USE_AUTH
if (acl->def->require_auth) {
- int ti;
/* Make sure the user is authenticated */
- debugs(82, 3, "aclMatchExternal: " << acl->def->name << " check user authenticated.");
-
- if ((ti = AuthenticateAcl(ch)) != 1) {
- debugs(82, 2, "aclMatchExternal: " << acl->def->name << " user not authenticated (" << ti << ")");
+ debugs(82, 3, HERE << acl->def->name << " check user authenticated.");
+ const allow_t ti = AuthenticateAcl(ch);
+ if (ti != ACCESS_ALLOWED) {
+ debugs(82, 2, HERE << acl->def->name << " user not authenticated (" << ti << ")");
return ti;
}
- debugs(82, 3, "aclMatchExternal: " << acl->def->name << " user is authenticated.");
+ debugs(82, 3, HERE << acl->def->name << " user is authenticated.");
}
-
+#endif
key = makeExternalAclKey(ch, acl);
if (!key) {
/* Not sufficient data to process */
- return -1;
+ return ACCESS_DUNNO;
}
entry = static_cast<external_acl_entry *>(hash_lookup(acl->def->cache, key));
- if (!entry || external_acl_grace_expired(acl->def, entry)) {
- debugs(82, 2, "aclMatchExternal: " << acl->def->name << "(\"" << key << "\") = lookup needed");
- debugs(82, 2, "aclMatchExternal: \"" << key << "\": entry=@" <<
+ external_acl_entry *staleEntry = entry;
+ if (entry && external_acl_entry_expired(acl->def, entry))
+ entry = NULL;
+
+ if (entry && external_acl_grace_expired(acl->def, entry)) {
+ // refresh in the background
+ ExternalACLLookup::Start(ch, acl, true);
+ debugs(82, 4, HERE << "no need to wait for the refresh of '" <<
+ key << "' in '" << acl->def->name << "' (ch=" << ch << ").");
+ }
+
+ if (!entry) {
+ debugs(82, 2, HERE << acl->def->name << "(\"" << key << "\") = lookup needed");
+ debugs(82, 2, HERE << "\"" << key << "\": entry=@" <<
entry << ", age=" << (entry ? (long int) squid_curtime - entry->date : 0));
if (acl->def->theHelper->stats.queue_size <= (int)acl->def->theHelper->childs.n_active) {
- debugs(82, 2, "aclMatchExternal: \"" << key << "\": queueing a call.");
- ch->changeState (ExternalACLLookup::Instance());
-
- if (entry == NULL) {
- debugs(82, 2, "aclMatchExternal: \"" << key << "\": return -1.");
- return -1;
- }
+ debugs(82, 2, HERE << "\"" << key << "\": queueing a call.");
+ ch->changeState(ExternalACLLookup::Instance());
+ debugs(82, 2, HERE << "\"" << key << "\": return -1.");
+ return ACCESS_DUNNO; // expired cached or simply absent entry
} else {
- if (!entry) {
- debugs(82, 1, "aclMatchExternal: '" << acl->def->name <<
+ if (!staleEntry) {
+ debugs(82, DBG_IMPORTANT, "WARNING: external ACL '" << acl->def->name <<
"' queue overload. Request rejected '" << key << "'.");
external_acl_message = "SYSTEM TOO BUSY, TRY AGAIN LATER";
- return -1;
+ return ACCESS_DUNNO;
} else {
- debugs(82, 1, "aclMatchExternal: '" << acl->def->name <<
+ debugs(82, DBG_IMPORTANT, "WARNING: external ACL '" << acl->def->name <<
"' queue overload. Using stale result. '" << key << "'.");
+ entry = staleEntry;
/* Fall thru to processing below */
}
}
}
}
+ debugs(82, 4, HERE << "entry = { date=" <<
+ (long unsigned int) entry->date <<
+ ", result=" << entry->result <<
+ " tag=" << entry->tag <<
+ " log=" << entry->log << " }");
+#if USE_AUTH
+ debugs(82, 4, HERE << "entry user=" << entry->user);
+#endif
+
external_acl_cache_touch(acl->def, entry);
- result = entry->result;
external_acl_message = entry->message.termedBuf();
- debugs(82, 2, "aclMatchExternal: " << acl->def->name << " = " << result);
-
- if (ch->request) {
- if (entry->user.size())
- ch->request->extacl_user = entry->user;
-
- if (entry->password.size())
- ch->request->extacl_passwd = entry->password;
-
- if (!ch->request->tag.size())
- ch->request->tag = entry->tag;
-
- if (entry->log.size())
- ch->request->extacl_log = entry->log;
-
- if (entry->message.size())
- ch->request->extacl_message = entry->message;
- }
-
- return result;
+ debugs(82, 2, HERE << acl->def->name << " = " << entry->result);
+ copyResultsFromEntry(ch->request, entry);
+ return entry->result;
}
int
ACLExternal::match(ACLChecklist *checklist)
{
- return aclMatchExternal (data, Filled(checklist));
+ allow_t answer = aclMatchExternal(data, Filled(checklist));
+
+ // convert to tri-state ACL match 1,0,-1
+ switch (answer) {
+ case ACCESS_ALLOWED:
+ return 1; // match
+
+ case ACCESS_DENIED:
+ return 0; // non-match
+
+ case ACCESS_DUNNO:
+ case ACCESS_AUTH_REQUIRED:
+ default:
+ // If the answer is not allowed or denied (matches/not matches) and
+ // async authentication is not needed (asyncNeeded), then we are done.
+ if (!checklist->asyncNeeded())
+ checklist->markFinished(answer, "aclMatchExternal exception");
+ return -1; // other
+ }
}
wordlist *
static void
external_acl_cache_touch(external_acl * def, external_acl_entry * entry)
{
+ // this must not be done when nothing is being cached.
+ if (def->cache_size <= 0 || (def->ttl <= 0 && entry->result == 1) || (def->negative_ttl <= 0 && entry->result != 1))
+ return;
+
dlinkDelete(&entry->lru, &def->lru_list);
dlinkAdd(entry, &entry->lru, &def->lru_list);
}
String sb;
switch (format->type) {
-
+#if USE_AUTH
case _external_acl_format::EXT_ACL_LOGIN:
- assert (ch->auth_user_request != NULL);
- str = ch->auth_user_request->username();
+ // if this ACL line was the cause of credentials fetch
+ // they may not already be in the checklist
+ if (ch->auth_user_request == NULL && ch->request)
+ ch->auth_user_request = ch->request->auth_user_request;
+
+ if (ch->auth_user_request != NULL)
+ str = ch->auth_user_request->username();
break;
+#endif
#if USE_IDENT
-
case _external_acl_format::EXT_ACL_IDENT:
str = ch->rfc931;
#if USE_SQUID_EUI
case _external_acl_format::EXT_ACL_SRCEUI48:
- if (request->client_eui48.encode(buf, sizeof(buf)))
+ if (request->clientConnectionManager.valid() && request->clientConnectionManager->clientConnection != NULL &&
+ request->clientConnectionManager->clientConnection->remoteEui48.encode(buf, sizeof(buf)))
str = buf;
break;
case _external_acl_format::EXT_ACL_SRCEUI64:
- if (request->client_eui64.encode(buf, sizeof(buf)))
+ if (request->clientConnectionManager.valid() && request->clientConnectionManager->clientConnection != NULL &&
+ request->clientConnectionManager->clientConnection->remoteEui64.encode(buf, sizeof(buf)))
str = buf;
break;
#endif
break;
case _external_acl_format::EXT_ACL_PROTO:
- str = ProtocolStr[request->protocol];
+ str = AnyP::ProtocolType_str[request->protocol];
break;
case _external_acl_format::EXT_ACL_PORT:
case _external_acl_format::EXT_ACL_USER_CERT_RAW:
- if (ch->conn() != NULL) {
- SSL *ssl = fd_table[ch->conn()->fd].ssl;
+ if (ch->conn() != NULL && Comm::IsConnOpen(ch->conn()->clientConnection)) {
+ SSL *ssl = fd_table[ch->conn()->clientConnection->fd].ssl;
if (ssl)
str = sslGetUserCertificatePEM(ssl);
case _external_acl_format::EXT_ACL_USER_CERTCHAIN_RAW:
- if (ch->conn() != NULL) {
- SSL *ssl = fd_table[ch->conn()->fd].ssl;
+ if (ch->conn() != NULL && Comm::IsConnOpen(ch->conn()->clientConnection)) {
+ SSL *ssl = fd_table[ch->conn()->clientConnection->fd].ssl;
if (ssl)
str = sslGetUserCertificateChainPEM(ssl);
case _external_acl_format::EXT_ACL_USER_CERT:
- if (ch->conn() != NULL) {
- SSL *ssl = fd_table[ch->conn()->fd].ssl;
+ if (ch->conn() != NULL && Comm::IsConnOpen(ch->conn()->clientConnection)) {
+ SSL *ssl = fd_table[ch->conn()->clientConnection->fd].ssl;
if (ssl)
str = sslGetUserAttribute(ssl, format->header);
case _external_acl_format::EXT_ACL_CA_CERT:
- if (ch->conn() != NULL) {
- SSL *ssl = fd_table[ch->conn()->fd].ssl;
+ if (ch->conn() != NULL && Comm::IsConnOpen(ch->conn()->clientConnection)) {
+ SSL *ssl = fd_table[ch->conn()->clientConnection->fd].ssl;
if (ssl)
str = sslGetCAAttribute(ssl, format->header);
break;
#endif
-
+#if USE_AUTH
case _external_acl_format::EXT_ACL_EXT_USER:
str = request->extacl_user.termedBuf();
break;
-
+#endif
+ case _external_acl_format::EXT_ACL_EXT_LOG:
+ str = request->extacl_log.termedBuf();
+ break;
+ case _external_acl_format::EXT_ACL_TAG:
+ str = request->tag.termedBuf();
+ break;
+ case _external_acl_format::EXT_ACL_PERCENT:
+ str = "%";
+ break;
case _external_acl_format::EXT_ACL_UNKNOWN:
case _external_acl_format::EXT_ACL_END:
static int
external_acl_entry_expired(external_acl * def, external_acl_entry * entry)
{
+ if (def->cache_size <= 0)
+ return 1;
+
if (entry->date + (entry->result == 1 ? def->ttl : def->negative_ttl) < squid_curtime)
return 1;
else
static int
external_acl_grace_expired(external_acl * def, external_acl_entry * entry)
{
+ if (def->cache_size <= 0)
+ return 1;
+
int ttl;
ttl = entry->result == 1 ? def->ttl : def->negative_ttl;
ttl = (ttl * (100 - def->grace)) / 100;
- if (entry->date + ttl < squid_curtime)
+ if (entry->date + ttl <= squid_curtime)
return 1;
else
return 0;
static external_acl_entry *
external_acl_cache_add(external_acl * def, const char *key, ExternalACLEntryData const & data)
{
- ExternalACLEntry *entry = static_cast<ExternalACLEntry *>(hash_lookup(def->cache, key));
+ ExternalACLEntry *entry;
+
+ // do not bother caching this result if TTL is going to expire it immediately
+ if (def->cache_size <= 0 || (def->ttl <= 0 && data.result == 1) || (def->negative_ttl <= 0 && data.result != 1)) {
+ debugs(82,6, HERE);
+ entry = new ExternalACLEntry;
+ entry->key = xstrdup(key);
+ entry->update(data);
+ entry->def = def;
+ return entry;
+ }
+
+ entry = static_cast<ExternalACLEntry *>(hash_lookup(def->cache, key));
debugs(82, 2, "external_acl_cache_add: Adding '" << key << "' = " << data.result);
if (entry) {
debugs(82, 3, "ExternalACLEntry::update: updating existing entry");
- entry->update (data);
+ entry->update(data);
external_acl_cache_touch(def, entry);
return entry;
entry = new ExternalACLEntry;
entry->key = xstrdup(key);
- entry->update (data);
+ entry->update(data);
- def->add
- (entry);
+ def->add(entry);
return entry;
}
static void
external_acl_cache_delete(external_acl * def, external_acl_entry * entry)
{
- assert (entry->def == def);
+ assert(def->cache_size > 0 && entry->def == def);
hash_remove_link(def->cache, entry);
dlinkDelete(&entry->lru, &def->lru_list);
def->cache_entries -= 1;
char *status;
char *token;
char *value;
- char *t;
+ char *t = NULL;
ExternalACLEntryData entryData;
- entryData.result = 0;
+ entryData.result = ACCESS_DENIED;
external_acl_entry *entry = NULL;
debugs(82, 2, "externalAclHandleReply: reply=\"" << reply << "\"");
status = strwordtok(reply, &t);
if (status && strcmp(status, "OK") == 0)
- entryData.result = 1;
+ entryData.result = ACCESS_ALLOWED;
while ((token = strwordtok(NULL, &t))) {
value = strchr(token, '=');
if (value) {
- *value++ = '\0'; /* terminate the token, and move up to the value */
+ *value = '\0'; /* terminate the token, and move up to the value */
+ ++value;
if (state->def->quote == external_acl::QUOTE_METHOD_URL)
rfc1738_unescape(value);
- if (strcmp(token, "user") == 0)
- entryData.user = value;
- else if (strcmp(token, "message") == 0)
+ if (strcmp(token, "message") == 0)
entryData.message = value;
else if (strcmp(token, "error") == 0)
entryData.message = value;
entryData.tag = value;
else if (strcmp(token, "log") == 0)
entryData.log = value;
+#if USE_AUTH
+ else if (strcmp(token, "user") == 0)
+ entryData.user = value;
else if (strcmp(token, "password") == 0)
entryData.password = value;
else if (strcmp(token, "passwd") == 0)
entryData.password = value;
else if (strcmp(token, "login") == 0)
entryData.user = value;
+#endif
}
}
}
}
void
-ACLExternal::ExternalAclLookup(ACLChecklist *checklist, ACLExternal * me, EAH * callback, void *callback_data)
+ACLExternal::ExternalAclLookup(ACLChecklist *checklist, ACLExternal * me)
+{
+ ExternalACLLookup::Start(checklist, me->data, false);
+}
+
+void
+ExternalACLLookup::Start(ACLChecklist *checklist, external_acl_data *acl, bool inBackground)
{
- MemBuf buf;
- external_acl_data *acl = me->data;
external_acl *def = acl->def;
- externalAclState *state;
- dlink_node *node;
- externalAclState *oldstate = NULL;
- bool graceful = 0;
ACLFilledChecklist *ch = Filled(checklist);
- if (acl->def->require_auth) {
- int ti;
- /* Make sure the user is authenticated */
- debugs(82, 3, "aclMatchExternal: " << acl->def->name << " check user authenticated.");
-
- if ((ti = AuthenticateAcl(ch)) != 1) {
- debugs(82, 1, "externalAclLookup: " << acl->def->name <<
- " user authentication failure (" << ti << ", ch=" << ch << ")");
- callback(callback_data, NULL);
- return;
- }
- debugs(82, 3, "aclMatchExternal: " << acl->def->name << " user is authenticated.");
- }
-
const char *key = makeExternalAclKey(ch, acl);
+ assert(key);
- if (!key) {
- debugs(82, 1, "externalAclLookup: lookup in '" << def->name <<
- "', prerequisit failure (ch=" << ch << ")");
- callback(callback_data, NULL);
- return;
- }
-
- debugs(82, 2, "externalAclLookup: lookup in '" << def->name << "' for '" << key << "'");
-
- external_acl_entry *entry = static_cast<external_acl_entry *>(hash_lookup(def->cache, key));
-
- if (entry && external_acl_entry_expired(def, entry))
- entry = NULL;
+ debugs(82, 2, HERE << (inBackground ? "bg" : "fg") << " lookup in '" <<
+ def->name << "' for '" << key << "'");
/* Check for a pending lookup to hook into */
- for (node = def->queue.head; node; node = node->next) {
- externalAclState *oldstatetmp = static_cast<externalAclState *>(node->data);
-
- if (strcmp(key, oldstatetmp->key) == 0) {
- oldstate = oldstatetmp;
- break;
- }
- }
+ // only possible if we are caching results.
+ externalAclState *oldstate = NULL;
+ if (def->cache_size > 0) {
+ for (dlink_node *node = def->queue.head; node; node = node->next) {
+ externalAclState *oldstatetmp = static_cast<externalAclState *>(node->data);
- if (entry && external_acl_grace_expired(def, entry)) {
- if (oldstate) {
- debugs(82, 4, "externalAclLookup: in grace period, but already pending lookup ('" << key << "', ch=" << ch << ")");
- callback(callback_data, entry);
- return;
- } else {
- graceful = 1; // grace expired, (neg)ttl did not, and we must start a new lookup.
+ if (strcmp(key, oldstatetmp->key) == 0) {
+ oldstate = oldstatetmp;
+ break;
+ }
}
}
- // The entry is in the cache, grace_ttl did not expired.
- if (!graceful && entry && !external_acl_grace_expired(def, entry)) {
- /* Should not really happen, but why not.. */
- callback(callback_data, entry);
- debugs(82, 4, "externalAclLookup: no lookup pending for '" << key << "', and grace not expired");
- debugs(82, 4, "externalAclLookup: (what tha' hell?)");
+ // A background refresh has no need to piggiback on a pending request:
+ // When the pending request completes, the cache will be refreshed anyway.
+ if (oldstate && inBackground) {
+ debugs(82, 7, HERE << "'" << def->name << "' queue is already being refreshed (ch=" << ch << ")");
return;
}
- /* No pending lookup found. Sumbit to helper */
- state = cbdataAlloc(externalAclState);
-
+ externalAclState *state = cbdataAlloc(externalAclState);
state->def = cbdataReference(def);
state->key = xstrdup(key);
- if (!graceful) {
- state->callback = callback;
- state->callback_data = cbdataReference(callback_data);
+ if (!inBackground) {
+ state->callback = &ExternalACLLookup::LookupDone;
+ state->callback_data = cbdataReference(checklist);
}
if (oldstate) {
state->queue = oldstate->queue;
oldstate->queue = state;
} else {
+ /* No pending lookup found. Sumbit to helper */
+
/* Check for queue overload */
if (def->theHelper->stats.queue_size >= (int)def->theHelper->childs.n_running) {
- debugs(82, 1, "externalAclLookup: '" << def->name << "' queue overload (ch=" << ch << ")");
+ debugs(82, 7, HERE << "'" << def->name << "' queue is too long");
+ assert(inBackground); // or the caller should have checked
cbdataFree(state);
- callback(callback_data, entry);
return;
}
/* Send it off to the helper */
+ MemBuf buf;
buf.init();
buf.Printf("%s\n", key);
buf.clean();
}
- if (graceful) {
- /* No need to wait during grace period */
- debugs(82, 4, "externalAclLookup: no need to wait for the result of '" <<
- key << "' in '" << def->name << "' (ch=" << ch << ").");
- debugs(82, 4, "externalAclLookup: using cached entry " << entry);
-
- if (entry != NULL) {
- debugs(82, 4, "externalAclLookup: entry = { date=" <<
- (long unsigned int) entry->date << ", result=" <<
- entry->result << ", user=" << entry->user << " tag=" <<
- entry->tag << " log=" << entry->log << " }");
-
- }
-
- callback(callback_data, entry);
- return;
- }
-
debugs(82, 4, "externalAclLookup: will wait for the result of '" << key <<
"' in '" << def->name << "' (ch=" << ch << ").");
}
static void
externalAclRegisterWithCacheManager(void)
{
- CacheManager::GetInstance()->
- registerAction("external_acl",
- "External ACL stats",
- externalAclStats, 0, 1);
+ Mgr::RegisterAction("external_acl",
+ "External ACL stats",
+ externalAclStats, 0, 1);
}
void
p->theHelper->cmdline = p->cmdline;
- p->theHelper->childs = p->children;
+ p->theHelper->childs.updateLimits(p->children);
p->theHelper->ipc_type = IPC_TCP_SOCKET;
ACLExternal *me = dynamic_cast<ACLExternal *> (acl);
assert (me);
checklist->asyncInProgress(true);
- ACLExternal::ExternalAclLookup(checklist, me, LookupDone, checklist);
+ ACLExternal::ExternalAclLookup(checklist, me);
}
+/// Called when an async lookup returns
void
ExternalACLLookup::LookupDone(void *data, void *result)
{
checklist->extacl_entry = cbdataReference((external_acl_entry *)result);
checklist->asyncInProgress(false);
checklist->changeState (ACLChecklist::NullState::Instance());
- checklist->check();
+ checklist->matchNonBlocking();
}
/* This registers "external" in the registry. To do dynamic definitions
bool
ACLExternal::isProxyAuth() const
{
+#if USE_AUTH
return data->def->require_auth;
+#else
+ return false;
+#endif
}