[BACK]Return to sshconnect2.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/sshconnect2.c between version 1.27.2.8 and 1.28

version 1.27.2.8, 2002/03/08 17:04:43 version 1.28, 2000/11/12 19:50:38
Line 25 
Line 25 
 #include "includes.h"  #include "includes.h"
 RCSID("$OpenBSD$");  RCSID("$OpenBSD$");
   
   #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 "ssh.h"
 #include "ssh2.h"  
 #include "xmalloc.h"  #include "xmalloc.h"
   #include "rsa.h"
 #include "buffer.h"  #include "buffer.h"
 #include "packet.h"  #include "packet.h"
   #include "uidswap.h"
 #include "compat.h"  #include "compat.h"
   #include "readconf.h"
 #include "bufaux.h"  #include "bufaux.h"
 #include "cipher.h"  #include "ssh2.h"
 #include "kex.h"  #include "kex.h"
 #include "myproposal.h"  #include "myproposal.h"
   #include "key.h"
 #include "sshconnect.h"  #include "sshconnect.h"
 #include "authfile.h"  #include "authfile.h"
 #include "dh.h"  #include "cli.h"
 #include "authfd.h"  
 #include "log.h"  
 #include "readconf.h"  
 #include "readpass.h"  
 #include "match.h"  
 #include "dispatch.h"  #include "dispatch.h"
 #include "canohost.h"  #include "authfd.h"
   
   void ssh_dh1_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *);
   void ssh_dhgex_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *);
   
 /* import */  /* import */
 extern char *client_version_string;  extern char *client_version_string;
 extern char *server_version_string;  extern char *server_version_string;
