]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Bug #1094: Fix for CVE-1999-0710: cachemgr malicouse use
authorserassio <>
Sun, 24 Apr 2005 02:40:50 +0000 (02:40 +0000)
committerserassio <>
Sun, 24 Apr 2005 02:40:50 +0000 (02:40 +0000)
This patch adds access controls to the cachemgr.cgi script, preventing
it from being abused to reach other servers than allowed in a local
configuration file.

Forward port of 2.5 patch.

configure.in
include/config.h
src/Makefile.am
src/cachemgr.cc
src/cachemgr.conf [new file with mode: 0755]

index 71cbe2708d6338d3915b403d69dfcf148c651cfa..e121d5dc1c651a26ddd386248150f53ece445866 100644 (file)
@@ -3,7 +3,7 @@ dnl  Configuration input file for Squid
 dnl
 dnl  Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9)
 dnl
-dnl  $Id: configure.in,v 1.372 2005/03/26 22:29:41 serassio Exp $
+dnl  $Id: configure.in,v 1.373 2005/04/23 20:40:50 serassio Exp $
 dnl
 dnl
 dnl
@@ -13,7 +13,7 @@ AC_CONFIG_SRCDIR([src/main.cc])
 AC_CONFIG_AUX_DIR(cfgaux)
 AM_INIT_AUTOMAKE(squid, 3.0-PRE3-CVS)
 AM_CONFIG_HEADER(include/autoconf.h)
-AC_REVISION($Revision: 1.372 $)dnl
+AC_REVISION($Revision: 1.373 $)dnl
 AC_PREFIX_DEFAULT(/usr/local/squid)
 AM_MAINTAINER_MODE
 
