- (djm) Merge OpenBSD changes:
   - markus@cvs.openbsd.org  2000/11/06 16:04:56
     [channels.c channels.h clientloop.c nchan.c serverloop.c]
     [session.c ssh.c]
     agent forwarding and -R for ssh2, based on work from
     jhuuskon@messi.uku.fi
   - markus@cvs.openbsd.org  2000/11/06 16:13:27
     [ssh.c sshconnect.c sshd.c]
     do not disabled rhosts(rsa) if server port > 1024; from
     pekkas@netcore.fi
   - markus@cvs.openbsd.org  2000/11/06 16:16:35
     [sshconnect.c]
     downgrade client to 1.3 if server is 1.4; help from mdb@juniper.net
   - markus@cvs.openbsd.org  2000/11/09 18:04:40
     [auth1.c]
     typo; from mouring@pconline.com
   - markus@cvs.openbsd.org  2000/11/12 12:03:28
     [ssh-agent.c]
     off-by-one when removing a key from the agent
   - markus@cvs.openbsd.org  2000/11/12 12:50:39
     [auth-rh-rsa.c auth2.c authfd.c authfd.h]
     [authfile.c hostfile.c kex.c kex.h key.c key.h myproposal.h]
     [readconf.c readconf.h rsa.c rsa.h servconf.c servconf.h ssh-add.c]
     [ssh-agent.c ssh-keygen.1 ssh-keygen.c ssh.1 ssh.c ssh_config]
     [sshconnect1.c sshconnect2.c sshd.8 sshd.c sshd_config ssh-dss.c]
     [ssh-dss.h ssh-rsa.c ssh-rsa.h dsa.c dsa.h]
     add support for RSA to SSH2.  please test.
     there are now 3 types of keys: RSA1 is used by ssh-1 only,
     RSA and DSA are used by SSH2.
     you can use 'ssh-keygen -t rsa -f ssh2_rsa_file' to generate RSA
     keys for SSH2 and use the RSA keys for hostkeys or for user keys.
     SSH2 RSA or DSA keys are added to .ssh/authorised_keys2 as before.
 - (djm) Fix up Makefile and Redhat init script to create RSA host keys
 - (djm) Change to interim version
diff --git a/ssh.c b/ssh.c
index 429d571..ab32e3b 100644
--- a/ssh.c
+++ b/ssh.c
@@ -39,11 +39,12 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: ssh.c,v 1.69 2000/10/27 07:32:19 markus Exp $");
+RCSID("$OpenBSD: ssh.c,v 1.72 2000/11/12 19:50:38 markus Exp $");
 
 #include <openssl/evp.h>
 #include <openssl/dsa.h>
 #include <openssl/rsa.h>
+#include <openssl/err.h>
 
 #include "xmalloc.h"
 #include "ssh.h"
@@ -218,8 +219,9 @@
 	exit(1);
 }
 
-int ssh_session(void);
-int ssh_session2(void);
+int	ssh_session(void);
+int	ssh_session2(void);
+int	guess_identity_file_type(const char *filename);
 
 /*
  * Main program for the ssh client.
@@ -370,14 +372,13 @@
 		case 'i':
 			if (stat(optarg, &st) < 0) {
 				fprintf(stderr, "Warning: Identity file %s does not exist.\n",
-					optarg);
+				    optarg);
 				break;
 			}
 			if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES)
 				fatal("Too many identity files specified (max %d)",
-				      SSH_MAX_IDENTITY_FILES);
-			options.identity_files[options.num_identity_files++] =
-				xstrdup(optarg);
+				    SSH_MAX_IDENTITY_FILES);
+			options.identity_files[options.num_identity_files++] = xstrdup(optarg);
 			break;
 		case 't':
 			tty_flag = 1;
@@ -487,6 +488,7 @@
 		usage();
 
 	SSLeay_add_all_algorithms();
+	ERR_load_crypto_strings();
 
 	/* Initialize the command to execute on remote host. */
 	buffer_init(&command);
@@ -563,20 +565,6 @@
 	/* reinit */
 	log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
 
-	/* check if RSA support exists */
-	if ((options.protocol & SSH_PROTO_1) &&
-	    rsa_alive() == 0) {
-		log("%s: no RSA support in libssl and libcrypto.  See ssl(8).",
-		    __progname);
-		log("Disabling protocol version 1");
-		options.protocol &= ~ (SSH_PROTO_1|SSH_PROTO_1_PREFERRED);
-	}
-	if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) {
-		fprintf(stderr, "%s: No protocol version available.\n",
-		    __progname);
- 		exit(1);
-	}
-
 	if (options.user == NULL)
 		options.user = xstrdup(pw->pw_name);
 
