]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/cache_cf.cc
SourceFormat: enforcement
[thirdparty/squid.git] / src / cache_cf.cc
index 0462b492b27f11dad9ba893fd333a6b57e653958..22a8d9fe90d0cf0116f18aacac332aa84309d2a1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cache_cf.cc,v 1.544 2008/03/04 12:00:36 amosjeffries Exp $
+ * $Id$
  *
  * DEBUG: section 3     Configuration File Parsing
  * AUTHOR: Harvest Derived
  */
 
 #include "squid.h"
-#include "authenticate.h"
 #include "ProtoPort.h"
 #include "HttpRequestMethod.h"
-#include "AuthConfig.h"
-#include "AuthScheme.h"
+#include "auth/Config.h"
+#include "auth/Scheme.h"
 #include "CacheManager.h"
 #include "Store.h"
 #include "SwapDir.h"
 #include "ConfigParser.h"
-#include "ACL.h"
+#include "acl/Acl.h"
+#include "acl/MethodData.h"
+#include "acl/Gadgets.h"
 #include "StoreFileSystem.h"
 #include "Parsing.h"
 #include "MemBuf.h"
 #include "wordlist.h"
+#include "ident/Config.h"
 #include "ip/IpIntercept.h"
 
 #if HAVE_GLOB_H
 #include "snmp.h"
 #endif
 #if USE_SQUID_ESI
-#include "ESIParser.h"
+#include "esi/Parser.h"
 #endif
 
 #if USE_ADAPTATION
 #include "adaptation/Config.h"
 
 static void parse_adaptation_service_set_type();
+static void parse_adaptation_service_chain_type();
 static void parse_adaptation_access_type();
 
 #endif
 
 #if ICAP_CLIENT
-#include "ICAP/ICAPConfig.h"
+#include "adaptation/icap/Config.h"
 
-static void parse_icap_service_type(ICAPConfig *);
-static void dump_icap_service_type(StoreEntry *, const char *, const ICAPConfig &);
-static void free_icap_service_type(ICAPConfig *);
+static void parse_icap_service_type(Adaptation::Icap::Config *);
+static void dump_icap_service_type(StoreEntry *, const char *, const Adaptation::Icap::Config &);
+static void free_icap_service_type(Adaptation::Icap::Config *);
 static void parse_icap_class_type();
 static void parse_icap_access_type();
 
 #endif
 
 #if USE_ECAP
-#include "eCAP/Config.h"
-static void parse_ecap_service_type(Ecap::Config *);
-static void dump_ecap_service_type(StoreEntry *, const char *, const Ecap::Config &);
-static void free_ecap_service_type(Ecap::Config *);
+#include "adaptation/ecap/Config.h"
+static void parse_ecap_service_type(Adaptation::Ecap::Config *);
+static void dump_ecap_service_type(StoreEntry *, const char *, const Adaptation::Ecap::Config &);
+static void free_ecap_service_type(Adaptation::Ecap::Config *);
 #endif
 
 CBDATA_TYPE(peer);
@@ -142,11 +145,11 @@ static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_li
 static void free_denyinfo(acl_deny_info_list ** var);
 
 #if USE_WCCPv2
-static void parse_IPAddress_list(IPAddress_list **);
-static void dump_IPAddress_list(StoreEntry *, const char *, const IPAddress_list *);
-static void free_IPAddress_list(IPAddress_list **);
+static void parse_IpAddress_list(IpAddress_list **);
+static void dump_IpAddress_list(StoreEntry *, const char *, const IpAddress_list *);
+static void free_IpAddress_list(IpAddress_list **);
 #if CURRENTLY_UNUSED
-static int check_null_IPAddress_list(const IPAddress_list *);
+static int check_null_IpAddress_list(const IpAddress_list *);
 #endif /* CURRENTLY_UNUSED */
 #endif /* USE_WCCPv2 */
 
@@ -387,6 +390,7 @@ parseConfigFile(const char *file_name)
 
     configFreeMemory();
 
+    ACLMethodData::ThePurgeCount = 0;
     default_all();
 
     err_count = parseOneConfigFile(file_name, 0);
