- Merge big update to OpenSSH-2.0 from OpenBSD CVS
   [README.openssh2]
   - interop w/ F-secure windows client
   - sync documentation
   - ssh_host_dsa_key not ssh_dsa_key
   [auth-rsa.c]
   - missing fclose
   [auth.c authfile.c compat.c dsa.c dsa.h hostfile.c key.c key.h radix.c]
   [readconf.c readconf.h ssh-add.c ssh-keygen.c ssh.c ssh.h sshconnect.c]
   [sshd.c uuencode.c uuencode.h authfile.h]
   - add DSA pubkey auth and other SSH2 fixes.  use ssh-keygen -[xX]
     for trading keys with the real and the original SSH, directly from the
     people who invented the SSH protocol.
   [auth.c auth.h authfile.c sshconnect.c auth1.c auth2.c sshconnect.h]
   [sshconnect1.c sshconnect2.c]
   - split auth/sshconnect in one file per protocol version
   [sshconnect2.c]
   - remove debug
   [uuencode.c]
   - add trailing =
   [version.h]
   - OpenSSH-2.0
   [ssh-keygen.1 ssh-keygen.c]
   - add -R flag: exit code indicates if RSA is alive
   [sshd.c]
   - remove unused
     silent if -Q is specified
   [ssh.h]
   - host key becomes /etc/ssh_host_dsa_key
   [readconf.c servconf.c ]
   - ssh/sshd default to proto 1 and 2
   [uuencode.c]
   - remove debug
   [auth2.c ssh-keygen.c sshconnect2.c sshd.c]
   - xfree DSA blobs
   [auth2.c serverloop.c session.c]
   - cleanup logging for sshd/2, respect PasswordAuth no
   [sshconnect2.c]
   - less debug, respect .ssh/config
   [README.openssh2 channels.c channels.h]
   - clientloop.c session.c ssh.c
   - support for x11-fwding, client+server
diff --git a/ChangeLog b/ChangeLog
index 98a5a9b..9efe31f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,47 @@
+20000429
+ - Merge big update to OpenSSH-2.0 from OpenBSD CVS
+   [README.openssh2]
+   - interop w/ F-secure windows client
+   - sync documentation
+   - ssh_host_dsa_key not ssh_dsa_key
+   [auth-rsa.c]
+   - missing fclose
+   [auth.c authfile.c compat.c dsa.c dsa.h hostfile.c key.c key.h radix.c]
+   [readconf.c readconf.h ssh-add.c ssh-keygen.c ssh.c ssh.h sshconnect.c]
+   [sshd.c uuencode.c uuencode.h authfile.h]
+   - add DSA pubkey auth and other SSH2 fixes.  use ssh-keygen -[xX]
+     for trading keys with the real and the original SSH, directly from the
+     people who invented the SSH protocol.
+   [auth.c auth.h authfile.c sshconnect.c auth1.c auth2.c sshconnect.h]
+   [sshconnect1.c sshconnect2.c]
+   - split auth/sshconnect in one file per protocol version
+   [sshconnect2.c]
+   - remove debug
+   [uuencode.c]
+   - add trailing =
+   [version.h]
+   - OpenSSH-2.0
+   [ssh-keygen.1 ssh-keygen.c]
+   - add -R flag: exit code indicates if RSA is alive
+   [sshd.c]
+   - remove unused
+     silent if -Q is specified
+   [ssh.h]
+   - host key becomes /etc/ssh_host_dsa_key
+   [readconf.c servconf.c ]
+   - ssh/sshd default to proto 1 and 2
+   [uuencode.c]
+   - remove debug
+   [auth2.c ssh-keygen.c sshconnect2.c sshd.c]
+   - xfree DSA blobs
+   [auth2.c serverloop.c session.c]
+   - cleanup logging for sshd/2, respect PasswordAuth no
+   [sshconnect2.c]
+   - less debug, respect .ssh/config
+   [README.openssh2 channels.c channels.h]
+   - clientloop.c session.c ssh.c 
+   - support for x11-fwding, client+server
+
 20000421
  - Merge fix from OpenBSD CVS
   [ssh-agent.c]
diff --git a/Makefile.in b/Makefile.in
index 196cc57..d5e3fde 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -31,11 +31,11 @@
 
 TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS)
 
-LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o dsa.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o 
+LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o dsa.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o 
 
-SSHOBJS= ssh.o sshconnect.o log-client.o readconf.o clientloop.o
+SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o log-client.o readconf.o clientloop.o
 
-SSHDOBJS= sshd.o auth-rhosts.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o servconf.o serverloop.o bsd-login.o md5crypt.o session.o auth.o
+SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-rhosts.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o servconf.o serverloop.o bsd-login.o md5crypt.o session.o
 
 TROFFMAN	= scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8
 CATMAN		= scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh.0 sshd.0
diff --git a/README.openssh2 b/README.openssh2
index bdf78bf..fca3173 100644
--- a/README.openssh2
+++ b/README.openssh2
@@ -1,13 +1,16 @@
-$Id: README.openssh2,v 1.3 2000/04/12 07:45:43 markus Exp $
+$Id: README.openssh2,v 1.6 2000/04/27 13:42:58 provos Exp $
 
 howto:
 	1) generate server key:
-		$ umask 077
-		$ openssl dsaparam 1024 -out dsa1024.pem
-		$ openssl gendsa -out /etc/ssh_dsa_key dsa1024.pem -rand /dev/arandom
+		$ ssh-keygen -d -f /etc/ssh_host_dsa_key -N ''
 	2) enable ssh2:
 		server: add 'Protocol 2,1' to /etc/sshd_config
 		client: ssh -o 'Protocol 2,1', or add to .ssh/config
+	3) interop w/ ssh.com dsa-keys:
+		ssh-keygen -f /key/from/ssh.com -X >> ~/.ssh/authorized_keys2
+	   and vice versa
+		ssh-keygen -f /privatekey/from/openssh -x > ~/.ssh2/mykey.pub
+		echo Key mykey.pub >> ~/.ssh2/authorization
 
 works:
 	secsh-transport: works w/o rekey
@@ -22,7 +25,7 @@
 		key database in ~/.ssh/known_hosts with bits == 0 hack
 	dss: signature works, keygen w/ openssl
 	client interops w/ sshd2, lshd
-	server interops w/ ssh2, lsh, ssh.com's Windows client, SecureCRT
+	server interops w/ ssh2, lsh, ssh.com's Windows client, SecureCRT, F-Secure SSH Client 4.0
 	server supports multiple concurrent sessions (e.g. with SSH.com Windows client)
 todo:
 	re-keying
@@ -38,4 +41,4 @@
 	sftp
 
 -markus
-$Date: 2000/04/12 07:45:43 $
+$Date: 2000/04/27 13:42:58 $
diff --git a/auth-rsa.c b/auth-rsa.c
index aa8be2b..c61eab2 100644
--- a/auth-rsa.c
+++ b/auth-rsa.c
@@ -16,7 +16,7 @@
  */
 
 #include "includes.h"
-RCSID("$Id: auth-rsa.c,v 1.17 2000/04/16 02:31:49 damien Exp $");
+RCSID("$Id: auth-rsa.c,v 1.18 2000/04/29 13:57:09 damien Exp $");
 
 #include "rsa.h"
 #include "packet.h"
