Commit 1e98727c authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

FTPS support added as RFC2228 and the murray-ftp-auth-ssl draft describe it

parent 1c700b5a
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@

/* This is the version number of the libcurl package from which this header
   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
   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
   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
   defines: */
#define LIBCURL_VERSION_MAJOR 7
#define LIBCURL_VERSION_MINOR 10
#define LIBCURL_VERSION_PATCH 9
#define LIBCURL_VERSION_MINOR 11
#define LIBCURL_VERSION_PATCH 0

#include <stdio.h>

+7 −6
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ CURLcode Curl_dict(struct connectdata *conn)
                          by RFC 2229 */
  CURLcode result=CURLE_OK;
  struct SessionHandle *data=conn->data;
  int sockfd = conn->sock[FIRSTSOCKET];

  char *path = conn->path;
  long *bytecount = &conn->bytecount;
@@ -134,7 +135,7 @@ CURLcode Curl_dict(struct connectdata *conn)
      nth = atoi(nthdef);
    }
      
    result = Curl_sendf(conn->firstsocket, conn,
    result = Curl_sendf(sockfd, conn,
                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
                        "MATCH "
                        "%s "    /* database */
@@ -149,7 +150,7 @@ CURLcode Curl_dict(struct connectdata *conn)
    if(result)
      failf(data, "Failed sending DICT request");
    else
      result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount,
      result = Curl_Transfer(conn, sockfd, -1, FALSE, bytecount,
                             -1, NULL); /* no upload */      
    if(result)
      return result;
@@ -184,7 +185,7 @@ CURLcode Curl_dict(struct connectdata *conn)
      nth = atoi(nthdef);
    }
      
    result = Curl_sendf(conn->firstsocket, conn,
    result = Curl_sendf(sockfd, conn,
                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
                        "DEFINE "
                        "%s "     /* database */
@@ -195,7 +196,7 @@ CURLcode Curl_dict(struct connectdata *conn)
    if(result)
      failf(data, "Failed sending DICT request");
    else
      result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount,
      result = Curl_Transfer(conn, sockfd, -1, FALSE, bytecount,
                             -1, NULL); /* no upload */
    
    if(result)
@@ -213,14 +214,14 @@ CURLcode Curl_dict(struct connectdata *conn)
        if (ppath[i] == ':')
          ppath[i] = ' ';
      }
      result = Curl_sendf(conn->firstsocket, conn,
      result = Curl_sendf(sockfd, conn,
                          "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
                          "%s\n"
                          "QUIT\n", ppath);
      if(result)
        failf(data, "Failed sending DICT request");
      else
        result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount,
        result = Curl_Transfer(conn, sockfd, -1, FALSE, bytecount,
                               -1, NULL);
      if(result)
        return result;
+97 −22
Original line number Diff line number Diff line
@@ -126,12 +126,12 @@ static void freedirs(struct FTP *ftp)
 * connected.
 *
 */
static CURLcode AllowServerConnect(struct SessionHandle *data,
                                   struct connectdata *conn,
                                   int sock)
static CURLcode AllowServerConnect(struct connectdata *conn)
{
  fd_set rdset;
  struct timeval dt;
  struct SessionHandle *data = conn->data;
  int sock = conn->sock[SECONDARYSOCKET];
  
  FD_ZERO(&rdset);

@@ -169,7 +169,7 @@ static CURLcode AllowServerConnect(struct SessionHandle *data,
      }
      infof(data, "Connection accepted from server\n");

      conn->secondarysocket = s;
      conn->sock[SECONDARYSOCKET] = s;
      Curl_nonblock(s, TRUE); /* enable non-blocking */
    }
    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
   * line in a response or continue reading.  */

  int sockfd = conn->firstsocket;
  int sockfd = conn->sock[FIRSTSOCKET];
  int perline; /* count bytes per line */
  bool keepon=TRUE;
  ssize_t gotbytes;
@@ -438,7 +438,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)

  if (data->set.tunnel_thru_httpproxy) {
    /* 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);
    if(CURLE_OK != result)
      return result;
@@ -447,7 +447,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
  if(conn->protocol & PROT_FTPS) {
    /* FTPS is simply ftp with SSL for the control channel */
    /* now, perform the SSL initialization for this socket */
    result = Curl_SSLConnect(conn);
    result = Curl_SSLConnect(conn, FIRSTSOCKET);
    if(result)
      return result;
  }
@@ -481,6 +481,71 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
  }
#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 */
  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);
