19768ca48f57aaf035f508a473421d210b5145e99Greg Hartman/* $OpenBSD: sshconnect.c,v 1.273 2017/03/10 03:22:40 dtucker Exp $ */ 2bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* 3bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Author: Tatu Ylonen <ylo@cs.hut.fi> 4bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * All rights reserved 6bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Code to connect to a remote host, and to perform the client side of the 7bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * login (authentication) dialog. 8bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 9bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * As far as I am concerned, the code I have written for this software 10bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * can be used freely for any purpose. Any derived versions of this 11bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * software must be clearly marked as such, and if the derived work is 12bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * incompatible with the protocol description in the RFC file, it must be 13bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * called by a name other than "ssh" or "Secure Shell". 14bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 15bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 16bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "includes.h" 17bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 18bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/types.h> 19bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/wait.h> 20bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/stat.h> 21bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/socket.h> 22bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef HAVE_SYS_TIME_H 23bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# include <sys/time.h> 24bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif 25bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 26bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <netinet/in.h> 27bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <arpa/inet.h> 28bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 29bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <ctype.h> 30bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <errno.h> 31bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <fcntl.h> 32bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <netdb.h> 33bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef HAVE_PATHS_H 34bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <paths.h> 35bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif 36bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <pwd.h> 37bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <signal.h> 38bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdarg.h> 39bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdio.h> 40bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdlib.h> 41bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <string.h> 42bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <unistd.h> 43bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 44bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "xmalloc.h" 45bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "key.h" 46bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "hostfile.h" 47bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "ssh.h" 48bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "rsa.h" 49bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "buffer.h" 50bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "packet.h" 51bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "uidswap.h" 52bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "compat.h" 53bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "key.h" 54bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "sshconnect.h" 55bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "hostfile.h" 56bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "log.h" 57d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "misc.h" 58bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "readconf.h" 59bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "atomicio.h" 60bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "dns.h" 61d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "monitor_fdpass.h" 62bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "ssh2.h" 63bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "version.h" 64d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "authfile.h" 65d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "ssherr.h" 669768ca48f57aaf035f508a473421d210b5145e99Greg Hartman#include "authfd.h" 67bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 68bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanchar *client_version_string = NULL; 69bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanchar *server_version_string = NULL; 70d059297112922cabb0c674840589be8db821fd9aAdam LangleyKey *previous_host_key = NULL; 71bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 72bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int matching_host_key_dns = 0; 73bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 74bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic pid_t proxy_command_pid = 0; 75bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 76bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* import */ 77bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanextern Options options; 78bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanextern char *__progname; 79bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanextern uid_t original_real_uid; 80bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanextern uid_t original_effective_uid; 81bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 82bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int show_other_keys(struct hostkeys *, Key *); 83bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void warn_changed_key(Key *); 84bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 85d059297112922cabb0c674840589be8db821fd9aAdam Langley/* Expand a proxy command */ 86d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic char * 87d059297112922cabb0c674840589be8db821fd9aAdam Langleyexpand_proxy_command(const char *proxy_command, const char *user, 88d059297112922cabb0c674840589be8db821fd9aAdam Langley const char *host, int port) 89d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 90d059297112922cabb0c674840589be8db821fd9aAdam Langley char *tmp, *ret, strport[NI_MAXSERV]; 91d059297112922cabb0c674840589be8db821fd9aAdam Langley 92d059297112922cabb0c674840589be8db821fd9aAdam Langley snprintf(strport, sizeof strport, "%d", port); 93d059297112922cabb0c674840589be8db821fd9aAdam Langley xasprintf(&tmp, "exec %s", proxy_command); 94d059297112922cabb0c674840589be8db821fd9aAdam Langley ret = percent_expand(tmp, "h", host, "p", strport, 95d059297112922cabb0c674840589be8db821fd9aAdam Langley "r", options.user, (char *)NULL); 96d059297112922cabb0c674840589be8db821fd9aAdam Langley free(tmp); 97d059297112922cabb0c674840589be8db821fd9aAdam Langley return ret; 98d059297112922cabb0c674840589be8db821fd9aAdam Langley} 99d059297112922cabb0c674840589be8db821fd9aAdam Langley 100d059297112922cabb0c674840589be8db821fd9aAdam Langley/* 101d059297112922cabb0c674840589be8db821fd9aAdam Langley * Connect to the given ssh server using a proxy command that passes a 102d059297112922cabb0c674840589be8db821fd9aAdam Langley * a connected fd back to us. 103d059297112922cabb0c674840589be8db821fd9aAdam Langley */ 104d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 105d059297112922cabb0c674840589be8db821fd9aAdam Langleyssh_proxy_fdpass_connect(const char *host, u_short port, 106d059297112922cabb0c674840589be8db821fd9aAdam Langley const char *proxy_command) 107d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 108d059297112922cabb0c674840589be8db821fd9aAdam Langley char *command_string; 109d059297112922cabb0c674840589be8db821fd9aAdam Langley int sp[2], sock; 110d059297112922cabb0c674840589be8db821fd9aAdam Langley pid_t pid; 111d059297112922cabb0c674840589be8db821fd9aAdam Langley char *shell; 112d059297112922cabb0c674840589be8db821fd9aAdam Langley 113d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((shell = getenv("SHELL")) == NULL) 114d059297112922cabb0c674840589be8db821fd9aAdam Langley shell = _PATH_BSHELL; 115d059297112922cabb0c674840589be8db821fd9aAdam Langley 116d059297112922cabb0c674840589be8db821fd9aAdam Langley if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) < 0) 117d059297112922cabb0c674840589be8db821fd9aAdam Langley fatal("Could not create socketpair to communicate with " 118d059297112922cabb0c674840589be8db821fd9aAdam Langley "proxy dialer: %.100s", strerror(errno)); 119d059297112922cabb0c674840589be8db821fd9aAdam Langley 120d059297112922cabb0c674840589be8db821fd9aAdam Langley command_string = expand_proxy_command(proxy_command, options.user, 121d059297112922cabb0c674840589be8db821fd9aAdam Langley host, port); 122d059297112922cabb0c674840589be8db821fd9aAdam Langley debug("Executing proxy dialer command: %.500s", command_string); 123d059297112922cabb0c674840589be8db821fd9aAdam Langley 124d059297112922cabb0c674840589be8db821fd9aAdam Langley /* Fork and execute the proxy command. */ 125d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((pid = fork()) == 0) { 126d059297112922cabb0c674840589be8db821fd9aAdam Langley char *argv[10]; 127d059297112922cabb0c674840589be8db821fd9aAdam Langley 128d059297112922cabb0c674840589be8db821fd9aAdam Langley /* Child. Permanently give up superuser privileges. */ 129d059297112922cabb0c674840589be8db821fd9aAdam Langley permanently_drop_suid(original_real_uid); 130d059297112922cabb0c674840589be8db821fd9aAdam Langley 131d059297112922cabb0c674840589be8db821fd9aAdam Langley close(sp[1]); 132d059297112922cabb0c674840589be8db821fd9aAdam Langley /* Redirect stdin and stdout. */ 133d059297112922cabb0c674840589be8db821fd9aAdam Langley if (sp[0] != 0) { 134d059297112922cabb0c674840589be8db821fd9aAdam Langley if (dup2(sp[0], 0) < 0) 135d059297112922cabb0c674840589be8db821fd9aAdam Langley perror("dup2 stdin"); 136d059297112922cabb0c674840589be8db821fd9aAdam Langley } 137d059297112922cabb0c674840589be8db821fd9aAdam Langley if (sp[0] != 1) { 138d059297112922cabb0c674840589be8db821fd9aAdam Langley if (dup2(sp[0], 1) < 0) 139d059297112922cabb0c674840589be8db821fd9aAdam Langley perror("dup2 stdout"); 140d059297112922cabb0c674840589be8db821fd9aAdam Langley } 141d059297112922cabb0c674840589be8db821fd9aAdam Langley if (sp[0] >= 2) 142d059297112922cabb0c674840589be8db821fd9aAdam Langley close(sp[0]); 143d059297112922cabb0c674840589be8db821fd9aAdam Langley 144d059297112922cabb0c674840589be8db821fd9aAdam Langley /* 145d059297112922cabb0c674840589be8db821fd9aAdam Langley * Stderr is left as it is so that error messages get 146d059297112922cabb0c674840589be8db821fd9aAdam Langley * printed on the user's terminal. 147d059297112922cabb0c674840589be8db821fd9aAdam Langley */ 148d059297112922cabb0c674840589be8db821fd9aAdam Langley argv[0] = shell; 149d059297112922cabb0c674840589be8db821fd9aAdam Langley argv[1] = "-c"; 150d059297112922cabb0c674840589be8db821fd9aAdam Langley argv[2] = command_string; 151d059297112922cabb0c674840589be8db821fd9aAdam Langley argv[3] = NULL; 152d059297112922cabb0c674840589be8db821fd9aAdam Langley 153d059297112922cabb0c674840589be8db821fd9aAdam Langley /* 154d059297112922cabb0c674840589be8db821fd9aAdam Langley * Execute the proxy command. 155d059297112922cabb0c674840589be8db821fd9aAdam Langley * Note that we gave up any extra privileges above. 156d059297112922cabb0c674840589be8db821fd9aAdam Langley */ 157d059297112922cabb0c674840589be8db821fd9aAdam Langley execv(argv[0], argv); 158d059297112922cabb0c674840589be8db821fd9aAdam Langley perror(argv[0]); 159d059297112922cabb0c674840589be8db821fd9aAdam Langley exit(1); 160d059297112922cabb0c674840589be8db821fd9aAdam Langley } 161d059297112922cabb0c674840589be8db821fd9aAdam Langley /* Parent. */ 162d059297112922cabb0c674840589be8db821fd9aAdam Langley if (pid < 0) 163d059297112922cabb0c674840589be8db821fd9aAdam Langley fatal("fork failed: %.100s", strerror(errno)); 164d059297112922cabb0c674840589be8db821fd9aAdam Langley close(sp[0]); 165d059297112922cabb0c674840589be8db821fd9aAdam Langley free(command_string); 166d059297112922cabb0c674840589be8db821fd9aAdam Langley 167d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((sock = mm_receive_fd(sp[1])) == -1) 168d059297112922cabb0c674840589be8db821fd9aAdam Langley fatal("proxy dialer did not pass back a connection"); 1699768ca48f57aaf035f508a473421d210b5145e99Greg Hartman close(sp[1]); 170d059297112922cabb0c674840589be8db821fd9aAdam Langley 171d059297112922cabb0c674840589be8db821fd9aAdam Langley while (waitpid(pid, NULL, 0) == -1) 172d059297112922cabb0c674840589be8db821fd9aAdam Langley if (errno != EINTR) 173d059297112922cabb0c674840589be8db821fd9aAdam Langley fatal("Couldn't wait for child: %s", strerror(errno)); 174d059297112922cabb0c674840589be8db821fd9aAdam Langley 175d059297112922cabb0c674840589be8db821fd9aAdam Langley /* Set the connection file descriptors. */ 176d059297112922cabb0c674840589be8db821fd9aAdam Langley packet_set_connection(sock, sock); 177d059297112922cabb0c674840589be8db821fd9aAdam Langley 178d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; 179d059297112922cabb0c674840589be8db821fd9aAdam Langley} 180d059297112922cabb0c674840589be8db821fd9aAdam Langley 181bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* 182bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Connect to the given ssh server using a proxy command. 183bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 184bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int 185bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanssh_proxy_connect(const char *host, u_short port, const char *proxy_command) 186bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 187d059297112922cabb0c674840589be8db821fd9aAdam Langley char *command_string; 188bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int pin[2], pout[2]; 189bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman pid_t pid; 190d059297112922cabb0c674840589be8db821fd9aAdam Langley char *shell; 191bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 192bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if ((shell = getenv("SHELL")) == NULL || *shell == '\0') 193bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman shell = _PATH_BSHELL; 194bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 195bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Create pipes for communicating with the proxy. */ 196bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (pipe(pin) < 0 || pipe(pout) < 0) 197bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("Could not create pipes to communicate with the proxy: %.100s", 198bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman strerror(errno)); 199bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 200d059297112922cabb0c674840589be8db821fd9aAdam Langley command_string = expand_proxy_command(proxy_command, options.user, 201d059297112922cabb0c674840589be8db821fd9aAdam Langley host, port); 202bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("Executing proxy command: %.500s", command_string); 203bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 204bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Fork and execute the proxy command. */ 205bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if ((pid = fork()) == 0) { 206bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *argv[10]; 207bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 208bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Child. Permanently give up superuser privileges. */ 209bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman permanently_drop_suid(original_real_uid); 210bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 211bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Redirect stdin and stdout. */ 212bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman close(pin[1]); 213bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (pin[0] != 0) { 214bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (dup2(pin[0], 0) < 0) 215bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman perror("dup2 stdin"); 216bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman close(pin[0]); 217bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 218bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman close(pout[0]); 219bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (dup2(pout[1], 1) < 0) 220bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman perror("dup2 stdout"); 221bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Cannot be 1 because pin allocated two descriptors. */ 222bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman close(pout[1]); 223bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 224bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Stderr is left as it is so that error messages get 225bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman printed on the user's terminal. */ 226bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman argv[0] = shell; 227bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman argv[1] = "-c"; 228bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman argv[2] = command_string; 229bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman argv[3] = NULL; 230bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 231bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Execute the proxy command. Note that we gave up any 232bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman extra privileges above. */ 233bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman signal(SIGPIPE, SIG_DFL); 234bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman execv(argv[0], argv); 235bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman perror(argv[0]); 236bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman exit(1); 237bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 238bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Parent. */ 239bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (pid < 0) 240bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("fork failed: %.100s", strerror(errno)); 241bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman else 242bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman proxy_command_pid = pid; /* save pid to clean up later */ 243bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 244bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Close child side of the descriptors. */ 245bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman close(pin[0]); 246bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman close(pout[1]); 247bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 248bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Free the command name. */ 249d059297112922cabb0c674840589be8db821fd9aAdam Langley free(command_string); 250bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 251bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Set the connection file descriptors. */ 252bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman packet_set_connection(pout[0], pin[1]); 253bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 254bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Indicate OK return */ 255bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 256bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 257bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 258bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanvoid 259bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanssh_kill_proxy_command(void) 260bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 261bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 262bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Send SIGHUP to proxy command if used. We don't wait() in 263bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * case it hangs and instead rely on init to reap the child 264bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 265bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (proxy_command_pid > 1) 266bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman kill(proxy_command_pid, SIGHUP); 267bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 268bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 269bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* 270bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Creates a (possibly privileged) socket for use as the ssh connection. 271bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 272bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int 273bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanssh_create_socket(int privileged, struct addrinfo *ai) 274bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 275d059297112922cabb0c674840589be8db821fd9aAdam Langley int sock, r, gaierr; 276d059297112922cabb0c674840589be8db821fd9aAdam Langley struct addrinfo hints, *res = NULL; 277bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 278bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 279bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (sock < 0) { 280d059297112922cabb0c674840589be8db821fd9aAdam Langley error("socket: %s", strerror(errno)); 281bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return -1; 282bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 283bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fcntl(sock, F_SETFD, FD_CLOEXEC); 284bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 285bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Bind the socket to an alternative local IP address */ 286d059297112922cabb0c674840589be8db821fd9aAdam Langley if (options.bind_address == NULL && !privileged) 287bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return sock; 288bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 289d059297112922cabb0c674840589be8db821fd9aAdam Langley if (options.bind_address) { 290d059297112922cabb0c674840589be8db821fd9aAdam Langley memset(&hints, 0, sizeof(hints)); 291d059297112922cabb0c674840589be8db821fd9aAdam Langley hints.ai_family = ai->ai_family; 292d059297112922cabb0c674840589be8db821fd9aAdam Langley hints.ai_socktype = ai->ai_socktype; 293d059297112922cabb0c674840589be8db821fd9aAdam Langley hints.ai_protocol = ai->ai_protocol; 294d059297112922cabb0c674840589be8db821fd9aAdam Langley hints.ai_flags = AI_PASSIVE; 295d059297112922cabb0c674840589be8db821fd9aAdam Langley gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res); 296d059297112922cabb0c674840589be8db821fd9aAdam Langley if (gaierr) { 297d059297112922cabb0c674840589be8db821fd9aAdam Langley error("getaddrinfo: %s: %s", options.bind_address, 298d059297112922cabb0c674840589be8db821fd9aAdam Langley ssh_gai_strerror(gaierr)); 299d059297112922cabb0c674840589be8db821fd9aAdam Langley close(sock); 300d059297112922cabb0c674840589be8db821fd9aAdam Langley return -1; 301d059297112922cabb0c674840589be8db821fd9aAdam Langley } 302bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 303d059297112922cabb0c674840589be8db821fd9aAdam Langley /* 304d059297112922cabb0c674840589be8db821fd9aAdam Langley * If we are running as root and want to connect to a privileged 305d059297112922cabb0c674840589be8db821fd9aAdam Langley * port, bind our own socket to a privileged port. 306d059297112922cabb0c674840589be8db821fd9aAdam Langley */ 307d059297112922cabb0c674840589be8db821fd9aAdam Langley if (privileged) { 308d059297112922cabb0c674840589be8db821fd9aAdam Langley PRIV_START; 309d059297112922cabb0c674840589be8db821fd9aAdam Langley r = bindresvport_sa(sock, res ? res->ai_addr : NULL); 310d059297112922cabb0c674840589be8db821fd9aAdam Langley PRIV_END; 311d059297112922cabb0c674840589be8db821fd9aAdam Langley if (r < 0) { 312d059297112922cabb0c674840589be8db821fd9aAdam Langley error("bindresvport_sa: af=%d %s", ai->ai_family, 313d059297112922cabb0c674840589be8db821fd9aAdam Langley strerror(errno)); 314d059297112922cabb0c674840589be8db821fd9aAdam Langley goto fail; 315d059297112922cabb0c674840589be8db821fd9aAdam Langley } 316d059297112922cabb0c674840589be8db821fd9aAdam Langley } else { 317d059297112922cabb0c674840589be8db821fd9aAdam Langley if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { 318d059297112922cabb0c674840589be8db821fd9aAdam Langley error("bind: %s: %s", options.bind_address, 319d059297112922cabb0c674840589be8db821fd9aAdam Langley strerror(errno)); 320d059297112922cabb0c674840589be8db821fd9aAdam Langley fail: 321d059297112922cabb0c674840589be8db821fd9aAdam Langley close(sock); 322d059297112922cabb0c674840589be8db821fd9aAdam Langley freeaddrinfo(res); 323d059297112922cabb0c674840589be8db821fd9aAdam Langley return -1; 324d059297112922cabb0c674840589be8db821fd9aAdam Langley } 325bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 326d059297112922cabb0c674840589be8db821fd9aAdam Langley if (res != NULL) 327d059297112922cabb0c674840589be8db821fd9aAdam Langley freeaddrinfo(res); 328bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return sock; 329bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 330bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 331bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int 332bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmantimeout_connect(int sockfd, const struct sockaddr *serv_addr, 333bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman socklen_t addrlen, int *timeoutp) 334bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 335bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fd_set *fdset; 336bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman struct timeval tv, t_start; 337bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman socklen_t optlen; 338bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int optval, rc, result = -1; 339bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 340bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman gettimeofday(&t_start, NULL); 341bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 342bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (*timeoutp <= 0) { 343bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman result = connect(sockfd, serv_addr, addrlen); 344bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto done; 345bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 346bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 347bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman set_nonblock(sockfd); 348bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman rc = connect(sockfd, serv_addr, addrlen); 349bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (rc == 0) { 350bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman unset_nonblock(sockfd); 351bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman result = 0; 352bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto done; 353bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 354bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (errno != EINPROGRESS) { 355bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman result = -1; 356bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto done; 357bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 358bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 359ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman fdset = xcalloc(howmany(sockfd + 1, NFDBITS), 360bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman sizeof(fd_mask)); 361bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman FD_SET(sockfd, fdset); 362bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ms_to_timeval(&tv, *timeoutp); 363bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 364bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (;;) { 365bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman rc = select(sockfd + 1, NULL, fdset, NULL, &tv); 366bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (rc != -1 || errno != EINTR) 367bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 368bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 369bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 370bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman switch (rc) { 371bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case 0: 372bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Timed out */ 373bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman errno = ETIMEDOUT; 374bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 375bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case -1: 376bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Select error */ 377bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("select: %s", strerror(errno)); 378bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 379bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case 1: 380bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Completed or failed */ 381bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman optval = 0; 382bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman optlen = sizeof(optval); 383bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, 384bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman &optlen) == -1) { 385bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("getsockopt: %s", strerror(errno)); 386bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 387bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 388bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (optval != 0) { 389bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman errno = optval; 390bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 391bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 392bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman result = 0; 393bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman unset_nonblock(sockfd); 394bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 395bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman default: 396bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Should not occur */ 397bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("Bogus return (%d) from select()", rc); 398bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 399bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 400d059297112922cabb0c674840589be8db821fd9aAdam Langley free(fdset); 401bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 402bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman done: 403bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (result == 0 && *timeoutp > 0) { 404bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ms_subtract_diff(&t_start, timeoutp); 405bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (*timeoutp <= 0) { 406bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman errno = ETIMEDOUT; 407bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman result = -1; 408bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 409bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 410bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 411bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return (result); 412bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 413bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 414bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* 415bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Opens a TCP/IP connection to the remote server on the given host. 416bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * The address of the remote host will be returned in hostaddr. 417bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * If port is 0, the default port will be used. If needpriv is true, 418bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * a privileged port will be allocated to make the connection. 419bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * This requires super-user privileges if needpriv is true. 420bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Connection_attempts specifies the maximum number of tries (one per 421bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * second). If proxy_command is non-NULL, it specifies the command (with %h 422bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * and %p substituted for host and port, respectively) to use to contact 423bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * the daemon. 424bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 425d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int 426d059297112922cabb0c674840589be8db821fd9aAdam Langleyssh_connect_direct(const char *host, struct addrinfo *aitop, 427d059297112922cabb0c674840589be8db821fd9aAdam Langley struct sockaddr_storage *hostaddr, u_short port, int family, 428d059297112922cabb0c674840589be8db821fd9aAdam Langley int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) 429bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 430bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int on = 1; 431bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int sock = -1, attempt; 432bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 433d059297112922cabb0c674840589be8db821fd9aAdam Langley struct addrinfo *ai; 434bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 4359768ca48f57aaf035f508a473421d210b5145e99Greg Hartman debug2("%s: needpriv %d", __func__, needpriv); 4369768ca48f57aaf035f508a473421d210b5145e99Greg Hartman memset(ntop, 0, sizeof(ntop)); 4379768ca48f57aaf035f508a473421d210b5145e99Greg Hartman memset(strport, 0, sizeof(strport)); 438bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 439bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (attempt = 0; attempt < connection_attempts; attempt++) { 440bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (attempt > 0) { 441bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Sleep a moment before retrying. */ 442bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman sleep(1); 443bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("Trying again..."); 444bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 445bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 446bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Loop through addresses for this host, and try each one in 447bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * sequence until the connection succeeds. 448bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 449bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (ai = aitop; ai; ai = ai->ai_next) { 450d059297112922cabb0c674840589be8db821fd9aAdam Langley if (ai->ai_family != AF_INET && 451d059297112922cabb0c674840589be8db821fd9aAdam Langley ai->ai_family != AF_INET6) 452bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 453bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (getnameinfo(ai->ai_addr, ai->ai_addrlen, 454bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ntop, sizeof(ntop), strport, sizeof(strport), 455bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 4569768ca48f57aaf035f508a473421d210b5145e99Greg Hartman error("%s: getnameinfo failed", __func__); 457bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 458bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 459bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("Connecting to %.200s [%.100s] port %s.", 460bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host, ntop, strport); 461bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 462bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Create a socket for connecting. */ 463bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman sock = ssh_create_socket(needpriv, ai); 464bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (sock < 0) 465bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Any error is already output */ 466bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 467bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 468bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, 469bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman timeout_ms) >= 0) { 470bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Successful connection. */ 471bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); 472bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 473bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else { 474bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("connect to address %s port %s: %s", 475bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ntop, strport, strerror(errno)); 476bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman close(sock); 477bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman sock = -1; 478bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 479bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 480bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (sock != -1) 481bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; /* Successful connection. */ 482bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 483bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 484bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Return failure if we didn't get a successful connection. */ 485bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (sock == -1) { 486bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("ssh: connect to host %s port %s: %s", 487bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host, strport, strerror(errno)); 488bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return (-1); 489bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 490bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 491bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("Connection established."); 492bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 493bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Set SO_KEEPALIVE if requested. */ 494bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (want_keepalive && 495bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, 496bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman sizeof(on)) < 0) 497bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); 498bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 499bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Set the connection. */ 500bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman packet_set_connection(sock, sock); 501bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 502bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 503bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 504bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 505d059297112922cabb0c674840589be8db821fd9aAdam Langleyint 506d059297112922cabb0c674840589be8db821fd9aAdam Langleyssh_connect(const char *host, struct addrinfo *addrs, 507d059297112922cabb0c674840589be8db821fd9aAdam Langley struct sockaddr_storage *hostaddr, u_short port, int family, 508d059297112922cabb0c674840589be8db821fd9aAdam Langley int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) 509d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 510d059297112922cabb0c674840589be8db821fd9aAdam Langley if (options.proxy_command == NULL) { 511d059297112922cabb0c674840589be8db821fd9aAdam Langley return ssh_connect_direct(host, addrs, hostaddr, port, family, 512d059297112922cabb0c674840589be8db821fd9aAdam Langley connection_attempts, timeout_ms, want_keepalive, needpriv); 513d059297112922cabb0c674840589be8db821fd9aAdam Langley } else if (strcmp(options.proxy_command, "-") == 0) { 514d059297112922cabb0c674840589be8db821fd9aAdam Langley packet_set_connection(STDIN_FILENO, STDOUT_FILENO); 515d059297112922cabb0c674840589be8db821fd9aAdam Langley return 0; /* Always succeeds */ 516d059297112922cabb0c674840589be8db821fd9aAdam Langley } else if (options.proxy_use_fdpass) { 517d059297112922cabb0c674840589be8db821fd9aAdam Langley return ssh_proxy_fdpass_connect(host, port, 518d059297112922cabb0c674840589be8db821fd9aAdam Langley options.proxy_command); 519d059297112922cabb0c674840589be8db821fd9aAdam Langley } 520d059297112922cabb0c674840589be8db821fd9aAdam Langley return ssh_proxy_connect(host, port, options.proxy_command); 521d059297112922cabb0c674840589be8db821fd9aAdam Langley} 522d059297112922cabb0c674840589be8db821fd9aAdam Langley 523d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic void 524d059297112922cabb0c674840589be8db821fd9aAdam Langleysend_client_banner(int connection_out, int minor1) 525d059297112922cabb0c674840589be8db821fd9aAdam Langley{ 526d059297112922cabb0c674840589be8db821fd9aAdam Langley /* Send our own protocol version identification. */ 527d059297112922cabb0c674840589be8db821fd9aAdam Langley if (compat20) { 528d059297112922cabb0c674840589be8db821fd9aAdam Langley xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n", 529d059297112922cabb0c674840589be8db821fd9aAdam Langley PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION); 530d059297112922cabb0c674840589be8db821fd9aAdam Langley } else { 531d059297112922cabb0c674840589be8db821fd9aAdam Langley xasprintf(&client_version_string, "SSH-%d.%d-%.100s\n", 532d059297112922cabb0c674840589be8db821fd9aAdam Langley PROTOCOL_MAJOR_1, minor1, SSH_VERSION); 533d059297112922cabb0c674840589be8db821fd9aAdam Langley } 5349768ca48f57aaf035f508a473421d210b5145e99Greg Hartman if (atomicio(vwrite, connection_out, client_version_string, 535d059297112922cabb0c674840589be8db821fd9aAdam Langley strlen(client_version_string)) != strlen(client_version_string)) 536d059297112922cabb0c674840589be8db821fd9aAdam Langley fatal("write: %.100s", strerror(errno)); 537d059297112922cabb0c674840589be8db821fd9aAdam Langley chop(client_version_string); 538d059297112922cabb0c674840589be8db821fd9aAdam Langley debug("Local version string %.100s", client_version_string); 539d059297112922cabb0c674840589be8db821fd9aAdam Langley} 540d059297112922cabb0c674840589be8db821fd9aAdam Langley 541bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* 542bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Waits for the server identification string, and sends our own 543bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * identification string. 544bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 545bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanvoid 546bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanssh_exchange_identification(int timeout_ms) 547bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 548bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char buf[256], remote_version[256]; /* must be same size! */ 549bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int remote_major, remote_minor, mismatch; 550bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int connection_in = packet_get_connection_in(); 551bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int connection_out = packet_get_connection_out(); 552d059297112922cabb0c674840589be8db821fd9aAdam Langley int minor1 = PROTOCOL_MINOR_1, client_banner_sent = 0; 553bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_int i, n; 554bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman size_t len; 555bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int fdsetsz, remaining, rc; 556bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman struct timeval t_start, t_remaining; 557bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fd_set *fdset; 558bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 559bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fdsetsz = howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask); 560bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fdset = xcalloc(1, fdsetsz); 561bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 562d059297112922cabb0c674840589be8db821fd9aAdam Langley /* 563d059297112922cabb0c674840589be8db821fd9aAdam Langley * If we are SSH2-only then we can send the banner immediately and 564d059297112922cabb0c674840589be8db821fd9aAdam Langley * save a round-trip. 565d059297112922cabb0c674840589be8db821fd9aAdam Langley */ 566d059297112922cabb0c674840589be8db821fd9aAdam Langley if (options.protocol == SSH_PROTO_2) { 567d059297112922cabb0c674840589be8db821fd9aAdam Langley enable_compat20(); 568d059297112922cabb0c674840589be8db821fd9aAdam Langley send_client_banner(connection_out, 0); 569d059297112922cabb0c674840589be8db821fd9aAdam Langley client_banner_sent = 1; 570d059297112922cabb0c674840589be8db821fd9aAdam Langley } 571d059297112922cabb0c674840589be8db821fd9aAdam Langley 572bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Read other side's version identification. */ 573bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman remaining = timeout_ms; 574bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (n = 0;;) { 575bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (i = 0; i < sizeof(buf) - 1; i++) { 576bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (timeout_ms > 0) { 577bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman gettimeofday(&t_start, NULL); 578bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ms_to_timeval(&t_remaining, remaining); 579bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman FD_SET(connection_in, fdset); 580bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman rc = select(connection_in + 1, fdset, NULL, 581bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fdset, &t_remaining); 582bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ms_subtract_diff(&t_start, &remaining); 583bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (rc == 0 || remaining <= 0) 584bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("Connection timed out during " 585bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "banner exchange"); 586bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (rc == -1) { 587bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (errno == EINTR) 588bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 589bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("ssh_exchange_identification: " 590bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "select: %s", strerror(errno)); 591bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 592bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 593bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 5949768ca48f57aaf035f508a473421d210b5145e99Greg Hartman len = atomicio(read, connection_in, &buf[i], 1); 595bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 596bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (len != 1 && errno == EPIPE) 597bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("ssh_exchange_identification: " 598bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "Connection closed by remote host"); 599bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman else if (len != 1) 600bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("ssh_exchange_identification: " 601bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "read: %.100s", strerror(errno)); 602bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (buf[i] == '\r') { 603bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buf[i] = '\n'; 604bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buf[i + 1] = 0; 605bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; /**XXX wait for \n */ 606bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 607bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (buf[i] == '\n') { 608bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buf[i + 1] = 0; 609bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 610bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 611bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (++n > 65536) 612bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("ssh_exchange_identification: " 613bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "No banner received"); 614bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 615bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman buf[sizeof(buf) - 1] = 0; 616bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (strncmp(buf, "SSH-", 4) == 0) 617bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 618bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("ssh_exchange_identification: %s", buf); 619bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 620bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman server_version_string = xstrdup(buf); 621d059297112922cabb0c674840589be8db821fd9aAdam Langley free(fdset); 622bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 623bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 624bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Check that the versions match. In future this might accept 625bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * several versions and set appropriate flags to handle them. 626bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 627bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n", 628bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman &remote_major, &remote_minor, remote_version) != 3) 629bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("Bad remote protocol version identification: '%.100s'", buf); 630bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("Remote protocol version %d.%d, remote software version %.100s", 631bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman remote_major, remote_minor, remote_version); 632bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 633d059297112922cabb0c674840589be8db821fd9aAdam Langley active_state->compat = compat_datafellows(remote_version); 634bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman mismatch = 0; 635bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 636bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman switch (remote_major) { 637bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case 1: 638bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (remote_minor == 99 && 639bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman (options.protocol & SSH_PROTO_2) && 640bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman !(options.protocol & SSH_PROTO_1_PREFERRED)) { 641bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman enable_compat20(); 642bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 643bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 644bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!(options.protocol & SSH_PROTO_1)) { 645bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman mismatch = 1; 646bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 647bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 648bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (remote_minor < 3) { 649bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("Remote machine has too old SSH software version."); 650bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else if (remote_minor == 3 || remote_minor == 4) { 651bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* We speak 1.3, too. */ 652bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman enable_compat13(); 653bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman minor1 = 3; 654bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.forward_agent) { 655bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman logit("Agent forwarding disabled for protocol 1.3"); 656bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.forward_agent = 0; 657bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 658bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 659bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 660bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case 2: 661bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.protocol & SSH_PROTO_2) { 662bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman enable_compat20(); 663bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 664bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 665bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* FALLTHROUGH */ 666bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman default: 667bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman mismatch = 1; 668bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 669bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 670bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (mismatch) 671bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("Protocol major versions differ: %d vs. %d", 672bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, 673bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman remote_major); 674d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((datafellows & SSH_BUG_DERIVEKEY) != 0) 675d059297112922cabb0c674840589be8db821fd9aAdam Langley fatal("Server version \"%.100s\" uses unsafe key agreement; " 676d059297112922cabb0c674840589be8db821fd9aAdam Langley "refusing connection", remote_version); 677d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((datafellows & SSH_BUG_RSASIGMD5) != 0) 678d059297112922cabb0c674840589be8db821fd9aAdam Langley logit("Server version \"%.100s\" uses unsafe RSA signature " 679d059297112922cabb0c674840589be8db821fd9aAdam Langley "scheme; disabling use of RSA keys", remote_version); 680d059297112922cabb0c674840589be8db821fd9aAdam Langley if (!client_banner_sent) 681d059297112922cabb0c674840589be8db821fd9aAdam Langley send_client_banner(connection_out, minor1); 682bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman chop(server_version_string); 683bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 684bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 685bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* defaults to 'no' */ 686bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int 687bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanconfirm(const char *prompt) 688bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 689bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman const char *msg, *again = "Please type 'yes' or 'no': "; 690bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *p; 691bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int ret = -1; 692bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 693bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.batch_mode) 694bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 695bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (msg = prompt;;msg = again) { 696bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman p = read_passphrase(msg, RP_ECHO); 697bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (p == NULL || 698bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman (p[0] == '\0') || (p[0] == '\n') || 699bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman strncasecmp(p, "no", 2) == 0) 700bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ret = 0; 701bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (p && strncasecmp(p, "yes", 3) == 0) 702bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ret = 1; 703d059297112922cabb0c674840589be8db821fd9aAdam Langley free(p); 704bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (ret != -1) 705bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return ret; 706bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 707bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 708bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 709bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int 710bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmancheck_host_cert(const char *host, const Key *host_key) 711bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 712bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman const char *reason; 713bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 714bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (key_cert_check_authority(host_key, 1, 0, host, &reason) != 0) { 715bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("%s", reason); 716bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 717bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 718d059297112922cabb0c674840589be8db821fd9aAdam Langley if (buffer_len(host_key->cert->critical) != 0) { 719bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Certificate for %s contains unsupported " 720bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "critical options(s)", host); 721bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 722bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 723bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 1; 724bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 725bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 726bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int 727bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmansockaddr_is_local(struct sockaddr *hostaddr) 728bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 729bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman switch (hostaddr->sa_family) { 730bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case AF_INET: 731bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return (ntohl(((struct sockaddr_in *)hostaddr)-> 732bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; 733bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case AF_INET6: 734bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return IN6_IS_ADDR_LOOPBACK( 735bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman &(((struct sockaddr_in6 *)hostaddr)->sin6_addr)); 736bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman default: 737bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 738bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 739bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 740bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 741bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* 742bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Prepare the hostname and ip address strings that are used to lookup 743bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * host keys in known_hosts files. These may have a port number appended. 744bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 745bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanvoid 746bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanget_hostfile_hostname_ipaddr(char *hostname, struct sockaddr *hostaddr, 747bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_short port, char **hostfile_hostname, char **hostfile_ipaddr) 748bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 749bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char ntop[NI_MAXHOST]; 750bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman socklen_t addrlen; 751bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 752bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman switch (hostaddr == NULL ? -1 : hostaddr->sa_family) { 753bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case -1: 754bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman addrlen = 0; 755bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 756bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case AF_INET: 757bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman addrlen = sizeof(struct sockaddr_in); 758bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 759bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case AF_INET6: 760bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman addrlen = sizeof(struct sockaddr_in6); 761bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 762bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman default: 763bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman addrlen = sizeof(struct sockaddr); 764bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 765bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 766bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 767bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 768bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * We don't have the remote ip-address for connections 769bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * using a proxy command 770bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 771bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (hostfile_ipaddr != NULL) { 772bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.proxy_command == NULL) { 773bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (getnameinfo(hostaddr, addrlen, 774bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0) 775d059297112922cabb0c674840589be8db821fd9aAdam Langley fatal("%s: getnameinfo failed", __func__); 776bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *hostfile_ipaddr = put_host_port(ntop, port); 777bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else { 778bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *hostfile_ipaddr = xstrdup("<no hostip for proxy " 779bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "command>"); 780bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 781bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 782bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 783bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 784bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Allow the user to record the key under a different name or 785bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * differentiate a non-standard port. This is useful for ssh 786bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * tunneling over forwarded connections or if you run multiple 787bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * sshd's on different ports on the same machine. 788bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 789bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (hostfile_hostname != NULL) { 790bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.host_key_alias != NULL) { 791bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *hostfile_hostname = xstrdup(options.host_key_alias); 792bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("using hostkeyalias: %s", *hostfile_hostname); 793bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else { 794bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *hostfile_hostname = put_host_port(hostname, port); 795bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 796bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 797bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 798bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 799bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* 800bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * check whether the supplied host key is valid, return -1 if the key 801bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * is not valid. user_hostfile[0] will not be updated if 'readonly' is true. 802bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 803bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#define RDRW 0 804bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#define RDONLY 1 805bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#define ROQUIET 2 806bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int 807bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmancheck_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, 808bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman Key *host_key, int readonly, 809bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char **user_hostfiles, u_int num_user_hostfiles, 810bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char **system_hostfiles, u_int num_system_hostfiles) 811bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 812bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman HostStatus host_status; 813bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman HostStatus ip_status; 814bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman Key *raw_key = NULL; 815bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *ip = NULL, *host = NULL; 816bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char hostline[1000], *hostp, *fp, *ra; 817bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char msg[1024]; 818bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman const char *type; 819bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman const struct hostkey_entry *host_found, *ip_found; 820bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int len, cancelled_forwarding = 0; 821bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int local = sockaddr_is_local(hostaddr); 822bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int r, want_cert = key_is_cert(host_key), host_ip_differ = 0; 823d059297112922cabb0c674840589be8db821fd9aAdam Langley int hostkey_trusted = 0; /* Known or explicitly accepted by user */ 824bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman struct hostkeys *host_hostkeys, *ip_hostkeys; 825bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman u_int i; 826bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 827bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 828bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Force accepting of the host key for loopback/localhost. The 829bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * problem is that if the home directory is NFS-mounted to multiple 830bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * machines, localhost will refer to a different machine in each of 831bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * them, and the user will get bogus HOST_CHANGED warnings. This 832bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * essentially disables host authentication for localhost; however, 833bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * this is probably not a real problem. 834bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 835bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.no_host_authentication_for_localhost == 1 && local && 836bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.host_key_alias == NULL) { 837bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("Forcing accepting of host key for " 838bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "loopback/localhost."); 839bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 840bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 841bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 842bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 843bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Prepare the hostname and address strings used for hostkey lookup. 844bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * In some cases, these will have a port number appended. 845bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 846bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman get_hostfile_hostname_ipaddr(hostname, hostaddr, port, &host, &ip); 847bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 848bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 849bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Turn off check_host_ip if the connection is to localhost, via proxy 850bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * command or if we don't have a hostname to compare with 851bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 852bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.check_host_ip && (local || 853bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman strcmp(hostname, ip) == 0 || options.proxy_command != NULL)) 854bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.check_host_ip = 0; 855bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 856bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host_hostkeys = init_hostkeys(); 857bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (i = 0; i < num_user_hostfiles; i++) 858bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman load_hostkeys(host_hostkeys, host, user_hostfiles[i]); 859bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (i = 0; i < num_system_hostfiles; i++) 860bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman load_hostkeys(host_hostkeys, host, system_hostfiles[i]); 861bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 862bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ip_hostkeys = NULL; 863bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!want_cert && options.check_host_ip) { 864bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ip_hostkeys = init_hostkeys(); 865bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (i = 0; i < num_user_hostfiles; i++) 866bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman load_hostkeys(ip_hostkeys, ip, user_hostfiles[i]); 867bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (i = 0; i < num_system_hostfiles; i++) 868bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman load_hostkeys(ip_hostkeys, ip, system_hostfiles[i]); 869bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 870bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 871bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman retry: 872bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Reload these as they may have changed on cert->key downgrade */ 873bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman want_cert = key_is_cert(host_key); 874bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman type = key_type(host_key); 875bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 876bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 877bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Check if the host key is present in the user's list of known 878bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * hosts or in the systemwide list. 879bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 880bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host_status = check_key_in_hostkeys(host_hostkeys, host_key, 881bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman &host_found); 882bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 883bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 884bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Also perform check for the ip address, skip the check if we are 885bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * localhost, looking for a certificate, or the hostname was an ip 886bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * address to begin with. 887bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 888bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!want_cert && ip_hostkeys != NULL) { 889bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ip_status = check_key_in_hostkeys(ip_hostkeys, host_key, 890bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman &ip_found); 891bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (host_status == HOST_CHANGED && 892bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman (ip_status != HOST_CHANGED || 893bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman (ip_found != NULL && 894bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman !key_equal(ip_found->key, host_found->key)))) 895bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host_ip_differ = 1; 896bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else 897bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ip_status = host_status; 898bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 899bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman switch (host_status) { 900bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case HOST_OK: 901bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* The host is known and the key matches. */ 902bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("Host '%.200s' is known and matches the %s host %s.", 903bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host, type, want_cert ? "certificate" : "key"); 904bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("Found %s in %s:%lu", want_cert ? "CA key" : "key", 905bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host_found->file, host_found->line); 906bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (want_cert && !check_host_cert(hostname, host_key)) 907bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto fail; 908bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.check_host_ip && ip_status == HOST_NEW) { 909bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (readonly || want_cert) 910bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman logit("%s host key for IP address " 911bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "'%.128s' not in list of known hosts.", 912bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman type, ip); 913bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman else if (!add_host_to_hostfile(user_hostfiles[0], ip, 914bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host_key, options.hash_known_hosts)) 915bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman logit("Failed to add the %s host key for IP " 916bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "address '%.128s' to the list of known " 917ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman "hosts (%.500s).", type, ip, 918bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman user_hostfiles[0]); 919bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman else 920bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman logit("Warning: Permanently added the %s host " 921bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "key for IP address '%.128s' to the list " 922bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "of known hosts.", type, ip); 923bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else if (options.visual_host_key) { 924d059297112922cabb0c674840589be8db821fd9aAdam Langley fp = sshkey_fingerprint(host_key, 925d059297112922cabb0c674840589be8db821fd9aAdam Langley options.fingerprint_hash, SSH_FP_DEFAULT); 926d059297112922cabb0c674840589be8db821fd9aAdam Langley ra = sshkey_fingerprint(host_key, 927d059297112922cabb0c674840589be8db821fd9aAdam Langley options.fingerprint_hash, SSH_FP_RANDOMART); 928d059297112922cabb0c674840589be8db821fd9aAdam Langley if (fp == NULL || ra == NULL) 929d059297112922cabb0c674840589be8db821fd9aAdam Langley fatal("%s: sshkey_fingerprint fail", __func__); 9309768ca48f57aaf035f508a473421d210b5145e99Greg Hartman logit("Host key fingerprint is %s\n%s", fp, ra); 931d059297112922cabb0c674840589be8db821fd9aAdam Langley free(ra); 932d059297112922cabb0c674840589be8db821fd9aAdam Langley free(fp); 933bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 934d059297112922cabb0c674840589be8db821fd9aAdam Langley hostkey_trusted = 1; 935bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 936bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case HOST_NEW: 937bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.host_key_alias == NULL && port != 0 && 938bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman port != SSH_DEFAULT_PORT) { 939bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("checking without port identifier"); 940bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (check_host_key(hostname, hostaddr, 0, host_key, 941bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ROQUIET, user_hostfiles, num_user_hostfiles, 942bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman system_hostfiles, num_system_hostfiles) == 0) { 943bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("found matching key w/out port"); 944bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 945bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 946bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 947bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (readonly || want_cert) 948bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto fail; 949bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* The host is new. */ 950bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.strict_host_key_checking == 1) { 951bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 952bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * User has requested strict host key checking. We 953bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * will not add the host key automatically. The only 954bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * alternative left is to abort. 955bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 956bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("No %s host key is known for %.200s and you " 957bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "have requested strict checking.", type, host); 958bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto fail; 959bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else if (options.strict_host_key_checking == 2) { 960bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char msg1[1024], msg2[1024]; 961bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 962bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (show_other_keys(host_hostkeys, host_key)) 963bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman snprintf(msg1, sizeof(msg1), 964bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "\nbut keys of different type are already" 965bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman " known for this host."); 966bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman else 967bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman snprintf(msg1, sizeof(msg1), "."); 968bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* The default */ 969d059297112922cabb0c674840589be8db821fd9aAdam Langley fp = sshkey_fingerprint(host_key, 970d059297112922cabb0c674840589be8db821fd9aAdam Langley options.fingerprint_hash, SSH_FP_DEFAULT); 971d059297112922cabb0c674840589be8db821fd9aAdam Langley ra = sshkey_fingerprint(host_key, 972d059297112922cabb0c674840589be8db821fd9aAdam Langley options.fingerprint_hash, SSH_FP_RANDOMART); 973d059297112922cabb0c674840589be8db821fd9aAdam Langley if (fp == NULL || ra == NULL) 974d059297112922cabb0c674840589be8db821fd9aAdam Langley fatal("%s: sshkey_fingerprint fail", __func__); 975bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman msg2[0] = '\0'; 976bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.verify_host_key_dns) { 977bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (matching_host_key_dns) 978bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman snprintf(msg2, sizeof(msg2), 979bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "Matching host key fingerprint" 980bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman " found in DNS.\n"); 981bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman else 982bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman snprintf(msg2, sizeof(msg2), 983bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "No matching host key fingerprint" 984bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman " found in DNS.\n"); 985bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 986bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman snprintf(msg, sizeof(msg), 987bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "The authenticity of host '%.200s (%s)' can't be " 988bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "established%s\n" 989bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "%s key fingerprint is %s.%s%s\n%s" 990bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "Are you sure you want to continue connecting " 991bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "(yes/no)? ", 992bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host, ip, msg1, type, fp, 993bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.visual_host_key ? "\n" : "", 994bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.visual_host_key ? ra : "", 995bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman msg2); 996d059297112922cabb0c674840589be8db821fd9aAdam Langley free(ra); 997d059297112922cabb0c674840589be8db821fd9aAdam Langley free(fp); 998bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!confirm(msg)) 999bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto fail; 1000d059297112922cabb0c674840589be8db821fd9aAdam Langley hostkey_trusted = 1; /* user explicitly confirmed */ 1001bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1002bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 1003bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * If not in strict mode, add the key automatically to the 1004bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * local known_hosts file. 1005bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 1006bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.check_host_ip && ip_status == HOST_NEW) { 1007bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); 1008bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman hostp = hostline; 1009bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.hash_known_hosts) { 1010bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Add hash of host and IP separately */ 1011bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman r = add_host_to_hostfile(user_hostfiles[0], 1012bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host, host_key, options.hash_known_hosts) && 1013bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman add_host_to_hostfile(user_hostfiles[0], ip, 1014bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host_key, options.hash_known_hosts); 1015bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else { 1016bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Add unhashed "host,ip" */ 1017bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman r = add_host_to_hostfile(user_hostfiles[0], 1018bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman hostline, host_key, 1019bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.hash_known_hosts); 1020bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1021bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else { 1022bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman r = add_host_to_hostfile(user_hostfiles[0], host, 1023bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host_key, options.hash_known_hosts); 1024bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman hostp = host; 1025bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1026bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1027bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!r) 1028bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman logit("Failed to add the host to the list of known " 1029bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "hosts (%.500s).", user_hostfiles[0]); 1030bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman else 1031bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman logit("Warning: Permanently added '%.200s' (%s) to the " 1032bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "list of known hosts.", hostp, type); 1033bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 1034bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case HOST_REVOKED: 1035bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1036bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("@ WARNING: REVOKED HOST KEY DETECTED! @"); 1037bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1038bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("The %s host key for %s is marked as revoked.", type, host); 1039bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("This could mean that a stolen key is being used to"); 1040bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("impersonate this host."); 1041bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1042bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 1043bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * If strict host key checking is in use, the user will have 1044bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * to edit the key manually and we can only abort. 1045bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 1046bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.strict_host_key_checking) { 1047bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("%s host key for %.200s was revoked and you have " 1048bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "requested strict checking.", type, host); 1049bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto fail; 1050bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1051bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto continue_unsafe; 1052bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1053bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case HOST_CHANGED: 1054bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (want_cert) { 1055bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 1056bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * This is only a debug() since it is valid to have 1057bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * CAs with wildcard DNS matches that don't match 1058bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * all hosts that one might visit. 1059bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 1060bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("Host certificate authority does not " 1061bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "match %s in %s:%lu", CA_MARKER, 1062bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host_found->file, host_found->line); 1063bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto fail; 1064bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1065bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (readonly == ROQUIET) 1066bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto fail; 1067bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.check_host_ip && host_ip_differ) { 1068bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *key_msg; 1069bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (ip_status == HOST_NEW) 1070bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman key_msg = "is unknown"; 1071bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman else if (ip_status == HOST_OK) 1072bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman key_msg = "is unchanged"; 1073bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman else 1074bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman key_msg = "has a different value"; 1075bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1076bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); 1077bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1078bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("The %s host key for %s has changed,", type, host); 1079bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("and the key for the corresponding IP address %s", ip); 1080bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("%s. This could either mean that", key_msg); 1081bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("DNS SPOOFING is happening or the IP address for the host"); 1082bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("and its host key have changed at the same time."); 1083bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (ip_status != HOST_NEW) 1084bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Offending key for IP in %s:%lu", 1085bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ip_found->file, ip_found->line); 1086bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1087bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* The host key has changed. */ 1088bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman warn_changed_key(host_key); 1089bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Add correct host key in %.100s to get rid of this message.", 1090bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman user_hostfiles[0]); 1091bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Offending %s key in %s:%lu", key_type(host_found->key), 1092bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host_found->file, host_found->line); 1093bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1094bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 1095bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * If strict host key checking is in use, the user will have 1096bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * to edit the key manually and we can only abort. 1097bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 1098bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.strict_host_key_checking) { 1099bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("%s host key for %.200s has changed and you have " 1100bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "requested strict checking.", type, host); 1101bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto fail; 1102bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1103bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1104bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue_unsafe: 1105bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 1106bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * If strict host key checking has not been requested, allow 1107bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * the connection but without MITM-able authentication or 1108bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * forwarding. 1109bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 1110bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.password_authentication) { 1111bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Password authentication is disabled to avoid " 1112bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "man-in-the-middle attacks."); 1113bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.password_authentication = 0; 1114bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman cancelled_forwarding = 1; 1115bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1116bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.kbd_interactive_authentication) { 1117bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Keyboard-interactive authentication is disabled" 1118bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman " to avoid man-in-the-middle attacks."); 1119bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.kbd_interactive_authentication = 0; 1120bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.challenge_response_authentication = 0; 1121bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman cancelled_forwarding = 1; 1122bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1123bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.challenge_response_authentication) { 1124bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Challenge/response authentication is disabled" 1125bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman " to avoid man-in-the-middle attacks."); 1126bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.challenge_response_authentication = 0; 1127bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman cancelled_forwarding = 1; 1128bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1129bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.forward_agent) { 1130bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Agent forwarding is disabled to avoid " 1131bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "man-in-the-middle attacks."); 1132bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.forward_agent = 0; 1133bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman cancelled_forwarding = 1; 1134bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1135bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.forward_x11) { 1136bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("X11 forwarding is disabled to avoid " 1137bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "man-in-the-middle attacks."); 1138bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.forward_x11 = 0; 1139bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman cancelled_forwarding = 1; 1140bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1141bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.num_local_forwards > 0 || 1142bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.num_remote_forwards > 0) { 1143bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Port forwarding is disabled to avoid " 1144bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "man-in-the-middle attacks."); 1145bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.num_local_forwards = 1146bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.num_remote_forwards = 0; 1147bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman cancelled_forwarding = 1; 1148bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1149bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.tun_open != SSH_TUNMODE_NO) { 1150bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Tunnel forwarding is disabled to avoid " 1151bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "man-in-the-middle attacks."); 1152bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.tun_open = SSH_TUNMODE_NO; 1153bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman cancelled_forwarding = 1; 1154bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1155bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.exit_on_forward_failure && cancelled_forwarding) 1156bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("Error: forwarding disabled due to host key " 1157bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "check failure"); 1158bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1159bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 1160bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * XXX Should permit the user to change to use the new id. 1161bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * This could be done by converting the host key to an 1162bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * identifying sentence, tell that the host identifies itself 1163bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * by that sentence, and ask the user if he/she wishes to 1164bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * accept the authentication. 1165bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 1166bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 1167bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman case HOST_FOUND: 1168bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("internal error"); 1169bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman break; 1170bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1171bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1172bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.check_host_ip && host_status != HOST_CHANGED && 1173bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ip_status == HOST_CHANGED) { 1174bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman snprintf(msg, sizeof(msg), 1175bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "Warning: the %s host key for '%.200s' " 1176bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "differs from the key for the IP address '%.128s'" 1177bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "\nOffending key for IP in %s:%lu", 1178bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman type, host, ip, ip_found->file, ip_found->line); 1179bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (host_status == HOST_OK) { 1180bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman len = strlen(msg); 1181bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman snprintf(msg + len, sizeof(msg) - len, 1182bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "\nMatching host key in %s:%lu", 1183bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host_found->file, host_found->line); 1184bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1185bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.strict_host_key_checking == 1) { 1186bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman logit("%s", msg); 1187bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Exiting, you have requested strict checking."); 1188bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto fail; 1189bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else if (options.strict_host_key_checking == 2) { 1190bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman strlcat(msg, "\nAre you sure you want " 1191bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "to continue connecting (yes/no)? ", sizeof(msg)); 1192bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!confirm(msg)) 1193bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto fail; 1194bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else { 1195bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman logit("%s", msg); 1196bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1197bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1198bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1199d059297112922cabb0c674840589be8db821fd9aAdam Langley if (!hostkey_trusted && options.update_hostkeys) { 1200d059297112922cabb0c674840589be8db821fd9aAdam Langley debug("%s: hostkey not known or explicitly trusted: " 1201d059297112922cabb0c674840589be8db821fd9aAdam Langley "disabling UpdateHostkeys", __func__); 1202d059297112922cabb0c674840589be8db821fd9aAdam Langley options.update_hostkeys = 0; 1203d059297112922cabb0c674840589be8db821fd9aAdam Langley } 1204d059297112922cabb0c674840589be8db821fd9aAdam Langley 1205d059297112922cabb0c674840589be8db821fd9aAdam Langley free(ip); 1206d059297112922cabb0c674840589be8db821fd9aAdam Langley free(host); 1207bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (host_hostkeys != NULL) 1208bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman free_hostkeys(host_hostkeys); 1209bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (ip_hostkeys != NULL) 1210bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman free_hostkeys(ip_hostkeys); 1211bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return 0; 1212bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1213bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanfail: 1214bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (want_cert && host_status != HOST_REVOKED) { 1215bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* 1216bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * No matching certificate. Downgrade cert to raw key and 1217bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * search normally. 1218bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 1219bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug("No matching CA found. Retry with plain key"); 1220bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman raw_key = key_from_private(host_key); 1221bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (key_drop_cert(raw_key) != 0) 1222bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("Couldn't drop certificate"); 1223bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host_key = raw_key; 1224bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman goto retry; 1225bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1226bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (raw_key != NULL) 1227bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman key_free(raw_key); 1228d059297112922cabb0c674840589be8db821fd9aAdam Langley free(ip); 1229d059297112922cabb0c674840589be8db821fd9aAdam Langley free(host); 1230bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (host_hostkeys != NULL) 1231bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman free_hostkeys(host_hostkeys); 1232bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (ip_hostkeys != NULL) 1233bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman free_hostkeys(ip_hostkeys); 1234bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return -1; 1235bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 1236bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1237bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* returns 0 if key verifies or -1 if key does NOT verify */ 1238bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint 1239bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanverify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) 1240bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 12419768ca48f57aaf035f508a473421d210b5145e99Greg Hartman u_int i; 1242d059297112922cabb0c674840589be8db821fd9aAdam Langley int r = -1, flags = 0; 12439768ca48f57aaf035f508a473421d210b5145e99Greg Hartman char valid[64], *fp = NULL, *cafp = NULL; 1244d059297112922cabb0c674840589be8db821fd9aAdam Langley struct sshkey *plain = NULL; 1245d059297112922cabb0c674840589be8db821fd9aAdam Langley 1246d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((fp = sshkey_fingerprint(host_key, 1247d059297112922cabb0c674840589be8db821fd9aAdam Langley options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { 1248d059297112922cabb0c674840589be8db821fd9aAdam Langley error("%s: fingerprint host key: %s", __func__, ssh_err(r)); 1249d059297112922cabb0c674840589be8db821fd9aAdam Langley r = -1; 1250d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 1251d059297112922cabb0c674840589be8db821fd9aAdam Langley } 1252bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 12539768ca48f57aaf035f508a473421d210b5145e99Greg Hartman if (sshkey_is_cert(host_key)) { 12549768ca48f57aaf035f508a473421d210b5145e99Greg Hartman if ((cafp = sshkey_fingerprint(host_key->cert->signature_key, 12559768ca48f57aaf035f508a473421d210b5145e99Greg Hartman options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { 12569768ca48f57aaf035f508a473421d210b5145e99Greg Hartman error("%s: fingerprint CA key: %s", 12579768ca48f57aaf035f508a473421d210b5145e99Greg Hartman __func__, ssh_err(r)); 12589768ca48f57aaf035f508a473421d210b5145e99Greg Hartman r = -1; 12599768ca48f57aaf035f508a473421d210b5145e99Greg Hartman goto out; 12609768ca48f57aaf035f508a473421d210b5145e99Greg Hartman } 12619768ca48f57aaf035f508a473421d210b5145e99Greg Hartman sshkey_format_cert_validity(host_key->cert, 12629768ca48f57aaf035f508a473421d210b5145e99Greg Hartman valid, sizeof(valid)); 12639768ca48f57aaf035f508a473421d210b5145e99Greg Hartman debug("Server host certificate: %s %s, serial %llu " 12649768ca48f57aaf035f508a473421d210b5145e99Greg Hartman "ID \"%s\" CA %s %s valid %s", 12659768ca48f57aaf035f508a473421d210b5145e99Greg Hartman sshkey_ssh_name(host_key), fp, 12669768ca48f57aaf035f508a473421d210b5145e99Greg Hartman (unsigned long long)host_key->cert->serial, 12679768ca48f57aaf035f508a473421d210b5145e99Greg Hartman host_key->cert->key_id, 12689768ca48f57aaf035f508a473421d210b5145e99Greg Hartman sshkey_ssh_name(host_key->cert->signature_key), cafp, 12699768ca48f57aaf035f508a473421d210b5145e99Greg Hartman valid); 12709768ca48f57aaf035f508a473421d210b5145e99Greg Hartman for (i = 0; i < host_key->cert->nprincipals; i++) { 12719768ca48f57aaf035f508a473421d210b5145e99Greg Hartman debug2("Server host certificate hostname: %s", 12729768ca48f57aaf035f508a473421d210b5145e99Greg Hartman host_key->cert->principals[i]); 12739768ca48f57aaf035f508a473421d210b5145e99Greg Hartman } 12749768ca48f57aaf035f508a473421d210b5145e99Greg Hartman } else { 12759768ca48f57aaf035f508a473421d210b5145e99Greg Hartman debug("Server host key: %s %s", compat20 ? 12769768ca48f57aaf035f508a473421d210b5145e99Greg Hartman sshkey_ssh_name(host_key) : sshkey_type(host_key), fp); 12779768ca48f57aaf035f508a473421d210b5145e99Greg Hartman } 1278bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1279d059297112922cabb0c674840589be8db821fd9aAdam Langley if (sshkey_equal(previous_host_key, host_key)) { 1280d059297112922cabb0c674840589be8db821fd9aAdam Langley debug2("%s: server host key %s %s matches cached key", 1281d059297112922cabb0c674840589be8db821fd9aAdam Langley __func__, sshkey_type(host_key), fp); 1282d059297112922cabb0c674840589be8db821fd9aAdam Langley r = 0; 1283d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 1284d059297112922cabb0c674840589be8db821fd9aAdam Langley } 1285bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1286d059297112922cabb0c674840589be8db821fd9aAdam Langley /* Check in RevokedHostKeys file if specified */ 1287d059297112922cabb0c674840589be8db821fd9aAdam Langley if (options.revoked_host_keys != NULL) { 1288d059297112922cabb0c674840589be8db821fd9aAdam Langley r = sshkey_check_revoked(host_key, options.revoked_host_keys); 1289d059297112922cabb0c674840589be8db821fd9aAdam Langley switch (r) { 1290d059297112922cabb0c674840589be8db821fd9aAdam Langley case 0: 1291d059297112922cabb0c674840589be8db821fd9aAdam Langley break; /* not revoked */ 1292d059297112922cabb0c674840589be8db821fd9aAdam Langley case SSH_ERR_KEY_REVOKED: 1293d059297112922cabb0c674840589be8db821fd9aAdam Langley error("Host key %s %s revoked by file %s", 1294d059297112922cabb0c674840589be8db821fd9aAdam Langley sshkey_type(host_key), fp, 1295d059297112922cabb0c674840589be8db821fd9aAdam Langley options.revoked_host_keys); 1296d059297112922cabb0c674840589be8db821fd9aAdam Langley r = -1; 1297d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 1298d059297112922cabb0c674840589be8db821fd9aAdam Langley default: 1299d059297112922cabb0c674840589be8db821fd9aAdam Langley error("Error checking host key %s %s in " 1300d059297112922cabb0c674840589be8db821fd9aAdam Langley "revoked keys file %s: %s", sshkey_type(host_key), 1301d059297112922cabb0c674840589be8db821fd9aAdam Langley fp, options.revoked_host_keys, ssh_err(r)); 1302d059297112922cabb0c674840589be8db821fd9aAdam Langley r = -1; 1303d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 1304d059297112922cabb0c674840589be8db821fd9aAdam Langley } 1305d059297112922cabb0c674840589be8db821fd9aAdam Langley } 1306bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1307d059297112922cabb0c674840589be8db821fd9aAdam Langley if (options.verify_host_key_dns) { 1308d059297112922cabb0c674840589be8db821fd9aAdam Langley /* 1309d059297112922cabb0c674840589be8db821fd9aAdam Langley * XXX certs are not yet supported for DNS, so downgrade 1310d059297112922cabb0c674840589be8db821fd9aAdam Langley * them and try the plain key. 1311d059297112922cabb0c674840589be8db821fd9aAdam Langley */ 1312d059297112922cabb0c674840589be8db821fd9aAdam Langley if ((r = sshkey_from_private(host_key, &plain)) != 0) 1313d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 1314d059297112922cabb0c674840589be8db821fd9aAdam Langley if (sshkey_is_cert(plain)) 1315d059297112922cabb0c674840589be8db821fd9aAdam Langley sshkey_drop_cert(plain); 1316d059297112922cabb0c674840589be8db821fd9aAdam Langley if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) { 1317d059297112922cabb0c674840589be8db821fd9aAdam Langley if (flags & DNS_VERIFY_FOUND) { 1318d059297112922cabb0c674840589be8db821fd9aAdam Langley if (options.verify_host_key_dns == 1 && 1319d059297112922cabb0c674840589be8db821fd9aAdam Langley flags & DNS_VERIFY_MATCH && 1320d059297112922cabb0c674840589be8db821fd9aAdam Langley flags & DNS_VERIFY_SECURE) { 1321d059297112922cabb0c674840589be8db821fd9aAdam Langley r = 0; 1322d059297112922cabb0c674840589be8db821fd9aAdam Langley goto out; 1323d059297112922cabb0c674840589be8db821fd9aAdam Langley } 1324d059297112922cabb0c674840589be8db821fd9aAdam Langley if (flags & DNS_VERIFY_MATCH) { 1325d059297112922cabb0c674840589be8db821fd9aAdam Langley matching_host_key_dns = 1; 1326d059297112922cabb0c674840589be8db821fd9aAdam Langley } else { 1327d059297112922cabb0c674840589be8db821fd9aAdam Langley warn_changed_key(plain); 1328d059297112922cabb0c674840589be8db821fd9aAdam Langley error("Update the SSHFP RR in DNS " 1329d059297112922cabb0c674840589be8db821fd9aAdam Langley "with the new host key to get rid " 1330d059297112922cabb0c674840589be8db821fd9aAdam Langley "of this message."); 1331d059297112922cabb0c674840589be8db821fd9aAdam Langley } 1332bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1333bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1334bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1335d059297112922cabb0c674840589be8db821fd9aAdam Langley r = check_host_key(host, hostaddr, options.port, host_key, RDRW, 1336bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.user_hostfiles, options.num_user_hostfiles, 1337bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman options.system_hostfiles, options.num_system_hostfiles); 1338d059297112922cabb0c674840589be8db821fd9aAdam Langley 1339d059297112922cabb0c674840589be8db821fd9aAdam Langleyout: 1340d059297112922cabb0c674840589be8db821fd9aAdam Langley sshkey_free(plain); 1341d059297112922cabb0c674840589be8db821fd9aAdam Langley free(fp); 13429768ca48f57aaf035f508a473421d210b5145e99Greg Hartman free(cafp); 1343d059297112922cabb0c674840589be8db821fd9aAdam Langley if (r == 0 && host_key != NULL) { 1344d059297112922cabb0c674840589be8db821fd9aAdam Langley key_free(previous_host_key); 1345d059297112922cabb0c674840589be8db821fd9aAdam Langley previous_host_key = key_from_private(host_key); 1346d059297112922cabb0c674840589be8db821fd9aAdam Langley } 1347d059297112922cabb0c674840589be8db821fd9aAdam Langley 1348d059297112922cabb0c674840589be8db821fd9aAdam Langley return r; 1349bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 1350bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1351bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* 1352bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Starts a dialog with the server, and authenticates the current user on the 1353bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * server. This does not need any extra privileges. The basic connection 1354bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * to the server must already have been established before this is called. 1355bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * If login fails, this function prints an error and never returns. 1356bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * This function does not require super-user privileges. 1357bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 1358bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanvoid 1359bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanssh_login(Sensitive *sensitive, const char *orighost, 1360bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms) 1361bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 1362d059297112922cabb0c674840589be8db821fd9aAdam Langley char *host; 1363bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *server_user, *local_user; 1364bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1365bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman local_user = xstrdup(pw->pw_name); 1366bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman server_user = options.user ? options.user : local_user; 1367bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1368bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Convert the user-supplied hostname into all lowercase. */ 1369bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman host = xstrdup(orighost); 1370d059297112922cabb0c674840589be8db821fd9aAdam Langley lowercase(host); 1371bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1372bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Exchange protocol version identification strings with the server. */ 1373bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ssh_exchange_identification(timeout_ms); 1374bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1375bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* Put the connection into non-blocking mode. */ 1376bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman packet_set_nonblocking(); 1377bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1378bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* key exchange */ 1379bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman /* authenticate user */ 1380ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman debug("Authenticating to %s:%d as '%s'", host, port, server_user); 1381bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (compat20) { 1382bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ssh_kex2(host, hostaddr, port); 1383bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ssh_userauth2(local_user, server_user, host, sensitive); 1384bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else { 1385d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1 1386bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ssh_kex(host, hostaddr); 1387bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ssh_userauth1(local_user, server_user, host, sensitive); 1388d059297112922cabb0c674840589be8db821fd9aAdam Langley#else 1389ccacbc9b0331c30b8be12e8e0349e983abf28fc0Greg Hartman fatal("ssh1 is not supported"); 1390d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif 1391bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1392d059297112922cabb0c674840589be8db821fd9aAdam Langley free(local_user); 1393bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 1394bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1395bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanvoid 1396bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanssh_put_password(char *password) 1397bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 1398bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int size; 1399bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *padded; 1400bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1401bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (datafellows & SSH_BUG_PASSWORDPAD) { 1402bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman packet_put_cstring(password); 1403bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return; 1404bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 14059768ca48f57aaf035f508a473421d210b5145e99Greg Hartman size = ROUNDUP(strlen(password) + 1, 32); 1406bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman padded = xcalloc(1, size); 1407bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman strlcpy(padded, password, size); 1408bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman packet_put_string(padded, size); 1409d059297112922cabb0c674840589be8db821fd9aAdam Langley explicit_bzero(padded, size); 1410d059297112922cabb0c674840589be8db821fd9aAdam Langley free(padded); 1411bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 1412bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1413bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* print all known host keys for a given host, but skip keys of given type */ 1414bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int 1415bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanshow_other_keys(struct hostkeys *hostkeys, Key *key) 1416bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 1417d059297112922cabb0c674840589be8db821fd9aAdam Langley int type[] = { 1418d059297112922cabb0c674840589be8db821fd9aAdam Langley KEY_RSA1, 1419d059297112922cabb0c674840589be8db821fd9aAdam Langley KEY_RSA, 1420d059297112922cabb0c674840589be8db821fd9aAdam Langley KEY_DSA, 1421d059297112922cabb0c674840589be8db821fd9aAdam Langley KEY_ECDSA, 1422d059297112922cabb0c674840589be8db821fd9aAdam Langley KEY_ED25519, 1423d059297112922cabb0c674840589be8db821fd9aAdam Langley -1 1424d059297112922cabb0c674840589be8db821fd9aAdam Langley }; 1425bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int i, ret = 0; 1426bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *fp, *ra; 1427bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman const struct hostkey_entry *found; 1428bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1429bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman for (i = 0; type[i] != -1; i++) { 1430bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (type[i] == key->type) 1431bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 1432bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found)) 1433bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman continue; 1434d059297112922cabb0c674840589be8db821fd9aAdam Langley fp = sshkey_fingerprint(found->key, 1435d059297112922cabb0c674840589be8db821fd9aAdam Langley options.fingerprint_hash, SSH_FP_DEFAULT); 1436d059297112922cabb0c674840589be8db821fd9aAdam Langley ra = sshkey_fingerprint(found->key, 1437d059297112922cabb0c674840589be8db821fd9aAdam Langley options.fingerprint_hash, SSH_FP_RANDOMART); 1438d059297112922cabb0c674840589be8db821fd9aAdam Langley if (fp == NULL || ra == NULL) 1439d059297112922cabb0c674840589be8db821fd9aAdam Langley fatal("%s: sshkey_fingerprint fail", __func__); 1440bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman logit("WARNING: %s key found for host %s\n" 1441bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "in %s:%lu\n" 1442bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman "%s key fingerprint %s.", 1443bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman key_type(found->key), 1444bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman found->host, found->file, found->line, 1445bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman key_type(found->key), fp); 1446bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (options.visual_host_key) 1447bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman logit("%s", ra); 1448d059297112922cabb0c674840589be8db821fd9aAdam Langley free(ra); 1449d059297112922cabb0c674840589be8db821fd9aAdam Langley free(fp); 1450bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman ret = 1; 1451bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } 1452bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return ret; 1453bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 1454bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1455bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic void 1456bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanwarn_changed_key(Key *host_key) 1457bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 1458bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *fp; 1459bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1460d059297112922cabb0c674840589be8db821fd9aAdam Langley fp = sshkey_fingerprint(host_key, options.fingerprint_hash, 1461d059297112922cabb0c674840589be8db821fd9aAdam Langley SSH_FP_DEFAULT); 1462d059297112922cabb0c674840589be8db821fd9aAdam Langley if (fp == NULL) 1463d059297112922cabb0c674840589be8db821fd9aAdam Langley fatal("%s: sshkey_fingerprint fail", __func__); 1464bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1465bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1466bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); 1467bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 1468bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); 1469bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); 1470bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("It is also possible that a host key has just been changed."); 1471bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("The fingerprint for the %s key sent by the remote host is\n%s.", 1472bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman key_type(host_key), fp); 1473bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Please contact your system administrator."); 1474bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1475d059297112922cabb0c674840589be8db821fd9aAdam Langley free(fp); 1476bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 1477bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1478bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* 1479bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Execute a local command 1480bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */ 1481bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint 1482bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanssh_local_cmd(const char *args) 1483bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{ 1484bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman char *shell; 1485bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman pid_t pid; 1486bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman int status; 1487bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman void (*osighand)(int); 1488bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1489bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!options.permit_local_command || 1490bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman args == NULL || !*args) 1491bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return (1); 1492bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1493bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if ((shell = getenv("SHELL")) == NULL || *shell == '\0') 1494bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman shell = _PATH_BSHELL; 1495bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1496bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman osighand = signal(SIGCHLD, SIG_DFL); 1497bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman pid = fork(); 1498bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (pid == 0) { 1499bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman signal(SIGPIPE, SIG_DFL); 1500bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman debug3("Executing %s -c \"%s\"", shell, args); 1501bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman execl(shell, shell, "-c", args, (char *)NULL); 1502bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman error("Couldn't execute %s -c \"%s\": %s", 1503bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman shell, args, strerror(errno)); 1504bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman _exit(1); 1505bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman } else if (pid == -1) 1506bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("fork failed: %.100s", strerror(errno)); 1507bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman while (waitpid(pid, &status, 0) == -1) 1508bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (errno != EINTR) 1509bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman fatal("Couldn't wait for child: %s", strerror(errno)); 1510bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman signal(SIGCHLD, osighand); 1511bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1512bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman if (!WIFEXITED(status)) 1513bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return (1); 1514bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman 1515bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman return (WEXITSTATUS(status)); 1516bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman} 15179768ca48f57aaf035f508a473421d210b5145e99Greg Hartman 15189768ca48f57aaf035f508a473421d210b5145e99Greg Hartmanvoid 15199768ca48f57aaf035f508a473421d210b5145e99Greg Hartmanmaybe_add_key_to_agent(char *authfile, Key *private, char *comment, 15209768ca48f57aaf035f508a473421d210b5145e99Greg Hartman char *passphrase) 15219768ca48f57aaf035f508a473421d210b5145e99Greg Hartman{ 15229768ca48f57aaf035f508a473421d210b5145e99Greg Hartman int auth_sock = -1, r; 15239768ca48f57aaf035f508a473421d210b5145e99Greg Hartman 15249768ca48f57aaf035f508a473421d210b5145e99Greg Hartman if (options.add_keys_to_agent == 0) 15259768ca48f57aaf035f508a473421d210b5145e99Greg Hartman return; 15269768ca48f57aaf035f508a473421d210b5145e99Greg Hartman 15279768ca48f57aaf035f508a473421d210b5145e99Greg Hartman if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) { 15289768ca48f57aaf035f508a473421d210b5145e99Greg Hartman debug3("no authentication agent, not adding key"); 15299768ca48f57aaf035f508a473421d210b5145e99Greg Hartman return; 15309768ca48f57aaf035f508a473421d210b5145e99Greg Hartman } 15319768ca48f57aaf035f508a473421d210b5145e99Greg Hartman 15329768ca48f57aaf035f508a473421d210b5145e99Greg Hartman if (options.add_keys_to_agent == 2 && 15339768ca48f57aaf035f508a473421d210b5145e99Greg Hartman !ask_permission("Add key %s (%s) to agent?", authfile, comment)) { 15349768ca48f57aaf035f508a473421d210b5145e99Greg Hartman debug3("user denied adding this key"); 15359768ca48f57aaf035f508a473421d210b5145e99Greg Hartman close(auth_sock); 15369768ca48f57aaf035f508a473421d210b5145e99Greg Hartman return; 15379768ca48f57aaf035f508a473421d210b5145e99Greg Hartman } 15389768ca48f57aaf035f508a473421d210b5145e99Greg Hartman 15399768ca48f57aaf035f508a473421d210b5145e99Greg Hartman if ((r = ssh_add_identity_constrained(auth_sock, private, comment, 0, 15409768ca48f57aaf035f508a473421d210b5145e99Greg Hartman (options.add_keys_to_agent == 3))) == 0) 15419768ca48f57aaf035f508a473421d210b5145e99Greg Hartman debug("identity added to agent: %s", authfile); 15429768ca48f57aaf035f508a473421d210b5145e99Greg Hartman else 15439768ca48f57aaf035f508a473421d210b5145e99Greg Hartman debug("could not add identity to agent: %s (%d)", authfile, r); 15449768ca48f57aaf035f508a473421d210b5145e99Greg Hartman close(auth_sock); 15459768ca48f57aaf035f508a473421d210b5145e99Greg Hartman} 1546