@@ -185,6 +185,7 @@
 			}
 		}
 		if (fail) {
+			fclose(f);
 			log(buf);
 			packet_send_debug(buf);
 			restore_uid();
diff --git a/auth.c b/auth.c
index 4c6f32b..3bfcfd8 100644
--- a/auth.c
+++ b/auth.c
@@ -5,7 +5,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth.c,v 1.4 2000/04/14 10:30:29 markus Exp $");
+RCSID("$OpenBSD: auth.c,v 1.6 2000/04/26 21:28:31 markus Exp $");
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -40,7 +40,7 @@
  * If the user's shell is not executable, false will be returned.
  * Otherwise true is returned.
  */
-static int
+int
 allowed_user(struct passwd * pw)
 {
 	struct stat st;
@@ -118,685 +118,3 @@
 	/* We found no reason not to let this user try to log on... */
 	return 1;
 }
-
-/*
- * convert ssh auth msg type into description
- */
-char *
-get_authname(int type)
-{
-	static char buf[1024];
-	switch (type) {
-	case SSH_CMSG_AUTH_PASSWORD:
-		return "password";
-	case SSH_CMSG_AUTH_RSA:
-		return "rsa";
-	case SSH_CMSG_AUTH_RHOSTS_RSA:
-		return "rhosts-rsa";
-	case SSH_CMSG_AUTH_RHOSTS:
-		return "rhosts";
-#ifdef KRB4
-	case SSH_CMSG_AUTH_KERBEROS:
-		return "kerberos";
-#endif
-#ifdef SKEY
-	case SSH_CMSG_AUTH_TIS_RESPONSE:
-		return "s/key";
-#endif
-	}
-	snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
-	return buf;
-}
-
-#define AUTH_FAIL_MAX 6
-#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
-#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
-
-/*
- * The user does not exist or access is denied,
- * but fake indication that authentication is needed.
- */
-void
-do_fake_authloop1(char *user)
-{
-	int attempt = 0;
-
-	log("Faking authloop for illegal user %.200s from %.200s port %d",
-	    user,
-	    get_remote_ipaddr(),
-	    get_remote_port());
-
-#ifdef WITH_AIXAUTHENTICATE 
-		if (strncmp(get_authname(type),"password",
-		    strlen(get_authname(type))) == 0)
-			loginfailed(pw->pw_name,get_canonical_hostname(),"ssh");
-#endif /* WITH_AIXAUTHENTICATE */
-
-	/* Indicate that authentication is needed. */
-	packet_start(SSH_SMSG_FAILURE);
-	packet_send();
-	packet_write_wait();
-
-	/*
-	 * Keep reading packets, and always respond with a failure.  This is
-	 * to avoid disclosing whether such a user really exists.
-	 */
-	for (attempt = 1;; attempt++) {
-		/* Read a packet.  This will not return if the client disconnects. */
-		int plen;
-#ifndef SKEY
-		(void)packet_read(&plen);
-#else /* SKEY */
-		int type = packet_read(&plen);
-		unsigned int dlen;
-		char *password, *skeyinfo;
-		/* Try to send a fake s/key challenge. */
-		if (options.skey_authentication == 1 &&
-		    (skeyinfo = skey_fake_keyinfo(user)) != NULL) {
-			password = NULL;
-			if (type == SSH_CMSG_AUTH_TIS) {
-				packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
-				packet_put_string(skeyinfo, strlen(skeyinfo));
-				packet_send();
-				packet_write_wait();
-				continue;
-			} else if (type == SSH_CMSG_AUTH_PASSWORD &&
-				   options.password_authentication &&
-				   (password = packet_get_string(&dlen)) != NULL &&
-				   dlen == 5 &&
-				   strncasecmp(password, "s/key", 5) == 0 ) {
-				packet_send_debug(skeyinfo);
-			}
-			if (password != NULL)
-				xfree(password);
-		}
-#endif
-		if (attempt > AUTH_FAIL_MAX)
-			packet_disconnect(AUTH_FAIL_MSG, user);
-
-		/*
-		 * Send failure.  This should be indistinguishable from a
-		 * failed authentication.
-		 */
-		packet_start(SSH_SMSG_FAILURE);
-		packet_send();
-		packet_write_wait();
-	}
-	/* NOTREACHED */
-	abort();
-}
-
-/*
- * read packets and try to authenticate local user *pw.
- * return if authentication is successfull
- */
-void
-do_authloop(struct passwd * pw)
-{
-	int attempt = 0;
-	unsigned int bits;
-	RSA *client_host_key;
-	BIGNUM *n;
-	char *client_user = NULL, *password = NULL;
-	char user[1024];
-	unsigned int dlen;
-	int plen, nlen, elen;
-	unsigned int ulen;
-	int type = 0;
-	void (*authlog) (const char *fmt,...) = verbose;
-
-	/* Indicate that authentication is needed. */
-	packet_start(SSH_SMSG_FAILURE);
-	packet_send();
-	packet_write_wait();
-
-	for (attempt = 1;; attempt++) {
-		int authenticated = 0;
-		strlcpy(user, "", sizeof user);
-
-		/* Get a packet from the client. */
-		type = packet_read(&plen);
-
-		/* Process the packet. */
-		switch (type) {
-#ifdef AFS
-		case SSH_CMSG_HAVE_KERBEROS_TGT:
-			if (!options.kerberos_tgt_passing) {
-				/* packet_get_all(); */
-				verbose("Kerberos tgt passing disabled.");
-				break;
-			} else {
-				/* Accept Kerberos tgt. */
-				char *tgt = packet_get_string(&dlen);
-				packet_integrity_check(plen, 4 + dlen, type);
-				if (!auth_kerberos_tgt(pw, tgt))
-					verbose("Kerberos tgt REFUSED for %s", pw->pw_name);
-				xfree(tgt);
-			}
-			continue;
-
-		case SSH_CMSG_HAVE_AFS_TOKEN:
-			if (!options.afs_token_passing || !k_hasafs()) {
-				/* packet_get_all(); */
-				verbose("AFS token passing disabled.");
-				break;
-			} else {
-				/* Accept AFS token. */
-				char *token_string = packet_get_string(&dlen);
-				packet_integrity_check(plen, 4 + dlen, type);
-				if (!auth_afs_token(pw, token_string))
-					verbose("AFS token REFUSED for %s", pw->pw_name);
-				xfree(token_string);
-			}
-			continue;
-#endif /* AFS */
-#ifdef KRB4
-		case SSH_CMSG_AUTH_KERBEROS:
-			if (!options.kerberos_authentication) {
-				/* packet_get_all(); */
-				verbose("Kerberos authentication disabled.");
-				break;
-			} else {
-				/* Try Kerberos v4 authentication. */
-				KTEXT_ST auth;
-				char *tkt_user = NULL;
-				char *kdata = packet_get_string((unsigned int *) &auth.length);
-				packet_integrity_check(plen, 4 + auth.length, type);
-
-				if (auth.length < MAX_KTXT_LEN)
-					memcpy(auth.dat, kdata, auth.length);
-				xfree(kdata);
-
-				authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
-
-				if (authenticated) {
-					snprintf(user, sizeof user, " tktuser %s", tkt_user);
-					xfree(tkt_user);
-				}
-			}
-			break;
-#endif /* KRB4 */
-
-		case SSH_CMSG_AUTH_RHOSTS:
-			if (!options.rhosts_authentication) {
-				verbose("Rhosts authentication disabled.");
-				break;
-			}
-			/*
-			 * Get client user name.  Note that we just have to
-			 * trust the client; this is one reason why rhosts
-			 * authentication is insecure. (Another is
-			 * IP-spoofing on a local network.)
-			 */
-			client_user = packet_get_string(&ulen);
-			packet_integrity_check(plen, 4 + ulen, type);
-
-			/* Try to authenticate using /etc/hosts.equiv and
-			   .rhosts. */
-			authenticated = auth_rhosts(pw, client_user);
-
-			snprintf(user, sizeof user, " ruser %s", client_user);
-			break;
-
-		case SSH_CMSG_AUTH_RHOSTS_RSA:
-			if (!options.rhosts_rsa_authentication) {
-				verbose("Rhosts with RSA authentication disabled.");
-				break;
-			}
-			/*
-			 * Get client user name.  Note that we just have to
-			 * trust the client; root on the client machine can
-			 * claim to be any user.
-			 */
-			client_user = packet_get_string(&ulen);
-
-			/* Get the client host key. */
-			client_host_key = RSA_new();
-			if (client_host_key == NULL)
-				fatal("RSA_new failed");
-			client_host_key->e = BN_new();
-			client_host_key->n = BN_new();
-			if (client_host_key->e == NULL || client_host_key->n == NULL)
-				fatal("BN_new failed");
-			bits = packet_get_int();
-			packet_get_bignum(client_host_key->e, &elen);
-			packet_get_bignum(client_host_key->n, &nlen);
-
-			if (bits != BN_num_bits(client_host_key->n))
-				error("Warning: keysize mismatch for client_host_key: "
-				      "actual %d, announced %d", BN_num_bits(client_host_key->n), bits);
-			packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
-
-			authenticated = auth_rhosts_rsa(pw, client_user, client_host_key);
-			RSA_free(client_host_key);
-
-			snprintf(user, sizeof user, " ruser %s", client_user);
-			break;
-
-		case SSH_CMSG_AUTH_RSA:
-			if (!options.rsa_authentication) {
-				verbose("RSA authentication disabled.");
-				break;
-			}
-			/* RSA authentication requested. */
-			n = BN_new();
-			packet_get_bignum(n, &nlen);
-			packet_integrity_check(plen, nlen, type);
-			authenticated = auth_rsa(pw, n);
-			BN_clear_free(n);
-			break;
-
-		case SSH_CMSG_AUTH_PASSWORD:
-			if (!options.password_authentication) {
-				verbose("Password authentication disabled.");
-				break;
-			}
-			/*
-			 * Read user password.  It is in plain text, but was
-			 * transmitted over the encrypted channel so it is
-			 * not visible to an outside observer.
-			 */
-			password = packet_get_string(&dlen);
-			packet_integrity_check(plen, 4 + dlen, type);
-
-#ifdef USE_PAM
-			/* Do PAM auth with password */
-			authenticated = auth_pam_password(pw, password);
-#else /* USE_PAM */
-			/* Try authentication with the password. */
-			authenticated = auth_password(pw, password);
-#endif /* USE_PAM */
-			memset(password, 0, strlen(password));
-			xfree(password);
-			break;
-
-#ifdef SKEY
-		case SSH_CMSG_AUTH_TIS:
-			debug("rcvd SSH_CMSG_AUTH_TIS");
-			if (options.skey_authentication == 1) {
-				char *skeyinfo = skey_keyinfo(pw->pw_name);
-				if (skeyinfo == NULL) {
-					debug("generating fake skeyinfo for %.100s.", pw->pw_name);
-					skeyinfo = skey_fake_keyinfo(pw->pw_name);
-				}
-				if (skeyinfo != NULL) {
-					/* we send our s/key- in tis-challenge messages */
-					debug("sending challenge '%s'", skeyinfo);
-					packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
-					packet_put_string(skeyinfo, strlen(skeyinfo));
-					packet_send();
-					packet_write_wait();
-					continue;
-				}
-			}
-			break;
-		case SSH_CMSG_AUTH_TIS_RESPONSE:
-			debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
-			if (options.skey_authentication == 1) {
-				char *response = packet_get_string(&dlen);
-				debug("skey response == '%s'", response);
-				packet_integrity_check(plen, 4 + dlen, type);
-				authenticated = (skey_haskey(pw->pw_name) == 0 &&
-						 skey_passcheck(pw->pw_name, response) != -1);
-				xfree(response);
-			}
-			break;
-#else
-		case SSH_CMSG_AUTH_TIS:
-			/* TIS Authentication is unsupported */
-			log("TIS authentication unsupported.");
-			break;
-#endif
-
-		default:
-			/*
-			 * Any unknown messages will be ignored (and failure
-			 * returned) during authentication.
-			 */
-			log("Unknown message during authentication: type %d", type);
-			break;
-		}
-
-		/*
-		 * Check if the user is logging in as root and root logins
-		 * are disallowed.
-		 * Note that root login is allowed for forced commands.
-		 */
-		if (authenticated && pw->pw_uid == 0 && !options.permit_root_login) {
-			if (forced_command) {
-				log("Root login accepted for forced command.");
-			} else {
-				authenticated = 0;
-				log("ROOT LOGIN REFUSED FROM %.200s",
-				    get_canonical_hostname());
-			}
-		}
-
-		/* Raise logging level */
-		if (authenticated ||
-		    attempt == AUTH_FAIL_LOG ||
-		    type == SSH_CMSG_AUTH_PASSWORD)
-			authlog = log;
-
-		authlog("%s %s for %.200s from %.200s port %d%s",
-			authenticated ? "Accepted" : "Failed",
-			get_authname(type),
-			pw->pw_uid == 0 ? "ROOT" : pw->pw_name,
-			get_remote_ipaddr(),
-			get_remote_port(),
-			user);
-
-#ifdef USE_PAM
-		if (authenticated) {
-			if (!do_pam_account(pw->pw_name, client_user)) {
-				if (client_user != NULL) {
-					xfree(client_user);
-					client_user = NULL;
-				}
-				do_fake_authloop1(pw->pw_name);
-			}
-			return;
-		}
-#else /* USE_PAM */
-		if (authenticated) {
-			return;
-		}
-#endif /* USE_PAM */
-
-		if (client_user != NULL) {
-			xfree(client_user);
-			client_user = NULL;
-		}
-
-		if (attempt > AUTH_FAIL_MAX)
-			packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
-
-		/* Send a message indicating that the authentication attempt failed. */
-		packet_start(SSH_SMSG_FAILURE);
-		packet_send();
-		packet_write_wait();
-	}
-}
-
-/*
- * Performs authentication of an incoming connection.  Session key has already
- * been exchanged and encryption is enabled.
- */
-void
-do_authentication()
-{
-	struct passwd *pw, pwcopy;
-	int plen;
-	unsigned int ulen;
-	char *user;
-#ifdef WITH_AIXAUTHENTICATE
-	char *loginmsg;
-#endif /* WITH_AIXAUTHENTICATE */
-
-	/* Get the name of the user that we wish to log in as. */
-	packet_read_expect(&plen, SSH_CMSG_USER);
-
-	/* Get the user name. */
-	user = packet_get_string(&ulen);
-	packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
-
-	setproctitle("%s", user);
-
-#ifdef AFS
-	/* If machine has AFS, set process authentication group. */
-	if (k_hasafs()) {
-		k_setpag();
-		k_unlog();
-	}
-#endif /* AFS */
-
-	/* Verify that the user is a valid user. */
-	pw = getpwnam(user);
-	if (!pw || !allowed_user(pw))
-		do_fake_authloop1(user);
-	xfree(user);
-
-	/* Take a copy of the returned structure. */
-	memset(&pwcopy, 0, sizeof(pwcopy));
-	pwcopy.pw_name = xstrdup(pw->pw_name);
-	pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
-	pwcopy.pw_uid = pw->pw_uid;
-	pwcopy.pw_gid = pw->pw_gid;
-	pwcopy.pw_dir = xstrdup(pw->pw_dir);
-	pwcopy.pw_shell = xstrdup(pw->pw_shell);
-	pw = &pwcopy;
-
-#ifdef USE_PAM
-	start_pam(pw);
-#endif
-
-	/*
-	 * If we are not running as root, the user must have the same uid as
-	 * the server.
-	 */
-	if (getuid() != 0 && pw->pw_uid != getuid())
-		packet_disconnect("Cannot change user when server not running as root.");
-
-	debug("Attempting authentication for %.100s.", pw->pw_name);
-
-	/* If the user has no password, accept authentication immediately. */
-	if (options.password_authentication &&
-#ifdef KRB4
-	    (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
-#endif /* KRB4 */
-#ifdef USE_PAM
-	    auth_pam_password(pw, "")) {
-#else /* USE_PAM */
-	    auth_password(pw, "")) {
-#endif /* USE_PAM */
-		/* Authentication with empty password succeeded. */
-		log("Login for user %s from %.100s, accepted without authentication.",
-		    pw->pw_name, get_remote_ipaddr());
-	} else {
-		/* Loop until the user has been authenticated or the
-		   connection is closed, do_authloop() returns only if
-		   authentication is successfull */
-		do_authloop(pw);
-	}
-
-	/* The user has been authenticated and accepted. */
-#ifdef WITH_AIXAUTHENTICATE
-	loginsuccess(user,get_canonical_hostname(),"ssh",&loginmsg);
-#endif /* WITH_AIXAUTHENTICATE */
-	packet_start(SSH_SMSG_SUCCESS);
-	packet_send();
-	packet_write_wait();
-
-	/* Perform session preparation. */
-	do_authenticated(pw);
-}
-
-
-void input_service_request(int type, int plen);
-void input_userauth_request(int type, int plen);
-void ssh2_pty_cleanup(void);
-
-typedef struct Authctxt Authctxt;
-struct Authctxt {
-	char *user;
-	char *service;
-	struct passwd pw;
-	int valid;
-};
-static Authctxt	*authctxt = NULL;
-static int userauth_success = 0;
-
-struct passwd*
-auth_get_user(void)
-{
-	return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
-}
-struct passwd*
-auth_set_user(char *u, char *s)
-{
-	struct passwd *pw, *copy;
-
-	if (authctxt == NULL) {
-		authctxt = xmalloc(sizeof(*authctxt));
-		authctxt->valid = 0;
-		authctxt->user = xstrdup(u);
-		authctxt->service = xstrdup(s);
-		setproctitle("%s", u);
-		pw = getpwnam(u);
-		if (!pw || !allowed_user(pw)) {
-			log("auth_set_user: bad user %s", u);
-			return NULL;
-		}
-#ifdef USE_PAM
-		start_pam(pw);
-#endif
-		copy = &authctxt->pw;
-		memset(copy, 0, sizeof(*copy));
-		copy->pw_name = xstrdup(pw->pw_name);
-		copy->pw_passwd = xstrdup(pw->pw_passwd);
-		copy->pw_uid = pw->pw_uid;
-		copy->pw_gid = pw->pw_gid;
-		copy->pw_dir = xstrdup(pw->pw_dir);
-		copy->pw_shell = xstrdup(pw->pw_shell);
-		authctxt->valid = 1;
-	} else {
-		if (strcmp(u, authctxt->user) != 0 ||
-		    strcmp(s, authctxt->service) != 0) {
-			log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
-			    u, s, authctxt->user, authctxt->service);
-			return NULL;
-		}
-	}
-	return auth_get_user();
-}
-
-static void
-protocol_error(int type, int plen)
-{
-	log("auth: protocol error: type %d plen %d", type, plen);
-	packet_start(SSH2_MSG_UNIMPLEMENTED);
-	packet_put_int(0);
-	packet_send();
-	packet_write_wait();
-}
-void
-input_service_request(int type, int plen)
-{
-	unsigned int len;
-	int accept = 0;
-	char *service = packet_get_string(&len);
-	packet_done();
-
-	if (strcmp(service, "ssh-userauth") == 0) {
-		if (!userauth_success) {
-			accept = 1;
-			/* now we can handle user-auth requests */
-			dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
-		}
-	}
-	/* XXX all other service requests are denied */
-
-	if (accept) {
-		packet_start(SSH2_MSG_SERVICE_ACCEPT);
-		packet_put_cstring(service);
-		packet_send();
-		packet_write_wait();
-	} else {
-		debug("bad service request %s", service);
-		packet_disconnect("bad service request %s", service);
-	}
-	xfree(service);
-}
-void
-input_userauth_request(int type, int plen)
-{
-	static int try = 0;
-	unsigned int len;
-	int c, authenticated = 0;
-	char *user, *service, *method;
-	struct passwd *pw;
-
-	if (++try == AUTH_FAIL_MAX)
-		packet_disconnect("too many failed userauth_requests");
-
-	user = packet_get_string(&len);
-	service = packet_get_string(&len);
-	method = packet_get_string(&len);
-	debug("userauth-request for user %s service %s method %s", user, service, method);
-
-	/* XXX we only allow the ssh-connection service */
-	pw = auth_set_user(user, service);
-	if (pw && strcmp(service, "ssh-connection")==0) {
-		if (strcmp(method, "none") == 0 && try == 1) {
-			packet_done();
-#ifdef USE_PAM
-			/* Do PAM auth with password */
-			authenticated = auth_pam_password(pw, "");
-#else /* USE_PAM */
-			/* Try authentication with the password. */
-			authenticated = auth_password(pw, "");
-#endif /* USE_PAM */
-		} else if (strcmp(method, "password") == 0) {
-			char *password;
-			c = packet_get_char();
-			if (c)
-				debug("password change not supported");
-			password = packet_get_string(&len);
-			packet_done();
-#ifdef USE_PAM
-			/* Do PAM auth with password */
-			authenticated = auth_pam_password(pw, password);
-#else /* USE_PAM */
-			/* Try authentication with the password. */
-			authenticated = auth_password(pw, password);
-#endif /* USE_PAM */
-			memset(password, 0, len);
-			xfree(password);
-		} else if (strcmp(method, "publickey") == 0) {
-			/* XXX TODO */
-			char *pkalg, *pkblob, *sig;
-			int have_sig = packet_get_char();
-			pkalg = packet_get_string(&len);
-			pkblob = packet_get_string(&len);
-			if (have_sig) {
-				sig = packet_get_string(&len);
-				/* test for correct signature */
-				packet_done();
-				xfree(sig);
-			} else {
-				packet_done();
-				/* test whether pkalg/pkblob are acceptable */
-			}
-			xfree(pkalg);
-			xfree(pkblob);
-		}
-	}
-	/* XXX check if other auth methods are needed */
-	if (authenticated) {
-		/* turn off userauth */
-		dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
-		packet_start(SSH2_MSG_USERAUTH_SUCCESS);
-		packet_send();
-		packet_write_wait();
-		log("userauth success for %s", user);
-		/* now we can break out */
-		userauth_success = 1;
-	} else {
-		packet_start(SSH2_MSG_USERAUTH_FAILURE);
-		packet_put_cstring("password");
-		packet_put_char(0);		/* partial success */
-		packet_send();
-		packet_write_wait();
-	}
-	xfree(service);
-	xfree(user);
-	xfree(method);
-}
-void
-do_authentication2()
-{
-	dispatch_init(&protocol_error);
-	dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
-	dispatch_run(DISPATCH_BLOCK, &userauth_success);
-	do_authenticated2();
-}
diff --git a/auth.h b/auth.h
index 3771e82..72126e0 100644
--- a/auth.h
+++ b/auth.h
@@ -7,4 +7,11 @@
 struct passwd *
 auth_get_user(void);
 
+int allowed_user(struct passwd * pw);;
+
+#define AUTH_FAIL_MAX 6
+#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
+#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
+
 #endif
+
diff --git a/auth1.c b/auth1.c
new file mode 100644
index 0000000..ae5f1cd
--- /dev/null
+++ b/auth1.c
@@ -0,0 +1,512 @@
+/*
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: auth1.c,v 1.1 2000/04/26 21:28:32 markus Exp $");
+
+#include "xmalloc.h"
+#include "rsa.h"
+#include "ssh.h"
+#include "packet.h"
+#include "buffer.h"
+#include "cipher.h"
+#include "mpaux.h"
+#include "servconf.h"
+#include "compat.h"
+#include "auth.h"
+#include "session.h"
+
+/* import */
+extern ServerOptions options;
+extern char *forced_command;
+
+/*
+ * convert ssh auth msg type into description
+ */
+char *
+get_authname(int type)
+{
+	static char buf[1024];
+	switch (type) {
+	case SSH_CMSG_AUTH_PASSWORD:
+		return "password";
+	case SSH_CMSG_AUTH_RSA:
+		return "rsa";
+	case SSH_CMSG_AUTH_RHOSTS_RSA:
+		return "rhosts-rsa";
+	case SSH_CMSG_AUTH_RHOSTS:
+		return "rhosts";
+#ifdef KRB4
+	case SSH_CMSG_AUTH_KERBEROS:
+		return "kerberos";
+#endif
+#ifdef SKEY
+	case SSH_CMSG_AUTH_TIS_RESPONSE:
+		return "s/key";
+#endif
+	}
+	snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
+	return buf;
+}
+
+/*
+ * The user does not exist or access is denied,
+ * but fake indication that authentication is needed.
+ */
+void
+do_fake_authloop1(char *user)
+{
+	int attempt = 0;
+
+	log("Faking authloop for illegal user %.200s from %.200s port %d",
+	    user,
+	    get_remote_ipaddr(),
+	    get_remote_port());
+
+#ifdef WITH_AIXAUTHENTICATE 
+		if (strncmp(get_authname(type),"password",
+		    strlen(get_authname(type))) == 0)
+			loginfailed(pw->pw_name,get_canonical_hostname(),"ssh");
+#endif /* WITH_AIXAUTHENTICATE */
+
+	/* Indicate that authentication is needed. */
+	packet_start(SSH_SMSG_FAILURE);
+	packet_send();
+	packet_write_wait();
+
+	/*
+	 * Keep reading packets, and always respond with a failure.  This is
+	 * to avoid disclosing whether such a user really exists.
+	 */
+	for (attempt = 1;; attempt++) {
+		/* Read a packet.  This will not return if the client disconnects. */
+		int plen;
+#ifndef SKEY
+		(void)packet_read(&plen);
+#else /* SKEY */
+		int type = packet_read(&plen);
+		unsigned int dlen;
+		char *password, *skeyinfo;
+		password = NULL;
+		/* Try to send a fake s/key challenge. */
+		if (options.skey_authentication == 1 &&
+		    (skeyinfo = skey_fake_keyinfo(user)) != NULL) {
+			if (type == SSH_CMSG_AUTH_TIS) {
+				packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
+				packet_put_string(skeyinfo, strlen(skeyinfo));
+				packet_send();
+				packet_write_wait();
+				continue;
+			} else if (type == SSH_CMSG_AUTH_PASSWORD &&
+				   options.password_authentication &&
+				   (password = packet_get_string(&dlen)) != NULL &&
+				   dlen == 5 &&
+				   strncasecmp(password, "s/key", 5) == 0 ) {
+				packet_send_debug(skeyinfo);
+			}
+		}
+		if (password != NULL)
+			xfree(password);
+#endif
+		if (attempt > AUTH_FAIL_MAX)
+			packet_disconnect(AUTH_FAIL_MSG, user);
+
+		/*
+		 * Send failure.  This should be indistinguishable from a
+		 * failed authentication.
+		 */
+		packet_start(SSH_SMSG_FAILURE);
+		packet_send();
+		packet_write_wait();
+	}
+	/* NOTREACHED */
+	abort();
+}
+
+/*
+ * read packets and try to authenticate local user *pw.
+ * return if authentication is successfull
+ */
+void
+do_authloop(struct passwd * pw)
+{
+	int attempt = 0;
+	unsigned int bits;
+	RSA *client_host_key;
+	BIGNUM *n;
+	char *client_user = NULL, *password = NULL;
+	char user[1024];
+	unsigned int dlen;
+	int plen, nlen, elen;
+	unsigned int ulen;
+	int type = 0;
+	void (*authlog) (const char *fmt,...) = verbose;
+
+	/* Indicate that authentication is needed. */
+	packet_start(SSH_SMSG_FAILURE);
+	packet_send();
+	packet_write_wait();
+
+	for (attempt = 1;; attempt++) {
+		int authenticated = 0;
+		strlcpy(user, "", sizeof user);
+
+		/* Get a packet from the client. */
+		type = packet_read(&plen);
+
+		/* Process the packet. */
+		switch (type) {
+#ifdef AFS
+		case SSH_CMSG_HAVE_KERBEROS_TGT:
+			if (!options.kerberos_tgt_passing) {
+				/* packet_get_all(); */
+				verbose("Kerberos tgt passing disabled.");
+				break;
+			} else {
+				/* Accept Kerberos tgt. */
+				char *tgt = packet_get_string(&dlen);
+				packet_integrity_check(plen, 4 + dlen, type);
+				if (!auth_kerberos_tgt(pw, tgt))
+					verbose("Kerberos tgt REFUSED for %s", pw->pw_name);
+				xfree(tgt);
+			}
+			continue;
+
+		case SSH_CMSG_HAVE_AFS_TOKEN:
+			if (!options.afs_token_passing || !k_hasafs()) {
+				/* packet_get_all(); */
+				verbose("AFS token passing disabled.");
+				break;
+			} else {
+				/* Accept AFS token. */
+				char *token_string = packet_get_string(&dlen);
+				packet_integrity_check(plen, 4 + dlen, type);
+				if (!auth_afs_token(pw, token_string))
+					verbose("AFS token REFUSED for %s", pw->pw_name);
+				xfree(token_string);
+			}
+			continue;
+#endif /* AFS */
+#ifdef KRB4
+		case SSH_CMSG_AUTH_KERBEROS:
+			if (!options.kerberos_authentication) {
+				/* packet_get_all(); */
+				verbose("Kerberos authentication disabled.");
+				break;
+			} else {
+				/* Try Kerberos v4 authentication. */
+				KTEXT_ST auth;
+				char *tkt_user = NULL;
+				char *kdata = packet_get_string((unsigned int *) &auth.length);
+				packet_integrity_check(plen, 4 + auth.length, type);
+
+				if (auth.length < MAX_KTXT_LEN)
+					memcpy(auth.dat, kdata, auth.length);
+				xfree(kdata);
+
+				authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
+
+				if (authenticated) {
+					snprintf(user, sizeof user, " tktuser %s", tkt_user);
+					xfree(tkt_user);
+				}
+			}
+			break;
+#endif /* KRB4 */
+
+		case SSH_CMSG_AUTH_RHOSTS:
+			if (!options.rhosts_authentication) {
+				verbose("Rhosts authentication disabled.");
+				break;
+			}
+			/*
+			 * Get client user name.  Note that we just have to
+			 * trust the client; this is one reason why rhosts
+			 * authentication is insecure. (Another is
+			 * IP-spoofing on a local network.)
+			 */
+			client_user = packet_get_string(&ulen);
+			packet_integrity_check(plen, 4 + ulen, type);
+
+			/* Try to authenticate using /etc/hosts.equiv and
+			   .rhosts. */
+			authenticated = auth_rhosts(pw, client_user);
+
+			snprintf(user, sizeof user, " ruser %s", client_user);
+			break;
+
+		case SSH_CMSG_AUTH_RHOSTS_RSA:
+			if (!options.rhosts_rsa_authentication) {
+				verbose("Rhosts with RSA authentication disabled.");
+				break;
+			}
+			/*
+			 * Get client user name.  Note that we just have to
+			 * trust the client; root on the client machine can
+			 * claim to be any user.
+			 */
+			client_user = packet_get_string(&ulen);
+
+			/* Get the client host key. */
+			client_host_key = RSA_new();
+			if (client_host_key == NULL)
+				fatal("RSA_new failed");
+			client_host_key->e = BN_new();
+			client_host_key->n = BN_new();
+			if (client_host_key->e == NULL || client_host_key->n == NULL)
+				fatal("BN_new failed");
+			bits = packet_get_int();
+			packet_get_bignum(client_host_key->e, &elen);
+			packet_get_bignum(client_host_key->n, &nlen);
+
+			if (bits != BN_num_bits(client_host_key->n))
+				error("Warning: keysize mismatch for client_host_key: "
+				      "actual %d, announced %d", BN_num_bits(client_host_key->n), bits);
+			packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
+
+			authenticated = auth_rhosts_rsa(pw, client_user, client_host_key);
+			RSA_free(client_host_key);
+
+			snprintf(user, sizeof user, " ruser %s", client_user);
+			break;
+
+		case SSH_CMSG_AUTH_RSA:
+			if (!options.rsa_authentication) {
+				verbose("RSA authentication disabled.");
+				break;
+			}
+			/* RSA authentication requested. */
+			n = BN_new();
+			packet_get_bignum(n, &nlen);
+			packet_integrity_check(plen, nlen, type);
+			authenticated = auth_rsa(pw, n);
+			BN_clear_free(n);
+			break;
+
+		case SSH_CMSG_AUTH_PASSWORD:
+			if (!options.password_authentication) {
+				verbose("Password authentication disabled.");
+				break;
+			}
+			/*
+			 * Read user password.  It is in plain text, but was
+			 * transmitted over the encrypted channel so it is
+			 * not visible to an outside observer.
+			 */
+			password = packet_get_string(&dlen);
+			packet_integrity_check(plen, 4 + dlen, type);
+
+#ifdef USE_PAM
+			/* Do PAM auth with password */
+			authenticated = auth_pam_password(pw, password);
+#else /* USE_PAM */
+			/* Try authentication with the password. */
+			authenticated = auth_password(pw, password);
+#endif /* USE_PAM */
+
+			memset(password, 0, strlen(password));
+			xfree(password);
+			break;
+
+#ifdef SKEY
+		case SSH_CMSG_AUTH_TIS:
+			debug("rcvd SSH_CMSG_AUTH_TIS");
+			if (options.skey_authentication == 1) {
+				char *skeyinfo = skey_keyinfo(pw->pw_name);
+				if (skeyinfo == NULL) {
+					debug("generating fake skeyinfo for %.100s.", pw->pw_name);
+					skeyinfo = skey_fake_keyinfo(pw->pw_name);
+				}
+				if (skeyinfo != NULL) {
+					/* we send our s/key- in tis-challenge messages */
+					debug("sending challenge '%s'", skeyinfo);
+					packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
+					packet_put_string(skeyinfo, strlen(skeyinfo));
+					packet_send();
+					packet_write_wait();
+					continue;
+				}
+			}
+			break;
+		case SSH_CMSG_AUTH_TIS_RESPONSE:
+			debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
+			if (options.skey_authentication == 1) {
+				char *response = packet_get_string(&dlen);
+				debug("skey response == '%s'", response);
+				packet_integrity_check(plen, 4 + dlen, type);
+				authenticated = (skey_haskey(pw->pw_name) == 0 &&
+						 skey_passcheck(pw->pw_name, response) != -1);
+				xfree(response);
+			}
+			break;
+#else
+		case SSH_CMSG_AUTH_TIS:
+			/* TIS Authentication is unsupported */
+			log("TIS authentication unsupported.");
+			break;
+#endif
+
+		default:
+			/*
+			 * Any unknown messages will be ignored (and failure
+			 * returned) during authentication.
+			 */
+			log("Unknown message during authentication: type %d", type);
+			break;
+		}
+
+		/*
+		 * Check if the user is logging in as root and root logins
+		 * are disallowed.
+		 * Note that root login is allowed for forced commands.
+		 */
+		if (authenticated && pw->pw_uid == 0 && !options.permit_root_login) {
+			if (forced_command) {
+				log("Root login accepted for forced command.");
+			} else {
+				authenticated = 0;
+				log("ROOT LOGIN REFUSED FROM %.200s",
+				    get_canonical_hostname());
+			}
+		}
+
+		/* Raise logging level */
+		if (authenticated ||
+		    attempt == AUTH_FAIL_LOG ||
+		    type == SSH_CMSG_AUTH_PASSWORD)
+			authlog = log;
+
+		authlog("%s %s for %.200s from %.200s port %d%s",
+			authenticated ? "Accepted" : "Failed",
+			get_authname(type),
+			pw->pw_uid == 0 ? "ROOT" : pw->pw_name,
+			get_remote_ipaddr(),
+			get_remote_port(),
+			user);
+
+#ifdef USE_PAM
+		if (authenticated) {
+			if (!do_pam_account(pw->pw_name, client_user)) {
+				if (client_user != NULL) {
+					xfree(client_user);
+					client_user = NULL;
+				}
+				do_fake_authloop1(pw->pw_name);
+			}
+			return;
+		}
+#else /* USE_PAM */
+		if (authenticated) {
+			return;
+		}
+#endif /* USE_PAM */
+
+		if (client_user != NULL) {
+			xfree(client_user);
+			client_user = NULL;
+		}
+
+		if (attempt > AUTH_FAIL_MAX)
+			packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
+
+		/* Send a message indicating that the authentication attempt failed. */
+		packet_start(SSH_SMSG_FAILURE);
+		packet_send();
+		packet_write_wait();
+	}
+}
+
+/*
+ * Performs authentication of an incoming connection.  Session key has already
+ * been exchanged and encryption is enabled.
+ */
+void
+do_authentication()
+{
+	struct passwd *pw, pwcopy;
+	int plen;
+	unsigned int ulen;
+	char *user;
+#ifdef WITH_AIXAUTHENTICATE
+	char *loginmsg;
+#endif /* WITH_AIXAUTHENTICATE */
+
+	/* Get the name of the user that we wish to log in as. */
+	packet_read_expect(&plen, SSH_CMSG_USER);
+
+	/* Get the user name. */
+	user = packet_get_string(&ulen);
+	packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
+
+	setproctitle("%s", user);
+
+#ifdef AFS
+	/* If machine has AFS, set process authentication group. */
+	if (k_hasafs()) {
+		k_setpag();
+		k_unlog();
+	}
+#endif /* AFS */
+
+	/* Verify that the user is a valid user. */
+	pw = getpwnam(user);
+	if (!pw || !allowed_user(pw))
+		do_fake_authloop1(user);
+	xfree(user);
+
+	/* Take a copy of the returned structure. */
+	memset(&pwcopy, 0, sizeof(pwcopy));
+	pwcopy.pw_name = xstrdup(pw->pw_name);
+	pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
+	pwcopy.pw_uid = pw->pw_uid;
+	pwcopy.pw_gid = pw->pw_gid;
+	pwcopy.pw_dir = xstrdup(pw->pw_dir);
+	pwcopy.pw_shell = xstrdup(pw->pw_shell);
+	pw = &pwcopy;
+
+#ifdef USE_PAM
+	start_pam(pw);
+#endif
+
+	/*
+	 * If we are not running as root, the user must have the same uid as
+	 * the server.
+	 */
+	if (getuid() != 0 && pw->pw_uid != getuid())
+		packet_disconnect("Cannot change user when server not running as root.");
+
+	debug("Attempting authentication for %.100s.", pw->pw_name);
+
+	/* If the user has no password, accept authentication immediately. */
+	if (options.password_authentication &&
+#ifdef KRB4
+	    (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
+#endif /* KRB4 */
+#ifdef USE_PAM
+	    auth_pam_password(pw, "")) {
+#else /* USE_PAM */
+	    auth_password(pw, "")) {
+#endif /* USE_PAM */
+		/* Authentication with empty password succeeded. */
+		log("Login for user %s from %.100s, accepted without authentication.",
+		    pw->pw_name, get_remote_ipaddr());
+	} else {
+		/* Loop until the user has been authenticated or the
+		   connection is closed, do_authloop() returns only if
+		   authentication is successfull */
+		do_authloop(pw);
+	}
+
+	/* The user has been authenticated and accepted. */
+#ifdef WITH_AIXAUTHENTICATE
+	loginsuccess(user,get_canonical_hostname(),"ssh",&loginmsg);
+#endif /* WITH_AIXAUTHENTICATE */
+	packet_start(SSH_SMSG_SUCCESS);
+	packet_send();
+	packet_write_wait();
+
+	/* Perform session preparation. */
+	do_authenticated(pw);
+}
diff --git a/auth2.c b/auth2.c
new file mode 100644
index 0000000..9937ed6
--- /dev/null
+++ b/auth2.c
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Markus Friedl.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "includes.h"
+RCSID("$OpenBSD: auth2.c,v 1.3 2000/04/27 15:23:02 markus Exp $");
+
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+
+#include "xmalloc.h"
+#include "rsa.h"
+#include "ssh.h"
+#include "pty.h"
+#include "packet.h"
+#include "buffer.h"
+#include "cipher.h"
+#include "servconf.h"
+#include "compat.h"
+#include "channels.h"
+#include "bufaux.h"
+#include "ssh2.h"
+#include "auth.h"
+#include "session.h"
+#include "dispatch.h"
+#include "auth.h"
+#include "key.h"
+#include "kex.h"
+
+#include "dsa.h"
+#include "uidswap.h"
+
+/* import */
+extern ServerOptions options;
+extern unsigned char *session_id2;
+extern int session_id2_len;
+
+/* protocol */
+
+void	input_service_request(int type, int plen);
+void	input_userauth_request(int type, int plen);
+void	protocol_error(int type, int plen);
+
+/* auth */
+int	ssh2_auth_none(struct passwd *pw);
+int	ssh2_auth_password(struct passwd *pw);
+int	ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen);
+
+/* helper */
+struct passwd*	 auth_set_user(char *u, char *s);
+int	user_dsa_key_allowed(struct passwd *pw, Key *key);
+
+typedef struct Authctxt Authctxt;
+struct Authctxt {
+	char *user;
+	char *service;
+	struct passwd pw;
+	int valid;
+};
+static Authctxt	*authctxt = NULL;
+static int userauth_success = 0;
+
+/*
+ * loop until userauth_success == TRUE
+ */
+
+void
+do_authentication2()
+{
+	dispatch_init(&protocol_error);
+	dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
+	dispatch_run(DISPATCH_BLOCK, &userauth_success);
+	do_authenticated2();
+}
+
+void
+protocol_error(int type, int plen)
+{
+	log("auth: protocol error: type %d plen %d", type, plen);
+	packet_start(SSH2_MSG_UNIMPLEMENTED);
+	packet_put_int(0);
+	packet_send();
+	packet_write_wait();
+}
+
+void
+input_service_request(int type, int plen)
+{
+	unsigned int len;
+	int accept = 0;
+	char *service = packet_get_string(&len);
+	packet_done();
+
+	if (strcmp(service, "ssh-userauth") == 0) {
+		if (!userauth_success) {
+			accept = 1;
+			/* now we can handle user-auth requests */
+			dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
+		}
+	}
+	/* XXX all other service requests are denied */
+
+	if (accept) {
+		packet_start(SSH2_MSG_SERVICE_ACCEPT);
+		packet_put_cstring(service);
+		packet_send();
+		packet_write_wait();
+	} else {
+		debug("bad service request %s", service);
+		packet_disconnect("bad service request %s", service);
+	}
+	xfree(service);
+}
+
+void
+input_userauth_request(int type, int plen)
+{
+	static void (*authlog) (const char *fmt,...) = verbose;
+	static int attempt = 0;
+	unsigned int len, rlen;
+	int authenticated = 0;
+	char *raw, *user, *service, *method, *authmsg = NULL;
+	struct passwd *pw;
+
+	if (++attempt == AUTH_FAIL_MAX)
+		packet_disconnect("too many failed userauth_requests");
+
+	raw = packet_get_raw(&rlen);
+	if (plen != rlen)
+		fatal("plen != rlen");
+	user = packet_get_string(&len);
+	service = packet_get_string(&len);
+	method = packet_get_string(&len);
+	debug("userauth-request for user %s service %s method %s", user, service, method);
+
+	/* XXX we only allow the ssh-connection service */
+	pw = auth_set_user(user, service);
+	if (pw && strcmp(service, "ssh-connection")==0) {
+		if (strcmp(method, "none") == 0) {
+			authenticated =	ssh2_auth_none(pw);
+		} else if (strcmp(method, "password") == 0) {
+			authenticated =	ssh2_auth_password(pw);
+		} else if (strcmp(method, "publickey") == 0) {
+			authenticated =	ssh2_auth_pubkey(pw, raw, rlen);
+		}
+	}
+	if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
+		authenticated = 0;
+		log("ROOT LOGIN REFUSED FROM %.200s",
+		    get_canonical_hostname());
+	}
+
+#ifdef USE_PAM
+		if (authenticated && !do_pam_account(pw->pw_name, NULL))
+			authenticated = 0;
+#endif /* USE_PAM */
+
+	/* XXX todo: check if multiple auth methods are needed */
+	if (authenticated == 1) {
+		authmsg = "Accepted";
+		/* turn off userauth */
+		dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
+		packet_start(SSH2_MSG_USERAUTH_SUCCESS);
+		packet_send();
+		packet_write_wait();
+		/* now we can break out */
+		userauth_success = 1;
+	} else if (authenticated == 0) {
+		authmsg = "Failed";
+		packet_start(SSH2_MSG_USERAUTH_FAILURE);
+		packet_put_cstring("publickey,password");	/* XXX dynamic */
+		packet_put_char(0);				/* XXX partial success, unused */
+		packet_send();
+		packet_write_wait();
+	} else {
+		authmsg = "Postponed";
+	}
+	/* Raise logging level */
+	if (authenticated == 1||
+	    attempt == AUTH_FAIL_LOG ||
+	    strcmp(method, "password") == 0)
+		authlog = log;
+
+	authlog("%s %s for %.200s from %.200s port %d ssh2",
+		authmsg,
+		method,
+		pw && pw->pw_uid == 0 ? "ROOT" : user,
+		get_remote_ipaddr(),
+		get_remote_port());
+
+	xfree(service);
+	xfree(user);
+	xfree(method);
+}
+
+int
+ssh2_auth_none(struct passwd *pw)
+{
+	packet_done();
+#ifdef USE_PAM
+	return auth_pam_password(pw, "");
+#else /* USE_PAM */
+	return auth_password(pw, "");
+#endif /* USE_PAM */
+}
+int
+ssh2_auth_password(struct passwd *pw)
+{
+	char *password;
+	int authenticated = 0;
+	int change;
+	unsigned int len;
+	change = packet_get_char();
+	if (change)
+		log("password change not supported");
+	password = packet_get_string(&len);
+	packet_done();
+	if (options.password_authentication &&
+#ifdef USE_PAM
+	    auth_pam_password(pw, password) == 1)
+#else /* USE_PAM */
+	    auth_password(pw, password) == 1)
+#endif /* USE_PAM */
+		authenticated = 1;
+	memset(password, 0, len);
+	xfree(password);
+	return authenticated;
+}
+int
+ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen)
+{
+	Buffer b;
+	Key *key;
+	char *pkalg, *pkblob, *sig;
+	unsigned int alen, blen, slen;
+	int have_sig;
+	int authenticated = 0;
+
+	if (options.rsa_authentication == 0) {
+		debug("pubkey auth disabled");
+		return 0;
+	}
+	have_sig = packet_get_char();
+	pkalg = packet_get_string(&alen);
+	if (strcmp(pkalg, KEX_DSS) != 0) {
+		xfree(pkalg);
+		log("bad pkalg %s", pkalg);	/*XXX*/
+		return 0;
+	}
+	pkblob = packet_get_string(&blen);
+	key = dsa_key_from_blob(pkblob, blen);
+	if (key != NULL) {
+		if (have_sig) {
+			sig = packet_get_string(&slen);
+			packet_done();
+			buffer_init(&b);
+			buffer_append(&b, session_id2, session_id2_len);
+			buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+			if (slen + 4 > rlen)
+				fatal("bad rlen/slen");
+			buffer_append(&b, raw, rlen - slen - 4);
+#ifdef DEBUG_DSS
+			buffer_dump(&b);
+#endif
+			/* test for correct signature */
+			if (user_dsa_key_allowed(pw, key) &&
+			    dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
+				authenticated = 1;
+			buffer_clear(&b);
+			xfree(sig);
+		} else {
+			packet_done();
+			debug("test key...");
+			/* test whether pkalg/pkblob are acceptable */
+			/* XXX fake reply and always send PK_OK ? */
+			if (user_dsa_key_allowed(pw, key)) {
+				packet_start(SSH2_MSG_USERAUTH_PK_OK);
+				packet_put_string(pkalg, alen);
+				packet_put_string(pkblob, blen);
+				packet_send();
+				packet_write_wait();
+				authenticated = -1;
+			}
+		}
+		key_free(key);
+	}
+	xfree(pkalg);
+	xfree(pkblob);
+	return authenticated;
+}
+
+/* set and get current user */
+
+struct passwd*
+auth_get_user(void)
+{
+	return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
+}
+
+struct passwd*
+auth_set_user(char *u, char *s)
+{
+	struct passwd *pw, *copy;
+
+	if (authctxt == NULL) {
+		authctxt = xmalloc(sizeof(*authctxt));
+		authctxt->valid = 0;
+		authctxt->user = xstrdup(u);
+		authctxt->service = xstrdup(s);
+		setproctitle("%s", u);
+		pw = getpwnam(u);
+		if (!pw || !allowed_user(pw)) {
+			log("auth_set_user: illegal user %s", u);
+			return NULL;
+		}
+#ifdef USE_PAM
+		start_pam(pw);
+#endif
+		copy = &authctxt->pw;
+		memset(copy, 0, sizeof(*copy));
+		copy->pw_name = xstrdup(pw->pw_name);
+		copy->pw_passwd = xstrdup(pw->pw_passwd);
+		copy->pw_uid = pw->pw_uid;
+		copy->pw_gid = pw->pw_gid;
+		copy->pw_dir = xstrdup(pw->pw_dir);
+		copy->pw_shell = xstrdup(pw->pw_shell);
+		authctxt->valid = 1;
+	} else {
+		if (strcmp(u, authctxt->user) != 0 ||
+		    strcmp(s, authctxt->service) != 0) {
+			log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
+			    u, s, authctxt->user, authctxt->service);
+			return NULL;
+		}
+	}
+	return auth_get_user();
+}
+
+/* return 1 if user allows given key */
+int
+user_dsa_key_allowed(struct passwd *pw, Key *key)
+{
+	char line[8192], file[1024];
+	int found_key = 0;
+	unsigned int bits = -1;
+	FILE *f;
+	unsigned long linenum = 0;
+	struct stat st;
+	Key *found;
+
+	/* Temporarily use the user's uid. */
+	temporarily_use_uid(pw->pw_uid);
+
+	/* The authorized keys. */
+	snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
+	    SSH_USER_PERMITTED_KEYS2);
+
+	/* Fail quietly if file does not exist */
+	if (stat(file, &st) < 0) {
+		/* Restore the privileged uid. */
+		restore_uid();
+		return 0;
+	}
+	/* Open the file containing the authorized keys. */
+	f = fopen(file, "r");
+	if (!f) {
+		/* Restore the privileged uid. */
+		restore_uid();
+		return 0;
+	}
+	if (options.strict_modes) {
+		int fail = 0;
+		char buf[1024];
+		/* Check open file in order to avoid open/stat races */
+		if (fstat(fileno(f), &st) < 0 ||
+		    (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
+		    (st.st_mode & 022) != 0) {
+			snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
+			    "bad ownership or modes for '%s'.", pw->pw_name, file);
+			fail = 1;
+		} else {
+			/* Check path to SSH_USER_PERMITTED_KEYS */
+			int i;
+			static const char *check[] = {
+				"", SSH_USER_DIR, NULL
+			};
+			for (i = 0; check[i]; i++) {
+				snprintf(line, sizeof line, "%.500s/%.100s",
+				    pw->pw_dir, check[i]);
+				if (stat(line, &st) < 0 ||
+				    (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
+				    (st.st_mode & 022) != 0) {
+					snprintf(buf, sizeof buf,
+					    "DSA authentication refused for %.100s: "
+					    "bad ownership or modes for '%s'.",
+					    pw->pw_name, line);
+					fail = 1;
+					break;
+				}
+			}
+		}
+		if (fail) {
+			log(buf);
+			fclose(f);
+			restore_uid();
+			return 0;
+		}
+	}
+	found_key = 0;
+	found = key_new(KEY_DSA);
+
+	while (fgets(line, sizeof(line), f)) {
+		char *cp;
+		linenum++;
+		/* Skip leading whitespace, empty and comment lines. */
+		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
+			;
+		if (!*cp || *cp == '\n' || *cp == '#')
+			continue;
+		bits = key_read(found, &cp);
+		if (bits == 0)
+			continue;
+		if (key_equal(found, key)) {
+			found_key = 1;
+			debug("matching key found: file %s, line %ld",
+			    file, linenum);
+			break;
+		}
+	}
+	restore_uid();
+	fclose(f);
+	key_free(found);
+	return found_key;
+}
diff --git a/authfile.c b/authfile.c
index e17c603..f93c9d4 100644
--- a/authfile.c
+++ b/authfile.c
@@ -15,14 +15,20 @@
  */
 
 #include "includes.h"
-RCSID("$Id: authfile.c,v 1.11 2000/04/16 02:31:49 damien Exp $");
+RCSID("$Id: authfile.c,v 1.12 2000/04/29 13:57:10 damien Exp $");
 
 #include <openssl/bn.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/evp.h>
+
 #include "xmalloc.h"
 #include "buffer.h"
 #include "bufaux.h"
 #include "cipher.h"
 #include "ssh.h"
+#include "key.h"
 
 /* Version identification string for identity files. */
 #define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
@@ -35,8 +41,8 @@
  */
 
 int
-save_private_key(const char *filename, const char *passphrase,
-		 RSA *key, const char *comment)
+save_private_key_rsa(const char *filename, const char *passphrase,
+    RSA *key, const char *comment)
 {
 	Buffer buffer, encrypted;
 	char buf[100], *cp;
@@ -128,6 +134,63 @@
 	return 1;
 }
 