#endif
  /* shut down the socket to inform the server we're done */
  sclose(conn->secondarysocket);
  conn->secondarysocket = -1;
  sclose(conn->sock[SECONDARYSOCKET]);
  conn->sock[SECONDARYSOCKET] = -1;

  if(!ftp->no_transfer) {
    /* 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.
   */
  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;
  
  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
     is only so that the cleanup function will close it in case
     we fail before the true secondary stuff is made */
  conn->secondarysocket = portsock;
  conn->sock[SECONDARYSOCKET] = portsock;
  
#else
  /******************************************************************
@@ -1249,7 +1314,8 @@ CURLcode ftp_use_port(struct connectdata *conn)
    socklen_t sslen;
    
    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");
      return CURLE_FTP_PORT_FAILED;
    }
@@ -1526,7 +1592,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
  result = Curl_connecthost(conn,
                            addr,
                            connectport,
                            &conn->secondarysocket,
                            &conn->sock[SECONDARYSOCKET],
                            &conninfo,
                            connected);

@@ -1547,7 +1613,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
  
  if (data->set.tunnel_thru_httpproxy) {
    /* We want "seamless" FTP operations through HTTP proxy tunnel */
    result = Curl_ConnectHTTPProxyTunnel(conn, conn->secondarysocket,
    result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET,
                                         newhostp, newport);
    if(CURLE_OK != result)
      return result;
@@ -1684,7 +1750,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)

    if(data->set.ftp_use_port) {
      /* PORT means we are now awaiting the server to connect to us. */
      result = AllowServerConnect(data, conn, conn->secondarysocket);
      result = AllowServerConnect(conn);
      if( result )
        return result;
    }
@@ -1697,7 +1763,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
    Curl_pgrsSetUploadSize(data, data->set.infilesize);

    result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
                      conn->secondarysocket, bytecountp);
                           SECONDARYSOCKET, bytecountp);
    if(result)
      return result;
      
@@ -1940,15 +2006,24 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
        size = downloadsize;

      if(data->set.ftp_use_port) {
        result = AllowServerConnect(data, conn, conn->secondarysocket);
        result = AllowServerConnect(conn);
        if( 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);

      /* FTP download: */
      result=Curl_Transfer(conn, conn->secondarysocket, size, FALSE,
      result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE,
                           bytecountp,
                           -1, NULL); /* no upload here */
      if(result)
@@ -2232,10 +2307,10 @@ CURLcode Curl_ftp(struct connectdata *conn)
    if(connected)
      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 */
      sclose(conn->secondarysocket);
      conn->secondarysocket = -1;
      sclose(conn->sock[SECONDARYSOCKET]);
      conn->sock[SECONDARYSOCKET] = -1;
    }

    if(ftp->no_transfer)
