~ubuntu-branches/ubuntu/lucid/curl/lucid-security

« back to all changes in this revision

Viewing changes to lib/ftp.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2005-12-12 15:04:52 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20051212150452-2ymlra67b2p7kjyy
Tags: 7.15.1-1ubuntu1
Resynchronise with Debian to get URL parser overflow fix from 7.15.1
(CVE-2005-4077).

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
 * KIND, either express or implied.
20
20
 *
21
 
 * $Id: ftp.c,v 1.322 2005/05/14 06:00:40 giva Exp $
 
21
 * $Id: ftp.c,v 1.339 2005/12/05 14:10:48 bagder Exp $
22
22
 ***************************************************************************/
23
23
 
24
24
#include "setup.h"
94
94
#include "inet_ntop.h"
95
95
#include "select.h"
96
96
#include "parsedate.h" /* for the week day and month names */
 
97
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
97
98
 
98
99
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
99
100
#include "inet_ntoa_r.h"
209
210
  default:
210
211
    /* we have received data here */
211
212
    {
212
 
      curl_socket_t s;
213
 
      size_t size = sizeof(struct sockaddr_in);
 
213
      curl_socket_t s = CURL_SOCKET_BAD;
 
214
      socklen_t size = (socklen_t) sizeof(struct sockaddr_in);
214
215
      struct sockaddr_in add;
215
216
 
216
 
      getsockname(sock, (struct sockaddr *) &add, (socklen_t *)&size);
217
 
      s=accept(sock, (struct sockaddr *) &add, (socklen_t *)&size);
 
217
      if(0 == getsockname(sock, (struct sockaddr *) &add, &size))
 
218
        s=accept(sock, (struct sockaddr *) &add, &size);
218
219
 
219
220
      sclose(sock); /* close the first socket */
220
221
 
777
778
  /******************************************************************
778
779
   * IPv6-specific section
779
780
   */
780
 
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
781
 
  struct sockaddr_storage ss;
782
 
#else
783
 
  char ss[256]; /* this should be big enough to fit a lot */
784
 
#endif
 
781
  struct Curl_sockaddr_storage ss;
785
782
  struct addrinfo *res, *ai;
786
783
  socklen_t sslen;
787
784
  char hbuf[NI_MAXHOST];
843
840
     * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
844
841
     */
845
842
    if (ai->ai_socktype == 0)
846
 
      ai->ai_socktype = SOCK_STREAM;
 
843
      ai->ai_socktype = conn->socktype;
847
844
 
848
845
    portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
849
846
    if (portsock == CURL_SOCKET_BAD) {
1110
1107
    }
1111
1108
  }
1112
1109
  else {
1113
 
    failf(data, "could't find IP address to use");
 
1110
    failf(data, "couldn't find IP address to use");
1114
1111
    return CURLE_FTP_PORT_FAILED;
1115
1112
  }
1116
1113
 
1586
1583
      return CURLE_FTP_WEIRD_227_FORMAT;
1587
1584
    }
1588
1585
 
1589
 
    snprintf(newhost, sizeof(newhost),
1590
 
             "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
 
1586
    /* we got OK from server */
 
1587
    if(data->set.ftp_skip_ip) {
 
1588
      /* told to ignore the remotely given IP but instead use the one we used
 
1589
         for the control connection */
 
1590
      infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
 
1591
            ip[0], ip[1], ip[2], ip[3],
 
1592
            conn->ip_addr_str);
 
1593
      snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str);
 
1594
    }
 
1595
    else
 
1596
      snprintf(newhost, sizeof(newhost),
 
1597
               "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1591
1598
    newport = (port[0]<<8) + port[1];
1592
1599
  }
1593
1600
  else if(ftp->count1 == 0) {
1607
1614
    return CURLE_FTP_WEIRD_PASV_REPLY;
1608
1615
  }
1609
1616
 
1610
 
  /* we got OK from server */
1611
 
 
1612
1617
  if(data->change.proxy && *data->change.proxy) {
1613
1618
    /*
1614
1619
     * This is a tunnel through a http proxy and we need to connect to the
1670
1675
 
1671
1676
    /* BLOCKING */
1672
1677
    /* We want "seamless" FTP operations through HTTP proxy tunnel */
1673
 
    result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET,
1674
 
                                         newhost, newport);
 
1678
    result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
1675
1679
    if(CURLE_OK != result)
1676
1680
      return result;
1677
1681
  }
