/// <summary>
 /// Initializes a new instance of the <see cref="FtpLoginStateMachine"/> class.
 /// </summary>
 /// <param name="connection">The FTP connection.</param>
 /// <param name="hostSelector">The FTP host selector.</param>
 public FtpLoginStateMachine(
     IFtpConnection connection,
     IFtpHostSelector hostSelector)
     : base(connection, _transitions, SecurityStatus.Unauthenticated)
 {
     _hostSelector = hostSelector;
 }
 public ConnectionKeepAlive(
     IFtpConnection connection,
     FtpCommand command)
 {
     _eventHost = connection.Features.Get <IFtpConnectionEventHost>();
     _eventHost.PublishEvent(new FtpConnectionDataTransferStartedEvent(_transferId, command));
 }
Exemplo n.º 3
0
        public static async Task <FtpResponse> SendResponseAsync(
            [NotNull] this IFtpConnection connection,
            [NotNull] Func <TcpClient, Task <FtpResponse> > asyncSendAction,
            [CanBeNull] Func <Exception, FtpResponse> createConnectionErrorFunc = null)
        {
            TcpClient responseSocket;

            try
            {
                responseSocket = await connection.CreateResponseSocket().ConfigureAwait(false);
            }
            catch (Exception ex) when(createConnectionErrorFunc != null)
            {
                return(createConnectionErrorFunc(ex));
            }

            try
            {
                return(await asyncSendAction(responseSocket).ConfigureAwait(false));
            }
            finally
            {
                responseSocket.Dispose();
                connection.Data.PassiveSocketClient = null;
            }
        }
Exemplo n.º 4
0
        /// <inheritdoc />
        public async Task <IPasvListener> CreateTcpListenerAsync(
            IFtpConnection connection,
            AddressFamily?addressFamily,
            int port,
            CancellationToken cancellationToken)
        {
            IPasvListener listener;

            if (port < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(port), "may not be less than 0");
            }

            var pasvOptions = await _addressResolver.GetOptionsAsync(connection, addressFamily, cancellationToken)
                              .ConfigureAwait(false);

            if (port > 0 && pasvOptions.HasPortRange && (port > pasvOptions.PasvMaxPort || port < pasvOptions.PasvMinPort))
            {
                throw new ArgumentOutOfRangeException(
                          nameof(port),
                          $"must be in {pasvOptions.PasvMinPort}:{pasvOptions.PasvMaxPort}");
            }

            if (port == 0 && pasvOptions.HasPortRange)
            {
                listener = CreateListenerInRange(connection, pasvOptions);
            }
            else
            {
                listener = new PasvListener(connection.LocalEndPoint.Address, port, pasvOptions.PublicAddress);
            }

            return(listener);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Gets a listener on a port within the assigned port range.
        /// </summary>
        /// <param name="connection">Connection for which to create the listener.</param>
        /// <param name="pasvOptions">The options for the <see cref="IPasvListener"/>.</param>
        /// <returns>Configured PasvListener.</returns>
        /// <exception cref="SocketException">When no free port could be found, or other bad things happen. See <see cref="SocketError"/>.</exception>
        private IPasvListener CreateListenerInRange(IFtpConnection connection, PasvListenerOptions pasvOptions)
        {
            lock (_listenerLock)
            {
                // randomize ports so we don't always get the ports in the same order
                foreach (var port in GetPorts(pasvOptions))
                {
                    try
                    {
                        return(new PasvListener(connection.LocalEndPoint.Address, port, pasvOptions.PublicAddress));
                    }
                    catch (SocketException se)
                    {
                        // retry if the socket is already in use, else throw the underlying exception
                        if (se.SocketErrorCode != SocketError.AddressAlreadyInUse)
                        {
                            _log?.LogError(se, "Could not create listener");
                            throw;
                        }
                    }
                }

                // if we reach this point, we have not been able to create a listener within range
                _log?.LogWarning("No free ports available for data connection");
                throw new SocketException((int)SocketError.AddressAlreadyInUse);
            }
        }
        private bool IsSocketConnectionEstablished(IFtpConnection connection)
        {
            try
            {
                var socketAccessor = connection.ConnectionServices.GetRequiredService <TcpSocketClientAccessor>();
                var client         = socketAccessor?.TcpSocketClient;
                if (client == null)
                {
                    return(false);
                }

                // https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.connected?view=netframework-4.7.2
                // Quote:
                // If you need to determine the current state of the connection, make a nonblocking, zero-byte
                // Send call. If the call returns successfully or throws a WAEWOULDBLOCK error code (10035),
                // then the socket is still connected; otherwise, the socket is no longer connected.
                client.Client.Send(Array.Empty <byte>(), 0, 0, SocketFlags.None, out var socketError);
                return(socketError == SocketError.Success || socketError == SocketError.WouldBlock);
            }
            catch
            {
                // Any error means that the connection isn't usable anymore.
                return(false);
            }
        }
