From: Daniel Stenberg Date: Mon, 13 Jun 2022 07:30:45 +0000 (+0200) Subject: setopt: add CURLOPT_PROTOCOLS_STR and CURLOPT_REDIR_PROTOCOLS_STR X-Git-Tag: curl-7_85_0~205 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e6f8445edef8e7996d;p=thirdparty%2Fcurl.git setopt: add CURLOPT_PROTOCOLS_STR and CURLOPT_REDIR_PROTOCOLS_STR ... as replacements for deprecated CURLOPT_PROTOCOLS and CURLOPT_REDIR_PROTOCOLS as these new ones do not risk running into the 32 bit limit the old ones are facing. CURLINFO_PROTCOOL is now deprecated. The curl tool is updated to use the new options. Added test 1597 to verify the libcurl protocol parser. Closes #8992 --- diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index c98c300bac..81982deffd 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -167,9 +167,14 @@ URL to work on. See \fICURLOPT_URL(3)\fP .IP CURLOPT_PATH_AS_IS Disable squashing /../ and /./ sequences in the path. See \fICURLOPT_PATH_AS_IS(3)\fP .IP CURLOPT_PROTOCOLS -Allowed protocols. See \fICURLOPT_PROTOCOLS(3)\fP +\fBDeprecated option\fP Allowed protocols. See \fICURLOPT_PROTOCOLS(3)\fP +.IP CURLOPT_PROTOCOLS_STR +Allowed protocols. See \fICURLOPT_PROTOCOLS_STR(3)\fP .IP CURLOPT_REDIR_PROTOCOLS -Protocols to allow redirects to. See \fICURLOPT_REDIR_PROTOCOLS(3)\fP +\fBDeprecated option\fP Protocols to allow redirects to. See +\fICURLOPT_REDIR_PROTOCOLS(3)\fP +.IP CURLOPT_REDIR_PROTOCOLS_STR +Protocols to allow redirects to. See \fICURLOPT_REDIR_PROTOCOLS_STR(3)\fP .IP CURLOPT_DEFAULT_PROTOCOL Default protocol. See \fICURLOPT_DEFAULT_PROTOCOL(3)\fP .IP CURLOPT_PROXY diff --git a/docs/libcurl/opts/CURLINFO_PROTOCOL.3 b/docs/libcurl/opts/CURLINFO_PROTOCOL.3 index 7c11ed3fba..27d5ddc3ac 100644 --- a/docs/libcurl/opts/CURLINFO_PROTOCOL.3 +++ b/docs/libcurl/opts/CURLINFO_PROTOCOL.3 @@ -32,6 +32,10 @@ CURLINFO_PROTOCOL \- get the protocol used in the connection CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PROTOCOL, long *p); .fi .SH DESCRIPTION +This option is deprecated. We strongly recommend using +\fICURLINFO_SCHEME(3)\fP instead, because this option cannot return all +possible protocols! + Pass a pointer to a long to receive the version used in the last http connection. The returned value will be exactly one of the CURLPROTO_* values: diff --git a/docs/libcurl/opts/CURLOPT_PROTOCOLS.3 b/docs/libcurl/opts/CURLOPT_PROTOCOLS.3 index aeeb475e30..9be3763be6 100644 --- a/docs/libcurl/opts/CURLOPT_PROTOCOLS.3 +++ b/docs/libcurl/opts/CURLOPT_PROTOCOLS.3 @@ -32,6 +32,10 @@ CURLOPT_PROTOCOLS \- allowed protocols CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROTOCOLS, long bitmask); .fi .SH DESCRIPTION +This option is deprecated. We strongly recommend using +\fICURLOPT_PROTOCOLS_STR(3)\fP instead because this option cannot control all +available 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 @@ -71,7 +75,7 @@ CURLPROTO_TELNET CURLPROTO_TFTP .fi .SH DEFAULT -All protocols built-in +All protocols built-in. .SH PROTOCOLS All .SH EXAMPLE diff --git a/docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.3 b/docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.3 new file mode 100644 index 0000000000..80ff05c2ce --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.3 @@ -0,0 +1,82 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" * SPDX-License-Identifier: curl +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROTOCOLS_STR 3 "11 Jun 2022" "libcurl 7.85.0" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROTOCOLS_STR \- allowed protocols +.SH SYNOPSIS +.nf +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROTOCOLS_STR, char *spec); +.fi +.SH DESCRIPTION +Pass a pointer to a string that holds a comma-separated list of case +insensitive protocol names (URL schemes) to allow in the transfer. This +option allows applications to use 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 accepts all protocols it was built with +support for. See also \fICURLOPT_REDIR_PROTOCOLS_STR(3)\fP. + +If trying to set a non-existing protocol or if no matching protocol at all is +set, it returns error. + +These are the available protocols: + +DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, +POP3, POP3S, RTMP, RTMPE, RTMPS, RTMPT, RTMPTE, RTMPTS, RTSP, SCP, SFTP, SMB, +SMBS, SMTP, SMTPS, TELNET, TFTP + +You can set "ALL" as a short-cut to enable all protocols. Note that by setting +all, you may enable protocols that were not supported the day you write this +but are introduced in a future libcurl version. + +\fIcurl_version_info(3)\fP can be used to get a list of all supported +protocols in the current libcurl. \fICURLINFO_SCHEME(3)\fP is the recommended +way to figure out the protocol used in a previous transfer. +.SH DEFAULT +All protocols built-in +.SH PROTOCOLS +All +.SH EXAMPLE +.nf +curl = curl_easy_init(); +if(curl) { + /* pass in the URL from an external source */ + curl_easy_setopt(curl, CURLOPT_URL, argv[1]); + + /* only allow HTTP, TFTP and SFTP */ + curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, "http,tftp,sftp"); + + /* Perform the request */ + curl_easy_perform(curl); +} +.fi +.SH AVAILABILITY +Added in 7.85.0 +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. +.SH "SEE ALSO" +.BR CURLOPT_REDIR_PROTOCOLS_STR "(3), " CURLOPT_URL "(3), " +.BR curl_version_info "(3), " CURLINFO_SCHEME "(3), " diff --git a/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.3 b/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.3 index 61ee4935f7..0babe43863 100644 --- a/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.3 +++ b/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.3 @@ -32,6 +32,10 @@ CURLOPT_REDIR_PROTOCOLS \- protocols allowed to redirect to CURLcode curl_easy_setopt(CURL *handle, CURLOPT_REDIR_PROTOCOLS, long bitmask); .fi .SH DESCRIPTION +This option is deprecated. We strongly recommend using +\fICURLOPT_REDIR_PROTOCOLS_STR(3)\fP instead because this option cannot +control all available 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(3)\fP is enabled. This allows you to diff --git a/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS_STR.3 b/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS_STR.3 new file mode 100644 index 0000000000..0fb42bab27 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS_STR.3 @@ -0,0 +1,89 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" * SPDX-License-Identifier: curl +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_REDIR_PROTOCOLS_STR 3 "19 Jun 2014" "libcurl 7.37.0" "curl_easy_setopt options" +.SH NAME +CURLOPT_REDIR_PROTOCOLS_STR \- protocols allowed to redirect to +.SH SYNOPSIS +.nf +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_REDIR_PROTOCOLS_STR, + char *spec); +.fi +.SH DESCRIPTION +Pass a pointer to a string that holds a comma-separated list of case +insensitive protocol names (URL schemes). That list limits what protocols +libcurl may use in a transfer that it follows to in a redirect when +\fICURLOPT_FOLLOWLOCATION(3)\fP is enabled. This option allows applications to +limit specific transfers to only be allowed to use a subset of protocols in +redirections. + +Protocols denied by \fICURLOPT_PROTOCOLS_STR(3)\fP are not overridden by this +option. + +By default libcurl will allow HTTP, HTTPS, FTP and FTPS on redirects (since +7.65.2). Older versions of libcurl allowed all protocols on redirect except +several disabled for security reasons: Since 7.19.4 FILE and SCP are disabled, +and since 7.40.0 SMB and SMBS are also disabled. + +These are the available protocols: + +DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, +POP3, POP3S, RTMP, RTMPE, RTMPS, RTMPT, RTMPTE, RTMPTS, RTSP, SCP, SFTP, SMB, +SMBS, SMTP, SMTPS, TELNET, TFTP + +You can set "ALL" as a short-cut to enable all protocols. Note that by setting +all, you may enable protocols that were not supported the day you write this +but are introduced in a future libcurl version. + +If trying to set a non-existing protocol or if no matching protocol at all is +set, it returns error. +.SH DEFAULT +HTTP, HTTPS, FTP and FTPS (Added in 7.65.2). + +Older versions defaulted to all protocols except FILE, SCP and since 7.40.0 +SMB and SMBS. +.SH PROTOCOLS +All +.SH EXAMPLE +.nf +curl = curl_easy_init(); +if(curl) { + /* pass in the URL from an external source */ + curl_easy_setopt(curl, CURLOPT_URL, argv[1]); + + /* only allow redirects to HTTP and HTTPS URLs */ + curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"); + + /* Perform the request */ + curl_easy_perform(curl); +} +.fi +.SH AVAILABILITY +Added in 7.85.0. +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. +.SH "SEE ALSO" +.BR CURLOPT_PROTOCOLS_STR "(3), " diff --git a/docs/libcurl/opts/Makefile.inc b/docs/libcurl/opts/Makefile.inc index 95aec8bdf6..a7c4735294 100644 --- a/docs/libcurl/opts/Makefile.inc +++ b/docs/libcurl/opts/Makefile.inc @@ -267,6 +267,7 @@ man_MANS = \ CURLOPT_PROGRESSDATA.3 \ CURLOPT_PROGRESSFUNCTION.3 \ CURLOPT_PROTOCOLS.3 \ + CURLOPT_PROTOCOLS_STR.3 \ CURLOPT_PROXY.3 \ CURLOPT_PROXYAUTH.3 \ CURLOPT_PROXYHEADER.3 \ @@ -307,6 +308,7 @@ man_MANS = \ CURLOPT_READDATA.3 \ CURLOPT_READFUNCTION.3 \ CURLOPT_REDIR_PROTOCOLS.3 \ + CURLOPT_REDIR_PROTOCOLS_STR.3 \ CURLOPT_REFERER.3 \ CURLOPT_REQUEST_TARGET.3 \ CURLOPT_RESOLVE.3 \ diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 74e2418540..0d358d40f6 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -722,6 +722,7 @@ CURLOPT_PRIVATE 7.10.3 CURLOPT_PROGRESSDATA 7.1 CURLOPT_PROGRESSFUNCTION 7.1 7.32.0 CURLOPT_PROTOCOLS 7.19.4 +CURLOPT_PROTOCOLS_STR 7.85.0 CURLOPT_PROXY 7.1 CURLOPT_PROXY_CAINFO 7.52.0 CURLOPT_PROXY_CAINFO_BLOB 7.77.0 @@ -762,6 +763,7 @@ CURLOPT_RANGE 7.1 CURLOPT_READDATA 7.9.7 CURLOPT_READFUNCTION 7.1 CURLOPT_REDIR_PROTOCOLS 7.19.4 +CURLOPT_REDIR_PROTOCOLS_STR 7.85.0 CURLOPT_REFERER 7.1 CURLOPT_REQUEST_TARGET 7.55.0 CURLOPT_RESOLVE 7.21.3 diff --git a/include/curl/curl.h b/include/curl/curl.h index 6527f2149e..cf11dc2eca 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -1010,7 +1010,8 @@ typedef CURLSTScode (*curl_hstswrite_callback)(CURL *easy, #define CURLHSTS_ENABLE (long)(1<<0) #define CURLHSTS_READONLYFILE (long)(1<<1) -/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ +/* The CURLPROTO_ defines below are for the **deprecated** CURLOPT_*PROTOCOLS + options. Do not use. */ #define CURLPROTO_HTTP (1<<0) #define CURLPROTO_HTTPS (1<<1) #define CURLPROTO_FTP (1<<2) @@ -2144,6 +2145,15 @@ typedef enum { /* set the SSH host key callback custom pointer */ CURLOPT(CURLOPT_SSH_HOSTKEYDATA, CURLOPTTYPE_CBPOINT, 317), + /* specify which 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 + all built-in protocols. */ + CURLOPT(CURLOPT_PROTOCOLS_STR, CURLOPTTYPE_STRINGPOINT, 318), + + /* specify which protocols that libcurl is allowed to follow directs to */ + CURLOPT(CURLOPT_REDIR_PROTOCOLS_STR, CURLOPTTYPE_STRINGPOINT, 319), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h index d7c7a9a309..2dabcb4166 100644 --- a/include/curl/typecheck-gcc.h +++ b/include/curl/typecheck-gcc.h @@ -272,9 +272,9 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t, (option) == CURLOPT_DNS_SERVERS || \ (option) == CURLOPT_DOH_URL || \ (option) == CURLOPT_EGDSOCKET || \ - (option) == CURLOPT_FTPPORT || \ (option) == CURLOPT_FTP_ACCOUNT || \ (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_FTPPORT || \ (option) == CURLOPT_HSTS || \ (option) == CURLOPT_INTERFACE || \ (option) == CURLOPT_ISSUERCERT || \ @@ -288,10 +288,8 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t, (option) == CURLOPT_PASSWORD || \ (option) == CURLOPT_PINNEDPUBLICKEY || \ (option) == CURLOPT_PRE_PROXY || \ + (option) == CURLOPT_PROTOCOLS_STR || \ (option) == CURLOPT_PROXY || \ - (option) == CURLOPT_PROXYPASSWORD || \ - (option) == CURLOPT_PROXYUSERNAME || \ - (option) == CURLOPT_PROXYUSERPWD || \ (option) == CURLOPT_PROXY_CAINFO || \ (option) == CURLOPT_PROXY_CAPATH || \ (option) == CURLOPT_PROXY_CRLFILE || \ @@ -299,17 +297,21 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t, (option) == CURLOPT_PROXY_KEYPASSWD || \ (option) == CURLOPT_PROXY_PINNEDPUBLICKEY || \ (option) == CURLOPT_PROXY_SERVICE_NAME || \ + (option) == CURLOPT_PROXY_SSL_CIPHER_LIST || \ (option) == CURLOPT_PROXY_SSLCERT || \ (option) == CURLOPT_PROXY_SSLCERTTYPE || \ (option) == CURLOPT_PROXY_SSLKEY || \ (option) == CURLOPT_PROXY_SSLKEYTYPE || \ - (option) == CURLOPT_PROXY_SSL_CIPHER_LIST || \ (option) == CURLOPT_PROXY_TLS13_CIPHERS || \ (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD || \ (option) == CURLOPT_PROXY_TLSAUTH_TYPE || \ (option) == CURLOPT_PROXY_TLSAUTH_USERNAME || \ + (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_PROXYUSERNAME || \ + (option) == CURLOPT_PROXYUSERPWD || \ (option) == CURLOPT_RANDOM_FILE || \ (option) == CURLOPT_RANGE || \ + (option) == CURLOPT_REDIR_PROTOCOLS_STR || \ (option) == CURLOPT_REFERER || \ (option) == CURLOPT_REQUEST_TARGET || \ (option) == CURLOPT_RTSP_SESSION_ID || \ diff --git a/lib/easyoptions.c b/lib/easyoptions.c index c99f135ffe..4fe483a4e4 100644 --- a/lib/easyoptions.c +++ b/lib/easyoptions.c @@ -203,6 +203,7 @@ struct curl_easyoption Curl_easyopts[] = { {"PROGRESSDATA", CURLOPT_XFERINFODATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS}, {"PROGRESSFUNCTION", CURLOPT_PROGRESSFUNCTION, CURLOT_FUNCTION, 0}, {"PROTOCOLS", CURLOPT_PROTOCOLS, CURLOT_LONG, 0}, + {"PROTOCOLS_STR", CURLOPT_PROTOCOLS_STR, CURLOT_STRING, 0}, {"PROXY", CURLOPT_PROXY, CURLOT_STRING, 0}, {"PROXYAUTH", CURLOPT_PROXYAUTH, CURLOT_VALUES, 0}, {"PROXYHEADER", CURLOPT_PROXYHEADER, CURLOT_SLIST, 0}, @@ -245,6 +246,7 @@ struct curl_easyoption Curl_easyopts[] = { {"READDATA", CURLOPT_READDATA, CURLOT_CBPTR, 0}, {"READFUNCTION", CURLOPT_READFUNCTION, CURLOT_FUNCTION, 0}, {"REDIR_PROTOCOLS", CURLOPT_REDIR_PROTOCOLS, CURLOT_LONG, 0}, + {"REDIR_PROTOCOLS_STR", CURLOPT_REDIR_PROTOCOLS_STR, CURLOT_STRING, 0}, {"REFERER", CURLOPT_REFERER, CURLOT_STRING, 0}, {"REQUEST_TARGET", CURLOPT_REQUEST_TARGET, CURLOT_STRING, 0}, {"RESOLVE", CURLOPT_RESOLVE, CURLOT_SLIST, 0}, @@ -275,14 +277,14 @@ struct curl_easyoption Curl_easyopts[] = { {"SOCKS5_GSSAPI_SERVICE", CURLOPT_SOCKS5_GSSAPI_SERVICE, CURLOT_STRING, 0}, {"SSH_AUTH_TYPES", CURLOPT_SSH_AUTH_TYPES, CURLOT_VALUES, 0}, {"SSH_COMPRESSION", CURLOPT_SSH_COMPRESSION, CURLOT_LONG, 0}, + {"SSH_HOSTKEYDATA", CURLOPT_SSH_HOSTKEYDATA, CURLOT_CBPTR, 0}, + {"SSH_HOSTKEYFUNCTION", CURLOPT_SSH_HOSTKEYFUNCTION, CURLOT_FUNCTION, 0}, {"SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, CURLOT_STRING, 0}, {"SSH_HOST_PUBLIC_KEY_SHA256", CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, CURLOT_STRING, 0}, {"SSH_KEYDATA", CURLOPT_SSH_KEYDATA, CURLOT_CBPTR, 0}, {"SSH_KEYFUNCTION", CURLOPT_SSH_KEYFUNCTION, CURLOT_FUNCTION, 0}, - {"SSH_HOSTKEYDATA", CURLOPT_SSH_HOSTKEYDATA, CURLOT_CBPTR, 0}, - {"SSH_HOSTKEYFUNCTION", CURLOPT_SSH_HOSTKEYFUNCTION, CURLOT_FUNCTION, 0}, {"SSH_KNOWNHOSTS", CURLOPT_SSH_KNOWNHOSTS, CURLOT_STRING, 0}, {"SSH_PRIVATE_KEYFILE", CURLOPT_SSH_PRIVATE_KEYFILE, CURLOT_STRING, 0}, {"SSH_PUBLIC_KEYFILE", CURLOPT_SSH_PUBLIC_KEYFILE, CURLOT_STRING, 0}, @@ -364,6 +366,6 @@ struct curl_easyoption Curl_easyopts[] = { */ int Curl_easyopts_check(void) { - return ((CURLOPT_LASTENTRY%10000) != (317 + 1)); + return ((CURLOPT_LASTENTRY%10000) != (319 + 1)); } #endif diff --git a/lib/setopt.c b/lib/setopt.c index 6b16e1c7c8..dc6bc2a09c 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -148,6 +148,85 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp) #define C_SSLVERSION_VALUE(x) (x & 0xffff) #define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000) +static CURLcode protocol2num(char *str, curl_off_t *val) +{ + bool found_comma = FALSE; + static struct scheme { + const char *name; + long bit; + } const protos[] = { + { "dict", CURLPROTO_DICT }, + { "file", CURLPROTO_FILE }, + { "ftp", CURLPROTO_FTP }, + { "ftps", CURLPROTO_FTPS }, + { "gopher", CURLPROTO_GOPHER }, + { "gophers", CURLPROTO_GOPHERS }, + { "http", CURLPROTO_HTTP }, + { "https", CURLPROTO_HTTPS }, + { "imap", CURLPROTO_IMAP }, + { "imaps", CURLPROTO_IMAPS }, + { "ldap", CURLPROTO_LDAP }, + { "ldaps", CURLPROTO_LDAPS }, + { "mqtt", CURLPROTO_MQTT }, + { "pop3", CURLPROTO_POP3 }, + { "pop3s", CURLPROTO_POP3S }, + { "rtmp", CURLPROTO_RTMP }, + { "rtmpe", CURLPROTO_RTMPE }, + { "rtmps", CURLPROTO_RTMPS }, + { "rtmpt", CURLPROTO_RTMPT }, + { "rtmpte", CURLPROTO_RTMPTE }, + { "rtmpts", CURLPROTO_RTMPTS }, + { "rtsp", CURLPROTO_RTSP }, + { "scp", CURLPROTO_SCP }, + { "sftp", CURLPROTO_SFTP }, + { "smb", CURLPROTO_SMB }, + { "smbs", CURLPROTO_SMBS }, + { "smtp", CURLPROTO_SMTP }, + { "smtps", CURLPROTO_SMTPS }, + { "telnet", CURLPROTO_TELNET }, + { "tftp", CURLPROTO_TFTP }, + { NULL, 0 } + }; + + if(!str) + return CURLE_BAD_FUNCTION_ARGUMENT; + else if(curl_strequal(str, "all")) { + *val = ~0; + return CURLE_OK; + } + + *val = 0; + + do { + size_t tlen; + struct scheme const *pp; + char *token; + token = strchr(str, ','); + found_comma = token ? TRUE : FALSE; + if(!token) + token = strchr(str, '\0'); + tlen = token - str; + if(tlen) { + for(pp = protos; pp->name; pp++) { + if((strlen(pp->name) == tlen) && + curl_strnequal(str, pp->name, tlen)) { + *val |= pp->bit; + break; + } + } + if(!(pp->name)) + /* protocol name didn't match */ + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(found_comma) + str = token + 1; + } while(found_comma); + if(!*val) + /* no matching protocol */ + return CURLE_BAD_FUNCTION_ARGUMENT; + return CURLE_OK; +} + /* * Do not make Curl_vsetopt() static: it is called from * packages/OS400/ccsidcurl.c. @@ -2560,14 +2639,30 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) 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 = (unsigned int)va_arg(param, long); + data->set.allowed_protocols = (curl_off_t)va_arg(param, long); 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. */ - data->set.redir_protocols = (unsigned int)va_arg(param, long); + data->set.redir_protocols = (curl_off_t)va_arg(param, long); + break; + + case CURLOPT_PROTOCOLS_STR: + argptr = va_arg(param, char *); + result = protocol2num(argptr, &bigsize); + if(result) + return result; + data->set.allowed_protocols = bigsize; + break; + + case CURLOPT_REDIR_PROTOCOLS_STR: + argptr = va_arg(param, char *); + result = protocol2num(argptr, &bigsize); + if(result) + return result; + data->set.redir_protocols = bigsize; break; case CURLOPT_DEFAULT_PROTOCOL: diff --git a/lib/urldata.h b/lib/urldata.h index 71ac2f1619..e815e83166 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1782,8 +1782,8 @@ struct UserDefined { #ifdef ENABLE_IPV6 unsigned int scope_id; /* Scope id for IPv6 */ #endif - unsigned int allowed_protocols; - unsigned int redir_protocols; + curl_off_t allowed_protocols; + curl_off_t redir_protocols; unsigned int mime_options; /* Mime option flags. */ #ifndef CURL_DISABLE_RTSP diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index 27232ebd8e..eccb3bcb59 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -36,11 +36,7 @@ void config_init(struct OperationConfig *config) config->use_httpget = FALSE; config->create_dirs = FALSE; config->maxredirs = DEFAULT_MAXREDIRS; - config->proto = CURLPROTO_ALL; config->proto_present = FALSE; - config->proto_redir = CURLPROTO_ALL & /* All except FILE, SCP and SMB */ - ~(CURLPROTO_FILE | CURLPROTO_SCP | CURLPROTO_SMB | - CURLPROTO_SMBS); config->proto_redir_present = FALSE; config->proto_default = NULL; config->tcp_nodelay = TRUE; /* enabled by default */ @@ -172,6 +168,8 @@ static void free_config_fields(struct OperationConfig *config) Curl_safefree(config->ftp_alternative_to_user); Curl_safefree(config->aws_sigv4); + Curl_safefree(config->proto_str); + Curl_safefree(config->proto_redir_str); } void config_free(struct OperationConfig *config) diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 7e43fe754c..9c44f7b4e9 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -67,9 +67,9 @@ struct OperationConfig { bool disable_epsv; bool disable_eprt; bool ftp_pret; - long proto; + char *proto_str; bool proto_present; - long proto_redir; + char *proto_redir_str; bool proto_redir_present; char *proto_default; curl_off_t resume_from; diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 27e801a98b..9d425c846a 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -1184,12 +1184,16 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ break; case 'D': /* --proto */ config->proto_present = TRUE; - if(proto2num(config, &config->proto, nextarg)) - return PARAM_BAD_USE; + err = proto2num(config, (unsigned int)CURLPROTO_ALL, + &config->proto_str, nextarg); + if(err) + return err; break; case 'E': /* --proto-redir */ config->proto_redir_present = TRUE; - if(proto2num(config, &config->proto_redir, nextarg)) + if(proto2num(config, CURLPROTO_HTTP|CURLPROTO_HTTPS| + CURLPROTO_FTP|CURLPROTO_FTPS, + &config->proto_redir_str, nextarg)) return PARAM_BAD_USE; break; case 'F': /* --resolve */ diff --git a/src/tool_operate.c b/src/tool_operate.c index 9d54e30363..133d5b1915 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1989,9 +1989,10 @@ static CURLcode single_transfer(struct GlobalConfig *global, my_setopt(curl, CURLOPT_NEW_FILE_PERMS, config->create_file_mode); if(config->proto_present) - my_setopt_flags(curl, CURLOPT_PROTOCOLS, config->proto); + my_setopt_str(curl, CURLOPT_PROTOCOLS_STR, config->proto_str); if(config->proto_redir_present) - my_setopt_flags(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir); + my_setopt_str(curl, CURLOPT_REDIR_PROTOCOLS_STR, + config->proto_redir_str); if(config->content_disposition && (urlnode->flags & GETOUT_USEREMOTE)) diff --git a/src/tool_paramhlp.c b/src/tool_paramhlp.c index 5f87c5e752..188d6a1da5 100644 --- a/src/tool_paramhlp.c +++ b/src/tool_paramhlp.c @@ -275,8 +275,8 @@ ParameterError str2udouble(double *valp, const char *str, long max) } /* - * Parse the string and modify the long in the given address. Return - * non-zero on failure, zero on success. + * Parse the string and provide an allocated libcurl compatible protocol + * string output. Return non-zero on failure, zero on success. * * The string is a list of protocols * @@ -285,17 +285,22 @@ ParameterError str2udouble(double *valp, const char *str, long max) * data. */ -long proto2num(struct OperationConfig *config, long *val, const char *str) +ParameterError proto2num(struct OperationConfig *config, + unsigned int val, char **ostr, const char *str) { char *buffer; const char *sep = ","; char *token; + char obuf[256]; + size_t olen = sizeof(obuf); + char *optr; + struct sprotos const *pp; static struct sprotos { const char *name; - long bit; + unsigned int bit; } const protos[] = { - { "all", CURLPROTO_ALL }, + { "all", (unsigned int)CURLPROTO_ALL }, { "http", CURLPROTO_HTTP }, { "https", CURLPROTO_HTTPS }, { "ftp", CURLPROTO_FTP }, @@ -305,6 +310,7 @@ long proto2num(struct OperationConfig *config, long *val, const char *str) { "telnet", CURLPROTO_TELNET }, { "ldap", CURLPROTO_LDAP }, { "ldaps", CURLPROTO_LDAPS }, + { "mqtt", CURLPROTO_MQTT }, { "dict", CURLPROTO_DICT }, { "file", CURLPROTO_FILE }, { "tftp", CURLPROTO_TFTP }, @@ -316,6 +322,7 @@ long proto2num(struct OperationConfig *config, long *val, const char *str) { "smtps", CURLPROTO_SMTPS }, { "rtsp", CURLPROTO_RTSP }, { "gopher", CURLPROTO_GOPHER }, + { "gophers", CURLPROTO_GOPHERS }, { "smb", CURLPROTO_SMB }, { "smbs", CURLPROTO_SMBS }, { NULL, 0 } @@ -335,8 +342,6 @@ long proto2num(struct OperationConfig *config, long *val, const char *str) token = strtok(NULL, sep)) { enum e_action { allow, deny, set } action = allow; - struct sprotos const *pp; - /* Process token modifiers */ while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */ switch (*token++) { @@ -359,13 +364,13 @@ long proto2num(struct OperationConfig *config, long *val, const char *str) if(curl_strequal(token, pp->name)) { switch(action) { case deny: - *val &= ~(pp->bit); + val &= ~(pp->bit); break; case allow: - *val |= pp->bit; + val |= pp->bit; break; case set: - *val = pp->bit; + val = pp->bit; break; } break; @@ -376,12 +381,25 @@ long proto2num(struct OperationConfig *config, long *val, const char *str) /* If they have specified only this protocol, we say treat it as if no protocols are allowed */ if(action == set) - *val = 0; + val = 0; warnf(config->global, "unrecognized protocol '%s'\n", token); } } Curl_safefree(buffer); - return 0; + + optr = obuf; + for(pp = &protos[1]; pp->name; pp++) { + if(val & pp->bit) { + size_t n = msnprintf(optr, olen, "%s%s", + olen != sizeof(obuf) ? "," : "", + pp->name); + olen -= n; + optr += n; + } + } + *ostr = strdup(obuf); + + return *ostr ? PARAM_OK : PARAM_NO_MEM; } /** diff --git a/src/tool_paramhlp.h b/src/tool_paramhlp.h index 9f8acf3c2b..297490b57c 100644 --- a/src/tool_paramhlp.h +++ b/src/tool_paramhlp.h @@ -39,7 +39,9 @@ ParameterError oct2nummax(long *val, const char *str, long max); ParameterError str2unummax(long *val, const char *str, long max); ParameterError str2udouble(double *val, const char *str, long max); -long proto2num(struct OperationConfig *config, long *val, const char *str); +ParameterError proto2num(struct OperationConfig *config, + unsigned int val, char **obuf, + const char *str); int check_protocol(const char *str); diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc index 96f1428d6d..eb42487680 100644 --- a/tests/data/Makefile.inc +++ b/tests/data/Makefile.inc @@ -201,7 +201,7 @@ test1550 test1551 test1552 test1553 test1554 test1555 test1556 test1557 \ test1558 test1559 test1560 test1561 test1562 test1563 test1564 test1565 \ test1566 test1567 test1568 test1569 test1570 \ \ -test1590 test1591 test1592 test1593 test1594 test1595 test1596 \ +test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 \ \ test1600 test1601 test1602 test1603 test1604 test1605 test1606 test1607 \ test1608 test1609 test1610 test1611 test1612 test1613 \ diff --git a/tests/data/test1401 b/tests/data/test1401 index 65efc474ce..247b061573 100644 --- a/tests/data/test1401 +++ b/tests/data/test1401 @@ -91,9 +91,7 @@ int main(int argc, char *argv[]) curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L); %endif curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L); - curl_easy_setopt(hnd, CURLOPT_PROTOCOLS, (long)CURLPROTO_FILE | - (long)CURLPROTO_FTP | - (long)CURLPROTO_HTTP); + curl_easy_setopt(hnd, CURLOPT_PROTOCOLS_STR, "http,ftp,file"); /* Here is a list of options the curl code used that cannot get generated as source easily. You may choose to either not use them or implement diff --git a/tests/data/test1597 b/tests/data/test1597 new file mode 100644 index 0000000000..047bf7bd80 --- /dev/null +++ b/tests/data/test1597 @@ -0,0 +1,32 @@ + + + +CURLOPT_PROTOCOLS_STR + + + +# Server-side + + +# Client-side + + +none + + +CURLOPT_PROTOCOLS_STR + + +lib%TESTNUMBER + + +- + + + + + +Tested 15 strings + + + diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index dbd5a60b71..83a8af45ba 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -60,7 +60,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \ lib1540 lib1542 lib1543 \ lib1550 lib1551 lib1552 lib1553 lib1554 lib1555 lib1556 lib1557 \ lib1558 lib1559 lib1560 lib1564 lib1565 lib1567 lib1568 lib1569 \ - lib1591 lib1592 lib1593 lib1594 lib1596 \ + lib1591 lib1592 lib1593 lib1594 lib1596 lib1597 \ lib1905 lib1906 lib1907 lib1908 lib1910 lib1911 lib1912 lib1913 \ lib1915 lib1916 lib1917 lib1918 lib1919 \ lib1933 lib1934 lib1935 lib1936 lib1937 lib1938 lib1939 lib1940 \ @@ -657,6 +657,9 @@ lib1596_SOURCES = lib1594.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib1596_LDADD = $(TESTUTIL_LIBS) lib1596_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1596 +lib1597_SOURCES = lib1597.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) +lib1597_LDADD = $(TESTUTIL_LIBS) + lib1905_SOURCES = lib1905.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib1905_LDADD = $(TESTUTIL_LIBS) lib1905_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/tests/libtest/lib1597.c b/tests/libtest/lib1597.c new file mode 100644 index 0000000000..3ac31a0c3a --- /dev/null +++ b/tests/libtest/lib1597.c @@ -0,0 +1,85 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +/* Testing CURLOPT_PROTOCOLS_STR */ + +#include "test.h" + +#include "memdebug.h" + +struct pair { + const char *in; + CURLcode exp; +}; + +int test(char *URL) +{ + CURL *curl = NULL; + int res = 0; + CURLcode result = CURLE_OK; + int i; + + struct pair prots[] = { + {"goobar", CURLE_BAD_FUNCTION_ARGUMENT}, + {"http ", CURLE_BAD_FUNCTION_ARGUMENT}, + {" http", CURLE_BAD_FUNCTION_ARGUMENT}, + {"http", CURLE_OK}, + {"http,", CURLE_OK}, + {"https,", CURLE_OK}, + {"https,http", CURLE_OK}, + {"http,http", CURLE_OK}, + {"HTTP,HTTP", CURLE_OK}, + {",HTTP,HTTP", CURLE_OK}, + {"http,http,ft", CURLE_BAD_FUNCTION_ARGUMENT}, + {"", CURLE_BAD_FUNCTION_ARGUMENT}, + {",,", CURLE_BAD_FUNCTION_ARGUMENT}, + {"DICT,FILE,FTP,FTPS,GOPHER,GOPHERS,HTTP,HTTPS,IMAP,IMAPS,LDAP,LDAPS," + "POP3,POP3S,RTMP,RTMPE,RTMPS,RTMPT,RTMPTE,RTMPTS,RTSP,SCP,SFTP,SMB," + "SMBS,SMTP,SMTPS,TELNET,TFTP", CURLE_OK}, + {"all", CURLE_OK}, + {NULL, FALSE}, + }; + (void)URL; + + global_init(CURL_GLOBAL_ALL); + + easy_init(curl); + + for(i = 0; prots[i].in; i++) { + result = curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, prots[i].in); + if(result != prots[i].exp) { + printf("unexpectedly '%s' returned %u\n", + prots[i].in, result); + break; + } + } + printf("Tested %u strings\n", i); + res = (int)result; + + test_cleanup: + curl_easy_cleanup(curl); + curl_global_cleanup(); + + return (int)result; +}