By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,028 Members | 1,869 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,028 IT Pros & Developers. It's quick & easy.

"FTP Pathname Glob BO" detected when using FtpWebRequest

P: n/a
I am using the following code to connect to and download files from an ftp
server, but the Symantec anti-virus software on some of my customers machines
tells them that their computers are attacking the Ftp server with "FTP
Pathname Glob BO". See the following link for more info:

http://www.symantec.com/avcenter/att...gs/s20430.html

This is standard .Net code, so I'm not understanding why it would trigger
such a response. Also, other searching on that name brings up almost nothing.

The only thing that I can guess is that it's because I'm using /%2E%2E/ to
move up a couple of directories. But the Uri class removes /../, so I had to
use the former. And I do have to move up two directories from where the ftp
login initially places me.

private void Form1_Load(object sender, EventArgs e)
{
Uri ftpConnectionString = new Uri("ftp://192.168.1.1/%2E%2E/%2E%2E/SIF1/IN");
FtpWebRequest ftpConnection =
(FtpWebRequest)FtpWebRequest.Create(ftpConnectionS tring);

ftpConnection.Credentials = new NetworkCredential("username", "password");
ftpConnection.KeepAlive = false;
ftpConnection.UseBinary = true;
ftpConnection.UsePassive = false;
ftpConnection.Method = WebRequestMethods.Ftp.GetFileSize;

using (FtpWebResponse ftpResponse =
(FtpWebResponse)ftpConnection.GetResponse())
{
long fileSize = ftpResponse.ContentLength;
ftpResponse.Close();
MessageBox.Show(fileSize.ToString());
}
}
}
Jul 30 '07 #1
Share this Question
Share on Google+
10 Replies


P: n/a
Hi,

Could you please tell us why you're using "ftp://192.168.1.1/../../"? Based
on my understanding, the Uri class will support "/../" as long as the path
is legal:

Uri u = new Uri("ftp://192.168.0.1/test/../temp/foo.txt");
Console.WriteLine(u.ToString());

The code will print "ftp://192.168.0.1/temp/foo.txt".

Do you mean that the ".." part is an existing path on the ftp server?