+/* save DSA key in OpenSSL PEM format */
+
+int
+save_private_key_dsa(const char *filename, const char *passphrase,
+    DSA *dsa, const char *comment)
+{
+	FILE *fp;
+	int fd;
+	int success = 1;
+	int len = strlen(passphrase);
+
+	if (len > 0 && len <= 4) {
+		error("passphrase too short: %d bytes", len);
+		errno = 0;
+		return 0;
+	}
+	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+	if (fd < 0) {
+		debug("open %s failed", filename);
+		return 0;
+	}
+	fp = fdopen(fd, "w");
+	if (fp == NULL ) {
+		debug("fdopen %s failed", filename);
+		close(fd);
+		return 0;
+	}
+	if (len > 0) {
+		if (!PEM_write_DSAPrivateKey(fp, dsa, EVP_des_ede3_cbc(),
+		    (char *)passphrase, strlen(passphrase), NULL, NULL))
+			success = 0;
+	} else {
+		if (!PEM_write_DSAPrivateKey(fp, dsa, NULL,
+		    NULL, 0, NULL, NULL))
+			success = 0;
+	}
+	fclose(fp);
+	return success;
+}
+
+int
+save_private_key(const char *filename, const char *passphrase, Key *key,
+    const char *comment)
+{
+	switch (key->type) {
+	case KEY_RSA:
+		return save_private_key_rsa(filename, passphrase, key->rsa, comment);
+		break;
+	case KEY_DSA:
+		return save_private_key_dsa(filename, passphrase, key->dsa, comment);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
 /*
  * Loads the public part of the key file.  Returns 0 if an error was
  * encountered (the file does not exist or is not readable), and non-zero
@@ -135,8 +198,7 @@
  */
 
 int
-load_public_key(const char *filename, RSA * pub,
-		char **comment_return)
+load_public_key_rsa(const char *filename, RSA * pub, char **comment_return)
 {
 	int fd, i;
 	off_t len;
@@ -154,7 +216,7 @@
 
 	if (read(fd, cp, (size_t) len) != (size_t) len) {
 		debug("Read from key file %.200s failed: %.100s", filename,
-		      strerror(errno));
+		    strerror(errno));
 		buffer_free(&buffer);
 		close(fd);
 		return 0;
@@ -183,9 +245,13 @@
 
 	/* Read the public key from the buffer. */
 	buffer_get_int(&buffer);
-	pub->n = BN_new();
+	/* XXX alloc */
+	if (pub->n == NULL)
+		pub->n = BN_new();
 	buffer_get_bignum(&buffer, pub->n);
-	pub->e = BN_new();
+	/* XXX alloc */
+	if (pub->e == NULL)
+		pub->e = BN_new();
 	buffer_get_bignum(&buffer, pub->e);
 	if (comment_return)
 		*comment_return = buffer_get_string(&buffer, NULL);
@@ -196,6 +262,20 @@
 	return 1;
 }
 
+int
+load_public_key(const char *filename, Key * key, char **comment_return)
+{
+	switch (key->type) {
+	case KEY_RSA:
+		return load_public_key_rsa(filename, key->rsa, comment_return);
+		break;
+	case KEY_DSA:
+	default:
+		break;
+	}
+	return 0;
+}
+
 /*
  * Loads the private key from the file.  Returns 0 if an error is encountered
  * (file does not exist or is not readable, or passphrase is bad). This
@@ -204,35 +284,17 @@
  */
 
 int
-load_private_key(const char *filename, const char *passphrase,
-		 RSA * prv, char **comment_return)
+load_private_key_rsa(int fd, const char *filename,
+    const char *passphrase, RSA * prv, char **comment_return)
 {
-	int fd, i, check1, check2, cipher_type;
+	int i, check1, check2, cipher_type;
 	off_t len;
 	Buffer buffer, decrypted;
 	char *cp;
 	CipherContext cipher;
 	BN_CTX *ctx;
 	BIGNUM *aux;
-	struct stat st;
 
-	fd = open(filename, O_RDONLY);
-	if (fd < 0)
-		return 0;
-
-	/* check owner and modes */
-	if (fstat(fd, &st) < 0 ||
-	    (st.st_uid != 0 && getuid() != 0 && st.st_uid != getuid()) ||
-	    (st.st_mode & 077) != 0) {
-		close(fd);
-		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
-		error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
-		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
-		error("Bad ownership or mode(0%3.3o) for '%s'.",
-		      st.st_mode & 0777, filename);
-		error("It is recommended that your private key files are NOT accessible by others.");
-		return 0;
-	}
 	len = lseek(fd, (off_t) 0, SEEK_END);
 	lseek(fd, (off_t) 0, SEEK_SET);
 
@@ -309,7 +371,9 @@
 		buffer_free(&decrypted);
 fail:
 		BN_clear_free(prv->n);
+		prv->n = NULL;
 		BN_clear_free(prv->e);
+		prv->e = NULL;
 		if (comment_return)
 			xfree(*comment_return);
 		return 0;
@@ -343,3 +407,87 @@
 
 	return 1;
 }
+
+int
+load_private_key_dsa(int fd, const char *passphrase, Key *k, char **comment_return)
+{
+	DSA *dsa;
+	BIO *in;
+	FILE *fp;
+
+	in = BIO_new(BIO_s_file());
+	if (in == NULL) {
+		error("BIO_new failed");
+		return 0;
+	}
+	fp = fdopen(fd, "r");
+	if (fp == NULL) {
+		error("fdopen failed");
+		return 0;
+	}
+	BIO_set_fp(in, fp, BIO_NOCLOSE);
+	dsa = PEM_read_bio_DSAPrivateKey(in, NULL, NULL, (char *)passphrase);
+	if (dsa == NULL) {
+		debug("PEM_read_bio_DSAPrivateKey failed");
+	} else {
+		/* replace k->dsa with loaded key */
+		DSA_free(k->dsa);
+		k->dsa = dsa;
+	}
+	BIO_free(in);
+	fclose(fp);
+	if (comment_return)
+		*comment_return = xstrdup("dsa w/o comment");
+	debug("read DSA private key done");
+#ifdef DEBUG_DSS
+	DSA_print_fp(stderr, dsa, 8);
+#endif
+	return dsa != NULL ? 1 : 0;
+}
+
+int
+load_private_key(const char *filename, const char *passphrase, Key *key,
+    char **comment_return)
+{
+	int fd;
+	int ret = 0;
+	struct stat st;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		return 0;
+
+	/* check owner and modes */
+	if (fstat(fd, &st) < 0 ||
+	    (st.st_uid != 0 && st.st_uid != getuid()) ||
+	    (st.st_mode & 077) != 0) {
+		close(fd);
+		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+		error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
+		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+		error("Bad ownership or mode(0%3.3o) for '%s'.",
+		      st.st_mode & 0777, filename);
+		error("It is recommended that your private key files are NOT accessible by others.");
+		return 0;
+	}
+	switch (key->type) {
+	case KEY_RSA:
+		if (key->rsa->e != NULL) {
+			BN_clear_free(key->rsa->e);
+			key->rsa->e = NULL;
+		}
+		if (key->rsa->n != NULL) {
+			BN_clear_free(key->rsa->n);
+			key->rsa->n = NULL;
+		}
+		ret = load_private_key_rsa(fd, filename, passphrase,
+		     key->rsa, comment_return);
+		break;
+	case KEY_DSA:
+		ret = load_private_key_dsa(fd, passphrase, key, comment_return);
+	default:
+		break;
+	}
+	close(fd);
+	return ret;
+}
diff --git a/authfile.h b/authfile.h
new file mode 100644
index 0000000..afec27d
--- /dev/null
+++ b/authfile.h
@@ -0,0 +1,36 @@
+#ifndef AUTHFILE_H
+#define AUTHFILE_H
+
+/*
+ * Saves the authentication (private) key in a file, encrypting it with
+ * passphrase.
+ * For RSA keys: The identification of the file (lowest 64 bits of n)
+ * will precede the key to provide identification of the key without
+ * needing a passphrase.
+ */
+int
+save_private_key(const char *filename, const char *passphrase,
+    Key * private_key, const char *comment);
+
+/*
+ * Loads the public part of the key file (public key and comment). Returns 0
+ * if an error occurred; zero if the public key was successfully read.  The
+ * comment of the key is returned in comment_return if it is non-NULL; the
+ * caller must free the value with xfree.
+ */
+int
+load_public_key(const char *filename, Key * pub,
+    char **comment_return);
+
+/*
+ * Loads the private key from the file.  Returns 0 if an error is encountered
+ * (file does not exist or is not readable, or passphrase is bad). This
+ * initializes the private key.  The comment of the key is returned in
+ * comment_return if it is non-NULL; the caller must free the value with
+ * xfree.
+ */
+int
+load_private_key(const char *filename, const char *passphrase,
+    Key * private_key, char **comment_return);
+
+#endif
diff --git a/compat.c b/compat.c
index 4673e3f..3bf45c1 100644
--- a/compat.c
+++ b/compat.c
@@ -28,7 +28,7 @@
  */
 
 #include "includes.h"
-RCSID("$Id: compat.c,v 1.8 2000/04/16 01:18:42 damien Exp $");
+RCSID("$Id: compat.c,v 1.9 2000/04/29 13:57:10 damien Exp $");
 
 #include "ssh.h"
 #include "packet.h"
@@ -44,7 +44,6 @@
 {
 	verbose("Enabling compatibility mode for protocol 2.0");
 	compat20 = 1;
-	packet_set_ssh2_format();
 }
 void
 enable_compat13(void)
diff --git a/dsa.c b/dsa.c
index 1594c14..a4f6d3e 100644
--- a/dsa.c
+++ b/dsa.c
@@ -28,7 +28,7 @@
  */
 
 #include "includes.h"
-RCSID("$Id: dsa.c,v 1.4 2000/04/14 10:30:31 markus Exp $");
+RCSID("$Id: dsa.c,v 1.5 2000/04/26 20:56:29 markus Exp $");
 
 #include "ssh.h"
 #include "xmalloc.h"
@@ -47,13 +47,14 @@
 #include <openssl/hmac.h>
 #include "kex.h"
 #include "key.h"
+#include "uuencode.h"
 
 #define INTBLOB_LEN	20
 #define SIGBLOB_LEN	(2*INTBLOB_LEN)
 
 Key *
-dsa_serverkey_from_blob(
-    char *serverhostkey, int serverhostkeylen)
+dsa_key_from_blob(
+    char *blob, int blen)
 {
 	Buffer b;
 	char *ktype;
@@ -61,14 +62,17 @@
 	DSA *dsa;
 	Key *key;
 
+#ifdef DEBUG_DSS
+	dump_base64(blob, blen);
+#endif
 	/* fetch & parse DSA/DSS pubkey */
 	key = key_new(KEY_DSA);
 	dsa = key->dsa;
 	buffer_init(&b);
-	buffer_append(&b, serverhostkey, serverhostkeylen);
+	buffer_append(&b, blob, blen);
 	ktype = buffer_get_string(&b, NULL);
 	if (strcmp(KEX_DSS, ktype) != 0) {
-		error("dsa_serverkey_from_blob: cannot handle type  %s", ktype);
+		error("dsa_key_from_blob: cannot handle type  %s", ktype);
 		key_free(key);
 		return NULL;
 	}
@@ -78,7 +82,7 @@
 	buffer_get_bignum2(&b, dsa->pub_key);
 	rlen = buffer_len(&b);
 	if(rlen != 0)
-		error("dsa_serverkey_from_blob: remaining bytes in serverhostkey %d", rlen);
+		error("dsa_key_from_blob: remaining bytes in key blob %d", rlen);
 	buffer_free(&b);
 
 	debug("keytype %s", ktype);
@@ -87,37 +91,8 @@
 #endif
 	return key;
 }
-DSA *
-dsa_load_private(char *filename)
-{
-	DSA *dsa;
-	BIO *in;
-
-	in = BIO_new(BIO_s_file());
-	if (in == NULL)
-		fatal("BIO_new failed");
-	if (BIO_read_filename(in, filename) <= 0)
-		fatal("BIO_read failed %s: %s", filename, strerror(errno));
-	fprintf(stderr, "read DSA private key\n");
-	dsa = PEM_read_bio_DSAPrivateKey(in,NULL,NULL,NULL);
-	if (dsa == NULL)
-		fatal("PEM_read_bio_DSAPrivateKey failed %s", filename);
-	BIO_free(in);
-	return dsa;
-}
-Key *
-dsa_get_serverkey(char *filename)
-{
-	Key *k = key_new(KEY_EMPTY);
-	k->type = KEY_DSA;
-	k->dsa = dsa_load_private(filename);
-#ifdef DEBUG_DSS
-	DSA_print_fp(stderr, dsa, 8);
-#endif
-	return k;
-}
 int
-dsa_make_serverkey_blob(Key *key, unsigned char **blobp, unsigned int *lenp)
+dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp)
 {
 	Buffer b;
 	int len;
@@ -146,7 +121,7 @@
 dsa_sign(
     Key *key,
     unsigned char **sigp, int *lenp,
-    unsigned char *hash, int hlen)
+    unsigned char *data, int datalen)
 {
 	unsigned char *digest;
 	unsigned char *ret;
@@ -165,10 +140,13 @@
 	}
 	digest = xmalloc(evp_md->md_size);
 	EVP_DigestInit(&md, evp_md);
-	EVP_DigestUpdate(&md, hash, hlen);
+	EVP_DigestUpdate(&md, data, datalen);
 	EVP_DigestFinal(&md, digest, NULL);
 
 	sig = DSA_do_sign(digest, evp_md->md_size, key->dsa);
+	if (sig == NULL) {
+		fatal("dsa_sign: cannot sign");
+	}
 
 	rlen = BN_num_bytes(sig->r);
 	slen = BN_num_bytes(sig->s);
@@ -212,7 +190,7 @@
 dsa_verify(
     Key *key,
     unsigned char *signature, int signaturelen,
-    unsigned char *hash, int hlen)
+    unsigned char *data, int datalen)
 {
 	Buffer b;
 	unsigned char *digest;
@@ -269,10 +247,10 @@
 		xfree(sigblob);
 	}
 	
-	/* sha1 the signed data (== session_id == hash) */
+	/* sha1 the data */
 	digest = xmalloc(evp_md->md_size);
 	EVP_DigestInit(&md, evp_md);
-	EVP_DigestUpdate(&md, hash, hlen);
+	EVP_DigestUpdate(&md, data, datalen);
 	EVP_DigestFinal(&md, digest, NULL);
 
 	ret = DSA_do_verify(digest, evp_md->md_size, sig, key->dsa);
@@ -296,3 +274,21 @@
 	debug("dsa_verify: signature %s", txt);
 	return ret;
 }
+
+Key *
+dsa_generate_key(unsigned int bits)
+{
+	DSA *dsa = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
+	Key *k;
+	if (dsa == NULL) {
+		fatal("DSA_generate_parameters failed");
+	}
+	if (!DSA_generate_key(dsa)) {
+		fatal("DSA_generate_keys failed");
+	}
+
+	k = key_new(KEY_EMPTY);
+	k->type = KEY_DSA;
+	k->dsa = dsa;
+	return k;
+}
diff --git a/dsa.h b/dsa.h
index 65e651d..3cece7c 100644
--- a/dsa.h
+++ b/dsa.h
@@ -1,20 +1,22 @@
 #ifndef DSA_H
 #define DSA_H
 
-Key	*dsa_serverkey_from_blob(char *serverhostkey, int serverhostkeylen);
-Key	*dsa_get_serverkey(char *filename);
-int	dsa_make_serverkey_blob(Key *key, unsigned char **blobp, unsigned int *lenp);
+Key	*dsa_key_from_blob(char *blob, int blen);
+int	dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp);
 
 int
 dsa_sign(
     Key *key,
     unsigned char **sigp, int *lenp,
-    unsigned char *hash, int hlen);
+    unsigned char *data, int datalen);
 
 int
 dsa_verify(
     Key *key,
     unsigned char *signature, int signaturelen,
-    unsigned char *hash, int hlen);
+    unsigned char *data, int datalen);
+
+Key *
+dsa_generate_key(unsigned int bits);
 
 #endif
diff --git a/hostfile.c b/hostfile.c
index 29efe56..e1c2429 100644
--- a/hostfile.c
+++ b/hostfile.c
@@ -14,7 +14,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: hostfile.c,v 1.16 2000/04/14 10:30:31 markus Exp $");
+RCSID("$OpenBSD: hostfile.c,v 1.17 2000/04/26 20:56:29 markus Exp $");
 
 #include "packet.h"
 #include "match.h"
@@ -39,13 +39,8 @@
 	for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
 		;
 
-	/* Get number of bits. */
-	if (*cp < '0' || *cp > '9')
-		return 0;	/* Bad bit count... */
-	for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
-		bits = 10 * bits + *cp - '0';
-
-	if (!key_read(ret, bits, &cp))
+	bits = key_read(ret, &cp);
+	if (bits == 0)
 		return 0;
 
 	/* Skip trailing whitespace. */
@@ -182,24 +177,18 @@
 {
 	FILE *f;
 	int success = 0;
-
 	if (key == NULL)
-		return 1;
-
-	/* Open the file for appending. */
+		return 1;	/* XXX ? */
 	f = fopen(filename, "a");
 	if (!f)
 		return 0;
-
 	fprintf(f, "%s ", host);
 	if (key_write(key, f)) {
-		fprintf(f, "\n");
 		success = 1;
 	} else {
-		error("add_host_to_hostfile: saving key failed");
+		error("add_host_to_hostfile: saving key in %s failed", filename);
 	}
-
-	/* Close the file. */
+	fprintf(f, "\n");
 	fclose(f);
 	return success;
 }
diff --git a/key.c b/key.c
index 872313a..583c529 100644
--- a/key.c
+++ b/key.c
@@ -38,6 +38,10 @@
 #include <openssl/evp.h>
 #include "xmalloc.h"
 #include "key.h"
+#include "dsa.h"
+#include "uuencode.h"
+
+#define SSH_DSS "ssh-dss"
 
 Key *
 key_new(int type)
@@ -47,6 +51,8 @@
 	DSA *dsa;
 	k = xmalloc(sizeof(*k));
 	k->type = type;
+	k->dsa = NULL;
+	k->rsa = NULL;
 	switch (k->type) {
 	case KEY_RSA:
 		rsa = RSA_new();
@@ -63,8 +69,6 @@
 		k->dsa = dsa;
 		break;
 	case KEY_EMPTY:
-		k->dsa = NULL;
-		k->rsa = NULL;
 		break;
 	default:
 		fatal("key_new: bad key type %d", k->type);
@@ -111,7 +115,7 @@
 		    BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
 		break;
 	default:
-		fatal("key_free: bad key type %d", a->type);
+		fatal("key_equal: bad key type %d", a->type);
 		break;
 	}
 	return 0;
@@ -127,46 +131,37 @@
 key_fingerprint(Key *k)
 {
 	static char retval[80];
-	unsigned char *buf = NULL;
+	unsigned char *blob = NULL;
 	int len = 0;
-	int nlen, elen, plen, qlen, glen, publen;
+	int nlen, elen;
 
 	switch (k->type) {
 	case KEY_RSA:
 		nlen = BN_num_bytes(k->rsa->n);
 		elen = BN_num_bytes(k->rsa->e);
 		len = nlen + elen;
-		buf = xmalloc(len);
-		BN_bn2bin(k->rsa->n, buf);
-		BN_bn2bin(k->rsa->e, buf + nlen);
+		blob = xmalloc(len);
+		BN_bn2bin(k->rsa->n, blob);
+		BN_bn2bin(k->rsa->e, blob + nlen);
 		break;
 	case KEY_DSA:
-		plen = BN_num_bytes(k->dsa->p);
-		qlen = BN_num_bytes(k->dsa->q);
-		glen = BN_num_bytes(k->dsa->g);
-		publen = BN_num_bytes(k->dsa->pub_key);
-		len = qlen + qlen + glen + publen;
-		buf = xmalloc(len);
-		BN_bn2bin(k->dsa->p, buf);
-		BN_bn2bin(k->dsa->q, buf + plen);
-		BN_bn2bin(k->dsa->g, buf + plen + qlen);
-		BN_bn2bin(k->dsa->pub_key , buf + plen + qlen + glen);
+		dsa_make_key_blob(k, &blob, &len);
 		break;
 	default:
 		fatal("key_fingerprint: bad key type %d", k->type);
 		break;
 	}
-	if (buf != NULL) {
+	if (blob != NULL) {
 		unsigned char d[16];
 		EVP_MD_CTX md;
 		EVP_DigestInit(&md, EVP_md5());
-		EVP_DigestUpdate(&md, buf, len);
+		EVP_DigestUpdate(&md, blob, len);
 		EVP_DigestFinal(&md, d, NULL);
 		snprintf(retval, sizeof(retval), FPRINT,
 		    d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
 		    d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
-		memset(buf, 0, len);
-		xfree(buf);
+		memset(blob, 0, len);
+		xfree(blob);
 	}
 	return retval;
 }
@@ -226,13 +221,27 @@
 	free(buf);
 	return 1;
 }
-int
-key_read(Key *ret, unsigned int bits, char **cpp)
+unsigned int
+key_read(Key *ret, char **cpp)
 {
+	Key *k;
+	unsigned int bits = 0;
+	char *cp;
+	int len, n;
+	unsigned char *blob;
+
+	cp = *cpp;
+
 	switch(ret->type) {
 	case KEY_RSA:
+		/* Get number of bits. */
+		if (*cp < '0' || *cp > '9')
+			return 0;	/* Bad bit count... */
+		for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
+			bits = 10 * bits + *cp - '0';
 		if (bits == 0)
 			return 0;
+		*cpp = cp;
 		/* Get public exponent, public modulus. */
 		if (!read_bignum(cpp, ret->rsa->e))
 			return 0;
@@ -240,22 +249,32 @@
 			return 0;
 		break;
 	case KEY_DSA:
-		if (bits != 0)
+		if (strncmp(cp, SSH_DSS " ", 7) != 0)
 			return 0;
-		if (!read_bignum(cpp, ret->dsa->p))
+		cp += 7;
+		len = 2*strlen(cp);
+		blob = xmalloc(len);
+		n = uudecode(cp, blob, len);
+		k = dsa_key_from_blob(blob, n);
+		if (k == NULL)
+			 return 0;
+		xfree(blob);
+		if (ret->dsa != NULL)
+			DSA_free(ret->dsa);
+		ret->dsa = k->dsa;
+		k->dsa = NULL;
+		key_free(k);
+		bits = BN_num_bits(ret->dsa->p);
+		cp = strchr(cp, '=');
+		if (cp == NULL)
 			return 0;
-		if (!read_bignum(cpp, ret->dsa->q))
-			return 0;
-		if (!read_bignum(cpp, ret->dsa->g))
-			return 0;
-		if (!read_bignum(cpp, ret->dsa->pub_key))
-			return 0;
+		*cpp = cp + 1;
 		break;
 	default:
-		fatal("bad key type: %d", ret->type);
+		fatal("key_read: bad key type: %d", ret->type);
 		break;
 	}
-	return 1;
+	return bits;
 }
 int
 key_write(Key *key, FILE *f)
@@ -274,17 +293,15 @@
 			error("key_write: failed for RSA key");
 		}
 	} else if (key->type == KEY_DSA && key->dsa != NULL) {
-		/* bits == 0 means DSA key */
-		bits = 0;
-		fprintf(f, "%u", bits);
-		if (write_bignum(f, key->dsa->p) &&
-		    write_bignum(f, key->dsa->q) &&
-		    write_bignum(f, key->dsa->g) &&
-		    write_bignum(f, key->dsa->pub_key)) {
-			success = 1;
-		} else {
-			error("key_write: failed for DSA key");
-		}
+		int len, n;
+		unsigned char *blob, *uu;
+		dsa_make_key_blob(key, &blob, &len);
+		uu = xmalloc(2*len);
+		n = uuencode(blob, len, uu);
+		fprintf(f, "%s %s", SSH_DSS, uu);
+		xfree(blob);
+		xfree(uu);
+		success = 1;
 	}
 	return success;
 }
diff --git a/key.h b/key.h
index 70f0c51..d1bcf3b 100644
--- a/key.h
+++ b/key.h
@@ -18,6 +18,7 @@
 int	key_equal(Key *a, Key *b);
 char	*key_fingerprint(Key *k);
 int	key_write(Key *key, FILE *f);
-int	key_read(Key *key, unsigned int bits, char **cpp);
+unsigned int
+key_read(Key *key, char **cpp);
 
 #endif
diff --git a/radix.c b/radix.c
index 84e390f..9d1c999 100644
--- a/radix.c
+++ b/radix.c
@@ -1,109 +1,15 @@
 /*
  *   radix.c
  *
- *   base-64 encoding pinched from lynx2-7-2, who pinched it from rpem.
- *   Originally written by Mark Riordan 12 August 1990 and 17 Feb 1991
- *   and placed in the public domain.
- *
  *   Dug Song <dugsong@UMICH.EDU>
  */
 
 #include "includes.h"
+#include "uuencode.h"
 
 #ifdef AFS
 #include <krb.h>
 
-char six2pr[64] = {
-	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
-	'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
-	'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
-	'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
-	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
-};
-
-unsigned char pr2six[256];
-
-int
-uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded)
-{
-	/* ENC is the basic 1 character encoding function to make a char printing */
-#define ENC(c) six2pr[c]
-
-	register char *outptr = bufcoded;
-	unsigned int i;
-
-	for (i = 0; i < nbytes; i += 3) {
-		*(outptr++) = ENC(*bufin >> 2);						/* c1 */
-		*(outptr++) = ENC(((*bufin << 4) & 060)   | ((bufin[1] >> 4) & 017));	/* c2 */
-		*(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03));	/* c3 */
-		*(outptr++) = ENC(bufin[2] & 077);					/* c4 */
-		bufin += 3;
-	}
-	if (i == nbytes + 1) {
-		outptr[-1] = '=';
-	} else if (i == nbytes + 2) {
-		outptr[-1] = '=';
-		outptr[-2] = '=';
-	}
-	*outptr = '\0';
-	return (outptr - bufcoded);
-}
-
-int
-uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize)
-{
-	/* single character decode */
-#define DEC(c) pr2six[(unsigned char)c]
-#define MAXVAL 63
-
-	static int first = 1;
-	int nbytesdecoded, j;
-	const char *bufin = bufcoded;
-	register unsigned char *bufout = bufplain;
-	register int nprbytes;
-
-	/* If this is the first call, initialize the mapping table. */
-	if (first) {
-		first = 0;
-		for (j = 0; j < 256; j++)
-			pr2six[j] = MAXVAL + 1;
-		for (j = 0; j < 64; j++)
-			pr2six[(unsigned char) six2pr[j]] = (unsigned char) j;
-	}
-	/* Strip leading whitespace. */
-	while (*bufcoded == ' ' || *bufcoded == '\t')
-		bufcoded++;
-
-	/*
-	 * Figure out how many characters are in the input buffer. If this
-	 * would decode into more bytes than would fit into the output
-	 * buffer, adjust the number of input bytes downwards.
-	 */
-	bufin = bufcoded;
-	while (DEC(*(bufin++)) <= MAXVAL);
-	nprbytes = bufin - bufcoded - 1;
-	nbytesdecoded = ((nprbytes + 3) / 4) * 3;
-	if (nbytesdecoded > outbufsize)
-		nprbytes = (outbufsize * 4) / 3;
-
-	bufin = bufcoded;
-
-	while (nprbytes > 0) {
-		*(bufout++) = (unsigned char) (DEC(*bufin)   << 2 | DEC(bufin[1]) >> 4);
-		*(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2);
-		*(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3]));
-		bufin += 4;
-		nprbytes -= 4;
-	}
-	if (nprbytes & 03) {
-		if (DEC(bufin[-2]) > MAXVAL)
-			nbytesdecoded -= 2;
-		else
-			nbytesdecoded -= 1;
-	}
-	return (nbytesdecoded);
-}
-
 typedef unsigned char my_u_char;
 typedef unsigned int my_u_int32_t;
 typedef unsigned short my_u_short;
diff --git a/readconf.c b/readconf.c
index 3b75290..529f803 100644
--- a/readconf.c
+++ b/readconf.c
@@ -14,7 +14,7 @@
  */
 
 #include "includes.h"
-RCSID("$Id: readconf.c,v 1.11 2000/04/16 01:18:44 damien Exp $");
+RCSID("$Id: readconf.c,v 1.12 2000/04/29 13:57:11 damien Exp $");
 
 #include "ssh.h"
 #include "cipher.h"
@@ -104,7 +104,8 @@
 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
 	oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
-	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol
+	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2,
+	oGlobalKnownHostsFile2, oUserKnownHostsFile2
 } OpCodes;
 
 /* Textual representations of the tokens. */
@@ -131,6 +132,7 @@
 	{ "fallbacktorsh", oFallBackToRsh },
 	{ "usersh", oUseRsh },
 	{ "identityfile", oIdentityFile },
+	{ "identityfile2", oIdentityFile2 },
 	{ "hostname", oHostName },
 	{ "proxycommand", oProxyCommand },
 	{ "port", oPort },
@@ -145,6 +147,8 @@
 	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
 	{ "userknownhostsfile", oUserKnownHostsFile },