@@ -403,7 +407,7 @@ parseConfigFile(const char *file_name)
     if (!Config.chroot_dir) {
         leave_suid();
         setUmask(Config.umask);
-        _db_init(Config.Log.log, Config.debugOptions);
+        _db_init(Debug::cache_log, Debug::debugOptions);
         enter_suid();
     }
 
@@ -426,6 +430,10 @@ configDoConfigure(void)
     memConfigure();
     /* Sanity checks */
 
+    if (Debug::rotateNumber < 0) {
+        Debug::rotateNumber = Config.Log.rotateNumber;
+    }
+
 #if SIZEOF_OFF_T <= 4
     if (Config.Store.maxObjectSize > 0x7FFF0000) {
         debugs(3, 0, "WARNING: This Squid binary can not handle files larger than 2GB. Limiting maximum_object_size to just below 2GB");
@@ -494,9 +502,6 @@ configDoConfigure(void)
     else
         Config.appendDomainLen = 0;
 
-    safe_free(debug_options)
-    debug_options = xstrdup(Config.debugOptions);
-
     if (Config.retry.maxtries > 10)
         fatal("maximum_single_addr_tries cannot be larger than 10");
 
@@ -582,6 +587,13 @@ configDoConfigure(void)
             break;
         }
 
+        for (R = Config.Refresh; R; R = R->next) {
+            if (!R->flags.ignore_must_revalidate)
+                continue;
+            debugs(22, 1, "WARNING: use of 'ignore-must-revalidate' in 'refresh_pattern' violates HTTP");
+            break;
+        }
+
         for (R = Config.Refresh; R; R = R->next) {
             if (!R->flags.ignore_private)
                 continue;
@@ -611,8 +623,9 @@ configDoConfigure(void)
 
 #endif
 
-    if (aclPurgeMethodInUse(Config.accessList.http))
-        Config2.onoff.enable_purge = 1;
+    // we enable runtime PURGE checks if there is at least one PURGE method ACL
+    // TODO: replace with a dedicated "purge" ACL option?
+    Config2.onoff.enable_purge = (ACLMethodData::ThePurgeCount > 0);
 
     Config2.onoff.mangle_request_headers = httpReqHdrManglersConfigured();
 
@@ -888,7 +901,7 @@ parseBytesUnits(const char *unit)
     if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
         return 1 << 30;
 
-    debugs(3, 1, "parseBytesUnits: unknown bytes unit '" << unit << "'");
+    debugs(3, DBG_CRITICAL, "WARNING: Unknown bytes unit '" << unit << "'");
 
     return 0;
 }
@@ -974,14 +987,14 @@ free_acl_access(acl_access ** head)
 }
 
 static void
-dump_address(StoreEntry * entry, const char *name, IPAddress &addr)
+dump_address(StoreEntry * entry, const char *name, IpAddress &addr)
 {
     char buf[MAX_IPSTRLEN];
     storeAppendPrintf(entry, "%s %s\n", name, addr.NtoA(buf,MAX_IPSTRLEN) );
 }
 
 static void
-parse_address(IPAddress *addr)
+parse_address(IpAddress *addr)
 {
     char *token = strtok(NULL, w_space);
 
@@ -1001,7 +1014,7 @@ parse_address(IPAddress *addr)
 }
 
 static void
-free_address(IPAddress *addr)
+free_address(IpAddress *addr)
 {
     addr->SetEmpty();
 }