@@ -2280,7 +2355,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
  write_len = strlen(s);

  do {
    res = Curl_write(conn, conn->firstsocket, sptr, write_len,
    res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
                     &bytes_written);

    if(CURLE_OK != res)
+17 −16
Original line number Diff line number Diff line
@@ -500,7 +500,6 @@ send_buffer *add_buffer_init(void)
 */
static
CURLcode add_buffer_send(send_buffer *in,
                         int sockfd,
                         struct connectdata *conn,
                         long *bytes_written) /* add the number of sent
                                                 bytes to this counter */
@@ -511,6 +510,7 @@ CURLcode add_buffer_send(send_buffer *in,
  int size;
  struct HTTP *http = conn->proto.http;
  int sendsize;
  int sockfd = conn->sock[FIRSTSOCKET];

  /* 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 */
@@ -708,7 +708,7 @@ Curl_compareheader(char *headerline, /* line to check */
 */

CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
                                     int tunnelsocket,
                                     int sockindex,
                                     char *hostname,
                                     int remote_port)
{
@@ -729,6 +729,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
  fd_set readfd;
  char *line_start;
  char *host_port;
  int tunnelsocket = conn->sock[sockindex];

#define SELECT_OK      0
#define SELECT_ERROR   1
@@ -936,7 +937,7 @@ CURLcode Curl_http_connect(struct connectdata *conn)
     ((conn->protocol & PROT_HTTPS) || data->set.tunnel_thru_httpproxy)) {

    /* 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);
    if(CURLE_OK != result)
      return result;
@@ -944,7 +945,7 @@ CURLcode Curl_http_connect(struct connectdata *conn)

  if(conn->protocol & PROT_HTTPS) {
    /* now, perform the SSL initialization for this socket */
    result = Curl_SSLConnect(conn);
    result = Curl_SSLConnect(conn, FIRSTSOCKET);
    if(result)
      return result;
  }
@@ -1491,15 +1492,15 @@ CURLcode Curl_http(struct connectdata *conn)
      Curl_pgrsSetUploadSize(data, http->postsize);

      /* 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);
      if(result)
        failf(data, "Failed sending POST request");
      else
        /* setup variables for the upcoming transfer */
        result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
        result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
                               &http->readbytecount,
                               conn->firstsocket,
                               FIRSTSOCKET,
                               &http->writebytecount);
      if(result) {
        Curl_formclean(http->sendit); /* free that whole lot */
@@ -1521,15 +1522,15 @@ CURLcode Curl_http(struct connectdata *conn)
      Curl_pgrsSetUploadSize(data, data->set.infilesize);

      /* 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);
      if(result)
        failf(data, "Failed sending POST request");
      else
        /* prepare for transfer */
        result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
        result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
                               &http->readbytecount,
                               conn->firstsocket,
                               FIRSTSOCKET,
                               &http->writebytecount);
      if(result)
        return result;
@@ -1602,16 +1603,16 @@ CURLcode Curl_http(struct connectdata *conn)
        http->postdata = (char *)&http->postdata;
      }
      /* issue the request */
      result = add_buffer_send(req_buffer, conn->firstsocket, conn,
      result = add_buffer_send(req_buffer, conn,
                               &data->info.request_size);

      if(result)
        failf(data, "Failed sending HTTP POST request");
      else
        result =
          Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
          Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
                        &http->readbytecount,
                        http->postdata?conn->firstsocket:-1,
                        http->postdata?FIRSTSOCKET:-1,
                        http->postdata?&http->writebytecount:NULL);
      break;

@@ -1619,16 +1620,16 @@ CURLcode Curl_http(struct connectdata *conn)
      add_buffer(req_buffer, "\r\n", 2);
      
      /* issue the request */
      result = add_buffer_send(req_buffer, conn->firstsocket, conn,
      result = add_buffer_send(req_buffer, conn,
                               &data->info.request_size);

      if(result)
        failf(data, "Failed sending HTTP request");
      else
        /* HTTP GET/HEAD download: */
        result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
        result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
                               &http->readbytecount,
                               http->postdata?conn->firstsocket:-1,
                               http->postdata?FIRSTSOCKET:-1,
                               http->postdata?&http->writebytecount:NULL);
    }
    if(result)
+7 −7
Original line number Diff line number Diff line
@@ -266,7 +266,7 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
        int sockfd;

        if(CURLM_STATE_WAITCONNECT == easy->state) {
          sockfd = conn->firstsocket;
          sockfd = conn->sock[FIRSTSOCKET];
          FD_SET(sockfd, write_fd_set);
        }
        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
             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 */
          sockfd = conn->secondarysocket;
          sockfd = conn->sock[SECONDARYSOCKET];
          FD_SET(sockfd, write_fd_set);
        }

@@ -390,7 +390,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
    case CURLM_STATE_WAITCONNECT:
      /* awaiting a completion of an asynch connect */
      easy->result = Curl_is_connected(easy->easy_conn,
                                       easy->easy_conn->firstsocket,
                                       easy->easy_conn->sock[FIRSTSOCKET],
                                       &connected);
      if(connected)
        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.
       */
      easy->result = Curl_is_connected(easy->easy_conn,
                                       easy->easy_conn->secondarysocket,
                                       easy->easy_conn->sock[SECONDARYSOCKET],
                                       &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. */
        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
             it was used */
          sclose(easy->easy_conn->secondarysocket);
          easy->easy_conn->secondarysocket=-1;
          sclose(easy->easy_conn->sock[SECONDARYSOCKET]);
          easy->easy_conn->sock[SECONDARYSOCKET]=-1;
        }
        Curl_posttransfer(easy->easy_handle);
        Curl_done(easy->easy_conn);
Loading