split auth/sshconnect in one file per protocol version
authormarkus <markus@openbsd.org>
Wed, 26 Apr 2000 21:28:31 +0000 (21:28 +0000)
committermarkus <markus@openbsd.org>
Wed, 26 Apr 2000 21:28:31 +0000 (21:28 +0000)
usr.bin/ssh/auth.c
usr.bin/ssh/auth.h
usr.bin/ssh/auth1.c [new file with mode: 0644]
usr.bin/ssh/auth2.c [new file with mode: 0644]
usr.bin/ssh/authfile.c
usr.bin/ssh/sshconnect.c
usr.bin/ssh/sshconnect.h [new file with mode: 0644]
usr.bin/ssh/sshconnect1.c [new file with mode: 0644]
usr.bin/ssh/sshconnect2.c [new file with mode: 0644]

index 7c88017..d3425a2 100644 (file)
@@ -5,11 +5,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth.c,v 1.5 2000/04/26 20:56:29 markus Exp $");
-
-#include <openssl/dsa.h>
-#include <openssl/rsa.h>
-#include <openssl/evp.h>
+RCSID("$OpenBSD: auth.c,v 1.6 2000/04/26 21:28:31 markus Exp $");
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -23,17 +19,13 @@ RCSID("$OpenBSD: auth.c,v 1.5 2000/04/26 20:56:29 markus Exp $");
 #include "compat.h"
 #include "channels.h"
 #include "match.h"
+
 #include "bufaux.h"
 #include "ssh2.h"
 #include "auth.h"
 #include "session.h"
 #include "dispatch.h"
 
-#include "key.h"
-#include "kex.h"
-#include "dsa.h"
-#include "uidswap.h"
-#include "channels.h"
 
 /* import */
 extern ServerOptions options;
@@ -117,819 +109,3 @@ allowed_user(struct passwd * pw)
        /* We found no reason not to let this user try to log on... */
        return 1;
 }