@@ -1624,6 +1624,7 @@ AC_CHECK_HEADERS( \
        errno.h \
        execinfo.h \
        fcntl.h \
+       fnmatch.h \
        getopt.h \
        gnumalloc.h \
        grp.h \
index 27e076c58b3354237f9dced1633bae97038e585f..93834f599aa1fbb66a92839ea37aab6517e4c78a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: config.h,v 1.17 2005/04/18 21:52:40 hno Exp $
+ * $Id: config.h,v 1.18 2005/04/23 20:40:50 serassio Exp $
  *
  * AUTHOR: Duane Wessels
  *
@@ -332,6 +332,8 @@ typedef union {
 
 #if !defined(CACHEMGR_HOSTNAME)
 #define CACHEMGR_HOSTNAME ""
+#else
+#define CACHEMGR_HOSTNAME_DEFINED 1
 #endif
 
 #if SQUID_DETECT_UDP_SO_SNDBUF > 16384
index 494c217c05652ed59941343ffab8db82b8d07a59..892a739a19305ecbb8dd2ae277bfbbb571933210 100644 (file)
@@ -1,7 +1,7 @@
 #
 #  Makefile for the Squid Object Cache server
 #
-#  $Id: Makefile.am,v 1.107 2005/04/06 19:07:03 serassio Exp $
+#  $Id: Makefile.am,v 1.108 2005/04/23 20:40:50 serassio Exp $
 #
 #  Uncomment and customize the following to suit your needs:
 #
@@ -196,6 +196,7 @@ nodist_cf_gen_HEADER = cf_gen_defines.h
 cf_gen.$(OBJEXT): cf_gen_defines.h
 squidclient_SOURCES = client.cc
 cachemgr__CGIEXT__SOURCES = cachemgr.cc
+cachemgr__CGIEXT__CFLAGS = -DDEFAULT_CACHEMGR_CONFIG=\"$(DEFAULT_CACHEMGR_CONFIG)\" $(AM_CFLAGS)
 
 all_FSMODULES = \
        fs/aufs/StoreFSaufs.cc \
@@ -783,6 +784,7 @@ EXTRA_DIST = \
        mk-string-arrays.pl \
        repl_modules.sh \
        mib.txt \
+       cachemgr.conf \
        mime.conf.default
 
 libAIO_a_SOURCES = \
@@ -824,6 +826,7 @@ DiskIO_DiskDaemon_diskd_LDADD = $(top_builddir)/lib/libmiscutil.a @XTRA_LIBS@
 
 DEFAULT_PREFIX         = $(prefix)
 DEFAULT_CONFIG_FILE     = $(sysconfdir)/squid.conf
+DEFAULT_CACHEMGR_CONFIG = $(sysconfdir)/cachemgr.conf
 DEFAULT_MIME_TABLE     = $(sysconfdir)/mime.conf
 DEFAULT_DNSSERVER       = $(libexecdir)/`echo dnsserver | sed '$(transform);s/$$/$(EXEEXT)/'`
 DEFAULT_LOG_PREFIX     = $(localstatedir)/logs
@@ -909,6 +912,12 @@ install-data-local: install-sysconfDATA install-dataDATA
                echo "$(INSTALL_DATA) squid.conf.default $(DESTDIR)$(DEFAULT_CONFIG_FILE)"; \
                $(INSTALL_DATA) squid.conf.default $(DESTDIR)$(DEFAULT_CONFIG_FILE); \
        fi
+       @if test -f $(DESTDIR)$(DEFAULT_CACHEMGR_CONFIG) ; then \
+               echo "$@ will not overwrite existing $(DESTDIR)$(DEFAULT_CACHEMGR_CONFIG)" ; \
+       else \
+               echo "$(INSTALL_DATA) $(srcdir)/cachemgr.conf $(DESTDIR)$(DEFAULT_CACHEMGR_CONFIG)"; \
+               $(INSTALL_DATA) $(srcdir)/cachemgr.conf $(DESTDIR)$(DEFAULT_CACHEMGR_CONFIG); \
+       fi
        $(mkinstalldirs) $(DESTDIR)$(DEFAULT_LOG_PREFIX)
 
 uninstall-local:
index 7bb171623eb1641ca7f5bbeb53495cc70c465082..3ebc7152d70204d3984060a7e1a53b2b5531c100 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: cachemgr.cc,v 1.108 2005/04/18 21:52:42 hno Exp $
+ * $Id: cachemgr.cc,v 1.109 2005/04/23 20:40:51 serassio Exp $
  *
  * DEBUG: section 0     CGI Cache Manager
  * AUTHOR: Duane Wessels
 #if HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
+#if HAVE_FNMATCH_H
+#include <fnmatch.h>
+#endif
 
 #include <assert.h>
 
 #include "util.h"
 #include "snprintf.h"
 
+#ifndef DEFAULT_CACHEMGR_CONFIG
+#define DEFAULT_CACHEMGR_CONFIG "/etc/squid/cahemgr.conf"
+#endif
+
 typedef struct
 {
+    char *server;
     char *hostname;
     int port;
     char *action;
@@ -188,6 +196,8 @@ static void decode_pub_auth(cachemgr_request * req);
 static void reset_auth(cachemgr_request * req);
 static const char *make_auth_header(const cachemgr_request * req);
 
+static int check_target_acl(const char *hostname, int port);
+
 #ifdef _SQUID_MSWIN_
 static int s_iInitCount = 0;
 int Win32SockInit(void)
@@ -287,11 +297,14 @@ print_trailer(void)
 static void
 auth_html(const char *host, int port, const char *user_name)
 {
+    FILE *fp;
+    int need_host = 1;
+
     if (!user_name)
         user_name = "";
 
     if (!host || !strlen(host))
-        host = "localhost";
+        host = "";
 
     printf("Content-Type: text/html\r\n\r\n");
 
@@ -313,13 +326,76 @@ auth_html(const char *host, int port, const char *user_name)
 
     printf("<TABLE BORDER=\"0\" CELLPADDING=\"10\" CELLSPACING=\"1\">\n");
 
-    printf("<TR><TH ALIGN=\"left\">Cache Host:</TH><TD><INPUT NAME=\"host\" ");
 
-    printf("size=\"30\" VALUE=\"%s\"></TD></TR>\n", host);
+    fp = fopen("cachemgr.conf", "r");
+
+    if (fp == NULL)
+        fp = fopen(DEFAULT_CACHEMGR_CONFIG, "r");
+
+    if (fp != NULL) {
+        int servers = 0;
+        char config_line[BUFSIZ];
+
+        while (fgets(config_line, BUFSIZ, fp)) {
+            char *server, *comment;
+            strtok(config_line, "\r\n");
+
+            if (config_line[0] == '#')
+                continue;
+
+            if (config_line[0] == '\0')
+                continue;
+
+            if ((server = strtok(config_line, " \t")) == NULL)
+                continue;
+
+            if (strchr(server, '*') || strchr(server, '[') || strchr(server, '?')) {
+                need_host = -1;
+                continue;
+            }
+
+            comment = strtok(NULL, "");
+
+            if (comment)
+                while (*comment == ' ' || *comment == '\t')
+                    comment++;
+
+            if (!comment || !*comment)
+                comment = server;
+
+            if (!servers) {
+                printf("<TR><TH ALIGN=\"left\">Cache Server:</TH><TD><SELECT NAME=\"server\">\n");
+            }
+
+            printf("<OPTION VALUE=\"%s\"%s>%s</OPTION>\n", server, (servers || *host) ? "" : " SELECTED", comment);
+            servers++;
+        }
+
+        if (servers) {
+            if (need_host == 1 && !*host)
+                need_host = 0;
+
+            if (need_host)
+                printf("<OPTION VALUE=\"\"%s>Other</OPTION>\n", (*host) ? " SELECTED" : "");
+
+            printf("</SELECT></TR>\n");
+        }
+
+        fclose(fp);
+    }
+
+    if (need_host) {
+        if (need_host == 1 && !*host)
+            host = "localhost";
+
+        printf("<TR><TH ALIGN=\"left\">Cache Host:</TH><TD><INPUT NAME=\"host\" ");
 
-    printf("<TR><TH ALIGN=\"left\">Cache Port:</TH><TD><INPUT NAME=\"port\" ");
+        printf("size=\"30\" VALUE=\"%s\"></TD></TR>\n", host);
 
-    printf("size=\"30\" VALUE=\"%d\"></TD></TR>\n", port);
+        printf("<TR><TH ALIGN=\"left\">Cache Port:</TH><TD><INPUT NAME=\"port\" ");
+
+        printf("size=\"30\" VALUE=\"%d\"></TD></TR>\n", port);
+    }
 
     printf("<TR><TH ALIGN=\"left\">Manager name:</TH><TD><INPUT NAME=\"user_name\" ");
 
@@ -702,11 +778,17 @@ process_request(cachemgr_request * req)
         req->action = xstrdup("");
     }
 
-    if (!strcmp(req->action, "authenticate")) {
+    if (strcmp(req->action, "authenticate") == 0) {
         auth_html(req->hostname, req->port, req->user_name);
         return 0;
     }
 
+    if (!check_target_acl(req->hostname, req->port)) {
+        snprintf(buf, 1024, "target %s:%d not allowed in cachemgr.conf\n", req->hostname, req->port);
+        error_html(buf);
+        return 1;
+    }
+
     if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
         snprintf(buf, 1024, "socket: %s\n", xstrerror());
         error_html(buf);
@@ -889,7 +971,13 @@ read_request(void) {
 
         *q++ = '\0';
 
-        if (0 == strcasecmp(t, "host") && strlen(q))
+        rfc1738_unescape(t);
+
+        rfc1738_unescape(q);
+
+        if (0 == strcasecmp(t, "server") && strlen(q))
+            req->server = xstrdup(q);
+        else if (0 == strcasecmp(t, "host") && strlen(q))
             req->hostname = xstrdup(q);
         else if (0 == strcasecmp(t, "port") && strlen(q))
             req->port = atoi(q);
@@ -903,6 +991,14 @@ read_request(void) {
             req->action = xstrdup(q);
     }
 
+    if (req->server && !req->hostname) {
+        char *p;
+        req->hostname = strtok(req->server, ":");
+
+        if ((p = strtok(NULL, ":")))
+            req->port = atoi(p);
+    }
+
     make_pub_auth(req);
     debug(1) fprintf(stderr, "cmgr: got req: host: '%s' port: %d uname: '%s' passwd: '%s' auth: '%s' oper: '%s'\n",
                      safe_str(req->hostname), req->port, safe_str(req->user_name), safe_str(req->passwd), safe_str(req->pub_auth), safe_str(req->action));
@@ -1027,3 +1123,77 @@ make_auth_header(const cachemgr_request * req) {
 
     return buf;
 }
+
+static int
+check_target_acl(const char *hostname, int port) {
+    char config_line[BUFSIZ];
+    FILE *fp = NULL;
+    int ret = 0;
+    fp = fopen("cachemgr.conf", "r");
+
+    if (fp == NULL)
+        fp = fopen(DEFAULT_CACHEMGR_CONFIG, "r");
+
+    if (fp == NULL) {
+#ifdef CACHEMGR_HOSTNAME_DEFINED
+
+        if (strcmp(hostname, CACHEMGR_HOSTNAME) == 0 && port == CACHE_HTTP_PORT)
+            return 1;
+
+#else
+
+        if (strcmp(hostname, "localhost") == 0)
+            return 1;
+
+        if (strcmp(hostname, getfullhostname()) == 0)
+            return 1;
+
+#endif
+
+        return 0;
+    }
+
+    while (fgets(config_line, BUFSIZ, fp)) {
+        char *token = NULL;
+        strtok(config_line, " \r\n\t");
+
+        if (config_line[0] == '#')
+            continue;
+
+        if (config_line[0] == '\0')
+            continue;
+
+        if ((token = strtok(config_line, ":")) == NULL)
+            continue;
+
+#if HAVE_FNMATCH_H
+
+        if (fnmatch(token, hostname, 0) != 0)
+            continue;
+
+#else
+
+        if (strcmp(token, hostname) != 0)
+            continue;
+
+#endif
+
+        if ((token = strtok(NULL, ":")) != NULL) {
+            int i;
+
+            if (sscanf(token, "%d", &i) != 1)
+                continue;
+
+            if (i != port)
+                continue;
+        } else if (port != CACHE_HTTP_PORT)
+            continue;
+
+        ret = 1;
+
+        break;
+    }
+
+    fclose(fp);
+    return ret;
+}
diff --git a/src/cachemgr.conf b/src/cachemgr.conf
new file mode 100755 (executable)
index 0000000..b7a2937
--- /dev/null
@@ -0,0 +1,12 @@
+# This file controls which servers may be managed by
+# the cachemgr.cgi script
+#
+# The file consists of one server per line on the format
+#   hostname:port  description
+#
+# Specifying :port is optional. If not specified then
+# the default proxy port is assumed.
+#
+# hostname is matched using shell filename matching, allowing
+# * and other shell wildcards.
+localhost