+	{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
+	{ "userknownhostsfile2", oUserKnownHostsFile2 },
 	{ "connectionattempts", oConnectionAttempts },
 	{ "batchmode", oBatchMode },
 	{ "checkhostip", oCheckHostIP },
@@ -368,14 +372,22 @@
 		goto parse_int;
 
 	case oIdentityFile:
+	case oIdentityFile2:
 		cp = strtok(NULL, WHITESPACE);
 		if (!cp)
 			fatal("%.200s line %d: Missing argument.", filename, linenum);
 		if (*activep) {
-			if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
+			intptr = (opcode == oIdentityFile) ?
+			    &options->num_identity_files :
+			    &options->num_identity_files2;
+			if (*intptr >= SSH_MAX_IDENTITY_FILES)
 				fatal("%.200s line %d: Too many identity files specified (max %d).",
 				      filename, linenum, SSH_MAX_IDENTITY_FILES);
-			options->identity_files[options->num_identity_files++] = xstrdup(cp);
+			charptr = (opcode == oIdentityFile) ?
+			    &options->identity_files[*intptr] :
+			    &options->identity_files2[*intptr];
+			*charptr = xstrdup(cp);
+			*intptr = *intptr + 1;
 		}
 		break;
 
@@ -397,6 +409,14 @@
 		charptr = &options->user_hostfile;
 		goto parse_string;
 
+	case oGlobalKnownHostsFile2:
+		charptr = &options->system_hostfile2;
+		goto parse_string;
+
+	case oUserKnownHostsFile2:
+		charptr = &options->user_hostfile2;
+		goto parse_string;
+
 	case oHostName:
 		charptr = &options->hostname;
 		goto parse_string;
@@ -642,12 +662,15 @@
 	options->ciphers = NULL;
 	options->protocol = SSH_PROTO_UNKNOWN;
 	options->num_identity_files = 0;
+	options->num_identity_files2 = 0;
 	options->hostname = NULL;
 	options->proxy_command = NULL;
 	options->user = NULL;
 	options->escape_char = -1;
 	options->system_hostfile = NULL;
 	options->user_hostfile = NULL;
+	options->system_hostfile2 = NULL;
+	options->user_hostfile2 = NULL;
 	options->num_local_forwards = 0;
 	options->num_remote_forwards = 0;
 	options->log_level = (LogLevel) - 1;
@@ -715,19 +738,31 @@
 	if (options->cipher == -1)
 		options->cipher = SSH_CIPHER_NOT_SET;
 	if (options->protocol == SSH_PROTO_UNKNOWN)
-		options->protocol = SSH_PROTO_1;
+		options->protocol = SSH_PROTO_1|SSH_PROTO_2|SSH_PROTO_1_PREFERRED;
 	if (options->num_identity_files == 0) {
 		options->identity_files[0] =
 			xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
 		sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
 		options->num_identity_files = 1;
 	}
+#if 0
+	if (options->num_identity_files2 == 0) {
+		options->identity_files2[0] =
+			xmalloc(2 + strlen(SSH2_CLIENT_IDENTITY) + 1);
+		sprintf(options->identity_files2[0], "~/%.100s", SSH2_CLIENT_IDENTITY);
+		options->num_identity_files2 = 1;
+	}
+#endif
 	if (options->escape_char == -1)
 		options->escape_char = '~';
 	if (options->system_hostfile == NULL)
 		options->system_hostfile = SSH_SYSTEM_HOSTFILE;
 	if (options->user_hostfile == NULL)
 		options->user_hostfile = SSH_USER_HOSTFILE;
+	if (options->system_hostfile2 == NULL)
+		options->system_hostfile2 = SSH_SYSTEM_HOSTFILE2;
+	if (options->user_hostfile2 == NULL)
+		options->user_hostfile2 = SSH_USER_HOSTFILE2;
 	if (options->log_level == (LogLevel) - 1)
 		options->log_level = SYSLOG_LEVEL_INFO;
 	/* options->proxy_command should not be set by default */
diff --git a/readconf.h b/readconf.h
index 0582a8f..bbef923 100644
--- a/readconf.h
+++ b/readconf.h
@@ -13,7 +13,7 @@
  *
  */
 
-/* RCSID("$Id: readconf.h,v 1.8 2000/04/16 01:18:44 damien Exp $"); */
+/* RCSID("$Id: readconf.h,v 1.9 2000/04/29 13:57:11 damien Exp $"); */
 
 #ifndef READCONF_H
 #define READCONF_H
@@ -73,9 +73,13 @@
 
 	char   *system_hostfile;/* Path for /etc/ssh_known_hosts. */
 	char   *user_hostfile;	/* Path for $HOME/.ssh/known_hosts. */
+	char   *system_hostfile2;
+	char   *user_hostfile2;
 
 	int     num_identity_files;	/* Number of files for RSA identities. */
+	int     num_identity_files2;	/* DSA identities. */
 	char   *identity_files[SSH_MAX_IDENTITY_FILES];
+	char   *identity_files2[SSH_MAX_IDENTITY_FILES];
 
 	/* Local TCP/IP forward requests. */
 	int     num_local_forwards;
diff --git a/servconf.c b/servconf.c
index fe72d27..298fefb 100644
--- a/servconf.c
+++ b/servconf.c
@@ -12,7 +12,7 @@
  */
 
 #include "includes.h"
-RCSID("$Id: servconf.c,v 1.12 2000/04/16 01:18:45 damien Exp $");
+RCSID("$Id: servconf.c,v 1.13 2000/04/29 13:57:11 damien Exp $");
 
 #include "ssh.h"
 #include "servconf.h"
@@ -143,7 +143,7 @@
 	if (options->use_login == -1)
 		options->use_login = 0;
 	if (options->protocol == SSH_PROTO_UNKNOWN)
-		options->protocol = SSH_PROTO_1;
+		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
 }
 
 #define WHITESPACE " \t\r\n"
diff --git a/serverloop.c b/serverloop.c
index 1a76b8d..1e03187 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -733,7 +733,7 @@
 	rwindow = packet_get_int();
 	rmaxpack = packet_get_int();
 