@@ -589,6 +577,8 @@
 	if (!options.use_privileged_port) {
 #else
 	if (original_effective_uid != 0 || !options.use_privileged_port) {
+		debug("Rhosts Authentication methods disabled, "
+		    "originating port will not be trusted.");
 #endif
 		options.rhosts_authentication = 0;
 		options.rhosts_rsa_authentication = 0;
@@ -635,7 +625,7 @@
 	if (ok && (options.protocol & SSH_PROTO_1)) {
 		Key k;
 		host_private_key = RSA_new();
-		k.type = KEY_RSA;
+		k.type = KEY_RSA1;
 		k.rsa = host_private_key;
 		if (load_private_key(HOST_KEY_FILE, "", &k, NULL))
 			host_private_key_loaded = 1;
@@ -682,23 +672,23 @@
 		}
 		exit(1);
 	}
-	/* Expand ~ in options.identity_files. */
+	/* Expand ~ in options.identity_files, known host file names. */
 	/* XXX mem-leaks */
-	for (i = 0; i < options.num_identity_files; i++)
+	for (i = 0; i < options.num_identity_files; i++) {
 		options.identity_files[i] =
-			tilde_expand_filename(options.identity_files[i], original_real_uid);
-	for (i = 0; i < options.num_identity_files2; i++)
-		options.identity_files2[i] =
-			tilde_expand_filename(options.identity_files2[i], original_real_uid);
-	/* Expand ~ in known host file names. */
-	options.system_hostfile = tilde_expand_filename(options.system_hostfile,
-	    original_real_uid);
-	options.user_hostfile = tilde_expand_filename(options.user_hostfile,
-	    original_real_uid);
-	options.system_hostfile2 = tilde_expand_filename(options.system_hostfile2,
-	    original_real_uid);
-	options.user_hostfile2 = tilde_expand_filename(options.user_hostfile2,
-	    original_real_uid);
+		    tilde_expand_filename(options.identity_files[i], original_real_uid);
+		options.identity_files_type[i] = guess_identity_file_type(options.identity_files[i]);
+		debug("identity file %s type %d", options.identity_files[i],
+		    options.identity_files_type[i]);
+	}
+	options.system_hostfile =
+	    tilde_expand_filename(options.system_hostfile, original_real_uid);
+	options.user_hostfile =
+	    tilde_expand_filename(options.user_hostfile, original_real_uid);
+	options.system_hostfile2 =
+	    tilde_expand_filename(options.system_hostfile2, original_real_uid);
+	options.user_hostfile2 =
+	    tilde_expand_filename(options.user_hostfile2, original_real_uid);
 
 	/* Log into the remote system.  This never returns if the login fails. */
 	ssh_login(host_private_key_loaded, host_private_key,
@@ -752,16 +742,57 @@
 	}
 }
 
