148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood/*
248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Please refer to the LICENSE.txt for licensing details.
448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */
548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodpackage ch.ethz.ssh2.transport;
648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.io.IOException;
848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.io.InputStream;
948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.io.OutputStream;
1048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
1148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.util.StringEncoder;
1248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
1348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood/**
1448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * ClientServerHello.
1548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood *
1648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * @author Christian Plattner
1748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * @version $Id: ClientServerHello.java 33 2011-05-28 21:59:37Z dkocher@sudo.ch $
1848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */
1948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodpublic class ClientServerHello
2048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood{
2148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	String server_line;
2248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	String client_line;
2348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
2448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	String server_versioncomment;
2548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
2648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public static int readLineRN(InputStream is, byte[] buffer) throws IOException
2748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
2848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int pos = 0;
2948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		boolean need10 = false;
3048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int len = 0;
3148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		while (true)
3248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
3348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			int c = is.read();
3448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			if (c == -1)
3548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				throw new IOException("Premature connection close");
3648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
3748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			buffer[pos++] = (byte) c;
3848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
3948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			if (c == 13)
4048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			{
4148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				need10 = true;
4248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				continue;
4348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			}
4448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
4548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			if (c == 10)
4648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				break;
4748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
4848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			if (need10 == true)
4948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				throw new IOException("Malformed line sent by the server, the line does not end correctly.");
5048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
5148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			len++;
5248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			if (pos >= buffer.length)
5348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				throw new IOException("The server sent a too long line.");
5448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
5548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
5648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		return len;
5748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
5848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
5948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public ClientServerHello(String identification, InputStream bi, OutputStream bo) throws IOException
6048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
6148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		client_line = "SSH-2.0-" + identification;
6248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
6348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		bo.write(StringEncoder.GetBytes(client_line + "\r\n"));
6448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		bo.flush();
6548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
6648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		byte[] serverVersion = new byte[512];
6748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
6848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		for (int i = 0; i < 50; i++)
6948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
7048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			int len = readLineRN(bi, serverVersion);
7148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
7248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			server_line = StringEncoder.GetString(serverVersion, 0, len);
7348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
7448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			if (server_line.startsWith("SSH-"))
7548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				break;
7648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
7748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
7848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (server_line.startsWith("SSH-") == false)
7948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			throw new IOException(
8048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood					"Malformed server identification string. There was no line starting with 'SSH-' amongst the first 50 lines.");
8148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
8248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (server_line.startsWith("SSH-1.99-"))
8348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			server_versioncomment = server_line.substring(9);
8448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		else if (server_line.startsWith("SSH-2.0-"))
8548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			server_versioncomment = server_line.substring(8);
8648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		else
8748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			throw new IOException("Server uses incompatible protocol, it is not SSH-2 compatible.");
8848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
8948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
9048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	/**
9148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	 * @return Returns the client_versioncomment.
9248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	 */
9348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public byte[] getClientString()
9448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
9548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		return StringEncoder.GetBytes(client_line);
9648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
9748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
9848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	/**
9948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	 * @return Returns the server_versioncomment.
10048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	 */
10148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public byte[] getServerString()
10248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
10348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		return StringEncoder.GetBytes(server_line);
10448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
10548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood}
106