/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Code to connect to a remote host, and to perform the client side of the
* login (authentication) dialog.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#include "includes.h"
RCSID("$OpenBSD: sshconnect.c,v 1.115 2001/10/08 19:05:05 markus Exp $");
#include <openssl/bn.h>
#include "ssh.h"
#include "xmalloc.h"
#include "rsa.h"
#include "buffer.h"
#include "packet.h"
#include "uidswap.h"
#include "compat.h"
#include "key.h"
#include "sshconnect.h"
#include "hostfile.h"
#include "log.h"
#include "readconf.h"
#include "atomicio.h"
#include "misc.h"
char *client_version_string = NULL;
char *server_version_string = NULL;
extern Options options;
extern char *__progname;
#ifndef INET6_ADDRSTRLEN /* for non IPv6 machines */
#define INET6_ADDRSTRLEN 46
#endif
static const char *
sockaddr_ntop(struct sockaddr *sa)
{
void *addr;
static char addrbuf[INET6_ADDRSTRLEN];
switch (sa->sa_family) {
case AF_INET:
addr = &((struct sockaddr_in *)sa)->sin_addr;
break;
case AF_INET6:
addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
break;
default:
/* This case should be protected against elsewhere */
abort();
}
inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
return addrbuf;
}
/*
* Connect to the given ssh server using a proxy command.
*/
static int
ssh_proxy_connect(const char *host, u_short port, struct passwd *pw,
const char *proxy_command)
{
Buffer command;
const char *cp;
char *command_string;
int pin[2], pout[2];
pid_t pid;
char strport[NI_MAXSERV];
/* Convert the port number into a string. */
snprintf(strport, sizeof strport, "%hu", 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, strport, strlen(strport));
cp++;
continue;
}
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(pw);
/* 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] = _PATH_BSHELL;
argv[1] = "-c";
argv[2] = command_string;
argv[3] = NULL;
/* Execute the proxy command. Note that we gave up any
extra privileges above. */
execv(argv[0], argv);
perror(argv[0]);
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