- implemented passive FTP transfers (PASV, needed for firewalls)

- fixed lstnSocket closing
This commit is contained in:
Andreas Mohr 2000-12-29 05:19:57 +00:00 committed by Alexandre Julliard
parent 0108d83818
commit f5682a0f8e
2 changed files with 153 additions and 19 deletions

View File

@ -5,6 +5,8 @@
* *
* Ulrich Czekalla * Ulrich Czekalla
* Noureddine Jemmali * Noureddine Jemmali
*
* Copyright 2000 Andreas Mohr
*/ */
#include "config.h" #include "config.h"
@ -70,6 +72,7 @@ typedef enum {
FTP_CMD_ABOR, FTP_CMD_ABOR,
FTP_CMD_LIST, FTP_CMD_LIST,
FTP_CMD_NLST, FTP_CMD_NLST,
FTP_CMD_PASV,
FTP_CMD_PWD, FTP_CMD_PWD,
FTP_CMD_QUIT, FTP_CMD_QUIT,
} FTP_COMMAND; } FTP_COMMAND;
@ -91,6 +94,7 @@ static const CHAR *szFtpCommands[] = {
"ABOR", "ABOR",
"LIST", "LIST",
"NLST", "NLST",
"PASV",
"PWD", "PWD",
"QUIT", "QUIT",
}; };
@ -100,7 +104,7 @@ static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam, BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext); INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType); BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
BOOL FTP_InitDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket); BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile); BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse, INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext); INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
@ -112,6 +116,8 @@ BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs); BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType); BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs); BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs);
BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs);
BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp); BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp); BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket, HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
@ -213,13 +219,13 @@ BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
{ {
INT nDataSocket; INT nDataSocket;
/* Accept connection from ftp server */ /* Get data socket to server */
if (FTP_InitDataSocket(lpwfs, &nDataSocket)) if (FTP_GetDataSocket(lpwfs, &nDataSocket))
{ {
FTP_SendData(lpwfs, nDataSocket, hFile); FTP_SendData(lpwfs, nDataSocket, hFile);
close(nDataSocket); close(nDataSocket);
nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
MAX_REPLY_LEN,0, 0, 0); MAX_REPLY_LEN, 0, 0, 0);
if (nResCode) if (nResCode)
{ {
if (nResCode == 226) if (nResCode == 226)
@ -231,6 +237,9 @@ BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
} }
lend: lend:
if (lpwfs->lstnSocket != INVALID_SOCKET)
close(lpwfs->lstnSocket);
if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB) if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
{ {
INTERNET_ASYNC_RESULT iar; INTERNET_ASYNC_RESULT iar;
@ -522,7 +531,7 @@ INTERNETAPI HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII)) if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
goto lend; goto lend;
if (!FTP_SendPort(lpwfs)) if (!FTP_SendPortOrPasv(lpwfs))
goto lend; goto lend;
hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
@ -538,7 +547,8 @@ INTERNETAPI HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
{ {
INT nDataSocket; INT nDataSocket;
if (FTP_InitDataSocket(lpwfs, &nDataSocket)) /* Get data socket to server */
if (FTP_GetDataSocket(lpwfs, &nDataSocket))
{ {
hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext); hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
@ -791,8 +801,8 @@ HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags); bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
} }
/* Accept connection from server */ /* Get data socket to server */
if (bSuccess && FTP_InitDataSocket(lpwfs, &nDataSocket)) if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
{ {
hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE)); hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
hFile->hdr.htype = WH_HFILE; hFile->hdr.htype = WH_HFILE;
@ -802,6 +812,9 @@ HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
hFile->nDataSocket = nDataSocket; hFile->nDataSocket = nDataSocket;
} }
if (lpwfs->lstnSocket != INVALID_SOCKET)
close(lpwfs->lstnSocket);
hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB) if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
{ {
@ -915,8 +928,8 @@ BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR l
{ {
INT nDataSocket; INT nDataSocket;
/* Accept connection from ftp server */ /* Get data socket to server */
if (FTP_InitDataSocket(lpwfs, &nDataSocket)) if (FTP_GetDataSocket(lpwfs, &nDataSocket))
{ {
INT nResCode; INT nResCode;
@ -936,6 +949,9 @@ BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR l
} }
lend: lend:
if (lpwfs->lstnSocket != INVALID_SOCKET)
close(lpwfs->lstnSocket);
if (hFile) if (hFile)
CloseHandle(hFile); CloseHandle(hFile);
@ -1389,7 +1405,7 @@ lerror:
/*********************************************************************** /***********************************************************************
* FTP_ConnectHost (internal) * FTP_ConnectToHost (internal)
* *
* Connect to a ftp server * Connect to a ftp server
* *
@ -1648,7 +1664,7 @@ BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwTy
if (!FTP_SendType(lpwfs, dwType)) if (!FTP_SendType(lpwfs, dwType))
goto lend; goto lend;
if (!FTP_SendPort(lpwfs)) if (!FTP_SendPortOrPasv(lpwfs))
goto lend; goto lend;
if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0)) if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
@ -1739,6 +1755,9 @@ lend:
* TRUE on success * TRUE on success
* FALSE on failure * FALSE on failure
* *
* W98SE doesn't cache the type that's currently set
* (i.e. it sends it always),
* so we probably don't want to do that either.
*/ */
BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType) BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
{ {
@ -1812,8 +1831,116 @@ lend:
/*********************************************************************** /***********************************************************************
* FTP_InitDataSocket (internal) * FTP_DoPassive (internal)
* *
* Tell server that we want to do passive transfers
* and connect data socket
*
* RETURNS
* TRUE on success
* FALSE on failure
*
*/
BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs)
{
INT nResCode;
BOOL bSuccess = FALSE;
TRACE("\n");
if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
goto lend;
nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
MAX_REPLY_LEN,0, 0, 0);
if (nResCode)
{
if (nResCode == 227)
{
LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
LPSTR p;
int f[6];
int i;
char *pAddr, *pPort;
INT nsocket = INVALID_SOCKET;
struct sockaddr_in dataSocketAddress;
p = lpszResponseBuffer+4; /* skip status code */
/* do a very strict check; we can improve that later. */
if (strncmp(p, "Entering Passive Mode", 21))
{
ERR("unknown response '%.*s', aborting\n", 21, p);
goto lend;
}
p += 21; /* skip string */
if ((*p++ != ' ') || (*p++ != '('))
{
ERR("unknown response format, aborting\n");
goto lend;
}
if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
&f[4], &f[5]) != 6)
{
ERR("unknown response address format '%s', aborting\n", p);
goto lend;
}
for (i=0; i < 6; i++)
f[i] = f[i] & 0xff;
dataSocketAddress = lpwfs->socketAddress;
pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
pPort = (char *)&(dataSocketAddress.sin_port);
pAddr[0] = f[0];
pAddr[1] = f[1];
pAddr[2] = f[2];
pAddr[3] = f[3];
pPort[0] = f[4];
pPort[1] = f[5];
if (INVALID_SOCKET == (nsocket = socket(AF_INET,SOCK_STREAM,0)))
goto lend;
if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
{
ERR("can't connect passive FTP data port.\n");
goto lend;
}
lpwfs->pasvSocket = nsocket;
bSuccess = TRUE;
}
else
FTP_SetResponseError(nResCode);
}
lend:
return bSuccess;
}
BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs)
{
if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
{
if (!FTP_DoPassive(lpwfs))
return FALSE;
}
else
{
if (!FTP_SendPort(lpwfs))
return FALSE;
}
return TRUE;
}
/***********************************************************************
* FTP_GetDataSocket (internal)
*
* Either accepts an incoming data socket connection from the server
* or just returns the already opened socket after a PASV command
* in case of passive FTP.
* *
* *
* RETURNS * RETURNS
@ -1821,16 +1948,22 @@ lend:
* FALSE on failure * FALSE on failure
* *
*/ */
BOOL FTP_InitDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket) BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
{ {
struct sockaddr_in saddr; struct sockaddr_in saddr;
size_t addrlen = sizeof(struct sockaddr); size_t addrlen = sizeof(struct sockaddr);
TRACE("\n"); TRACE("\n");
if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
{
*nDataSocket = lpwfs->pasvSocket;
}
else
{
*nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen); *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
close(lpwfs->lstnSocket); close(lpwfs->lstnSocket);
lpwfs->lstnSocket = INVALID_SOCKET; lpwfs->lstnSocket = INVALID_SOCKET;
}
return *nDataSocket != INVALID_SOCKET; return *nDataSocket != INVALID_SOCKET;
} }
@ -1939,7 +2072,7 @@ DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD
if (!FTP_SendType(lpwfs, dwType)) if (!FTP_SendType(lpwfs, dwType))
goto lend; goto lend;
if (!FTP_SendPort(lpwfs)) if (!FTP_SendPortOrPasv(lpwfs))
goto lend; goto lend;
if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0)) if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))

View File

@ -74,6 +74,7 @@ typedef struct
WININETHANDLEHEADER hdr; WININETHANDLEHEADER hdr;
int sndSocket; int sndSocket;
int lstnSocket; int lstnSocket;
int pasvSocket; /* data socket connected by us in case of passive FTP */
struct sockaddr_in socketAddress; struct sockaddr_in socketAddress;
struct sockaddr_in lstnSocketAddress; struct sockaddr_in lstnSocketAddress;
struct hostent *phostent; struct hostent *phostent;