-	log("channel_input_open: ctype %s rchan %d win %d max %d",
+	debug("channel_input_open: ctype %s rchan %d win %d max %d",
 	    ctype, rchan, rwindow, rmaxpack);
 
 	if (strcmp(ctype, "session") == 0) {
diff --git a/session.c b/session.c
index 68a016e..d5c53f1 100644
--- a/session.c
+++ b/session.c
@@ -8,7 +8,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.5 2000/04/19 09:24:39 markus Exp $");
+RCSID("$OpenBSD: session.c,v 1.6 2000/04/27 15:23:02 markus Exp $");
 
 #include "xmalloc.h"
 #include "ssh.h"
@@ -1474,6 +1474,5 @@
 	 * authentication.
 	 */
 	alarm(0);
-	log("do_authenticated2");
 	server_loop2();
 }
diff --git a/ssh-add.c b/ssh-add.c
index f01cca5..0d38830 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -7,13 +7,18 @@
  */
 
 #include "includes.h"
-RCSID("$Id: ssh-add.c,v 1.16 1999/12/06 00:47:29 damien Exp $");
+RCSID("$Id: ssh-add.c,v 1.17 2000/04/29 13:57:12 damien Exp $");
+
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
 
 #include "rsa.h"
 #include "ssh.h"
 #include "xmalloc.h"
 #include "authfd.h"
 #include "fingerprint.h"
+#include "key.h"
+#include "authfile.h"
 
 #ifdef HAVE___PROGNAME
 extern char *__progname;
@@ -24,19 +29,19 @@
 void
 delete_file(AuthenticationConnection *ac, const char *filename)
 {
-	RSA *key;
+	Key *public;
 	char *comment;
 
-	key = RSA_new();
-	if (!load_public_key(filename, key, &comment)) {
+	public = key_new(KEY_RSA);
+	if (!load_public_key(filename, public, &comment)) {
 		printf("Bad key file %s: %s\n", filename, strerror(errno));
 		return;
 	}
-	if (ssh_remove_identity(ac, key))
+	if (ssh_remove_identity(ac, public->rsa))
 		fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
 	else
 		fprintf(stderr, "Could not remove identity: %s\n", filename);
-	RSA_free(key);
+	key_free(public);
 	xfree(comment);
 }
 
@@ -91,20 +96,19 @@
 void
 add_file(AuthenticationConnection *ac, const char *filename)
 {
-	RSA *key;
-	RSA *public_key;
+	Key *public;
+	Key *private;
 	char *saved_comment, *comment, *askpass = NULL;
 	char buf[1024], msg[1024];
 	int success;
 	int interactive = isatty(STDIN_FILENO);
 
-	key = RSA_new();
-	public_key = RSA_new();
-	if (!load_public_key(filename, public_key, &saved_comment)) {
+	public = key_new(KEY_RSA);
+	if (!load_public_key(filename, public, &saved_comment)) {
 		printf("Bad key file %s: %s\n", filename, strerror(errno));
 		return;
 	}
-	RSA_free(public_key);
+	key_free(public);
 
 	if (!interactive && getenv("DISPLAY")) {
 		if (getenv(SSH_ASKPASS_ENV))
@@ -114,7 +118,8 @@
 	}
 
 	/* At first, try empty passphrase */
-	success = load_private_key(filename, "", key, &comment);
+	private = key_new(KEY_RSA);
+	success = load_private_key(filename, "", private, &comment);
 	if (!success) {
 		printf("Need passphrase for %.200s\n", filename);
 		if (!interactive && askpass == NULL) {
@@ -135,7 +140,7 @@
 				xfree(saved_comment);
 				return;
 			}
-			success = load_private_key(filename, pass, key, &comment);
+			success = load_private_key(filename, pass, private, &comment);
 			memset(pass, 0, strlen(pass));
 			xfree(pass);
 			if (success)
@@ -145,11 +150,11 @@
 	}
 	xfree(saved_comment);
 
-	if (ssh_add_identity(ac, key, comment))
+	if (ssh_add_identity(ac, private->rsa, comment))
 		fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
 	else
 		fprintf(stderr, "Could not add identity: %s\n", filename);
-	RSA_free(key);
+	key_free(private);
 	xfree(comment);
 }
 
diff --git a/ssh-keygen.1 b/ssh-keygen.1
index b809a1a..486de04 100644
--- a/ssh-keygen.1
+++ b/ssh-keygen.1
@@ -9,7 +9,7 @@
 .\"
 .\" Created: Sat Apr 22 23:55:14 1995 ylo
 .\"
-.\" $Id: ssh-keygen.1,v 1.12 2000/04/20 13:27:27 damien Exp $
+.\" $Id: ssh-keygen.1,v 1.13 2000/04/29 13:57:12 damien Exp $
 .\"
 .Dd September 25, 1999
 .Dt SSH-KEYGEN 1
@@ -37,6 +37,8 @@
 .Nm ssh-keygen
 .Fl l
 .Op Fl f Ar keyfile
+.Nm ssh-keygen
+.Fl R
 .Sh DESCRIPTION
 .Nm
 generates and manages authentication keys for
@@ -112,6 +114,10 @@
 Provides the new passphrase.
 .It Fl P Ar passphrase
 Provides the (old) passphrase.
+.It Fl R
+If RSA support is functional, immediately exits with code 0.  If RSA
+support is not functional, exits with code 1.  This flag will be
+removed once the RSA patent expires.
 .El
 .Sh FILES
 .Bl -tag -width Ds
diff --git a/ssh-keygen.c b/ssh-keygen.c
index f2484a4..0155949 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -7,20 +7,23 @@
  */
 
 #include "includes.h"
-RCSID("$Id: ssh-keygen.c,v 1.13 2000/04/16 01:18:46 damien Exp $");
+RCSID("$Id: ssh-keygen.c,v 1.14 2000/04/29 13:57:12 damien Exp $");
 
-#include "rsa.h"
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+
 #include "ssh.h"
 #include "xmalloc.h"
 #include "fingerprint.h"
+#include "key.h"
+#include "rsa.h"
+#include "dsa.h"
+#include "authfile.h"
+#include "uuencode.h"
 
-/* Generated private key. */
-RSA *private_key;
-
-/* Generated public key. */
-RSA *public_key;
-
-/* Number of bits in the RSA key.  This value can be changed on the command line. */
+/* Number of bits in the RSA/DSA key.  This value can be changed on the command line. */
 int bits = 1024;
 
 /*
@@ -53,6 +56,12 @@
 /* This is set to the new comment if given on the command line. */
 char *identity_comment = NULL;
 
+/* Dump public key file in format used by real and the original SSH 2 */
+int convert_to_ssh2 = 0;
+int convert_from_ssh2 = 0;
+int print_public = 0;
+int dsa_mode = 0;
+
 /* argv0 */
 #ifdef HAVE___PROGNAME
 extern char *__progname;
@@ -60,6 +69,8 @@
 const char *__progname = "ssh-keygen";
 #endif /* HAVE___PROGNAME */
 
+char hostname[MAXHOSTNAMELEN];
+
 void
 ask_filename(struct passwd *pw, const char *prompt)
 {
@@ -77,12 +88,140 @@
 	have_identity = 1;
 }
 
+int
+try_load_key(char *filename, Key *k)
+{
+	int success = 1;
+	if (!load_private_key(filename, "", k, NULL)) {
+		char *pass = read_passphrase("Enter passphrase: ", 1);
+		if (!load_private_key(filename, pass, k, NULL)) {
+			success = 0;
+		}
+		memset(pass, 0, strlen(pass));
+		xfree(pass);
+	}
+	return success;
+}
+
+#define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
+#define SSH_COM_MAGIC_END   "---- END SSH2 PUBLIC KEY ----"
+
+void
+do_convert_to_ssh2(struct passwd *pw)
+{
+	Key *k;
+	int len;
+	unsigned char *blob;
+	struct stat st;
+
+	if (!have_identity)
+		ask_filename(pw, "Enter file in which the key is");
+	if (stat(identity_file, &st) < 0) {
+		perror(identity_file);
+		exit(1);
+	}
+	k = key_new(KEY_DSA);
+	if (!try_load_key(identity_file, k)) {
+		fprintf(stderr, "load failed\n");
+		exit(1);
+	}
+	dsa_make_key_blob(k, &blob, &len);
+	fprintf(stdout, SSH_COM_MAGIC_BEGIN "\n");
+	fprintf(stdout,
+	    "Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n",
+	    BN_num_bits(k->dsa->p),
+	    pw->pw_name, hostname);
+	dump_base64(stdout, blob, len);
+	fprintf(stdout, SSH_COM_MAGIC_END "\n");
+	key_free(k);
+	xfree(blob);
+	exit(0);
+}
+
+void
+do_convert_from_ssh2(struct passwd *pw)
+{
+	Key *k;
+	int blen;
+	char line[1024], *p;
+	char blob[8096];
+	char encoded[8096];
+	struct stat st;
+	FILE *fp;
+
+	if (!have_identity)
+		ask_filename(pw, "Enter file in which the key is");
+	if (stat(identity_file, &st) < 0) {
+		perror(identity_file);
+		exit(1);
+	}
+	fp = fopen(identity_file, "r");
+	if (fp == NULL) {
+		perror(identity_file);
+		exit(1);
+	}
+	encoded[0] = '\0';
+	while (fgets(line, sizeof(line), fp)) {
+		if (strncmp(line, "----", 4) == 0 ||
+		    strstr(line, ": ") != NULL) {
+			fprintf(stderr, "ignore: %s", line);
+			continue;
+		}
+		if (!(p = strchr(line, '\n'))) {
+			fprintf(stderr, "input line too long.\n");
+			exit(1);
+		}
+		*p = '\0';
+		strlcat(encoded, line, sizeof(encoded));
+	}
+	blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob));
+	if (blen < 0) {
+		fprintf(stderr, "uudecode failed.\n");
+		exit(1);
+	}
+	k = dsa_key_from_blob(blob, blen);
+	if (!key_write(k, stdout))
+		fprintf(stderr, "key_write failed");
+	key_free(k);
+	fprintf(stdout, "\n");
+	fclose(fp);
+	exit(0);
+}
+
+void
+do_print_public(struct passwd *pw)
+{
+	Key *k;
+	int len;
+	unsigned char *blob;
+	struct stat st;
+
+	if (!have_identity)
+		ask_filename(pw, "Enter file in which the key is");
+	if (stat(identity_file, &st) < 0) {
+		perror(identity_file);
+		exit(1);
+	}
+	k = key_new(KEY_DSA);
+	if (!try_load_key(identity_file, k)) {
+		fprintf(stderr, "load failed\n");
+		exit(1);
+	}
+	dsa_make_key_blob(k, &blob, &len);
+	if (!key_write(k, stdout))
+		fprintf(stderr, "key_write failed");
+	key_free(k);
+	xfree(blob);
+	fprintf(stdout, "\n");
+	exit(0);
+}
+
 void
 do_fingerprint(struct passwd *pw)
 {
 	FILE *f;
 	BIGNUM *e, *n;
-	RSA *public_key;
+	Key *public;
 	char *comment = NULL, *cp, *ep, line[16*1024];
 	int i, skip = 0, num = 1, invalid = 1;
 	unsigned int ignore;
@@ -94,17 +233,16 @@
 		perror(identity_file);
 		exit(1);
 	}
-	
-	public_key = RSA_new();
-	if (load_public_key(identity_file, public_key, &comment)) {
-		printf("%d %s %s\n", BN_num_bits(public_key->n),
-		    fingerprint(public_key->e, public_key->n),
-		    comment);
-		RSA_free(public_key);
+	public = key_new(KEY_RSA);
+	if (load_public_key(identity_file, public, &comment)) {
+		printf("%d %s %s\n", BN_num_bits(public->rsa->n),
+		    key_fingerprint(public), comment);
+		key_free(public);
 		exit(0);
 	}
-	RSA_free(public_key);
+	key_free(public);
 
+	/* XXX */
 	f = fopen(identity_file, "r");
 	if (f != NULL) {
 		n = BN_new();
@@ -172,7 +310,9 @@
 	char *comment;
 	char *old_passphrase, *passphrase1, *passphrase2;
 	struct stat st;
-	RSA *private_key;
+	Key *private;
+	Key *public;
+	int type = dsa_mode ? KEY_DSA : KEY_RSA;
 
 	if (!have_identity)
 		ask_filename(pw, "Enter file in which the key is");
@@ -180,22 +320,26 @@
 		perror(identity_file);
 		exit(1);
 	}
-	public_key = RSA_new();
-	if (!load_public_key(identity_file, public_key, NULL)) {
-		printf("%s is not a valid key file.\n", identity_file);
-		exit(1);
+
+	if (type == KEY_RSA) {
+		/* XXX this works currently only for RSA */
+		public = key_new(type);
+		if (!load_public_key(identity_file, public, NULL)) {
+			printf("%s is not a valid key file.\n", identity_file);
+			exit(1);
+		}
+		/* Clear the public key since we are just about to load the whole file. */
+		key_free(public);
 	}
-	/* Clear the public key since we are just about to load the whole file. */
-	RSA_free(public_key);
 
 	/* Try to load the file with empty passphrase. */
-	private_key = RSA_new();
-	if (!load_private_key(identity_file, "", private_key, &comment)) {
+	private = key_new(type);
+	if (!load_private_key(identity_file, "", private, &comment)) {
 		if (identity_passphrase)
 			old_passphrase = xstrdup(identity_passphrase);
 		else
 			old_passphrase = read_passphrase("Enter old passphrase: ", 1);
-		if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) {
+		if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
 			memset(old_passphrase, 0, strlen(old_passphrase));
 			xfree(old_passphrase);
 			printf("Bad passphrase.\n");
@@ -230,19 +374,19 @@
 	}
 
 	/* Save the file using the new passphrase. */
-	if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
+	if (!save_private_key(identity_file, passphrase1, private, comment)) {
 		printf("Saving the key failed: %s: %s.\n",
 		       identity_file, strerror(errno));
 		memset(passphrase1, 0, strlen(passphrase1));
 		xfree(passphrase1);
-		RSA_free(private_key);
+		key_free(private);
 		xfree(comment);
 		exit(1);
 	}
 	/* Destroy the passphrase and the copy of the key in memory. */
 	memset(passphrase1, 0, strlen(passphrase1));
 	xfree(passphrase1);
-	RSA_free(private_key);	/* Destroys contents */
+	key_free(private);		 /* Destroys contents */
 	xfree(comment);
 
 	printf("Your identification has been saved with the new passphrase.\n");
@@ -256,11 +400,11 @@
 do_change_comment(struct passwd *pw)
 {
 	char new_comment[1024], *comment;
-	RSA *private_key;
+	Key *private;
+	Key *public;
 	char *passphrase;
 	struct stat st;
 	FILE *f;
-	char *tmpbuf;
 
 	if (!have_identity)
 		ask_filename(pw, "Enter file in which the key is");
@@ -272,14 +416,14 @@
 	 * Try to load the public key from the file the verify that it is
 	 * readable and of the proper format.
 	 */
-	public_key = RSA_new();
-	if (!load_public_key(identity_file, public_key, NULL)) {
+	public = key_new(KEY_RSA);
+	if (!load_public_key(identity_file, public, NULL)) {
 		printf("%s is not a valid key file.\n", identity_file);
 		exit(1);
 	}
-	private_key = RSA_new();
 
-	if (load_private_key(identity_file, "", private_key, &comment))
+	private = key_new(KEY_RSA);
+	if (load_private_key(identity_file, "", private, &comment))
 		passphrase = xstrdup("");
 	else {
 		if (identity_passphrase)
@@ -289,7 +433,7 @@
 		else
 			passphrase = read_passphrase("Enter passphrase: ", 1);
 		/* Try to load using the passphrase. */
-		if (!load_private_key(identity_file, passphrase, private_key, &comment)) {
+		if (!load_private_key(identity_file, passphrase, private, &comment)) {
 			memset(passphrase, 0, strlen(passphrase));
 			xfree(passphrase);
 			printf("Bad passphrase.\n");
@@ -305,7 +449,7 @@
 		fflush(stdout);
 		if (!fgets(new_comment, sizeof(new_comment), stdin)) {
 			memset(passphrase, 0, strlen(passphrase));
-			RSA_free(private_key);
+			key_free(private);
 			exit(1);
 		}
 		if (strchr(new_comment, '\n'))
@@ -313,18 +457,18 @@
 	}
 
 	/* Save the file using the new passphrase. */
-	if (!save_private_key(identity_file, passphrase, private_key, new_comment)) {
+	if (!save_private_key(identity_file, passphrase, private, new_comment)) {
 		printf("Saving the key failed: %s: %s.\n",
 		       identity_file, strerror(errno));
 		memset(passphrase, 0, strlen(passphrase));
 		xfree(passphrase);
-		RSA_free(private_key);
+		key_free(private);
 		xfree(comment);
 		exit(1);
 	}
 	memset(passphrase, 0, strlen(passphrase));
 	xfree(passphrase);
-	RSA_free(private_key);
+	key_free(private);
 
 	strlcat(identity_file, ".pub", sizeof(identity_file));
 	f = fopen(identity_file, "w");
@@ -332,13 +476,10 @@
 		printf("Could not save your public key in %s\n", identity_file);
 		exit(1);
 	}
-	fprintf(f, "%d ", BN_num_bits(public_key->n));
-	tmpbuf = BN_bn2dec(public_key->e);
-	fprintf(f, "%s ", tmpbuf);
-	free(tmpbuf);
-	tmpbuf = BN_bn2dec(public_key->n);
-	fprintf(f, "%s %s\n", tmpbuf, new_comment);
-	free(tmpbuf);
+	if (!key_write(public, f))
+		fprintf(stderr, "write key failed");
+	key_free(public);
+	fprintf(f, " %s\n", new_comment);
 	fclose(f);
 
 	xfree(comment);
@@ -351,7 +492,7 @@
 usage(void)
 {
 	printf("ssh-keygen version %s\n", SSH_VERSION);
-	printf("Usage: %s [-b bits] [-p] [-c] [-l] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
+	printf("Usage: %s [-b bits] [-p] [-c] [-l] [-x] [-X] [-y] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
 	exit(1);
 }
 
@@ -363,29 +504,28 @@
 {
 	char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
 	struct passwd *pw;
-	char *tmpbuf;
 	int opt;
 	struct stat st;
 	FILE *f;
-	char hostname[MAXHOSTNAMELEN];
+	Key *private;
+	Key *public;
 	extern int optind;
 	extern char *optarg;
 
-	/* check if RSA support exists */
-	if (rsa_alive() == 0) {
-		fprintf(stderr,
-			"%s: no RSA support in libssl and libcrypto.  See ssl(8).\n",
-			__progname);
-		exit(1);
-	}
+	OpenSSL_add_all_algorithms();
+
 	/* we need this for the home * directory.  */
 	pw = getpwuid(getuid());
 	if (!pw) {
 		printf("You don't exist, go away!\n");
 		exit(1);
 	}
+	if (gethostname(hostname, sizeof(hostname)) < 0) {
+		perror("gethostname");
+		exit(1);
+	}
 
-	while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) {
+	while ((opt = getopt(ac, av, "dqpclRxXyb:f:P:N:C:")) != EOF) {
 		switch (opt) {
 		case 'b':
 			bits = atoi(optarg);
@@ -428,6 +568,29 @@
 			quiet = 1;
 			break;
 
+		case 'R':
+			if (rsa_alive() == 0)
+				exit(1);
+			else
+				exit(0);
+			break;
+
+		case 'x':
+			convert_to_ssh2 = 1;
+			break;
+
+		case 'X':
+			convert_from_ssh2 = 1;
+			break;
+
+		case 'y':
+			print_public = 1;
+			break;
+
+		case 'd':
+			dsa_mode = 1;
+			break;
+
 		case '?':
 		default:
 			usage();
@@ -441,22 +604,44 @@
 		printf("Can only have one of -p and -c.\n");
 		usage();
 	}
+	/* check if RSA support is needed and exists */
+	if (dsa_mode == 0 && rsa_alive() == 0) {
+		fprintf(stderr,
+			"%s: no RSA support in libssl and libcrypto.  See ssl(8).\n",
+			__progname);
+		exit(1);
+	}
 	if (print_fingerprint)
 		do_fingerprint(pw);
 	if (change_passphrase)
 		do_change_passphrase(pw);
 	if (change_comment)
 		do_change_comment(pw);
+	if (convert_to_ssh2)
+		do_convert_to_ssh2(pw);
+	if (convert_from_ssh2)
+		do_convert_from_ssh2(pw);
+	if (print_public)
+		do_print_public(pw);
 
 	arc4random_stir();
 
-	if (quiet)
-		rsa_set_verbose(0);
-
-	/* Generate the rsa key pair. */
-	private_key = RSA_new();
-	public_key = RSA_new();
-	rsa_generate_key(private_key, public_key, bits);
+	if (dsa_mode != 0) {
+		if (!quiet)
+			printf("Generating DSA parameter and key.\n");
+		public = private = dsa_generate_key(bits);
+		if (private == NULL) {
+			fprintf(stderr, "dsa_generate_keys failed");
+			exit(1);
+		}
+	} else {
+		if (quiet)
+			rsa_set_verbose(0);
+		/* Generate the rsa key pair. */
+		public = key_new(KEY_RSA);
+		private = key_new(KEY_RSA);
+		rsa_generate_key(private->rsa, public->rsa, bits);
+	}
 
 	if (!have_identity)
 		ask_filename(pw, "Enter file in which to save the key");
@@ -509,17 +694,13 @@
 		strlcpy(comment, identity_comment, sizeof(comment));
 	} else {
 		/* Create default commend field for the passphrase. */
-		if (gethostname(hostname, sizeof(hostname)) < 0) {
-			perror("gethostname");
-			exit(1);
-		}
 		snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
 	}
 
 	/* Save the key with the given passphrase and comment. */
-	if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
+	if (!save_private_key(identity_file, passphrase1, private, comment)) {
 		printf("Saving the key failed: %s: %s.\n",
-		       identity_file, strerror(errno));
+		    identity_file, strerror(errno));
 		memset(passphrase1, 0, strlen(passphrase1));
 		xfree(passphrase1);
 		exit(1);
@@ -529,7 +710,9 @@
 	xfree(passphrase1);
 
 	/* Clear the private key and the random number generator. */
-	RSA_free(private_key);
+	if (private != public) {
+		key_free(private);
+	}
 	arc4random_stir();
 
 	if (!quiet)
@@ -541,21 +724,18 @@
 		printf("Could not save your public key in %s\n", identity_file);
 		exit(1);
 	}
-	fprintf(f, "%d ", BN_num_bits(public_key->n));
-	tmpbuf = BN_bn2dec(public_key->e);
-	fprintf(f, "%s ", tmpbuf);
-	free(tmpbuf);
-	tmpbuf = BN_bn2dec(public_key->n);
-	fprintf(f, "%s %s\n", tmpbuf, comment);
-	free(tmpbuf);
+	if (!key_write(public, f))
+		fprintf(stderr, "write key failed");
+	fprintf(f, " %s\n", comment);
 	fclose(f);
 
 	if (!quiet) {
-		printf("Your public key has been saved in %s.\n", identity_file);
+		printf("Your public key has been saved in %s.\n",
+		    identity_file);
 		printf("The key fingerprint is:\n");
-		printf("%d %s %s\n", BN_num_bits(public_key->n),
-		       fingerprint(public_key->e, public_key->n),
-		       comment);
+		printf("%s %s\n", key_fingerprint(public), comment);
 	}
+
+	key_free(public);
 	exit(0);
 }
diff --git a/ssh.c b/ssh.c
index 456570f..bdf6180 100644
--- a/ssh.c
+++ b/ssh.c
@@ -11,7 +11,11 @@
  */
 
 #include "includes.h"
-RCSID("$Id: ssh.c,v 1.26 2000/04/16 01:18:46 damien Exp $");
+RCSID("$Id: ssh.c,v 1.27 2000/04/29 13:57:12 damien Exp $");
+
+#include <openssl/evp.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
 
 #include "xmalloc.h"
 #include "ssh.h"
@@ -24,6 +28,8 @@
 #include "ssh2.h"
 #include "compat.h"
 #include "channels.h"
+#include "key.h"
+#include "authfile.h"
 
 #ifdef HAVE___PROGNAME
 extern char *__progname;
@@ -358,10 +364,16 @@
 			}
 			break;
 		case 'c':
-			options.cipher = cipher_number(optarg);
-			if (options.cipher == -1) {
-				fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
-				exit(1);
+			if (ciphers_valid(optarg)) {
+				/* SSH2 only */
+				options.ciphers = xstrdup(optarg);
+			} else {
+				/* SSH1 only */
+				options.cipher = cipher_number(optarg);
+				if (options.cipher == -1) {
+					fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
+					exit(1);
+				}
 			}
 			break;
 		case 'p':
@@ -417,16 +429,11 @@
 	if (!host)
 		usage();
 
-	/* check if RSA support exists */
-	if (rsa_alive() == 0) {
-		fprintf(stderr,
-			"%s: no RSA support in libssl and libcrypto.  See ssl(8).\n",
-			__progname);
-		exit(1);
-	}
 	/* Initialize the command to execute on remote host. */
 	buffer_init(&command);
 
+	OpenSSL_add_all_algorithms();
+	
 	/*
 	 * Save the command to execute on the remote host in a buffer. There
 	 * is no limit on the length of the command, except by the maximum
@@ -496,6 +503,20 @@
 	/* 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);
 
@@ -562,9 +583,12 @@
 	 * authentication. This must be done before releasing extra
 	 * privileges, because the file is only readable by root.
 	 */
-	if (ok) {
+	if (ok && (options.protocol & SSH_PROTO_1)) {
+		Key k;
 		host_private_key = RSA_new();
-		if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
+		k.type = KEY_RSA;
+		k.rsa = host_private_key;
+		if (load_private_key(HOST_KEY_FILE, "", &k, NULL))
 			host_private_key_loaded = 1;
 	}
 	/*
@@ -610,15 +634,22 @@
 		exit(1);
 	}
 	/* Expand ~ in options.identity_files. */
+	/* XXX mem-leaks */
 	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);
+	    original_real_uid);
 	options.user_hostfile = tilde_expand_filename(options.user_hostfile,
-						      original_real_uid);
+	    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,
diff --git a/ssh.h b/ssh.h
index 8782139..57d7827 100644
--- a/ssh.h
+++ b/ssh.h
@@ -13,7 +13,7 @@
  *
  */
 
-/* RCSID("$Id: ssh.h,v 1.34 2000/04/20 13:12:59 damien Exp $"); */
+/* RCSID("$Id: ssh.h,v 1.35 2000/04/29 13:57:12 damien Exp $"); */
 
 #ifndef SSH_H
 #define SSH_H
@@ -88,6 +88,7 @@
  * world-readable.
  */
 #define SSH_SYSTEM_HOSTFILE	ETCDIR "/ssh_known_hosts"
+#define SSH_SYSTEM_HOSTFILE2	ETCDIR "/ssh_known_hosts2"
 
 /*
  * Of these, ssh_host_key must be readable only by root, whereas ssh_config
@@ -96,7 +97,7 @@
 #define HOST_KEY_FILE		ETCDIR "/ssh_host_key"
 #define SERVER_CONFIG_FILE	ETCDIR "/sshd_config"
 #define HOST_CONFIG_FILE	ETCDIR "/ssh_config"
-#define DSA_KEY_FILE		ETCDIR "/ssh_dsa_key"
+#define DSA_KEY_FILE		ETCDIR "/ssh_host_dsa_key"
 
 #ifndef SSH_PROGRAM
 #define SSH_PROGRAM			"/usr/bin/ssh"
@@ -128,6 +129,7 @@
  * contain anything particularly secret.
  */
 #define SSH_USER_HOSTFILE	"~/.ssh/known_hosts"
+#define SSH_USER_HOSTFILE2	"~/.ssh/known_hosts2"
 
 /*
  * Name of the default file containing client-side authentication key. This
@@ -152,6 +154,7 @@
  * running as root.)
  */
 #define SSH_USER_PERMITTED_KEYS	".ssh/authorized_keys"
+#define SSH_USER_PERMITTED_KEYS2	".ssh/authorized_keys2"
 
 /*
  * Per-user and system-wide ssh "rc" files.  These files are executed with
@@ -407,36 +410,6 @@
  */
 char   *read_passphrase(const char *prompt, int from_stdin);
 
-/*
- * Saves the authentication (private) key in a file, encrypting it with
- * passphrase.  The identification of the file (lowest 64 bits of n) will
- * precede the key to provide identification of the key without needing a
- * passphrase.
- */
-int
-save_private_key(const char *filename, const char *passphrase,
-    RSA * private_key, const char *comment);
-
-/*
- * Loads the public part of the key file (public key and comment). Returns 0
- * if an error occurred; zero if the public key was successfully read.  The
- * comment of the key is returned in comment_return if it is non-NULL; the
- * caller must free the value with xfree.
- */
-int
-load_public_key(const char *filename, RSA * pub,
-    char **comment_return);
-
-/*
- * Loads the private key from the file.  Returns 0 if an error is encountered
- * (file does not exist or is not readable, or passphrase is bad). This
- * initializes the private key.  The comment of the key is returned in
- * comment_return if it is non-NULL; the caller must free the value with
- * xfree.
- */
-int
-load_private_key(const char *filename, const char *passphrase,
-    RSA * private_key, char **comment_return);
 
 /*------------ Definitions for logging. -----------------------*/
 
diff --git a/sshconnect.c b/sshconnect.c
index f58289e..5554c06 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -5,48 +5,29 @@
  * Created: Sat Mar 18 22:15:47 1995 ylo
  * Code to connect to a remote host, and to perform the client side of the
  * login (authentication) dialog.
- *
- * SSH2 support added by Markus Friedl.
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshconnect.c,v 1.69 2000/04/19 07:05:50 deraadt Exp $");
+RCSID("$OpenBSD: sshconnect.c,v 1.71 2000/04/26 21:28:33 markus Exp $");
 
 #include <openssl/bn.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+
 #include "xmalloc.h"
 #include "rsa.h"
 #include "ssh.h"
 #include "buffer.h"
 #include "packet.h"
-#include "authfd.h"
-#include "cipher.h"
-#include "mpaux.h"
 #include "uidswap.h"
 #include "compat.h"
 #include "readconf.h"
-
-#include "bufaux.h"
-#include <openssl/rsa.h>
-#include <openssl/dsa.h>
-
-#include "ssh2.h"
-#include <openssl/md5.h>
-#include <openssl/dh.h>
-#include <openssl/hmac.h>
-#include "kex.h"
-#include "myproposal.h"
 #include "key.h"
-#include "dsa.h"
+#include "sshconnect.h"
 #include "hostfile.h"
 
-/* Session id for the current session. */
-unsigned char session_id[16];
-
-/* authentications supported by server */
-unsigned int supported_authentications;
-
-static char *client_version_string = NULL;
-static char *server_version_string = NULL;
+char *client_version_string = NULL;
+char *server_version_string = NULL;
 
 extern Options options;
 extern char *__progname;
@@ -316,653 +297,6 @@
 	return 1;
 }
 
-/*
- * Checks if the user has an authentication agent, and if so, tries to
- * authenticate using the agent.
- */
-int
-try_agent_authentication()
-{
-	int status, type;
-	char *comment;
-	AuthenticationConnection *auth;
-	unsigned char response[16];
-	unsigned int i;
-	BIGNUM *e, *n, *challenge;
-
-	/* Get connection to the agent. */
-	auth = ssh_get_authentication_connection();
-	if (!auth)
-		return 0;
-
-	e = BN_new();
-	n = BN_new();
-	challenge = BN_new();
-
-	/* Loop through identities served by the agent. */
-	for (status = ssh_get_first_identity(auth, e, n, &comment);
-	     status;
-	     status = ssh_get_next_identity(auth, e, n, &comment)) {
-		int plen, clen;
-
-		/* Try this identity. */
-		debug("Trying RSA authentication via agent with '%.100s'", comment);
-		xfree(comment);
-
-		/* Tell the server that we are willing to authenticate using this key. */
-		packet_start(SSH_CMSG_AUTH_RSA);
-		packet_put_bignum(n);
-		packet_send();
-		packet_write_wait();
-
-		/* Wait for server's response. */
-		type = packet_read(&plen);
-
-		/* The server sends failure if it doesn\'t like our key or
-		   does not support RSA authentication. */
-		if (type == SSH_SMSG_FAILURE) {
-			debug("Server refused our key.");
-			continue;
-		}
-		/* Otherwise it should have sent a challenge. */
-		if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
-			packet_disconnect("Protocol error during RSA authentication: %d",
-					  type);
-
-		packet_get_bignum(challenge, &clen);
-
-		packet_integrity_check(plen, clen, type);
-
-		debug("Received RSA challenge from server.");
-
-		/* Ask the agent to decrypt the challenge. */
-		if (!ssh_decrypt_challenge(auth, e, n, challenge,
-					   session_id, 1, response)) {
-			/* The agent failed to authenticate this identifier although it
-			   advertised it supports this.  Just return a wrong value. */
-			log("Authentication agent failed to decrypt challenge.");
-			memset(response, 0, sizeof(response));
-		}
-		debug("Sending response to RSA challenge.");
-
-		/* Send the decrypted challenge back to the server. */
-		packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
-		for (i = 0; i < 16; i++)
-			packet_put_char(response[i]);
-		packet_send();
-		packet_write_wait();
-
-		/* Wait for response from the server. */
-		type = packet_read(&plen);
-
-		/* The server returns success if it accepted the authentication. */
-		if (type == SSH_SMSG_SUCCESS) {
-			debug("RSA authentication accepted by server.");
-			BN_clear_free(e);
-			BN_clear_free(n);
-			BN_clear_free(challenge);
-			return 1;
-		}
-		/* Otherwise it should return failure. */
-		if (type != SSH_SMSG_FAILURE)
-			packet_disconnect("Protocol error waiting RSA auth response: %d",
-					  type);
-	}
-
-	BN_clear_free(e);
-	BN_clear_free(n);
-	BN_clear_free(challenge);
-
-	debug("RSA authentication using agent refused.");
-	return 0;
-}
-
-/*
- * Computes the proper response to a RSA challenge, and sends the response to
- * the server.
- */
-void
-respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv)
-{
-	unsigned char buf[32], response[16];
-	MD5_CTX md;
-	int i, len;
-
-	/* Decrypt the challenge using the private key. */
-	rsa_private_decrypt(challenge, challenge, prv);
-
-	/* Compute the response. */
-	/* The response is MD5 of decrypted challenge plus session id. */
-	len = BN_num_bytes(challenge);
-	if (len <= 0 || len > sizeof(buf))
-		packet_disconnect("respond_to_rsa_challenge: bad challenge length %d",
-				  len);
-
-	memset(buf, 0, sizeof(buf));
-	BN_bn2bin(challenge, buf + sizeof(buf) - len);
-	MD5_Init(&md);
-	MD5_Update(&md, buf, 32);
-	MD5_Update(&md, session_id, 16);
-	MD5_Final(response, &md);
-
-	debug("Sending response to host key RSA challenge.");
-
-	/* Send the response back to the server. */
-	packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
-	for (i = 0; i < 16; i++)
-		packet_put_char(response[i]);
-	packet_send();
-	packet_write_wait();
-
-	memset(buf, 0, sizeof(buf));
-	memset(response, 0, sizeof(response));
-	memset(&md, 0, sizeof(md));
-}
-
-/*
- * Checks if the user has authentication file, and if so, tries to authenticate
- * the user using it.
- */
-int
-try_rsa_authentication(const char *authfile)
-{
-	BIGNUM *challenge;
-	RSA *private_key;
-	RSA *public_key;
-	char *passphrase, *comment;
-	int type, i;
-	int plen, clen;
-
-	/* Try to load identification for the authentication key. */
-	public_key = RSA_new();
-	if (!load_public_key(authfile, public_key, &comment)) {
-		RSA_free(public_key);
-		/* Could not load it.  Fail. */
-		return 0;
-	}
-	debug("Trying RSA authentication with key '%.100s'", comment);
-
-	/* Tell the server that we are willing to authenticate using this key. */
-	packet_start(SSH_CMSG_AUTH_RSA);
-	packet_put_bignum(public_key->n);
-	packet_send();
-	packet_write_wait();
-
-	/* We no longer need the public key. */
-	RSA_free(public_key);
-
-	/* Wait for server's response. */
-	type = packet_read(&plen);
-
-	/*
-	 * The server responds with failure if it doesn\'t like our key or
-	 * doesn\'t support RSA authentication.
-	 */
-	if (type == SSH_SMSG_FAILURE) {
-		debug("Server refused our key.");
-		xfree(comment);
-		return 0;
-	}
-	/* Otherwise, the server should respond with a challenge. */
-	if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
-		packet_disconnect("Protocol error during RSA authentication: %d", type);
-
-	/* Get the challenge from the packet. */
-	challenge = BN_new();
-	packet_get_bignum(challenge, &clen);
-
-	packet_integrity_check(plen, clen, type);
-
-	debug("Received RSA challenge from server.");
-
-	private_key = RSA_new();
-	/*
-	 * Load the private key.  Try first with empty passphrase; if it
-	 * fails, ask for a passphrase.
-	 */
-	if (!load_private_key(authfile, "", private_key, NULL)) {
-		char buf[300];
-		snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
-		    comment);
-		if (!options.batch_mode)
-			passphrase = read_passphrase(buf, 0);
-		else {
-			debug("Will not query passphrase for %.100s in batch mode.",
-			      comment);
-			passphrase = xstrdup("");
-		}
-
-		/* Load the authentication file using the pasphrase. */
-		if (!load_private_key(authfile, passphrase, private_key, NULL)) {
-			memset(passphrase, 0, strlen(passphrase));
-			xfree(passphrase);
-			error("Bad passphrase.");
-
-			/* Send a dummy response packet to avoid protocol error. */
-			packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
-			for (i = 0; i < 16; i++)
-				packet_put_char(0);
-			packet_send();
-			packet_write_wait();
-
-			/* Expect the server to reject it... */
-			packet_read_expect(&plen, SSH_SMSG_FAILURE);
-			xfree(comment);
-			return 0;
-		}
-		/* Destroy the passphrase. */
-		memset(passphrase, 0, strlen(passphrase));
-		xfree(passphrase);
-	}
-	/* We no longer need the comment. */
-	xfree(comment);
-
-	/* Compute and send a response to the challenge. */
-	respond_to_rsa_challenge(challenge, private_key);
-
-	/* Destroy the private key. */
-	RSA_free(private_key);
-
-	/* We no longer need the challenge. */
-	BN_clear_free(challenge);
-
-	/* Wait for response from the server. */
-	type = packet_read(&plen);
-	if (type == SSH_SMSG_SUCCESS) {
-		debug("RSA authentication accepted by server.");
-		return 1;
-	}
-	if (type != SSH_SMSG_FAILURE)
-		packet_disconnect("Protocol error waiting RSA auth response: %d", type);
-	debug("RSA authentication refused.");
-	return 0;
-}
-
-/*
- * Tries to authenticate the user using combined rhosts or /etc/hosts.equiv
- * authentication and RSA host authentication.
- */
-int
-try_rhosts_rsa_authentication(const char *local_user, RSA * host_key)
-{
-	int type;
-	BIGNUM *challenge;
-	int plen, clen;
-
-	debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication.");
-
-	/* Tell the server that we are willing to authenticate using this key. */
-	packet_start(SSH_CMSG_AUTH_RHOSTS_RSA);
-	packet_put_string(local_user, strlen(local_user));
-	packet_put_int(BN_num_bits(host_key->n));
-	packet_put_bignum(host_key->e);
-	packet_put_bignum(host_key->n);
-	packet_send();
-	packet_write_wait();
-
-	/* Wait for server's response. */
-	type = packet_read(&plen);
-
-	/* The server responds with failure if it doesn't admit our
-	   .rhosts authentication or doesn't know our host key. */
-	if (type == SSH_SMSG_FAILURE) {
-		debug("Server refused our rhosts authentication or host key.");
-		return 0;
-	}
-	/* Otherwise, the server should respond with a challenge. */
-	if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
-		packet_disconnect("Protocol error during RSA authentication: %d", type);
-
-	/* Get the challenge from the packet. */
-	challenge = BN_new();
-	packet_get_bignum(challenge, &clen);
-
-	packet_integrity_check(plen, clen, type);
-
-	debug("Received RSA challenge for host key from server.");
-
-	/* Compute a response to the challenge. */
-	respond_to_rsa_challenge(challenge, host_key);
-
-	/* We no longer need the challenge. */
-	BN_clear_free(challenge);
-
-	/* Wait for response from the server. */
-	type = packet_read(&plen);
-	if (type == SSH_SMSG_SUCCESS) {
-		debug("Rhosts or /etc/hosts.equiv with RSA host authentication accepted by server.");
-		return 1;
-	}
-	if (type != SSH_SMSG_FAILURE)
-		packet_disconnect("Protocol error waiting RSA auth response: %d", type);
-	debug("Rhosts or /etc/hosts.equiv with RSA host authentication refused.");
-	return 0;
-}
-
-#ifdef KRB4
-int
-try_kerberos_authentication()
-{
-	KTEXT_ST auth;		/* Kerberos data */
-	char *reply;
-	char inst[INST_SZ];
-	char *realm;
-	CREDENTIALS cred;
-	int r, type, plen;
-	socklen_t slen;
-	Key_schedule schedule;
-	u_long checksum, cksum;
-	MSG_DAT msg_data;
-	struct sockaddr_in local, foreign;
-	struct stat st;
-
-	/* Don't do anything if we don't have any tickets. */
-	if (stat(tkt_string(), &st) < 0)
-		return 0;
-
-	strncpy(inst, (char *) krb_get_phost(get_canonical_hostname()), INST_SZ);
-
-	realm = (char *) krb_realmofhost(get_canonical_hostname());
-	if (!realm) {
-		debug("Kerberos V4: no realm for %s", get_canonical_hostname());
-		return 0;
-	}
-	/* This can really be anything. */
-	checksum = (u_long) getpid();
-
-	r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum);
-	if (r != KSUCCESS) {
-		debug("Kerberos V4 krb_mk_req failed: %s", krb_err_txt[r]);
-		return 0;
-	}
-	/* Get session key to decrypt the server's reply with. */
-	r = krb_get_cred(KRB4_SERVICE_NAME, inst, realm, &cred);
-	if (r != KSUCCESS) {
-		debug("get_cred failed: %s", krb_err_txt[r]);
-		return 0;
-	}
-	des_key_sched((des_cblock *) cred.session, schedule);
-
-	/* Send authentication info to server. */
-	packet_start(SSH_CMSG_AUTH_KERBEROS);
-	packet_put_string((char *) auth.dat, auth.length);
-	packet_send();
-	packet_write_wait();
-
-	/* Zero the buffer. */
-	(void) memset(auth.dat, 0, MAX_KTXT_LEN);
-
-	slen = sizeof(local);
-	memset(&local, 0, sizeof(local));
-	if (getsockname(packet_get_connection_in(),
-			(struct sockaddr *) & local, &slen) < 0)
-		debug("getsockname failed: %s", strerror(errno));
-
-	slen = sizeof(foreign);
-	memset(&foreign, 0, sizeof(foreign));
-	if (getpeername(packet_get_connection_in(),
-			(struct sockaddr *) & foreign, &slen) < 0) {
-		debug("getpeername failed: %s", strerror(errno));
-		fatal_cleanup();
-	}
-	/* Get server reply. */
-	type = packet_read(&plen);
-	switch (type) {
-	case SSH_SMSG_FAILURE:
-		/* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */
-		debug("Kerberos V4 authentication failed.");
-		return 0;
-		break;
-
-	case SSH_SMSG_AUTH_KERBEROS_RESPONSE:
-		/* SSH_SMSG_AUTH_KERBEROS_SUCCESS */
-		debug("Kerberos V4 authentication accepted.");
-
-		/* Get server's response. */
-		reply = packet_get_string((unsigned int *) &auth.length);
-		memcpy(auth.dat, reply, auth.length);
-		xfree(reply);
-
-		packet_integrity_check(plen, 4 + auth.length, type);
-
-		/*
-		 * If his response isn't properly encrypted with the session
-		 * key, and the decrypted checksum fails to match, he's
-		 * bogus. Bail out.
-		 */
-		r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session,
-				&foreign, &local, &msg_data);
-		if (r != KSUCCESS) {
-			debug("Kerberos V4 krb_rd_priv failed: %s", krb_err_txt[r]);
-			packet_disconnect("Kerberos V4 challenge failed!");
-		}
-		/* Fetch the (incremented) checksum that we supplied in the request. */
-		(void) memcpy((char *) &cksum, (char *) msg_data.app_data, sizeof(cksum));
-		cksum = ntohl(cksum);
-
-		/* If it matches, we're golden. */
-		if (cksum == checksum + 1) {
-			debug("Kerberos V4 challenge successful.");
-			return 1;
-		} else
-			packet_disconnect("Kerberos V4 challenge failed!");
-		break;
-
-	default:
-		packet_disconnect("Protocol error on Kerberos V4 response: %d", type);
-	}
-	return 0;
-}
-
-#endif /* KRB4 */
-
-#ifdef AFS
-int
-send_kerberos_tgt()
-{
-	CREDENTIALS *creds;
-	char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
-	int r, type, plen;
-	char buffer[8192];
-	struct stat st;
-
-	/* Don't do anything if we don't have any tickets. */
-	if (stat(tkt_string(), &st) < 0)
-		return 0;
-
-	creds = xmalloc(sizeof(*creds));
-
-	if ((r = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm)) != KSUCCESS) {
-		debug("Kerberos V4 tf_fullname failed: %s", krb_err_txt[r]);
-		return 0;
-	}
-	if ((r = krb_get_cred("krbtgt", prealm, prealm, creds)) != GC_OK) {
-		debug("Kerberos V4 get_cred failed: %s", krb_err_txt[r]);
-		return 0;
-	}
-	if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) {
-		debug("Kerberos V4 ticket expired: %s", TKT_FILE);
-		return 0;
-	}
-	creds_to_radix(creds, (unsigned char *)buffer);
-	xfree(creds);
-
-	packet_start(SSH_CMSG_HAVE_KERBEROS_TGT);
-	packet_put_string(buffer, strlen(buffer));
-	packet_send();
-	packet_write_wait();
-
-	type = packet_read(&plen);
-
-	if (type == SSH_SMSG_FAILURE)
-		debug("Kerberos TGT for realm %s rejected.", prealm);
-	else if (type != SSH_SMSG_SUCCESS)
-		packet_disconnect("Protocol error on Kerberos TGT response: %d", type);
-
-	return 1;
-}
-
-void
-send_afs_tokens(void)
-{
-	CREDENTIALS creds;
-	struct ViceIoctl parms;
-	struct ClearToken ct;
-	int i, type, len, plen;
-	char buf[2048], *p, *server_cell;
-	char buffer[8192];
-
-	/* Move over ktc_GetToken, here's something leaner. */
-	for (i = 0; i < 100; i++) {	/* just in case */
-		parms.in = (char *) &i;
-		parms.in_size = sizeof(i);
-		parms.out = buf;
-		parms.out_size = sizeof(buf);
-		if (k_pioctl(0, VIOCGETTOK, &parms, 0) != 0)
-			break;
-		p = buf;
-
-		/* Get secret token. */
-		memcpy(&creds.ticket_st.length, p, sizeof(unsigned int));
-		if (creds.ticket_st.length > MAX_KTXT_LEN)
-			break;
-		p += sizeof(unsigned int);
-		memcpy(creds.ticket_st.dat, p, creds.ticket_st.length);
-		p += creds.ticket_st.length;
-
-		/* Get clear token. */
-		memcpy(&len, p, sizeof(len));
-		if (len != sizeof(struct ClearToken))
-			break;
-		p += sizeof(len);
-		memcpy(&ct, p, len);
-		p += len;
-		p += sizeof(len);	/* primary flag */
-		server_cell = p;
-
-		/* Flesh out our credentials. */
-		strlcpy(creds.service, "afs", sizeof creds.service);
-		creds.instance[0] = '\0';
-		strlcpy(creds.realm, server_cell, REALM_SZ);
-		memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ);
-		creds.issue_date = ct.BeginTimestamp;
-		creds.lifetime = krb_time_to_life(creds.issue_date, ct.EndTimestamp);
-		creds.kvno = ct.AuthHandle;
-		snprintf(creds.pname, sizeof(creds.pname), "AFS ID %d", ct.ViceId);
-		creds.pinst[0] = '\0';
-
-		/* Encode token, ship it off. */
-		if (!creds_to_radix(&creds, (unsigned char*) buffer))
-			break;
-		packet_start(SSH_CMSG_HAVE_AFS_TOKEN);
-		packet_put_string(buffer, strlen(buffer));
-		packet_send();
-		packet_write_wait();
-
-		/* Roger, Roger. Clearance, Clarence. What's your vector,
-		   Victor? */
-		type = packet_read(&plen);
-
-		if (type == SSH_SMSG_FAILURE)
-			debug("AFS token for cell %s rejected.", server_cell);
-		else if (type != SSH_SMSG_SUCCESS)
-			packet_disconnect("Protocol error on AFS token response: %d", type);
-	}
-}
-
-#endif /* AFS */
-
-/*
- * Tries to authenticate with any string-based challenge/response system.
- * Note that the client code is not tied to s/key or TIS.
- */
-int
-try_skey_authentication()
-{
-	int type, i;
-	int payload_len;
-	unsigned int clen;
-	char *challenge, *response;
-
-	debug("Doing skey authentication.");
-
-	/* request a challenge */
-	packet_start(SSH_CMSG_AUTH_TIS);
-	packet_send();
-	packet_write_wait();
-
-	type = packet_read(&payload_len);
-	if (type != SSH_SMSG_FAILURE &&
-	    type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
-		packet_disconnect("Protocol error: got %d in response "
-				  "to skey-auth", type);
-	}
-	if (type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
-		debug("No challenge for skey authentication.");
-		return 0;
-	}
-	challenge = packet_get_string(&clen);
-	packet_integrity_check(payload_len, (4 + clen), type);
-	if (options.cipher == SSH_CIPHER_NONE)
-		log("WARNING: Encryption is disabled! "
-		    "Reponse will be transmitted in clear text.");
-	fprintf(stderr, "%s\n", challenge);
-	xfree(challenge);
-	fflush(stderr);
-	for (i = 0; i < options.number_of_password_prompts; i++) {
-		if (i != 0)
-			error("Permission denied, please try again.");
-		response = read_passphrase("Response: ", 0);
-		packet_start(SSH_CMSG_AUTH_TIS_RESPONSE);
-		packet_put_string(response, strlen(response));
-		memset(response, 0, strlen(response));
-		xfree(response);
-		packet_send();
-		packet_write_wait();
-		type = packet_read(&payload_len);
-		if (type == SSH_SMSG_SUCCESS)
-			return 1;
-		if (type != SSH_SMSG_FAILURE)
-			packet_disconnect("Protocol error: got %d in response "
-					  "to skey-auth-reponse", type);
-	}
-	/* failure */
-	return 0;
-}
-
-/*
- * Tries to authenticate with plain passwd authentication.
- */
-int
-try_password_authentication(char *prompt)
-{
-	int type, i, payload_len;
-	char *password;
-
-	debug("Doing password authentication.");
-	if (options.cipher == SSH_CIPHER_NONE)
-		log("WARNING: Encryption is disabled! Password will be transmitted in clear text.");
-	for (i = 0; i < options.number_of_password_prompts; i++) {
-		if (i != 0)
-			error("Permission denied, please try again.");
-		password = read_passphrase(prompt, 0);
-		packet_start(SSH_CMSG_AUTH_PASSWORD);
-		packet_put_string(password, strlen(password));
-		memset(password, 0, strlen(password));
-		xfree(password);
-		packet_send();
-		packet_write_wait();
-
-		type = packet_read(&payload_len);
-		if (type == SSH_SMSG_SUCCESS)
-			return 1;
-		if (type != SSH_SMSG_FAILURE)
-			packet_disconnect("Protocol error: got %d in response to passwd auth", type);
-	}
-	/* failure */
-	return 0;
-}
-
 char *
 chop(char *s)
 {
@@ -1060,7 +394,8 @@
 		fatal("Protocol major versions differ: %d vs. %d",
 		    (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
 		    remote_major);
-
+	if (compat20)
+		packet_set_ssh2_format();
 	/* Send our own protocol version identification. */
 	snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
 	    compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
@@ -1122,7 +457,8 @@
  */
 
 void
-check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
+check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
+	const char *user_hostfile, const char *system_hostfile)
 {
 	Key *file_key;
 	char *ip = NULL;
@@ -1141,6 +477,7 @@
 	 * essentially disables host authentication for localhost; however,
 	 * this is probably not a real problem.
 	 */
+	/**  hostaddr == 0! */
 	switch (hostaddr->sa_family) {
 	case AF_INET:
 		local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
@@ -1184,19 +521,19 @@
 	 * Check if the host key is present in the user\'s list of known
 	 * hosts or in the systemwide list.
 	 */
-	host_status = check_host_in_hostfile(options.user_hostfile, host, host_key, file_key);
+	host_status = check_host_in_hostfile(user_hostfile, host, host_key, file_key);
 	if (host_status == HOST_NEW)
-		host_status = check_host_in_hostfile(options.system_hostfile, host, host_key, file_key);
+		host_status = check_host_in_hostfile(system_hostfile, host, host_key, file_key);
 	/*
 	 * Also perform check for the ip address, skip the check if we are
 	 * localhost or the hostname was an ip address to begin with
 	 */
 	if (options.check_host_ip && !local && strcmp(host, ip)) {
 		Key *ip_key = key_new(host_key->type);
-		ip_status = check_host_in_hostfile(options.user_hostfile, ip, host_key, ip_key);
+		ip_status = check_host_in_hostfile(user_hostfile, ip, host_key, ip_key);
 
 		if (ip_status == HOST_NEW)
-			ip_status = check_host_in_hostfile(options.system_hostfile, ip, host_key, ip_key);
+			ip_status = check_host_in_hostfile(system_hostfile, ip, host_key, ip_key);
 		if (host_status == HOST_CHANGED &&
 		    (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
 			host_ip_differ = 1;
@@ -1213,9 +550,9 @@
 		debug("Host '%.200s' is known and matches the host key.", host);
 		if (options.check_host_ip) {
 			if (ip_status == HOST_NEW) {
-				if (!add_host_to_hostfile(options.user_hostfile, ip, host_key))
+				if (!add_host_to_hostfile(user_hostfile, ip, host_key))
 					log("Failed to add the host key for IP address '%.30s' to the list of known hosts (%.30s).",
-					    ip, options.user_hostfile);
+					    ip, user_hostfile);
 				else
 					log("Warning: Permanently added host key for IP address '%.30s' to the list of known hosts.",
 					    ip);
@@ -1249,9 +586,9 @@
 			hostp = host;
 
 		/* If not in strict mode, add the key automatically to the local known_hosts file. */
-		if (!add_host_to_hostfile(options.user_hostfile, hostp, host_key))
+		if (!add_host_to_hostfile(user_hostfile, hostp, host_key))
 			log("Failed to add the host to the list of known hosts (%.500s).",
-			    options.user_hostfile);
+			    user_hostfile);
 		else
 			log("Warning: Permanently added '%.200s' to the list of known hosts.",
 			    hostp);
@@ -1283,7 +620,7 @@
 		error("It is also possible that the host key has just been changed.");
 		error("Please contact your system administrator.");
 		error("Add correct host key in %.100s to get rid of this message.",
-		      options.user_hostfile);
+		      user_hostfile);
 
 		/*
 		 * If strict host key checking is in use, the user will have
@@ -1317,644 +654,7 @@
 	if (options.check_host_ip)
 		xfree(ip);
 }
-void
-check_rsa_host_key(char *host, struct sockaddr *hostaddr, RSA *host_key)
-{
-	Key k;
-	k.type = KEY_RSA;
-	k.rsa = host_key;
-	check_host_key(host, hostaddr, &k);
-}
-
-/*
- * SSH2 key exchange
- */
-void
-ssh_kex2(char *host, struct sockaddr *hostaddr)
-{
-	Kex *kex;
-	char *cprop[PROPOSAL_MAX];
-	char *sprop[PROPOSAL_MAX];
-	Buffer *client_kexinit;
-	Buffer *server_kexinit;
-	int payload_len, dlen;
-	unsigned int klen, kout;
-	char *ptr;
-	char *signature = NULL;
-	unsigned int slen;
-	char *server_host_key_blob = NULL;
-	Key *server_host_key;
-	unsigned int sbloblen;
-	DH *dh;
-	BIGNUM *dh_server_pub = 0;
-	BIGNUM *shared_secret = 0;
-	int i;
-	unsigned char *kbuf;
-	unsigned char *hash;
-
-/* KEXINIT */
-
-	debug("Sending KEX init.");
-	if (options.ciphers != NULL) {
-		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
-		myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
-	} else if (
-	    options.cipher == SSH_CIPHER_ARCFOUR ||
-	    options.cipher == SSH_CIPHER_3DES_CBC ||
-	    options.cipher == SSH_CIPHER_CAST128_CBC ||
-	    options.cipher == SSH_CIPHER_BLOWFISH_CBC) {
-		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
-		myproposal[PROPOSAL_ENC_ALGS_STOC] = cipher_name(options.cipher);
-	}
-	if (options.compression) {
-		myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib";
-		myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
-	} else {
-		myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none";
-		myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
-	}
-	for (i = 0; i < PROPOSAL_MAX; i++)
-		cprop[i] = xstrdup(myproposal[i]);
-
-	client_kexinit = kex_init(cprop);
-	packet_start(SSH2_MSG_KEXINIT);
-	packet_put_raw(buffer_ptr(client_kexinit), buffer_len(client_kexinit));	
-	packet_send();
-	packet_write_wait();
-
-	debug("done");
-
-	packet_read_expect(&payload_len, SSH2_MSG_KEXINIT);
-
-	/* save payload for session_id */
-	server_kexinit = xmalloc(sizeof(*server_kexinit));
-	buffer_init(server_kexinit);
-	ptr = packet_get_raw(&payload_len);
-	buffer_append(server_kexinit, ptr, payload_len);
-
-	/* skip cookie */
-	for (i = 0; i < 16; i++)
-		(void) packet_get_char();
-	/* kex init proposal strings */
-	for (i = 0; i < PROPOSAL_MAX; i++) {
-		sprop[i] = packet_get_string(NULL);
-		debug("got kexinit string: %s", sprop[i]);
-	}
-	i = (int) packet_get_char();
-	debug("first kex follow == %d", i);
-	i = packet_get_int();
-	debug("reserved == %d", i);
-	packet_done();
-
-	debug("done read kexinit");
-	kex = kex_choose_conf(cprop, sprop, 0);
-
-/* KEXDH */
-
-	debug("Sending SSH2_MSG_KEXDH_INIT.");
-
-	/* generate and send 'e', client DH public key */
-	dh = dh_new_group1();
-	packet_start(SSH2_MSG_KEXDH_INIT);
-	packet_put_bignum2(dh->pub_key);
-	packet_send();
-	packet_write_wait();
-
-#ifdef DEBUG_KEXDH
-	fprintf(stderr, "\np= ");
-	bignum_print(dh->p);
-	fprintf(stderr, "\ng= ");
-	bignum_print(dh->g);
-	fprintf(stderr, "\npub= ");
-	bignum_print(dh->pub_key);
-	fprintf(stderr, "\n");
-	DHparams_print_fp(stderr, dh);
-#endif
-
-	debug("Wait SSH2_MSG_KEXDH_REPLY.");
-
-	packet_read_expect(&payload_len, SSH2_MSG_KEXDH_REPLY);
-
-	debug("Got SSH2_MSG_KEXDH_REPLY.");
-
-	/* key, cert */
-	server_host_key_blob = packet_get_string(&sbloblen);
-	server_host_key = dsa_serverkey_from_blob(server_host_key_blob, sbloblen);
-	if (server_host_key == NULL)
-		fatal("cannot decode server_host_key_blob");
-
-	check_host_key(host, hostaddr, server_host_key);
-
-	/* DH paramter f, server public DH key */
-	dh_server_pub = BN_new();
-	if (dh_server_pub == NULL)
-		fatal("dh_server_pub == NULL");
-	packet_get_bignum2(dh_server_pub, &dlen);
-
-#ifdef DEBUG_KEXDH
-	fprintf(stderr, "\ndh_server_pub= ");
-	bignum_print(dh_server_pub);
-	fprintf(stderr, "\n");
-	debug("bits %d", BN_num_bits(dh_server_pub));
-#endif
-
-	/* signed H */
-	signature = packet_get_string(&slen);
-	packet_done();
-
-	if (!dh_pub_is_valid(dh, dh_server_pub))
-		packet_disconnect("bad server public DH value");
-
-	klen = DH_size(dh);
-	kbuf = xmalloc(klen);
-	kout = DH_compute_key(kbuf, dh_server_pub, dh);
-#ifdef DEBUG_KEXDH
-	debug("shared secret: len %d/%d", klen, kout);
-	fprintf(stderr, "shared secret == ");
-	for (i = 0; i< kout; i++)
-		fprintf(stderr, "%02x", (kbuf[i])&0xff);
-	fprintf(stderr, "\n");
-#endif
-	shared_secret = BN_new();
-
-	BN_bin2bn(kbuf, kout, shared_secret);
-	memset(kbuf, 0, klen);
-	xfree(kbuf);
-
-	/* calc and verify H */
-	hash = kex_hash(
-	    client_version_string,
-	    server_version_string,
-	    buffer_ptr(client_kexinit), buffer_len(client_kexinit),
-	    buffer_ptr(server_kexinit), buffer_len(server_kexinit),
-	    server_host_key_blob, sbloblen,
-	    dh->pub_key,
-	    dh_server_pub,
-	    shared_secret
-	);
-	buffer_free(client_kexinit);
-	buffer_free(server_kexinit);
-	xfree(client_kexinit);
-	xfree(server_kexinit);
-#ifdef DEBUG_KEXDH
-	fprintf(stderr, "hash == ");
-	for (i = 0; i< 20; i++)
-		fprintf(stderr, "%02x", (hash[i])&0xff);
-	fprintf(stderr, "\n");
-#endif
-	dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20);
-	key_free(server_host_key);
-
-	kex_derive_keys(kex, hash, shared_secret);
-	packet_set_kex(kex);
-
-	/* have keys, free DH */
-	DH_free(dh);
-
-	debug("Wait SSH2_MSG_NEWKEYS.");
-	packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS);
-	packet_done();
-	debug("GOT SSH2_MSG_NEWKEYS.");
-
-	debug("send SSH2_MSG_NEWKEYS.");
-	packet_start(SSH2_MSG_NEWKEYS);
-	packet_send();
-	packet_write_wait();
-	debug("done: send SSH2_MSG_NEWKEYS.");
-
-#ifdef DEBUG_KEXDH
-	/* send 1st encrypted/maced/compressed message */
-	packet_start(SSH2_MSG_IGNORE);
-	packet_put_cstring("markus");
-	packet_send();
-	packet_write_wait();
-#endif
-	debug("done: KEX2.");
-}
-/*
- * Authenticate user
- */
-void
-ssh_userauth2(int host_key_valid, RSA *own_host_key,
-    uid_t original_real_uid, char *host)
-{
-	int type;
-	int plen;
-	unsigned int dlen;
-	int partial;
-	struct passwd *pw;
-	char prompt[80];
-	char *server_user, *local_user;
-	char *auths;
-	char *password;
-	char *service = "ssh-connection";		/* service name */
-
-	debug("send SSH2_MSG_SERVICE_REQUEST");
-	packet_start(SSH2_MSG_SERVICE_REQUEST);
-	packet_put_cstring("ssh-userauth");
-	packet_send();
-	packet_write_wait();
-
-	type = packet_read(&plen);
-	if (type != SSH2_MSG_SERVICE_ACCEPT) {
-		fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
-	}
-	if (packet_remaining() > 0) {
-		char *reply = packet_get_string(&plen);
-		debug("service_accept: %s", reply);
-		xfree(reply);
-	} else {
-		/* payload empty for ssh-2.0.13 ?? */
-		log("buggy server: service_accept w/o service");
-	}
-	packet_done();
-	debug("got SSH2_MSG_SERVICE_ACCEPT");
-
-	/*XX COMMONCODE: */
-	/* Get local user name.  Use it as server user if no user name was given. */
-	pw = getpwuid(original_real_uid);
-	if (!pw)
-		fatal("User id %d not found from user database.", original_real_uid);
-	local_user = xstrdup(pw->pw_name);
-	server_user = options.user ? options.user : local_user;
-
-	/* INITIAL request for auth */
-	packet_start(SSH2_MSG_USERAUTH_REQUEST);
-	packet_put_cstring(server_user);
-	packet_put_cstring(service);
-	packet_put_cstring("none");
-	packet_send();
-	packet_write_wait();
-
-	for (;;) {
-		type = packet_read(&plen);
-		if (type == SSH2_MSG_USERAUTH_SUCCESS)
-			break;
-		if (type != SSH2_MSG_USERAUTH_FAILURE)
-			fatal("access denied: %d", type);
-		/* SSH2_MSG_USERAUTH_FAILURE means: try again */
-		auths = packet_get_string(&dlen);
-		debug("authentications that can continue: %s", auths);
-		partial = packet_get_char();
-		packet_done();
-		if (partial)
-			debug("partial success");
-		if (strstr(auths, "password") == NULL)
-			fatal("passwd auth not supported: %s", auths);
-		xfree(auths);
-		/* try passwd */
-		snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
-		    server_user, host);
-		password = read_passphrase(prompt, 0);
-		packet_start(SSH2_MSG_USERAUTH_REQUEST);
-		packet_put_cstring(server_user);
-		packet_put_cstring(service);
-		packet_put_cstring("password");
-		packet_put_char(0);
-		packet_put_cstring(password);
-		memset(password, 0, strlen(password));
-		xfree(password);
-		packet_send();
-		packet_write_wait();
-	}
-	packet_done();
-	debug("ssh-userauth2 successfull");
-}
-
-/*
- * SSH1 key exchange
- */
-void
-ssh_kex(char *host, struct sockaddr *hostaddr)
-{
-	int i;
-	BIGNUM *key;
-	RSA *host_key;
-	RSA *public_key;
-	int bits, rbits;
-	int ssh_cipher_default = SSH_CIPHER_3DES;
-	unsigned char session_key[SSH_SESSION_KEY_LENGTH];
-	unsigned char cookie[8];
-	unsigned int supported_ciphers;
-	unsigned int server_flags, client_flags;
-	int payload_len, clen, sum_len = 0;
-	u_int32_t rand = 0;
-
-	debug("Waiting for server public key.");
-
-	/* Wait for a public key packet from the server. */
-	packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY);
-
-	/* Get cookie from the packet. */
-	for (i = 0; i < 8; i++)
-		cookie[i] = packet_get_char();
-
-	/* Get the public key. */
-	public_key = RSA_new();
-	bits = packet_get_int();/* bits */
-	public_key->e = BN_new();
-	packet_get_bignum(public_key->e, &clen);
-	sum_len += clen;
-	public_key->n = BN_new();
-	packet_get_bignum(public_key->n, &clen);
-	sum_len += clen;
-
-	rbits = BN_num_bits(public_key->n);
-	if (bits != rbits) {
-		log("Warning: Server lies about size of server public key: "
-		    "actual size is %d bits vs. announced %d.", rbits, bits);
-		log("Warning: This may be due to an old implementation of ssh.");
-	}
-	/* Get the host key. */
-	host_key = RSA_new();
-	bits = packet_get_int();/* bits */
-	host_key->e = BN_new();
-	packet_get_bignum(host_key->e, &clen);
-	sum_len += clen;
-	host_key->n = BN_new();
-	packet_get_bignum(host_key->n, &clen);
-	sum_len += clen;
-
-	rbits = BN_num_bits(host_key->n);
-	if (bits != rbits) {
-		log("Warning: Server lies about size of server host key: "
-		    "actual size is %d bits vs. announced %d.", rbits, bits);
-		log("Warning: This may be due to an old implementation of ssh.");
-	}
-
-	/* Get protocol flags. */
-	server_flags = packet_get_int();
-	packet_set_protocol_flags(server_flags);
-
-	supported_ciphers = packet_get_int();
-	supported_authentications = packet_get_int();
-
-	debug("Received server public key (%d bits) and host key (%d bits).",
-	      BN_num_bits(public_key->n), BN_num_bits(host_key->n));
-
-	packet_integrity_check(payload_len,
-			       8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
-			       SSH_SMSG_PUBLIC_KEY);
-
-	check_rsa_host_key(host, hostaddr, host_key);
-
-	client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN;
-
-	compute_session_id(session_id, cookie, host_key->n, public_key->n);
-
-	/* Generate a session key. */
-	arc4random_stir();
-
-	/*
-	 * Generate an encryption key for the session.   The key is a 256 bit
-	 * random number, interpreted as a 32-byte key, with the least
-	 * significant 8 bits being the first byte of the key.
-	 */
-	for (i = 0; i < 32; i++) {
-		if (i % 4 == 0)
-			rand = arc4random();
-		session_key[i] = rand & 0xff;
-		rand >>= 8;
-	}
-
-	/*
-	 * According to the protocol spec, the first byte of the session key
-	 * is the highest byte of the integer.  The session key is xored with
-	 * the first 16 bytes of the session id.
-	 */
-	key = BN_new();
-	BN_set_word(key, 0);
-	for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
-		BN_lshift(key, key, 8);
-		if (i < 16)
-			BN_add_word(key, session_key[i] ^ session_id[i]);
-		else
-			BN_add_word(key, session_key[i]);
-	}
-
-	/*
-	 * Encrypt the integer using the public key and host key of the
-	 * server (key with smaller modulus first).
-	 */
-	if (BN_cmp(public_key->n, host_key->n) < 0) {
-		/* Public key has smaller modulus. */
-		if (BN_num_bits(host_key->n) <
-		    BN_num_bits(public_key->n) + SSH_KEY_BITS_RESERVED) {
-			fatal("respond_to_rsa_challenge: host_key %d < public_key %d + "
-			      "SSH_KEY_BITS_RESERVED %d",
-			      BN_num_bits(host_key->n),
-			      BN_num_bits(public_key->n),
-			      SSH_KEY_BITS_RESERVED);
-		}
-		rsa_public_encrypt(key, key, public_key);
-		rsa_public_encrypt(key, key, host_key);
-	} else {
-		/* Host key has smaller modulus (or they are equal). */
-		if (BN_num_bits(public_key->n) <
-		    BN_num_bits(host_key->n) + SSH_KEY_BITS_RESERVED) {
-			fatal("respond_to_rsa_challenge: public_key %d < host_key %d + "
-			      "SSH_KEY_BITS_RESERVED %d",
-			      BN_num_bits(public_key->n),
-			      BN_num_bits(host_key->n),
-			      SSH_KEY_BITS_RESERVED);
-		}
-		rsa_public_encrypt(key, key, host_key);
-		rsa_public_encrypt(key, key, public_key);
-	}
-
-	/* Destroy the public keys since we no longer need them. */
-	RSA_free(public_key);
-	RSA_free(host_key);
-
-	if (options.cipher == SSH_CIPHER_NOT_SET) {
-		if (cipher_mask1() & supported_ciphers & (1 << ssh_cipher_default))
-			options.cipher = ssh_cipher_default;
-		else {
-			debug("Cipher %s not supported, using %.100s instead.",
-			      cipher_name(ssh_cipher_default),
-			      cipher_name(SSH_FALLBACK_CIPHER));
-			options.cipher = SSH_FALLBACK_CIPHER;
-		}
-	}
-	/* Check that the selected cipher is supported. */
-	if (!(supported_ciphers & (1 << options.cipher)))
-		fatal("Selected cipher type %.100s not supported by server.",
-		      cipher_name(options.cipher));
-
-	debug("Encryption type: %.100s", cipher_name(options.cipher));
-
-	/* Send the encrypted session key to the server. */
-	packet_start(SSH_CMSG_SESSION_KEY);
-	packet_put_char(options.cipher);
-
-	/* Send the cookie back to the server. */
-	for (i = 0; i < 8; i++)
-		packet_put_char(cookie[i]);
-
-	/* Send and destroy the encrypted encryption key integer. */
-	packet_put_bignum(key);
-	BN_clear_free(key);
-
-	/* Send protocol flags. */
-	packet_put_int(client_flags);
-
-	/* Send the packet now. */
-	packet_send();
-	packet_write_wait();
-
-	debug("Sent encrypted session key.");
-
-	/* Set the encryption key. */
-	packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, options.cipher);
-
-	/* We will no longer need the session key here.  Destroy any extra copies. */
-	memset(session_key, 0, sizeof(session_key));
-
-	/*
-	 * Expect a success message from the server.  Note that this message
-	 * will be received in encrypted form.
-	 */
-	packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
-
-	debug("Received encrypted confirmation.");
-}
-
-/*
- * Authenticate user
- */
-void
-ssh_userauth(int host_key_valid, RSA *own_host_key,
-    uid_t original_real_uid, char *host)
-{
-	int i, type;
-	int payload_len;
-	struct passwd *pw;
-	const char *server_user, *local_user;
-
-	/* Get local user name.  Use it as server user if no user name was given. */
-	pw = getpwuid(original_real_uid);
-	if (!pw)
-		fatal("User id %d not found from user database.", original_real_uid);
-	local_user = xstrdup(pw->pw_name);
-	server_user = options.user ? options.user : local_user;
-
-	/* Send the name of the user to log in as on the server. */
-	packet_start(SSH_CMSG_USER);
-	packet_put_string(server_user, strlen(server_user));
-	packet_send();
-	packet_write_wait();
-
-	/*
-	 * The server should respond with success if no authentication is
-	 * needed (the user has no password).  Otherwise the server responds
-	 * with failure.
-	 */
-	type = packet_read(&payload_len);
-
-	/* check whether the connection was accepted without authentication. */
-	if (type == SSH_SMSG_SUCCESS)
-		return;
-	if (type != SSH_SMSG_FAILURE)
-		packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER",
-				  type);
-
-#ifdef AFS
-	/* Try Kerberos tgt passing if the server supports it. */
-	if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
-	    options.kerberos_tgt_passing) {
-		if (options.cipher == SSH_CIPHER_NONE)
-			log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
-		(void) send_kerberos_tgt();
-	}
-	/* Try AFS token passing if the server supports it. */
-	if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) &&
-	    options.afs_token_passing && k_hasafs()) {
-		if (options.cipher == SSH_CIPHER_NONE)
-			log("WARNING: Encryption is disabled! Token will be transmitted in the clear!");
-		send_afs_tokens();
-	}
-#endif /* AFS */
-
-#ifdef KRB4
-	if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&
-	    options.kerberos_authentication) {
-		debug("Trying Kerberos authentication.");
-		if (try_kerberos_authentication()) {
-			/* The server should respond with success or failure. */
-			type = packet_read(&payload_len);
-			if (type == SSH_SMSG_SUCCESS)
-				return;
-			if (type != SSH_SMSG_FAILURE)
-				packet_disconnect("Protocol error: got %d in response to Kerberos auth", type);
-		}
-	}
-#endif /* KRB4 */
-
-	/*
-	 * Use rhosts authentication if running in privileged socket and we
-	 * do not wish to remain anonymous.
-	 */
-	if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) &&
-	    options.rhosts_authentication) {
-		debug("Trying rhosts authentication.");
-		packet_start(SSH_CMSG_AUTH_RHOSTS);
-		packet_put_string(local_user, strlen(local_user));
-		packet_send();
-		packet_write_wait();
-
-		/* The server should respond with success or failure. */
-		type = packet_read(&payload_len);
-		if (type == SSH_SMSG_SUCCESS)
-			return;
-		if (type != SSH_SMSG_FAILURE)
-			packet_disconnect("Protocol error: got %d in response to rhosts auth",
-					  type);
-	}
-	/*
-	 * Try .rhosts or /etc/hosts.equiv authentication with RSA host
-	 * authentication.
-	 */
-	if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&
-	    options.rhosts_rsa_authentication && host_key_valid) {
-		if (try_rhosts_rsa_authentication(local_user, own_host_key))
-			return;
-	}
-	/* Try RSA authentication if the server supports it. */
-	if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
-	    options.rsa_authentication) {
-		/*
-		 * Try RSA authentication using the authentication agent. The
-		 * agent is tried first because no passphrase is needed for
-		 * it, whereas identity files may require passphrases.
-		 */
-		if (try_agent_authentication())
-			return;
-
-		/* Try RSA authentication for each identity. */
-		for (i = 0; i < options.num_identity_files; i++)
-			if (try_rsa_authentication(options.identity_files[i]))
-				return;
-	}
-	/* Try skey authentication if the server supports it. */
-	if ((supported_authentications & (1 << SSH_AUTH_TIS)) &&
-	    options.skey_authentication && !options.batch_mode) {
-		if (try_skey_authentication())
-			return;
-	}
-	/* Try password authentication if the server supports it. */
-	if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) &&
-	    options.password_authentication && !options.batch_mode) {
-		char prompt[80];
 
-		snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
-		    server_user, host);
-		if (try_password_authentication(prompt))
-			return;
-	}
-	/* All authentication methods have failed.  Exit with an error message. */
-	fatal("Permission denied.");
-	/* NOTREACHED */
-}
 /*
  * Starts a dialog with the server, and authenticates the current user on the
  * server.  This does not need any extra privileges.  The basic connection
@@ -1966,7 +666,16 @@
 ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
     struct sockaddr *hostaddr, uid_t original_real_uid)
 {
+	struct passwd *pw;
 	char *host, *cp;
+	char *server_user, *local_user;
+
+	/* Get local user name.  Use it as server user if no user name was given. */
+	pw = getpwuid(original_real_uid);
+	if (!pw)
+		fatal("User id %d not found from user database.", original_real_uid);
+	local_user = xstrdup(pw->pw_name);
+	server_user = options.user ? options.user : local_user;
 
 	/* Convert the user-supplied hostname into all lowercase. */
 	host = xstrdup(orighost);
