/*
* 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.108 2001/06/23 02:34:31 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;
/* AF_UNSPEC or AF_INET or AF_INET6 */
extern int IPv4or6;
/*
* Connect to the given ssh server using a proxy command.
*/
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[0], pin[1]);
return 1;
}
/*
* Creates a (possibly privileged) socket for use as the ssh connection.
*/
int
ssh_create_socket(struct passwd *pw, int privileged, int family)
{
int sock, gaierr;
struct addrinfo hints, *res;
/*
* 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_af(&p, family);
if (sock < 0)
error("rresvport: af=%d %.100s", family, strerror(errno));
else
debug("Allocated local port %d.", p);
return sock;
}
/*
* Just create an ordinary socket on arbitrary port. We use
* the user's uid to create the socket.
*/
temporarily_use_uid(pw);
sock = socket(family, SOCK_STREAM,