home *** CD-ROM | disk | FTP | other *** search
/ ftp.ncftp.com / ftp.ncftp.com.zip / ftp.ncftp.com / ncftp / older_versions / ncftp-3.2.2-src.tar.bz2 / ncftp-3.2.2-src.tar / ncftp-3.2.2 / libncftp / ftp.c < prev    next >
C/C++ Source or Header  |  2008-07-13  |  36KB  |  1,285 lines

  1. /* ftp.c
  2.  *
  3.  * Copyright (c) 1996-2005 Mike Gleason, NcFTP Software.
  4.  * All rights reserved.
  5.  *
  6.  */
  7.  
  8. #include "syshdrs.h"
  9. #ifdef PRAGMA_HDRSTOP
  10. #    pragma hdrstop
  11. #endif
  12.  
  13. #define _CRT_SECURE_NO_WARNINGS 1
  14.  
  15. const char gLibNcFTPVersion[] = kLibraryVersion;
  16.  
  17. #ifdef NO_SIGNALS
  18. static const char gNoSignalsMarker[] = "@(#) LibNcFTP - NO_SIGNALS";
  19. #else
  20.  
  21. static int gGotSig = 0;
  22. #ifdef HAVE_SIGSETJMP
  23. static sigjmp_buf gCancelConnectJmp;
  24. #else
  25. static jmp_buf gCancelConnectJmp;
  26. #endif    /* HAVE_SIGSETJMP */
  27.  
  28. #endif    /* NO_SIGNALS */
  29.  
  30.  
  31. #ifndef lint
  32. static const char gCopyright[] = "@(#) LibNcFTP Copyright 1995-2001, by Mike Gleason.  All rights reserved.";
  33. #endif
  34.  
  35. #ifdef HAVE_LIBSOCKS5
  36. #    define SOCKS 5
  37. #    include <socks.h>
  38. #else
  39. #    ifdef HAVE_LIBSOCKS
  40. #        define accept        Raccept
  41. #        define connect        Rconnect
  42. #        define getsockname    Rgetsockname
  43. #        define listen        Rlisten
  44. #    endif
  45. #endif
  46.  
  47. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  48. #    define DisposeSocket(a) shutdown(a, 2); closesocket(a)
  49. #else
  50. #    define DisposeSocket(a) close(a)
  51. #endif
  52.  
  53. static const char *gPrivateNetworks[] = {
  54.     "192.168.",
  55.     "10.",
  56.     "172.16.",
  57.     "172.17.",
  58.     "172.18.",
  59.     "172.19.",
  60.     "172.20.",
  61.     "172.21.",
  62.     "172.22.",
  63.     "172.23.",
  64.     "172.24.",
  65.     "172.25.",
  66.     "172.26.",
  67.     "172.27.",
  68.     "172.28.",
  69.     "172.29.",
  70.     "172.30.",
  71.     "172.31.",
  72.     NULL
  73. };
  74.  
  75.  
  76.  
  77.  
  78. void
  79. FTPCloseControlConnection(const FTPCIPtr cip)
  80. {
  81.     /* This will close each file, if it was open. */
  82. #ifdef NO_SIGNALS
  83.     SClose(cip->ctrlSocketR, 3);
  84.     cip->ctrlSocketR = kClosedFileDescriptor;
  85.     cip->ctrlSocketW = kClosedFileDescriptor;
  86.     DisposeSReadlineInfo(&cip->ctrlSrl);
  87. #else    /* NO_SIGNALS */
  88.     if (cip->ctrlTimeout > 0)
  89.         (void) alarm(cip->ctrlTimeout);
  90.     CloseFile(&cip->cin);
  91.     CloseFile(&cip->cout);
  92.     cip->ctrlSocketR = kClosedFileDescriptor;
  93.     cip->ctrlSocketW = kClosedFileDescriptor;
  94.     if (cip->ctrlTimeout > 0)
  95.         (void) alarm(0);
  96. #endif    /* NO_SIGNALS */
  97.     cip->connected = 0;
  98.     cip->loggedIn = 0;
  99. }    /* FTPCloseControlConnection */
  100.  
  101.  
  102.  
  103. static int
  104. GetSocketAddress(const FTPCIPtr cip, int sockfd, struct sockaddr_in *saddr)
  105. {
  106.     sockaddr_size_t len = (sockaddr_size_t) sizeof (struct sockaddr_in);
  107.     int result = 0;
  108.  
  109.     if (getsockname(sockfd, (struct sockaddr *)saddr, &len) < 0) {
  110.         FTPLogError(cip, kDoPerror, "Could not get socket name.\n");
  111.         cip->errNo = kErrGetSockName;
  112.         result = kErrGetSockName;
  113.     }
  114.     return (result);
  115. }    /* GetSocketAddress */
  116.  
  117.  
  118.  
  119.  
  120. #ifndef NO_SIGNALS
  121.  
  122. static void
  123. CancelConnect(int signum)
  124. {
  125.     gGotSig = signum;
  126. #ifdef HAVE_SIGSETJMP
  127.     siglongjmp(gCancelConnectJmp, 1);
  128. #else
  129.     longjmp(gCancelConnectJmp, 1);
  130. #endif    /* HAVE_SIGSETJMP */
  131. }    /* CancelConnect */
  132.  
  133. #endif    /* NO_SIGNALS */
  134.  
  135.  
  136.  
  137. int
  138. OpenControlConnection(const FTPCIPtr cip, char *host, unsigned int port)
  139. {
  140.     struct in_addr ip_address;
  141.     int err = 0;
  142.     int result;
  143.     int oerrno;
  144.     volatile int sockfd = -1;
  145.     volatile int sock2fd = -1;
  146.     ResponsePtr rp = NULL;
  147.     char **volatile curaddr;
  148.     int hpok;
  149.     struct hostent hp;
  150.     char *volatile fhost;
  151.     unsigned int fport;
  152. #ifndef NO_SIGNALS
  153.     volatile FTPSigProc osigint;
  154.     volatile FTPSigProc osigalrm;
  155.     volatile FTPCIPtr vcip;
  156.     int sj;
  157. #endif    /* NO_SIGNALS */
  158.     const char *firstLine, *secondLine, *srvr;
  159.  
  160.     LIBNCFTP_USE_VAR(gLibNcFTPVersion);
  161.     LIBNCFTP_USE_VAR(gCopyright);
  162. #ifdef NO_SIGNALS
  163.     LIBNCFTP_USE_VAR(gNoSignalsMarker);
  164. #endif    /* NO_SIGNALS */
  165.  
  166.     if (cip->firewallType == kFirewallNotInUse) {
  167.         fhost = host;
  168.         fport = port;
  169.     } else {
  170.         fhost = cip->firewallHost;
  171.         fport = cip->firewallPort;
  172.     }
  173.     if (fport == 0)
  174.         fport = cip->lip->defaultPort;
  175.  
  176.     /* Since we're the client, we just have to get a socket() and
  177.      * connect() it.
  178.      */
  179.     (void) ZERO(cip->servCtlAddr);
  180.     cip->cin = NULL;
  181.     cip->cout = NULL;
  182.  
  183.     /* Make sure we use network byte-order. */
  184.     fport = (unsigned int) htons((unsigned short) fport);
  185.  
  186.     cip->servCtlAddr.sin_port = (unsigned short) fport;
  187.  
  188.     if (GetHostEntry(&hp, fhost, &ip_address, cip->buf, cip->bufSize) != 0) {
  189.         hpok = 0;
  190.         /* Okay, no Host entry, but maybe we have a numeric address
  191.          * in ip_address we can try.
  192.          */
  193.         if (ip_address.s_addr == INADDR_NONE) {
  194.             FTPLogError(cip, kDontPerror, "%s: unknown host.\n", fhost);
  195.             cip->errNo = kErrHostUnknown;
  196.             return (kErrHostUnknown);
  197.         }
  198.         cip->servCtlAddr.sin_family = AF_INET;
  199.         cip->servCtlAddr.sin_addr.s_addr = ip_address.s_addr;
  200.     } else {
  201.         hpok = 1;
  202.         cip->servCtlAddr.sin_family = hp.h_addrtype;
  203.         /* We'll fill in the rest of the structure below. */
  204.     }
  205.     
  206.     /* After obtaining a socket, try to connect it to a remote
  207.      * address.  If we didn't get a host entry, we will only have
  208.      * one thing to try (ip_address);  if we do have one, we can try
  209.      * every address in the list from the host entry.
  210.      */
  211.  
  212.     if (hpok == 0) {
  213.         /* Since we're given a single raw address, and not a host entry,
  214.          * we can only try this one address and not any other addresses
  215.          * that could be present for a site with a host entry.
  216.          */
  217.  
  218.         if ((sockfd = socket(cip->servCtlAddr.sin_family, SOCK_STREAM, 0)) < 0) {
  219.             FTPLogError(cip, kDoPerror, "Could not get a socket.\n");
  220.             cip->errNo = kErrNewStreamSocket;
  221.             return (kErrNewStreamSocket);
  222.         }
  223.  
  224.         /* This doesn't do anything if you left these
  225.          * at their defaults (zero).  Otherwise it
  226.          * tries to set the buffer size to the
  227.          * size specified.
  228.          */
  229.         (void) SetSocketBufSize(sockfd, cip->ctrlSocketRBufSize, cip->ctrlSocketSBufSize);
  230.  
  231. #ifdef NO_SIGNALS
  232.         err = SConnect(sockfd, &cip->servCtlAddr, (int) cip->connTimeout);
  233.  
  234.         if (err < 0) {
  235.             oerrno = errno;
  236.             (void) SClose(sockfd, 3);
  237.             errno = oerrno;
  238.             sockfd = -1;
  239.         }
  240. #else    /* NO_SIGNALS */
  241.         osigint = (volatile FTPSigProc) signal(SIGINT, CancelConnect);
  242.         if (cip->connTimeout > 0) {
  243.             osigalrm = (volatile FTPSigProc) signal(SIGALRM, CancelConnect);
  244.             (void) alarm(cip->connTimeout);
  245.         }
  246.  
  247.         vcip = cip;
  248.  
  249. #ifdef HAVE_SIGSETJMP
  250.         sj = sigsetjmp(gCancelConnectJmp, 1);
  251. #else
  252.         sj = setjmp(gCancelConnectJmp);
  253. #endif    /* HAVE_SIGSETJMP */
  254.  
  255.         if (sj != 0) {
  256.             /* Interrupted by a signal. */
  257.             (void) DisposeSocket(sockfd);
  258.             (void) signal(SIGINT, (FTPSigProc) osigint);
  259.             if (vcip->connTimeout > 0) {
  260.                 (void) alarm(0);
  261.                 (void) signal(SIGALRM, (FTPSigProc) osigalrm);
  262.             }
  263.             if (gGotSig == SIGINT) {
  264.                 result = vcip->errNo = kErrConnectMiscErr;
  265.                 Error(vcip, kDontPerror, "Connection attempt canceled.\n");
  266.                 (void) kill(getpid(), SIGINT);
  267.             } else if (gGotSig == SIGALRM) {
  268.                 result = vcip->errNo = kErrConnectRetryableErr;
  269.                 Error(vcip, kDontPerror, "Connection attempt timed-out.\n");
  270.                 (void) kill(getpid(), SIGALRM);
  271.             } else {
  272.                 result = vcip->errNo = kErrConnectMiscErr;
  273.                 Error(vcip, kDontPerror, "Connection attempt failed due to an unexpected signal (%d).\n", gGotSig);
  274.             }
  275.             return (result);
  276.         } else  {
  277.             err = connect(sockfd, (struct sockaddr *) &cip->servCtlAddr,
  278.                       (int) sizeof (cip->servCtlAddr));
  279.             if (cip->connTimeout > 0) {
  280.                 (void) alarm(0);
  281.                 (void) signal(SIGALRM, (FTPSigProc) osigalrm);
  282.             }
  283.             (void) signal(SIGINT, (FTPSigProc) osigint);
  284.         }
  285.  
  286.         if (err < 0) {
  287.             oerrno = errno;
  288.             (void) DisposeSocket(sockfd);
  289.             errno = oerrno;
  290.             sockfd = -1;
  291.         }
  292. #endif    /* NO_SIGNALS */
  293.     } else {
  294.         /* We can try each address in the list.  We'll quit when we
  295.          * run out of addresses to try or get a successful connection.
  296.          */
  297.         for (curaddr = hp.h_addr_list; *curaddr != NULL; curaddr++) {
  298.             if ((sockfd = socket(cip->servCtlAddr.sin_family, SOCK_STREAM, 0)) < 0) {
  299.                 FTPLogError(cip, kDoPerror, "Could not get a socket.\n");
  300.                 cip->errNo = kErrNewStreamSocket;
  301.                 return (kErrNewStreamSocket);
  302.             }
  303.             /* This could overwrite the address field in the structure,
  304.              * but this is okay because the structure has a junk field
  305.              * just for this purpose.
  306.              */
  307.             (void) memcpy(&cip->servCtlAddr.sin_addr, *curaddr, (size_t) hp.h_length);
  308.  
  309.             /* This doesn't do anything if you left these
  310.              * at their defaults (zero).  Otherwise it
  311.              * tries to set the buffer size to the
  312.              * size specified.
  313.              */
  314.             (void) SetSocketBufSize(sockfd, cip->ctrlSocketRBufSize, cip->ctrlSocketSBufSize);
  315.  
  316. #ifdef NO_SIGNALS
  317.             err = SConnect(sockfd, &cip->servCtlAddr, (int) cip->connTimeout);
  318.  
  319.             if (err == 0)
  320.                 break;
  321.             oerrno = errno;
  322.             (void) SClose(sockfd, 3);
  323.             errno = oerrno;
  324.             sockfd = -1;
  325. #else    /* NO_SIGNALS */
  326.  
  327.             osigint = (volatile FTPSigProc) signal(SIGINT, CancelConnect);
  328.             if (cip->connTimeout > 0) {
  329.                 osigalrm = (volatile FTPSigProc) signal(SIGALRM, CancelConnect);
  330.                 (void) alarm(cip->connTimeout);
  331.             }
  332.  
  333.             vcip = cip;
  334. #ifdef HAVE_SIGSETJMP
  335.             sj = sigsetjmp(gCancelConnectJmp, 1);
  336. #else
  337.             sj = setjmp(gCancelConnectJmp);
  338. #endif    /* HAVE_SIGSETJMP */
  339.  
  340.             if (sj != 0) {
  341.                 /* Interrupted by a signal. */
  342.                 (void) DisposeSocket(sockfd);
  343.                 (void) signal(SIGINT, (FTPSigProc) osigint);
  344.                 if (vcip->connTimeout > 0) {
  345.                     (void) alarm(0);
  346.                     (void) signal(SIGALRM, (FTPSigProc) osigalrm);
  347.                 }
  348.                 if (gGotSig == SIGINT) {
  349.                     result = vcip->errNo = kErrConnectMiscErr;
  350.                     Error(vcip, kDontPerror, "Connection attempt canceled.\n");
  351.                     (void) kill(getpid(), SIGINT);
  352.                 } else if (gGotSig == SIGALRM) {
  353.                     result = vcip->errNo = kErrConnectRetryableErr;
  354.                     Error(vcip, kDontPerror, "Connection attempt timed-out.\n");
  355.                     (void) kill(getpid(), SIGALRM);
  356.                 } else {
  357.                     result = vcip->errNo = kErrConnectMiscErr;
  358.                     Error(vcip, kDontPerror, "Connection attempt failed due to an unexpected signal (%d).\n", gGotSig);
  359.                 }
  360.                 return (result);
  361.             } else {
  362.                 err = connect(sockfd, (struct sockaddr *) &cip->servCtlAddr,
  363.                           (int) sizeof (cip->servCtlAddr));
  364.                 if (cip->connTimeout > 0) {
  365.                     (void) alarm(0);
  366.                     (void) signal(SIGALRM, (FTPSigProc) osigalrm);
  367.                 }
  368.                 (void) signal(SIGINT, (FTPSigProc) osigint);
  369.             }
  370.  
  371.             if (err == 0)
  372.                 break;
  373.             oerrno = errno;
  374.             (void) DisposeSocket(sockfd);
  375.             errno = oerrno;
  376.             sockfd = -1;
  377. #endif /* NO_SIGNALS */
  378.         }
  379.     }
  380.     
  381.     if (err < 0) {
  382.         /* Could not connect.  Close up shop and go home. */
  383.  
  384.         /* If possible, tell the caller if they should bother
  385.          * calling back later.
  386.          */
  387.         switch (errno) {
  388. #ifdef ENETDOWN
  389.             case ENETDOWN:
  390. #elif defined(WSAENETDOWN)
  391.             case WSAENETDOWN:
  392. #endif
  393. #ifdef ENETUNREACH
  394.             case ENETUNREACH:
  395. #elif defined(WSAENETUNREACH)
  396.             case WSAENETUNREACH:
  397. #endif
  398. #ifdef ECONNABORTED
  399.             case ECONNABORTED:
  400. #elif defined(WSAECONNABORTED)
  401.             case WSAECONNABORTED:
  402. #endif
  403. #ifdef ETIMEDOUT
  404.             case ETIMEDOUT:
  405. #elif defined(WSAETIMEDOUT)
  406.             case WSAETIMEDOUT:
  407. #endif
  408. #ifdef EHOSTDOWN
  409.             case EHOSTDOWN:
  410. #elif defined(WSAEHOSTDOWN)
  411.             case WSAEHOSTDOWN:
  412. #endif
  413. #ifdef ECONNRESET
  414.             case ECONNRESET:
  415. #elif defined(WSAECONNRESET)
  416.             case WSAECONNRESET:
  417. #endif
  418.                 FTPLogError(cip, kDoPerror, "Could not connect to %s -- try again later.\n", fhost);
  419.                 result = cip->errNo = kErrConnectRetryableErr;
  420.                 break;
  421. #ifdef ECONNREFUSED
  422.             case ECONNREFUSED:
  423. #elif defined(WSAECONNREFUSED)
  424.             case WSAECONNREFUSED:
  425. #endif
  426.                 FTPLogError(cip, kDoPerror, "Could not connect to %s.\n", fhost);
  427.                 result = cip->errNo = kErrConnectRefused;
  428.                 break;
  429.             default:
  430.                 FTPLogError(cip, kDoPerror, "Could not connect to %s.\n", fhost);
  431.                 result = cip->errNo = kErrConnectMiscErr;
  432.         }
  433.         goto fatal;
  434.     }
  435.  
  436.     /* Get our end of the socket address for later use. */
  437.     if ((result = GetSocketAddress(cip, sockfd, &cip->ourCtlAddr)) < 0)
  438.         goto fatal;
  439.  
  440.     /* We want Out-of-band data to appear in the regular stream,
  441.      * since we can handle TELNET.
  442.      */
  443.     (void) SetSocketInlineOutOfBandData(sockfd, 1);
  444.     (void) SetSocketKeepAlive(sockfd, 1);
  445.     (void) SetSocketLinger(sockfd, 0, 0);    /* Don't need it for ctrl. */
  446.  
  447.     /* Control connection is somewhat interactive, so quick response
  448.      * is desired.
  449.      */
  450.     (void) SetSocketTypeOfService(sockfd, IPTOS_LOWDELAY);
  451.  
  452. #ifdef NO_SIGNALS
  453.     cip->ctrlSocketR = sockfd;
  454.     cip->ctrlSocketW = sockfd;
  455.     cip->cout = NULL;
  456.     cip->cin = NULL;
  457.     sock2fd = kClosedFileDescriptor;
  458.  
  459.     if (InitSReadlineInfo(&cip->ctrlSrl, sockfd, cip->srlBuf, sizeof(cip->srlBuf), (int) cip->ctrlTimeout, 1) < 0) {
  460.         result = kErrFdopenW;
  461.         cip->errNo = kErrFdopenW;
  462.         FTPLogError(cip, kDoPerror, "Could not fdopen.\n");
  463.         goto fatal;
  464.     }
  465. #else    /* NO_SIGNALS */
  466.     if ((sock2fd = dup(sockfd)) < 0) {
  467.         result = kErrDupSocket;
  468.         cip->errNo = kErrDupSocket;
  469.         FTPLogError(cip, kDoPerror, "Could not duplicate a file descriptor.\n");
  470.         goto fatal;
  471.     }
  472.  
  473.     /* Now setup the FILE pointers for use with the Std I/O library
  474.      * routines.
  475.      */
  476.     if ((cip->cin = fdopen(sockfd, "r")) == NULL) {
  477.         result = kErrFdopenR;
  478.         cip->errNo = kErrFdopenR;
  479.         FTPLogError(cip, kDoPerror, "Could not fdopen.\n");
  480.         goto fatal;
  481.     }
  482.  
  483.     if ((cip->cout = fdopen(sock2fd, "w")) == NULL) {
  484.         result = kErrFdopenW;
  485.         cip->errNo = kErrFdopenW;
  486.         FTPLogError(cip, kDoPerror, "Could not fdopen.\n");
  487.         CloseFile(&cip->cin);
  488.         sockfd = kClosedFileDescriptor;
  489.         goto fatal;
  490.     }
  491.  
  492.     cip->ctrlSocketR = sockfd;
  493.     cip->ctrlSocketW = sockfd;
  494.  
  495.     /* We'll be reading and writing lines, so use line buffering.  This
  496.      * is necessary since the stdio library will use full buffering
  497.      * for all streams not associated with the tty.
  498.      */
  499. #ifdef HAVE_SETLINEBUF
  500.     setlinebuf(cip->cin);
  501.     setlinebuf(cip->cout);
  502. #else
  503.     (void) SETVBUF(cip->cin, NULL, _IOLBF, (size_t) BUFSIZ);
  504.     (void) SETVBUF(cip->cout, NULL, _IOLBF, (size_t) BUFSIZ);
  505. #endif
  506. #endif    /* NO_SIGNALS */
  507.  
  508.     InetNtoA(cip->ip, &cip->servCtlAddr.sin_addr, sizeof(cip->ip));
  509.     if ((hpok == 0) || (hp.h_name == NULL))
  510.         (void) STRNCPY(cip->actualHost, fhost);
  511.     else
  512.         (void) STRNCPY(cip->actualHost, (char *) hp.h_name);
  513.  
  514.     /* Read the startup message from the server. */    
  515.     rp = InitResponse();
  516.     if (rp == NULL) {
  517.         FTPLogError(cip, kDontPerror, "Malloc failed.\n");
  518.         cip->errNo = kErrMallocFailed;
  519.         result = cip->errNo;
  520.         goto fatal;
  521.     }
  522.  
  523.     result = GetResponse(cip, rp);
  524.     if ((result < 0) && (rp->msg.first == NULL)) {
  525.         goto fatal;
  526.     }
  527.     if (rp->msg.first != NULL) {
  528.         cip->serverType = kServerTypeUnknown;
  529.         srvr = NULL;
  530.         firstLine = rp->msg.first->line;
  531.         secondLine = NULL;
  532.         if (rp->msg.first->next != NULL)
  533.             secondLine = rp->msg.first->next->line;
  534.         
  535.         if (strstr(firstLine, "Version wu-") != NULL) {
  536.             cip->serverType = kServerTypeWuFTPd;
  537.             srvr = "wu-ftpd";
  538.         } else if (strstr(firstLine, "NcFTPd") != NULL) {
  539.             cip->serverType = kServerTypeNcFTPd;
  540.             srvr = "NcFTPd Server";
  541.         } else if (STRNEQ("ProFTPD", firstLine, 7)) {
  542.             cip->serverType = kServerTypeProFTPD;
  543.             srvr = "ProFTPD";
  544.         } else if (strstr(firstLine, "Microsoft FTP Service") != NULL) {
  545.             cip->serverType = kServerTypeMicrosoftFTP;
  546.             srvr = "Microsoft FTP Service";
  547.         } else if (strstr(firstLine, "(NetWare ") != NULL) {
  548.             cip->serverType = kServerTypeNetWareFTP;
  549.             srvr = "NetWare FTP Service";
  550.         } else if (strstr(firstLine, "(DG/UX ") != NULL) {
  551.             cip->serverType = kServerTypeDguxFTP;
  552.             srvr = "DG/UX FTP Service";
  553.         } else if (strstr(firstLine, "IBM FTP CS ") != NULL) {
  554.             cip->serverType = kServerTypeIBMFTPCS;
  555.             srvr = "IBM FTP CS Server";
  556.         } else if (strstr(firstLine, "DC/OSx") != NULL) {
  557.             cip->serverType = kServerTypePyramid;
  558.             srvr = "Pyramid DC/OSx FTP Service";
  559.         } else if (STRNEQ("WFTPD", firstLine, 5)) {
  560.             cip->serverType = kServerTypeWFTPD;
  561.             srvr = "WFTPD";
  562.         } else if (STRNEQ("Serv-U FTP", firstLine, 10)) {
  563.             cip->serverType = kServerTypeServ_U;
  564.             srvr = "Serv-U FTP-Server";
  565.         } else if (strstr(firstLine, "VFTPD") != NULL) {
  566.             cip->serverType = kServerTypeVFTPD;
  567.             srvr = "VFTPD";
  568.         } else if (STRNEQ("FTP-Max", firstLine, 7)) {
  569.             cip->serverType = kServerTypeFTP_Max;
  570.             srvr = "FTP-Max";
  571.         } else if (strstr(firstLine, "Roxen") != NULL) {
  572.             cip->serverType = kServerTypeRoxen;
  573.             srvr = "Roxen";
  574.         } else if (strstr(firstLine, "WS_FTP") != NULL) {
  575.             cip->serverType = kServerTypeWS_FTP;
  576.             srvr = "WS_FTP Server";
  577.         } else if ((secondLine != NULL) && (strstr(secondLine, "WarFTP") != NULL)) {
  578.             cip->serverType = kServerTypeWarFTPd;
  579.             srvr = "WarFTPd";
  580.         }
  581.  
  582.         if (srvr != NULL)
  583.             PrintF(cip, "Remote server is running %s.\n", srvr);
  584.  
  585.         /* Do the application's connect message callback, if present. */
  586.         if ((cip->onConnectMsgProc != 0) && (rp->codeType < 4))
  587.             (*cip->onConnectMsgProc)(cip, rp);
  588.     }
  589.  
  590.     if (rp->codeType >= 4) {
  591.         /* They probably hung up on us right away.  That's too bad,
  592.          * but we can tell the caller that they can call back later
  593.          * and try again.
  594.          */
  595.         result = cip->errNo = kErrConnectRetryableErr;
  596.         FTPLogError(cip, kDontPerror, "Server hungup immediately after connect.\n");
  597.         goto fatal;
  598.     }
  599.     if (result < 0)        /* Some other error occurred during connect message */
  600.         goto fatal;
  601.     cip->connected = 1;
  602.     DoneWithResponse(cip, rp);
  603.     return (kNoErr);
  604.     
  605. fatal:
  606.     if (rp != NULL)
  607.         DoneWithResponse(cip, rp);
  608.     if (sockfd > 0)
  609.         (void) DisposeSocket(sockfd);
  610.     if (sock2fd > 0)
  611.         (void) DisposeSocket(sock2fd);        
  612.     CloseFile(&cip->cin);
  613.     CloseFile(&cip->cout);
  614.     cip->ctrlSocketR = kClosedFileDescriptor;
  615.     cip->ctrlSocketW = kClosedFileDescriptor;
  616.     return (result);
  617. }    /* OpenControlConnection */
  618.  
  619.  
  620.  
  621.  
  622. void
  623. CloseDataConnection(const FTPCIPtr cip)
  624. {
  625.     if (cip->dataSocket != kClosedFileDescriptor) {
  626. #ifdef NO_SIGNALS
  627. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  628.         if (cip->dataSocketConnected != 0) {
  629.             /* This could block if we were uploading, but only if
  630.              * linger mode was set.
  631.              */
  632.             SClose(cip->dataSocket, cip->xferTimeout);
  633.         } else {
  634.             DisposeSocket(cip->dataSocket);
  635.         }
  636. #else
  637.         /* This could block, but only if
  638.          * linger mode was set.
  639.          */
  640.         DisposeSocket(cip->dataSocket);
  641. #endif
  642. #else    /* NO_SIGNALS */
  643.         if (cip->xferTimeout > 0)
  644.             (void) alarm(cip->xferTimeout);
  645.         (void) DisposeSocket(cip->dataSocket);
  646.         if (cip->xferTimeout > 0)
  647.             (void) alarm(0);
  648. #endif    /* NO_SIGNALS */
  649.         cip->dataSocket = kClosedFileDescriptor;
  650.     }
  651.     cip->dataSocketConnected = 0;
  652.     memset(&cip->ourDataAddr, 0, sizeof(cip->ourDataAddr));
  653.     memset(&cip->servDataAddr, 0, sizeof(cip->servDataAddr));
  654. }    /* CloseDataConnection */
  655.  
  656.  
  657.  
  658.  
  659.  
  660. int
  661. FTPSetStartOffset(const FTPCIPtr cip, longest_int restartPt)
  662. {
  663.     ResponsePtr rp;
  664.     int result;
  665.  
  666.     if (restartPt != (longest_int) 0) {
  667.         rp = InitResponse();
  668.         if (rp == NULL) {
  669.             FTPLogError(cip, kDontPerror, "Malloc failed.\n");
  670.             cip->errNo = kErrMallocFailed;
  671.             return (cip->errNo);
  672.         }
  673.  
  674.         /* Force reset to offset zero. */
  675.         if (restartPt == (longest_int) -1)
  676.             restartPt = (longest_int) 0;
  677. #ifdef PRINTF_LONG_LONG
  678.         result = RCmd(cip, rp,
  679.         "REST " PRINTF_LONG_LONG,
  680.         restartPt);
  681. #else
  682.         result = RCmd(cip, rp, "REST %ld", (long) restartPt);
  683. #endif
  684.  
  685.         if (result < 0) {
  686.             DoneWithResponse(cip, rp);
  687.             return (result);
  688.         } else if (result <= 3) {
  689.             /* Success */
  690.             cip->hasREST = kCommandAvailable;
  691.         } else if (FTP_UNIMPLEMENTED_CMD(rp->code)) {
  692.             cip->hasREST = kCommandNotAvailable;
  693.             DoneWithResponse(cip, rp);
  694.             cip->errNo = kErrSetStartPoint;
  695.             return (kErrSetStartPoint);
  696.         } else {
  697.             DoneWithResponse(cip, rp);
  698.             cip->errNo = kErrSetStartPoint;
  699.             return (kErrSetStartPoint);
  700.         }
  701.         DoneWithResponse(cip, rp);
  702.     }
  703.     return (0);
  704. }    /* FTPSetStartOffset */
  705.  
  706.  
  707.  
  708. int
  709. FTPSendPort(const FTPCIPtr cip, struct sockaddr_in *saddr)
  710. {
  711.     char *a, *p;
  712.     int result;
  713.     ResponsePtr rp;
  714.  
  715.     rp = InitResponse();
  716.     if (rp == NULL) {
  717.         FTPLogError(cip, kDontPerror, "Malloc failed.\n");
  718.         cip->errNo = kErrMallocFailed;
  719.         return (cip->errNo);
  720.     }
  721.  
  722.     /* These will point to data in network byte order. */
  723.     a = (char *) &saddr->sin_addr;
  724.     p = (char *) &saddr->sin_port;
  725. #define UC(x) (int) (((int) x) & 0xff)
  726.  
  727.     /* Need to tell the other side which host (the address) and
  728.      * which process (port) on that host to send data to.
  729.      */
  730.     result = RCmd(cip, rp, "PORT %d,%d,%d,%d,%d,%d",
  731.         UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  732.  
  733.     DoneWithResponse(cip, rp);
  734.     if (result < 0) {
  735.         return (result);
  736.     } else if (result != 2) {
  737.         /* A 500'ish response code means the PORT command failed. */
  738.         cip->errNo = kErrPORTFailed;
  739.         return (cip->errNo);
  740.     }
  741.     return (kNoErr);
  742. }    /* FTPSendPort */
  743.  
  744.  
  745.  
  746.  
  747. int
  748. FTPSendPassive(const FTPCIPtr cip, struct sockaddr_in *saddr, int *weird)
  749. {
  750.     ResponsePtr rp;
  751.     int i[6], j;
  752.     unsigned char n[6];
  753.     char *cp;
  754.     int result;
  755.  
  756.     rp = InitResponse();
  757.     if (rp == NULL) {
  758.         FTPLogError(cip, kDontPerror, "Malloc failed.\n");
  759.         cip->errNo = kErrMallocFailed;
  760.         return (cip->errNo);
  761.     }
  762.  
  763.     result = RCmd(cip, rp, "PASV");
  764.     if (result < 0)
  765.         goto done;
  766.  
  767.     if (rp->codeType != 2) {
  768.         /* Didn't understand or didn't want passive port selection. */
  769.         cip->errNo = result = kErrPASVFailed;
  770.         goto done;
  771.     }
  772.  
  773.     /* The other side returns a specification in the form of
  774.      * an internet address as the first four integers (each
  775.      * integer stands for 8-bits of the real 32-bit address),
  776.      * and two more integers for the port (16-bit port).
  777.      *
  778.      * It should give us something like:
  779.      * "Entering Passive Mode (129,93,33,1,10,187)", so look for
  780.      * digits with sscanf() starting 24 characters down the string.
  781.      */
  782.     for (cp = rp->msg.first->line; ; cp++) {
  783.         if (*cp == '\0') {
  784.             FTPLogError(cip, kDontPerror, "Cannot parse PASV response: %s\n", rp->msg.first->line);
  785.             goto done;
  786.         }
  787.         if (isdigit((int) *cp))
  788.             break;
  789.     }
  790.  
  791.     if (sscanf(cp, "%d,%d,%d,%d,%d,%d",
  792.             &i[0], &i[1], &i[2], &i[3], &i[4], &i[5]) != 6) {
  793.         FTPLogError(cip, kDontPerror, "Cannot parse PASV response: %s\n", rp->msg.first->line);
  794.         goto done;
  795.     }
  796.  
  797.     if (weird != (int *) 0)
  798.         *weird = 0;
  799.         
  800.     for (j=0; j<6; j++) {
  801.         /* Some ftp servers return bogus port octets, such as
  802.          * boombox.micro.umn.edu.  Let the caller know if we got a
  803.          * weird looking octet.
  804.          */
  805.         if (((i[j] < 0) || (i[j] > 255)) && (weird != (int *) 0))
  806.             *weird = *weird + 1;
  807.         n[j] = (unsigned char) (i[j] & 0xff);
  808.     }
  809.     
  810.     (void) memcpy(&saddr->sin_addr, &n[0], (size_t) 4);
  811.     (void) memcpy(&saddr->sin_port, &n[4], (size_t) 2);
  812.  
  813.     result = kNoErr;
  814. done:
  815.     DoneWithResponse(cip, rp);
  816.     return (result);
  817. }    /* FTPSendPassive */
  818.  
  819.  
  820.  
  821.  
  822. int
  823. FTPFixPrivateAddr(struct sockaddr_in *maybePrivateAddr, struct sockaddr_in *knownNonPrivateAddrToUseIfNeeded)
  824. {
  825.     int i;
  826.     char maybePrivateAddrStr[64];
  827.     char knownNonPrivateAddrToUseIfNeededStr[64];
  828.  
  829.     AddrToAddrStr(maybePrivateAddrStr, sizeof(maybePrivateAddrStr), maybePrivateAddr, 0, "%h");
  830.     AddrToAddrStr(knownNonPrivateAddrToUseIfNeededStr, sizeof(knownNonPrivateAddrToUseIfNeededStr), knownNonPrivateAddrToUseIfNeeded, 0, "%h");
  831.  
  832.     if (strcmp(maybePrivateAddrStr, knownNonPrivateAddrToUseIfNeededStr) == 0)
  833.         return (0);        /* Assume if we could reach the Ctl, we can reach Data. */
  834.  
  835.     for (i=0; gPrivateNetworks[i] != NULL; i++) {
  836.         if (strncmp(maybePrivateAddrStr, gPrivateNetworks[i], strlen(gPrivateNetworks[i])) == 0)
  837.             break;
  838.     }
  839.  
  840.     if (gPrivateNetworks[i] == NULL)
  841.         return (0);        /* It wasn't a private network. */
  842.  
  843.     if (strncmp(knownNonPrivateAddrToUseIfNeededStr, gPrivateNetworks[i], strlen(gPrivateNetworks[i])) == 0)
  844.         return (0);        /* Assume we might be able to reach slightly different net */
  845.  
  846.     memcpy(&maybePrivateAddr->sin_addr, &knownNonPrivateAddrToUseIfNeeded->sin_addr, sizeof(maybePrivateAddr->sin_addr));
  847.     return (1);
  848. }    /* FTPFixPrivateAddr */
  849.  
  850.  
  851.  
  852.  
  853. void
  854. FTPFixServerDataAddr(const FTPCIPtr cip)
  855. {
  856.     struct sockaddr_in oldServDataAddr;
  857.     char servDataAddrStr[64];
  858.     char newDataAddrStr[64];
  859.  
  860.     memcpy(&oldServDataAddr, &cip->servDataAddr, sizeof(oldServDataAddr));
  861.     if (FTPFixPrivateAddr(&cip->servDataAddr, &cip->servCtlAddr)) {
  862.         AddrToAddrStr(servDataAddrStr, sizeof(servDataAddrStr), &oldServDataAddr, 0, NULL);
  863.         AddrToAddrStr(newDataAddrStr, sizeof(newDataAddrStr), &cip->servDataAddr, 0, NULL);
  864.         PrintF(cip, "Fixing bogus PASV data address from %s to %s.\n", servDataAddrStr, newDataAddrStr);
  865.     }
  866. }    /* FTPFixServerDataAddr */
  867.  
  868.  
  869.  
  870.  
  871. void
  872. FTPFixClientDataAddr(const FTPCIPtr cip)
  873. {
  874.     struct sockaddr_in oldClientDataAddr, newClientDataAddr;
  875.     char ourDataAddrStr[64];
  876.     char newDataAddrStr[64];
  877.  
  878.     if (cip->clientKnownExternalAddr.sin_family == 0)
  879.         return;
  880.  
  881.     memcpy(&oldClientDataAddr, &cip->ourDataAddr, sizeof(oldClientDataAddr));
  882.     if (FTPFixPrivateAddr(&cip->ourDataAddr, &cip->clientKnownExternalAddr)) {
  883.         memcpy(&newClientDataAddr, &cip->clientKnownExternalAddr, sizeof(newClientDataAddr));
  884.         newClientDataAddr.sin_port = cip->ourDataAddr.sin_port;
  885.         AddrToAddrStr(ourDataAddrStr, sizeof(ourDataAddrStr), &oldClientDataAddr, 0, NULL);
  886.         AddrToAddrStr(newDataAddrStr, sizeof(newDataAddrStr), &newClientDataAddr, 0, NULL);
  887.         PrintF(cip, "Fixing what would have been a bogus PORT data address from %s to %s.\n", ourDataAddrStr, newDataAddrStr);
  888.     }
  889. }    /* FTPFixClientDataAddr */
  890.  
  891.  
  892.  
  893.  
  894. static int
  895. BindToEphemeralPortNumber(int sockfd, struct sockaddr_in *addrp, int ephemLo, int ephemHi)
  896. {
  897.     int i;
  898.     int result;
  899.     int rangesize;
  900.     unsigned short port;
  901.  
  902.     addrp->sin_family = AF_INET;
  903.     if (((int) ephemLo == 0) || ((int) ephemLo >= (int) ephemHi)) {
  904.         /* Do it the normal way.  System will
  905.          * pick one, typically in the range
  906.          * of 1024-4999.
  907.          */
  908.         addrp->sin_port = 0;    /* Let system pick one. */
  909.  
  910.         result = bind(sockfd, (struct sockaddr *) addrp, sizeof(struct sockaddr_in));
  911.     } else {
  912.         rangesize = (int) ((int) ephemHi - (int) ephemLo);
  913.         result = 0;
  914.         for (i=0; i<10; i++) {
  915.             port = (unsigned short) (((int) rand() % rangesize) + (int) ephemLo);
  916.             addrp->sin_port = htons(port);
  917.  
  918.             result = bind(sockfd, (struct sockaddr *) addrp, sizeof(struct sockaddr_in));
  919.             if (result == 0)
  920.                 break;
  921.             sleep(1);
  922.             if ((errno != 999)
  923.                 /* This next line is just fodder to
  924.                  * shut the compiler up about variable
  925.                  * not being used.
  926.                  */
  927.                 && (gCopyright[0] != '\0'))
  928.                 break;
  929.         }
  930.     }
  931.     return (result);
  932. }    /* BindToEphemeralPortNumber */
  933.  
  934.  
  935.  
  936.  
  937. int
  938. OpenDataConnection(const FTPCIPtr cip, int mode)
  939. {
  940.     int dataSocket;
  941.     int weirdPort;
  942.     int result;
  943.     int setsbufs;
  944.     size_t rbs, sbs;
  945.     int passiveAttemptsRemaining = cip->maxNumberOfSuccessivePASVAttempts;
  946.  
  947.     /* Before we can transfer any data, and before we even ask the
  948.      * remote server to start transferring via RETR/NLST/etc, we have
  949.      * to setup the connection.
  950.      */
  951.  
  952. tryPort2:
  953.     weirdPort = 0;
  954.     result = 0;
  955.     CloseDataConnection(cip);    /* In case we didn't before... */
  956.  
  957.     dataSocket = socket(AF_INET, SOCK_STREAM, 0);
  958.     if (dataSocket < 0) {
  959.         FTPLogError(cip, kDoPerror, "Could not get a data socket.\n");
  960.         result = kErrNewStreamSocket;
  961.         cip->errNo = kErrNewStreamSocket;
  962.         return result;
  963.     }
  964.  
  965.     if ((cip->dataSocketRBufSize != 0) || (cip->dataSocketSBufSize != 0)) {
  966.         (void) SetSocketBufSize(dataSocket, cip->dataSocketRBufSize, cip->dataSocketSBufSize);
  967.     } else if (GetSocketBufSize(dataSocket, &rbs, &sbs) == 0) {
  968.         /* Use maximum size buffers that qualify for TCP Small Windows
  969.          * for file transfers.
  970.          */
  971.         setsbufs = 0;
  972.         if (rbs < 65536) {
  973.             rbs = 65536;
  974.             setsbufs++;
  975.         }
  976.         if (sbs < 65536) {
  977.             sbs = 65536;
  978.             setsbufs++;
  979.         }
  980.         if (setsbufs > 0) {
  981.                 (void) SetSocketBufSize(dataSocket, rbs, sbs);
  982.         }
  983.     }
  984.  
  985.     if ((cip->hasPASV == kCommandNotAvailable) || (mode == kSendPortMode)) {
  986. tryPort:
  987.         cip->ourDataAddr = cip->ourCtlAddr;
  988.         cip->ourDataAddr.sin_family = AF_INET;
  989.  
  990. #ifdef HAVE_LIBSOCKS
  991.         cip->ourDataAddr.sin_port = 0;
  992.         if (Rbind(dataSocket, (struct sockaddr *) &cip->ourDataAddr,
  993.             (int) sizeof (cip->ourDataAddr),
  994.             cip->servCtlAddr.sin_addr.s_addr) < 0) 
  995. #else
  996.         if (BindToEphemeralPortNumber(dataSocket, &cip->ourDataAddr, (int) cip->ephemLo, (int) cip->ephemHi) < 0)
  997. #endif
  998.         {
  999.             FTPLogError(cip, kDoPerror, "Could not bind the data socket");
  1000.             result = kErrBindDataSocket;
  1001.             cip->errNo = kErrBindDataSocket;
  1002.             goto bad;
  1003.         }
  1004.     
  1005.         /* Need to do this so we can figure out which port the system
  1006.          * gave to us.
  1007.          */
  1008.         if ((result = GetSocketAddress(cip, dataSocket, &cip->ourDataAddr)) < 0)
  1009.             goto bad;
  1010.     
  1011.         if (listen(dataSocket, 1) < 0) {
  1012.             FTPLogError(cip, kDoPerror, "listen failed");
  1013.             result = kErrListenDataSocket;
  1014.             cip->errNo = kErrListenDataSocket;
  1015.             goto bad;
  1016.         }
  1017.  
  1018.         FTPFixClientDataAddr(cip);
  1019.         if ((result = FTPSendPort(cip, &cip->ourDataAddr)) < 0)
  1020.             goto bad;
  1021.     
  1022.         cip->dataPortMode = kSendPortMode;
  1023.     } else {
  1024.         /* Passive mode.  Let the other side decide where to send. */
  1025.     
  1026.         while (--passiveAttemptsRemaining >= 0) {
  1027.             cip->servDataAddr = cip->servCtlAddr;
  1028.             cip->servDataAddr.sin_family = AF_INET;
  1029.             cip->ourDataAddr = cip->ourCtlAddr;
  1030.             cip->ourDataAddr.sin_family = AF_INET;
  1031.  
  1032.             if (FTPSendPassive(cip, &cip->servDataAddr, &weirdPort) < 0) {
  1033.                 FTPLogError(cip, kDontPerror, "Passive mode refused.\n");
  1034.                 cip->hasPASV = kCommandNotAvailable;
  1035.                 
  1036.                 /* We can try using regular PORT commands, which are required
  1037.                  * by all FTP protocol compliant programs, if you said so.
  1038.                  *
  1039.                  * We don't do this automatically, because if your host
  1040.                  * is running a firewall you (probably) do not want SendPort
  1041.                  * FTP for security reasons.
  1042.                  */
  1043.                 if (mode == kFallBackToSendPortMode)
  1044.                     goto tryPort;
  1045.                 result = kErrPassiveModeFailed;
  1046.                 cip->errNo = kErrPassiveModeFailed;
  1047.                 goto bad;
  1048.             }
  1049.             FTPFixServerDataAddr(cip);
  1050.  
  1051. #ifdef HAVE_LIBSOCKS
  1052.             cip->ourDataAddr.sin_port = 0;
  1053.             if (Rbind(dataSocket, (struct sockaddr *) &cip->ourDataAddr,
  1054.                 (int) sizeof (cip->ourDataAddr),
  1055.                 cip->servCtlAddr.sin_addr.s_addr) < 0) 
  1056. #else
  1057.             if (BindToEphemeralPortNumber(dataSocket, &cip->ourDataAddr, (int) cip->ephemLo, (int) cip->ephemHi) < 0)
  1058. #endif
  1059.             {
  1060.                 FTPLogError(cip, kDoPerror, "Could not bind the data socket");
  1061.                 result = kErrBindDataSocket;
  1062.                 cip->errNo = kErrBindDataSocket;
  1063.                 goto bad;
  1064.             }
  1065.  
  1066.             result = SConnect(dataSocket, &cip->servDataAddr, (int) cip->connTimeout);
  1067.  
  1068.             if (result == kTimeoutErr) {
  1069.                 if (mode == kFallBackToSendPortMode) {
  1070.                     FTPLogError(cip, kDontPerror, "Data connection timed out.\n");
  1071.                     if (passiveAttemptsRemaining == 0) {
  1072.                         FTPLogError(cip, kDontPerror, "Falling back to PORT instead of PASV mode.\n");
  1073.                         (void) DisposeSocket(dataSocket);
  1074.                         dataSocket = kClosedFileDescriptor;
  1075.                         if (cip->hasPASV == kCommandAvailabilityUnknown)
  1076.                             cip->hasPASV = kCommandNotAvailable;
  1077.                         goto tryPort2;
  1078.                     }
  1079.                 } else {
  1080.                     FTPLogError(cip, kDontPerror, "Data connection timed out.\n");
  1081.                 }
  1082.                 result = kErrConnectDataSocket;
  1083.                 cip->errNo = kErrConnectDataSocket;
  1084.                 if (passiveAttemptsRemaining == 0)
  1085.                     goto bad;
  1086.             } else if (result < 0) {
  1087. #ifdef ECONNREFUSED
  1088.                 if ((weirdPort > 0) && (errno == ECONNREFUSED))
  1089. #elif defined(WSAECONNREFUSED)
  1090.                 if ((weirdPort > 0) && (errno == WSAECONNREFUSED))
  1091. #endif
  1092.                 {
  1093.                     if (mode == kFallBackToSendPortMode) {
  1094.                         if (passiveAttemptsRemaining == 0) {
  1095.                             if (cip->hasPASV == kCommandAvailabilityUnknown)
  1096.                                 cip->hasPASV = kCommandNotAvailable;
  1097.                             FTPLogError(cip, kDontPerror, "Server sent back a bogus port number.\nI will fall back to PORT instead of PASV mode.\n");
  1098.                             (void) DisposeSocket(dataSocket);
  1099.                             dataSocket = kClosedFileDescriptor;
  1100.                             goto tryPort2;
  1101.                         }
  1102.                     }
  1103.                     FTPLogError(cip, kDontPerror, "Server sent back a bogus port number.\n");
  1104.                     result = kErrServerSentBogusPortNumber;
  1105.                     cip->errNo = kErrServerSentBogusPortNumber;
  1106.                     if (passiveAttemptsRemaining == 0)
  1107.                         goto bad;
  1108.                 }
  1109.                 if ((mode == kFallBackToSendPortMode) && (passiveAttemptsRemaining == 0)) {
  1110.                     FTPLogError(cip, kDoPerror, "connect failed.\n");
  1111.                     FTPLogError(cip, kDontPerror, "Falling back to PORT instead of PASV mode.\n");
  1112.                     (void) DisposeSocket(dataSocket);
  1113.                     dataSocket = kClosedFileDescriptor;
  1114.                     if (cip->hasPASV == kCommandAvailabilityUnknown)
  1115.                         cip->hasPASV = kCommandNotAvailable;
  1116.                     goto tryPort2;
  1117.                 }
  1118.                 FTPLogError(cip, kDoPerror, "connect failed.\n");
  1119.                 result = kErrConnectDataSocket;
  1120.                 cip->errNo = kErrConnectDataSocket;
  1121.             } else {
  1122.                 /* Success, break loop because we do not need to do PASV again. */
  1123.                 break;
  1124.             }
  1125.  
  1126.             if (dataSocket != kClosedFileDescriptor)
  1127.                 (void) DisposeSocket(dataSocket);
  1128.  
  1129.             dataSocket = socket(AF_INET, SOCK_STREAM, 0);
  1130.             if (dataSocket < 0) {
  1131.                 FTPLogError(cip, kDoPerror, "Could not get a data socket.\n");
  1132.                 result = kErrNewStreamSocket;
  1133.                 cip->errNo = kErrNewStreamSocket;
  1134.                 return result;
  1135.             }
  1136.             PrintF(cip, "Retrying PASV mode (%d %s left).\n", passiveAttemptsRemaining, (passiveAttemptsRemaining == 1) ? "try" : "tries");
  1137.         }
  1138.  
  1139.         if (result != kNoErr)
  1140.             goto bad;
  1141.  
  1142.         /* Need to do this so we can figure out which port the system
  1143.          * gave to us.
  1144.          */
  1145.         if ((result = GetSocketAddress(cip, dataSocket, &cip->ourDataAddr)) < 0)
  1146.             goto bad;
  1147.  
  1148.         cip->hasPASV = kCommandAvailable;
  1149.     }
  1150.  
  1151.     (void) SetSocketKeepAlive(dataSocket, 1);
  1152.  
  1153.     /* Data connection is a non-interactive data stream, so
  1154.      * high throughput is desired, at the expense of low
  1155.      * response time.
  1156.      */
  1157.     (void) SetSocketTypeOfService(dataSocket, IPTOS_THROUGHPUT);
  1158.  
  1159.     cip->dataSocket = dataSocket;
  1160.     return (0);
  1161. bad:
  1162.     (void) DisposeSocket(dataSocket);
  1163.     return (result);
  1164. }    /* OpenDataConnection */
  1165.  
  1166.  
  1167.  
  1168.  
  1169. int
  1170. AcceptDataConnection(const FTPCIPtr cip)
  1171. {
  1172.     int newSocket;
  1173. #ifndef NO_SIGNALS
  1174.     int len;
  1175. #endif
  1176.     unsigned short remoteDataPort;
  1177.     unsigned short remoteCtrlPort;
  1178.     char ctrlAddrStr[64], dataAddrStr[64];
  1179.  
  1180.     /* If we did a PORT, we have some things to finish up.
  1181.      * If we did a PASV, we're ready to go.
  1182.      */
  1183.     if (cip->dataPortMode == kSendPortMode) {
  1184.         /* Accept will give us back the server's data address;  at the
  1185.          * moment we don't do anything with it though.
  1186.          */
  1187.         memset(&cip->servDataAddr, 0, sizeof(cip->servDataAddr));
  1188.  
  1189. #ifdef NO_SIGNALS
  1190.         newSocket = SAccept(cip->dataSocket, &cip->servDataAddr, (int) cip->connTimeout);
  1191. #else    /* NO_SIGNALS */
  1192.         len = (int) sizeof(cip->servDataAddr);
  1193.         if (cip->connTimeout > 0)
  1194.             (void) alarm(cip->connTimeout);
  1195.         newSocket = accept(cip->dataSocket, (struct sockaddr *) &cip->servDataAddr, &len);
  1196.         if (cip->connTimeout > 0)
  1197.             (void) alarm(0);
  1198. #endif    /* NO_SIGNALS */
  1199.  
  1200.         (void) DisposeSocket(cip->dataSocket);
  1201.         if (newSocket < 0) {
  1202.             FTPLogError(cip, kDoPerror, "Could not accept a data connection.\n");
  1203.             cip->dataSocket = kClosedFileDescriptor;
  1204.             cip->errNo = kErrAcceptDataSocket;
  1205.             return (kErrAcceptDataSocket);
  1206.         }
  1207.     
  1208.         if (cip->allowProxyForPORT == 0) {
  1209.             if (memcmp(&cip->servDataAddr.sin_addr.s_addr, &cip->servCtlAddr.sin_addr.s_addr, sizeof(cip->servDataAddr.sin_addr.s_addr)) != 0) {
  1210.                 AddrToAddrStr(ctrlAddrStr, sizeof(ctrlAddrStr), &cip->servCtlAddr, 0, NULL);
  1211.                 AddrToAddrStr(dataAddrStr, sizeof(dataAddrStr), &cip->servDataAddr, 0, NULL);
  1212.                 FTPLogError(cip, kDontPerror, "Data connection from %s did not originate from remote server %s!\n", dataAddrStr, ctrlAddrStr);
  1213.                 (void) DisposeSocket(newSocket);
  1214.                 cip->dataSocket = kClosedFileDescriptor;
  1215.                 cip->errNo = kErrProxyDataConnectionsDisabled;
  1216.                 return (kErrProxyDataConnectionsDisabled);
  1217.             }
  1218.         }
  1219.  
  1220.         if (cip->require20 != 0) {
  1221.             remoteDataPort = ntohs(cip->servDataAddr.sin_port);
  1222.             remoteCtrlPort = ntohs(cip->servCtlAddr.sin_port);
  1223.             if ((int) remoteDataPort != ((int) remoteCtrlPort - 1)) {
  1224.                 FTPLogError(cip, kDontPerror, "Data connection did not originate on correct port (expecting %d, got %d)!\n", (int) remoteCtrlPort - 1, (int) remoteDataPort);
  1225.                 (void) DisposeSocket(newSocket);
  1226.                 cip->dataSocket = kClosedFileDescriptor;
  1227.                 cip->errNo = kErrDataConnOriginatedFromBadPort;
  1228.                 return (kErrDataConnOriginatedFromBadPort);
  1229.             }
  1230.         }
  1231.         cip->dataSocket = newSocket;
  1232.     }
  1233.  
  1234.     return (0);
  1235. }    /* AcceptDataConnection */
  1236.  
  1237.  
  1238.  
  1239.  
  1240. void
  1241. HangupOnServer(const FTPCIPtr cip)
  1242. {
  1243.     /* Since we want to close both sides of the connection for each
  1244.      * socket, we can just have them closed with close() instead of
  1245.      * using shutdown().
  1246.      */
  1247.     FTPCloseControlConnection(cip);
  1248.     CloseDataConnection(cip);
  1249. }    /* HangupOnServer */
  1250.  
  1251.  
  1252.  
  1253.  
  1254. void
  1255. SendTelnetInterrupt(const FTPCIPtr cip)
  1256. {
  1257.     unsigned char msg[4];
  1258.  
  1259.     /* 1. User system inserts the Telnet "Interrupt Process" (IP) signal
  1260.      *    in the Telnet stream.
  1261.      */
  1262.  
  1263.     if (cip->cout != NULL)
  1264.         (void) fflush(cip->cout);
  1265.     
  1266.     msg[0] = (unsigned char) IAC;
  1267.     msg[1] = (unsigned char) IP;
  1268. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  1269.     (void) send(cip->ctrlSocketW, (const char *) msg, 2, 0);
  1270. #else
  1271.     (void) send(cip->ctrlSocketW, (const char *) msg, 2, 0);
  1272. #endif
  1273.     /* 2. User system sends the Telnet "Sync" signal. */
  1274.     msg[0] = (unsigned char) IAC;
  1275.     msg[1] = (unsigned char) DM;
  1276. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  1277.     if (send(cip->ctrlSocketW, (const char *) msg, 2, MSG_OOB) != 2)
  1278. #else
  1279.     if (send(cip->ctrlSocketW, (const char *) msg, 2, MSG_OOB) != 2)
  1280. #endif
  1281.         FTPLogError(cip, kDoPerror, "Could not send an urgent message.\n");
  1282. }    /* SendTelnetInterrupt */
  1283.  
  1284. /* eof FTP.c */
  1285.