Line 55 
Line 63 
  * SSH2 key exchange   * SSH2 key exchange
  */   */
   
 u_char *session_id2 = NULL;  unsigned char *session_id2 = NULL;
 int session_id2_len = 0;  int session_id2_len = 0;
   
 char *xxx_host;  
 struct sockaddr *xxx_hostaddr;  
   
 Kex *xxx_kex = NULL;  
   
 static int  
 verify_host_key_callback(Key *hostkey)  
 {  
         if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1)  
                 fatal("Host key verification failed.");  
         return 0;  
 }  
   
 void  void
 ssh_kex2(char *host, struct sockaddr *hostaddr)  ssh_kex2(char *host, struct sockaddr *hostaddr)
 {  {
           int i, plen;
         Kex *kex;          Kex *kex;
           Buffer *client_kexinit, *server_kexinit;
           char *sprop[PROPOSAL_MAX];
   
         xxx_host = host;          if (options.ciphers == NULL) {
         xxx_hostaddr = hostaddr;                  if (options.cipher == SSH_CIPHER_3DES) {
                           options.ciphers = "3des-cbc";
         if (options.ciphers == (char *)-1) {                  } else if (options.cipher == SSH_CIPHER_BLOWFISH) {
                 log("No valid ciphers for protocol version 2 given, using defaults.");                          options.ciphers = "blowfish-cbc";
                 options.ciphers = NULL;                  } else if (options.cipher == SSH_CIPHER_DES) {
                           fatal("cipher DES not supported for protocol version 2");
                   }
         }          }
         if (options.ciphers != NULL) {          if (options.ciphers != NULL) {
                 myproposal[PROPOSAL_ENC_ALGS_CTOS] =                  myproposal[PROPOSAL_ENC_ALGS_CTOS] =
                 myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;                  myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
         }          }
         myproposal[PROPOSAL_ENC_ALGS_CTOS] =  
             compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);  
         myproposal[PROPOSAL_ENC_ALGS_STOC] =  
             compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]);  
         if (options.compression) {          if (options.compression) {
                 myproposal[PROPOSAL_COMP_ALGS_CTOS] =                  myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib";
                 myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";                  myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
         } else {          } else {
                 myproposal[PROPOSAL_COMP_ALGS_CTOS] =                  myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none";
                 myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";                  myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
         }          }
         if (options.macs != NULL) {  
                 myproposal[PROPOSAL_MAC_ALGS_CTOS] =  
                 myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;  
         }  
         if (options.hostkeyalgorithms != NULL)  
                 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =  
                     options.hostkeyalgorithms;  
   
         /* start key exchange */          /* buffers with raw kexinit messages */
         kex = kex_setup(myproposal);          server_kexinit = xmalloc(sizeof(*server_kexinit));
         kex->client_version_string=client_version_string;          buffer_init(server_kexinit);
         kex->server_version_string=server_version_string;          client_kexinit = kex_init(myproposal);
         kex->verify_host_key=&verify_host_key_callback;  
   
         xxx_kex = kex;          /* algorithm negotiation */
           kex_exchange_kexinit(client_kexinit, server_kexinit, sprop);
           kex = kex_choose_conf(myproposal, sprop, 0);
           for (i = 0; i < PROPOSAL_MAX; i++)
                   xfree(sprop[i]);
   
         dispatch_run(DISPATCH_BLOCK, &kex->done, kex);          /* server authentication and session key agreement */
           switch(kex->kex_type) {
           case DH_GRP1_SHA1:
                   ssh_dh1_client(kex, host, hostaddr,
                                  client_kexinit, server_kexinit);
                   break;
           case DH_GEX_SHA1:
                   ssh_dhgex_client(kex, host, hostaddr, client_kexinit,
                                    server_kexinit);
                   break;
           default:
                   fatal("Unsupported key exchange %d", kex->kex_type);
           }
   
         session_id2 = kex->session_id;          buffer_free(client_kexinit);
         session_id2_len = kex->session_id_len;          buffer_free(server_kexinit);
           xfree(client_kexinit);
           xfree(server_kexinit);
   
           debug("Wait SSH2_MSG_NEWKEYS.");
           packet_read_expect(&plen, 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  #ifdef DEBUG_KEXDH
         /* send 1st encrypted/maced/compressed message */          /* send 1st encrypted/maced/compressed message */
         packet_start(SSH2_MSG_IGNORE);          packet_start(SSH2_MSG_IGNORE);
Line 126 
Line 143 
         packet_send();          packet_send();
         packet_write_wait();          packet_write_wait();
 #endif  #endif
         debug("done: ssh_kex2.");          debug("done: KEX2.");
 }  }
   
   /* diffie-hellman-group1-sha1 */
   
   void
   ssh_dh1_client(Kex *kex, char *host, struct sockaddr *hostaddr,
                  Buffer *client_kexinit, Buffer *server_kexinit)
   {
   #ifdef DEBUG_KEXDH
           int i;
   #endif
           int plen, dlen;
           unsigned int klen, kout;
           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;
           unsigned char *kbuf;
           unsigned char *hash;
   
           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= ");
           BN_print_fp(stderr, dh->p);
           fprintf(stderr, "\ng= ");
           BN_print_fp(stderr, dh->g);
           fprintf(stderr, "\npub= ");
           BN_print_fp(stderr, dh->pub_key);
           fprintf(stderr, "\n");
           DHparams_print_fp(stderr, dh);
   #endif
   
           debug("Wait SSH2_MSG_KEXDH_REPLY.");
   
           packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY);
   
           debug("Got SSH2_MSG_KEXDH_REPLY.");
   
           /* key, cert */
           server_host_key_blob = packet_get_string(&sbloblen);
           server_host_key = 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= ");
           BN_print_fp(stderr, dh_server_pub);
           fprintf(stderr, "\n");
           debug("bits %d", BN_num_bits(dh_server_pub));
   #endif
   
           /* signed H */
           signature = packet_get_string(&slen);
           packet_done();
   
           if (!dh_pub_is_valid(dh, dh_server_pub))
                   packet_disconnect("bad server public DH value");
   
           klen = DH_size(dh);
           kbuf = xmalloc(klen);
           kout = DH_compute_key(kbuf, dh_server_pub, dh);
   #ifdef DEBUG_KEXDH
           debug("shared secret: len %d/%d", klen, kout);
           fprintf(stderr, "shared secret == ");
           for (i = 0; i< kout; i++)
                   fprintf(stderr, "%02x", (kbuf[i])&0xff);
           fprintf(stderr, "\n");
   #endif
           shared_secret = BN_new();
   
           BN_bin2bn(kbuf, kout, shared_secret);
           memset(kbuf, 0, klen);
           xfree(kbuf);
   
           /* calc and verify H */
           hash = kex_hash(
               client_version_string,
               server_version_string,
               buffer_ptr(client_kexinit), buffer_len(client_kexinit),
               buffer_ptr(server_kexinit), buffer_len(server_kexinit),
               server_host_key_blob, sbloblen,
               dh->pub_key,
               dh_server_pub,
               shared_secret
           );
           xfree(server_host_key_blob);
           DH_free(dh);
   #ifdef DEBUG_KEXDH
           fprintf(stderr, "hash == ");
           for (i = 0; i< 20; i++)
                   fprintf(stderr, "%02x", (hash[i])&0xff);
           fprintf(stderr, "\n");
   #endif
           if (key_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1)
                   fatal("key_verify failed for server_host_key");
           key_free(server_host_key);
   
           kex_derive_keys(kex, hash, shared_secret);
           packet_set_kex(kex);
   
           /* save session id */
           session_id2_len = 20;
           session_id2 = xmalloc(session_id2_len);
           memcpy(session_id2, hash, session_id2_len);
   }
   
   /* diffie-hellman-group-exchange-sha1 */
   
 /*  /*
    * Estimates the group order for a Diffie-Hellman group that has an
    * attack complexity approximately the same as O(2**bits).  Estimate
    * with:  O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3)))
    */
   
   int
   dh_estimate(int bits)
   {
   
           if (bits < 64)
                   return (512);   /* O(2**63) */
           if (bits < 128)
                   return (1024);  /* O(2**86) */
           if (bits < 192)
                   return (2048);  /* O(2**116) */
           return (4096);          /* O(2**156) */
   }
   
   void
   ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr,
                    Buffer *client_kexinit, Buffer *server_kexinit)
   {
   #ifdef DEBUG_KEXDH
           int i;
   #endif
           int plen, dlen;
           unsigned int klen, kout;
           char *signature = NULL;
           unsigned int slen, nbits;
           char *server_host_key_blob = NULL;
           Key *server_host_key;
           unsigned int sbloblen;
           DH *dh;
           BIGNUM *dh_server_pub = 0;
           BIGNUM *shared_secret = 0;
           BIGNUM *p = 0, *g = 0;
           unsigned char *kbuf;
           unsigned char *hash;
   
           nbits = dh_estimate(kex->enc[MODE_OUT].cipher->key_len * 8);
   
           debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST.");
           packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
           packet_put_int(nbits);
           packet_send();
           packet_write_wait();
   
   #ifdef DEBUG_KEXDH
           fprintf(stderr, "\nnbits = %d", nbits);
   #endif
   
           debug("Wait SSH2_MSG_KEX_DH_GEX_GROUP.");
   
           packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP);
   
           debug("Got SSH2_MSG_KEX_DH_GEX_GROUP.");
   
           if ((p = BN_new()) == NULL)
                   fatal("BN_new");
           packet_get_bignum2(p, &dlen);
           if ((g = BN_new()) == NULL)
                   fatal("BN_new");
           packet_get_bignum2(g, &dlen);
           if ((dh = dh_new_group(g, p)) == NULL)
                   fatal("dh_new_group");
   
   #ifdef DEBUG_KEXDH
           fprintf(stderr, "\np= ");
           BN_print_fp(stderr, dh->p);
           fprintf(stderr, "\ng= ");
           BN_print_fp(stderr, dh->g);
           fprintf(stderr, "\npub= ");
           BN_print_fp(stderr, dh->pub_key);
           fprintf(stderr, "\n");
           DHparams_print_fp(stderr, dh);
   #endif
   
           debug("Sending SSH2_MSG_KEX_DH_GEX_INIT.");
           /* generate and send 'e', client DH public key */
           packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
           packet_put_bignum2(dh->pub_key);
           packet_send();
           packet_write_wait();
   
           debug("Wait SSH2_MSG_KEX_DH_GEX_REPLY.");
   
           packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY);
   
           debug("Got SSH2_MSG_KEXDH_REPLY.");
   
           /* key, cert */
           server_host_key_blob = packet_get_string(&sbloblen);
           server_host_key = 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= ");
           BN_print_fp(stderr, 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_gex(
               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,
               nbits, dh->p, dh->g,
               dh->pub_key,
               dh_server_pub,
               shared_secret
           );
           xfree(server_host_key_blob);
           DH_free(dh);
   #ifdef DEBUG_KEXDH
           fprintf(stderr, "hash == ");
           for (i = 0; i< 20; i++)
                   fprintf(stderr, "%02x", (hash[i])&0xff);
           fprintf(stderr, "\n");
   #endif
           if (key_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1)
                   fatal("key_verify failed for server_host_key");
           key_free(server_host_key);
   
           kex_derive_keys(kex, hash, shared_secret);
           packet_set_kex(kex);
   
           /* save session id */
           session_id2_len = 20;
           session_id2 = xmalloc(session_id2_len);
           memcpy(session_id2, hash, session_id2_len);
   }
   
   /*
  * Authenticate user   * Authenticate user
  */   */
   
