//synchronous reception internal DataFragment ReceivePacket() { while(true) { DataFragment data = _packetReceiver.WaitResponse(); PacketType pt = (PacketType)data.ByteAt(0); //sneak //filter unnecessary packet if(pt==PacketType.SSH_MSG_IGNORE) { SSH2DataReader r = new SSH2DataReader(data); r.ReadPacketType(); //skip byte[] msg = r.ReadString(); if(_eventReceiver!=null) _eventReceiver.OnIgnoreMessage(msg); TraceReceptionEvent(pt, msg); } else if(pt==PacketType.SSH_MSG_DEBUG) { SSH2DataReader r = new SSH2DataReader(data); r.ReadPacketType(); //skip bool f = r.ReadBool(); byte[] msg = r.ReadString(); if(_eventReceiver!=null) _eventReceiver.OnDebugMessage(f, msg); TraceReceptionEvent(pt, msg); } else { return data; } } }
private void ProcessChannelLocalData(ISSHChannelEventReceiver receiver, PacketType pt, SSH2DataReader re) { switch(pt) { case PacketType.SSH_MSG_CHANNEL_DATA: { int len = re.ReadInt32(); receiver.OnData(re.Image, re.Offset, len); } break; case PacketType.SSH_MSG_CHANNEL_EXTENDED_DATA: { int t = re.ReadInt32(); byte[] data = re.ReadString(); receiver.OnExtendedData(t, data); } break; case PacketType.SSH_MSG_CHANNEL_REQUEST: { string request = Encoding.ASCII.GetString(re.ReadString()); bool reply = re.ReadBool(); if(request=="exit-status") { int status = re.ReadInt32(); } else if(reply) { //we reject unknown requests including keep-alive check SSH2DataWriter wr = new SSH2DataWriter(); wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_FAILURE); wr.Write(_remoteID); TransmitPayload(wr.ToByteArray()); } } break; case PacketType.SSH_MSG_CHANNEL_EOF: receiver.OnChannelEOF(); break; case PacketType.SSH_MSG_CHANNEL_CLOSE: _connection.ChannelCollection.UnregisterChannelEventReceiver(_localID); receiver.OnChannelClosed(); break; case PacketType.SSH_MSG_CHANNEL_FAILURE: receiver.OnMiscPacket((byte)pt, re.Image, re.Offset, re.Rest); break; default: receiver.OnMiscPacket((byte)pt, re.Image, re.Offset, re.Rest); Debug.WriteLine("Unknown Packet "+pt); break; } }
private AuthenticationResult ProcessAuthenticationResponse() { do { SSH2DataReader response = new SSH2DataReader(ReceivePacket()); PacketType h = response.ReadPacketType(); if(h==PacketType.SSH_MSG_USERAUTH_FAILURE) { string msg = Encoding.ASCII.GetString(response.ReadString()); TraceReceptionEvent(h, "user authentication failed:" + msg); return AuthenticationResult.Failure; } else if(h==PacketType.SSH_MSG_USERAUTH_BANNER) { TraceReceptionEvent(h, ""); } else if(h==PacketType.SSH_MSG_USERAUTH_SUCCESS) { TraceReceptionEvent(h, "user authentication succeeded"); _packetBuilder.InnerHandler = new CallbackSSH2PacketHandler(this); return AuthenticationResult.Success; //successfully exit } else if(h==PacketType.SSH_MSG_USERAUTH_INFO_REQUEST) { string name = Encoding.ASCII.GetString(response.ReadString()); string inst = Encoding.ASCII.GetString(response.ReadString()); string lang = Encoding.ASCII.GetString(response.ReadString()); int num = response.ReadInt32(); string[] prompts = new string[num]; for(int i=0; i<num; i++) { prompts[i] = Encoding.ASCII.GetString(response.ReadString()); 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 ProcessKEXINIT(DataFragment packet) { SSH2DataReader re = null; do { _serverKEXINITPayload = packet.ToNewArray(); re = new SSH2DataReader(_serverKEXINITPayload); byte[] head = re.Read(17); //Type and cookie PacketType pt = (PacketType)head[0]; if(pt==PacketType.SSH_MSG_KEXINIT) break; //successfully exit else if(pt==PacketType.SSH_MSG_IGNORE || pt==PacketType.SSH_MSG_DEBUG) { //continue packet = _connection.ReceivePacket(); } else throw new SSHException(String.Format("Server response is not SSH_MSG_KEXINIT but {0}", head[0])); } while(true); Encoding enc = Encoding.ASCII; string kex = enc.GetString(re.ReadString()); _cInfo._supportedKEXAlgorithms = kex; CheckAlgorithmSupport("keyexchange", kex, "diffie-hellman-group1-sha1"); string host_key = enc.GetString(re.ReadString()); _cInfo._supportedHostKeyAlgorithms = host_key; _cInfo._algorithmForHostKeyVerification = DecideHostKeyAlgorithm(host_key); string enc_cs = enc.GetString(re.ReadString()); _cInfo._supportedCipherAlgorithms = enc_cs; _cInfo._algorithmForTransmittion = DecideCipherAlgorithm(enc_cs); string enc_sc = enc.GetString(re.ReadString()); _cInfo._algorithmForReception = DecideCipherAlgorithm(enc_sc); string mac_cs = enc.GetString(re.ReadString()); CheckAlgorithmSupport("mac", mac_cs, "hmac-sha1"); string mac_sc = enc.GetString(re.ReadString()); CheckAlgorithmSupport("mac", mac_sc, "hmac-sha1"); string comp_cs = enc.GetString(re.ReadString()); CheckAlgorithmSupport("compression", comp_cs, "none"); string comp_sc = enc.GetString(re.ReadString()); CheckAlgorithmSupport("compression", comp_sc, "none"); string lang_cs = enc.GetString(re.ReadString()); string lang_sc = enc.GetString(re.ReadString()); bool flag = re.ReadBool(); int reserved = re.ReadInt32(); Debug.Assert(re.Rest==0); if(_connection.IsEventTracerAvailable) { StringBuilder bld = new StringBuilder(); bld.Append("kex_algorithm="); bld.Append(kex); bld.Append("; server_host_key_algorithms="); bld.Append(host_key); bld.Append("; encryption_algorithms_client_to_server="); bld.Append(enc_cs); bld.Append("; encryption_algorithms_server_to_client="); bld.Append(enc_sc); bld.Append("; mac_algorithms_client_to_server="); bld.Append(mac_cs); bld.Append("; mac_algorithms_server_to_client="); bld.Append(mac_sc); bld.Append("; comression_algorithms_client_to_server="); bld.Append(comp_cs); bld.Append("; comression_algorithms_server_to_client="); bld.Append(comp_sc); TraceReceptionNegotiation(PacketType.SSH_MSG_KEXINIT, bld.ToString()); } if(flag) throw new SSHException("Algorithm negotiation failed"); }
/// <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 void ProcessChannelLocalData(ISSHChannelEventReceiver receiver, SSH2PacketType pt, SSH2DataReader re) { switch (pt) { case SSH2PacketType.SSH_MSG_CHANNEL_DATA: { int len = re.ReadInt32(); DataFragment frag = re.GetRemainingDataView(len); receiver.OnData(frag.Data, frag.Offset, frag.Length); } break; case SSH2PacketType.SSH_MSG_CHANNEL_EXTENDED_DATA: { int t = re.ReadInt32(); byte[] data = re.ReadByteString(); receiver.OnExtendedData(t, data); } break; case SSH2PacketType.SSH_MSG_CHANNEL_REQUEST: { string request = re.ReadString(); bool reply = re.ReadBool(); if (request == "exit-status") { int status = re.ReadInt32(); } else if (reply) { //we reject unknown requests including keep-alive check Transmit( 0, new SSH2Packet(SSH2PacketType.SSH_MSG_CHANNEL_FAILURE) .WriteInt32(_remoteID) ); } } break; case SSH2PacketType.SSH_MSG_CHANNEL_EOF: receiver.OnChannelEOF(); break; case SSH2PacketType.SSH_MSG_CHANNEL_CLOSE: _connection.ChannelCollection.UnregisterChannelEventReceiver(_localID); receiver.OnChannelClosed(); break; case SSH2PacketType.SSH_MSG_CHANNEL_FAILURE: { DataFragment frag = re.GetRemainingDataView(); receiver.OnMiscPacket((byte)pt, frag.Data, frag.Offset, frag.Length); } break; default: { DataFragment frag = re.GetRemainingDataView(); receiver.OnMiscPacket((byte)pt, frag.Data, frag.Offset, frag.Length); } Debug.WriteLine("Unknown Packet " + pt); break; } }
private void ProcessKEXINIT(DataFragment packet) { SSH2DataReader re = null; do { _serverKEXINITPayload = packet.GetBytes(); re = new SSH2DataReader(_serverKEXINITPayload); byte[] head = re.Read(17); //Type and cookie SSH2PacketType pt = (SSH2PacketType)head[0]; if (pt == SSH2PacketType.SSH_MSG_KEXINIT) break; //successfully exit if (pt == SSH2PacketType.SSH_MSG_IGNORE || pt == SSH2PacketType.SSH_MSG_DEBUG) { //continue packet = _connection.ReceivePacket(); } else { throw new SSHException(String.Format("Server response is not SSH_MSG_KEXINIT but {0}", head[0])); } } while (true); string kex = re.ReadString(); _cInfo.SupportedKEXAlgorithms = kex; _cInfo.KEXAlgorithm = DecideKexAlgorithm(kex); string host_key = re.ReadString(); _cInfo.SupportedHostKeyAlgorithms = host_key; _cInfo.HostKeyAlgorithm = DecideHostKeyAlgorithm(host_key); string enc_cs = re.ReadString(); _cInfo.SupportedEncryptionAlgorithmsClientToServer = enc_cs; _cInfo.OutgoingPacketCipher = DecideCipherAlgorithm(enc_cs); string enc_sc = re.ReadString(); _cInfo.SupportedEncryptionAlgorithmsServerToClient = enc_sc; _cInfo.IncomingPacketCipher = DecideCipherAlgorithm(enc_sc); string mac_cs = re.ReadString(); CheckAlgorithmSupport("mac", mac_cs, "hmac-sha1"); string mac_sc = re.ReadString(); CheckAlgorithmSupport("mac", mac_sc, "hmac-sha1"); string comp_cs = re.ReadString(); CheckAlgorithmSupport("compression", comp_cs, "none"); string comp_sc = re.ReadString(); CheckAlgorithmSupport("compression", comp_sc, "none"); string lang_cs = re.ReadString(); string lang_sc = re.ReadString(); bool flag = re.ReadBool(); int reserved = re.ReadInt32(); Debug.Assert(re.RemainingDataLength == 0); if (_connection.IsEventTracerAvailable) { StringBuilder bld = new StringBuilder(); bld.Append("kex_algorithm="); bld.Append(kex); bld.Append("; server_host_key_algorithms="); bld.Append(host_key); bld.Append("; encryption_algorithms_client_to_server="); bld.Append(enc_cs); bld.Append("; encryption_algorithms_server_to_client="); bld.Append(enc_sc); bld.Append("; mac_algorithms_client_to_server="); bld.Append(mac_cs); bld.Append("; mac_algorithms_server_to_client="); bld.Append(mac_sc); bld.Append("; comression_algorithms_client_to_server="); bld.Append(comp_cs); bld.Append("; comression_algorithms_server_to_client="); bld.Append(comp_sc); TraceReceptionNegotiation(SSH2PacketType.SSH_MSG_KEXINIT, bld.ToString()); } if (flag) throw new SSHException("Algorithm negotiation failed"); }