protected void ProcessMsgUserAuthRequestNone(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Raise event to get result of auth attempt.
            var authUserEventArgs = new AuthUserNoMethodEventArgs(_lastUserName);

            if (AuthenticateUserNoMethod != null)
            {
                AuthenticateUserNoMethod(this, authUserEventArgs);
            }

            // Check result of auth attempt.
            switch (authUserEventArgs.Result)
            {
            case AuthenticationResult.Success:
                // Auth has succeeded.
                AuthenticateUser(_lastServiceName);

                break;

            case AuthenticationResult.Failure:
                // Send list of supported auth methods.
                SendMsgUserAuthFailure(false);

                break;
            }
        }
        protected void ProcessMsgGlobalRequest(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Read request information.
            string requestName = msgReader.ReadString();
            bool   wantReply   = msgReader.ReadBoolean();

            switch (requestName)
            {
            case "tcpip-forward":
                throw new NotImplementedException();

            //if (wantReply) SendMsgRequestSuccess(null);

            //return;
            default:
                // Unrecognised request type.
                break;
            }

            // Request has failed.
            if (wantReply)
            {
                SendMsgRequestFailure();
            }
        }
        protected List <TerminalMode> ReadTerminalModes(byte[] encodedModes)
        {
            var termModes = new List <TerminalMode>();
            TerminalModeOpCode opCode;

            // Read modes from encoded byte stream.
            using (var streamReader = new SshStreamReader(new MemoryStream(encodedModes)))
            {
                while (true)
                {
                    opCode = (TerminalModeOpCode)streamReader.ReadByte();

                    if (opCode == TerminalModeOpCode.TtyOpEnd)
                    {
                        break;
                    }
                    if ((byte)opCode >= 1 && (byte)opCode <= 160)
                    {
                        // Add mode to list.
                        termModes.Add(new TerminalMode(opCode, streamReader.ReadUInt32()));
                    }
                    else
                    {
                        // Undefined op code.
                        break;
                    }
                }
            }

            return(termModes);
        }
        protected void ProcessMsgRequestSuccess(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            //
        }
        protected void ProcessMsgChannelOpenFailure(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            //
        }
        protected void ProcessMsgUserInfoResponse(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Read response info.
            int numResponses = msgReader.ReadInt32();

            string[] responses = new string[numResponses];

            for (int i = 0; i < numResponses; i++)
            {
                responses[i] = Encoding.UTF8.GetString(msgReader.ReadByteString());
            }

            // Raise event to get result of auth attempt.
            var authUserEventArgs = new AuthUserKeyboardInteractiveEventArgs(_lastUserName,
                                                                             responses);

            if (AuthenticateUserKeyboardInteractive != null)
            {
                AuthenticateUserKeyboardInteractive(this,
                                                    authUserEventArgs);
            }

            // Check result of auth attempt.
            switch (authUserEventArgs.Result)
            {
            case AuthenticationResult.Success:
                // Auth has succeeded.
                AuthenticateUser(_lastServiceName);

                break;

            case AuthenticationResult.FurtherAuthRequired:
                // Auth has succeeded, but further auth is required.
                SendMsgUserAuthFailure(true);

                break;

            case AuthenticationResult.Failure:
                // Auth has failed.
                SendMsgUserAuthFailure(false);

                break;

            case AuthenticationResult.RequestMoreInfo:
                // Request more prompt info from client.
                RequestPromptInfo(null);

                break;
            }
        }
        protected void ProcessMsgUserAuthRequest(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Read auth information.
            string userName    = Encoding.UTF8.GetString(msgReader.ReadByteString());
            string serviceName = msgReader.ReadString();
            string methodName  = msgReader.ReadString();

            // Store user name and service name used for this auth.
            _lastUserName    = userName;
            _lastServiceName = serviceName;

            // Check if service with specified name exists.
            if (_client.Services.Count(item => item.Name == serviceName) == 0)
            {
                // Service was not found.
                _client.Disconnect(SshDisconnectReason.ServiceNotAvailable, string.Format(
                                       "The service with name {0} is not supported by this server."));
                throw new DisconnectedException();
            }

            // Check method of authentication.
            switch (methodName)
            {
            case "none":
                ProcessMsgUserAuthRequestNone(msgReader);
                break;

            case "publickey":
                ProcessMsgUserAuthRequestPublicKey(msgReader);
                break;

            case "password":
                ProcessMsgUserAuthRequestPassword(msgReader);
                break;

            case "hostbased":
                ProcessMsgUserAuthRequestHostBased(msgReader);
                break;

            case "keyboard-interactive":
                ProcessMsgUserAuthRequestKeyboardInteractive(msgReader);
                break;

            default:
                // Invalid auth method.
                _client.Disconnect(false);
                break;
            }
        }
        internal override bool ProcessMessage(byte[] payload)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Check if banner message has not yet been set.
            if (!_bannerMsgSent)
            {
                // Send banner message if one has been specified.
                if (this.BannerMessage != null)
                {
                    SendMsgUserAuthBanner(this.BannerMessage,
                                          this.BannerMessageLanguage);
                }

                _bannerMsgSent = true;
            }

            using (var msgReader = new SshStreamReader(new MemoryStream(payload)))
            {
                // Check message ID.
                SshAuthenticationMessage messageId = (SshAuthenticationMessage)msgReader.ReadByte();

#if DEBUG
                if (System.Enum.IsDefined(typeof(SshAuthenticationMessage), messageId))
                {
                    Debug.WriteLine(string.Format(">>> {0}", System.Enum.GetName(
                                                      typeof(SshAuthenticationMessage), messageId)));
                }
#endif

                switch (messageId)
                {
                // User auth messages
                case SshAuthenticationMessage.Request:
                    ProcessMsgUserAuthRequest(msgReader);
                    break;

                case SshAuthenticationMessage.InfoResponse:
                    ProcessMsgUserInfoResponse(msgReader);
                    break;

                // Unrecognised message
                default:
                    return(false);
                }
            }

            // Message was recognised.
            return(true);
        }
        protected void ProcessMsgChannelClose(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Read channel number and get channel object.
            uint       channelNum = msgReader.ReadUInt32();
            SshChannel channel;

            try { channel = _channels.SingleOrDefault(item => item.ServerChannel == channelNum); }
            catch (InvalidOperationException) { return; }

            channel.Close();
        }
