[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.10.2.2 and 1.10.2.3

version 1.10.2.2, 2000/09/01 18:23:24 version 1.10.2.3, 2000/11/08 21:31:30
Line 9 
Line 9 
  * 2. Redistributions in binary form must reproduce the above copyright   * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the   *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.   *    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   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Line 42 
Line 37 
 #include "rsa.h"  #include "rsa.h"
 #include "buffer.h"  #include "buffer.h"
 #include "packet.h"  #include "packet.h"
 #include "cipher.h"  
 #include "uidswap.h"  #include "uidswap.h"
 #include "compat.h"  #include "compat.h"
 #include "readconf.h"  #include "readconf.h"
Line 54 
Line 48 
 #include "dsa.h"  #include "dsa.h"
 #include "sshconnect.h"  #include "sshconnect.h"
 #include "authfile.h"  #include "authfile.h"
   #include "cli.h"
   #include "dispatch.h"
 #include "authfd.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 69 
Line 68 
 int session_id2_len = 0;  int session_id2_len = 0;
   
 void  void
 ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr,  ssh_kex2(char *host, struct sockaddr *hostaddr)
     Buffer *client_kexinit, Buffer *server_kexinit)  
 {  {
           int i, plen;
           Kex *kex;
           Buffer *client_kexinit, *server_kexinit;
           char *sprop[PROPOSAL_MAX];
   
           if (options.ciphers == NULL) {
                   if (options.cipher == SSH_CIPHER_3DES) {
                           options.ciphers = "3des-cbc";
                   } else if (options.cipher == SSH_CIPHER_BLOWFISH) {
                           options.ciphers = "blowfish-cbc";
                   } else if (options.cipher == SSH_CIPHER_DES) {
                           fatal("cipher DES not supported for protocol version 2");
                   }
           }
           if (options.ciphers != NULL) {
                   myproposal[PROPOSAL_ENC_ALGS_CTOS] =
                   myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
           }
           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";
           }
   
           /* buffers with raw kexinit messages */
           server_kexinit = xmalloc(sizeof(*server_kexinit));
           buffer_init(server_kexinit);
           client_kexinit = kex_init(myproposal);
   
           /* 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]);
   
           /* 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);
           }
   
           buffer_free(client_kexinit);
           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
           /* send 1st encrypted/maced/compressed message */
           packet_start(SSH2_MSG_IGNORE);
           packet_put_cstring("markus");
           packet_send();
           packet_write_wait();
   #endif
           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;          int plen, dlen;
         unsigned int klen, kout;          unsigned int klen, kout;
         char *signature = NULL;          char *signature = NULL;
Line 95 
Line 179 
   
 #ifdef DEBUG_KEXDH  #ifdef DEBUG_KEXDH
         fprintf(stderr, "\np= ");          fprintf(stderr, "\np= ");
         bignum_print(dh->p);          BN_print_fp(stderr, dh->p);
         fprintf(stderr, "\ng= ");          fprintf(stderr, "\ng= ");
         bignum_print(dh->g);          BN_print_fp(stderr, dh->g);
         fprintf(stderr, "\npub= ");          fprintf(stderr, "\npub= ");
         bignum_print(dh->pub_key);          BN_print_fp(stderr, dh->pub_key);
         fprintf(stderr, "\n");          fprintf(stderr, "\n");
         DHparams_print_fp(stderr, dh);          DHparams_print_fp(stderr, dh);
 #endif  #endif
Line 117 
Line 201 
                 fatal("cannot decode server_host_key_blob");                  fatal("cannot decode server_host_key_blob");
   
         check_host_key(host, hostaddr, server_host_key,          check_host_key(host, hostaddr, server_host_key,
             options.user_hostfile2, options.system_hostfile2);                         options.user_hostfile2, options.system_hostfile2);
   
         /* DH paramter f, server public DH key */          /* DH paramter f, server public DH key */
         dh_server_pub = BN_new();          dh_server_pub = BN_new();
Line 127 
Line 211 
   
 #ifdef DEBUG_KEXDH  #ifdef DEBUG_KEXDH
         fprintf(stderr, "\ndh_server_pub= ");          fprintf(stderr, "\ndh_server_pub= ");
         bignum_print(dh_server_pub);          BN_print_fp(stderr, dh_server_pub);
         fprintf(stderr, "\n");          fprintf(stderr, "\n");
         debug("bits %d", BN_num_bits(dh_server_pub));          debug("bits %d", BN_num_bits(dh_server_pub));
 #endif  #endif
Line 187 
Line 271 
         memcpy(session_id2, hash, 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  void
 ssh_kex2(char *host, struct sockaddr *hostaddr)  ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr,
                    Buffer *client_kexinit, Buffer *server_kexinit)
 {  {
         int i, plen;  #ifdef DEBUG_KEXDH
         Kex *kex;          int i;
         Buffer *client_kexinit, *server_kexinit;  #endif
         char *sprop[PROPOSAL_MAX];          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;
   
         if (options.ciphers != NULL) {          nbits = dh_estimate(kex->enc[MODE_OUT].cipher->key_len * 8);
                 myproposal[PROPOSAL_ENC_ALGS_CTOS] =  
                 myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;  
         } else if (options.cipher == SSH_CIPHER_3DES) {  
                 myproposal[PROPOSAL_ENC_ALGS_CTOS] =  
                 myproposal[PROPOSAL_ENC_ALGS_STOC] =  
                     (char *) cipher_name(SSH_CIPHER_3DES_CBC);  
         } else if (options.cipher == SSH_CIPHER_BLOWFISH) {  
                 myproposal[PROPOSAL_ENC_ALGS_CTOS] =  
                 myproposal[PROPOSAL_ENC_ALGS_STOC] =  
                     (char *) cipher_name(SSH_CIPHER_BLOWFISH_CBC);  
         }  
         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";  
         }  
   
         /* buffers with raw kexinit messages */          debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST.");
         server_kexinit = xmalloc(sizeof(*server_kexinit));          packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
         buffer_init(server_kexinit);          packet_put_int(nbits);
         client_kexinit = kex_init(myproposal);          packet_send();
           packet_write_wait();
   
         /* algorithm negotiation */  #ifdef DEBUG_KEXDH
         kex_exchange_kexinit(client_kexinit, server_kexinit, sprop);          fprintf(stderr, "\nnbits = %d", nbits);
         kex = kex_choose_conf(myproposal, sprop, 0);  #endif
         for (i = 0; i < PROPOSAL_MAX; i++)  
                 xfree(sprop[i]);  
   
         /* server authentication and session key agreement */          debug("Wait SSH2_MSG_KEX_DH_GEX_GROUP.");
         ssh_kex_dh(kex, host, hostaddr, client_kexinit, server_kexinit);  
   
         buffer_free(client_kexinit);          packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP);
         buffer_free(server_kexinit);  
         xfree(client_kexinit);  
         xfree(server_kexinit);  
   
         debug("Wait SSH2_MSG_NEWKEYS.");          debug("Got SSH2_MSG_KEX_DH_GEX_GROUP.");
         packet_read_expect(&plen, SSH2_MSG_NEWKEYS);  
         packet_done();  
         debug("GOT SSH2_MSG_NEWKEYS.");  
   
         debug("send SSH2_MSG_NEWKEYS.");          if ((p = BN_new()) == NULL)
         packet_start(SSH2_MSG_NEWKEYS);                  fatal("BN_new");
         packet_send();          packet_get_bignum2(p, &dlen);
         packet_write_wait();          if ((g = BN_new()) == NULL)
         debug("done: send SSH2_MSG_NEWKEYS.");                  fatal("BN_new");
           packet_get_bignum2(g, &dlen);
           if ((dh = dh_new_group(g, p)) == NULL)
                   fatal("dh_new_group");
   
 #ifdef DEBUG_KEXDH  #ifdef DEBUG_KEXDH
         /* send 1st encrypted/maced/compressed message */          fprintf(stderr, "\np= ");
         packet_start(SSH2_MSG_IGNORE);          BN_print_fp(stderr, dh->p);
         packet_put_cstring("markus");          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_send();
         packet_write_wait();          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 = 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= ");
           BN_print_fp(stderr, dh_server_pub);
           fprintf(stderr, "\n");
           debug("bits %d", BN_num_bits(dh_server_pub));
 #endif  #endif
         debug("done: KEX2.");  
           /* 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 (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);
   
           /* save session id */
           session_id2_len = 20;
           session_id2 = xmalloc(session_id2_len);
           memcpy(session_id2, hash, session_id2_len);
 }  }
   
 /*  /*
  * Authenticate user   * Authenticate user
  */   */
   
   typedef struct Authctxt Authctxt;
   typedef struct Authmethod Authmethod;
   
   typedef int sign_cb_fn(
       Authctxt *authctxt, Key *key,
       unsigned char **sigp, int *lenp, unsigned char *data, int datalen);
   
   struct Authctxt {
           const char *server_user;
           const char *host;
           const char *service;
           AuthenticationConnection *agent;
           Authmethod *method;
           int success;
   };
   struct Authmethod {
           char    *name;          /* string to compare against server's list */
           int     (*userauth)(Authctxt *authctxt);
           int     *enabled;       /* flag in option struct that enables method */
           int     *batch_flag;    /* flag in option struct that disables method */
   };
   
   void    input_userauth_success(int type, int plen, void *ctxt);
   void    input_userauth_failure(int type, int plen, void *ctxt);
   void    input_userauth_error(int type, int plen, void *ctxt);
   void    input_userauth_info_req(int type, int plen, void *ctxt);
   
   int     userauth_none(Authctxt *authctxt);
   int     userauth_pubkey(Authctxt *authctxt);
   int     userauth_passwd(Authctxt *authctxt);
   int     userauth_kbdint(Authctxt *authctxt);
   
   void    authmethod_clear();
   Authmethod *authmethod_get(char *authlist);
   Authmethod *authmethod_lookup(const char *name);
   
   Authmethod authmethods[] = {
           {"publickey",
                   userauth_pubkey,
                   &options.dsa_authentication,
                   NULL},
           {"password",
                   userauth_passwd,
                   &options.password_authentication,
                   &options.batch_mode},
           {"keyboard-interactive",
                   userauth_kbdint,
                   &options.kbd_interactive_authentication,
                   &options.batch_mode},
           {"none",
                   userauth_none,
                   NULL,
                   NULL},
           {NULL, NULL, NULL, NULL}
   };
   
   void
   ssh_userauth2(const char *server_user, char *host)
   {
           Authctxt authctxt;
           int type;
           int plen;
   
           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);
                   packet_done();
           } else {
                   debug("buggy server: service_accept w/o service");
           }
           packet_done();
           debug("got SSH2_MSG_SERVICE_ACCEPT");
   
           /* setup authentication context */
           authctxt.agent = ssh_get_authentication_connection();
           authctxt.server_user = server_user;
           authctxt.host = host;
           authctxt.service = "ssh-connection";            /* service name */
           authctxt.success = 0;
           authctxt.method = authmethod_lookup("none");
           if (authctxt.method == NULL)
                   fatal("ssh_userauth2: internal error: cannot send userauth none request");
           authmethod_clear();
   
           /* initial userauth request */
           userauth_none(&authctxt);
   
           dispatch_init(&input_userauth_error);
           dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
           dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
           dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt);     /* loop until success */
   
           if (authctxt.agent != NULL)
                   ssh_close_authentication_connection(authctxt.agent);
   
           debug("ssh-userauth2 successfull: method %s", authctxt.method->name);
   }
   void
   input_userauth_error(int type, int plen, void *ctxt)
   {
           fatal("input_userauth_error: bad message during authentication");
   }
   void
   input_userauth_success(int type, int plen, void *ctxt)
   {
           Authctxt *authctxt = ctxt;
           if (authctxt == NULL)
                   fatal("input_userauth_success: no authentication context");
           authctxt->success = 1;                  /* break out */
   }
   void
   input_userauth_failure(int type, int plen, void *ctxt)
   {
           Authmethod *method = NULL;
           Authctxt *authctxt = ctxt;
           char *authlist = NULL;
           int partial;
   
           if (authctxt == NULL)
                   fatal("input_userauth_failure: no authentication context");
   
           authlist = packet_get_string(NULL);
           partial = packet_get_char();
           packet_done();
   
           if (partial != 0)
                   debug("partial success");
           debug("authentications that can continue: %s", authlist);
   
           for (;;) {
                   method = authmethod_get(authlist);
                   if (method == NULL)
                           fatal("Unable to find an authentication method");
                   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;
                   }
           }
           xfree(authlist);
   }
   
 int  int
 ssh2_try_passwd(const char *server_user, const char *host, const char *service)  userauth_none(Authctxt *authctxt)
 {  {
           /* initial userauth request */
           packet_start(SSH2_MSG_USERAUTH_REQUEST);
           packet_put_cstring(authctxt->server_user);
           packet_put_cstring(authctxt->service);
           packet_put_cstring(authctxt->method->name);
           packet_send();
           packet_write_wait();
           return 1;
   }
   
   int
   userauth_passwd(Authctxt *authctxt)
   {
         static int attempt = 0;          static int attempt = 0;
         char prompt[80];          char prompt[80];
         char *password;          char *password;
Line 272 
Line 628 
                 error("Permission denied, please try again.");                  error("Permission denied, please try again.");
   
         snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",          snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
             server_user, 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);
         packet_put_cstring(server_user);          packet_put_cstring(authctxt->server_user);
         packet_put_cstring(service);          packet_put_cstring(authctxt->service);
         packet_put_cstring("password");          packet_put_cstring(authctxt->method->name);
         packet_put_char(0);          packet_put_char(0);
         packet_put_cstring(password);          packet_put_cstring(password);
         memset(password, 0, strlen(password));          memset(password, 0, strlen(password));
Line 287 
Line 643 
         return 1;          return 1;
 }  }
   
 typedef int sign_fn(  
     Key *key,  
     unsigned char **sigp, int *lenp,  
     unsigned char *data, int datalen);  
   
 int  int
 ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign,  sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
     const char *server_user, const char *host, const char *service)  
 {  {
         Buffer b;          Buffer b;
         unsigned char *blob, *signature;          unsigned char *blob, *signature;
         int bloblen, slen;          int bloblen, slen;
         int skip = 0;          int skip = 0;
         int ret = -1;          int ret = -1;
           int have_sig = 1;
   
         dsa_make_key_blob(k, &blob, &bloblen);          dsa_make_key_blob(k, &blob, &bloblen);
   
         /* data to be signed */          /* data to be signed */
         buffer_init(&b);          buffer_init(&b);
         if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) {          if (datafellows & SSH_OLD_SESSIONID) {
                 buffer_put_string(&b, session_id2, session_id2_len);  
                 skip = buffer_len(&b);  
         } else {  
                 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 {
                   buffer_put_string(&b, session_id2, session_id2_len);
                   skip = buffer_len(&b);
         }          }
         buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);          buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
         buffer_put_cstring(&b, server_user);          buffer_put_cstring(&b, authctxt->server_user);
         buffer_put_cstring(&b,          buffer_put_cstring(&b,
             datafellows & SSH_BUG_PUBKEYAUTH ?              datafellows & SSH_BUG_PUBKEYAUTH ?
             "ssh-userauth" :              "ssh-userauth" :
             service);              authctxt->service);
         buffer_put_cstring(&b, "publickey");          buffer_put_cstring(&b, authctxt->method->name);
         buffer_put_char(&b, 1);          buffer_put_char(&b, have_sig);
         buffer_put_cstring(&b, KEX_DSS);          buffer_put_cstring(&b, KEX_DSS);
         buffer_put_string(&b, blob, bloblen);          buffer_put_string(&b, blob, bloblen);
   
         /* generate signature */          /* generate signature */
         ret = do_sign(k, &signature, &slen, buffer_ptr(&b), buffer_len(&b));          ret = (*sign_callback)(authctxt, k, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
         if (ret == -1) {          if (ret == -1) {
                 xfree(blob);                  xfree(blob);
                 buffer_free(&b);                  buffer_free(&b);
Line 338 
Line 689 
                 buffer_clear(&b);                  buffer_clear(&b);
                 buffer_append(&b, session_id2, session_id2_len);                  buffer_append(&b, session_id2, session_id2_len);
                 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);                  buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
                 buffer_put_cstring(&b, server_user);                  buffer_put_cstring(&b, authctxt->server_user);
                 buffer_put_cstring(&b, service);                  buffer_put_cstring(&b, authctxt->service);
                 buffer_put_cstring(&b, "publickey");                  buffer_put_cstring(&b, authctxt->method->name);
                 buffer_put_char(&b, 1);                  buffer_put_char(&b, have_sig);
                 buffer_put_cstring(&b, KEX_DSS);                  buffer_put_cstring(&b, KEX_DSS);
                 buffer_put_string(&b, blob, bloblen);                  buffer_put_string(&b, blob, bloblen);
         }          }
Line 352 
Line 703 
   
         /* skip session id and packet type */          /* skip session id and packet type */
         if (buffer_len(&b) < skip + 1)          if (buffer_len(&b) < skip + 1)
                 fatal("ssh2_try_pubkey: internal error");                  fatal("userauth_pubkey: internal error");
         buffer_consume(&b, skip + 1);          buffer_consume(&b, skip + 1);
   
         /* put remaining data from buffer into packet */          /* put remaining data from buffer into packet */
Line 367 
Line 718 
         return 1;          return 1;
 }  }
   
   /* sign callback */
   int dsa_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp,
       unsigned char *data, int datalen)
   {
           return dsa_sign(key, sigp, lenp, data, datalen);
   }
   
 int  int
 ssh2_try_pubkey(char *filename,  userauth_pubkey_identity(Authctxt *authctxt, char *filename)
     const char *server_user, const char *host, const char *service)  
 {  {
         Key *k;          Key *k;
         int ret = 0;          int i, ret, try_next;
         struct stat st;          struct stat st;
   
         if (stat(filename, &st) != 0) {          if (stat(filename, &st) != 0) {
Line 387 
Line 744 
                 char *passphrase;                  char *passphrase;
                 char prompt[300];                  char prompt[300];
                 snprintf(prompt, sizeof prompt,                  snprintf(prompt, sizeof prompt,
                      "Enter passphrase for DSA key '%.100s': ",                       "Enter passphrase for %s key '%.100s': ",
                      filename);                       key_type(k), filename);
                 passphrase = read_passphrase(prompt, 0);                  for (i = 0; i < options.number_of_password_prompts; i++) {
                 success = load_private_key(filename, passphrase, k, NULL);                          passphrase = read_passphrase(prompt, 0);
                 memset(passphrase, 0, strlen(passphrase));                          if (strcmp(passphrase, "") != 0) {
                 xfree(passphrase);                                  success = load_private_key(filename, passphrase, k, NULL);
                                   try_next = 0;
                           } else {
                                   debug2("no passphrase given, try next key");
                                   try_next = 1;
                           }
                           memset(passphrase, 0, strlen(passphrase));
                           xfree(passphrase);
                           if (success || try_next)
                                   break;
                           debug2("bad passphrase given, try again...");
                   }
                 if (!success) {                  if (!success) {
                         key_free(k);                          key_free(k);
                         return 0;                          return 0;
                 }                  }
         }          }
         ret = ssh2_sign_and_send_pubkey(k, dsa_sign, server_user, host, service);          ret = sign_and_send_pubkey(authctxt, k, dsa_sign_cb);
         key_free(k);          key_free(k);
         return ret;          return ret;
 }  }
   
 int agent_sign(  /* sign callback */
     Key *key,  int agent_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp,
     unsigned char **sigp, int *lenp,  
     unsigned char *data, int datalen)      unsigned char *data, int datalen)
 {  {
         int ret = -1;          return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
         AuthenticationConnection *ac = ssh_get_authentication_connection();  
         if (ac != NULL) {  
                 ret = ssh_agent_sign(ac, key, sigp, lenp, data, datalen);  
                 ssh_close_authentication_connection(ac);  
         }  
         return ret;  
 }  }
   
 int  int
 ssh2_try_agent(AuthenticationConnection *ac,  userauth_pubkey_agent(Authctxt *authctxt)
     const char *server_user, const char *host, const char *service)  
 {  {
         static int called = 0;          static int called = 0;
         char *comment;          char *comment;
Line 427 
Line 787 
         int ret;          int ret;
   
         if (called == 0) {          if (called == 0) {
                 k = ssh_get_first_identity(ac, &comment, 2);                  k = ssh_get_first_identity(authctxt->agent, &comment, 2);
                 called ++;                  called = 1;
         } else {          } else {
                 k = ssh_get_next_identity(ac, &comment, 2);                  k = ssh_get_next_identity(authctxt->agent, &comment, 2);
         }          }
         if (k == NULL)          if (k == NULL) {
                   debug2("no more DSA keys from agent");
                 return 0;                  return 0;
           }
         debug("trying DSA agent key %s", comment);          debug("trying DSA agent key %s", comment);
         xfree(comment);          xfree(comment);
         ret = ssh2_sign_and_send_pubkey(k, agent_sign, server_user, host, service);          ret = sign_and_send_pubkey(authctxt, k, agent_sign_cb);
         key_free(k);          key_free(k);
         return ret;          return ret;
 }  }
   
 void  int
 ssh_userauth2(const char *server_user, char *host)  userauth_pubkey(Authctxt *authctxt)
 {  {
         AuthenticationConnection *ac = ssh_get_authentication_connection();          static int idx = 0;
         int type;          int sent = 0;
         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");          if (authctxt->agent != NULL)
         packet_start(SSH2_MSG_SERVICE_REQUEST);                  sent = userauth_pubkey_agent(authctxt);
         packet_put_cstring("ssh-userauth");          while (sent == 0 && idx < options.num_identity_files2)
                   sent = userauth_pubkey_identity(authctxt, options.identity_files2[idx++]);
           return sent;
   }
   
   /*
    * Send userauth request message specifying keyboard-interactive method.
    */
   int
   userauth_kbdint(Authctxt *authctxt)
   {
           static int attempt = 0;
   
           if (attempt++ >= options.number_of_password_prompts)
                   return 0;
   
           debug2("userauth_kbdint");
           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("");                                 /* lang */
           packet_put_cstring(options.kbd_interactive_devices ?
               options.kbd_interactive_devices : "");
         packet_send();          packet_send();
         packet_write_wait();          packet_write_wait();
   
         type = packet_read(&plen);          dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
         if (type != SSH2_MSG_SERVICE_ACCEPT) {          return 1;
                 fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);  }
   
   /*
    * parse SSH2_MSG_USERAUTH_INFO_REQUEST, prompt user and send
    * SSH2_MSG_USERAUTH_INFO_RESPONSE
    */
   void
   input_userauth_info_req(int type, int plen, void *ctxt)
   {
           Authctxt *authctxt = ctxt;
           char *name = NULL;
           char *inst = NULL;
           char *lang = NULL;
           char *prompt = NULL;
           char *response = NULL;
           unsigned int num_prompts, i;
           int echo = 0;
   
           debug2("input_userauth_info_req");
   
           if (authctxt == NULL)
                   fatal("input_userauth_info_req: no authentication context");
   
           name = packet_get_string(NULL);
           inst = packet_get_string(NULL);
           lang = packet_get_string(NULL);
   
           if (strlen(name) > 0)
                   cli_mesg(name);
           xfree(name);
   
           if (strlen(inst) > 0)
                   cli_mesg(inst);
           xfree(inst);
           xfree(lang);                            /* unused */
   
           num_prompts = packet_get_int();
           /*
            * Begin to build info response packet based on prompts requested.
            * We commit to providing the correct number of responses, so if
            * further on we run into a problem that prevents this, we have to
            * be sure and clean this up and send a correct error response.
            */
           packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
           packet_put_int(num_prompts);
   
           for (i = 0; i < num_prompts; i++) {
                   prompt = packet_get_string(NULL);
                   echo = packet_get_char();
   
                   response = cli_prompt(prompt, echo);
   
                   packet_put_cstring(response);
                   memset(response, 0, strlen(response));
                   xfree(response);
                   xfree(prompt);
         }          }
         if (packet_remaining() > 0) {          packet_done(); /* done with parsing incoming message. */
                 char *reply = packet_get_string(&plen);  
                 debug("service_accept: %s", reply);  
                 xfree(reply);  
         } else {  
                 /* payload empty for ssh-2.0.13 ?? */  
                 debug("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_send();
         packet_write_wait();          packet_write_wait();
   }
   
         for (;;) {  /* find auth method */
                 sent = 0;  
                 type = packet_read(&plen);  #define DELIM   ","
                 if (type == SSH2_MSG_USERAUTH_SUCCESS)  
   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() */
   
   /*
    * Before starting to use a new authentication method list sent by the
    * server, reset internal variables.  This should also be called when
    * finished processing server list to free resources.
    */
   void
   authmethod_clear()
   {
           if (authlist_current != NULL) {
                   xfree(authlist_current);
                   authlist_current = NULL;
           }
           if (authlist_working != NULL) {
                   xfree(authlist_working);
                   authlist_working = NULL;
           }
           if (authname_current != NULL) {
                   xfree(authname_current);
                   authlist_state = NULL;
           }
           if (authlist_state != NULL)
                   authlist_state = NULL;
           return;
   }
   
   /*
    * given auth method name, if configurable options permit this method fill
    * in auth_ident field and return true, otherwise return false.
    */
   int
   authmethod_is_enabled(Authmethod *method)
   {
           if (method == NULL)
                   return 0;
           /* return false if options indicate this method is disabled */
           if  (method->enabled == NULL || *method->enabled == 0)
                   return 0;
           /* return false if batch mode is enabled but method needs interactive mode */
           if  (method->batch_flag != NULL && *method->batch_flag != 0)
                   return 0;
           return 1;
   }
   
   Authmethod *
   authmethod_lookup(const char *name)
   {
           Authmethod *method = NULL;
           if (name != NULL)
                   for (method = authmethods; method->name != NULL; method++)
                           if (strcmp(name, method->name) == 0)
                                   return method;
           debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
           return NULL;
   }
   
   /*
    * Given the authentication method list sent by the server, return the
    * next method we should try.  If the server initially sends a nil 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
    * sent.
    */
   
   Authmethod *
   authmethod_get(char *authlist)
   {
           char *name = NULL, *authname_old;
           Authmethod *method = NULL;
   
           /* Use a suitable default if we're passed a nil list.  */
           if (authlist == NULL || strlen(authlist) == 0)
                   authlist = def_authlist;
   
           if (authlist_current == NULL || strcmp(authlist, authlist_current) != 0) {
                   /* start over if passed a different list */
                   debug3("start over, passed a different list");
                   authmethod_clear();
                   authlist_current = xstrdup(authlist);
                   authlist_working = xstrdup(authlist);
                   name = strtok_r(authlist_working, DELIM, &authlist_state);
           } else {
                   /*
                    * 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);
           }
   
           while (name != NULL) {
                   debug3("authmethod_lookup %s", name);
                   method = authmethod_lookup(name);
                   if (method != NULL && authmethod_is_enabled(method)) {
                           debug3("authmethod_is_enabled %s", name);
                         break;                          break;
                 if (type != SSH2_MSG_USERAUTH_FAILURE)  
                         fatal("access denied: %d", type);  
                 /* SSH2_MSG_USERAUTH_FAILURE means: try again */  
                 auths = packet_get_string(&dlen);  
                 debug("authentications that can continue: %s", auths);  
                 partial = packet_get_char();  
                 packet_done();  
                 if (partial)  
                         debug("partial success");  
                 if (options.dsa_authentication &&  
                     strstr(auths, "publickey") != NULL) {  
                         if (ac != NULL)  
                                 sent = ssh2_try_agent(ac,  
                                     server_user, host, service);  
                         if (!sent) {  
                                 while (i < options.num_identity_files2) {  
                                         sent = ssh2_try_pubkey(  
                                             options.identity_files2[i++],  
                                             server_user, host, service);  
                                         if (sent)  
                                                 break;  
                                 }  
                         }  
                 }                  }
                 if (!sent) {                  name = strtok_r(NULL, DELIM, &authlist_state);
                         if (options.password_authentication &&                  method = NULL;
                             !options.batch_mode &&  
                             strstr(auths, "password") != NULL) {  
                                 sent = ssh2_try_passwd(server_user, host, service);  
                         }  
                 }  
                 if (!sent)  
                         fatal("Permission denied (%s).", auths);  
                 xfree(auths);  
         }          }
         if (ac != NULL)  
                 ssh_close_authentication_connection(ac);          authname_old = authname_current;
         packet_done();          if (method != NULL) {
         debug("ssh-userauth2 successfull");                  debug("next auth method to try is %s", name);
                   authname_current = xstrdup(name);
           } else {
                   debug("no more auth methods to try");
                   authname_current = NULL;
           }
   
           if (authname_old != NULL)
                   xfree(authname_old);
   
           return (method);
 }  }

Legend:
Removed from v.1.10.2.2  
changed lines
  Added in v.1.10.2.3