]> andersk Git - openssh.git/commitdiff
- Merge big update to OpenSSH-2.0 from OpenBSD CVS
authordamien <damien>
Sat, 29 Apr 2000 13:57:08 +0000 (13:57 +0000)
committerdamien <damien>
Sat, 29 Apr 2000 13:57:08 +0000 (13:57 +0000)
   [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

35 files changed:
ChangeLog
Makefile.in
README.openssh2
auth-rsa.c
auth.c
auth.h
auth1.c [new file with mode: 0644]
auth2.c [new file with mode: 0644]
authfile.c
authfile.h [new file with mode: 0644]
compat.c
dsa.c
dsa.h
hostfile.c
key.c
key.h
radix.c
readconf.c
readconf.h
servconf.c
serverloop.c
session.c
ssh-add.c
ssh-keygen.1
ssh-keygen.c
ssh.c
ssh.h
sshconnect.c
sshconnect.h [new file with mode: 0644]
sshconnect1.c [new file with mode: 0644]
sshconnect2.c [new file with mode: 0644]
sshd.c
uuencode.c [new file with mode: 0644]
uuencode.h [new file with mode: 0644]
version.h

index 98a5a9b313277dfb462033bc62f303d70a0377df..9efe31fef0ad75e4aac20aad8b08e8dc36ff510e 100644 (file)
--- 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]
index 196cc5786837fe49b74616644266fa72525c8b41..d5e3fde6c4ba381ed4602aa79a1004ce8a2f3188 100644 (file)
@@ -31,11 +31,11 @@ LDFLAGS=-L. @LDFLAGS@
 
 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
index 18722b3ca6586de41b740dbea91771c033142326..76a6879bad2c785a9b3323900396bc121ed1549a 100644 (file)
@@ -2,12 +2,15 @@ $Id$
 
 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 @@ works:
                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