Пример #10
0
        public byte[] GetSignature(byte[] signatureData)
        {
            using (var dataStream = new MemoryStream(signatureData))
            {
                using (var dataReader = new SshStreamReader(dataStream))
                {
                    // Read signature from stream.
                    if (dataReader.ReadString() != this.Name)
                    {
                        throw new CryptographicException(
                                  "Signature was not created with this algorithm.");
                    }
                    var signature = dataReader.ReadByteString();

                    return(signature);
                }
            }
        }
        protected void ProcessMsgChannelExtendedData(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Read channel number and get channel object.
            uint       channelNum = msgReader.ReadUInt32();
            SshChannel channel;

            try { channel = _channels.SingleOrDefault(item => item.ServerChannel == channelNum); }
            catch (InvalidOperationException) { return; }

            // Let channel read extended data.
            var dataType = (SshExtendedDataType)msgReader.ReadUInt32();
            var data     = msgReader.ReadByteString();

            channel.ProcessExtendedData(dataType, data);
        }
        protected void ProcessMsgChannelRequest(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Read channel number and get channel object.
            uint       channelNum = msgReader.ReadUInt32();
            SshChannel channel;

            try { channel = _channels.SingleOrDefault(item => item.ServerChannel == channelNum); }
            catch (InvalidOperationException) { return; }

            string requestType = msgReader.ReadString();
            bool   wantReply   = msgReader.ReadBoolean();

            // Let channel process request.
            channel.ProcessRequest(requestType, wantReply, msgReader);
        }
        protected void ProcessMsgUserAuthRequestKeyboardInteractive(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Raise event to specify requested auth method.
            if (AuthenticationMethodRequested != null)
            {
                AuthenticationMethodRequested(this,
                                              new AuthMethodRequestedEventArgs(AuthenticationMethod.KeyboardInteractive));
            }

            // Read request information.
            string language = msgReader.ReadString();

            string[] subMethods = Encoding.UTF8.GetString(msgReader.ReadByteString()).Split(
                new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);

            // Request prompt info from client.
            RequestPromptInfo(subMethods);
        }
        protected void ProcessMsgUserAuthRequestPassword(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Raise event to specify requested auth method.
            if (AuthenticationMethodRequested != null)
            {
                AuthenticationMethodRequested(this,
                                              new AuthMethodRequestedEventArgs(AuthenticationMethod.Password));
            }

            // Check whether client is changing password.
            bool changingPassword = msgReader.ReadBoolean();

            if (changingPassword)
            {
                // Read old and new passwords (in plaintext).
                string oldPassword = Encoding.UTF8.GetString(msgReader.ReadByteString());
                string newPassword = Encoding.UTF8.GetString(msgReader.ReadByteString());

                // Raise event to get result of password change request.
                var changePasswordEventArgs = new ChangePasswordEventArgs(oldPassword, newPassword);

                if (ChangePassword != null)
                {
                    ChangePassword(this, changePasswordEventArgs);
                }

                // Check result of password change request.
                switch (changePasswordEventArgs.Result)
                {
                case PasswordChangeResult.Success:
                    // Password change and auth have succeeded.
                    AuthenticateUser(_lastServiceName);

                    break;

                case PasswordChangeResult.FurtherAuthRequired:
                    // Password change has succeeded, but further auth is required.
                    SendMsgUserAuthFailure(true);

                    break;

                case PasswordChangeResult.Failure:
                    // Password change has failed.
                    SendMsgUserAuthFailure(false);

                    break;

                case PasswordChangeResult.NewPasswordUnacceptable:
                    // Password was not changed.
                    SendMsgUserAuthPasswdChangeReq(changePasswordEventArgs.ReplyPrompt, "");

                    break;
                }
            }
            else
            {
                // Read password (in plaintext).
                string password = Encoding.UTF8.GetString(msgReader.ReadByteString());

                // Raise event to get result of auth attempt.
                var authUserEventArgs = new AuthUserPasswordEventArgs(_lastUserName, password);

                if (AuthenticateUserPassword != null)
                {
                    AuthenticateUserPassword(this, authUserEventArgs);
                }

                // Check result of auth attempt.
                switch (authUserEventArgs.Result)
                {
                case AuthenticationResult.Success:
                    // Auth has succeeded.
                    AuthenticateUser(_lastServiceName);

                    break;

                case AuthenticationResult.FurtherAuthRequired:
                    // Auth has succeeded, but further auth is required.
                    SendMsgUserAuthFailure(true);

                    break;

                case AuthenticationResult.Failure:
                    // Increment number of failed auth attempts.
                    _failedAuthAttempts++;

                    if (_failedAuthAttempts < this.MaximumAuthAttempts)
                    {
                        // Auth has failed, but allow client to reattempt auth.
                        SendMsgUserAuthFailure(false);
                    }
                    else
                    {
                        // Auth has failed too many times, disconnect.
                        _client.Disconnect(false);
                        throw new DisconnectedException();
                    }

                    break;

                case AuthenticationResult.PasswordExpired:
                    // Password change is required.
                    SendMsgUserAuthPasswdChangeReq("The specified password has expired.", "");

                    break;
                }
            }
        }
        protected void ProcessMsgChannelOpen(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Read channel information.
            string channelType       = msgReader.ReadString();
            uint   senderChannel     = msgReader.ReadUInt32();
            uint   initialWindowSize = msgReader.ReadUInt32();
            uint   maxPacketSize     = msgReader.ReadUInt32();

            // Check channel type.
            switch (channelType)
            {
            default:
                // Raise event to request channel.
                var channelRequestedEventArgs = new ChannelOpenRequestEventArgs(senderChannel,
                                                                                (uint)_channels.Count, channelType, initialWindowSize, maxPacketSize);

                if (ChannelOpenRequest != null)
                {
                    ChannelOpenRequest(this, channelRequestedEventArgs);
                }

                var channel = channelRequestedEventArgs.Channel;

                // Check if channel was created.
                if (channel != null)
                {
                    channel.Opened          += new EventHandler <EventArgs>(channel_Opened);
                    channel.Closed          += new EventHandler <EventArgs>(channel_Closed);
                    channel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(
                        channel_PropertyChanged);
                    channel.Open(this);

                    _channels.Add(channel);

                    // Send confirmation message.
                    SendMsgChannelOpenConfirmation(channel);
                }
                else
                {
                    string failureDescription = channelRequestedEventArgs.FailureDescription;

                    if (failureDescription != null)
                    {
                        // Create description of failure from reason code.
                        switch (channelRequestedEventArgs.FailureReason)
                        {
                        case SshChannelOpenFailureReason.AdministrativelyProhibited:
                            failureDescription = "Administratively prohibited.";
                            break;

                        case SshChannelOpenFailureReason.ConnectFailed:
                            failureDescription = "Connect attempt failed.";
                            break;

                        case SshChannelOpenFailureReason.UnknownChannelType:
                            failureDescription = string.Format("Unknown channel type '{0}'.",
                                                               channelType);
                            break;

                        case SshChannelOpenFailureReason.ResourceShortage:
                            failureDescription = "Resource shortage on server.";
                            break;
                        }
                    }

                    // Channel open request has failed.
                    SendMsgChannelOpenFailure(channel, channelRequestedEventArgs.FailureReason,
                                              failureDescription, "");
                    return;
                }

                break;
            }
        }
        protected void ProcessMsgUserAuthRequestHostBased(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Raise event to specify requested auth method.
            if (AuthenticationMethodRequested != null)
            {
                AuthenticationMethodRequested(this,
                                              new AuthMethodRequestedEventArgs(AuthenticationMethod.HostBased));
            }

            // Read request information.
            string keyAlgName = msgReader.ReadString();

            byte[] keyAndCertsData = msgReader.ReadByteString();
            string clientHostName  = msgReader.ReadString();
            string clientUserName  = msgReader.ReadString();

            // Try to find public key algorithm.
            PublicKeyAlgorithm keyAlg = null;

            try
            {
                keyAlg = (PublicKeyAlgorithm)_client.PublicKeyAlgorithms.Single(item =>
                                                                                item.Name == keyAlgName).Clone();
            }
            catch (InvalidOperationException)
            {
                // Public key algorithm is not supported.
                SendMsgUserAuthFailure(false);
            }

            // Load key and certificats data for algorithm.
            keyAlg.LoadKeyAndCertificatesData(keyAndCertsData);

            // Read client signature.
            var signatureData = msgReader.ReadByteString();
            var signature     = keyAlg.GetSignature(signatureData);

            // Verify signature.
            var payloadData = ((MemoryStream)msgReader.BaseStream).ToArray();

            if (VerifyPublicKeySignature(keyAlg, payloadData, 0, payloadData.Length -
                                         signatureData.Length - 4, signature))
            {
                // Raise event to get result of auth attempt.
                var authUserEventArgs = new AuthUserHostBasedEventArgs(_lastUserName, clientHostName,
                                                                       clientUserName, keyAlg.ExportPublicKey());

                if (AuthenticateUserHostBased != null)
                {
                    AuthenticateUserHostBased(this, authUserEventArgs);
                }

                // Check result of auth attempt.
                switch (authUserEventArgs.Result)
                {
                case AuthenticationResult.Success:
                    // Auth has succeeded.
                    AuthenticateUser(_lastServiceName);

                    break;

                case AuthenticationResult.FurtherAuthRequired:
                    // Auth has succeeded, but further auth is required.
                    SendMsgUserAuthFailure(true);

                    break;

                case AuthenticationResult.Failure:
                    // Auth has failed.
                    SendMsgUserAuthFailure(false);

                    break;
                }
            }
            else
            {
                // Signature is invalid.
                SendMsgUserAuthFailure(false);
            }
        }
        public byte[] GetSignature(byte[] signatureData)
        {
            using (var dataStream = new MemoryStream(signatureData))
            {
                using (var dataReader = new SshStreamReader(dataStream))
                {
                    // Read signature from stream.
                    if (dataReader.ReadString() != this.Name) throw new CryptographicException(
                       "Signature was not created with this algorithm.");
                    var signature = dataReader.ReadByteString();

                    return signature;
                }
            }
        }
        internal override bool ProcessMessage(byte[] payload)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Create memory stream from payload data.
            using (var msgStream = new MemoryStream(payload))
            using (var msgReader = new SshStreamReader(msgStream))
            {
                // Check message ID.
                SshConnectionMessage messageId = (SshConnectionMessage)msgReader.ReadByte();

            #if DEBUG
                if (System.Enum.IsDefined(typeof(SshConnectionMessage), messageId))
                    Debug.WriteLine(string.Format(">>> {0}", System.Enum.GetName(
                        typeof(SshConnectionMessage), messageId)));
            #endif

                switch (messageId)
                {
                    // Global request messages
                    case SshConnectionMessage.GlobalRequest:
                        ProcessMsgGlobalRequest(msgReader);
                        break;
                    case SshConnectionMessage.RequestSuccess:
                        ProcessMsgRequestSuccess(msgReader);
                        break;
                    case SshConnectionMessage.RequestFailure:
                        ProcessMsgRequestFailure(msgReader);
                        break;
                    // Channel messages
                    case SshConnectionMessage.ChannelOpen:
                        ProcessMsgChannelOpen(msgReader);
                        break;
                    case SshConnectionMessage.ChannelOpenConfirmation:
                        ProcessMsgChannelOpenConfirmation(msgReader);
                        break;
                    case SshConnectionMessage.ChannelOpenFailure:
                        ProcessMsgChannelOpenFailure(msgReader);
                        break;
                    case SshConnectionMessage.ChannelEof:
                        ProcessMsgChannelEof(msgReader);
                        break;
                    case SshConnectionMessage.ChannelClose:
                        ProcessMsgChannelClose(msgReader);
                        break;
                    case SshConnectionMessage.ChannelRequest:
                        ProcessMsgChannelRequest(msgReader);
                        break;
                    case SshConnectionMessage.ChannelWindowAdjust:
                        ProcessMsgChannelWindowAdjust(msgReader);
                        break;
                    case SshConnectionMessage.ChannelData:
                        ProcessMsgChannelData(msgReader);
                        break;
                    case SshConnectionMessage.ChannelExtendedData:
                        ProcessMsgChannelExtendedData(msgReader);
                        break;
                    // Unrecognised message
                    default:
                        return false;
                }
            }

            // Message was recognised.
            return true;
        }
        protected void ProcessMsgUserInfoResponse(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Read response info.
            int numResponses = msgReader.ReadInt32();
            string[] responses = new string[numResponses];

            for (int i = 0; i < numResponses; i++)
                responses[i] = Encoding.UTF8.GetString(msgReader.ReadByteString());

            // Raise event to get result of auth attempt.
            var authUserEventArgs = new AuthUserKeyboardInteractiveEventArgs(_lastUserName,
                responses);

            if (AuthenticateUserKeyboardInteractive != null) AuthenticateUserKeyboardInteractive(this,
                authUserEventArgs);

            // Check result of auth attempt.
            switch (authUserEventArgs.Result)
            {
                case AuthenticationResult.Success:
                    // Auth has succeeded.
                    AuthenticateUser(_lastServiceName);

                    break;
                case AuthenticationResult.FurtherAuthRequired:
                    // Auth has succeeded, but further auth is required.
                    SendMsgUserAuthFailure(true);

                    break;
                case AuthenticationResult.Failure:
                    // Auth has failed.
                    SendMsgUserAuthFailure(false);

                    break;
                case AuthenticationResult.RequestMoreInfo:
                    // Request more prompt info from client.
                    RequestPromptInfo(null);

                    break;
            }
        }
        protected internal override void ProcessRequest(string requestType, bool wantReply,
            SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            switch (requestType)
            {
                case "pty-req":
                    // Read information about pseudo-terminal.
                    var termEnvVar = msgReader.ReadString();
                    var termCharsWidth = msgReader.ReadUInt32();
                    var termCharsHeight = msgReader.ReadUInt32();
                    var termPixelsWidth = msgReader.ReadUInt32();
                    var termPixelsHeight = msgReader.ReadUInt32();
                    var termModes = ReadTerminalModes(msgReader.ReadByteString());

                    // Raise event to request pseudo terminal.
                    var pseudoTerminalRequestedEventArgs = new PseudoTerminalRequestedEventArgs(termEnvVar);

                    OnPseudoTerminalRequested(pseudoTerminalRequestedEventArgs);

                    // Check if request to allocate pseudo terminal failed.
                    if (!pseudoTerminalRequestedEventArgs.Success) break;

                    _termEnvVar = termEnvVar;
                    _termCharsWidth = termCharsWidth;
                    _termCharsHeight = termCharsHeight;
                    _termPixelsWidth = termPixelsWidth;
                    _termPixelsHeight = termPixelsHeight;
                    _termModes = termModes;

                    // Add TERM to list of environment variables.
                    _envVars.Add("TERM", _termEnvVar);

                    // Raise event, pseudo terminal has been allocated.
                    OnPseudoTerminalAllocated(new EventArgs());

                    if (wantReply) _connService.SendMsgChannelSuccess(this);
                    return;

                case "env":
                    // Read name and value of environment variable.
                    var varName = msgReader.ReadString();
                    var varValue = msgReader.ReadString();

                    // Add variable to list.
                    _envVars.Add(varName, varValue);

                    if (wantReply) _connService.SendMsgChannelSuccess(this);
                    return;
                case "shell":
                    // Start default shell.
                    StartShell();

                    if (wantReply) _connService.SendMsgChannelSuccess(this);
                    return;
                case "exec":
                    // not implemented

                    break;
                default:
                    base.ProcessRequest(requestType, wantReply, msgReader);
                    return;
            }

            // Request has failed.
            if (wantReply) _connService.SendMsgChannelFailure(this);
        }
        protected void ProcessMsgUserAuthRequestKeyboardInteractive(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Raise event to specify requested auth method.
            if (AuthenticationMethodRequested != null) AuthenticationMethodRequested(this,
                new AuthMethodRequestedEventArgs(AuthenticationMethod.KeyboardInteractive));

            // Read request information.
            string language = msgReader.ReadString();
            string[] subMethods = Encoding.UTF8.GetString(msgReader.ReadByteString()).Split(
                new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);

            // Request prompt info from client.
            RequestPromptInfo(subMethods);
        }
        protected void ProcessMsgUserAuthRequestPassword(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Raise event to specify requested auth method.
            if (AuthenticationMethodRequested != null) AuthenticationMethodRequested(this,
                new AuthMethodRequestedEventArgs(AuthenticationMethod.Password));

            // Check whether client is changing password.
            bool changingPassword = msgReader.ReadBoolean();

            if (changingPassword)
            {
                // Read old and new passwords (in plaintext).
                string oldPassword = Encoding.UTF8.GetString(msgReader.ReadByteString());
                string newPassword = Encoding.UTF8.GetString(msgReader.ReadByteString());

                // Raise event to get result of password change request.
                var changePasswordEventArgs = new ChangePasswordEventArgs(oldPassword, newPassword);

                if (ChangePassword != null) ChangePassword(this, changePasswordEventArgs);

                // Check result of password change request.
                switch (changePasswordEventArgs.Result)
                {
                    case PasswordChangeResult.Success:
                        // Password change and auth have succeeded.
                        AuthenticateUser(_lastServiceName);

                        break;
                    case PasswordChangeResult.FurtherAuthRequired:
                        // Password change has succeeded, but further auth is required.
                        SendMsgUserAuthFailure(true);

                        break;
                    case PasswordChangeResult.Failure:
                        // Password change has failed.
                        SendMsgUserAuthFailure(false);

                        break;
                    case PasswordChangeResult.NewPasswordUnacceptable:
                        // Password was not changed.
                        SendMsgUserAuthPasswdChangeReq(changePasswordEventArgs.ReplyPrompt, "");

                        break;
                }
            }
            else
            {
                // Read password (in plaintext).
                string password = Encoding.UTF8.GetString(msgReader.ReadByteString());

                // Raise event to get result of auth attempt.
                var authUserEventArgs = new AuthUserPasswordEventArgs(_lastUserName, password);

                if (AuthenticateUserPassword != null) AuthenticateUserPassword(this, authUserEventArgs);

                // Check result of auth attempt.
                switch (authUserEventArgs.Result)
                {
                    case AuthenticationResult.Success:
                        // Auth has succeeded.
                        AuthenticateUser(_lastServiceName);

                        break;
                    case AuthenticationResult.FurtherAuthRequired:
                        // Auth has succeeded, but further auth is required.
                        SendMsgUserAuthFailure(true);

                        break;
                    case AuthenticationResult.Failure:
                        // Increment number of failed auth attempts.
                        _failedAuthAttempts++;

                        if (_failedAuthAttempts < this.MaximumAuthAttempts)
                        {
                            // Auth has failed, but allow client to reattempt auth.
                            SendMsgUserAuthFailure(false);
                        }
                        else
                        {
                            // Auth has failed too many times, disconnect.
                            _client.Disconnect(false);
                            throw new DisconnectedException();
                        }

                        break;
                    case AuthenticationResult.PasswordExpired:
                        // Password change is required.
                        SendMsgUserAuthPasswdChangeReq("The specified password has expired.", "");

                        break;
                }
            }
        }
        internal override bool ProcessMessage(byte[] payload)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Check if banner message has not yet been set.
            if (!_bannerMsgSent)
            {
                // Send banner message if one has been specified.
                if (this.BannerMessage != null) SendMsgUserAuthBanner(this.BannerMessage,
                    this.BannerMessageLanguage);

                _bannerMsgSent = true;
            }

            using (var msgReader = new SshStreamReader(new MemoryStream(payload)))
            {
                // Check message ID.
                SshAuthenticationMessage messageId = (SshAuthenticationMessage)msgReader.ReadByte();

            #if DEBUG
                if (System.Enum.IsDefined(typeof(SshAuthenticationMessage), messageId))
                    Debug.WriteLine(string.Format(">>> {0}", System.Enum.GetName(
                        typeof(SshAuthenticationMessage), messageId)));
            #endif

                switch (messageId)
                {
                    // User auth messages
                    case SshAuthenticationMessage.Request:
                        ProcessMsgUserAuthRequest(msgReader);
                        break;
                    case SshAuthenticationMessage.InfoResponse:
                        ProcessMsgUserInfoResponse(msgReader);
                        break;
                    // Unrecognised message
                    default:
                        return false;
                }
            }

            // Message was recognised.
            return true;
        }
        protected void ProcessMsgChannelExtendedData(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Read channel number and get channel object.
            uint channelNum = msgReader.ReadUInt32();
            SshChannel channel;

            try { channel = _channels.SingleOrDefault(item => item.ServerChannel == channelNum); }
            catch (InvalidOperationException) { return; }

            // Let channel read extended data.
            var dataType = (SshExtendedDataType)msgReader.ReadUInt32();
            var data = msgReader.ReadByteString();

            channel.ProcessExtendedData(dataType, data);
        }
        protected void ProcessMsgChannelClose(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Read channel number and get channel object.
            uint channelNum = msgReader.ReadUInt32();
            SshChannel channel;

            try { channel = _channels.SingleOrDefault(item => item.ServerChannel == channelNum); }
            catch (InvalidOperationException) { return; }

            channel.Close();
        }
        protected List<TerminalMode> ReadTerminalModes(byte[] encodedModes)
        {
            var termModes = new List<TerminalMode>();
            TerminalModeOpCode opCode;

            // Read modes from encoded byte stream.
            using (var streamReader = new SshStreamReader(new MemoryStream(encodedModes)))
            {
                while (true)
                {
                    opCode = (TerminalModeOpCode)streamReader.ReadByte();

                    if (opCode == TerminalModeOpCode.TtyOpEnd) break;
                    if ((byte)opCode >= 1 && (byte)opCode <= 160)
                    {
                        // Add mode to list.
                        termModes.Add(new TerminalMode(opCode, streamReader.ReadUInt32()));
                    }
                    else
                    {
                        // Undefined op code.
                        break;
                    }
                }
            }

            return termModes;
        }
        protected void ProcessMsgRequestSuccess(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            //
        }
        internal override bool ProcessMessage(byte[] payload)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Create memory stream from payload data.
            using (var msgStream = new MemoryStream(payload))
                using (var msgReader = new SshStreamReader(msgStream))
                {
                    // Check message ID.
                    SshConnectionMessage messageId = (SshConnectionMessage)msgReader.ReadByte();

#if DEBUG
                    if (System.Enum.IsDefined(typeof(SshConnectionMessage), messageId))
                    {
                        Debug.WriteLine(string.Format(">>> {0}", System.Enum.GetName(
                                                          typeof(SshConnectionMessage), messageId)));
                    }
#endif

                    switch (messageId)
                    {
                    // Global request messages
                    case SshConnectionMessage.GlobalRequest:
                        ProcessMsgGlobalRequest(msgReader);
                        break;

                    case SshConnectionMessage.RequestSuccess:
                        ProcessMsgRequestSuccess(msgReader);
                        break;

                    case SshConnectionMessage.RequestFailure:
                        ProcessMsgRequestFailure(msgReader);
                        break;

                    // Channel messages
                    case SshConnectionMessage.ChannelOpen:
                        ProcessMsgChannelOpen(msgReader);
                        break;

                    case SshConnectionMessage.ChannelOpenConfirmation:
                        ProcessMsgChannelOpenConfirmation(msgReader);
                        break;

                    case SshConnectionMessage.ChannelOpenFailure:
                        ProcessMsgChannelOpenFailure(msgReader);
                        break;

                    case SshConnectionMessage.ChannelEof:
                        ProcessMsgChannelEof(msgReader);
                        break;

                    case SshConnectionMessage.ChannelClose:
                        ProcessMsgChannelClose(msgReader);
                        break;

                    case SshConnectionMessage.ChannelRequest:
                        ProcessMsgChannelRequest(msgReader);
                        break;

                    case SshConnectionMessage.ChannelWindowAdjust:
                        ProcessMsgChannelWindowAdjust(msgReader);
                        break;

                    case SshConnectionMessage.ChannelData:
                        ProcessMsgChannelData(msgReader);
                        break;

                    case SshConnectionMessage.ChannelExtendedData:
                        ProcessMsgChannelExtendedData(msgReader);
                        break;

                    // Unrecognised message
                    default:
                        return(false);
                    }
                }

            // Message was recognised.
            return(true);
        }
