summaryrefslogtreecommitdiffstats
path: root/sshconnect.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>1999-11-25 00:26:21 +1100
committerDamien Miller <djm@mindrot.org>1999-11-25 00:26:21 +1100
commit95def09838fc61b37b6ea7cd5c234a465b4b129b (patch)
tree042744f76f40a326b873cb1c3690a6d7d966bc3e /sshconnect.c
parent4d2f15f895f4c795afc008aeff3fd2ceffbc44f4 (diff)
- Merged very large OpenBSD source code reformat
- OpenBSD CVS updates - [channels.c cipher.c compat.c log-client.c scp.c serverloop.c] [ssh.h sshd.8 sshd.c] syslog changes: * Unified Logmessage for all auth-types, for success and for failed * Standard connections get only ONE line in the LOG when level==LOG: Auth-attempts are logged only, if authentication is: a) successfull or b) with passwd or c) we had more than AUTH_FAIL_LOG failues * many log() became verbose() * old behaviour with level=VERBOSE - [readconf.c readconf.h ssh.1 ssh.h sshconnect.c sshd.c] tranfer s/key challenge/response data in SSH_SMSG_AUTH_TIS_CHALLENGE messages. allows use of s/key in windows (ttssh, securecrt) and ssh-1.2.27 clients without 'ssh -v', ok: niels@ - [sshd.8] -V, for fallback to openssh in SSH2 compatibility mode - [sshd.c] fix sigchld race; cjc5@po.cwru.edu
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c2851
1 files changed, 1421 insertions, 1430 deletions
diff --git a/sshconnect.c b/sshconnect.c
index fba389d8..0657c37e 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,21 +1,14 @@
/*
-
-sshconnect.c
-
-Author: Tatu Ylonen <ylo@cs.hut.fi>
-
-Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- All rights reserved
-
-Created: Sat Mar 18 22:15:47 1995 ylo
-
-Code to connect to a remote host, and to perform the client side of the
-login (authentication) dialog.
-
-*/
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ * Created: Sat Mar 18 22:15:47 1995 ylo
+ * Code to connect to a remote host, and to perform the client side of the
+ * login (authentication) dialog.
+ */
#include "includes.h"
-RCSID("$Id: sshconnect.c,v 1.13 1999/11/21 02:23:53 damien Exp $");
+RCSID("$Id: sshconnect.c,v 1.14 1999/11/24 13:26:23 damien Exp $");
#ifdef HAVE_OPENSSL
#include <openssl/bn.h>
@@ -41,1497 +34,1495 @@ RCSID("$Id: sshconnect.c,v 1.13 1999/11/21 02:23:53 damien Exp $");
/* Session id for the current session. */
unsigned char session_id[16];
-/* Connect to the given ssh server using a proxy command. */
-
+/*
+ * Connect to the given ssh server using a proxy command.
+ */
int
ssh_proxy_connect(const char *host, int port, uid_t original_real_uid,
const char *proxy_command)
{
- Buffer command;
- const char *cp;
- char *command_string;
- int pin[2], pout[2];
- int pid;
- char portstring[100];
-
- /* Convert the port number into a string. */
- snprintf(portstring, sizeof portstring, "%d", port);
-
- /* Build the final command string in the buffer by making the appropriate
- substitutions to the given proxy command. */
- buffer_init(&command);
- for (cp = proxy_command; *cp; cp++)
- {
- if (cp[0] == '%' && cp[1] == '%')
- {
- buffer_append(&command, "%", 1);
- cp++;
- continue;
- }
- if (cp[0] == '%' && cp[1] == 'h')
- {
- buffer_append(&command, host, strlen(host));
- cp++;
- continue;
- }
- if (cp[0] == '%' && cp[1] == 'p')
- {
- buffer_append(&command, portstring, strlen(portstring));
- cp++;
- continue;
+ Buffer command;
+ const char *cp;
+ char *command_string;
+ int pin[2], pout[2];
+ int pid;
+ char portstring[100];
+
+ /* Convert the port number into a string. */
+ snprintf(portstring, sizeof portstring, "%d", port);
+
+ /* Build the final command string in the buffer by making the
+ appropriate substitutions to the given proxy command. */
+ buffer_init(&command);
+ for (cp = proxy_command; *cp; cp++) {
+ if (cp[0] == '%' && cp[1] == '%') {
+ buffer_append(&command, "%", 1);
+ cp++;
+ continue;
+ }
+ if (cp[0] == '%' && cp[1] == 'h') {
+ buffer_append(&command, host, strlen(host));
+ cp++;
+ continue;
+ }
+ if (cp[0] == '%' && cp[1] == 'p') {
+ buffer_append(&command, portstring, strlen(portstring));
+ cp++;
+ continue;
+ }
+ buffer_append(&command, cp, 1);
}
- buffer_append(&command, cp, 1);
- }
- buffer_append(&command, "\0", 1);
-
- /* Get the final command string. */
- command_string = buffer_ptr(&command);
-
- /* Create pipes for communicating with the proxy. */
- if (pipe(pin) < 0 || pipe(pout) < 0)
- fatal("Could not create pipes to communicate with the proxy: %.100s",
- strerror(errno));
-
- debug("Executing proxy command: %.500s", command_string);
-
- /* Fork and execute the proxy command. */
- if ((pid = fork()) == 0)
- {
- char *argv[10];
-
- /* Child. Permanently give up superuser privileges. */
- permanently_set_uid(original_real_uid);
-
- /* Redirect stdin and stdout. */
- close(pin[1]);
- if (pin[0] != 0)
- {
- if (dup2(pin[0], 0) < 0)
- perror("dup2 stdin");
- close(pin[0]);
+ buffer_append(&command, "\0", 1);
+
+ /* Get the final command string. */
+ command_string = buffer_ptr(&command);
+
+ /* Create pipes for communicating with the proxy. */
+ if (pipe(pin) < 0 || pipe(pout) < 0)
+ fatal("Could not create pipes to communicate with the proxy: %.100s",
+ strerror(errno));
+
+ debug("Executing proxy command: %.500s", command_string);
+
+ /* Fork and execute the proxy command. */
+ if ((pid = fork()) == 0) {
+ char *argv[10];
+
+ /* Child. Permanently give up superuser privileges. */
+ permanently_set_uid(original_real_uid);
+
+ /* Redirect stdin and stdout. */
+ close(pin[1]);
+ if (pin[0] != 0) {
+ if (dup2(pin[0], 0) < 0)
+ perror("dup2 stdin");
+ close(pin[0]);
+ }
+ close(pout[0]);
+ if (dup2(pout[1], 1) < 0)
+ perror("dup2 stdout");
+ /* Cannot be 1 because pin allocated two descriptors. */
+ close(pout[1]);
+
+ /* Stderr is left as it is so that error messages get
+ printed on the user's terminal. */
+ argv[0] = "/bin/sh";
+ argv[1] = "-c";
+ argv[2] = command_string;
+ argv[3] = NULL;
+
+ /* Execute the proxy command. Note that we gave up any
+ extra privileges above. */
+ execv("/bin/sh", argv);
+ perror("/bin/sh");
+ exit(1);
}
- close(pout[0]);
- if (dup2(pout[1], 1) < 0)
- perror("dup2 stdout");
- close(pout[1]); /* Cannot be 1 because pin allocated two descriptors. */
-
- /* Stderr is left as it is so that error messages get printed on
- the user's terminal. */
- argv[0] = "/bin/sh";
- argv[1] = "-c";
- argv[2] = command_string;
- argv[3] = NULL;
-
- /* Execute the proxy command. Note that we gave up any extra
- privileges above. */
- execv("/bin/sh", argv);
- perror("/bin/sh");
- exit(1);
- }
- /* Parent. */
- if (pid < 0)
- fatal("fork failed: %.100s", strerror(errno));
-
- /* Close child side of the descriptors. */
- close(pin[0]);
- close(pout[1]);
-
- /* Free the command name. */
- buffer_free(&command);
-
- /* Set the connection file descriptors. */
- packet_set_connection(pout[0], pin[1]);
-
- return 1;
-}
+ /* Parent. */
+ if (pid < 0)
+ fatal("fork failed: %.100s", strerror(errno));
+
+ /* Close child side of the descriptors. */
+ close(pin[0]);
+ close(pout[1]);
+
+ /* Free the command name. */
+ buffer_free(&command);
+
+ /* Set the connection file descriptors. */
+ packet_set_connection(pout[0], pin[1]);
-/* Creates a (possibly privileged) socket for use as the ssh connection. */
+ return 1;
+}
-int ssh_create_socket(uid_t original_real_uid, int privileged)
+/*
+ * Creates a (possibly privileged) socket for use as the ssh connection.
+ */
+int
+ssh_create_socket(uid_t original_real_uid, int privileged)
{
- int sock;
-
- /* If we are running as root and want to connect to a privileged port,
- bind our own socket to a privileged port. */
- if (privileged)
- {
- int p = IPPORT_RESERVED - 1;
-
- sock = rresvport(&p);
- if (sock < 0)
- fatal("rresvport: %.100s", strerror(errno));
- debug("Allocated local port %d.", p);
- }
- else
- {
- /* Just create an ordinary socket on arbitrary port. We use the
- user's uid to create the socket. */
- temporarily_use_uid(original_real_uid);
- sock = socket(AF_INET, SOCK_STREAM, 0);
- if (sock < 0)
- fatal("socket: %.100s", strerror(errno));
- restore_uid();
- }
- return sock;
+ int sock;
+
+ /* If we are running as root and want to connect to a privileged
+ port, bind our own socket to a privileged port. */
+ if (privileged) {
+ int p = IPPORT_RESERVED - 1;
+
+ sock = rresvport(&p);
+ if (sock < 0)
+ fatal("rresvport: %.100s", strerror(errno));
+ debug("Allocated local port %d.", p);
+ } else {
+ /* Just create an ordinary socket on arbitrary port. We
+ use the user's uid to create the socket. */
+ temporarily_use_uid(original_real_uid);
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0)
+ fatal("socket: %.100s", strerror(errno));
+ restore_uid();
+ }
+ return sock;
}
-/* Opens a TCP/IP connection to the remote server on the given host. If
- port is 0, the default port will be used. If anonymous is zero,
- a privileged port will be allocated to make the connection.
- This requires super-user privileges if anonymous is false.
- Connection_attempts specifies the maximum number of tries (one per
- second). If proxy_command is non-NULL, it specifies the command (with %h
- and %p substituted for host and port, respectively) to use to contact
- the daemon. */
-
-int ssh_connect(const char *host, struct sockaddr_in *hostaddr,
- int port, int connection_attempts,
- int anonymous, uid_t original_real_uid,
- const char *proxy_command)
+/*
+ * Opens a TCP/IP connection to the remote server on the given host. If
+ * port is 0, the default port will be used. If anonymous is zero,
+ * a privileged port will be allocated to make the connection.
+ * This requires super-user privileges if anonymous is false.
+ * Connection_attempts specifies the maximum number of tries (one per
+ * second). If proxy_command is non-NULL, it specifies the command (with %h
+ * and %p substituted for host and port, respectively) to use to contact
+ * the daemon.
+ */
+int
+ssh_connect(const char *host, struct sockaddr_in * hostaddr,
+ int port, int connection_attempts,
+ int anonymous, uid_t original_real_uid,
+ const char *proxy_command)
{
- int sock = -1, attempt, i;
- int on = 1;
- struct servent *sp;
- struct hostent *hp;
- struct linger linger;
-
- debug("ssh_connect: getuid %d geteuid %d anon %d",
- (int)getuid(), (int)geteuid(), anonymous);
-
- /* Get default port if port has not been set. */
- if (port == 0)
- {
- sp = getservbyname(SSH_SERVICE_NAME, "tcp");
- if (sp)
- port = ntohs(sp->s_port);
- else
- port = SSH_DEFAULT_PORT;
- }
-
- /* If a proxy command is given, connect using it. */
- if (proxy_command != NULL)
- return ssh_proxy_connect(host, port, original_real_uid, proxy_command);
-
- /* No proxy command. */
-
- /* No host lookup made yet. */
- hp = NULL;
-
- /* Try to connect several times. On some machines, the first time will
- sometimes fail. In general socket code appears to behave quite
- magically on many machines. */
- for (attempt = 0; attempt < connection_attempts; attempt++)
- {
- if (attempt > 0)
- debug("Trying again...");
-
- /* Try to parse the host name as a numeric inet address. */
- memset(hostaddr, 0, sizeof(hostaddr));
- hostaddr->sin_family = AF_INET;
- hostaddr->sin_port = htons(port);
- hostaddr->sin_addr.s_addr = inet_addr(host);
- if ((hostaddr->sin_addr.s_addr & 0xffffffff) != 0xffffffff)
- {
- /* Valid numeric IP address */
- debug("Connecting to %.100s port %d.",
- inet_ntoa(hostaddr->sin_addr), port);
-
- /* Create a socket. */
- sock = ssh_create_socket(original_real_uid,
- !anonymous && geteuid() == 0 &&
- port < IPPORT_RESERVED);
-
- /* Connect to the host. We use the user's uid in the hope that
- it will help with the problems of tcp_wrappers showing the
- remote uid as root. */
- temporarily_use_uid(original_real_uid);
- if (connect(sock, (struct sockaddr *)hostaddr, sizeof(*hostaddr))
- >= 0)
- {
- /* Successful connect. */
- restore_uid();
- break;
- }
- debug("connect: %.100s", strerror(errno));
- restore_uid();
-
- /* Destroy the failed socket. */
- shutdown(sock, SHUT_RDWR);
- close(sock);
+ int sock = -1, attempt, i;
+ int on = 1;
+ struct servent *sp;
+ struct hostent *hp;
+ struct linger linger;
+
+ debug("ssh_connect: getuid %d geteuid %d anon %d",
+ (int) getuid(), (int) geteuid(), anonymous);
+
+ /* Get default port if port has not been set. */
+ if (port == 0) {
+ sp = getservbyname(SSH_SERVICE_NAME, "tcp");
+ if (sp)
+ port = ntohs(sp->s_port);
+ else
+ port = SSH_DEFAULT_PORT;
}
- else
- {
- /* Not a valid numeric inet address. */
- /* Map host name to an address. */
- if (!hp)
- hp = gethostbyname(host);
- if (!hp)
- fatal("Bad host name: %.100s", host);
- if (!hp->h_addr_list[0])
- fatal("Host does not have an IP address: %.100s", host);
-
- /* Loop through addresses for this host, and try each one in
- sequence until the connection succeeds. */
- for (i = 0; hp->h_addr_list[i]; i++)
- {
- /* Set the address to connect to. */
- hostaddr->sin_family = hp->h_addrtype;
- memcpy(&hostaddr->sin_addr, hp->h_addr_list[i],
- sizeof(hostaddr->sin_addr));
-
- debug("Connecting to %.200s [%.100s] port %d.",
- host, inet_ntoa(hostaddr->sin_addr), port);
-
- /* Create a socket for connecting. */
- sock = ssh_create_socket(original_real_uid,
- !anonymous && geteuid() == 0 &&
- port < IPPORT_RESERVED);
-
- /* Connect to the host. We use the user's uid in the hope that
- it will help with tcp_wrappers showing the remote uid as
- root. */
- temporarily_use_uid(original_real_uid);
- if (connect(sock, (struct sockaddr *)hostaddr,
- sizeof(*hostaddr)) >= 0)
- {
- /* Successful connection. */
- restore_uid();
- break;
+ /* If a proxy command is given, connect using it. */
+ if (proxy_command != NULL)
+ return ssh_proxy_connect(host, port, original_real_uid, proxy_command);
+
+ /* No proxy command. */
+
+ /* No host lookup made yet. */
+ hp = NULL;
+
+ /* Try to connect several times. On some machines, the first time
+ will sometimes fail. In general socket code appears to behave
+ quite magically on many machines. */
+ for (attempt = 0; attempt < connection_attempts; attempt++) {
+ if (attempt > 0)
+ debug("Trying again...");
+
+ /* Try to parse the host name as a numeric inet address. */
+ memset(hostaddr, 0, sizeof(hostaddr));
+ hostaddr->sin_family = AF_INET;
+ hostaddr->sin_port = htons(port);
+ hostaddr->sin_addr.s_addr = inet_addr(host);
+ if ((hostaddr->sin_addr.s_addr & 0xffffffff) != 0xffffffff) {
+ /* Valid numeric IP address */
+ debug("Connecting to %.100s port %d.",
+ inet_ntoa(hostaddr->sin_addr), port);
+
+ /* Create a socket. */
+ sock = ssh_create_socket(original_real_uid,
+ !anonymous && geteuid() == 0 &&
+ port < IPPORT_RESERVED);
+
+ /* Connect to the host. We use the user's uid in
+ the hope that it will help with the problems of
+ tcp_wrappers showing the remote uid as root. */
+ temporarily_use_uid(original_real_uid);
+ if (connect(sock, (struct sockaddr *) hostaddr, sizeof(*hostaddr))
+ >= 0) {
+ /* Successful connect. */
+ restore_uid();
+ break;
+ }
+ debug("connect: %.100s", strerror(errno));
+ restore_uid();
+
+ /* Destroy the failed socket. */
+ shutdown(sock, SHUT_RDWR);
+ close(sock);
+ } else {
+ /* Not a valid numeric inet address. */
+ /* Map host name to an address. */
+ if (!hp)
+ hp = gethostbyname(host);
+ if (!hp)
+ fatal("Bad host name: %.100s", host);
+ if (!hp->h_addr_list[0])
+ fatal("Host does not have an IP address: %.100s", host);
+
+ /* Loop through addresses for this host, and try
+ each one in sequence until the connection
+ succeeds. */
+ for (i = 0; hp->h_addr_list[i]; i++) {
+ /* Set the address to connect to. */
+ hostaddr->sin_family = hp->h_addrtype;
+ memcpy(&hostaddr->sin_addr, hp->h_addr_list[i],
+ sizeof(hostaddr->sin_addr));
+
+ debug("Connecting to %.200s [%.100s] port %d.",
+ host, inet_ntoa(hostaddr->sin_addr), port);
+
+ /* Create a socket for connecting. */
+ sock = ssh_create_socket(original_real_uid,
+ !anonymous && geteuid() == 0 &&
+ port < IPPORT_RESERVED);
+
+ /* Connect to the host. We use the user's uid in the hope that
+ it will help with tcp_wrappers showing the remote uid as root. */
+ temporarily_use_uid(original_real_uid);
+ if (connect(sock, (struct sockaddr *) hostaddr,
+ sizeof(*hostaddr)) >= 0) {
+ /* Successful connection. */
+ restore_uid();
+ break;
+ }
+ debug("connect: %.100s", strerror(errno));
+ restore_uid();
+
+ /* Close the failed socket; there appear to be some problems when
+ reusing a socket for which connect() has already returned an error. */
+ shutdown(sock, SHUT_RDWR);
+ close(sock);
+ }
+ if (hp->h_addr_list[i])
+ break; /* Successful connection. */
}
- debug("connect: %.100s", strerror(errno));
- restore_uid();
-
- /* Close the failed socket; there appear to be some problems
- when reusing a socket for which connect() has already
- returned an error. */
- shutdown(sock, SHUT_RDWR);
- close(sock);
- }
- if (hp->h_addr_list[i])
- break; /* Successful connection. */
- }
- /* Sleep a moment before retrying. */
- sleep(1);
- }
- /* Return failure if we didn't get a successful connection. */
- if (attempt >= connection_attempts)
- return 0;
+ /* Sleep a moment before retrying. */
+ sleep(1);
+ }
+ /* Return failure if we didn't get a successful connection. */
+ if (attempt >= connection_attempts)
+ return 0;
- debug("Connection established.");
+ debug("Connection established.");
- /* Set socket options. We would like the socket to disappear as soon as
- it has been closed for whatever reason. */
- /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
- setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(on));
- linger.l_onoff = 1;
- linger.l_linger = 5;
- setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
+ /* Set socket options. We would like the socket to disappear as
+ soon as it has been closed for whatever reason. */
+ /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
+ sizeof(on)); */
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on));
+ linger.l_onoff = 1;
+ linger.l_linger = 5;
+ setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
- /* Set the connection. */
- packet_set_connection(sock, sock);
+ /* Set the connection. */
+ packet_set_connection(sock, sock);
- return 1;
+ return 1;
}
-/* Checks if the user has an authentication agent, and if so, tries to
- authenticate using the agent. */
-
+/*
+ * Checks if the user has an authentication agent, and if so, tries to
+ * authenticate using the agent.
+ */
int
try_agent_authentication()
{
- int status, type;
- char *comment;
- AuthenticationConnection *auth;
- unsigned char response[16];
- unsigned int i;
- BIGNUM *e, *n, *challenge;
-
- /* Get connection to the agent. */
- auth = ssh_get_authentication_connection();
- if (!auth)
- return 0;
-
- e = BN_new();
- n = BN_new();
- challenge = BN_new();
-
- /* Loop through identities served by the agent. */
- for (status = ssh_get_first_identity(auth, e, n, &comment);
- status;
- status = ssh_get_next_identity(auth, e, n, &comment))
- {
- int plen, clen;
-
- /* Try this identity. */
- debug("Trying RSA authentication via agent with '%.100s'", comment);
- xfree(comment);
-
- /* Tell the server that we are willing to authenticate using this key. */
- packet_start(SSH_CMSG_AUTH_RSA);
- packet_put_bignum(n);
- packet_send();
- packet_write_wait();
-
- /* Wait for server's response. */
- type = packet_read(&plen);
-
- /* The server sends failure if it doesn\'t like our key or does not
- support RSA authentication. */
- if (type == SSH_SMSG_FAILURE)
- {
- debug("Server refused our key.");
- continue;
- }
-
- /* Otherwise it should have sent a challenge. */
- if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
- packet_disconnect("Protocol error during RSA authentication: %d",
- type);
-
- packet_get_bignum(challenge, &clen);
-
- packet_integrity_check(plen, clen, type);
-
- debug("Received RSA challenge from server.");
-
- /* Ask the agent to decrypt the challenge. */
- if (!ssh_decrypt_challenge(auth, e, n, challenge,
- session_id, 1, response))
- {
- /* The agent failed to authenticate this identifier although it
- advertised it supports this. Just return a wrong value. */
- log("Authentication agent failed to decrypt challenge.");
- memset(response, 0, sizeof(response));
- }
-
- debug("Sending response to RSA challenge.");
-
- /* Send the decrypted challenge back to the server. */
- packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
- for (i = 0; i < 16; i++)
- packet_put_char(response[i]);
- packet_send();
- packet_write_wait();
-
- /* Wait for response from the server. */
- type = packet_read(&plen);
-
- /* The server returns success if it accepted the authentication. */
- if (type == SSH_SMSG_SUCCESS)
- {
- debug("RSA authentication accepted by server.");
- BN_clear_free(e);
- BN_clear_free(n);
- BN_clear_free(challenge);
- return 1;
- }
+ int status, type;
+ char *comment;
+ AuthenticationConnection *auth;
+ unsigned char response[16];
+ unsigned int i;
+ BIGNUM *e, *n, *challenge;
+
+ /* Get connection to the agent. */
+ auth = ssh_get_authentication_connection();
+ if (!auth)
+ return 0;
+
+ e = BN_new();
+ n = BN_new();
+ challenge = BN_new();
+
+ /* Loop through identities served by the agent. */
+ for (status = ssh_get_first_identity(auth, e, n, &comment);
+ status;
+ status = ssh_get_next_identity(auth, e, n, &comment)) {
+ int plen, clen;
+
+ /* Try this identity. */
+ debug("Trying RSA authentication via agent with '%.100s'", comment);
+ xfree(comment);
+
+ /* Tell the server that we are willing to authenticate using this key. */
+ packet_start(SSH_CMSG_AUTH_RSA);
+ packet_put_bignum(n);
+ packet_send();
+ packet_write_wait();
+
+ /* Wait for server's response. */
+ type = packet_read(&plen);
+
+ /* The server sends failure if it doesn\'t like our key or
+ does not support RSA authentication. */
+ if (type == SSH_SMSG_FAILURE) {
+ debug("Server refused our key.");
+ continue;
+ }
+ /* Otherwise it should have sent a challenge. */
+ if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
+ packet_disconnect("Protocol error during RSA authentication: %d",
+ type);
- /* Otherwise it should return failure. */
- if (type != SSH_SMSG_FAILURE)
- packet_disconnect("Protocol error waiting RSA auth response: %d",
- type);
- }
+ packet_get_bignum(challenge, &clen);
- BN_clear_free(e);
- BN_clear_free(n);
- BN_clear_free(challenge);
+ packet_integrity_check(plen, clen, type);
- debug("RSA authentication using agent refused.");
- return 0;
-}
+ debug("Received RSA challenge from server.");
+
+ /* Ask the agent to decrypt the challenge. */
+ if (!ssh_decrypt_challenge(auth, e, n, challenge,
+ session_id, 1, response)) {
+ /* The agent failed to authenticate this identifier although it
+ advertised it supports this. Just return a wrong value. */
+ log("Authentication agent failed to decrypt challenge.");
+ memset(response, 0, sizeof(response));
+ }
+ debug("Sending response to RSA challenge.");
+
+ /* Send the decrypted challenge back to the server. */
+ packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
+ for (i = 0; i < 16; i++)
+ packet_put_char(response[i]);
+ packet_send();
+ packet_write_wait();
+
+ /* Wait for response from the server. */
+ type = packet_read(&plen);
+
+ /* The server returns success if it accepted the authentication. */
+ if (type == SSH_SMSG_SUCCESS) {
+ debug("RSA authentication accepted by server.");
+ BN_clear_free(e);
+ BN_clear_free(n);
+ BN_clear_free(challenge);
+ return 1;
+ }
+ /* Otherwise it should return failure. */
+ if (type != SSH_SMSG_FAILURE)
+ packet_disconnect("Protocol error waiting RSA auth response: %d",
+ type);
+ }
+
+ BN_clear_free(e);
+ BN_clear_free(n);
+ BN_clear_free(challenge);
-/* Computes the proper response to a RSA challenge, and sends the response to
- the server. */
+ debug("RSA authentication using agent refused.");
+ return 0;
+}
+/*
+ * Computes the proper response to a RSA challenge, and sends the response to
+ * the server.
+ */
void
-respond_to_rsa_challenge(BIGNUM *challenge, RSA *prv)
+respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv)
{
- unsigned char buf[32], response[16];
- MD5_CTX md;
- int i, len;
-
- /* Decrypt the challenge using the private key. */
- rsa_private_decrypt(challenge, challenge, prv);
-
- /* Compute the response. */
- /* The response is MD5 of decrypted challenge plus session id. */
- len = BN_num_bytes(challenge);
- if (len <= 0 || len > sizeof(buf))
- packet_disconnect("respond_to_rsa_challenge: bad challenge length %d",
- len);
-
- memset(buf, 0, sizeof(buf));
- BN_bn2bin(challenge, buf + sizeof(buf) - len);
- MD5_Init(&md);
- MD5_Update(&md, buf, 32);
- MD5_Update(&md, session_id, 16);
- MD5_Final(response, &md);
-
- debug("Sending response to host key RSA challenge.");
-
- /* Send the response back to the server. */
- packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
- for (i = 0; i < 16; i++)
- packet_put_char(response[i]);
- packet_send();
- packet_write_wait();
-
- memset(buf, 0, sizeof(buf));
- memset(response, 0, sizeof(response));
- memset(&md, 0, sizeof(md));
-}
+ unsigned char buf[32], response[16];
+ MD5_CTX md;
+ int i, len;
+
+ /* Decrypt the challenge using the private key. */
+ rsa_private_decrypt(challenge, challenge, prv);
+
+ /* Compute the response. */
+ /* The response is MD5 of decrypted challenge plus session id. */
+ len = BN_num_bytes(challenge);
+ if (len <= 0 || len > sizeof(buf))
+ packet_disconnect("respond_to_rsa_challenge: bad challenge length %d",
+ len);
+
+ memset(buf, 0, sizeof(buf));
+ BN_bn2bin(challenge, buf + sizeof(buf) - len);
+ MD5_Init(&md);
+ MD5_Update(&md, buf, 32);
+ MD5_Update(&md, session_id, 16);
+ MD5_Final(response, &md);
+
+ debug("Sending response to host key RSA challenge.");
+
+ /* Send the response back to the server. */
+ packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
+ for (i = 0; i < 16; i++)
+ packet_put_char(response[i]);
+ packet_send();
+ packet_write_wait();
-/* Checks if the user has authentication file, and if so, tries to authenticate
- the user using it. */
+ memset(buf, 0, sizeof(buf));
+ memset(response, 0, sizeof(response));
+ memset(&md, 0, sizeof(md));
+}
+/*
+ * Checks if the user has authentication file, and if so, tries to authenticate
+ * the user using it.
+ */
int
-try_rsa_authentication(struct passwd *pw, const char *authfile)
+try_rsa_authentication(struct passwd * pw, const char *authfile)
{
- extern Options options;
- BIGNUM *challenge;
- RSA *private_key;
- RSA *public_key;
- char *passphrase, *comment;
- int type, i;
- int plen, clen;
-
- /* Try to load identification for the authentication key. */
- public_key = RSA_new();
- if (!load_public_key(authfile, public_key, &comment)) {
- RSA_free(public_key);
- return 0; /* Could not load it. Fail. */
- }
-
- debug("Trying RSA authentication with key '%.100s'", comment);
-
- /* Tell the server that we are willing to authenticate using this key. */
- packet_start(SSH_CMSG_AUTH_RSA);
- packet_put_bignum(public_key->n);
- packet_send();
- packet_write_wait();
-
- /* We no longer need the public key. */
- RSA_free(public_key);
-
- /* Wait for server's response. */
- type = packet_read(&plen);
-
- /* The server responds with failure if it doesn\'t like our key or doesn\'t
- support RSA authentication. */
- if (type == SSH_SMSG_FAILURE)
- {
- debug("Server refused our key.");
- xfree(comment);
- return 0; /* Server refuses to authenticate with this key. */
- }
-
- /* Otherwise, the server should respond with a challenge. */
- if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
- packet_disconnect("Protocol error during RSA authentication: %d", type);
-
- /* Get the challenge from the packet. */
- challenge = BN_new();
- packet_get_bignum(challenge, &clen);
-
- packet_integrity_check(plen, clen, type);
-
- debug("Received RSA challenge from server.");
-
- private_key = RSA_new();
- /* Load the private key. Try first with empty passphrase; if it fails,
- ask for a passphrase. */
- if (!load_private_key(authfile, "", private_key, NULL))
- {
- char buf[300];
- /* Request passphrase from the user. We read from /dev/tty to make
- this work even if stdin has been redirected. If running in
- batch mode, we just use the empty passphrase, which will fail and
- return. */
- snprintf(buf, sizeof buf,
- "Enter passphrase for RSA key '%.100s': ", comment);
- if (!options.batch_mode)
- passphrase = read_passphrase(buf, 0);
- else
- {
- debug("Will not query passphrase for %.100s in batch mode.",
- comment);
- passphrase = xstrdup("");
+ extern Options options;
+ BIGNUM *challenge;
+ RSA *private_key;
+ RSA *public_key;
+ char *passphrase, *comment;
+ int type, i;
+ int plen, clen;
+
+ /* Try to load identification for the authentication key. */
+ public_key = RSA_new();
+ if (!load_public_key(authfile, public_key, &comment)) {
+ RSA_free(public_key);
+ return 0; /* Could not load it. Fail. */
}
-
- /* Load the authentication file using the pasphrase. */
- if (!load_private_key(authfile, passphrase, private_key, NULL))
- {
- memset(passphrase, 0, strlen(passphrase));
- xfree(passphrase);
- error("Bad passphrase.");
-
- /* Send a dummy response packet to avoid protocol error. */
- packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
- for (i = 0; i < 16; i++)
- packet_put_char(0);
- packet_send();
- packet_write_wait();
-
- /* Expect the server to reject it... */
- packet_read_expect(&plen, SSH_SMSG_FAILURE);
- xfree(comment);
- return 0;
+ debug("Trying RSA authentication with key '%.100s'", comment);
+
+ /* Tell the server that we are willing to authenticate using this key. */
+ packet_start(SSH_CMSG_AUTH_RSA);
+ packet_put_bignum(public_key->n);
+ packet_send();
+ packet_write_wait();
+
+ /* We no longer need the public key. */
+ RSA_free(public_key);
+
+ /* Wait for server's response. */
+ type = packet_read(&plen);
+
+ /* The server responds with failure if it doesn\'t like our key or
+ doesn\'t support RSA authentication. */
+ if (type == SSH_SMSG_FAILURE) {
+ debug("Server refused our key.");
+ xfree(comment);
+ return 0; /* Server refuses to authenticate with
+ this key. */
}
+ /* Otherwise, the server should respond with a challenge. */
+ if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
+ packet_disconnect("Protocol error during RSA authentication: %d", type);
+
+ /* Get the challenge from the packet. */
+ challenge = BN_new();
+ packet_get_bignum(challenge, &clen);
+
+ packet_integrity_check(plen, clen, type);
+
+ debug("Received RSA challenge from server.");
+
+ private_key = RSA_new();
+ /* Load the private key. Try first with empty passphrase; if it
+ fails, ask for a passphrase. */
+ if (!load_private_key(authfile, "", private_key, NULL)) {
+ char buf[300];
+ snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
+ comment);
+ if (!options.batch_mode)
+ passphrase = read_passphrase(buf, 0);
+ else {
+ debug("Will not query passphrase for %.100s in batch mode.",
+ comment);
+ passphrase = xstrdup("");
+ }
- /* Destroy the passphrase. */
- memset(passphrase, 0, strlen(passphrase));
- xfree(passphrase);
- }
-
- /* We no longer need the comment. */
- xfree(comment);
-
- /* Compute and send a response to the challenge. */
- respond_to_rsa_challenge(challenge, private_key);
-
- /* Destroy the private key. */
- RSA_free(private_key);
-
- /* We no longer need the challenge. */