FTPS support added as RFC2228 and the murray-ftp-auth-ssl draft describe it
This commit is contained in:
		| @@ -29,7 +29,7 @@ | |||||||
|  |  | ||||||
| /* This is the version number of the libcurl package from which this header | /* This is the version number of the libcurl package from which this header | ||||||
|    file origins: */ |    file origins: */ | ||||||
| #define LIBCURL_VERSION "7.10.9-CVS" | #define LIBCURL_VERSION "7.11.0-CVS" | ||||||
|  |  | ||||||
| /* This is the numeric version of the libcurl version number, meant for easier | /* This is the numeric version of the libcurl version number, meant for easier | ||||||
|    parsing and comparions by programs. The LIBCURL_VERSION_NUM define will |    parsing and comparions by programs. The LIBCURL_VERSION_NUM define will | ||||||
| @@ -45,13 +45,13 @@ | |||||||
|    always a greater number in a more recent release. It makes comparisons with |    always a greater number in a more recent release. It makes comparisons with | ||||||
|    greater than and less than work. |    greater than and less than work. | ||||||
| */ | */ | ||||||
| #define LIBCURL_VERSION_NUM 0x070a09 | #define LIBCURL_VERSION_NUM 0x070b00 | ||||||
|  |  | ||||||
| /* The numeric version number is also available "in parts" by using these | /* The numeric version number is also available "in parts" by using these | ||||||
|    defines: */ |    defines: */ | ||||||
| #define LIBCURL_VERSION_MAJOR 7 | #define LIBCURL_VERSION_MAJOR 7 | ||||||
| #define LIBCURL_VERSION_MINOR 10 | #define LIBCURL_VERSION_MINOR 11 | ||||||
| #define LIBCURL_VERSION_PATCH 9 | #define LIBCURL_VERSION_PATCH 0 | ||||||
|  |  | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								lib/dict.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								lib/dict.c
									
									
									
									
									
								
							| @@ -89,6 +89,7 @@ CURLcode Curl_dict(struct connectdata *conn) | |||||||
|                           by RFC 2229 */ |                           by RFC 2229 */ | ||||||
|   CURLcode result=CURLE_OK; |   CURLcode result=CURLE_OK; | ||||||
|   struct SessionHandle *data=conn->data; |   struct SessionHandle *data=conn->data; | ||||||
|  |   int sockfd = conn->sock[FIRSTSOCKET]; | ||||||
|  |  | ||||||
|   char *path = conn->path; |   char *path = conn->path; | ||||||
|   long *bytecount = &conn->bytecount; |   long *bytecount = &conn->bytecount; | ||||||
| @@ -134,7 +135,7 @@ CURLcode Curl_dict(struct connectdata *conn) | |||||||
|       nth = atoi(nthdef); |       nth = atoi(nthdef); | ||||||
|     } |     } | ||||||
|        |        | ||||||
|     result = Curl_sendf(conn->firstsocket, conn, |     result = Curl_sendf(sockfd, conn, | ||||||
|                         "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" |                         "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" | ||||||
|                         "MATCH " |                         "MATCH " | ||||||
|                         "%s "    /* database */ |                         "%s "    /* database */ | ||||||
| @@ -149,7 +150,7 @@ CURLcode Curl_dict(struct connectdata *conn) | |||||||
|     if(result) |     if(result) | ||||||
|       failf(data, "Failed sending DICT request"); |       failf(data, "Failed sending DICT request"); | ||||||
|     else |     else | ||||||
|       result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount, |       result = Curl_Transfer(conn, sockfd, -1, FALSE, bytecount, | ||||||
|                              -1, NULL); /* no upload */       |                              -1, NULL); /* no upload */       | ||||||
|     if(result) |     if(result) | ||||||
|       return result; |       return result; | ||||||
| @@ -184,7 +185,7 @@ CURLcode Curl_dict(struct connectdata *conn) | |||||||
|       nth = atoi(nthdef); |       nth = atoi(nthdef); | ||||||
|     } |     } | ||||||
|        |        | ||||||
|     result = Curl_sendf(conn->firstsocket, conn, |     result = Curl_sendf(sockfd, conn, | ||||||
|                         "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" |                         "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" | ||||||
|                         "DEFINE " |                         "DEFINE " | ||||||
|                         "%s "     /* database */ |                         "%s "     /* database */ | ||||||
| @@ -195,7 +196,7 @@ CURLcode Curl_dict(struct connectdata *conn) | |||||||
|     if(result) |     if(result) | ||||||
|       failf(data, "Failed sending DICT request"); |       failf(data, "Failed sending DICT request"); | ||||||
|     else |     else | ||||||
|       result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount, |       result = Curl_Transfer(conn, sockfd, -1, FALSE, bytecount, | ||||||
|                              -1, NULL); /* no upload */ |                              -1, NULL); /* no upload */ | ||||||
|      |      | ||||||
|     if(result) |     if(result) | ||||||
| @@ -213,14 +214,14 @@ CURLcode Curl_dict(struct connectdata *conn) | |||||||
|         if (ppath[i] == ':') |         if (ppath[i] == ':') | ||||||
|           ppath[i] = ' '; |           ppath[i] = ' '; | ||||||
|       } |       } | ||||||
|       result = Curl_sendf(conn->firstsocket, conn, |       result = Curl_sendf(sockfd, conn, | ||||||
|                           "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" |                           "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" | ||||||
|                           "%s\n" |                           "%s\n" | ||||||
|                           "QUIT\n", ppath); |                           "QUIT\n", ppath); | ||||||
|       if(result) |       if(result) | ||||||
|         failf(data, "Failed sending DICT request"); |         failf(data, "Failed sending DICT request"); | ||||||
|       else |       else | ||||||
|         result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount, |         result = Curl_Transfer(conn, sockfd, -1, FALSE, bytecount, | ||||||
|                                -1, NULL); |                                -1, NULL); | ||||||
|       if(result) |       if(result) | ||||||
|         return result; |         return result; | ||||||
|   | |||||||
							
								
								
									
										119
									
								
								lib/ftp.c
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								lib/ftp.c
									
									
									
									
									
								
							| @@ -126,12 +126,12 @@ static void freedirs(struct FTP *ftp) | |||||||
