if (options->check_host_ip && strcmp(host, inet_ntoa(hostaddr->sin_addr))) {  file_key = RSA_new(); file_key->n = BN_new(); file_key->e = BN_new(); }
file_key = RSA_new(); file_key->n = BN_new(); file_key->e = BN_new();
void ssh_login(int host_key_valid, 	       RSA *own_host_key,	       const char *orighost, 	       struct sockaddr_in *hostaddr,	       Options *options, uid_t original_real_uid){  int i, type;  char *password;  struct passwd *pw;  BIGNUM *key;  RSA *host_key, *file_key;  RSA *public_key;  unsigned char session_key[SSH_SESSION_KEY_LENGTH];  const char *server_user, *local_user;  char *cp, *host;  unsigned char check_bytes[8];  unsigned int supported_ciphers, supported_authentications, protocol_flags;  HostStatus host_status;  HostStatus ip_status;  int payload_len, clen, sum_len = 0;  u_int32_t rand = 0;  /* Convert the user-supplied hostname into all lowercase. */  host = xstrdup(orighost);  for (cp = host; *cp; cp++)    if (isupper(*cp))      *cp = tolower(*cp);  /* Exchange protocol version identification strings with the server. */  ssh_exchange_identification();  /* Put the connection into non-blocking mode. */  packet_set_nonblocking();  /* 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;  debug("Waiting for server public key.");  /* Wait for a public key packet from the server. */  packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY);  /* Get check bytes from the packet. */  for (i = 0; i < 8; i++)    check_bytes[i] = packet_get_char();  /* Get the public key. */  public_key = RSA_new();  packet_get_int();	/* bits */  public_key->e = BN_new();  packet_get_bignum(public_key->e, &clen);  sum_len += clen;  public_key->n = BN_new();  packet_get_bignum(public_key->n, &clen);  sum_len += clen;  /* Get the host key. */  host_key = RSA_new();  packet_get_int();	/* bits */  host_key->e = BN_new();  packet_get_bignum(host_key->e, &clen);  sum_len += clen;  host_key->n = BN_new();  packet_get_bignum(host_key->n, &clen);  sum_len += clen;  if (options->check_host_ip && strcmp(host, inet_ntoa(hostaddr->sin_addr))) {    /* Store the host key from the known host file in here     * so that we can compare it with the key for the IP     * address. */    file_key = RSA_new();    file_key->n = BN_new();    file_key->e = BN_new();  }  /* Get protocol flags. */  protocol_flags = packet_get_int();  packet_set_protocol_flags(protocol_flags);  /* Get supported cipher types. */  supported_ciphers = packet_get_int();  /* Get supported authentication types. */  supported_authentications = packet_get_int();  debug("Received server public key (%d bits) and host key (%d bits).", 	BN_num_bits(public_key->n), BN_num_bits(host_key->n));  packet_integrity_check(payload_len,			 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,			 SSH_SMSG_PUBLIC_KEY);  /* Compute the session id. */  compute_session_id(session_id, check_bytes, 		     BN_num_bits(host_key->n), host_key->n, 		     BN_num_bits(public_key->n), public_key->n);  /* Check if the host key is present in the user\'s list of known hosts     or in the systemwide list. */  host_status = check_host_in_hostfile(options->user_hostfile, 				       host, BN_num_bits(host_key->n), 				       host_key->e, host_key->n,				       file_key->e, file_key->n);  if (host_status == HOST_NEW)    host_status = check_host_in_hostfile(options->system_hostfile, host, 					 BN_num_bits(host_key->n),					 host_key->e, host_key->n,					 file_key->e, file_key->n);  /* Force accepting of the host key for localhost and 127.0.0.1.     The problem is that if the home directory is NFS-mounted to multiple     machines, localhost will refer to a different machine in each of them,     and the user will get bogus HOST_CHANGED warnings.  This essentially     disables host authentication for localhost; however, this is probably     not a real problem. */  if (strcmp(host, "localhost") == 0 ||      strcmp(host, "127.0.0.1") == 0)    {      debug("Forcing accepting of host key for localhost.");      host_status = HOST_OK;    }  /* Also perform check for the ip address */  if (options->check_host_ip && strcmp(host, inet_ntoa(hostaddr->sin_addr))) {    RSA *ip_key = RSA_new();    ip_key->n = BN_new();    ip_key->e = BN_new();    ip_status = check_host_in_hostfile(options->user_hostfile,				       inet_ntoa(hostaddr->sin_addr), 				       BN_num_bits(host_key->n),				       host_key->e, host_key->n,				       ip_key->e, ip_key->n);    if (ip_status == HOST_NEW)      ip_status = check_host_in_hostfile(options->system_hostfile,					 inet_ntoa(hostaddr->sin_addr), 					 BN_num_bits(host_key->n),					 host_key->e, host_key->n,					 ip_key->e, ip_key->n);    if (ip_status == HOST_CHANGED && host_status == HOST_CHANGED &&	(BN_cmp(ip_key->e, file_key->e) || BN_cmp(ip_key->n, file_key->n)))      ip_status = HOST_DIFFER;    RSA_free(ip_key);    RSA_free(file_key);  } else    ip_status = host_status;  switch (host_status) {  case HOST_OK:    /* The host is known and the key matches. */    debug("Host '%.200s' is known and matches the host key.", host);    if (options->check_host_ip) {      if (ip_status == HOST_NEW) {	if (!add_host_to_hostfile(options->user_hostfile,				  inet_ntoa(hostaddr->sin_addr),				  BN_num_bits(host_key->n), 				  host_key->e, host_key->n))	  log("Failed to add the host ip to the list of known hosts (%.30s).", 	      options->user_hostfile);	else	  log("Warning: Permanently added host ip '%.30s' to the list of known hosts.", inet_ntoa(hostaddr->sin_addr));      } else if (ip_status != HOST_OK)	log("Warning: the host key differ from the key of the ip address '%.30s' differs", inet_ntoa(hostaddr->sin_addr));    }        break;  case HOST_NEW:    {      char hostline[1000], *hostp = hostline;      /* The host is new. */      if (options->strict_host_key_checking == 1) {	/* User has requested strict host key checking.  We will not	   add the host key automatically.  The only alternative left	   is to abort. */	fatal("No host key is known for %.200s and you have requested strict checking.", host);      } else if (options->strict_host_key_checking == 2) { /* The default */	char prompt[1024];	snprintf(prompt, sizeof(prompt),		 "The authenticity of host '%.200s' can't be established.\n"		 "Are you sure you want to continue connecting (yes/no)? ",		 host);	if (!read_yes_or_no(prompt, -1))	  fatal("Aborted by user!\n");      }            if (options->check_host_ip && ip_status == HOST_NEW &&	  strcmp(host, inet_ntoa(hostaddr->sin_addr)))	snprintf(hostline, sizeof(hostline), "%s,%s",		 host, inet_ntoa(hostaddr->sin_addr));      else	hostp = host;            /* If not in strict mode, add the key automatically to the local	 known_hosts file. */      if (!add_host_to_hostfile(options->user_hostfile, hostp,				BN_num_bits(host_key->n), 				host_key->e, host_key->n))	log("Failed to add the host to the list of known hosts (%.500s).", 	    options->user_hostfile);      else	log("Warning: Permanently added '%.200s' to the list of known hosts.",	    hostp);      break;    }  case HOST_CHANGED:    if (options->check_host_ip) {      if (ip_status != HOST_CHANGED) {	error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");	error("@       WARNING: POSSIBLE DNS SPOOFNG DETECTED!           @");	error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");	error("The host key for %s has changed,", host);	error("but the key for the according IP address %s has",	      inet_ntoa(hostaddr->sin_addr));	error("a different status.  This could either mean that DNS");	error("SPOOFING is happening or the IP address for the host");	error("and its host key have changed at the same time");      }    }        /* The host key has changed. */    error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");    error("@       WARNING: HOST IDENTIFICATION HAS CHANGED!         @");    error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");    error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");    error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");    error("It is also possible that the host key has just been changed.");    error("Please contact your system administrator.");    error("Add correct host key in %.100s to get rid of this message.", 	  options->user_hostfile);        /* If strict host key checking is in use, the user will have to edit       the key manually and we can only abort. */    if (options->strict_host_key_checking)      fatal("Host key for %.200s has changed and you have requested strict checking.", host);        /* If strict host key checking has not been requested, allow the       connection but without password authentication. */    error("Password authentication is disabled to avoid trojan horses.");    options->password_authentication = 0;    /* XXX Should permit the user to change to use the new id.  This could       be done by converting the host key to an identifying sentence, tell       that the host identifies itself by that sentence, and ask the user       if he/she whishes to accept the authentication. */    break;  }    /* Generate a session key. */  arc4random_stir();    /* Generate an encryption key for the session.   The key is a 256 bit     random number, interpreted as a 32-byte key, with the least significant     8 bits being the first byte of the key. */  for (i = 0; i < 32; i++) {    if (i % 4 == 0)      rand = arc4random();    session_key[i] = rand & 0xff;    rand >>= 8;  }  /* According to the protocol spec, the first byte of the session key is     the highest byte of the integer.  The session key is xored with the     first 16 bytes of the session id. */  key = BN_new();  BN_set_word(key, 0);  for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++)    {      BN_lshift(key, key, 8);      if (i < 16)	BN_add_word(key, session_key[i] ^ session_id[i]);      else	BN_add_word(key, session_key[i]);    }  /* Encrypt the integer using the public key and host key of the server     (key with smaller modulus first). */  if (BN_cmp(public_key->n, host_key->n) < 0)    {      /* Public key has smaller modulus. */      assert(BN_num_bits(host_key->n) >= 	     BN_num_bits(public_key->n) + SSH_KEY_BITS_RESERVED);      rsa_public_encrypt(key, key, public_key);      rsa_public_encrypt(key, key, host_key);    }  else    {      /* Host key has smaller modulus (or they are equal). */      assert(BN_num_bits(public_key->n) >=	     BN_num_bits(host_key->n) + SSH_KEY_BITS_RESERVED);      rsa_public_encrypt(key, key, host_key);      rsa_public_encrypt(key, key, public_key);    }  if (options->cipher == SSH_CIPHER_NOT_SET) {    if (cipher_mask() & supported_ciphers & (1 << ssh_cipher_default))      options->cipher = ssh_cipher_default;    else {      debug("Cipher %d not supported, using %.100s instead.",	    cipher_name(ssh_cipher_default),	    cipher_name(SSH_FALLBACK_CIPHER));      options->cipher = SSH_FALLBACK_CIPHER;    }  }  /* Check that the selected cipher is supported. */  if (!(supported_ciphers & (1 << options->cipher)))    fatal("Selected cipher type %.100s not supported by server.", 	  cipher_name(options->cipher));  debug("Encryption type: %.100s", cipher_name(options->cipher));  /* Send the encrypted session key to the server. */  packet_start(SSH_CMSG_SESSION_KEY);  packet_put_char(options->cipher);  /* Send the check bytes back to the server. */  for (i = 0; i < 8; i++)    packet_put_char(check_bytes[i]);  /* Send the encrypted encryption key. */  packet_put_bignum(key);  /* Send protocol flags. */  packet_put_int(SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN);  /* Send the packet now. */  packet_send();  packet_write_wait();  /* Destroy the session key integer and the public keys since we no longer     need them. */  BN_clear_free(key);  RSA_free(public_key);  RSA_free(host_key);  debug("Sent encrypted session key.");    /* Set the encryption key. */  packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, 			    options->cipher, 1);  /* We will no longer need the session key here.  Destroy any extra copies. */  memset(session_key, 0, sizeof(session_key));  /* Expect a success message from the server.  Note that this message will     be received in encrypted form. */  packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);  debug("Received encrypted confirmation.");  /* Send the name of the user to log in as on the server. */  packet_start(SSH_CMSG_USER);  packet_put_string(server_user, strlen(server_user));  packet_send();  packet_write_wait();  /* The server should respond with success if no authentication is needed     (the user has no password).  Otherwise the server responds with      failure. */  type = packet_read(&payload_len);  if (type == SSH_SMSG_SUCCESS)    return;  /* Connection was accepted without authentication. */  if (type != SSH_SMSG_FAILURE)    packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER",		      type);  #ifdef AFS  /* Try Kerberos tgt passing if the server supports it. */  if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&      options->kerberos_tgt_passing)    {      if (options->cipher == SSH_CIPHER_NONE)	log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");      (void)send_kerberos_tgt();    }  /* Try AFS token passing if the server supports it. */  if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) &&      options->afs_token_passing && k_hasafs())  {    if (options->cipher == SSH_CIPHER_NONE)      log("WARNING: Encryption is disabled! Token will be transmitted in the clear!");    send_afs_tokens();  }#endif /* AFS */  #ifdef KRB4  if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&      options->kerberos_authentication)    {      debug("Trying Kerberos authentication.");      if (try_kerberos_authentication()) {        /* The server should respond with success or failure. */        type = packet_read(&payload_len);        if (type == SSH_SMSG_SUCCESS)          return; /* Successful connection. */        if (type != SSH_SMSG_FAILURE)          packet_disconnect("Protocol error: got %d in response to Kerberos auth", type);      }    }#endif /* KRB4 */    /* Use rhosts authentication if running in privileged socket and we do not     wish to remain anonymous. */  if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) &&       options->rhosts_authentication)    {      debug("Trying rhosts authentication.");      packet_start(SSH_CMSG_AUTH_RHOSTS);      packet_put_string(local_user, strlen(local_user));      packet_send();      packet_write_wait();      /* The server should respond with success or failure. */      type = packet_read(&payload_len);      if (type == SSH_SMSG_SUCCESS)	return; /* Successful connection. */      if (type != SSH_SMSG_FAILURE)	packet_disconnect("Protocol error: got %d in response to rhosts auth",			  type);    }  /* Try .rhosts or /etc/hosts.equiv authentication with RSA host      authentication. */  if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&      options->rhosts_rsa_authentication && host_key_valid)    {      if (try_rhosts_rsa_authentication(local_user, own_host_key))	return; /* Successful authentication. */    }  /* Try RSA authentication if the server supports it. */  if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&      options->rsa_authentication)    {      /* Try RSA authentication using the authentication agent.  The agent         is tried first because no passphrase is needed for it, whereas	 identity files may require passphrases. */      if (try_agent_authentication())	return; /* Successful connection. */      /* Try RSA authentication for each identity. */      for (i = 0; i < options->num_identity_files; i++)	if (try_rsa_authentication(pw, options->identity_files[i],				   !options->batch_mode))	  return; /* Successful connection. */    }    /* Try password authentication if the server supports it. */  if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) &&      options->password_authentication && !options->batch_mode)    {      char prompt[80];      snprintf(prompt, sizeof(prompt), "%.30s@%.30s's password: ",	server_user, host);      debug("Doing password authentication.");      if (options->cipher == SSH_CIPHER_NONE)	log("WARNING: Encryption is disabled! Password will be transmitted in clear text.");      password = read_passphrase(prompt, 0);      packet_start(SSH_CMSG_AUTH_PASSWORD);      packet_put_string(password, strlen(password));      memset(password, 0, strlen(password));      xfree(password);      packet_send();      packet_write_wait();        type = packet_read(&payload_len);      if (type == SSH_SMSG_SUCCESS)	return; /* Successful connection. */      if (type != SSH_SMSG_FAILURE)	packet_disconnect("Protocol error: got %d in response to passwd auth",			  type);    }  /* All authentication methods have failed.  Exit with an error message. */  fatal("Permission denied.");  /*NOTREACHED*/}