+void
+ssh_init_forwarding(void)
+{
+	int i;
+	/* Initiate local TCP/IP port forwardings. */
+	for (i = 0; i < options.num_local_forwards; i++) {
+		debug("Connections to local port %d forwarded to remote address %.200s:%d",
+		    options.local_forwards[i].port,
+		    options.local_forwards[i].host,
+		    options.local_forwards[i].host_port);
+		channel_request_local_forwarding(
+		    options.local_forwards[i].port,
+		    options.local_forwards[i].host,
+		    options.local_forwards[i].host_port,
+		    options.gateway_ports);
+	}
+
+	/* Initiate remote TCP/IP port forwardings. */
+	for (i = 0; i < options.num_remote_forwards; i++) {
+		debug("Connections to remote port %d forwarded to local address %.200s:%d",
+		    options.remote_forwards[i].port,
+		    options.remote_forwards[i].host,
+		    options.remote_forwards[i].host_port);
+		channel_request_remote_forwarding(
+		    options.remote_forwards[i].port,
+		    options.remote_forwards[i].host,
+		    options.remote_forwards[i].host_port);
+	}
+}
+
+void
+check_agent_present(void)
+{
+	if (options.forward_agent) {
+		/* Clear agent forwarding if we don\'t have an agent. */
+		int authfd = ssh_get_authentication_socket();
+		if (authfd < 0)
+			options.forward_agent = 0;
+		else
+			ssh_close_authentication_socket(authfd);
+	}
+}
+
 int
 ssh_session(void)
 {
 	int type;
-	int i;
 	int plen;
 	int interactive = 0;
 	int have_tty = 0;
 	struct winsize ws;
-	int authfd;
 	char *cp;
 
 	/* Enable compression if requested. */
@@ -845,14 +876,10 @@
 	/* Tell the packet module whether this is an interactive session. */
 	packet_set_interactive(interactive, options.keepalives);
 
-	/* Clear agent forwarding if we don\'t have an agent. */
-	authfd = ssh_get_authentication_socket();
-	if (authfd < 0)
-		options.forward_agent = 0;
-	else
-		ssh_close_authentication_socket(authfd);
 
 	/* Request authentication agent forwarding if appropriate. */
+	check_agent_present();
+
 	if (options.forward_agent) {
 		debug("Requesting authentication agent forwarding.");
 		auth_request_forwarding();
@@ -863,28 +890,9 @@
 		if (type != SSH_SMSG_SUCCESS)
 			log("Warning: Remote host denied authentication agent forwarding.");
 	}
-	/* Initiate local TCP/IP port forwardings. */
-	for (i = 0; i < options.num_local_forwards; i++) {
-		debug("Connections to local port %d forwarded to remote address %.200s:%d",
-		      options.local_forwards[i].port,
-		      options.local_forwards[i].host,
-		      options.local_forwards[i].host_port);
-		channel_request_local_forwarding(options.local_forwards[i].port,
-						 options.local_forwards[i].host,
-						 options.local_forwards[i].host_port,
-						 options.gateway_ports);
-	}
 
-	/* Initiate remote TCP/IP port forwardings. */
-	for (i = 0; i < options.num_remote_forwards; i++) {
-		debug("Connections to remote port %d forwarded to local address %.200s:%d",
-		      options.remote_forwards[i].port,
-		      options.remote_forwards[i].host,
-		      options.remote_forwards[i].host_port);
-		channel_request_remote_forwarding(options.remote_forwards[i].port,
-						  options.remote_forwards[i].host,
-						  options.remote_forwards[i].host_port);
-	}
+	/* Initiate port forwardings. */
+	ssh_init_forwarding();
 
 	/* If requested, let ssh continue in the background. */
 	if (fork_after_authentication_flag)
@@ -915,27 +923,10 @@
 	return client_loop(have_tty, tty_flag ? options.escape_char : -1, 0);
 }
 
-void
-init_local_fwd(void)
-{
-	int i;
-	/* Initiate local TCP/IP port forwardings. */
-	for (i = 0; i < options.num_local_forwards; i++) {
-		debug("Connections to local port %d forwarded to remote address %.200s:%d",
-		      options.local_forwards[i].port,
-		      options.local_forwards[i].host,
-		      options.local_forwards[i].host_port);
-		channel_request_local_forwarding(options.local_forwards[i].port,
-						 options.local_forwards[i].host,
-						 options.local_forwards[i].host_port,
-						 options.gateway_ports);
-	}
-}
-
 extern void client_set_session_ident(int id);
 
 void
-client_init(int id, void *arg)
+ssh_session2_callback(int id, void *arg)
 {
 	int len;
 	debug("client_init id %d arg %d", id, (int)arg);
@@ -974,6 +965,13 @@
 		/* XXX wait for reply */
 	}
 
+	check_agent_present();
+	if (options.forward_agent) {
+		debug("Requesting authentication agent forwarding.");
+		channel_request_start(id, "auth-agent-req@openssh.com", 0);
+		packet_send();
+	}
+
 	len = buffer_len(&command);
 	if (len > 0) {
 		if (len > 900)
@@ -1016,8 +1014,8 @@
 	if (!isatty(err))
 		set_nonblock(err);
 
-	/* should be pre-session */
-	init_local_fwd();
+	/* XXX should be pre-session */
+	ssh_init_forwarding();
 	
 	/* If requested, let ssh continue in the background. */
 	if (fork_after_authentication_flag)
@@ -1036,7 +1034,28 @@
 	    xstrdup("client-session"), /*nonblock*/0);
 
 	channel_open(id);
-	channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, client_init, (void *)0);
+	channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,
+	     ssh_session2_callback, (void *)0);
 
 	return client_loop(tty_flag, tty_flag ? options.escape_char : -1, id);
 }
+
+int
+guess_identity_file_type(const char *filename)
+{
+	struct stat st;
+	Key *public;
+	int type = KEY_RSA1; /* default */
+
+	if (stat(filename, &st) < 0) {
+		perror(filename);
+		return KEY_UNSPEC;
+	}
+	public = key_new(type);
+	if (!load_public_key(filename, public, NULL)) {
+		/* ok, so we will assume this is 'some' key */
+		type = KEY_UNSPEC;
+	}
+	key_free(public);
+	return type;
+}