|  * connected. |  * connected. | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| static CURLcode AllowServerConnect(struct SessionHandle *data, | static CURLcode AllowServerConnect(struct connectdata *conn) | ||||||
|                                    struct connectdata *conn, |  | ||||||
|                                    int sock) |  | ||||||
| { | { | ||||||
|   fd_set rdset; |   fd_set rdset; | ||||||
|   struct timeval dt; |   struct timeval dt; | ||||||
|  |   struct SessionHandle *data = conn->data; | ||||||
|  |   int sock = conn->sock[SECONDARYSOCKET]; | ||||||
|    |    | ||||||
|   FD_ZERO(&rdset); |   FD_ZERO(&rdset); | ||||||
|  |  | ||||||
| @@ -169,7 +169,7 @@ static CURLcode AllowServerConnect(struct SessionHandle *data, | |||||||
|       } |       } | ||||||
|       infof(data, "Connection accepted from server\n"); |       infof(data, "Connection accepted from server\n"); | ||||||
|  |  | ||||||
|       conn->secondarysocket = s; |       conn->sock[SECONDARYSOCKET] = s; | ||||||
|       Curl_nonblock(s, TRUE); /* enable non-blocking */ |       Curl_nonblock(s, TRUE); /* enable non-blocking */ | ||||||
|     } |     } | ||||||
|     break; |     break; | ||||||
| @@ -197,7 +197,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ | |||||||
|    * Alas, read as much as possible, split up into lines, use the ending |    * Alas, read as much as possible, split up into lines, use the ending | ||||||
|    * line in a response or continue reading.  */ |    * line in a response or continue reading.  */ | ||||||
|  |  | ||||||
|   int sockfd = conn->firstsocket; |   int sockfd = conn->sock[FIRSTSOCKET]; | ||||||
|   int perline; /* count bytes per line */ |   int perline; /* count bytes per line */ | ||||||
|   bool keepon=TRUE; |   bool keepon=TRUE; | ||||||
|   ssize_t gotbytes; |   ssize_t gotbytes; | ||||||
| @@ -438,7 +438,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) | |||||||
|  |  | ||||||
|   if (data->set.tunnel_thru_httpproxy) { |   if (data->set.tunnel_thru_httpproxy) { | ||||||
|     /* We want "seamless" FTP operations through HTTP proxy tunnel */ |     /* We want "seamless" FTP operations through HTTP proxy tunnel */ | ||||||
|     result = Curl_ConnectHTTPProxyTunnel(conn, conn->firstsocket, |     result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET, | ||||||
|                                          conn->hostname, conn->remote_port); |                                          conn->hostname, conn->remote_port); | ||||||
|     if(CURLE_OK != result) |     if(CURLE_OK != result) | ||||||
|       return result; |       return result; | ||||||
| @@ -447,7 +447,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) | |||||||
|   if(conn->protocol & PROT_FTPS) { |   if(conn->protocol & PROT_FTPS) { | ||||||
|     /* FTPS is simply ftp with SSL for the control channel */ |     /* FTPS is simply ftp with SSL for the control channel */ | ||||||
|     /* now, perform the SSL initialization for this socket */ |     /* now, perform the SSL initialization for this socket */ | ||||||
|     result = Curl_SSLConnect(conn); |     result = Curl_SSLConnect(conn, FIRSTSOCKET); | ||||||
|     if(result) |     if(result) | ||||||
|       return result; |       return result; | ||||||
|   } |   } | ||||||
| @@ -481,6 +481,71 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) | |||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |   if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) { | ||||||
|  |     /* we don't have a ssl connection, try a FTPS connection now */ | ||||||
|  |     FTPSENDF(conn, "AUTH TLS", NULL); | ||||||
|  |  | ||||||
|  |     result = Curl_GetFTPResponse(&nread, conn, &ftpcode); | ||||||
|  |     if(result) | ||||||
|  |       return result; | ||||||
|  |  | ||||||
|  |     /* RFC2228 (page 5) says: | ||||||
|  |      * | ||||||
|  |      * If the server is willing to accept the named security mechanism, and | ||||||
|  |      * does not require any security data, it must respond with reply code | ||||||
|  |      * 234. | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     if(234 == ftpcode) { | ||||||
|  |       result = Curl_SSLConnect(conn, FIRSTSOCKET); | ||||||
|  |       if(result) | ||||||
|  |         return result; | ||||||
|  |       conn->protocol |= PROT_FTPS; | ||||||
|  |       conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */ | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if(conn->ssl[FIRSTSOCKET].use) { | ||||||
|  |     /* PBSZ = PROTECTION BUFFER SIZE. | ||||||
|  |  | ||||||
|  |        The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says: | ||||||
|  |  | ||||||
|  |        Specifically, the PROT command MUST be preceded by a PBSZ command | ||||||
|  |        and a PBSZ command MUST be preceded by a successful security data | ||||||
|  |        exchange (the TLS negotiation in this case) | ||||||
|  |  | ||||||
|  |        ... (and on page 8): | ||||||
|  |           | ||||||
|  |        Thus the PBSZ command must still be issued, but must have a parameter | ||||||
|  |        of '0' to indicate that no buffering is taking place and the data | ||||||
|  |        connection should not be encapsulated. | ||||||
|  |     */ | ||||||
|  |     FTPSENDF(conn, "PBSZ %d", 0); | ||||||
|  |     result = Curl_GetFTPResponse(&nread, conn, &ftpcode); | ||||||
|  |     if(result) | ||||||
|  |       return result; | ||||||
|  |  | ||||||
|  |     /* For TLS, the data connection can have one of two security levels. | ||||||
|  |  | ||||||
|  |        1)Clear (requested by 'PROT C') | ||||||
|  |  | ||||||
|  |        2)Private (requested by 'PROT P') | ||||||
|  |     */ | ||||||
|  |     if(!conn->ssl[SECONDARYSOCKET].use) { | ||||||
|  |       FTPSENDF(conn, "PROT %c", 'P'); | ||||||
|  |       result = Curl_GetFTPResponse(&nread, conn, &ftpcode); | ||||||
|  |       if(result) | ||||||
|  |         return result; | ||||||
|  |      | ||||||
|  |       if(ftpcode == 200) | ||||||
|  |         /* We have enabled SSL for the data connection! */ | ||||||
|  |         conn->ssl[SECONDARYSOCKET].use = TRUE; | ||||||
|  |  | ||||||
|  |       /* FTP servers typically responds with 500 if they decide to reject | ||||||
|  |          our 'P' request */ | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |    | ||||||
|   /* send USER */ |   /* send USER */ | ||||||
|   FTPSENDF(conn, "USER %s", ftp->user?ftp->user:""); |   FTPSENDF(conn, "USER %s", ftp->user?ftp->user:""); | ||||||
|  |  | ||||||
| @@ -666,8 +731,8 @@ CURLcode Curl_ftp_done(struct connectdata *conn) | |||||||
|   Curl_sec_fflush_fd(conn, conn->secondarysocket); |   Curl_sec_fflush_fd(conn, conn->secondarysocket); | ||||||
| #endif | #endif | ||||||
|   /* shut down the socket to inform the server we're done */ |   /* shut down the socket to inform the server we're done */ | ||||||
|   sclose(conn->secondarysocket); |   sclose(conn->sock[SECONDARYSOCKET]); | ||||||
|   conn->secondarysocket = -1; |   conn->sock[SECONDARYSOCKET] = -1; | ||||||
|  |  | ||||||
|   if(!ftp->no_transfer) { |   if(!ftp->no_transfer) { | ||||||
|     /* Let's see what the server says about the transfer we just performed, |     /* Let's see what the server says about the transfer we just performed, | ||||||
| @@ -1039,7 +1104,7 @@ CURLcode ftp_use_port(struct connectdata *conn) | |||||||
|    * I believe we should use the same address as the control connection. |    * I believe we should use the same address as the control connection. | ||||||
|    */ |    */ | ||||||
|   sslen = sizeof(ss); |   sslen = sizeof(ss); | ||||||
|   if (getsockname(conn->firstsocket, (struct sockaddr *)&ss, &sslen) < 0) |   if (getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen) < 0) | ||||||
|     return CURLE_FTP_PORT_FAILED; |     return CURLE_FTP_PORT_FAILED; | ||||||
|    |    | ||||||
|   if (getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0, |   if (getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0, | ||||||
| @@ -1205,7 +1270,7 @@ CURLcode ftp_use_port(struct connectdata *conn) | |||||||
|   /* we set the secondary socket variable to this for now, it |   /* we set the secondary socket variable to this for now, it | ||||||
|      is only so that the cleanup function will close it in case |      is only so that the cleanup function will close it in case | ||||||
|      we fail before the true secondary stuff is made */ |      we fail before the true secondary stuff is made */ | ||||||
|   conn->secondarysocket = portsock; |   conn->sock[SECONDARYSOCKET] = portsock; | ||||||
|    |    | ||||||
| #else | #else | ||||||
|   /****************************************************************** |   /****************************************************************** | ||||||
| @@ -1249,7 +1314,8 @@ CURLcode ftp_use_port(struct connectdata *conn) | |||||||
|     socklen_t sslen; |     socklen_t sslen; | ||||||
|      |      | ||||||
|     sslen = sizeof(sa); |     sslen = sizeof(sa); | ||||||
|     if (getsockname(conn->firstsocket, (struct sockaddr *)&sa, &sslen) < 0) { |     if (getsockname(conn->sock[FIRSTSOCKET], | ||||||
|  |                     (struct sockaddr *)&sa, &sslen) < 0) { | ||||||
|       failf(data, "getsockname() failed"); |       failf(data, "getsockname() failed"); | ||||||
|       return CURLE_FTP_PORT_FAILED; |       return CURLE_FTP_PORT_FAILED; | ||||||
|     } |     } | ||||||
| @@ -1526,7 +1592,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn, | |||||||
|   result = Curl_connecthost(conn, |   result = Curl_connecthost(conn, | ||||||
|                             addr, |                             addr, | ||||||
|                             connectport, |                             connectport, | ||||||
|                             &conn->secondarysocket, |                             &conn->sock[SECONDARYSOCKET], | ||||||
|                             &conninfo, |                             &conninfo, | ||||||
|                             connected); |                             connected); | ||||||
|  |  | ||||||
| @@ -1547,7 +1613,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn, | |||||||
|    |    | ||||||
|   if (data->set.tunnel_thru_httpproxy) { |   if (data->set.tunnel_thru_httpproxy) { | ||||||
|     /* We want "seamless" FTP operations through HTTP proxy tunnel */ |     /* We want "seamless" FTP operations through HTTP proxy tunnel */ | ||||||
|     result = Curl_ConnectHTTPProxyTunnel(conn, conn->secondarysocket, |     result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET, | ||||||
|                                          newhostp, newport); |                                          newhostp, newport); | ||||||
|     if(CURLE_OK != result) |     if(CURLE_OK != result) | ||||||
|       return result; |       return result; | ||||||
| @@ -1684,7 +1750,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn) | |||||||
|  |  | ||||||
|     if(data->set.ftp_use_port) { |     if(data->set.ftp_use_port) { | ||||||
|       /* PORT means we are now awaiting the server to connect to us. */ |       /* PORT means we are now awaiting the server to connect to us. */ | ||||||
|       result = AllowServerConnect(data, conn, conn->secondarysocket); |       result = AllowServerConnect(conn); | ||||||
|       if( result ) |       if( result ) | ||||||
|         return result; |         return result; | ||||||
|     } |     } | ||||||
| @@ -1697,7 +1763,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn) | |||||||
|     Curl_pgrsSetUploadSize(data, data->set.infilesize); |     Curl_pgrsSetUploadSize(data, data->set.infilesize); | ||||||
|  |  | ||||||
|     result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */ |     result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */ | ||||||
|                       conn->secondarysocket, bytecountp); |                            SECONDARYSOCKET, bytecountp); | ||||||
|     if(result) |     if(result) | ||||||
|       return result; |       return result; | ||||||
|        |        | ||||||
| @@ -1940,15 +2006,24 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn) | |||||||
|         size = downloadsize; |         size = downloadsize; | ||||||
|  |  | ||||||
|       if(data->set.ftp_use_port) { |       if(data->set.ftp_use_port) { | ||||||
|         result = AllowServerConnect(data, conn, conn->secondarysocket); |         result = AllowServerConnect(conn); | ||||||
|         if( result ) |         if( result ) | ||||||
|           return result; |           return result; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  | #if 1 | ||||||
|  |       if(conn->ssl[SECONDARYSOCKET].use) { | ||||||
|  |         /* since we only have a TCP connection, we must now do the TLS stuff */ | ||||||
|  |         infof(data, "Doing the SSL/TSL handshake on the data stream\n"); | ||||||
|  |         result = Curl_SSLConnect(conn, SECONDARYSOCKET); | ||||||
|  |         if(result) | ||||||
|  |           return result; | ||||||
|  |       } | ||||||
|  | #endif | ||||||
|       infof(data, "Getting file with size: %d\n", size); |       infof(data, "Getting file with size: %d\n", size); | ||||||
|  |  | ||||||
|       /* FTP download: */ |       /* FTP download: */ | ||||||
|       result=Curl_Transfer(conn, conn->secondarysocket, size, FALSE, |       result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE, | ||||||
|                            bytecountp, |                            bytecountp, | ||||||
|                            -1, NULL); /* no upload here */ |                            -1, NULL); /* no upload here */ | ||||||
|       if(result) |       if(result) | ||||||
| @@ -2232,10 +2307,10 @@ CURLcode Curl_ftp(struct connectdata *conn) | |||||||
|     if(connected) |     if(connected) | ||||||
|       retcode = Curl_ftp_nextconnect(conn); |       retcode = Curl_ftp_nextconnect(conn); | ||||||
|  |  | ||||||
|     if(retcode && (conn->secondarysocket >= 0)) { |     if(retcode && (conn->sock[SECONDARYSOCKET] >= 0)) { | ||||||
|       /* Failure detected, close the second socket if it was created already */ |       /* Failure detected, close the second socket if it was created already */ | ||||||
|       sclose(conn->secondarysocket); |       sclose(conn->sock[SECONDARYSOCKET]); | ||||||
|       conn->secondarysocket = -1; |       conn->sock[SECONDARYSOCKET] = -1; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if(ftp->no_transfer) |     if(ftp->no_transfer) | ||||||
| @@ -2280,7 +2355,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn, | |||||||
|   write_len = strlen(s); |   write_len = strlen(s); | ||||||
|  |  | ||||||
|   do { |   do { | ||||||
|     res = Curl_write(conn, conn->firstsocket, sptr, write_len, |     res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, | ||||||
|                      &bytes_written); |                      &bytes_written); | ||||||
|  |  | ||||||
|     if(CURLE_OK != res) |     if(CURLE_OK != res) | ||||||
|   | |||||||
							
								
								
									
										33
									
								
								lib/http.c
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								lib/http.c
									
									
									
									
									
								
							| @@ -500,7 +500,6 @@ send_buffer *add_buffer_init(void) | |||||||
|  */ |  */ | ||||||
| static | static | ||||||
| CURLcode add_buffer_send(send_buffer *in, | CURLcode add_buffer_send(send_buffer *in, | ||||||
|                          int sockfd, |  | ||||||
|                          struct connectdata *conn, |                          struct connectdata *conn, | ||||||
|                          long *bytes_written) /* add the number of sent |                          long *bytes_written) /* add the number of sent | ||||||
|                                                  bytes to this counter */ |                                                  bytes to this counter */ | ||||||
| @@ -511,6 +510,7 @@ CURLcode add_buffer_send(send_buffer *in, | |||||||
|   int size; |   int size; | ||||||
|   struct HTTP *http = conn->proto.http; |   struct HTTP *http = conn->proto.http; | ||||||
|   int sendsize; |   int sendsize; | ||||||
|  |   int sockfd = conn->sock[FIRSTSOCKET]; | ||||||
|  |  | ||||||
|   /* The looping below is required since we use non-blocking sockets, but due |   /* The looping below is required since we use non-blocking sockets, but due | ||||||
|      to the circumstances we will just loop and try again and again etc */ |      to the circumstances we will just loop and try again and again etc */ | ||||||
| @@ -708,7 +708,7 @@ Curl_compareheader(char *headerline,    /* line to check */ | |||||||
|  */ |  */ | ||||||
|  |  | ||||||
| CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, | CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, | ||||||
|                                      int tunnelsocket, |                                      int sockindex, | ||||||
|                                      char *hostname, |                                      char *hostname, | ||||||
|                                      int remote_port) |                                      int remote_port) | ||||||
| { | { | ||||||
| @@ -729,6 +729,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, | |||||||
|   fd_set readfd; |   fd_set readfd; | ||||||
|   char *line_start; |   char *line_start; | ||||||
|   char *host_port; |   char *host_port; | ||||||
|  |   int tunnelsocket = conn->sock[sockindex]; | ||||||
|  |  | ||||||
| #define SELECT_OK      0 | #define SELECT_OK      0 | ||||||
| #define SELECT_ERROR   1 | #define SELECT_ERROR   1 | ||||||
| @@ -936,7 +937,7 @@ CURLcode Curl_http_connect(struct connectdata *conn) | |||||||
|      ((conn->protocol & PROT_HTTPS) || data->set.tunnel_thru_httpproxy)) { |      ((conn->protocol & PROT_HTTPS) || data->set.tunnel_thru_httpproxy)) { | ||||||
|  |  | ||||||
|     /* either HTTPS over proxy, OR explicitly asked for a tunnel */ |     /* either HTTPS over proxy, OR explicitly asked for a tunnel */ | ||||||
|     result = Curl_ConnectHTTPProxyTunnel(conn, conn->firstsocket, |     result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET, | ||||||
|                                          conn->hostname, conn->remote_port); |                                          conn->hostname, conn->remote_port); | ||||||
|     if(CURLE_OK != result) |     if(CURLE_OK != result) | ||||||
|       return result; |       return result; | ||||||
| @@ -944,7 +945,7 @@ CURLcode Curl_http_connect(struct connectdata *conn) | |||||||
|  |  | ||||||
|   if(conn->protocol & PROT_HTTPS) { |   if(conn->protocol & PROT_HTTPS) { | ||||||
|     /* now, perform the SSL initialization for this socket */ |     /* now, perform the SSL initialization for this socket */ | ||||||
|     result = Curl_SSLConnect(conn); |     result = Curl_SSLConnect(conn, FIRSTSOCKET); | ||||||
|     if(result) |     if(result) | ||||||
|       return result; |       return result; | ||||||
|   } |   } | ||||||
| @@ -1491,15 +1492,15 @@ CURLcode Curl_http(struct connectdata *conn) | |||||||
|       Curl_pgrsSetUploadSize(data, http->postsize); |       Curl_pgrsSetUploadSize(data, http->postsize); | ||||||
|  |  | ||||||
|       /* fire away the whole request to the server */ |       /* fire away the whole request to the server */ | ||||||
|       result = add_buffer_send(req_buffer, conn->firstsocket, conn,  |       result = add_buffer_send(req_buffer, conn,  | ||||||
|                                &data->info.request_size); |                                &data->info.request_size); | ||||||
|       if(result) |       if(result) | ||||||
|         failf(data, "Failed sending POST request"); |         failf(data, "Failed sending POST request"); | ||||||
|       else |       else | ||||||
|         /* setup variables for the upcoming transfer */ |         /* setup variables for the upcoming transfer */ | ||||||
|         result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, |         result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE, | ||||||
|                                &http->readbytecount, |                                &http->readbytecount, | ||||||
|                                conn->firstsocket, |                                FIRSTSOCKET, | ||||||
|                                &http->writebytecount); |                                &http->writebytecount); | ||||||
|       if(result) { |       if(result) { | ||||||
|         Curl_formclean(http->sendit); /* free that whole lot */ |         Curl_formclean(http->sendit); /* free that whole lot */ | ||||||
| @@ -1521,15 +1522,15 @@ CURLcode Curl_http(struct connectdata *conn) | |||||||
|       Curl_pgrsSetUploadSize(data, data->set.infilesize); |       Curl_pgrsSetUploadSize(data, data->set.infilesize); | ||||||
|  |  | ||||||
|       /* this sends the buffer and frees all the buffer resources */ |       /* this sends the buffer and frees all the buffer resources */ | ||||||
|       result = add_buffer_send(req_buffer, conn->firstsocket, conn, |       result = add_buffer_send(req_buffer, conn, | ||||||
|                                &data->info.request_size); |                                &data->info.request_size); | ||||||
|       if(result) |       if(result) | ||||||
|         failf(data, "Failed sending POST request"); |         failf(data, "Failed sending POST request"); | ||||||
|       else |       else | ||||||
|         /* prepare for transfer */ |         /* prepare for transfer */ | ||||||
|         result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, |         result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE, | ||||||
|                                &http->readbytecount, |                                &http->readbytecount, | ||||||
|                                conn->firstsocket, |                                FIRSTSOCKET, | ||||||
|                                &http->writebytecount); |                                &http->writebytecount); | ||||||
|       if(result) |       if(result) | ||||||
|         return result; |         return result; | ||||||
| @@ -1602,16 +1603,16 @@ CURLcode Curl_http(struct connectdata *conn) | |||||||
|         http->postdata = (char *)&http->postdata; |         http->postdata = (char *)&http->postdata; | ||||||
|       } |       } | ||||||
|       /* issue the request */ |       /* issue the request */ | ||||||
|       result = add_buffer_send(req_buffer, conn->firstsocket, conn, |       result = add_buffer_send(req_buffer, conn, | ||||||
|                                &data->info.request_size); |                                &data->info.request_size); | ||||||
|  |  | ||||||
|       if(result) |       if(result) | ||||||
|         failf(data, "Failed sending HTTP POST request"); |         failf(data, "Failed sending HTTP POST request"); | ||||||
|       else |       else | ||||||
|         result = |         result = | ||||||
|           Curl_Transfer(conn, conn->firstsocket, -1, TRUE, |           Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE, | ||||||
|                         &http->readbytecount, |                         &http->readbytecount, | ||||||
|                         http->postdata?conn->firstsocket:-1, |                         http->postdata?FIRSTSOCKET:-1, | ||||||
|                         http->postdata?&http->writebytecount:NULL); |                         http->postdata?&http->writebytecount:NULL); | ||||||
|       break; |       break; | ||||||
|  |  | ||||||
| @@ -1619,16 +1620,16 @@ CURLcode Curl_http(struct connectdata *conn) | |||||||
|       add_buffer(req_buffer, "\r\n", 2); |       add_buffer(req_buffer, "\r\n", 2); | ||||||
|        |        | ||||||
|       /* issue the request */ |       /* issue the request */ | ||||||
|       result = add_buffer_send(req_buffer, conn->firstsocket, conn, |       result = add_buffer_send(req_buffer, conn, | ||||||
|                                &data->info.request_size); |                                &data->info.request_size); | ||||||
|  |  | ||||||
|       if(result) |       if(result) | ||||||
|         failf(data, "Failed sending HTTP request"); |         failf(data, "Failed sending HTTP request"); | ||||||
|       else |       else | ||||||
|         /* HTTP GET/HEAD download: */ |         /* HTTP GET/HEAD download: */ | ||||||
|         result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, |         result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE, | ||||||
|                                &http->readbytecount, |                                &http->readbytecount, | ||||||
|                                http->postdata?conn->firstsocket:-1, |                                http->postdata?FIRSTSOCKET:-1, | ||||||
|                                http->postdata?&http->writebytecount:NULL); |                                http->postdata?&http->writebytecount:NULL); | ||||||
|     } |     } | ||||||
|     if(result) |     if(result) | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								lib/multi.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								lib/multi.c
									
									
									
									
									
								
							| @@ -266,7 +266,7 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle, | |||||||