Line 138 
Line 450 
   
 typedef int sign_cb_fn(  typedef int sign_cb_fn(
     Authctxt *authctxt, Key *key,      Authctxt *authctxt, Key *key,
     u_char **sigp, u_int *lenp, u_char *data, u_int datalen);      unsigned char **sigp, int *lenp, unsigned char *data, int datalen);
   
 struct Authctxt {  struct Authctxt {
         const char *server_user;          const char *server_user;
         const char *local_user;  
         const char *host;          const char *host;
         const char *service;          const char *service;
           AuthenticationConnection *agent;
         Authmethod *method;          Authmethod *method;
         int success;          int success;
         char *authlist;  
         /* pubkey */  
         Key *last_key;  
         sign_cb_fn *last_key_sign;  
         int last_key_hint;  
         AuthenticationConnection *agent;  
         /* hostbased */  
         Key **keys;  
         int nkeys;  
         /* kbd-interactive */  
         int info_req_seen;  
 };  };
 struct Authmethod {  struct Authmethod {
         char    *name;          /* string to compare against server's list */          char    *name;          /* string to compare against server's list */
Line 166 
Line 467 
         int     *batch_flag;    /* flag in option struct that disables method */          int     *batch_flag;    /* flag in option struct that disables method */
 };  };
   
 void    input_userauth_success(int, u_int32_t, void *);  void    input_userauth_success(int type, int plen, void *ctxt);
 void    input_userauth_failure(int, u_int32_t, void *);  void    input_userauth_failure(int type, int plen, void *ctxt);
 void    input_userauth_banner(int, u_int32_t, void *);  void    input_userauth_error(int type, int plen, void *ctxt);
 void    input_userauth_error(int, u_int32_t, void *);  void    input_userauth_info_req(int type, int plen, void *ctxt);
 void    input_userauth_info_req(int, u_int32_t, void *);  
 void    input_userauth_pk_ok(int, u_int32_t, void *);  
   
 int     userauth_none(Authctxt *);  int     userauth_none(Authctxt *authctxt);
 int     userauth_pubkey(Authctxt *);  int     userauth_pubkey(Authctxt *authctxt);
 int     userauth_passwd(Authctxt *);  int     userauth_passwd(Authctxt *authctxt);
 int     userauth_kbdint(Authctxt *);  int     userauth_kbdint(Authctxt *authctxt);
 int     userauth_hostbased(Authctxt *);  
   
 void    userauth(Authctxt *, char *);  void    authmethod_clear();
   Authmethod *authmethod_get(char *authlist);
   Authmethod *authmethod_lookup(const char *name);
   
 static int sign_and_send_pubkey(Authctxt *, Key *, sign_cb_fn *);  
 static void clear_auth_state(Authctxt *);  
   
 static Authmethod *authmethod_get(char *authlist);  
 static Authmethod *authmethod_lookup(const char *name);  
 static char *authmethods_get(void);  
   
 Authmethod authmethods[] = {  Authmethod authmethods[] = {
         {"hostbased",  
                 userauth_hostbased,  
                 &options.hostbased_authentication,  
                 NULL},  
         {"publickey",          {"publickey",
                 userauth_pubkey,                  userauth_pubkey,
                 &options.pubkey_authentication,                  &options.pubkey_authentication,
                 NULL},                  NULL},
         {"keyboard-interactive",  
                 userauth_kbdint,  
                 &options.kbd_interactive_authentication,  
                 &options.batch_mode},  
         {"password",          {"password",
                 userauth_passwd,                  userauth_passwd,
                 &options.password_authentication,                  &options.password_authentication,
                 &options.batch_mode},                  &options.batch_mode},
           {"keyboard-interactive",
                   userauth_kbdint,
                   &options.kbd_interactive_authentication,
                   &options.batch_mode},
         {"none",          {"none",
                 userauth_none,                  userauth_none,
                 NULL,                  NULL,
Line 213 
Line 502 
 };  };
   
 void  void
 ssh_userauth2(const char *local_user, const char *server_user, char *host,  ssh_userauth2(const char *server_user, char *host)
     Key **keys, int nkeys)  
 {  {
         Authctxt authctxt;          Authctxt authctxt;
         int type;          int type;
           int plen;
   
         if (options.challenge_response_authentication)  
                 options.kbd_interactive_authentication = 1;  
   
         debug("send SSH2_MSG_SERVICE_REQUEST");          debug("send SSH2_MSG_SERVICE_REQUEST");
         packet_start(SSH2_MSG_SERVICE_REQUEST);          packet_start(SSH2_MSG_SERVICE_REQUEST);
         packet_put_cstring("ssh-userauth");          packet_put_cstring("ssh-userauth");
         packet_send();          packet_send();
         packet_write_wait();          packet_write_wait();
         type = packet_read();          type = packet_read(&plen);
         if (type != SSH2_MSG_SERVICE_ACCEPT) {          if (type != SSH2_MSG_SERVICE_ACCEPT) {
                 fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);                  fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
         }          }
         if (packet_remaining() > 0) {          if (packet_remaining() > 0) {
                 char *reply = packet_get_string(NULL);                  char *reply = packet_get_string(&plen);
                 debug("service_accept: %s", reply);                  debug("service_accept: %s", reply);
                 xfree(reply);                  xfree(reply);
                   packet_done();
         } else {          } else {
                 debug("buggy server: service_accept w/o service");                  debug("buggy server: service_accept w/o service");
         }          }
         packet_check_eom();          packet_done();
         debug("got SSH2_MSG_SERVICE_ACCEPT");          debug("got SSH2_MSG_SERVICE_ACCEPT");
   
         if (options.preferred_authentications == NULL)  
                 options.preferred_authentications = authmethods_get();  
   
         /* setup authentication context */          /* setup authentication context */
         memset(&authctxt, 0, sizeof(authctxt));  
         authctxt.agent = ssh_get_authentication_connection();          authctxt.agent = ssh_get_authentication_connection();
         authctxt.server_user = server_user;          authctxt.server_user = server_user;
         authctxt.local_user = local_user;  
         authctxt.host = host;          authctxt.host = host;
         authctxt.service = "ssh-connection";            /* service name */          authctxt.service = "ssh-connection";            /* service name */
         authctxt.success = 0;          authctxt.success = 0;
         authctxt.method = authmethod_lookup("none");          authctxt.method = authmethod_lookup("none");
         authctxt.authlist = NULL;  
         authctxt.keys = keys;  
         authctxt.nkeys = nkeys;  
         authctxt.info_req_seen = 0;  
         if (authctxt.method == NULL)          if (authctxt.method == NULL)
                 fatal("ssh_userauth2: internal error: cannot send userauth none request");                  fatal("ssh_userauth2: internal error: cannot send userauth none request");
           authmethod_clear();
   
         /* initial userauth request */          /* initial userauth request */
         userauth_none(&authctxt);          userauth_none(&authctxt);
Line 266 
Line 545 
         dispatch_init(&input_userauth_error);          dispatch_init(&input_userauth_error);
         dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);          dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
         dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);          dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
         dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);  
         dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt);     /* loop until success */          dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt);     /* loop until success */
   
         if (authctxt.agent != NULL)          if (authctxt.agent != NULL)
                 ssh_close_authentication_connection(authctxt.agent);                  ssh_close_authentication_connection(authctxt.agent);
   
         debug("ssh-userauth2 successful: method %s", authctxt.method->name);          debug("ssh-userauth2 successfull: method %s", authctxt.method->name);
 }  }
 void  void
 userauth(Authctxt *authctxt, char *authlist)  input_userauth_error(int type, int plen, void *ctxt)
 {  {
         if (authlist == NULL) {          fatal("input_userauth_error: bad message during authentication");
                 authlist = authctxt->authlist;  
         } else {  
                 if (authctxt->authlist)  
                         xfree(authctxt->authlist);  
                 authctxt->authlist = authlist;  
         }  
         for (;;) {  
                 Authmethod *method = authmethod_get(authlist);  
                 if (method == NULL)  
                         fatal("Permission denied (%s).", authlist);  
                 authctxt->method = method;  
                 if (method->userauth(authctxt) != 0) {  
                         debug2("we sent a %s packet, wait for reply", method->name);  
                         break;  
                 } else {  
                         debug2("we did not send a packet, disable method");  
                         method->enabled = NULL;  
                 }  
         }  
 }  }
 void  void
 input_userauth_error(int type, u_int32_t seq, void *ctxt)  input_userauth_success(int type, int plen, void *ctxt)
 {  {
         fatal("input_userauth_error: bad message during authentication: "  
            "type %d", type);  
 }  
 void  
 input_userauth_banner(int type, u_int32_t seq, void *ctxt)  
 {  
         char *msg, *lang;  
         debug3("input_userauth_banner");  
         msg = packet_get_string(NULL);  
         lang = packet_get_string(NULL);  
         fprintf(stderr, "%s", msg);  
         xfree(msg);  
         xfree(lang);  
 }  
 void  
 input_userauth_success(int type, u_int32_t seq, void *ctxt)  
 {  
         Authctxt *authctxt = ctxt;          Authctxt *authctxt = ctxt;
         if (authctxt == NULL)          if (authctxt == NULL)
                 fatal("input_userauth_success: no authentication context");                  fatal("input_userauth_success: no authentication context");
         if (authctxt->authlist)  
                 xfree(authctxt->authlist);  
         clear_auth_state(authctxt);  
         authctxt->success = 1;                  /* break out */          authctxt->success = 1;                  /* break out */
 }  }
 void  void
 input_userauth_failure(int type, u_int32_t seq, void *ctxt)  input_userauth_failure(int type, int plen, void *ctxt)
 {  {
           Authmethod *method = NULL;
         Authctxt *authctxt = ctxt;          Authctxt *authctxt = ctxt;
         char *authlist = NULL;          char *authlist = NULL;
         int partial;          int partial;
Line 338 
Line 578 
   
         authlist = packet_get_string(NULL);          authlist = packet_get_string(NULL);
         partial = packet_get_char();          partial = packet_get_char();
         packet_check_eom();          packet_done();
   
         if (partial != 0)          if (partial != 0)
                 log("Authenticated with partial success.");                  debug("partial success");
         debug("authentications that can continue: %s", authlist);          debug("authentications that can continue: %s", authlist);
   
         clear_auth_state(authctxt);          for (;;) {
         userauth(authctxt, authlist);                  method = authmethod_get(authlist);
 }                  if (method == NULL)
 void                          fatal("Unable to find an authentication method");
 input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)                  authctxt->method = method;
 {                  if (method->userauth(authctxt) != 0) {
         Authctxt *authctxt = ctxt;                          debug2("we sent a %s packet, wait for reply", method->name);
         Key *key = NULL;  
         Buffer b;  
         int pktype, sent = 0;  
         u_int alen, blen;  
         char *pkalg, *fp;  
         u_char *pkblob;  
   
         if (authctxt == NULL)  
                 fatal("input_userauth_pk_ok: no authentication context");  
         if (datafellows & SSH_BUG_PKOK) {  
                 /* this is similar to SSH_BUG_PKAUTH */  
                 debug2("input_userauth_pk_ok: SSH_BUG_PKOK");  
                 pkblob = packet_get_string(&blen);  
                 buffer_init(&b);  
                 buffer_append(&b, pkblob, blen);  
                 pkalg = buffer_get_string(&b, &alen);  
                 buffer_free(&b);  
         } else {  
                 pkalg = packet_get_string(&alen);  
                 pkblob = packet_get_string(&blen);  
         }  
         packet_check_eom();  
   
         debug("input_userauth_pk_ok: pkalg %s blen %d lastkey %p hint %d",  
             pkalg, blen, authctxt->last_key, authctxt->last_key_hint);  
   
         do {  
                 if (authctxt->last_key == NULL ||  
                     authctxt->last_key_sign == NULL) {  
                         debug("no last key or no sign cb");  
                         break;                          break;
                   } else {
                           debug2("we did not send a packet, disable method");
                           method->enabled = NULL;
                 }                  }
                 if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {          }
                         debug("unknown pkalg %s", pkalg);          xfree(authlist);
                         break;  
                 }  
                 if ((key = key_from_blob(pkblob, blen)) == NULL) {  
                         debug("no key from blob. pkalg %s", pkalg);  
                         break;  
                 }  
                 if (key->type != pktype) {  
                         error("input_userauth_pk_ok: type mismatch "  
                             "for decoded key (received %d, expected %d)",  
                              key->type, pktype);  
                         break;  
                 }  
                 fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);  
                 debug2("input_userauth_pk_ok: fp %s", fp);  
                 xfree(fp);  
                 if (!key_equal(key, authctxt->last_key)) {  
                         debug("key != last_key");  
                         break;  
                 }  
                 sent = sign_and_send_pubkey(authctxt, key,  
                    authctxt->last_key_sign);  
         } while (0);  
   
         if (key != NULL)  
                 key_free(key);  
         xfree(pkalg);  
         xfree(pkblob);  
   
         /* unregister */  
         clear_auth_state(authctxt);  
         dispatch_set(SSH2_MSG_USERAUTH_PK_OK, NULL);  
   
         /* try another method if we did not send a packet*/  
         if (sent == 0)  
                 userauth(authctxt, NULL);  
   
 }  }
   
 int  int
