ca55133
From e8705acd69383c13191c9dd4867d5118e58c54ba Mon Sep 17 00:00:00 2001
ca55133
From: Daniel Stenberg <daniel@haxx.se>
ca55133
Date: Thu, 6 Oct 2022 00:49:10 +0200
ca55133
Subject: [PATCH 1/2] strcase: add Curl_timestrcmp
ca55133
ca55133
This is a strcmp() alternative function for comparing "secrets",
ca55133
designed to take the same time no matter the content to not leak
ca55133
match/non-match info to observers based on how fast it is.
ca55133
ca55133
The time this function takes is only a function of the shortest input
ca55133
string.
ca55133
ca55133
Reported-by: Trail of Bits
ca55133
ca55133
Closes #9658
ca55133
ca55133
Upstream-commit: ed5095ed94281989e103c72e032200b83be37878
ca55133
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
ca55133
---
ca55133
 lib/strcase.c | 22 ++++++++++++++++++++++
ca55133
 lib/strcase.h |  1 +
ca55133
 2 files changed, 23 insertions(+)
ca55133
ca55133
diff --git a/lib/strcase.c b/lib/strcase.c
ca55133
index f932485..c73907d 100644
ca55133
--- a/lib/strcase.c
ca55133
+++ b/lib/strcase.c
ca55133
@@ -179,6 +179,28 @@ bool Curl_safecmp(char *a, char *b)
ca55133
   return !a && !b;
ca55133
 }
ca55133
 
ca55133
+/*
ca55133
+ * Curl_timestrcmp() returns 0 if the two strings are identical. The time this
ca55133
+ * function spends is a function of the shortest string, not of the contents.
ca55133
+ */
ca55133
+int Curl_timestrcmp(const char *a, const char *b)
ca55133
+{
ca55133
+  int match = 0;
ca55133
+  int i = 0;
ca55133
+
ca55133
+  if(a && b) {
ca55133
+    while(1) {
ca55133
+      match |= a[i]^b[i];
ca55133
+      if(!a[i] || !b[i])
ca55133
+        break;
ca55133
+      i++;
ca55133
+    }
ca55133
+  }
ca55133
+  else
ca55133
+    return a || b;
ca55133
+  return match;
ca55133
+}
ca55133
+
ca55133
 /* --- public functions --- */
ca55133
 
ca55133
 int curl_strequal(const char *first, const char *second)
ca55133
diff --git a/lib/strcase.h b/lib/strcase.h
ca55133
index d245929..11a67a1 100644
ca55133
--- a/lib/strcase.h
ca55133
+++ b/lib/strcase.h
ca55133
@@ -52,5 +52,6 @@ void Curl_strntoupper(char *dest, const char *src, size_t n);
ca55133
 void Curl_strntolower(char *dest, const char *src, size_t n);
ca55133
 
ca55133
 bool Curl_safecmp(char *a, char *b);
ca55133
+int Curl_timestrcmp(const char *first, const char *second);
ca55133
 
ca55133
 #endif /* HEADER_CURL_STRCASE_H */
ca55133
-- 
ca55133
2.39.2
ca55133
ca55133
ca55133
From 9cfaea212ff347937a38f6b5d6b885ed8ba1b931 Mon Sep 17 00:00:00 2001
ca55133
From: Daniel Stenberg <daniel@haxx.se>
ca55133
Date: Thu, 9 Mar 2023 17:47:06 +0100
ca55133
Subject: [PATCH 2/2] ftp: add more conditions for connection reuse
ca55133
ca55133
Reported-by: Harry Sintonen
ca55133
Closes #10730
ca55133
ca55133
Upstream-commit: 8f4608468b890dce2dad9f91d5607ee7e9c1aba1
ca55133
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
ca55133
---
ca55133
 lib/ftp.c     | 28 ++++++++++++++++++++++++++--
ca55133
 lib/ftp.h     |  5 +++++
ca55133
 lib/setopt.c  |  2 +-
ca55133
 lib/url.c     | 16 +++++++++++++++-
ca55133
 lib/urldata.h |  4 ++--
ca55133
 5 files changed, 49 insertions(+), 6 deletions(-)
ca55133
ca55133
diff --git a/lib/ftp.c b/lib/ftp.c
ca55133
index 9442832..df15bc0 100644
ca55133
--- a/lib/ftp.c
ca55133
+++ b/lib/ftp.c
ca55133
@@ -4107,6 +4107,8 @@ static CURLcode ftp_disconnect(struct Curl_easy *data,
ca55133
   }
ca55133
 
ca55133
   freedirs(ftpc);
ca55133
+  Curl_safefree(ftpc->account);
ca55133
+  Curl_safefree(ftpc->alternative_to_user);
ca55133
   Curl_safefree(ftpc->prevpath);
ca55133
   Curl_safefree(ftpc->server_os);
ca55133
   Curl_pp_disconnect(pp);
ca55133
@@ -4374,11 +4376,31 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
ca55133
 {
ca55133
   char *type;
ca55133
   struct FTP *ftp;
ca55133
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
ca55133
 
ca55133
-  data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1);
ca55133
+  ftp = calloc(sizeof(struct FTP), 1);
ca55133
   if(!ftp)
ca55133
     return CURLE_OUT_OF_MEMORY;
ca55133
 
ca55133
+  /* clone connection related data that is FTP specific */
ca55133
+  if(data->set.str[STRING_FTP_ACCOUNT]) {
ca55133
+    ftpc->account = strdup(data->set.str[STRING_FTP_ACCOUNT]);
ca55133
+    if(!ftpc->account) {
ca55133
+      free(ftp);
ca55133
+      return CURLE_OUT_OF_MEMORY;
ca55133
+    }
ca55133
+  }
ca55133
+  if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]) {
ca55133
+    ftpc->alternative_to_user =
ca55133
+      strdup(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
ca55133
+    if(!ftpc->alternative_to_user) {
ca55133
+      Curl_safefree(ftpc->account);
ca55133
+      free(ftp);
ca55133
+      return CURLE_OUT_OF_MEMORY;
ca55133
+    }
ca55133
+  }
ca55133
+  data->req.p.ftp = ftp;
ca55133
+
ca55133
   ftp->path = &data->state.up.path[1]; /* don't include the initial slash */
ca55133
 
ca55133
   /* FTP URLs support an extension like ";type=<typecode>" that
ca55133
@@ -4413,7 +4435,9 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
ca55133
   /* get some initial data into the ftp struct */
ca55133
   ftp->transfer = PPTRANSFER_BODY;
ca55133
   ftp->downloadsize = 0;
ca55133
-  conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
ca55133
+  ftpc->known_filesize = -1; /* unknown size for now */
ca55133
+  ftpc->use_ssl = data->set.use_ssl;
ca55133
+  ftpc->ccc = data->set.ftp_ccc;
ca55133
 
ca55133
   return CURLE_OK;
ca55133
 }
ca55133
diff --git a/lib/ftp.h b/lib/ftp.h
ca55133
index 7f6f432..3f33e27 100644
ca55133
--- a/lib/ftp.h
ca55133
+++ b/lib/ftp.h
ca55133
@@ -119,6 +119,8 @@ struct FTP {
ca55133
    struct */
ca55133
 struct ftp_conn {
ca55133
   struct pingpong pp;
ca55133
+  char *account;
ca55133
+  char *alternative_to_user;
ca55133
   char *entrypath; /* the PWD reply when we logged on */
ca55133
   char *file;    /* url-decoded file name (or path) */
ca55133
   char **dirs;   /* realloc()ed array for path components */
ca55133
@@ -148,6 +150,9 @@ struct ftp_conn {
ca55133
   ftpstate state; /* always use ftp.c:state() to change state! */
ca55133
   ftpstate state_saved; /* transfer type saved to be reloaded after
ca55133
                            data connection is established */
ca55133
+  unsigned char use_ssl;   /* if AUTH TLS is to be attempted etc, for FTP or
ca55133
+                              IMAP or POP3 or others! (type: curl_usessl)*/
ca55133
+  unsigned char ccc;       /* ccc level for this connection */
ca55133
   curl_off_t retr_size_saved; /* Size of retrieved file saved */
ca55133
   char *server_os;     /* The target server operating system. */
ca55133
   curl_off_t known_filesize; /* file size is different from -1, if wildcard
ca55133
diff --git a/lib/setopt.c b/lib/setopt.c
ca55133
index 3339a67..6fc111d 100644
ca55133
--- a/lib/setopt.c
ca55133
+++ b/lib/setopt.c
ca55133
@@ -2374,7 +2374,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
ca55133
     arg = va_arg(param, long);
ca55133
     if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST))
ca55133
       return CURLE_BAD_FUNCTION_ARGUMENT;
ca55133
-    data->set.use_ssl = (curl_usessl)arg;
ca55133
+    data->set.use_ssl = (unsigned char)arg;
ca55133
     break;
ca55133
 
ca55133
   case CURLOPT_SSL_OPTIONS:
ca55133
diff --git a/lib/url.c b/lib/url.c
ca55133
index 61ba832..4e21838 100644
ca55133
--- a/lib/url.c
ca55133
+++ b/lib/url.c
ca55133
@@ -1378,10 +1378,24 @@ ConnectionExists(struct Curl_easy *data,
ca55133
          (data->state.httpwant < CURL_HTTP_VERSION_2_0))
ca55133
         continue;
ca55133
 
ca55133
-      if(get_protocol_family(needle->handler) == PROTO_FAMILY_SSH) {
ca55133
+#ifdef USE_SSH
ca55133
+      else if(get_protocol_family(needle->handler) == PROTO_FAMILY_SSH) {
ca55133
         if(!ssh_config_matches(needle, check))
ca55133
           continue;
ca55133
       }
ca55133
+#endif
ca55133
+#ifndef CURL_DISABLE_FTP
ca55133
+      else if(get_protocol_family(needle->handler) & PROTO_FAMILY_FTP) {
ca55133
+        /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */
ca55133
+        if(Curl_timestrcmp(needle->proto.ftpc.account,
ca55133
+                           check->proto.ftpc.account) ||
ca55133
+           Curl_timestrcmp(needle->proto.ftpc.alternative_to_user,
ca55133
+                           check->proto.ftpc.alternative_to_user) ||
ca55133
+           (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) ||
ca55133
+           (needle->proto.ftpc.ccc != check->proto.ftpc.ccc))
ca55133
+          continue;
ca55133
+      }
ca55133
+#endif
ca55133
 
ca55133
       if((needle->handler->flags&PROTOPT_SSL)
ca55133
 #ifndef CURL_DISABLE_PROXY
ca55133
diff --git a/lib/urldata.h b/lib/urldata.h
ca55133
index 9d9ca92..4e2f5b9 100644
ca55133
--- a/lib/urldata.h
ca55133
+++ b/lib/urldata.h
ca55133
@@ -1760,8 +1760,6 @@ struct UserDefined {
ca55133
 #ifndef CURL_DISABLE_NETRC
ca55133
   unsigned char use_netrc;        /* enum CURL_NETRC_OPTION values  */
ca55133
 #endif
ca55133
-  curl_usessl use_ssl;   /* if AUTH TLS is to be attempted etc, for FTP or
ca55133
-                            IMAP or POP3 or others! */
ca55133
   unsigned int new_file_perms;      /* when creating remote files */
ca55133
   unsigned int new_directory_perms; /* when creating remote dirs */
ca55133
   int ssh_auth_types;    /* allowed SSH auth types */
ca55133
@@ -1820,6 +1818,8 @@ struct UserDefined {
ca55133
   BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some
ca55133
                                 recipients */
ca55133
 #endif
ca55133
+  unsigned char use_ssl;   /* if AUTH TLS is to be attempted etc, for FTP or
ca55133
+                              IMAP or POP3 or others! (type: curl_usessl)*/
ca55133
   BIT(is_fread_set); /* has read callback been set to non-NULL? */
ca55133
 #ifndef CURL_DISABLE_TFTP
ca55133
   BIT(tftp_no_options); /* do not send TFTP options requests */
ca55133
-- 
ca55133
2.39.2
ca55133