1791
1795
      switch(data->set.timecondition) {
1792
1796
      case CURL_TIMECOND_IFMODSINCE:
1793
1797
      default:
1794
 
        if(data->info.filetime < data->set.timevalue) {
 
1798
        if(data->info.filetime <= data->set.timevalue) {
1795
1799
          infof(data, "The requested document is not new enough\n");
1796
1800
          ftp->no_transfer = TRUE; /* mark this to not transfer data */
1797
1801
          state(conn, FTP_STOP);
1826
1830
  CURLcode result = CURLE_OK;
1827
1831
  struct SessionHandle *data=conn->data;
1828
1832
 
1829
 
  if(ftpcode != 200) {
 
1833
  if(ftpcode/100 != 2) {
 
1834
    /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
 
1835
       successful 'TYPE I'. While that is not as RFC959 says, it is still a
 
1836
       positive response code and we allow that. */
1830
1837
    failf(data, "Couldn't set desired mode");
1831
1838
    return CURLE_FTP_COULDNT_SET_BINARY; /* FIX */
1832
1839
  }
 
1840
  if(ftpcode != 200)
 
1841
    infof(data, "Got a %03d response code instead of the assumed 200\n",
 
1842
          ftpcode);
 
1843
 
1833
1844
  if(instate == FTP_TYPE)
1834
1845
    result = ftp_state_post_type(conn);
1835
1846
  else if(instate == FTP_LIST_TYPE)
2515
2526
          NBFTPSENDF(conn, "MKD %s", ftp->dirs[ftp->count1 - 1]);
2516
2527
          state(conn, FTP_MKD);
2517
2528
        }
2518
 
        else
 
2529
        else {
2519
2530
          /* return failure */
 
2531
          failf(data, "Server denied you to change to the given directory");
2520
2532
          return CURLE_FTP_ACCESS_DENIED;
 
2533
        }
2521
2534
      }
2522
2535
      else {
2523
2536
        /* success */
2738
2751
  if (conn->bits.tunnel_proxy) {
2739
2752
    /* BLOCKING */
2740
2753
    /* We want "seamless" FTP operations through HTTP proxy tunnel */
2741
 
    result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET,
2742
 
                                         conn->host.name, conn->remote_port);
 
2754
    result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
 
2755
                               conn->host.name, conn->remote_port);
2743
2756
    if(CURLE_OK != result)
2744
2757
      return result;
2745
2758
  }
3164
3177
  *connected = conn->bits.tcpconnect;
3165
3178
 
3166
3179
  if(*dophase_done)
3167
 
    DEBUGF(infof(conn->data, "DO phase is comlete\n"));
 
3180
    DEBUGF(infof(conn->data, "DO phase is complete\n"));
3168
3181
 
3169
3182
  return result;
3170
3183
}
3629
3642
  return CURLE_OK;
3630
3643
}
3631
3644
 
3632
 
 
3633
 
 
3634
3645
/***********************************************************************
3635
3646
 *
3636
3647
 * ftp_parse_url_path()
3654
3665
  ftp = conn->proto.ftp;
3655
3666
  ftp->ctl_valid = FALSE;
3656
3667
 
3657
 
  ftp->dirdepth = 0;
3658
 
  ftp->diralloc = 5; /* default dir depth to allocate */
3659
 
  ftp->dirs = (char **)calloc(ftp->diralloc, sizeof(ftp->dirs[0]));
3660
 
  if(!ftp->dirs)
3661
 
    return CURLE_OUT_OF_MEMORY;
3662
 
 
3663
 
  /* parse the URL path into separate path components */
3664
 
  while((slash_pos=strchr(cur_pos, '/'))) {
3665
 
    /* 1 or 0 to indicate absolute directory */
3666
 
    bool absolute_dir = (cur_pos - conn->path > 0) && (ftp->dirdepth == 0);
3667
 
 
3668
 
    /* seek out the next path component */
3669
 
    if (slash_pos-cur_pos) {
3670
 
      /* we skip empty path components, like "x//y" since the FTP command CWD
3671
 
         requires a parameter and a non-existant parameter a) doesn't work on
3672
 
         many servers and b) has no effect on the others. */
3673
 
      int len = (int)(slash_pos - cur_pos + absolute_dir);
3674
 
      ftp->dirs[ftp->dirdepth] = curl_unescape(cur_pos - absolute_dir, len);
3675
 
 
3676
 
      if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
3677
 
        failf(data, "no memory");
3678
 
        freedirs(ftp);
3679
 
        return CURLE_OUT_OF_MEMORY;
3680
 
      }
3681
 
      if (isBadFtpString(ftp->dirs[ftp->dirdepth])) {
3682
 
        freedirs(ftp);
3683
 
        return CURLE_URL_MALFORMAT;
3684
 
      }
3685
 
    }
3686
 
    else {
3687
 
      cur_pos = slash_pos + 1; /* jump to the rest of the string */
3688
 
      continue;
3689
 
    }