@@ -1984,12 +693,9 @@
 	/* authenticate user */
 	if (compat20) {
 		ssh_kex2(host, hostaddr);
-		ssh_userauth2(host_key_valid, own_host_key, original_real_uid, host);
+		ssh_userauth2(server_user, host);
 	} else {
-		supported_authentications = 0;
 		ssh_kex(host, hostaddr);
-		if (supported_authentications == 0)
-			fatal("supported_authentications == 0.");
-		ssh_userauth(host_key_valid, own_host_key, original_real_uid, host);
+		ssh_userauth(local_user, server_user, host, host_key_valid, own_host_key);
 	}
 }
diff --git a/sshconnect.h b/sshconnect.h
new file mode 100644
index 0000000..13d395f
--- /dev/null
+++ b/sshconnect.h
@@ -0,0 +1,16 @@
+#ifndef SSHCONNECT_H
+#define SSHCONNECT_H
+
+void
+check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
+    const char *user_hostfile, const char *system_hostfile);
+
+void	ssh_kex(char *host, struct sockaddr *hostaddr);
+void
+ssh_userauth(const char* local_user, const char* server_user, char *host,
+    int host_key_valid, RSA *own_host_key);
+
+void	ssh_kex2(char *host, struct sockaddr *hostaddr);
+void	ssh_userauth2(const char *server_user, char *host);
+
+#endif
diff --git a/sshconnect1.c b/sshconnect1.c
new file mode 100644
index 0000000..c5a7665
--- /dev/null
+++ b/sshconnect1.c
@@ -0,0 +1,1020 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    All rights reserved
+ * Created: Sat Mar 18 22:15:47 1995 ylo
+ * Code to connect to a remote host, and to perform the client side of the
+ * login (authentication) dialog.
+ *
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: sshconnect1.c,v 1.1 2000/04/26 21:28:33 markus Exp $");
+
+#include <openssl/bn.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+
+#include "xmalloc.h"
+#include "rsa.h"
+#include "ssh.h"
+#include "buffer.h"
+#include "packet.h"
+#include "authfd.h"
+#include "cipher.h"
+#include "mpaux.h"
+#include "uidswap.h"
+#include "readconf.h"
+#include "key.h"
+#include "sshconnect.h"
+#include "authfile.h"
+
+/* Session id for the current session. */
+unsigned char session_id[16];
+unsigned int supported_authentications = 0;
+
+extern Options options;
+extern char *__progname;
+
+/*
+ * Checks if the user has an authentication agent, and if so, tries to
+ * authenticate using the agent.
+ */
+int
+try_agent_authentication()
+{
+	int status, type;
+	char *comment;
+	AuthenticationConnection *auth;
+	unsigned char response[16];
+	unsigned int i;
+	BIGNUM *e, *n, *challenge;
+
+	/* Get connection to the agent. */
+	auth = ssh_get_authentication_connection();
+	if (!auth)
+		return 0;
+
+	e = BN_new();
+	n = BN_new();
+	challenge = BN_new();
+
+	/* Loop through identities served by the agent. */
+	for (status = ssh_get_first_identity(auth, e, n, &comment);
+	     status;
+	     status = ssh_get_next_identity(auth, e, n, &comment)) {
+		int plen, clen;
+
+		/* Try this identity. */
+		debug("Trying RSA authentication via agent with '%.100s'", comment);
+		xfree(comment);
+
+		/* Tell the server that we are willing to authenticate using this key. */
+		packet_start(SSH_CMSG_AUTH_RSA);
+		packet_put_bignum(n);
+		packet_send();
+		packet_write_wait();
+
+		/* Wait for server's response. */
+		type = packet_read(&plen);
+
+		/* The server sends failure if it doesn\'t like our key or
+		   does not support RSA authentication. */
+		if (type == SSH_SMSG_FAILURE) {
+			debug("Server refused our key.");
+			continue;
+		}
+		/* Otherwise it should have sent a challenge. */
+		if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
+			packet_disconnect("Protocol error during RSA authentication: %d",
+					  type);
+
+		packet_get_bignum(challenge, &clen);
+
+		packet_integrity_check(plen, clen, type);
+
+		debug("Received RSA challenge from server.");
+
+		/* Ask the agent to decrypt the challenge. */
+		if (!ssh_decrypt_challenge(auth, e, n, challenge,
+					   session_id, 1, response)) {
+			/* The agent failed to authenticate this identifier although it
+			   advertised it supports this.  Just return a wrong value. */
+			log("Authentication agent failed to decrypt challenge.");
+			memset(response, 0, sizeof(response));
+		}
+		debug("Sending response to RSA challenge.");
+
+		/* Send the decrypted challenge back to the server. */
+		packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
+		for (i = 0; i < 16; i++)
+			packet_put_char(response[i]);
+		packet_send();
+		packet_write_wait();
+
+		/* Wait for response from the server. */
+		type = packet_read(&plen);
+
+		/* The server returns success if it accepted the authentication. */
+		if (type == SSH_SMSG_SUCCESS) {
+			debug("RSA authentication accepted by server.");
+			BN_clear_free(e);
+			BN_clear_free(n);
+			BN_clear_free(challenge);
+			return 1;
+		}
+		/* Otherwise it should return failure. */
+		if (type != SSH_SMSG_FAILURE)
+			packet_disconnect("Protocol error waiting RSA auth response: %d",
+					  type);
+	}
+
+	BN_clear_free(e);
+	BN_clear_free(n);
+	BN_clear_free(challenge);
+
+	debug("RSA authentication using agent refused.");
+	return 0;
+}
+
+/*
+ * Computes the proper response to a RSA challenge, and sends the response to
+ * the server.
+ */
+void
+respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv)
+{
+	unsigned char buf[32], response[16];
+	MD5_CTX md;
+	int i, len;
+
+	/* Decrypt the challenge using the private key. */
+	rsa_private_decrypt(challenge, challenge, prv);
+
+	/* Compute the response. */
+	/* The response is MD5 of decrypted challenge plus session id. */
+	len = BN_num_bytes(challenge);
+	if (len <= 0 || len > sizeof(buf))
+		packet_disconnect("respond_to_rsa_challenge: bad challenge length %d",
+				  len);
+
+	memset(buf, 0, sizeof(buf));
+	BN_bn2bin(challenge, buf + sizeof(buf) - len);
+	MD5_Init(&md);
+	MD5_Update(&md, buf, 32);
+	MD5_Update(&md, session_id, 16);
+	MD5_Final(response, &md);
+
+	debug("Sending response to host key RSA challenge.");
+
+	/* Send the response back to the server. */
+	packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
+	for (i = 0; i < 16; i++)
+		packet_put_char(response[i]);
+	packet_send();
+	packet_write_wait();
+
+	memset(buf, 0, sizeof(buf));
+	memset(response, 0, sizeof(response));
+	memset(&md, 0, sizeof(md));
+}
+
+/*
+ * Checks if the user has authentication file, and if so, tries to authenticate
+ * the user using it.
+ */
+int
+try_rsa_authentication(const char *authfile)
+{
+	BIGNUM *challenge;
+	Key *public;
+	Key *private;
+	char *passphrase, *comment;
+	int type, i;
+	int plen, clen;
+
+	/* Try to load identification for the authentication key. */
+	public = key_new(KEY_RSA);
+	if (!load_public_key(authfile, public, &comment)) {
+		key_free(public);
+		/* Could not load it.  Fail. */
+		return 0;
+	}
+	debug("Trying RSA authentication with key '%.100s'", comment);
+
+	/* Tell the server that we are willing to authenticate using this key. */
+	packet_start(SSH_CMSG_AUTH_RSA);
+	packet_put_bignum(public->rsa->n);
+	packet_send();
+	packet_write_wait();
+
+	/* We no longer need the public key. */
+	key_free(public);
+
+	/* Wait for server's response. */
+	type = packet_read(&plen);
+
+	/*
+	 * The server responds with failure if it doesn\'t like our key or
+	 * doesn\'t support RSA authentication.
+	 */
+	if (type == SSH_SMSG_FAILURE) {
+		debug("Server refused our key.");
+		xfree(comment);
+		return 0;
+	}
+	/* Otherwise, the server should respond with a challenge. */
+	if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
+		packet_disconnect("Protocol error during RSA authentication: %d", type);
+
+	/* Get the challenge from the packet. */
+	challenge = BN_new();
+	packet_get_bignum(challenge, &clen);
+
+	packet_integrity_check(plen, clen, type);
+
+	debug("Received RSA challenge from server.");
+
+	private = key_new(KEY_RSA);
+	/*
+	 * Load the private key.  Try first with empty passphrase; if it
+	 * fails, ask for a passphrase.
+	 */
+	if (!load_private_key(authfile, "", private, NULL)) {
+		char buf[300];
+		snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
+		    comment);
+		if (!options.batch_mode)
+			passphrase = read_passphrase(buf, 0);
+		else {
+			debug("Will not query passphrase for %.100s in batch mode.",
+			      comment);
+			passphrase = xstrdup("");
+		}
+
+		/* Load the authentication file using the pasphrase. */
+		if (!load_private_key(authfile, passphrase, private, NULL)) {
+			memset(passphrase, 0, strlen(passphrase));
+			xfree(passphrase);
+			error("Bad passphrase.");
+
+			/* Send a dummy response packet to avoid protocol error. */
+			packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
+			for (i = 0; i < 16; i++)
+				packet_put_char(0);
+			packet_send();
+			packet_write_wait();
+
+			/* Expect the server to reject it... */
+			packet_read_expect(&plen, SSH_SMSG_FAILURE);
+			xfree(comment);
+			return 0;
+		}
+		/* Destroy the passphrase. */
+		memset(passphrase, 0, strlen(passphrase));
+		xfree(passphrase);
+	}
+	/* We no longer need the comment. */
+	xfree(comment);
+
+	/* Compute and send a response to the challenge. */
+	respond_to_rsa_challenge(challenge, private->rsa);
+
+	/* Destroy the private key. */
+	key_free(private);
+
+	/* We no longer need the challenge. */
+	BN_clear_free(challenge);
+
+	/* Wait for response from the server. */
+	type = packet_read(&plen);
+	if (type == SSH_SMSG_SUCCESS) {
+		debug("RSA authentication accepted by server.");
+		return 1;
+	}
+	if (type != SSH_SMSG_FAILURE)
+		packet_disconnect("Protocol error waiting RSA auth response: %d", type);
+	debug("RSA authentication refused.");
+	return 0;
+}
+
+/*
+ * Tries to authenticate the user using combined rhosts or /etc/hosts.equiv
+ * authentication and RSA host authentication.
+ */
+int
+try_rhosts_rsa_authentication(const char *local_user, RSA * host_key)
+{
+	int type;
+	BIGNUM *challenge;
+	int plen, clen;
+
+	debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication.");
+
+	/* Tell the server that we are willing to authenticate using this key. */
+	packet_start(SSH_CMSG_AUTH_RHOSTS_RSA);
+	packet_put_string(local_user, strlen(local_user));
+	packet_put_int(BN_num_bits(host_key->n));
+	packet_put_bignum(host_key->e);
+	packet_put_bignum(host_key->n);
+	packet_send();
+	packet_write_wait();
+
+	/* Wait for server's response. */
+	type = packet_read(&plen);
+
+	/* The server responds with failure if it doesn't admit our
+	   .rhosts authentication or doesn't know our host key. */
+	if (type == SSH_SMSG_FAILURE) {
+		debug("Server refused our rhosts authentication or host key.");
+		return 0;
+	}
+	/* Otherwise, the server should respond with a challenge. */
+	if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
+		packet_disconnect("Protocol error during RSA authentication: %d", type);
+
+	/* Get the challenge from the packet. */
+	challenge = BN_new();
+	packet_get_bignum(challenge, &clen);
+
+	packet_integrity_check(plen, clen, type);
+
+	debug("Received RSA challenge for host key from server.");
+
+	/* Compute a response to the challenge. */
+	respond_to_rsa_challenge(challenge, host_key);
+
+	/* We no longer need the challenge. */
+	BN_clear_free(challenge);
+
+	/* Wait for response from the server. */
+	type = packet_read(&plen);
+	if (type == SSH_SMSG_SUCCESS) {
+		debug("Rhosts or /etc/hosts.equiv with RSA host authentication accepted by server.");
+		return 1;
+	}
+	if (type != SSH_SMSG_FAILURE)
+		packet_disconnect("Protocol error waiting RSA auth response: %d", type);
+	debug("Rhosts or /etc/hosts.equiv with RSA host authentication refused.");
+	return 0;
+}
+
+#ifdef KRB4
+int
+try_kerberos_authentication()
+{
+	KTEXT_ST auth;		/* Kerberos data */
+	char *reply;
+	char inst[INST_SZ];
+	char *realm;
+	CREDENTIALS cred;
+	int r, type, plen;
+	socklen_t slen;
+	Key_schedule schedule;
+	u_long checksum, cksum;
+	MSG_DAT msg_data;
+	struct sockaddr_in local, foreign;
+	struct stat st;
+
+	/* Don't do anything if we don't have any tickets. */
+	if (stat(tkt_string(), &st) < 0)
+		return 0;
+
+	strncpy(inst, (char *) krb_get_phost(get_canonical_hostname()), INST_SZ);
+
+	realm = (char *) krb_realmofhost(get_canonical_hostname());
+	if (!realm) {
+		debug("Kerberos V4: no realm for %s", get_canonical_hostname());
+		return 0;
+	}
+	/* This can really be anything. */
+	checksum = (u_long) getpid();
+
+	r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum);
+	if (r != KSUCCESS) {
+		debug("Kerberos V4 krb_mk_req failed: %s", krb_err_txt[r]);
+		return 0;
+	}
+	/* Get session key to decrypt the server's reply with. */
+	r = krb_get_cred(KRB4_SERVICE_NAME, inst, realm, &cred);
+	if (r != KSUCCESS) {
+		debug("get_cred failed: %s", krb_err_txt[r]);
+		return 0;
+	}
+	des_key_sched((des_cblock *) cred.session, schedule);
+
+	/* Send authentication info to server. */
+	packet_start(SSH_CMSG_AUTH_KERBEROS);
+	packet_put_string((char *) auth.dat, auth.length);
+	packet_send();
+	packet_write_wait();
+
+	/* Zero the buffer. */
+	(void) memset(auth.dat, 0, MAX_KTXT_LEN);
+
+	slen = sizeof(local);
+	memset(&local, 0, sizeof(local));
+	if (getsockname(packet_get_connection_in(),
+			(struct sockaddr *) & local, &slen) < 0)
+		debug("getsockname failed: %s", strerror(errno));
+
+	slen = sizeof(foreign);
+	memset(&foreign, 0, sizeof(foreign));
+	if (getpeername(packet_get_connection_in(),
+			(struct sockaddr *) & foreign, &slen) < 0) {
+		debug("getpeername failed: %s", strerror(errno));
+		fatal_cleanup();
+	}
+	/* Get server reply. */
+	type = packet_read(&plen);
+	switch (type) {
+	case SSH_SMSG_FAILURE:
+		/* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */
+		debug("Kerberos V4 authentication failed.");
+		return 0;
+		break;
+
+	case SSH_SMSG_AUTH_KERBEROS_RESPONSE:
+		/* SSH_SMSG_AUTH_KERBEROS_SUCCESS */
+		debug("Kerberos V4 authentication accepted.");
+
+		/* Get server's response. */
+		reply = packet_get_string((unsigned int *) &auth.length);
+		memcpy(auth.dat, reply, auth.length);
+		xfree(reply);
+
+		packet_integrity_check(plen, 4 + auth.length, type);
+
+		/*
+		 * If his response isn't properly encrypted with the session
+		 * key, and the decrypted checksum fails to match, he's
+		 * bogus. Bail out.
+		 */
+		r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session,
+				&foreign, &local, &msg_data);
+		if (r != KSUCCESS) {
+			debug("Kerberos V4 krb_rd_priv failed: %s", krb_err_txt[r]);
+			packet_disconnect("Kerberos V4 challenge failed!");
+		}
+		/* Fetch the (incremented) checksum that we supplied in the request. */
+		(void) memcpy((char *) &cksum, (char *) msg_data.app_data, sizeof(cksum));
+		cksum = ntohl(cksum);
+
+		/* If it matches, we're golden. */
+		if (cksum == checksum + 1) {
+			debug("Kerberos V4 challenge successful.");
+			return 1;
+		} else
+			packet_disconnect("Kerberos V4 challenge failed!");
+		break;
+
+	default:
+		packet_disconnect("Protocol error on Kerberos V4 response: %d", type);
+	}
+	return 0;
+}
+
+#endif /* KRB4 */
+
+#ifdef AFS
+int
+send_kerberos_tgt()
+{
+	CREDENTIALS *creds;
+	char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
+	int r, type, plen;
+	char buffer[8192];
+	struct stat st;
+
+	/* Don't do anything if we don't have any tickets. */
+	if (stat(tkt_string(), &st) < 0)
+		return 0;
+
+	creds = xmalloc(sizeof(*creds));
+
+	if ((r = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm)) != KSUCCESS) {
+		debug("Kerberos V4 tf_fullname failed: %s", krb_err_txt[r]);
+		return 0;
+	}
+	if ((r = krb_get_cred("krbtgt", prealm, prealm, creds)) != GC_OK) {
+		debug("Kerberos V4 get_cred failed: %s", krb_err_txt[r]);
+		return 0;
+	}
+	if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) {
+		debug("Kerberos V4 ticket expired: %s", TKT_FILE);
+		return 0;
+	}
+	creds_to_radix(creds, (unsigned char *)buffer);
+	xfree(creds);
+
+	packet_start(SSH_CMSG_HAVE_KERBEROS_TGT);
+	packet_put_string(buffer, strlen(buffer));
+	packet_send();
+	packet_write_wait();
+
+	type = packet_read(&plen);
+
+	if (type == SSH_SMSG_FAILURE)
+		debug("Kerberos TGT for realm %s rejected.", prealm);
+	else if (type != SSH_SMSG_SUCCESS)
+		packet_disconnect("Protocol error on Kerberos TGT response: %d", type);
+
+	return 1;
+}
+
+void
+send_afs_tokens(void)
+{
+	CREDENTIALS creds;
+	struct ViceIoctl parms;
+	struct ClearToken ct;
+	int i, type, len, plen;
+	char buf[2048], *p, *server_cell;
+	char buffer[8192];
+
+	/* Move over ktc_GetToken, here's something leaner. */
+	for (i = 0; i < 100; i++) {	/* just in case */
+		parms.in = (char *) &i;
+		parms.in_size = sizeof(i);
+		parms.out = buf;
+		parms.out_size = sizeof(buf);
+		if (k_pioctl(0, VIOCGETTOK, &parms, 0) != 0)
+			break;
+		p = buf;
+
+		/* Get secret token. */
+		memcpy(&creds.ticket_st.length, p, sizeof(unsigned int));
+		if (creds.ticket_st.length > MAX_KTXT_LEN)
+			break;
+		p += sizeof(unsigned int);
+		memcpy(creds.ticket_st.dat, p, creds.ticket_st.length);
+		p += creds.ticket_st.length;
+
+		/* Get clear token. */
+		memcpy(&len, p, sizeof(len));
+		if (len != sizeof(struct ClearToken))
+			break;
+		p += sizeof(len);
+		memcpy(&ct, p, len);
+		p += len;
+		p += sizeof(len);	/* primary flag */
+		server_cell = p;
+
+		/* Flesh out our credentials. */
+		strlcpy(creds.service, "afs", sizeof creds.service);
+		creds.instance[0] = '\0';
+		strlcpy(creds.realm, server_cell, REALM_SZ);
+		memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ);
+		creds.issue_date = ct.BeginTimestamp;
+		creds.lifetime = krb_time_to_life(creds.issue_date, ct.EndTimestamp);
+		creds.kvno = ct.AuthHandle;
+		snprintf(creds.pname, sizeof(creds.pname), "AFS ID %d", ct.ViceId);
+		creds.pinst[0] = '\0';
+
+		/* Encode token, ship it off. */
+		if (!creds_to_radix(&creds, (unsigned char*) buffer))
+			break;
+		packet_start(SSH_CMSG_HAVE_AFS_TOKEN);
+		packet_put_string(buffer, strlen(buffer));
+		packet_send();
+		packet_write_wait();
+
+		/* Roger, Roger. Clearance, Clarence. What's your vector,
+		   Victor? */
+		type = packet_read(&plen);
+
+		if (type == SSH_SMSG_FAILURE)
+			debug("AFS token for cell %s rejected.", server_cell);
+		else if (type != SSH_SMSG_SUCCESS)
+			packet_disconnect("Protocol error on AFS token response: %d", type);
+	}
+}
+
+#endif /* AFS */
+
+/*
+ * Tries to authenticate with any string-based challenge/response system.
+ * Note that the client code is not tied to s/key or TIS.
+ */
+int
+try_skey_authentication()
+{
+	int type, i;
+	int payload_len;
+	unsigned int clen;
+	char *challenge, *response;
+
+	debug("Doing skey authentication.");
+
+	/* request a challenge */
+	packet_start(SSH_CMSG_AUTH_TIS);
+	packet_send();
+	packet_write_wait();
+
+	type = packet_read(&payload_len);
+	if (type != SSH_SMSG_FAILURE &&
+	    type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
+		packet_disconnect("Protocol error: got %d in response "
+				  "to skey-auth", type);
+	}
+	if (type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
+		debug("No challenge for skey authentication.");
+		return 0;
+	}
+	challenge = packet_get_string(&clen);
+	packet_integrity_check(payload_len, (4 + clen), type);
+	if (options.cipher == SSH_CIPHER_NONE)
+		log("WARNING: Encryption is disabled! "
+		    "Reponse will be transmitted in clear text.");
+	fprintf(stderr, "%s\n", challenge);
+	xfree(challenge);
+	fflush(stderr);
+	for (i = 0; i < options.number_of_password_prompts; i++) {
+		if (i != 0)
+			error("Permission denied, please try again.");
+		response = read_passphrase("Response: ", 0);
+		packet_start(SSH_CMSG_AUTH_TIS_RESPONSE);
+		packet_put_string(response, strlen(response));
+		memset(response, 0, strlen(response));
+		xfree(response);
+		packet_send();
+		packet_write_wait();
+		type = packet_read(&payload_len);
+		if (type == SSH_SMSG_SUCCESS)
+			return 1;
+		if (type != SSH_SMSG_FAILURE)
+			packet_disconnect("Protocol error: got %d in response "
+					  "to skey-auth-reponse", type);
+	}
+	/* failure */
+	return 0;
+}
+
+/*
+ * Tries to authenticate with plain passwd authentication.
+ */
+int
+try_password_authentication(char *prompt)
+{
+	int type, i, payload_len;
+	char *password;
+
+	debug("Doing password authentication.");
+	if (options.cipher == SSH_CIPHER_NONE)
+		log("WARNING: Encryption is disabled! Password will be transmitted in clear text.");
+	for (i = 0; i < options.number_of_password_prompts; i++) {
+		if (i != 0)
+			error("Permission denied, please try again.");
+		password = read_passphrase(prompt, 0);
+		packet_start(SSH_CMSG_AUTH_PASSWORD);
+		packet_put_string(password, strlen(password));
+		memset(password, 0, strlen(password));
+		xfree(password);
+		packet_send();
+		packet_write_wait();
+
+		type = packet_read(&payload_len);
+		if (type == SSH_SMSG_SUCCESS)
+			return 1;
+		if (type != SSH_SMSG_FAILURE)
+			packet_disconnect("Protocol error: got %d in response to passwd auth", type);
+	}
+	/* failure */
+	return 0;
+}
+
+/*
+ * SSH1 key exchange
+ */
+void
+ssh_kex(char *host, struct sockaddr *hostaddr)
+{
+	int i;
+	BIGNUM *key;
+	RSA *host_key;
+	RSA *public_key;
+	Key k;
+	int bits, rbits;
+	int ssh_cipher_default = SSH_CIPHER_3DES;
+	unsigned char session_key[SSH_SESSION_KEY_LENGTH];
+	unsigned char cookie[8];
+	unsigned int supported_ciphers;
+	unsigned int server_flags, client_flags;
+	int payload_len, clen, sum_len = 0;
+	u_int32_t rand = 0;
+
+	debug("Waiting for server public key.");
+
+	/* Wait for a public key packet from the server. */
+	packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY);
+
+	/* Get cookie from the packet. */
+	for (i = 0; i < 8; i++)
+		cookie[i] = packet_get_char();
+
+	/* Get the public key. */
+	public_key = RSA_new();
+	bits = packet_get_int();/* bits */
+	public_key->e = BN_new();
+	packet_get_bignum(public_key->e, &clen);
+	sum_len += clen;
+	public_key->n = BN_new();
+	packet_get_bignum(public_key->n, &clen);
+	sum_len += clen;
+
+	rbits = BN_num_bits(public_key->n);
+	if (bits != rbits) {
+		log("Warning: Server lies about size of server public key: "
+		    "actual size is %d bits vs. announced %d.", rbits, bits);
+		log("Warning: This may be due to an old implementation of ssh.");
+	}
+	/* Get the host key. */
+	host_key = RSA_new();
+	bits = packet_get_int();/* bits */
+	host_key->e = BN_new();
+	packet_get_bignum(host_key->e, &clen);
+	sum_len += clen;
+	host_key->n = BN_new();
+	packet_get_bignum(host_key->n, &clen);
+	sum_len += clen;
+
+	rbits = BN_num_bits(host_key->n);
+	if (bits != rbits) {
+		log("Warning: Server lies about size of server host key: "
+		    "actual size is %d bits vs. announced %d.", rbits, bits);
+		log("Warning: This may be due to an old implementation of ssh.");
+	}
+
+	/* Get protocol flags. */
+	server_flags = packet_get_int();
+	packet_set_protocol_flags(server_flags);
+
+	supported_ciphers = packet_get_int();
+	supported_authentications = packet_get_int();
+
+	debug("Received server public key (%d bits) and host key (%d bits).",
+	      BN_num_bits(public_key->n), BN_num_bits(host_key->n));
+
+	packet_integrity_check(payload_len,
+			       8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
+			       SSH_SMSG_PUBLIC_KEY);
+	k.type = KEY_RSA;
+	k.rsa = host_key;
+	check_host_key(host, hostaddr, &k,
+	    options.user_hostfile, options.system_hostfile);
+
+	client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN;
+
+	compute_session_id(session_id, cookie, host_key->n, public_key->n);
+
+	/* Generate a session key. */
+	arc4random_stir();
+
+	/*
+	 * Generate an encryption key for the session.   The key is a 256 bit
+	 * random number, interpreted as a 32-byte key, with the least
+	 * significant 8 bits being the first byte of the key.
+	 */
+	for (i = 0; i < 32; i++) {
+		if (i % 4 == 0)
+			rand = arc4random();
+		session_key[i] = rand & 0xff;
+		rand >>= 8;
+	}
+
+	/*
+	 * According to the protocol spec, the first byte of the session key
+	 * is the highest byte of the integer.  The session key is xored with
+	 * the first 16 bytes of the session id.
+	 */
+	key = BN_new();
+	BN_set_word(key, 0);
+	for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
+		BN_lshift(key, key, 8);
+		if (i < 16)
+			BN_add_word(key, session_key[i] ^ session_id[i]);
+		else
+			BN_add_word(key, session_key[i]);
+	}
+
+	/*
+	 * Encrypt the integer using the public key and host key of the
+	 * server (key with smaller modulus first).
+	 */
+	if (BN_cmp(public_key->n, host_key->n) < 0) {
+		/* Public key has smaller modulus. */
+		if (BN_num_bits(host_key->n) <
+		    BN_num_bits(public_key->n) + SSH_KEY_BITS_RESERVED) {
+			fatal("respond_to_rsa_challenge: host_key %d < public_key %d + "
+			      "SSH_KEY_BITS_RESERVED %d",
+			      BN_num_bits(host_key->n),
+			      BN_num_bits(public_key->n),
+			      SSH_KEY_BITS_RESERVED);
+		}
+		rsa_public_encrypt(key, key, public_key);
+		rsa_public_encrypt(key, key, host_key);
+	} else {
+		/* Host key has smaller modulus (or they are equal). */
+		if (BN_num_bits(public_key->n) <
+		    BN_num_bits(host_key->n) + SSH_KEY_BITS_RESERVED) {
+			fatal("respond_to_rsa_challenge: public_key %d < host_key %d + "
+			      "SSH_KEY_BITS_RESERVED %d",
+			      BN_num_bits(public_key->n),
+			      BN_num_bits(host_key->n),
+			      SSH_KEY_BITS_RESERVED);
+		}
+		rsa_public_encrypt(key, key, host_key);
+		rsa_public_encrypt(key, key, public_key);
+	}
+
+	/* Destroy the public keys since we no longer need them. */
+	RSA_free(public_key);
+	RSA_free(host_key);
+
+	if (options.cipher == SSH_CIPHER_NOT_SET) {
+		if (cipher_mask1() & supported_ciphers & (1 << ssh_cipher_default))
+			options.cipher = ssh_cipher_default;
+		else {
+			debug("Cipher %s not supported, using %.100s instead.",
+			      cipher_name(ssh_cipher_default),
+			      cipher_name(SSH_FALLBACK_CIPHER));
+			options.cipher = SSH_FALLBACK_CIPHER;
+		}
+	}
+	/* Check that the selected cipher is supported. */
+	if (!(supported_ciphers & (1 << options.cipher)))
+		fatal("Selected cipher type %.100s not supported by server.",
+		      cipher_name(options.cipher));
+
+	debug("Encryption type: %.100s", cipher_name(options.cipher));
+
+	/* Send the encrypted session key to the server. */
+	packet_start(SSH_CMSG_SESSION_KEY);
+	packet_put_char(options.cipher);
+
+	/* Send the cookie back to the server. */
+	for (i = 0; i < 8; i++)
+		packet_put_char(cookie[i]);
+
+	/* Send and destroy the encrypted encryption key integer. */
+	packet_put_bignum(key);
+	BN_clear_free(key);
+
+	/* Send protocol flags. */
+	packet_put_int(client_flags);
+
+	/* Send the packet now. */
+	packet_send();
+	packet_write_wait();
+
+	debug("Sent encrypted session key.");
+
+	/* Set the encryption key. */
+	packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, options.cipher);
+
+	/* We will no longer need the session key here.  Destroy any extra copies. */
+	memset(session_key, 0, sizeof(session_key));
+
+	/*
+	 * Expect a success message from the server.  Note that this message
+	 * will be received in encrypted form.
+	 */
+	packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
+
+	debug("Received encrypted confirmation.");
+}
+
+/*
+ * Authenticate user
+ */
+void
+ssh_userauth(
+    const char* local_user,
+    const char* server_user,
+    char *host,
+    int host_key_valid, RSA *own_host_key)
+{
+	int i, type;
+	int payload_len;
+
+	if (supported_authentications == 0)
+		fatal("ssh_userauth: server supports no auth methods");
+
+	/* Send the name of the user to log in as on the server. */
+	packet_start(SSH_CMSG_USER);
+	packet_put_string(server_user, strlen(server_user));
+	packet_send();
+	packet_write_wait();
+
+	/*
+	 * The server should respond with success if no authentication is
+	 * needed (the user has no password).  Otherwise the server responds
+	 * with failure.
+	 */
+	type = packet_read(&payload_len);
+
+	/* check whether the connection was accepted without authentication. */
+	if (type == SSH_SMSG_SUCCESS)
+		return;
+	if (type != SSH_SMSG_FAILURE)
+		packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER",
+				  type);
+
+#ifdef AFS
+	/* Try Kerberos tgt passing if the server supports it. */
+	if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
+	    options.kerberos_tgt_passing) {
+		if (options.cipher == SSH_CIPHER_NONE)
+			log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
+		(void) send_kerberos_tgt();
+	}
+	/* Try AFS token passing if the server supports it. */
+	if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) &&
+	    options.afs_token_passing && k_hasafs()) {
+		if (options.cipher == SSH_CIPHER_NONE)
+			log("WARNING: Encryption is disabled! Token will be transmitted in the clear!");
+		send_afs_tokens();
+	}
+#endif /* AFS */
+
+#ifdef KRB4
+	if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&
+	    options.kerberos_authentication) {
+		debug("Trying Kerberos authentication.");
+		if (try_kerberos_authentication()) {
+			/* The server should respond with success or failure. */
+			type = packet_read(&payload_len);
+			if (type == SSH_SMSG_SUCCESS)
+				return;
+			if (type != SSH_SMSG_FAILURE)
+				packet_disconnect("Protocol error: got %d in response to Kerberos auth", type);
+		}
+	}
+#endif /* KRB4 */
+
+	/*
+	 * Use rhosts authentication if running in privileged socket and we
+	 * do not wish to remain anonymous.
+	 */
+	if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) &&
+	    options.rhosts_authentication) {
+		debug("Trying rhosts authentication.");
+		packet_start(SSH_CMSG_AUTH_RHOSTS);
+		packet_put_string(local_user, strlen(local_user));
+		packet_send();
+		packet_write_wait();
+
+		/* The server should respond with success or failure. */
+		type = packet_read(&payload_len);
+		if (type == SSH_SMSG_SUCCESS)
+			return;
+		if (type != SSH_SMSG_FAILURE)
+			packet_disconnect("Protocol error: got %d in response to rhosts auth",
+					  type);
+	}
+	/*
+	 * Try .rhosts or /etc/hosts.equiv authentication with RSA host
+	 * authentication.
+	 */
+	if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&
+	    options.rhosts_rsa_authentication && host_key_valid) {
+		if (try_rhosts_rsa_authentication(local_user, own_host_key))
+			return;
+	}
+	/* Try RSA authentication if the server supports it. */
+	if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
+	    options.rsa_authentication) {
+		/*
+		 * Try RSA authentication using the authentication agent. The
+		 * agent is tried first because no passphrase is needed for
+		 * it, whereas identity files may require passphrases.
+		 */
+		if (try_agent_authentication())
+			return;
+
+		/* Try RSA authentication for each identity. */
+		for (i = 0; i < options.num_identity_files; i++)
+			if (try_rsa_authentication(options.identity_files[i]))
+				return;
+	}
+	/* Try skey authentication if the server supports it. */
+	if ((supported_authentications & (1 << SSH_AUTH_TIS)) &&
+	    options.skey_authentication && !options.batch_mode) {
+		if (try_skey_authentication())
+			return;
+	}
+	/* Try password authentication if the server supports it. */
+	if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) &&
+	    options.password_authentication && !options.batch_mode) {
+		char prompt[80];
+
+		snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
+		    server_user, host);
+		if (try_password_authentication(prompt))
+			return;
+	}
+	/* All authentication methods have failed.  Exit with an error message. */
+	fatal("Permission denied.");
+	/* NOTREACHED */
+}
diff --git a/sshconnect2.c b/sshconnect2.c
new file mode 100644
index 0000000..31ef308
--- /dev/null
+++ b/sshconnect2.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Markus Friedl.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: sshconnect2.c,v 1.4 2000/04/27 17:54:01 markus Exp $");
+
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/md5.h>
+#include <openssl/dh.h>
+#include <openssl/hmac.h>
+
+#include "ssh.h"
+#include "xmalloc.h"
+#include "rsa.h"
+#include "buffer.h"
+#include "packet.h"
+#include "cipher.h"
+#include "uidswap.h"
+#include "compat.h"
+#include "readconf.h"
+#include "bufaux.h"
+#include "ssh2.h"
+#include "kex.h"
+#include "myproposal.h"
+#include "key.h"
+#include "dsa.h"
+#include "sshconnect.h"
+#include "authfile.h"
+
+/* import */
+extern char *client_version_string;
+extern char *server_version_string;
+extern Options options;
+
+/*
+ * SSH2 key exchange
+ */
+
+unsigned char *session_id2 = NULL;
+int session_id2_len = 0;
+
+void
+ssh_kex2(char *host, struct sockaddr *hostaddr)
+{
+	Kex *kex;
+	char *cprop[PROPOSAL_MAX];
+	char *sprop[PROPOSAL_MAX];
+	Buffer *client_kexinit;
+	Buffer *server_kexinit;
+	int payload_len, dlen;
+	unsigned int klen, kout;
+	char *ptr;
+	char *signature = NULL;
+	unsigned int slen;
+	char *server_host_key_blob = NULL;
+	Key *server_host_key;
+	unsigned int sbloblen;
+	DH *dh;
+	BIGNUM *dh_server_pub = 0;
+	BIGNUM *shared_secret = 0;
+	int i;
+	unsigned char *kbuf;
+	unsigned char *hash;
+
+/* KEXINIT */
+
+	debug("Sending KEX init.");
+	if (options.ciphers != NULL) {
+		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+		myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
+	} else if (
+	    options.cipher == SSH_CIPHER_ARCFOUR ||
+	    options.cipher == SSH_CIPHER_3DES_CBC ||
+	    options.cipher == SSH_CIPHER_CAST128_CBC ||
+	    options.cipher == SSH_CIPHER_BLOWFISH_CBC) {
+		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+		myproposal[PROPOSAL_ENC_ALGS_STOC] = cipher_name(options.cipher);
+	}
+	if (options.compression) {
+		myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib";
+		myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
+	} else {
+		myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none";
+		myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
+	}
+	for (i = 0; i < PROPOSAL_MAX; i++)
+		cprop[i] = xstrdup(myproposal[i]);
+
+	client_kexinit = kex_init(cprop);
+	packet_start(SSH2_MSG_KEXINIT);
+	packet_put_raw(buffer_ptr(client_kexinit), buffer_len(client_kexinit));	
+	packet_send();
+	packet_write_wait();
+
+	debug("done");
+
+	packet_read_expect(&payload_len, SSH2_MSG_KEXINIT);
+
+	/* save payload for session_id */
+	server_kexinit = xmalloc(sizeof(*server_kexinit));
+	buffer_init(server_kexinit);
+	ptr = packet_get_raw(&payload_len);
+	buffer_append(server_kexinit, ptr, payload_len);
+
+	/* skip cookie */
+	for (i = 0; i < 16; i++)
+		(void) packet_get_char();
+	/* kex init proposal strings */
+	for (i = 0; i < PROPOSAL_MAX; i++) {
+		sprop[i] = packet_get_string(NULL);
+		debug("got kexinit string: %s", sprop[i]);
+	}
+	i = (int) packet_get_char();
+	debug("first kex follow == %d", i);
+	i = packet_get_int();
+	debug("reserved == %d", i);
+	packet_done();
+
+	debug("done read kexinit");
+	kex = kex_choose_conf(cprop, sprop, 0);
+
+/* KEXDH */
+
+	debug("Sending SSH2_MSG_KEXDH_INIT.");
+
+	/* generate and send 'e', client DH public key */
+	dh = dh_new_group1();
+	packet_start(SSH2_MSG_KEXDH_INIT);
+	packet_put_bignum2(dh->pub_key);
+	packet_send();
+	packet_write_wait();
+
+#ifdef DEBUG_KEXDH
+	fprintf(stderr, "\np= ");
+	bignum_print(dh->p);
+	fprintf(stderr, "\ng= ");
+	bignum_print(dh->g);
+	fprintf(stderr, "\npub= ");
+	bignum_print(dh->pub_key);
+	fprintf(stderr, "\n");
+	DHparams_print_fp(stderr, dh);
+#endif
+
+	debug("Wait SSH2_MSG_KEXDH_REPLY.");
+
+	packet_read_expect(&payload_len, SSH2_MSG_KEXDH_REPLY);
+
+	debug("Got SSH2_MSG_KEXDH_REPLY.");
+
+	/* key, cert */
+	server_host_key_blob = packet_get_string(&sbloblen);
+	server_host_key = dsa_key_from_blob(server_host_key_blob, sbloblen);
+	if (server_host_key == NULL)
+		fatal("cannot decode server_host_key_blob");
+
+	check_host_key(host, hostaddr, server_host_key,
+	    options.user_hostfile2, options.system_hostfile2);
+
+	/* DH paramter f, server public DH key */
+	dh_server_pub = BN_new();
+	if (dh_server_pub == NULL)
+		fatal("dh_server_pub == NULL");
+	packet_get_bignum2(dh_server_pub, &dlen);
+
+#ifdef DEBUG_KEXDH
+	fprintf(stderr, "\ndh_server_pub= ");
+	bignum_print(dh_server_pub);
+	fprintf(stderr, "\n");
+	debug("bits %d", BN_num_bits(dh_server_pub));
+#endif
+
+	/* signed H */
+	signature = packet_get_string(&slen);
+	packet_done();
+
+	if (!dh_pub_is_valid(dh, dh_server_pub))
+		packet_disconnect("bad server public DH value");
+
+	klen = DH_size(dh);
+	kbuf = xmalloc(klen);
+	kout = DH_compute_key(kbuf, dh_server_pub, dh);
+#ifdef DEBUG_KEXDH
+	debug("shared secret: len %d/%d", klen, kout);
+	fprintf(stderr, "shared secret == ");
+	for (i = 0; i< kout; i++)
+		fprintf(stderr, "%02x", (kbuf[i])&0xff);
+	fprintf(stderr, "\n");
+#endif
+	shared_secret = BN_new();
+
+	BN_bin2bn(kbuf, kout, shared_secret);
+	memset(kbuf, 0, klen);
+	xfree(kbuf);
+
+	/* calc and verify H */
+	hash = kex_hash(
+	    client_version_string,
+	    server_version_string,
+	    buffer_ptr(client_kexinit), buffer_len(client_kexinit),
+	    buffer_ptr(server_kexinit), buffer_len(server_kexinit),
+	    server_host_key_blob, sbloblen,
+	    dh->pub_key,
+	    dh_server_pub,
+	    shared_secret
+	);
+	xfree(server_host_key_blob);
+	buffer_free(client_kexinit);
+	buffer_free(server_kexinit);
+	xfree(client_kexinit);
+	xfree(server_kexinit);
+#ifdef DEBUG_KEXDH
+	fprintf(stderr, "hash == ");
+	for (i = 0; i< 20; i++)
+		fprintf(stderr, "%02x", (hash[i])&0xff);
+	fprintf(stderr, "\n");
+#endif
+	if (dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1)
+		fatal("dsa_verify failed for server_host_key");
+	key_free(server_host_key);
+
+	kex_derive_keys(kex, hash, shared_secret);
+	packet_set_kex(kex);
+
+	/* have keys, free DH */
+	DH_free(dh);
+
+	/* save session id */
+	session_id2_len = 20;
+	session_id2 = xmalloc(session_id2_len);
+	memcpy(session_id2, hash, session_id2_len);
+
+	debug("Wait SSH2_MSG_NEWKEYS.");
+	packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS);
+	packet_done();
+	debug("GOT SSH2_MSG_NEWKEYS.");
+
+	debug("send SSH2_MSG_NEWKEYS.");
+	packet_start(SSH2_MSG_NEWKEYS);
+	packet_send();
+	packet_write_wait();
+	debug("done: send SSH2_MSG_NEWKEYS.");
+
+#ifdef DEBUG_KEXDH
+	/* send 1st encrypted/maced/compressed message */
+	packet_start(SSH2_MSG_IGNORE);
+	packet_put_cstring("markus");
+	packet_send();
+	packet_write_wait();
+#endif
+	debug("done: KEX2.");
+}
+/*
+ * Authenticate user
+ */
+int
+ssh2_try_passwd(const char *server_user, const char *host, const char *service)
+{
+	char prompt[80];
+	char *password;
+
+	snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
+	    server_user, host);
+	password = read_passphrase(prompt, 0);
+	packet_start(SSH2_MSG_USERAUTH_REQUEST);
+	packet_put_cstring(server_user);
+	packet_put_cstring(service);
+	packet_put_cstring("password");
+	packet_put_char(0);
+	packet_put_cstring(password);
+	memset(password, 0, strlen(password));
+	xfree(password);
+	packet_send();
+	packet_write_wait();
+	return 1;
+}
+
+int
+ssh2_try_pubkey(char *filename,
+    const char *server_user, const char *host, const char *service)
+{
+	Buffer b;
+	Key *k;
+	unsigned char *blob, *signature;
+	int bloblen, slen;
+
+	debug("try pubkey: %s", filename);
+
+	k = key_new(KEY_DSA);
+	if (!load_private_key(filename, "", k, NULL)) {
+		int success = 0;
+		char *passphrase;
+		char prompt[300];
+                snprintf(prompt, sizeof prompt,
+		     "Enter passphrase for DSA key '%.100s': ",
+                     filename);
+		passphrase = read_passphrase(prompt, 0);
+		success = load_private_key(filename, passphrase, k, NULL);
+		memset(passphrase, 0, strlen(passphrase));
+		xfree(passphrase);
+		if (!success)
+			return 0;
+	}
+	dsa_make_key_blob(k, &blob, &bloblen);
+
+	/* data to be signed */
+	buffer_init(&b);
+	buffer_append(&b, session_id2, session_id2_len);
+	buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+	buffer_put_cstring(&b, server_user);
+	buffer_put_cstring(&b, service);
+	buffer_put_cstring(&b, "publickey");
+	buffer_put_char(&b, 1);
+	buffer_put_cstring(&b, KEX_DSS); 
+	buffer_put_string(&b, blob, bloblen);
+	xfree(blob);
+
+	/* generate signature */
+	dsa_sign(k, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
+	key_free(k);
+#ifdef DEBUG_DSS
+	buffer_dump(&b);
+#endif
+	/* append signature */
+	buffer_put_string(&b, signature, slen);
+	xfree(signature);
+
+	/* skip session id and packet type */
+	if (buffer_len(&b) < session_id2_len + 1)
+		fatal("ssh2_try_pubkey: internal error");
+	buffer_consume(&b, session_id2_len + 1);
+
+	/* put remaining data from buffer into packet */
+	packet_start(SSH2_MSG_USERAUTH_REQUEST);
+	packet_put_raw(buffer_ptr(&b), buffer_len(&b));
+	buffer_free(&b);
+
+	/* send */
+	packet_send();
+	packet_write_wait();
+	return 1;
+}
+
+void
+ssh_userauth2(const char *server_user, char *host)
+{
+	int type;
+	int plen;
+	int sent;
+	unsigned int dlen;
+	int partial;
+	int i = 0;
+	char *auths;
+	char *service = "ssh-connection";		/* service name */
+
+	debug("send SSH2_MSG_SERVICE_REQUEST");
+	packet_start(SSH2_MSG_SERVICE_REQUEST);
+	packet_put_cstring("ssh-userauth");
+	packet_send();
+	packet_write_wait();
+
+	type = packet_read(&plen);
+	if (type != SSH2_MSG_SERVICE_ACCEPT) {
+		fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
+	}
+	if (packet_remaining() > 0) {
+		char *reply = packet_get_string(&plen);
+		debug("service_accept: %s", reply);
+		xfree(reply);
+	} else {
+		/* payload empty for ssh-2.0.13 ?? */
+		log("buggy server: service_accept w/o service");
+	}
+	packet_done();
+	debug("got SSH2_MSG_SERVICE_ACCEPT");
+
+	/* INITIAL request for auth */
+	packet_start(SSH2_MSG_USERAUTH_REQUEST);
+	packet_put_cstring(server_user);
+	packet_put_cstring(service);
+	packet_put_cstring("none");
+	packet_send();
+	packet_write_wait();
+
+	for (;;) {
+		sent = 0;
+		type = packet_read(&plen);
+		if (type == SSH2_MSG_USERAUTH_SUCCESS)
+			break;
+		if (type != SSH2_MSG_USERAUTH_FAILURE)
+			fatal("access denied: %d", type);
+		/* SSH2_MSG_USERAUTH_FAILURE means: try again */
+		auths = packet_get_string(&dlen);
+		debug("authentications that can continue: %s", auths);
+		partial = packet_get_char();
+		packet_done();
+		if (partial)
+			debug("partial success");
+		if (options.rsa_authentication &&
+		    strstr(auths, "publickey") != NULL) {
+			while (i < options.num_identity_files2) {
+				sent = ssh2_try_pubkey(
+				    options.identity_files2[i++],
+				    server_user, host, service);
+				if (sent)
+					break;
+			}
+		}
+		if (!sent) {
+			if (options.password_authentication &&
+			    !options.batch_mode &&
+			    strstr(auths, "password") != NULL) {
+				sent = ssh2_try_passwd(server_user, host, service);
+			}
+		}
+		if (!sent)
+			fatal("Permission denied (%s).", auths);
+		xfree(auths);
+	}
+	packet_done();
+	debug("ssh-userauth2 successfull");
+}
diff --git a/sshd.c b/sshd.c
index c1dcdd8..fc2d1d2 100644
--- a/sshd.c
+++ b/sshd.c
@@ -14,7 +14,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.107 2000/04/19 07:05:50 deraadt Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.111 2000/04/27 08:01:28 markus Exp $");
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -40,6 +40,7 @@
 
 #include "auth.h"
 #include "myproposal.h"
+#include "authfile.h"
 
 #ifdef LIBWRAP
 #include <tcpd.h>
@@ -112,8 +113,9 @@
  * not very useful.  Currently, memory locking is not implemented.
  */
 struct {
-	RSA *private_key;	 /* Private part of server key. */
+	RSA *private_key;	 /* Private part of empheral server key. */
 	RSA *host_key;		 /* Private part of host key. */
+	Key *dsa_host_key;       /* Private DSA host key. */
 } sensitive_data;
 
 /*
@@ -132,6 +134,10 @@
 /* session identifier, used by RSA-auth */
 unsigned char session_id[16];
 
+/* same for ssh2 */
+unsigned char *session_id2 = NULL;
+int session_id2_len = 0;
+
 /* Prototypes for various functions defined later in this file. */
 void do_ssh1_kex();
 void do_ssh2_kex();
@@ -224,6 +230,7 @@
  * Thus there should be no concurrency control/asynchronous execution
  * problems.
  */
+/* XXX do we really want this work to be done in a signal handler ? -m */
 void
 key_regeneration_alarm(int sig)
 {
@@ -344,6 +351,13 @@
 	mismatch = 0;
 	switch(remote_major) {
 	case 1:
+		if (remote_minor == 99) {
+			if (options.protocol & SSH_PROTO_2)
+				enable_compat20();
+			else
+				mismatch = 1;
+			break;
+		}
 		if (!(options.protocol & SSH_PROTO_1)) {
 			mismatch = 1;
 			break;
@@ -355,12 +369,6 @@
 			/* note that this disables agent-forwarding */
 			enable_compat13();
 		}
-		if (remote_minor == 99) {
-			if (options.protocol & SSH_PROTO_2)
-				enable_compat20();
-			else
-				mismatch = 1;
-		}
 		break;
 	case 2:
 		if (options.protocol & SSH_PROTO_2) {
@@ -386,6 +394,20 @@
 		    server_version_string, client_version_string);
 		fatal_cleanup();
 	}
+	if (compat20)
+		packet_set_ssh2_format();
+}
+
+
+void
+destroy_sensitive_data(void)
+{
+	/* Destroy the private and public keys.  They will no longer be needed. */
+	RSA_free(public_key);
+	RSA_free(sensitive_data.private_key);
+	RSA_free(sensitive_data.host_key);
+	if (sensitive_data.dsa_host_key != NULL)
+		key_free(sensitive_data.dsa_host_key);
 }
 
 /*
@@ -399,12 +421,11 @@
 	int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, on = 1;
 	pid_t pid;
 	socklen_t fromlen;
-	int silentrsa = 0;
+	int silent = 0;
 	fd_set *fdset;
 	struct sockaddr_storage from;
 	const char *remote_ip;
 	int remote_port;
-	char *comment;
 	FILE *f;
 	struct linger linger;
 	struct addrinfo *ai;
@@ -441,7 +462,7 @@
 			inetd_flag = 1;
 			break;
 		case 'Q':
-			silentrsa = 1;
+			silent = 1;
 			break;
 		case 'q':
 			options.log_level = SYSLOG_LEVEL_QUIET;
@@ -497,27 +518,14 @@
 	log_init(av0,
 	    options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
 	    options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,
-	    !inetd_flag);
+	    !silent && !inetd_flag);
 
-	/* check if RSA support exists */
-	if (rsa_alive() == 0) {
-		if (silentrsa == 0)
-			printf("sshd: no RSA support in libssl and libcrypto -- exiting.  See ssl(8)\n");
-		log("no RSA support in libssl and libcrypto -- exiting.  See ssl(8)");
-		exit(1);
-	}
 	/* Read server configuration options from the configuration file. */
 	read_server_config(&options, config_file_name);
 
 	/* Fill in default values for those options not explicitly set. */
 	fill_default_server_options(&options);
 
-	/* Check certain values for sanity. */
-	if (options.server_key_bits < 512 ||
-	    options.server_key_bits > 32768) {
-		fprintf(stderr, "Bad server key size.\n");
-		exit(1);
-	}
 	/* Check that there are no remaining arguments. */
 	if (optind < ac) {
 		fprintf(stderr, "Extra argument %s.\n", av[optind]);
@@ -526,26 +534,79 @@
 
 	debug("sshd version %.100s", SSH_VERSION);
 
-	sensitive_data.host_key = RSA_new();
-	errno = 0;
-	/* Load the host key.  It must have empty passphrase. */
-	if (!load_private_key(options.host_key_file, "",
-			      sensitive_data.host_key, &comment)) {
-		error("Could not load host key: %.200s: %.100s",
-		      options.host_key_file, strerror(errno));
+	sensitive_data.dsa_host_key = NULL;
+	sensitive_data.host_key = NULL;
+
+	/* check if RSA support exists */
+	if ((options.protocol & SSH_PROTO_1) &&
+	    rsa_alive() == 0) {
+		log("no RSA support in libssl and libcrypto.  See ssl(8)");
+		log("Disabling protocol version 1");
+		options.protocol &= ~SSH_PROTO_1;
+	}
+	/* Load the RSA/DSA host key.  It must have empty passphrase. */
+	if (options.protocol & SSH_PROTO_1) {
+		Key k;
+		sensitive_data.host_key = RSA_new();
+		k.type = KEY_RSA;
+		k.rsa = sensitive_data.host_key;
+		errno = 0;
+		if (!load_private_key(options.host_key_file, "", &k, NULL)) {
+			error("Could not load host key: %.200s: %.100s",
+			    options.host_key_file, strerror(errno));
+			log("Disabling protocol version 1");
+			options.protocol &= ~SSH_PROTO_1;
+		}
+		k.rsa = NULL;
+	}
+	if (options.protocol & SSH_PROTO_2) {
+		sensitive_data.dsa_host_key = key_new(KEY_DSA);
+		if (!load_private_key(options.dsa_key_file, "", sensitive_data.dsa_host_key, NULL)) {
+			error("Could not load DSA host key: %.200s", options.dsa_key_file);
+			log("Disabling protocol version 2");
+			options.protocol &= ~SSH_PROTO_2;
+		}
+	}
+	if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) {
+		if (silent == 0)
+			fprintf(stderr, "sshd: no hostkeys available -- exiting.\n");
+		log("sshd: no hostkeys available -- exiting.\n");
 		exit(1);
 	}
-	xfree(comment);
 
-	/* Initialize the log (it is reinitialized below in case we
-	   forked). */
+	/* Check certain values for sanity. */
+	if (options.protocol & SSH_PROTO_1) {
+		if (options.server_key_bits < 512 ||
+		    options.server_key_bits > 32768) {
+			fprintf(stderr, "Bad server key size.\n");
+			exit(1);
+		}
+		/*
+		 * Check that server and host key lengths differ sufficiently. This
+		 * is necessary to make double encryption work with rsaref. Oh, I
+		 * hate software patents. I dont know if this can go? Niels
+		 */
+		if (options.server_key_bits >
+		    BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
+		    options.server_key_bits <
+		    BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
+			options.server_key_bits =
+			    BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
+			debug("Forcing server key to %d bits to make it differ from host key.",
+			    options.server_key_bits);
+		}
+	}
+
+	/* Initialize the log (it is reinitialized below in case we forked). */
 	if (debug_flag && !inetd_flag)
 		log_stderr = 1;
 	log_init(av0, options.log_level, options.log_facility, log_stderr);
 
-	/* If not in debugging mode, and not started from inetd,
-	   disconnect from the controlling terminal, and fork.  The
-	   original process exits. */
+	/*
+	 * If not in debugging mode, and not started from inetd, disconnect
+	 * from the controlling terminal, and fork.  The original process
+	 * exits.
+	 */
 	if (!debug_flag && !inetd_flag) {
 #ifdef TIOCNOTTY
 		int fd;
@@ -565,18 +626,6 @@
 	/* Reinitialize the log (because of the fork above). */
 	log_init(av0, options.log_level, options.log_facility, log_stderr);
 
-	/* Check that server and host key lengths differ sufficiently.
-	   This is necessary to make double encryption work with rsaref.
-	   Oh, I hate software patents. I dont know if this can go? Niels */
-	if (options.server_key_bits >
-	BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
-	    options.server_key_bits <
-	BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
-		options.server_key_bits =
-			BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
-		debug("Forcing server key to %d bits to make it differ from host key.",
-		      options.server_key_bits);
-	}
 	/* Do not display messages to stdout in RSA code. */
 	rsa_set_verbose(0);
 
@@ -594,20 +643,22 @@
 		s2 = dup(s1);
 		sock_in = dup(0);
 		sock_out = dup(1);
-		/* We intentionally do not close the descriptors 0, 1, and 2
-		   as our code for setting the descriptors won\'t work
-		   if ttyfd happens to be one of those. */
+		/*
+		 * We intentionally do not close the descriptors 0, 1, and 2
+		 * as our code for setting the descriptors won\'t work if
+		 * ttyfd happens to be one of those.
+		 */
 		debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);
 
-		public_key = RSA_new();
-		sensitive_data.private_key = RSA_new();
-
-		/* XXX check options.protocol */
-		log("Generating %d bit RSA key.", options.server_key_bits);
-		rsa_generate_key(sensitive_data.private_key, public_key,
-				 options.server_key_bits);
-		arc4random_stir();
-		log("RSA key generation complete.");
+		if (options.protocol & SSH_PROTO_1) {
+			public_key = RSA_new();
+			sensitive_data.private_key = RSA_new();
+			log("Generating %d bit RSA key.", options.server_key_bits);
+			rsa_generate_key(sensitive_data.private_key, public_key,
+			    options.server_key_bits);
+			arc4random_stir();
+			log("RSA key generation complete.");
+		}
 	} else {
 		for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
 			if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
@@ -684,19 +735,20 @@
 				fclose(f);
 			}
 		}