Also, I don't think this is an issue of the .NET network library. If you
use other ftp clients, the anti-virus software will probably also treat it
as an attack since you're trying to access path beyond the intended scope.
Regards,
Walter Wang (wa****@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.

Jul 31 '07 #2

P: n/a
Your example would work. The difference is that the /../ is at the beginning
of the path in mine. Uri treats

Uri ftpConnectionString = new Uri("ftp://192.168.1.1/../../SIF1/IN");

the same as

Uri ftpConnectionString = new Uri("ftp://192.168.1.1/SIF1/IN");

The directory structure is the following:

root
>users
>>username
SIF
When you log in, it puts you in the username directory, so you have to go up
two to the root and then down one to SIF. Other ftp clients all work because
they log in and then change directories. If you can tell me how to make the
..Net libraries log in, navigate directories, and then download files, I'd be
more than happy to do that. Right now I don't believe they're capable of that
because they inherit from WebRequest. You have to specify the whole path in
advance.

I also haven't been able to find anywhere in the Symantec software to
specifically unblock my program and their tech support if far less than
helpful with this sort of thing. This might belong in another forum, but does
anyone know how to unblock a program in Norton Internet Security?
Jul 31 '07 #3

P: n/a
Hi,

I believe the "other ftp clients" will first login to the ftp site, then
use additional FTP commands to change directory, and get the file; that's
why the "/../" following the ftp root works.

I'm curious to know if you turn off the anti-virous software, will it work?

Anyway, .NET Framework currently doesn't have a ftp client built-in, but
there's many open source ftp client in .NET, for example:

http://csharp-source.net/open-source/network-clients
Regards,
Walter Wang (wa****@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.

Aug 1 '07 #4

P: n/a
Yeah, it works fine on every other computer. And I'm certain that every one
of my customers has other anti-virus software too. It only the symantec that
catches it.

Also, I'm selling this software, so I thought I couldn't use open-source
code because I'd have to distribute the code under the GNU license.

Aug 1 '07 #5

P: n/a
Hi,

I'm writing to check the status of this post. Since .NET Framework
WebClient/WebRequest is currently using Uri class to represent the URL and
it will remove the "/../" part from the URL, we cannot use them here.
That's why I suggested to use WiniNet api instead. If this is a simple ftp
downloading, I think this should be ok. Anyway, please feel free to let me
know if you have any concerns or anything unclear. Thanks.
Regards,
Walter Wang (wa****@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.

Aug 6 '07 #6

P: n/a
Sorry for the delayed response, but yes it does work great.

The same thing seems to happen in Vista as well, so this workaround is
multi-purpose.

I have been having some trouble trying to get a status callback to work so I
can report how much of the file has been downloaded. Right now the following
code never calls the InternetStatusCallback function. Everything compiles and
runs without error, but it never fires the callback.

I've never used interop before, so I'm guessing it has something to do with
either the InternetSetStatusCallback definition or the
INTERNET_STATUS_CALLBACK delegate.

Thanks again
Matt
public class MasterFtp : IDisposable
{
[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
static extern IntPtr InternetOpen(
string lpszAgent,
int dwAccessType,
string lpszProxyName,
string lpszProxyBypass,
int dwFlags);

[DllImport("wininet.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool InternetCloseHandle(IntPtr hInternet);

[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
static extern IntPtr InternetConnect(
IntPtr hInternet,
string lpszServerName,
short nServerPort,
string lpszUsername,
string lpszPassword,
int dwService,
int dwFlags,
IntPtr dwContext);

[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
static extern bool FtpGetCurrentDirectory(
IntPtr hConnect,
StringBuilder directory,
ref int bufferLength);

[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
static extern bool FtpSetCurrentDirectory(
IntPtr hFtpConnection,
string lpszDirectory);

[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
static extern IntPtr FtpOpenFile(
IntPtr hConnect,
string lpszFileName,
int dwAccess,
int dwFlags,
IntPtr dwContext);

[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
static extern uint FtpGetFileSize(
IntPtr hFile,
out ulong lpdwFileSizeHigh);

[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FtpGetFile(
IntPtr hConnect,
string remoteFile,
string newFile,
[MarshalAs(UnmanagedType.Bool)] bool failIfExists,
int flagsAndAttributes,
int flags,
IntPtr context);

[DllImport("wininet.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool InternetGetLastResponseInfo(
out int errorCode,
StringBuilder buffer,
ref int bufferLength);

[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
static extern IntPtr InternetSetStatusCallback(
IntPtr hInternet,
INTERNET_STATUS_CALLBACK lpfnInternetCallback);

private delegate void INTERNET_STATUS_CALLBACK(
IntPtr hInternet,
IntPtr dwContext,
InternetStatus dwInternetStatus,
InternetState lpvStatusInformation,
int dwStatusInformationLength);

private enum InternetStatus
{
ResolvingName = 10,
NameResolved = 11,
ConnectingToServer = 20,
ConnectedToServer = 21,
SendingRequest = 30,
RequestSent = 31,
ReceivingResponse = 40,
ResponseReceived = 41,
CtlResponseReceived = 42,
Prefetch = 43,
ClosingConnection = 50,
ConnectionClosed = 51,
HandleCreated = 60,
HandleClosing = 70,
RequestComplete = 100,
Redirect = 110,
IntermediateResponse = 120,
StateChange = 200
}

private enum InternetState
{
Connected = 1,
Disconnected = 2,
DisconnectedByUser = 16,
Idle = 256,
Busy = 512
}

private enum ConnectionState
{
Internet,
Connection,
Directory,
Size,
Download
}

const int ERROR_SUCCESS = 0;
const int INTERNET_OPEN_TYPE_PRECONFIG = 0;
const int INTERNET_SERVICE_FTP = 1;
const int INTERNET_FLAG_PASSIVE = 0x8000000;
const int FTP_TRANSFER_BINARY = 0x2;
const int FTP_TRANSFER_ASCII = 0x1;
const int GENERIC_READ = unchecked((int)0x80000000);
const int INTERNET_INVALID_STATUS_CALLBACK = -1;
int MAX_PATH = 260;

private IntPtr hOpen;
private IntPtr hConnection;

public MasterFtp(string ftpHost, short port, string user, string
password, bool usePasv)
{
hOpen = InternetOpen("C# FtpDownloader",
INTERNET_OPEN_TYPE_PRECONFIG, null, null, 0);

if (hOpen == IntPtr.Zero)
GetError(ConnectionState.Internet);

hConnection = InternetConnect(hOpen, ftpHost, port, user,
password, INTERNET_SERVICE_FTP, usePasv ? INTERNET_FLAG_PASSIVE : 0, new
IntPtr());

if (hConnection == IntPtr.Zero)
GetError(ConnectionState.Connection);
}

public void SetDirectory(string directory)
{
StringBuilder dir = new StringBuilder(MAX_PATH);

foreach (string currentChange in directory.Split('\\'))
{
MAX_PATH = 260;
dir = new StringBuilder(MAX_PATH);

if (!FtpGetCurrentDirectory(hConnection, dir, ref MAX_PATH))
GetError(ConnectionState.Directory);

Trace.WriteLine(dir, "Current Directory");
Trace.WriteLine(currentChange, "Change");

if (!FtpSetCurrentDirectory(hConnection, currentChange))
GetError(ConnectionState.Directory);

Trace.WriteLine("Changed");

MAX_PATH = 260;
dir = new StringBuilder(MAX_PATH);

if (!FtpGetCurrentDirectory(hConnection, dir, ref MAX_PATH))
GetError(ConnectionState.Directory);

Trace.WriteLine(dir, "New Directory");
}
}

public uint GetFileSize(string remoteFile)
{
IntPtr hFile = FtpOpenFile(hConnection, remoteFile,
GENERIC_READ, FTP_TRANSFER_BINARY, new IntPtr());

if (hFile == IntPtr.Zero)
GetError(ConnectionState.Size);

ulong sizeHigh = 0;

return FtpGetFileSize(hFile, out sizeHigh);
}

public void DownloadFile(string remoteFile, string localFile, bool
bFailIfExists)
{
INTERNET_STATUS_CALLBACK callback = new
INTERNET_STATUS_CALLBACK(InternetStatusCallback);

IntPtr callbackPtr = InternetSetStatusCallback(hOpen, callback);

if (!FtpGetFile(hConnection, remoteFile, localFile,
bFailIfExists, (int)FileAttributes.Normal, FTP_TRANSFER_BINARY, new IntPtr()))
GetError(ConnectionState.Download);
}

private void InternetStatusCallback(IntPtr hInternet,
IntPtr dwContext,
InternetStatus dwInternetStatus,
InternetState lpvStatusInformation,
int dwStatusInformationLength)
{
Trace.WriteLine(dwInternetStatus + " - " + lpvStatusInformation
+ " - " + dwStatusInformationLength);
}

private void GetError(ConnectionState state)
{
int errorCode = Marshal.GetLastWin32Error();

Trace.WriteLine("Ftp Error: " + errorCode);
}

#region IDisposable Members

public void Dispose()
{
if (hConnection != IntPtr.Zero)
{
InternetCloseHandle(hConnection);
hConnection = IntPtr.Zero;
}
if (hOpen != IntPtr.Zero)
{
InternetCloseHandle(hOpen);
hOpen = IntPtr.Zero;
}
}

#endregion
}
}

Aug 7 '07 #7

P: n/a
Hi Matt,

I currently don't have a sample code on the InternetSetStatusCallback at
hand. It will take me some time to bring up a working sample for you. I'll
keep you posted as soon as possible. Thank you for your patience and
understanding.

Regards,
Walter Wang (wa****@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.

Aug 8 '07 #8

P: n/a
Hi Matt,

I've done some research and managed to make the callback to work in your
code:

public class MasterFtp : IDisposable
{
[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
static extern IntPtr InternetOpen(
string lpszAgent,
int dwAccessType,
string lpszProxyName,
string lpszProxyBypass,
int dwFlags);

[DllImport("wininet.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool InternetCloseHandle(IntPtr hInternet);

[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
static extern IntPtr InternetConnect(
IntPtr hInternet,
string lpszServerName,
short nServerPort,
string lpszUsername,
string lpszPassword,
int dwService,
int dwFlags,
IntPtr dwContext);

[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
static extern bool FtpGetCurrentDirectory(
IntPtr hConnect,
StringBuilder directory,
ref int bufferLength);

[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
static extern bool FtpSetCurrentDirectory(
IntPtr hFtpConnection,
string lpszDirectory);

[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
static extern IntPtr FtpOpenFile(
IntPtr hConnect,
string lpszFileName,
int dwAccess,
int dwFlags,
IntPtr dwContext);

[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
static extern uint FtpGetFileSize(
IntPtr hFile,
out ulong lpdwFileSizeHigh);

[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FtpGetFile(
IntPtr hConnect,
string remoteFile,
string newFile,
[MarshalAs(UnmanagedType.Bool)] bool failIfExists,
int flagsAndAttributes,
int flags,
IntPtr context);

[DllImport("wininet.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool InternetGetLastResponseInfo(
out int errorCode,
StringBuilder buffer,
ref int bufferLength);

[DllImport("wininet.dll", SetLastError = true, CharSet =
CharSet.Auto)]
static extern IntPtr InternetSetStatusCallback(
IntPtr hInternet,
INTERNET_STATUS_CALLBACK lpfnInternetCallback);

private delegate void INTERNET_STATUS_CALLBACK(
IntPtr hInternet,
IntPtr dwContext,
InternetStatus dwInternetStatus,
IntPtr lpvStatusInformation,
int dwStatusInformationLength);

private enum InternetStatus
{
ResolvingName = 10,
NameResolved = 11,
ConnectingToServer = 20,
ConnectedToServer = 21,
SendingRequest = 30,
RequestSent = 31,
ReceivingResponse = 40,
ResponseReceived = 41,
CtlResponseReceived = 42,
Prefetch = 43,
ClosingConnection = 50,
ConnectionClosed = 51,
HandleCreated = 60,
HandleClosing = 70,
RequestComplete = 100,
Redirect = 110,
IntermediateResponse = 120,
StateChange = 200
}

private enum InternetState
{
Connected = 1,
Disconnected = 2,
DisconnectedByUser = 16,
Idle = 256,
Busy = 512
}

private enum ConnectionState
{
Internet,
Connection,
Directory,
Size,
Download
}

const int ERROR_SUCCESS = 0;
const int INTERNET_OPEN_TYPE_PRECONFIG = 0;
const int INTERNET_SERVICE_FTP = 1;
const int INTERNET_FLAG_PASSIVE = 0x8000000;
const int FTP_TRANSFER_BINARY = 0x2;
const int FTP_TRANSFER_ASCII = 0x1;
const int GENERIC_READ = unchecked((int)0x80000000);
const int INTERNET_INVALID_STATUS_CALLBACK = -1;
int MAX_PATH = 260;

private IntPtr hOpen;
private IntPtr hConnection;
private IntPtr hContext;

public MasterFtp(string ftpHost, short port, string user, string
password, bool usePasv)
{
hContext = Marshal.AllocHGlobal(1);

hOpen = InternetOpen("C# FtpDownloader",
INTERNET_OPEN_TYPE_PRECONFIG, null, null, 0);

if (hOpen == IntPtr.Zero)
GetError(ConnectionState.Internet);

hConnection = InternetConnect(hOpen, ftpHost, port, user,
password, INTERNET_SERVICE_FTP, usePasv ? INTERNET_FLAG_PASSIVE : 0,
hContext);

if (hConnection == IntPtr.Zero)
GetError(ConnectionState.Connection);
}

public void SetDirectory(string directory)
{
StringBuilder dir = new StringBuilder(MAX_PATH);

foreach (string currentChange in directory.Split('\\'))
{
MAX_PATH = 260;
dir = new StringBuilder(MAX_PATH);

if (!FtpGetCurrentDirectory(hConnection, dir, ref MAX_PATH))
GetError(ConnectionState.Directory);

Trace.WriteLine(dir, "Current Directory");
Trace.WriteLine(currentChange, "Change");

if (!FtpSetCurrentDirectory(hConnection, currentChange))
GetError(ConnectionState.Directory);

Trace.WriteLine("Changed");

MAX_PATH = 260;
dir = new StringBuilder(MAX_PATH);

if (!FtpGetCurrentDirectory(hConnection, dir, ref MAX_PATH))
GetError(ConnectionState.Directory);

Trace.WriteLine(dir, "New Directory");
}
}

public uint GetFileSize(string remoteFile)
{
IntPtr hFile = FtpOpenFile(hConnection, remoteFile,
GENERIC_READ, FTP_TRANSFER_BINARY, new IntPtr());

if (hFile == IntPtr.Zero)
GetError(ConnectionState.Size);

ulong sizeHigh = 0;

return FtpGetFileSize(hFile, out sizeHigh);
}

INTERNET_STATUS_CALLBACK callback;

public void DownloadFile(string remoteFile, string localFile, bool
bFailIfExists)
{
callback = new INTERNET_STATUS_CALLBACK(InternetStatusCallback);
IntPtr callbackPtr = InternetSetStatusCallback(hConnection,
callback);

if (!FtpGetFile(hConnection, remoteFile, localFile,
bFailIfExists, (int)FileAttributes.Normal, FTP_TRANSFER_BINARY, hContext))
GetError(ConnectionState.Download);
}

private void InternetStatusCallback(IntPtr hInternet,
IntPtr dwContext,
InternetStatus dwInternetStatus,
IntPtr lpvStatusInformation,
int dwStatusInformationLength)
{
Trace.WriteLine(dwInternetStatus + " - " + lpvStatusInformation
+ " - " + dwStatusInformationLength);
}

private void GetError(ConnectionState state)
{
int errorCode = Marshal.GetLastWin32Error();

Trace.WriteLine("Ftp Error: " + errorCode);
}

#region IDisposable Members

public void Dispose()
{
if (hConnection != IntPtr.Zero)
{
InternetCloseHandle(hConnection);
hConnection = IntPtr.Zero;
}
if (hOpen != IntPtr.Zero)
{
InternetCloseHandle(hOpen);
hOpen = IntPtr.Zero;
}
if (hContext != IntPtr.Zero)
{
Marshal.FreeHGlobal(hContext);
hContext = IntPtr.Zero;
}
}

#endregion
}
Some changes:

1) The dwContext passed to InternetConnect and FtpGetFile should be
consistent, therefore I created a member variable hContext to track it,
it's initalized with Marshal.AllocHGlobal with 1 byte.

2) The delegate instance needs to stay at member scope, it must be kept
alive during the lifetime of the class.

3) The handle passed to InternetSetStatusCallback should be the handle
returned from InternetConnect instead of InternetOpen.
Hope this helps.
Regards,
Walter Wang (wa****@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.

Aug 9 '07 #9

P: n/a
Forgot another change:

4) The lpvStatusInformation of INTERNET_STATUS_CALLBACK should be a pointer
instead of an integer:

[in] Address of a buffer that contains information pertinent to this call
to the callback function.

Please feel free to let me know if you find any other issues when
implementing the workaround.
Regards,
Walter Wang (wa****@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.

Aug 9 '07 #10

P: n/a
Works great.

Thanks,
Matt
Aug 13 '07 #11

This discussion thread is closed

Replies have been disabled for this discussion.