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

Diff for /src/usr.bin/ssh/sshconnect.c between version 1.58 and 1.59

version 1.58, 2000/03/23 22:15:33 version 1.59, 2000/04/04 15:19:43
Line 5 
Line 5 
  * Created: Sat Mar 18 22:15:47 1995 ylo   * Created: Sat Mar 18 22:15:47 1995 ylo
  * Code to connect to a remote host, and to perform the client side of the   * Code to connect to a remote host, and to perform the client side of the
  * login (authentication) dialog.   * login (authentication) dialog.
    *
    * SSH2 support added by Markus Friedl.
  */   */
   
 #include "includes.h"  #include "includes.h"
Line 14 
Line 16 
 #include "xmalloc.h"  #include "xmalloc.h"
 #include "rsa.h"  #include "rsa.h"
 #include "ssh.h"  #include "ssh.h"
   #include "buffer.h"
 #include "packet.h"  #include "packet.h"
 #include "authfd.h"  #include "authfd.h"
 #include "cipher.h"  #include "cipher.h"
Line 22 
Line 25 
 #include "compat.h"  #include "compat.h"
 #include "readconf.h"  #include "readconf.h"
   
   #include "bufaux.h"
 #include <ssl/rsa.h>  #include <ssl/rsa.h>
 #include <ssl/dsa.h>  #include <ssl/dsa.h>
   
   #include "ssh2.h"
 #include <ssl/md5.h>  #include <ssl/md5.h>
   #include <ssl/dh.h>
   #include <ssl/hmac.h>
   #include "kex.h"
   #include "myproposal.h"
 #include "key.h"  #include "key.h"
   #include "dsa.h"
 #include "hostfile.h"  #include "hostfile.h"
   
 /* Session id for the current session. */  /* Session id for the current session. */
Line 34 
Line 45 
 /* authentications supported by server */  /* authentications supported by server */
 unsigned int supported_authentications;  unsigned int supported_authentications;
   
   static char *client_version_string = NULL;
   static char *server_version_string = NULL;
   
 extern Options options;  extern Options options;
 extern char *__progname;  extern char *__progname;
   
Line 949 
Line 963 
         return 0;          return 0;
 }  }
   
   char *
   chop(char *s)
   {
           char *t = s;
           while (*t) {
                   if(*t == '\n' || *t == '\r') {
                           *t = '\0';
                           return s;
                   }
                   t++;
           }
           return s;
   
   }
   
 /*  /*
  * Waits for the server identification string, and sends our own   * Waits for the server identification string, and sends our own
  * identification string.   * identification string.
Line 971 
Line 1000 
                 if (buf[i] == '\r') {                  if (buf[i] == '\r') {
                         buf[i] = '\n';                          buf[i] = '\n';
                         buf[i + 1] = 0;                          buf[i + 1] = 0;
                         break;                          continue;               /**XXX wait for \n */
                 }                  }
                 if (buf[i] == '\n') {                  if (buf[i] == '\n') {
                         buf[i + 1] = 0;                          buf[i + 1] = 0;
Line 979 
Line 1008 
                 }                  }
         }          }
         buf[sizeof(buf) - 1] = 0;          buf[sizeof(buf) - 1] = 0;
           server_version_string = xstrdup(buf);
   
         /*          /*
          * Check that the versions match.  In future this might accept           * Check that the versions match.  In future this might accept
          * several versions and set appropriate flags to handle them.           * several versions and set appropriate flags to handle them.
          */           */
         if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,          if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n",
                    remote_version) != 3)              &remote_major, &remote_minor, remote_version) != 3)
                 fatal("Bad remote protocol version identification: '%.100s'", buf);                  fatal("Bad remote protocol version identification: '%.100s'", buf);
         debug("Remote protocol version %d.%d, remote software version %.100s",          debug("Remote protocol version %d.%d, remote software version %.100s",
               remote_major, remote_minor, remote_version);                remote_major, remote_minor, remote_version);
   
   /*** XXX option for disabling 2.0 or 1.5 */
           compat_datafellows(remote_version);
   
         /* Check if the remote protocol version is too old. */          /* Check if the remote protocol version is too old. */
         if (remote_major == 1 && remote_minor < 3)          if (remote_major == 1 && remote_minor < 3)
                 fatal("Remote machine has too old SSH software version.");                  fatal("Remote machine has too old SSH software version.");