Exemplo n.º 7
0
        public static async Task <IFtpResponse> SendDataAsync(
            [NotNull] this IFtpConnection connection,
            [NotNull] Func <IFtpDataConnection, CancellationToken, Task <IFtpResponse> > asyncSendAction,
            [CanBeNull] ILogger logger,
            CancellationToken cancellationToken)
        {
            IFtpDataConnection dataConnection;

            try
            {
                dataConnection = await connection.OpenDataConnectionAsync(null, cancellationToken)
                                 .ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                logger?.LogWarning(0, ex, "Could not open data connection: {error}", ex.Message);
                var localizationFeature = connection.Features.Get <ILocalizationFeature>();
                return(new FtpResponse(425, localizationFeature.Catalog.GetString("Could not open data connection")));
            }

            try
            {
                return(await asyncSendAction(dataConnection, cancellationToken)
                       .ConfigureAwait(false));
            }
            finally
            {
                await dataConnection.CloseAsync(cancellationToken)
                .ConfigureAwait(false);
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="TlsAuthenticationMechanism"/> class.
 /// </summary>
 /// <param name="connection">The required FTP connection.</param>
 /// <param name="sslStreamWrapperFactory">The SslStream wrapper factory.</param>
 public TlsAuthenticationMechanism(
     IFtpConnection connection,
     ISslStreamWrapperFactory sslStreamWrapperFactory)
     : base(connection)
 {
     _sslStreamWrapperFactory = sslStreamWrapperFactory;
 }
Exemplo n.º 9
0
        /// <inheritdoc />
        public Task <IPasvListener> CreateTcpListener(IFtpConnection connection, int port)
        {
            IPasvListener listener;

            if (port < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(port), "may not be less than 0");
            }

            if (port > 0 && _pasvMinPort > 0 && (port > _pasvMaxPort || port < _pasvMinPort))
            {
                throw new ArgumentOutOfRangeException(nameof(port), $"must be in {_pasvMinPort}:{_pasvMaxPort}");
            }

            if (port == 0 && _pasvPorts != null)
            {
                listener = CreateListenerInRange(connection);
            }
            else
            {
                listener = new PasvListener(connection.LocalEndPoint.Address, port, PasvExternalAddress);
            }

            return(Task.FromResult(listener));
        }
Exemplo n.º 10
0
        private IEnumerable <ConnectionInitAsyncDelegate> OnConfigureConnection(IFtpConnection connection)
        {
            var eventArgs = new ConnectionEventArgs(connection);

            ConfigureConnection?.Invoke(this, eventArgs);
            return(eventArgs.AsyncInitFunctions);
        }
Exemplo n.º 11
0
        public static FtpCommand Parse(IFtpConnection connection, [NotNull] string command)
        {
            var spaceIndex       = command.IndexOfAny(_whiteSpaces);
            var commandName      = spaceIndex == -1 ? command : command.Substring(0, spaceIndex);
            var commandArguments = spaceIndex == -1 ? string.Empty : command.Substring(spaceIndex + 1);

            return(new FtpCommand(connection, commandName, commandArguments));
        }
Exemplo n.º 12
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PassCommandHandler"/> class.
 /// </summary>
 /// <param name="connection">The connection to create this command handler for.</param>
 /// <param name="membershipProviders">The membership providers.</param>
 /// <param name="fileSystemClassFactory">The file system access factory.</param>
 public PassCommandHandler(
     [NotNull] IFtpConnection connection,
     [NotNull] IEnumerable <IMembershipProvider> membershipProviders,
     [NotNull] IFileSystemClassFactory fileSystemClassFactory)
     : base(connection, "PASS")
 {
     _membershipProviders    = membershipProviders;
     _fileSystemClassFactory = fileSystemClassFactory;
 }
Exemplo n.º 13
0
 /// <summary>
 /// Initializes a new instance of the <see cref="FtpContext"/> class.
 /// </summary>
 /// <param name="command">The FTP command.</param>
 /// <param name="serverCommandWriter">The FTP response writer.</param>
 /// <param name="connection">The FTP connection.</param>
 public FtpContext(
     [NotNull] FtpCommand command,
     [NotNull] ChannelWriter <IServerCommand> serverCommandWriter,
     [NotNull] IFtpConnection connection)
 {
     Command             = command;
     ServerCommandWriter = serverCommandWriter;
     Connection          = connection;
 }
Exemplo n.º 14
0
 /// <summary>
 /// Initializes a new instance of the <see cref="FtpContext"/> class.
 /// </summary>
 /// <param name="command">The FTP command.</param>
 /// <param name="serverCommandWriter">The FTP response writer.</param>
 /// <param name="connection">The FTP connection.</param>
 public FtpContext(
     FtpCommand command,
     ChannelWriter <IServerCommand> serverCommandWriter,
     IFtpConnection connection)
 {
     Command             = command;
     ServerCommandWriter = serverCommandWriter;
     Connection          = connection;
 }
Exemplo n.º 15
0
        /// <summary>
        /// Collects data and handles the <code>Synch</code> and <code>Interrupt Process</code> TELNET commands.
        /// </summary>
        /// <param name="data">The data buffer.</param>
        /// <param name="offset">The offset into the data buffer.</param>
        /// <param name="length">The length of the data to read from the data buffer.</param>
        /// <returns>The list of items found inside the collected data.</returns>
        public IReadOnlyList <T> Collect(IFtpConnection connection, byte[] data, int offset, int length)
        {
            var result     = new List <T>();
            var endOffset  = offset + length;
            var dataOffset = offset;

            for (var index = offset; index != endOffset; ++index)
            {
                var v = data[index];
                if (_interpretAsCommandReceived)
                {
                    dataOffset = index + 1;
                    _interpretAsCommandReceived = false;
                    switch (v)
                    {
                    case 0xF2:
                        result.AddRange(Synch());
                        break;

                    case 0xF4:
                        result.AddRange(InterruptProcess());
                        break;

                    case 0xFF:
                        // Double-Escape
                        result.AddRange(DataReceived(connection, data, index, length: 1));
                        break;

                    default:
                        Debug.WriteLine("TELNET: Unknown command received - skipping 0xFF");
                        dataOffset = index;
                        break;
                    }
                    _interpretAsCommandReceived = false;
                }
                else if (v == 0xFF)
                {
                    var dataLength = index - dataOffset;
                    if (dataLength != 0)
                    {
                        result.AddRange(DataReceived(connection, data, dataOffset, dataLength));
                    }

                    _interpretAsCommandReceived = true;
                    dataOffset = index + 2;
                }
            }
            if (dataOffset < endOffset)
            {
                var dataLength = endOffset - dataOffset;
                if (dataLength != 0)
                {
                    result.AddRange(DataReceived(connection, data, dataOffset, dataLength));
                }
            }
            return(result);
        }
        private async Task WriteResponseAsync(
            IFtpConnection connection,
            IFtpResponse response,
            CancellationToken cancellationToken)
        {
            var networkStreamFeature = connection.Features.Get <INetworkStreamFeature>();
            var encoding             = connection.Features.Get <IEncodingFeature>().Encoding;

            var writer = networkStreamFeature.Output;

            object?token = null;

            do
            {
                var line = await response.GetNextLineAsync(token, cancellationToken)
                           .ConfigureAwait(false);

                if (line.HasText)
                {
                    _logger?.LogDebug("{Response}", line.Text);
                    var data   = encoding.GetBytes($"{line.Text}\r\n");
                    var memory = writer.GetMemory(data.Length);
                    data.AsSpan().CopyTo(memory.Span);
                    writer.Advance(data.Length);
                    var flushResult = await writer.FlushAsync(cancellationToken);

                    if (flushResult.IsCanceled || flushResult.IsCompleted)
                    {
                        break;
                    }
                }

                if (!line.HasMoreData)
                {
                    break;
                }

                token = line.Token;
            }while (token != null);

#pragma warning disable CS0618 // Typ oder Element ist veraltet
            if (response.AfterWriteAction != null)
            {
                var nextResponse = await response.AfterWriteAction(connection, cancellationToken)
                                   .ConfigureAwait(false);

                if (nextResponse != null)
                {
                    await WriteResponseAsync(connection, nextResponse, cancellationToken)
                    .ConfigureAwait(false);
                }
            }
#pragma warning restore CS0618 // Typ oder Element ist veraltet

            await writer.FlushAsync(cancellationToken)
            .ConfigureAwait(false);
        }
Exemplo n.º 17
0
        /// <inheritdoc/>
        public string BuildInfo(IFtpConnection connection)
        {
            if (_toString == null)
            {
                return(_name);
            }

            return(_toString(connection));
        }
 public UploadService(
     IFtpConnection ftpConnection,
     IOrafinFormatter orafinFormatter,
     IPublicServiceRepository publicServiceRepository)
 {
     _ftpConnection           = ftpConnection;
     _orafinFormatter         = orafinFormatter;
     _publicServiceRepository = publicServiceRepository;
 }
Exemplo n.º 19
0
        public IEnumerable <FtpCommand> Collect(IFtpConnection connection, byte[] buffer, int offset, int length)
        {
            Debug.WriteLine("Collected data: {0}", string.Join(string.Empty, Enumerable.Range(offset, length).Select(x => buffer[x].ToString("X2"))));

            var commands = new List <FtpCommand>();

            commands.AddRange(_telnetInputParser.Collect(connection, buffer, offset, length));
            return(commands);
        }
Exemplo n.º 20
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MlstCommandHandler"/> class.
 /// </summary>
 /// <param name="connection">The FTP connection this command handler is created for.</param>
 /// <param name="logger">The logger.</param>
 public MlstCommandHandler([NotNull] IFtpConnection connection, [CanBeNull] ILogger <MlstCommandHandler> logger = null)
     : base(connection, "MLST", "MLSD")
 {
     _logger = logger;
     connection.Data.ActiveMlstFacts.Clear();
     foreach (var knownFact in _knownFacts)
     {
         connection.Data.ActiveMlstFacts.Add(knownFact);
     }
 }
Exemplo n.º 21
0
            /// <inheritdoc />
            public Task Configure(IFtpConnection connection, CancellationToken cancellationToken)
            {
                var serviceProvider  = connection.Features.Get <IServiceProvidersFeature>().RequestServices;
                var stateMachine     = serviceProvider.GetRequiredService <IFtpLoginStateMachine>();
                var authTlsMechanism = serviceProvider.GetRequiredService <IEnumerable <IAuthenticationMechanism> >()
                                       .Single(x => x.CanHandle("TLS"));

                stateMachine.Activate(authTlsMechanism);
                return(Task.CompletedTask);
            }
Exemplo n.º 22
0
        public static IEnumerable <string> CreateAuthTlsFeatureString([NotNull] IFtpConnection connection)
        {
            var hostSelector = connection.ConnectionServices.GetRequiredService <IFtpHostSelector>();

            if (hostSelector.SelectedHost.Certificate != null)
            {
                return(new[] { "AUTH TLS", "PBSZ", "PROT" });
            }

            return(new string[0]);
        }
Exemplo n.º 23
0
        private static string FeatureStatus(IFtpConnection connection)
        {
            var result = new StringBuilder();

            result.Append("MLST ");
            foreach (var fact in KnownFacts)
            {
                result.AppendFormat("{0}{1};", fact, connection.Data.ActiveMlstFacts.Contains(fact) ? "*" : string.Empty);
            }
            return(result.ToString());
        }
Exemplo n.º 24
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PasswordAuthorization"/> class.
 /// </summary>
 /// <param name="connection">The required FTP connection.</param>
 /// <param name="membershipProviders">The membership providers for password authorization.</param>
 /// <param name="authorizationActions">Actions to be executed upon authorization.</param>
 /// <param name="serverMessages">The FTP server messages.</param>
 public PasswordAuthorization(
     [NotNull] IFtpConnection connection,
     [NotNull, ItemNotNull] IEnumerable <IMembershipProvider> membershipProviders,
     [NotNull, ItemNotNull] IEnumerable <IAuthorizationAction> authorizationActions,
     [NotNull] IFtpServerMessages serverMessages)
     : base(connection)
 {
     _serverMessages       = serverMessages;
     _authorizationActions = authorizationActions.OrderByDescending(x => x.Level).ToList();
     _membershipProviders  = membershipProviders.ToList();
 }
Exemplo n.º 25
0
        /// <summary>
        /// Initializes a new instance of the <see cref="FtpCommandHandler"/> class.
        /// </summary>
        /// <param name="connection">The connection this instance is used for.</param>
        /// <param name="name">The command name.</param>
        /// <param name="alternativeNames">Alternative names.</param>
        protected FtpCommandHandler([NotNull] IFtpConnection connection, [NotNull] string name, [NotNull, ItemNotNull] params string[] alternativeNames)
        {
            Connection = connection;
            var names = new List <string>
            {
                name,
            };

            names.AddRange(alternativeNames);
            Names = names;
        }
Exemplo n.º 26
0
        /// <summary>
        /// Initializes a new instance of the <see cref="FtpCommandHandlerExtension"/> class.
        /// </summary>
        /// <param name="connection">The connection this instance is used for.</param>
        /// <param name="extensionFor">The name of the command this extension is for.</param>
        /// <param name="name">The command name.</param>
        /// <param name="alternativeNames">Alternative names.</param>
        protected FtpCommandHandlerExtension([NotNull] IFtpConnection connection, [NotNull] string extensionFor, [NotNull] string name, [NotNull, ItemNotNull] params string[] alternativeNames)
        {
            var names = new List <string>
            {
                name,
            };

            names.AddRange(alternativeNames);
            Names        = names;
            ExtensionFor = extensionFor;
            Connection   = connection;
        }
Exemplo n.º 27
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SingleFtpHostSelector"/> class.
 /// </summary>
 /// <param name="connection">The FTP connection.</param>
 /// <param name="authenticationMechanisms">The registered authentication mechanisms.</param>
 /// <param name="authorizationMechanisms">The registered authorization mechanisms.</param>
 /// <param name="authTlsOptions">The options for the AUTH TLS command.</param>
 public SingleFtpHostSelector(
     IFtpConnection connection,
     IEnumerable <IAuthenticationMechanism> authenticationMechanisms,
     IEnumerable <IAuthorizationMechanism> authorizationMechanisms,
     IOptions <AuthTlsOptions> authTlsOptions)
 {
     SelectedHost = new DefaultFtpHost(
         authenticationMechanisms.ToList(),
         authorizationMechanisms.ToList(),
         authTlsOptions);
     _connection = connection;
 }
Exemplo n.º 28
0
 /// <summary>
 /// Initializes a new instance of the <see cref="FtpStateMachine{TStatus}"/> class.
 /// </summary>
 /// <param name="connection">The FTP connection.</param>
 /// <param name="transitions">The supported transitions.</param>
 /// <param name="initialStatus">The initial status.</param>
 protected FtpStateMachine(
     [NotNull] IFtpConnection connection,
     [NotNull, ItemNotNull] IEnumerable <Transition> transitions,
     TStatus initialStatus)
 {
     Connection     = connection;
     _initialStatus = initialStatus;
     _transitions   = transitions
                      .ToLookup(x => x.Source)
                      .ToDictionary(x => x.Key, x => (IReadOnlyCollection <Transition>)x.ToList());
     Status = initialStatus;
     _possibleTransitions = GetPossibleTransitions(initialStatus);
 }
        public IEnumerable <IFeatureInfo> GetSupportedFeatures(IFtpConnection connection)
        {
            var hostSelector = connection.ConnectionServices.GetRequiredService <IFtpHostSelector>();

            if (hostSelector.SelectedHost.Certificate != null)
            {
                yield return(new GenericFeatureInfo("AUTH", conn => "AUTH TLS", false));

                yield return(new GenericFeatureInfo("PBSZ", false));

                yield return(new GenericFeatureInfo("PROT", false));
            }
        }
Exemplo n.º 30
0
        /// <summary>
        /// Gets the feature string for the <c>MFF</c> command.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <returns>The feature string.</returns>
        public static string FeatureStatus(IFtpConnection connection)
        {
            var factsFeature = connection.Features.Get <IMlstFactsFeature>() ?? CreateMlstFactsFeature();
            var result       = new StringBuilder();

            result.Append("MLST ");
            foreach (var fact in KnownFacts)
            {
                result.AppendFormat("{0}{1};", fact, factsFeature.ActiveMlstFacts.Contains(fact) ? "*" : string.Empty);
            }

            return(result.ToString());
        }