index 1e8c947f52a96c730a4eabe902f1f9a62d5d04a8..63aa345bb2663fe9ea411016e3bf7f7d532f336e 100644 (file)
@@ -185,6 +185,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
                        }
                }
                if (fail) {
+                       fclose(f);
                        log(buf);
                        packet_send_debug(buf);
                        restore_uid();
diff --git a/auth.c b/auth.c
index 4c6f32b0a7481e59948ee47e310b8b512d67c643..3bfcfd8e231b630b72bb63467c399e861e6ad060 100644 (file)
--- 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 @@ extern char *forced_command;
  * 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 @@ allowed_user(struct passwd * pw)
        /* 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 3771e826fd686371bb0f51834e77757ac23ee49b..72126e0992d9bb5834e07c233ac322dafec32429 100644 (file)
--- a/auth.h
+++ b/auth.h
@@ -7,4 +7,11 @@ void   do_authentication2(void);
 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 (file)
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 (file)
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;
+}
index 2998cc596968aeac5e7d9d5dedf8d85abb3f7227..c284a646f8ddeebb94d8a45e65b7007313b10522 100644 (file)
 RCSID("$Id$");
 
 #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 @@ RCSID("$Id$");
  */
 
 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 @@ save_private_key(const char *filename, const char *passphrase,
        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 @@ save_private_key(const char *filename, const char *passphrase,
  */
 
 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 @@ load_public_key(const char *filename, RSA * pub,
 
        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 @@ load_public_key(const char *filename, RSA * pub,
 
        /* 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 @@ load_public_key(const char *filename, RSA * pub,
        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 @@ load_public_key(const char *filename, RSA * pub,
  */
 
 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 @@ load_private_key(const char *filename, const char *passphrase,
                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 @@ fail:
 
        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 (file)
index 0000000..afec27d
--- /dev/null
@@ -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
index e4abaa02a492140601f793d7ec6b29142de743db..524e3f27c91a44e2ec6a35fc8ab28d7122156e4d 100644 (file)
--- a/compat.c
+++ b/compat.c
@@ -44,7 +44,6 @@ enable_compat20(void)
 {
        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 2d4febe7d33040f2bc70ec420329d6c215272415..e1f23ec3f14c1b54ff0d319494d639322979a6bc 100644 (file)
--- a/dsa.c
+++ b/dsa.c
@@ -47,13 +47,14 @@ RCSID("$Id$");
 #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_serverkey_from_blob(
        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 @@ dsa_serverkey_from_blob(
        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 @@ dsa_serverkey_from_blob(
 #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 @@ int
 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 @@ dsa_sign(
        }
        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 @@ int
 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 @@ dsa_verify(
                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 @@ dsa_verify(
        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 65e651d9b91abdbc5853db502846a163ff3bd529..3cece7c1f22be43d308510b2fdbebdddae5e06c2 100644 (file)
--- 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
index 29efe5656a13d0a59061149e836b75b3c3f79455..e1c2429bd649f5d5dc81fe7dbbf21ee1fad46c7b 100644 (file)
@@ -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 @@ hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret)
        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 @@ add_host_to_hostfile(const char *filename, const char *host, Key *key)
 {
        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 872313abc296069b8a1e00ba1a2155c287a3c4b9..583c529010ddae08e223d2a8c4418ee2c449d7f9 100644 (file)
--- a/key.c
+++ b/key.c
 #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 @@ key_new(int type)
        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 @@ key_new(int type)
                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 @@ key_equal(Key *a, Key *b)
                    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 @@ char *
 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 @@ write_bignum(FILE *f, BIGNUM *num)
        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 @@ key_read(Key *ret, unsigned int bits, char **cpp)
                        return 0;
                break;
        case KEY_DSA:
-               if (bits != 0)
-                       return 0;
-               if (!read_bignum(cpp, ret->dsa->p))
+               if (strncmp(cp, SSH_DSS " ", 7) != 0)
                        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))
+               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;
+               *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 @@ key_write(Key *key, FILE *f)
                        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 70f0c518b8aba90a931d53719efd742ee185e537..d1bcf3b1bed7e3df49c2d29c15b6a2ae54138dfa 100644 (file)
--- a/key.h
+++ b/key.h
@@ -18,6 +18,7 @@ void  key_free(Key *k);
 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 84e390fd1d61bf4fac9de79d3e29b200b5a0878b..9d1c999a12becd13ebc4ac5fa5ec62183d23f559 100644 (file)
--- a/radix.c
+++ b/radix.c
 /*
  *   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;
index 1e3476b8e86cd5d87c6807408f5f00e6e828a99a..6c00cd6617f2ccf25374b6c2f749474cc66f4767 100644 (file)
@@ -104,7 +104,8 @@ typedef enum {
        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 @@ static struct {
        { "fallbacktorsh", oFallBackToRsh },
        { "usersh", oUseRsh },
        { "identityfile", oIdentityFile },
+       { "identityfile2", oIdentityFile2 },
        { "hostname", oHostName },
        { "proxycommand", oProxyCommand },
        { "port", oPort },
@@ -145,6 +147,8 @@ static struct {
        { "rhostsrsaauthentication", oRhostsRSAAuthentication },
        { "globalknownhostsfile", oGlobalKnownHostsFile },
        { "userknownhostsfile", oUserKnownHostsFile },
+       { "globalknownhostsfile2", oGlobalKnownHostsFile2 },
+       { "userknownhostsfile2", oUserKnownHostsFile2 },
        { "connectionattempts", oConnectionAttempts },
        { "batchmode", oBatchMode },
        { "checkhostip", oCheckHostIP },
@@ -368,14 +372,22 @@ parse_flag:
                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 @@ parse_string:
                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 @@ initialize_options(Options * options)
        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 @@ fill_default_options(Options * options)
        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 */
index d65edab048595e9409295ddf9ea2a9d037108201..7a6dcc815ed6d632e5e80753317d8d229fdba5bd 100644 (file)
@@ -73,9 +73,13 @@ typedef struct {
 
        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;
index 5cf6416ca2b25886dd94496ad523f5b68d763e53..21123144dfd079b5064afe2b9553883b7ff2ed70 100644 (file)
@@ -143,7 +143,7 @@ fill_default_server_options(ServerOptions *options)
        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"
index 1a76b8da808b5af935c471bbf87a776f0b4f344e..1e031873c9dee1b740ac34a3b82adaec9969b805 100644 (file)
@@ -733,7 +733,7 @@ server_input_channel_open(int type, int plen)
        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) {
index 68a016e0b5329705be9cd50b0083cb0f92a6980e..d5c53f11fbe940d4ace269d209a05a1f0ef39b7a 100644 (file)
--- 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 @@ do_authenticated2(void)
         * authentication.
         */
        alarm(0);
-       log("do_authenticated2");
        server_loop2();
 }
index d81510e1d63b64cec91da3f5eb4f39cdc2a12d28..34713110ccfcf79dd18197c5a9aa1439c6b238ee 100644 (file)
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -9,11 +9,16 @@
 #include "includes.h"
 RCSID("$Id$");
 
+#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 @@ const char *__progname = "ssh-add";
 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 @@ ssh_askpass(char *askpass, char *msg)
 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 @@ add_file(AuthenticationConnection *ac, const char *filename)
        }
 
        /* 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 @@ add_file(AuthenticationConnection *ac, const char *filename)
                                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 @@ add_file(AuthenticationConnection *ac, const char *filename)
        }
        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);
 }
 
index 38ce251a578370a2cedf3255fcc07c8d21979dfe..dfc404089a00bbf0fca9710fb571471bc9b7ed1c 100644 (file)
@@ -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 comment.
 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
index 1b5261d8c6070670db28a49d7e3a1e8d76599d3b..31352aa7e1b40cb5f699b7e78493777d3fb99aaf 100644 (file)
@@ -9,18 +9,21 @@
 #include "includes.h"
 RCSID("$Id$");
 
-#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 @@ char *identity_new_passphrase = NULL;
 /* 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 @@ extern char *__progname;
 const char *__progname = "ssh-keygen";
 #endif /* HAVE___PROGNAME */
 
+char hostname[MAXHOSTNAMELEN];
+
 void
 ask_filename(struct passwd *pw, const char *prompt)
 {
@@ -77,12 +88,140 @@ ask_filename(struct passwd *pw, const char *prompt)
        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 @@ do_fingerprint(struct passwd *pw)
                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 @@ do_change_passphrase(struct passwd *pw)
        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 @@ do_change_passphrase(struct passwd *pw)
                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 @@ do_change_passphrase(struct passwd *pw)
        }
 
        /* 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 @@ void
 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 @@ do_change_comment(struct passwd *pw)
         * 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 @@ do_change_comment(struct passwd *pw)
                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 @@ do_change_comment(struct passwd *pw)
                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 @@ do_change_comment(struct passwd *pw)
        }
 
        /* 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 @@ do_change_comment(struct passwd *pw)
                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 @@ void
 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 @@ main(int ac, char **av)
 {
        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 @@ main(int ac, char **av)
                        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 @@ main(int ac, char **av)
                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 @@ passphrase_again:
                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 @@ passphrase_again:
        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 @@ passphrase_again:
                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 417332850a60771f4e0b2430c9c942168cfa38c1..0d3e70e0f23040b118e3117e4202f4d4609ceba9 100644 (file)
--- a/ssh.c
+++ b/ssh.c
 #include "includes.h"
 RCSID("$Id$");
 
+#include <openssl/evp.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+
 #include "xmalloc.h"
 #include "ssh.h"
 #include "packet.h"
@@ -24,6 +28,8 @@ RCSID("$Id$");
 #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 @@ main(int ac, char **av)
                        }
                        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 @@ main(int ac, char **av)
        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 @@ main(int ac, char **av)
        /* 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 @@ main(int ac, char **av)
         * 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 @@ main(int ac, char **av)
                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 4d1b26dfc99076f9e62531628f415a03112ae060..f9bdb96eefe75555f143f691a97faa4a54e3d0e0 100644 (file)
--- a/ssh.h
+++ b/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"
  * 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
  * 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 @@ int     auth_rsa_challenge_dialog(RSA *pk);
  */
 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. -----------------------*/
 
index f58289e7bd7a07d9e25e2a6b03c00668e64284ab..5554c0643c6164d8b92038d46dcff5347ed0562b 100644 (file)
@@ -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 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
        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 @@ ssh_exchange_identification()
                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 @@ read_yes_or_no(const char *prompt, int defval)
  */
 
 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 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
         * 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_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
         * 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 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
                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 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
                        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 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
                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,260 +654,22 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
        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
+ * Starts a dialog with the server, and authenticates the current user on the
+ * server.  This does not need any extra privileges.  The basic connection
+ * to the server must already have been established before this is called.
+ * If login fails, this function prints an error and never returns.
+ * This function does not require super-user privileges.
  */
 void
-ssh_userauth2(int host_key_valid, RSA *own_host_key,
-    uid_t original_real_uid, char *host)
+ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
+    struct sockaddr *hostaddr, uid_t original_real_uid)
 {
-       int type;
-       int plen;
-       unsigned int dlen;
-       int partial;
        struct passwd *pw;
-       char prompt[80];
+       char *host, *cp;
        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)
@@ -1578,396 +677,6 @@ ssh_userauth2(int host_key_valid, RSA *own_host_key,
        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
- * to the server must already have been established before this is called.
- * If login fails, this function prints an error and never returns.
- * This function does not require super-user privileges.
- */
-void
-ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
-    struct sockaddr *hostaddr, uid_t original_real_uid)
-{
-       char *host, *cp;
-
        /* Convert the user-supplied hostname into all lowercase. */
        host = xstrdup(orighost);
        for (cp = host; *cp; cp++)
@@ -1984,12 +693,9 @@ ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
        /* 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 (file)
index 0000000..13d395f
--- /dev/null
@@ -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 (file)
index 0000000..c5a7665
--- /dev/null
@@ -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 (file)
index 0000000..31ef308
--- /dev/null
@@ -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 c1dcdd8e9fe0e3a6bd29dea94d9845927c5507a7..fc2d1d20ea21d292f6221dcb24e4f350e7294618 100644 (file)
--- 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 @@ RCSID("$OpenBSD: sshd.c,v 1.107 2000/04/19 07:05:50 deraadt Exp $");
 
 #include "auth.h"
 #include "myproposal.h"
+#include "authfile.h"
 
 #ifdef LIBWRAP
 #include <tcpd.h>
@@ -112,8 +113,9 @@ char *server_version_string = NULL;
  * 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 @@ RSA *public_key;
 /* 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 @@ grace_alarm_handler(int sig)
  * 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 @@ sshd_exchange_identification(int sock_in, int sock_out)
        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 @@ sshd_exchange_identification(int sock_in, int sock_out)
                        /* 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 @@ sshd_exchange_identification(int sock_in, int sock_out)
                    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 @@ main(int ac, char **av)
        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 @@ main(int ac, char **av)
                        inetd_flag = 1;
                        break;
                case 'Q':
-                       silentrsa = 1;
+                       silent = 1;
                        break;
                case 'q':
                        options.log_level = SYSLOG_LEVEL_QUIET;
@@ -497,27 +518,14 @@ main(int ac, char **av)
        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 @@ main(int ac, char **av)
 
        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 @@ main(int ac, char **av)
        /* 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 @@ main(int ac, char **av)
                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 @@ main(int ac, char **av)
                                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 @@ do_ssh1_kex()
                           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 @@ do_ssh2_kex()
        unsigned char *kbuf;
        unsigned char *hash;
        Kex *kex;
-       Key *server_host_key;
        char *cprop[PROPOSAL_MAX];
        char *sprop[PROPOSAL_MAX];
 
@@ -1231,8 +1280,8 @@ do_ssh2_kex()
        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 @@ do_ssh2_kex()
                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 @@ do_ssh2_kex()
        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 (file)
index 0000000..6268900
--- /dev/null
@@ -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 (file)
index 0000000..d3f4462
--- /dev/null
@@ -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
index fe2e876ea87ce21cef71c550e641b5a0c7189fd6..5e7a38da09424a077cc80afdaf50131e8896bec0 100644 (file)
--- a/version.h
+++ b/version.h
@@ -1 +1 @@
-#define SSH_VERSION    "OpenSSH-1.2.3"
+#define SSH_VERSION    "OpenSSH-2.0"
This page took 0.356047 seconds and 5 git commands to generate.