Line 1002 
Line 1035 
                         options.forward_agent = 0;                          options.forward_agent = 0;
                 }                  }
         }          }
           if ((remote_major == 2 && remote_minor == 0) ||
               (remote_major == 1 && remote_minor == 99)) {
                   enable_compat20();
           }
 #if 0  #if 0
         /*          /*
          * Removed for now, to permit compatibility with latter versions. The           * Removed for now, to permit compatibility with latter versions. The
Line 1012 
Line 1049 
                 fatal("Protocol major versions differ: %d vs. %d",                  fatal("Protocol major versions differ: %d vs. %d",
                       PROTOCOL_MAJOR, remote_major);                        PROTOCOL_MAJOR, remote_major);
 #endif  #endif
   
         /* Send our own protocol version identification. */          /* Send our own protocol version identification. */
         snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",          snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
             PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION);              compat20 ? 2 : PROTOCOL_MAJOR,
               compat20 ? 0 : PROTOCOL_MINOR,
               SSH_VERSION);
         if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf))          if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf))
                 fatal("write: %.100s", strerror(errno));                  fatal("write: %.100s", strerror(errno));
           client_version_string = xstrdup(buf);
           chop(client_version_string);
           chop(server_version_string);
           debug("Local version string %.100s", client_version_string);
 }  }
   
 int ssh_cipher_default = SSH_CIPHER_3DES;  
   
 int  int
 read_yes_or_no(const char *prompt, int defval)  read_yes_or_no(const char *prompt, int defval)
 {  {
Line 1271 
Line 1311 
 }  }
   
 /*  /*
    * SSH2 key exchange
    */
   void
   ssh_kex2(char *host, struct sockaddr *hostaddr)
   {
           Kex *kex;
           char *cprop[PROPOSAL_MAX];
           char *sprop[PROPOSAL_MAX];
           Buffer *client_kexinit;
           Buffer *server_kexinit;
           int payload_len, dlen;
           unsigned int klen, kout;
           char *ptr;
           char *signature = NULL;
           unsigned int slen;
           char *server_host_key_blob = NULL;
           Key *server_host_key;
           unsigned int sbloblen;
           DH *dh;
           BIGNUM *dh_server_pub = 0;
           BIGNUM *shared_secret = 0;
           int i;
           unsigned char *kbuf;
           unsigned char *hash;
   
   /* KEXINIT */
   
           debug("Sending KEX init.");
           if (options.cipher == SSH_CIPHER_ARCFOUR ||
               options.cipher == SSH_CIPHER_3DES_CBC ||
               options.cipher == SSH_CIPHER_CAST128_CBC ||
               options.cipher == SSH_CIPHER_BLOWFISH_CBC) {
                   myproposal[PROPOSAL_ENC_ALGS_CTOS] = cipher_name(options.cipher);
                   myproposal[PROPOSAL_ENC_ALGS_STOC] = cipher_name(options.cipher);
           }
           if (options.compression) {
                   myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib";
                   myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
           } else {
                   myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none";
                   myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
           }
           for (i = 0; i < PROPOSAL_MAX; i++)
                   cprop[i] = xstrdup(myproposal[i]);
   
           client_kexinit = kex_init(cprop);
           packet_start(SSH2_MSG_KEXINIT);
           packet_put_raw(buffer_ptr(client_kexinit), buffer_len(client_kexinit));
           packet_send();
           packet_write_wait();
   
           debug("done");
   
           packet_read_expect(&payload_len, SSH2_MSG_KEXINIT);
   
           /* save payload for session_id */
           server_kexinit = xmalloc(sizeof(*server_kexinit));
           buffer_init(server_kexinit);
           ptr = packet_get_raw(&payload_len);
           buffer_append(server_kexinit, ptr, payload_len);
   
           /* skip cookie */
           for (i = 0; i < 16; i++)
                   (void) packet_get_char();
           /* kex init proposal strings */
           for (i = 0; i < PROPOSAL_MAX; i++) {
                   sprop[i] = packet_get_string(NULL);
                   debug("got kexinit string: %s", sprop[i]);
           }
           i = (int) packet_get_char();
           debug("first kex follow == %d", i);
           i = packet_get_int();
           debug("reserved == %d", i);
   
           debug("done read kexinit");
           kex = kex_choose_conf(cprop, sprop, 0);
   
   /* KEXDH */
   
           debug("Sending SSH2_MSG_KEXDH_INIT.");
   
           /* generate and send 'e', client DH public key */
           dh = new_dh_group1();
           packet_start(SSH2_MSG_KEXDH_INIT);
           packet_put_bignum2(dh->pub_key);
           packet_send();
           packet_write_wait();
   
   #ifdef DEBUG_KEXDH
           fprintf(stderr, "\np= ");
           bignum_print(dh->p);
           fprintf(stderr, "\ng= ");
           bignum_print(dh->g);
           fprintf(stderr, "\npub= ");
           bignum_print(dh->pub_key);
           fprintf(stderr, "\n");
           DHparams_print_fp(stderr, dh);
   #endif
   
           debug("Wait SSH2_MSG_KEXDH_REPLY.");
   
           packet_read_expect(&payload_len, SSH2_MSG_KEXDH_REPLY);
   
           debug("Got SSH2_MSG_KEXDH_REPLY.");
   
           /* key, cert */
           server_host_key_blob = packet_get_string(&sbloblen);
           server_host_key = dsa_serverkey_from_blob(server_host_key_blob, sbloblen);
           if (server_host_key == NULL)
                   fatal("cannot decode server_host_key_blob");
   
           check_host_key(host, hostaddr, server_host_key);
   
           /* DH paramter f, server public DH key */
           dh_server_pub = BN_new();
           if (dh_server_pub == NULL)
                   fatal("dh_server_pub == NULL");
           packet_get_bignum2(dh_server_pub, &dlen);
   
   #ifdef DEBUG_KEXDH
           fprintf(stderr, "\ndh_server_pub= ");
           bignum_print(dh_server_pub);
           fprintf(stderr, "\n");
           debug("bits %d", BN_num_bits(dh_server_pub));
   #endif
   
           /* signed H */
           signature = packet_get_string(&slen);
   
           klen = DH_size(dh);
           kbuf = xmalloc(klen);
           kout = DH_compute_key(kbuf, dh_server_pub, dh);
   #ifdef DEBUG_KEXDH
           debug("shared secret: len %d/%d", klen, kout);
           fprintf(stderr, "shared secret == ");
           for (i = 0; i< kout; i++)
                   fprintf(stderr, "%02x", (kbuf[i])&0xff);
           fprintf(stderr, "\n");
   #endif
           shared_secret = BN_new();
   
           BN_bin2bn(kbuf, kout, shared_secret);
           memset(kbuf, 0, klen);
           xfree(kbuf);
   
           /* calc and verify H */
           hash = kex_hash(
               client_version_string,
               server_version_string,
               buffer_ptr(client_kexinit), buffer_len(client_kexinit),
               buffer_ptr(server_kexinit), buffer_len(server_kexinit),
               server_host_key_blob, sbloblen,
               dh->pub_key,
               dh_server_pub,
               shared_secret
           );
           buffer_clear(client_kexinit);
           buffer_clear(server_kexinit);
           xfree(client_kexinit);
           xfree(server_kexinit);
   #ifdef DEBUG_KEXDH
           fprintf(stderr, "hash == ");
           for (i = 0; i< 20; i++)
                   fprintf(stderr, "%02x", (hash[i])&0xff);
           fprintf(stderr, "\n");
   #endif
           dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20);
           key_free(server_host_key);
   
           kex_derive_keys(kex, hash, shared_secret);
           packet_set_kex(kex);
   
           /* have keys, free DH */
           DH_free(dh);
   
           debug("Wait SSH2_MSG_NEWKEYS.");
           packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS);
           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.");
   
           /* send 1st encrypted/maced/compressed message */
           packet_start(SSH2_MSG_IGNORE);
           packet_put_cstring("markus");
           packet_send();
           packet_write_wait();
   
           debug("done: KEX2.");
   }
   /*
    * Authenticate user
    */
   void
   ssh_userauth2(int host_key_valid, RSA *own_host_key,
       uid_t original_real_uid, char *host)
   {
           int type;
           int plen;
           unsigned int dlen;
           int partial;
           struct passwd *pw;
           char *server_user, *local_user;
           char *auths;
           char *password;
           char *service = "ssh-connection";               // service name
   
           debug("send SSH2_MSG_SERVICE_REQUEST");
           packet_start(SSH2_MSG_SERVICE_REQUEST);
           packet_put_cstring("ssh-userauth");
           packet_send();
           packet_write_wait();
   
           type = packet_read(&plen);
           if (type != SSH2_MSG_SERVICE_ACCEPT) {
                   fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
           }
           /* payload empty for ssh-2.0.13 ?? */
           /* reply = packet_get_string(&payload_len); */
           debug("got SSH2_MSG_SERVICE_ACCEPT");
   
           /*XX COMMONCODE: */
           /* Get local user name.  Use it as server user if no user name was given. */
           pw = getpwuid(original_real_uid);
           if (!pw)
                   fatal("User id %d not found from user database.", original_real_uid);
           local_user = xstrdup(pw->pw_name);
           server_user = options.user ? options.user : local_user;
   
           /* INITIAL request for auth */
           packet_start(SSH2_MSG_USERAUTH_REQUEST);
           packet_put_cstring(server_user);
           packet_put_cstring(service);
           packet_put_cstring("none");
           packet_send();
           packet_write_wait();
   
           for (;;) {
                   type = packet_read(&plen);
                   if (type == SSH2_MSG_USERAUTH_SUCCESS)
                           break;
                   if (type != SSH2_MSG_USERAUTH_FAILURE)
                           fatal("access denied: %d", type);
                   /* SSH2_MSG_USERAUTH_FAILURE means: try again */
                   auths = packet_get_string(&dlen);
                   debug("authentications that can continue: %s", auths);
                   partial = packet_get_char();
                   if (partial)
                           debug("partial success");
                   if (strstr(auths, "password") == NULL)
                           fatal("passwd auth not supported: %s", auths);
                   xfree(auths);
                   /* try passwd */
                   password = read_passphrase("password: ", 0);
                   packet_start(SSH2_MSG_USERAUTH_REQUEST);
                   packet_put_cstring(server_user);
                   packet_put_cstring(service);
                   packet_put_cstring("password");
                   packet_put_char(0);
                   packet_put_cstring(password);
                   memset(password, 0, strlen(password));
                   xfree(password);
                   packet_send();
                   packet_write_wait();
           }
           debug("ssh-userauth2 successfull");
   }
   
   /*
  * SSH1 key exchange   * SSH1 key exchange
  */   */
 void  void