Line 432 
Line 609 
         packet_put_cstring(authctxt->service);          packet_put_cstring(authctxt->service);
         packet_put_cstring(authctxt->method->name);          packet_put_cstring(authctxt->method->name);
         packet_send();          packet_send();
           packet_write_wait();
         return 1;          return 1;
 }  }
   
Line 445 
Line 623 
         if (attempt++ >= options.number_of_password_prompts)          if (attempt++ >= options.number_of_password_prompts)
                 return 0;                  return 0;
   
         if (attempt != 1)          if(attempt != 1)
                 error("Permission denied, please try again.");                  error("Permission denied, please try again.");
   
         snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",          snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
             authctxt->server_user, authctxt->host);              authctxt->server_user, authctxt->host);
         password = read_passphrase(prompt, 0);          password = read_passphrase(prompt, 0);
         packet_start(SSH2_MSG_USERAUTH_REQUEST);          packet_start(SSH2_MSG_USERAUTH_REQUEST);
Line 459 
Line 637 
         packet_put_cstring(password);          packet_put_cstring(password);
         memset(password, 0, strlen(password));          memset(password, 0, strlen(password));
         xfree(password);          xfree(password);
         packet_add_padding(64);  
         packet_send();          packet_send();
           packet_write_wait();
         return 1;          return 1;
 }  }
   
 static void  int
 clear_auth_state(Authctxt *authctxt)  
 {  
         /* XXX clear authentication state */  
         if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) {  
                 debug3("clear_auth_state: key_free %p", authctxt->last_key);  
                 key_free(authctxt->last_key);  
         }  
         authctxt->last_key = NULL;  
         authctxt->last_key_hint = -2;  
         authctxt->last_key_sign = NULL;  
 }  
   
 static int  
 sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)  sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
 {  {
         Buffer b;          Buffer b;
         u_char *blob, *signature;          unsigned char *blob, *signature;
         u_int bloblen, slen;          int bloblen, slen;
         int skip = 0;          int skip = 0;
         int ret = -1;          int ret = -1;
         int have_sig = 1;          int have_sig = 1;
   
         debug3("sign_and_send_pubkey");  
   
         if (key_to_blob(k, &blob, &bloblen) == 0) {          if (key_to_blob(k, &blob, &bloblen) == 0) {
                 /* we cannot handle this key */                  /* we cannot handle this key */
                 debug3("sign_and_send_pubkey: cannot handle key");  
                 return 0;                  return 0;
         }          }
         /* data to be signed */          /* data to be signed */
         buffer_init(&b);          buffer_init(&b);
         if (datafellows & SSH_OLD_SESSIONID) {          if (datafellows & SSH_OLD_SESSIONID) {
                 buffer_append(&b, session_id2, session_id2_len);                  buffer_append(&b, session_id2, session_id2_len);
                 skip = session_id2_len;                  skip = session_id2_len;
         } else {          } else {
                 buffer_put_string(&b, session_id2, session_id2_len);                  buffer_put_string(&b, session_id2, session_id2_len);
                 skip = buffer_len(&b);                  skip = buffer_len(&b);
Line 506 
Line 668 
         buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);          buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
         buffer_put_cstring(&b, authctxt->server_user);          buffer_put_cstring(&b, authctxt->server_user);
         buffer_put_cstring(&b,          buffer_put_cstring(&b,
             datafellows & SSH_BUG_PKSERVICE ?              datafellows & SSH_BUG_PUBKEYAUTH ?
             "ssh-userauth" :              "ssh-userauth" :
             authctxt->service);              authctxt->service);
         if (datafellows & SSH_BUG_PKAUTH) {          buffer_put_cstring(&b, authctxt->method->name);
                 buffer_put_char(&b, have_sig);          buffer_put_char(&b, have_sig);
         } else {          buffer_put_cstring(&b, key_ssh_name(k));
                 buffer_put_cstring(&b, authctxt->method->name);  
                 buffer_put_char(&b, have_sig);  
                 buffer_put_cstring(&b, key_ssh_name(k));  
         }  
         buffer_put_string(&b, blob, bloblen);          buffer_put_string(&b, blob, bloblen);
   
         /* generate signature */          /* generate signature */
         ret = (*sign_callback)(authctxt, k, &signature, &slen,          ret = (*sign_callback)(authctxt, k, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
             buffer_ptr(&b), buffer_len(&b));  
         if (ret == -1) {          if (ret == -1) {
                 xfree(blob);                  xfree(blob);
                 buffer_free(&b);                  buffer_free(&b);
Line 529 
Line 686 
 #ifdef DEBUG_PK  #ifdef DEBUG_PK
         buffer_dump(&b);          buffer_dump(&b);
 #endif  #endif
         if (datafellows & SSH_BUG_PKSERVICE) {          if (datafellows & SSH_BUG_PUBKEYAUTH) {
                 buffer_clear(&b);                  buffer_clear(&b);
                 buffer_append(&b, session_id2, session_id2_len);                  buffer_append(&b, session_id2, session_id2_len);
                 skip = session_id2_len;  
                 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);                  buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
                 buffer_put_cstring(&b, authctxt->server_user);                  buffer_put_cstring(&b, authctxt->server_user);
                 buffer_put_cstring(&b, authctxt->service);                  buffer_put_cstring(&b, authctxt->service);
                 buffer_put_cstring(&b, authctxt->method->name);                  buffer_put_cstring(&b, authctxt->method->name);
                 buffer_put_char(&b, have_sig);                  buffer_put_char(&b, have_sig);
                 if (!(datafellows & SSH_BUG_PKAUTH))                  buffer_put_cstring(&b, key_ssh_name(k));
                         buffer_put_cstring(&b, key_ssh_name(k));  
                 buffer_put_string(&b, blob, bloblen);                  buffer_put_string(&b, blob, bloblen);
         }          }
         xfree(blob);          xfree(blob);
   
         /* append signature */          /* append signature */
         buffer_put_string(&b, signature, slen);          buffer_put_string(&b, signature, slen);
         xfree(signature);          xfree(signature);
Line 557 
Line 711 
         packet_start(SSH2_MSG_USERAUTH_REQUEST);          packet_start(SSH2_MSG_USERAUTH_REQUEST);
         packet_put_raw(buffer_ptr(&b), buffer_len(&b));          packet_put_raw(buffer_ptr(&b), buffer_len(&b));
         buffer_free(&b);          buffer_free(&b);
   
           /* send */
         packet_send();          packet_send();
           packet_write_wait();
   
         return 1;          return 1;
 }  }
   
 static int  /* sign callback */
 send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,  int key_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp,
     int hint)      unsigned char *data, int datalen)
 {  {
         u_char *blob;          return key_sign(key, sigp, lenp, data, datalen);
         u_int bloblen, have_sig = 0;  
   
         debug3("send_pubkey_test");  
   
         if (key_to_blob(k, &blob, &bloblen) == 0) {  
                 /* we cannot handle this key */  
                 debug3("send_pubkey_test: cannot handle key");  
                 return 0;  
         }  
         /* register callback for USERAUTH_PK_OK message */  
         authctxt->last_key_sign = sign_callback;  
         authctxt->last_key_hint = hint;  
         authctxt->last_key = k;  
         dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);  
   
         packet_start(SSH2_MSG_USERAUTH_REQUEST);  
         packet_put_cstring(authctxt->server_user);  
         packet_put_cstring(authctxt->service);  
         packet_put_cstring(authctxt->method->name);  
         packet_put_char(have_sig);  
         if (!(datafellows & SSH_BUG_PKAUTH))  
                 packet_put_cstring(key_ssh_name(k));  
         packet_put_string(blob, bloblen);  
         xfree(blob);  
         packet_send();  
         return 1;  
 }  }
   
 static Key *  int
 load_identity_file(char *filename)  userauth_pubkey_identity(Authctxt *authctxt, char *filename)
 {  {
         Key *private;          Key *k;
         char prompt[300], *passphrase;          int i, ret, try_next;
         int quit, i;  
         struct stat st;          struct stat st;
   
         if (stat(filename, &st) < 0) {          if (stat(filename, &st) != 0) {
                 debug3("no such identity: %s", filename);                  debug("key does not exist: %s", filename);
                 return NULL;                  return 0;
         }          }
         private = key_load_private_type(KEY_UNSPEC, filename, "", NULL);          debug("try pubkey: %s", filename);
         if (private == NULL) {  
                 if (options.batch_mode)          k = key_new(KEY_UNSPEC);
                         return NULL;          if (!load_private_key(filename, "", k, NULL)) {
                   int success = 0;
                   char *passphrase;
                   char prompt[300];
                 snprintf(prompt, sizeof prompt,                  snprintf(prompt, sizeof prompt,
                     "Enter passphrase for key '%.100s': ", filename);                       "Enter passphrase for key '%.100s': ", filename);
                 for (i = 0; i < options.number_of_password_prompts; i++) {                  for (i = 0; i < options.number_of_password_prompts; i++) {
                         passphrase = read_passphrase(prompt, 0);                          passphrase = read_passphrase(prompt, 0);
                         if (strcmp(passphrase, "") != 0) {                          if (strcmp(passphrase, "") != 0) {
                                 private = key_load_private_type(KEY_UNSPEC, filename,                                  success = load_private_key(filename, passphrase, k, NULL);
                                     passphrase, NULL);                                  try_next = 0;
                                 quit = 0;  
                         } else {                          } else {
                                 debug2("no passphrase given, try next key");                                  debug2("no passphrase given, try next key");
                                 quit = 1;                                  try_next = 1;
                         }                          }
                         memset(passphrase, 0, strlen(passphrase));                          memset(passphrase, 0, strlen(passphrase));
                         xfree(passphrase);                          xfree(passphrase);
                         if (private != NULL || quit)                          if (success || try_next)
                                 break;                                  break;
                         debug2("bad passphrase given, try again...");                          debug2("bad passphrase given, try again...");
                 }                  }
                   if (!success) {
                           key_free(k);
                           return 0;
                   }
         }          }
         return private;          ret = sign_and_send_pubkey(authctxt, k, key_sign_cb);
 }          key_free(k);
   
 static int  
 identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,  
     u_char *data, u_int datalen)  
 {  
         Key *private;  
         int idx, ret;  
   
         idx = authctxt->last_key_hint;  
         if (idx < 0)  
                 return -1;  
   
         /* private key is stored in external hardware */  
         if (options.identity_keys[idx]->flags & KEY_FLAG_EXT)  
                 return key_sign(options.identity_keys[idx], sigp, lenp, data, datalen);  
   
         private = load_identity_file(options.identity_files[idx]);  
         if (private == NULL)  
                 return -1;  
         ret = key_sign(private, sigp, lenp, data, datalen);  
         key_free(private);  
         return ret;          return ret;
 }  }
   
 static int  /* sign callback */
 agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,  int agent_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp,
     u_char *data, u_int datalen)      unsigned char *data, int datalen)
 {  {
         return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);          return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
 }  }
   
 static int  int
 key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,  
     u_char *data, u_int datalen)  
 {  
         return key_sign(key, sigp, lenp, data, datalen);  
 }  
   
 static int  
 userauth_pubkey_agent(Authctxt *authctxt)  userauth_pubkey_agent(Authctxt *authctxt)
 {  {
         static int called = 0;          static int called = 0;
Line 687 
Line 795 
         if (k == NULL) {          if (k == NULL) {
                 debug2("userauth_pubkey_agent: no more keys");                  debug2("userauth_pubkey_agent: no more keys");
         } else {          } else {
                 debug("userauth_pubkey_agent: testing agent key %s", comment);                  debug("userauth_pubkey_agent: trying agent key %s", comment);
                 xfree(comment);                  xfree(comment);
                 ret = send_pubkey_test(authctxt, k, agent_sign_cb, -1);                  ret = sign_and_send_pubkey(authctxt, k, agent_sign_cb);
                 if (ret == 0)                  key_free(k);
                         key_free(k);  
         }          }
         if (ret == 0)          if (ret == 0)
                 debug2("userauth_pubkey_agent: no message sent");                  debug2("userauth_pubkey_agent: no message sent");
Line 703 
Line 810 
 {  {
         static int idx = 0;          static int idx = 0;
         int sent = 0;          int sent = 0;
         Key *key;  
         char *filename;  
   
         if (authctxt->agent != NULL) {          if (authctxt->agent != NULL) {
                 do {                  do {
                         sent = userauth_pubkey_agent(authctxt);                          sent = userauth_pubkey_agent(authctxt);
                 } while (!sent && authctxt->agent->howmany > 0);                  } while(!sent && authctxt->agent->howmany > 0);
         }          }
         while (!sent && idx < options.num_identity_files) {          while (!sent && idx < options.num_identity_files) {
                 key = options.identity_keys[idx];                  if (options.identity_files_type[idx] != KEY_RSA1)
                 filename = options.identity_files[idx];                          sent = userauth_pubkey_identity(authctxt,
                 if (key == NULL) {                              options.identity_files[idx]);
                         debug("try privkey: %s", filename);  
                         key = load_identity_file(filename);  
                         if (key != NULL) {  
                                 sent = sign_and_send_pubkey(authctxt, key,  
                                     key_sign_cb);  
                                 key_free(key);  
                         }  
                 } else if (key->type != KEY_RSA1) {  
                         debug("try pubkey: %s", filename);  
                         sent = send_pubkey_test(authctxt, key,  
                             identity_sign_cb, idx);  
                 }  
                 idx++;                  idx++;
         }          }
         return sent;          return sent;
Line 742 
Line 835 
   
         if (attempt++ >= options.number_of_password_prompts)          if (attempt++ >= options.number_of_password_prompts)
                 return 0;                  return 0;
         /* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */  
         if (attempt > 1 && !authctxt->info_req_seen) {  
                 debug3("userauth_kbdint: disable: no info_req_seen");  
                 dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);  
                 return 0;  
         }  
   
         debug2("userauth_kbdint");          debug2("userauth_kbdint");
         packet_start(SSH2_MSG_USERAUTH_REQUEST);          packet_start(SSH2_MSG_USERAUTH_REQUEST);
Line 758 
Line 845 
         packet_put_cstring(options.kbd_interactive_devices ?          packet_put_cstring(options.kbd_interactive_devices ?
             options.kbd_interactive_devices : "");              options.kbd_interactive_devices : "");
         packet_send();          packet_send();
           packet_write_wait();
   
         dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);          dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
         return 1;          return 1;
 }  }
   
 /*  /*
  * parse INFO_REQUEST, prompt user and send INFO_RESPONSE   * parse SSH2_MSG_USERAUTH_INFO_REQUEST, prompt user and send
    * SSH2_MSG_USERAUTH_INFO_RESPONSE
  */   */
 void  void
 input_userauth_info_req(int type, u_int32_t seq, void *ctxt)  input_userauth_info_req(int type, int plen, void *ctxt)
 {  {
         Authctxt *authctxt = ctxt;          Authctxt *authctxt = ctxt;
         char *name, *inst, *lang, *prompt, *response;          char *name = NULL;
         u_int num_prompts, i;          char *inst = NULL;
           char *lang = NULL;
           char *prompt = NULL;
           char *response = NULL;
           unsigned int num_prompts, i;
         int echo = 0;          int echo = 0;
   
         debug2("input_userauth_info_req");          debug2("input_userauth_info_req");
Line 779 
Line 872 
         if (authctxt == NULL)          if (authctxt == NULL)
                 fatal("input_userauth_info_req: no authentication context");                  fatal("input_userauth_info_req: no authentication context");
   
         authctxt->info_req_seen = 1;  
   
         name = packet_get_string(NULL);          name = packet_get_string(NULL);
         inst = packet_get_string(NULL);          inst = packet_get_string(NULL);
         lang = packet_get_string(NULL);          lang = packet_get_string(NULL);
   
         if (strlen(name) > 0)          if (strlen(name) > 0)
                 log("%s", name);                  cli_mesg(name);
         if (strlen(inst) > 0)  
                 log("%s", inst);  
         xfree(name);          xfree(name);
   
           if (strlen(inst) > 0)
                   cli_mesg(inst);
         xfree(inst);          xfree(inst);
         xfree(lang);          xfree(lang);                            /* unused */
   
         num_prompts = packet_get_int();          num_prompts = packet_get_int();
         /*          /*
Line 802 
Line 895 
         packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);          packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
         packet_put_int(num_prompts);          packet_put_int(num_prompts);
   
         debug2("input_userauth_info_req: num_prompts %d", num_prompts);  
         for (i = 0; i < num_prompts; i++) {          for (i = 0; i < num_prompts; i++) {
                 prompt = packet_get_string(NULL);                  prompt = packet_get_string(NULL);
                 echo = packet_get_char();                  echo = packet_get_char();
   
                 response = read_passphrase(prompt, echo ? RP_ECHO : 0);                  response = cli_prompt(prompt, echo);
   
                 packet_put_cstring(response);                  packet_put_cstring(response);
                 memset(response, 0, strlen(response));                  memset(response, 0, strlen(response));
                 xfree(response);                  xfree(response);
                 xfree(prompt);                  xfree(prompt);
         }          }
         packet_check_eom(); /* done with parsing incoming message. */          packet_done(); /* done with parsing incoming message. */
   
         packet_add_padding(64);  
         packet_send();          packet_send();
           packet_write_wait();
 }  }
   
   /* find auth method */
   
   #define DELIM   ","
   
   static char *def_authlist = "publickey,password";
   static char *authlist_current = NULL;    /* clean copy used for comparison */
   static char *authname_current = NULL;    /* last used auth method */
   static char *authlist_working = NULL;    /* copy that gets modified by strtok_r() */
   static char *authlist_state = NULL;      /* state variable for strtok_r() */
   
 /*  /*
  * this will be move to an external program (ssh-keysign) ASAP. ssh-keysign   * Before starting to use a new authentication method list sent by the
  * will be setuid-root and the sbit can be removed from /usr/bin/ssh.   * server, reset internal variables.  This should also be called when
    * finished processing server list to free resources.
  */   */
 int  void
 userauth_hostbased(Authctxt *authctxt)  authmethod_clear()
 {  {
         Key *private = NULL;          if (authlist_current != NULL) {
         Buffer b;                  xfree(authlist_current);
         u_char *signature, *blob;                  authlist_current = NULL;
         char *chost, *pkalg, *p;  
         const char *service;  
         u_int blen, slen;  
         int ok, i, len, found = 0;  
   
         /* check for a useful key */  
         for (i = 0; i < authctxt->nkeys; i++) {  
                 private = authctxt->keys[i];  
                 if (private && private->type != KEY_RSA1) {  
                         found = 1;  
                         /* we take and free the key */  
                         authctxt->keys[i] = NULL;  
                         break;  
                 }  
         }          }
         if (!found) {          if (authlist_working != NULL) {
                 debug("userauth_hostbased: no more client hostkeys");                  xfree(authlist_working);
                 return 0;                  authlist_working = NULL;
         }          }
         if (key_to_blob(private, &blob, &blen) == 0) {          if (authname_current != NULL) {
                 key_free(private);                  xfree(authname_current);
                 return 0;                  authlist_state = NULL;
         }          }
         /* figure out a name for the client host */          if (authlist_state != NULL)
         p = get_local_name(packet_get_connection_in());                  authlist_state = NULL;
         if (p == NULL) {          return;
                 error("userauth_hostbased: cannot get local ipaddr/name");  
                 key_free(private);  
                 return 0;  
         }  
         len = strlen(p) + 2;  
         chost = xmalloc(len);  
         strlcpy(chost, p, len);  
         strlcat(chost, ".", len);  
         debug2("userauth_hostbased: chost %s", chost);  
   
         service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :  
             authctxt->service;  
         pkalg = xstrdup(key_ssh_name(private));  
         buffer_init(&b);  
         /* construct data */  
         buffer_put_string(&b, session_id2, session_id2_len);  
         buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);  
         buffer_put_cstring(&b, authctxt->server_user);  
         buffer_put_cstring(&b, service);  
         buffer_put_cstring(&b, authctxt->method->name);  
         buffer_put_cstring(&b, pkalg);  
         buffer_put_string(&b, blob, blen);  
         buffer_put_cstring(&b, chost);  
         buffer_put_cstring(&b, authctxt->local_user);  
 #ifdef DEBUG_PK  
         buffer_dump(&b);  
 #endif  
         ok = key_sign(private, &signature, &slen, buffer_ptr(&b), buffer_len(&b));  
         key_free(private);  
         buffer_free(&b);  
         if (ok != 0) {  
                 error("key_sign failed");  
                 xfree(chost);  
                 xfree(pkalg);  
                 return 0;  
         }  
         packet_start(SSH2_MSG_USERAUTH_REQUEST);  
         packet_put_cstring(authctxt->server_user);  
         packet_put_cstring(authctxt->service);  
         packet_put_cstring(authctxt->method->name);  
         packet_put_cstring(pkalg);  
         packet_put_string(blob, blen);  
         packet_put_cstring(chost);  
         packet_put_cstring(authctxt->local_user);  
         packet_put_string(signature, slen);  
         memset(signature, 's', slen);  
         xfree(signature);  
         xfree(chost);  
         xfree(pkalg);  
   
         packet_send();  
         return 1;  
 }  }
   
 /* find auth method */  
   
 /*  /*
  * given auth method name, if configurable options permit this method fill   * given auth method name, if configurable options permit this method fill
  * in auth_ident field and return true, otherwise return false.   * in auth_ident field and return true, otherwise return false.
  */   */
 static int  int
 authmethod_is_enabled(Authmethod *method)  authmethod_is_enabled(Authmethod *method)
 {  {
         if (method == NULL)          if (method == NULL)
Line 930 
Line 965 
         return 1;          return 1;
 }  }
   
 static Authmethod *  Authmethod *
 authmethod_lookup(const char *name)  authmethod_lookup(const char *name)
 {  {
         Authmethod *method = NULL;          Authmethod *method = NULL;
Line 942 
Line 977 
         return NULL;          return NULL;
 }  }
   
 /* XXX internal state */  
 static Authmethod *current = NULL;  
 static char *supported = NULL;  
 static char *preferred = NULL;  
 /*  /*
  * Given the authentication method list sent by the server, return the   * Given the authentication method list sent by the server, return the
  * next method we should try.  If the server initially sends a nil list,   * next method we should try.  If the server initially sends a nil list,
  * use a built-in default list.   * use a built-in default list.  If the server sends a nil list after
  */   * previously sending a valid list, continue using the list originally
 static Authmethod *   * sent.
    */
   
   Authmethod *
 authmethod_get(char *authlist)  authmethod_get(char *authlist)
 {  {
           char *name = NULL, *authname_old;
         char *name = NULL;          Authmethod *method = NULL;
         u_int next;  
   
         /* Use a suitable default if we're passed a nil list.  */          /* Use a suitable default if we're passed a nil list.  */
         if (authlist == NULL || strlen(authlist) == 0)          if (authlist == NULL || strlen(authlist) == 0)
                 authlist = options.preferred_authentications;                  authlist = def_authlist;
   
         if (supported == NULL || strcmp(authlist, supported) != 0) {          if (authlist_current == NULL || strcmp(authlist, authlist_current) != 0) {
                 debug3("start over, passed a different list %s", authlist);                  /* start over if passed a different list */
                 if (supported != NULL)                  debug3("start over, passed a different list");
                         xfree(supported);                  authmethod_clear();
                 supported = xstrdup(authlist);                  authlist_current = xstrdup(authlist);
                 preferred = options.preferred_authentications;                  authlist_working = xstrdup(authlist);
                 debug3("preferred %s", preferred);                  name = strtok_r(authlist_working, DELIM, &authlist_state);
                 current = NULL;          } else {
         } else if (current != NULL && authmethod_is_enabled(current))                  /*
                 return current;                   * try to use previously used authentication method
                    * or continue to use previously passed list
                    */
                   name = (authname_current != NULL) ?
                       authname_current : strtok_r(NULL, DELIM, &authlist_state);
           }
   
         for (;;) {          while (name != NULL) {
                 if ((name = match_list(preferred, supported, &next)) == NULL) {  
                         debug("no more auth methods to try");  
                         current = NULL;  
                         return NULL;  
                 }  
                 preferred += next;  
                 debug3("authmethod_lookup %s", name);                  debug3("authmethod_lookup %s", name);
                 debug3("remaining preferred: %s", preferred);                  method = authmethod_lookup(name);
                 if ((current = authmethod_lookup(name)) != NULL &&                  if (method != NULL && authmethod_is_enabled(method)) {
                     authmethod_is_enabled(current)) {  
                         debug3("authmethod_is_enabled %s", name);                          debug3("authmethod_is_enabled %s", name);
                         debug("next auth method to try is %s", name);                          break;
                         return current;  
                 }                  }
                   name = strtok_r(NULL, DELIM, &authlist_state);
                   method = NULL;
         }          }
 }  
   
 static char *          authname_old = authname_current;
 authmethods_get(void)          if (method != NULL) {
 {                  debug("next auth method to try is %s", name);
         Authmethod *method = NULL;                  authname_current = xstrdup(name);
         Buffer b;          } else {
         char *list;                  debug("no more auth methods to try");
                   authname_current = NULL;
         buffer_init(&b);  
         for (method = authmethods; method->name != NULL; method++) {  
                 if (authmethod_is_enabled(method)) {  
                         if (buffer_len(&b) > 0)  
                                 buffer_append(&b, ",", 1);  
                         buffer_append(&b, method->name, strlen(method->name));  
                 }  
         }          }
         buffer_append(&b, "\0", 1);  
         list = xstrdup(buffer_ptr(&b));          if (authname_old != NULL)
         buffer_free(&b);                  xfree(authname_old);
         return list;  
           return (method);
 }  }

Legend:
Removed from v.1.27.2.8  
changed lines
  Added in v.1.28