* [dunfell][PATCH 1/2] curl: Fix CVE-2020-8284, CVE-2020-8285, CVE-2020-8286
@ 2021-01-15 18:02 akuster
2021-01-15 18:02 ` [dunfell][PATCH 2/2] curl: Security fix for CVE-2020-8231 akuster
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: akuster @ 2021-01-15 18:02 UTC (permalink / raw)
To: openembedded-core; +Cc: Khairul Rohaizzat Jamaluddin, Anuj Mittal
From: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
Source: git.openembedded.org
MR: 107592, 107620, 107606
Type: Security Fix
Disposition: Backport from https://git.openembedded.org/openembedded-core-contrib/commit/?h=anujm/gatesgarth&id=f1a0ea55c0ae2cce7f7c3c6c73f57c5b8222c860
ChangeID: 8d65a5974018f276bef9054cbbdcd5a2a5f0a154
Description:
Backport the CVE patches from upstream
https://github.com/curl/curl/commit/ec9cc725d598ac
https://github.com/curl/curl/commit/a95a6ce6b809693a1195e3b4347a6cfa0fbc2ee7
https://github.com/curl/curl/commit/69a358f2186e04
https://github.com/curl/curl/commit/d9d01672785b.patch
0002-remove-void-protop-create-union-p.patch is added because the CVE-2020-8285 fix is
dependent on it.
CVE:
CVE-2020-8284
CVE-2020-8285
CVE-2020-8286
Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
Signed-off-by: Armin Kuster <akuster808@gmail.com>
---
...02-remove-void-protop-create-union-p.patch | 1609 +++++++++++++++++
.../curl/curl/CVE-2020-8284.patch | 210 +++
.../curl/curl/CVE-2020-8285.patch | 261 +++
.../curl/curl/CVE-2020-8286.patch | 138 ++
meta/recipes-support/curl/curl_7.69.1.bb | 3 +
5 files changed, 2221 insertions(+)
create mode 100644 meta/recipes-support/curl/curl/0002-remove-void-protop-create-union-p.patch
create mode 100644 meta/recipes-support/curl/curl/CVE-2020-8284.patch
create mode 100644 meta/recipes-support/curl/curl/CVE-2020-8285.patch
create mode 100644 meta/recipes-support/curl/curl/CVE-2020-8286.patch
diff --git a/meta/recipes-support/curl/curl/0002-remove-void-protop-create-union-p.patch b/meta/recipes-support/curl/curl/0002-remove-void-protop-create-union-p.patch
new file mode 100644
index 00000000000..d0d01fb97cb
--- /dev/null
+++ b/meta/recipes-support/curl/curl/0002-remove-void-protop-create-union-p.patch
@@ -0,0 +1,1609 @@
+From bfdb7ee65fc8b96f1fce10ef23871acb092b74b6 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Mon, 23 Nov 2020 08:32:41 +0100
+Subject: [PATCH] urldata: remove 'void *protop' and create the union 'p'
+
+... to avoid the use of 'void *' for the protocol specific structs done
+per transfer.
+
+Closes #6238
+
+Upstream-Status: Backport [https://github.com/curl/curl/commit/a95a6ce6b809693a1195e3b4347a6cfa0fbc2ee7]
+
+CVE: CVE-2020-8285
+
+Signed-off-by: Daniel Stenberg <daniel@haxx.se>
+Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
+
+---
+ docs/INTERNALS.md | 4 ++--
+ lib/file.c | 14 +++++++-------
+ lib/ftp.c | 36 ++++++++++++++++++------------------
+ lib/http.c | 14 +++++++-------
+ lib/http2.c | 50 +++++++++++++++++++++++++-------------------------
+ lib/http_proxy.c | 6 +++---
+ lib/imap.c | 26 +++++++++++++-------------
+ lib/mqtt.c | 10 +++++-----
+ lib/openldap.c | 8 ++++----
+ lib/pop3.c | 14 +++++++-------
+ lib/rtsp.c | 8 ++++----
+ lib/smb.c | 20 ++++++++++----------
+ lib/smtp.c | 22 +++++++++++-----------
+ lib/telnet.c | 30 +++++++++++++++---------------
+ lib/transfer.c | 8 ++++----
+ lib/url.c | 2 +-
+ lib/urldata.h | 19 +++++++++++++++++--
+ lib/vquic/ngtcp2.c | 24 ++++++++++++------------
+ lib/vquic/quiche.c | 10 +++++-----
+ lib/vssh/libssh.c | 10 +++++-----
+ lib/vssh/libssh2.c | 8 ++++----
+ lib/vssh/wolfssh.c | 8 ++++----
+ 22 files changed, 183 insertions(+), 168 deletions(-)
+
+diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md
+index 635e7b2..ca8988e 100644
+--- a/docs/INTERNALS.md
++++ b/docs/INTERNALS.md
+@@ -980,8 +980,8 @@ for older and later versions as things don't change drastically that often.
+ protocol specific data that then gets associated with that `Curl_easy` for
+ the rest of this transfer. It gets freed again at the end of the transfer.
+ It will be called before the `connectdata` for the transfer has been
+- selected/created. Most protocols will allocate its private
+- `struct [PROTOCOL]` here and assign `Curl_easy->req.protop` to point to it.
++ selected/created. Most protocols will allocate its private `struct
++ [PROTOCOL]` here and assign `Curl_easy->req.p.[protocol]` to it.
+
+ `->connect_it` allows a protocol to do some specific actions after the TCP
+ connect is done, that can still be considered part of the connection phase.
+diff --git a/lib/file.c b/lib/file.c
+index cd3e49c..110e5c2 100644
+--- a/lib/file.c
++++ b/lib/file.c
+@@ -119,8 +119,8 @@ const struct Curl_handler Curl_handler_file = {
+ static CURLcode file_setup_connection(struct connectdata *conn)
+ {
+ /* allocate the FILE specific struct */
+- conn->data->req.protop = calloc(1, sizeof(struct FILEPROTO));
+- if(!conn->data->req.protop)
++ conn->data->req.p.file = calloc(1, sizeof(struct FILEPROTO));
++ if(!conn->data->req.p.file)
+ return CURLE_OUT_OF_MEMORY;
+
+ return CURLE_OK;
+@@ -135,7 +135,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
+ {
+ struct Curl_easy *data = conn->data;
+ char *real_path;
+- struct FILEPROTO *file = data->req.protop;
++ struct FILEPROTO *file = data->req.p.file;
+ int fd;
+ #ifdef DOS_FILESYSTEM
+ size_t i;
+@@ -209,7 +209,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
+ static CURLcode file_done(struct connectdata *conn,
+ CURLcode status, bool premature)
+ {
+- struct FILEPROTO *file = conn->data->req.protop;
++ struct FILEPROTO *file = conn->data->req.p.file;
+ (void)status; /* not used */
+ (void)premature; /* not used */
+
+@@ -227,7 +227,7 @@ static CURLcode file_done(struct connectdata *conn,
+ static CURLcode file_disconnect(struct connectdata *conn,
+ bool dead_connection)
+ {
+- struct FILEPROTO *file = conn->data->req.protop;
++ struct FILEPROTO *file = conn->data->req.p.file;
+ (void)dead_connection; /* not used */
+
+ if(file) {
+@@ -249,7 +249,7 @@ static CURLcode file_disconnect(struct connectdata *conn,
+
+ static CURLcode file_upload(struct connectdata *conn)
+ {
+- struct FILEPROTO *file = conn->data->req.protop;
++ struct FILEPROTO *file = conn->data->req.p.file;
+ const char *dir = strchr(file->path, DIRSEP);
+ int fd;
+ int mode;
+@@ -391,7 +391,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
+ if(data->set.upload)
+ return file_upload(conn);
+
+- file = conn->data->req.protop;
++ file = conn->data->req.p.file;
+
+ /* get the fd from the connection phase */
+ fd = file->fd;
+diff --git a/lib/ftp.c b/lib/ftp.c
+index 9fadac5..d1a9447 100644
+--- a/lib/ftp.c
++++ b/lib/ftp.c
+@@ -1345,7 +1345,7 @@ static CURLcode ftp_state_use_pasv(struct connectdata *conn)
+ static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+- struct FTP *ftp = conn->data->req.protop;
++ struct FTP *ftp = conn->data->req.p.ftp;
+ struct Curl_easy *data = conn->data;
+
+ if(ftp->transfer != FTPTRANSFER_BODY) {
+@@ -1388,7 +1388,7 @@ static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
+ static CURLcode ftp_state_rest(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+- struct FTP *ftp = conn->data->req.protop;
++ struct FTP *ftp = conn->data->req.p.ftp;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
+@@ -1409,7 +1409,7 @@ static CURLcode ftp_state_rest(struct connectdata *conn)
+ static CURLcode ftp_state_size(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+- struct FTP *ftp = conn->data->req.protop;
++ struct FTP *ftp = conn->data->req.p.ftp;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
+@@ -1430,7 +1430,7 @@ static CURLcode ftp_state_list(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct FTP *ftp = data->req.protop;
++ struct FTP *ftp = data->req.p.ftp;
+
+ /* If this output is to be machine-parsed, the NLST command might be better
+ to use, since the LIST command output is not specified or standard in any
+@@ -1508,7 +1508,7 @@ static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
+ static CURLcode ftp_state_type(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+- struct FTP *ftp = conn->data->req.protop;
++ struct FTP *ftp = conn->data->req.p.ftp;
+ struct Curl_easy *data = conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+@@ -1565,7 +1565,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
+ bool sizechecked)
+ {
+ CURLcode result = CURLE_OK;
+- struct FTP *ftp = conn->data->req.protop;
++ struct FTP *ftp = conn->data->req.p.ftp;
+ struct Curl_easy *data = conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+@@ -1664,7 +1664,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct FTP *ftp = data->req.protop;
++ struct FTP *ftp = data->req.p.ftp;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ bool quote = FALSE;
+ struct curl_slist *item;
+@@ -2033,7 +2033,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct FTP *ftp = data->req.protop;
++ struct FTP *ftp = data->req.p.ftp;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ switch(ftpcode) {
+@@ -2166,7 +2166,7 @@ static CURLcode ftp_state_retr(struct connectdata *conn,
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct FTP *ftp = data->req.protop;
++ struct FTP *ftp = data->req.p.ftp;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
+@@ -2378,7 +2378,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct FTP *ftp = data->req.protop;
++ struct FTP *ftp = data->req.p.ftp;
+
+ if((ftpcode == 150) || (ftpcode == 125)) {
+
+@@ -3138,7 +3138,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+ {
+ struct Curl_easy *data = conn->data;
+- struct FTP *ftp = data->req.protop;
++ struct FTP *ftp = data->req.p.ftp;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+ ssize_t nread;
+@@ -3492,7 +3492,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
+ bool complete = FALSE;
+
+ /* the ftp struct is inited in ftp_connect() */
+- struct FTP *ftp = data->req.protop;
++ struct FTP *ftp = data->req.p.ftp;
+
+ /* if the second connection isn't done yet, wait for it */
+ if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
+@@ -3657,7 +3657,7 @@ CURLcode ftp_perform(struct connectdata *conn,
+
+ if(conn->data->set.opt_no_body) {
+ /* requested no body means no transfer... */
+- struct FTP *ftp = conn->data->req.protop;
++ struct FTP *ftp = conn->data->req.p.ftp;
+ ftp->transfer = FTPTRANSFER_INFO;
+ }
+
+@@ -3692,7 +3692,7 @@ static void wc_data_dtor(void *ptr)
+ static CURLcode init_wc_data(struct connectdata *conn)
+ {
+ char *last_slash;
+- struct FTP *ftp = conn->data->req.protop;
++ struct FTP *ftp = conn->data->req.p.ftp;
+ char *path = ftp->path;
+ struct WildcardData *wildcard = &(conn->data->wildcard);
+ CURLcode result = CURLE_OK;
+@@ -3826,7 +3826,7 @@ static CURLcode wc_statemach(struct connectdata *conn)
+ /* filelist has at least one file, lets get first one */
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
+- struct FTP *ftp = conn->data->req.protop;
++ struct FTP *ftp = conn->data->req.p.ftp;
+
+ char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
+ if(!tmp_path)
+@@ -4099,7 +4099,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
+ {
+ struct Curl_easy *data = conn->data;
+ /* the ftp struct is already inited in ftp_connect() */
+- struct FTP *ftp = data->req.protop;
++ struct FTP *ftp = data->req.p.ftp;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ const char *slashPos = NULL;
+ const char *fileName = NULL;
+@@ -4244,7 +4244,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
+ static CURLcode ftp_dophase_done(struct connectdata *conn,
+ bool connected)
+ {
+- struct FTP *ftp = conn->data->req.protop;
++ struct FTP *ftp = conn->data->req.p.ftp;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if(connected) {
+@@ -4341,7 +4341,7 @@ static CURLcode ftp_setup_connection(struct connectdata *conn)
+ char *type;
+ struct FTP *ftp;
+
+- conn->data->req.protop = ftp = calloc(sizeof(struct FTP), 1);
++ conn->data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1);
+ if(NULL == ftp)
+ return CURLE_OUT_OF_MEMORY;
+
+diff --git a/lib/http.c b/lib/http.c
+index 8fcdd43..31d9112 100644
+--- a/lib/http.c
++++ b/lib/http.c
+@@ -162,14 +162,14 @@ static CURLcode http_setup_conn(struct connectdata *conn)
+ during this request */
+ struct HTTP *http;
+ struct Curl_easy *data = conn->data;
+- DEBUGASSERT(data->req.protop == NULL);
++ DEBUGASSERT(data->req.p.http == NULL);
+
+ http = calloc(1, sizeof(struct HTTP));
+ if(!http)
+ return CURLE_OUT_OF_MEMORY;
+
+ Curl_mime_initpart(&http->form, conn->data);
+- data->req.protop = http;
++ data->req.p.http = http;
+
+ if(data->set.httpversion == CURL_HTTP_VERSION_3) {
+ if(conn->handler->flags & PROTOPT_SSL)
+@@ -425,7 +425,7 @@ static bool pickoneauth(struct auth *pick, unsigned long mask)
+ static CURLcode http_perhapsrewind(struct connectdata *conn)
+ {
+ struct Curl_easy *data = conn->data;
+- struct HTTP *http = data->req.protop;
++ struct HTTP *http = data->req.p.http;
+ curl_off_t bytessent;
+ curl_off_t expectsend = -1; /* default is unknown */
+
+@@ -1109,7 +1109,7 @@ static size_t readmoredata(char *buffer,
+ void *userp)
+ {
+ struct connectdata *conn = (struct connectdata *)userp;
+- struct HTTP *http = conn->data->req.protop;
++ struct HTTP *http = conn->data->req.p.http;
+ size_t fullsize = size * nitems;
+
+ if(!http->postsize)
+@@ -1167,7 +1167,7 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
+ char *ptr;
+ size_t size;
+ struct Curl_easy *data = conn->data;
+- struct HTTP *http = data->req.protop;
++ struct HTTP *http = data->req.p.http;
+ size_t sendsize;
+ curl_socket_t sockfd;
+ size_t headersize;
+@@ -1517,7 +1517,7 @@ CURLcode Curl_http_done(struct connectdata *conn,
+ CURLcode status, bool premature)
+ {
+ struct Curl_easy *data = conn->data;
+- struct HTTP *http = data->req.protop;
++ struct HTTP *http = data->req.p.http;
+
+ /* Clear multipass flag. If authentication isn't done yet, then it will get
+ * a chance to be set back to true when we output the next auth header */
+@@ -1978,7 +1978,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
+ return result;
+ }
+ }
+- http = data->req.protop;
++ http = data->req.p.http;
+ DEBUGASSERT(http);
+
+ if(!data->state.this_is_a_follow) {
+diff --git a/lib/http2.c b/lib/http2.c
+index d316da8..c41a1c2 100644
+--- a/lib/http2.c
++++ b/lib/http2.c
+@@ -257,7 +257,7 @@ static unsigned int http2_conncheck(struct connectdata *check,
+ /* called from http_setup_conn */
+ void Curl_http2_setup_req(struct Curl_easy *data)
+ {
+- struct HTTP *http = data->req.protop;
++ struct HTTP *http = data->req.p.http;
+ http->bodystarted = FALSE;
+ http->status_code = -1;
+ http->pausedata = NULL;
+@@ -391,7 +391,7 @@ char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
+ if(!h || !GOOD_EASY_HANDLE(h->data))
+ return NULL;
+ else {
+- struct HTTP *stream = h->data->req.protop;
++ struct HTTP *stream = h->data->req.p.http;
+ if(num < stream->push_headers_used)
+ return stream->push_headers[num];
+ }
+@@ -413,7 +413,7 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
+ !strcmp(header, ":") || strchr(header + 1, ':'))
+ return NULL;
+ else {
+- struct HTTP *stream = h->data->req.protop;
++ struct HTTP *stream = h->data->req.p.http;
+ size_t len = strlen(header);
+ size_t i;
+ for(i = 0; i<stream->push_headers_used; i++) {
+@@ -460,7 +460,7 @@ static struct Curl_easy *duphandle(struct Curl_easy *data)
+ (void)Curl_close(&second);
+ }
+ else {
+- second->req.protop = http;
++ second->req.p.http = http;
+ Curl_dyn_init(&http->header_recvbuf, DYN_H2_HEADERS);
+ Curl_http2_setup_req(second);
+ second->state.stream_weight = data->state.stream_weight;
+@@ -537,7 +537,7 @@ static int push_promise(struct Curl_easy *data,
+ /* ask the application */
+ H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!\n"));
+
+- stream = data->req.protop;
++ stream = data->req.p.http;
+ if(!stream) {
+ failf(data, "Internal NULL stream!\n");
+ (void)Curl_close(&newhandle);
+@@ -567,13 +567,13 @@ static int push_promise(struct Curl_easy *data,
+ if(rv) {
+ DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
+ /* denied, kill off the new handle again */
+- http2_stream_free(newhandle->req.protop);
+- newhandle->req.protop = NULL;
++ http2_stream_free(newhandle->req.p.http);
++ newhandle->req.p.http = NULL;
+ (void)Curl_close(&newhandle);
+ goto fail;
+ }
+
+- newstream = newhandle->req.protop;
++ newstream = newhandle->req.p.http;
+ newstream->stream_id = frame->promised_stream_id;
+ newhandle->req.maxdownload = -1;
+ newhandle->req.size = -1;
+@@ -583,8 +583,8 @@ static int push_promise(struct Curl_easy *data,
+ rc = Curl_multi_add_perform(data->multi, newhandle, conn);
+ if(rc) {
+ infof(data, "failed to add handle to multi\n");
+- http2_stream_free(newhandle->req.protop);
+- newhandle->req.protop = NULL;
++ http2_stream_free(newhandle->req.p.http);
++ newhandle->req.p.http = NULL;
+ Curl_close(&newhandle);
+ rv = CURL_PUSH_DENY;
+ goto fail;
+@@ -667,7 +667,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
+ return 0;
+ }
+
+- stream = data_s->req.protop;
++ stream = data_s->req.p.http;
+ if(!stream) {
+ H2BUGF(infof(data_s, "No proto pointer for stream: %x\n",
+ stream_id));
+@@ -783,7 +783,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
+ internal error more than anything else! */
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+- stream = data_s->req.protop;
++ stream = data_s->req.p.http;
+ if(!stream)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+@@ -849,7 +849,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
+ }
+ H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
+ nghttp2_http2_strerror(error_code), error_code, stream_id));
+- stream = data_s->req.protop;
++ stream = data_s->req.p.http;
+ if(!stream)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+@@ -894,7 +894,7 @@ static int on_begin_headers(nghttp2_session *session,
+ return 0;
+ }
+
+- stream = data_s->req.protop;
++ stream = data_s->req.p.http;
+ if(!stream || !stream->bodystarted) {
+ return 0;
+ }
+@@ -952,7 +952,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
+ internal error more than anything else! */
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+- stream = data_s->req.protop;
++ stream = data_s->req.p.http;
+ if(!stream) {
+ failf(data_s, "Internal NULL stream! 5\n");
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+@@ -1100,7 +1100,7 @@ static ssize_t data_source_read_callback(nghttp2_session *session,
+ internal error more than anything else! */
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+- stream = data_s->req.protop;
++ stream = data_s->req.p.http;
+ if(!stream)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+@@ -1161,7 +1161,7 @@ static void populate_settings(struct connectdata *conn,
+
+ void Curl_http2_done(struct Curl_easy *data, bool premature)
+ {
+- struct HTTP *http = data->req.protop;
++ struct HTTP *http = data->req.p.http;
+ struct http_conn *httpc = &data->conn->proto.httpc;
+
+ /* there might be allocated resources done before this got the 'h2' pointer
+@@ -1398,7 +1398,7 @@ CURLcode Curl_http2_done_sending(struct connectdata *conn)
+ (conn->handler == &Curl_handler_http2)) {
+ /* make sure this is only attempted for HTTP/2 transfers */
+
+- struct HTTP *stream = conn->data->req.protop;
++ struct HTTP *stream = conn->data->req.p.http;
+
+ struct http_conn *httpc = &conn->proto.httpc;
+ nghttp2_session *h2 = httpc->h2;
+@@ -1522,7 +1522,7 @@ static void h2_pri_spec(struct Curl_easy *data,
+ nghttp2_priority_spec *pri_spec)
+ {
+ struct HTTP *depstream = (data->set.stream_depends_on?
+- data->set.stream_depends_on->req.protop:NULL);
++ data->set.stream_depends_on->req.p.http:NULL);
+ int32_t depstream_id = depstream? depstream->stream_id:0;
+ nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight,
+ data->set.stream_depends_e);
+@@ -1539,7 +1539,7 @@ static void h2_pri_spec(struct Curl_easy *data,
+ static int h2_session_send(struct Curl_easy *data,
+ nghttp2_session *h2)
+ {
+- struct HTTP *stream = data->req.protop;
++ struct HTTP *stream = data->req.p.http;
+ if((data->set.stream_weight != data->state.stream_weight) ||
+ (data->set.stream_depends_e != data->state.stream_depends_e) ||
+ (data->set.stream_depends_on != data->state.stream_depends_on) ) {
+@@ -1569,7 +1569,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
+ ssize_t nread;
+ struct http_conn *httpc = &conn->proto.httpc;
+ struct Curl_easy *data = conn->data;
+- struct HTTP *stream = data->req.protop;
++ struct HTTP *stream = data->req.p.http;
+
+ (void)sockindex; /* we always do HTTP2 on sockindex 0 */
+
+@@ -1874,7 +1874,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
+ */
+ int rv;
+ struct http_conn *httpc = &conn->proto.httpc;
+- struct HTTP *stream = conn->data->req.protop;
++ struct HTTP *stream = conn->data->req.p.http;
+ nghttp2_nv *nva = NULL;
+ size_t nheader;
+ size_t i;
+@@ -2183,7 +2183,7 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
+ {
+ CURLcode result;
+ struct http_conn *httpc = &conn->proto.httpc;
+- struct HTTP *stream = conn->data->req.protop;
++ struct HTTP *stream = conn->data->req.p.http;
+
+ DEBUGASSERT(conn->data->state.buffer);
+
+@@ -2238,7 +2238,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
+ int rv;
+ ssize_t nproc;
+ struct Curl_easy *data = conn->data;
+- struct HTTP *stream = conn->data->req.protop;
++ struct HTTP *stream = conn->data->req.p.http;
+
+ result = Curl_http2_setup(conn);
+ if(result)
+@@ -2358,7 +2358,7 @@ CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
+ return CURLE_OK;
+ #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
+ else {
+- struct HTTP *stream = data->req.protop;
++ struct HTTP *stream = data->req.p.http;
+ struct http_conn *httpc = &data->conn->proto.httpc;
+ uint32_t window = !pause * HTTP2_HUGE_WINDOW_SIZE;
+ int rv = nghttp2_session_set_local_window_size(httpc->h2,
+diff --git a/lib/http_proxy.c b/lib/http_proxy.c
+index f188cbf..69aacb4 100644
+--- a/lib/http_proxy.c
++++ b/lib/http_proxy.c
+@@ -102,9 +102,9 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
+ * This function might be called several times in the multi interface case
+ * if the proxy's CONNECT response is not instant.
+ */
+- prot_save = conn->data->req.protop;
++ prot_save = conn->data->req.p.http;
+ memset(&http_proxy, 0, sizeof(http_proxy));
+- conn->data->req.protop = &http_proxy;
++ conn->data->req.p.http = &http_proxy;
+ connkeep(conn, "HTTP proxy CONNECT");
+
+ /* for the secondary socket (FTP), use the "connect to host"
+@@ -125,7 +125,7 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
+ else
+ remote_port = conn->remote_port;
+ result = Curl_proxyCONNECT(conn, sockindex, hostname, remote_port);
+- conn->data->req.protop = prot_save;
++ conn->data->req.p.http = prot_save;
+ if(CURLE_OK != result)
+ return result;
+ Curl_safefree(data->state.aptr.proxyuserpwd);
+diff --git a/lib/imap.c b/lib/imap.c
+index cad0e59..bda23a5 100644
+--- a/lib/imap.c
++++ b/lib/imap.c
+@@ -244,7 +244,7 @@ static bool imap_matchresp(const char *line, size_t len, const char *cmd)
+ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
+ int *resp)
+ {
+- struct IMAP *imap = conn->data->req.protop;
++ struct IMAP *imap = conn->data->req.p.imap;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ const char *id = imapc->resptag;
+ size_t id_len = strlen(id);
+@@ -605,7 +605,7 @@ static CURLcode imap_perform_list(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct IMAP *imap = data->req.protop;
++ struct IMAP *imap = data->req.p.imap;
+
+ if(imap->custom)
+ /* Send the custom request */
+@@ -640,7 +640,7 @@ static CURLcode imap_perform_select(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct IMAP *imap = data->req.protop;
++ struct IMAP *imap = data->req.p.imap;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ char *mailbox;
+
+@@ -679,7 +679,7 @@ static CURLcode imap_perform_select(struct connectdata *conn)
+ static CURLcode imap_perform_fetch(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+- struct IMAP *imap = conn->data->req.protop;
++ struct IMAP *imap = conn->data->req.p.imap;
+ /* Check we have a UID */
+ if(imap->uid) {
+
+@@ -727,7 +727,7 @@ static CURLcode imap_perform_append(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct IMAP *imap = data->req.protop;
++ struct IMAP *imap = data->req.p.imap;
+ char *mailbox;
+
+ /* Check we have a mailbox */
+@@ -797,7 +797,7 @@ static CURLcode imap_perform_append(struct connectdata *conn)
+ static CURLcode imap_perform_search(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+- struct IMAP *imap = conn->data->req.protop;
++ struct IMAP *imap = conn->data->req.p.imap;
+
+ /* Check we have a query string */
+ if(!imap->query) {
+@@ -1051,7 +1051,7 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct IMAP *imap = conn->data->req.protop;
++ struct IMAP *imap = conn->data->req.p.imap;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ const char *line = data->state.buffer;
+
+@@ -1380,7 +1380,7 @@ static CURLcode imap_init(struct connectdata *conn)
+ struct Curl_easy *data = conn->data;
+ struct IMAP *imap;
+
+- imap = data->req.protop = calloc(sizeof(struct IMAP), 1);
++ imap = data->req.p.imap = calloc(sizeof(struct IMAP), 1);
+ if(!imap)
+ result = CURLE_OUT_OF_MEMORY;
+
+@@ -1457,7 +1457,7 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct IMAP *imap = data->req.protop;
++ struct IMAP *imap = data->req.p.imap;
+
+ (void)premature;
+
+@@ -1517,7 +1517,7 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected,
+ /* This is IMAP and no proxy */
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct IMAP *imap = data->req.protop;
++ struct IMAP *imap = data->req.p.imap;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ bool selected = FALSE;
+
+@@ -1640,7 +1640,7 @@ static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
+ /* Call this when the DO phase has completed */
+ static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
+ {
+- struct IMAP *imap = conn->data->req.protop;
++ struct IMAP *imap = conn->data->req.p.imap;
+
+ (void)connected;
+
+@@ -1942,7 +1942,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
+ /* The imap struct is already initialised in imap_connect() */
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct IMAP *imap = data->req.protop;
++ struct IMAP *imap = data->req.p.imap;
+ const char *begin = &data->state.up.path[1]; /* skip leading slash */
+ const char *ptr = begin;
+
+@@ -2074,7 +2074,7 @@ static CURLcode imap_parse_custom_request(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct IMAP *imap = data->req.protop;
++ struct IMAP *imap = data->req.p.imap;
+ const char *custom = data->set.str[STRING_CUSTOMREQUEST];
+
+ if(custom) {
+diff --git a/lib/mqtt.c b/lib/mqtt.c
+index f6f4416..86b22b8 100644
+--- a/lib/mqtt.c
++++ b/lib/mqtt.c
+@@ -95,12 +95,12 @@ static CURLcode mqtt_setup_conn(struct connectdata *conn)
+ during this request */
+ struct MQTT *mq;
+ struct Curl_easy *data = conn->data;
+- DEBUGASSERT(data->req.protop == NULL);
++ DEBUGASSERT(data->req.p.mqtt == NULL);
+
+ mq = calloc(1, sizeof(struct MQTT));
+ if(!mq)
+ return CURLE_OUT_OF_MEMORY;
+- data->req.protop = mq;
++ data->req.p.mqtt = mq;
+ return CURLE_OK;
+ }
+
+@@ -110,7 +110,7 @@ static CURLcode mqtt_send(struct connectdata *conn,
+ CURLcode result = CURLE_OK;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+ struct Curl_easy *data = conn->data;
+- struct MQTT *mq = data->req.protop;
++ struct MQTT *mq = data->req.p.mqtt;
+ ssize_t n;
+ result = Curl_write(conn, sockfd, buf, len, &n);
+ if(!result && data->set.verbose)
+@@ -426,7 +426,7 @@ static CURLcode mqtt_read_publish(struct connectdata *conn,
+ unsigned char *pkt = (unsigned char *)data->state.buffer;
+ size_t remlen;
+ struct mqtt_conn *mqtt = &conn->proto.mqtt;
+- struct MQTT *mq = data->req.protop;
++ struct MQTT *mq = data->req.p.mqtt;
+ unsigned char packet;
+
+ switch(mqtt->state) {
+@@ -533,7 +533,7 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
+ CURLcode result = CURLE_OK;
+ struct mqtt_conn *mqtt = &conn->proto.mqtt;
+ struct Curl_easy *data = conn->data;
+- struct MQTT *mq = data->req.protop;
++ struct MQTT *mq = data->req.p.mqtt;
+ ssize_t nread;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+ unsigned char *pkt = (unsigned char *)data->state.buffer;
+diff --git a/lib/openldap.c b/lib/openldap.c
+index 782d6a0..c955df6 100644
+--- a/lib/openldap.c
++++ b/lib/openldap.c
+@@ -410,7 +410,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
+ if(!lr)
+ return CURLE_OUT_OF_MEMORY;
+ lr->msgid = msgid;
+- data->req.protop = lr;
++ data->req.p.ldap = lr;
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
+ *done = TRUE;
+ return CURLE_OK;
+@@ -419,7 +419,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
+ static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
+ bool premature)
+ {
+- struct ldapreqinfo *lr = conn->data->req.protop;
++ struct ldapreqinfo *lr = conn->data->req.p.ldap;
+
+ (void)res;
+ (void)premature;
+@@ -431,7 +431,7 @@ static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
+ ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
+ lr->msgid = 0;
+ }
+- conn->data->req.protop = NULL;
++ conn->data->req.p.ldap = NULL;
+ free(lr);
+ }
+
+@@ -443,7 +443,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
+ {
+ struct ldapconninfo *li = conn->proto.ldapc;
+ struct Curl_easy *data = conn->data;
+- struct ldapreqinfo *lr = data->req.protop;
++ struct ldapreqinfo *lr = data->req.p.ldap;
+ int rc, ret;
+ LDAPMessage *msg = NULL;
+ LDAPMessage *ent;
+diff --git a/lib/pop3.c b/lib/pop3.c
+index 9ff5c78..04cc887 100644
+--- a/lib/pop3.c
++++ b/lib/pop3.c
+@@ -551,7 +551,7 @@ static CURLcode pop3_perform_command(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct POP3 *pop3 = data->req.protop;
++ struct POP3 *pop3 = data->req.p.pop3;
+ const char *command = NULL;
+
+ /* Calculate the default command */
+@@ -884,7 +884,7 @@ static CURLcode pop3_state_command_resp(struct connectdata *conn,
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct POP3 *pop3 = data->req.protop;
++ struct POP3 *pop3 = data->req.p.pop3;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ struct pingpong *pp = &pop3c->pp;
+
+@@ -1046,7 +1046,7 @@ static CURLcode pop3_init(struct connectdata *conn)
+ struct Curl_easy *data = conn->data;
+ struct POP3 *pop3;
+
+- pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
++ pop3 = data->req.p.pop3 = calloc(sizeof(struct POP3), 1);
+ if(!pop3)
+ result = CURLE_OUT_OF_MEMORY;
+
+@@ -1120,7 +1120,7 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct POP3 *pop3 = data->req.protop;
++ struct POP3 *pop3 = data->req.p.pop3;
+
+ (void)premature;
+
+@@ -1154,7 +1154,7 @@ static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
+ {
+ /* This is POP3 and no proxy */
+ CURLcode result = CURLE_OK;
+- struct POP3 *pop3 = conn->data->req.protop;
++ struct POP3 *pop3 = conn->data->req.p.pop3;
+
+ DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+@@ -1386,7 +1386,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn)
+ {
+ /* The POP3 struct is already initialised in pop3_connect() */
+ struct Curl_easy *data = conn->data;
+- struct POP3 *pop3 = data->req.protop;
++ struct POP3 *pop3 = data->req.p.pop3;
+ const char *path = &data->state.up.path[1]; /* skip leading path */
+
+ /* URL decode the path for the message ID */
+@@ -1403,7 +1403,7 @@ static CURLcode pop3_parse_custom_request(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct POP3 *pop3 = data->req.protop;
++ struct POP3 *pop3 = data->req.p.pop3;
+ const char *custom = data->set.str[STRING_CUSTOMREQUEST];
+
+ /* URL decode the custom request */
+diff --git a/lib/rtsp.c b/lib/rtsp.c
+index dbd7dc6..29e6d58 100644
+--- a/lib/rtsp.c
++++ b/lib/rtsp.c
+@@ -114,7 +114,7 @@ static CURLcode rtsp_setup_connection(struct connectdata *conn)
+ {
+ struct RTSP *rtsp;
+
+- conn->data->req.protop = rtsp = calloc(1, sizeof(struct RTSP));
++ conn->data->req.p.rtsp = rtsp = calloc(1, sizeof(struct RTSP));
+ if(!rtsp)
+ return CURLE_OUT_OF_MEMORY;
+
+@@ -199,7 +199,7 @@ static CURLcode rtsp_done(struct connectdata *conn,
+ CURLcode status, bool premature)
+ {
+ struct Curl_easy *data = conn->data;
+- struct RTSP *rtsp = data->req.protop;
++ struct RTSP *rtsp = data->req.p.rtsp;
+ CURLcode httpStatus;
+
+ /* Bypass HTTP empty-reply checks on receive */
+@@ -232,7 +232,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
+ struct Curl_easy *data = conn->data;
+ CURLcode result = CURLE_OK;
+ Curl_RtspReq rtspreq = data->set.rtspreq;
+- struct RTSP *rtsp = data->req.protop;
++ struct RTSP *rtsp = data->req.p.rtsp;
+ struct dynbuf req_buffer;
+ curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */
+ curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */
+@@ -764,7 +764,7 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
+ /* Store the received CSeq. Match is verified in rtsp_done */
+ int nc = sscanf(&header[4], ": %ld", &CSeq);
+ if(nc == 1) {
+- struct RTSP *rtsp = data->req.protop;
++ struct RTSP *rtsp = data->req.p.rtsp;
+ rtsp->CSeq_recv = CSeq; /* mark the request */
+ data->state.rtsp_CSeq_recv = CSeq; /* update the handle */
+ }
+diff --git a/lib/smb.c b/lib/smb.c
+index d493adc..9eba7ab 100644
+--- a/lib/smb.c
++++ b/lib/smb.c
+@@ -204,7 +204,7 @@ static void conn_state(struct connectdata *conn, enum smb_conn_state newstate)
+ static void request_state(struct connectdata *conn,
+ enum smb_req_state newstate)
+ {
+- struct smb_request *req = conn->data->req.protop;
++ struct smb_request *req = conn->data->req.p.smb;
+ #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* For debug purposes */
+ static const char * const names[] = {
+@@ -234,7 +234,7 @@ static CURLcode smb_setup_connection(struct connectdata *conn)
+ struct smb_request *req;
+
+ /* Initialize the request state */
+- conn->data->req.protop = req = calloc(1, sizeof(struct smb_request));
++ conn->data->req.p.smb = req = calloc(1, sizeof(struct smb_request));
+ if(!req)
+ return CURLE_OUT_OF_MEMORY;
+
+@@ -342,7 +342,7 @@ static void smb_format_message(struct connectdata *conn, struct smb_header *h,
+ unsigned char cmd, size_t len)
+ {
+ struct smb_conn *smbc = &conn->proto.smbc;
+- struct smb_request *req = conn->data->req.protop;
++ struct smb_request *req = conn->data->req.p.smb;
+ unsigned int pid;
+
+ memset(h, 0, sizeof(*h));
+@@ -505,7 +505,7 @@ static CURLcode smb_send_tree_connect(struct connectdata *conn)
+
+ static CURLcode smb_send_open(struct connectdata *conn)
+ {
+- struct smb_request *req = conn->data->req.protop;
++ struct smb_request *req = conn->data->req.p.smb;
+ struct smb_nt_create msg;
+ size_t byte_count;
+
+@@ -535,7 +535,7 @@ static CURLcode smb_send_open(struct connectdata *conn)
+
+ static CURLcode smb_send_close(struct connectdata *conn)
+ {
+- struct smb_request *req = conn->data->req.protop;
++ struct smb_request *req = conn->data->req.p.smb;
+ struct smb_close msg;
+
+ memset(&msg, 0, sizeof(msg));
+@@ -556,7 +556,7 @@ static CURLcode smb_send_tree_disconnect(struct connectdata *conn)
+
+ static CURLcode smb_send_read(struct connectdata *conn)
+ {
+- struct smb_request *req = conn->data->req.protop;
++ struct smb_request *req = conn->data->req.p.smb;
+ curl_off_t offset = conn->data->req.offset;
+ struct smb_read msg;
+
+@@ -575,7 +575,7 @@ static CURLcode smb_send_read(struct connectdata *conn)
+ static CURLcode smb_send_write(struct connectdata *conn)
+ {
+ struct smb_write *msg;
+- struct smb_request *req = conn->data->req.protop;
++ struct smb_request *req = conn->data->req.p.smb;
+ curl_off_t offset = conn->data->req.offset;
+ curl_off_t upload_size = conn->data->req.size - conn->data->req.bytecount;
+ CURLcode result = Curl_get_upload_buffer(conn->data);
+@@ -738,7 +738,7 @@ static void get_posix_time(time_t *out, curl_off_t timestamp)
+
+ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
+ {
+- struct smb_request *req = conn->data->req.protop;
++ struct smb_request *req = conn->data->req.p.smb;
+ struct smb_header *h;
+ struct smb_conn *smbc = &conn->proto.smbc;
+ enum smb_req_state next_state = SMB_DONE;
+@@ -923,7 +923,7 @@ static CURLcode smb_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+ {
+ (void) premature;
+- Curl_safefree(conn->data->req.protop);
++ Curl_safefree(conn->data->req.p.smb);
+ return status;
+ }
+
+@@ -957,7 +957,7 @@ static CURLcode smb_do(struct connectdata *conn, bool *done)
+ static CURLcode smb_parse_url_path(struct connectdata *conn)
+ {
+ struct Curl_easy *data = conn->data;
+- struct smb_request *req = data->req.protop;
++ struct smb_request *req = data->req.p.smb;
+ struct smb_conn *smbc = &conn->proto.smbc;
+ char *path;
+ char *slash;
+diff --git a/lib/smtp.c b/lib/smtp.c
+index aea41bb..c5d0296 100644
+--- a/lib/smtp.c
++++ b/lib/smtp.c
+@@ -484,7 +484,7 @@ static CURLcode smtp_perform_command(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct SMTP *smtp = data->req.protop;
++ struct SMTP *smtp = data->req.p.smtp;
+
+ if(smtp->rcpt) {
+ /* We notify the server we are sending UTF-8 data if a) it supports the
+@@ -697,7 +697,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
+ any there do, as we need to correctly identify our support for SMTPUTF8
+ in the envelope, as per RFC-6531 sect. 3.4 */
+ if(conn->proto.smtpc.utf8_supported && !utf8) {
+- struct SMTP *smtp = data->req.protop;
++ struct SMTP *smtp = data->req.p.smtp;
+ struct curl_slist *rcpt = smtp->rcpt;
+
+ while(rcpt && !utf8) {
+@@ -741,7 +741,7 @@ static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct SMTP *smtp = data->req.protop;
++ struct SMTP *smtp = data->req.p.smtp;
+ char *address = NULL;
+ struct hostname host = { NULL, NULL, NULL, NULL };
+
+@@ -989,7 +989,7 @@ static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct SMTP *smtp = data->req.protop;
++ struct SMTP *smtp = data->req.p.smtp;
+ char *line = data->state.buffer;
+ size_t len = strlen(line);
+
+@@ -1055,7 +1055,7 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct SMTP *smtp = data->req.protop;
++ struct SMTP *smtp = data->req.p.smtp;
+ bool is_smtp_err = FALSE;
+ bool is_smtp_blocking_err = FALSE;
+
+@@ -1278,7 +1278,7 @@ static CURLcode smtp_init(struct connectdata *conn)
+ struct Curl_easy *data = conn->data;
+ struct SMTP *smtp;
+
+- smtp = data->req.protop = calloc(sizeof(struct SMTP), 1);
++ smtp = data->req.p.smtp = calloc(sizeof(struct SMTP), 1);
+ if(!smtp)
+ result = CURLE_OUT_OF_MEMORY;
+
+@@ -1356,7 +1356,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct SMTP *smtp = data->req.protop;
++ struct SMTP *smtp = data->req.p.smtp;
+ struct pingpong *pp = &conn->proto.smtpc.pp;
+ char *eob;
+ ssize_t len;
+@@ -1442,7 +1442,7 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
+ /* This is SMTP and no proxy */
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct SMTP *smtp = data->req.protop;
++ struct SMTP *smtp = data->req.p.smtp;
+
+ DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+@@ -1550,7 +1550,7 @@ static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
+ /* Call this when the DO phase has completed */
+ static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
+ {
+- struct SMTP *smtp = conn->data->req.protop;
++ struct SMTP *smtp = conn->data->req.p.smtp;
+
+ (void)connected;
+
+@@ -1703,7 +1703,7 @@ static CURLcode smtp_parse_custom_request(struct connectdata *conn)
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct SMTP *smtp = data->req.protop;
++ struct SMTP *smtp = data->req.p.smtp;
+ const char *custom = data->set.str[STRING_CUSTOMREQUEST];
+
+ /* URL decode the custom request */
+@@ -1796,7 +1796,7 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
+ ssize_t i;
+ ssize_t si;
+ struct Curl_easy *data = conn->data;
+- struct SMTP *smtp = data->req.protop;
++ struct SMTP *smtp = data->req.p.smtp;
+ char *scratch = data->state.scratch;
+ char *newscratch = NULL;
+ char *oldscratch = NULL;
+diff --git a/lib/telnet.c b/lib/telnet.c
+index c3b58e5..1fc5af1 100644
+--- a/lib/telnet.c
++++ b/lib/telnet.c
+@@ -247,7 +247,7 @@ CURLcode init_telnet(struct connectdata *conn)
+ if(!tn)
+ return CURLE_OUT_OF_MEMORY;
+
+- conn->data->req.protop = tn; /* make us known */
++ conn->data->req.p.telnet = tn; /* make us known */
+
+ tn->telrcv_state = CURL_TS_DATA;
+
+@@ -292,7 +292,7 @@ CURLcode init_telnet(struct connectdata *conn)
+ static void negotiate(struct connectdata *conn)
+ {
+ int i;
+- struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
++ struct TELNET *tn = (struct TELNET *) conn->data->req.p.telnet;
+
+ for(i = 0; i < CURL_NTELOPTS; i++) {
+ if(i == CURL_TELOPT_ECHO)
+@@ -365,7 +365,7 @@ static void send_negotiation(struct connectdata *conn, int cmd, int option)
+ static
+ void set_remote_option(struct connectdata *conn, int option, int newstate)
+ {
+- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
+ if(newstate == CURL_YES) {
+ switch(tn->him[option]) {
+ case CURL_NO:
+@@ -439,7 +439,7 @@ void set_remote_option(struct connectdata *conn, int option, int newstate)
+ static
+ void rec_will(struct connectdata *conn, int option)
+ {
+- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
+ switch(tn->him[option]) {
+ case CURL_NO:
+ if(tn->him_preferred[option] == CURL_YES) {
+@@ -487,7 +487,7 @@ void rec_will(struct connectdata *conn, int option)
+ static
+ void rec_wont(struct connectdata *conn, int option)
+ {
+- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
+ switch(tn->him[option]) {
+ case CURL_NO:
+ /* Already disabled */
+@@ -529,7 +529,7 @@ void rec_wont(struct connectdata *conn, int option)
+ static void
+ set_local_option(struct connectdata *conn, int option, int newstate)
+ {
+- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
+ if(newstate == CURL_YES) {
+ switch(tn->us[option]) {
+ case CURL_NO:
+@@ -603,7 +603,7 @@ set_local_option(struct connectdata *conn, int option, int newstate)
+ static
+ void rec_do(struct connectdata *conn, int option)
+ {
+- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
+ switch(tn->us[option]) {
+ case CURL_NO:
+ if(tn->us_preferred[option] == CURL_YES) {
+@@ -663,7 +663,7 @@ void rec_do(struct connectdata *conn, int option)
+ static
+ void rec_dont(struct connectdata *conn, int option)
+ {
+- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
+ switch(tn->us[option]) {
+ case CURL_NO:
+ /* Already disabled */
+@@ -822,7 +822,7 @@ static CURLcode check_telnet_options(struct connectdata *conn)
+ char option_keyword[128] = "";
+ char option_arg[256] = "";
+ struct Curl_easy *data = conn->data;
+- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
+ CURLcode result = CURLE_OK;
+ int binary_option;
+
+@@ -929,7 +929,7 @@ static void suboption(struct connectdata *conn)
+ char varname[128] = "";
+ char varval[128] = "";
+ struct Curl_easy *data = conn->data;
+- struct TELNET *tn = (struct TELNET *)data->req.protop;
++ struct TELNET *tn = (struct TELNET *)data->req.p.telnet;
+
+ printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2);
+ switch(CURL_SB_GET(tn)) {
+@@ -1004,7 +1004,7 @@ static void sendsuboption(struct connectdata *conn, int option)
+ unsigned char *uc1, *uc2;
+
+ struct Curl_easy *data = conn->data;
+- struct TELNET *tn = (struct TELNET *)data->req.protop;
++ struct TELNET *tn = (struct TELNET *)data->req.p.telnet;
+
+ switch(option) {
+ case CURL_TELOPT_NAWS:
+@@ -1062,7 +1062,7 @@ CURLcode telrcv(struct connectdata *conn,
+ int in = 0;
+ int startwrite = -1;
+ struct Curl_easy *data = conn->data;
+- struct TELNET *tn = (struct TELNET *)data->req.protop;
++ struct TELNET *tn = (struct TELNET *)data->req.p.telnet;
+
+ #define startskipping() \
+ if(startwrite >= 0) { \
+@@ -1280,7 +1280,7 @@ static CURLcode send_telnet_data(struct connectdata *conn,
+ static CURLcode telnet_done(struct connectdata *conn,
+ CURLcode status, bool premature)
+ {
+- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
+ (void)status; /* unused */
+ (void)premature; /* not used */
+
+@@ -1290,7 +1290,7 @@ static CURLcode telnet_done(struct connectdata *conn,
+ curl_slist_free_all(tn->telnet_vars);
+ tn->telnet_vars = NULL;
+
+- Curl_safefree(conn->data->req.protop);
++ Curl_safefree(conn->data->req.p.telnet);
+
+ return CURLE_OK;
+ }
+@@ -1333,7 +1333,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
+ if(result)
+ return result;
+
+- tn = (struct TELNET *)data->req.protop;
++ tn = data->req.p.telnet;
+
+ result = check_telnet_options(conn);
+ if(result)
+diff --git a/lib/transfer.c b/lib/transfer.c
+index a07c7af..4630609 100644
+--- a/lib/transfer.c
++++ b/lib/transfer.c
+@@ -167,7 +167,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
+ bool sending_http_headers = FALSE;
+
+ if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) {
+- const struct HTTP *http = data->req.protop;
++ const struct HTTP *http = data->req.p.http;
+
+ if(http->sending == HTTPSEND_REQUEST)
+ /* We're sending the HTTP request headers, not the data.
+@@ -426,7 +426,7 @@ CURLcode Curl_readrewind(struct connectdata *conn)
+ CURLOPT_HTTPPOST, call app to rewind
+ */
+ if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
+- struct HTTP *http = data->req.protop;
++ struct HTTP *http = data->req.p.http;
+
+ if(http->sendit)
+ mimepart = http->sendit;
+@@ -1028,7 +1028,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
+ /* HTTP pollution, this should be written nicer to become more
+ protocol agnostic. */
+ size_t fillcount;
+- struct HTTP *http = k->protop;
++ struct HTTP *http = k->p.http;
+
+ if((k->exp100 == EXP100_SENDING_REQUEST) &&
+ (http->sending == HTTPSEND_BODY)) {
+@@ -1853,7 +1853,7 @@ Curl_setup_transfer(
+ {
+ struct SingleRequest *k = &data->req;
+ struct connectdata *conn = data->conn;
+- struct HTTP *http = data->req.protop;
++ struct HTTP *http = data->req.p.http;
+ bool httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) &&
+ (http->sending == HTTPSEND_REQUEST));
+ DEBUGASSERT(conn != NULL);
+diff --git a/lib/url.c b/lib/url.c
+index 150667a..849d527 100644
+--- a/lib/url.c
++++ b/lib/url.c
+@@ -2060,7 +2060,7 @@ static CURLcode setup_connection_internals(struct connectdata *conn)
+
+ void Curl_free_request_state(struct Curl_easy *data)
+ {
+- Curl_safefree(data->req.protop);
++ Curl_safefree(data->req.p.http);
+ Curl_safefree(data->req.newurl);
+
+ #ifndef CURL_DISABLE_DOH
+diff --git a/lib/urldata.h b/lib/urldata.h
+index 0ae9269..76baee3 100644
+--- a/lib/urldata.h
++++ b/lib/urldata.h
+@@ -645,8 +645,23 @@ struct SingleRequest {
+ and the 'upload_present' contains the number of bytes available at this
+ position */
+ char *upload_fromhere;
+- void *protop; /* Allocated protocol-specific data. Each protocol
+- handler makes sure this points to data it needs. */
++
++ /* Allocated protocol-specific data. Each protocol handler makes sure this
++ points to data it needs. */
++ union {
++ struct FILEPROTO *file;
++ struct FTP *ftp;
++ struct HTTP *http;
++ struct IMAP *imap;
++ struct ldapreqinfo *ldap;
++ struct MQTT *mqtt;
++ struct POP3 *pop3;
++ struct RTSP *rtsp;
++ struct smb_request *smb;
++ struct SMTP *smtp;
++ struct SSHPROTO *ssh;
++ struct TELNET *telnet;
++ } p;
+ #ifndef CURL_DISABLE_DOH
+ struct dohdata doh; /* DoH specific data for this request */
+ #endif
+diff --git a/lib/vquic/ngtcp2.c b/lib/vquic/ngtcp2.c
+index 20ee08d..18eeda8 100644
+--- a/lib/vquic/ngtcp2.c
++++ b/lib/vquic/ngtcp2.c
+@@ -962,7 +962,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
+ void *stream_user_data)
+ {
+ struct Curl_easy *data = stream_user_data;
+- struct HTTP *stream = data->req.protop;
++ struct HTTP *stream = data->req.p.http;
+ (void)conn;
+ (void)stream_id;
+ (void)app_error_code;
+@@ -1008,7 +1008,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream_id,
+ void *user_data, void *stream_user_data)
+ {
+ struct Curl_easy *data = stream_user_data;
+- struct HTTP *stream = data->req.protop;
++ struct HTTP *stream = data->req.p.http;
+ CURLcode result = CURLE_OK;
+ (void)conn;
+
+@@ -1067,7 +1067,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
+ void *user_data, void *stream_user_data)
+ {
+ struct Curl_easy *data = stream_user_data;
+- struct HTTP *stream = data->req.protop;
++ struct HTTP *stream = data->req.p.http;
+ CURLcode result = CURLE_OK;
+ (void)conn;
+ (void)stream_id;
+@@ -1091,7 +1091,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
+ nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
+ nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
+ struct Curl_easy *data = stream_user_data;
+- struct HTTP *stream = data->req.protop;
++ struct HTTP *stream = data->req.p.http;
+ CURLcode result = CURLE_OK;
+ (void)conn;
+ (void)stream_id;
+@@ -1255,7 +1255,7 @@ static ssize_t ngh3_stream_recv(struct connectdata *conn,
+ CURLcode *curlcode)
+ {
+ curl_socket_t sockfd = conn->sock[sockindex];
+- struct HTTP *stream = conn->data->req.protop;
++ struct HTTP *stream = conn->data->req.p.http;
+ struct quicsocket *qs = conn->quic;
+
+ if(!stream->memlen) {
+@@ -1313,7 +1313,7 @@ static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
+ void *stream_user_data)
+ {
+ struct Curl_easy *data = stream_user_data;
+- struct HTTP *stream = data->req.protop;
++ struct HTTP *stream = data->req.p.http;
+ (void)conn;
+ (void)stream_id;
+ (void)user_data;
+@@ -1335,7 +1335,7 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
+ {
+ struct Curl_easy *data = stream_user_data;
+ size_t nread;
+- struct HTTP *stream = data->req.protop;
++ struct HTTP *stream = data->req.p.http;
+ (void)conn;
+ (void)stream_id;
+ (void)user_data;
+@@ -1398,7 +1398,7 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
+ static CURLcode http_request(struct connectdata *conn, const void *mem,
+ size_t len)
+ {
+- struct HTTP *stream = conn->data->req.protop;
++ struct HTTP *stream = conn->data->req.p.http;
+ size_t nheader;
+ size_t i;
+ size_t authority_idx;
+@@ -1641,7 +1641,7 @@ static ssize_t ngh3_stream_send(struct connectdata *conn,
+ ssize_t sent;
+ struct quicsocket *qs = conn->quic;
+ curl_socket_t sockfd = conn->sock[sockindex];
+- struct HTTP *stream = conn->data->req.protop;
++ struct HTTP *stream = conn->data->req.p.http;
+
+ if(!stream->h3req) {
+ CURLcode result = http_request(conn, mem, len);
+@@ -1909,7 +1909,7 @@ CURLcode Curl_quic_done_sending(struct connectdata *conn)
+ {
+ if(conn->handler == &Curl_handler_http3) {
+ /* only for HTTP/3 transfers */
+- struct HTTP *stream = conn->data->req.protop;
++ struct HTTP *stream = conn->data->req.p.http;
+ struct quicsocket *qs = conn->quic;
+ stream->upload_done = TRUE;
+ (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
+@@ -1926,7 +1926,7 @@ void Curl_quic_done(struct Curl_easy *data, bool premature)
+ (void)premature;
+ if(data->conn->handler == &Curl_handler_http3) {
+ /* only for HTTP/3 transfers */
+- struct HTTP *stream = data->req.protop;
++ struct HTTP *stream = data->req.p.http;
+ Curl_dyn_free(&stream->overflow);
+ }
+ }
+@@ -1941,7 +1941,7 @@ bool Curl_quic_data_pending(const struct Curl_easy *data)
+ buffer and allocated an overflow buffer. Since it's possible that
+ there's no more data coming on the socket, we need to keep reading
+ until the overflow buffer is empty. */
+- const struct HTTP *stream = data->req.protop;
++ const struct HTTP *stream = data->req.p.http;
+ return Curl_dyn_len(&stream->overflow) > 0;
+ }
+
+diff --git a/lib/vquic/quiche.c b/lib/vquic/quiche.c
+index fd9cb8b..c0e250d 100644
+--- a/lib/vquic/quiche.c
++++ b/lib/vquic/quiche.c
+@@ -131,7 +131,7 @@ static unsigned int quiche_conncheck(struct connectdata *conn,
+
+ static CURLcode quiche_do(struct connectdata *conn, bool *done)
+ {
+- struct HTTP *stream = conn->data->req.protop;
++ struct HTTP *stream = conn->data->req.p.http;
+ stream->h3req = FALSE; /* not sent */
+ return Curl_http(conn, done);
+ }
+@@ -460,7 +460,7 @@ static ssize_t h3_stream_recv(struct connectdata *conn,
+ int rc;
+ struct h3h1header headers;
+ struct Curl_easy *data = conn->data;
+- struct HTTP *stream = data->req.protop;
++ struct HTTP *stream = data->req.p.http;
+ headers.dest = buf;
+ headers.destlen = buffersize;
+ headers.nlen = 0;
+@@ -548,7 +548,7 @@ static ssize_t h3_stream_send(struct connectdata *conn,
+ ssize_t sent;
+ struct quicsocket *qs = conn->quic;
+ curl_socket_t sockfd = conn->sock[sockindex];
+- struct HTTP *stream = conn->data->req.protop;
++ struct HTTP *stream = conn->data->req.p.http;
+
+ if(!stream->h3req) {
+ CURLcode result = http_request(conn, mem, len);
+@@ -596,7 +596,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
+ {
+ /*
+ */
+- struct HTTP *stream = conn->data->req.protop;
++ struct HTTP *stream = conn->data->req.p.http;
+ size_t nheader;
+ size_t i;
+ size_t authority_idx;
+@@ -824,7 +824,7 @@ CURLcode Curl_quic_done_sending(struct connectdata *conn)
+ if(conn->handler == &Curl_handler_http3) {
+ /* only for HTTP/3 transfers */
+ ssize_t sent;
+- struct HTTP *stream = conn->data->req.protop;
++ struct HTTP *stream = conn->data->req.p.http;
+ struct quicsocket *qs = conn->quic;
+ fprintf(stderr, "!!! Curl_quic_done_sending\n");
+ stream->upload_done = TRUE;
+diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c
+index 8988e23..a84e1bf 100644
+--- a/lib/vssh/libssh.c
++++ b/lib/vssh/libssh.c
+@@ -662,7 +662,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct SSHPROTO *protop = data->req.protop;
++ struct SSHPROTO *protop = data->req.p.ssh;
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ int rc = SSH_NO_ERROR, err;
+@@ -2129,7 +2129,7 @@ static CURLcode myssh_setup_connection(struct connectdata *conn)
+ {
+ struct SSHPROTO *ssh;
+
+- conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
++ conn->data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
+ if(!ssh)
+ return CURLE_OUT_OF_MEMORY;
+
+@@ -2152,7 +2152,7 @@ static CURLcode myssh_connect(struct connectdata *conn, bool *done)
+ int rc;
+
+ /* initialize per-handle data if not already */
+- if(!data->req.protop)
++ if(!data->req.p.ssh)
+ myssh_setup_connection(conn);
+
+ /* We default to persistent connections. We set this already in this connect
+@@ -2353,7 +2353,7 @@ static CURLcode scp_disconnect(struct connectdata *conn,
+ static CURLcode myssh_done(struct connectdata *conn, CURLcode status)
+ {
+ CURLcode result = CURLE_OK;
+- struct SSHPROTO *protop = conn->data->req.protop;
++ struct SSHPROTO *protop = conn->data->req.p.ssh;
+
+ if(!status) {
+ /* run the state-machine */
+@@ -2606,7 +2606,7 @@ static void sftp_quote(struct connectdata *conn)
+ {
+ const char *cp;
+ struct Curl_easy *data = conn->data;
+- struct SSHPROTO *protop = data->req.protop;
++ struct SSHPROTO *protop = data->req.p.ssh;
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ CURLcode result;
+
+diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c
+index 4f56bb4..3ed777f 100644
+--- a/lib/vssh/libssh2.c
++++ b/lib/vssh/libssh2.c
+@@ -789,7 +789,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
+ {
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+- struct SSHPROTO *sftp_scp = data->req.protop;
++ struct SSHPROTO *sftp_scp = data->req.p.ssh;
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ int rc = LIBSSH2_ERROR_NONE;
+@@ -2989,7 +2989,7 @@ static CURLcode ssh_setup_connection(struct connectdata *conn)
+ {
+ struct SSHPROTO *ssh;
+
+- conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
++ conn->data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
+ if(!ssh)
+ return CURLE_OUT_OF_MEMORY;
+
+@@ -3013,7 +3013,7 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
+ struct Curl_easy *data = conn->data;
+
+ /* initialize per-handle data if not already */
+- if(!data->req.protop)
++ if(!data->req.p.ssh)
+ ssh_setup_connection(conn);
+
+ /* We default to persistent connections. We set this already in this connect
+@@ -3192,7 +3192,7 @@ static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection)
+ static CURLcode ssh_done(struct connectdata *conn, CURLcode status)
+ {
+ CURLcode result = CURLE_OK;
+- struct SSHPROTO *sftp_scp = conn->data->req.protop;
++ struct SSHPROTO *sftp_scp = conn->data->req.p.ssh;
+
+ if(!status) {
+ /* run the state-machine */
+diff --git a/lib/vssh/wolfssh.c b/lib/vssh/wolfssh.c
+index dcbbab6..1b990e3 100644
+--- a/lib/vssh/wolfssh.c
++++ b/lib/vssh/wolfssh.c
+@@ -322,7 +322,7 @@ static CURLcode wssh_setup_connection(struct connectdata *conn)
+ {
+ struct SSHPROTO *ssh;
+
+- conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
++ conn->data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
+ if(!ssh)
+ return CURLE_OUT_OF_MEMORY;
+
+@@ -356,7 +356,7 @@ static CURLcode wssh_connect(struct connectdata *conn, bool *done)
+ int rc;
+
+ /* initialize per-handle data if not already */
+- if(!data->req.protop)
++ if(!data->req.p.ssh)
+ wssh_setup_connection(conn);
+
+ /* We default to persistent connections. We set this already in this connect
+@@ -429,7 +429,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
+ CURLcode result = CURLE_OK;
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ struct Curl_easy *data = conn->data;
+- struct SSHPROTO *sftp_scp = data->req.protop;
++ struct SSHPROTO *sftp_scp = data->req.p.ssh;
+ WS_SFTPNAME *name;
+ int rc = 0;
+ *block = FALSE; /* we're not blocking by default */
+@@ -1027,7 +1027,7 @@ static CURLcode wssh_block_statemach(struct connectdata *conn,
+ static CURLcode wssh_done(struct connectdata *conn, CURLcode status)
+ {
+ CURLcode result = CURLE_OK;
+- struct SSHPROTO *sftp_scp = conn->data->req.protop;
++ struct SSHPROTO *sftp_scp = conn->data->req.p.ssh;
+
+ if(!status) {
+ /* run the state-machine */
diff --git a/meta/recipes-support/curl/curl/CVE-2020-8284.patch b/meta/recipes-support/curl/curl/CVE-2020-8284.patch
new file mode 100644
index 00000000000..4ae514ffa8b
--- /dev/null
+++ b/meta/recipes-support/curl/curl/CVE-2020-8284.patch
@@ -0,0 +1,210 @@
+From ec9cc725d598ac77de7b6df8afeec292b3c8ad46 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Tue, 24 Nov 2020 14:56:57 +0100
+Subject: [PATCH] ftp: CURLOPT_FTP_SKIP_PASV_IP by default
+
+The command line tool also independently sets --ftp-skip-pasv-ip by
+default.
+
+Ten test cases updated to adapt the modified --libcurl output.
+
+Bug: https://curl.se/docs/CVE-2020-8284.html
+CVE-2020-8284
+
+Reported-by: Varnavas Papaioannou
+
+Upstream-Status: Backport [https://github.com/curl/curl/commit/ec9cc725d598ac]
+
+CVE: CVE-2020-8284
+
+Signed-off-by: Daniel Stenberg <daniel@haxx.se>
+Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
+---
+ docs/cmdline-opts/ftp-skip-pasv-ip.d | 2 ++
+ docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 | 8 +++++---
+ lib/url.c | 1 +
+ src/tool_cfgable.c | 1 +
+ tests/data/test1400 | 1 +
+ tests/data/test1401 | 1 +
+ tests/data/test1402 | 1 +
+ tests/data/test1403 | 1 +
+ tests/data/test1404 | 1 +
+ tests/data/test1405 | 1 +
+ tests/data/test1406 | 1 +
+ tests/data/test1407 | 1 +
+ tests/data/test1420 | 1 +
+ 14 files changed, 18 insertions(+), 3 deletions(-)
+
+diff --git a/docs/cmdline-opts/ftp-skip-pasv-ip.d b/docs/cmdline-opts/ftp-skip-pasv-ip.d
+index d6fd4589b1e..bcf4e7e62f2 100644
+--- a/docs/cmdline-opts/ftp-skip-pasv-ip.d
++++ b/docs/cmdline-opts/ftp-skip-pasv-ip.d
+@@ -10,4 +10,6 @@ to curl's PASV command when curl connects the data connection. Instead curl
+ will re-use the same IP address it already uses for the control
+ connection.
+
++Since curl 7.74.0 this option is enabled by default.
++
+ This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
+diff --git a/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 b/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3
+index d6217d0d8ca..fa87ddce769 100644
+--- a/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3
++++ b/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3
+@@ -5,7 +5,7 @@
+ .\" * | (__| |_| | _ <| |___
+ .\" * \___|\___/|_| \_\_____|
+ .\" *
+-.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
++.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ .\" *
+ .\" * This software is licensed as described in the file COPYING, which
+ .\" * you should have received as part of this distribution. The terms
+@@ -35,11 +35,13 @@ address it already uses for the control connection. But it will use the port
+ number from the 227-response.
+
+ This option thus allows libcurl to work around broken server installations
+-that due to NATs, firewalls or incompetence report the wrong IP address back.
++that due to NATs, firewalls or incompetence report the wrong IP address
++back. Setting the option also reduces the risk for various sorts of client
++abuse by malicious servers.
+
+ This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
+ .SH DEFAULT
+-0
++1 since 7.74.0, was 0 before then.
+ .SH PROTOCOLS
+ FTP
+ .SH EXAMPLE
+diff --git a/lib/url.c b/lib/url.c
+index f8b2a0030de..2b0ba87ba87 100644
+--- a/lib/url.c
++++ b/lib/url.c
+@@ -497,6 +497,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
+ set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
+ set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */
+ set->ftp_filemethod = FTPFILE_MULTICWD;
++ set->ftp_skip_ip = TRUE; /* skip PASV IP by default */
+ #endif
+ set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
+
+diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c
+index c52d8e1c6bb..4c06d3557b7 100644
+--- a/src/tool_cfgable.c
++++ b/src/tool_cfgable.c
+@@ -44,6 +44,7 @@ void config_init(struct OperationConfig *config)
+ config->tcp_nodelay = TRUE; /* enabled by default */
+ config->happy_eyeballs_timeout_ms = CURL_HET_DEFAULT;
+ config->http09_allowed = FALSE;
++ config->ftp_skip_ip = TRUE;
+ }
+
+ static void free_config_fields(struct OperationConfig *config)
+diff --git a/tests/data/test1400 b/tests/data/test1400
+index 812ad0b88d9..b7060eca58e 100644
+--- a/tests/data/test1400
++++ b/tests/data/test1400
+@@ -73,6 +73,7 @@ int main(int argc, char *argv[])
+ curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
+ curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
+ curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+ curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+
+ /* Here is a list of options the curl code used that cannot get generated
+diff --git a/tests/data/test1401 b/tests/data/test1401
+index f93b3d637de..a2629683aff 100644
+--- a/tests/data/test1401
++++ b/tests/data/test1401
+@@ -87,6 +87,7 @@ int main(int argc, char *argv[])
+ curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
+ curl_easy_setopt(hnd, CURLOPT_COOKIE, "chocolate=chip");
+ curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+ curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+ curl_easy_setopt(hnd, CURLOPT_PROTOCOLS, (long)CURLPROTO_FILE |
+ (long)CURLPROTO_FTP |
+diff --git a/tests/data/test1402 b/tests/data/test1402
+index 7593c516da1..1bd55cb4e3b 100644
+--- a/tests/data/test1402
++++ b/tests/data/test1402
+@@ -78,6 +78,7 @@ int main(int argc, char *argv[])
+ curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
+ curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
+ curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+ curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+
+ /* Here is a list of options the curl code used that cannot get generated
+diff --git a/tests/data/test1403 b/tests/data/test1403
+index ecb4dd3dcab..a7c9fcca322 100644
+--- a/tests/data/test1403
++++ b/tests/data/test1403
+@@ -73,6 +73,7 @@ int main(int argc, char *argv[])
+ curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
+ curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
+ curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+ curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+
+ /* Here is a list of options the curl code used that cannot get generated
+diff --git a/tests/data/test1404 b/tests/data/test1404
+index 97622b63948..1d8e8cf7779 100644
+--- a/tests/data/test1404
++++ b/tests/data/test1404
+@@ -147,6 +147,7 @@ int main(int argc, char *argv[])
+ curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
+ curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
+ curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+ curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+
+ /* Here is a list of options the curl code used that cannot get generated
+diff --git a/tests/data/test1405 b/tests/data/test1405
+index 2bac79eda74..b4087704f7b 100644
+--- a/tests/data/test1405
++++ b/tests/data/test1405
+@@ -89,6 +89,7 @@ int main(int argc, char *argv[])
+ curl_easy_setopt(hnd, CURLOPT_POSTQUOTE, slist2);
+ curl_easy_setopt(hnd, CURLOPT_PREQUOTE, slist3);
+ curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+ curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+
+ /* Here is a list of options the curl code used that cannot get generated
+diff --git a/tests/data/test1406 b/tests/data/test1406
+index 51a166adff2..38f68d11ee1 100644
+--- a/tests/data/test1406
++++ b/tests/data/test1406
+@@ -79,6 +79,7 @@ int main(int argc, char *argv[])
+ curl_easy_setopt(hnd, CURLOPT_URL, "smtp://%HOSTIP:%SMTPPORT/1406");
+ curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L);
+ curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+ curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+ curl_easy_setopt(hnd, CURLOPT_MAIL_FROM, "sender@example.com");
+ curl_easy_setopt(hnd, CURLOPT_MAIL_RCPT, slist1);
+diff --git a/tests/data/test1407 b/tests/data/test1407
+index f6879008fb2..a7e13ba7585 100644
+--- a/tests/data/test1407
++++ b/tests/data/test1407
+@@ -62,6 +62,7 @@ int main(int argc, char *argv[])
+ curl_easy_setopt(hnd, CURLOPT_DIRLISTONLY, 1L);
+ curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret");
+ curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+ curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+
+ /* Here is a list of options the curl code used that cannot get generated
+diff --git a/tests/data/test1420 b/tests/data/test1420
+index 057ecc4773a..4b8d7bbf418 100644
+--- a/tests/data/test1420
++++ b/tests/data/test1420
+@@ -67,6 +67,7 @@ int main(int argc, char *argv[])
+ curl_easy_setopt(hnd, CURLOPT_URL, "imap://%HOSTIP:%IMAPPORT/1420/;MAILINDEX=1");
+ curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret");
+ curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+ curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+
+ /* Here is a list of options the curl code used that cannot get generated
+
diff --git a/meta/recipes-support/curl/curl/CVE-2020-8285.patch b/meta/recipes-support/curl/curl/CVE-2020-8285.patch
new file mode 100644
index 00000000000..7a8be684775
--- /dev/null
+++ b/meta/recipes-support/curl/curl/CVE-2020-8285.patch
@@ -0,0 +1,261 @@
+From 69a358f2186e04cf44698b5100332cbf1ee7f01d Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Sat, 28 Nov 2020 00:27:21 +0100
+Subject: [PATCH] ftp: make wc_statemach loop instead of recurse
+
+CVE-2020-8285
+
+Fixes #6255
+Bug: https://curl.se/docs/CVE-2020-8285.html
+Reported-by: xnynx on github
+
+Upstream-Status: Backport [https://github.com/curl/curl/commit/69a358f2186e04]
+
+CVE: CVE-2020-8285
+
+Signed-off-by: Daniel Stenberg <daniel@haxx.se>
+Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
+
+[Ajusted to match Dunfell context]
+Signed-off-by: Armin Kuster <akuster@mvista.com>
+---
+ lib/ftp.c | 202 +++++++++++++++++++++++++++---------------------------
+ 1 file changed, 102 insertions(+), 100 deletions(-)
+
+Index: curl-7.69.1/lib/ftp.c
+===================================================================
+--- curl-7.69.1.orig/lib/ftp.c
++++ curl-7.69.1/lib/ftp.c
+@@ -3763,129 +3763,134 @@ static CURLcode init_wc_data(struct conn
+ return result;
+ }
+
+-/* This is called recursively */
+ static CURLcode wc_statemach(struct connectdata *conn)
+ {
+ struct WildcardData * const wildcard = &(conn->data->wildcard);
+ CURLcode result = CURLE_OK;
+
+- switch(wildcard->state) {
+- case CURLWC_INIT:
+- result = init_wc_data(conn);
+- if(wildcard->state == CURLWC_CLEAN)
+- /* only listing! */
+- break;
+- wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
+- break;
+-
+- case CURLWC_MATCHING: {
+- /* In this state is LIST response successfully parsed, so lets restore
+- previous WRITEFUNCTION callback and WRITEDATA pointer */
+- struct ftp_wc *ftpwc = wildcard->protdata;
+- conn->data->set.fwrite_func = ftpwc->backup.write_function;
+- conn->data->set.out = ftpwc->backup.file_descriptor;
+- ftpwc->backup.write_function = ZERO_NULL;
+- ftpwc->backup.file_descriptor = NULL;
+- wildcard->state = CURLWC_DOWNLOADING;
+-
+- if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
+- /* error found in LIST parsing */
+- wildcard->state = CURLWC_CLEAN;
+- return wc_statemach(conn);
+- }
+- if(wildcard->filelist.size == 0) {
+- /* no corresponding file */
+- wildcard->state = CURLWC_CLEAN;
+- return CURLE_REMOTE_FILE_NOT_FOUND;
++ for(;;) {
++ switch(wildcard->state) {
++ case CURLWC_INIT:
++ result = init_wc_data(conn);
++ if(wildcard->state == CURLWC_CLEAN)
++ /* only listing! */
++ return result;
++ wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
++ return result;
++
++ case CURLWC_MATCHING: {
++ /* In this state is LIST response successfully parsed, so lets restore
++ previous WRITEFUNCTION callback and WRITEDATA pointer */
++ struct ftp_wc *ftpwc = wildcard->protdata;
++ conn->data->set.fwrite_func = ftpwc->backup.write_function;
++ conn->data->set.out = ftpwc->backup.file_descriptor;
++ ftpwc->backup.write_function = ZERO_NULL;
++ ftpwc->backup.file_descriptor = NULL;
++ wildcard->state = CURLWC_DOWNLOADING;
++
++ if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
++ /* error found in LIST parsing */
++ wildcard->state = CURLWC_CLEAN;
++ continue;
++ }
++ if(wildcard->filelist.size == 0) {
++ /* no corresponding file */
++ wildcard->state = CURLWC_CLEAN;
++ return CURLE_REMOTE_FILE_NOT_FOUND;
++ }
++ continue;
++
+ }
+- return wc_statemach(conn);
+- }
+
+- case CURLWC_DOWNLOADING: {
+- /* filelist has at least one file, lets get first one */
+- struct ftp_conn *ftpc = &conn->proto.ftpc;
+- struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
+- struct FTP *ftp = conn->data->req.protop;
++ case CURLWC_DOWNLOADING: {
++ /* filelist has at least one file, lets get first one */
++ struct ftp_conn *ftpc = &conn->proto.ftpc;
++ struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
++ struct FTP *ftp = conn->data->req.protop;
+
+ char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
+ if(!tmp_path)
+ return CURLE_OUT_OF_MEMORY;
+
+- /* switch default ftp->path and tmp_path */
+- free(ftp->pathalloc);
+- ftp->pathalloc = ftp->path = tmp_path;
+-
+- infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
+- if(conn->data->set.chunk_bgn) {
+- long userresponse;
+- Curl_set_in_callback(conn->data, true);
+- userresponse = conn->data->set.chunk_bgn(
+- finfo, wildcard->customptr, (int)wildcard->filelist.size);
+- Curl_set_in_callback(conn->data, false);
+- switch(userresponse) {
+- case CURL_CHUNK_BGN_FUNC_SKIP:
+- infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
+- finfo->filename);
++ /* switch default ftp->path and tmp_path */
++ free(ftp->pathalloc);
++ ftp->pathalloc = ftp->path = tmp_path;
++
++ infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
++ if(conn->data->set.chunk_bgn) {
++ long userresponse;
++ Curl_set_in_callback(conn->data, true);
++ userresponse = conn->data->set.chunk_bgn(
++ finfo, wildcard->customptr, (int)wildcard->filelist.size);
++ Curl_set_in_callback(conn->data, false);
++ switch(userresponse) {
++ case CURL_CHUNK_BGN_FUNC_SKIP:
++ infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
++ finfo->filename);
++ wildcard->state = CURLWC_SKIP;
++ continue;
++ case CURL_CHUNK_BGN_FUNC_FAIL:
++ return CURLE_CHUNK_FAILED;
++ }
++
++ }
++
++ if(finfo->filetype != CURLFILETYPE_FILE) {
+ wildcard->state = CURLWC_SKIP;
+- return wc_statemach(conn);
+- case CURL_CHUNK_BGN_FUNC_FAIL:
+- return CURLE_CHUNK_FAILED;
++ continue;
+ }
++
++ if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
++ ftpc->known_filesize = finfo->size;
++
++ result = ftp_parse_url_path(conn);
++ if(result)
++ return result;
++
++ /* we don't need the Curl_fileinfo of first file anymore */
++ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
++
++ if(wildcard->filelist.size == 0) { /* remains only one file to down. */
++ wildcard->state = CURLWC_CLEAN;
++ /* after that will be ftp_do called once again and no transfer
++ will be done because of CURLWC_CLEAN state */
++ return CURLE_OK;
++ }
++ return result;
+ }
+
+- if(finfo->filetype != CURLFILETYPE_FILE) {
+- wildcard->state = CURLWC_SKIP;
+- return wc_statemach(conn);
++ case CURLWC_SKIP: {
++ if(conn->data->set.chunk_end) {
++ Curl_set_in_callback(conn->data, true);
++ conn->data->set.chunk_end(conn->data->wildcard.customptr);
++ Curl_set_in_callback(conn->data, false);
++ }
++ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
++ wildcard->state = (wildcard->filelist.size == 0) ?
++ CURLWC_CLEAN : CURLWC_DOWNLOADING;
++ continue;
+ }
+
+- if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
+- ftpc->known_filesize = finfo->size;
++ case CURLWC_CLEAN: {
++ struct ftp_wc *ftpwc = wildcard->protdata;
++ result = CURLE_OK;
++ if(ftpwc)
++ result = Curl_ftp_parselist_geterror(ftpwc->parser);
+
+- result = ftp_parse_url_path(conn);
+- if(result)
++ wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
+ return result;
+-
+- /* we don't need the Curl_fileinfo of first file anymore */
+- Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
+-
+- if(wildcard->filelist.size == 0) { /* remains only one file to down. */
+- wildcard->state = CURLWC_CLEAN;
+- /* after that will be ftp_do called once again and no transfer
+- will be done because of CURLWC_CLEAN state */
+- return CURLE_OK;
+ }
+- } break;
+
+- case CURLWC_SKIP: {
+- if(conn->data->set.chunk_end) {
+- Curl_set_in_callback(conn->data, true);
+- conn->data->set.chunk_end(conn->data->wildcard.customptr);
+- Curl_set_in_callback(conn->data, false);
++ case CURLWC_DONE:
++ case CURLWC_ERROR:
++ case CURLWC_CLEAR:
++ if(wildcard->dtor)
++ wildcard->dtor(wildcard->protdata);
++ return result;
+ }
+- Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
+- wildcard->state = (wildcard->filelist.size == 0) ?
+- CURLWC_CLEAN : CURLWC_DOWNLOADING;
+- return wc_statemach(conn);
+- }
+
+- case CURLWC_CLEAN: {
+- struct ftp_wc *ftpwc = wildcard->protdata;
+- result = CURLE_OK;
+- if(ftpwc)
+- result = Curl_ftp_parselist_geterror(ftpwc->parser);
+-
+- wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
+- } break;
+-
+- case CURLWC_DONE:
+- case CURLWC_ERROR:
+- case CURLWC_CLEAR:
+- if(wildcard->dtor)
+- wildcard->dtor(wildcard->protdata);
+- break;
+ }
+-
+- return result;
++/* UNREACHABLE */
+ }
+
+ /***********************************************************************
diff --git a/meta/recipes-support/curl/curl/CVE-2020-8286.patch b/meta/recipes-support/curl/curl/CVE-2020-8286.patch
new file mode 100644
index 00000000000..21e72da0206
--- /dev/null
+++ b/meta/recipes-support/curl/curl/CVE-2020-8286.patch
@@ -0,0 +1,138 @@
+From 5d3b28deac44c19e4d73fc80e4917d42ee43adfe Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Wed, 2 Dec 2020 23:01:11 +0100
+Subject: [PATCH] openssl: make the OCSP verification verify the certificate id
+
+CVE-2020-8286
+
+Reported by anonymous
+
+Bug: https://curl.se/docs/CVE-2020-8286.html
+
+Upstream-Status: Backport [https://github.com/curl/curl/commit/d9d01672785b]
+
+CVE: CVE-2020-8286
+
+Signed-off-by: Daniel Stenberg <daniel@haxx.se>
+Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
+[Fixup for Dunfell context]
+Signed-off-by: Armin Kuster <akuster@mvista.com>
+
+---
+ lib/vtls/openssl.c | 83 +++++++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 54 insertions(+), 29 deletions(-)
+
+Index: curl-7.69.1/lib/vtls/openssl.c
+===================================================================
+--- curl-7.69.1.orig/lib/vtls/openssl.c
++++ curl-7.69.1/lib/vtls/openssl.c
+@@ -1717,6 +1717,11 @@ static CURLcode verifystatus(struct conn
+ OCSP_BASICRESP *br = NULL;
+ X509_STORE *st = NULL;
+ STACK_OF(X509) *ch = NULL;
++ X509 *cert;
++ OCSP_CERTID *id = NULL;
++ int cert_status, crl_reason;
++ ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
++ int ret;
+
+ long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &status);
+
+@@ -1785,43 +1790,63 @@ static CURLcode verifystatus(struct conn
+ goto end;
+ }
+
+- for(i = 0; i < OCSP_resp_count(br); i++) {
+- int cert_status, crl_reason;
+- OCSP_SINGLERESP *single = NULL;
+-
+- ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
+-
+- single = OCSP_resp_get0(br, i);
+- if(!single)
+- continue;
+-
+- cert_status = OCSP_single_get0_status(single, &crl_reason, &rev,
+- &thisupd, &nextupd);
+-
+- if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
+- failf(data, "OCSP response has expired");
+- result = CURLE_SSL_INVALIDCERTSTATUS;
+- goto end;
++ /* Compute the certificate's ID */
++ cert = SSL_get_peer_certificate(BACKEND->handle);
++ if(!cert) {
++ failf(data, "Error getting peer certficate");
++ result = CURLE_SSL_INVALIDCERTSTATUS;
++ goto end;
++ }
++
++ for(i = 0; i < sk_X509_num(ch); i++) {
++ X509 *issuer = sk_X509_value(ch, i);
++ if(X509_check_issued(issuer, cert) == X509_V_OK) {
++ id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
++ break;
+ }
++ }
++ X509_free(cert);
+
+- infof(data, "SSL certificate status: %s (%d)\n",
+- OCSP_cert_status_str(cert_status), cert_status);
++ if(!id) {
++ failf(data, "Error computing OCSP ID");
++ result = CURLE_SSL_INVALIDCERTSTATUS;
++ goto end;
++ }
+
+- switch(cert_status) {
+- case V_OCSP_CERTSTATUS_GOOD:
+- break;
+-
+- case V_OCSP_CERTSTATUS_REVOKED:
+- result = CURLE_SSL_INVALIDCERTSTATUS;
+-
+- failf(data, "SSL certificate revocation reason: %s (%d)",
+- OCSP_crl_reason_str(crl_reason), crl_reason);
+- goto end;
+-
+- case V_OCSP_CERTSTATUS_UNKNOWN:
+- result = CURLE_SSL_INVALIDCERTSTATUS;
+- goto end;
+- }
++ /* Find the single OCSP response corresponding to the certificate ID */
++ ret = OCSP_resp_find_status(br, id, &cert_status, &crl_reason, &rev,
++ &thisupd, &nextupd);
++ OCSP_CERTID_free(id);
++ if(ret != 1) {
++ failf(data, "Could not find certificate ID in OCSP response");
++ result = CURLE_SSL_INVALIDCERTSTATUS;
++ goto end;
++ }
++
++ /* Validate the corresponding single OCSP response */
++ if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
++ failf(data, "OCSP response has expired");
++ result = CURLE_SSL_INVALIDCERTSTATUS;
++ goto end;
++ }
++
++ infof(data, "SSL certificate status: %s (%d)\n",
++ OCSP_cert_status_str(cert_status), cert_status);
++
++ switch(cert_status) {
++ case V_OCSP_CERTSTATUS_GOOD:
++ break;
++
++ case V_OCSP_CERTSTATUS_REVOKED:
++ result = CURLE_SSL_INVALIDCERTSTATUS;
++ failf(data, "SSL certificate revocation reason: %s (%d)",
++ OCSP_crl_reason_str(crl_reason), crl_reason);
++ goto end;
++
++ case V_OCSP_CERTSTATUS_UNKNOWN:
++ default:
++ result = CURLE_SSL_INVALIDCERTSTATUS;
++ goto end;
+ }
+
+ end:
diff --git a/meta/recipes-support/curl/curl_7.69.1.bb b/meta/recipes-support/curl/curl_7.69.1.bb
index 239852db09c..c0db01ac5d0 100644
--- a/meta/recipes-support/curl/curl_7.69.1.bb
+++ b/meta/recipes-support/curl/curl_7.69.1.bb
@@ -9,6 +9,9 @@ SRC_URI = "https://curl.haxx.se/download/curl-${PV}.tar.bz2 \
file://0001-replace-krb5-config-with-pkg-config.patch \
file://CVE-2020-8169.patch \
file://CVE-2020-8177.patch \
+ file://CVE-2020-8284.patch \
+ file://CVE-2020-8285.patch \
+ file://CVE-2020-8286.patch \
"
SRC_URI[md5sum] = "ec5fc263f898a3dfef08e805f1ecca42"
--
2.17.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [dunfell][PATCH 2/2] curl: Security fix for CVE-2020-8231
2021-01-15 18:02 [dunfell][PATCH 1/2] curl: Fix CVE-2020-8284, CVE-2020-8285, CVE-2020-8286 akuster
@ 2021-01-15 18:02 ` akuster
2021-01-15 18:16 ` [OE-core] [dunfell][PATCH 1/2] curl: Fix CVE-2020-8284, CVE-2020-8285, CVE-2020-8286 Steve Sakoman
2021-01-15 18:25 ` Steve Sakoman
2 siblings, 0 replies; 4+ messages in thread
From: akuster @ 2021-01-15 18:02 UTC (permalink / raw)
To: openembedded-core; +Cc: Armin Kuster
From: Armin Kuster <akuster@mvista.com>
Source: https://curl.se/
MR: 105190
Type: Security Fix
Disposition: Backport from https://github.com/curl/curl/commit/3c9e021f86872baae412a427e807fbfa2f3e8
ChangeID: 7cb4278f48b0da2009b5b7cf2b2383b12a5660ab
Description:
Fixes CVE-2020-8231
Affects 7.29.0 to 7.71.1
Signed-off-by: Armin Kuster <akuster@mvista.com>
---
.../curl/curl/CVE-2020-8231.patch | 143 ++++++++++++++++++
meta/recipes-support/curl/curl_7.69.1.bb | 1 +
2 files changed, 144 insertions(+)
create mode 100644 meta/recipes-support/curl/curl/CVE-2020-8231.patch
diff --git a/meta/recipes-support/curl/curl/CVE-2020-8231.patch b/meta/recipes-support/curl/curl/CVE-2020-8231.patch
new file mode 100644
index 00000000000..f01e225e754
--- /dev/null
+++ b/meta/recipes-support/curl/curl/CVE-2020-8231.patch
@@ -0,0 +1,143 @@
+From 3c9e021f86872baae412a427e807fbfa2f3e8a22 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Sun, 16 Aug 2020 11:34:35 +0200
+Subject: [PATCH] Curl_easy: remember last connection by id, not by pointer
+
+CVE-2020-8231
+
+Bug: https://curl.haxx.se/docs/CVE-2020-8231.html
+
+Reported-by: Marc Aldorasi
+Closes #5824
+
+Upstream-Status: Backport [https://github.com/curl/curl/commit/3c9e021f86872baae412a427e807fbfa2f3e8]
+CVE: CVE-2020-8231
+Affects: 7.20.0 to 7.71.1
+Signed-off-by: Armin Kuster <akuster@mvista.com>
+
+---
+ lib/connect.c | 19 ++++++++++---------
+ lib/easy.c | 3 +--
+ lib/multi.c | 9 +++++----
+ lib/url.c | 2 +-
+ lib/urldata.h | 2 +-
+ 5 files changed, 18 insertions(+), 17 deletions(-)
+
+Index: curl-7.69.1/lib/connect.c
+===================================================================
+--- curl-7.69.1.orig/lib/connect.c
++++ curl-7.69.1/lib/connect.c
+@@ -1356,15 +1356,15 @@ CURLcode Curl_connecthost(struct connect
+ }
+
+ struct connfind {
+- struct connectdata *tofind;
+- bool found;
++ long id_tofind;
++ struct connectdata *found;
+ };
+
+ static int conn_is_conn(struct connectdata *conn, void *param)
+ {
+ struct connfind *f = (struct connfind *)param;
+- if(conn == f->tofind) {
+- f->found = TRUE;
++ if(conn->connection_id == f->id_tofind) {
++ f->found = conn;
+ return 1;
+ }
+ return 0;
+@@ -1386,21 +1386,22 @@ curl_socket_t Curl_getconnectinfo(struct
+ * - that is associated with a multi handle, and whose connection
+ * was detached with CURLOPT_CONNECT_ONLY
+ */
+- if(data->state.lastconnect && (data->multi_easy || data->multi)) {
+- struct connectdata *c = data->state.lastconnect;
++ if((data->state.lastconnect_id != -1) && (data->multi_easy || data->multi)) {
++ struct connectdata *c;
+ struct connfind find;
+- find.tofind = data->state.lastconnect;
+- find.found = FALSE;
++ find.id_tofind = data->state.lastconnect_id;
++ find.found = NULL;
+
+ Curl_conncache_foreach(data, data->multi_easy?
+ &data->multi_easy->conn_cache:
+ &data->multi->conn_cache, &find, conn_is_conn);
+
+ if(!find.found) {
+- data->state.lastconnect = NULL;
++ data->state.lastconnect_id = -1;
+ return CURL_SOCKET_BAD;
+ }
+
++ c = find.found;
+ if(connp) {
+ /* only store this if the caller cares for it */
+ *connp = c;
+Index: curl-7.69.1/lib/easy.c
+===================================================================
+--- curl-7.69.1.orig/lib/easy.c
++++ curl-7.69.1/lib/easy.c
+@@ -831,8 +831,7 @@ struct Curl_easy *curl_easy_duphandle(st
+
+ /* the connection cache is setup on demand */
+ outcurl->state.conn_cache = NULL;
+-
+- outcurl->state.lastconnect = NULL;
++ outcurl->state.lastconnect_id = -1;
+
+ outcurl->progress.flags = data->progress.flags;
+ outcurl->progress.callback = data->progress.callback;
+Index: curl-7.69.1/lib/multi.c
+===================================================================
+--- curl-7.69.1.orig/lib/multi.c
++++ curl-7.69.1/lib/multi.c
+@@ -454,6 +454,7 @@ CURLMcode curl_multi_add_handle(struct C
+ data->state.conn_cache = &data->share->conn_cache;
+ else
+ data->state.conn_cache = &multi->conn_cache;
++ data->state.lastconnect_id = -1;
+
+ #ifdef USE_LIBPSL
+ /* Do the same for PSL. */
+@@ -669,11 +670,11 @@ static CURLcode multi_done(struct Curl_e
+ CONN_UNLOCK(data);
+ if(Curl_conncache_return_conn(data, conn)) {
+ /* remember the most recently used connection */
+- data->state.lastconnect = conn;
++ data->state.lastconnect_id = conn->connection_id;
+ infof(data, "%s\n", buffer);
+ }
+ else
+- data->state.lastconnect = NULL;
++ data->state.lastconnect_id = -1;
+ }
+
+ Curl_free_request_state(data);
+Index: curl-7.69.1/lib/url.c
+===================================================================
+--- curl-7.69.1.orig/lib/url.c
++++ curl-7.69.1/lib/url.c
+@@ -618,7 +618,7 @@ CURLcode Curl_open(struct Curl_easy **cu
+ Curl_initinfo(data);
+
+ /* most recent connection is not yet defined */
+- data->state.lastconnect = NULL;
++ data->state.lastconnect_id = -1;
+
+ data->progress.flags |= PGRS_HIDE;
+ data->state.current_speed = -1; /* init to negative == impossible */
+Index: curl-7.69.1/lib/urldata.h
+===================================================================
+--- curl-7.69.1.orig/lib/urldata.h
++++ curl-7.69.1/lib/urldata.h
+@@ -1332,7 +1332,7 @@ struct UrlState {
+ /* buffers to store authentication data in, as parsed from input options */
+ struct curltime keeps_speed; /* for the progress meter really */
+
+- struct connectdata *lastconnect; /* The last connection, NULL if undefined */
++ long lastconnect_id; /* The last connection, -1 if undefined */
+
+ char *headerbuff; /* allocated buffer to store headers in */
+ size_t headersize; /* size of the allocation */
diff --git a/meta/recipes-support/curl/curl_7.69.1.bb b/meta/recipes-support/curl/curl_7.69.1.bb
index c0db01ac5d0..6dc2e4132e4 100644
--- a/meta/recipes-support/curl/curl_7.69.1.bb
+++ b/meta/recipes-support/curl/curl_7.69.1.bb
@@ -12,6 +12,7 @@ SRC_URI = "https://curl.haxx.se/download/curl-${PV}.tar.bz2 \
file://CVE-2020-8284.patch \
file://CVE-2020-8285.patch \
file://CVE-2020-8286.patch \
+ file://CVE-2020-8231.patch \
"
SRC_URI[md5sum] = "ec5fc263f898a3dfef08e805f1ecca42"
--
2.17.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [OE-core] [dunfell][PATCH 1/2] curl: Fix CVE-2020-8284, CVE-2020-8285, CVE-2020-8286
2021-01-15 18:02 [dunfell][PATCH 1/2] curl: Fix CVE-2020-8284, CVE-2020-8285, CVE-2020-8286 akuster
2021-01-15 18:02 ` [dunfell][PATCH 2/2] curl: Security fix for CVE-2020-8231 akuster
@ 2021-01-15 18:16 ` Steve Sakoman
2021-01-15 18:25 ` Steve Sakoman
2 siblings, 0 replies; 4+ messages in thread
From: Steve Sakoman @ 2021-01-15 18:16 UTC (permalink / raw)
To: akuster
Cc: Patches and discussions about the oe-core layer,
Khairul Rohaizzat Jamaluddin, Anuj Mittal
On Fri, Jan 15, 2021 at 8:03 AM akuster <akuster808@gmail.com> wrote:
>
> From: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
>
> Source: git.openembedded.org
> MR: 107592, 107620, 107606
> Type: Security Fix
> Disposition: Backport from https://git.openembedded.org/openembedded-core-contrib/commit/?h=anujm/gatesgarth&id=f1a0ea55c0ae2cce7f7c3c6c73f57c5b8222c860
> ChangeID: 8d65a5974018f276bef9054cbbdcd5a2a5f0a154
> Description:
>
> Backport the CVE patches from upstream
> https://github.com/curl/curl/commit/ec9cc725d598ac
> https://github.com/curl/curl/commit/a95a6ce6b809693a1195e3b4347a6cfa0fbc2ee7
> https://github.com/curl/curl/commit/69a358f2186e04
> https://github.com/curl/curl/commit/d9d01672785b.patch
>
> 0002-remove-void-protop-create-union-p.patch is added because the CVE-2020-8285 fix is
> dependent on it.
>
> CVE:
I assume this blank tag was unintentional and I can remove it?
Steve
> CVE-2020-8284
> CVE-2020-8285
> CVE-2020-8286
>
> Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
> Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
> Signed-off-by: Armin Kuster <akuster808@gmail.com>
> ---
> ...02-remove-void-protop-create-union-p.patch | 1609 +++++++++++++++++
> .../curl/curl/CVE-2020-8284.patch | 210 +++
> .../curl/curl/CVE-2020-8285.patch | 261 +++
> .../curl/curl/CVE-2020-8286.patch | 138 ++
> meta/recipes-support/curl/curl_7.69.1.bb | 3 +
> 5 files changed, 2221 insertions(+)
> create mode 100644 meta/recipes-support/curl/curl/0002-remove-void-protop-create-union-p.patch
> create mode 100644 meta/recipes-support/curl/curl/CVE-2020-8284.patch
> create mode 100644 meta/recipes-support/curl/curl/CVE-2020-8285.patch
> create mode 100644 meta/recipes-support/curl/curl/CVE-2020-8286.patch
>
> diff --git a/meta/recipes-support/curl/curl/0002-remove-void-protop-create-union-p.patch b/meta/recipes-support/curl/curl/0002-remove-void-protop-create-union-p.patch
> new file mode 100644
> index 00000000000..d0d01fb97cb
> --- /dev/null
> +++ b/meta/recipes-support/curl/curl/0002-remove-void-protop-create-union-p.patch
> @@ -0,0 +1,1609 @@
> +From bfdb7ee65fc8b96f1fce10ef23871acb092b74b6 Mon Sep 17 00:00:00 2001
> +From: Daniel Stenberg <daniel@haxx.se>
> +Date: Mon, 23 Nov 2020 08:32:41 +0100
> +Subject: [PATCH] urldata: remove 'void *protop' and create the union 'p'
> +
> +... to avoid the use of 'void *' for the protocol specific structs done
> +per transfer.
> +
> +Closes #6238
> +
> +Upstream-Status: Backport [https://github.com/curl/curl/commit/a95a6ce6b809693a1195e3b4347a6cfa0fbc2ee7]
> +
> +CVE: CVE-2020-8285
> +
> +Signed-off-by: Daniel Stenberg <daniel@haxx.se>
> +Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
> +
> +---
> + docs/INTERNALS.md | 4 ++--
> + lib/file.c | 14 +++++++-------
> + lib/ftp.c | 36 ++++++++++++++++++------------------
> + lib/http.c | 14 +++++++-------
> + lib/http2.c | 50 +++++++++++++++++++++++++-------------------------
> + lib/http_proxy.c | 6 +++---
> + lib/imap.c | 26 +++++++++++++-------------
> + lib/mqtt.c | 10 +++++-----
> + lib/openldap.c | 8 ++++----
> + lib/pop3.c | 14 +++++++-------
> + lib/rtsp.c | 8 ++++----
> + lib/smb.c | 20 ++++++++++----------
> + lib/smtp.c | 22 +++++++++++-----------
> + lib/telnet.c | 30 +++++++++++++++---------------
> + lib/transfer.c | 8 ++++----
> + lib/url.c | 2 +-
> + lib/urldata.h | 19 +++++++++++++++++--
> + lib/vquic/ngtcp2.c | 24 ++++++++++++------------
> + lib/vquic/quiche.c | 10 +++++-----
> + lib/vssh/libssh.c | 10 +++++-----
> + lib/vssh/libssh2.c | 8 ++++----
> + lib/vssh/wolfssh.c | 8 ++++----
> + 22 files changed, 183 insertions(+), 168 deletions(-)
> +
> +diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md
> +index 635e7b2..ca8988e 100644
> +--- a/docs/INTERNALS.md
> ++++ b/docs/INTERNALS.md
> +@@ -980,8 +980,8 @@ for older and later versions as things don't change drastically that often.
> + protocol specific data that then gets associated with that `Curl_easy` for
> + the rest of this transfer. It gets freed again at the end of the transfer.
> + It will be called before the `connectdata` for the transfer has been
> +- selected/created. Most protocols will allocate its private
> +- `struct [PROTOCOL]` here and assign `Curl_easy->req.protop` to point to it.
> ++ selected/created. Most protocols will allocate its private `struct
> ++ [PROTOCOL]` here and assign `Curl_easy->req.p.[protocol]` to it.
> +
> + `->connect_it` allows a protocol to do some specific actions after the TCP
> + connect is done, that can still be considered part of the connection phase.
> +diff --git a/lib/file.c b/lib/file.c
> +index cd3e49c..110e5c2 100644
> +--- a/lib/file.c
> ++++ b/lib/file.c
> +@@ -119,8 +119,8 @@ const struct Curl_handler Curl_handler_file = {
> + static CURLcode file_setup_connection(struct connectdata *conn)
> + {
> + /* allocate the FILE specific struct */
> +- conn->data->req.protop = calloc(1, sizeof(struct FILEPROTO));
> +- if(!conn->data->req.protop)
> ++ conn->data->req.p.file = calloc(1, sizeof(struct FILEPROTO));
> ++ if(!conn->data->req.p.file)
> + return CURLE_OUT_OF_MEMORY;
> +
> + return CURLE_OK;
> +@@ -135,7 +135,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
> + {
> + struct Curl_easy *data = conn->data;
> + char *real_path;
> +- struct FILEPROTO *file = data->req.protop;
> ++ struct FILEPROTO *file = data->req.p.file;
> + int fd;
> + #ifdef DOS_FILESYSTEM
> + size_t i;
> +@@ -209,7 +209,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
> + static CURLcode file_done(struct connectdata *conn,
> + CURLcode status, bool premature)
> + {
> +- struct FILEPROTO *file = conn->data->req.protop;
> ++ struct FILEPROTO *file = conn->data->req.p.file;
> + (void)status; /* not used */
> + (void)premature; /* not used */
> +
> +@@ -227,7 +227,7 @@ static CURLcode file_done(struct connectdata *conn,
> + static CURLcode file_disconnect(struct connectdata *conn,
> + bool dead_connection)
> + {
> +- struct FILEPROTO *file = conn->data->req.protop;
> ++ struct FILEPROTO *file = conn->data->req.p.file;
> + (void)dead_connection; /* not used */
> +
> + if(file) {
> +@@ -249,7 +249,7 @@ static CURLcode file_disconnect(struct connectdata *conn,
> +
> + static CURLcode file_upload(struct connectdata *conn)
> + {
> +- struct FILEPROTO *file = conn->data->req.protop;
> ++ struct FILEPROTO *file = conn->data->req.p.file;
> + const char *dir = strchr(file->path, DIRSEP);
> + int fd;
> + int mode;
> +@@ -391,7 +391,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
> + if(data->set.upload)
> + return file_upload(conn);
> +
> +- file = conn->data->req.protop;
> ++ file = conn->data->req.p.file;
> +
> + /* get the fd from the connection phase */
> + fd = file->fd;
> +diff --git a/lib/ftp.c b/lib/ftp.c
> +index 9fadac5..d1a9447 100644
> +--- a/lib/ftp.c
> ++++ b/lib/ftp.c
> +@@ -1345,7 +1345,7 @@ static CURLcode ftp_state_use_pasv(struct connectdata *conn)
> + static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + struct Curl_easy *data = conn->data;
> +
> + if(ftp->transfer != FTPTRANSFER_BODY) {
> +@@ -1388,7 +1388,7 @@ static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
> + static CURLcode ftp_state_rest(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> +
> + if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
> +@@ -1409,7 +1409,7 @@ static CURLcode ftp_state_rest(struct connectdata *conn)
> + static CURLcode ftp_state_size(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> +
> + if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
> +@@ -1430,7 +1430,7 @@ static CURLcode ftp_state_list(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> +
> + /* If this output is to be machine-parsed, the NLST command might be better
> + to use, since the LIST command output is not specified or standard in any
> +@@ -1508,7 +1508,7 @@ static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
> + static CURLcode ftp_state_type(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + struct Curl_easy *data = conn->data;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> +
> +@@ -1565,7 +1565,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
> + bool sizechecked)
> + {
> + CURLcode result = CURLE_OK;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + struct Curl_easy *data = conn->data;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> +
> +@@ -1664,7 +1664,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> + bool quote = FALSE;
> + struct curl_slist *item;
> +@@ -2033,7 +2033,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> +
> + switch(ftpcode) {
> +@@ -2166,7 +2166,7 @@ static CURLcode ftp_state_retr(struct connectdata *conn,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> +
> + if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
> +@@ -2378,7 +2378,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> +
> + if((ftpcode == 150) || (ftpcode == 125)) {
> +
> +@@ -3138,7 +3138,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
> + bool premature)
> + {
> + struct Curl_easy *data = conn->data;
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> + struct pingpong *pp = &ftpc->pp;
> + ssize_t nread;
> +@@ -3492,7 +3492,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
> + bool complete = FALSE;
> +
> + /* the ftp struct is inited in ftp_connect() */
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> +
> + /* if the second connection isn't done yet, wait for it */
> + if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
> +@@ -3657,7 +3657,7 @@ CURLcode ftp_perform(struct connectdata *conn,
> +
> + if(conn->data->set.opt_no_body) {
> + /* requested no body means no transfer... */
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + ftp->transfer = FTPTRANSFER_INFO;
> + }
> +
> +@@ -3692,7 +3692,7 @@ static void wc_data_dtor(void *ptr)
> + static CURLcode init_wc_data(struct connectdata *conn)
> + {
> + char *last_slash;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + char *path = ftp->path;
> + struct WildcardData *wildcard = &(conn->data->wildcard);
> + CURLcode result = CURLE_OK;
> +@@ -3826,7 +3826,7 @@ static CURLcode wc_statemach(struct connectdata *conn)
> + /* filelist has at least one file, lets get first one */
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> + struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> +
> + char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
> + if(!tmp_path)
> +@@ -4099,7 +4099,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
> + {
> + struct Curl_easy *data = conn->data;
> + /* the ftp struct is already inited in ftp_connect() */
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> + const char *slashPos = NULL;
> + const char *fileName = NULL;
> +@@ -4244,7 +4244,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
> + static CURLcode ftp_dophase_done(struct connectdata *conn,
> + bool connected)
> + {
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> +
> + if(connected) {
> +@@ -4341,7 +4341,7 @@ static CURLcode ftp_setup_connection(struct connectdata *conn)
> + char *type;
> + struct FTP *ftp;
> +
> +- conn->data->req.protop = ftp = calloc(sizeof(struct FTP), 1);
> ++ conn->data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1);
> + if(NULL == ftp)
> + return CURLE_OUT_OF_MEMORY;
> +
> +diff --git a/lib/http.c b/lib/http.c
> +index 8fcdd43..31d9112 100644
> +--- a/lib/http.c
> ++++ b/lib/http.c
> +@@ -162,14 +162,14 @@ static CURLcode http_setup_conn(struct connectdata *conn)
> + during this request */
> + struct HTTP *http;
> + struct Curl_easy *data = conn->data;
> +- DEBUGASSERT(data->req.protop == NULL);
> ++ DEBUGASSERT(data->req.p.http == NULL);
> +
> + http = calloc(1, sizeof(struct HTTP));
> + if(!http)
> + return CURLE_OUT_OF_MEMORY;
> +
> + Curl_mime_initpart(&http->form, conn->data);
> +- data->req.protop = http;
> ++ data->req.p.http = http;
> +
> + if(data->set.httpversion == CURL_HTTP_VERSION_3) {
> + if(conn->handler->flags & PROTOPT_SSL)
> +@@ -425,7 +425,7 @@ static bool pickoneauth(struct auth *pick, unsigned long mask)
> + static CURLcode http_perhapsrewind(struct connectdata *conn)
> + {
> + struct Curl_easy *data = conn->data;
> +- struct HTTP *http = data->req.protop;
> ++ struct HTTP *http = data->req.p.http;
> + curl_off_t bytessent;
> + curl_off_t expectsend = -1; /* default is unknown */
> +
> +@@ -1109,7 +1109,7 @@ static size_t readmoredata(char *buffer,
> + void *userp)
> + {
> + struct connectdata *conn = (struct connectdata *)userp;
> +- struct HTTP *http = conn->data->req.protop;
> ++ struct HTTP *http = conn->data->req.p.http;
> + size_t fullsize = size * nitems;
> +
> + if(!http->postsize)
> +@@ -1167,7 +1167,7 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
> + char *ptr;
> + size_t size;
> + struct Curl_easy *data = conn->data;
> +- struct HTTP *http = data->req.protop;
> ++ struct HTTP *http = data->req.p.http;
> + size_t sendsize;
> + curl_socket_t sockfd;
> + size_t headersize;
> +@@ -1517,7 +1517,7 @@ CURLcode Curl_http_done(struct connectdata *conn,
> + CURLcode status, bool premature)
> + {
> + struct Curl_easy *data = conn->data;
> +- struct HTTP *http = data->req.protop;
> ++ struct HTTP *http = data->req.p.http;
> +
> + /* Clear multipass flag. If authentication isn't done yet, then it will get
> + * a chance to be set back to true when we output the next auth header */
> +@@ -1978,7 +1978,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
> + return result;
> + }
> + }
> +- http = data->req.protop;
> ++ http = data->req.p.http;
> + DEBUGASSERT(http);
> +
> + if(!data->state.this_is_a_follow) {
> +diff --git a/lib/http2.c b/lib/http2.c
> +index d316da8..c41a1c2 100644
> +--- a/lib/http2.c
> ++++ b/lib/http2.c
> +@@ -257,7 +257,7 @@ static unsigned int http2_conncheck(struct connectdata *check,
> + /* called from http_setup_conn */
> + void Curl_http2_setup_req(struct Curl_easy *data)
> + {
> +- struct HTTP *http = data->req.protop;
> ++ struct HTTP *http = data->req.p.http;
> + http->bodystarted = FALSE;
> + http->status_code = -1;
> + http->pausedata = NULL;
> +@@ -391,7 +391,7 @@ char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
> + if(!h || !GOOD_EASY_HANDLE(h->data))
> + return NULL;
> + else {
> +- struct HTTP *stream = h->data->req.protop;
> ++ struct HTTP *stream = h->data->req.p.http;
> + if(num < stream->push_headers_used)
> + return stream->push_headers[num];
> + }
> +@@ -413,7 +413,7 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
> + !strcmp(header, ":") || strchr(header + 1, ':'))
> + return NULL;
> + else {
> +- struct HTTP *stream = h->data->req.protop;
> ++ struct HTTP *stream = h->data->req.p.http;
> + size_t len = strlen(header);
> + size_t i;
> + for(i = 0; i<stream->push_headers_used; i++) {
> +@@ -460,7 +460,7 @@ static struct Curl_easy *duphandle(struct Curl_easy *data)
> + (void)Curl_close(&second);
> + }
> + else {
> +- second->req.protop = http;
> ++ second->req.p.http = http;
> + Curl_dyn_init(&http->header_recvbuf, DYN_H2_HEADERS);
> + Curl_http2_setup_req(second);
> + second->state.stream_weight = data->state.stream_weight;
> +@@ -537,7 +537,7 @@ static int push_promise(struct Curl_easy *data,
> + /* ask the application */
> + H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!\n"));
> +
> +- stream = data->req.protop;
> ++ stream = data->req.p.http;
> + if(!stream) {
> + failf(data, "Internal NULL stream!\n");
> + (void)Curl_close(&newhandle);
> +@@ -567,13 +567,13 @@ static int push_promise(struct Curl_easy *data,
> + if(rv) {
> + DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
> + /* denied, kill off the new handle again */
> +- http2_stream_free(newhandle->req.protop);
> +- newhandle->req.protop = NULL;
> ++ http2_stream_free(newhandle->req.p.http);
> ++ newhandle->req.p.http = NULL;
> + (void)Curl_close(&newhandle);
> + goto fail;
> + }
> +
> +- newstream = newhandle->req.protop;
> ++ newstream = newhandle->req.p.http;
> + newstream->stream_id = frame->promised_stream_id;
> + newhandle->req.maxdownload = -1;
> + newhandle->req.size = -1;
> +@@ -583,8 +583,8 @@ static int push_promise(struct Curl_easy *data,
> + rc = Curl_multi_add_perform(data->multi, newhandle, conn);
> + if(rc) {
> + infof(data, "failed to add handle to multi\n");
> +- http2_stream_free(newhandle->req.protop);
> +- newhandle->req.protop = NULL;
> ++ http2_stream_free(newhandle->req.p.http);
> ++ newhandle->req.p.http = NULL;
> + Curl_close(&newhandle);
> + rv = CURL_PUSH_DENY;
> + goto fail;
> +@@ -667,7 +667,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
> + return 0;
> + }
> +
> +- stream = data_s->req.protop;
> ++ stream = data_s->req.p.http;
> + if(!stream) {
> + H2BUGF(infof(data_s, "No proto pointer for stream: %x\n",
> + stream_id));
> +@@ -783,7 +783,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
> + internal error more than anything else! */
> + return NGHTTP2_ERR_CALLBACK_FAILURE;
> +
> +- stream = data_s->req.protop;
> ++ stream = data_s->req.p.http;
> + if(!stream)
> + return NGHTTP2_ERR_CALLBACK_FAILURE;
> +
> +@@ -849,7 +849,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
> + }
> + H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
> + nghttp2_http2_strerror(error_code), error_code, stream_id));
> +- stream = data_s->req.protop;
> ++ stream = data_s->req.p.http;
> + if(!stream)
> + return NGHTTP2_ERR_CALLBACK_FAILURE;
> +
> +@@ -894,7 +894,7 @@ static int on_begin_headers(nghttp2_session *session,
> + return 0;
> + }
> +
> +- stream = data_s->req.protop;
> ++ stream = data_s->req.p.http;
> + if(!stream || !stream->bodystarted) {
> + return 0;
> + }
> +@@ -952,7 +952,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
> + internal error more than anything else! */
> + return NGHTTP2_ERR_CALLBACK_FAILURE;
> +
> +- stream = data_s->req.protop;
> ++ stream = data_s->req.p.http;
> + if(!stream) {
> + failf(data_s, "Internal NULL stream! 5\n");
> + return NGHTTP2_ERR_CALLBACK_FAILURE;
> +@@ -1100,7 +1100,7 @@ static ssize_t data_source_read_callback(nghttp2_session *session,
> + internal error more than anything else! */
> + return NGHTTP2_ERR_CALLBACK_FAILURE;
> +
> +- stream = data_s->req.protop;
> ++ stream = data_s->req.p.http;
> + if(!stream)
> + return NGHTTP2_ERR_CALLBACK_FAILURE;
> + }
> +@@ -1161,7 +1161,7 @@ static void populate_settings(struct connectdata *conn,
> +
> + void Curl_http2_done(struct Curl_easy *data, bool premature)
> + {
> +- struct HTTP *http = data->req.protop;
> ++ struct HTTP *http = data->req.p.http;
> + struct http_conn *httpc = &data->conn->proto.httpc;
> +
> + /* there might be allocated resources done before this got the 'h2' pointer
> +@@ -1398,7 +1398,7 @@ CURLcode Curl_http2_done_sending(struct connectdata *conn)
> + (conn->handler == &Curl_handler_http2)) {
> + /* make sure this is only attempted for HTTP/2 transfers */
> +
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> +
> + struct http_conn *httpc = &conn->proto.httpc;
> + nghttp2_session *h2 = httpc->h2;
> +@@ -1522,7 +1522,7 @@ static void h2_pri_spec(struct Curl_easy *data,
> + nghttp2_priority_spec *pri_spec)
> + {
> + struct HTTP *depstream = (data->set.stream_depends_on?
> +- data->set.stream_depends_on->req.protop:NULL);
> ++ data->set.stream_depends_on->req.p.http:NULL);
> + int32_t depstream_id = depstream? depstream->stream_id:0;
> + nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight,
> + data->set.stream_depends_e);
> +@@ -1539,7 +1539,7 @@ static void h2_pri_spec(struct Curl_easy *data,
> + static int h2_session_send(struct Curl_easy *data,
> + nghttp2_session *h2)
> + {
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + if((data->set.stream_weight != data->state.stream_weight) ||
> + (data->set.stream_depends_e != data->state.stream_depends_e) ||
> + (data->set.stream_depends_on != data->state.stream_depends_on) ) {
> +@@ -1569,7 +1569,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
> + ssize_t nread;
> + struct http_conn *httpc = &conn->proto.httpc;
> + struct Curl_easy *data = conn->data;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> +
> + (void)sockindex; /* we always do HTTP2 on sockindex 0 */
> +
> +@@ -1874,7 +1874,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
> + */
> + int rv;
> + struct http_conn *httpc = &conn->proto.httpc;
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> + nghttp2_nv *nva = NULL;
> + size_t nheader;
> + size_t i;
> +@@ -2183,7 +2183,7 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
> + {
> + CURLcode result;
> + struct http_conn *httpc = &conn->proto.httpc;
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> +
> + DEBUGASSERT(conn->data->state.buffer);
> +
> +@@ -2238,7 +2238,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
> + int rv;
> + ssize_t nproc;
> + struct Curl_easy *data = conn->data;
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> +
> + result = Curl_http2_setup(conn);
> + if(result)
> +@@ -2358,7 +2358,7 @@ CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
> + return CURLE_OK;
> + #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
> + else {
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + struct http_conn *httpc = &data->conn->proto.httpc;
> + uint32_t window = !pause * HTTP2_HUGE_WINDOW_SIZE;
> + int rv = nghttp2_session_set_local_window_size(httpc->h2,
> +diff --git a/lib/http_proxy.c b/lib/http_proxy.c
> +index f188cbf..69aacb4 100644
> +--- a/lib/http_proxy.c
> ++++ b/lib/http_proxy.c
> +@@ -102,9 +102,9 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
> + * This function might be called several times in the multi interface case
> + * if the proxy's CONNECT response is not instant.
> + */
> +- prot_save = conn->data->req.protop;
> ++ prot_save = conn->data->req.p.http;
> + memset(&http_proxy, 0, sizeof(http_proxy));
> +- conn->data->req.protop = &http_proxy;
> ++ conn->data->req.p.http = &http_proxy;
> + connkeep(conn, "HTTP proxy CONNECT");
> +
> + /* for the secondary socket (FTP), use the "connect to host"
> +@@ -125,7 +125,7 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
> + else
> + remote_port = conn->remote_port;
> + result = Curl_proxyCONNECT(conn, sockindex, hostname, remote_port);
> +- conn->data->req.protop = prot_save;
> ++ conn->data->req.p.http = prot_save;
> + if(CURLE_OK != result)
> + return result;
> + Curl_safefree(data->state.aptr.proxyuserpwd);
> +diff --git a/lib/imap.c b/lib/imap.c
> +index cad0e59..bda23a5 100644
> +--- a/lib/imap.c
> ++++ b/lib/imap.c
> +@@ -244,7 +244,7 @@ static bool imap_matchresp(const char *line, size_t len, const char *cmd)
> + static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
> + int *resp)
> + {
> +- struct IMAP *imap = conn->data->req.protop;
> ++ struct IMAP *imap = conn->data->req.p.imap;
> + struct imap_conn *imapc = &conn->proto.imapc;
> + const char *id = imapc->resptag;
> + size_t id_len = strlen(id);
> +@@ -605,7 +605,7 @@ static CURLcode imap_perform_list(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = data->req.protop;
> ++ struct IMAP *imap = data->req.p.imap;
> +
> + if(imap->custom)
> + /* Send the custom request */
> +@@ -640,7 +640,7 @@ static CURLcode imap_perform_select(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = data->req.protop;
> ++ struct IMAP *imap = data->req.p.imap;
> + struct imap_conn *imapc = &conn->proto.imapc;
> + char *mailbox;
> +
> +@@ -679,7 +679,7 @@ static CURLcode imap_perform_select(struct connectdata *conn)
> + static CURLcode imap_perform_fetch(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> +- struct IMAP *imap = conn->data->req.protop;
> ++ struct IMAP *imap = conn->data->req.p.imap;
> + /* Check we have a UID */
> + if(imap->uid) {
> +
> +@@ -727,7 +727,7 @@ static CURLcode imap_perform_append(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = data->req.protop;
> ++ struct IMAP *imap = data->req.p.imap;
> + char *mailbox;
> +
> + /* Check we have a mailbox */
> +@@ -797,7 +797,7 @@ static CURLcode imap_perform_append(struct connectdata *conn)
> + static CURLcode imap_perform_search(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> +- struct IMAP *imap = conn->data->req.protop;
> ++ struct IMAP *imap = conn->data->req.p.imap;
> +
> + /* Check we have a query string */
> + if(!imap->query) {
> +@@ -1051,7 +1051,7 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = conn->data->req.protop;
> ++ struct IMAP *imap = conn->data->req.p.imap;
> + struct imap_conn *imapc = &conn->proto.imapc;
> + const char *line = data->state.buffer;
> +
> +@@ -1380,7 +1380,7 @@ static CURLcode imap_init(struct connectdata *conn)
> + struct Curl_easy *data = conn->data;
> + struct IMAP *imap;
> +
> +- imap = data->req.protop = calloc(sizeof(struct IMAP), 1);
> ++ imap = data->req.p.imap = calloc(sizeof(struct IMAP), 1);
> + if(!imap)
> + result = CURLE_OUT_OF_MEMORY;
> +
> +@@ -1457,7 +1457,7 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = data->req.protop;
> ++ struct IMAP *imap = data->req.p.imap;
> +
> + (void)premature;
> +
> +@@ -1517,7 +1517,7 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected,
> + /* This is IMAP and no proxy */
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = data->req.protop;
> ++ struct IMAP *imap = data->req.p.imap;
> + struct imap_conn *imapc = &conn->proto.imapc;
> + bool selected = FALSE;
> +
> +@@ -1640,7 +1640,7 @@ static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
> + /* Call this when the DO phase has completed */
> + static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
> + {
> +- struct IMAP *imap = conn->data->req.protop;
> ++ struct IMAP *imap = conn->data->req.p.imap;
> +
> + (void)connected;
> +
> +@@ -1942,7 +1942,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
> + /* The imap struct is already initialised in imap_connect() */
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = data->req.protop;
> ++ struct IMAP *imap = data->req.p.imap;
> + const char *begin = &data->state.up.path[1]; /* skip leading slash */
> + const char *ptr = begin;
> +
> +@@ -2074,7 +2074,7 @@ static CURLcode imap_parse_custom_request(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = data->req.protop;
> ++ struct IMAP *imap = data->req.p.imap;
> + const char *custom = data->set.str[STRING_CUSTOMREQUEST];
> +
> + if(custom) {
> +diff --git a/lib/mqtt.c b/lib/mqtt.c
> +index f6f4416..86b22b8 100644
> +--- a/lib/mqtt.c
> ++++ b/lib/mqtt.c
> +@@ -95,12 +95,12 @@ static CURLcode mqtt_setup_conn(struct connectdata *conn)
> + during this request */
> + struct MQTT *mq;
> + struct Curl_easy *data = conn->data;
> +- DEBUGASSERT(data->req.protop == NULL);
> ++ DEBUGASSERT(data->req.p.mqtt == NULL);
> +
> + mq = calloc(1, sizeof(struct MQTT));
> + if(!mq)
> + return CURLE_OUT_OF_MEMORY;
> +- data->req.protop = mq;
> ++ data->req.p.mqtt = mq;
> + return CURLE_OK;
> + }
> +
> +@@ -110,7 +110,7 @@ static CURLcode mqtt_send(struct connectdata *conn,
> + CURLcode result = CURLE_OK;
> + curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
> + struct Curl_easy *data = conn->data;
> +- struct MQTT *mq = data->req.protop;
> ++ struct MQTT *mq = data->req.p.mqtt;
> + ssize_t n;
> + result = Curl_write(conn, sockfd, buf, len, &n);
> + if(!result && data->set.verbose)
> +@@ -426,7 +426,7 @@ static CURLcode mqtt_read_publish(struct connectdata *conn,
> + unsigned char *pkt = (unsigned char *)data->state.buffer;
> + size_t remlen;
> + struct mqtt_conn *mqtt = &conn->proto.mqtt;
> +- struct MQTT *mq = data->req.protop;
> ++ struct MQTT *mq = data->req.p.mqtt;
> + unsigned char packet;
> +
> + switch(mqtt->state) {
> +@@ -533,7 +533,7 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
> + CURLcode result = CURLE_OK;
> + struct mqtt_conn *mqtt = &conn->proto.mqtt;
> + struct Curl_easy *data = conn->data;
> +- struct MQTT *mq = data->req.protop;
> ++ struct MQTT *mq = data->req.p.mqtt;
> + ssize_t nread;
> + curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
> + unsigned char *pkt = (unsigned char *)data->state.buffer;
> +diff --git a/lib/openldap.c b/lib/openldap.c
> +index 782d6a0..c955df6 100644
> +--- a/lib/openldap.c
> ++++ b/lib/openldap.c
> +@@ -410,7 +410,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
> + if(!lr)
> + return CURLE_OUT_OF_MEMORY;
> + lr->msgid = msgid;
> +- data->req.protop = lr;
> ++ data->req.p.ldap = lr;
> + Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
> + *done = TRUE;
> + return CURLE_OK;
> +@@ -419,7 +419,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
> + static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
> + bool premature)
> + {
> +- struct ldapreqinfo *lr = conn->data->req.protop;
> ++ struct ldapreqinfo *lr = conn->data->req.p.ldap;
> +
> + (void)res;
> + (void)premature;
> +@@ -431,7 +431,7 @@ static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
> + ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
> + lr->msgid = 0;
> + }
> +- conn->data->req.protop = NULL;
> ++ conn->data->req.p.ldap = NULL;
> + free(lr);
> + }
> +
> +@@ -443,7 +443,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
> + {
> + struct ldapconninfo *li = conn->proto.ldapc;
> + struct Curl_easy *data = conn->data;
> +- struct ldapreqinfo *lr = data->req.protop;
> ++ struct ldapreqinfo *lr = data->req.p.ldap;
> + int rc, ret;
> + LDAPMessage *msg = NULL;
> + LDAPMessage *ent;
> +diff --git a/lib/pop3.c b/lib/pop3.c
> +index 9ff5c78..04cc887 100644
> +--- a/lib/pop3.c
> ++++ b/lib/pop3.c
> +@@ -551,7 +551,7 @@ static CURLcode pop3_perform_command(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct POP3 *pop3 = data->req.protop;
> ++ struct POP3 *pop3 = data->req.p.pop3;
> + const char *command = NULL;
> +
> + /* Calculate the default command */
> +@@ -884,7 +884,7 @@ static CURLcode pop3_state_command_resp(struct connectdata *conn,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct POP3 *pop3 = data->req.protop;
> ++ struct POP3 *pop3 = data->req.p.pop3;
> + struct pop3_conn *pop3c = &conn->proto.pop3c;
> + struct pingpong *pp = &pop3c->pp;
> +
> +@@ -1046,7 +1046,7 @@ static CURLcode pop3_init(struct connectdata *conn)
> + struct Curl_easy *data = conn->data;
> + struct POP3 *pop3;
> +
> +- pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
> ++ pop3 = data->req.p.pop3 = calloc(sizeof(struct POP3), 1);
> + if(!pop3)
> + result = CURLE_OUT_OF_MEMORY;
> +
> +@@ -1120,7 +1120,7 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct POP3 *pop3 = data->req.protop;
> ++ struct POP3 *pop3 = data->req.p.pop3;
> +
> + (void)premature;
> +
> +@@ -1154,7 +1154,7 @@ static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
> + {
> + /* This is POP3 and no proxy */
> + CURLcode result = CURLE_OK;
> +- struct POP3 *pop3 = conn->data->req.protop;
> ++ struct POP3 *pop3 = conn->data->req.p.pop3;
> +
> + DEBUGF(infof(conn->data, "DO phase starts\n"));
> +
> +@@ -1386,7 +1386,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn)
> + {
> + /* The POP3 struct is already initialised in pop3_connect() */
> + struct Curl_easy *data = conn->data;
> +- struct POP3 *pop3 = data->req.protop;
> ++ struct POP3 *pop3 = data->req.p.pop3;
> + const char *path = &data->state.up.path[1]; /* skip leading path */
> +
> + /* URL decode the path for the message ID */
> +@@ -1403,7 +1403,7 @@ static CURLcode pop3_parse_custom_request(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct POP3 *pop3 = data->req.protop;
> ++ struct POP3 *pop3 = data->req.p.pop3;
> + const char *custom = data->set.str[STRING_CUSTOMREQUEST];
> +
> + /* URL decode the custom request */
> +diff --git a/lib/rtsp.c b/lib/rtsp.c
> +index dbd7dc6..29e6d58 100644
> +--- a/lib/rtsp.c
> ++++ b/lib/rtsp.c
> +@@ -114,7 +114,7 @@ static CURLcode rtsp_setup_connection(struct connectdata *conn)
> + {
> + struct RTSP *rtsp;
> +
> +- conn->data->req.protop = rtsp = calloc(1, sizeof(struct RTSP));
> ++ conn->data->req.p.rtsp = rtsp = calloc(1, sizeof(struct RTSP));
> + if(!rtsp)
> + return CURLE_OUT_OF_MEMORY;
> +
> +@@ -199,7 +199,7 @@ static CURLcode rtsp_done(struct connectdata *conn,
> + CURLcode status, bool premature)
> + {
> + struct Curl_easy *data = conn->data;
> +- struct RTSP *rtsp = data->req.protop;
> ++ struct RTSP *rtsp = data->req.p.rtsp;
> + CURLcode httpStatus;
> +
> + /* Bypass HTTP empty-reply checks on receive */
> +@@ -232,7 +232,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
> + struct Curl_easy *data = conn->data;
> + CURLcode result = CURLE_OK;
> + Curl_RtspReq rtspreq = data->set.rtspreq;
> +- struct RTSP *rtsp = data->req.protop;
> ++ struct RTSP *rtsp = data->req.p.rtsp;
> + struct dynbuf req_buffer;
> + curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */
> + curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */
> +@@ -764,7 +764,7 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
> + /* Store the received CSeq. Match is verified in rtsp_done */
> + int nc = sscanf(&header[4], ": %ld", &CSeq);
> + if(nc == 1) {
> +- struct RTSP *rtsp = data->req.protop;
> ++ struct RTSP *rtsp = data->req.p.rtsp;
> + rtsp->CSeq_recv = CSeq; /* mark the request */
> + data->state.rtsp_CSeq_recv = CSeq; /* update the handle */
> + }
> +diff --git a/lib/smb.c b/lib/smb.c
> +index d493adc..9eba7ab 100644
> +--- a/lib/smb.c
> ++++ b/lib/smb.c
> +@@ -204,7 +204,7 @@ static void conn_state(struct connectdata *conn, enum smb_conn_state newstate)
> + static void request_state(struct connectdata *conn,
> + enum smb_req_state newstate)
> + {
> +- struct smb_request *req = conn->data->req.protop;
> ++ struct smb_request *req = conn->data->req.p.smb;
> + #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
> + /* For debug purposes */
> + static const char * const names[] = {
> +@@ -234,7 +234,7 @@ static CURLcode smb_setup_connection(struct connectdata *conn)
> + struct smb_request *req;
> +
> + /* Initialize the request state */
> +- conn->data->req.protop = req = calloc(1, sizeof(struct smb_request));
> ++ conn->data->req.p.smb = req = calloc(1, sizeof(struct smb_request));
> + if(!req)
> + return CURLE_OUT_OF_MEMORY;
> +
> +@@ -342,7 +342,7 @@ static void smb_format_message(struct connectdata *conn, struct smb_header *h,
> + unsigned char cmd, size_t len)
> + {
> + struct smb_conn *smbc = &conn->proto.smbc;
> +- struct smb_request *req = conn->data->req.protop;
> ++ struct smb_request *req = conn->data->req.p.smb;
> + unsigned int pid;
> +
> + memset(h, 0, sizeof(*h));
> +@@ -505,7 +505,7 @@ static CURLcode smb_send_tree_connect(struct connectdata *conn)
> +
> + static CURLcode smb_send_open(struct connectdata *conn)
> + {
> +- struct smb_request *req = conn->data->req.protop;
> ++ struct smb_request *req = conn->data->req.p.smb;
> + struct smb_nt_create msg;
> + size_t byte_count;
> +
> +@@ -535,7 +535,7 @@ static CURLcode smb_send_open(struct connectdata *conn)
> +
> + static CURLcode smb_send_close(struct connectdata *conn)
> + {
> +- struct smb_request *req = conn->data->req.protop;
> ++ struct smb_request *req = conn->data->req.p.smb;
> + struct smb_close msg;
> +
> + memset(&msg, 0, sizeof(msg));
> +@@ -556,7 +556,7 @@ static CURLcode smb_send_tree_disconnect(struct connectdata *conn)
> +
> + static CURLcode smb_send_read(struct connectdata *conn)
> + {
> +- struct smb_request *req = conn->data->req.protop;
> ++ struct smb_request *req = conn->data->req.p.smb;
> + curl_off_t offset = conn->data->req.offset;
> + struct smb_read msg;
> +
> +@@ -575,7 +575,7 @@ static CURLcode smb_send_read(struct connectdata *conn)
> + static CURLcode smb_send_write(struct connectdata *conn)
> + {
> + struct smb_write *msg;
> +- struct smb_request *req = conn->data->req.protop;
> ++ struct smb_request *req = conn->data->req.p.smb;
> + curl_off_t offset = conn->data->req.offset;
> + curl_off_t upload_size = conn->data->req.size - conn->data->req.bytecount;
> + CURLcode result = Curl_get_upload_buffer(conn->data);
> +@@ -738,7 +738,7 @@ static void get_posix_time(time_t *out, curl_off_t timestamp)
> +
> + static CURLcode smb_request_state(struct connectdata *conn, bool *done)
> + {
> +- struct smb_request *req = conn->data->req.protop;
> ++ struct smb_request *req = conn->data->req.p.smb;
> + struct smb_header *h;
> + struct smb_conn *smbc = &conn->proto.smbc;
> + enum smb_req_state next_state = SMB_DONE;
> +@@ -923,7 +923,7 @@ static CURLcode smb_done(struct connectdata *conn, CURLcode status,
> + bool premature)
> + {
> + (void) premature;
> +- Curl_safefree(conn->data->req.protop);
> ++ Curl_safefree(conn->data->req.p.smb);
> + return status;
> + }
> +
> +@@ -957,7 +957,7 @@ static CURLcode smb_do(struct connectdata *conn, bool *done)
> + static CURLcode smb_parse_url_path(struct connectdata *conn)
> + {
> + struct Curl_easy *data = conn->data;
> +- struct smb_request *req = data->req.protop;
> ++ struct smb_request *req = data->req.p.smb;
> + struct smb_conn *smbc = &conn->proto.smbc;
> + char *path;
> + char *slash;
> +diff --git a/lib/smtp.c b/lib/smtp.c
> +index aea41bb..c5d0296 100644
> +--- a/lib/smtp.c
> ++++ b/lib/smtp.c
> +@@ -484,7 +484,7 @@ static CURLcode smtp_perform_command(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> +
> + if(smtp->rcpt) {
> + /* We notify the server we are sending UTF-8 data if a) it supports the
> +@@ -697,7 +697,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
> + any there do, as we need to correctly identify our support for SMTPUTF8
> + in the envelope, as per RFC-6531 sect. 3.4 */
> + if(conn->proto.smtpc.utf8_supported && !utf8) {
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> + struct curl_slist *rcpt = smtp->rcpt;
> +
> + while(rcpt && !utf8) {
> +@@ -741,7 +741,7 @@ static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> + char *address = NULL;
> + struct hostname host = { NULL, NULL, NULL, NULL };
> +
> +@@ -989,7 +989,7 @@ static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> + char *line = data->state.buffer;
> + size_t len = strlen(line);
> +
> +@@ -1055,7 +1055,7 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> + bool is_smtp_err = FALSE;
> + bool is_smtp_blocking_err = FALSE;
> +
> +@@ -1278,7 +1278,7 @@ static CURLcode smtp_init(struct connectdata *conn)
> + struct Curl_easy *data = conn->data;
> + struct SMTP *smtp;
> +
> +- smtp = data->req.protop = calloc(sizeof(struct SMTP), 1);
> ++ smtp = data->req.p.smtp = calloc(sizeof(struct SMTP), 1);
> + if(!smtp)
> + result = CURLE_OUT_OF_MEMORY;
> +
> +@@ -1356,7 +1356,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> + struct pingpong *pp = &conn->proto.smtpc.pp;
> + char *eob;
> + ssize_t len;
> +@@ -1442,7 +1442,7 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
> + /* This is SMTP and no proxy */
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> +
> + DEBUGF(infof(conn->data, "DO phase starts\n"));
> +
> +@@ -1550,7 +1550,7 @@ static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
> + /* Call this when the DO phase has completed */
> + static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
> + {
> +- struct SMTP *smtp = conn->data->req.protop;
> ++ struct SMTP *smtp = conn->data->req.p.smtp;
> +
> + (void)connected;
> +
> +@@ -1703,7 +1703,7 @@ static CURLcode smtp_parse_custom_request(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> + const char *custom = data->set.str[STRING_CUSTOMREQUEST];
> +
> + /* URL decode the custom request */
> +@@ -1796,7 +1796,7 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
> + ssize_t i;
> + ssize_t si;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> + char *scratch = data->state.scratch;
> + char *newscratch = NULL;
> + char *oldscratch = NULL;
> +diff --git a/lib/telnet.c b/lib/telnet.c
> +index c3b58e5..1fc5af1 100644
> +--- a/lib/telnet.c
> ++++ b/lib/telnet.c
> +@@ -247,7 +247,7 @@ CURLcode init_telnet(struct connectdata *conn)
> + if(!tn)
> + return CURLE_OUT_OF_MEMORY;
> +
> +- conn->data->req.protop = tn; /* make us known */
> ++ conn->data->req.p.telnet = tn; /* make us known */
> +
> + tn->telrcv_state = CURL_TS_DATA;
> +
> +@@ -292,7 +292,7 @@ CURLcode init_telnet(struct connectdata *conn)
> + static void negotiate(struct connectdata *conn)
> + {
> + int i;
> +- struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *) conn->data->req.p.telnet;
> +
> + for(i = 0; i < CURL_NTELOPTS; i++) {
> + if(i == CURL_TELOPT_ECHO)
> +@@ -365,7 +365,7 @@ static void send_negotiation(struct connectdata *conn, int cmd, int option)
> + static
> + void set_remote_option(struct connectdata *conn, int option, int newstate)
> + {
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + if(newstate == CURL_YES) {
> + switch(tn->him[option]) {
> + case CURL_NO:
> +@@ -439,7 +439,7 @@ void set_remote_option(struct connectdata *conn, int option, int newstate)
> + static
> + void rec_will(struct connectdata *conn, int option)
> + {
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + switch(tn->him[option]) {
> + case CURL_NO:
> + if(tn->him_preferred[option] == CURL_YES) {
> +@@ -487,7 +487,7 @@ void rec_will(struct connectdata *conn, int option)
> + static
> + void rec_wont(struct connectdata *conn, int option)
> + {
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + switch(tn->him[option]) {
> + case CURL_NO:
> + /* Already disabled */
> +@@ -529,7 +529,7 @@ void rec_wont(struct connectdata *conn, int option)
> + static void
> + set_local_option(struct connectdata *conn, int option, int newstate)
> + {
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + if(newstate == CURL_YES) {
> + switch(tn->us[option]) {
> + case CURL_NO:
> +@@ -603,7 +603,7 @@ set_local_option(struct connectdata *conn, int option, int newstate)
> + static
> + void rec_do(struct connectdata *conn, int option)
> + {
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + switch(tn->us[option]) {
> + case CURL_NO:
> + if(tn->us_preferred[option] == CURL_YES) {
> +@@ -663,7 +663,7 @@ void rec_do(struct connectdata *conn, int option)
> + static
> + void rec_dont(struct connectdata *conn, int option)
> + {
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + switch(tn->us[option]) {
> + case CURL_NO:
> + /* Already disabled */
> +@@ -822,7 +822,7 @@ static CURLcode check_telnet_options(struct connectdata *conn)
> + char option_keyword[128] = "";
> + char option_arg[256] = "";
> + struct Curl_easy *data = conn->data;
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + CURLcode result = CURLE_OK;
> + int binary_option;
> +
> +@@ -929,7 +929,7 @@ static void suboption(struct connectdata *conn)
> + char varname[128] = "";
> + char varval[128] = "";
> + struct Curl_easy *data = conn->data;
> +- struct TELNET *tn = (struct TELNET *)data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)data->req.p.telnet;
> +
> + printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2);
> + switch(CURL_SB_GET(tn)) {
> +@@ -1004,7 +1004,7 @@ static void sendsuboption(struct connectdata *conn, int option)
> + unsigned char *uc1, *uc2;
> +
> + struct Curl_easy *data = conn->data;
> +- struct TELNET *tn = (struct TELNET *)data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)data->req.p.telnet;
> +
> + switch(option) {
> + case CURL_TELOPT_NAWS:
> +@@ -1062,7 +1062,7 @@ CURLcode telrcv(struct connectdata *conn,
> + int in = 0;
> + int startwrite = -1;
> + struct Curl_easy *data = conn->data;
> +- struct TELNET *tn = (struct TELNET *)data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)data->req.p.telnet;
> +
> + #define startskipping() \
> + if(startwrite >= 0) { \
> +@@ -1280,7 +1280,7 @@ static CURLcode send_telnet_data(struct connectdata *conn,
> + static CURLcode telnet_done(struct connectdata *conn,
> + CURLcode status, bool premature)
> + {
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + (void)status; /* unused */
> + (void)premature; /* not used */
> +
> +@@ -1290,7 +1290,7 @@ static CURLcode telnet_done(struct connectdata *conn,
> + curl_slist_free_all(tn->telnet_vars);
> + tn->telnet_vars = NULL;
> +
> +- Curl_safefree(conn->data->req.protop);
> ++ Curl_safefree(conn->data->req.p.telnet);
> +
> + return CURLE_OK;
> + }
> +@@ -1333,7 +1333,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
> + if(result)
> + return result;
> +
> +- tn = (struct TELNET *)data->req.protop;
> ++ tn = data->req.p.telnet;
> +
> + result = check_telnet_options(conn);
> + if(result)
> +diff --git a/lib/transfer.c b/lib/transfer.c
> +index a07c7af..4630609 100644
> +--- a/lib/transfer.c
> ++++ b/lib/transfer.c
> +@@ -167,7 +167,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
> + bool sending_http_headers = FALSE;
> +
> + if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) {
> +- const struct HTTP *http = data->req.protop;
> ++ const struct HTTP *http = data->req.p.http;
> +
> + if(http->sending == HTTPSEND_REQUEST)
> + /* We're sending the HTTP request headers, not the data.
> +@@ -426,7 +426,7 @@ CURLcode Curl_readrewind(struct connectdata *conn)
> + CURLOPT_HTTPPOST, call app to rewind
> + */
> + if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
> +- struct HTTP *http = data->req.protop;
> ++ struct HTTP *http = data->req.p.http;
> +
> + if(http->sendit)
> + mimepart = http->sendit;
> +@@ -1028,7 +1028,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
> + /* HTTP pollution, this should be written nicer to become more
> + protocol agnostic. */
> + size_t fillcount;
> +- struct HTTP *http = k->protop;
> ++ struct HTTP *http = k->p.http;
> +
> + if((k->exp100 == EXP100_SENDING_REQUEST) &&
> + (http->sending == HTTPSEND_BODY)) {
> +@@ -1853,7 +1853,7 @@ Curl_setup_transfer(
> + {
> + struct SingleRequest *k = &data->req;
> + struct connectdata *conn = data->conn;
> +- struct HTTP *http = data->req.protop;
> ++ struct HTTP *http = data->req.p.http;
> + bool httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) &&
> + (http->sending == HTTPSEND_REQUEST));
> + DEBUGASSERT(conn != NULL);
> +diff --git a/lib/url.c b/lib/url.c
> +index 150667a..849d527 100644
> +--- a/lib/url.c
> ++++ b/lib/url.c
> +@@ -2060,7 +2060,7 @@ static CURLcode setup_connection_internals(struct connectdata *conn)
> +
> + void Curl_free_request_state(struct Curl_easy *data)
> + {
> +- Curl_safefree(data->req.protop);
> ++ Curl_safefree(data->req.p.http);
> + Curl_safefree(data->req.newurl);
> +
> + #ifndef CURL_DISABLE_DOH
> +diff --git a/lib/urldata.h b/lib/urldata.h
> +index 0ae9269..76baee3 100644
> +--- a/lib/urldata.h
> ++++ b/lib/urldata.h
> +@@ -645,8 +645,23 @@ struct SingleRequest {
> + and the 'upload_present' contains the number of bytes available at this
> + position */
> + char *upload_fromhere;
> +- void *protop; /* Allocated protocol-specific data. Each protocol
> +- handler makes sure this points to data it needs. */
> ++
> ++ /* Allocated protocol-specific data. Each protocol handler makes sure this
> ++ points to data it needs. */
> ++ union {
> ++ struct FILEPROTO *file;
> ++ struct FTP *ftp;
> ++ struct HTTP *http;
> ++ struct IMAP *imap;
> ++ struct ldapreqinfo *ldap;
> ++ struct MQTT *mqtt;
> ++ struct POP3 *pop3;
> ++ struct RTSP *rtsp;
> ++ struct smb_request *smb;
> ++ struct SMTP *smtp;
> ++ struct SSHPROTO *ssh;
> ++ struct TELNET *telnet;
> ++ } p;
> + #ifndef CURL_DISABLE_DOH
> + struct dohdata doh; /* DoH specific data for this request */
> + #endif
> +diff --git a/lib/vquic/ngtcp2.c b/lib/vquic/ngtcp2.c
> +index 20ee08d..18eeda8 100644
> +--- a/lib/vquic/ngtcp2.c
> ++++ b/lib/vquic/ngtcp2.c
> +@@ -962,7 +962,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
> + void *stream_user_data)
> + {
> + struct Curl_easy *data = stream_user_data;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + (void)conn;
> + (void)stream_id;
> + (void)app_error_code;
> +@@ -1008,7 +1008,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream_id,
> + void *user_data, void *stream_user_data)
> + {
> + struct Curl_easy *data = stream_user_data;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + CURLcode result = CURLE_OK;
> + (void)conn;
> +
> +@@ -1067,7 +1067,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
> + void *user_data, void *stream_user_data)
> + {
> + struct Curl_easy *data = stream_user_data;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + CURLcode result = CURLE_OK;
> + (void)conn;
> + (void)stream_id;
> +@@ -1091,7 +1091,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
> + nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
> + nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
> + struct Curl_easy *data = stream_user_data;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + CURLcode result = CURLE_OK;
> + (void)conn;
> + (void)stream_id;
> +@@ -1255,7 +1255,7 @@ static ssize_t ngh3_stream_recv(struct connectdata *conn,
> + CURLcode *curlcode)
> + {
> + curl_socket_t sockfd = conn->sock[sockindex];
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> + struct quicsocket *qs = conn->quic;
> +
> + if(!stream->memlen) {
> +@@ -1313,7 +1313,7 @@ static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
> + void *stream_user_data)
> + {
> + struct Curl_easy *data = stream_user_data;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + (void)conn;
> + (void)stream_id;
> + (void)user_data;
> +@@ -1335,7 +1335,7 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
> + {
> + struct Curl_easy *data = stream_user_data;
> + size_t nread;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + (void)conn;
> + (void)stream_id;
> + (void)user_data;
> +@@ -1398,7 +1398,7 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
> + static CURLcode http_request(struct connectdata *conn, const void *mem,
> + size_t len)
> + {
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> + size_t nheader;
> + size_t i;
> + size_t authority_idx;
> +@@ -1641,7 +1641,7 @@ static ssize_t ngh3_stream_send(struct connectdata *conn,
> + ssize_t sent;
> + struct quicsocket *qs = conn->quic;
> + curl_socket_t sockfd = conn->sock[sockindex];
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> +
> + if(!stream->h3req) {
> + CURLcode result = http_request(conn, mem, len);
> +@@ -1909,7 +1909,7 @@ CURLcode Curl_quic_done_sending(struct connectdata *conn)
> + {
> + if(conn->handler == &Curl_handler_http3) {
> + /* only for HTTP/3 transfers */
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> + struct quicsocket *qs = conn->quic;
> + stream->upload_done = TRUE;
> + (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
> +@@ -1926,7 +1926,7 @@ void Curl_quic_done(struct Curl_easy *data, bool premature)
> + (void)premature;
> + if(data->conn->handler == &Curl_handler_http3) {
> + /* only for HTTP/3 transfers */
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + Curl_dyn_free(&stream->overflow);
> + }
> + }
> +@@ -1941,7 +1941,7 @@ bool Curl_quic_data_pending(const struct Curl_easy *data)
> + buffer and allocated an overflow buffer. Since it's possible that
> + there's no more data coming on the socket, we need to keep reading
> + until the overflow buffer is empty. */
> +- const struct HTTP *stream = data->req.protop;
> ++ const struct HTTP *stream = data->req.p.http;
> + return Curl_dyn_len(&stream->overflow) > 0;
> + }
> +
> +diff --git a/lib/vquic/quiche.c b/lib/vquic/quiche.c
> +index fd9cb8b..c0e250d 100644
> +--- a/lib/vquic/quiche.c
> ++++ b/lib/vquic/quiche.c
> +@@ -131,7 +131,7 @@ static unsigned int quiche_conncheck(struct connectdata *conn,
> +
> + static CURLcode quiche_do(struct connectdata *conn, bool *done)
> + {
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> + stream->h3req = FALSE; /* not sent */
> + return Curl_http(conn, done);
> + }
> +@@ -460,7 +460,7 @@ static ssize_t h3_stream_recv(struct connectdata *conn,
> + int rc;
> + struct h3h1header headers;
> + struct Curl_easy *data = conn->data;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + headers.dest = buf;
> + headers.destlen = buffersize;
> + headers.nlen = 0;
> +@@ -548,7 +548,7 @@ static ssize_t h3_stream_send(struct connectdata *conn,
> + ssize_t sent;
> + struct quicsocket *qs = conn->quic;
> + curl_socket_t sockfd = conn->sock[sockindex];
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> +
> + if(!stream->h3req) {
> + CURLcode result = http_request(conn, mem, len);
> +@@ -596,7 +596,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
> + {
> + /*
> + */
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> + size_t nheader;
> + size_t i;
> + size_t authority_idx;
> +@@ -824,7 +824,7 @@ CURLcode Curl_quic_done_sending(struct connectdata *conn)
> + if(conn->handler == &Curl_handler_http3) {
> + /* only for HTTP/3 transfers */
> + ssize_t sent;
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> + struct quicsocket *qs = conn->quic;
> + fprintf(stderr, "!!! Curl_quic_done_sending\n");
> + stream->upload_done = TRUE;
> +diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c
> +index 8988e23..a84e1bf 100644
> +--- a/lib/vssh/libssh.c
> ++++ b/lib/vssh/libssh.c
> +@@ -662,7 +662,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SSHPROTO *protop = data->req.protop;
> ++ struct SSHPROTO *protop = data->req.p.ssh;
> + struct ssh_conn *sshc = &conn->proto.sshc;
> + curl_socket_t sock = conn->sock[FIRSTSOCKET];
> + int rc = SSH_NO_ERROR, err;
> +@@ -2129,7 +2129,7 @@ static CURLcode myssh_setup_connection(struct connectdata *conn)
> + {
> + struct SSHPROTO *ssh;
> +
> +- conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
> ++ conn->data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
> + if(!ssh)
> + return CURLE_OUT_OF_MEMORY;
> +
> +@@ -2152,7 +2152,7 @@ static CURLcode myssh_connect(struct connectdata *conn, bool *done)
> + int rc;
> +
> + /* initialize per-handle data if not already */
> +- if(!data->req.protop)
> ++ if(!data->req.p.ssh)
> + myssh_setup_connection(conn);
> +
> + /* We default to persistent connections. We set this already in this connect
> +@@ -2353,7 +2353,7 @@ static CURLcode scp_disconnect(struct connectdata *conn,
> + static CURLcode myssh_done(struct connectdata *conn, CURLcode status)
> + {
> + CURLcode result = CURLE_OK;
> +- struct SSHPROTO *protop = conn->data->req.protop;
> ++ struct SSHPROTO *protop = conn->data->req.p.ssh;
> +
> + if(!status) {
> + /* run the state-machine */
> +@@ -2606,7 +2606,7 @@ static void sftp_quote(struct connectdata *conn)
> + {
> + const char *cp;
> + struct Curl_easy *data = conn->data;
> +- struct SSHPROTO *protop = data->req.protop;
> ++ struct SSHPROTO *protop = data->req.p.ssh;
> + struct ssh_conn *sshc = &conn->proto.sshc;
> + CURLcode result;
> +
> +diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c
> +index 4f56bb4..3ed777f 100644
> +--- a/lib/vssh/libssh2.c
> ++++ b/lib/vssh/libssh2.c
> +@@ -789,7 +789,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SSHPROTO *sftp_scp = data->req.protop;
> ++ struct SSHPROTO *sftp_scp = data->req.p.ssh;
> + struct ssh_conn *sshc = &conn->proto.sshc;
> + curl_socket_t sock = conn->sock[FIRSTSOCKET];
> + int rc = LIBSSH2_ERROR_NONE;
> +@@ -2989,7 +2989,7 @@ static CURLcode ssh_setup_connection(struct connectdata *conn)
> + {
> + struct SSHPROTO *ssh;
> +
> +- conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
> ++ conn->data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
> + if(!ssh)
> + return CURLE_OUT_OF_MEMORY;
> +
> +@@ -3013,7 +3013,7 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
> + struct Curl_easy *data = conn->data;
> +
> + /* initialize per-handle data if not already */
> +- if(!data->req.protop)
> ++ if(!data->req.p.ssh)
> + ssh_setup_connection(conn);
> +
> + /* We default to persistent connections. We set this already in this connect
> +@@ -3192,7 +3192,7 @@ static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection)
> + static CURLcode ssh_done(struct connectdata *conn, CURLcode status)
> + {
> + CURLcode result = CURLE_OK;
> +- struct SSHPROTO *sftp_scp = conn->data->req.protop;
> ++ struct SSHPROTO *sftp_scp = conn->data->req.p.ssh;
> +
> + if(!status) {
> + /* run the state-machine */
> +diff --git a/lib/vssh/wolfssh.c b/lib/vssh/wolfssh.c
> +index dcbbab6..1b990e3 100644
> +--- a/lib/vssh/wolfssh.c
> ++++ b/lib/vssh/wolfssh.c
> +@@ -322,7 +322,7 @@ static CURLcode wssh_setup_connection(struct connectdata *conn)
> + {
> + struct SSHPROTO *ssh;
> +
> +- conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
> ++ conn->data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
> + if(!ssh)
> + return CURLE_OUT_OF_MEMORY;
> +
> +@@ -356,7 +356,7 @@ static CURLcode wssh_connect(struct connectdata *conn, bool *done)
> + int rc;
> +
> + /* initialize per-handle data if not already */
> +- if(!data->req.protop)
> ++ if(!data->req.p.ssh)
> + wssh_setup_connection(conn);
> +
> + /* We default to persistent connections. We set this already in this connect
> +@@ -429,7 +429,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
> + CURLcode result = CURLE_OK;
> + struct ssh_conn *sshc = &conn->proto.sshc;
> + struct Curl_easy *data = conn->data;
> +- struct SSHPROTO *sftp_scp = data->req.protop;
> ++ struct SSHPROTO *sftp_scp = data->req.p.ssh;
> + WS_SFTPNAME *name;
> + int rc = 0;
> + *block = FALSE; /* we're not blocking by default */
> +@@ -1027,7 +1027,7 @@ static CURLcode wssh_block_statemach(struct connectdata *conn,
> + static CURLcode wssh_done(struct connectdata *conn, CURLcode status)
> + {
> + CURLcode result = CURLE_OK;
> +- struct SSHPROTO *sftp_scp = conn->data->req.protop;
> ++ struct SSHPROTO *sftp_scp = conn->data->req.p.ssh;
> +
> + if(!status) {
> + /* run the state-machine */
> diff --git a/meta/recipes-support/curl/curl/CVE-2020-8284.patch b/meta/recipes-support/curl/curl/CVE-2020-8284.patch
> new file mode 100644
> index 00000000000..4ae514ffa8b
> --- /dev/null
> +++ b/meta/recipes-support/curl/curl/CVE-2020-8284.patch
> @@ -0,0 +1,210 @@
> +From ec9cc725d598ac77de7b6df8afeec292b3c8ad46 Mon Sep 17 00:00:00 2001
> +From: Daniel Stenberg <daniel@haxx.se>
> +Date: Tue, 24 Nov 2020 14:56:57 +0100
> +Subject: [PATCH] ftp: CURLOPT_FTP_SKIP_PASV_IP by default
> +
> +The command line tool also independently sets --ftp-skip-pasv-ip by
> +default.
> +
> +Ten test cases updated to adapt the modified --libcurl output.
> +
> +Bug: https://curl.se/docs/CVE-2020-8284.html
> +CVE-2020-8284
> +
> +Reported-by: Varnavas Papaioannou
> +
> +Upstream-Status: Backport [https://github.com/curl/curl/commit/ec9cc725d598ac]
> +
> +CVE: CVE-2020-8284
> +
> +Signed-off-by: Daniel Stenberg <daniel@haxx.se>
> +Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
> +---
> + docs/cmdline-opts/ftp-skip-pasv-ip.d | 2 ++
> + docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 | 8 +++++---
> + lib/url.c | 1 +
> + src/tool_cfgable.c | 1 +
> + tests/data/test1400 | 1 +
> + tests/data/test1401 | 1 +
> + tests/data/test1402 | 1 +
> + tests/data/test1403 | 1 +
> + tests/data/test1404 | 1 +
> + tests/data/test1405 | 1 +
> + tests/data/test1406 | 1 +
> + tests/data/test1407 | 1 +
> + tests/data/test1420 | 1 +
> + 14 files changed, 18 insertions(+), 3 deletions(-)
> +
> +diff --git a/docs/cmdline-opts/ftp-skip-pasv-ip.d b/docs/cmdline-opts/ftp-skip-pasv-ip.d
> +index d6fd4589b1e..bcf4e7e62f2 100644
> +--- a/docs/cmdline-opts/ftp-skip-pasv-ip.d
> ++++ b/docs/cmdline-opts/ftp-skip-pasv-ip.d
> +@@ -10,4 +10,6 @@ to curl's PASV command when curl connects the data connection. Instead curl
> + will re-use the same IP address it already uses for the control
> + connection.
> +
> ++Since curl 7.74.0 this option is enabled by default.
> ++
> + This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
> +diff --git a/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 b/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3
> +index d6217d0d8ca..fa87ddce769 100644
> +--- a/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3
> ++++ b/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3
> +@@ -5,7 +5,7 @@
> + .\" * | (__| |_| | _ <| |___
> + .\" * \___|\___/|_| \_\_____|
> + .\" *
> +-.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
> ++.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
> + .\" *
> + .\" * This software is licensed as described in the file COPYING, which
> + .\" * you should have received as part of this distribution. The terms
> +@@ -35,11 +35,13 @@ address it already uses for the control connection. But it will use the port
> + number from the 227-response.
> +
> + This option thus allows libcurl to work around broken server installations
> +-that due to NATs, firewalls or incompetence report the wrong IP address back.
> ++that due to NATs, firewalls or incompetence report the wrong IP address
> ++back. Setting the option also reduces the risk for various sorts of client
> ++abuse by malicious servers.
> +
> + This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
> + .SH DEFAULT
> +-0
> ++1 since 7.74.0, was 0 before then.
> + .SH PROTOCOLS
> + FTP
> + .SH EXAMPLE
> +diff --git a/lib/url.c b/lib/url.c
> +index f8b2a0030de..2b0ba87ba87 100644
> +--- a/lib/url.c
> ++++ b/lib/url.c
> +@@ -497,6 +497,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
> + set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
> + set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */
> + set->ftp_filemethod = FTPFILE_MULTICWD;
> ++ set->ftp_skip_ip = TRUE; /* skip PASV IP by default */
> + #endif
> + set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
> +
> +diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c
> +index c52d8e1c6bb..4c06d3557b7 100644
> +--- a/src/tool_cfgable.c
> ++++ b/src/tool_cfgable.c
> +@@ -44,6 +44,7 @@ void config_init(struct OperationConfig *config)
> + config->tcp_nodelay = TRUE; /* enabled by default */
> + config->happy_eyeballs_timeout_ms = CURL_HET_DEFAULT;
> + config->http09_allowed = FALSE;
> ++ config->ftp_skip_ip = TRUE;
> + }
> +
> + static void free_config_fields(struct OperationConfig *config)
> +diff --git a/tests/data/test1400 b/tests/data/test1400
> +index 812ad0b88d9..b7060eca58e 100644
> +--- a/tests/data/test1400
> ++++ b/tests/data/test1400
> +@@ -73,6 +73,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
> + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> +
> + /* Here is a list of options the curl code used that cannot get generated
> +diff --git a/tests/data/test1401 b/tests/data/test1401
> +index f93b3d637de..a2629683aff 100644
> +--- a/tests/data/test1401
> ++++ b/tests/data/test1401
> +@@ -87,6 +87,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
> + curl_easy_setopt(hnd, CURLOPT_COOKIE, "chocolate=chip");
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> + curl_easy_setopt(hnd, CURLOPT_PROTOCOLS, (long)CURLPROTO_FILE |
> + (long)CURLPROTO_FTP |
> +diff --git a/tests/data/test1402 b/tests/data/test1402
> +index 7593c516da1..1bd55cb4e3b 100644
> +--- a/tests/data/test1402
> ++++ b/tests/data/test1402
> +@@ -78,6 +78,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
> + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> +
> + /* Here is a list of options the curl code used that cannot get generated
> +diff --git a/tests/data/test1403 b/tests/data/test1403
> +index ecb4dd3dcab..a7c9fcca322 100644
> +--- a/tests/data/test1403
> ++++ b/tests/data/test1403
> +@@ -73,6 +73,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
> + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> +
> + /* Here is a list of options the curl code used that cannot get generated
> +diff --git a/tests/data/test1404 b/tests/data/test1404
> +index 97622b63948..1d8e8cf7779 100644
> +--- a/tests/data/test1404
> ++++ b/tests/data/test1404
> +@@ -147,6 +147,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
> + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> +
> + /* Here is a list of options the curl code used that cannot get generated
> +diff --git a/tests/data/test1405 b/tests/data/test1405
> +index 2bac79eda74..b4087704f7b 100644
> +--- a/tests/data/test1405
> ++++ b/tests/data/test1405
> +@@ -89,6 +89,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_POSTQUOTE, slist2);
> + curl_easy_setopt(hnd, CURLOPT_PREQUOTE, slist3);
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> +
> + /* Here is a list of options the curl code used that cannot get generated
> +diff --git a/tests/data/test1406 b/tests/data/test1406
> +index 51a166adff2..38f68d11ee1 100644
> +--- a/tests/data/test1406
> ++++ b/tests/data/test1406
> +@@ -79,6 +79,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_URL, "smtp://%HOSTIP:%SMTPPORT/1406");
> + curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L);
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> + curl_easy_setopt(hnd, CURLOPT_MAIL_FROM, "sender@example.com");
> + curl_easy_setopt(hnd, CURLOPT_MAIL_RCPT, slist1);
> +diff --git a/tests/data/test1407 b/tests/data/test1407
> +index f6879008fb2..a7e13ba7585 100644
> +--- a/tests/data/test1407
> ++++ b/tests/data/test1407
> +@@ -62,6 +62,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_DIRLISTONLY, 1L);
> + curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret");
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> +
> + /* Here is a list of options the curl code used that cannot get generated
> +diff --git a/tests/data/test1420 b/tests/data/test1420
> +index 057ecc4773a..4b8d7bbf418 100644
> +--- a/tests/data/test1420
> ++++ b/tests/data/test1420
> +@@ -67,6 +67,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_URL, "imap://%HOSTIP:%IMAPPORT/1420/;MAILINDEX=1");
> + curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret");
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> +
> + /* Here is a list of options the curl code used that cannot get generated
> +
> diff --git a/meta/recipes-support/curl/curl/CVE-2020-8285.patch b/meta/recipes-support/curl/curl/CVE-2020-8285.patch
> new file mode 100644
> index 00000000000..7a8be684775
> --- /dev/null
> +++ b/meta/recipes-support/curl/curl/CVE-2020-8285.patch
> @@ -0,0 +1,261 @@
> +From 69a358f2186e04cf44698b5100332cbf1ee7f01d Mon Sep 17 00:00:00 2001
> +From: Daniel Stenberg <daniel@haxx.se>
> +Date: Sat, 28 Nov 2020 00:27:21 +0100
> +Subject: [PATCH] ftp: make wc_statemach loop instead of recurse
> +
> +CVE-2020-8285
> +
> +Fixes #6255
> +Bug: https://curl.se/docs/CVE-2020-8285.html
> +Reported-by: xnynx on github
> +
> +Upstream-Status: Backport [https://github.com/curl/curl/commit/69a358f2186e04]
> +
> +CVE: CVE-2020-8285
> +
> +Signed-off-by: Daniel Stenberg <daniel@haxx.se>
> +Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
> +
> +[Ajusted to match Dunfell context]
> +Signed-off-by: Armin Kuster <akuster@mvista.com>
> +---
> + lib/ftp.c | 202 +++++++++++++++++++++++++++---------------------------
> + 1 file changed, 102 insertions(+), 100 deletions(-)
> +
> +Index: curl-7.69.1/lib/ftp.c
> +===================================================================
> +--- curl-7.69.1.orig/lib/ftp.c
> ++++ curl-7.69.1/lib/ftp.c
> +@@ -3763,129 +3763,134 @@ static CURLcode init_wc_data(struct conn
> + return result;
> + }
> +
> +-/* This is called recursively */
> + static CURLcode wc_statemach(struct connectdata *conn)
> + {
> + struct WildcardData * const wildcard = &(conn->data->wildcard);
> + CURLcode result = CURLE_OK;
> +
> +- switch(wildcard->state) {
> +- case CURLWC_INIT:
> +- result = init_wc_data(conn);
> +- if(wildcard->state == CURLWC_CLEAN)
> +- /* only listing! */
> +- break;
> +- wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
> +- break;
> +-
> +- case CURLWC_MATCHING: {
> +- /* In this state is LIST response successfully parsed, so lets restore
> +- previous WRITEFUNCTION callback and WRITEDATA pointer */
> +- struct ftp_wc *ftpwc = wildcard->protdata;
> +- conn->data->set.fwrite_func = ftpwc->backup.write_function;
> +- conn->data->set.out = ftpwc->backup.file_descriptor;
> +- ftpwc->backup.write_function = ZERO_NULL;
> +- ftpwc->backup.file_descriptor = NULL;
> +- wildcard->state = CURLWC_DOWNLOADING;
> +-
> +- if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
> +- /* error found in LIST parsing */
> +- wildcard->state = CURLWC_CLEAN;
> +- return wc_statemach(conn);
> +- }
> +- if(wildcard->filelist.size == 0) {
> +- /* no corresponding file */
> +- wildcard->state = CURLWC_CLEAN;
> +- return CURLE_REMOTE_FILE_NOT_FOUND;
> ++ for(;;) {
> ++ switch(wildcard->state) {
> ++ case CURLWC_INIT:
> ++ result = init_wc_data(conn);
> ++ if(wildcard->state == CURLWC_CLEAN)
> ++ /* only listing! */
> ++ return result;
> ++ wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
> ++ return result;
> ++
> ++ case CURLWC_MATCHING: {
> ++ /* In this state is LIST response successfully parsed, so lets restore
> ++ previous WRITEFUNCTION callback and WRITEDATA pointer */
> ++ struct ftp_wc *ftpwc = wildcard->protdata;
> ++ conn->data->set.fwrite_func = ftpwc->backup.write_function;
> ++ conn->data->set.out = ftpwc->backup.file_descriptor;
> ++ ftpwc->backup.write_function = ZERO_NULL;
> ++ ftpwc->backup.file_descriptor = NULL;
> ++ wildcard->state = CURLWC_DOWNLOADING;
> ++
> ++ if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
> ++ /* error found in LIST parsing */
> ++ wildcard->state = CURLWC_CLEAN;
> ++ continue;
> ++ }
> ++ if(wildcard->filelist.size == 0) {
> ++ /* no corresponding file */
> ++ wildcard->state = CURLWC_CLEAN;
> ++ return CURLE_REMOTE_FILE_NOT_FOUND;
> ++ }
> ++ continue;
> ++
> + }
> +- return wc_statemach(conn);
> +- }
> +
> +- case CURLWC_DOWNLOADING: {
> +- /* filelist has at least one file, lets get first one */
> +- struct ftp_conn *ftpc = &conn->proto.ftpc;
> +- struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ case CURLWC_DOWNLOADING: {
> ++ /* filelist has at least one file, lets get first one */
> ++ struct ftp_conn *ftpc = &conn->proto.ftpc;
> ++ struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
> ++ struct FTP *ftp = conn->data->req.protop;
> +
> + char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
> + if(!tmp_path)
> + return CURLE_OUT_OF_MEMORY;
> +
> +- /* switch default ftp->path and tmp_path */
> +- free(ftp->pathalloc);
> +- ftp->pathalloc = ftp->path = tmp_path;
> +-
> +- infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
> +- if(conn->data->set.chunk_bgn) {
> +- long userresponse;
> +- Curl_set_in_callback(conn->data, true);
> +- userresponse = conn->data->set.chunk_bgn(
> +- finfo, wildcard->customptr, (int)wildcard->filelist.size);
> +- Curl_set_in_callback(conn->data, false);
> +- switch(userresponse) {
> +- case CURL_CHUNK_BGN_FUNC_SKIP:
> +- infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
> +- finfo->filename);
> ++ /* switch default ftp->path and tmp_path */
> ++ free(ftp->pathalloc);
> ++ ftp->pathalloc = ftp->path = tmp_path;
> ++
> ++ infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
> ++ if(conn->data->set.chunk_bgn) {
> ++ long userresponse;
> ++ Curl_set_in_callback(conn->data, true);
> ++ userresponse = conn->data->set.chunk_bgn(
> ++ finfo, wildcard->customptr, (int)wildcard->filelist.size);
> ++ Curl_set_in_callback(conn->data, false);
> ++ switch(userresponse) {
> ++ case CURL_CHUNK_BGN_FUNC_SKIP:
> ++ infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
> ++ finfo->filename);
> ++ wildcard->state = CURLWC_SKIP;
> ++ continue;
> ++ case CURL_CHUNK_BGN_FUNC_FAIL:
> ++ return CURLE_CHUNK_FAILED;
> ++ }
> ++
> ++ }
> ++
> ++ if(finfo->filetype != CURLFILETYPE_FILE) {
> + wildcard->state = CURLWC_SKIP;
> +- return wc_statemach(conn);
> +- case CURL_CHUNK_BGN_FUNC_FAIL:
> +- return CURLE_CHUNK_FAILED;
> ++ continue;
> + }
> ++
> ++ if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
> ++ ftpc->known_filesize = finfo->size;
> ++
> ++ result = ftp_parse_url_path(conn);
> ++ if(result)
> ++ return result;
> ++
> ++ /* we don't need the Curl_fileinfo of first file anymore */
> ++ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
> ++
> ++ if(wildcard->filelist.size == 0) { /* remains only one file to down. */
> ++ wildcard->state = CURLWC_CLEAN;
> ++ /* after that will be ftp_do called once again and no transfer
> ++ will be done because of CURLWC_CLEAN state */
> ++ return CURLE_OK;
> ++ }
> ++ return result;
> + }
> +
> +- if(finfo->filetype != CURLFILETYPE_FILE) {
> +- wildcard->state = CURLWC_SKIP;
> +- return wc_statemach(conn);
> ++ case CURLWC_SKIP: {
> ++ if(conn->data->set.chunk_end) {
> ++ Curl_set_in_callback(conn->data, true);
> ++ conn->data->set.chunk_end(conn->data->wildcard.customptr);
> ++ Curl_set_in_callback(conn->data, false);
> ++ }
> ++ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
> ++ wildcard->state = (wildcard->filelist.size == 0) ?
> ++ CURLWC_CLEAN : CURLWC_DOWNLOADING;
> ++ continue;
> + }
> +
> +- if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
> +- ftpc->known_filesize = finfo->size;
> ++ case CURLWC_CLEAN: {
> ++ struct ftp_wc *ftpwc = wildcard->protdata;
> ++ result = CURLE_OK;
> ++ if(ftpwc)
> ++ result = Curl_ftp_parselist_geterror(ftpwc->parser);
> +
> +- result = ftp_parse_url_path(conn);
> +- if(result)
> ++ wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
> + return result;
> +-
> +- /* we don't need the Curl_fileinfo of first file anymore */
> +- Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
> +-
> +- if(wildcard->filelist.size == 0) { /* remains only one file to down. */
> +- wildcard->state = CURLWC_CLEAN;
> +- /* after that will be ftp_do called once again and no transfer
> +- will be done because of CURLWC_CLEAN state */
> +- return CURLE_OK;
> + }
> +- } break;
> +
> +- case CURLWC_SKIP: {
> +- if(conn->data->set.chunk_end) {
> +- Curl_set_in_callback(conn->data, true);
> +- conn->data->set.chunk_end(conn->data->wildcard.customptr);
> +- Curl_set_in_callback(conn->data, false);
> ++ case CURLWC_DONE:
> ++ case CURLWC_ERROR:
> ++ case CURLWC_CLEAR:
> ++ if(wildcard->dtor)
> ++ wildcard->dtor(wildcard->protdata);
> ++ return result;
> + }
> +- Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
> +- wildcard->state = (wildcard->filelist.size == 0) ?
> +- CURLWC_CLEAN : CURLWC_DOWNLOADING;
> +- return wc_statemach(conn);
> +- }
> +
> +- case CURLWC_CLEAN: {
> +- struct ftp_wc *ftpwc = wildcard->protdata;
> +- result = CURLE_OK;
> +- if(ftpwc)
> +- result = Curl_ftp_parselist_geterror(ftpwc->parser);
> +-
> +- wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
> +- } break;
> +-
> +- case CURLWC_DONE:
> +- case CURLWC_ERROR:
> +- case CURLWC_CLEAR:
> +- if(wildcard->dtor)
> +- wildcard->dtor(wildcard->protdata);
> +- break;
> + }
> +-
> +- return result;
> ++/* UNREACHABLE */
> + }
> +
> + /***********************************************************************
> diff --git a/meta/recipes-support/curl/curl/CVE-2020-8286.patch b/meta/recipes-support/curl/curl/CVE-2020-8286.patch
> new file mode 100644
> index 00000000000..21e72da0206
> --- /dev/null
> +++ b/meta/recipes-support/curl/curl/CVE-2020-8286.patch
> @@ -0,0 +1,138 @@
> +From 5d3b28deac44c19e4d73fc80e4917d42ee43adfe Mon Sep 17 00:00:00 2001
> +From: Daniel Stenberg <daniel@haxx.se>
> +Date: Wed, 2 Dec 2020 23:01:11 +0100
> +Subject: [PATCH] openssl: make the OCSP verification verify the certificate id
> +
> +CVE-2020-8286
> +
> +Reported by anonymous
> +
> +Bug: https://curl.se/docs/CVE-2020-8286.html
> +
> +Upstream-Status: Backport [https://github.com/curl/curl/commit/d9d01672785b]
> +
> +CVE: CVE-2020-8286
> +
> +Signed-off-by: Daniel Stenberg <daniel@haxx.se>
> +Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
> +[Fixup for Dunfell context]
> +Signed-off-by: Armin Kuster <akuster@mvista.com>
> +
> +---
> + lib/vtls/openssl.c | 83 +++++++++++++++++++++++++++++++++++-------------------
> + 1 file changed, 54 insertions(+), 29 deletions(-)
> +
> +Index: curl-7.69.1/lib/vtls/openssl.c
> +===================================================================
> +--- curl-7.69.1.orig/lib/vtls/openssl.c
> ++++ curl-7.69.1/lib/vtls/openssl.c
> +@@ -1717,6 +1717,11 @@ static CURLcode verifystatus(struct conn
> + OCSP_BASICRESP *br = NULL;
> + X509_STORE *st = NULL;
> + STACK_OF(X509) *ch = NULL;
> ++ X509 *cert;
> ++ OCSP_CERTID *id = NULL;
> ++ int cert_status, crl_reason;
> ++ ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
> ++ int ret;
> +
> + long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &status);
> +
> +@@ -1785,43 +1790,63 @@ static CURLcode verifystatus(struct conn
> + goto end;
> + }
> +
> +- for(i = 0; i < OCSP_resp_count(br); i++) {
> +- int cert_status, crl_reason;
> +- OCSP_SINGLERESP *single = NULL;
> +-
> +- ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
> +-
> +- single = OCSP_resp_get0(br, i);
> +- if(!single)
> +- continue;
> +-
> +- cert_status = OCSP_single_get0_status(single, &crl_reason, &rev,
> +- &thisupd, &nextupd);
> +-
> +- if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
> +- failf(data, "OCSP response has expired");
> +- result = CURLE_SSL_INVALIDCERTSTATUS;
> +- goto end;
> ++ /* Compute the certificate's ID */
> ++ cert = SSL_get_peer_certificate(BACKEND->handle);
> ++ if(!cert) {
> ++ failf(data, "Error getting peer certficate");
> ++ result = CURLE_SSL_INVALIDCERTSTATUS;
> ++ goto end;
> ++ }
> ++
> ++ for(i = 0; i < sk_X509_num(ch); i++) {
> ++ X509 *issuer = sk_X509_value(ch, i);
> ++ if(X509_check_issued(issuer, cert) == X509_V_OK) {
> ++ id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
> ++ break;
> + }
> ++ }
> ++ X509_free(cert);
> +
> +- infof(data, "SSL certificate status: %s (%d)\n",
> +- OCSP_cert_status_str(cert_status), cert_status);
> ++ if(!id) {
> ++ failf(data, "Error computing OCSP ID");
> ++ result = CURLE_SSL_INVALIDCERTSTATUS;
> ++ goto end;
> ++ }
> +
> +- switch(cert_status) {
> +- case V_OCSP_CERTSTATUS_GOOD:
> +- break;
> +-
> +- case V_OCSP_CERTSTATUS_REVOKED:
> +- result = CURLE_SSL_INVALIDCERTSTATUS;
> +-
> +- failf(data, "SSL certificate revocation reason: %s (%d)",
> +- OCSP_crl_reason_str(crl_reason), crl_reason);
> +- goto end;
> +-
> +- case V_OCSP_CERTSTATUS_UNKNOWN:
> +- result = CURLE_SSL_INVALIDCERTSTATUS;
> +- goto end;
> +- }
> ++ /* Find the single OCSP response corresponding to the certificate ID */
> ++ ret = OCSP_resp_find_status(br, id, &cert_status, &crl_reason, &rev,
> ++ &thisupd, &nextupd);
> ++ OCSP_CERTID_free(id);
> ++ if(ret != 1) {
> ++ failf(data, "Could not find certificate ID in OCSP response");
> ++ result = CURLE_SSL_INVALIDCERTSTATUS;
> ++ goto end;
> ++ }
> ++
> ++ /* Validate the corresponding single OCSP response */
> ++ if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
> ++ failf(data, "OCSP response has expired");
> ++ result = CURLE_SSL_INVALIDCERTSTATUS;
> ++ goto end;
> ++ }
> ++
> ++ infof(data, "SSL certificate status: %s (%d)\n",
> ++ OCSP_cert_status_str(cert_status), cert_status);
> ++
> ++ switch(cert_status) {
> ++ case V_OCSP_CERTSTATUS_GOOD:
> ++ break;
> ++
> ++ case V_OCSP_CERTSTATUS_REVOKED:
> ++ result = CURLE_SSL_INVALIDCERTSTATUS;
> ++ failf(data, "SSL certificate revocation reason: %s (%d)",
> ++ OCSP_crl_reason_str(crl_reason), crl_reason);
> ++ goto end;
> ++
> ++ case V_OCSP_CERTSTATUS_UNKNOWN:
> ++ default:
> ++ result = CURLE_SSL_INVALIDCERTSTATUS;
> ++ goto end;
> + }
> +
> + end:
> diff --git a/meta/recipes-support/curl/curl_7.69.1.bb b/meta/recipes-support/curl/curl_7.69.1.bb
> index 239852db09c..c0db01ac5d0 100644
> --- a/meta/recipes-support/curl/curl_7.69.1.bb
> +++ b/meta/recipes-support/curl/curl_7.69.1.bb
> @@ -9,6 +9,9 @@ SRC_URI = "https://curl.haxx.se/download/curl-${PV}.tar.bz2 \
> file://0001-replace-krb5-config-with-pkg-config.patch \
> file://CVE-2020-8169.patch \
> file://CVE-2020-8177.patch \
> + file://CVE-2020-8284.patch \
> + file://CVE-2020-8285.patch \
> + file://CVE-2020-8286.patch \
> "
>
> SRC_URI[md5sum] = "ec5fc263f898a3dfef08e805f1ecca42"
> --
> 2.17.1
>
>
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [OE-core] [dunfell][PATCH 1/2] curl: Fix CVE-2020-8284, CVE-2020-8285, CVE-2020-8286
2021-01-15 18:02 [dunfell][PATCH 1/2] curl: Fix CVE-2020-8284, CVE-2020-8285, CVE-2020-8286 akuster
2021-01-15 18:02 ` [dunfell][PATCH 2/2] curl: Security fix for CVE-2020-8231 akuster
2021-01-15 18:16 ` [OE-core] [dunfell][PATCH 1/2] curl: Fix CVE-2020-8284, CVE-2020-8285, CVE-2020-8286 Steve Sakoman
@ 2021-01-15 18:25 ` Steve Sakoman
2 siblings, 0 replies; 4+ messages in thread
From: Steve Sakoman @ 2021-01-15 18:25 UTC (permalink / raw)
To: akuster
Cc: Patches and discussions about the oe-core layer,
Khairul Rohaizzat Jamaluddin, Anuj Mittal
I've already merged "curl: fix CVE-2020-8231/8284/8285/8286" from Lee
Chee Yang <chee.yang.lee@intel.com>, so these CVE's are already taken
care of!
Steve
On Fri, Jan 15, 2021 at 8:03 AM akuster <akuster808@gmail.com> wrote:
>
> From: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
>
> Source: git.openembedded.org
> MR: 107592, 107620, 107606
> Type: Security Fix
> Disposition: Backport from https://git.openembedded.org/openembedded-core-contrib/commit/?h=anujm/gatesgarth&id=f1a0ea55c0ae2cce7f7c3c6c73f57c5b8222c860
> ChangeID: 8d65a5974018f276bef9054cbbdcd5a2a5f0a154
> Description:
>
> Backport the CVE patches from upstream
> https://github.com/curl/curl/commit/ec9cc725d598ac
> https://github.com/curl/curl/commit/a95a6ce6b809693a1195e3b4347a6cfa0fbc2ee7
> https://github.com/curl/curl/commit/69a358f2186e04
> https://github.com/curl/curl/commit/d9d01672785b.patch
>
> 0002-remove-void-protop-create-union-p.patch is added because the CVE-2020-8285 fix is
> dependent on it.
>
> CVE:
> CVE-2020-8284
> CVE-2020-8285
> CVE-2020-8286
>
> Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
> Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
> Signed-off-by: Armin Kuster <akuster808@gmail.com>
> ---
> ...02-remove-void-protop-create-union-p.patch | 1609 +++++++++++++++++
> .../curl/curl/CVE-2020-8284.patch | 210 +++
> .../curl/curl/CVE-2020-8285.patch | 261 +++
> .../curl/curl/CVE-2020-8286.patch | 138 ++
> meta/recipes-support/curl/curl_7.69.1.bb | 3 +
> 5 files changed, 2221 insertions(+)
> create mode 100644 meta/recipes-support/curl/curl/0002-remove-void-protop-create-union-p.patch
> create mode 100644 meta/recipes-support/curl/curl/CVE-2020-8284.patch
> create mode 100644 meta/recipes-support/curl/curl/CVE-2020-8285.patch
> create mode 100644 meta/recipes-support/curl/curl/CVE-2020-8286.patch
>
> diff --git a/meta/recipes-support/curl/curl/0002-remove-void-protop-create-union-p.patch b/meta/recipes-support/curl/curl/0002-remove-void-protop-create-union-p.patch
> new file mode 100644
> index 00000000000..d0d01fb97cb
> --- /dev/null
> +++ b/meta/recipes-support/curl/curl/0002-remove-void-protop-create-union-p.patch
> @@ -0,0 +1,1609 @@
> +From bfdb7ee65fc8b96f1fce10ef23871acb092b74b6 Mon Sep 17 00:00:00 2001
> +From: Daniel Stenberg <daniel@haxx.se>
> +Date: Mon, 23 Nov 2020 08:32:41 +0100
> +Subject: [PATCH] urldata: remove 'void *protop' and create the union 'p'
> +
> +... to avoid the use of 'void *' for the protocol specific structs done
> +per transfer.
> +
> +Closes #6238
> +
> +Upstream-Status: Backport [https://github.com/curl/curl/commit/a95a6ce6b809693a1195e3b4347a6cfa0fbc2ee7]
> +
> +CVE: CVE-2020-8285
> +
> +Signed-off-by: Daniel Stenberg <daniel@haxx.se>
> +Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
> +
> +---
> + docs/INTERNALS.md | 4 ++--
> + lib/file.c | 14 +++++++-------
> + lib/ftp.c | 36 ++++++++++++++++++------------------
> + lib/http.c | 14 +++++++-------
> + lib/http2.c | 50 +++++++++++++++++++++++++-------------------------
> + lib/http_proxy.c | 6 +++---
> + lib/imap.c | 26 +++++++++++++-------------
> + lib/mqtt.c | 10 +++++-----
> + lib/openldap.c | 8 ++++----
> + lib/pop3.c | 14 +++++++-------
> + lib/rtsp.c | 8 ++++----
> + lib/smb.c | 20 ++++++++++----------
> + lib/smtp.c | 22 +++++++++++-----------
> + lib/telnet.c | 30 +++++++++++++++---------------
> + lib/transfer.c | 8 ++++----
> + lib/url.c | 2 +-
> + lib/urldata.h | 19 +++++++++++++++++--
> + lib/vquic/ngtcp2.c | 24 ++++++++++++------------
> + lib/vquic/quiche.c | 10 +++++-----
> + lib/vssh/libssh.c | 10 +++++-----
> + lib/vssh/libssh2.c | 8 ++++----
> + lib/vssh/wolfssh.c | 8 ++++----
> + 22 files changed, 183 insertions(+), 168 deletions(-)
> +
> +diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md
> +index 635e7b2..ca8988e 100644
> +--- a/docs/INTERNALS.md
> ++++ b/docs/INTERNALS.md
> +@@ -980,8 +980,8 @@ for older and later versions as things don't change drastically that often.
> + protocol specific data that then gets associated with that `Curl_easy` for
> + the rest of this transfer. It gets freed again at the end of the transfer.
> + It will be called before the `connectdata` for the transfer has been
> +- selected/created. Most protocols will allocate its private
> +- `struct [PROTOCOL]` here and assign `Curl_easy->req.protop` to point to it.
> ++ selected/created. Most protocols will allocate its private `struct
> ++ [PROTOCOL]` here and assign `Curl_easy->req.p.[protocol]` to it.
> +
> + `->connect_it` allows a protocol to do some specific actions after the TCP
> + connect is done, that can still be considered part of the connection phase.
> +diff --git a/lib/file.c b/lib/file.c
> +index cd3e49c..110e5c2 100644
> +--- a/lib/file.c
> ++++ b/lib/file.c
> +@@ -119,8 +119,8 @@ const struct Curl_handler Curl_handler_file = {
> + static CURLcode file_setup_connection(struct connectdata *conn)
> + {
> + /* allocate the FILE specific struct */
> +- conn->data->req.protop = calloc(1, sizeof(struct FILEPROTO));
> +- if(!conn->data->req.protop)
> ++ conn->data->req.p.file = calloc(1, sizeof(struct FILEPROTO));
> ++ if(!conn->data->req.p.file)
> + return CURLE_OUT_OF_MEMORY;
> +
> + return CURLE_OK;
> +@@ -135,7 +135,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
> + {
> + struct Curl_easy *data = conn->data;
> + char *real_path;
> +- struct FILEPROTO *file = data->req.protop;
> ++ struct FILEPROTO *file = data->req.p.file;
> + int fd;
> + #ifdef DOS_FILESYSTEM
> + size_t i;
> +@@ -209,7 +209,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
> + static CURLcode file_done(struct connectdata *conn,
> + CURLcode status, bool premature)
> + {
> +- struct FILEPROTO *file = conn->data->req.protop;
> ++ struct FILEPROTO *file = conn->data->req.p.file;
> + (void)status; /* not used */
> + (void)premature; /* not used */
> +
> +@@ -227,7 +227,7 @@ static CURLcode file_done(struct connectdata *conn,
> + static CURLcode file_disconnect(struct connectdata *conn,
> + bool dead_connection)
> + {
> +- struct FILEPROTO *file = conn->data->req.protop;
> ++ struct FILEPROTO *file = conn->data->req.p.file;
> + (void)dead_connection; /* not used */
> +
> + if(file) {
> +@@ -249,7 +249,7 @@ static CURLcode file_disconnect(struct connectdata *conn,
> +
> + static CURLcode file_upload(struct connectdata *conn)
> + {
> +- struct FILEPROTO *file = conn->data->req.protop;
> ++ struct FILEPROTO *file = conn->data->req.p.file;
> + const char *dir = strchr(file->path, DIRSEP);
> + int fd;
> + int mode;
> +@@ -391,7 +391,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
> + if(data->set.upload)
> + return file_upload(conn);
> +
> +- file = conn->data->req.protop;
> ++ file = conn->data->req.p.file;
> +
> + /* get the fd from the connection phase */
> + fd = file->fd;
> +diff --git a/lib/ftp.c b/lib/ftp.c
> +index 9fadac5..d1a9447 100644
> +--- a/lib/ftp.c
> ++++ b/lib/ftp.c
> +@@ -1345,7 +1345,7 @@ static CURLcode ftp_state_use_pasv(struct connectdata *conn)
> + static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + struct Curl_easy *data = conn->data;
> +
> + if(ftp->transfer != FTPTRANSFER_BODY) {
> +@@ -1388,7 +1388,7 @@ static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
> + static CURLcode ftp_state_rest(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> +
> + if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
> +@@ -1409,7 +1409,7 @@ static CURLcode ftp_state_rest(struct connectdata *conn)
> + static CURLcode ftp_state_size(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> +
> + if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
> +@@ -1430,7 +1430,7 @@ static CURLcode ftp_state_list(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> +
> + /* If this output is to be machine-parsed, the NLST command might be better
> + to use, since the LIST command output is not specified or standard in any
> +@@ -1508,7 +1508,7 @@ static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
> + static CURLcode ftp_state_type(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + struct Curl_easy *data = conn->data;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> +
> +@@ -1565,7 +1565,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
> + bool sizechecked)
> + {
> + CURLcode result = CURLE_OK;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + struct Curl_easy *data = conn->data;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> +
> +@@ -1664,7 +1664,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> + bool quote = FALSE;
> + struct curl_slist *item;
> +@@ -2033,7 +2033,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> +
> + switch(ftpcode) {
> +@@ -2166,7 +2166,7 @@ static CURLcode ftp_state_retr(struct connectdata *conn,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> +
> + if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
> +@@ -2378,7 +2378,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> +
> + if((ftpcode == 150) || (ftpcode == 125)) {
> +
> +@@ -3138,7 +3138,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
> + bool premature)
> + {
> + struct Curl_easy *data = conn->data;
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> + struct pingpong *pp = &ftpc->pp;
> + ssize_t nread;
> +@@ -3492,7 +3492,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
> + bool complete = FALSE;
> +
> + /* the ftp struct is inited in ftp_connect() */
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> +
> + /* if the second connection isn't done yet, wait for it */
> + if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
> +@@ -3657,7 +3657,7 @@ CURLcode ftp_perform(struct connectdata *conn,
> +
> + if(conn->data->set.opt_no_body) {
> + /* requested no body means no transfer... */
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + ftp->transfer = FTPTRANSFER_INFO;
> + }
> +
> +@@ -3692,7 +3692,7 @@ static void wc_data_dtor(void *ptr)
> + static CURLcode init_wc_data(struct connectdata *conn)
> + {
> + char *last_slash;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + char *path = ftp->path;
> + struct WildcardData *wildcard = &(conn->data->wildcard);
> + CURLcode result = CURLE_OK;
> +@@ -3826,7 +3826,7 @@ static CURLcode wc_statemach(struct connectdata *conn)
> + /* filelist has at least one file, lets get first one */
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> + struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> +
> + char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
> + if(!tmp_path)
> +@@ -4099,7 +4099,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
> + {
> + struct Curl_easy *data = conn->data;
> + /* the ftp struct is already inited in ftp_connect() */
> +- struct FTP *ftp = data->req.protop;
> ++ struct FTP *ftp = data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> + const char *slashPos = NULL;
> + const char *fileName = NULL;
> +@@ -4244,7 +4244,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
> + static CURLcode ftp_dophase_done(struct connectdata *conn,
> + bool connected)
> + {
> +- struct FTP *ftp = conn->data->req.protop;
> ++ struct FTP *ftp = conn->data->req.p.ftp;
> + struct ftp_conn *ftpc = &conn->proto.ftpc;
> +
> + if(connected) {
> +@@ -4341,7 +4341,7 @@ static CURLcode ftp_setup_connection(struct connectdata *conn)
> + char *type;
> + struct FTP *ftp;
> +
> +- conn->data->req.protop = ftp = calloc(sizeof(struct FTP), 1);
> ++ conn->data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1);
> + if(NULL == ftp)
> + return CURLE_OUT_OF_MEMORY;
> +
> +diff --git a/lib/http.c b/lib/http.c
> +index 8fcdd43..31d9112 100644
> +--- a/lib/http.c
> ++++ b/lib/http.c
> +@@ -162,14 +162,14 @@ static CURLcode http_setup_conn(struct connectdata *conn)
> + during this request */
> + struct HTTP *http;
> + struct Curl_easy *data = conn->data;
> +- DEBUGASSERT(data->req.protop == NULL);
> ++ DEBUGASSERT(data->req.p.http == NULL);
> +
> + http = calloc(1, sizeof(struct HTTP));
> + if(!http)
> + return CURLE_OUT_OF_MEMORY;
> +
> + Curl_mime_initpart(&http->form, conn->data);
> +- data->req.protop = http;
> ++ data->req.p.http = http;
> +
> + if(data->set.httpversion == CURL_HTTP_VERSION_3) {
> + if(conn->handler->flags & PROTOPT_SSL)
> +@@ -425,7 +425,7 @@ static bool pickoneauth(struct auth *pick, unsigned long mask)
> + static CURLcode http_perhapsrewind(struct connectdata *conn)
> + {
> + struct Curl_easy *data = conn->data;
> +- struct HTTP *http = data->req.protop;
> ++ struct HTTP *http = data->req.p.http;
> + curl_off_t bytessent;
> + curl_off_t expectsend = -1; /* default is unknown */
> +
> +@@ -1109,7 +1109,7 @@ static size_t readmoredata(char *buffer,
> + void *userp)
> + {
> + struct connectdata *conn = (struct connectdata *)userp;
> +- struct HTTP *http = conn->data->req.protop;
> ++ struct HTTP *http = conn->data->req.p.http;
> + size_t fullsize = size * nitems;
> +
> + if(!http->postsize)
> +@@ -1167,7 +1167,7 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
> + char *ptr;
> + size_t size;
> + struct Curl_easy *data = conn->data;
> +- struct HTTP *http = data->req.protop;
> ++ struct HTTP *http = data->req.p.http;
> + size_t sendsize;
> + curl_socket_t sockfd;
> + size_t headersize;
> +@@ -1517,7 +1517,7 @@ CURLcode Curl_http_done(struct connectdata *conn,
> + CURLcode status, bool premature)
> + {
> + struct Curl_easy *data = conn->data;
> +- struct HTTP *http = data->req.protop;
> ++ struct HTTP *http = data->req.p.http;
> +
> + /* Clear multipass flag. If authentication isn't done yet, then it will get
> + * a chance to be set back to true when we output the next auth header */
> +@@ -1978,7 +1978,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
> + return result;
> + }
> + }
> +- http = data->req.protop;
> ++ http = data->req.p.http;
> + DEBUGASSERT(http);
> +
> + if(!data->state.this_is_a_follow) {
> +diff --git a/lib/http2.c b/lib/http2.c
> +index d316da8..c41a1c2 100644
> +--- a/lib/http2.c
> ++++ b/lib/http2.c
> +@@ -257,7 +257,7 @@ static unsigned int http2_conncheck(struct connectdata *check,
> + /* called from http_setup_conn */
> + void Curl_http2_setup_req(struct Curl_easy *data)
> + {
> +- struct HTTP *http = data->req.protop;
> ++ struct HTTP *http = data->req.p.http;
> + http->bodystarted = FALSE;
> + http->status_code = -1;
> + http->pausedata = NULL;
> +@@ -391,7 +391,7 @@ char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
> + if(!h || !GOOD_EASY_HANDLE(h->data))
> + return NULL;
> + else {
> +- struct HTTP *stream = h->data->req.protop;
> ++ struct HTTP *stream = h->data->req.p.http;
> + if(num < stream->push_headers_used)
> + return stream->push_headers[num];
> + }
> +@@ -413,7 +413,7 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
> + !strcmp(header, ":") || strchr(header + 1, ':'))
> + return NULL;
> + else {
> +- struct HTTP *stream = h->data->req.protop;
> ++ struct HTTP *stream = h->data->req.p.http;
> + size_t len = strlen(header);
> + size_t i;
> + for(i = 0; i<stream->push_headers_used; i++) {
> +@@ -460,7 +460,7 @@ static struct Curl_easy *duphandle(struct Curl_easy *data)
> + (void)Curl_close(&second);
> + }
> + else {
> +- second->req.protop = http;
> ++ second->req.p.http = http;
> + Curl_dyn_init(&http->header_recvbuf, DYN_H2_HEADERS);
> + Curl_http2_setup_req(second);
> + second->state.stream_weight = data->state.stream_weight;
> +@@ -537,7 +537,7 @@ static int push_promise(struct Curl_easy *data,
> + /* ask the application */
> + H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!\n"));
> +
> +- stream = data->req.protop;
> ++ stream = data->req.p.http;
> + if(!stream) {
> + failf(data, "Internal NULL stream!\n");
> + (void)Curl_close(&newhandle);
> +@@ -567,13 +567,13 @@ static int push_promise(struct Curl_easy *data,
> + if(rv) {
> + DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
> + /* denied, kill off the new handle again */
> +- http2_stream_free(newhandle->req.protop);
> +- newhandle->req.protop = NULL;
> ++ http2_stream_free(newhandle->req.p.http);
> ++ newhandle->req.p.http = NULL;
> + (void)Curl_close(&newhandle);
> + goto fail;
> + }
> +
> +- newstream = newhandle->req.protop;
> ++ newstream = newhandle->req.p.http;
> + newstream->stream_id = frame->promised_stream_id;
> + newhandle->req.maxdownload = -1;
> + newhandle->req.size = -1;
> +@@ -583,8 +583,8 @@ static int push_promise(struct Curl_easy *data,
> + rc = Curl_multi_add_perform(data->multi, newhandle, conn);
> + if(rc) {
> + infof(data, "failed to add handle to multi\n");
> +- http2_stream_free(newhandle->req.protop);
> +- newhandle->req.protop = NULL;
> ++ http2_stream_free(newhandle->req.p.http);
> ++ newhandle->req.p.http = NULL;
> + Curl_close(&newhandle);
> + rv = CURL_PUSH_DENY;
> + goto fail;
> +@@ -667,7 +667,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
> + return 0;
> + }
> +
> +- stream = data_s->req.protop;
> ++ stream = data_s->req.p.http;
> + if(!stream) {
> + H2BUGF(infof(data_s, "No proto pointer for stream: %x\n",
> + stream_id));
> +@@ -783,7 +783,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
> + internal error more than anything else! */
> + return NGHTTP2_ERR_CALLBACK_FAILURE;
> +
> +- stream = data_s->req.protop;
> ++ stream = data_s->req.p.http;
> + if(!stream)
> + return NGHTTP2_ERR_CALLBACK_FAILURE;
> +
> +@@ -849,7 +849,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
> + }
> + H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
> + nghttp2_http2_strerror(error_code), error_code, stream_id));
> +- stream = data_s->req.protop;
> ++ stream = data_s->req.p.http;
> + if(!stream)
> + return NGHTTP2_ERR_CALLBACK_FAILURE;
> +
> +@@ -894,7 +894,7 @@ static int on_begin_headers(nghttp2_session *session,
> + return 0;
> + }
> +
> +- stream = data_s->req.protop;
> ++ stream = data_s->req.p.http;
> + if(!stream || !stream->bodystarted) {
> + return 0;
> + }
> +@@ -952,7 +952,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
> + internal error more than anything else! */
> + return NGHTTP2_ERR_CALLBACK_FAILURE;
> +
> +- stream = data_s->req.protop;
> ++ stream = data_s->req.p.http;
> + if(!stream) {
> + failf(data_s, "Internal NULL stream! 5\n");
> + return NGHTTP2_ERR_CALLBACK_FAILURE;
> +@@ -1100,7 +1100,7 @@ static ssize_t data_source_read_callback(nghttp2_session *session,
> + internal error more than anything else! */
> + return NGHTTP2_ERR_CALLBACK_FAILURE;
> +
> +- stream = data_s->req.protop;
> ++ stream = data_s->req.p.http;
> + if(!stream)
> + return NGHTTP2_ERR_CALLBACK_FAILURE;
> + }
> +@@ -1161,7 +1161,7 @@ static void populate_settings(struct connectdata *conn,
> +
> + void Curl_http2_done(struct Curl_easy *data, bool premature)
> + {
> +- struct HTTP *http = data->req.protop;
> ++ struct HTTP *http = data->req.p.http;
> + struct http_conn *httpc = &data->conn->proto.httpc;
> +
> + /* there might be allocated resources done before this got the 'h2' pointer
> +@@ -1398,7 +1398,7 @@ CURLcode Curl_http2_done_sending(struct connectdata *conn)
> + (conn->handler == &Curl_handler_http2)) {
> + /* make sure this is only attempted for HTTP/2 transfers */
> +
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> +
> + struct http_conn *httpc = &conn->proto.httpc;
> + nghttp2_session *h2 = httpc->h2;
> +@@ -1522,7 +1522,7 @@ static void h2_pri_spec(struct Curl_easy *data,
> + nghttp2_priority_spec *pri_spec)
> + {
> + struct HTTP *depstream = (data->set.stream_depends_on?
> +- data->set.stream_depends_on->req.protop:NULL);
> ++ data->set.stream_depends_on->req.p.http:NULL);
> + int32_t depstream_id = depstream? depstream->stream_id:0;
> + nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight,
> + data->set.stream_depends_e);
> +@@ -1539,7 +1539,7 @@ static void h2_pri_spec(struct Curl_easy *data,
> + static int h2_session_send(struct Curl_easy *data,
> + nghttp2_session *h2)
> + {
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + if((data->set.stream_weight != data->state.stream_weight) ||
> + (data->set.stream_depends_e != data->state.stream_depends_e) ||
> + (data->set.stream_depends_on != data->state.stream_depends_on) ) {
> +@@ -1569,7 +1569,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
> + ssize_t nread;
> + struct http_conn *httpc = &conn->proto.httpc;
> + struct Curl_easy *data = conn->data;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> +
> + (void)sockindex; /* we always do HTTP2 on sockindex 0 */
> +
> +@@ -1874,7 +1874,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
> + */
> + int rv;
> + struct http_conn *httpc = &conn->proto.httpc;
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> + nghttp2_nv *nva = NULL;
> + size_t nheader;
> + size_t i;
> +@@ -2183,7 +2183,7 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
> + {
> + CURLcode result;
> + struct http_conn *httpc = &conn->proto.httpc;
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> +
> + DEBUGASSERT(conn->data->state.buffer);
> +
> +@@ -2238,7 +2238,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
> + int rv;
> + ssize_t nproc;
> + struct Curl_easy *data = conn->data;
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> +
> + result = Curl_http2_setup(conn);
> + if(result)
> +@@ -2358,7 +2358,7 @@ CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
> + return CURLE_OK;
> + #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
> + else {
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + struct http_conn *httpc = &data->conn->proto.httpc;
> + uint32_t window = !pause * HTTP2_HUGE_WINDOW_SIZE;
> + int rv = nghttp2_session_set_local_window_size(httpc->h2,
> +diff --git a/lib/http_proxy.c b/lib/http_proxy.c
> +index f188cbf..69aacb4 100644
> +--- a/lib/http_proxy.c
> ++++ b/lib/http_proxy.c
> +@@ -102,9 +102,9 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
> + * This function might be called several times in the multi interface case
> + * if the proxy's CONNECT response is not instant.
> + */
> +- prot_save = conn->data->req.protop;
> ++ prot_save = conn->data->req.p.http;
> + memset(&http_proxy, 0, sizeof(http_proxy));
> +- conn->data->req.protop = &http_proxy;
> ++ conn->data->req.p.http = &http_proxy;
> + connkeep(conn, "HTTP proxy CONNECT");
> +
> + /* for the secondary socket (FTP), use the "connect to host"
> +@@ -125,7 +125,7 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
> + else
> + remote_port = conn->remote_port;
> + result = Curl_proxyCONNECT(conn, sockindex, hostname, remote_port);
> +- conn->data->req.protop = prot_save;
> ++ conn->data->req.p.http = prot_save;
> + if(CURLE_OK != result)
> + return result;
> + Curl_safefree(data->state.aptr.proxyuserpwd);
> +diff --git a/lib/imap.c b/lib/imap.c
> +index cad0e59..bda23a5 100644
> +--- a/lib/imap.c
> ++++ b/lib/imap.c
> +@@ -244,7 +244,7 @@ static bool imap_matchresp(const char *line, size_t len, const char *cmd)
> + static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
> + int *resp)
> + {
> +- struct IMAP *imap = conn->data->req.protop;
> ++ struct IMAP *imap = conn->data->req.p.imap;
> + struct imap_conn *imapc = &conn->proto.imapc;
> + const char *id = imapc->resptag;
> + size_t id_len = strlen(id);
> +@@ -605,7 +605,7 @@ static CURLcode imap_perform_list(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = data->req.protop;
> ++ struct IMAP *imap = data->req.p.imap;
> +
> + if(imap->custom)
> + /* Send the custom request */
> +@@ -640,7 +640,7 @@ static CURLcode imap_perform_select(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = data->req.protop;
> ++ struct IMAP *imap = data->req.p.imap;
> + struct imap_conn *imapc = &conn->proto.imapc;
> + char *mailbox;
> +
> +@@ -679,7 +679,7 @@ static CURLcode imap_perform_select(struct connectdata *conn)
> + static CURLcode imap_perform_fetch(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> +- struct IMAP *imap = conn->data->req.protop;
> ++ struct IMAP *imap = conn->data->req.p.imap;
> + /* Check we have a UID */
> + if(imap->uid) {
> +
> +@@ -727,7 +727,7 @@ static CURLcode imap_perform_append(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = data->req.protop;
> ++ struct IMAP *imap = data->req.p.imap;
> + char *mailbox;
> +
> + /* Check we have a mailbox */
> +@@ -797,7 +797,7 @@ static CURLcode imap_perform_append(struct connectdata *conn)
> + static CURLcode imap_perform_search(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> +- struct IMAP *imap = conn->data->req.protop;
> ++ struct IMAP *imap = conn->data->req.p.imap;
> +
> + /* Check we have a query string */
> + if(!imap->query) {
> +@@ -1051,7 +1051,7 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = conn->data->req.protop;
> ++ struct IMAP *imap = conn->data->req.p.imap;
> + struct imap_conn *imapc = &conn->proto.imapc;
> + const char *line = data->state.buffer;
> +
> +@@ -1380,7 +1380,7 @@ static CURLcode imap_init(struct connectdata *conn)
> + struct Curl_easy *data = conn->data;
> + struct IMAP *imap;
> +
> +- imap = data->req.protop = calloc(sizeof(struct IMAP), 1);
> ++ imap = data->req.p.imap = calloc(sizeof(struct IMAP), 1);
> + if(!imap)
> + result = CURLE_OUT_OF_MEMORY;
> +
> +@@ -1457,7 +1457,7 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = data->req.protop;
> ++ struct IMAP *imap = data->req.p.imap;
> +
> + (void)premature;
> +
> +@@ -1517,7 +1517,7 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected,
> + /* This is IMAP and no proxy */
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = data->req.protop;
> ++ struct IMAP *imap = data->req.p.imap;
> + struct imap_conn *imapc = &conn->proto.imapc;
> + bool selected = FALSE;
> +
> +@@ -1640,7 +1640,7 @@ static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
> + /* Call this when the DO phase has completed */
> + static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
> + {
> +- struct IMAP *imap = conn->data->req.protop;
> ++ struct IMAP *imap = conn->data->req.p.imap;
> +
> + (void)connected;
> +
> +@@ -1942,7 +1942,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
> + /* The imap struct is already initialised in imap_connect() */
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = data->req.protop;
> ++ struct IMAP *imap = data->req.p.imap;
> + const char *begin = &data->state.up.path[1]; /* skip leading slash */
> + const char *ptr = begin;
> +
> +@@ -2074,7 +2074,7 @@ static CURLcode imap_parse_custom_request(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct IMAP *imap = data->req.protop;
> ++ struct IMAP *imap = data->req.p.imap;
> + const char *custom = data->set.str[STRING_CUSTOMREQUEST];
> +
> + if(custom) {
> +diff --git a/lib/mqtt.c b/lib/mqtt.c
> +index f6f4416..86b22b8 100644
> +--- a/lib/mqtt.c
> ++++ b/lib/mqtt.c
> +@@ -95,12 +95,12 @@ static CURLcode mqtt_setup_conn(struct connectdata *conn)
> + during this request */
> + struct MQTT *mq;
> + struct Curl_easy *data = conn->data;
> +- DEBUGASSERT(data->req.protop == NULL);
> ++ DEBUGASSERT(data->req.p.mqtt == NULL);
> +
> + mq = calloc(1, sizeof(struct MQTT));
> + if(!mq)
> + return CURLE_OUT_OF_MEMORY;
> +- data->req.protop = mq;
> ++ data->req.p.mqtt = mq;
> + return CURLE_OK;
> + }
> +
> +@@ -110,7 +110,7 @@ static CURLcode mqtt_send(struct connectdata *conn,
> + CURLcode result = CURLE_OK;
> + curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
> + struct Curl_easy *data = conn->data;
> +- struct MQTT *mq = data->req.protop;
> ++ struct MQTT *mq = data->req.p.mqtt;
> + ssize_t n;
> + result = Curl_write(conn, sockfd, buf, len, &n);
> + if(!result && data->set.verbose)
> +@@ -426,7 +426,7 @@ static CURLcode mqtt_read_publish(struct connectdata *conn,
> + unsigned char *pkt = (unsigned char *)data->state.buffer;
> + size_t remlen;
> + struct mqtt_conn *mqtt = &conn->proto.mqtt;
> +- struct MQTT *mq = data->req.protop;
> ++ struct MQTT *mq = data->req.p.mqtt;
> + unsigned char packet;
> +
> + switch(mqtt->state) {
> +@@ -533,7 +533,7 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
> + CURLcode result = CURLE_OK;
> + struct mqtt_conn *mqtt = &conn->proto.mqtt;
> + struct Curl_easy *data = conn->data;
> +- struct MQTT *mq = data->req.protop;
> ++ struct MQTT *mq = data->req.p.mqtt;
> + ssize_t nread;
> + curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
> + unsigned char *pkt = (unsigned char *)data->state.buffer;
> +diff --git a/lib/openldap.c b/lib/openldap.c
> +index 782d6a0..c955df6 100644
> +--- a/lib/openldap.c
> ++++ b/lib/openldap.c
> +@@ -410,7 +410,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
> + if(!lr)
> + return CURLE_OUT_OF_MEMORY;
> + lr->msgid = msgid;
> +- data->req.protop = lr;
> ++ data->req.p.ldap = lr;
> + Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
> + *done = TRUE;
> + return CURLE_OK;
> +@@ -419,7 +419,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
> + static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
> + bool premature)
> + {
> +- struct ldapreqinfo *lr = conn->data->req.protop;
> ++ struct ldapreqinfo *lr = conn->data->req.p.ldap;
> +
> + (void)res;
> + (void)premature;
> +@@ -431,7 +431,7 @@ static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
> + ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
> + lr->msgid = 0;
> + }
> +- conn->data->req.protop = NULL;
> ++ conn->data->req.p.ldap = NULL;
> + free(lr);
> + }
> +
> +@@ -443,7 +443,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
> + {
> + struct ldapconninfo *li = conn->proto.ldapc;
> + struct Curl_easy *data = conn->data;
> +- struct ldapreqinfo *lr = data->req.protop;
> ++ struct ldapreqinfo *lr = data->req.p.ldap;
> + int rc, ret;
> + LDAPMessage *msg = NULL;
> + LDAPMessage *ent;
> +diff --git a/lib/pop3.c b/lib/pop3.c
> +index 9ff5c78..04cc887 100644
> +--- a/lib/pop3.c
> ++++ b/lib/pop3.c
> +@@ -551,7 +551,7 @@ static CURLcode pop3_perform_command(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct POP3 *pop3 = data->req.protop;
> ++ struct POP3 *pop3 = data->req.p.pop3;
> + const char *command = NULL;
> +
> + /* Calculate the default command */
> +@@ -884,7 +884,7 @@ static CURLcode pop3_state_command_resp(struct connectdata *conn,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct POP3 *pop3 = data->req.protop;
> ++ struct POP3 *pop3 = data->req.p.pop3;
> + struct pop3_conn *pop3c = &conn->proto.pop3c;
> + struct pingpong *pp = &pop3c->pp;
> +
> +@@ -1046,7 +1046,7 @@ static CURLcode pop3_init(struct connectdata *conn)
> + struct Curl_easy *data = conn->data;
> + struct POP3 *pop3;
> +
> +- pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
> ++ pop3 = data->req.p.pop3 = calloc(sizeof(struct POP3), 1);
> + if(!pop3)
> + result = CURLE_OUT_OF_MEMORY;
> +
> +@@ -1120,7 +1120,7 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct POP3 *pop3 = data->req.protop;
> ++ struct POP3 *pop3 = data->req.p.pop3;
> +
> + (void)premature;
> +
> +@@ -1154,7 +1154,7 @@ static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
> + {
> + /* This is POP3 and no proxy */
> + CURLcode result = CURLE_OK;
> +- struct POP3 *pop3 = conn->data->req.protop;
> ++ struct POP3 *pop3 = conn->data->req.p.pop3;
> +
> + DEBUGF(infof(conn->data, "DO phase starts\n"));
> +
> +@@ -1386,7 +1386,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn)
> + {
> + /* The POP3 struct is already initialised in pop3_connect() */
> + struct Curl_easy *data = conn->data;
> +- struct POP3 *pop3 = data->req.protop;
> ++ struct POP3 *pop3 = data->req.p.pop3;
> + const char *path = &data->state.up.path[1]; /* skip leading path */
> +
> + /* URL decode the path for the message ID */
> +@@ -1403,7 +1403,7 @@ static CURLcode pop3_parse_custom_request(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct POP3 *pop3 = data->req.protop;
> ++ struct POP3 *pop3 = data->req.p.pop3;
> + const char *custom = data->set.str[STRING_CUSTOMREQUEST];
> +
> + /* URL decode the custom request */
> +diff --git a/lib/rtsp.c b/lib/rtsp.c
> +index dbd7dc6..29e6d58 100644
> +--- a/lib/rtsp.c
> ++++ b/lib/rtsp.c
> +@@ -114,7 +114,7 @@ static CURLcode rtsp_setup_connection(struct connectdata *conn)
> + {
> + struct RTSP *rtsp;
> +
> +- conn->data->req.protop = rtsp = calloc(1, sizeof(struct RTSP));
> ++ conn->data->req.p.rtsp = rtsp = calloc(1, sizeof(struct RTSP));
> + if(!rtsp)
> + return CURLE_OUT_OF_MEMORY;
> +
> +@@ -199,7 +199,7 @@ static CURLcode rtsp_done(struct connectdata *conn,
> + CURLcode status, bool premature)
> + {
> + struct Curl_easy *data = conn->data;
> +- struct RTSP *rtsp = data->req.protop;
> ++ struct RTSP *rtsp = data->req.p.rtsp;
> + CURLcode httpStatus;
> +
> + /* Bypass HTTP empty-reply checks on receive */
> +@@ -232,7 +232,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
> + struct Curl_easy *data = conn->data;
> + CURLcode result = CURLE_OK;
> + Curl_RtspReq rtspreq = data->set.rtspreq;
> +- struct RTSP *rtsp = data->req.protop;
> ++ struct RTSP *rtsp = data->req.p.rtsp;
> + struct dynbuf req_buffer;
> + curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */
> + curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */
> +@@ -764,7 +764,7 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
> + /* Store the received CSeq. Match is verified in rtsp_done */
> + int nc = sscanf(&header[4], ": %ld", &CSeq);
> + if(nc == 1) {
> +- struct RTSP *rtsp = data->req.protop;
> ++ struct RTSP *rtsp = data->req.p.rtsp;
> + rtsp->CSeq_recv = CSeq; /* mark the request */
> + data->state.rtsp_CSeq_recv = CSeq; /* update the handle */
> + }
> +diff --git a/lib/smb.c b/lib/smb.c
> +index d493adc..9eba7ab 100644
> +--- a/lib/smb.c
> ++++ b/lib/smb.c
> +@@ -204,7 +204,7 @@ static void conn_state(struct connectdata *conn, enum smb_conn_state newstate)
> + static void request_state(struct connectdata *conn,
> + enum smb_req_state newstate)
> + {
> +- struct smb_request *req = conn->data->req.protop;
> ++ struct smb_request *req = conn->data->req.p.smb;
> + #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
> + /* For debug purposes */
> + static const char * const names[] = {
> +@@ -234,7 +234,7 @@ static CURLcode smb_setup_connection(struct connectdata *conn)
> + struct smb_request *req;
> +
> + /* Initialize the request state */
> +- conn->data->req.protop = req = calloc(1, sizeof(struct smb_request));
> ++ conn->data->req.p.smb = req = calloc(1, sizeof(struct smb_request));
> + if(!req)
> + return CURLE_OUT_OF_MEMORY;
> +
> +@@ -342,7 +342,7 @@ static void smb_format_message(struct connectdata *conn, struct smb_header *h,
> + unsigned char cmd, size_t len)
> + {
> + struct smb_conn *smbc = &conn->proto.smbc;
> +- struct smb_request *req = conn->data->req.protop;
> ++ struct smb_request *req = conn->data->req.p.smb;
> + unsigned int pid;
> +
> + memset(h, 0, sizeof(*h));
> +@@ -505,7 +505,7 @@ static CURLcode smb_send_tree_connect(struct connectdata *conn)
> +
> + static CURLcode smb_send_open(struct connectdata *conn)
> + {
> +- struct smb_request *req = conn->data->req.protop;
> ++ struct smb_request *req = conn->data->req.p.smb;
> + struct smb_nt_create msg;
> + size_t byte_count;
> +
> +@@ -535,7 +535,7 @@ static CURLcode smb_send_open(struct connectdata *conn)
> +
> + static CURLcode smb_send_close(struct connectdata *conn)
> + {
> +- struct smb_request *req = conn->data->req.protop;
> ++ struct smb_request *req = conn->data->req.p.smb;
> + struct smb_close msg;
> +
> + memset(&msg, 0, sizeof(msg));
> +@@ -556,7 +556,7 @@ static CURLcode smb_send_tree_disconnect(struct connectdata *conn)
> +
> + static CURLcode smb_send_read(struct connectdata *conn)
> + {
> +- struct smb_request *req = conn->data->req.protop;
> ++ struct smb_request *req = conn->data->req.p.smb;
> + curl_off_t offset = conn->data->req.offset;
> + struct smb_read msg;
> +
> +@@ -575,7 +575,7 @@ static CURLcode smb_send_read(struct connectdata *conn)
> + static CURLcode smb_send_write(struct connectdata *conn)
> + {
> + struct smb_write *msg;
> +- struct smb_request *req = conn->data->req.protop;
> ++ struct smb_request *req = conn->data->req.p.smb;
> + curl_off_t offset = conn->data->req.offset;
> + curl_off_t upload_size = conn->data->req.size - conn->data->req.bytecount;
> + CURLcode result = Curl_get_upload_buffer(conn->data);
> +@@ -738,7 +738,7 @@ static void get_posix_time(time_t *out, curl_off_t timestamp)
> +
> + static CURLcode smb_request_state(struct connectdata *conn, bool *done)
> + {
> +- struct smb_request *req = conn->data->req.protop;
> ++ struct smb_request *req = conn->data->req.p.smb;
> + struct smb_header *h;
> + struct smb_conn *smbc = &conn->proto.smbc;
> + enum smb_req_state next_state = SMB_DONE;
> +@@ -923,7 +923,7 @@ static CURLcode smb_done(struct connectdata *conn, CURLcode status,
> + bool premature)
> + {
> + (void) premature;
> +- Curl_safefree(conn->data->req.protop);
> ++ Curl_safefree(conn->data->req.p.smb);
> + return status;
> + }
> +
> +@@ -957,7 +957,7 @@ static CURLcode smb_do(struct connectdata *conn, bool *done)
> + static CURLcode smb_parse_url_path(struct connectdata *conn)
> + {
> + struct Curl_easy *data = conn->data;
> +- struct smb_request *req = data->req.protop;
> ++ struct smb_request *req = data->req.p.smb;
> + struct smb_conn *smbc = &conn->proto.smbc;
> + char *path;
> + char *slash;
> +diff --git a/lib/smtp.c b/lib/smtp.c
> +index aea41bb..c5d0296 100644
> +--- a/lib/smtp.c
> ++++ b/lib/smtp.c
> +@@ -484,7 +484,7 @@ static CURLcode smtp_perform_command(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> +
> + if(smtp->rcpt) {
> + /* We notify the server we are sending UTF-8 data if a) it supports the
> +@@ -697,7 +697,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
> + any there do, as we need to correctly identify our support for SMTPUTF8
> + in the envelope, as per RFC-6531 sect. 3.4 */
> + if(conn->proto.smtpc.utf8_supported && !utf8) {
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> + struct curl_slist *rcpt = smtp->rcpt;
> +
> + while(rcpt && !utf8) {
> +@@ -741,7 +741,7 @@ static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> + char *address = NULL;
> + struct hostname host = { NULL, NULL, NULL, NULL };
> +
> +@@ -989,7 +989,7 @@ static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> + char *line = data->state.buffer;
> + size_t len = strlen(line);
> +
> +@@ -1055,7 +1055,7 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> + bool is_smtp_err = FALSE;
> + bool is_smtp_blocking_err = FALSE;
> +
> +@@ -1278,7 +1278,7 @@ static CURLcode smtp_init(struct connectdata *conn)
> + struct Curl_easy *data = conn->data;
> + struct SMTP *smtp;
> +
> +- smtp = data->req.protop = calloc(sizeof(struct SMTP), 1);
> ++ smtp = data->req.p.smtp = calloc(sizeof(struct SMTP), 1);
> + if(!smtp)
> + result = CURLE_OUT_OF_MEMORY;
> +
> +@@ -1356,7 +1356,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> + struct pingpong *pp = &conn->proto.smtpc.pp;
> + char *eob;
> + ssize_t len;
> +@@ -1442,7 +1442,7 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
> + /* This is SMTP and no proxy */
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> +
> + DEBUGF(infof(conn->data, "DO phase starts\n"));
> +
> +@@ -1550,7 +1550,7 @@ static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
> + /* Call this when the DO phase has completed */
> + static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
> + {
> +- struct SMTP *smtp = conn->data->req.protop;
> ++ struct SMTP *smtp = conn->data->req.p.smtp;
> +
> + (void)connected;
> +
> +@@ -1703,7 +1703,7 @@ static CURLcode smtp_parse_custom_request(struct connectdata *conn)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> + const char *custom = data->set.str[STRING_CUSTOMREQUEST];
> +
> + /* URL decode the custom request */
> +@@ -1796,7 +1796,7 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
> + ssize_t i;
> + ssize_t si;
> + struct Curl_easy *data = conn->data;
> +- struct SMTP *smtp = data->req.protop;
> ++ struct SMTP *smtp = data->req.p.smtp;
> + char *scratch = data->state.scratch;
> + char *newscratch = NULL;
> + char *oldscratch = NULL;
> +diff --git a/lib/telnet.c b/lib/telnet.c
> +index c3b58e5..1fc5af1 100644
> +--- a/lib/telnet.c
> ++++ b/lib/telnet.c
> +@@ -247,7 +247,7 @@ CURLcode init_telnet(struct connectdata *conn)
> + if(!tn)
> + return CURLE_OUT_OF_MEMORY;
> +
> +- conn->data->req.protop = tn; /* make us known */
> ++ conn->data->req.p.telnet = tn; /* make us known */
> +
> + tn->telrcv_state = CURL_TS_DATA;
> +
> +@@ -292,7 +292,7 @@ CURLcode init_telnet(struct connectdata *conn)
> + static void negotiate(struct connectdata *conn)
> + {
> + int i;
> +- struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *) conn->data->req.p.telnet;
> +
> + for(i = 0; i < CURL_NTELOPTS; i++) {
> + if(i == CURL_TELOPT_ECHO)
> +@@ -365,7 +365,7 @@ static void send_negotiation(struct connectdata *conn, int cmd, int option)
> + static
> + void set_remote_option(struct connectdata *conn, int option, int newstate)
> + {
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + if(newstate == CURL_YES) {
> + switch(tn->him[option]) {
> + case CURL_NO:
> +@@ -439,7 +439,7 @@ void set_remote_option(struct connectdata *conn, int option, int newstate)
> + static
> + void rec_will(struct connectdata *conn, int option)
> + {
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + switch(tn->him[option]) {
> + case CURL_NO:
> + if(tn->him_preferred[option] == CURL_YES) {
> +@@ -487,7 +487,7 @@ void rec_will(struct connectdata *conn, int option)
> + static
> + void rec_wont(struct connectdata *conn, int option)
> + {
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + switch(tn->him[option]) {
> + case CURL_NO:
> + /* Already disabled */
> +@@ -529,7 +529,7 @@ void rec_wont(struct connectdata *conn, int option)
> + static void
> + set_local_option(struct connectdata *conn, int option, int newstate)
> + {
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + if(newstate == CURL_YES) {
> + switch(tn->us[option]) {
> + case CURL_NO:
> +@@ -603,7 +603,7 @@ set_local_option(struct connectdata *conn, int option, int newstate)
> + static
> + void rec_do(struct connectdata *conn, int option)
> + {
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + switch(tn->us[option]) {
> + case CURL_NO:
> + if(tn->us_preferred[option] == CURL_YES) {
> +@@ -663,7 +663,7 @@ void rec_do(struct connectdata *conn, int option)
> + static
> + void rec_dont(struct connectdata *conn, int option)
> + {
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + switch(tn->us[option]) {
> + case CURL_NO:
> + /* Already disabled */
> +@@ -822,7 +822,7 @@ static CURLcode check_telnet_options(struct connectdata *conn)
> + char option_keyword[128] = "";
> + char option_arg[256] = "";
> + struct Curl_easy *data = conn->data;
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + CURLcode result = CURLE_OK;
> + int binary_option;
> +
> +@@ -929,7 +929,7 @@ static void suboption(struct connectdata *conn)
> + char varname[128] = "";
> + char varval[128] = "";
> + struct Curl_easy *data = conn->data;
> +- struct TELNET *tn = (struct TELNET *)data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)data->req.p.telnet;
> +
> + printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2);
> + switch(CURL_SB_GET(tn)) {
> +@@ -1004,7 +1004,7 @@ static void sendsuboption(struct connectdata *conn, int option)
> + unsigned char *uc1, *uc2;
> +
> + struct Curl_easy *data = conn->data;
> +- struct TELNET *tn = (struct TELNET *)data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)data->req.p.telnet;
> +
> + switch(option) {
> + case CURL_TELOPT_NAWS:
> +@@ -1062,7 +1062,7 @@ CURLcode telrcv(struct connectdata *conn,
> + int in = 0;
> + int startwrite = -1;
> + struct Curl_easy *data = conn->data;
> +- struct TELNET *tn = (struct TELNET *)data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)data->req.p.telnet;
> +
> + #define startskipping() \
> + if(startwrite >= 0) { \
> +@@ -1280,7 +1280,7 @@ static CURLcode send_telnet_data(struct connectdata *conn,
> + static CURLcode telnet_done(struct connectdata *conn,
> + CURLcode status, bool premature)
> + {
> +- struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
> ++ struct TELNET *tn = (struct TELNET *)conn->data->req.p.telnet;
> + (void)status; /* unused */
> + (void)premature; /* not used */
> +
> +@@ -1290,7 +1290,7 @@ static CURLcode telnet_done(struct connectdata *conn,
> + curl_slist_free_all(tn->telnet_vars);
> + tn->telnet_vars = NULL;
> +
> +- Curl_safefree(conn->data->req.protop);
> ++ Curl_safefree(conn->data->req.p.telnet);
> +
> + return CURLE_OK;
> + }
> +@@ -1333,7 +1333,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
> + if(result)
> + return result;
> +
> +- tn = (struct TELNET *)data->req.protop;
> ++ tn = data->req.p.telnet;
> +
> + result = check_telnet_options(conn);
> + if(result)
> +diff --git a/lib/transfer.c b/lib/transfer.c
> +index a07c7af..4630609 100644
> +--- a/lib/transfer.c
> ++++ b/lib/transfer.c
> +@@ -167,7 +167,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
> + bool sending_http_headers = FALSE;
> +
> + if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) {
> +- const struct HTTP *http = data->req.protop;
> ++ const struct HTTP *http = data->req.p.http;
> +
> + if(http->sending == HTTPSEND_REQUEST)
> + /* We're sending the HTTP request headers, not the data.
> +@@ -426,7 +426,7 @@ CURLcode Curl_readrewind(struct connectdata *conn)
> + CURLOPT_HTTPPOST, call app to rewind
> + */
> + if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
> +- struct HTTP *http = data->req.protop;
> ++ struct HTTP *http = data->req.p.http;
> +
> + if(http->sendit)
> + mimepart = http->sendit;
> +@@ -1028,7 +1028,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
> + /* HTTP pollution, this should be written nicer to become more
> + protocol agnostic. */
> + size_t fillcount;
> +- struct HTTP *http = k->protop;
> ++ struct HTTP *http = k->p.http;
> +
> + if((k->exp100 == EXP100_SENDING_REQUEST) &&
> + (http->sending == HTTPSEND_BODY)) {
> +@@ -1853,7 +1853,7 @@ Curl_setup_transfer(
> + {
> + struct SingleRequest *k = &data->req;
> + struct connectdata *conn = data->conn;
> +- struct HTTP *http = data->req.protop;
> ++ struct HTTP *http = data->req.p.http;
> + bool httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) &&
> + (http->sending == HTTPSEND_REQUEST));
> + DEBUGASSERT(conn != NULL);
> +diff --git a/lib/url.c b/lib/url.c
> +index 150667a..849d527 100644
> +--- a/lib/url.c
> ++++ b/lib/url.c
> +@@ -2060,7 +2060,7 @@ static CURLcode setup_connection_internals(struct connectdata *conn)
> +
> + void Curl_free_request_state(struct Curl_easy *data)
> + {
> +- Curl_safefree(data->req.protop);
> ++ Curl_safefree(data->req.p.http);
> + Curl_safefree(data->req.newurl);
> +
> + #ifndef CURL_DISABLE_DOH
> +diff --git a/lib/urldata.h b/lib/urldata.h
> +index 0ae9269..76baee3 100644
> +--- a/lib/urldata.h
> ++++ b/lib/urldata.h
> +@@ -645,8 +645,23 @@ struct SingleRequest {
> + and the 'upload_present' contains the number of bytes available at this
> + position */
> + char *upload_fromhere;
> +- void *protop; /* Allocated protocol-specific data. Each protocol
> +- handler makes sure this points to data it needs. */
> ++
> ++ /* Allocated protocol-specific data. Each protocol handler makes sure this
> ++ points to data it needs. */
> ++ union {
> ++ struct FILEPROTO *file;
> ++ struct FTP *ftp;
> ++ struct HTTP *http;
> ++ struct IMAP *imap;
> ++ struct ldapreqinfo *ldap;
> ++ struct MQTT *mqtt;
> ++ struct POP3 *pop3;
> ++ struct RTSP *rtsp;
> ++ struct smb_request *smb;
> ++ struct SMTP *smtp;
> ++ struct SSHPROTO *ssh;
> ++ struct TELNET *telnet;
> ++ } p;
> + #ifndef CURL_DISABLE_DOH
> + struct dohdata doh; /* DoH specific data for this request */
> + #endif
> +diff --git a/lib/vquic/ngtcp2.c b/lib/vquic/ngtcp2.c
> +index 20ee08d..18eeda8 100644
> +--- a/lib/vquic/ngtcp2.c
> ++++ b/lib/vquic/ngtcp2.c
> +@@ -962,7 +962,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
> + void *stream_user_data)
> + {
> + struct Curl_easy *data = stream_user_data;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + (void)conn;
> + (void)stream_id;
> + (void)app_error_code;
> +@@ -1008,7 +1008,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream_id,
> + void *user_data, void *stream_user_data)
> + {
> + struct Curl_easy *data = stream_user_data;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + CURLcode result = CURLE_OK;
> + (void)conn;
> +
> +@@ -1067,7 +1067,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
> + void *user_data, void *stream_user_data)
> + {
> + struct Curl_easy *data = stream_user_data;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + CURLcode result = CURLE_OK;
> + (void)conn;
> + (void)stream_id;
> +@@ -1091,7 +1091,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
> + nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
> + nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
> + struct Curl_easy *data = stream_user_data;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + CURLcode result = CURLE_OK;
> + (void)conn;
> + (void)stream_id;
> +@@ -1255,7 +1255,7 @@ static ssize_t ngh3_stream_recv(struct connectdata *conn,
> + CURLcode *curlcode)
> + {
> + curl_socket_t sockfd = conn->sock[sockindex];
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> + struct quicsocket *qs = conn->quic;
> +
> + if(!stream->memlen) {
> +@@ -1313,7 +1313,7 @@ static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
> + void *stream_user_data)
> + {
> + struct Curl_easy *data = stream_user_data;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + (void)conn;
> + (void)stream_id;
> + (void)user_data;
> +@@ -1335,7 +1335,7 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
> + {
> + struct Curl_easy *data = stream_user_data;
> + size_t nread;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + (void)conn;
> + (void)stream_id;
> + (void)user_data;
> +@@ -1398,7 +1398,7 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
> + static CURLcode http_request(struct connectdata *conn, const void *mem,
> + size_t len)
> + {
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> + size_t nheader;
> + size_t i;
> + size_t authority_idx;
> +@@ -1641,7 +1641,7 @@ static ssize_t ngh3_stream_send(struct connectdata *conn,
> + ssize_t sent;
> + struct quicsocket *qs = conn->quic;
> + curl_socket_t sockfd = conn->sock[sockindex];
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> +
> + if(!stream->h3req) {
> + CURLcode result = http_request(conn, mem, len);
> +@@ -1909,7 +1909,7 @@ CURLcode Curl_quic_done_sending(struct connectdata *conn)
> + {
> + if(conn->handler == &Curl_handler_http3) {
> + /* only for HTTP/3 transfers */
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> + struct quicsocket *qs = conn->quic;
> + stream->upload_done = TRUE;
> + (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
> +@@ -1926,7 +1926,7 @@ void Curl_quic_done(struct Curl_easy *data, bool premature)
> + (void)premature;
> + if(data->conn->handler == &Curl_handler_http3) {
> + /* only for HTTP/3 transfers */
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + Curl_dyn_free(&stream->overflow);
> + }
> + }
> +@@ -1941,7 +1941,7 @@ bool Curl_quic_data_pending(const struct Curl_easy *data)
> + buffer and allocated an overflow buffer. Since it's possible that
> + there's no more data coming on the socket, we need to keep reading
> + until the overflow buffer is empty. */
> +- const struct HTTP *stream = data->req.protop;
> ++ const struct HTTP *stream = data->req.p.http;
> + return Curl_dyn_len(&stream->overflow) > 0;
> + }
> +
> +diff --git a/lib/vquic/quiche.c b/lib/vquic/quiche.c
> +index fd9cb8b..c0e250d 100644
> +--- a/lib/vquic/quiche.c
> ++++ b/lib/vquic/quiche.c
> +@@ -131,7 +131,7 @@ static unsigned int quiche_conncheck(struct connectdata *conn,
> +
> + static CURLcode quiche_do(struct connectdata *conn, bool *done)
> + {
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> + stream->h3req = FALSE; /* not sent */
> + return Curl_http(conn, done);
> + }
> +@@ -460,7 +460,7 @@ static ssize_t h3_stream_recv(struct connectdata *conn,
> + int rc;
> + struct h3h1header headers;
> + struct Curl_easy *data = conn->data;
> +- struct HTTP *stream = data->req.protop;
> ++ struct HTTP *stream = data->req.p.http;
> + headers.dest = buf;
> + headers.destlen = buffersize;
> + headers.nlen = 0;
> +@@ -548,7 +548,7 @@ static ssize_t h3_stream_send(struct connectdata *conn,
> + ssize_t sent;
> + struct quicsocket *qs = conn->quic;
> + curl_socket_t sockfd = conn->sock[sockindex];
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> +
> + if(!stream->h3req) {
> + CURLcode result = http_request(conn, mem, len);
> +@@ -596,7 +596,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
> + {
> + /*
> + */
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> + size_t nheader;
> + size_t i;
> + size_t authority_idx;
> +@@ -824,7 +824,7 @@ CURLcode Curl_quic_done_sending(struct connectdata *conn)
> + if(conn->handler == &Curl_handler_http3) {
> + /* only for HTTP/3 transfers */
> + ssize_t sent;
> +- struct HTTP *stream = conn->data->req.protop;
> ++ struct HTTP *stream = conn->data->req.p.http;
> + struct quicsocket *qs = conn->quic;
> + fprintf(stderr, "!!! Curl_quic_done_sending\n");
> + stream->upload_done = TRUE;
> +diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c
> +index 8988e23..a84e1bf 100644
> +--- a/lib/vssh/libssh.c
> ++++ b/lib/vssh/libssh.c
> +@@ -662,7 +662,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SSHPROTO *protop = data->req.protop;
> ++ struct SSHPROTO *protop = data->req.p.ssh;
> + struct ssh_conn *sshc = &conn->proto.sshc;
> + curl_socket_t sock = conn->sock[FIRSTSOCKET];
> + int rc = SSH_NO_ERROR, err;
> +@@ -2129,7 +2129,7 @@ static CURLcode myssh_setup_connection(struct connectdata *conn)
> + {
> + struct SSHPROTO *ssh;
> +
> +- conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
> ++ conn->data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
> + if(!ssh)
> + return CURLE_OUT_OF_MEMORY;
> +
> +@@ -2152,7 +2152,7 @@ static CURLcode myssh_connect(struct connectdata *conn, bool *done)
> + int rc;
> +
> + /* initialize per-handle data if not already */
> +- if(!data->req.protop)
> ++ if(!data->req.p.ssh)
> + myssh_setup_connection(conn);
> +
> + /* We default to persistent connections. We set this already in this connect
> +@@ -2353,7 +2353,7 @@ static CURLcode scp_disconnect(struct connectdata *conn,
> + static CURLcode myssh_done(struct connectdata *conn, CURLcode status)
> + {
> + CURLcode result = CURLE_OK;
> +- struct SSHPROTO *protop = conn->data->req.protop;
> ++ struct SSHPROTO *protop = conn->data->req.p.ssh;
> +
> + if(!status) {
> + /* run the state-machine */
> +@@ -2606,7 +2606,7 @@ static void sftp_quote(struct connectdata *conn)
> + {
> + const char *cp;
> + struct Curl_easy *data = conn->data;
> +- struct SSHPROTO *protop = data->req.protop;
> ++ struct SSHPROTO *protop = data->req.p.ssh;
> + struct ssh_conn *sshc = &conn->proto.sshc;
> + CURLcode result;
> +
> +diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c
> +index 4f56bb4..3ed777f 100644
> +--- a/lib/vssh/libssh2.c
> ++++ b/lib/vssh/libssh2.c
> +@@ -789,7 +789,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
> + {
> + CURLcode result = CURLE_OK;
> + struct Curl_easy *data = conn->data;
> +- struct SSHPROTO *sftp_scp = data->req.protop;
> ++ struct SSHPROTO *sftp_scp = data->req.p.ssh;
> + struct ssh_conn *sshc = &conn->proto.sshc;
> + curl_socket_t sock = conn->sock[FIRSTSOCKET];
> + int rc = LIBSSH2_ERROR_NONE;
> +@@ -2989,7 +2989,7 @@ static CURLcode ssh_setup_connection(struct connectdata *conn)
> + {
> + struct SSHPROTO *ssh;
> +
> +- conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
> ++ conn->data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
> + if(!ssh)
> + return CURLE_OUT_OF_MEMORY;
> +
> +@@ -3013,7 +3013,7 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
> + struct Curl_easy *data = conn->data;
> +
> + /* initialize per-handle data if not already */
> +- if(!data->req.protop)
> ++ if(!data->req.p.ssh)
> + ssh_setup_connection(conn);
> +
> + /* We default to persistent connections. We set this already in this connect
> +@@ -3192,7 +3192,7 @@ static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection)
> + static CURLcode ssh_done(struct connectdata *conn, CURLcode status)
> + {
> + CURLcode result = CURLE_OK;
> +- struct SSHPROTO *sftp_scp = conn->data->req.protop;
> ++ struct SSHPROTO *sftp_scp = conn->data->req.p.ssh;
> +
> + if(!status) {
> + /* run the state-machine */
> +diff --git a/lib/vssh/wolfssh.c b/lib/vssh/wolfssh.c
> +index dcbbab6..1b990e3 100644
> +--- a/lib/vssh/wolfssh.c
> ++++ b/lib/vssh/wolfssh.c
> +@@ -322,7 +322,7 @@ static CURLcode wssh_setup_connection(struct connectdata *conn)
> + {
> + struct SSHPROTO *ssh;
> +
> +- conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
> ++ conn->data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
> + if(!ssh)
> + return CURLE_OUT_OF_MEMORY;
> +
> +@@ -356,7 +356,7 @@ static CURLcode wssh_connect(struct connectdata *conn, bool *done)
> + int rc;
> +
> + /* initialize per-handle data if not already */
> +- if(!data->req.protop)
> ++ if(!data->req.p.ssh)
> + wssh_setup_connection(conn);
> +
> + /* We default to persistent connections. We set this already in this connect
> +@@ -429,7 +429,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
> + CURLcode result = CURLE_OK;
> + struct ssh_conn *sshc = &conn->proto.sshc;
> + struct Curl_easy *data = conn->data;
> +- struct SSHPROTO *sftp_scp = data->req.protop;
> ++ struct SSHPROTO *sftp_scp = data->req.p.ssh;
> + WS_SFTPNAME *name;
> + int rc = 0;
> + *block = FALSE; /* we're not blocking by default */
> +@@ -1027,7 +1027,7 @@ static CURLcode wssh_block_statemach(struct connectdata *conn,
> + static CURLcode wssh_done(struct connectdata *conn, CURLcode status)
> + {
> + CURLcode result = CURLE_OK;
> +- struct SSHPROTO *sftp_scp = conn->data->req.protop;
> ++ struct SSHPROTO *sftp_scp = conn->data->req.p.ssh;
> +
> + if(!status) {
> + /* run the state-machine */
> diff --git a/meta/recipes-support/curl/curl/CVE-2020-8284.patch b/meta/recipes-support/curl/curl/CVE-2020-8284.patch
> new file mode 100644
> index 00000000000..4ae514ffa8b
> --- /dev/null
> +++ b/meta/recipes-support/curl/curl/CVE-2020-8284.patch
> @@ -0,0 +1,210 @@
> +From ec9cc725d598ac77de7b6df8afeec292b3c8ad46 Mon Sep 17 00:00:00 2001
> +From: Daniel Stenberg <daniel@haxx.se>
> +Date: Tue, 24 Nov 2020 14:56:57 +0100
> +Subject: [PATCH] ftp: CURLOPT_FTP_SKIP_PASV_IP by default
> +
> +The command line tool also independently sets --ftp-skip-pasv-ip by
> +default.
> +
> +Ten test cases updated to adapt the modified --libcurl output.
> +
> +Bug: https://curl.se/docs/CVE-2020-8284.html
> +CVE-2020-8284
> +
> +Reported-by: Varnavas Papaioannou
> +
> +Upstream-Status: Backport [https://github.com/curl/curl/commit/ec9cc725d598ac]
> +
> +CVE: CVE-2020-8284
> +
> +Signed-off-by: Daniel Stenberg <daniel@haxx.se>
> +Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
> +---
> + docs/cmdline-opts/ftp-skip-pasv-ip.d | 2 ++
> + docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 | 8 +++++---
> + lib/url.c | 1 +
> + src/tool_cfgable.c | 1 +
> + tests/data/test1400 | 1 +
> + tests/data/test1401 | 1 +
> + tests/data/test1402 | 1 +
> + tests/data/test1403 | 1 +
> + tests/data/test1404 | 1 +
> + tests/data/test1405 | 1 +
> + tests/data/test1406 | 1 +
> + tests/data/test1407 | 1 +
> + tests/data/test1420 | 1 +
> + 14 files changed, 18 insertions(+), 3 deletions(-)
> +
> +diff --git a/docs/cmdline-opts/ftp-skip-pasv-ip.d b/docs/cmdline-opts/ftp-skip-pasv-ip.d
> +index d6fd4589b1e..bcf4e7e62f2 100644
> +--- a/docs/cmdline-opts/ftp-skip-pasv-ip.d
> ++++ b/docs/cmdline-opts/ftp-skip-pasv-ip.d
> +@@ -10,4 +10,6 @@ to curl's PASV command when curl connects the data connection. Instead curl
> + will re-use the same IP address it already uses for the control
> + connection.
> +
> ++Since curl 7.74.0 this option is enabled by default.
> ++
> + This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
> +diff --git a/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 b/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3
> +index d6217d0d8ca..fa87ddce769 100644
> +--- a/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3
> ++++ b/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3
> +@@ -5,7 +5,7 @@
> + .\" * | (__| |_| | _ <| |___
> + .\" * \___|\___/|_| \_\_____|
> + .\" *
> +-.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
> ++.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
> + .\" *
> + .\" * This software is licensed as described in the file COPYING, which
> + .\" * you should have received as part of this distribution. The terms
> +@@ -35,11 +35,13 @@ address it already uses for the control connection. But it will use the port
> + number from the 227-response.
> +
> + This option thus allows libcurl to work around broken server installations
> +-that due to NATs, firewalls or incompetence report the wrong IP address back.
> ++that due to NATs, firewalls or incompetence report the wrong IP address
> ++back. Setting the option also reduces the risk for various sorts of client
> ++abuse by malicious servers.
> +
> + This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
> + .SH DEFAULT
> +-0
> ++1 since 7.74.0, was 0 before then.
> + .SH PROTOCOLS
> + FTP
> + .SH EXAMPLE
> +diff --git a/lib/url.c b/lib/url.c
> +index f8b2a0030de..2b0ba87ba87 100644
> +--- a/lib/url.c
> ++++ b/lib/url.c
> +@@ -497,6 +497,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
> + set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
> + set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */
> + set->ftp_filemethod = FTPFILE_MULTICWD;
> ++ set->ftp_skip_ip = TRUE; /* skip PASV IP by default */
> + #endif
> + set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
> +
> +diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c
> +index c52d8e1c6bb..4c06d3557b7 100644
> +--- a/src/tool_cfgable.c
> ++++ b/src/tool_cfgable.c
> +@@ -44,6 +44,7 @@ void config_init(struct OperationConfig *config)
> + config->tcp_nodelay = TRUE; /* enabled by default */
> + config->happy_eyeballs_timeout_ms = CURL_HET_DEFAULT;
> + config->http09_allowed = FALSE;
> ++ config->ftp_skip_ip = TRUE;
> + }
> +
> + static void free_config_fields(struct OperationConfig *config)
> +diff --git a/tests/data/test1400 b/tests/data/test1400
> +index 812ad0b88d9..b7060eca58e 100644
> +--- a/tests/data/test1400
> ++++ b/tests/data/test1400
> +@@ -73,6 +73,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
> + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> +
> + /* Here is a list of options the curl code used that cannot get generated
> +diff --git a/tests/data/test1401 b/tests/data/test1401
> +index f93b3d637de..a2629683aff 100644
> +--- a/tests/data/test1401
> ++++ b/tests/data/test1401
> +@@ -87,6 +87,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
> + curl_easy_setopt(hnd, CURLOPT_COOKIE, "chocolate=chip");
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> + curl_easy_setopt(hnd, CURLOPT_PROTOCOLS, (long)CURLPROTO_FILE |
> + (long)CURLPROTO_FTP |
> +diff --git a/tests/data/test1402 b/tests/data/test1402
> +index 7593c516da1..1bd55cb4e3b 100644
> +--- a/tests/data/test1402
> ++++ b/tests/data/test1402
> +@@ -78,6 +78,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
> + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> +
> + /* Here is a list of options the curl code used that cannot get generated
> +diff --git a/tests/data/test1403 b/tests/data/test1403
> +index ecb4dd3dcab..a7c9fcca322 100644
> +--- a/tests/data/test1403
> ++++ b/tests/data/test1403
> +@@ -73,6 +73,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
> + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> +
> + /* Here is a list of options the curl code used that cannot get generated
> +diff --git a/tests/data/test1404 b/tests/data/test1404
> +index 97622b63948..1d8e8cf7779 100644
> +--- a/tests/data/test1404
> ++++ b/tests/data/test1404
> +@@ -147,6 +147,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
> + curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> +
> + /* Here is a list of options the curl code used that cannot get generated
> +diff --git a/tests/data/test1405 b/tests/data/test1405
> +index 2bac79eda74..b4087704f7b 100644
> +--- a/tests/data/test1405
> ++++ b/tests/data/test1405
> +@@ -89,6 +89,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_POSTQUOTE, slist2);
> + curl_easy_setopt(hnd, CURLOPT_PREQUOTE, slist3);
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> +
> + /* Here is a list of options the curl code used that cannot get generated
> +diff --git a/tests/data/test1406 b/tests/data/test1406
> +index 51a166adff2..38f68d11ee1 100644
> +--- a/tests/data/test1406
> ++++ b/tests/data/test1406
> +@@ -79,6 +79,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_URL, "smtp://%HOSTIP:%SMTPPORT/1406");
> + curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L);
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> + curl_easy_setopt(hnd, CURLOPT_MAIL_FROM, "sender@example.com");
> + curl_easy_setopt(hnd, CURLOPT_MAIL_RCPT, slist1);
> +diff --git a/tests/data/test1407 b/tests/data/test1407
> +index f6879008fb2..a7e13ba7585 100644
> +--- a/tests/data/test1407
> ++++ b/tests/data/test1407
> +@@ -62,6 +62,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_DIRLISTONLY, 1L);
> + curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret");
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> +
> + /* Here is a list of options the curl code used that cannot get generated
> +diff --git a/tests/data/test1420 b/tests/data/test1420
> +index 057ecc4773a..4b8d7bbf418 100644
> +--- a/tests/data/test1420
> ++++ b/tests/data/test1420
> +@@ -67,6 +67,7 @@ int main(int argc, char *argv[])
> + curl_easy_setopt(hnd, CURLOPT_URL, "imap://%HOSTIP:%IMAPPORT/1420/;MAILINDEX=1");
> + curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret");
> + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
> ++ curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
> + curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
> +
> + /* Here is a list of options the curl code used that cannot get generated
> +
> diff --git a/meta/recipes-support/curl/curl/CVE-2020-8285.patch b/meta/recipes-support/curl/curl/CVE-2020-8285.patch
> new file mode 100644
> index 00000000000..7a8be684775
> --- /dev/null
> +++ b/meta/recipes-support/curl/curl/CVE-2020-8285.patch
> @@ -0,0 +1,261 @@
> +From 69a358f2186e04cf44698b5100332cbf1ee7f01d Mon Sep 17 00:00:00 2001
> +From: Daniel Stenberg <daniel@haxx.se>
> +Date: Sat, 28 Nov 2020 00:27:21 +0100
> +Subject: [PATCH] ftp: make wc_statemach loop instead of recurse
> +
> +CVE-2020-8285
> +
> +Fixes #6255
> +Bug: https://curl.se/docs/CVE-2020-8285.html
> +Reported-by: xnynx on github
> +
> +Upstream-Status: Backport [https://github.com/curl/curl/commit/69a358f2186e04]
> +
> +CVE: CVE-2020-8285
> +
> +Signed-off-by: Daniel Stenberg <daniel@haxx.se>
> +Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
> +
> +[Ajusted to match Dunfell context]
> +Signed-off-by: Armin Kuster <akuster@mvista.com>
> +---
> + lib/ftp.c | 202 +++++++++++++++++++++++++++---------------------------
> + 1 file changed, 102 insertions(+), 100 deletions(-)
> +
> +Index: curl-7.69.1/lib/ftp.c
> +===================================================================
> +--- curl-7.69.1.orig/lib/ftp.c
> ++++ curl-7.69.1/lib/ftp.c
> +@@ -3763,129 +3763,134 @@ static CURLcode init_wc_data(struct conn
> + return result;
> + }
> +
> +-/* This is called recursively */
> + static CURLcode wc_statemach(struct connectdata *conn)
> + {
> + struct WildcardData * const wildcard = &(conn->data->wildcard);
> + CURLcode result = CURLE_OK;
> +
> +- switch(wildcard->state) {
> +- case CURLWC_INIT:
> +- result = init_wc_data(conn);
> +- if(wildcard->state == CURLWC_CLEAN)
> +- /* only listing! */
> +- break;
> +- wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
> +- break;
> +-
> +- case CURLWC_MATCHING: {
> +- /* In this state is LIST response successfully parsed, so lets restore
> +- previous WRITEFUNCTION callback and WRITEDATA pointer */
> +- struct ftp_wc *ftpwc = wildcard->protdata;
> +- conn->data->set.fwrite_func = ftpwc->backup.write_function;
> +- conn->data->set.out = ftpwc->backup.file_descriptor;
> +- ftpwc->backup.write_function = ZERO_NULL;
> +- ftpwc->backup.file_descriptor = NULL;
> +- wildcard->state = CURLWC_DOWNLOADING;
> +-
> +- if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
> +- /* error found in LIST parsing */
> +- wildcard->state = CURLWC_CLEAN;
> +- return wc_statemach(conn);
> +- }
> +- if(wildcard->filelist.size == 0) {
> +- /* no corresponding file */
> +- wildcard->state = CURLWC_CLEAN;
> +- return CURLE_REMOTE_FILE_NOT_FOUND;
> ++ for(;;) {
> ++ switch(wildcard->state) {
> ++ case CURLWC_INIT:
> ++ result = init_wc_data(conn);
> ++ if(wildcard->state == CURLWC_CLEAN)
> ++ /* only listing! */
> ++ return result;
> ++ wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
> ++ return result;
> ++
> ++ case CURLWC_MATCHING: {
> ++ /* In this state is LIST response successfully parsed, so lets restore
> ++ previous WRITEFUNCTION callback and WRITEDATA pointer */
> ++ struct ftp_wc *ftpwc = wildcard->protdata;
> ++ conn->data->set.fwrite_func = ftpwc->backup.write_function;
> ++ conn->data->set.out = ftpwc->backup.file_descriptor;
> ++ ftpwc->backup.write_function = ZERO_NULL;
> ++ ftpwc->backup.file_descriptor = NULL;
> ++ wildcard->state = CURLWC_DOWNLOADING;
> ++
> ++ if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
> ++ /* error found in LIST parsing */
> ++ wildcard->state = CURLWC_CLEAN;
> ++ continue;
> ++ }
> ++ if(wildcard->filelist.size == 0) {
> ++ /* no corresponding file */
> ++ wildcard->state = CURLWC_CLEAN;
> ++ return CURLE_REMOTE_FILE_NOT_FOUND;
> ++ }
> ++ continue;
> ++
> + }
> +- return wc_statemach(conn);
> +- }
> +
> +- case CURLWC_DOWNLOADING: {
> +- /* filelist has at least one file, lets get first one */
> +- struct ftp_conn *ftpc = &conn->proto.ftpc;
> +- struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
> +- struct FTP *ftp = conn->data->req.protop;
> ++ case CURLWC_DOWNLOADING: {
> ++ /* filelist has at least one file, lets get first one */
> ++ struct ftp_conn *ftpc = &conn->proto.ftpc;
> ++ struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
> ++ struct FTP *ftp = conn->data->req.protop;
> +
> + char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
> + if(!tmp_path)
> + return CURLE_OUT_OF_MEMORY;
> +
> +- /* switch default ftp->path and tmp_path */
> +- free(ftp->pathalloc);
> +- ftp->pathalloc = ftp->path = tmp_path;
> +-
> +- infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
> +- if(conn->data->set.chunk_bgn) {
> +- long userresponse;
> +- Curl_set_in_callback(conn->data, true);
> +- userresponse = conn->data->set.chunk_bgn(
> +- finfo, wildcard->customptr, (int)wildcard->filelist.size);
> +- Curl_set_in_callback(conn->data, false);
> +- switch(userresponse) {
> +- case CURL_CHUNK_BGN_FUNC_SKIP:
> +- infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
> +- finfo->filename);
> ++ /* switch default ftp->path and tmp_path */
> ++ free(ftp->pathalloc);
> ++ ftp->pathalloc = ftp->path = tmp_path;
> ++
> ++ infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
> ++ if(conn->data->set.chunk_bgn) {
> ++ long userresponse;
> ++ Curl_set_in_callback(conn->data, true);
> ++ userresponse = conn->data->set.chunk_bgn(
> ++ finfo, wildcard->customptr, (int)wildcard->filelist.size);
> ++ Curl_set_in_callback(conn->data, false);
> ++ switch(userresponse) {
> ++ case CURL_CHUNK_BGN_FUNC_SKIP:
> ++ infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
> ++ finfo->filename);
> ++ wildcard->state = CURLWC_SKIP;
> ++ continue;
> ++ case CURL_CHUNK_BGN_FUNC_FAIL:
> ++ return CURLE_CHUNK_FAILED;
> ++ }
> ++
> ++ }
> ++
> ++ if(finfo->filetype != CURLFILETYPE_FILE) {
> + wildcard->state = CURLWC_SKIP;
> +- return wc_statemach(conn);
> +- case CURL_CHUNK_BGN_FUNC_FAIL:
> +- return CURLE_CHUNK_FAILED;
> ++ continue;
> + }
> ++
> ++ if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
> ++ ftpc->known_filesize = finfo->size;
> ++
> ++ result = ftp_parse_url_path(conn);
> ++ if(result)
> ++ return result;
> ++
> ++ /* we don't need the Curl_fileinfo of first file anymore */
> ++ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
> ++
> ++ if(wildcard->filelist.size == 0) { /* remains only one file to down. */
> ++ wildcard->state = CURLWC_CLEAN;
> ++ /* after that will be ftp_do called once again and no transfer
> ++ will be done because of CURLWC_CLEAN state */
> ++ return CURLE_OK;
> ++ }
> ++ return result;
> + }
> +
> +- if(finfo->filetype != CURLFILETYPE_FILE) {
> +- wildcard->state = CURLWC_SKIP;
> +- return wc_statemach(conn);
> ++ case CURLWC_SKIP: {
> ++ if(conn->data->set.chunk_end) {
> ++ Curl_set_in_callback(conn->data, true);
> ++ conn->data->set.chunk_end(conn->data->wildcard.customptr);
> ++ Curl_set_in_callback(conn->data, false);
> ++ }
> ++ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
> ++ wildcard->state = (wildcard->filelist.size == 0) ?
> ++ CURLWC_CLEAN : CURLWC_DOWNLOADING;
> ++ continue;
> + }
> +
> +- if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
> +- ftpc->known_filesize = finfo->size;
> ++ case CURLWC_CLEAN: {
> ++ struct ftp_wc *ftpwc = wildcard->protdata;
> ++ result = CURLE_OK;
> ++ if(ftpwc)
> ++ result = Curl_ftp_parselist_geterror(ftpwc->parser);
> +
> +- result = ftp_parse_url_path(conn);
> +- if(result)
> ++ wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
> + return result;
> +-
> +- /* we don't need the Curl_fileinfo of first file anymore */
> +- Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
> +-
> +- if(wildcard->filelist.size == 0) { /* remains only one file to down. */
> +- wildcard->state = CURLWC_CLEAN;
> +- /* after that will be ftp_do called once again and no transfer
> +- will be done because of CURLWC_CLEAN state */
> +- return CURLE_OK;
> + }
> +- } break;
> +
> +- case CURLWC_SKIP: {
> +- if(conn->data->set.chunk_end) {
> +- Curl_set_in_callback(conn->data, true);
> +- conn->data->set.chunk_end(conn->data->wildcard.customptr);
> +- Curl_set_in_callback(conn->data, false);
> ++ case CURLWC_DONE:
> ++ case CURLWC_ERROR:
> ++ case CURLWC_CLEAR:
> ++ if(wildcard->dtor)
> ++ wildcard->dtor(wildcard->protdata);
> ++ return result;
> + }
> +- Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
> +- wildcard->state = (wildcard->filelist.size == 0) ?
> +- CURLWC_CLEAN : CURLWC_DOWNLOADING;
> +- return wc_statemach(conn);
> +- }
> +
> +- case CURLWC_CLEAN: {
> +- struct ftp_wc *ftpwc = wildcard->protdata;
> +- result = CURLE_OK;
> +- if(ftpwc)
> +- result = Curl_ftp_parselist_geterror(ftpwc->parser);
> +-
> +- wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
> +- } break;
> +-
> +- case CURLWC_DONE:
> +- case CURLWC_ERROR:
> +- case CURLWC_CLEAR:
> +- if(wildcard->dtor)
> +- wildcard->dtor(wildcard->protdata);
> +- break;
> + }
> +-
> +- return result;
> ++/* UNREACHABLE */
> + }
> +
> + /***********************************************************************
> diff --git a/meta/recipes-support/curl/curl/CVE-2020-8286.patch b/meta/recipes-support/curl/curl/CVE-2020-8286.patch
> new file mode 100644
> index 00000000000..21e72da0206
> --- /dev/null
> +++ b/meta/recipes-support/curl/curl/CVE-2020-8286.patch
> @@ -0,0 +1,138 @@
> +From 5d3b28deac44c19e4d73fc80e4917d42ee43adfe Mon Sep 17 00:00:00 2001
> +From: Daniel Stenberg <daniel@haxx.se>
> +Date: Wed, 2 Dec 2020 23:01:11 +0100
> +Subject: [PATCH] openssl: make the OCSP verification verify the certificate id
> +
> +CVE-2020-8286
> +
> +Reported by anonymous
> +
> +Bug: https://curl.se/docs/CVE-2020-8286.html
> +
> +Upstream-Status: Backport [https://github.com/curl/curl/commit/d9d01672785b]
> +
> +CVE: CVE-2020-8286
> +
> +Signed-off-by: Daniel Stenberg <daniel@haxx.se>
> +Signed-off-by: Khairul Rohaizzat Jamaluddin <khairul.rohaizzat.jamaluddin@intel.com>
> +[Fixup for Dunfell context]
> +Signed-off-by: Armin Kuster <akuster@mvista.com>
> +
> +---
> + lib/vtls/openssl.c | 83 +++++++++++++++++++++++++++++++++++-------------------
> + 1 file changed, 54 insertions(+), 29 deletions(-)
> +
> +Index: curl-7.69.1/lib/vtls/openssl.c
> +===================================================================
> +--- curl-7.69.1.orig/lib/vtls/openssl.c
> ++++ curl-7.69.1/lib/vtls/openssl.c
> +@@ -1717,6 +1717,11 @@ static CURLcode verifystatus(struct conn
> + OCSP_BASICRESP *br = NULL;
> + X509_STORE *st = NULL;
> + STACK_OF(X509) *ch = NULL;
> ++ X509 *cert;
> ++ OCSP_CERTID *id = NULL;
> ++ int cert_status, crl_reason;
> ++ ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
> ++ int ret;
> +
> + long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &status);
> +
> +@@ -1785,43 +1790,63 @@ static CURLcode verifystatus(struct conn
> + goto end;
> + }
> +
> +- for(i = 0; i < OCSP_resp_count(br); i++) {
> +- int cert_status, crl_reason;
> +- OCSP_SINGLERESP *single = NULL;
> +-
> +- ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
> +-
> +- single = OCSP_resp_get0(br, i);
> +- if(!single)
> +- continue;
> +-
> +- cert_status = OCSP_single_get0_status(single, &crl_reason, &rev,
> +- &thisupd, &nextupd);
> +-
> +- if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
> +- failf(data, "OCSP response has expired");
> +- result = CURLE_SSL_INVALIDCERTSTATUS;
> +- goto end;
> ++ /* Compute the certificate's ID */
> ++ cert = SSL_get_peer_certificate(BACKEND->handle);
> ++ if(!cert) {
> ++ failf(data, "Error getting peer certficate");
> ++ result = CURLE_SSL_INVALIDCERTSTATUS;
> ++ goto end;
> ++ }
> ++
> ++ for(i = 0; i < sk_X509_num(ch); i++) {
> ++ X509 *issuer = sk_X509_value(ch, i);
> ++ if(X509_check_issued(issuer, cert) == X509_V_OK) {
> ++ id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
> ++ break;
> + }
> ++ }
> ++ X509_free(cert);
> +
> +- infof(data, "SSL certificate status: %s (%d)\n",
> +- OCSP_cert_status_str(cert_status), cert_status);
> ++ if(!id) {
> ++ failf(data, "Error computing OCSP ID");
> ++ result = CURLE_SSL_INVALIDCERTSTATUS;
> ++ goto end;
> ++ }
> +
> +- switch(cert_status) {
> +- case V_OCSP_CERTSTATUS_GOOD:
> +- break;
> +-
> +- case V_OCSP_CERTSTATUS_REVOKED:
> +- result = CURLE_SSL_INVALIDCERTSTATUS;
> +-
> +- failf(data, "SSL certificate revocation reason: %s (%d)",
> +- OCSP_crl_reason_str(crl_reason), crl_reason);
> +- goto end;
> +-
> +- case V_OCSP_CERTSTATUS_UNKNOWN:
> +- result = CURLE_SSL_INVALIDCERTSTATUS;
> +- goto end;
> +- }
> ++ /* Find the single OCSP response corresponding to the certificate ID */
> ++ ret = OCSP_resp_find_status(br, id, &cert_status, &crl_reason, &rev,
> ++ &thisupd, &nextupd);
> ++ OCSP_CERTID_free(id);
> ++ if(ret != 1) {
> ++ failf(data, "Could not find certificate ID in OCSP response");
> ++ result = CURLE_SSL_INVALIDCERTSTATUS;
> ++ goto end;
> ++ }
> ++
> ++ /* Validate the corresponding single OCSP response */
> ++ if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
> ++ failf(data, "OCSP response has expired");
> ++ result = CURLE_SSL_INVALIDCERTSTATUS;
> ++ goto end;
> ++ }
> ++
> ++ infof(data, "SSL certificate status: %s (%d)\n",
> ++ OCSP_cert_status_str(cert_status), cert_status);
> ++
> ++ switch(cert_status) {
> ++ case V_OCSP_CERTSTATUS_GOOD:
> ++ break;
> ++
> ++ case V_OCSP_CERTSTATUS_REVOKED:
> ++ result = CURLE_SSL_INVALIDCERTSTATUS;
> ++ failf(data, "SSL certificate revocation reason: %s (%d)",
> ++ OCSP_crl_reason_str(crl_reason), crl_reason);
> ++ goto end;
> ++
> ++ case V_OCSP_CERTSTATUS_UNKNOWN:
> ++ default:
> ++ result = CURLE_SSL_INVALIDCERTSTATUS;
> ++ goto end;
> + }
> +
> + end:
> diff --git a/meta/recipes-support/curl/curl_7.69.1.bb b/meta/recipes-support/curl/curl_7.69.1.bb
> index 239852db09c..c0db01ac5d0 100644
> --- a/meta/recipes-support/curl/curl_7.69.1.bb
> +++ b/meta/recipes-support/curl/curl_7.69.1.bb
> @@ -9,6 +9,9 @@ SRC_URI = "https://curl.haxx.se/download/curl-${PV}.tar.bz2 \
> file://0001-replace-krb5-config-with-pkg-config.patch \
> file://CVE-2020-8169.patch \
> file://CVE-2020-8177.patch \
> + file://CVE-2020-8284.patch \
> + file://CVE-2020-8285.patch \
> + file://CVE-2020-8286.patch \
> "
>
> SRC_URI[md5sum] = "ec5fc263f898a3dfef08e805f1ecca42"
> --
> 2.17.1
>
>
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2021-01-15 18:25 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-01-15 18:02 [dunfell][PATCH 1/2] curl: Fix CVE-2020-8284, CVE-2020-8285, CVE-2020-8286 akuster
2021-01-15 18:02 ` [dunfell][PATCH 2/2] curl: Security fix for CVE-2020-8231 akuster
2021-01-15 18:16 ` [OE-core] [dunfell][PATCH 1/2] curl: Fix CVE-2020-8284, CVE-2020-8285, CVE-2020-8286 Steve Sakoman
2021-01-15 18:25 ` Steve Sakoman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox