Browse Source

Bug 1597: It was not possible to work with S3 buckets with a dot in their name

https://winscp.net/tracker/1597

Source commit: 5c3c525dbddd2350210f67779f7ebd484f9aebfa
Martin Prikryl 7 years ago
parent
commit
2345df95dd

+ 9 - 1
libs/libs3/src/request.c

@@ -1075,8 +1075,13 @@ static S3Status compose_uri(char *buffer, int bufferSize,
     if (bucketContext->bucketName &&
         bucketContext->bucketName[0]) {
         if (bucketContext->uriStyle == S3UriStyleVirtualHost) {
+#ifndef WINSCP
+            // We cannot change Host: header with neon.
+            // Instead we tweak host name validation
             if (strchr(bucketContext->bucketName, '.') == NULL) {
+#endif
                 uri_append("%s.%s", bucketContext->bucketName, hostName);
+#ifndef WINSCP
             }
             else {
                 // We'll use the hostName in the URL, and then explicitly set
@@ -1084,6 +1089,7 @@ static S3Status compose_uri(char *buffer, int bufferSize,
                 // works.
                 uri_append("%s", hostName);
             }
+#endif
         }
         else {
             uri_append("%s/%s", hostName, bucketContext->bucketName);
@@ -1238,7 +1244,9 @@ static S3Status setup_neon(Request *request,
         do_add_header(values-> fieldName);                               \
     }
 
-    // WINSCP (hostHeader is added implicitly by neon based on uri)
+    // WINSCP (hostHeader is added implicitly by neon based on uri, but for certificate check, we use base hostname
+    // as the bucket name can contain dots, for which the certificate check would fail)
+    ne_set_realhost(request->NeonSession, params->bucketContext.hostName ? params->bucketContext.hostName : defaultHostNameG);
     append_standard_header(cacheControlHeader);
     append_standard_header(contentTypeHeader);
     append_standard_header(md5Header);

+ 4 - 0
libs/neon/src/ne_openssl.c

@@ -473,7 +473,11 @@ static int check_certificate(ne_session *sess, SSL *ssl, ne_ssl_certificate *cha
     /* Check certificate was issued to this server; pass URI of
      * server. */
     memset(&server, 0, sizeof server);
+    #ifdef WINSCP
+    ne_fill_real_server_uri(sess, &server);
+    #else
     ne_fill_server_uri(sess, &server);
+    #endif
     ret = check_identity(&server, cert, NULL);
     ne_uri_free(&server);
     if (ret < 0) {

+ 4 - 0
libs/neon/src/ne_private.h

@@ -114,6 +114,10 @@ struct ne_session_s {
 
     char *user_agent; /* full User-Agent: header field */
 
+#ifdef WINSCP
+    char *realhost;
+#endif
+
 #ifdef NE_HAVE_SSL
     ne_ssl_client_cert *client_cert;
     ne_ssl_certificate *server_cert;

+ 22 - 0
libs/neon/src/ne_session.c

@@ -112,6 +112,9 @@ void ne_session_destroy(ne_session *sess)
     free_proxies(sess);
 
     if (sess->user_agent) ne_free(sess->user_agent);
+#ifdef WINSCP
+    if (sess->realhost) ne_free(sess->realhost);
+#endif
     if (sess->socks_user) ne_free(sess->socks_user);
     if (sess->socks_password) ne_free(sess->socks_password);
 
@@ -455,6 +458,25 @@ void ne_fill_server_uri(ne_session *sess, ne_uri *uri)
     uri->scheme = ne_strdup(sess->scheme);
 }
 
+#ifdef WINSCP
+void ne_set_realhost(ne_session *sess, const char *realhost)
+{
+    if (sess->realhost) ne_free(sess->realhost);
+    sess->realhost = ne_strdup(realhost);
+}
+
+void ne_fill_real_server_uri(ne_session *sess, ne_uri *uri)
+{
+    ne_fill_server_uri(sess, uri);
+
+    if (sess->realhost)
+    {
+        ne_free(uri->host);
+        uri->host = ne_strdup(sess->realhost);
+    }
+}
+#endif
+
 void ne_fill_proxy_uri(ne_session *sess, ne_uri *uri)
 {
     if (sess->proxies) {

+ 4 - 0
libs/neon/src/ne_session.h

@@ -318,6 +318,10 @@ void ne_set_connect_timeout(ne_session *sess, int timeout);
  * where token is any alpha-numeric-y string [a-zA-Z0-9]* */
 void ne_set_useragent(ne_session *sess, const char *product);
 
+#ifdef WINSCP
+void ne_set_realhost(ne_session *sess, const char *realhost);
+#endif
+
 /* Returns non-zero if next-hop server does not claim compliance to
  * HTTP/1.1 or later. */
 int ne_version_pre_http11(ne_session *sess);