/// <summary> /// Process packet about this channel. /// </summary> /// <param name="packetType">a packet type (message number)</param> /// <param name="packetFragment">a packet image except message number and recipient channel.</param> public void ProcessPacket(SSH2PacketType packetType, DataFragment packetFragment) { if (_state == State.Closed) { return; // ignore } DataFragment dataFragmentArg; uint dataTypeCodeArg; lock (_stateSync) { switch (_state) { case State.InitiatedByServer: break; case State.InitiatedByClient: if (packetType == SSH2PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) { SSH2DataReader reader = new SSH2DataReader(packetFragment); RemoteChannel = reader.ReadUInt32(); _serverWindowSizeLeft = reader.ReadUInt32(); _serverMaxPacketSize = reader.ReadUInt32(); _state = State.Established; Monitor.PulseAll(_stateSync); // notifies state change dataFragmentArg = reader.GetRemainingDataView(); goto OnEstablished; // do it out of the lock block } if (packetType == SSH2PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE) { SSH2DataReader reader = new SSH2DataReader(packetFragment); uint reasonCode = reader.ReadUInt32(); string description = reader.ReadUTF8String(); string lang = reader.ReadString(); goto RequestFailed; // do it out of the lock block } break; case State.Closing: if (packetType == SSH2PacketType.SSH_MSG_CHANNEL_CLOSE) { goto SetStateClosedByClient; // do it out of the lock block } break; case State.Established: case State.Ready: if (ProcessPacketSub(packetType, packetFragment) == SubPacketProcessResult.Consumed) { return; } switch (packetType) { case SSH2PacketType.SSH_MSG_CHANNEL_DATA: { SSH2DataReader reader = new SSH2DataReader(packetFragment); int len = reader.ReadInt32(); dataFragmentArg = reader.GetRemainingDataView(len); AdjustWindowSize(len); } goto OnData; // do it out of the lock block case SSH2PacketType.SSH_MSG_CHANNEL_EXTENDED_DATA: { SSH2DataReader reader = new SSH2DataReader(packetFragment); dataTypeCodeArg = reader.ReadUInt32(); int len = reader.ReadInt32(); dataFragmentArg = reader.GetRemainingDataView(len); AdjustWindowSize(len); } goto OnExtendedData; // do it out of the lock block case SSH2PacketType.SSH_MSG_CHANNEL_REQUEST: { SSH2DataReader reader = new SSH2DataReader(packetFragment); string request = reader.ReadString(); bool wantReply = reader.ReadBool(); if (wantReply) { //we reject unknown requests including keep-alive check Transmit( 0, new SSH2Packet(SSH2PacketType.SSH_MSG_CHANNEL_FAILURE) .WriteUInt32(RemoteChannel) ); } } break; case SSH2PacketType.SSH_MSG_CHANNEL_EOF: goto OnEOF; // do it out of the lock block case SSH2PacketType.SSH_MSG_CHANNEL_CLOSE: Transmit( 0, new SSH2Packet(SSH2PacketType.SSH_MSG_CHANNEL_CLOSE) .WriteUInt32(RemoteChannel) ); goto SetStateClosedByServer; // do it out of the lock block case SSH2PacketType.SSH_MSG_CHANNEL_WINDOW_ADJUST: { SSH2DataReader reader = new SSH2DataReader(packetFragment); uint bytesToAdd = reader.ReadUInt32(); // some servers may not send SSH_MSG_CHANNEL_WINDOW_ADJUST. // it is dangerous to wait this message in send procedure _serverWindowSizeLeft += bytesToAdd; } goto OnWindowAdjust; case SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS: case SSH2PacketType.SSH_MSG_CHANNEL_FAILURE: { _channelRequestResult.TrySet(packetType == SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS, 1000); } break; default: goto OnUnhandledPacket; } break; // case State.Ready } } return; OnEstablished: _protocolEventManager.Trace( "CH[{0}] remoteCH={1} remoteWindowSize={2} remoteMaxPacketSize={3}", LocalChannel, RemoteChannel, _serverWindowSizeLeft, _serverMaxPacketSize); _handler.OnEstablished(dataFragmentArg); OnChannelEstablished(); return; RequestFailed: _protocolEventManager.Trace("CH[{0}] request failed", LocalChannel); RequestFailed(); return; SetStateClosedByClient: _protocolEventManager.Trace("CH[{0}] closed completely", LocalChannel); SetStateClosed(false); return; SetStateClosedByServer: _protocolEventManager.Trace("CH[{0}] closed by server", LocalChannel); SetStateClosed(true); return; OnData: _handler.OnData(dataFragmentArg); return; OnExtendedData: _handler.OnExtendedData(dataTypeCodeArg, dataFragmentArg); return; OnEOF: _protocolEventManager.Trace("CH[{0}] caught EOF", LocalChannel); _handler.OnEOF(); return; OnWindowAdjust: _protocolEventManager.Trace( "CH[{0}] adjusted remote window size to {1}", LocalChannel, _serverWindowSizeLeft); return; OnUnhandledPacket: _handler.OnUnhandledPacket((byte)packetType, packetFragment); return; }
private AuthenticationResult ProcessAuthenticationResponse() { do { SSH2DataReader response = new SSH2DataReader(ReceivePacket()); SSH2PacketType h = (SSH2PacketType) response.ReadByte(); if (h == SSH2PacketType.SSH_MSG_USERAUTH_FAILURE) { string msg = response.ReadString(); TraceReceptionEvent(h, "user authentication failed:" + msg); return AuthenticationResult.Failure; } else if (h == SSH2PacketType.SSH_MSG_USERAUTH_BANNER) { TraceReceptionEvent(h, ""); } else if (h == SSH2PacketType.SSH_MSG_USERAUTH_SUCCESS) { TraceReceptionEvent(h, "user authentication succeeded"); _packetizer.SetInnerHandler(new CallbackSSH2PacketHandler(this)); return AuthenticationResult.Success; //successfully exit } else if (h == SSH2PacketType.SSH_MSG_USERAUTH_INFO_REQUEST) { string name = response.ReadUTF8String(); string inst = response.ReadUTF8String(); string lang = response.ReadString(); int num = response.ReadInt32(); string[] prompts = new string[num]; for (int i = 0; i < num; i++) { prompts[i] = response.ReadUTF8String(); bool echo = response.ReadBool(); } _eventReceiver.OnAuthenticationPrompt(prompts); _requiredResponseCount = num; return AuthenticationResult.Prompt; } else throw new SSHException("protocol error: unexpected packet type " + h); } while (true); }
private void OpenShellOrSubsystem(ISSHChannelEventReceiver receiver, SSH2PacketType pt, SSH2DataReader reader, string scheme) { if (_negotiationStatus == NegotiationStatus.WaitingChannelConfirmation) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE) receiver.OnChannelError(new SSHException("opening channel failed; packet type=" + pt)); else { int errcode = reader.ReadInt32(); string msg = reader.ReadUTF8String(); receiver.OnChannelError(new SSHException(msg)); } // Close() shouldn't be called because remote channel number is not given yet. // We just remove an event receiver from the collection of channels. // FIXME: _negotiationStatus sould be set an error status ? _connection.ChannelCollection.UnregisterChannelEventReceiver(_localID); } else { _remoteID = reader.ReadInt32(); _allowedDataSize = reader.ReadUInt32(); _serverMaxPacketSize = reader.ReadInt32(); if (_type == ChannelType.Subsystem) { OpenScheme(scheme); _negotiationStatus = NegotiationStatus.WaitingSubsystemConfirmation; } else { //open pty SSHConnectionParameter param = _connection.Param; Transmit( 0, new SSH2Packet(SSH2PacketType.SSH_MSG_CHANNEL_REQUEST) .WriteInt32(_remoteID) .WriteString("pty-req") .WriteBool(true) .WriteString(param.TerminalName) .WriteInt32(param.TerminalWidth) .WriteInt32(param.TerminalHeight) .WriteInt32(param.TerminalPixelWidth) .WriteInt32(param.TerminalPixelHeight) .WriteAsString(new byte[0]) ); if (_connection.IsEventTracerAvailable) { _connection.TraceTransmissionEvent( SSH2PacketType.SSH_MSG_CHANNEL_REQUEST, "pty-req", "terminal={0} width={1} height={2}", param.TerminalName, param.TerminalWidth, param.TerminalHeight); } _negotiationStatus = NegotiationStatus.WaitingPtyReqConfirmation; } } } else if (_negotiationStatus == NegotiationStatus.WaitingPtyReqConfirmation) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS) { receiver.OnChannelError(new SSHException("opening pty failed")); Close(); } else { //agent request (optional) if (_connection.Param.AgentForward != null) { Transmit( 0, new SSH2Packet(SSH2PacketType.SSH_MSG_CHANNEL_REQUEST) .WriteInt32(_remoteID) .WriteString("*****@*****.**") .WriteBool(true) ); _connection.TraceTransmissionEvent(SSH2PacketType.SSH_MSG_CHANNEL_REQUEST, "auth-agent-req", ""); _negotiationStatus = NegotiationStatus.WaitingAuthAgentReqConfirmation; } else { OpenScheme(scheme); _negotiationStatus = NegotiationStatus.WaitingShellConfirmation; } } } else if (_negotiationStatus == NegotiationStatus.WaitingAuthAgentReqConfirmation) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS && pt != SSH2PacketType.SSH_MSG_CHANNEL_FAILURE) { receiver.OnChannelError(new SSHException("auth-agent-req error")); Close(); } else { //auth-agent-req is optional _connection.SetAgentForwardConfirmed(pt == SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS); _connection.TraceReceptionEvent(pt, "auth-agent-req"); OpenScheme(scheme); _negotiationStatus = NegotiationStatus.WaitingShellConfirmation; } } else if (_negotiationStatus == NegotiationStatus.WaitingShellConfirmation) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS) { receiver.OnChannelError(new SSHException("Opening shell failed: packet type=" + pt.ToString())); Close(); } else { receiver.OnChannelReady(); _negotiationStatus = NegotiationStatus.Ready; //goal! } } else if (_negotiationStatus == NegotiationStatus.WaitingSubsystemConfirmation) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_SUCCESS) { receiver.OnChannelError(new SSHException("Opening subsystem failed: packet type=" + pt.ToString())); Close(); } else { receiver.OnChannelReady(); _negotiationStatus = NegotiationStatus.Ready; //goal! } } }
private void ReceivePortForwardingResponse(ISSHChannelEventReceiver receiver, SSH2PacketType pt, SSH2DataReader reader) { if (_negotiationStatus == NegotiationStatus.WaitingChannelConfirmation) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE) receiver.OnChannelError(new SSHException("opening channel failed; packet type=" + pt)); else { int errcode = reader.ReadInt32(); string msg = reader.ReadUTF8String(); receiver.OnChannelError(new SSHException(msg)); } Close(); } else { _remoteID = reader.ReadInt32(); _serverMaxPacketSize = reader.ReadInt32(); _negotiationStatus = NegotiationStatus.Ready; receiver.OnChannelReady(); } } else throw new SSHException("internal state error"); }
// sending "exec" service for SCP protocol. private void ExecCommand(ISSHChannelEventReceiver receiver, SSH2PacketType pt, SSH2DataReader reader) { if (_negotiationStatus == NegotiationStatus.WaitingChannelConfirmation) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE) receiver.OnChannelError(new SSHException("opening channel failed; packet type=" + pt)); else { int errcode = reader.ReadInt32(); string msg = reader.ReadUTF8String(); receiver.OnChannelError(new SSHException(msg)); } Close(); } else { _remoteID = reader.ReadInt32(); _allowedDataSize = reader.ReadUInt32(); _serverMaxPacketSize = reader.ReadInt32(); // exec command SSHConnectionParameter param = _connection.Param; Transmit( 0, new SSH2Packet(SSH2PacketType.SSH_MSG_CHANNEL_REQUEST) .WriteInt32(_remoteID) .WriteString("exec") // "exec" .WriteBool(false) // want confirm is disabled. (*) .WriteString(_command) ); if (_connection.IsEventTracerAvailable) _connection.TraceTransmissionEvent("exec command", "cmd={0}", _command); //confirmation is omitted receiver.OnChannelReady(); _negotiationStatus = NegotiationStatus.Ready; //goal! } } else if (_negotiationStatus == NegotiationStatus.WaitingExecCmdConfirmation) { if (pt != SSH2PacketType.SSH_MSG_CHANNEL_DATA) { receiver.OnChannelError(new SSHException("exec command failed")); Close(); } else { receiver.OnChannelReady(); _negotiationStatus = NegotiationStatus.Ready; //goal! } } else throw new SSHException("internal state error"); }