@@ -1490,8 +1503,7 @@ parse_cachedir(SquidConfig::_cacheSwap * swap)
     for (i = 0; i < swap->n_configured; i++) {
         assert (swap->swapDirs[i].getRaw());
 
-        if ((strcasecmp(path_str, dynamic_cast<SwapDir *>(swap->swapDirs[i].getRaw())->path)
-            ) == 0) {
+        if ((strcasecmp(path_str, dynamic_cast<SwapDir *>(swap->swapDirs[i].getRaw())->path)) == 0) {
             /* this is specific to on-fs Stores. The right
              * way to handle this is probably to have a mapping
              * from paths to stores, and have on-fs stores
@@ -1516,7 +1528,13 @@ parse_cachedir(SquidConfig::_cacheSwap * swap)
     }
 
     /* new cache_dir */
-    assert(swap->n_configured < 63);   /* 7 bits, signed */
+    if (swap->n_configured > 63) {
+        /* 7 bits, signed */
+        debugs(3, DBG_CRITICAL, "WARNING: There is a fixed maximum of 63 cache_dir entries Squid can handle.");
+        debugs(3, DBG_CRITICAL, "WARNING: '" << path_str << "' is one to many.");
+        self_destruct();
+        return;
+    }
 
     allocate_new_swapdir(swap);
 
@@ -1599,6 +1617,22 @@ dump_peer(StoreEntry * entry, const char *name, peer * p)
     }
 }
 
+/**
+ * utility function to prevent getservbyname() being called with a numeric value
+ * on Windows at least it returns garage results.
+ */
+static bool
+isUnsignedNumeric(const char *str, size_t len)
+{
+    if (len < 1) return false;
+
+    for (; len >0 && *str; str++, len--) {
+        if (! isdigit(*str))
+            return false;
+    }
+    return true;
+}
+
 /**
  \param proto  'tcp' or 'udp' for protocol
  \returns       Port the named service is supposed to be listening on.
@@ -1614,7 +1648,8 @@ GetService(const char *proto)
         return 0; /* NEVER REACHED */
     }
     /** Returns either the service port number from /etc/services */
-    port = getservbyname(token, proto);
+    if ( !isUnsignedNumeric(token, strlen(token)) )
+        port = getservbyname(token, proto);
     if (port != NULL) {
         return ntohs((u_short)port->s_port);
     }
@@ -1768,8 +1803,9 @@ parse_peer(peer ** head)
             rfc1738_unescape(p->login);
         } else if (!strncasecmp(token, "connect-timeout=", 16)) {
             p->connect_timeout = xatoi(token + 16);
+        } else if (!strncasecmp(token, "connect-fail-limit=", 19)) {
+            p->connect_fail_limit = xatoi(token + 19);
 #if USE_CACHE_DIGESTS
-
         } else if (!strncasecmp(token, "digest-url=", 11)) {
             p->digest_url = xstrdup(token + 11);
 #endif
@@ -1852,6 +1888,9 @@ parse_peer(peer ** head)
     if (p->weight < 1)
         p->weight = 1;
 
+    if (p->connect_fail_limit < 1)
+        p->connect_fail_limit = 1;
+
     p->icp.version = ICP_VERSION_CURRENT;
 
     p->test_fd = -1;
@@ -2206,6 +2245,9 @@ dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
         if (head->flags.ignore_no_store)
             storeAppendPrintf(entry, " ignore-no-store");
 
+        if (head->flags.ignore_must_revalidate)
+            storeAppendPrintf(entry, " ignore-must-revalidate");
+
         if (head->flags.ignore_private)
             storeAppendPrintf(entry, " ignore-private");
 
@@ -2237,6 +2279,7 @@ parse_refreshpattern(refresh_t ** head)
     int ignore_reload = 0;
     int ignore_no_cache = 0;
     int ignore_no_store = 0;
+    int ignore_must_revalidate = 0;
     int ignore_private = 0;
     int ignore_auth = 0;
 #endif
@@ -2293,6 +2336,8 @@ parse_refreshpattern(refresh_t ** head)
             ignore_no_cache = 1;
         else if (!strcmp(token, "ignore-no-store"))
             ignore_no_store = 1;
+        else if (!strcmp(token, "ignore-must-revalidate"))
+            ignore_must_revalidate = 1;
         else if (!strcmp(token, "ignore-private"))
             ignore_private = 1;
         else if (!strcmp(token, "ignore-auth"))
@@ -2354,6 +2399,9 @@ parse_refreshpattern(refresh_t ** head)
     if (ignore_no_store)
         t->flags.ignore_no_store = 1;
 
+    if (ignore_must_revalidate)
+        t->flags.ignore_must_revalidate = 1;
+
     if (ignore_private)
         t->flags.ignore_private = 1;
 
@@ -2475,13 +2523,11 @@ free_time_t(time_t * var)
     *var = 0;
 }
 
