From: serassio <> Date: Sun, 24 Apr 2005 02:40:50 +0000 (+0000) Subject: Bug #1094: Fix for CVE-1999-0710: cachemgr malicouse use X-Git-Tag: SQUID_3_0_PRE4~798 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=42ad37afe78aa892c232a24047339ffbc3dd3d37;p=thirdparty%2Fsquid.git Bug #1094: Fix for CVE-1999-0710: cachemgr malicouse use 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. --- diff --git a/configure.in b/configure.in index 71cbe2708d..e121d5dc1c 100644 --- a/configure.in +++ b/configure.in @@ -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 \ diff --git a/include/config.h b/include/config.h index 27e076c58b..93834f599a 100644 --- a/include/config.h +++ b/include/config.h @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index 494c217c05..892a739a19 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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: diff --git a/src/cachemgr.cc b/src/cachemgr.cc index 7bb171623e..3ebc7152d7 100644 --- a/src/cachemgr.cc +++ b/src/cachemgr.cc @@ -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 @@ -125,14 +125,22 @@ #if HAVE_SYS_SELECT_H #include #endif +#if HAVE_FNMATCH_H +#include +#endif #include #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("\n"); - printf("\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("\n"); + } + + fclose(fp); + } + + if (need_host) { + if (need_host == 1 && !*host) + host = "localhost"; + + printf("\n", host); - printf("size=\"30\" VALUE=\"%d\">\n", port); + printf("\n", port); + } printf("
Cache Host:
Cache Server:
Cache Host:Cache Port:
Cache Port:
Manager name: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 index 0000000000..b7a2937aa4 --- /dev/null +++ b/src/cachemgr.conf @@ -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