+}
+
+/*
+ * Starts a dialog with the server, and authenticates the current user on the
+ * server. This does not need any extra privileges. The basic connection
+ * to the server must already have been established before this is called.
+ * User is the remote user; if it is NULL, the current local user name will
+ * be used. Anonymous indicates that no rhosts authentication will be used.
+ * If login fails, this function prints an error and never returns.
+ * This function does not require super-user privileges.
+ */
+void
+ssh_login(int host_key_valid,
+ RSA *own_host_key,
+ const char *orighost,
+ struct sockaddr_in *hostaddr,
+ uid_t original_real_uid)
+{
+ int i, type;
+ struct passwd *pw;
+ BIGNUM *key;
+ RSA *host_key;
+ RSA *public_key;
+ int bits, rbits;
+ unsigned char session_key[SSH_SESSION_KEY_LENGTH];
+ const char *server_user, *local_user;
+ char *host, *cp;
+ unsigned char check_bytes[8];
+ unsigned int supported_ciphers, supported_authentications;
+ unsigned int server_flags, client_flags;
+ 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();
+ bits = packet_get_int();/* bits */
+ public_key->e = BN_new();
+ packet_get_bignum(public_key->e, &clen);
+ sum_len += clen;
+ public_key->n = BN_new();
+ packet_get_bignum(public_key->n, &clen);
+ sum_len += clen;
+
+ rbits = BN_num_bits(public_key->n);
+ if (bits != rbits) {
+ log("Warning: Server lies about size of server public key: "
+ "actual size is %d bits vs. announced %d.", rbits, bits);
+ log("Warning: This may be due to an old implementation of ssh.");
+ }
+ /* Get the host key. */
+ host_key = RSA_new();
+ bits = packet_get_int();/* bits */
+ host_key->e = BN_new();
+ packet_get_bignum(host_key->e, &clen);
+ sum_len += clen;
+ host_key->n = BN_new();
+ packet_get_bignum(host_key->n, &clen);
+ sum_len += clen;
+
+ rbits = BN_num_bits(host_key->n);
+ if (bits != rbits) {
+ log("Warning: Server lies about size of server host key: "
+ "actual size is %d bits vs. announced %d.", rbits, bits);
+ log("Warning: This may be due to an old implementation of ssh.");
+ }
+
+ /* Get protocol flags. */
+ server_flags = packet_get_int();
+ packet_set_protocol_flags(server_flags);
+
+ supported_ciphers = packet_get_int();
+ supported_authentications = packet_get_int();
+
+ debug("Received server public key (%d bits) and host key (%d bits).",
+ BN_num_bits(public_key->n), BN_num_bits(host_key->n));
+
+ packet_integrity_check(payload_len,
+ 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
+ SSH_SMSG_PUBLIC_KEY);
+
+ check_host_key(host, hostaddr, host_key);
+
+ client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN;
+
+ compute_session_id(session_id, check_bytes, host_key->n, public_key->n);