+		if (options.protocol & SSH_PROTO_1) {
+			public_key = RSA_new();
+			sensitive_data.private_key = RSA_new();
 
-		public_key = RSA_new();
-		sensitive_data.private_key = RSA_new();
+			log("Generating %d bit RSA key.", options.server_key_bits);
+			rsa_generate_key(sensitive_data.private_key, public_key,
+			    options.server_key_bits);
+			arc4random_stir();
+			log("RSA key generation complete.");
 
-		log("Generating %d bit RSA key.", options.server_key_bits);
-		rsa_generate_key(sensitive_data.private_key, public_key,
-				 options.server_key_bits);
-		arc4random_stir();
-		log("RSA key generation complete.");
-
-		/* Schedule server key regeneration alarm. */
-		signal(SIGALRM, key_regeneration_alarm);
-		alarm(options.key_regeneration_time);
+			/* Schedule server key regeneration alarm. */
+			signal(SIGALRM, key_regeneration_alarm);
+			alarm(options.key_regeneration_time);
+		}
 
 		/* Arrange to restart on SIGHUP.  The handler needs listen_sock. */
 		signal(SIGHUP, sighup_handler);
@@ -1069,9 +1121,7 @@
 			   sensitive_data.private_key->n);
 
 	/* Destroy the private and public keys.  They will no longer be needed. */