-
-/* 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;
-}
-
-#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());
-
-       /* 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;
-               int type = packet_read(&plen);
-#ifdef SKEY
-               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, *password;
-       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);
-                       xfree(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);
-                       xfree(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);
-
-                       /* Try authentication with the password. */
-                       authenticated = auth_password(pw, password);
-
-                       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);
-
-               if (authenticated)
-                       return;
-
-               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;
-
-       /* 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;
-
-       /*
-        * 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 */
-           auth_password(pw, "")) {
-               /* 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. */
-       packet_start(SSH_SMSG_SUCCESS);
-       packet_send();
-       packet_write_wait();
-
-       /* Perform session preparation. */
-       do_authenticated(pw);
-}
-
-/* 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;
-
-/* 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: bad user %s", u);
-                       return NULL;
-               }
-               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();
-}
-
-/*
- * 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 int try = 0;
-       unsigned int len, rlen;
-       int authenticated = 0;
-       char *raw, *user, *service, *method;
-       struct passwd *pw;
-
-       if (++try == 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);
-               }
-       }
-       /* XXX check if other auth methods are needed */
-       if (authenticated == 1) {
-               log("userauth success for %s method %s", user, method);
-               /* 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) {
-               log("userauth failure for %s method %s", user, method);
-               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 {
-               log("userauth postponed for %s method %s", user, method);
-       }
-       xfree(service);
-       xfree(user);
-       xfree(method);
-}
-
-int
-ssh2_auth_none(struct passwd *pw)
-{
-       packet_done();
-       return auth_password(pw, "");
-}
-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 (auth_password(pw, password))
-               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;
-
-       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 (have_sig && key != NULL) {
-               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 if (!have_sig && key != NULL) {
-               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;
-               }
-       }
-       xfree(pkalg);
-       xfree(pkblob);
-       return authenticated;
-}
-
-/* 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();
-               packet_send_debug("Could not open %.900s for reading.", file);
-               packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");
-               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 3771e82..72126e0 100644 (file)
@@ -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/usr.bin/ssh/auth1.c b/usr.bin/ssh/auth1.c
new file mode 100644 (file)
index 0000000..d90c114
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ * 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());
+
+       /* 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;
+               int type = packet_read(&plen);
+#ifdef SKEY
+               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, *password;
+       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);
+                       xfree(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);
+                       xfree(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);
+
+                       /* Try authentication with the password. */
+                       authenticated = auth_password(pw, password);
+
+                       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);
+
+               if (authenticated)
+                       return;
+
+               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;
+
+       /* 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;
+
+       /*
+        * 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 */
+           auth_password(pw, "")) {
+               /* 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. */
+       packet_start(SSH_SMSG_SUCCESS);
+       packet_send();
+       packet_write_wait();
+
+       /* Perform session preparation. */
+       do_authenticated(pw);
+}
diff --git a/usr.bin/ssh/auth2.c b/usr.bin/ssh/auth2.c
new file mode 100644 (file)
index 0000000..b896bc2
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * 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.1 2000/04/26 21:28:32 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 int try = 0;
+       unsigned int len, rlen;
+       int authenticated = 0;
+       char *raw, *user, *service, *method;
+       struct passwd *pw;
+
+       if (++try == 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);
+               }
+       }
+       /* XXX check if other auth methods are needed */
+       if (authenticated == 1) {
+               log("userauth success for %s method %s", user, method);
+               /* 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) {
+               log("userauth failure for %s method %s", user, method);
+               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 {
+               log("userauth postponed for %s method %s", user, method);
+       }
+       xfree(service);
+       xfree(user);
+       xfree(method);
+}
+
+int
+ssh2_auth_none(struct passwd *pw)
+{
+       packet_done();
+       return auth_password(pw, "");
+}
+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 (auth_password(pw, password))
+               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;
+
+       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 (have_sig && key != NULL) {
+               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 if (!have_sig && key != NULL) {
+               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;
+               }
+       }
+       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: bad user %s", u);
+                       return NULL;
+               }
+               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();
+               packet_send_debug("Could not open %.900s for reading.", file);
+               packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");
+               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 b6c4de3..92740c4 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 #include "includes.h"
-RCSID("$Id: authfile.c,v 1.15 2000/04/26 20:56:29 markus Exp $");
+RCSID("$Id: authfile.c,v 1.16 2000/04/26 21:28:32 markus Exp $");
 
 #include <openssl/bn.h>
 #include <openssl/dsa.h>
index 9c551d4..73e6915 100644 (file)
@@ -8,42 +8,23 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshconnect.c,v 1.70 2000/04/26 20:56:30 markus 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"
-#include "authfile.h"
-
-/* Session id for the current session. */
-unsigned char session_id[16];
-unsigned int supported_authentications = 0;
-
-unsigned char *session_id2 = NULL;
-int session_id2_len = 0;
 
 char *client_version_string = NULL;
 char *server_version_string = NULL;
@@ -316,655 +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;
-       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;
-}
-
-
 char *
 chop(char *s)
 {
@@ -1319,723 +651,6 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
                xfree(ip);
 }
 
-/*
- * 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_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
-       );
-       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);
-
-       /* 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 (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 (strstr(auths, "password") != NULL) {
-                               sent = ssh2_try_passwd(server_user, host, service);
-                       } else {
-                               fatal("passwd auth not supported: %s", auths);
-                       }
-                       if (!sent)
-                               fatal("no more auths: %s", auths);
-               }
-               xfree(auths);
-       }
-       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;
-       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 */
-}
-
 /*
  * Starts a dialog with the server, and authenticates the current user on the
  * server.  This does not need any extra privileges.  The basic connection
diff --git a/usr.bin/ssh/sshconnect.h b/usr.bin/ssh/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/usr.bin/ssh/sshconnect1.c b/usr.bin/ssh/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/usr.bin/ssh/sshconnect2.c b/usr.bin/ssh/sshconnect2.c
new file mode 100644 (file)
index 0000000..e0e5172
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * 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.1 2000/04/26 21:28:33 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");
+
+dump_base64(stderr, server_host_key_blob, sbloblen);
+
+       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
+       );
+       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);
+
+//DSA_print_fp(stderr, k->dsa, 8);
+
+       /* 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);
+
+       /* 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 (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 (strstr(auths, "password") != NULL) {
+                               sent = ssh2_try_passwd(server_user, host, service);
+                       } else {
+                               fatal("passwd auth not supported: %s", auths);
+                       }
+                       if (!sent)
+                               fatal("no more auths: %s", auths);
+               }
+               xfree(auths);
+       }
+       packet_done();
+       debug("ssh-userauth2 successfull");
+}