public void OnData(byte[] data, int offset, int length) { _buffer.Write(data, offset, length); int expectedLength = SSHUtil.ReadInt32(_buffer.UnderlyingBuffer, 0); if(expectedLength + 4 <= _buffer.Length) { SSH2DataReader r = new SSH2DataReader(new DataFragment(_buffer.UnderlyingBuffer, 4, _buffer.Length-4)); AgentForwadPacketType pt = (AgentForwadPacketType)r.ReadByte(); //remaining len-1 _buffer.SetOffset(0); switch(pt) { case AgentForwadPacketType.SSH2_AGENTC_REQUEST_IDENTITIES: SendKeyList(); break; case AgentForwadPacketType.SSH2_AGENTC_SIGN_REQUEST: SendSign(r); break; default: //Debug.WriteLine("Unknown agent packet " + pt.ToString()); TransmitWriter(OpenWriter(AgentForwadPacketType.SSH_AGENT_FAILURE)); break; } } }
public void OnData(byte[] data, int offset, int length) { #if DUMP_PACKET Dump("SFTP: OnData", data, offset, length); #endif DataFragment dataFragment; if (_isDataIncomplete) { // append to buffer _dataBuffer.Write(data, offset, length); if (_dataTotal == 0) { // not determined yet if (_dataBuffer.Length < 4) return; _dataTotal = SSHUtil.ReadInt32(_dataBuffer.UnderlyingBuffer, 0); } if (_dataBuffer.Length < _dataTotal) return; _isDataIncomplete = false; _dataTotal = 0; dataFragment = new DataFragment(_dataBuffer.UnderlyingBuffer, 0, (int)_dataBuffer.Length); } else { if (length < 4) { _dataBuffer.Reset(); _dataBuffer.Write(data, offset, length); _isDataIncomplete = true; _dataTotal = 0; // determine later... return; } int total = SSHUtil.ReadInt32(data, offset); if (length - 4 < total) { _dataBuffer.Reset(); _dataBuffer.Write(data, offset, length); _isDataIncomplete = true; _dataTotal = total; return; } dataFragment = new DataFragment(data, offset, length); } SSH2DataReader reader = new SSH2DataReader(dataFragment); int dataLength = reader.ReadInt32(); if (dataLength >= 1) { SFTPPacketType packetType = (SFTPPacketType)reader.ReadByte(); dataLength--; lock (ResponseNotifier) { bool processed = false; if (_responseHandler != null) { try { processed = _responseHandler(packetType, reader); } catch (Exception e) { _responseHandlerException = e; processed = true; } } else { processed = true; } if (processed) { Monitor.PulseAll(_responseNotifier); } } } // FIXME: invalid packet should be alerted }
private bool ProcessPacket(DataFragment packet) { SSH2DataReader r = new SSH2DataReader(packet); SSH2PacketType pt = (SSH2PacketType) r.ReadByte(); if (pt == SSH2PacketType.SSH_MSG_DISCONNECT) { int errorcode = r.ReadInt32(); _eventReceiver.OnConnectionClosed(); return false; } else if (_waitingForPortForwardingResponse) { if (pt != SSH2PacketType.SSH_MSG_REQUEST_SUCCESS) _eventReceiver.OnUnknownMessage((byte)pt, packet.GetBytes()); _waitingForPortForwardingResponse = false; return true; } else if (pt == SSH2PacketType.SSH_MSG_CHANNEL_OPEN) { string method = r.ReadString(); if (method == "forwarded-tcpip") ProcessPortforwardingRequest(_eventReceiver, r); else if (method.StartsWith("auth-agent")) //in most cases, method is "*****@*****.**" ProcessAgentForwardRequest(_eventReceiver, r); else { SSH2DataWriter wr = new SSH2DataWriter(); wr.WriteByte((byte)SSH2PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE); wr.WriteInt32(r.ReadInt32()); wr.WriteInt32(0); wr.WriteString("unknown method"); wr.WriteString(""); //lang tag TraceReceptionEvent("SSH_MSG_CHANNEL_OPEN rejected", "method={0}", method); } return true; } else if (pt >= SSH2PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION && pt <= SSH2PacketType.SSH_MSG_CHANNEL_FAILURE) { int local_channel = r.ReadInt32(); ChannelCollection.Entry e = this.ChannelCollection.FindChannelEntry(local_channel); if (e != null) ((SSH2Channel)e.Channel).ProcessPacket(e.Receiver, pt, r); else Debug.WriteLine("unexpected channel pt=" + pt + " local_channel=" + local_channel.ToString()); return true; } else if (pt == SSH2PacketType.SSH_MSG_IGNORE) { _eventReceiver.OnIgnoreMessage(r.ReadByteString()); return true; } else if (_asyncKeyExchanger != null) { _asyncKeyExchanger.AsyncProcessPacket(packet); return true; } else if (pt == SSH2PacketType.SSH_MSG_KEXINIT) { //Debug.WriteLine("Host sent KEXINIT"); _asyncKeyExchanger = new KeyExchanger(this, _sessionID); _asyncKeyExchanger.AsyncProcessPacket(packet); return true; } else { _eventReceiver.OnUnknownMessage((byte)pt, packet.GetBytes()); return false; } }
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); }
//synchronous reception internal DataFragment ReceivePacket() { while (true) { DataFragment data = _packetReceiver.WaitResponse(); SSH2PacketType pt = (SSH2PacketType)data[0]; //sneak //filter unnecessary packet if (pt == SSH2PacketType.SSH_MSG_IGNORE) { SSH2DataReader r = new SSH2DataReader(data); r.ReadByte(); //skip byte[] msg = r.ReadByteString(); if (_eventReceiver != null) _eventReceiver.OnIgnoreMessage(msg); TraceReceptionEvent(pt, msg); } else if (pt == SSH2PacketType.SSH_MSG_DEBUG) { SSH2DataReader r = new SSH2DataReader(data); r.ReadByte(); //skip bool f = r.ReadBool(); byte[] msg = r.ReadByteString(); if (_eventReceiver != null) _eventReceiver.OnDebugMessage(f, msg); TraceReceptionEvent(pt, msg); } else { return data; } } }
private bool ProcessKEXDHREPLY(DataFragment packet) { //Round2 receives response SSH2DataReader re = null; SSH2PacketType h; do { re = new SSH2DataReader(packet); h = (SSH2PacketType) re.ReadByte(); if (h == SSH2PacketType.SSH_MSG_KEXDH_REPLY) break; //successfully exit else if (h == SSH2PacketType.SSH_MSG_IGNORE || h == SSH2PacketType.SSH_MSG_DEBUG) { //continue packet = _connection.ReceivePacket(); } else throw new SSHException(String.Format("KeyExchange response is not KEXDH_REPLY but {0}", h)); } while (true); byte[] key_and_cert = re.ReadByteString(); BigInteger f = re.ReadMPInt(); byte[] signature = re.ReadByteString(); Debug.Assert(re.RemainingDataLength == 0); //Round3 calc hash H SSH2DataWriter wr = new SSH2DataWriter(); _k = f.ModPow(_x, GetDiffieHellmanPrime(_cInfo.KEXAlgorithm.Value)); wr = new SSH2DataWriter(); wr.WriteString(_cInfo.ClientVersionString); wr.WriteString(_cInfo.ServerVersionString); wr.WriteAsString(_clientKEXINITPayload); wr.WriteAsString(_serverKEXINITPayload); wr.WriteAsString(key_and_cert); wr.WriteBigInteger(_e); wr.WriteBigInteger(f); wr.WriteBigInteger(_k); _hash = KexComputeHash(wr.ToByteArray()); _connection.TraceReceptionEvent(h, "verifying host key"); if (!VerifyHostKey(key_and_cert, signature, _hash)) return false; //Debug.WriteLine("hash="+DebugUtil.DumpByteArray(hash)); if (_sessionID == null) _sessionID = _hash; return true; }
private void ServiceRequest(string servicename) { Transmit( new SSH2Packet(SSH2PacketType.SSH_MSG_SERVICE_REQUEST) .WriteString(servicename) ); TraceTransmissionEvent("SSH_MSG_SERVICE_REQUEST", servicename); DataFragment response = ReceivePacket(); SSH2DataReader re = new SSH2DataReader(response); SSH2PacketType t = (SSH2PacketType) re.ReadByte(); if (t != SSH2PacketType.SSH_MSG_SERVICE_ACCEPT) { TraceReceptionEvent(t.ToString(), "service request failed"); throw new SSHException("service establishment failed " + t); } string s = re.ReadString(); if (servicename != s) throw new SSHException("protocol error"); }
/// <summary> /// Wait for response. /// </summary> /// <remarks> /// <para> /// Caller should lock ResponseNotifier before send a request packet, /// and this method should be called in the lock-block. /// </para> /// </remarks> /// <param name="responseHandler">delegate which handles response data</param> /// <param name="millisecondsTimeout">timeout in milliseconds</param> /// <exception cref="SFTPClientTimeoutException">Timeout has occured.</exception> /// <exception cref="Exception">an exception which was thrown while executing responseHandler.</exception> public void WaitResponse(DataReceivedDelegate responseHandler, int millisecondsTimeout) { lock (_dataBufferSync) { bool processed = false; while (!processed) { while (_dataBuffer.Length < 4) { if (!Monitor.Wait(_dataBufferSync, millisecondsTimeout)) { throw new SFTPClientTimeoutException(); } } int totalSize = SSHUtil.ReadInt32(_dataBuffer.RawBuffer, _dataBuffer.RawBufferOffset); while (_dataBuffer.Length < 4 + totalSize) { if (!Monitor.Wait(_dataBufferSync, millisecondsTimeout)) { throw new SFTPClientTimeoutException(); } } _dataBuffer.RemoveHead(4); // length field if (totalSize >= 1) { SSH2DataReader reader = new SSH2DataReader( new DataFragment(_dataBuffer.RawBuffer, _dataBuffer.RawBufferOffset, totalSize)); SFTPPacketType packetType = (SFTPPacketType)reader.ReadByte(); if (responseHandler != null) { processed = responseHandler(packetType, reader); } else { processed = true; } } _dataBuffer.RemoveHead(totalSize); } } }