public void CloseConnection() { try { if (_sslStream != null) { _sslStream.Close(); } if (_controlStream != null) { _controlStream.Close(); } } catch (Exception) { // ignored } _sslStream = null; _controlStream = null; lock (_controlClientLocker) { if (_controlClient != null) { _controlClient.Close(); } _controlClient = null; } }
public ClientConnection(TcpClient client, X509Certificate2 x509, bool useImplicit) { Client = client; X509 = x509; UseImplicit = useImplicit; ControlStream = Client.GetStream(); LogUser = new LogUser(); Logger.RegisterUser(LogUser); LoggedIn = false; if (UseImplicit) { SslControlStream = new FixedSslStream(ControlStream); SslControlStream.AuthenticateAsServer(X509); ControlReader = new StreamReader(SslControlStream); ControlWriter = new StreamWriter(SslControlStream); } else { ControlReader = new StreamReader(ControlStream); ControlWriter = new StreamWriter(ControlStream); } ThreadPool.QueueUserWorkItem(HandleControl, null); }
private void HandleNLST(IAsyncResult ar) { if (DataConnectionType == ConnectionType.Active) { DataActive.EndConnect(ar); } else { DataActive = DataPassive.EndAcceptTcpClient(ar); } string pathname = (string)ar.AsyncState; FixedSslStream ssl = null; NetworkStream stream = null; if (Protocol == Protocol.P) { ssl = new FixedSslStream(DataActive.GetStream()); ssl.AuthenticateAsServer(X509, false, SslProtocols.Default, false); DataWriter = new StreamWriter(ssl, Encoding.ASCII); } else { stream = DataActive.GetStream(); DataWriter = new StreamWriter(stream, Encoding.ASCII); } IEnumerable <string> directories = Directory.EnumerateDirectories(pathname); foreach (string dir in directories) { DirectoryInfo d = new DirectoryInfo(dir); string line = d.Name; DataWriter.WriteLine(line); DataWriter.Flush(); } IEnumerable <string> files = Directory.EnumerateFiles(pathname); foreach (string file in files) { FileInfo f = new FileInfo(file); string line = f.Name; DataWriter.WriteLine(line); DataWriter.Flush(); } ssl.Dispose(); DataActive.Close(); DataActive = null; LogUser.LogMsg("226 NLST complete"); ControlWriter.WriteLine("226 NLST complete"); ControlWriter.Flush(); }
private void HandleStor(IAsyncResult ar) { if (DataConnectionType == ConnectionType.Active) { DataActive.EndConnect(ar); } else { DataActive = DataPassive.EndAcceptTcpClient(ar); } string pathname = (string)ar.AsyncState; FixedSslStream ssl = null; NetworkStream stream = null; if (Protocol == Protocol.P || UseImplicit) { ssl = new FixedSslStream(DataActive.GetStream()); ssl.AuthenticateAsServer(X509, false, SslProtocols.Default, false); DataWriter = new StreamWriter(ssl, Encoding.ASCII); using (FileStream fs = new FileStream(pathname, FileMode.Open, FileAccess.Read)) { CopyStream(ssl, fs); } } else { stream = DataActive.GetStream(); DataWriter = new StreamWriter(stream, Encoding.ASCII); using (FileStream fs = new FileStream(pathname, FileMode.Open, FileAccess.Read)) { CopyStream(stream, fs); } } if (ssl != null) { ssl.Dispose(); } if (stream != null) { stream.Dispose(); } DataActive.Close(); DataActive = null; LogUser.LogMsg("226 Closing data connection, file transfer successful"); ControlWriter.WriteLine("226 Closing data connection, file transfer successful"); ControlWriter.Flush(); }
public void SetUpSecureConnectionAsServer(X509Certificate certificate) { lock (_controlClientLocker) { lock (_activeStreamLocker) { _sslStream = new FixedSslStream(_controlStream, true); _sslStream.AuthenticateAsServer(certificate); } } }
private static void Main() { // Load server certificate var cert = new X509Certificate2("test.pfx"); AuthTlsCommandHandler.ServerCertificate = cert; // Only allow anonymous login var membershipProvider = new AnonymousMembershipProvider(new NoValidation()); // Use the .NET file system var fsProvider = new DotNetFileSystemProvider(Path.Combine(Path.GetTempPath(), "TestFtpServer")); // Use all commands from the FtpServer assembly and the one(s) from the AuthTls assembly var commandFactory = new AssemblyFtpCommandHandlerFactory(typeof(FtpServer).Assembly, typeof(AuthTlsCommandHandler).Assembly); // Initialize the FTP server using (var ftpServer = new FtpServer(fsProvider, membershipProvider, "127.0.0.1", Port, commandFactory) { DefaultEncoding = Encoding.ASCII, LogManager = new FtpLogManager(), }) { #if USE_FTPS_IMPLICIT // Use an implicit SSL connection (without the AUTHTLS command) ftpServer.ConfigureConnection += (s, e) => { var sslStream = new FixedSslStream(e.Connection.OriginalStream); sslStream.AuthenticateAsServer(cert); e.Connection.SocketStream = sslStream; }; #endif // Create the default logger var log = ftpServer.LogManager?.CreateLog(typeof(Program)); try { // Start the FTP server ftpServer.Start(); Console.WriteLine("Press ENTER/RETURN to close the test application."); Console.ReadLine(); // Stop the FTP server ftpServer.Stop(); } catch (Exception ex) { log?.Error(ex, "Error during main FTP server loop"); } } }
public void SetUpSecureConnectionAsClient() { _sslStream = new FixedSslStream(_controlStream, false, (sender, certificate, chain, errors) => true, null); _sslStream.AuthenticateAsClient(IpAddress.ToString()); }
private void HandleControl(object state) { try { LogUser.Address = Client.Client.RemoteEndPoint.ToString(); LogUser.LogMsg($"220 Ready As I'll Ever Be"); ControlWriter.WriteLine("220 Ready As I'll Ever Be"); ControlWriter.Flush(); string line = null; while (!string.IsNullOrEmpty(line = ControlReader.ReadLine())) { LogUser.LogMsg($"Command: {line}"); string response = null; bool authTls = false; string[] command = line.Split(' '); string cmd = command[0].ToUpperInvariant(); string args = command.Length > 1 ? line.Substring(command[0].Length + 1) : null; if (response == null) { switch (cmd) { case "USER": if (LoggedIn) { response = "230 User already logged in"; break; } response = Login(args); break; case "PASS": response = Login(args); break; case "AUTH": if (args == "TLS" || args == "SSL") { response = "234 Enable TLS/SSL Connection"; authTls = true; break; } response = $"502 Unknown Argument '{args}'"; break; // File Commands case "CDUP": response = ChangeWD(".."); break; case "CWD": response = ChangeWD(args); break; case "PWD": try { string cur = CurrentDir.Replace(Root, string.Empty).Replace('\\', '/'); response = cur.Length > 0 ? cur : "257 \"/\" is current directory"; } catch { response = "550 PWD Failed Sucessfully"; } break; case "TYPE": string[] splitArgs = args.Split(' '); response = Type(splitArgs[0], splitArgs.Length > 1 ? splitArgs[1] : null); break; case "PASV": response = Passive(); break; case "PORT": response = Port(args); break; case "LIST": response = List(args ?? CurrentDir); break; case "RETR": response = Retrieve(args); break; case "STOR": response = Store(args); break; case "RNFR": renameFrom = args; response = "350 Requested file action pending further information"; break; case "RNTO": response = Rename(renameFrom, args); break; case "PBSZ": response = $"200 PBSZ={args}"; break; case "PROT": response = $"200 Protection level set to {args}"; Protocol = (args == "P") ? Protocol.P : Protocol.C; break; case "MLSD": response = MLSD(args); break; case "NLSD": response = NLST(args); break; case "SIZE": args = Helpers.NormalizeFilename(args, Root, CurrentDir); if (!Helpers.IsValidPath(args, Root)) { response = "550 File Not Found"; break; } response = (File.Exists(args)) ? $"213 {new FileInfo(args).Length}" : "550 File Not Found"; break; case "MDTM": args = Helpers.NormalizeFilename(args, Root, CurrentDir); if (!Helpers.IsValidPath(args, Root)) { response = "550 File Not Found"; break; } response = (File.Exists(args)) ? $"213 {new FileInfo(args).LastWriteTime:yyyyMMddHHmmss.fff}" : "550 File Not Found"; break; case "QUIT": response = "221 Goodbye"; break; case "DELE": response = Delete(args); break; case "RMD": response = RemoveDir(args); break; case "MKD": response = CreateDir(args); break; case "SYST": response = "215 UNIX Type: L8"; break; default: response = $"502 Command '{line}' Not Implemented"; break; } try { LogUser.LogMsg($"Response: {response}"); ControlWriter.WriteLine(response); ControlWriter.Flush(); } catch { } if (response.StartsWith("221")) { if (SslControlStream != null) { SslControlStream.Dispose(); } Client.Close(); break; } if (authTls) { SslControlStream = new FixedSslStream(ControlStream); SslControlStream.AuthenticateAsServer(X509, false, SslProtocols.Default, false); ControlWriter = new StreamWriter(SslControlStream); ControlReader = new StreamReader(SslControlStream); } } } Logger.UnregisterUser(LogUser); } catch (Exception e) { Logger.Log($"Client {Client.Client.RemoteEndPoint} disconnected due to an error ({e.Message})"); Client.Close(); Logger.UnregisterUser(LogUser); } }
// Handlers private void HandleList(IAsyncResult ar) { if (DataConnectionType == ConnectionType.Active) { DataActive.EndConnect(ar); } else { DataActive = DataPassive.EndAcceptTcpClient(ar); } string pathname = (string)ar.AsyncState; pathname = pathname.Replace("-l", "").Replace("-a", ""); FixedSslStream ssl = null; NetworkStream stream = null; if (Protocol == Protocol.P || UseImplicit) { ssl = new FixedSslStream(DataActive.GetStream()); ssl.AuthenticateAsServer(X509, false, SslProtocols.Default, false); DataWriter = new StreamWriter(ssl, Encoding.ASCII); } else { stream = DataActive.GetStream(); DataWriter = new StreamWriter(stream, Encoding.ASCII); } IEnumerable <string> directories = Directory.EnumerateDirectories(pathname); foreach (string dir in directories) { DirectoryInfo d = new DirectoryInfo(dir); string line = string.Format("drwxr-xr-x 2 2003 2003 {0,8} {1} {2}", "4096", d.LastWriteTime.ToString("MMM dd yyyy"), d.Name); DataWriter.WriteLine(line); DataWriter.Flush(); } IEnumerable <string> files = Directory.EnumerateFiles(pathname); foreach (string file in files) { FileInfo f = new FileInfo(file); string line = string.Format("-rw-r--r-- 2 2003 2003 {0,8} {1} {2}", f.Length, f.LastWriteTime.ToString("MMM dd yyyy"), f.Name); DataWriter.WriteLine(line); DataWriter.Flush(); } // Virtual Directories if (pathname == Root) { foreach (VirtualDirectory vd in User.Directories) { if (vd.IsRoot) { continue; } DirectoryInfo d = new DirectoryInfo(vd.Path); string line = string.Format("drwxr-xr-x 2 2003 2003 {0,8} {1} {2}", "4096", d.LastWriteTime.ToString("MMM dd yyyy"), vd.Alias); DataWriter.WriteLine(line); DataWriter.Flush(); } } if (ssl != null) { ssl.Dispose(); } if (stream != null) { stream.Dispose(); } DataActive.Close(); DataActive = null; LogUser.LogMsg("226 List complete"); ControlWriter.WriteLine("226 List complete"); ControlWriter.Flush(); }