|         int sockfd; |         int sockfd; | ||||||
|  |  | ||||||
|         if(CURLM_STATE_WAITCONNECT == easy->state) { |         if(CURLM_STATE_WAITCONNECT == easy->state) { | ||||||
|           sockfd = conn->firstsocket; |           sockfd = conn->sock[FIRSTSOCKET]; | ||||||
|           FD_SET(sockfd, write_fd_set); |           FD_SET(sockfd, write_fd_set); | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
| @@ -275,7 +275,7 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle, | |||||||
|              to connect to us. It makes a difference in the way: if we |              to connect to us. It makes a difference in the way: if we | ||||||
|              connect to the site we wait for the socket to become writable, if  |              connect to the site we wait for the socket to become writable, if  | ||||||
|              the site connects to us we wait for it to become readable */ |              the site connects to us we wait for it to become readable */ | ||||||
|           sockfd = conn->secondarysocket; |           sockfd = conn->sock[SECONDARYSOCKET]; | ||||||
|           FD_SET(sockfd, write_fd_set); |           FD_SET(sockfd, write_fd_set); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -390,7 +390,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) | |||||||
|     case CURLM_STATE_WAITCONNECT: |     case CURLM_STATE_WAITCONNECT: | ||||||
|       /* awaiting a completion of an asynch connect */ |       /* awaiting a completion of an asynch connect */ | ||||||
|       easy->result = Curl_is_connected(easy->easy_conn, |       easy->result = Curl_is_connected(easy->easy_conn, | ||||||
|                                        easy->easy_conn->firstsocket, |                                        easy->easy_conn->sock[FIRSTSOCKET], | ||||||
|                                        &connected); |                                        &connected); | ||||||
|       if(connected) |       if(connected) | ||||||
|         easy->result = Curl_protocol_connect(easy->easy_conn, NULL); |         easy->result = Curl_protocol_connect(easy->easy_conn, NULL); | ||||||
| @@ -437,7 +437,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) | |||||||
|        * First, check if we really are ready to do more. |        * First, check if we really are ready to do more. | ||||||
|        */ |        */ | ||||||
|       easy->result = Curl_is_connected(easy->easy_conn, |       easy->result = Curl_is_connected(easy->easy_conn, | ||||||
|                                        easy->easy_conn->secondarysocket, |                                        easy->easy_conn->sock[SECONDARYSOCKET], | ||||||
|                                        &connected); |                                        &connected); | ||||||
|       if(connected) { |       if(connected) { | ||||||
|         /* |         /* | ||||||
| @@ -465,11 +465,11 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) | |||||||
|          * possibly know if the connection is in a good shape or not now. */ |          * possibly know if the connection is in a good shape or not now. */ | ||||||
|         easy->easy_conn->bits.close = TRUE; |         easy->easy_conn->bits.close = TRUE; | ||||||
|  |  | ||||||
|         if(-1 !=easy->easy_conn->secondarysocket) { |         if(-1 !=easy->easy_conn->sock[SECONDARYSOCKET]) { | ||||||
|           /* if we failed anywhere, we must clean up the secondary socket if |           /* if we failed anywhere, we must clean up the secondary socket if | ||||||
|              it was used */ |              it was used */ | ||||||
|           sclose(easy->easy_conn->secondarysocket); |           sclose(easy->easy_conn->sock[SECONDARYSOCKET]); | ||||||
|           easy->easy_conn->secondarysocket=-1; |           easy->easy_conn->sock[SECONDARYSOCKET]=-1; | ||||||
|         } |         } | ||||||
|         Curl_posttransfer(easy->easy_handle); |         Curl_posttransfer(easy->easy_handle); | ||||||
|         Curl_done(easy->easy_conn); |         Curl_done(easy->easy_conn); | ||||||
|   | |||||||
							
								
								
									
										35
									
								
								lib/sendf.c
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								lib/sendf.c
									
									
									
									
									
								
							| @@ -220,23 +220,27 @@ CURLcode Curl_sendf(int sockfd, struct connectdata *conn, | |||||||
|  * to the server. Works with plain sockets, SSL or kerberos. |  * to the server. Works with plain sockets, SSL or kerberos. | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| CURLcode Curl_write(struct connectdata *conn, int sockfd, | CURLcode Curl_write(struct connectdata *conn, | ||||||
|  |                     int sockfd, | ||||||
|                     void *mem, size_t len, |                     void *mem, size_t len, | ||||||
|                     ssize_t *written) |                     ssize_t *written) | ||||||
| { | { | ||||||
|   ssize_t bytes_written; |   ssize_t bytes_written; | ||||||
|   CURLcode retcode; |   CURLcode retcode; | ||||||
|   (void)conn; |  | ||||||
|  |  | ||||||
| #ifdef USE_SSLEAY | #ifdef USE_SSLEAY | ||||||
|  |   /* Set 'num' to 0 or 1, depending on which socket that has been sent here. | ||||||
|  |      If it is the second socket, we set num to 1. Otherwise to 0. This lets | ||||||
|  |      us use the correct ssl handle. */ | ||||||
|  |   int num = (sockfd == conn->sock[SECONDARYSOCKET]); | ||||||
|   /* SSL_write() is said to return 'int' while write() and send() returns |   /* SSL_write() is said to return 'int' while write() and send() returns | ||||||
|      'size_t' */ |      'size_t' */ | ||||||
|   if (conn->ssl.use) { |   if (conn->ssl[num].use) { | ||||||
|     int err; |     int err; | ||||||
|     int rc = SSL_write(conn->ssl.handle, mem, len); |     int rc = SSL_write(conn->ssl[num].handle, mem, len); | ||||||
|  |  | ||||||
|     if(rc < 0) { |     if(rc < 0) { | ||||||
|       err = SSL_get_error(conn->ssl.handle, rc); |       err = SSL_get_error(conn->ssl[num].handle, rc); | ||||||
|      |      | ||||||
|       switch(err) { |       switch(err) { | ||||||
|       case SSL_ERROR_WANT_READ: |       case SSL_ERROR_WANT_READ: | ||||||
| @@ -271,6 +275,8 @@ CURLcode Curl_write(struct connectdata *conn, int sockfd, | |||||||
|     bytes_written = rc; |     bytes_written = rc; | ||||||
|   } |   } | ||||||
|   else { |   else { | ||||||
|  | #else | ||||||
|  |   (void)conn; | ||||||
| #endif | #endif | ||||||
| #ifdef KRB4 | #ifdef KRB4 | ||||||
|     if(conn->sec_complete) { |     if(conn->sec_complete) { | ||||||
| @@ -364,16 +370,20 @@ int Curl_read(struct connectdata *conn, | |||||||
|               ssize_t *n) |               ssize_t *n) | ||||||
| { | { | ||||||
|   ssize_t nread; |   ssize_t nread; | ||||||
|   (void)conn; | #ifdef USE_SSLEAY | ||||||
|  |   /* Set 'num' to 0 or 1, depending on which socket that has been sent here. | ||||||
|  |      If it is the second socket, we set num to 1. Otherwise to 0. This lets | ||||||
|  |      us use the correct ssl handle. */ | ||||||
|  |   int num = (sockfd == conn->sock[SECONDARYSOCKET]); | ||||||
|  |  | ||||||
|   *n=0; /* reset amount to zero */ |   *n=0; /* reset amount to zero */ | ||||||
|  |  | ||||||
| #ifdef USE_SSLEAY |   if (conn->ssl[num].use) { | ||||||
|   if (conn->ssl.use) { |     nread = SSL_read(conn->ssl[num].handle, buf, buffersize); | ||||||
|     nread = SSL_read(conn->ssl.handle, buf, buffersize); |  | ||||||
|  |  | ||||||
|     if(nread < 0) { |     if(nread < 0) { | ||||||
|       /* failed SSL_read */ |       /* failed SSL_read */ | ||||||
|       int err = SSL_get_error(conn->ssl.handle, nread); |       int err = SSL_get_error(conn->ssl[num].handle, nread); | ||||||
|  |  | ||||||
|       switch(err) { |       switch(err) { | ||||||
|       case SSL_ERROR_NONE: /* this is not an error */ |       case SSL_ERROR_NONE: /* this is not an error */ | ||||||
| @@ -398,13 +408,16 @@ int Curl_read(struct connectdata *conn, | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   else { |   else { | ||||||
|  | #else | ||||||
|  |     (void)conn; | ||||||
| #endif | #endif | ||||||
|  |     *n=0; /* reset amount to zero */ | ||||||
| #ifdef KRB4 | #ifdef KRB4 | ||||||
|     if(conn->sec_complete) |     if(conn->sec_complete) | ||||||
|       nread = Curl_sec_read(conn, sockfd, buf, buffersize); |       nread = Curl_sec_read(conn, sockfd, buf, buffersize); | ||||||
|     else |     else | ||||||
| #endif | #endif | ||||||
|       nread = sread (sockfd, buf, buffersize); |       nread = sread(sockfd, buf, buffersize); | ||||||
|  |  | ||||||
|     if(-1 == nread) { |     if(-1 == nread) { | ||||||
|       int err = Curl_ourerrno(); |       int err = Curl_ourerrno(); | ||||||
|   | |||||||
							
								
								
									
										151
									
								
								lib/ssluse.c
									
									
									
									
									
								
							
							
						
						
									
										151
									
								
								lib/ssluse.c
									
									
									
									
									
								
							| @@ -223,6 +223,7 @@ static int do_file_type(const char *type) | |||||||
|  |  | ||||||
| static | static | ||||||
| int cert_stuff(struct connectdata *conn, | int cert_stuff(struct connectdata *conn, | ||||||
|  |                SSL_CTX* ctx, | ||||||
|                char *cert_file, |                char *cert_file, | ||||||
|                const char *cert_type, |                const char *cert_type, | ||||||
|                char *key_file, |                char *key_file, | ||||||
| @@ -246,11 +247,11 @@ int cert_stuff(struct connectdata *conn, | |||||||
|       /* |       /* | ||||||
|        * We set the password in the callback userdata |        * We set the password in the callback userdata | ||||||
|        */ |        */ | ||||||
|       SSL_CTX_set_default_passwd_cb_userdata(conn->ssl.ctx, |       SSL_CTX_set_default_passwd_cb_userdata(ctx, | ||||||
|                                              data->set.key_passwd); |                                              data->set.key_passwd); | ||||||
| #endif | #endif | ||||||
|       /* Set passwd callback: */ |       /* Set passwd callback: */ | ||||||
|       SSL_CTX_set_default_passwd_cb(conn->ssl.ctx, passwd_callback); |       SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     file_type = do_file_type(cert_type); |     file_type = do_file_type(cert_type); | ||||||
| @@ -258,7 +259,7 @@ int cert_stuff(struct connectdata *conn, | |||||||
|     switch(file_type) { |     switch(file_type) { | ||||||
|     case SSL_FILETYPE_PEM: |     case SSL_FILETYPE_PEM: | ||||||
|       /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ |       /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ | ||||||
|       if(SSL_CTX_use_certificate_chain_file(conn->ssl.ctx, |       if(SSL_CTX_use_certificate_chain_file(ctx, | ||||||
|                                             cert_file) != 1) { |                                             cert_file) != 1) { | ||||||
|         failf(data, "unable to set certificate file (wrong password?)"); |         failf(data, "unable to set certificate file (wrong password?)"); | ||||||
|         return 0; |         return 0; | ||||||
| @@ -269,7 +270,7 @@ int cert_stuff(struct connectdata *conn, | |||||||
|       /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but |       /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but | ||||||
|          we use the case above for PEM so this can only be performed with |          we use the case above for PEM so this can only be performed with | ||||||
|          ASN1 files. */ |          ASN1 files. */ | ||||||
|       if(SSL_CTX_use_certificate_file(conn->ssl.ctx, |       if(SSL_CTX_use_certificate_file(ctx, | ||||||
|                                       cert_file, |                                       cert_file, | ||||||
|                                       file_type) != 1) { |                                       file_type) != 1) { | ||||||
|         failf(data, "unable to set certificate file (wrong password?)"); |         failf(data, "unable to set certificate file (wrong password?)"); | ||||||
| @@ -293,9 +294,7 @@ int cert_stuff(struct connectdata *conn, | |||||||
|         /* cert & key can only be in PEM case in the same file */ |         /* cert & key can only be in PEM case in the same file */ | ||||||
|         key_file=cert_file; |         key_file=cert_file; | ||||||
|     case SSL_FILETYPE_ASN1: |     case SSL_FILETYPE_ASN1: | ||||||
|       if(SSL_CTX_use_PrivateKey_file(conn->ssl.ctx, |       if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) { | ||||||
|                                       key_file, |  | ||||||
|                                       file_type) != 1) { |  | ||||||
|         failf(data, "unable to set private key file: '%s' type %s\n", |         failf(data, "unable to set private key file: '%s' type %s\n", | ||||||
|               key_file, key_type?key_type:"PEM"); |               key_file, key_type?key_type:"PEM"); | ||||||
|         return 0; |         return 0; | ||||||
| @@ -322,7 +321,7 @@ int cert_stuff(struct connectdata *conn, | |||||||
|             failf(data, "failed to load private key from crypto engine\n"); |             failf(data, "failed to load private key from crypto engine\n"); | ||||||
|             return 0; |             return 0; | ||||||
|           } |           } | ||||||
|           if(SSL_CTX_use_PrivateKey(conn->ssl.ctx, priv_key) != 1) { |           if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) { | ||||||
|             failf(data, "unable to set private key\n"); |             failf(data, "unable to set private key\n"); | ||||||
|             EVP_PKEY_free(priv_key); |             EVP_PKEY_free(priv_key); | ||||||
|             return 0; |             return 0; | ||||||
| @@ -344,7 +343,7 @@ int cert_stuff(struct connectdata *conn, | |||||||
|       return 0; |       return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ssl=SSL_new(conn->ssl.ctx); |     ssl=SSL_new(ctx); | ||||||
|     x509=SSL_get_certificate(ssl); |     x509=SSL_get_certificate(ssl); | ||||||
|  |  | ||||||
|     /* This version was provided by Evan Jordan and is supposed to not |     /* This version was provided by Evan Jordan and is supposed to not | ||||||
| @@ -363,7 +362,7 @@ int cert_stuff(struct connectdata *conn, | |||||||
|      |      | ||||||
|     /* Now we know that a key and cert have been set against |     /* Now we know that a key and cert have been set against | ||||||
|      * the SSL context */ |      * the SSL context */ | ||||||
|     if(!SSL_CTX_check_private_key(conn->ssl.ctx)) { |     if(!SSL_CTX_check_private_key(ctx)) { | ||||||
|       failf(data, "Private key does not match the certificate public key"); |       failf(data, "Private key does not match the certificate public key"); | ||||||
|       return(0); |       return(0); | ||||||
|     } |     } | ||||||
| @@ -453,6 +452,13 @@ void Curl_SSL_cleanup(void) | |||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #ifndef USE_SSLEAY | ||||||
|  | void Curl_SSL_Close(struct connectdata *conn) | ||||||
|  | { | ||||||
|  |   (void)conn; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #ifdef USE_SSLEAY | #ifdef USE_SSLEAY | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -460,7 +466,8 @@ void Curl_SSL_cleanup(void) | |||||||
|  */ |  */ | ||||||
| void Curl_SSL_Close(struct connectdata *conn) | void Curl_SSL_Close(struct connectdata *conn) | ||||||
| { | { | ||||||
|   if(conn->ssl.use) { |   if(conn->ssl[FIRSTSOCKET].use) { | ||||||
|  |     int i; | ||||||
|     /* |     /* | ||||||
|       ERR_remove_state() frees the error queue associated with |       ERR_remove_state() frees the error queue associated with | ||||||
|       thread pid.  If pid == 0, the current thread will have its |       thread pid.  If pid == 0, the current thread will have its | ||||||
| @@ -472,18 +479,22 @@ void Curl_SSL_Close(struct connectdata *conn) | |||||||
|     */ |     */ | ||||||
|     ERR_remove_state(0); |     ERR_remove_state(0); | ||||||
|  |  | ||||||
|     if(conn->ssl.handle) { |     for(i=0; i<2; i++) { | ||||||
|       (void)SSL_shutdown(conn->ssl.handle); |       struct ssl_connect_data *connssl = &conn->ssl[i]; | ||||||
|       SSL_set_connect_state(conn->ssl.handle); |  | ||||||
|        |        | ||||||
|       SSL_free (conn->ssl.handle); |       if(connssl->handle) { | ||||||
|       conn->ssl.handle = NULL; |         (void)SSL_shutdown(connssl->handle); | ||||||
|  |         SSL_set_connect_state(connssl->handle); | ||||||
|  |          | ||||||
|  |         SSL_free (connssl->handle); | ||||||
|  |         connssl->handle = NULL; | ||||||
|       } |       } | ||||||
|     if(conn->ssl.ctx) { |       if(connssl->ctx) { | ||||||
|       SSL_CTX_free (conn->ssl.ctx); |         SSL_CTX_free (connssl->ctx); | ||||||
|       conn->ssl.ctx = NULL; |         connssl->ctx = NULL; | ||||||
|  |       } | ||||||
|  |       connssl->use = FALSE; /* get back to ordinary socket usage */ | ||||||
|     } |     } | ||||||
|     conn->ssl.use = FALSE; /* get back to ordinary socket usage */ |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -598,7 +609,8 @@ int Curl_SSL_Close_All(struct SessionHandle *data) | |||||||
| /* | /* | ||||||
|  * Extract the session id and store it in the session cache. |  * Extract the session id and store it in the session cache. | ||||||
|  */ |  */ | ||||||
| static int Store_SSL_Session(struct connectdata *conn) | static int Store_SSL_Session(struct connectdata *conn, | ||||||
|  |                              struct ssl_connect_data *ssl) | ||||||
| { | { | ||||||
|   SSL_SESSION *ssl_sessionid; |   SSL_SESSION *ssl_sessionid; | ||||||
|   int i; |   int i; | ||||||
| @@ -609,14 +621,14 @@ static int Store_SSL_Session(struct connectdata *conn) | |||||||
|   /* ask OpenSSL, say please */ |   /* ask OpenSSL, say please */ | ||||||
|  |  | ||||||
| #ifdef HAVE_SSL_GET1_SESSION | #ifdef HAVE_SSL_GET1_SESSION | ||||||
|   ssl_sessionid = SSL_get1_session(conn->ssl.handle); |   ssl_sessionid = SSL_get1_session(ssl->handle); | ||||||
|  |  | ||||||
|   /* SSL_get1_session() will increment the reference |   /* SSL_get1_session() will increment the reference | ||||||
|      count and the session will stay in memory until explicitly freed with |      count and the session will stay in memory until explicitly freed with | ||||||
|      SSL_SESSION_free(3), regardless of its state.  |      SSL_SESSION_free(3), regardless of its state.  | ||||||
|      This function was introduced in openssl 0.9.5a. */ |      This function was introduced in openssl 0.9.5a. */ | ||||||
| #else | #else | ||||||
|   ssl_sessionid = SSL_get_session(conn->ssl.handle); |   ssl_sessionid = SSL_get_session(ssl->handle); | ||||||
|  |  | ||||||
|   /* if SSL_get1_session() is unavailable, use SSL_get_session(). |   /* if SSL_get1_session() is unavailable, use SSL_get_session(). | ||||||
|      This is an inferior option because the session can be flushed |      This is an inferior option because the session can be flushed | ||||||
| @@ -765,7 +777,8 @@ cert_hostcheck(const char *certname, const char *hostname) | |||||||
|    in the certificate and must exactly match the IP in the URI. |    in the certificate and must exactly match the IP in the URI. | ||||||
|  |  | ||||||
| */ | */ | ||||||
| static CURLcode verifyhost(struct connectdata *conn) | static CURLcode verifyhost(struct connectdata *conn, | ||||||
|  |                            X509 *server_cert) | ||||||
| { | { | ||||||
|   char peer_CN[257]; |   char peer_CN[257]; | ||||||
|   bool matched = FALSE; /* no alternative match yet */ |   bool matched = FALSE; /* no alternative match yet */ | ||||||
| @@ -793,8 +806,7 @@ static CURLcode verifyhost(struct connectdata *conn) | |||||||
|     } |     } | ||||||
|    |    | ||||||
|   /* get a "list" of alternative names */ |   /* get a "list" of alternative names */ | ||||||
|   altnames = X509_get_ext_d2i(conn->ssl.server_cert, NID_subject_alt_name, |   altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL); | ||||||
|                               NULL, NULL); |  | ||||||
|    |    | ||||||
|   if(altnames) { |   if(altnames) { | ||||||
|     int hostlen; |     int hostlen; | ||||||
| @@ -856,7 +868,7 @@ static CURLcode verifyhost(struct connectdata *conn) | |||||||
|     infof(data, "\t subjectAltName: %s matched\n", conn->hostname); |     infof(data, "\t subjectAltName: %s matched\n", conn->hostname); | ||||||
|   else { |   else { | ||||||
|     bool obtain=FALSE; |     bool obtain=FALSE; | ||||||
|     if(X509_NAME_get_text_by_NID(X509_get_subject_name(conn->ssl.server_cert), |     if(X509_NAME_get_text_by_NID(X509_get_subject_name(server_cert), | ||||||
|                                  NID_commonName, |                                  NID_commonName, | ||||||
|                                  peer_CN, |                                  peer_CN, | ||||||
|                                  sizeof(peer_CN)) < 0) { |                                  sizeof(peer_CN)) < 0) { | ||||||
| @@ -896,7 +908,8 @@ static CURLcode verifyhost(struct connectdata *conn) | |||||||
|  |  | ||||||
| /* ====================================================== */ | /* ====================================================== */ | ||||||
| CURLcode | CURLcode | ||||||
| Curl_SSLConnect(struct connectdata *conn) | Curl_SSLConnect(struct connectdata *conn, | ||||||
|  |                 int sockindex) | ||||||
| { | { | ||||||
|   CURLcode retcode = CURLE_OK; |   CURLcode retcode = CURLE_OK; | ||||||
|  |  | ||||||
| @@ -908,9 +921,11 @@ Curl_SSLConnect(struct connectdata *conn) | |||||||
|   SSL_METHOD *req_method; |   SSL_METHOD *req_method; | ||||||
|   SSL_SESSION *ssl_sessionid=NULL; |   SSL_SESSION *ssl_sessionid=NULL; | ||||||
|   ASN1_TIME *certdate; |   ASN1_TIME *certdate; | ||||||
|  |   int sockfd = conn->sock[sockindex]; | ||||||
|  |   struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | ||||||
|  |  | ||||||
|   /* mark this is being ssl enabled from here on out. */ |   /* mark this is being ssl enabled from here on out. */ | ||||||
|   conn->ssl.use = TRUE; |   connssl->use = TRUE; | ||||||
|  |  | ||||||
|   if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) { |   if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) { | ||||||
|     /* Make funny stuff to get random input */ |     /* Make funny stuff to get random input */ | ||||||
| @@ -937,9 +952,9 @@ Curl_SSLConnect(struct connectdata *conn) | |||||||
|     break; |     break; | ||||||
|   } |   } | ||||||
|      |      | ||||||
|   conn->ssl.ctx = SSL_CTX_new(req_method); |   connssl->ctx = SSL_CTX_new(req_method); | ||||||
|  |  | ||||||
|   if(!conn->ssl.ctx) { |   if(!connssl->ctx) { | ||||||
|     failf(data, "SSL: couldn't create a context!"); |     failf(data, "SSL: couldn't create a context!"); | ||||||
|     return CURLE_OUT_OF_MEMORY; |     return CURLE_OUT_OF_MEMORY; | ||||||
|   } |   } | ||||||
| @@ -952,10 +967,11 @@ Curl_SSLConnect(struct connectdata *conn) | |||||||
|      implementations is desired." |      implementations is desired." | ||||||
|  |  | ||||||
|   */ |   */ | ||||||
|   SSL_CTX_set_options(conn->ssl.ctx, SSL_OP_ALL); |   SSL_CTX_set_options(connssl->ctx, SSL_OP_ALL); | ||||||
|      |      | ||||||
|   if(data->set.cert) { |   if(data->set.cert) { | ||||||
|     if(!cert_stuff(conn, |     if(!cert_stuff(conn, | ||||||
|  |                    connssl->ctx, | ||||||
|                    data->set.cert, |                    data->set.cert, | ||||||
|                    data->set.cert_type, |                    data->set.cert_type, | ||||||
|                    data->set.key, |                    data->set.key, | ||||||
| @@ -966,7 +982,7 @@ Curl_SSLConnect(struct connectdata *conn) | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   if(data->set.ssl.cipher_list) { |   if(data->set.ssl.cipher_list) { | ||||||
|     if(!SSL_CTX_set_cipher_list(conn->ssl.ctx, |     if(!SSL_CTX_set_cipher_list(connssl->ctx, | ||||||
|                                 data->set.ssl.cipher_list)) { |                                 data->set.ssl.cipher_list)) { | ||||||
|       failf(data, "failed setting cipher list"); |       failf(data, "failed setting cipher list"); | ||||||
|       return CURLE_SSL_CIPHER; |       return CURLE_SSL_CIPHER; | ||||||
| @@ -976,7 +992,7 @@ Curl_SSLConnect(struct connectdata *conn) | |||||||
|   if (data->set.ssl.CAfile || data->set.ssl.CApath) { |   if (data->set.ssl.CAfile || data->set.ssl.CApath) { | ||||||
|     /* tell SSL where to find CA certificates that are used to verify |     /* tell SSL where to find CA certificates that are used to verify | ||||||
|        the servers certificate. */ |        the servers certificate. */ | ||||||
|     if (!SSL_CTX_load_verify_locations(conn->ssl.ctx, data->set.ssl.CAfile, |     if (!SSL_CTX_load_verify_locations(connssl->ctx, data->set.ssl.CAfile, | ||||||
|                                        data->set.ssl.CApath)) { |                                        data->set.ssl.CApath)) { | ||||||
|       if (data->set.ssl.verifypeer) { |       if (data->set.ssl.verifypeer) { | ||||||
|  	/* Fail if we insist on successfully verifying the server. */ |  	/* Fail if we insist on successfully verifying the server. */ | ||||||
| @@ -989,34 +1005,31 @@ Curl_SSLConnect(struct connectdata *conn) | |||||||
|       else { |       else { | ||||||
|         /* Just continue with a warning if no strict  certificate verification |         /* Just continue with a warning if no strict  certificate verification | ||||||
|            is required. */ |            is required. */ | ||||||
|         infof(data,"error setting certificate verify locations," |         infof(data, "error setting certificate verify locations," | ||||||
|               " continuing anyway:\n"); |               " continuing anyway:\n"); | ||||||
|         infof(data, "  CAfile: %s\n", |  | ||||||
|               data->set.ssl.CAfile ? data->set.ssl.CAfile : "none"); |  | ||||||
|         infof(data, "  CApath: %s\n", |  | ||||||
|               data->set.ssl.CApath ? data->set.ssl.CApath : "none"); |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|       /* Everything is fine. */ |       /* Everything is fine. */ | ||||||
|       infof(data,"successfully set certificate verify locations:\n"); |       infof(data, "successfully set certificate verify locations:\n"); | ||||||
|       infof(data, "  CAfile: %s\n", |  | ||||||
|             data->set.ssl.CAfile ? data->set.ssl.CAfile : "none"); |  | ||||||
|       infof(data, "  CApath: %s\n", |  | ||||||
|             data->set.ssl.CApath ? data->set.ssl.CApath : "none"); |  | ||||||
|     } |     } | ||||||
|  |     infof(data, | ||||||
|  |           "  CAfile: %s\n" | ||||||
|  |           "  CApath: %s\n", | ||||||
|  |           data->set.ssl.CAfile ? data->set.ssl.CAfile : "none", | ||||||
|  |           data->set.ssl.CApath ? data->set.ssl.CApath : "none"); | ||||||
|   } |   } | ||||||
|   /* SSL always tries to verify the peer, this only says whether it should |   /* SSL always tries to verify the peer, this only says whether it should | ||||||
|    * fail to connect if the verification fails, or if it should continue |    * fail to connect if the verification fails, or if it should continue | ||||||
|    * anyway. In the latter case the result of the verification is checked with |    * anyway. In the latter case the result of the verification is checked with | ||||||
|    * SSL_get_verify_result() below. */ |    * SSL_get_verify_result() below. */ | ||||||
|   SSL_CTX_set_verify(conn->ssl.ctx, |   SSL_CTX_set_verify(connssl->ctx, | ||||||
|                      data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, |                      data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, | ||||||
|                      cert_verify_callback); |                      cert_verify_callback); | ||||||
|  |  | ||||||
|   /* give application a chance to interfere with SSL set up. */ |   /* give application a chance to interfere with SSL set up. */ | ||||||
|   if(data->set.ssl.fsslctx) { |   if(data->set.ssl.fsslctx) { | ||||||
|     retcode = (*data->set.ssl.fsslctx)(data, conn->ssl.ctx, |     retcode = (*data->set.ssl.fsslctx)(data, connssl->ctx, | ||||||
|                                        data->set.ssl.fsslctxp); |                                        data->set.ssl.fsslctxp); | ||||||
|     if(retcode) { |     if(retcode) { | ||||||
|       failf(data,"error signaled by ssl ctx callback"); |       failf(data,"error signaled by ssl ctx callback"); | ||||||
| @@ -1025,24 +1038,24 @@ Curl_SSLConnect(struct connectdata *conn) | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   /* Lets make an SSL structure */ |   /* Lets make an SSL structure */ | ||||||
|   conn->ssl.handle = SSL_new (conn->ssl.ctx); |   connssl->handle = SSL_new(connssl->ctx); | ||||||
|   SSL_set_connect_state (conn->ssl.handle); |   SSL_set_connect_state(connssl->handle); | ||||||
|  |  | ||||||
|   conn->ssl.server_cert = 0x0; |   connssl->server_cert = 0x0; | ||||||
|  |  | ||||||
|   if(!conn->bits.reuse) { |   if(!conn->bits.reuse) { | ||||||
|     /* We're not re-using a connection, check if there's a cached ID we |     /* We're not re-using a connection, check if there's a cached ID we | ||||||
|        can/should use here! */ |        can/should use here! */ | ||||||
|     if(!Get_SSL_Session(conn, &ssl_sessionid)) { |     if(!Get_SSL_Session(conn, &ssl_sessionid)) { | ||||||
|       /* we got a session id, use it! */ |       /* we got a session id, use it! */ | ||||||
|       SSL_set_session(conn->ssl.handle, ssl_sessionid); |       SSL_set_session(connssl->handle, ssl_sessionid); | ||||||
|       /* Informational message */ |       /* Informational message */ | ||||||
|       infof (data, "SSL re-using session ID\n"); |       infof (data, "SSL re-using session ID\n"); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /* pass the raw socket into the SSL layers */ |   /* pass the raw socket into the SSL layers */ | ||||||
|   SSL_set_fd(conn->ssl.handle, conn->firstsocket); |   SSL_set_fd(connssl->handle, sockfd); | ||||||
|  |  | ||||||
|   do { |   do { | ||||||
|     fd_set writefd; |     fd_set writefd; | ||||||
| @@ -1088,18 +1101,18 @@ Curl_SSLConnect(struct connectdata *conn) | |||||||
|     FD_ZERO(&writefd); |     FD_ZERO(&writefd); | ||||||
|     FD_ZERO(&readfd); |     FD_ZERO(&readfd); | ||||||
|  |  | ||||||
|     err = SSL_connect(conn->ssl.handle); |     err = SSL_connect(connssl->handle); | ||||||
|  |  | ||||||
|     /* 1  is fine |     /* 1  is fine | ||||||
|        0  is "not successful but was shut down controlled" |        0  is "not successful but was shut down controlled" | ||||||
|        <0 is "handshake was not successful, because a fatal error occurred" */ |        <0 is "handshake was not successful, because a fatal error occurred" */ | ||||||
|     if(1 != err) { |     if(1 != err) { | ||||||
|       int detail = SSL_get_error(conn->ssl.handle, err); |       int detail = SSL_get_error(connssl->handle, err); | ||||||
|  |  | ||||||
|       if(SSL_ERROR_WANT_READ == detail) |       if(SSL_ERROR_WANT_READ == detail) | ||||||
|         FD_SET(conn->firstsocket, &readfd); |         FD_SET(sockfd, &readfd); | ||||||
|       else if(SSL_ERROR_WANT_WRITE == detail) |       else if(SSL_ERROR_WANT_WRITE == detail) | ||||||
|         FD_SET(conn->firstsocket, &writefd); |         FD_SET(sockfd, &writefd); | ||||||
|       else { |       else { | ||||||
|         /* untreated error */ |         /* untreated error */ | ||||||
|         char error_buffer[120]; /* OpenSSL documents that this must be at least |         char error_buffer[120]; /* OpenSSL documents that this must be at least | ||||||
| @@ -1143,7 +1156,7 @@ Curl_SSLConnect(struct connectdata *conn) | |||||||
|  |  | ||||||
|     interval.tv_usec = timeout_ms*1000; |     interval.tv_usec = timeout_ms*1000; | ||||||
|  |  | ||||||
|     what = select(conn->firstsocket+1, &readfd, &writefd, NULL, &interval); |     what = select(sockfd+1, &readfd, &writefd, NULL, &interval); | ||||||
|     if(what > 0) |     if(what > 0) | ||||||
|       /* reabable or writable, go loop yourself */ |       /* reabable or writable, go loop yourself */ | ||||||
|       continue; |       continue; | ||||||
| @@ -1158,12 +1171,12 @@ Curl_SSLConnect(struct connectdata *conn) | |||||||
|  |  | ||||||
|   /* Informational message */ |   /* Informational message */ | ||||||
|   infof (data, "SSL connection using %s\n", |   infof (data, "SSL connection using %s\n", | ||||||
|          SSL_get_cipher(conn->ssl.handle)); |          SSL_get_cipher(connssl->handle)); | ||||||
|  |  | ||||||
|   if(!ssl_sessionid) { |   if(!ssl_sessionid) { | ||||||
|     /* Since this is not a cached session ID, then we want to stach this one |     /* Since this is not a cached session ID, then we want to stach this one | ||||||
|        in the cache! */ |        in the cache! */ | ||||||
|     Store_SSL_Session(conn); |     Store_SSL_Session(conn, connssl); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|    |    | ||||||
| @@ -1173,38 +1186,38 @@ Curl_SSLConnect(struct connectdata *conn) | |||||||
|    * attack |    * attack | ||||||
|    */ |    */ | ||||||
|  |  | ||||||
|   conn->ssl.server_cert = SSL_get_peer_certificate(conn->ssl.handle); |   connssl->server_cert = SSL_get_peer_certificate(connssl->handle); | ||||||
|   if(!conn->ssl.server_cert) { |   if(!connssl->server_cert) { | ||||||
|     failf(data, "SSL: couldn't get peer certificate!"); |     failf(data, "SSL: couldn't get peer certificate!"); | ||||||
|     return CURLE_SSL_PEER_CERTIFICATE; |     return CURLE_SSL_PEER_CERTIFICATE; | ||||||
|   } |   } | ||||||
|   infof (data, "Server certificate:\n"); |   infof (data, "Server certificate:\n"); | ||||||
|    |    | ||||||
|   str = X509_NAME_oneline(X509_get_subject_name(conn->ssl.server_cert), |   str = X509_NAME_oneline(X509_get_subject_name(connssl->server_cert), | ||||||
|                           NULL, 0); |                           NULL, 0); | ||||||
|   if(!str) { |   if(!str) { | ||||||
|     failf(data, "SSL: couldn't get X509-subject!"); |     failf(data, "SSL: couldn't get X509-subject!"); | ||||||
|     X509_free(conn->ssl.server_cert); |     X509_free(connssl->server_cert); | ||||||
|     return CURLE_SSL_CONNECT_ERROR; |     return CURLE_SSL_CONNECT_ERROR; | ||||||
|   } |   } | ||||||
|   infof(data, "\t subject: %s\n", str); |   infof(data, "\t subject: %s\n", str); | ||||||
|   CRYPTO_free(str); |   CRYPTO_free(str); | ||||||
|  |  | ||||||
|   certdate = X509_get_notBefore(conn->ssl.server_cert); |   certdate = X509_get_notBefore(connssl->server_cert); | ||||||
|   Curl_ASN1_UTCTIME_output(conn, "\t start date: ", certdate); |   Curl_ASN1_UTCTIME_output(conn, "\t start date: ", certdate); | ||||||
|  |  | ||||||
|   certdate = X509_get_notAfter(conn->ssl.server_cert); |   certdate = X509_get_notAfter(connssl->server_cert); | ||||||
|   Curl_ASN1_UTCTIME_output(conn, "\t expire date: ", certdate); |   Curl_ASN1_UTCTIME_output(conn, "\t expire date: ", certdate); | ||||||
|  |  | ||||||
|   if(data->set.ssl.verifyhost) { |   if(data->set.ssl.verifyhost) { | ||||||
|     retcode = verifyhost(conn); |     retcode = verifyhost(conn, connssl->server_cert); | ||||||
|     if(retcode) { |     if(retcode) { | ||||||
|       X509_free(conn->ssl.server_cert); |       X509_free(connssl->server_cert); | ||||||
|       return retcode; |       return retcode; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   str = X509_NAME_oneline(X509_get_issuer_name(conn->ssl.server_cert), |   str = X509_NAME_oneline(X509_get_issuer_name(connssl->server_cert), | ||||||
|                           NULL, 0); |                           NULL, 0); | ||||||
|   if(!str) { |   if(!str) { | ||||||
|     failf(data, "SSL: couldn't get X509-issuer name!"); |     failf(data, "SSL: couldn't get X509-issuer name!"); | ||||||
| @@ -1217,7 +1230,7 @@ Curl_SSLConnect(struct connectdata *conn) | |||||||
|     /* We could do all sorts of certificate verification stuff here before |     /* We could do all sorts of certificate verification stuff here before | ||||||
|        deallocating the certificate. */ |        deallocating the certificate. */ | ||||||
|      |      | ||||||
|     data->set.ssl.certverifyresult=SSL_get_verify_result(conn->ssl.handle); |     data->set.ssl.certverifyresult=SSL_get_verify_result(connssl->handle); | ||||||
|     if(data->set.ssl.certverifyresult != X509_V_OK) { |     if(data->set.ssl.certverifyresult != X509_V_OK) { | ||||||
|       if(data->set.ssl.verifypeer) { |       if(data->set.ssl.verifypeer) { | ||||||
|         /* We probably never reach this, because SSL_connect() will fail |         /* We probably never reach this, because SSL_connect() will fail | ||||||
| @@ -1234,7 +1247,7 @@ Curl_SSLConnect(struct connectdata *conn) | |||||||
|       infof(data, "SSL certificate verify ok.\n"); |       infof(data, "SSL certificate verify ok.\n"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   X509_free(conn->ssl.server_cert); |   X509_free(connssl->server_cert); | ||||||
| #else /* USE_SSLEAY */ | #else /* USE_SSLEAY */ | ||||||
|   /* this is for "-ansi -Wall -pedantic" to stop complaining!   (rabe) */ |   /* this is for "-ansi -Wall -pedantic" to stop complaining!   (rabe) */ | ||||||
|   (void) conn; |   (void) conn; | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ | |||||||
|  * $Id$ |  * $Id$ | ||||||
|  ***************************************************************************/ |  ***************************************************************************/ | ||||||
| #include "urldata.h" | #include "urldata.h" | ||||||
| CURLcode Curl_SSLConnect(struct connectdata *conn); | CURLcode Curl_SSLConnect(struct connectdata *conn, int sockfd); | ||||||
|  |  | ||||||
| void Curl_SSL_init(void);    /* Global SSL init */ | void Curl_SSL_init(void);    /* Global SSL init */ | ||||||
| void Curl_SSL_cleanup(void); /* Global SSL cleanup */ | void Curl_SSL_cleanup(void); /* Global SSL cleanup */ | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								lib/telnet.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								lib/telnet.c
									
									
									
									
									
								
							| @@ -262,7 +262,7 @@ static void send_negotiation(struct connectdata *conn, int cmd, int option) | |||||||
|    buf[1] = cmd; |    buf[1] = cmd; | ||||||
|    buf[2] = option; |    buf[2] = option; | ||||||
|     |     | ||||||
|    (void)swrite(conn->firstsocket, buf, 3); |    (void)swrite(conn->sock[FIRSTSOCKET], buf, 3); | ||||||
|     |     | ||||||
|    printoption(conn->data, "SENT", cmd, option); |    printoption(conn->data, "SENT", cmd, option); | ||||||
| } | } | ||||||
| @@ -826,7 +826,7 @@ static void suboption(struct connectdata *conn) | |||||||
|       snprintf((char *)temp, sizeof(temp), |       snprintf((char *)temp, sizeof(temp), | ||||||
|                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, |                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, | ||||||
|                CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); |                CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); | ||||||
|       (void)swrite(conn->firstsocket, temp, len); |       (void)swrite(conn->sock[FIRSTSOCKET], temp, len); | ||||||
|       printsub(data, '>', &temp[2], len-2); |       printsub(data, '>', &temp[2], len-2); | ||||||
|       break; |       break; | ||||||
|     case CURL_TELOPT_XDISPLOC: |     case CURL_TELOPT_XDISPLOC: | ||||||
| @@ -834,7 +834,7 @@ static void suboption(struct connectdata *conn) | |||||||
|       snprintf((char *)temp, sizeof(temp), |       snprintf((char *)temp, sizeof(temp), | ||||||
|                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, |                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, | ||||||
|                CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); |                CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); | ||||||
|       (void)swrite(conn->firstsocket, temp, len); |       (void)swrite(conn->sock[FIRSTSOCKET], temp, len); | ||||||
|       printsub(data, '>', &temp[2], len-2); |       printsub(data, '>', &temp[2], len-2); | ||||||
|       break; |       break; | ||||||
|     case CURL_TELOPT_NEW_ENVIRON: |     case CURL_TELOPT_NEW_ENVIRON: | ||||||
| @@ -857,7 +857,7 @@ static void suboption(struct connectdata *conn) | |||||||
|       snprintf((char *)&temp[len], sizeof(temp) - len, |       snprintf((char *)&temp[len], sizeof(temp) - len, | ||||||
|                "%c%c", CURL_IAC, CURL_SE); |                "%c%c", CURL_IAC, CURL_SE); | ||||||
|       len += 2; |       len += 2; | ||||||
|       (void)swrite(conn->firstsocket, temp, len); |       (void)swrite(conn->sock[FIRSTSOCKET], temp, len); | ||||||
|       printsub(data, '>', &temp[2], len-2); |       printsub(data, '>', &temp[2], len-2); | ||||||
|       break; |       break; | ||||||
|   } |   } | ||||||
| @@ -1035,7 +1035,7 @@ CURLcode Curl_telnet(struct connectdata *conn) | |||||||
| { | { | ||||||
|   CURLcode code; |   CURLcode code; | ||||||
|   struct SessionHandle *data = conn->data; |   struct SessionHandle *data = conn->data; | ||||||
|   int sockfd = conn->firstsocket; |   int sockfd = conn->sock[FIRSTSOCKET]; | ||||||
| #ifdef WIN32 | #ifdef WIN32 | ||||||
|   WSAEVENT event_handle; |   WSAEVENT event_handle; | ||||||
|   WSANETWORKEVENTS events; |   WSANETWORKEVENTS events; | ||||||
| @@ -1105,7 +1105,7 @@ CURLcode Curl_telnet(struct connectdata *conn) | |||||||
|           if(outbuf[0] == CURL_IAC) |           if(outbuf[0] == CURL_IAC) | ||||||
|             outbuf[out_count++] = CURL_IAC; |             outbuf[out_count++] = CURL_IAC; | ||||||
|            |            | ||||||
|           Curl_write(conn, conn->firstsocket, outbuf, |           Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf, | ||||||
|                      out_count, &bytes_written); |                      out_count, &bytes_written); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @@ -1176,7 +1176,7 @@ CURLcode Curl_telnet(struct connectdata *conn) | |||||||
|           if(outbuf[0] == CURL_IAC) |           if(outbuf[0] == CURL_IAC) | ||||||
|             outbuf[out_count++] = CURL_IAC; |             outbuf[out_count++] = CURL_IAC; | ||||||
|        |        | ||||||
|           Curl_write(conn, conn->firstsocket, outbuf, |           Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf, | ||||||
|                      out_count, &bytes_written); |                      out_count, &bytes_written); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -1865,14 +1865,7 @@ CURLcode Curl_perform(struct SessionHandle *data) | |||||||
|       res = Curl_do(&conn); |       res = Curl_do(&conn); | ||||||
|  |  | ||||||
|       if(res == CURLE_OK) { |       if(res == CURLE_OK) { | ||||||
|         if(conn->protocol&PROT_FTPS) |  | ||||||
|           /* FTPS, disable ssl while transfering data */ |  | ||||||
|           conn->ssl.use = FALSE; |  | ||||||
|         res = Transfer(conn); /* now fetch that URL please */ |         res = Transfer(conn); /* now fetch that URL please */ | ||||||
|         if(conn->protocol&PROT_FTPS) |  | ||||||
|           /* FTPS, enable ssl again after havving transferred data */ |  | ||||||
|           conn->ssl.use = TRUE; |  | ||||||
|  |  | ||||||
|         if(res == CURLE_OK) |         if(res == CURLE_OK) | ||||||
|           /* |           /* | ||||||
|            * We must duplicate the new URL here as the connection data |            * We must duplicate the new URL here as the connection data | ||||||
| @@ -1885,11 +1878,11 @@ CURLcode Curl_perform(struct SessionHandle *data) | |||||||
|            * possibly know if the connection is in a good shape or not now. */ |            * possibly know if the connection is in a good shape or not now. */ | ||||||
|           conn->bits.close = TRUE; |           conn->bits.close = TRUE; | ||||||
|  |  | ||||||
|           if(-1 !=conn->secondarysocket) { |           if(-1 != conn->sock[SECONDARYSOCKET]) { | ||||||
|             /* if we failed anywhere, we must clean up the secondary socket if |             /* if we failed anywhere, we must clean up the secondary socket if | ||||||
|                it was used */ |                it was used */ | ||||||
|             sclose(conn->secondarysocket); |             sclose(conn->sock[SECONDARYSOCKET]); | ||||||
|             conn->secondarysocket=-1; |             conn->sock[SECONDARYSOCKET]=-1; | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -1932,12 +1925,13 @@ CURLcode Curl_perform(struct SessionHandle *data) | |||||||
|  |  | ||||||
| CURLcode  | CURLcode  | ||||||
| Curl_Transfer(struct connectdata *c_conn, /* connection data */ | Curl_Transfer(struct connectdata *c_conn, /* connection data */ | ||||||
|               int sockfd,       /* socket to read from or -1 */ |               int sockindex,    /* socket index to read from or -1 */ | ||||||
|               int size,         /* -1 if unknown at this point */ |               int size,         /* -1 if unknown at this point */ | ||||||
|               bool getheader,   /* TRUE if header parsing is wanted */ |               bool getheader,   /* TRUE if header parsing is wanted */ | ||||||
|               long *bytecountp, /* return number of bytes read or NULL */ |               long *bytecountp, /* return number of bytes read or NULL */ | ||||||
|               int writesockfd,  /* socket to write to, it may very well be |               int writesockindex,  /* socket index to write to, it may very | ||||||
|                                    the same we read from. -1 disables */ |                                       well be the same we read from. -1 | ||||||
|  |                                       disables */ | ||||||
|               long *writebytecountp /* return number of bytes written or |               long *writebytecountp /* return number of bytes written or | ||||||
|                                        NULL */ |                                        NULL */ | ||||||
|               ) |               ) | ||||||
| @@ -1947,11 +1941,11 @@ Curl_Transfer(struct connectdata *c_conn, /* connection data */ | |||||||
|     return CURLE_BAD_FUNCTION_ARGUMENT; |     return CURLE_BAD_FUNCTION_ARGUMENT; | ||||||
|  |  | ||||||
|   /* now copy all input parameters */ |   /* now copy all input parameters */ | ||||||
|   conn->sockfd = sockfd; |   conn->sockfd = sockindex==-1?-1:conn->sock[sockindex]; | ||||||
|   conn->size = size; |   conn->size = size; | ||||||
|   conn->bits.getheader = getheader; |   conn->bits.getheader = getheader; | ||||||
|   conn->bytecountp = bytecountp; |   conn->bytecountp = bytecountp; | ||||||
|   conn->writesockfd = writesockfd; |   conn->writesockfd = writesockindex==-1?-1:conn->sock[writesockindex]; | ||||||
|   conn->writebytecountp = writebytecountp; |   conn->writebytecountp = writebytecountp; | ||||||
|  |  | ||||||
|   return CURLE_OK; |   return CURLE_OK; | ||||||
|   | |||||||
							
								
								
									
										39
									
								
								lib/url.c
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								lib/url.c
									
									
									
									
									
								
							| @@ -1251,6 +1251,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) | |||||||
|     data->set.max_filesize = va_arg(param, long); |     data->set.max_filesize = va_arg(param, long); | ||||||
|     break; |     break; | ||||||
|  |  | ||||||
|  |   case CURLOPT_FTP_SSL: | ||||||
|  |     /* | ||||||
|  |      * Make FTP transfers attempt to use SSL/TLS. | ||||||
|  |      */ | ||||||
|  |     data->set.ftp_ssl = va_arg(param, long); | ||||||
|  |     break; | ||||||
|  |  | ||||||
|   default: |   default: | ||||||
|     /* unknown tag and its companion, just ignore: */ |     /* unknown tag and its companion, just ignore: */ | ||||||
|     return CURLE_FAILED_INIT; /* correct this */ |     return CURLE_FAILED_INIT; /* correct this */ | ||||||
| @@ -1293,16 +1300,13 @@ CURLcode Curl_disconnect(struct connectdata *conn) | |||||||
|   Curl_safefree(conn->proto.generic); |   Curl_safefree(conn->proto.generic); | ||||||
|   Curl_safefree(conn->newurl); |   Curl_safefree(conn->newurl); | ||||||
|   Curl_safefree(conn->path);  /* the URL path part */ |   Curl_safefree(conn->path);  /* the URL path part */ | ||||||
|  |  | ||||||
| #ifdef USE_SSLEAY |  | ||||||
|   Curl_SSL_Close(conn); |   Curl_SSL_Close(conn); | ||||||
| #endif /* USE_SSLEAY */ |  | ||||||
|  |  | ||||||
|   /* close possibly still open sockets */ |   /* close possibly still open sockets */ | ||||||
|   if(-1 != conn->secondarysocket) |   if(-1 != conn->sock[SECONDARYSOCKET]) | ||||||
|     sclose(conn->secondarysocket); |     sclose(conn->sock[SECONDARYSOCKET]); | ||||||
|   if(-1 != conn->firstsocket) |   if(-1 != conn->sock[FIRSTSOCKET]) | ||||||
|     sclose(conn->firstsocket); |     sclose(conn->sock[FIRSTSOCKET]); | ||||||
|  |  | ||||||
|   Curl_safefree(conn->user); |   Curl_safefree(conn->user); | ||||||
|   Curl_safefree(conn->passwd); |   Curl_safefree(conn->passwd); | ||||||
| @@ -1429,7 +1433,7 @@ ConnectionExists(struct SessionHandle *data, | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if(match) { |     if(match) { | ||||||
|       bool dead = SocketIsDead(check->firstsocket); |       bool dead = SocketIsDead(check->sock[FIRSTSOCKET]); | ||||||
|       if(dead) { |       if(dead) { | ||||||
|         /* |         /* | ||||||
|          */ |          */ | ||||||
| @@ -1549,16 +1553,15 @@ ConnectionStore(struct SessionHandle *data, | |||||||
|  * This function logs in to a SOCKS5 proxy and sends the specifies the final |  * This function logs in to a SOCKS5 proxy and sends the specifies the final | ||||||
|  * desitination server. |  * desitination server. | ||||||
|  */ |  */ | ||||||
| static int handleSock5Proxy( | static int handleSock5Proxy(const char *proxy_name, | ||||||
|     const char *proxy_name, |  | ||||||
|                             const char *proxy_password, |                             const char *proxy_password, | ||||||
|     struct connectdata *conn, |                             struct connectdata *conn) | ||||||
|     int sock) |  | ||||||
| { | { | ||||||
|   unsigned char socksreq[600]; /* room for large user/pw (255 max each) */ |   unsigned char socksreq[600]; /* room for large user/pw (255 max each) */ | ||||||
|   ssize_t actualread; |   ssize_t actualread; | ||||||
|   ssize_t written; |   ssize_t written; | ||||||
|   CURLcode result; |   CURLcode result; | ||||||
|  |   int sock = conn->sock[FIRSTSOCKET]; | ||||||
|  |  | ||||||
|   Curl_nonblock(sock, FALSE); |   Curl_nonblock(sock, FALSE); | ||||||
|  |  | ||||||
| @@ -1754,7 +1757,7 @@ static CURLcode ConnectPlease(struct connectdata *conn, | |||||||
|   result= Curl_connecthost(conn, |   result= Curl_connecthost(conn, | ||||||
|                            hostaddr, |                            hostaddr, | ||||||
|                            conn->port, |                            conn->port, | ||||||
|                            &conn->firstsocket, |                            &conn->sock[FIRSTSOCKET], | ||||||
|                            &addr, |                            &addr, | ||||||
|                            connected); |                            connected); | ||||||
|   if(CURLE_OK == result) { |   if(CURLE_OK == result) { | ||||||
| @@ -1776,8 +1779,7 @@ static CURLcode ConnectPlease(struct connectdata *conn, | |||||||
|     if (conn->data->set.proxytype == CURLPROXY_SOCKS5) { |     if (conn->data->set.proxytype == CURLPROXY_SOCKS5) { | ||||||
|       return handleSock5Proxy(conn->proxyuser, |       return handleSock5Proxy(conn->proxyuser, | ||||||
|                               conn->proxypasswd, |                               conn->proxypasswd, | ||||||
|                               conn, |                               conn) ? | ||||||
|                               conn->firstsocket) ? |  | ||||||
|         CURLE_COULDNT_CONNECT : CURLE_OK; |         CURLE_COULDNT_CONNECT : CURLE_OK; | ||||||
|     } |     } | ||||||
|     else if (conn->data->set.proxytype == CURLPROXY_HTTP) { |     else if (conn->data->set.proxytype == CURLPROXY_HTTP) { | ||||||
| @@ -1953,8 +1955,8 @@ static CURLcode CreateConnection(struct SessionHandle *data, | |||||||
|  |  | ||||||
|   /* and we setup a few fields in case we end up actually using this struct */ |   /* and we setup a few fields in case we end up actually using this struct */ | ||||||
|   conn->data = data;           /* remember our daddy */ |   conn->data = data;           /* remember our daddy */ | ||||||
|   conn->firstsocket = -1;     /* no file descriptor */ |   conn->sock[FIRSTSOCKET] = -1;     /* no file descriptor */ | ||||||
|   conn->secondarysocket = -1; /* no file descriptor */ |   conn->sock[SECONDARYSOCKET] = -1; /* no file descriptor */ | ||||||
|   conn->connectindex = -1;    /* no index */ |   conn->connectindex = -1;    /* no index */ | ||||||
|   conn->bits.httpproxy = (data->change.proxy && *data->change.proxy && |   conn->bits.httpproxy = (data->change.proxy && *data->change.proxy && | ||||||
|                           (data->set.proxytype == CURLPROXY_HTTP))? |                           (data->set.proxytype == CURLPROXY_HTTP))? | ||||||
| @@ -2419,6 +2421,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, | |||||||
|     if(strequal(conn->protostr, "FTPS")) { |     if(strequal(conn->protostr, "FTPS")) { | ||||||
| #ifdef USE_SSLEAY | #ifdef USE_SSLEAY | ||||||
|       conn->protocol |= PROT_FTPS|PROT_SSL; |       conn->protocol |= PROT_FTPS|PROT_SSL; | ||||||
|  |       conn->ssl[SECONDARYSOCKET].use = TRUE; /* send data securely */ | ||||||
| #else | #else | ||||||
|       failf(data, LIBCURL_NAME |       failf(data, LIBCURL_NAME | ||||||
|             " was built with SSL disabled, ftps: not supported!"); |             " was built with SSL disabled, ftps: not supported!"); | ||||||
| @@ -3100,7 +3103,7 @@ static CURLcode SetupConnection(struct connectdata *conn, | |||||||
|   conn->bytecount = 0; |   conn->bytecount = 0; | ||||||
|   conn->headerbytecount = 0; |   conn->headerbytecount = 0; | ||||||
|  |  | ||||||
|   if(-1 == conn->firstsocket) { |   if(-1 == conn->sock[FIRSTSOCKET]) { | ||||||
|     bool connected; |     bool connected; | ||||||
|  |  | ||||||
|     /* Connect only if not already connected! */ |     /* Connect only if not already connected! */ | ||||||
|   | |||||||
| @@ -130,7 +130,7 @@ enum protection_level { | |||||||
| }; | }; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| /* struct for data related to SSL and SSL connections */ | /* struct for data related to each SSL connection */ | ||||||
| struct ssl_connect_data { | struct ssl_connect_data { | ||||||
|   bool use;        /* use ssl encrypted communications TRUE/FALSE */ |   bool use;        /* use ssl encrypted communications TRUE/FALSE */ | ||||||
| #ifdef USE_SSLEAY | #ifdef USE_SSLEAY | ||||||
| @@ -385,6 +385,9 @@ struct Curl_async { | |||||||
| }; | }; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #define FIRSTSOCKET     0 | ||||||
|  | #define SECONDARYSOCKET 1 | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * The connectdata struct contains all fields and variables that should be |  * The connectdata struct contains all fields and variables that should be | ||||||
|  * unique for an entire connection. |  * unique for an entire connection. | ||||||
| @@ -442,12 +445,12 @@ struct connectdata { | |||||||
|    |    | ||||||
|   struct timeval now;     /* "current" time */ |   struct timeval now;     /* "current" time */ | ||||||
|   struct timeval created; /* creation time */ |   struct timeval created; /* creation time */ | ||||||
|   int firstsocket;     /* the main socket to use */ |   int sock[2];       /* two sockets, the second is used for the data transfer | ||||||
|   int secondarysocket; /* for i.e ftp transfers */ |                         when doing FTP */ | ||||||
|   long maxdownload; /* in bytes, the maximum amount of data to fetch, 0 |   long maxdownload; /* in bytes, the maximum amount of data to fetch, 0 | ||||||
|                        means unlimited */ |                        means unlimited */ | ||||||
|    |    | ||||||
|   struct ssl_connect_data ssl; /* this is for ssl-stuff */ |   struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */ | ||||||
|   struct ssl_config_data ssl_config; |   struct ssl_config_data ssl_config; | ||||||
|  |  | ||||||
|   struct ConnectBits bits;    /* various state-flags for this connection */ |   struct ConnectBits bits;    /* various state-flags for this connection */ | ||||||
| @@ -486,8 +489,8 @@ struct connectdata { | |||||||
|   long *bytecountp;	 /* return number of bytes read or NULL */ |   long *bytecountp;	 /* return number of bytes read or NULL */ | ||||||
|            |            | ||||||
|   /* WRITE stuff */ |   /* WRITE stuff */ | ||||||
|   int writesockfd;       /* socket to write to, it may very well be |   int writesockfd;       /* socket to write to, it may very | ||||||
|                             the same we read from. -1 disables */ |                             well be the same we read from. -1 disables */ | ||||||
|   long *writebytecountp; /* return number of bytes written or NULL */ |   long *writebytecountp; /* return number of bytes written or NULL */ | ||||||
|  |  | ||||||
|   /** Dynamicly allocated strings, may need to be freed before this **/ |   /** Dynamicly allocated strings, may need to be freed before this **/ | ||||||
| @@ -863,6 +866,7 @@ struct UserDefined { | |||||||
|   bool expect100header;  /* TRUE if we added Expect: 100-continue */ |   bool expect100header;  /* TRUE if we added Expect: 100-continue */ | ||||||
|   bool ftp_use_epsv;     /* if EPSV is to be attempted or not */ |   bool ftp_use_epsv;     /* if EPSV is to be attempted or not */ | ||||||
|   bool ftp_use_eprt;     /* if EPRT is to be attempted or not */ |   bool ftp_use_eprt;     /* if EPRT is to be attempted or not */ | ||||||
|  |   curl_ftpssl ftp_ssl;   /* if AUTH TLS is to be attempted etc */ | ||||||
|   bool no_signal;        /* do not use any signal/alarm handler */ |   bool no_signal;        /* do not use any signal/alarm handler */ | ||||||
|  |  | ||||||
|   bool global_dns_cache; |   bool global_dns_cache; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Daniel Stenberg
					Daniel Stenberg