-	RSA_free(public_key);
-	RSA_free(sensitive_data.private_key);
-	RSA_free(sensitive_data.host_key);
+	destroy_sensitive_data();
 
 	/*
 	 * Extract session key from the decrypted integer.  The key is in the
@@ -1130,7 +1180,6 @@
 	unsigned char *kbuf;
 	unsigned char *hash;
 	Kex *kex;
-	Key *server_host_key;
 	char *cprop[PROPOSAL_MAX];
 	char *sprop[PROPOSAL_MAX];
 
@@ -1231,8 +1280,8 @@
 	memset(kbuf, 0, klen);
 	xfree(kbuf);
 
-	server_host_key = dsa_get_serverkey(options.dsa_key_file);
-	dsa_make_serverkey_blob(server_host_key, &server_host_key_blob, &sbloblen);
+	/* XXX precompute? */
+	dsa_make_key_blob(sensitive_data.dsa_host_key, &server_host_key_blob, &sbloblen);
 
 	/* calc H */			/* XXX depends on 'kex' */
 	hash = kex_hash(
@@ -1255,10 +1304,17 @@
 		fprintf(stderr, "%02x", (hash[i])&0xff);
 	fprintf(stderr, "\n");
 #endif
+	/* save session id := H */
+	/* XXX hashlen depends on KEX */
+	session_id2_len = 20;
+	session_id2 = xmalloc(session_id2_len);
+	memcpy(session_id2, hash, session_id2_len);
+
 	/* sign H */
-	dsa_sign(server_host_key, &signature, &slen, hash, 20);
-		/* hashlen depends on KEX */
-	key_free(server_host_key);
+	/* XXX hashlen depends on KEX */
+	dsa_sign(sensitive_data.dsa_host_key, &signature, &slen, hash, 20);
+
+	destroy_sensitive_data();
 
 	/* send server hostkey, DH pubkey 'f' and singed H */
 	packet_start(SSH2_MSG_KEXDH_REPLY);
@@ -1267,6 +1323,7 @@
 	packet_put_string((char *)signature, slen);
 	packet_send();
 	xfree(signature);
+	xfree(server_host_key_blob);
 	packet_write_wait();
 
 	kex_derive_keys(kex, hash, shared_secret);
diff --git a/uuencode.c b/uuencode.c
new file mode 100644
index 0000000..6268900
--- /dev/null
+++ b/uuencode.c
@@ -0,0 +1,120 @@
+/*
+ *   base-64 encoding pinched from lynx2-7-2, who pinched it from rpem.
+ *   Originally written by Mark Riordan 12 August 1990 and 17 Feb 1991
+ *   and placed in the public domain.
+ *
+ *   Dug Song <dugsong@UMICH.EDU>
+ */
+
+#include "includes.h"
+#include "xmalloc.h"
+
+char six2pr[64] = {
+	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+	'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+	'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+	'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+unsigned char pr2six[256];
+
+int
+uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded)
+{
+	/* ENC is the basic 1 character encoding function to make a char printing */
+#define ENC(c) six2pr[c]
+
+	register char *outptr = bufcoded;
+	unsigned int i;
+
+	for (i = 0; i < nbytes; i += 3) {
+		*(outptr++) = ENC(*bufin >> 2);						/* c1 */
+		*(outptr++) = ENC(((*bufin << 4) & 060)   | ((bufin[1] >> 4) & 017));	/* c2 */
+		*(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03));	/* c3 */
+		*(outptr++) = ENC(bufin[2] & 077);					/* c4 */
+		bufin += 3;
+	}
+	if (i == nbytes + 1) {
+		outptr[-1] = '=';
+	} else if (i == nbytes + 2) {
+		outptr[-1] = '=';
+		outptr[-2] = '=';
+	} else if (i == nbytes) {
+		*(outptr++) = '=';
+	}
+	*outptr = '\0';
+	return (outptr - bufcoded);
+}
+
+int
+uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize)
+{
+	/* single character decode */
+#define DEC(c) pr2six[(unsigned char)c]
+#define MAXVAL 63
+
+	static int first = 1;
+	int nbytesdecoded, j;
+	const char *bufin = bufcoded;
+	register unsigned char *bufout = bufplain;
+	register int nprbytes;
+
+	/* If this is the first call, initialize the mapping table. */
+	if (first) {
+		first = 0;
+		for (j = 0; j < 256; j++)
+			pr2six[j] = MAXVAL + 1;
+		for (j = 0; j < 64; j++)
+			pr2six[(unsigned char) six2pr[j]] = (unsigned char) j;
+	}
+	/* Strip leading whitespace. */
+	while (*bufcoded == ' ' || *bufcoded == '\t')
+		bufcoded++;
+
+	/*
+	 * Figure out how many characters are in the input buffer. If this
+	 * would decode into more bytes than would fit into the output
+	 * buffer, adjust the number of input bytes downwards.
+	 */
+	bufin = bufcoded;
+	while (DEC(*(bufin++)) <= MAXVAL)
+		;
+	nprbytes = bufin - bufcoded - 1;
+	nbytesdecoded = ((nprbytes + 3) / 4) * 3;
+	if (nbytesdecoded > outbufsize)
+		nprbytes = (outbufsize * 4) / 3;
+
+	bufin = bufcoded;
+
+	while (nprbytes > 0) {
+		*(bufout++) = (unsigned char) (DEC(*bufin)   << 2 | DEC(bufin[1]) >> 4);
+		*(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2);
+		*(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3]));
+		bufin += 4;
+		nprbytes -= 4;
+	}
+	if (nprbytes & 03) {
+		if (DEC(bufin[-2]) > MAXVAL)
+			nbytesdecoded -= 2;
+		else
+			nbytesdecoded -= 1;
+	}
+	return (nbytesdecoded);
+}
+
+void
+dump_base64(FILE *fp, unsigned char *data, int len)
+{
+	unsigned char *buf = xmalloc(2*len);
+	int i, n;
+	n = uuencode(data, len, buf);
+	for (i = 0; i < n; i++) {
+		fprintf(fp, "%c", buf[i]);
+		if (i % 70 == 69)
+			fprintf(fp, "\n");
+	}
+	if (i % 70 != 69)
+		fprintf(fp, "\n");
+	xfree(buf);
+}
diff --git a/uuencode.h b/uuencode.h
new file mode 100644
index 0000000..d3f4462
--- /dev/null
+++ b/uuencode.h
@@ -0,0 +1,6 @@
+#ifndef UUENCODE_H
+#define UUENCODE_H
+int	uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded);
+int	uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize);
+void	dump_base64(FILE *fp, unsigned char *data, int len);
+#endif
diff --git a/version.h b/version.h
index fe2e876..5e7a38d 100644
--- a/version.h
+++ b/version.h
@@ -1 +1 @@
-#define SSH_VERSION	"OpenSSH-1.2.3"
+#define SSH_VERSION	"OpenSSH-2.0"