-#if UNUSED_CODE
 static void
 dump_size_t(StoreEntry * entry, const char *name, size_t var)
 {
     storeAppendPrintf(entry, "%s %d\n", name, (int) var);
 }
-#endif
 
 static void
 dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
@@ -2509,7 +2555,6 @@ dump_kb_int64_t(StoreEntry * entry, const char *name, int64_t var)
     storeAppendPrintf(entry, "%s %"PRId64" %s\n", name, var, B_KBYTES_STR);
 }
 
-#if UNUSED_CODE
 static void
 parse_size_t(size_t * var)
 {
@@ -2517,7 +2562,6 @@ parse_size_t(size_t * var)
     i = GetInteger();
     *var = (size_t) i;
 }
-#endif
 
 static void
 parse_b_size_t(size_t * var)
@@ -2727,6 +2771,50 @@ dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings *
     storeAppendPrintf(entry, "\n");
 }
 
+static void
+free_memcachemode(SquidConfig * config)
+{
+    return;
+}
+
+static void
+parse_memcachemode(SquidConfig * config)
+{
+    char *token = strtok(NULL, w_space);
+    if (!token)
+        self_destruct();
+
+    if (strcmp(token, "always") == 0) {
+        Config.onoff.memory_cache_first = 1;
+        Config.onoff.memory_cache_disk = 1;
+    } else if (strcmp(token, "disk") == 0) {
+        Config.onoff.memory_cache_first = 0;
+        Config.onoff.memory_cache_disk = 1;
+    } else if (strncmp(token, "net", 3) == 0) {
+        Config.onoff.memory_cache_first = 1;
+        Config.onoff.memory_cache_disk = 0;
+    } else if (strcmp(token, "never") == 0) {
+        Config.onoff.memory_cache_first = 0;
+        Config.onoff.memory_cache_disk = 0;
+    } else
+        self_destruct();
+}
+
+static void
+dump_memcachemode(StoreEntry * entry, const char *name, SquidConfig &config)
+{
+    storeAppendPrintf(entry, "%s ", name);
+    if (Config.onoff.memory_cache_first && Config.onoff.memory_cache_disk)
+        storeAppendPrintf(entry, "always");
+    else if (!Config.onoff.memory_cache_first && Config.onoff.memory_cache_disk)
+        storeAppendPrintf(entry, "disk");
+    else if (Config.onoff.memory_cache_first && !Config.onoff.memory_cache_disk)
+        storeAppendPrintf(entry, "network");
+    else if (!Config.onoff.memory_cache_first && !Config.onoff.memory_cache_disk)
+        storeAppendPrintf(entry, "none");
+    storeAppendPrintf(entry, "\n");
+}
+
 #include "cf_parser.h"
 
 peer_t
@@ -2754,15 +2842,15 @@ parseNeighborType(const char *s)
 
 #if USE_WCCPv2
 void
-parse_IPAddress_list_token(IPAddress_list ** head, char *token)
+parse_IpAddress_list_token(IpAddress_list ** head, char *token)
 {
     char *t;
     char *host;
     char *tmp;
 
-    IPAddress ipa;
+    IpAddress ipa;
     unsigned short port;
-    IPAddress_list *s;
+    IpAddress_list *s;
 
     host = NULL;
     port = 0;
@@ -2808,24 +2896,24 @@ parse_IPAddress_list_token(IPAddress_list ** head, char *token)
     while (*head)
         head = &(*head)->next;
 
-    s = static_cast<IPAddress_list *>(xcalloc(1, sizeof(*s)));
+    s = static_cast<IpAddress_list *>(xcalloc(1, sizeof(*s)));
     s->s = ipa;
 
     *head = s;
 }
 
 static void
-parse_IPAddress_list(IPAddress_list ** head)
+parse_IpAddress_list(IpAddress_list ** head)
 {
     char *token;
 
     while ((token = strtok(NULL, w_space))) {
-        parse_IPAddress_list_token(head, token);
+        parse_IpAddress_list_token(head, token);
     }
 }
 
 static void