Пример #29
0
        protected internal virtual void ProcessRequest(string requestType, bool wantReply, SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            switch (requestType)
            {
                case "signal":
                    // Process signal.
                    ProcessSignal(msgReader.ReadString());

                    if (wantReply) _connService.SendMsgChannelSuccess(this);
                    return;
                default:
                    // Unrecognised request type.
                    break;
            }

            // Request has failed.
            if (wantReply) _connService.SendMsgChannelFailure(this);
        }
        protected void ProcessMsgChannelOpen(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Read channel information.
            string channelType = msgReader.ReadString();
            uint senderChannel = msgReader.ReadUInt32();
            uint initialWindowSize = msgReader.ReadUInt32();
            uint maxPacketSize = msgReader.ReadUInt32();

            // Check channel type.
            switch (channelType)
            {
                default:
                    // Raise event to request channel.
                    var channelRequestedEventArgs = new ChannelOpenRequestEventArgs(senderChannel,
                        (uint)_channels.Count, channelType, initialWindowSize, maxPacketSize);

                    if (ChannelOpenRequest != null) ChannelOpenRequest(this, channelRequestedEventArgs);

                    var channel = channelRequestedEventArgs.Channel;

                    // Check if channel was created.
                    if (channel != null)
                    {
                        channel.Opened += new EventHandler<EventArgs>(channel_Opened);
                        channel.Closed += new EventHandler<EventArgs>(channel_Closed);
                        channel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(
                            channel_PropertyChanged);
                        channel.Open(this);

                        _channels.Add(channel);

                        // Send confirmation message.
                        SendMsgChannelOpenConfirmation(channel);
                    }
                    else
                    {
                        string failureDescription = channelRequestedEventArgs.FailureDescription;

                        if (failureDescription != null)
                        {
                            // Create description of failure from reason code.
                            switch (channelRequestedEventArgs.FailureReason)
                            {
                                case SshChannelOpenFailureReason.AdministrativelyProhibited:
                                    failureDescription = "Administratively prohibited.";
                                    break;
                                case SshChannelOpenFailureReason.ConnectFailed:
                                    failureDescription = "Connect attempt failed.";
                                    break;
                                case SshChannelOpenFailureReason.UnknownChannelType:
                                    failureDescription = string.Format("Unknown channel type '{0}'.",
                                        channelType);
                                    break;
                                case SshChannelOpenFailureReason.ResourceShortage:
                                    failureDescription = "Resource shortage on server.";
                                    break;
                            }
                        }

                        // Channel open request has failed.
                        SendMsgChannelOpenFailure(channel, channelRequestedEventArgs.FailureReason,
                            failureDescription, "");
                        return;
                    }

                    break;
            }
        }
        protected internal override void ProcessRequest(string requestType, bool wantReply,
                                                        SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            switch (requestType)
            {
            case "pty-req":
                // Read information about pseudo-terminal.
                var termEnvVar       = msgReader.ReadString();
                var termCharsWidth   = msgReader.ReadUInt32();
                var termCharsHeight  = msgReader.ReadUInt32();
                var termPixelsWidth  = msgReader.ReadUInt32();
                var termPixelsHeight = msgReader.ReadUInt32();
                var termModes        = ReadTerminalModes(msgReader.ReadByteString());

                // Raise event to request pseudo terminal.
                var pseudoTerminalRequestedEventArgs = new PseudoTerminalRequestedEventArgs(termEnvVar);

                OnPseudoTerminalRequested(pseudoTerminalRequestedEventArgs);

                // Check if request to allocate pseudo terminal failed.
                if (!pseudoTerminalRequestedEventArgs.Success)
                {
                    break;
                }

                _termEnvVar       = termEnvVar;
                _termCharsWidth   = termCharsWidth;
                _termCharsHeight  = termCharsHeight;
                _termPixelsWidth  = termPixelsWidth;
                _termPixelsHeight = termPixelsHeight;
                _termModes        = termModes;

                // Add TERM to list of environment variables.
                _envVars.Add("TERM", _termEnvVar);

                // Raise event, pseudo terminal has been allocated.
                OnPseudoTerminalAllocated(new EventArgs());

                if (wantReply)
                {
                    _connService.SendMsgChannelSuccess(this);
                }
                return;

            case "env":
                // Read name and value of environment variable.
                var varName  = msgReader.ReadString();
                var varValue = msgReader.ReadString();

                // Add variable to list.
                _envVars.Add(varName, varValue);

                if (wantReply)
                {
                    _connService.SendMsgChannelSuccess(this);
                }
                return;

            case "shell":
                // Start default shell.
                StartShell();

                if (wantReply)
                {
                    _connService.SendMsgChannelSuccess(this);
                }
                return;

            case "exec":
                // not implemented

                break;

            default:
                base.ProcessRequest(requestType, wantReply, msgReader);
                return;
            }

            // Request has failed.
            if (wantReply)
            {
                _connService.SendMsgChannelFailure(this);
            }
        }
        protected void ProcessMsgUserAuthRequest(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Read auth information.
            string userName = Encoding.UTF8.GetString(msgReader.ReadByteString());
            string serviceName = msgReader.ReadString();
            string methodName = msgReader.ReadString();

            // Store user name and service name used for this auth.
            _lastUserName = userName;
            _lastServiceName = serviceName;

            // Check if service with specified name exists.
            if (_client.Services.Count(item => item.Name == serviceName) == 0)
            {
                // Service was not found.
                _client.Disconnect(SshDisconnectReason.ServiceNotAvailable, string.Format(
                    "The service with name {0} is not supported by this server."));
                throw new DisconnectedException();
            }

            // Check method of authentication.
            switch (methodName)
            {
                case "none":
                    ProcessMsgUserAuthRequestNone(msgReader);
                    break;
                case "publickey":
                    ProcessMsgUserAuthRequestPublicKey(msgReader);
                    break;
                case "password":
                    ProcessMsgUserAuthRequestPassword(msgReader);
                    break;
                case "hostbased":
                    ProcessMsgUserAuthRequestHostBased(msgReader);
                    break;
                case "keyboard-interactive":
                    ProcessMsgUserAuthRequestKeyboardInteractive(msgReader);
                    break;
                default:
                    // Invalid auth method.
                    _client.Disconnect(false);
                    break;
            }
        }
        protected void ProcessMsgChannelOpenFailure(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            //
        }
        protected void ProcessMsgUserAuthRequestNone(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Raise event to get result of auth attempt.
            var authUserEventArgs = new AuthUserNoMethodEventArgs(_lastUserName);

            if (AuthenticateUserNoMethod != null) AuthenticateUserNoMethod(this, authUserEventArgs);

            // Check result of auth attempt.
            switch (authUserEventArgs.Result)
            {
                case AuthenticationResult.Success:
                    // Auth has succeeded.
                    AuthenticateUser(_lastServiceName);

                    break;
                case AuthenticationResult.Failure:
                    // Send list of supported auth methods.
                    SendMsgUserAuthFailure(false);

                    break;
            }
        }
        protected void ProcessMsgChannelRequest(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Read channel number and get channel object.
            uint channelNum = msgReader.ReadUInt32();
            SshChannel channel;

            try { channel = _channels.SingleOrDefault(item => item.ServerChannel == channelNum); }
            catch (InvalidOperationException) { return; }

            string requestType = msgReader.ReadString();
            bool wantReply = msgReader.ReadBoolean();

            // Let channel process request.
            channel.ProcessRequest(requestType, wantReply, msgReader);
        }
        protected void ProcessMsgUserAuthRequestPublicKey(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Raise event to specify requested auth method.
            if (AuthenticationMethodRequested != null) AuthenticationMethodRequested(this,
                new AuthMethodRequestedEventArgs(AuthenticationMethod.PublicKey));

            // Read request information.
            bool isAuthRequest = msgReader.ReadBoolean();
            string keyAlgName = msgReader.ReadString();
            byte[] keyAndCertsData = msgReader.ReadByteString();

            // Try to find public key algorithm.
            PublicKeyAlgorithm keyAlg = null;

            try
            {
                keyAlg = (PublicKeyAlgorithm)_client.PublicKeyAlgorithms.Single(item =>
                    item.Name == keyAlgName).Clone();
            }
            catch (InvalidOperationException)
            {
                // Public key algorithm is not supported.
                SendMsgUserAuthFailure(false);
            }

            // Load key and certificats data for algorithm.
            keyAlg.LoadKeyAndCertificatesData(keyAndCertsData);

            // Check if request is actual auth request or query of whether specified public key is
            // acceptable.
            if (isAuthRequest)
            {
                // Read client signature.
                var signatureData = msgReader.ReadByteString();
                var signature = keyAlg.GetSignature(signatureData);

                // Verify signature.
                var payloadData = ((MemoryStream)msgReader.BaseStream).ToArray();

                if (VerifyPublicKeySignature(keyAlg, payloadData, 0, payloadData.Length -
                   signatureData.Length - 4, signature))
                {
                    // Raise event to get result of auth attempt.
                    var authUserEventArgs = new AuthUserPublicKeyEventArgs(_lastUserName,
                        keyAlg.ExportPublicKey());

                    AuthenticateUserPublicKey(this, authUserEventArgs);

                    // Check result of auth attempt.
                    switch (authUserEventArgs.Result)
                    {
                        case AuthenticationResult.Success:
                            // Auth has succeeded.
                            AuthenticateUser(_lastServiceName);

                            break;
                        case AuthenticationResult.FurtherAuthRequired:
                            // Auth has succeeded, but further auth is required.
                            SendMsgUserAuthFailure(true);

                            break;
                        case AuthenticationResult.Failure:
                            // Auth has failed.
                            SendMsgUserAuthFailure(false);

                            break;
                    }
                }
                else
                {
                    // Signature is invalid.
                    SendMsgUserAuthFailure(false);
                }
            }
            else
            {
                // Public key is acceptable.
                SendMsgUserAuthPkOk(keyAlgName, keyAndCertsData);
            }
        }
        protected void ProcessMsgChannelWindowAdjust(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Read channel number and get channel object.
            uint channelNum = msgReader.ReadUInt32();
            SshChannel channel;

            try { channel = _channels.SingleOrDefault(item => item.ServerChannel == channelNum); }
            catch (InvalidOperationException) { return; }

            // Let channel adjust window size.
            var bytesToAdd = msgReader.ReadUInt32();

            channel.ProcessWindowAdjust(bytesToAdd);
        }
        protected void ProcessMsgGlobalRequest(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Read request information.
            string requestName = msgReader.ReadString();
            bool wantReply = msgReader.ReadBoolean();

            switch (requestName)
            {
                case "tcpip-forward":
                    throw new NotImplementedException();

                    //if (wantReply) SendMsgRequestSuccess(null);

                    //return;
                default:
                    // Unrecognised request type.
                    break;
            }

            // Request has failed.
            if (wantReply) SendMsgRequestFailure();
        }
        protected internal virtual void ProcessRequest(string requestType, bool wantReply, SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            switch (requestType)
            {
            case "signal":
                // Process signal.
                ProcessSignal(msgReader.ReadString());

                if (wantReply)
                {
                    _connService.SendMsgChannelSuccess(this);
                }
                return;

            default:
                // Unrecognised request type.
                break;
            }

            // Request has failed.
            if (wantReply)
            {
                _connService.SendMsgChannelFailure(this);
            }
        }