3690
 
 
3691
 
    if(!retcode) {
3692
 
      cur_pos = slash_pos + 1; /* jump to the rest of the string */
3693
 
      if(++ftp->dirdepth >= ftp->diralloc) {
3694
 
        /* enlarge array */
3695
 
        char *bigger;
3696
 
        ftp->diralloc *= 2; /* double the size each time */
3697
 
        bigger = realloc(ftp->dirs, ftp->diralloc * sizeof(ftp->dirs[0]));
3698
 
        if(!bigger) {
3699
 
          ftp->dirdepth--;
 
3668
  switch(data->set.ftp_filemethod) {
 
3669
  case FTPFILE_NOCWD:
 
3670
    /* fastest, but less standard-compliant */
 
3671
    ftp->file = conn->path;  /* this is a full file path */
 
3672
    break;
 
3673
 
 
3674
  case FTPFILE_SINGLECWD:
 
3675
    /* get the last slash */
 
3676
    slash_pos=strrchr(cur_pos, '/');
 
3677
    if(slash_pos) {
 
3678
      ftp->dirdepth = 1; /* we consider it to be a single dir */
 
3679
      ftp->dirs = (char **)calloc(1, sizeof(ftp->dirs[0]));
 
3680
      if(!ftp->dirs)
 
3681
        return CURLE_OUT_OF_MEMORY;
 
3682
 
 
3683
      ftp->dirs[0] = curl_unescape(cur_pos, (int)(slash_pos-cur_pos));
 
3684
      if(!ftp->dirs[0]) {
 
3685
        free(ftp->dirs);
 
3686
        return CURLE_OUT_OF_MEMORY;
 
3687
      }
 
3688
      ftp->file = slash_pos+1;  /* the rest is the file name */
 
3689
    }
 
3690
    else
 
3691
      ftp->file = cur_pos;  /* this is a file name only */
 
3692
    break;
 
3693
 
 
3694
  default: /* allow pretty much anything */
 
3695
  case FTPFILE_MULTICWD:
 
3696
    ftp->dirdepth = 0;
 
3697
    ftp->diralloc = 5; /* default dir depth to allocate */
 
3698
    ftp->dirs = (char **)calloc(ftp->diralloc, sizeof(ftp->dirs[0]));
 
3699
    if(!ftp->dirs)
 
3700
      return CURLE_OUT_OF_MEMORY;
 
3701
 
 
3702
    /* parse the URL path into separate path components */
 
3703
    while((slash_pos=strchr(cur_pos, '/'))) {
 
3704
      /* 1 or 0 to indicate absolute directory */
 
3705
      bool absolute_dir = (cur_pos - conn->path > 0) && (ftp->dirdepth == 0);
 
3706
 
 
3707
      /* seek out the next path component */
 
3708
      if (slash_pos-cur_pos) {
 
3709
        /* we skip empty path components, like "x//y" since the FTP command CWD
 
3710
           requires a parameter and a non-existant parameter a) doesn't work on
 
3711
           many servers and b) has no effect on the others. */
 
3712
        int len = (int)(slash_pos - cur_pos + absolute_dir);
 
3713
        ftp->dirs[ftp->dirdepth] = curl_unescape(cur_pos - absolute_dir, len);
 
3714
 
 
3715
        if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
 
3716
          failf(data, "no memory");
3700
3717
          freedirs(ftp);
3701
3718
          return CURLE_OUT_OF_MEMORY;
3702
3719
        }
3703
 
        ftp->dirs = (char **)bigger;
 
3720
        if (isBadFtpString(ftp->dirs[ftp->dirdepth])) {
 
3721
          freedirs(ftp);
 
3722
          return CURLE_URL_MALFORMAT;
 
3723
        }
 
3724
      }
 
3725
      else {
 
3726
        cur_pos = slash_pos + 1; /* jump to the rest of the string */
 
3727
        continue;
 
3728
      }
 
3729
 
 
3730
      if(!retcode) {
 
3731
        cur_pos = slash_pos + 1; /* jump to the rest of the string */
 
3732
        if(++ftp->dirdepth >= ftp->diralloc) {
 
3733
          /* enlarge array */
 
3734
          char *bigger;
 
3735
          ftp->diralloc *= 2; /* double the size each time */
 
3736
          bigger = realloc(ftp->dirs, ftp->diralloc * sizeof(ftp->dirs[0]));
 
3737
          if(!bigger) {
 
3738
            ftp->dirdepth--;
 
3739
            freedirs(ftp);
 
3740
            return CURLE_OUT_OF_MEMORY;
 
3741
          }
 
3742
          ftp->dirs = (char **)bigger;
 
3743
        }
3704
3744
      }
3705
3745
    }
 
3746
 
 
3747
    ftp->file = cur_pos;  /* the rest is the file name */
3706
3748
  }
3707
3749
 
3708
 
  ftp->file = cur_pos;  /* the rest is the file name */
3709
 
 
3710
3750
  if(*ftp->file) {
3711
3751
    ftp->file = curl_unescape(ftp->file, 0);
3712
3752
    if(NULL == ftp->file) {
3797
3837
    /* Failure detected, close the second socket if it was created already */
3798
3838
    sclose(conn->sock[SECONDARYSOCKET]);
3799
3839
    conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
 
3840
    return result;
3800
3841
  }
3801
3842
 
3802
3843
  if(ftp->no_transfer)
3821
3862
  if(*dophase_done) {
3822
3863
    result = ftp_dophase_done(conn, FALSE /* not connected */);
3823
3864
 
3824
 
    DEBUGF(infof(conn->data, "DO phase is comlete\n"));
 
3865
    DEBUGF(infof(conn->data, "DO phase is complete\n"));
3825
3866
  }
3826
3867
  return result;
3827
3868
}