-dump_IPAddress_list(StoreEntry * e, const char *n, const IPAddress_list * s)
+dump_IpAddress_list(StoreEntry * e, const char *n, const IpAddress_list * s)
 {
     char ntoabuf[MAX_IPSTRLEN];
 
@@ -2838,7 +2926,7 @@ dump_IPAddress_list(StoreEntry * e, const char *n, const IPAddress_list * s)
 }
 
 static void
-free_IPAddress_list(IPAddress_list ** head)
+free_IpAddress_list(IpAddress_list ** head)
 {
     if (*head) delete *head;
     *head = NULL;
@@ -2849,7 +2937,7 @@ free_IPAddress_list(IPAddress_list ** head)
  * be used by icp_port and htcp_port
  */
 static int
-check_null_IPAddress_list(const IPAdress_list * s)
+check_null_IpAddress_list(const IpAddress_list * s)
 {
     return NULL == s;
 }
@@ -2911,7 +2999,7 @@ parse_http_port_specification(http_port_list * s, char *token)
     if (NULL == host) {
         s->s.SetAnyAddr();
         s->s.SetPort(port);
-        debugs(3, 3, "http(s)_port: found Listen on wildcard address: " << s->s);
+        debugs(3, 3, "http(s)_port: found Listen on wildcard address: *:" << s->s.GetPort() );
     } else if ( s->s = host ) { /* check/parse numeric IPA */
         s->s.SetPort(port);
         debugs(3, 3, "http(s)_port: Listen on Host/IP: " << host << " --> " << s->s);
@@ -2950,6 +3038,8 @@ parse_http_port_option(http_port_list * s, char *token)
         s->accel = 1;
     } else if (strcmp(token, "accel") == 0) {
         s->accel = 1;
+    } else if (strcmp(token, "allow-direct") == 0) {
+        s->allow_direct = 1;
     } else if (strcmp(token, "no-connection-auth") == 0) {
         s->connection_auth_disabled = true;
     } else if (strcmp(token, "connection-auth=off") == 0) {
@@ -3091,10 +3181,64 @@ void
 add_http_port(char *portspec)
 {
     http_port_list *s = create_http_port(portspec);
+    // we may need to merge better of the above returns a list with clones
+    assert(s->next == NULL);
     s->next = Config.Sockaddr.http;
     Config.Sockaddr.http = s;
 }
 
+#if IPV6_SPECIAL_SPLITSTACK
+http_port_list *
+clone_http_port_list(http_port_list *a)
+{
+    http_port_list *b = new http_port_list(a->protocol);
+
+    b->s = a->s;
+    if (a->name)
+        b->name = xstrdup(a->name);
+    if (a->defaultsite)
+        b->defaultsite = xstrdup(a->defaultsite);
+
+    b->intercepted = a->intercepted;
+    b->spoof_client_ip = a->spoof_client_ip;
+    b->accel = a->accel;
+    b->allow_direct = a->allow_direct;
+    b->vhost = a->vhost;
+    b->sslBump = a->sslBump;
+    b->vport = a->vport;
+    b->connection_auth_disabled = a->connection_auth_disabled;
+    b->disable_pmtu_discovery = a->disable_pmtu_discovery;
+
+    memcpy( &(b->tcp_keepalive), &(a->tcp_keepalive), sizeof(a->tcp_keepalive));
+
+#if 0
+    // AYJ: 2009-07-18: for now SSL does not clone. Configure separate ports with IPs and SSL settings
+
+#if USE_SSL
+    // XXX: temporary hack to ease move of SSL options to http_port
+    http_port_list &http;
+
+    char *cert;
+    char *key;
+    int version;
+    char *cipher;
+    char *options;
+    char *clientca;
+    char *cafile;
+    char *capath;
+    char *crlfile;
+    char *dhfile;
+    char *sslflags;
+    char *sslcontext;
+    SSL_CTX *sslContext;
+#endif
+
+#endif /*0*/
+
+    return b;
+}
+#endif
+
 static void
 parse_http_port_list(http_port_list ** head)
 {
@@ -3112,6 +3256,15 @@ parse_http_port_list(http_port_list ** head)
         parse_http_port_option(s, token);
     }
 
+#if IPV6_SPECIAL_SPLITSTACK
+    if (s->s.IsAnyAddr()) {
+        // clone the port options from *s to *(s->next)
+        s->next = clone_http_port_list(s);
+        s->next->s.SetIPv4();
+        debugs(3, 3, "http(s)_port: clone wildcard address for split-stack: " << s->s << " and " << s->next->s);
+    }
+#endif
+
     while (*head)
         head = &(*head)->next;
 
@@ -3157,9 +3310,9 @@ dump_generic_http_port(StoreEntry * e, const char *n, const http_port_list * s)
 
     if (s->tcp_keepalive.enabled) {
         if (s->tcp_keepalive.idle || s->tcp_keepalive.interval || s->tcp_keepalive.timeout) {
-            storeAppendPrintf(e, " tcp_keepalive=%d,%d,%d", s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
+            storeAppendPrintf(e, " tcpkeepalive=%d,%d,%d", s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
         } else {
-            storeAppendPrintf(e, " tcp_keepalive");
+            storeAppendPrintf(e, " tcpkeepalive");
         }
     }
 
@@ -3388,6 +3541,10 @@ parse_access_log(customlog ** logs)
         cl->type = CLF_SQUID;
     } else if (strcmp(logdef_name, "common") == 0) {
         cl->type = CLF_COMMON;
+#if ICAP_CLIENT
+    } else if (strcmp(logdef_name, "icap_squid") == 0) {
+        cl->type = CLF_ICAP_SQUID;
+#endif
     } else {
         debugs(3, 0, "Log format '" << logdef_name << "' is not defined");
         self_destruct();
@@ -3440,7 +3597,11 @@ dump_access_log(StoreEntry * entry, const char *name, customlog * logs)
         case CLF_COMMON:
             storeAppendPrintf(entry, "%s squid", log->filename);
             break;
-
+#if ICAP_CLIENT
+        case CLF_ICAP_SQUID:
+            storeAppendPrintf(entry, "%s icap_squid", log->filename);
+            break;
+#endif
         case CLF_AUTO:
 
             if (log->aclList)
@@ -3467,6 +3628,7 @@ free_logformat(logformat ** definitions)
     while (*definitions) {
         logformat *format = *definitions;
         *definitions = format->next;
+        safe_free(format->name);
         accessLogFreeLogFormat(&format->format);
         xfree(format);
     }
@@ -3499,6 +3661,12 @@ parse_adaptation_service_set_type()
     Adaptation::Config::ParseServiceSet();
 }
 
+static void
+parse_adaptation_service_chain_type()
+{
+    Adaptation::Config::ParseServiceChain();
+}
+
 static void
 parse_adaptation_access_type()
 {
@@ -3511,19 +3679,19 @@ parse_adaptation_access_type()
 #if ICAP_CLIENT
 
 static void
-parse_icap_service_type(ICAPConfig * cfg)
+parse_icap_service_type(Adaptation::Icap::Config * cfg)
 {
     cfg->parseService();
 }
 
 static void
-free_icap_service_type(ICAPConfig * cfg)
+free_icap_service_type(Adaptation::Icap::Config * cfg)
 {
     cfg->freeService();
 }
 
 static void
-dump_icap_service_type(StoreEntry * entry, const char *name, const ICAPConfig &cfg)
+dump_icap_service_type(StoreEntry * entry, const char *name, const Adaptation::Icap::Config &cfg)
 {
     cfg.dumpService(entry, name);
 }
@@ -3550,19 +3718,19 @@ parse_icap_access_type()
 #if USE_ECAP
 
 static void
-parse_ecap_service_type(Ecap::Config * cfg)
+parse_ecap_service_type(Adaptation::Ecap::Config * cfg)
 {
     cfg->parseService();
 }
 
 static void
-free_ecap_service_type(Ecap::Config * cfg)
+free_ecap_service_type(Adaptation::Ecap::Config * cfg)
 {
     cfg->freeService();
 }
 
 static void
-dump_ecap_service_type(StoreEntry * entry, const char *name, const Ecap::Config &cfg)
+dump_ecap_service_type(StoreEntry * entry, const char *name, const Adaptation::Ecap::Config &cfg)
 {
     cfg.dumpService(entry, name);
 }