From 042cc1f69ec0878f542667cb684378869f859911 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 2 Mar 2009 23:05:31 +0000 Subject: - 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. --- lib/url.c | 36 +++++++++++++++++++++++++++++++++++- lib/urldata.h | 35 ++++++++++++++++++++++------------- 2 files changed, 57 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/url.c b/lib/url.c index 389fdc84f..6d2e6d4b7 100644 --- a/lib/url.c +++ b/lib/url.c @@ -683,6 +683,12 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) 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 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, 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 @@ static CURLcode setup_connection_internals(struct SessionHandle *data, 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 6969f1ebb..a50ede005 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -891,19 +891,26 @@ struct connectdata { 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 @@ struct UserDefined { 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 -- cgit v1.2.3