]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/external_acl.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / external_acl.cc
index f463e5bfb86b549c54678a62bca9071af06d2eb0..d7b01e597a6518afc6dddc6211e686282e876494 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
@@ -22,6 +22,7 @@
 #include "format/Token.h"
 #include "helper.h"
 #include "helper/Reply.h"
+#include "http/Stream.h"
 #include "HttpHeaderTools.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
@@ -120,10 +121,7 @@ public:
     bool require_auth;
 #endif
 
-    enum {
-        QUOTE_METHOD_SHELL = 1,
-        QUOTE_METHOD_URL
-    } quote;
+    Format::Quoting quote; // default quoting to use, set by protocol= parameter
 
     Ip::Address local_addr;
 };
@@ -146,7 +144,7 @@ external_acl::external_acl() :
 #if USE_AUTH
     require_auth(0),
 #endif
-    quote(external_acl::QUOTE_METHOD_URL)
+    quote(Format::LOG_QUOTE_URL)
 {
     local_addr.setLocalhost();
 }
@@ -180,12 +178,14 @@ external_acl::~external_acl()
 void
 parse_externalAclHelper(external_acl ** list)
 {
-    external_acl *a = new external_acl;
     char *token = ConfigParser::NextToken();
 
-    if (!token)
+    if (!token) {
         self_destruct();
+        return;
+    }
 
+    external_acl *a = new external_acl;
     a->name = xstrdup(token);
 
     // Allow supported %macros inside quoted tokens
@@ -217,16 +217,16 @@ parse_externalAclHelper(external_acl ** list)
         } else if (strncmp(token, "grace=", 6) == 0) {
             a->grace = atoi(token + 6);
         } else if (strcmp(token, "protocol=2.5") == 0) {
-            a->quote = external_acl::QUOTE_METHOD_SHELL;
+            a->quote = Format::LOG_QUOTE_SHELL;
         } else if (strcmp(token, "protocol=3.0") == 0) {
             debugs(3, DBG_PARSE_NOTE(2), "WARNING: external_acl_type option protocol=3.0 is deprecated. Remove this from your config.");
-            a->quote = external_acl::QUOTE_METHOD_URL;
+            a->quote = Format::LOG_QUOTE_URL;
         } else if (strcmp(token, "quote=url") == 0) {
             debugs(3, DBG_PARSE_NOTE(2), "WARNING: external_acl_type option quote=url is deprecated. Remove this from your config.");
-            a->quote = external_acl::QUOTE_METHOD_URL;
+            a->quote = Format::LOG_QUOTE_URL;
         } else if (strcmp(token, "quote=shell") == 0) {
             debugs(3, DBG_PARSE_NOTE(2), "WARNING: external_acl_type option quote=shell is deprecated. Use protocol=2.5 if still needed.");
-            a->quote = external_acl::QUOTE_METHOD_SHELL;
+            a->quote = Format::LOG_QUOTE_SHELL;
 
             /* INET6: allow admin to configure some helpers explicitly to
                       bind to IPv4/v6 localhost port. */
@@ -268,12 +268,19 @@ parse_externalAclHelper(external_acl ** list)
      */
     enum Format::Quoting quote = Format::LOG_QUOTE_NONE;
     Format::Token **fmt = &a->format.format;
+    bool data_used = false;
     while (token) {
         /* stop on first non-% token found */
         if (*token != '%')
             break;
 
         *fmt = new Format::Token;
+        // these tokens are whitespace delimited
+        (*fmt)->space = true;
+
+        // set the default encoding to match the protocol= config
+        // this will be overridden by explicit %macro attributes
+        (*fmt)->quote = a->quote;
 
         // compatibility for old tokens incompatible with Format::Token syntax
 #if USE_OPENSSL // dont bother if we dont have to.
@@ -306,17 +313,33 @@ parse_externalAclHelper(external_acl ** list)
             a->require_auth = true;
 #endif
 
+        if ((*fmt)->type == Format::LFT_EXT_ACL_DATA)
+            data_used = true;
+
         fmt = &((*fmt)->next);
         token = ConfigParser::NextToken();
     }
 
     /* There must be at least one format token */
-    if (!a->format.format)
+    if (!a->format.format) {
+        delete a;
         self_destruct();
+        return;
+    }
+
+    // format has implicit %DATA on the end if not used explicitly
+    if (!data_used) {
+        *fmt = new Format::Token;
+        (*fmt)->type = Format::LFT_EXT_ACL_DATA;
+        (*fmt)->quote = Format::LOG_QUOTE_NONE;
+    }
 
     /* helper */
-    if (!token)
+    if (!token) {
+        delete a;
         self_destruct();
+        return;
+    }
 
     wordlistAdd(&a->cmdline, token);
 
@@ -355,19 +378,19 @@ dump_externalAclHelper(StoreEntry * sentry, const char *name, const external_acl
         if (node->children.n_max != DEFAULT_EXTERNAL_ACL_CHILDREN)
             storeAppendPrintf(sentry, " children-max=%d", node->children.n_max);
 
-        if (node->children.n_startup != 1)
+        if (node->children.n_startup != 0) // sync with helper/ChildConfig.cc default
             storeAppendPrintf(sentry, " children-startup=%d", node->children.n_startup);
 
-        if (node->children.n_idle != (node->children.n_max + node->children.n_startup) )
+        if (node->children.n_idle != 1) // sync with helper/ChildConfig.cc default
             storeAppendPrintf(sentry, " children-idle=%d", node->children.n_idle);
 
-        if (node->children.concurrency)
+        if (node->children.concurrency != 0)
             storeAppendPrintf(sentry, " concurrency=%d", node->children.concurrency);
 
         if (node->cache)
             storeAppendPrintf(sentry, " cache=%d", node->cache_size);
 
-        if (node->quote == external_acl::QUOTE_METHOD_SHELL)
+        if (node->quote == Format::LOG_QUOTE_SHELL)
             storeAppendPrintf(sentry, " protocol=2.5");
 
         node->format.dump(sentry, NULL, false);
@@ -451,18 +474,25 @@ external_acl_data::~external_acl_data()
 void
 ACLExternal::parse()
 {
-    if (data)
+    if (data) {
         self_destruct();
+        return;
+    }
 
     char *token = ConfigParser::strtokFile();
 
-    if (!token)
+    if (!token) {
         self_destruct();
+        return;
+    }
 
     data = new external_acl_data(find_externalAclHelper(token));
 
-    if (!data->def)
+    if (!data->def) {
+        delete data;
         self_destruct();
+        return;
+    }
 
     // def->name is the name of the external_acl_type.
     // this is the name of the 'acl' directive being tested
@@ -598,7 +628,8 @@ aclMatchExternal(external_acl_data *acl, ACLFilledChecklist *ch)
         if (!entry) {
             debugs(82, 2, HERE << acl->def->name << "(\"" << key << "\") = lookup needed");
 
-            if (!acl->def->theHelper->queueFull()) {
+            // TODO: All other helpers allow temporary overload. Should not we?
+            if (!acl->def->theHelper->willOverload()) {
                 debugs(82, 2, HERE << "\"" << key << "\": queueing a call.");
                 if (!ch->goAsync(ExternalACLLookup::Instance()))
                     debugs(82, 2, "\"" << key << "\": no async support!");
@@ -607,12 +638,12 @@ aclMatchExternal(external_acl_data *acl, ACLFilledChecklist *ch)
             } else {
                 if (!staleEntry) {
                     debugs(82, DBG_IMPORTANT, "WARNING: external ACL '" << acl->def->name <<
-                           "' queue overload. Request rejected '" << key << "'.");
+                           "' queue full. Request rejected '" << key << "'.");
                     external_acl_message = "SYSTEM TOO BUSY, TRY AGAIN LATER";
                     return ACCESS_DUNNO;
                 } else {
                     debugs(82, DBG_IMPORTANT, "WARNING: external ACL '" << acl->def->name <<
-                           "' queue overload. Using stale result. '" << key << "'.");
+                           "' queue full. Using stale result. '" << key << "'.");
                     entry = staleEntry;
                     /* Fall thru to processing below */
                 }
@@ -697,25 +728,25 @@ static char *
 makeExternalAclKey(ACLFilledChecklist * ch, external_acl_data * acl_data)
 {
     static MemBuf mb;
+    mb.reset();
 
     // check for special case tokens in the format
     for (Format::Token *t = acl_data->def->format.format; t ; t = t->next) {
 
         if (t->type == Format::LFT_EXT_ACL_NAME) {
             // setup for %ACL
-            safe_free(ch->al->_private.lastAclName);
-            ch->al->_private.lastAclName = xstrdup(acl_data->name);
+            safe_free(ch->al->lastAclName);
+            ch->al->lastAclName = xstrdup(acl_data->name);
         }
 
-        if (t->type == Format::LFT_EXT_ACL_NAME) {
+        if (t->type == Format::LFT_EXT_ACL_DATA) {
             // setup string for %DATA
             SBuf sb;
-            bool first = true;
             for (auto arg = acl_data->arguments; arg; arg = arg->next) {
-                if (!first)
+                if (sb.length())
                     sb.append(" ", 1);
 
-                if (acl_data->def->quote == external_acl::QUOTE_METHOD_URL) {
+                if (acl_data->def->quote == Format::LOG_QUOTE_URL) {
                     const char *quoted = rfc1738_escape(arg->key);
                     sb.append(quoted, strlen(quoted));
                 } else {
@@ -725,21 +756,24 @@ makeExternalAclKey(ACLFilledChecklist * ch, external_acl_data * acl_data)
                     sb.append(mb2.buf, mb2.size);
                     mb2.clean();
                 }
-
-                first = false;
             }
+
+            ch->al->lastAclData = sb;
         }
 
+#if USE_IDENT
         if (t->type == Format::LFT_USER_IDENT) {
-            if (!ch->rfc931 || !*ch->rfc931) {
+            if (!*ch->rfc931) {
                 // if we fail to go async, we still return NULL and the caller
                 // will detect the failure in ACLExternal::match().
                 (void)ch->goAsync(IdentLookup::Instance());
                 return NULL;
             }
         }
+#endif
     }
 
+    // assemble the full helper lookup string
     acl_data->def->format.assemble(mb, ch->al, 0);
 
     return mb.buf;