Line 1281 
Line 1593 
         RSA *host_key;          RSA *host_key;
         RSA *public_key;          RSA *public_key;
         int bits, rbits;          int bits, rbits;
           int ssh_cipher_default = SSH_CIPHER_3DES;
         unsigned char session_key[SSH_SESSION_KEY_LENGTH];          unsigned char session_key[SSH_SESSION_KEY_LENGTH];
         unsigned char cookie[8];          unsigned char cookie[8];
         unsigned int supported_ciphers;          unsigned int supported_ciphers;
Line 1628 
Line 1941 
         /* Put the connection into non-blocking mode. */          /* Put the connection into non-blocking mode. */
         packet_set_nonblocking();          packet_set_nonblocking();
   
         supported_authentications = 0;  
         /* key exchange */          /* key exchange */
         ssh_kex(host, hostaddr);  
         if (supported_authentications == 0)  
                 fatal("supported_authentications == 0.");  
   
         /* authenticate user */          /* authenticate user */
         ssh_userauth(host_key_valid, own_host_key, original_real_uid, host);          if (compat20) {
                   ssh_kex2(host, hostaddr);
                   ssh_userauth2(host_key_valid, own_host_key, original_real_uid, host);
           } else {
                   supported_authentications = 0;
                   ssh_kex(host, hostaddr);
                   if (supported_authentications == 0)
                           fatal("supported_authentications == 0.");
                   ssh_userauth(host_key_valid, own_host_key, original_real_uid, host);
           }
 }  }

Legend:
Removed from v.1.58  
changed lines
  Added in v.1.59