- David Kierznowski notified us about a security flaw
  (http://curl.haxx.se/docs/adv_20090303.html also known as CVE-2009-0037) in
  which previous libcurl versions (by design) can be tricked to access an
  arbitrary local/different file instead of a remote one when
  CURLOPT_FOLLOWLOCATION is enabled. This flaw is now fixed in this release
  together this the addition of two new setopt options for controlling this
  new behavior:

  o CURLOPT_REDIR_PROTOCOLS controls what protocols libcurl is allowed to
  follow to when CURLOPT_FOLLOWLOCATION is enabled. By default, this option
  excludes the FILE and SCP protocols and thus you nee to explicitly allow
  them in your app if you really want that behavior.

  o CURLOPT_PROTOCOLS controls what protocol(s) libcurl is allowed to fetch
  using the primary URL option. This is useful if you want to allow a user or
  other outsiders control what URL to pass to libcurl and yet not allow all
  protocols libcurl may have been built to support.
diff --git a/CHANGES b/CHANGES
index 4074f10..10e6b7d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,27 @@
 
                                   Changelog
 
+Version 7.19.4 (3 March 2009)
+
+Daniel Stenberg (3 Mar 2009)
+- David Kierznowski notified us about a security flaw
+  (http://curl.haxx.se/docs/adv_20090303.html also known as CVE-2009-0037) in
+  which previous libcurl versions (by design) can be tricked to access an
+  arbitrary local/different file instead of a remote one when
+  CURLOPT_FOLLOWLOCATION is enabled. This flaw is now fixed in this release
+  together this the addition of two new setopt options for controlling this
+  new behavior:
+
+  o CURLOPT_REDIR_PROTOCOLS controls what protocols libcurl is allowed to
+  follow to when CURLOPT_FOLLOWLOCATION is enabled. By default, this option
+  excludes the FILE and SCP protocols and thus you nee to explicitly allow
+  them in your app if you really want that behavior.
+
+  o CURLOPT_PROTOCOLS controls what protocol(s) libcurl is allowed to fetch
+  using the primary URL option. This is useful if you want to allow a user or
+  other outsiders control what URL to pass to libcurl and yet not allow all
+  protocols libcurl may have been built to support.
+
 Daniel Stenberg (27 Feb 2009)
 - Senthil Raja Velu reported a problem when CURLOPT_INTERFACE and
   CURLOPT_LOCALPORT were used together (the local port bind failed), and
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 0027eeb..7152534 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -2,11 +2,16 @@
 
  Public curl releases:         110
  Command line options:         132
- curl_easy_setopt() options:   161
+ curl_easy_setopt() options:   163
  Public functions in libcurl:  58
  Known libcurl bindings:       38
  Contributors:                 700
 
+This release includes the following security-related fix:
+
+ o CVE-2009-0037 with the curl advisory here:
+   http://curl.haxx.se/docs/adv_20090303.html
+
 This release includes the following changes:
 
  o Added CURLOPT_NOPROXY and the corresponding --noproxy
@@ -24,6 +29,7 @@
  o CURLOPT_FTP_CREATE_MISSING_DIRS can now be set to 2 to retry the CWD even
    when MKD fails
  o GnuTLS initing moved to curl_global_init()
+ o Added CURLOPT_REDIR_PROTOCOLS and CURLOPT_PROTOCOLS
 
 This release includes the following bugfixes:
 
@@ -59,6 +65,6 @@
  Patrick Scott, Hidemoto Nakada, Jocelyn Jaubert, Andre Guibert de Bruet,
  Kamil Dudka, Patrik Thunstrom, Linus Nielsen Feltzing, Mark Incley,
  Daniel Johnson, James Cheng, Brian J. Murrell, Senthil Raja Velu,
- Markus Koetter
+ Markus Koetter, David Kierznowski, Michal Marek
 
         Thanks! (and sorry if I forgot to mention someone)
diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3
index 9c4c6af..dd3473b 100644
--- a/docs/libcurl/curl_easy_setopt.3
+++ b/docs/libcurl/curl_easy_setopt.3
@@ -440,6 +440,26 @@
 
 \fICURLOPT_URL\fP is the only option that \fBmust\fP be set before
 \fIcurl_easy_perform(3)\fP is called.
+
+\fICURLOPT_PROTOCOLS\fP can be used to limit what protocols libcurl will use
+for this transfer, independent of what libcurl has been compiled to
+support. That may be useful if you accept the URL from an external source and
+want to limit the accessibility.
+.IP CURLOPT_PROTOCOLS
+Pass a long that holds a bitmask of CURLPROTO_* defines. If used, this bitmask
+limits what protocols libcurl may use in the transfer. This allows you to have
+a libcurl built to support a wide range of protocols but still limit specific
+transfers to only be allowed to use a subset of them. By default libcurl will
+accept all protocols it supports. See also
+\fICURLOPT_REDIR_PROTOCOLS\fP. (Added in 7.19.4)
+.IP CURLOPT_REDIR_PROTOCOLS
+Pass a long that holds a bitmask of CURLPROTO_* defines. If used, this bitmask
+limits what protocols libcurl may use in a transfer that it follows to in a
+redirect when \fICURLOPT_FOLLOWLOCATION\fP is enabled. This allows you to
+limit specific transfers to only be allowed to use a subset of protocols in
+redirections. By default libcurl will allow all protocols except for FILE and
+SCP. This is a difference compared to pre-7.19.4 versions which
+unconditionally would follow to all protocols supported. (Added in 7.19.4)
 .IP CURLOPT_PROXY
 Set HTTP proxy to use. The parameter should be a char * to a zero terminated
 string holding the host name or dotted IP address. To specify port number in
@@ -743,6 +763,10 @@
 and follow new Location: headers all the way until no more such headers are
 returned. \fICURLOPT_MAXREDIRS\fP can be used to limit the number of redirects
 libcurl will follow.
+
+NOTE: since 7.19.4, libcurl can limit to what protocols it will automatically
+follow. The accepted protocols are set with \fICURLOPT_REDIR_PROTOCOLS\fP and
+it excludes the FILE protocol by default.
 .IP CURLOPT_UNRESTRICTED_AUTH
 A parameter set to 1 tells the library it can continue to send authentication
 (user+password) when following locations, even when hostname changed. This
diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions
index 7184ecc..e429f2e 100644
--- a/docs/libcurl/symbols-in-versions
+++ b/docs/libcurl/symbols-in-versions
@@ -191,6 +191,7 @@
 CURLOPT_PROGRESSDATA            7.1
 CURLOPT_PROGRESSFUNCTION        7.1
 CURLOPT_PROGRESSMODE            7.1           -           7.9.2
+CURLOPT_PROTOCOLS               7.19.4
 CURLOPT_PROXY                   7.1
 CURLOPT_PROXYAUTH               7.10.7
 CURLOPT_PROXYPASSWORD           7.19.1
@@ -205,6 +206,7 @@
 CURLOPT_RANGE                   7.1
 CURLOPT_READDATA                7.9.7
 CURLOPT_READFUNCTION            7.1
+CURLOPT_REDIR_PROTOCOLS         7.19.4
 CURLOPT_REFERER                 7.1
 CURLOPT_RESUME_FROM             7.1
 CURLOPT_RESUME_FROM_LARGE       7.11.0
@@ -261,6 +263,19 @@
 CURLOPT_WRITEDATA               7.9.7
 CURLOPT_WRITEFUNCTION           7.1
 CURLOPT_WRITEHEADER             7.1
+CURLPROTO_ALL                   7.19.4
+CURLPROTO_DICT                  7.19.4
+CURLPROTO_FILE                  7.19.4
+CURLPROTO_FTP                   7.19.4
+CURLPROTO_FTPS                  7.19.4
+CURLPROTO_HTTP                  7.19.4
+CURLPROTO_HTTPS                 7.19.4
+CURLPROTO_LDAP                  7.19.4
+CURLPROTO_LDAPS                 7.19.4
+CURLPROTO_SCP                   7.19.4
+CURLPROTO_SFTP                  7.19.4
+CURLPROTO_TELNET                7.19.4
+CURLPROTO_TFTP                  7.19.4
 CURLPROXY_HTTP                  7.10
 CURLPROXY_HTTP_1_0              7.19.4
 CURLPROXY_SOCKS4                7.10
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 69fe457..8d952ca 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -550,6 +550,21 @@
   CURLFTPMETHOD_LAST       /* not an option, never use */
 } curl_ftpmethod;
 
+/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */
+#define CURLPROTO_HTTP   (1<<0)
+#define CURLPROTO_HTTPS  (1<<1)
+#define CURLPROTO_FTP    (1<<2)
+#define CURLPROTO_FTPS   (1<<3)
+#define CURLPROTO_SCP    (1<<4)
+#define CURLPROTO_SFTP   (1<<5)
+#define CURLPROTO_TELNET (1<<6)
+#define CURLPROTO_LDAP   (1<<7)
+#define CURLPROTO_LDAPS  (1<<8)
+#define CURLPROTO_DICT   (1<<9)
+#define CURLPROTO_FILE   (1<<10)
+#define CURLPROTO_TFTP   (1<<11)
+#define CURLPROTO_ALL    (~0) /* enable everything */
+
 /* long may be 32 or 64 bits, but we should never depend on anything else
    but 32 */
 #define CURLOPTTYPE_LONG          0
@@ -1185,6 +1200,18 @@
   /* Socks Service */
   CINIT(SOCKS5_GSSAPI_NEC, LONG, 180),
 
+  /* set the bitmask for the protocols that are allowed to be used for the
+     transfer, which thus helps the app which takes URLs from users or other
+     external inputs and want to restrict what protocol(s) to deal
+     with. Defaults to CURLPROTO_ALL. */
+  CINIT(PROTOCOLS, LONG, 181),
+
+  /* set the bitmask for the protocols that libcurl is allowed to follow to,
+     as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
+     to be set in both bitmasks to be allowed to get redirected to. Defaults
+     to all protocols except FILE and SCP. */
+  CINIT(REDIR_PROTOCOLS, LONG, 182),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
diff --git a/lib/url.c b/lib/url.c
index 389fdc8..6d2e6d4 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -683,6 +683,12 @@
   set->new_file_perms = 0644;    /* Default permissions */
   set->new_directory_perms = 0755; /* Default permissions */
 
+  /* for the *protocols fields we don't use the CURLPROTO_ALL convenience
+     define since we internally only use the lower 16 bits for the passed
+     in bitmask to not conflict with the private bits */
+  set->allowed_protocols = PROT_EXTMASK;
+  set->redir_protocols =
+    PROT_EXTMASK & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */
 
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
   /*
@@ -2217,6 +2223,22 @@
     data->set.scope = (unsigned int) va_arg(param, long);
     break;
 
+  case CURLOPT_PROTOCOLS:
+    /* set the bitmask for the protocols that are allowed to be used for the
+       transfer, which thus helps the app which takes URLs from users or other
+       external inputs and want to restrict what protocol(s) to deal
+       with. Defaults to CURLPROTO_ALL. */
+    data->set.allowed_protocols = va_arg(param, long) & PROT_EXTMASK;
+    break;
+
+  case CURLOPT_REDIR_PROTOCOLS:
+    /* set the bitmask for the protocols that libcurl is allowed to follow to,
+       as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
+       to be set in both bitmasks to be allowed to get redirected to. Defaults
+       to all protocols except FILE and SCP. */
+    data->set.redir_protocols = va_arg(param, long) & PROT_EXTMASK;
+    break;
+
   default:
     /* unknown tag and its companion, just ignore: */
     result = CURLE_FAILED_INIT; /* correct this */
@@ -3371,7 +3393,19 @@
 
   for (pp = protocols; (p = *pp) != NULL; pp++)
     if(Curl_raw_equal(p->scheme, conn->protostr)) {
-      /* Protocol found in table. Perform setup complement if some. */
+      /* Protocol found in table. Check if allowed */
+      if(!(data->set.allowed_protocols & p->protocol))
+        /* nope, get out */
+        break;
+
+      /* it is allowed for "normal" request, now do an extra check if this is
+         the result of a redirect */
+      if(data->state.this_is_a_follow &&
+         !(data->set.redir_protocols & p->protocol))
+        /* nope, get out */
+        break;
+
+      /* Perform setup complement if some. */
       conn->handler = p;
 
       if(p->setup_connection) {
diff --git a/lib/urldata.h b/lib/urldata.h
index 6969f1e..a50ede0 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -891,19 +891,26 @@
   long connectindex; /* what index in the connection cache connects index this
                         particular struct has */
   long protocol; /* PROT_* flags concerning the protocol set */
-#define PROT_MISSING (1<<0)
-#define PROT_HTTP    (1<<2)
-#define PROT_HTTPS   (1<<3)
-#define PROT_FTP     (1<<4)
-#define PROT_TELNET  (1<<5)
-#define PROT_DICT    (1<<6)
-#define PROT_LDAP    (1<<7)
-#define PROT_FILE    (1<<8)
-#define PROT_FTPS    (1<<9)
-#define PROT_SSL     (1<<10) /* protocol requires SSL */
-#define PROT_TFTP    (1<<11)
-#define PROT_SCP     (1<<12)
-#define PROT_SFTP    (1<<13)
+#define PROT_HTTP    CURLPROTO_HTTP
+#define PROT_HTTPS   CURLPROTO_HTTPS
+#define PROT_FTP     CURLPROTO_FTP
+#define PROT_TELNET  CURLPROTO_TELNET
+#define PROT_DICT    CURLPROTO_DICT
+#define PROT_LDAP    CURLPROTO_LDAP
+#define PROT_FILE    CURLPROTO_FILE
+#define PROT_FTPS    CURLPROTO_FTPS
+#define PROT_TFTP    CURLPROTO_TFTP
+#define PROT_SCP     CURLPROTO_SCP
+#define PROT_SFTP    CURLPROTO_SFTP
+
+/* CURLPROTO_TFTP (1<<11) is currently the highest used bit in the public
+   bitmask. We make sure we use "private bits" above the first 16 to make
+   things easier. */
+
+#define PROT_EXTMASK 0xffff
+
+#define PROT_SSL     (1<<22) /* protocol requires SSL */
+#define PROT_MISSING (1<<23)
 
 #define PROT_CLOSEACTION PROT_FTP /* these ones need action before socket
                                      close */
@@ -1533,6 +1540,8 @@
                                via an HTTP proxy */
   char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
   unsigned int scope;    /* address scope for IPv6 */
+  long allowed_protocols;
+  long redir_protocols;
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
   long socks5_gssapi_nec; /* flag to support nec socks5 server */
 #endif