dotnet general:
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/attack_sigs/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(ftpConnectionString); 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()); } } }
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 (wawang@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.
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 [quoted text, click to view] >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?
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 (wawang@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.
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.
Hi, We can use WinInet API in .NET via P/Invoke to download the ftp file. Following is my simple example which currently only has download function: using System; using System.Text; using System.Net; using System.IO; using System.Runtime.InteropServices; using System.ComponentModel; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { using (FtpDownloader fd = new FtpDownloader("wawangvsrv1", 21, "test", "test", false)) { fd.DownloadFile("../../public/hello.txt", @"c:\temp\hello.txt", false); } } } class FtpDownloader : IDisposable { [DllImport("WININET", EntryPoint = "InternetOpen", SetLastError = true, CharSet = CharSet.Auto)] static extern IntPtr InternetOpen( string lpszAgent, int dwAccessType, string lpszProxyName, string lpszProxyBypass, int dwFlags); [DllImport("WININET", EntryPoint = "InternetCloseHandle", SetLastError = true, CharSet = CharSet.Auto)] static extern bool InternetCloseHandle(IntPtr hInternet); [DllImport("WININET", EntryPoint = "InternetConnect", SetLastError = true, CharSet = CharSet.Auto)] static extern IntPtr InternetConnect( IntPtr hInternet, string lpszServerName, int nServerPort, string lpszUsername, string lpszPassword, int dwService, int dwFlags, int dwContext); [DllImport("WININET", EntryPoint = "FtpSetCurrentDirectory", SetLastError = true, CharSet = CharSet.Auto)] static extern bool FtpSetCurrentDirectory(IntPtr hConnect, string lpszDirectory); [DllImport("WININET", EntryPoint = "FtpGetFile", SetLastError = true, CharSet = CharSet.Auto)] static extern bool FtpGetFile( IntPtr hConnect, string lpszRemoteFile, string lpszNewFile, bool fFailIfExists, FileAttributes dwFlagsAndAttributes, int dwFlags, int dwContext); 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; private IntPtr hOpen; private IntPtr hConnection; public FtpDownloader(string ftpHost, int port, string user, string password, bool usePasv) { hOpen = InternetOpen("C# FtpDownloader", INTERNET_OPEN_TYPE_PRECONFIG, null, null, 0); if (hOpen == IntPtr.Zero) throw new Win32Exception(); hConnection = InternetConnect(hOpen, ftpHost, port, user, password, INTERNET_SERVICE_FTP, usePasv ? INTERNET_FLAG_PASSIVE : 0, 0); if (hConnection == IntPtr.Zero) throw new Win32Exception(); } public void DownloadFile(string remoteFile, string localFile, bool bFailIfExists) { if (!FtpGetFile(hConnection, remoteFile, localFile, bFailIfExists, FileAttributes.Normal, FTP_TRANSFER_BINARY, 0)) throw new Win32Exception(); } #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 } } Since we're using INTERNET_OPEN_TYPE_PRECONFIG, it will use IE's proxy setting to connect to the ftp host. You can also specify proxy manually if needed. For more information, please refer to wininet functions documentation. Hope this helps.
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 (wawang@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.
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,
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 (wawang@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.
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);
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 (wawang@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.
Don't see what you're looking for? Try a search.
|