1323124Sdes/* $OpenBSD: ssh.c,v 1.445 2016/07/17 04:20:16 djm Exp $ */ 257429Smarkm/* 357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 557429Smarkm * All rights reserved 657429Smarkm * Ssh client program. This program can be used to log into a remote machine. 757429Smarkm * The software supports strong authentication, encryption, and forwarding 857429Smarkm * of X11, TCP/IP, and authentication connections. 957429Smarkm * 1065674Skris * As far as I am concerned, the code I have written for this software 1165674Skris * can be used freely for any purpose. Any derived versions of this 1265674Skris * software must be clearly marked as such, and if the derived work is 1365674Skris * incompatible with the protocol description in the RFC file, it must be 1465674Skris * called by a name other than "ssh" or "Secure Shell". 1557432Smarkm * 1665674Skris * Copyright (c) 1999 Niels Provos. All rights reserved. 17126277Sdes * Copyright (c) 2000, 2001, 2002, 2003 Markus Friedl. All rights reserved. 1865674Skris * 1965674Skris * Modified to work with SSL by Niels Provos <provos@citi.umich.edu> 2065674Skris * in Canada (German citizen). 2165674Skris * 2265674Skris * Redistribution and use in source and binary forms, with or without 2365674Skris * modification, are permitted provided that the following conditions 2465674Skris * are met: 2565674Skris * 1. Redistributions of source code must retain the above copyright 2665674Skris * notice, this list of conditions and the following disclaimer. 2765674Skris * 2. Redistributions in binary form must reproduce the above copyright 2865674Skris * notice, this list of conditions and the following disclaimer in the 2965674Skris * documentation and/or other materials provided with the distribution. 3065674Skris * 3165674Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 3265674Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 3365674Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 3465674Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 3565674Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 3665674Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3765674Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3865674Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3965674Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 4065674Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4157429Smarkm */ 4257429Smarkm 4357429Smarkm#include "includes.h" 44162856Sdes__RCSID("$FreeBSD: stable/10/crypto/openssh/ssh.c 323124 2017-09-01 22:52:18Z des $"); 4557429Smarkm 46162856Sdes#include <sys/types.h> 47162856Sdes#ifdef HAVE_SYS_STAT_H 48162856Sdes# include <sys/stat.h> 49162856Sdes#endif 50162856Sdes#include <sys/resource.h> 51162856Sdes#include <sys/ioctl.h> 52162856Sdes#include <sys/socket.h> 53221420Sdes#include <sys/wait.h> 54162856Sdes 55162856Sdes#include <ctype.h> 56162856Sdes#include <errno.h> 57162856Sdes#include <fcntl.h> 58162856Sdes#include <netdb.h> 59162856Sdes#ifdef HAVE_PATHS_H 60162856Sdes#include <paths.h> 61162856Sdes#endif 62162856Sdes#include <pwd.h> 63162856Sdes#include <signal.h> 64162856Sdes#include <stdarg.h> 65162856Sdes#include <stddef.h> 66162856Sdes#include <stdio.h> 67162856Sdes#include <stdlib.h> 68162856Sdes#include <string.h> 69162856Sdes#include <unistd.h> 70295367Sdes#include <limits.h> 71323124Sdes#include <locale.h> 72162856Sdes 73162856Sdes#include <netinet/in.h> 74162856Sdes#include <arpa/inet.h> 75162856Sdes 76295367Sdes#ifdef WITH_OPENSSL 7760576Skris#include <openssl/evp.h> 7876262Sgreen#include <openssl/err.h> 79295367Sdes#endif 80181111Sdes#include "openbsd-compat/openssl-compat.h" 81181111Sdes#include "openbsd-compat/sys-queue.h" 8260576Skris 83162856Sdes#include "xmalloc.h" 8476262Sgreen#include "ssh.h" 8576262Sgreen#include "ssh1.h" 8676262Sgreen#include "ssh2.h" 87215116Sdes#include "canohost.h" 8876262Sgreen#include "compat.h" 8976262Sgreen#include "cipher.h" 90295367Sdes#include "digest.h" 9157429Smarkm#include "packet.h" 9257429Smarkm#include "buffer.h" 9360576Skris#include "channels.h" 9460576Skris#include "key.h" 9565674Skris#include "authfd.h" 9660576Skris#include "authfile.h" 9776262Sgreen#include "pathnames.h" 98137019Sdes#include "dispatch.h" 9976262Sgreen#include "clientloop.h" 10076262Sgreen#include "log.h" 101295367Sdes#include "misc.h" 10276262Sgreen#include "readconf.h" 10376262Sgreen#include "sshconnect.h" 10476262Sgreen#include "kex.h" 10576262Sgreen#include "mac.h" 106137019Sdes#include "sshpty.h" 107137019Sdes#include "match.h" 108137019Sdes#include "msg.h" 109137019Sdes#include "uidswap.h" 110162856Sdes#include "version.h" 111295367Sdes#include "ssherr.h" 112295367Sdes#include "myproposal.h" 11360576Skris 114204917Sdes#ifdef ENABLE_PKCS11 115204917Sdes#include "ssh-pkcs11.h" 11692559Sdes#endif 11792559Sdes 11860576Skrisextern char *__progname; 11960576Skris 120226046Sdes/* Saves a copy of argv for setproctitle emulation */ 121226046Sdes#ifndef HAVE_SETPROCTITLE 122226046Sdesstatic char **saved_av; 123226046Sdes#endif 124226046Sdes 125181111Sdes/* Flag indicating whether debug mode is on. May be set on the command line. */ 12657429Smarkmint debug_flag = 0; 12757429Smarkm 128226046Sdes/* Flag indicating whether a tty should be requested */ 12957429Smarkmint tty_flag = 0; 13057429Smarkm 13160576Skris/* don't exec a shell */ 13260576Skrisint no_shell_flag = 0; 13360576Skris 13457429Smarkm/* 13557429Smarkm * Flag indicating that nothing should be read from stdin. This can be set 13657429Smarkm * on the command line. 13757429Smarkm */ 13857429Smarkmint stdin_null_flag = 0; 13957429Smarkm 14057429Smarkm/* 141215116Sdes * Flag indicating that the current process should be backgrounded and 142215116Sdes * a new slave launched in the foreground for ControlPersist. 143215116Sdes */ 144215116Sdesint need_controlpersist_detach = 0; 145215116Sdes 146215116Sdes/* Copies of flags for ControlPersist foreground slave */ 147226046Sdesint ostdin_null_flag, ono_shell_flag, otty_flag, orequest_tty; 148215116Sdes 149215116Sdes/* 15057429Smarkm * Flag indicating that ssh should fork after authentication. This is useful 15198684Sdes * so that the passphrase can be entered manually, and then ssh goes to the 15257429Smarkm * background. 15357429Smarkm */ 15457429Smarkmint fork_after_authentication_flag = 0; 15557429Smarkm 15657429Smarkm/* 15757429Smarkm * General data structure for command line options and options configurable 15857429Smarkm * in configuration files. See readconf.h. 15957429Smarkm */ 16057429SmarkmOptions options; 16157429Smarkm 16292559Sdes/* optional user configfile */ 16392559Sdeschar *config = NULL; 16492559Sdes 16557429Smarkm/* 16657429Smarkm * Name of the host we are connecting to. This is the name given on the 16757429Smarkm * command line, or the HostName specified for the user-supplied name in a 16857429Smarkm * configuration file. 16957429Smarkm */ 17057429Smarkmchar *host; 17157429Smarkm 17257429Smarkm/* socket address the host resolves to */ 17357429Smarkmstruct sockaddr_storage hostaddr; 17457429Smarkm 17576262Sgreen/* Private host keys. */ 17698684SdesSensitive sensitive_data; 17757429Smarkm 17857429Smarkm/* Original real UID. */ 17957429Smarkmuid_t original_real_uid; 18098684Sdesuid_t original_effective_uid; 18157429Smarkm 18260576Skris/* command to be executed */ 18360576SkrisBuffer command; 18460576Skris 18576262Sgreen/* Should we execute a command or invoke a subsystem? */ 18676262Sgreenint subsystem_flag = 0; 18776262Sgreen 18898684Sdes/* # of replies received for global requests */ 189181111Sdesstatic int remote_forward_confirms_received = 0; 19098684Sdes 191181111Sdes/* mux.c */ 192181111Sdesextern int muxserver_sock; 193181111Sdesextern u_int muxclient_command; 194137019Sdes 19557429Smarkm/* Prints a help message to the user. This function never returns. */ 19657429Smarkm 19792559Sdesstatic void 19876262Sgreenusage(void) 19957429Smarkm{ 200128460Sdes fprintf(stderr, 201295367Sdes"usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n" 202255767Sdes" [-D [bind_address:]port] [-E log_file] [-e escape_char]\n" 203323124Sdes" [-F configfile] [-I pkcs11] [-i identity_file]\n" 204323124Sdes" [-J [user@]host[:port]] [-L address] [-l login_name] [-m mac_spec]\n" 205323124Sdes" [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address]\n" 206323124Sdes" [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]\n" 207323124Sdes" [user@]hostname [command]\n" 208128460Sdes ); 209157019Sdes exit(255); 21057429Smarkm} 21157429Smarkm 21292559Sdesstatic int ssh_session(void); 21392559Sdesstatic int ssh_session2(void); 21492559Sdesstatic void load_public_identity_files(void); 215221420Sdesstatic void main_sigchld_handler(int); 21660576Skris 217181111Sdes/* from muxclient.c */ 218181111Sdesvoid muxclient(const char *); 219181111Sdesvoid muxserver_listen(void); 220181111Sdes 221226046Sdes/* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */ 222226046Sdesstatic void 223226046Sdestilde_expand_paths(char **paths, u_int num_paths) 224226046Sdes{ 225226046Sdes u_int i; 226226046Sdes char *cp; 227226046Sdes 228226046Sdes for (i = 0; i < num_paths; i++) { 229226046Sdes cp = tilde_expand_filename(paths[i], original_real_uid); 230255767Sdes free(paths[i]); 231226046Sdes paths[i] = cp; 232226046Sdes } 233226046Sdes} 234226046Sdes 235264377Sdes/* 236264377Sdes * Attempt to resolve a host name / port to a set of addresses and 237264377Sdes * optionally return any CNAMEs encountered along the way. 238264377Sdes * Returns NULL on failure. 239264377Sdes * NB. this function must operate with a options having undefined members. 240264377Sdes */ 241262566Sdesstatic struct addrinfo * 242264377Sdesresolve_host(const char *name, int port, int logerr, char *cname, size_t clen) 243262566Sdes{ 244262566Sdes char strport[NI_MAXSERV]; 245262566Sdes struct addrinfo hints, *res; 246262566Sdes int gaierr, loglevel = SYSLOG_LEVEL_DEBUG1; 247262566Sdes 248264377Sdes if (port <= 0) 249264377Sdes port = default_ssh_port(); 250264377Sdes 251296781Sdes snprintf(strport, sizeof strport, "%d", port); 252264377Sdes memset(&hints, 0, sizeof(hints)); 253264377Sdes hints.ai_family = options.address_family == -1 ? 254264377Sdes AF_UNSPEC : options.address_family; 255262566Sdes hints.ai_socktype = SOCK_STREAM; 256262566Sdes if (cname != NULL) 257262566Sdes hints.ai_flags = AI_CANONNAME; 258262566Sdes if ((gaierr = getaddrinfo(name, strport, &hints, &res)) != 0) { 259262566Sdes if (logerr || (gaierr != EAI_NONAME && gaierr != EAI_NODATA)) 260262566Sdes loglevel = SYSLOG_LEVEL_ERROR; 261262566Sdes do_log2(loglevel, "%s: Could not resolve hostname %.100s: %s", 262262566Sdes __progname, name, ssh_gai_strerror(gaierr)); 263262566Sdes return NULL; 264262566Sdes } 265262566Sdes if (cname != NULL && res->ai_canonname != NULL) { 266262566Sdes if (strlcpy(cname, res->ai_canonname, clen) >= clen) { 267262566Sdes error("%s: host \"%s\" cname \"%s\" too long (max %lu)", 268262566Sdes __func__, name, res->ai_canonname, (u_long)clen); 269262566Sdes if (clen > 0) 270262566Sdes *cname = '\0'; 271262566Sdes } 272262566Sdes } 273262566Sdes return res; 274262566Sdes} 275262566Sdes 27657429Smarkm/* 277295367Sdes * Attempt to resolve a numeric host address / port to a single address. 278295367Sdes * Returns a canonical address string. 279295367Sdes * Returns NULL on failure. 280295367Sdes * NB. this function must operate with a options having undefined members. 281295367Sdes */ 282295367Sdesstatic struct addrinfo * 283295367Sdesresolve_addr(const char *name, int port, char *caddr, size_t clen) 284295367Sdes{ 285295367Sdes char addr[NI_MAXHOST], strport[NI_MAXSERV]; 286295367Sdes struct addrinfo hints, *res; 287295367Sdes int gaierr; 288295367Sdes 289295367Sdes if (port <= 0) 290295367Sdes port = default_ssh_port(); 291295367Sdes snprintf(strport, sizeof strport, "%u", port); 292295367Sdes memset(&hints, 0, sizeof(hints)); 293295367Sdes hints.ai_family = options.address_family == -1 ? 294295367Sdes AF_UNSPEC : options.address_family; 295295367Sdes hints.ai_socktype = SOCK_STREAM; 296295367Sdes hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV; 297295367Sdes if ((gaierr = getaddrinfo(name, strport, &hints, &res)) != 0) { 298295367Sdes debug2("%s: could not resolve name %.100s as address: %s", 299295367Sdes __func__, name, ssh_gai_strerror(gaierr)); 300295367Sdes return NULL; 301295367Sdes } 302295367Sdes if (res == NULL) { 303295367Sdes debug("%s: getaddrinfo %.100s returned no addresses", 304295367Sdes __func__, name); 305295367Sdes return NULL; 306295367Sdes } 307295367Sdes if (res->ai_next != NULL) { 308295367Sdes debug("%s: getaddrinfo %.100s returned multiple addresses", 309295367Sdes __func__, name); 310295367Sdes goto fail; 311295367Sdes } 312295367Sdes if ((gaierr = getnameinfo(res->ai_addr, res->ai_addrlen, 313295367Sdes addr, sizeof(addr), NULL, 0, NI_NUMERICHOST)) != 0) { 314295367Sdes debug("%s: Could not format address for name %.100s: %s", 315295367Sdes __func__, name, ssh_gai_strerror(gaierr)); 316295367Sdes goto fail; 317295367Sdes } 318295367Sdes if (strlcpy(caddr, addr, clen) >= clen) { 319295367Sdes error("%s: host \"%s\" addr \"%s\" too long (max %lu)", 320295367Sdes __func__, name, addr, (u_long)clen); 321295367Sdes if (clen > 0) 322295367Sdes *caddr = '\0'; 323295367Sdes fail: 324295367Sdes freeaddrinfo(res); 325295367Sdes return NULL; 326295367Sdes } 327295367Sdes return res; 328295367Sdes} 329295367Sdes 330295367Sdes/* 331262566Sdes * Check whether the cname is a permitted replacement for the hostname 332262566Sdes * and perform the replacement if it is. 333264377Sdes * NB. this function must operate with a options having undefined members. 334262566Sdes */ 335262566Sdesstatic int 336323124Sdescheck_follow_cname(int direct, char **namep, const char *cname) 337262566Sdes{ 338262566Sdes int i; 339262566Sdes struct allowed_cname *rule; 340262566Sdes 341262566Sdes if (*cname == '\0' || options.num_permitted_cnames == 0 || 342262566Sdes strcmp(*namep, cname) == 0) 343262566Sdes return 0; 344262566Sdes if (options.canonicalize_hostname == SSH_CANONICALISE_NO) 345262566Sdes return 0; 346262566Sdes /* 347262566Sdes * Don't attempt to canonicalize names that will be interpreted by 348323124Sdes * a proxy or jump host unless the user specifically requests so. 349262566Sdes */ 350323124Sdes if (!direct && 351262566Sdes options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) 352262566Sdes return 0; 353262566Sdes debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname); 354262566Sdes for (i = 0; i < options.num_permitted_cnames; i++) { 355262566Sdes rule = options.permitted_cnames + i; 356295367Sdes if (match_pattern_list(*namep, rule->source_list, 1) != 1 || 357295367Sdes match_pattern_list(cname, rule->target_list, 1) != 1) 358262566Sdes continue; 359262566Sdes verbose("Canonicalized DNS aliased hostname " 360262566Sdes "\"%s\" => \"%s\"", *namep, cname); 361262566Sdes free(*namep); 362262566Sdes *namep = xstrdup(cname); 363262566Sdes return 1; 364262566Sdes } 365262566Sdes return 0; 366262566Sdes} 367262566Sdes 368262566Sdes/* 369262566Sdes * Attempt to resolve the supplied hostname after applying the user's 370262566Sdes * canonicalization rules. Returns the address list for the host or NULL 371262566Sdes * if no name was found after canonicalization. 372264377Sdes * NB. this function must operate with a options having undefined members. 373262566Sdes */ 374262566Sdesstatic struct addrinfo * 375264377Sdesresolve_canonicalize(char **hostp, int port) 376262566Sdes{ 377323124Sdes int i, direct, ndots; 378295367Sdes char *cp, *fullhost, newname[NI_MAXHOST]; 379262566Sdes struct addrinfo *addrs; 380262566Sdes 381262566Sdes if (options.canonicalize_hostname == SSH_CANONICALISE_NO) 382262566Sdes return NULL; 383264377Sdes 384262566Sdes /* 385262566Sdes * Don't attempt to canonicalize names that will be interpreted by 386262566Sdes * a proxy unless the user specifically requests so. 387262566Sdes */ 388323124Sdes direct = option_clear_or_none(options.proxy_command) && 389323124Sdes options.jump_host == NULL; 390323124Sdes if (!direct && 391262566Sdes options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) 392262566Sdes return NULL; 393264377Sdes 394295367Sdes /* Try numeric hostnames first */ 395295367Sdes if ((addrs = resolve_addr(*hostp, port, 396295367Sdes newname, sizeof(newname))) != NULL) { 397295367Sdes debug2("%s: hostname %.100s is address", __func__, *hostp); 398295367Sdes if (strcasecmp(*hostp, newname) != 0) { 399295367Sdes debug2("%s: canonicalised address \"%s\" => \"%s\"", 400295367Sdes __func__, *hostp, newname); 401295367Sdes free(*hostp); 402295367Sdes *hostp = xstrdup(newname); 403295367Sdes } 404295367Sdes return addrs; 405295367Sdes } 406295367Sdes 407296781Sdes /* If domain name is anchored, then resolve it now */ 408296781Sdes if ((*hostp)[strlen(*hostp) - 1] == '.') { 409296781Sdes debug3("%s: name is fully qualified", __func__); 410296781Sdes fullhost = xstrdup(*hostp); 411296781Sdes if ((addrs = resolve_host(fullhost, port, 0, 412296781Sdes newname, sizeof(newname))) != NULL) 413296781Sdes goto found; 414296781Sdes free(fullhost); 415296781Sdes goto notfound; 416296781Sdes } 417296781Sdes 418262566Sdes /* Don't apply canonicalization to sufficiently-qualified hostnames */ 419262566Sdes ndots = 0; 420262566Sdes for (cp = *hostp; *cp != '\0'; cp++) { 421262566Sdes if (*cp == '.') 422262566Sdes ndots++; 423262566Sdes } 424262566Sdes if (ndots > options.canonicalize_max_dots) { 425262566Sdes debug3("%s: not canonicalizing hostname \"%s\" (max dots %d)", 426262566Sdes __func__, *hostp, options.canonicalize_max_dots); 427262566Sdes return NULL; 428262566Sdes } 429262566Sdes /* Attempt each supplied suffix */ 430262566Sdes for (i = 0; i < options.num_canonical_domains; i++) { 431295367Sdes *newname = '\0'; 432262566Sdes xasprintf(&fullhost, "%s.%s.", *hostp, 433262566Sdes options.canonical_domains[i]); 434264377Sdes debug3("%s: attempting \"%s\" => \"%s\"", __func__, 435264377Sdes *hostp, fullhost); 436264377Sdes if ((addrs = resolve_host(fullhost, port, 0, 437295367Sdes newname, sizeof(newname))) == NULL) { 438262566Sdes free(fullhost); 439262566Sdes continue; 440262566Sdes } 441296781Sdes found: 442262566Sdes /* Remove trailing '.' */ 443262566Sdes fullhost[strlen(fullhost) - 1] = '\0'; 444262566Sdes /* Follow CNAME if requested */ 445323124Sdes if (!check_follow_cname(direct, &fullhost, newname)) { 446262566Sdes debug("Canonicalized hostname \"%s\" => \"%s\"", 447262566Sdes *hostp, fullhost); 448262566Sdes } 449262566Sdes free(*hostp); 450262566Sdes *hostp = fullhost; 451262566Sdes return addrs; 452262566Sdes } 453296781Sdes notfound: 454262566Sdes if (!options.canonicalize_fallback_local) 455264377Sdes fatal("%s: Could not resolve host \"%s\"", __progname, *hostp); 456264377Sdes debug2("%s: host %s not found in any suffix", __func__, *hostp); 457262566Sdes return NULL; 458262566Sdes} 459262566Sdes 460262566Sdes/* 461264377Sdes * Read per-user configuration file. Ignore the system wide config 462264377Sdes * file if the user specifies a config file on the command line. 463264377Sdes */ 464264377Sdesstatic void 465295367Sdesprocess_config_files(const char *host_arg, struct passwd *pw, int post_canon) 466264377Sdes{ 467295367Sdes char buf[PATH_MAX]; 468264377Sdes int r; 469264377Sdes 470264377Sdes if (config != NULL) { 471264377Sdes if (strcasecmp(config, "none") != 0 && 472295367Sdes !read_config_file(config, pw, host, host_arg, &options, 473295367Sdes SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0))) 474264377Sdes fatal("Can't open user config file %.100s: " 475264377Sdes "%.100s", config, strerror(errno)); 476264377Sdes } else { 477264377Sdes r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, 478264377Sdes _PATH_SSH_USER_CONFFILE); 479264377Sdes if (r > 0 && (size_t)r < sizeof(buf)) 480295367Sdes (void)read_config_file(buf, pw, host, host_arg, 481295367Sdes &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | 482295367Sdes (post_canon ? SSHCONF_POSTCANON : 0)); 483264377Sdes 484264377Sdes /* Read systemwide configuration file after user config. */ 485295367Sdes (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, 486295367Sdes host, host_arg, &options, 487295367Sdes post_canon ? SSHCONF_POSTCANON : 0); 488264377Sdes } 489264377Sdes} 490264377Sdes 491295367Sdes/* Rewrite the port number in an addrinfo list of addresses */ 492295367Sdesstatic void 493295367Sdesset_addrinfo_port(struct addrinfo *addrs, int port) 494295367Sdes{ 495295367Sdes struct addrinfo *addr; 496295367Sdes 497295367Sdes for (addr = addrs; addr != NULL; addr = addr->ai_next) { 498295367Sdes switch (addr->ai_family) { 499295367Sdes case AF_INET: 500295367Sdes ((struct sockaddr_in *)addr->ai_addr)-> 501295367Sdes sin_port = htons(port); 502295367Sdes break; 503295367Sdes case AF_INET6: 504295367Sdes ((struct sockaddr_in6 *)addr->ai_addr)-> 505295367Sdes sin6_port = htons(port); 506295367Sdes break; 507295367Sdes } 508295367Sdes } 509295367Sdes} 510295367Sdes 511264377Sdes/* 51257429Smarkm * Main program for the ssh client. 51357429Smarkm */ 51457429Smarkmint 51557429Smarkmmain(int ac, char **av) 51657429Smarkm{ 517323124Sdes struct ssh *ssh = NULL; 518323124Sdes int i, r, opt, exit_status, use_syslog, direct, config_test = 0; 519295367Sdes char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile; 520226046Sdes char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; 521296781Sdes char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex; 52257429Smarkm struct stat st; 52376262Sgreen struct passwd *pw; 524262566Sdes int timeout_ms; 52592559Sdes extern int optind, optreset; 52692559Sdes extern char *optarg; 527295367Sdes struct Forward fwd; 528262566Sdes struct addrinfo *addrs = NULL; 529295367Sdes struct ssh_digest_ctx *md; 530295367Sdes u_char conn_hash[SSH_DIGEST_MAX_LENGTH]; 53157429Smarkm 532296781Sdes ssh_malloc_init(); /* must be called before any mallocs */ 533157019Sdes /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 534157019Sdes sanitise_stdfd(); 535157019Sdes 536124211Sdes __progname = ssh_get_progname(av[0]); 53798941Sdes 538226046Sdes#ifndef HAVE_SETPROCTITLE 539226046Sdes /* Prepare for later setproctitle emulation */ 540226046Sdes /* Save argv so it isn't clobbered by setproctitle() emulation */ 541226046Sdes saved_av = xcalloc(ac + 1, sizeof(*saved_av)); 542226046Sdes for (i = 0; i < ac; i++) 543226046Sdes saved_av[i] = xstrdup(av[i]); 544226046Sdes saved_av[i] = NULL; 545226046Sdes compat_init_setproctitle(ac, av); 546226046Sdes av = saved_av; 547226046Sdes#endif 548226046Sdes 54957429Smarkm /* 550215116Sdes * Discard other fds that are hanging around. These can cause problem 551215116Sdes * with backgrounded ssh processes started by ControlPersist. 552215116Sdes */ 553215116Sdes closefrom(STDERR_FILENO + 1); 554215116Sdes 555215116Sdes /* 55657429Smarkm * Save the original real uid. It will be needed later (uid-swapping 55757429Smarkm * may clobber the real uid). 55857429Smarkm */ 55957429Smarkm original_real_uid = getuid(); 56057429Smarkm original_effective_uid = geteuid(); 561126277Sdes 562106130Sdes /* 563106130Sdes * Use uid-swapping to give up root privileges for the duration of 564106130Sdes * option processing. We will re-instantiate the rights when we are 565106130Sdes * ready to create the privileged port, and will permanently drop 566106130Sdes * them when the port has been created (actually, when the connection 567106130Sdes * has been made, as we may need to create the port several times). 568106130Sdes */ 569106130Sdes PRIV_END; 57057429Smarkm 57198941Sdes#ifdef HAVE_SETRLIMIT 57257429Smarkm /* If we are installed setuid root be careful to not drop core. */ 57357429Smarkm if (original_real_uid != original_effective_uid) { 57457429Smarkm struct rlimit rlim; 57557429Smarkm rlim.rlim_cur = rlim.rlim_max = 0; 57657429Smarkm if (setrlimit(RLIMIT_CORE, &rlim) < 0) 57757429Smarkm fatal("setrlimit failed: %.100s", strerror(errno)); 57857429Smarkm } 57998941Sdes#endif 58076262Sgreen /* Get user data. */ 58176262Sgreen pw = getpwuid(original_real_uid); 58276262Sgreen if (!pw) { 583255767Sdes logit("No user exists for uid %lu", (u_long)original_real_uid); 584157019Sdes exit(255); 58576262Sgreen } 58676262Sgreen /* Take a copy of the returned structure. */ 58776262Sgreen pw = pwcopy(pw); 58876262Sgreen 58957429Smarkm /* 59057429Smarkm * Set our umask to something reasonable, as some files are created 59157429Smarkm * with the default umask. This will make them world-readable but 59257429Smarkm * writable only by the owner, which is ok for all files for which we 59357429Smarkm * don't set the modes explicitly. 59457429Smarkm */ 59557429Smarkm umask(022); 59657429Smarkm 597323124Sdes setlocale(LC_CTYPE, ""); 598323124Sdes 599181111Sdes /* 600181111Sdes * Initialize option structure to indicate that no values have been 601181111Sdes * set. 602181111Sdes */ 60357429Smarkm initialize_options(&options); 60457429Smarkm 60557429Smarkm /* Parse command-line arguments. */ 60657429Smarkm host = NULL; 607192595Sdes use_syslog = 0; 608255767Sdes logfile = NULL; 609197679Sdes argv0 = av[0]; 61057429Smarkm 611162856Sdes again: 612181111Sdes while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" 613323124Sdes "ACD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { 61457429Smarkm switch (opt) { 61576262Sgreen case '1': 61676262Sgreen options.protocol = SSH_PROTO_1; 61776262Sgreen break; 61860576Skris case '2': 61960576Skris options.protocol = SSH_PROTO_2; 62060576Skris break; 62157429Smarkm case '4': 622124211Sdes options.address_family = AF_INET; 62357429Smarkm break; 62457429Smarkm case '6': 625124211Sdes options.address_family = AF_INET6; 62657429Smarkm break; 62757429Smarkm case 'n': 62857429Smarkm stdin_null_flag = 1; 62957429Smarkm break; 63057429Smarkm case 'f': 63157429Smarkm fork_after_authentication_flag = 1; 63257429Smarkm stdin_null_flag = 1; 63357429Smarkm break; 63457429Smarkm case 'x': 63557429Smarkm options.forward_x11 = 0; 63657429Smarkm break; 63757429Smarkm case 'X': 63857429Smarkm options.forward_x11 = 1; 63957429Smarkm break; 640192595Sdes case 'y': 641192595Sdes use_syslog = 1; 642192595Sdes break; 643255767Sdes case 'E': 644296781Sdes logfile = optarg; 645255767Sdes break; 646295367Sdes case 'G': 647295367Sdes config_test = 1; 648295367Sdes break; 649126277Sdes case 'Y': 650126277Sdes options.forward_x11 = 1; 651126277Sdes options.forward_x11_trusted = 1; 652126277Sdes break; 65357429Smarkm case 'g': 654295367Sdes options.fwd_opts.gateway_ports = 1; 65557429Smarkm break; 656147005Sdes case 'O': 657323124Sdes if (options.stdio_forward_host != NULL) 658204917Sdes fatal("Cannot specify multiplexing " 659204917Sdes "command with -W"); 660204917Sdes else if (muxclient_command != 0) 661204917Sdes fatal("Multiplexing command already specified"); 662147005Sdes if (strcmp(optarg, "check") == 0) 663181111Sdes muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK; 664215116Sdes else if (strcmp(optarg, "forward") == 0) 665215116Sdes muxclient_command = SSHMUX_COMMAND_FORWARD; 666147005Sdes else if (strcmp(optarg, "exit") == 0) 667181111Sdes muxclient_command = SSHMUX_COMMAND_TERMINATE; 668226046Sdes else if (strcmp(optarg, "stop") == 0) 669226046Sdes muxclient_command = SSHMUX_COMMAND_STOP; 670240075Sdes else if (strcmp(optarg, "cancel") == 0) 671240075Sdes muxclient_command = SSHMUX_COMMAND_CANCEL_FWD; 672147005Sdes else 673147005Sdes fatal("Invalid multiplex command."); 674147005Sdes break; 675106130Sdes case 'P': /* deprecated */ 67657429Smarkm options.use_privileged_port = 0; 67757429Smarkm break; 678262566Sdes case 'Q': 679255767Sdes cp = NULL; 680262566Sdes if (strcmp(optarg, "cipher") == 0) 681262566Sdes cp = cipher_alg_list('\n', 0); 682262566Sdes else if (strcmp(optarg, "cipher-auth") == 0) 683262566Sdes cp = cipher_alg_list('\n', 1); 684262566Sdes else if (strcmp(optarg, "mac") == 0) 685262566Sdes cp = mac_alg_list('\n'); 686262566Sdes else if (strcmp(optarg, "kex") == 0) 687262566Sdes cp = kex_alg_list('\n'); 688262566Sdes else if (strcmp(optarg, "key") == 0) 689262566Sdes cp = key_alg_list(0, 0); 690262566Sdes else if (strcmp(optarg, "key-cert") == 0) 691262566Sdes cp = key_alg_list(1, 0); 692262566Sdes else if (strcmp(optarg, "key-plain") == 0) 693262566Sdes cp = key_alg_list(0, 1); 694295367Sdes else if (strcmp(optarg, "protocol-version") == 0) { 695295367Sdes#ifdef WITH_SSH1 696295367Sdes cp = xstrdup("1\n2"); 697295367Sdes#else 698295367Sdes cp = xstrdup("2"); 699295367Sdes#endif 700295367Sdes } 701255767Sdes if (cp == NULL) 702255767Sdes fatal("Unsupported query \"%s\"", optarg); 703255767Sdes printf("%s\n", cp); 704255767Sdes free(cp); 705255767Sdes exit(0); 706255767Sdes break; 70757429Smarkm case 'a': 70857429Smarkm options.forward_agent = 0; 70957429Smarkm break; 71061203Skris case 'A': 71161203Skris options.forward_agent = 1; 71261203Skris break; 71357429Smarkm case 'k': 714126277Sdes options.gss_deleg_creds = 0; 71557429Smarkm break; 716181111Sdes case 'K': 717181111Sdes options.gss_authentication = 1; 718181111Sdes options.gss_deleg_creds = 1; 719181111Sdes break; 72057429Smarkm case 'i': 721296781Sdes p = tilde_expand_filename(optarg, original_real_uid); 722296781Sdes if (stat(p, &st) < 0) 72392559Sdes fprintf(stderr, "Warning: Identity file %s " 724296781Sdes "not accessible: %s.\n", p, 725147005Sdes strerror(errno)); 726296781Sdes else 727296781Sdes add_identity_file(&options, NULL, p, 1); 728296781Sdes free(p); 72957429Smarkm break; 73092559Sdes case 'I': 731204917Sdes#ifdef ENABLE_PKCS11 732296781Sdes free(options.pkcs11_provider); 733204917Sdes options.pkcs11_provider = xstrdup(optarg); 73492559Sdes#else 735204917Sdes fprintf(stderr, "no support for PKCS#11.\n"); 73692559Sdes#endif 73792559Sdes break; 738323124Sdes case 'J': 739323124Sdes if (options.jump_host != NULL) 740323124Sdes fatal("Only a single -J option permitted"); 741323124Sdes if (options.proxy_command != NULL) 742323124Sdes fatal("Cannot specify -J with ProxyCommand"); 743323124Sdes if (parse_jump(optarg, &options, 1) == -1) 744323124Sdes fatal("Invalid -J argument"); 745323124Sdes options.proxy_command = xstrdup("none"); 746323124Sdes break; 74757429Smarkm case 't': 748226046Sdes if (options.request_tty == REQUEST_TTY_YES) 749226046Sdes options.request_tty = REQUEST_TTY_FORCE; 750226046Sdes else 751226046Sdes options.request_tty = REQUEST_TTY_YES; 75257429Smarkm break; 75357429Smarkm case 'v': 754124211Sdes if (debug_flag == 0) { 75569591Sgreen debug_flag = 1; 75669591Sgreen options.log_level = SYSLOG_LEVEL_DEBUG1; 757124211Sdes } else { 758323124Sdes if (options.log_level < SYSLOG_LEVEL_DEBUG3) { 759323124Sdes debug_flag++; 760124211Sdes options.log_level++; 761323124Sdes } 762124211Sdes } 763255767Sdes break; 76457429Smarkm case 'V': 765240075Sdes if (options.version_addendum && 766240075Sdes *options.version_addendum != '\0') 767294693Sdes fprintf(stderr, "%s %s, %s\n", SSH_RELEASE, 768240075Sdes options.version_addendum, 769295367Sdes OPENSSL_VERSION); 770240075Sdes else 771294693Sdes fprintf(stderr, "%s, %s\n", SSH_RELEASE, 772295367Sdes OPENSSL_VERSION); 77357429Smarkm if (opt == 'V') 77457429Smarkm exit(0); 77557429Smarkm break; 776157019Sdes case 'w': 777157019Sdes if (options.tun_open == -1) 778157019Sdes options.tun_open = SSH_TUNMODE_DEFAULT; 779157019Sdes options.tun_local = a2tun(optarg, &options.tun_remote); 780157019Sdes if (options.tun_local == SSH_TUNID_ERR) { 781181111Sdes fprintf(stderr, 782181111Sdes "Bad tun device '%s'\n", optarg); 783157019Sdes exit(255); 784157019Sdes } 785157019Sdes break; 786204917Sdes case 'W': 787323124Sdes if (options.stdio_forward_host != NULL) 788204917Sdes fatal("stdio forward already specified"); 789204917Sdes if (muxclient_command != 0) 790204917Sdes fatal("Cannot specify stdio forward with -O"); 791204917Sdes if (parse_forward(&fwd, optarg, 1, 0)) { 792323124Sdes options.stdio_forward_host = fwd.listen_host; 793323124Sdes options.stdio_forward_port = fwd.listen_port; 794255767Sdes free(fwd.connect_host); 795204917Sdes } else { 796204917Sdes fprintf(stderr, 797204917Sdes "Bad stdio forwarding specification '%s'\n", 798204917Sdes optarg); 799204917Sdes exit(255); 800204917Sdes } 801226046Sdes options.request_tty = REQUEST_TTY_NO; 802204917Sdes no_shell_flag = 1; 803204917Sdes break; 80457429Smarkm case 'q': 80557429Smarkm options.log_level = SYSLOG_LEVEL_QUIET; 80657429Smarkm break; 80757429Smarkm case 'e': 80857429Smarkm if (optarg[0] == '^' && optarg[2] == 0 && 80992559Sdes (u_char) optarg[1] >= 64 && 81092559Sdes (u_char) optarg[1] < 128) 81176262Sgreen options.escape_char = (u_char) optarg[1] & 31; 81257429Smarkm else if (strlen(optarg) == 1) 81376262Sgreen options.escape_char = (u_char) optarg[0]; 81457429Smarkm else if (strcmp(optarg, "none") == 0) 81592559Sdes options.escape_char = SSH_ESCAPECHAR_NONE; 81657429Smarkm else { 81792559Sdes fprintf(stderr, "Bad escape character '%s'.\n", 81892559Sdes optarg); 819157019Sdes exit(255); 82057429Smarkm } 82157429Smarkm break; 82257429Smarkm case 'c': 823295367Sdes if (ciphers_valid(*optarg == '+' ? 824295367Sdes optarg + 1 : optarg)) { 82560576Skris /* SSH2 only */ 826296781Sdes free(options.ciphers); 82760576Skris options.ciphers = xstrdup(optarg); 828137019Sdes options.cipher = SSH_CIPHER_INVALID; 829295367Sdes break; 83057429Smarkm } 831295367Sdes /* SSH1 only */ 832295367Sdes options.cipher = cipher_number(optarg); 833295367Sdes if (options.cipher == -1) { 834295367Sdes fprintf(stderr, "Unknown cipher type '%s'\n", 835295367Sdes optarg); 836295367Sdes exit(255); 837295367Sdes } 838295367Sdes if (options.cipher == SSH_CIPHER_3DES) 839295367Sdes options.ciphers = xstrdup("3des-cbc"); 840295367Sdes else if (options.cipher == SSH_CIPHER_BLOWFISH) 841295367Sdes options.ciphers = xstrdup("blowfish-cbc"); 842295367Sdes else 843295367Sdes options.ciphers = xstrdup(KEX_CLIENT_ENCRYPT); 84457429Smarkm break; 84576262Sgreen case 'm': 846296781Sdes if (mac_valid(optarg)) { 847296781Sdes free(options.macs); 84876262Sgreen options.macs = xstrdup(optarg); 849296781Sdes } else { 85092559Sdes fprintf(stderr, "Unknown mac type '%s'\n", 85192559Sdes optarg); 852157019Sdes exit(255); 85376262Sgreen } 85476262Sgreen break; 855137019Sdes case 'M': 856149753Sdes if (options.control_master == SSHCTL_MASTER_YES) 857149753Sdes options.control_master = SSHCTL_MASTER_ASK; 858149753Sdes else 859149753Sdes options.control_master = SSHCTL_MASTER_YES; 860137019Sdes break; 86157429Smarkm case 'p': 86276262Sgreen options.port = a2port(optarg); 863192595Sdes if (options.port <= 0) { 86476262Sgreen fprintf(stderr, "Bad port '%s'\n", optarg); 865157019Sdes exit(255); 86676262Sgreen } 86757429Smarkm break; 86857429Smarkm case 'l': 86957429Smarkm options.user = optarg; 87057429Smarkm break; 87192559Sdes 87292559Sdes case 'L': 873192595Sdes if (parse_forward(&fwd, optarg, 0, 0)) 874147005Sdes add_local_forward(&options, &fwd); 875147005Sdes else { 87692559Sdes fprintf(stderr, 877147005Sdes "Bad local forwarding specification '%s'\n", 87892559Sdes optarg); 879157019Sdes exit(255); 88057429Smarkm } 881147005Sdes break; 882147005Sdes 883147005Sdes case 'R': 884192595Sdes if (parse_forward(&fwd, optarg, 0, 1)) { 885147005Sdes add_remote_forward(&options, &fwd); 886147005Sdes } else { 88792559Sdes fprintf(stderr, 888147005Sdes "Bad remote forwarding specification " 889147005Sdes "'%s'\n", optarg); 890157019Sdes exit(255); 89157429Smarkm } 89257429Smarkm break; 89376262Sgreen 89476262Sgreen case 'D': 895192595Sdes if (parse_forward(&fwd, optarg, 1, 0)) { 896192595Sdes add_local_forward(&options, &fwd); 897147005Sdes } else { 898192595Sdes fprintf(stderr, 899192595Sdes "Bad dynamic forwarding specification " 900192595Sdes "'%s'\n", optarg); 901157019Sdes exit(255); 90276262Sgreen } 90376262Sgreen break; 90476262Sgreen 90557429Smarkm case 'C': 90657429Smarkm options.compression = 1; 90757429Smarkm break; 90860576Skris case 'N': 90960576Skris no_shell_flag = 1; 910226046Sdes options.request_tty = REQUEST_TTY_NO; 91160576Skris break; 91260576Skris case 'T': 913226046Sdes options.request_tty = REQUEST_TTY_NO; 91460576Skris break; 91557429Smarkm case 'o': 916126277Sdes line = xstrdup(optarg); 917295367Sdes if (process_config_line(&options, pw, 918295367Sdes host ? host : "", host ? host : "", line, 919295367Sdes "command-line", 0, NULL, SSHCONF_USERCONF) != 0) 920157019Sdes exit(255); 921255767Sdes free(line); 92257429Smarkm break; 92376262Sgreen case 's': 92476262Sgreen subsystem_flag = 1; 92576262Sgreen break; 926137019Sdes case 'S': 927296781Sdes free(options.control_path); 928137019Sdes options.control_path = xstrdup(optarg); 929137019Sdes break; 93092559Sdes case 'b': 93192559Sdes options.bind_address = optarg; 93292559Sdes break; 93392559Sdes case 'F': 93492559Sdes config = optarg; 93592559Sdes break; 93657429Smarkm default: 93757429Smarkm usage(); 93857429Smarkm } 93957429Smarkm } 94057429Smarkm 94192559Sdes ac -= optind; 94292559Sdes av += optind; 94392559Sdes 944204917Sdes if (ac > 0 && !host) { 945113911Sdes if (strrchr(*av, '@')) { 94692559Sdes p = xstrdup(*av); 947113911Sdes cp = strrchr(p, '@'); 94892559Sdes if (cp == NULL || cp == p) 94992559Sdes usage(); 95092559Sdes options.user = p; 95192559Sdes *cp = '\0'; 952262566Sdes host = xstrdup(++cp); 95392559Sdes } else 954262566Sdes host = xstrdup(*av); 955113911Sdes if (ac > 1) { 956113911Sdes optind = optreset = 1; 95792559Sdes goto again; 95892559Sdes } 959113911Sdes ac--, av++; 96092559Sdes } 96192559Sdes 96257429Smarkm /* Check that we got a host name. */ 96357429Smarkm if (!host) 96457429Smarkm usage(); 96557429Smarkm 966262566Sdes host_arg = xstrdup(host); 967262566Sdes 968295367Sdes#ifdef WITH_OPENSSL 969221420Sdes OpenSSL_add_all_algorithms(); 97076262Sgreen ERR_load_crypto_strings(); 971295367Sdes#endif 97257429Smarkm 97357429Smarkm /* Initialize the command to execute on remote host. */ 97457429Smarkm buffer_init(&command); 97557429Smarkm 97657429Smarkm /* 97757429Smarkm * Save the command to execute on the remote host in a buffer. There 97857429Smarkm * is no limit on the length of the command, except by the maximum 97957429Smarkm * packet size. Also sets the tty flag if there is no command. 98057429Smarkm */ 98192559Sdes if (!ac) { 98257429Smarkm /* No command specified - execute shell on a tty. */ 98376262Sgreen if (subsystem_flag) { 98492559Sdes fprintf(stderr, 98592559Sdes "You must specify a subsystem to invoke.\n"); 98676262Sgreen usage(); 98776262Sgreen } 98857429Smarkm } else { 98992559Sdes /* A command has been specified. Store it into the buffer. */ 99092559Sdes for (i = 0; i < ac; i++) { 99192559Sdes if (i) 99257429Smarkm buffer_append(&command, " ", 1); 99357429Smarkm buffer_append(&command, av[i], strlen(av[i])); 99457429Smarkm } 99557429Smarkm } 99657429Smarkm 99757429Smarkm /* Cannot fork to background if no command. */ 998181111Sdes if (fork_after_authentication_flag && buffer_len(&command) == 0 && 999181111Sdes !no_shell_flag) 1000181111Sdes fatal("Cannot fork into background without a command " 1001181111Sdes "to execute."); 100257429Smarkm 100376262Sgreen /* 100476262Sgreen * Initialize "log" output. Since we are the client all output 1005255767Sdes * goes to stderr unless otherwise specified by -y or -E. 100676262Sgreen */ 1007255767Sdes if (use_syslog && logfile != NULL) 1008255767Sdes fatal("Can't specify both -y and -E"); 1009296781Sdes if (logfile != NULL) 1010255767Sdes log_redirect_stderr_to(logfile); 1011197679Sdes log_init(argv0, 1012181111Sdes options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, 1013192595Sdes SYSLOG_FACILITY_USER, !use_syslog); 101457429Smarkm 1015255767Sdes if (debug_flag) 1016295367Sdes /* version_addendum is always NULL at this point */ 1017295367Sdes logit("%s, %s", SSH_RELEASE, OPENSSL_VERSION); 1018255767Sdes 1019264377Sdes /* Parse the configuration files */ 1020295367Sdes process_config_files(host_arg, pw, 0); 1021264377Sdes 1022264377Sdes /* Hostname canonicalisation needs a few options filled. */ 1023264377Sdes fill_default_options_for_canonicalization(&options); 1024264377Sdes 1025264377Sdes /* If the user has replaced the hostname then take it into use now */ 1026264377Sdes if (options.hostname != NULL) { 1027264377Sdes /* NB. Please keep in sync with readconf.c:match_cfg_line() */ 1028264377Sdes cp = percent_expand(options.hostname, 1029264377Sdes "h", host, (char *)NULL); 1030264377Sdes free(host); 1031264377Sdes host = cp; 1032295367Sdes free(options.hostname); 1033295367Sdes options.hostname = xstrdup(host); 1034264377Sdes } 1035264377Sdes 1036264377Sdes /* If canonicalization requested then try to apply it */ 1037264377Sdes lowercase(host); 1038264377Sdes if (options.canonicalize_hostname != SSH_CANONICALISE_NO) 1039264377Sdes addrs = resolve_canonicalize(&host, options.port); 1040264377Sdes 104192559Sdes /* 1042264377Sdes * If CanonicalizePermittedCNAMEs have been specified but 1043264377Sdes * other canonicalization did not happen (by not being requested 1044264377Sdes * or by failing with fallback) then the hostname may still be changed 1045264377Sdes * as a result of CNAME following. 1046264377Sdes * 1047264377Sdes * Try to resolve the bare hostname name using the system resolver's 1048264377Sdes * usual search rules and then apply the CNAME follow rules. 1049264377Sdes * 1050264377Sdes * Skip the lookup if a ProxyCommand is being used unless the user 1051264377Sdes * has specifically requested canonicalisation for this case via 1052264377Sdes * CanonicalizeHostname=always 105392559Sdes */ 1054323124Sdes direct = option_clear_or_none(options.proxy_command) && 1055323124Sdes options.jump_host == NULL; 1056323124Sdes if (addrs == NULL && options.num_permitted_cnames != 0 && (direct || 1057323124Sdes options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) { 1058295367Sdes if ((addrs = resolve_host(host, options.port, 1059295367Sdes option_clear_or_none(options.proxy_command), 1060295367Sdes cname, sizeof(cname))) == NULL) { 1061295367Sdes /* Don't fatal proxied host names not in the DNS */ 1062295367Sdes if (option_clear_or_none(options.proxy_command)) 1063295367Sdes cleanup_exit(255); /* logged in resolve_host */ 1064295367Sdes } else 1065323124Sdes check_follow_cname(direct, &host, cname); 1066264377Sdes } 106757429Smarkm 1068264377Sdes /* 1069295367Sdes * If canonicalisation is enabled then re-parse the configuration 1070295367Sdes * files as new stanzas may match. 1071264377Sdes */ 1072295367Sdes if (options.canonicalize_hostname != 0) { 1073295367Sdes debug("Re-reading configuration after hostname " 1074295367Sdes "canonicalisation"); 1075295367Sdes free(options.hostname); 1076295367Sdes options.hostname = xstrdup(host); 1077295367Sdes process_config_files(host_arg, pw, 1); 1078295367Sdes /* 1079295367Sdes * Address resolution happens early with canonicalisation 1080295367Sdes * enabled and the port number may have changed since, so 1081295367Sdes * reset it in address list 1082295367Sdes */ 1083295367Sdes if (addrs != NULL && options.port > 0) 1084295367Sdes set_addrinfo_port(addrs, options.port); 108592559Sdes } 108657429Smarkm 108757429Smarkm /* Fill configuration defaults. */ 108857429Smarkm fill_default_options(&options); 108957429Smarkm 1090323124Sdes /* 1091323124Sdes * If ProxyJump option specified, then construct a ProxyCommand now. 1092323124Sdes */ 1093323124Sdes if (options.jump_host != NULL) { 1094323124Sdes char port_s[8]; 1095323124Sdes 1096323124Sdes /* Consistency check */ 1097323124Sdes if (options.proxy_command != NULL) 1098323124Sdes fatal("inconsistent options: ProxyCommand+ProxyJump"); 1099323124Sdes /* Never use FD passing for ProxyJump */ 1100323124Sdes options.proxy_use_fdpass = 0; 1101323124Sdes snprintf(port_s, sizeof(port_s), "%d", options.jump_port); 1102323124Sdes xasprintf(&options.proxy_command, 1103323124Sdes "ssh%s%s%s%s%s%s%s%s%s%.*s -W %%h:%%p %s", 1104323124Sdes /* Optional "-l user" argument if jump_user set */ 1105323124Sdes options.jump_user == NULL ? "" : " -l ", 1106323124Sdes options.jump_user == NULL ? "" : options.jump_user, 1107323124Sdes /* Optional "-p port" argument if jump_port set */ 1108323124Sdes options.jump_port <= 0 ? "" : " -p ", 1109323124Sdes options.jump_port <= 0 ? "" : port_s, 1110323124Sdes /* Optional additional jump hosts ",..." */ 1111323124Sdes options.jump_extra == NULL ? "" : " -J ", 1112323124Sdes options.jump_extra == NULL ? "" : options.jump_extra, 1113323124Sdes /* Optional "-F" argumment if -F specified */ 1114323124Sdes config == NULL ? "" : " -F ", 1115323124Sdes config == NULL ? "" : config, 1116323124Sdes /* Optional "-v" arguments if -v set */ 1117323124Sdes debug_flag ? " -" : "", 1118323124Sdes debug_flag, "vvv", 1119323124Sdes /* Mandatory hostname */ 1120323124Sdes options.jump_host); 1121323124Sdes debug("Setting implicit ProxyCommand from ProxyJump: %s", 1122323124Sdes options.proxy_command); 1123323124Sdes } 1124323124Sdes 1125264377Sdes if (options.port == 0) 1126264377Sdes options.port = default_ssh_port(); 1127124211Sdes channel_set_af(options.address_family); 1128124211Sdes 1129262566Sdes /* Tidy and check options */ 1130262566Sdes if (options.host_key_alias != NULL) 1131262566Sdes lowercase(options.host_key_alias); 1132262566Sdes if (options.proxy_command != NULL && 1133262566Sdes strcmp(options.proxy_command, "-") == 0 && 1134262566Sdes options.proxy_use_fdpass) 1135262566Sdes fatal("ProxyCommand=- and ProxyUseFDPass are incompatible"); 1136295367Sdes if (options.control_persist && 1137295367Sdes options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK) { 1138295367Sdes debug("UpdateHostKeys=ask is incompatible with ControlPersist; " 1139295367Sdes "disabling"); 1140295367Sdes options.update_hostkeys = 0; 1141295367Sdes } 1142296781Sdes if (options.connection_attempts <= 0) 1143296781Sdes fatal("Invalid number of ConnectionAttempts"); 1144262566Sdes#ifndef HAVE_CYGWIN 1145262566Sdes if (original_effective_uid != 0) 1146262566Sdes options.use_privileged_port = 0; 1147262566Sdes#endif 1148262566Sdes 114957429Smarkm /* reinit */ 1150197679Sdes log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog); 115157429Smarkm 1152240075Sdes if (options.request_tty == REQUEST_TTY_YES || 1153240075Sdes options.request_tty == REQUEST_TTY_FORCE) 1154240075Sdes tty_flag = 1; 1155240075Sdes 1156240075Sdes /* Allocate a tty by default if no command specified. */ 1157240075Sdes if (buffer_len(&command) == 0) 1158240075Sdes tty_flag = options.request_tty != REQUEST_TTY_NO; 1159240075Sdes 1160240075Sdes /* Force no tty */ 1161240075Sdes if (options.request_tty == REQUEST_TTY_NO || muxclient_command != 0) 1162240075Sdes tty_flag = 0; 1163240075Sdes /* Do not allocate a tty if stdin is not a tty. */ 1164240075Sdes if ((!isatty(fileno(stdin)) || stdin_null_flag) && 1165240075Sdes options.request_tty != REQUEST_TTY_FORCE) { 1166240075Sdes if (tty_flag) 1167240075Sdes logit("Pseudo-terminal will not be allocated because " 1168240075Sdes "stdin is not a terminal."); 1169240075Sdes tty_flag = 0; 1170240075Sdes } 1171240075Sdes 117298941Sdes seed_rng(); 117398941Sdes 117457429Smarkm if (options.user == NULL) 117557429Smarkm options.user = xstrdup(pw->pw_name); 117657429Smarkm 1177226046Sdes if (gethostname(thishost, sizeof(thishost)) == -1) 1178226046Sdes fatal("gethostname: %s", strerror(errno)); 1179226046Sdes strlcpy(shorthost, thishost, sizeof(shorthost)); 1180226046Sdes shorthost[strcspn(thishost, ".")] = '\0'; 1181226046Sdes snprintf(portstr, sizeof(portstr), "%d", options.port); 1182296781Sdes snprintf(uidstr, sizeof(uidstr), "%d", pw->pw_uid); 1183226046Sdes 1184285750Svangyzen /* Find canonic host name. */ 1185285750Svangyzen if (strchr(host, '.') == 0) { 1186285750Svangyzen struct addrinfo hints; 1187285750Svangyzen struct addrinfo *ai = NULL; 1188285750Svangyzen int errgai; 1189285750Svangyzen memset(&hints, 0, sizeof(hints)); 1190285750Svangyzen hints.ai_family = options.address_family; 1191285750Svangyzen hints.ai_flags = AI_CANONNAME; 1192285750Svangyzen hints.ai_socktype = SOCK_STREAM; 1193285750Svangyzen errgai = getaddrinfo(host, NULL, &hints, &ai); 1194285750Svangyzen if (errgai == 0) { 1195285750Svangyzen if (ai->ai_canonname != NULL) 1196285750Svangyzen host = xstrdup(ai->ai_canonname); 1197285750Svangyzen freeaddrinfo(ai); 1198285750Svangyzen } 1199285750Svangyzen } 1200285750Svangyzen 1201295367Sdes if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL || 1202295367Sdes ssh_digest_update(md, thishost, strlen(thishost)) < 0 || 1203295367Sdes ssh_digest_update(md, host, strlen(host)) < 0 || 1204295367Sdes ssh_digest_update(md, portstr, strlen(portstr)) < 0 || 1205295367Sdes ssh_digest_update(md, options.user, strlen(options.user)) < 0 || 1206295367Sdes ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0) 1207295367Sdes fatal("%s: mux digest failed", __func__); 1208295367Sdes ssh_digest_free(md); 1209295367Sdes conn_hash_hex = tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1)); 1210295367Sdes 1211181111Sdes if (options.local_command != NULL) { 1212181111Sdes debug3("expanding LocalCommand: %s", options.local_command); 1213181111Sdes cp = options.local_command; 1214295367Sdes options.local_command = percent_expand(cp, 1215295367Sdes "C", conn_hash_hex, 1216295367Sdes "L", shorthost, 1217295367Sdes "d", pw->pw_dir, 1218295367Sdes "h", host, 1219295367Sdes "l", thishost, 1220295367Sdes "n", host_arg, 1221295367Sdes "p", portstr, 1222295367Sdes "r", options.user, 1223295367Sdes "u", pw->pw_name, 1224226046Sdes (char *)NULL); 1225181111Sdes debug3("expanded LocalCommand: %s", options.local_command); 1226255767Sdes free(cp); 1227181111Sdes } 1228181111Sdes 1229137019Sdes if (options.control_path != NULL) { 1230149753Sdes cp = tilde_expand_filename(options.control_path, 1231149753Sdes original_real_uid); 1232255767Sdes free(options.control_path); 1233295367Sdes options.control_path = percent_expand(cp, 1234295367Sdes "C", conn_hash_hex, 1235295367Sdes "L", shorthost, 1236295367Sdes "h", host, 1237295367Sdes "l", thishost, 1238295367Sdes "n", host_arg, 1239295367Sdes "p", portstr, 1240295367Sdes "r", options.user, 1241295367Sdes "u", pw->pw_name, 1242296781Sdes "i", uidstr, 1243226046Sdes (char *)NULL); 1244255767Sdes free(cp); 1245137019Sdes } 1246295367Sdes free(conn_hash_hex); 1247295367Sdes 1248295367Sdes if (config_test) { 1249295367Sdes dump_client_config(&options, host); 1250295367Sdes exit(0); 1251295367Sdes } 1252295367Sdes 1253181111Sdes if (muxclient_command != 0 && options.control_path == NULL) 1254149753Sdes fatal("No ControlPath specified for \"-O\" command"); 1255149753Sdes if (options.control_path != NULL) 1256181111Sdes muxclient(options.control_path); 1257137019Sdes 1258264377Sdes /* 1259264377Sdes * If hostname canonicalisation was not enabled, then we may not 1260264377Sdes * have yet resolved the hostname. Do so now. 1261264377Sdes */ 1262264377Sdes if (addrs == NULL && options.proxy_command == NULL) { 1263296781Sdes debug2("resolving \"%s\" port %d", host, options.port); 1264264377Sdes if ((addrs = resolve_host(host, options.port, 1, 1265264377Sdes cname, sizeof(cname))) == NULL) 1266264377Sdes cleanup_exit(255); /* resolve_host logs the error */ 1267264377Sdes } 1268264377Sdes 1269181111Sdes timeout_ms = options.connection_timeout * 1000; 1270181111Sdes 127176262Sgreen /* Open a connection to the remote host. */ 1272262566Sdes if (ssh_connect(host, addrs, &hostaddr, options.port, 1273262566Sdes options.address_family, options.connection_attempts, 1274262566Sdes &timeout_ms, options.tcp_keep_alive, 1275262566Sdes options.use_privileged_port) != 0) 1276262566Sdes exit(255); 127757429Smarkm 1278262566Sdes if (addrs != NULL) 1279262566Sdes freeaddrinfo(addrs); 1280262566Sdes 1281262566Sdes packet_set_timeout(options.server_alive_interval, 1282262566Sdes options.server_alive_count_max); 1283262566Sdes 1284323124Sdes ssh = active_state; /* XXX */ 1285323124Sdes 1286181111Sdes if (timeout_ms > 0) 1287181111Sdes debug3("timeout: %d ms remain after connect", timeout_ms); 1288181111Sdes 128957429Smarkm /* 129057429Smarkm * If we successfully made the connection, load the host private key 129157429Smarkm * in case we will need it later for combined rsa-rhosts 129257429Smarkm * authentication. This must be done before releasing extra 129357429Smarkm * privileges, because the file is only readable by root. 129498684Sdes * If we cannot access the private keys, load the public keys 129598684Sdes * instead and try to execute the ssh-keysign helper instead. 129657429Smarkm */ 129776262Sgreen sensitive_data.nkeys = 0; 129876262Sgreen sensitive_data.keys = NULL; 129998684Sdes sensitive_data.external_keysign = 0; 130098684Sdes if (options.rhosts_rsa_authentication || 130198684Sdes options.hostbased_authentication) { 1302262566Sdes sensitive_data.nkeys = 9; 1303162856Sdes sensitive_data.keys = xcalloc(sensitive_data.nkeys, 1304106130Sdes sizeof(Key)); 1305221420Sdes for (i = 0; i < sensitive_data.nkeys; i++) 1306221420Sdes sensitive_data.keys[i] = NULL; 130798684Sdes 130898684Sdes PRIV_START; 1309296781Sdes#if WITH_SSH1 131076262Sgreen sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, 1311162856Sdes _PATH_HOST_KEY_FILE, "", NULL, NULL); 1312296781Sdes#endif 1313221420Sdes#ifdef OPENSSL_HAS_ECC 1314295367Sdes sensitive_data.keys[1] = key_load_private_cert(KEY_ECDSA, 1315221420Sdes _PATH_HOST_ECDSA_KEY_FILE, "", NULL); 1316221420Sdes#endif 1317295367Sdes sensitive_data.keys[2] = key_load_private_cert(KEY_ED25519, 1318295367Sdes _PATH_HOST_ED25519_KEY_FILE, "", NULL); 1319221420Sdes sensitive_data.keys[3] = key_load_private_cert(KEY_RSA, 1320215116Sdes _PATH_HOST_RSA_KEY_FILE, "", NULL); 1321295367Sdes sensitive_data.keys[4] = key_load_private_cert(KEY_DSA, 1322295367Sdes _PATH_HOST_DSA_KEY_FILE, "", NULL); 1323221420Sdes#ifdef OPENSSL_HAS_ECC 1324295367Sdes sensitive_data.keys[5] = key_load_private_type(KEY_ECDSA, 1325221420Sdes _PATH_HOST_ECDSA_KEY_FILE, "", NULL, NULL); 1326221420Sdes#endif 1327295367Sdes sensitive_data.keys[6] = key_load_private_type(KEY_ED25519, 1328295367Sdes _PATH_HOST_ED25519_KEY_FILE, "", NULL, NULL); 1329262566Sdes sensitive_data.keys[7] = key_load_private_type(KEY_RSA, 1330162856Sdes _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL); 1331295367Sdes sensitive_data.keys[8] = key_load_private_type(KEY_DSA, 1332295367Sdes _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL); 133398684Sdes PRIV_END; 133498684Sdes 1335106130Sdes if (options.hostbased_authentication == 1 && 1336106130Sdes sensitive_data.keys[0] == NULL && 1337221420Sdes sensitive_data.keys[5] == NULL && 1338262566Sdes sensitive_data.keys[6] == NULL && 1339262566Sdes sensitive_data.keys[7] == NULL && 1340262566Sdes sensitive_data.keys[8] == NULL) { 1341295367Sdes#ifdef OPENSSL_HAS_ECC 1342215116Sdes sensitive_data.keys[1] = key_load_cert( 1343221420Sdes _PATH_HOST_ECDSA_KEY_FILE); 1344221420Sdes#endif 1345295367Sdes sensitive_data.keys[2] = key_load_cert( 1346295367Sdes _PATH_HOST_ED25519_KEY_FILE); 1347221420Sdes sensitive_data.keys[3] = key_load_cert( 1348215116Sdes _PATH_HOST_RSA_KEY_FILE); 1349262566Sdes sensitive_data.keys[4] = key_load_cert( 1350295367Sdes _PATH_HOST_DSA_KEY_FILE); 1351295367Sdes#ifdef OPENSSL_HAS_ECC 1352262566Sdes sensitive_data.keys[5] = key_load_public( 1353221420Sdes _PATH_HOST_ECDSA_KEY_FILE, NULL); 1354221420Sdes#endif 1355295367Sdes sensitive_data.keys[6] = key_load_public( 1356295367Sdes _PATH_HOST_ED25519_KEY_FILE, NULL); 1357262566Sdes sensitive_data.keys[7] = key_load_public( 135898684Sdes _PATH_HOST_RSA_KEY_FILE, NULL); 1359262566Sdes sensitive_data.keys[8] = key_load_public( 1360295367Sdes _PATH_HOST_DSA_KEY_FILE, NULL); 136198684Sdes sensitive_data.external_keysign = 1; 136298684Sdes } 136357429Smarkm } 136457429Smarkm /* 136557429Smarkm * Get rid of any extra privileges that we may have. We will no 136657429Smarkm * longer need them. Also, extra privileges could make it very hard 136757429Smarkm * to read identity files and other non-world-readable files from the 136857429Smarkm * user's home directory if it happens to be on a NFS volume where 136957429Smarkm * root is mapped to nobody. 137057429Smarkm */ 1371137019Sdes if (original_effective_uid == 0) { 1372137019Sdes PRIV_START; 1373137019Sdes permanently_set_uid(pw); 1374137019Sdes } 137557429Smarkm 137657429Smarkm /* 137757429Smarkm * Now that we are back to our own permissions, create ~/.ssh 1378157019Sdes * directory if it doesn't already exist. 137957429Smarkm */ 1380240075Sdes if (config == NULL) { 1381240075Sdes r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir, 1382240075Sdes strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); 1383240075Sdes if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) { 1384221420Sdes#ifdef WITH_SELINUX 1385240075Sdes ssh_selinux_setfscreatecon(buf); 1386221420Sdes#endif 1387240075Sdes if (mkdir(buf, 0700) < 0) 1388240075Sdes error("Could not create directory '%.200s'.", 1389240075Sdes buf); 1390221420Sdes#ifdef WITH_SELINUX 1391240075Sdes ssh_selinux_setfscreatecon(NULL); 1392221420Sdes#endif 1393240075Sdes } 1394221420Sdes } 139576262Sgreen /* load options.identity_files */ 139676262Sgreen load_public_identity_files(); 139776262Sgreen 1398323124Sdes /* optionally set the SSH_AUTHSOCKET_ENV_NAME varibale */ 1399323124Sdes if (options.identity_agent && 1400323124Sdes strcmp(options.identity_agent, SSH_AUTHSOCKET_ENV_NAME) != 0) { 1401323124Sdes if (strcmp(options.identity_agent, "none") == 0) { 1402323124Sdes unsetenv(SSH_AUTHSOCKET_ENV_NAME); 1403323124Sdes } else { 1404323124Sdes p = tilde_expand_filename(options.identity_agent, 1405323124Sdes original_real_uid); 1406323124Sdes cp = percent_expand(p, "d", pw->pw_dir, 1407323124Sdes "u", pw->pw_name, "l", thishost, "h", host, 1408323124Sdes "r", options.user, (char *)NULL); 1409323124Sdes setenv(SSH_AUTHSOCKET_ENV_NAME, cp, 1); 1410323124Sdes free(cp); 1411323124Sdes free(p); 1412323124Sdes } 1413323124Sdes } 1414323124Sdes 141557429Smarkm /* Expand ~ in known host file names. */ 1416226046Sdes tilde_expand_paths(options.system_hostfiles, 1417226046Sdes options.num_system_hostfiles); 1418226046Sdes tilde_expand_paths(options.user_hostfiles, options.num_user_hostfiles); 141957429Smarkm 142092559Sdes signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ 1421221420Sdes signal(SIGCHLD, main_sigchld_handler); 142292559Sdes 1423181111Sdes /* Log into the remote system. Never returns if the login fails. */ 1424181111Sdes ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, 1425221420Sdes options.port, pw, timeout_ms); 142657429Smarkm 1427215116Sdes if (packet_connection_is_on_socket()) { 1428215116Sdes verbose("Authenticated to %s ([%s]:%d).", host, 1429323124Sdes ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); 1430215116Sdes } else { 1431215116Sdes verbose("Authenticated to %s (via proxy).", host); 1432215116Sdes } 1433215116Sdes 143476262Sgreen /* We no longer need the private host keys. Clear them now. */ 143576262Sgreen if (sensitive_data.nkeys != 0) { 143676262Sgreen for (i = 0; i < sensitive_data.nkeys; i++) { 143776262Sgreen if (sensitive_data.keys[i] != NULL) { 143876262Sgreen /* Destroys contents safely */ 143976262Sgreen debug3("clear hostkey %d", i); 144076262Sgreen key_free(sensitive_data.keys[i]); 144176262Sgreen sensitive_data.keys[i] = NULL; 144276262Sgreen } 144376262Sgreen } 1444255767Sdes free(sensitive_data.keys); 144576262Sgreen } 144692559Sdes for (i = 0; i < options.num_identity_files; i++) { 1447255767Sdes free(options.identity_files[i]); 1448255767Sdes options.identity_files[i] = NULL; 144992559Sdes if (options.identity_keys[i]) { 145092559Sdes key_free(options.identity_keys[i]); 145192559Sdes options.identity_keys[i] = NULL; 145292559Sdes } 145392559Sdes } 1454296781Sdes for (i = 0; i < options.num_certificate_files; i++) { 1455296781Sdes free(options.certificate_files[i]); 1456296781Sdes options.certificate_files[i] = NULL; 1457296781Sdes } 145857429Smarkm 145960576Skris exit_status = compat20 ? ssh_session2() : ssh_session(); 146060576Skris packet_close(); 1461106130Sdes 1462181111Sdes if (options.control_path != NULL && muxserver_sock != -1) 1463137019Sdes unlink(options.control_path); 1464137019Sdes 1465221420Sdes /* Kill ProxyCommand if it is running. */ 1466221420Sdes ssh_kill_proxy_command(); 1467106130Sdes 146860576Skris return exit_status; 146960576Skris} 147060576Skris 1471215116Sdesstatic void 1472215116Sdescontrol_persist_detach(void) 1473215116Sdes{ 1474215116Sdes pid_t pid; 1475323124Sdes int devnull, keep_stderr; 1476215116Sdes 1477215116Sdes debug("%s: backgrounding master process", __func__); 1478215116Sdes 1479215116Sdes /* 1480215116Sdes * master (current process) into the background, and make the 1481215116Sdes * foreground process a client of the backgrounded master. 1482215116Sdes */ 1483215116Sdes switch ((pid = fork())) { 1484215116Sdes case -1: 1485215116Sdes fatal("%s: fork: %s", __func__, strerror(errno)); 1486215116Sdes case 0: 1487215116Sdes /* Child: master process continues mainloop */ 1488215116Sdes break; 1489215116Sdes default: 1490215116Sdes /* Parent: set up mux slave to connect to backgrounded master */ 1491215116Sdes debug2("%s: background process is %ld", __func__, (long)pid); 1492215116Sdes stdin_null_flag = ostdin_null_flag; 1493226046Sdes options.request_tty = orequest_tty; 1494215116Sdes tty_flag = otty_flag; 1495215116Sdes close(muxserver_sock); 1496215116Sdes muxserver_sock = -1; 1497221420Sdes options.control_master = SSHCTL_MASTER_NO; 1498215116Sdes muxclient(options.control_path); 1499215116Sdes /* muxclient() doesn't return on success. */ 1500215116Sdes fatal("Failed to connect to new control master"); 1501215116Sdes } 1502215116Sdes if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { 1503215116Sdes error("%s: open(\"/dev/null\"): %s", __func__, 1504215116Sdes strerror(errno)); 1505215116Sdes } else { 1506323124Sdes keep_stderr = log_is_on_stderr() && debug_flag; 1507215116Sdes if (dup2(devnull, STDIN_FILENO) == -1 || 1508323124Sdes dup2(devnull, STDOUT_FILENO) == -1 || 1509323124Sdes (!keep_stderr && dup2(devnull, STDERR_FILENO) == -1)) 1510215116Sdes error("%s: dup2: %s", __func__, strerror(errno)); 1511215116Sdes if (devnull > STDERR_FILENO) 1512215116Sdes close(devnull); 1513215116Sdes } 1514255767Sdes daemon(1, 1); 1515226046Sdes setproctitle("%s [mux]", options.control_path); 1516215116Sdes} 1517215116Sdes 1518215116Sdes/* Do fork() after authentication. Used by "ssh -f" */ 1519215116Sdesstatic void 1520215116Sdesfork_postauth(void) 1521215116Sdes{ 1522215116Sdes if (need_controlpersist_detach) 1523215116Sdes control_persist_detach(); 1524215116Sdes debug("forking to background"); 1525215116Sdes fork_after_authentication_flag = 0; 1526215116Sdes if (daemon(1, 1) < 0) 1527215116Sdes fatal("daemon() failed: %.200s", strerror(errno)); 1528215116Sdes} 1529215116Sdes 1530181111Sdes/* Callback for remote forward global requests */ 153192559Sdesstatic void 1532181111Sdesssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) 1533181111Sdes{ 1534295367Sdes struct Forward *rfwd = (struct Forward *)ctxt; 1535181111Sdes 1536192595Sdes /* XXX verbose() on failure? */ 1537295367Sdes debug("remote forward %s for: listen %s%s%d, connect %s:%d", 1538181111Sdes type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", 1539295367Sdes rfwd->listen_path ? rfwd->listen_path : 1540295367Sdes rfwd->listen_host ? rfwd->listen_host : "", 1541295367Sdes (rfwd->listen_path || rfwd->listen_host) ? ":" : "", 1542295367Sdes rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path : 1543295367Sdes rfwd->connect_host, rfwd->connect_port); 1544295367Sdes if (rfwd->listen_path == NULL && rfwd->listen_port == 0) { 1545240075Sdes if (type == SSH2_MSG_REQUEST_SUCCESS) { 1546240075Sdes rfwd->allocated_port = packet_get_int(); 1547240075Sdes logit("Allocated port %u for remote forward to %s:%d", 1548240075Sdes rfwd->allocated_port, 1549240075Sdes rfwd->connect_host, rfwd->connect_port); 1550240075Sdes channel_update_permitted_opens(rfwd->handle, 1551240075Sdes rfwd->allocated_port); 1552240075Sdes } else { 1553240075Sdes channel_update_permitted_opens(rfwd->handle, -1); 1554240075Sdes } 1555192595Sdes } 1556192595Sdes 1557181111Sdes if (type == SSH2_MSG_REQUEST_FAILURE) { 1558295367Sdes if (options.exit_on_forward_failure) { 1559295367Sdes if (rfwd->listen_path != NULL) 1560295367Sdes fatal("Error: remote port forwarding failed " 1561295367Sdes "for listen path %s", rfwd->listen_path); 1562295367Sdes else 1563295367Sdes fatal("Error: remote port forwarding failed " 1564295367Sdes "for listen port %d", rfwd->listen_port); 1565295367Sdes } else { 1566295367Sdes if (rfwd->listen_path != NULL) 1567295367Sdes logit("Warning: remote port forwarding failed " 1568295367Sdes "for listen path %s", rfwd->listen_path); 1569295367Sdes else 1570295367Sdes logit("Warning: remote port forwarding failed " 1571295367Sdes "for listen port %d", rfwd->listen_port); 1572295367Sdes } 1573181111Sdes } 1574181111Sdes if (++remote_forward_confirms_received == options.num_remote_forwards) { 1575181111Sdes debug("All remote forwarding requests processed"); 1576215116Sdes if (fork_after_authentication_flag) 1577215116Sdes fork_postauth(); 1578181111Sdes } 1579181111Sdes} 1580181111Sdes 1581181111Sdesstatic void 1582204917Sdesclient_cleanup_stdio_fwd(int id, void *arg) 1583204917Sdes{ 1584204917Sdes debug("stdio forwarding: done"); 1585204917Sdes cleanup_exit(0); 1586204917Sdes} 1587204917Sdes 1588240075Sdesstatic void 1589295367Sdesssh_stdio_confirm(int id, int success, void *arg) 1590295367Sdes{ 1591295367Sdes if (!success) 1592295367Sdes fatal("stdio forwarding failed"); 1593295367Sdes} 1594295367Sdes 1595295367Sdesstatic void 1596240075Sdesssh_init_stdio_forwarding(void) 1597204917Sdes{ 1598204917Sdes Channel *c; 1599204917Sdes int in, out; 1600204917Sdes 1601323124Sdes if (options.stdio_forward_host == NULL) 1602240075Sdes return; 1603262566Sdes if (!compat20) 1604240075Sdes fatal("stdio forwarding require Protocol 2"); 1605204917Sdes 1606323124Sdes debug3("%s: %s:%d", __func__, options.stdio_forward_host, 1607323124Sdes options.stdio_forward_port); 1608240075Sdes 1609240075Sdes if ((in = dup(STDIN_FILENO)) < 0 || 1610240075Sdes (out = dup(STDOUT_FILENO)) < 0) 1611204917Sdes fatal("channel_connect_stdio_fwd: dup() in/out failed"); 1612323124Sdes if ((c = channel_connect_stdio_fwd(options.stdio_forward_host, 1613323124Sdes options.stdio_forward_port, in, out)) == NULL) 1614240075Sdes fatal("%s: channel_connect_stdio_fwd failed", __func__); 1615204917Sdes channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0); 1616295367Sdes channel_register_open_confirm(c->self, ssh_stdio_confirm, NULL); 1617204917Sdes} 1618204917Sdes 1619204917Sdesstatic void 162076262Sgreenssh_init_forwarding(void) 162176262Sgreen{ 162276262Sgreen int success = 0; 162376262Sgreen int i; 162476262Sgreen 162576262Sgreen /* Initiate local TCP/IP port forwardings. */ 162676262Sgreen for (i = 0; i < options.num_local_forwards; i++) { 1627147005Sdes debug("Local connections to %.200s:%d forwarded to remote " 1628147005Sdes "address %.200s:%d", 1629295367Sdes (options.local_forwards[i].listen_path != NULL) ? 1630295367Sdes options.local_forwards[i].listen_path : 1631147005Sdes (options.local_forwards[i].listen_host == NULL) ? 1632295367Sdes (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") : 1633147005Sdes options.local_forwards[i].listen_host, 1634147005Sdes options.local_forwards[i].listen_port, 1635295367Sdes (options.local_forwards[i].connect_path != NULL) ? 1636295367Sdes options.local_forwards[i].connect_path : 1637147005Sdes options.local_forwards[i].connect_host, 1638147005Sdes options.local_forwards[i].connect_port); 163992559Sdes success += channel_setup_local_fwd_listener( 1640295367Sdes &options.local_forwards[i], &options.fwd_opts); 164176262Sgreen } 1642162856Sdes if (i > 0 && success != i && options.exit_on_forward_failure) 1643162856Sdes fatal("Could not request local forwarding."); 164476262Sgreen if (i > 0 && success == 0) 164576262Sgreen error("Could not request local forwarding."); 164676262Sgreen 164776262Sgreen /* Initiate remote TCP/IP port forwardings. */ 164876262Sgreen for (i = 0; i < options.num_remote_forwards; i++) { 1649147005Sdes debug("Remote connections from %.200s:%d forwarded to " 1650147005Sdes "local address %.200s:%d", 1651295367Sdes (options.remote_forwards[i].listen_path != NULL) ? 1652295367Sdes options.remote_forwards[i].listen_path : 1653149753Sdes (options.remote_forwards[i].listen_host == NULL) ? 1654157019Sdes "LOCALHOST" : options.remote_forwards[i].listen_host, 1655147005Sdes options.remote_forwards[i].listen_port, 1656295367Sdes (options.remote_forwards[i].connect_path != NULL) ? 1657295367Sdes options.remote_forwards[i].connect_path : 1658147005Sdes options.remote_forwards[i].connect_host, 1659147005Sdes options.remote_forwards[i].connect_port); 1660240075Sdes options.remote_forwards[i].handle = 1661240075Sdes channel_request_remote_forwarding( 1662295367Sdes &options.remote_forwards[i]); 1663240075Sdes if (options.remote_forwards[i].handle < 0) { 1664162856Sdes if (options.exit_on_forward_failure) 1665162856Sdes fatal("Could not request remote forwarding."); 1666162856Sdes else 1667162856Sdes logit("Warning: Could not request remote " 1668162856Sdes "forwarding."); 1669240075Sdes } else { 1670240075Sdes client_register_global_confirm(ssh_confirm_remote_forward, 1671240075Sdes &options.remote_forwards[i]); 1672162856Sdes } 167376262Sgreen } 1674181111Sdes 1675181111Sdes /* Initiate tunnel forwarding. */ 1676181111Sdes if (options.tun_open != SSH_TUNMODE_NO) { 1677181111Sdes if (client_request_tun_fwd(options.tun_open, 1678181111Sdes options.tun_local, options.tun_remote) == -1) { 1679181111Sdes if (options.exit_on_forward_failure) 1680181111Sdes fatal("Could not request tunnel forwarding."); 1681181111Sdes else 1682181111Sdes error("Could not request tunnel forwarding."); 1683181111Sdes } 1684181111Sdes } 168576262Sgreen} 168676262Sgreen 168792559Sdesstatic void 168876262Sgreencheck_agent_present(void) 168976262Sgreen{ 1690295367Sdes int r; 1691295367Sdes 169276262Sgreen if (options.forward_agent) { 1693157019Sdes /* Clear agent forwarding if we don't have an agent. */ 1694295367Sdes if ((r = ssh_get_authentication_socket(NULL)) != 0) { 169576262Sgreen options.forward_agent = 0; 1696295367Sdes if (r != SSH_ERR_AGENT_NOT_PRESENT) 1697295367Sdes debug("ssh_get_authentication_socket: %s", 1698295367Sdes ssh_err(r)); 1699295367Sdes } 170076262Sgreen } 170176262Sgreen} 170276262Sgreen 170392559Sdesstatic int 170460576Skrisssh_session(void) 170560576Skris{ 170660576Skris int type; 170760576Skris int interactive = 0; 170860576Skris int have_tty = 0; 170960576Skris struct winsize ws; 171060576Skris char *cp; 1711149753Sdes const char *display; 1712296781Sdes char *proto = NULL, *data = NULL; 171360576Skris 171457429Smarkm /* Enable compression if requested. */ 171557429Smarkm if (options.compression) { 1716181111Sdes debug("Requesting compression at level %d.", 1717181111Sdes options.compression_level); 171857429Smarkm 1719181111Sdes if (options.compression_level < 1 || 1720181111Sdes options.compression_level > 9) 1721181111Sdes fatal("Compression level must be from 1 (fast) to " 1722181111Sdes "9 (slow, best)."); 172357429Smarkm 172457429Smarkm /* Send the request. */ 172557429Smarkm packet_start(SSH_CMSG_REQUEST_COMPRESSION); 172657429Smarkm packet_put_int(options.compression_level); 172757429Smarkm packet_send(); 172857429Smarkm packet_write_wait(); 172992559Sdes type = packet_read(); 173057429Smarkm if (type == SSH_SMSG_SUCCESS) 173157429Smarkm packet_start_compression(options.compression_level); 173257429Smarkm else if (type == SSH_SMSG_FAILURE) 1733124211Sdes logit("Warning: Remote host refused compression."); 173457429Smarkm else 1735181111Sdes packet_disconnect("Protocol error waiting for " 1736181111Sdes "compression response."); 173757429Smarkm } 173857429Smarkm /* Allocate a pseudo tty if appropriate. */ 173957429Smarkm if (tty_flag) { 174057429Smarkm debug("Requesting pty."); 174157429Smarkm 174257429Smarkm /* Start the packet. */ 174357429Smarkm packet_start(SSH_CMSG_REQUEST_PTY); 174457429Smarkm 174557429Smarkm /* Store TERM in the packet. There is no limit on the 174657429Smarkm length of the string. */ 174757429Smarkm cp = getenv("TERM"); 174857429Smarkm if (!cp) 174957429Smarkm cp = ""; 175092559Sdes packet_put_cstring(cp); 175157429Smarkm 175257429Smarkm /* Store window size in the packet. */ 175357429Smarkm if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) 175457429Smarkm memset(&ws, 0, sizeof(ws)); 1755162856Sdes packet_put_int((u_int)ws.ws_row); 1756162856Sdes packet_put_int((u_int)ws.ws_col); 1757162856Sdes packet_put_int((u_int)ws.ws_xpixel); 1758162856Sdes packet_put_int((u_int)ws.ws_ypixel); 175957429Smarkm 176057429Smarkm /* Store tty modes in the packet. */ 176176262Sgreen tty_make_modes(fileno(stdin), NULL); 176257429Smarkm 176357429Smarkm /* Send the packet, and wait for it to leave. */ 176457429Smarkm packet_send(); 176557429Smarkm packet_write_wait(); 176657429Smarkm 176757429Smarkm /* Read response from the server. */ 176892559Sdes type = packet_read(); 176958585Skris if (type == SSH_SMSG_SUCCESS) { 177057429Smarkm interactive = 1; 177160576Skris have_tty = 1; 177258585Skris } else if (type == SSH_SMSG_FAILURE) 1773181111Sdes logit("Warning: Remote host failed or refused to " 1774181111Sdes "allocate a pseudo tty."); 177557429Smarkm else 1776181111Sdes packet_disconnect("Protocol error waiting for pty " 1777181111Sdes "request response."); 177857429Smarkm } 177957429Smarkm /* Request X11 forwarding if enabled and DISPLAY is set. */ 1780149753Sdes display = getenv("DISPLAY"); 1781295367Sdes if (display == NULL && options.forward_x11) 1782295367Sdes debug("X11 forwarding requested but DISPLAY not set"); 1783296781Sdes if (options.forward_x11 && client_x11_get_proto(display, 1784296781Sdes options.xauth_location, options.forward_x11_trusted, 1785296781Sdes options.forward_x11_timeout, &proto, &data) == 0) { 178660576Skris /* Request forwarding with authentication spoofing. */ 1787181111Sdes debug("Requesting X11 forwarding with authentication " 1788181111Sdes "spoofing."); 1789226046Sdes x11_request_forwarding_with_spoofing(0, display, proto, 1790226046Sdes data, 0); 179157429Smarkm /* Read response from the server. */ 179292559Sdes type = packet_read(); 179357429Smarkm if (type == SSH_SMSG_SUCCESS) { 179457429Smarkm interactive = 1; 179560576Skris } else if (type == SSH_SMSG_FAILURE) { 1796124211Sdes logit("Warning: Remote host denied X11 forwarding."); 179760576Skris } else { 1798181111Sdes packet_disconnect("Protocol error waiting for X11 " 1799181111Sdes "forwarding"); 180060576Skris } 180157429Smarkm } 180257429Smarkm /* Tell the packet module whether this is an interactive session. */ 1803221420Sdes packet_set_interactive(interactive, 1804221420Sdes options.ip_qos_interactive, options.ip_qos_bulk); 180557429Smarkm 180676262Sgreen /* Request authentication agent forwarding if appropriate. */ 180776262Sgreen check_agent_present(); 180857429Smarkm 180957429Smarkm if (options.forward_agent) { 181057429Smarkm debug("Requesting authentication agent forwarding."); 181157429Smarkm auth_request_forwarding(); 181257429Smarkm 181357429Smarkm /* Read response from the server. */ 181492559Sdes type = packet_read(); 181592559Sdes packet_check_eom(); 181657429Smarkm if (type != SSH_SMSG_SUCCESS) 1817124211Sdes logit("Warning: Remote host denied authentication agent forwarding."); 181857429Smarkm } 181957429Smarkm 182076262Sgreen /* Initiate port forwardings. */ 1821240075Sdes ssh_init_stdio_forwarding(); 182276262Sgreen ssh_init_forwarding(); 182357429Smarkm 1824181111Sdes /* Execute a local command */ 1825181111Sdes if (options.local_command != NULL && 1826181111Sdes options.permit_local_command) 1827181111Sdes ssh_local_cmd(options.local_command); 1828181111Sdes 1829181111Sdes /* 1830181111Sdes * If requested and we are not interested in replies to remote 1831181111Sdes * forwarding requests, then let ssh continue in the background. 1832181111Sdes */ 1833215116Sdes if (fork_after_authentication_flag) { 1834215116Sdes if (options.exit_on_forward_failure && 1835215116Sdes options.num_remote_forwards > 0) { 1836215116Sdes debug("deferring postauth fork until remote forward " 1837215116Sdes "confirmation received"); 1838215116Sdes } else 1839215116Sdes fork_postauth(); 1840181111Sdes } 184157429Smarkm 184257429Smarkm /* 184357429Smarkm * If a command was specified on the command line, execute the 184457429Smarkm * command now. Otherwise request the server to start a shell. 184557429Smarkm */ 184657429Smarkm if (buffer_len(&command) > 0) { 184757429Smarkm int len = buffer_len(&command); 184857429Smarkm if (len > 900) 184957429Smarkm len = 900; 1850181111Sdes debug("Sending command: %.*s", len, 1851181111Sdes (u_char *)buffer_ptr(&command)); 185257429Smarkm packet_start(SSH_CMSG_EXEC_CMD); 185357429Smarkm packet_put_string(buffer_ptr(&command), buffer_len(&command)); 185457429Smarkm packet_send(); 185557429Smarkm packet_write_wait(); 185657429Smarkm } else { 185757429Smarkm debug("Requesting shell."); 185857429Smarkm packet_start(SSH_CMSG_EXEC_SHELL); 185957429Smarkm packet_send(); 186057429Smarkm packet_write_wait(); 186157429Smarkm } 186257429Smarkm 186357429Smarkm /* Enter the interactive session. */ 186492559Sdes return client_loop(have_tty, tty_flag ? 186592559Sdes options.escape_char : SSH_ESCAPECHAR_NONE, 0); 186660576Skris} 186757429Smarkm 1868137019Sdes/* request pty/x11/agent/tcpfwd/shell for channel */ 1869137019Sdesstatic void 1870215116Sdesssh_session2_setup(int id, int success, void *arg) 1871137019Sdes{ 1872137019Sdes extern char **environ; 1873149753Sdes const char *display; 1874149753Sdes int interactive = tty_flag; 1875296781Sdes char *proto = NULL, *data = NULL; 1876137019Sdes 1877215116Sdes if (!success) 1878215116Sdes return; /* No need for error message, channels code sens one */ 1879215116Sdes 1880149753Sdes display = getenv("DISPLAY"); 1881295367Sdes if (display == NULL && options.forward_x11) 1882295367Sdes debug("X11 forwarding requested but DISPLAY not set"); 1883296781Sdes if (options.forward_x11 && client_x11_get_proto(display, 1884296781Sdes options.xauth_location, options.forward_x11_trusted, 1885296781Sdes options.forward_x11_timeout, &proto, &data) == 0) { 188660576Skris /* Request forwarding with authentication spoofing. */ 1887181111Sdes debug("Requesting X11 forwarding with authentication " 1888181111Sdes "spoofing."); 1889226046Sdes x11_request_forwarding_with_spoofing(id, display, proto, 1890226046Sdes data, 1); 1891226046Sdes client_expect_confirm(id, "X11 forwarding", CONFIRM_WARN); 1892226046Sdes /* XXX exit_on_forward_failure */ 189376262Sgreen interactive = 1; 189460576Skris } 189560576Skris 189676262Sgreen check_agent_present(); 189776262Sgreen if (options.forward_agent) { 189876262Sgreen debug("Requesting authentication agent forwarding."); 189976262Sgreen channel_request_start(id, "auth-agent-req@openssh.com", 0); 190076262Sgreen packet_send(); 190176262Sgreen } 190276262Sgreen 1903240075Sdes /* Tell the packet module whether this is an interactive session. */ 1904240075Sdes packet_set_interactive(interactive, 1905240075Sdes options.ip_qos_interactive, options.ip_qos_bulk); 1906240075Sdes 1907137019Sdes client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"), 1908181111Sdes NULL, fileno(stdin), &command, environ); 190957429Smarkm} 191060576Skris 191192559Sdes/* open new channel for a session */ 191292559Sdesstatic int 191392559Sdesssh_session2_open(void) 191460576Skris{ 191592559Sdes Channel *c; 191692559Sdes int window, packetmax, in, out, err; 191760576Skris 191865674Skris if (stdin_null_flag) { 191976262Sgreen in = open(_PATH_DEVNULL, O_RDONLY); 192065674Skris } else { 192165674Skris in = dup(STDIN_FILENO); 192265674Skris } 192365674Skris out = dup(STDOUT_FILENO); 192465674Skris err = dup(STDERR_FILENO); 192565674Skris 192660576Skris if (in < 0 || out < 0 || err < 0) 192765674Skris fatal("dup() in/out/err failed"); 192860576Skris 192969591Sgreen /* enable nonblocking unless tty */ 193069591Sgreen if (!isatty(in)) 193169591Sgreen set_nonblock(in); 193269591Sgreen if (!isatty(out)) 193369591Sgreen set_nonblock(out); 193469591Sgreen if (!isatty(err)) 193569591Sgreen set_nonblock(err); 193669591Sgreen 1937294693Sdes window = CHAN_SES_WINDOW_DEFAULT; 193865674Skris packetmax = CHAN_SES_PACKET_DEFAULT; 193992559Sdes if (tty_flag) { 194092559Sdes window >>= 1; 194192559Sdes packetmax >>= 1; 194260576Skris } 194392559Sdes c = channel_new( 194460576Skris "session", SSH_CHANNEL_OPENING, in, out, err, 194565674Skris window, packetmax, CHAN_EXTENDED_WRITE, 1946124211Sdes "client-session", /*nonblock*/0); 1947231584Sed 194892559Sdes debug3("ssh_session2_open: channel_new: %d", c->self); 194976262Sgreen 195092559Sdes channel_send_open(c->self); 195192559Sdes if (!no_shell_flag) 1952181111Sdes channel_register_open_confirm(c->self, 1953181111Sdes ssh_session2_setup, NULL); 195460576Skris 195592559Sdes return c->self; 195676262Sgreen} 195776262Sgreen 195892559Sdesstatic int 195976262Sgreenssh_session2(void) 196076262Sgreen{ 196192559Sdes int id = -1; 196276262Sgreen 196376262Sgreen /* XXX should be pre-session */ 1964240075Sdes if (!options.control_persist) 1965240075Sdes ssh_init_stdio_forwarding(); 196676262Sgreen ssh_init_forwarding(); 196776262Sgreen 1968215116Sdes /* Start listening for multiplex clients */ 1969215116Sdes muxserver_listen(); 1970215116Sdes 1971215116Sdes /* 1972240075Sdes * If we are in control persist mode and have a working mux listen 1973240075Sdes * socket, then prepare to background ourselves and have a foreground 1974240075Sdes * client attach as a control slave. 1975240075Sdes * NB. we must save copies of the flags that we override for 1976215116Sdes * the backgrounding, since we defer attachment of the slave until 1977215116Sdes * after the connection is fully established (in particular, 1978215116Sdes * async rfwd replies have been received for ExitOnForwardFailure). 1979215116Sdes */ 1980215116Sdes if (options.control_persist && muxserver_sock != -1) { 1981215116Sdes ostdin_null_flag = stdin_null_flag; 1982215116Sdes ono_shell_flag = no_shell_flag; 1983226046Sdes orequest_tty = options.request_tty; 1984215116Sdes otty_flag = tty_flag; 1985215116Sdes stdin_null_flag = 1; 1986215116Sdes no_shell_flag = 1; 1987215116Sdes tty_flag = 0; 1988215116Sdes if (!fork_after_authentication_flag) 1989215116Sdes need_controlpersist_detach = 1; 1990215116Sdes fork_after_authentication_flag = 1; 1991215116Sdes } 1992240075Sdes /* 1993240075Sdes * ControlPersist mux listen socket setup failed, attempt the 1994240075Sdes * stdio forward setup that we skipped earlier. 1995240075Sdes */ 1996240075Sdes if (options.control_persist && muxserver_sock == -1) 1997240075Sdes ssh_init_stdio_forwarding(); 1998215116Sdes 199992559Sdes if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) 200092559Sdes id = ssh_session2_open(); 2001255767Sdes else { 2002255767Sdes packet_set_interactive( 2003255767Sdes options.control_master == SSHCTL_MASTER_NO, 2004255767Sdes options.ip_qos_interactive, options.ip_qos_bulk); 2005255767Sdes } 200676262Sgreen 2007181111Sdes /* If we don't expect to open a new session, then disallow it */ 2008192595Sdes if (options.control_master == SSHCTL_MASTER_NO && 2009192595Sdes (datafellows & SSH_NEW_OPENSSH)) { 2010181111Sdes debug("Requesting no-more-sessions@openssh.com"); 2011181111Sdes packet_start(SSH2_MSG_GLOBAL_REQUEST); 2012181111Sdes packet_put_cstring("no-more-sessions@openssh.com"); 2013181111Sdes packet_put_char(0); 2014181111Sdes packet_send(); 2015181111Sdes } 2016181111Sdes 2017157019Sdes /* Execute a local command */ 2018157019Sdes if (options.local_command != NULL && 2019157019Sdes options.permit_local_command) 2020157019Sdes ssh_local_cmd(options.local_command); 2021157019Sdes 2022215116Sdes /* 2023215116Sdes * If requested and we are not interested in replies to remote 2024215116Sdes * forwarding requests, then let ssh continue in the background. 2025215116Sdes */ 2026181111Sdes if (fork_after_authentication_flag) { 2027215116Sdes if (options.exit_on_forward_failure && 2028215116Sdes options.num_remote_forwards > 0) { 2029215116Sdes debug("deferring postauth fork until remote forward " 2030215116Sdes "confirmation received"); 2031215116Sdes } else 2032215116Sdes fork_postauth(); 2033181111Sdes } 203476262Sgreen 203592559Sdes return client_loop(tty_flag, tty_flag ? 203692559Sdes options.escape_char : SSH_ESCAPECHAR_NONE, id); 203760576Skris} 203876262Sgreen 2039296781Sdes/* Loads all IdentityFile and CertificateFile keys */ 204092559Sdesstatic void 204176262Sgreenload_public_identity_files(void) 204276262Sgreen{ 2043162856Sdes char *filename, *cp, thishost[NI_MAXHOST]; 2044181111Sdes char *pwdir = NULL, *pwname = NULL; 204576262Sgreen Key *public; 2046162856Sdes struct passwd *pw; 2047296781Sdes int i; 2048296781Sdes u_int n_ids, n_certs; 2049204917Sdes char *identity_files[SSH_MAX_IDENTITY_FILES]; 2050204917Sdes Key *identity_keys[SSH_MAX_IDENTITY_FILES]; 2051296781Sdes char *certificate_files[SSH_MAX_CERTIFICATE_FILES]; 2052296781Sdes struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES]; 2053204917Sdes#ifdef ENABLE_PKCS11 205498684Sdes Key **keys; 2055204917Sdes int nkeys; 2056204917Sdes#endif /* PKCS11 */ 205776262Sgreen 2058296781Sdes n_ids = n_certs = 0; 2059264377Sdes memset(identity_files, 0, sizeof(identity_files)); 2060264377Sdes memset(identity_keys, 0, sizeof(identity_keys)); 2061296781Sdes memset(certificate_files, 0, sizeof(certificate_files)); 2062296781Sdes memset(certificates, 0, sizeof(certificates)); 2063204917Sdes 2064204917Sdes#ifdef ENABLE_PKCS11 2065204917Sdes if (options.pkcs11_provider != NULL && 206698684Sdes options.num_identity_files < SSH_MAX_IDENTITY_FILES && 2067204917Sdes (pkcs11_init(!options.batch_mode) == 0) && 2068204917Sdes (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL, 2069204917Sdes &keys)) > 0) { 2070204917Sdes for (i = 0; i < nkeys; i++) { 2071204917Sdes if (n_ids >= SSH_MAX_IDENTITY_FILES) { 2072204917Sdes key_free(keys[i]); 2073204917Sdes continue; 2074204917Sdes } 2075204917Sdes identity_keys[n_ids] = keys[i]; 2076204917Sdes identity_files[n_ids] = 2077204917Sdes xstrdup(options.pkcs11_provider); /* XXX */ 2078204917Sdes n_ids++; 207998684Sdes } 2080255767Sdes free(keys); 208192559Sdes } 2082204917Sdes#endif /* ENABLE_PKCS11 */ 2083162856Sdes if ((pw = getpwuid(original_real_uid)) == NULL) 2084162856Sdes fatal("load_public_identity_files: getpwuid failed"); 2085181111Sdes pwname = xstrdup(pw->pw_name); 2086181111Sdes pwdir = xstrdup(pw->pw_dir); 2087162856Sdes if (gethostname(thishost, sizeof(thishost)) == -1) 2088162856Sdes fatal("load_public_identity_files: gethostname: %s", 2089162856Sdes strerror(errno)); 2090204917Sdes for (i = 0; i < options.num_identity_files; i++) { 2091249839Sdes if (n_ids >= SSH_MAX_IDENTITY_FILES || 2092249839Sdes strcasecmp(options.identity_files[i], "none") == 0) { 2093255767Sdes free(options.identity_files[i]); 2094296781Sdes options.identity_files[i] = NULL; 2095204917Sdes continue; 2096204917Sdes } 2097162856Sdes cp = tilde_expand_filename(options.identity_files[i], 209876262Sgreen original_real_uid); 2099181111Sdes filename = percent_expand(cp, "d", pwdir, 2100181111Sdes "u", pwname, "l", thishost, "h", host, 2101162856Sdes "r", options.user, (char *)NULL); 2102255767Sdes free(cp); 210376262Sgreen public = key_load_public(filename, NULL); 210476262Sgreen debug("identity file %s type %d", filename, 210576262Sgreen public ? public->type : -1); 2106255767Sdes free(options.identity_files[i]); 2107204917Sdes identity_files[n_ids] = filename; 2108204917Sdes identity_keys[n_ids] = public; 2109204917Sdes 2110204917Sdes if (++n_ids >= SSH_MAX_IDENTITY_FILES) 2111204917Sdes continue; 2112204917Sdes 2113296781Sdes /* 2114296781Sdes * If no certificates have been explicitly listed then try 2115296781Sdes * to add the default certificate variant too. 2116296781Sdes */ 2117296781Sdes if (options.num_certificate_files != 0) 2118296781Sdes continue; 2119204917Sdes xasprintf(&cp, "%s-cert", filename); 2120204917Sdes public = key_load_public(cp, NULL); 2121204917Sdes debug("identity file %s type %d", cp, 2122204917Sdes public ? public->type : -1); 2123204917Sdes if (public == NULL) { 2124255767Sdes free(cp); 2125204917Sdes continue; 2126204917Sdes } 2127204917Sdes if (!key_is_cert(public)) { 2128204917Sdes debug("%s: key %s type %s is not a certificate", 2129204917Sdes __func__, cp, key_type(public)); 2130204917Sdes key_free(public); 2131255767Sdes free(cp); 2132204917Sdes continue; 2133204917Sdes } 2134204917Sdes identity_keys[n_ids] = public; 2135296781Sdes identity_files[n_ids] = cp; 2136204917Sdes n_ids++; 213776262Sgreen } 2138296781Sdes 2139296781Sdes if (options.num_certificate_files > SSH_MAX_CERTIFICATE_FILES) 2140296781Sdes fatal("%s: too many certificates", __func__); 2141296781Sdes for (i = 0; i < options.num_certificate_files; i++) { 2142296781Sdes cp = tilde_expand_filename(options.certificate_files[i], 2143296781Sdes original_real_uid); 2144296781Sdes filename = percent_expand(cp, "d", pwdir, 2145296781Sdes "u", pwname, "l", thishost, "h", host, 2146296781Sdes "r", options.user, (char *)NULL); 2147296781Sdes free(cp); 2148296781Sdes 2149296781Sdes public = key_load_public(filename, NULL); 2150296781Sdes debug("certificate file %s type %d", filename, 2151296781Sdes public ? public->type : -1); 2152296781Sdes free(options.certificate_files[i]); 2153296781Sdes options.certificate_files[i] = NULL; 2154296781Sdes if (public == NULL) { 2155296781Sdes free(filename); 2156296781Sdes continue; 2157296781Sdes } 2158296781Sdes if (!key_is_cert(public)) { 2159296781Sdes debug("%s: key %s type %s is not a certificate", 2160296781Sdes __func__, filename, key_type(public)); 2161296781Sdes key_free(public); 2162296781Sdes free(filename); 2163296781Sdes continue; 2164296781Sdes } 2165296781Sdes certificate_files[n_certs] = filename; 2166296781Sdes certificates[n_certs] = public; 2167296781Sdes ++n_certs; 2168296781Sdes } 2169296781Sdes 2170204917Sdes options.num_identity_files = n_ids; 2171204917Sdes memcpy(options.identity_files, identity_files, sizeof(identity_files)); 2172204917Sdes memcpy(options.identity_keys, identity_keys, sizeof(identity_keys)); 2173204917Sdes 2174296781Sdes options.num_certificate_files = n_certs; 2175296781Sdes memcpy(options.certificate_files, 2176296781Sdes certificate_files, sizeof(certificate_files)); 2177296781Sdes memcpy(options.certificates, certificates, sizeof(certificates)); 2178296781Sdes 2179264377Sdes explicit_bzero(pwname, strlen(pwname)); 2180255767Sdes free(pwname); 2181264377Sdes explicit_bzero(pwdir, strlen(pwdir)); 2182255767Sdes free(pwdir); 218376262Sgreen} 2184221420Sdes 2185221420Sdesstatic void 2186221420Sdesmain_sigchld_handler(int sig) 2187221420Sdes{ 2188221420Sdes int save_errno = errno; 2189221420Sdes pid_t pid; 2190221420Sdes int status; 2191221420Sdes 2192221420Sdes while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || 2193221420Sdes (pid < 0 && errno == EINTR)) 2194221420Sdes ; 2195221420Sdes 2196221420Sdes signal(sig, main_sigchld_handler); 2197221420Sdes errno = save_errno; 2198221420Sdes} 2199