1264377Sdes/* $OpenBSD: ssh.c,v 1.401 2014/02/26 20:18:37 djm Exp $ */ 2224638Sbrooks/* $FreeBSD$ */ 357429Smarkm/* 457429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 557429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 657429Smarkm * All rights reserved 757429Smarkm * Ssh client program. This program can be used to log into a remote machine. 857429Smarkm * The software supports strong authentication, encryption, and forwarding 957429Smarkm * of X11, TCP/IP, and authentication connections. 1057429Smarkm * 1165674Skris * As far as I am concerned, the code I have written for this software 1265674Skris * can be used freely for any purpose. Any derived versions of this 1365674Skris * software must be clearly marked as such, and if the derived work is 1465674Skris * incompatible with the protocol description in the RFC file, it must be 1565674Skris * called by a name other than "ssh" or "Secure Shell". 1657432Smarkm * 1765674Skris * Copyright (c) 1999 Niels Provos. All rights reserved. 18126277Sdes * Copyright (c) 2000, 2001, 2002, 2003 Markus Friedl. All rights reserved. 1965674Skris * 2065674Skris * Modified to work with SSL by Niels Provos <provos@citi.umich.edu> 2165674Skris * in Canada (German citizen). 2265674Skris * 2365674Skris * Redistribution and use in source and binary forms, with or without 2465674Skris * modification, are permitted provided that the following conditions 2565674Skris * are met: 2665674Skris * 1. Redistributions of source code must retain the above copyright 2765674Skris * notice, this list of conditions and the following disclaimer. 2865674Skris * 2. Redistributions in binary form must reproduce the above copyright 2965674Skris * notice, this list of conditions and the following disclaimer in the 3065674Skris * documentation and/or other materials provided with the distribution. 3165674Skris * 3265674Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 3365674Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 3465674Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 3565674Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 3665674Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 3765674Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3865674Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3965674Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 4065674Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 4165674Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4257429Smarkm */ 4357429Smarkm 4457429Smarkm#include "includes.h" 45162856Sdes__RCSID("$FreeBSD$"); 4657429Smarkm 47162856Sdes#include <sys/types.h> 48162856Sdes#ifdef HAVE_SYS_STAT_H 49162856Sdes# include <sys/stat.h> 50162856Sdes#endif 51162856Sdes#include <sys/resource.h> 52162856Sdes#include <sys/ioctl.h> 53197679Sdes#include <sys/param.h> 54162856Sdes#include <sys/socket.h> 55221420Sdes#include <sys/wait.h> 56162856Sdes 57162856Sdes#include <ctype.h> 58162856Sdes#include <errno.h> 59162856Sdes#include <fcntl.h> 60162856Sdes#include <netdb.h> 61162856Sdes#ifdef HAVE_PATHS_H 62162856Sdes#include <paths.h> 63162856Sdes#endif 64162856Sdes#include <pwd.h> 65162856Sdes#include <signal.h> 66162856Sdes#include <stdarg.h> 67162856Sdes#include <stddef.h> 68162856Sdes#include <stdio.h> 69162856Sdes#include <stdlib.h> 70162856Sdes#include <string.h> 71162856Sdes#include <unistd.h> 72162856Sdes 73162856Sdes#include <netinet/in.h> 74162856Sdes#include <arpa/inet.h> 75162856Sdes 7660576Skris#include <openssl/evp.h> 7776262Sgreen#include <openssl/err.h> 78181111Sdes#include "openbsd-compat/openssl-compat.h" 79181111Sdes#include "openbsd-compat/sys-queue.h" 8060576Skris 81162856Sdes#include "xmalloc.h" 8276262Sgreen#include "ssh.h" 8376262Sgreen#include "ssh1.h" 8476262Sgreen#include "ssh2.h" 85215116Sdes#include "canohost.h" 8676262Sgreen#include "compat.h" 8776262Sgreen#include "cipher.h" 8857429Smarkm#include "packet.h" 8957429Smarkm#include "buffer.h" 9060576Skris#include "channels.h" 9160576Skris#include "key.h" 9265674Skris#include "authfd.h" 9360576Skris#include "authfile.h" 9476262Sgreen#include "pathnames.h" 95137019Sdes#include "dispatch.h" 9676262Sgreen#include "clientloop.h" 9776262Sgreen#include "log.h" 9876262Sgreen#include "readconf.h" 9976262Sgreen#include "sshconnect.h" 10076262Sgreen#include "misc.h" 10176262Sgreen#include "kex.h" 10276262Sgreen#include "mac.h" 103137019Sdes#include "sshpty.h" 104137019Sdes#include "match.h" 105137019Sdes#include "msg.h" 106137019Sdes#include "uidswap.h" 107204917Sdes#include "roaming.h" 108162856Sdes#include "version.h" 10960576Skris 110204917Sdes#ifdef ENABLE_PKCS11 111204917Sdes#include "ssh-pkcs11.h" 11292559Sdes#endif 11392559Sdes 11460576Skrisextern char *__progname; 11560576Skris 116226046Sdes/* Saves a copy of argv for setproctitle emulation */ 117226046Sdes#ifndef HAVE_SETPROCTITLE 118226046Sdesstatic char **saved_av; 119226046Sdes#endif 120226046Sdes 121181111Sdes/* Flag indicating whether debug mode is on. May be set on the command line. */ 12257429Smarkmint debug_flag = 0; 12357429Smarkm 124226046Sdes/* Flag indicating whether a tty should be requested */ 12557429Smarkmint tty_flag = 0; 12657429Smarkm 12760576Skris/* don't exec a shell */ 12860576Skrisint no_shell_flag = 0; 12960576Skris 13057429Smarkm/* 13157429Smarkm * Flag indicating that nothing should be read from stdin. This can be set 13257429Smarkm * on the command line. 13357429Smarkm */ 13457429Smarkmint stdin_null_flag = 0; 13557429Smarkm 13657429Smarkm/* 137215116Sdes * Flag indicating that the current process should be backgrounded and 138215116Sdes * a new slave launched in the foreground for ControlPersist. 139215116Sdes */ 140215116Sdesint need_controlpersist_detach = 0; 141215116Sdes 142215116Sdes/* Copies of flags for ControlPersist foreground slave */ 143226046Sdesint ostdin_null_flag, ono_shell_flag, otty_flag, orequest_tty; 144215116Sdes 145215116Sdes/* 14657429Smarkm * Flag indicating that ssh should fork after authentication. This is useful 14798684Sdes * so that the passphrase can be entered manually, and then ssh goes to the 14857429Smarkm * background. 14957429Smarkm */ 15057429Smarkmint fork_after_authentication_flag = 0; 15157429Smarkm 152204917Sdes/* forward stdio to remote host and port */ 153204917Sdeschar *stdio_forward_host = NULL; 154204917Sdesint stdio_forward_port = 0; 155204917Sdes 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, 201192595Sdes"usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n" 202255767Sdes" [-D [bind_address:]port] [-E log_file] [-e escape_char]\n" 203255767Sdes" [-F configfile] [-I pkcs11] [-i identity_file]\n" 204262566Sdes" [-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec]\n" 205262566Sdes" [-O ctl_cmd] [-o option] [-p port]\n" 206262566Sdes" [-Q cipher | cipher-auth | mac | kex | key]\n" 207262566Sdes" [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port]\n" 208262566Sdes" [-w local_tun[:remote_tun]] [user@]hostname [command]\n" 209128460Sdes ); 210157019Sdes exit(255); 21157429Smarkm} 21257429Smarkm 21392559Sdesstatic int ssh_session(void); 21492559Sdesstatic int ssh_session2(void); 21592559Sdesstatic void load_public_identity_files(void); 216221420Sdesstatic void main_sigchld_handler(int); 21760576Skris 218181111Sdes/* from muxclient.c */ 219181111Sdesvoid muxclient(const char *); 220181111Sdesvoid muxserver_listen(void); 221181111Sdes 222226046Sdes/* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */ 223226046Sdesstatic void 224226046Sdestilde_expand_paths(char **paths, u_int num_paths) 225226046Sdes{ 226226046Sdes u_int i; 227226046Sdes char *cp; 228226046Sdes 229226046Sdes for (i = 0; i < num_paths; i++) { 230226046Sdes cp = tilde_expand_filename(paths[i], original_real_uid); 231255767Sdes free(paths[i]); 232226046Sdes paths[i] = cp; 233226046Sdes } 234226046Sdes} 235226046Sdes 236264377Sdes/* 237264377Sdes * Attempt to resolve a host name / port to a set of addresses and 238264377Sdes * optionally return any CNAMEs encountered along the way. 239264377Sdes * Returns NULL on failure. 240264377Sdes * NB. this function must operate with a options having undefined members. 241264377Sdes */ 242262566Sdesstatic struct addrinfo * 243264377Sdesresolve_host(const char *name, int port, int logerr, char *cname, size_t clen) 244262566Sdes{ 245262566Sdes char strport[NI_MAXSERV]; 246262566Sdes struct addrinfo hints, *res; 247262566Sdes int gaierr, loglevel = SYSLOG_LEVEL_DEBUG1; 248262566Sdes 249264377Sdes if (port <= 0) 250264377Sdes port = default_ssh_port(); 251264377Sdes 252262566Sdes snprintf(strport, sizeof strport, "%u", port); 253264377Sdes memset(&hints, 0, sizeof(hints)); 254264377Sdes hints.ai_family = options.address_family == -1 ? 255264377Sdes AF_UNSPEC : options.address_family; 256262566Sdes hints.ai_socktype = SOCK_STREAM; 257262566Sdes if (cname != NULL) 258262566Sdes hints.ai_flags = AI_CANONNAME; 259262566Sdes if ((gaierr = getaddrinfo(name, strport, &hints, &res)) != 0) { 260262566Sdes if (logerr || (gaierr != EAI_NONAME && gaierr != EAI_NODATA)) 261262566Sdes loglevel = SYSLOG_LEVEL_ERROR; 262262566Sdes do_log2(loglevel, "%s: Could not resolve hostname %.100s: %s", 263262566Sdes __progname, name, ssh_gai_strerror(gaierr)); 264262566Sdes return NULL; 265262566Sdes } 266262566Sdes if (cname != NULL && res->ai_canonname != NULL) { 267262566Sdes if (strlcpy(cname, res->ai_canonname, clen) >= clen) { 268262566Sdes error("%s: host \"%s\" cname \"%s\" too long (max %lu)", 269262566Sdes __func__, name, res->ai_canonname, (u_long)clen); 270262566Sdes if (clen > 0) 271262566Sdes *cname = '\0'; 272262566Sdes } 273262566Sdes } 274262566Sdes return res; 275262566Sdes} 276262566Sdes 27757429Smarkm/* 278262566Sdes * Check whether the cname is a permitted replacement for the hostname 279262566Sdes * and perform the replacement if it is. 280264377Sdes * NB. this function must operate with a options having undefined members. 281262566Sdes */ 282262566Sdesstatic int 283262566Sdescheck_follow_cname(char **namep, const char *cname) 284262566Sdes{ 285262566Sdes int i; 286262566Sdes struct allowed_cname *rule; 287262566Sdes 288262566Sdes if (*cname == '\0' || options.num_permitted_cnames == 0 || 289262566Sdes strcmp(*namep, cname) == 0) 290262566Sdes return 0; 291262566Sdes if (options.canonicalize_hostname == SSH_CANONICALISE_NO) 292262566Sdes return 0; 293262566Sdes /* 294262566Sdes * Don't attempt to canonicalize names that will be interpreted by 295262566Sdes * a proxy unless the user specifically requests so. 296262566Sdes */ 297264377Sdes if (!option_clear_or_none(options.proxy_command) && 298262566Sdes options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) 299262566Sdes return 0; 300262566Sdes debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname); 301262566Sdes for (i = 0; i < options.num_permitted_cnames; i++) { 302262566Sdes rule = options.permitted_cnames + i; 303262566Sdes if (match_pattern_list(*namep, rule->source_list, 304262566Sdes strlen(rule->source_list), 1) != 1 || 305262566Sdes match_pattern_list(cname, rule->target_list, 306262566Sdes strlen(rule->target_list), 1) != 1) 307262566Sdes continue; 308262566Sdes verbose("Canonicalized DNS aliased hostname " 309262566Sdes "\"%s\" => \"%s\"", *namep, cname); 310262566Sdes free(*namep); 311262566Sdes *namep = xstrdup(cname); 312262566Sdes return 1; 313262566Sdes } 314262566Sdes return 0; 315262566Sdes} 316262566Sdes 317262566Sdes/* 318262566Sdes * Attempt to resolve the supplied hostname after applying the user's 319262566Sdes * canonicalization rules. Returns the address list for the host or NULL 320262566Sdes * if no name was found after canonicalization. 321264377Sdes * NB. this function must operate with a options having undefined members. 322262566Sdes */ 323262566Sdesstatic struct addrinfo * 324264377Sdesresolve_canonicalize(char **hostp, int port) 325262566Sdes{ 326262566Sdes int i, ndots; 327262566Sdes char *cp, *fullhost, cname_target[NI_MAXHOST]; 328262566Sdes struct addrinfo *addrs; 329262566Sdes 330262566Sdes if (options.canonicalize_hostname == SSH_CANONICALISE_NO) 331262566Sdes return NULL; 332264377Sdes 333262566Sdes /* 334262566Sdes * Don't attempt to canonicalize names that will be interpreted by 335262566Sdes * a proxy unless the user specifically requests so. 336262566Sdes */ 337264377Sdes if (!option_clear_or_none(options.proxy_command) && 338262566Sdes options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) 339262566Sdes return NULL; 340264377Sdes 341262566Sdes /* Don't apply canonicalization to sufficiently-qualified hostnames */ 342262566Sdes ndots = 0; 343262566Sdes for (cp = *hostp; *cp != '\0'; cp++) { 344262566Sdes if (*cp == '.') 345262566Sdes ndots++; 346262566Sdes } 347262566Sdes if (ndots > options.canonicalize_max_dots) { 348262566Sdes debug3("%s: not canonicalizing hostname \"%s\" (max dots %d)", 349262566Sdes __func__, *hostp, options.canonicalize_max_dots); 350262566Sdes return NULL; 351262566Sdes } 352262566Sdes /* Attempt each supplied suffix */ 353262566Sdes for (i = 0; i < options.num_canonical_domains; i++) { 354262566Sdes *cname_target = '\0'; 355262566Sdes xasprintf(&fullhost, "%s.%s.", *hostp, 356262566Sdes options.canonical_domains[i]); 357264377Sdes debug3("%s: attempting \"%s\" => \"%s\"", __func__, 358264377Sdes *hostp, fullhost); 359264377Sdes if ((addrs = resolve_host(fullhost, port, 0, 360262566Sdes cname_target, sizeof(cname_target))) == NULL) { 361262566Sdes free(fullhost); 362262566Sdes continue; 363262566Sdes } 364262566Sdes /* Remove trailing '.' */ 365262566Sdes fullhost[strlen(fullhost) - 1] = '\0'; 366262566Sdes /* Follow CNAME if requested */ 367262566Sdes if (!check_follow_cname(&fullhost, cname_target)) { 368262566Sdes debug("Canonicalized hostname \"%s\" => \"%s\"", 369262566Sdes *hostp, fullhost); 370262566Sdes } 371262566Sdes free(*hostp); 372262566Sdes *hostp = fullhost; 373262566Sdes return addrs; 374262566Sdes } 375262566Sdes if (!options.canonicalize_fallback_local) 376264377Sdes fatal("%s: Could not resolve host \"%s\"", __progname, *hostp); 377264377Sdes debug2("%s: host %s not found in any suffix", __func__, *hostp); 378262566Sdes return NULL; 379262566Sdes} 380262566Sdes 381262566Sdes/* 382264377Sdes * Read per-user configuration file. Ignore the system wide config 383264377Sdes * file if the user specifies a config file on the command line. 384264377Sdes */ 385264377Sdesstatic void 386264377Sdesprocess_config_files(struct passwd *pw) 387264377Sdes{ 388264377Sdes char buf[MAXPATHLEN]; 389264377Sdes int r; 390264377Sdes 391264377Sdes if (config != NULL) { 392264377Sdes if (strcasecmp(config, "none") != 0 && 393264377Sdes !read_config_file(config, pw, host, &options, 394264377Sdes SSHCONF_USERCONF)) 395264377Sdes fatal("Can't open user config file %.100s: " 396264377Sdes "%.100s", config, strerror(errno)); 397264377Sdes } else { 398264377Sdes r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, 399264377Sdes _PATH_SSH_USER_CONFFILE); 400264377Sdes if (r > 0 && (size_t)r < sizeof(buf)) 401264377Sdes (void)read_config_file(buf, pw, host, &options, 402264377Sdes SSHCONF_CHECKPERM|SSHCONF_USERCONF); 403264377Sdes 404264377Sdes /* Read systemwide configuration file after user config. */ 405264377Sdes (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, host, 406264377Sdes &options, 0); 407264377Sdes } 408264377Sdes} 409264377Sdes 410264377Sdes/* 41157429Smarkm * Main program for the ssh client. 41257429Smarkm */ 41357429Smarkmint 41457429Smarkmmain(int ac, char **av) 41557429Smarkm{ 416197679Sdes int i, r, opt, exit_status, use_syslog; 417255767Sdes char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg, *logfile; 418226046Sdes char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; 419262566Sdes char cname[NI_MAXHOST]; 42057429Smarkm struct stat st; 42176262Sgreen struct passwd *pw; 422262566Sdes int timeout_ms; 42392559Sdes extern int optind, optreset; 42492559Sdes extern char *optarg; 425147005Sdes Forward fwd; 426262566Sdes struct addrinfo *addrs = NULL; 42757429Smarkm 428157019Sdes /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 429157019Sdes sanitise_stdfd(); 430157019Sdes 431124211Sdes __progname = ssh_get_progname(av[0]); 43298941Sdes 433226046Sdes#ifndef HAVE_SETPROCTITLE 434226046Sdes /* Prepare for later setproctitle emulation */ 435226046Sdes /* Save argv so it isn't clobbered by setproctitle() emulation */ 436226046Sdes saved_av = xcalloc(ac + 1, sizeof(*saved_av)); 437226046Sdes for (i = 0; i < ac; i++) 438226046Sdes saved_av[i] = xstrdup(av[i]); 439226046Sdes saved_av[i] = NULL; 440226046Sdes compat_init_setproctitle(ac, av); 441226046Sdes av = saved_av; 442226046Sdes#endif 443226046Sdes 44457429Smarkm /* 445215116Sdes * Discard other fds that are hanging around. These can cause problem 446215116Sdes * with backgrounded ssh processes started by ControlPersist. 447215116Sdes */ 448215116Sdes closefrom(STDERR_FILENO + 1); 449215116Sdes 450215116Sdes /* 45157429Smarkm * Save the original real uid. It will be needed later (uid-swapping 45257429Smarkm * may clobber the real uid). 45357429Smarkm */ 45457429Smarkm original_real_uid = getuid(); 45557429Smarkm original_effective_uid = geteuid(); 456126277Sdes 457106130Sdes /* 458106130Sdes * Use uid-swapping to give up root privileges for the duration of 459106130Sdes * option processing. We will re-instantiate the rights when we are 460106130Sdes * ready to create the privileged port, and will permanently drop 461106130Sdes * them when the port has been created (actually, when the connection 462106130Sdes * has been made, as we may need to create the port several times). 463106130Sdes */ 464106130Sdes PRIV_END; 46557429Smarkm 46698941Sdes#ifdef HAVE_SETRLIMIT 46757429Smarkm /* If we are installed setuid root be careful to not drop core. */ 46857429Smarkm if (original_real_uid != original_effective_uid) { 46957429Smarkm struct rlimit rlim; 47057429Smarkm rlim.rlim_cur = rlim.rlim_max = 0; 47157429Smarkm if (setrlimit(RLIMIT_CORE, &rlim) < 0) 47257429Smarkm fatal("setrlimit failed: %.100s", strerror(errno)); 47357429Smarkm } 47498941Sdes#endif 47576262Sgreen /* Get user data. */ 47676262Sgreen pw = getpwuid(original_real_uid); 47776262Sgreen if (!pw) { 478255767Sdes logit("No user exists for uid %lu", (u_long)original_real_uid); 479157019Sdes exit(255); 48076262Sgreen } 48176262Sgreen /* Take a copy of the returned structure. */ 48276262Sgreen pw = pwcopy(pw); 48376262Sgreen 48457429Smarkm /* 48557429Smarkm * Set our umask to something reasonable, as some files are created 48657429Smarkm * with the default umask. This will make them world-readable but 48757429Smarkm * writable only by the owner, which is ok for all files for which we 48857429Smarkm * don't set the modes explicitly. 48957429Smarkm */ 49057429Smarkm umask(022); 49157429Smarkm 492181111Sdes /* 493181111Sdes * Initialize option structure to indicate that no values have been 494181111Sdes * set. 495181111Sdes */ 49657429Smarkm initialize_options(&options); 49757429Smarkm 49857429Smarkm /* Parse command-line arguments. */ 49957429Smarkm host = NULL; 500192595Sdes use_syslog = 0; 501255767Sdes logfile = NULL; 502197679Sdes argv0 = av[0]; 50357429Smarkm 504162856Sdes again: 505181111Sdes while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" 506255767Sdes "ACD:E:F:I:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { 50757429Smarkm switch (opt) { 50876262Sgreen case '1': 50976262Sgreen options.protocol = SSH_PROTO_1; 51076262Sgreen break; 51160576Skris case '2': 51260576Skris options.protocol = SSH_PROTO_2; 51360576Skris break; 51457429Smarkm case '4': 515124211Sdes options.address_family = AF_INET; 51657429Smarkm break; 51757429Smarkm case '6': 518124211Sdes options.address_family = AF_INET6; 51957429Smarkm break; 52057429Smarkm case 'n': 52157429Smarkm stdin_null_flag = 1; 52257429Smarkm break; 52357429Smarkm case 'f': 52457429Smarkm fork_after_authentication_flag = 1; 52557429Smarkm stdin_null_flag = 1; 52657429Smarkm break; 52757429Smarkm case 'x': 52857429Smarkm options.forward_x11 = 0; 52957429Smarkm break; 53057429Smarkm case 'X': 53157429Smarkm options.forward_x11 = 1; 53257429Smarkm break; 533192595Sdes case 'y': 534192595Sdes use_syslog = 1; 535192595Sdes break; 536255767Sdes case 'E': 537255767Sdes logfile = xstrdup(optarg); 538255767Sdes break; 539126277Sdes case 'Y': 540126277Sdes options.forward_x11 = 1; 541126277Sdes options.forward_x11_trusted = 1; 542126277Sdes break; 54357429Smarkm case 'g': 54457429Smarkm options.gateway_ports = 1; 54557429Smarkm break; 546147005Sdes case 'O': 547204917Sdes if (stdio_forward_host != NULL) 548204917Sdes fatal("Cannot specify multiplexing " 549204917Sdes "command with -W"); 550204917Sdes else if (muxclient_command != 0) 551204917Sdes fatal("Multiplexing command already specified"); 552147005Sdes if (strcmp(optarg, "check") == 0) 553181111Sdes muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK; 554215116Sdes else if (strcmp(optarg, "forward") == 0) 555215116Sdes muxclient_command = SSHMUX_COMMAND_FORWARD; 556147005Sdes else if (strcmp(optarg, "exit") == 0) 557181111Sdes muxclient_command = SSHMUX_COMMAND_TERMINATE; 558226046Sdes else if (strcmp(optarg, "stop") == 0) 559226046Sdes muxclient_command = SSHMUX_COMMAND_STOP; 560240075Sdes else if (strcmp(optarg, "cancel") == 0) 561240075Sdes muxclient_command = SSHMUX_COMMAND_CANCEL_FWD; 562147005Sdes else 563147005Sdes fatal("Invalid multiplex command."); 564147005Sdes break; 565106130Sdes case 'P': /* deprecated */ 56657429Smarkm options.use_privileged_port = 0; 56757429Smarkm break; 568262566Sdes case 'Q': 569255767Sdes cp = NULL; 570262566Sdes if (strcmp(optarg, "cipher") == 0) 571262566Sdes cp = cipher_alg_list('\n', 0); 572262566Sdes else if (strcmp(optarg, "cipher-auth") == 0) 573262566Sdes cp = cipher_alg_list('\n', 1); 574262566Sdes else if (strcmp(optarg, "mac") == 0) 575262566Sdes cp = mac_alg_list('\n'); 576262566Sdes else if (strcmp(optarg, "kex") == 0) 577262566Sdes cp = kex_alg_list('\n'); 578262566Sdes else if (strcmp(optarg, "key") == 0) 579262566Sdes cp = key_alg_list(0, 0); 580262566Sdes else if (strcmp(optarg, "key-cert") == 0) 581262566Sdes cp = key_alg_list(1, 0); 582262566Sdes else if (strcmp(optarg, "key-plain") == 0) 583262566Sdes cp = key_alg_list(0, 1); 584255767Sdes if (cp == NULL) 585255767Sdes fatal("Unsupported query \"%s\"", optarg); 586255767Sdes printf("%s\n", cp); 587255767Sdes free(cp); 588255767Sdes exit(0); 589255767Sdes break; 59057429Smarkm case 'a': 59157429Smarkm options.forward_agent = 0; 59257429Smarkm break; 59361203Skris case 'A': 59461203Skris options.forward_agent = 1; 59561203Skris break; 59657429Smarkm case 'k': 597126277Sdes options.gss_deleg_creds = 0; 59857429Smarkm break; 599181111Sdes case 'K': 600181111Sdes options.gss_authentication = 1; 601181111Sdes options.gss_deleg_creds = 1; 602181111Sdes break; 60357429Smarkm case 'i': 60457429Smarkm if (stat(optarg, &st) < 0) { 60592559Sdes fprintf(stderr, "Warning: Identity file %s " 606147005Sdes "not accessible: %s.\n", optarg, 607147005Sdes strerror(errno)); 60857429Smarkm break; 60957429Smarkm } 610249016Sdes add_identity_file(&options, NULL, optarg, 1); 61157429Smarkm break; 61292559Sdes case 'I': 613204917Sdes#ifdef ENABLE_PKCS11 614204917Sdes options.pkcs11_provider = xstrdup(optarg); 61592559Sdes#else 616204917Sdes fprintf(stderr, "no support for PKCS#11.\n"); 61792559Sdes#endif 61892559Sdes break; 61957429Smarkm case 't': 620226046Sdes if (options.request_tty == REQUEST_TTY_YES) 621226046Sdes options.request_tty = REQUEST_TTY_FORCE; 622226046Sdes else 623226046Sdes options.request_tty = REQUEST_TTY_YES; 62457429Smarkm break; 62557429Smarkm case 'v': 626124211Sdes if (debug_flag == 0) { 62769591Sgreen debug_flag = 1; 62869591Sgreen options.log_level = SYSLOG_LEVEL_DEBUG1; 629124211Sdes } else { 630124211Sdes if (options.log_level < SYSLOG_LEVEL_DEBUG3) 631124211Sdes options.log_level++; 632124211Sdes } 633255767Sdes break; 63457429Smarkm case 'V': 635240075Sdes if (options.version_addendum && 636240075Sdes *options.version_addendum != '\0') 637240075Sdes fprintf(stderr, "%s%s %s, %s\n", SSH_RELEASE, 638240075Sdes options.hpn_disabled ? "" : SSH_VERSION_HPN, 639240075Sdes options.version_addendum, 640240075Sdes SSLeay_version(SSLEAY_VERSION)); 641240075Sdes else 642240075Sdes fprintf(stderr, "%s%s, %s\n", SSH_RELEASE, 643240075Sdes options.hpn_disabled ? "" : SSH_VERSION_HPN, 644240075Sdes SSLeay_version(SSLEAY_VERSION)); 64557429Smarkm if (opt == 'V') 64657429Smarkm exit(0); 64757429Smarkm break; 648157019Sdes case 'w': 649157019Sdes if (options.tun_open == -1) 650157019Sdes options.tun_open = SSH_TUNMODE_DEFAULT; 651157019Sdes options.tun_local = a2tun(optarg, &options.tun_remote); 652157019Sdes if (options.tun_local == SSH_TUNID_ERR) { 653181111Sdes fprintf(stderr, 654181111Sdes "Bad tun device '%s'\n", optarg); 655157019Sdes exit(255); 656157019Sdes } 657157019Sdes break; 658204917Sdes case 'W': 659204917Sdes if (stdio_forward_host != NULL) 660204917Sdes fatal("stdio forward already specified"); 661204917Sdes if (muxclient_command != 0) 662204917Sdes fatal("Cannot specify stdio forward with -O"); 663204917Sdes if (parse_forward(&fwd, optarg, 1, 0)) { 664204917Sdes stdio_forward_host = fwd.listen_host; 665204917Sdes stdio_forward_port = fwd.listen_port; 666255767Sdes free(fwd.connect_host); 667204917Sdes } else { 668204917Sdes fprintf(stderr, 669204917Sdes "Bad stdio forwarding specification '%s'\n", 670204917Sdes optarg); 671204917Sdes exit(255); 672204917Sdes } 673226046Sdes options.request_tty = REQUEST_TTY_NO; 674204917Sdes no_shell_flag = 1; 675204917Sdes options.clear_forwardings = 1; 676204917Sdes options.exit_on_forward_failure = 1; 677204917Sdes break; 67857429Smarkm case 'q': 67957429Smarkm options.log_level = SYSLOG_LEVEL_QUIET; 68057429Smarkm break; 68157429Smarkm case 'e': 68257429Smarkm if (optarg[0] == '^' && optarg[2] == 0 && 68392559Sdes (u_char) optarg[1] >= 64 && 68492559Sdes (u_char) optarg[1] < 128) 68576262Sgreen options.escape_char = (u_char) optarg[1] & 31; 68657429Smarkm else if (strlen(optarg) == 1) 68776262Sgreen options.escape_char = (u_char) optarg[0]; 68857429Smarkm else if (strcmp(optarg, "none") == 0) 68992559Sdes options.escape_char = SSH_ESCAPECHAR_NONE; 69057429Smarkm else { 69192559Sdes fprintf(stderr, "Bad escape character '%s'.\n", 69292559Sdes optarg); 693157019Sdes exit(255); 69457429Smarkm } 69557429Smarkm break; 69657429Smarkm case 'c': 69760576Skris if (ciphers_valid(optarg)) { 69860576Skris /* SSH2 only */ 69960576Skris options.ciphers = xstrdup(optarg); 700137019Sdes options.cipher = SSH_CIPHER_INVALID; 70160576Skris } else { 70260576Skris /* SSH1 only */ 70376262Sgreen options.cipher = cipher_number(optarg); 70476262Sgreen if (options.cipher == -1) { 70592559Sdes fprintf(stderr, 70692559Sdes "Unknown cipher type '%s'\n", 70792559Sdes optarg); 708157019Sdes exit(255); 70960576Skris } 71092559Sdes if (options.cipher == SSH_CIPHER_3DES) 71176262Sgreen options.ciphers = "3des-cbc"; 71292559Sdes else if (options.cipher == SSH_CIPHER_BLOWFISH) 71376262Sgreen options.ciphers = "blowfish-cbc"; 71492559Sdes else 71576262Sgreen options.ciphers = (char *)-1; 71657429Smarkm } 71757429Smarkm break; 71876262Sgreen case 'm': 71976262Sgreen if (mac_valid(optarg)) 72076262Sgreen options.macs = xstrdup(optarg); 72176262Sgreen else { 72292559Sdes fprintf(stderr, "Unknown mac type '%s'\n", 72392559Sdes optarg); 724157019Sdes exit(255); 72576262Sgreen } 72676262Sgreen break; 727137019Sdes case 'M': 728149753Sdes if (options.control_master == SSHCTL_MASTER_YES) 729149753Sdes options.control_master = SSHCTL_MASTER_ASK; 730149753Sdes else 731149753Sdes options.control_master = SSHCTL_MASTER_YES; 732137019Sdes break; 73357429Smarkm case 'p': 73476262Sgreen options.port = a2port(optarg); 735192595Sdes if (options.port <= 0) { 73676262Sgreen fprintf(stderr, "Bad port '%s'\n", optarg); 737157019Sdes exit(255); 73876262Sgreen } 73957429Smarkm break; 74057429Smarkm case 'l': 74157429Smarkm options.user = optarg; 74257429Smarkm break; 74392559Sdes 74492559Sdes case 'L': 745192595Sdes if (parse_forward(&fwd, optarg, 0, 0)) 746147005Sdes add_local_forward(&options, &fwd); 747147005Sdes else { 74892559Sdes fprintf(stderr, 749147005Sdes "Bad local forwarding specification '%s'\n", 75092559Sdes optarg); 751157019Sdes exit(255); 75257429Smarkm } 753147005Sdes break; 754147005Sdes 755147005Sdes case 'R': 756192595Sdes if (parse_forward(&fwd, optarg, 0, 1)) { 757147005Sdes add_remote_forward(&options, &fwd); 758147005Sdes } else { 75992559Sdes fprintf(stderr, 760147005Sdes "Bad remote forwarding specification " 761147005Sdes "'%s'\n", optarg); 762157019Sdes exit(255); 76357429Smarkm } 76457429Smarkm break; 76576262Sgreen 76676262Sgreen case 'D': 767192595Sdes if (parse_forward(&fwd, optarg, 1, 0)) { 768192595Sdes add_local_forward(&options, &fwd); 769147005Sdes } else { 770192595Sdes fprintf(stderr, 771192595Sdes "Bad dynamic forwarding specification " 772192595Sdes "'%s'\n", optarg); 773157019Sdes exit(255); 77476262Sgreen } 77576262Sgreen break; 77676262Sgreen 77757429Smarkm case 'C': 77857429Smarkm options.compression = 1; 77957429Smarkm break; 78060576Skris case 'N': 78160576Skris no_shell_flag = 1; 782226046Sdes options.request_tty = REQUEST_TTY_NO; 78360576Skris break; 78460576Skris case 'T': 785226046Sdes options.request_tty = REQUEST_TTY_NO; 786224638Sbrooks#ifdef NONE_CIPHER_ENABLED 787224638Sbrooks /* 788224638Sbrooks * Ensure that the user does not try to backdoor a 789224638Sbrooks * NONE cipher switch on an interactive session by 790224638Sbrooks * explicitly disabling it if the user asks for a 791224638Sbrooks * session without a tty. 792224638Sbrooks */ 793224638Sbrooks options.none_switch = 0; 794224638Sbrooks#endif 79560576Skris break; 79657429Smarkm case 'o': 797126277Sdes line = xstrdup(optarg); 798262566Sdes if (process_config_line(&options, pw, host ? host : "", 799262566Sdes line, "command-line", 0, NULL, SSHCONF_USERCONF) 800249839Sdes != 0) 801157019Sdes exit(255); 802255767Sdes free(line); 80357429Smarkm break; 80476262Sgreen case 's': 80576262Sgreen subsystem_flag = 1; 80676262Sgreen break; 807137019Sdes case 'S': 808137019Sdes if (options.control_path != NULL) 809137019Sdes free(options.control_path); 810137019Sdes options.control_path = xstrdup(optarg); 811137019Sdes break; 81292559Sdes case 'b': 81392559Sdes options.bind_address = optarg; 81492559Sdes break; 81592559Sdes case 'F': 81692559Sdes config = optarg; 81792559Sdes break; 81857429Smarkm default: 81957429Smarkm usage(); 82057429Smarkm } 82157429Smarkm } 82257429Smarkm 82392559Sdes ac -= optind; 82492559Sdes av += optind; 82592559Sdes 826204917Sdes if (ac > 0 && !host) { 827113911Sdes if (strrchr(*av, '@')) { 82892559Sdes p = xstrdup(*av); 829113911Sdes cp = strrchr(p, '@'); 83092559Sdes if (cp == NULL || cp == p) 83192559Sdes usage(); 83292559Sdes options.user = p; 83392559Sdes *cp = '\0'; 834262566Sdes host = xstrdup(++cp); 83592559Sdes } else 836262566Sdes host = xstrdup(*av); 837113911Sdes if (ac > 1) { 838113911Sdes optind = optreset = 1; 83992559Sdes goto again; 84092559Sdes } 841113911Sdes ac--, av++; 84292559Sdes } 84392559Sdes 84457429Smarkm /* Check that we got a host name. */ 84557429Smarkm if (!host) 84657429Smarkm usage(); 84757429Smarkm 848262566Sdes host_arg = xstrdup(host); 849262566Sdes 850221420Sdes OpenSSL_add_all_algorithms(); 85176262Sgreen ERR_load_crypto_strings(); 85257429Smarkm 85357429Smarkm /* Initialize the command to execute on remote host. */ 85457429Smarkm buffer_init(&command); 85557429Smarkm 85657429Smarkm /* 85757429Smarkm * Save the command to execute on the remote host in a buffer. There 85857429Smarkm * is no limit on the length of the command, except by the maximum 85957429Smarkm * packet size. Also sets the tty flag if there is no command. 86057429Smarkm */ 86192559Sdes if (!ac) { 86257429Smarkm /* No command specified - execute shell on a tty. */ 86376262Sgreen if (subsystem_flag) { 86492559Sdes fprintf(stderr, 86592559Sdes "You must specify a subsystem to invoke.\n"); 86676262Sgreen usage(); 86776262Sgreen } 86857429Smarkm } else { 86992559Sdes /* A command has been specified. Store it into the buffer. */ 87092559Sdes for (i = 0; i < ac; i++) { 87192559Sdes if (i) 87257429Smarkm buffer_append(&command, " ", 1); 87357429Smarkm buffer_append(&command, av[i], strlen(av[i])); 87457429Smarkm } 87557429Smarkm } 87657429Smarkm 87757429Smarkm /* Cannot fork to background if no command. */ 878181111Sdes if (fork_after_authentication_flag && buffer_len(&command) == 0 && 879181111Sdes !no_shell_flag) 880181111Sdes fatal("Cannot fork into background without a command " 881181111Sdes "to execute."); 88257429Smarkm 88376262Sgreen /* 88476262Sgreen * Initialize "log" output. Since we are the client all output 885255767Sdes * goes to stderr unless otherwise specified by -y or -E. 88676262Sgreen */ 887255767Sdes if (use_syslog && logfile != NULL) 888255767Sdes fatal("Can't specify both -y and -E"); 889255767Sdes if (logfile != NULL) { 890255767Sdes log_redirect_stderr_to(logfile); 891255767Sdes free(logfile); 892255767Sdes } 893197679Sdes log_init(argv0, 894181111Sdes options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, 895192595Sdes SYSLOG_FACILITY_USER, !use_syslog); 89657429Smarkm 897255767Sdes if (debug_flag) 898264377Sdes logit("%s, %s", SSH_RELEASE, SSLeay_version(SSLEAY_VERSION)); 899255767Sdes 900264377Sdes /* Parse the configuration files */ 901264377Sdes process_config_files(pw); 902264377Sdes 903264377Sdes /* Hostname canonicalisation needs a few options filled. */ 904264377Sdes fill_default_options_for_canonicalization(&options); 905264377Sdes 906264377Sdes /* If the user has replaced the hostname then take it into use now */ 907264377Sdes if (options.hostname != NULL) { 908264377Sdes /* NB. Please keep in sync with readconf.c:match_cfg_line() */ 909264377Sdes cp = percent_expand(options.hostname, 910264377Sdes "h", host, (char *)NULL); 911264377Sdes free(host); 912264377Sdes host = cp; 913264377Sdes } 914264377Sdes 915264377Sdes /* If canonicalization requested then try to apply it */ 916264377Sdes lowercase(host); 917264377Sdes if (options.canonicalize_hostname != SSH_CANONICALISE_NO) 918264377Sdes addrs = resolve_canonicalize(&host, options.port); 919264377Sdes 92092559Sdes /* 921264377Sdes * If CanonicalizePermittedCNAMEs have been specified but 922264377Sdes * other canonicalization did not happen (by not being requested 923264377Sdes * or by failing with fallback) then the hostname may still be changed 924264377Sdes * as a result of CNAME following. 925264377Sdes * 926264377Sdes * Try to resolve the bare hostname name using the system resolver's 927264377Sdes * usual search rules and then apply the CNAME follow rules. 928264377Sdes * 929264377Sdes * Skip the lookup if a ProxyCommand is being used unless the user 930264377Sdes * has specifically requested canonicalisation for this case via 931264377Sdes * CanonicalizeHostname=always 93292559Sdes */ 933264377Sdes if (addrs == NULL && options.num_permitted_cnames != 0 && 934264377Sdes (option_clear_or_none(options.proxy_command) || 935264377Sdes options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) { 936264377Sdes if ((addrs = resolve_host(host, options.port, 1, 937264377Sdes cname, sizeof(cname))) == NULL) 938264377Sdes cleanup_exit(255); /* resolve_host logs the error */ 939264377Sdes check_follow_cname(&host, cname); 940264377Sdes } 94157429Smarkm 942264377Sdes /* 943264377Sdes * If the target hostname has changed as a result of canonicalisation 944264377Sdes * then re-parse the configuration files as new stanzas may match. 945264377Sdes */ 946264377Sdes if (strcasecmp(host_arg, host) != 0) { 947264377Sdes debug("Hostname has changed; re-reading configuration"); 948264377Sdes process_config_files(pw); 94992559Sdes } 95057429Smarkm 95157429Smarkm /* Fill configuration defaults. */ 95257429Smarkm fill_default_options(&options); 95357429Smarkm 954264377Sdes if (options.port == 0) 955264377Sdes options.port = default_ssh_port(); 956124211Sdes channel_set_af(options.address_family); 957124211Sdes 958262566Sdes /* Tidy and check options */ 959262566Sdes if (options.host_key_alias != NULL) 960262566Sdes lowercase(options.host_key_alias); 961262566Sdes if (options.proxy_command != NULL && 962262566Sdes strcmp(options.proxy_command, "-") == 0 && 963262566Sdes options.proxy_use_fdpass) 964262566Sdes fatal("ProxyCommand=- and ProxyUseFDPass are incompatible"); 965262566Sdes#ifndef HAVE_CYGWIN 966262566Sdes if (original_effective_uid != 0) 967262566Sdes options.use_privileged_port = 0; 968262566Sdes#endif 969262566Sdes 97057429Smarkm /* reinit */ 971197679Sdes log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog); 97257429Smarkm 973240075Sdes if (options.request_tty == REQUEST_TTY_YES || 974240075Sdes options.request_tty == REQUEST_TTY_FORCE) 975240075Sdes tty_flag = 1; 976240075Sdes 977240075Sdes /* Allocate a tty by default if no command specified. */ 978240075Sdes if (buffer_len(&command) == 0) 979240075Sdes tty_flag = options.request_tty != REQUEST_TTY_NO; 980240075Sdes 981240075Sdes /* Force no tty */ 982240075Sdes if (options.request_tty == REQUEST_TTY_NO || muxclient_command != 0) 983240075Sdes tty_flag = 0; 984240075Sdes /* Do not allocate a tty if stdin is not a tty. */ 985240075Sdes if ((!isatty(fileno(stdin)) || stdin_null_flag) && 986240075Sdes options.request_tty != REQUEST_TTY_FORCE) { 987240075Sdes if (tty_flag) 988240075Sdes logit("Pseudo-terminal will not be allocated because " 989240075Sdes "stdin is not a terminal."); 990240075Sdes tty_flag = 0; 991240075Sdes } 992240075Sdes 99398941Sdes seed_rng(); 99498941Sdes 99557429Smarkm if (options.user == NULL) 99657429Smarkm options.user = xstrdup(pw->pw_name); 99757429Smarkm 998226046Sdes if (gethostname(thishost, sizeof(thishost)) == -1) 999226046Sdes fatal("gethostname: %s", strerror(errno)); 1000226046Sdes strlcpy(shorthost, thishost, sizeof(shorthost)); 1001226046Sdes shorthost[strcspn(thishost, ".")] = '\0'; 1002226046Sdes snprintf(portstr, sizeof(portstr), "%d", options.port); 1003226046Sdes 1004181111Sdes if (options.local_command != NULL) { 1005181111Sdes debug3("expanding LocalCommand: %s", options.local_command); 1006181111Sdes cp = options.local_command; 1007181111Sdes options.local_command = percent_expand(cp, "d", pw->pw_dir, 1008221420Sdes "h", host, "l", thishost, "n", host_arg, "r", options.user, 1009226046Sdes "p", portstr, "u", pw->pw_name, "L", shorthost, 1010226046Sdes (char *)NULL); 1011181111Sdes debug3("expanded LocalCommand: %s", options.local_command); 1012255767Sdes free(cp); 1013181111Sdes } 1014181111Sdes 1015137019Sdes if (options.control_path != NULL) { 1016149753Sdes cp = tilde_expand_filename(options.control_path, 1017149753Sdes original_real_uid); 1018255767Sdes free(options.control_path); 1019226046Sdes options.control_path = percent_expand(cp, "h", host, 1020226046Sdes "l", thishost, "n", host_arg, "r", options.user, 1021226046Sdes "p", portstr, "u", pw->pw_name, "L", shorthost, 1022226046Sdes (char *)NULL); 1023255767Sdes free(cp); 1024137019Sdes } 1025181111Sdes if (muxclient_command != 0 && options.control_path == NULL) 1026149753Sdes fatal("No ControlPath specified for \"-O\" command"); 1027149753Sdes if (options.control_path != NULL) 1028181111Sdes muxclient(options.control_path); 1029137019Sdes 1030264377Sdes /* 1031264377Sdes * If hostname canonicalisation was not enabled, then we may not 1032264377Sdes * have yet resolved the hostname. Do so now. 1033264377Sdes */ 1034264377Sdes if (addrs == NULL && options.proxy_command == NULL) { 1035264377Sdes if ((addrs = resolve_host(host, options.port, 1, 1036264377Sdes cname, sizeof(cname))) == NULL) 1037264377Sdes cleanup_exit(255); /* resolve_host logs the error */ 1038264377Sdes } 1039264377Sdes 1040181111Sdes timeout_ms = options.connection_timeout * 1000; 1041181111Sdes 104276262Sgreen /* Open a connection to the remote host. */ 1043262566Sdes if (ssh_connect(host, addrs, &hostaddr, options.port, 1044262566Sdes options.address_family, options.connection_attempts, 1045262566Sdes &timeout_ms, options.tcp_keep_alive, 1046262566Sdes options.use_privileged_port) != 0) 1047262566Sdes exit(255); 104857429Smarkm 1049262566Sdes if (addrs != NULL) 1050262566Sdes freeaddrinfo(addrs); 1051262566Sdes 1052262566Sdes packet_set_timeout(options.server_alive_interval, 1053262566Sdes options.server_alive_count_max); 1054262566Sdes 1055181111Sdes if (timeout_ms > 0) 1056181111Sdes debug3("timeout: %d ms remain after connect", timeout_ms); 1057181111Sdes 105857429Smarkm /* 105957429Smarkm * If we successfully made the connection, load the host private key 106057429Smarkm * in case we will need it later for combined rsa-rhosts 106157429Smarkm * authentication. This must be done before releasing extra 106257429Smarkm * privileges, because the file is only readable by root. 106398684Sdes * If we cannot access the private keys, load the public keys 106498684Sdes * instead and try to execute the ssh-keysign helper instead. 106557429Smarkm */ 106676262Sgreen sensitive_data.nkeys = 0; 106776262Sgreen sensitive_data.keys = NULL; 106898684Sdes sensitive_data.external_keysign = 0; 106998684Sdes if (options.rhosts_rsa_authentication || 107098684Sdes options.hostbased_authentication) { 1071262566Sdes sensitive_data.nkeys = 9; 1072162856Sdes sensitive_data.keys = xcalloc(sensitive_data.nkeys, 1073106130Sdes sizeof(Key)); 1074221420Sdes for (i = 0; i < sensitive_data.nkeys; i++) 1075221420Sdes sensitive_data.keys[i] = NULL; 107698684Sdes 107798684Sdes PRIV_START; 107876262Sgreen sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, 1079162856Sdes _PATH_HOST_KEY_FILE, "", NULL, NULL); 1080215116Sdes sensitive_data.keys[1] = key_load_private_cert(KEY_DSA, 1081215116Sdes _PATH_HOST_DSA_KEY_FILE, "", NULL); 1082221420Sdes#ifdef OPENSSL_HAS_ECC 1083221420Sdes sensitive_data.keys[2] = key_load_private_cert(KEY_ECDSA, 1084221420Sdes _PATH_HOST_ECDSA_KEY_FILE, "", NULL); 1085221420Sdes#endif 1086221420Sdes sensitive_data.keys[3] = key_load_private_cert(KEY_RSA, 1087215116Sdes _PATH_HOST_RSA_KEY_FILE, "", NULL); 1088262566Sdes sensitive_data.keys[4] = key_load_private_cert(KEY_ED25519, 1089262566Sdes _PATH_HOST_ED25519_KEY_FILE, "", NULL); 1090262566Sdes sensitive_data.keys[5] = key_load_private_type(KEY_DSA, 1091162856Sdes _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL); 1092221420Sdes#ifdef OPENSSL_HAS_ECC 1093262566Sdes sensitive_data.keys[6] = key_load_private_type(KEY_ECDSA, 1094221420Sdes _PATH_HOST_ECDSA_KEY_FILE, "", NULL, NULL); 1095221420Sdes#endif 1096262566Sdes sensitive_data.keys[7] = key_load_private_type(KEY_RSA, 1097162856Sdes _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL); 1098262566Sdes sensitive_data.keys[8] = key_load_private_type(KEY_ED25519, 1099262566Sdes _PATH_HOST_ED25519_KEY_FILE, "", NULL, NULL); 110098684Sdes PRIV_END; 110198684Sdes 1102106130Sdes if (options.hostbased_authentication == 1 && 1103106130Sdes sensitive_data.keys[0] == NULL && 1104221420Sdes sensitive_data.keys[5] == NULL && 1105262566Sdes sensitive_data.keys[6] == NULL && 1106262566Sdes sensitive_data.keys[7] == NULL && 1107262566Sdes sensitive_data.keys[8] == NULL) { 1108215116Sdes sensitive_data.keys[1] = key_load_cert( 1109215116Sdes _PATH_HOST_DSA_KEY_FILE); 1110221420Sdes#ifdef OPENSSL_HAS_ECC 1111215116Sdes sensitive_data.keys[2] = key_load_cert( 1112221420Sdes _PATH_HOST_ECDSA_KEY_FILE); 1113221420Sdes#endif 1114221420Sdes sensitive_data.keys[3] = key_load_cert( 1115215116Sdes _PATH_HOST_RSA_KEY_FILE); 1116262566Sdes sensitive_data.keys[4] = key_load_cert( 1117262566Sdes _PATH_HOST_ED25519_KEY_FILE); 1118262566Sdes sensitive_data.keys[5] = key_load_public( 111998684Sdes _PATH_HOST_DSA_KEY_FILE, NULL); 1120221420Sdes#ifdef OPENSSL_HAS_ECC 1121262566Sdes sensitive_data.keys[6] = key_load_public( 1122221420Sdes _PATH_HOST_ECDSA_KEY_FILE, NULL); 1123221420Sdes#endif 1124262566Sdes sensitive_data.keys[7] = key_load_public( 112598684Sdes _PATH_HOST_RSA_KEY_FILE, NULL); 1126262566Sdes sensitive_data.keys[8] = key_load_public( 1127262566Sdes _PATH_HOST_ED25519_KEY_FILE, NULL); 112898684Sdes sensitive_data.external_keysign = 1; 112998684Sdes } 113057429Smarkm } 113157429Smarkm /* 113257429Smarkm * Get rid of any extra privileges that we may have. We will no 113357429Smarkm * longer need them. Also, extra privileges could make it very hard 113457429Smarkm * to read identity files and other non-world-readable files from the 113557429Smarkm * user's home directory if it happens to be on a NFS volume where 113657429Smarkm * root is mapped to nobody. 113757429Smarkm */ 1138137019Sdes if (original_effective_uid == 0) { 1139137019Sdes PRIV_START; 1140137019Sdes permanently_set_uid(pw); 1141137019Sdes } 114257429Smarkm 114357429Smarkm /* 114457429Smarkm * Now that we are back to our own permissions, create ~/.ssh 1145157019Sdes * directory if it doesn't already exist. 114657429Smarkm */ 1147240075Sdes if (config == NULL) { 1148240075Sdes r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir, 1149240075Sdes strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); 1150240075Sdes if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) { 1151221420Sdes#ifdef WITH_SELINUX 1152240075Sdes ssh_selinux_setfscreatecon(buf); 1153221420Sdes#endif 1154240075Sdes if (mkdir(buf, 0700) < 0) 1155240075Sdes error("Could not create directory '%.200s'.", 1156240075Sdes buf); 1157221420Sdes#ifdef WITH_SELINUX 1158240075Sdes ssh_selinux_setfscreatecon(NULL); 1159221420Sdes#endif 1160240075Sdes } 1161221420Sdes } 116276262Sgreen /* load options.identity_files */ 116376262Sgreen load_public_identity_files(); 116476262Sgreen 116557429Smarkm /* Expand ~ in known host file names. */ 1166226046Sdes tilde_expand_paths(options.system_hostfiles, 1167226046Sdes options.num_system_hostfiles); 1168226046Sdes tilde_expand_paths(options.user_hostfiles, options.num_user_hostfiles); 116957429Smarkm 117092559Sdes signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ 1171221420Sdes signal(SIGCHLD, main_sigchld_handler); 117292559Sdes 1173181111Sdes /* Log into the remote system. Never returns if the login fails. */ 1174181111Sdes ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, 1175221420Sdes options.port, pw, timeout_ms); 117657429Smarkm 1177215116Sdes if (packet_connection_is_on_socket()) { 1178215116Sdes verbose("Authenticated to %s ([%s]:%d).", host, 1179215116Sdes get_remote_ipaddr(), get_remote_port()); 1180215116Sdes } else { 1181215116Sdes verbose("Authenticated to %s (via proxy).", host); 1182215116Sdes } 1183215116Sdes 118476262Sgreen /* We no longer need the private host keys. Clear them now. */ 118576262Sgreen if (sensitive_data.nkeys != 0) { 118676262Sgreen for (i = 0; i < sensitive_data.nkeys; i++) { 118776262Sgreen if (sensitive_data.keys[i] != NULL) { 118876262Sgreen /* Destroys contents safely */ 118976262Sgreen debug3("clear hostkey %d", i); 119076262Sgreen key_free(sensitive_data.keys[i]); 119176262Sgreen sensitive_data.keys[i] = NULL; 119276262Sgreen } 119376262Sgreen } 1194255767Sdes free(sensitive_data.keys); 119576262Sgreen } 119692559Sdes for (i = 0; i < options.num_identity_files; i++) { 1197255767Sdes free(options.identity_files[i]); 1198255767Sdes options.identity_files[i] = NULL; 119992559Sdes if (options.identity_keys[i]) { 120092559Sdes key_free(options.identity_keys[i]); 120192559Sdes options.identity_keys[i] = NULL; 120292559Sdes } 120392559Sdes } 120457429Smarkm 120560576Skris exit_status = compat20 ? ssh_session2() : ssh_session(); 120660576Skris packet_close(); 1207106130Sdes 1208181111Sdes if (options.control_path != NULL && muxserver_sock != -1) 1209137019Sdes unlink(options.control_path); 1210137019Sdes 1211221420Sdes /* Kill ProxyCommand if it is running. */ 1212221420Sdes ssh_kill_proxy_command(); 1213106130Sdes 121460576Skris return exit_status; 121560576Skris} 121660576Skris 1217215116Sdesstatic void 1218215116Sdescontrol_persist_detach(void) 1219215116Sdes{ 1220215116Sdes pid_t pid; 1221215116Sdes int devnull; 1222215116Sdes 1223215116Sdes debug("%s: backgrounding master process", __func__); 1224215116Sdes 1225215116Sdes /* 1226215116Sdes * master (current process) into the background, and make the 1227215116Sdes * foreground process a client of the backgrounded master. 1228215116Sdes */ 1229215116Sdes switch ((pid = fork())) { 1230215116Sdes case -1: 1231215116Sdes fatal("%s: fork: %s", __func__, strerror(errno)); 1232215116Sdes case 0: 1233215116Sdes /* Child: master process continues mainloop */ 1234215116Sdes break; 1235215116Sdes default: 1236215116Sdes /* Parent: set up mux slave to connect to backgrounded master */ 1237215116Sdes debug2("%s: background process is %ld", __func__, (long)pid); 1238215116Sdes stdin_null_flag = ostdin_null_flag; 1239226046Sdes options.request_tty = orequest_tty; 1240215116Sdes tty_flag = otty_flag; 1241215116Sdes close(muxserver_sock); 1242215116Sdes muxserver_sock = -1; 1243221420Sdes options.control_master = SSHCTL_MASTER_NO; 1244215116Sdes muxclient(options.control_path); 1245215116Sdes /* muxclient() doesn't return on success. */ 1246215116Sdes fatal("Failed to connect to new control master"); 1247215116Sdes } 1248215116Sdes if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { 1249215116Sdes error("%s: open(\"/dev/null\"): %s", __func__, 1250215116Sdes strerror(errno)); 1251215116Sdes } else { 1252215116Sdes if (dup2(devnull, STDIN_FILENO) == -1 || 1253215116Sdes dup2(devnull, STDOUT_FILENO) == -1) 1254215116Sdes error("%s: dup2: %s", __func__, strerror(errno)); 1255215116Sdes if (devnull > STDERR_FILENO) 1256215116Sdes close(devnull); 1257215116Sdes } 1258255767Sdes daemon(1, 1); 1259226046Sdes setproctitle("%s [mux]", options.control_path); 1260215116Sdes} 1261215116Sdes 1262215116Sdes/* Do fork() after authentication. Used by "ssh -f" */ 1263215116Sdesstatic void 1264215116Sdesfork_postauth(void) 1265215116Sdes{ 1266215116Sdes if (need_controlpersist_detach) 1267215116Sdes control_persist_detach(); 1268215116Sdes debug("forking to background"); 1269215116Sdes fork_after_authentication_flag = 0; 1270215116Sdes if (daemon(1, 1) < 0) 1271215116Sdes fatal("daemon() failed: %.200s", strerror(errno)); 1272215116Sdes} 1273215116Sdes 1274181111Sdes/* Callback for remote forward global requests */ 127592559Sdesstatic void 1276181111Sdesssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) 1277181111Sdes{ 1278181111Sdes Forward *rfwd = (Forward *)ctxt; 1279181111Sdes 1280192595Sdes /* XXX verbose() on failure? */ 1281181111Sdes debug("remote forward %s for: listen %d, connect %s:%d", 1282181111Sdes type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", 1283181111Sdes rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); 1284240075Sdes if (rfwd->listen_port == 0) { 1285240075Sdes if (type == SSH2_MSG_REQUEST_SUCCESS) { 1286240075Sdes rfwd->allocated_port = packet_get_int(); 1287240075Sdes logit("Allocated port %u for remote forward to %s:%d", 1288240075Sdes rfwd->allocated_port, 1289240075Sdes rfwd->connect_host, rfwd->connect_port); 1290240075Sdes channel_update_permitted_opens(rfwd->handle, 1291240075Sdes rfwd->allocated_port); 1292240075Sdes } else { 1293240075Sdes channel_update_permitted_opens(rfwd->handle, -1); 1294240075Sdes } 1295192595Sdes } 1296192595Sdes 1297181111Sdes if (type == SSH2_MSG_REQUEST_FAILURE) { 1298181111Sdes if (options.exit_on_forward_failure) 1299181111Sdes fatal("Error: remote port forwarding failed for " 1300181111Sdes "listen port %d", rfwd->listen_port); 1301181111Sdes else 1302181111Sdes logit("Warning: remote port forwarding failed for " 1303181111Sdes "listen port %d", rfwd->listen_port); 1304181111Sdes } 1305181111Sdes if (++remote_forward_confirms_received == options.num_remote_forwards) { 1306181111Sdes debug("All remote forwarding requests processed"); 1307215116Sdes if (fork_after_authentication_flag) 1308215116Sdes fork_postauth(); 1309181111Sdes } 1310181111Sdes} 1311181111Sdes 1312181111Sdesstatic void 1313204917Sdesclient_cleanup_stdio_fwd(int id, void *arg) 1314204917Sdes{ 1315204917Sdes debug("stdio forwarding: done"); 1316204917Sdes cleanup_exit(0); 1317204917Sdes} 1318204917Sdes 1319240075Sdesstatic void 1320240075Sdesssh_init_stdio_forwarding(void) 1321204917Sdes{ 1322204917Sdes Channel *c; 1323204917Sdes int in, out; 1324204917Sdes 1325240075Sdes if (stdio_forward_host == NULL) 1326240075Sdes return; 1327262566Sdes if (!compat20) 1328240075Sdes fatal("stdio forwarding require Protocol 2"); 1329204917Sdes 1330240075Sdes debug3("%s: %s:%d", __func__, stdio_forward_host, stdio_forward_port); 1331240075Sdes 1332240075Sdes if ((in = dup(STDIN_FILENO)) < 0 || 1333240075Sdes (out = dup(STDOUT_FILENO)) < 0) 1334204917Sdes fatal("channel_connect_stdio_fwd: dup() in/out failed"); 1335240075Sdes if ((c = channel_connect_stdio_fwd(stdio_forward_host, 1336240075Sdes stdio_forward_port, in, out)) == NULL) 1337240075Sdes fatal("%s: channel_connect_stdio_fwd failed", __func__); 1338204917Sdes channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0); 1339204917Sdes} 1340204917Sdes 1341204917Sdesstatic void 134276262Sgreenssh_init_forwarding(void) 134376262Sgreen{ 134476262Sgreen int success = 0; 134576262Sgreen int i; 134676262Sgreen 134776262Sgreen /* Initiate local TCP/IP port forwardings. */ 134876262Sgreen for (i = 0; i < options.num_local_forwards; i++) { 1349147005Sdes debug("Local connections to %.200s:%d forwarded to remote " 1350147005Sdes "address %.200s:%d", 1351147005Sdes (options.local_forwards[i].listen_host == NULL) ? 1352147005Sdes (options.gateway_ports ? "*" : "LOCALHOST") : 1353147005Sdes options.local_forwards[i].listen_host, 1354147005Sdes options.local_forwards[i].listen_port, 1355147005Sdes options.local_forwards[i].connect_host, 1356147005Sdes options.local_forwards[i].connect_port); 135792559Sdes success += channel_setup_local_fwd_listener( 1358147005Sdes options.local_forwards[i].listen_host, 1359147005Sdes options.local_forwards[i].listen_port, 1360147005Sdes options.local_forwards[i].connect_host, 1361147005Sdes options.local_forwards[i].connect_port, 136276262Sgreen options.gateway_ports); 136376262Sgreen } 1364162856Sdes if (i > 0 && success != i && options.exit_on_forward_failure) 1365162856Sdes fatal("Could not request local forwarding."); 136676262Sgreen if (i > 0 && success == 0) 136776262Sgreen error("Could not request local forwarding."); 136876262Sgreen 136976262Sgreen /* Initiate remote TCP/IP port forwardings. */ 137076262Sgreen for (i = 0; i < options.num_remote_forwards; i++) { 1371147005Sdes debug("Remote connections from %.200s:%d forwarded to " 1372147005Sdes "local address %.200s:%d", 1373149753Sdes (options.remote_forwards[i].listen_host == NULL) ? 1374157019Sdes "LOCALHOST" : options.remote_forwards[i].listen_host, 1375147005Sdes options.remote_forwards[i].listen_port, 1376147005Sdes options.remote_forwards[i].connect_host, 1377147005Sdes options.remote_forwards[i].connect_port); 1378240075Sdes options.remote_forwards[i].handle = 1379240075Sdes channel_request_remote_forwarding( 1380147005Sdes options.remote_forwards[i].listen_host, 1381147005Sdes options.remote_forwards[i].listen_port, 1382147005Sdes options.remote_forwards[i].connect_host, 1383240075Sdes options.remote_forwards[i].connect_port); 1384240075Sdes if (options.remote_forwards[i].handle < 0) { 1385162856Sdes if (options.exit_on_forward_failure) 1386162856Sdes fatal("Could not request remote forwarding."); 1387162856Sdes else 1388162856Sdes logit("Warning: Could not request remote " 1389162856Sdes "forwarding."); 1390240075Sdes } else { 1391240075Sdes client_register_global_confirm(ssh_confirm_remote_forward, 1392240075Sdes &options.remote_forwards[i]); 1393162856Sdes } 139476262Sgreen } 1395181111Sdes 1396181111Sdes /* Initiate tunnel forwarding. */ 1397181111Sdes if (options.tun_open != SSH_TUNMODE_NO) { 1398181111Sdes if (client_request_tun_fwd(options.tun_open, 1399181111Sdes options.tun_local, options.tun_remote) == -1) { 1400181111Sdes if (options.exit_on_forward_failure) 1401181111Sdes fatal("Could not request tunnel forwarding."); 1402181111Sdes else 1403181111Sdes error("Could not request tunnel forwarding."); 1404181111Sdes } 1405181111Sdes } 140676262Sgreen} 140776262Sgreen 140892559Sdesstatic void 140976262Sgreencheck_agent_present(void) 141076262Sgreen{ 141176262Sgreen if (options.forward_agent) { 1412157019Sdes /* Clear agent forwarding if we don't have an agent. */ 1413106130Sdes if (!ssh_agent_present()) 141476262Sgreen options.forward_agent = 0; 141576262Sgreen } 141676262Sgreen} 141776262Sgreen 141892559Sdesstatic int 141960576Skrisssh_session(void) 142060576Skris{ 142160576Skris int type; 142260576Skris int interactive = 0; 142360576Skris int have_tty = 0; 142460576Skris struct winsize ws; 142560576Skris char *cp; 1426149753Sdes const char *display; 142760576Skris 142857429Smarkm /* Enable compression if requested. */ 142957429Smarkm if (options.compression) { 1430181111Sdes debug("Requesting compression at level %d.", 1431181111Sdes options.compression_level); 143257429Smarkm 1433181111Sdes if (options.compression_level < 1 || 1434181111Sdes options.compression_level > 9) 1435181111Sdes fatal("Compression level must be from 1 (fast) to " 1436181111Sdes "9 (slow, best)."); 143757429Smarkm 143857429Smarkm /* Send the request. */ 143957429Smarkm packet_start(SSH_CMSG_REQUEST_COMPRESSION); 144057429Smarkm packet_put_int(options.compression_level); 144157429Smarkm packet_send(); 144257429Smarkm packet_write_wait(); 144392559Sdes type = packet_read(); 144457429Smarkm if (type == SSH_SMSG_SUCCESS) 144557429Smarkm packet_start_compression(options.compression_level); 144657429Smarkm else if (type == SSH_SMSG_FAILURE) 1447124211Sdes logit("Warning: Remote host refused compression."); 144857429Smarkm else 1449181111Sdes packet_disconnect("Protocol error waiting for " 1450181111Sdes "compression response."); 145157429Smarkm } 145257429Smarkm /* Allocate a pseudo tty if appropriate. */ 145357429Smarkm if (tty_flag) { 145457429Smarkm debug("Requesting pty."); 145557429Smarkm 145657429Smarkm /* Start the packet. */ 145757429Smarkm packet_start(SSH_CMSG_REQUEST_PTY); 145857429Smarkm 145957429Smarkm /* Store TERM in the packet. There is no limit on the 146057429Smarkm length of the string. */ 146157429Smarkm cp = getenv("TERM"); 146257429Smarkm if (!cp) 146357429Smarkm cp = ""; 146492559Sdes packet_put_cstring(cp); 146557429Smarkm 146657429Smarkm /* Store window size in the packet. */ 146757429Smarkm if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) 146857429Smarkm memset(&ws, 0, sizeof(ws)); 1469162856Sdes packet_put_int((u_int)ws.ws_row); 1470162856Sdes packet_put_int((u_int)ws.ws_col); 1471162856Sdes packet_put_int((u_int)ws.ws_xpixel); 1472162856Sdes packet_put_int((u_int)ws.ws_ypixel); 147357429Smarkm 147457429Smarkm /* Store tty modes in the packet. */ 147576262Sgreen tty_make_modes(fileno(stdin), NULL); 147657429Smarkm 147757429Smarkm /* Send the packet, and wait for it to leave. */ 147857429Smarkm packet_send(); 147957429Smarkm packet_write_wait(); 148057429Smarkm 148157429Smarkm /* Read response from the server. */ 148292559Sdes type = packet_read(); 148358585Skris if (type == SSH_SMSG_SUCCESS) { 148457429Smarkm interactive = 1; 148560576Skris have_tty = 1; 148658585Skris } else if (type == SSH_SMSG_FAILURE) 1487181111Sdes logit("Warning: Remote host failed or refused to " 1488181111Sdes "allocate a pseudo tty."); 148957429Smarkm else 1490181111Sdes packet_disconnect("Protocol error waiting for pty " 1491181111Sdes "request response."); 149257429Smarkm } 149357429Smarkm /* Request X11 forwarding if enabled and DISPLAY is set. */ 1494149753Sdes display = getenv("DISPLAY"); 1495149753Sdes if (options.forward_x11 && display != NULL) { 149692559Sdes char *proto, *data; 149760576Skris /* Get reasonable local authentication information. */ 1498149753Sdes client_x11_get_proto(display, options.xauth_location, 1499262566Sdes options.forward_x11_trusted, 1500215116Sdes options.forward_x11_timeout, 1501215116Sdes &proto, &data); 150260576Skris /* Request forwarding with authentication spoofing. */ 1503181111Sdes debug("Requesting X11 forwarding with authentication " 1504181111Sdes "spoofing."); 1505226046Sdes x11_request_forwarding_with_spoofing(0, display, proto, 1506226046Sdes data, 0); 150757429Smarkm /* Read response from the server. */ 150892559Sdes type = packet_read(); 150957429Smarkm if (type == SSH_SMSG_SUCCESS) { 151057429Smarkm interactive = 1; 151160576Skris } else if (type == SSH_SMSG_FAILURE) { 1512124211Sdes logit("Warning: Remote host denied X11 forwarding."); 151360576Skris } else { 1514181111Sdes packet_disconnect("Protocol error waiting for X11 " 1515181111Sdes "forwarding"); 151660576Skris } 151757429Smarkm } 151857429Smarkm /* Tell the packet module whether this is an interactive session. */ 1519221420Sdes packet_set_interactive(interactive, 1520221420Sdes options.ip_qos_interactive, options.ip_qos_bulk); 152157429Smarkm 152276262Sgreen /* Request authentication agent forwarding if appropriate. */ 152376262Sgreen check_agent_present(); 152457429Smarkm 152557429Smarkm if (options.forward_agent) { 152657429Smarkm debug("Requesting authentication agent forwarding."); 152757429Smarkm auth_request_forwarding(); 152857429Smarkm 152957429Smarkm /* Read response from the server. */ 153092559Sdes type = packet_read(); 153192559Sdes packet_check_eom(); 153257429Smarkm if (type != SSH_SMSG_SUCCESS) 1533124211Sdes logit("Warning: Remote host denied authentication agent forwarding."); 153457429Smarkm } 153557429Smarkm 153676262Sgreen /* Initiate port forwardings. */ 1537240075Sdes ssh_init_stdio_forwarding(); 153876262Sgreen ssh_init_forwarding(); 153957429Smarkm 1540181111Sdes /* Execute a local command */ 1541181111Sdes if (options.local_command != NULL && 1542181111Sdes options.permit_local_command) 1543181111Sdes ssh_local_cmd(options.local_command); 1544181111Sdes 1545181111Sdes /* 1546181111Sdes * If requested and we are not interested in replies to remote 1547181111Sdes * forwarding requests, then let ssh continue in the background. 1548181111Sdes */ 1549215116Sdes if (fork_after_authentication_flag) { 1550215116Sdes if (options.exit_on_forward_failure && 1551215116Sdes options.num_remote_forwards > 0) { 1552215116Sdes debug("deferring postauth fork until remote forward " 1553215116Sdes "confirmation received"); 1554215116Sdes } else 1555215116Sdes fork_postauth(); 1556181111Sdes } 155757429Smarkm 155857429Smarkm /* 155957429Smarkm * If a command was specified on the command line, execute the 156057429Smarkm * command now. Otherwise request the server to start a shell. 156157429Smarkm */ 156257429Smarkm if (buffer_len(&command) > 0) { 156357429Smarkm int len = buffer_len(&command); 156457429Smarkm if (len > 900) 156557429Smarkm len = 900; 1566181111Sdes debug("Sending command: %.*s", len, 1567181111Sdes (u_char *)buffer_ptr(&command)); 156857429Smarkm packet_start(SSH_CMSG_EXEC_CMD); 156957429Smarkm packet_put_string(buffer_ptr(&command), buffer_len(&command)); 157057429Smarkm packet_send(); 157157429Smarkm packet_write_wait(); 157257429Smarkm } else { 157357429Smarkm debug("Requesting shell."); 157457429Smarkm packet_start(SSH_CMSG_EXEC_SHELL); 157557429Smarkm packet_send(); 157657429Smarkm packet_write_wait(); 157757429Smarkm } 157857429Smarkm 157957429Smarkm /* Enter the interactive session. */ 158092559Sdes return client_loop(have_tty, tty_flag ? 158192559Sdes options.escape_char : SSH_ESCAPECHAR_NONE, 0); 158260576Skris} 158357429Smarkm 1584137019Sdes/* request pty/x11/agent/tcpfwd/shell for channel */ 1585137019Sdesstatic void 1586215116Sdesssh_session2_setup(int id, int success, void *arg) 1587137019Sdes{ 1588137019Sdes extern char **environ; 1589149753Sdes const char *display; 1590149753Sdes int interactive = tty_flag; 1591137019Sdes 1592215116Sdes if (!success) 1593215116Sdes return; /* No need for error message, channels code sens one */ 1594215116Sdes 1595149753Sdes display = getenv("DISPLAY"); 1596149753Sdes if (options.forward_x11 && display != NULL) { 159792559Sdes char *proto, *data; 159860576Skris /* Get reasonable local authentication information. */ 1599149753Sdes client_x11_get_proto(display, options.xauth_location, 1600215116Sdes options.forward_x11_trusted, 1601215116Sdes options.forward_x11_timeout, &proto, &data); 160260576Skris /* Request forwarding with authentication spoofing. */ 1603181111Sdes debug("Requesting X11 forwarding with authentication " 1604181111Sdes "spoofing."); 1605226046Sdes x11_request_forwarding_with_spoofing(id, display, proto, 1606226046Sdes data, 1); 1607226046Sdes client_expect_confirm(id, "X11 forwarding", CONFIRM_WARN); 1608226046Sdes /* XXX exit_on_forward_failure */ 160976262Sgreen interactive = 1; 161060576Skris } 161160576Skris 161276262Sgreen check_agent_present(); 161376262Sgreen if (options.forward_agent) { 161476262Sgreen debug("Requesting authentication agent forwarding."); 161576262Sgreen channel_request_start(id, "auth-agent-req@openssh.com", 0); 161676262Sgreen packet_send(); 161776262Sgreen } 161876262Sgreen 1619240075Sdes /* Tell the packet module whether this is an interactive session. */ 1620240075Sdes packet_set_interactive(interactive, 1621240075Sdes options.ip_qos_interactive, options.ip_qos_bulk); 1622240075Sdes 1623137019Sdes client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"), 1624181111Sdes NULL, fileno(stdin), &command, environ); 162557429Smarkm} 162660576Skris 162792559Sdes/* open new channel for a session */ 162892559Sdesstatic int 162992559Sdesssh_session2_open(void) 163060576Skris{ 163192559Sdes Channel *c; 163292559Sdes int window, packetmax, in, out, err; 163360576Skris 163465674Skris if (stdin_null_flag) { 163576262Sgreen in = open(_PATH_DEVNULL, O_RDONLY); 163665674Skris } else { 163765674Skris in = dup(STDIN_FILENO); 163865674Skris } 163965674Skris out = dup(STDOUT_FILENO); 164065674Skris err = dup(STDERR_FILENO); 164165674Skris 164260576Skris if (in < 0 || out < 0 || err < 0) 164365674Skris fatal("dup() in/out/err failed"); 164460576Skris 164569591Sgreen /* enable nonblocking unless tty */ 164669591Sgreen if (!isatty(in)) 164769591Sgreen set_nonblock(in); 164869591Sgreen if (!isatty(out)) 164969591Sgreen set_nonblock(out); 165069591Sgreen if (!isatty(err)) 165169591Sgreen set_nonblock(err); 165269591Sgreen 1653224638Sbrooks /* 1654224638Sbrooks * We need to check to see what to do about buffer sizes here. 1655224638Sbrooks * - In an HPN to non-HPN connection we want to limit the window size to 1656224638Sbrooks * something reasonable in case the far side has the large window bug. 1657224638Sbrooks * - In an HPN to HPN connection we want to use the max window size but 1658224638Sbrooks * allow the user to override it. 1659224638Sbrooks * - Lastly if HPN is disabled then use the ssh standard window size. 1660224638Sbrooks * 1661224638Sbrooks * We cannot just do a getsockopt() here and set the ssh window to that 1662224638Sbrooks * as in case of autotuning of socket buffers the window would get stuck 1663224638Sbrooks * at the initial buffer size, generally less than 96k. Therefore we 1664224638Sbrooks * need to set the maximum ssh window size to the maximum HPN buffer 1665224638Sbrooks * size unless the user has set TcpRcvBufPoll to no. In that case we 1666224638Sbrooks * can just set the window to the minimum of HPN buffer size and TCP 1667224638Sbrooks * receive buffer size. 1668224638Sbrooks */ 1669224638Sbrooks if (tty_flag) 1670224638Sbrooks options.hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT; 1671224638Sbrooks else 1672224638Sbrooks options.hpn_buffer_size = CHAN_HPN_MIN_WINDOW_DEFAULT; 1673224638Sbrooks 1674224638Sbrooks if (datafellows & SSH_BUG_LARGEWINDOW) { 1675224638Sbrooks debug("HPN to Non-HPN Connection"); 1676224638Sbrooks } else if (options.tcp_rcv_buf_poll <= 0) { 1677224638Sbrooks sock_get_rcvbuf(&options.hpn_buffer_size, 0); 1678224638Sbrooks debug("HPNBufferSize set to TCP RWIN: %d", 1679224638Sbrooks options.hpn_buffer_size); 1680224638Sbrooks } else if (options.tcp_rcv_buf > 0) { 1681224638Sbrooks sock_get_rcvbuf(&options.hpn_buffer_size, 1682224638Sbrooks options.tcp_rcv_buf); 1683224638Sbrooks debug("HPNBufferSize set to user TCPRcvBuf: %d", 1684224638Sbrooks options.hpn_buffer_size); 1685224638Sbrooks } 1686224638Sbrooks debug("Final hpn_buffer_size = %d", options.hpn_buffer_size); 1687224638Sbrooks channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size); 1688224638Sbrooks window = options.hpn_buffer_size; 1689224638Sbrooks 169065674Skris packetmax = CHAN_SES_PACKET_DEFAULT; 169192559Sdes if (tty_flag) { 1692224638Sbrooks window = CHAN_SES_WINDOW_DEFAULT; 169392559Sdes window >>= 1; 169492559Sdes packetmax >>= 1; 169560576Skris } 169692559Sdes c = channel_new( 169760576Skris "session", SSH_CHANNEL_OPENING, in, out, err, 169865674Skris window, packetmax, CHAN_EXTENDED_WRITE, 1699124211Sdes "client-session", /*nonblock*/0); 1700224638Sbrooks if (!options.hpn_disabled && options.tcp_rcv_buf_poll > 0) { 1701224638Sbrooks c->dynamic_window = 1; 1702224638Sbrooks debug("Enabled Dynamic Window Scaling\n"); 1703224638Sbrooks } 1704231584Sed 170592559Sdes debug3("ssh_session2_open: channel_new: %d", c->self); 170676262Sgreen 170792559Sdes channel_send_open(c->self); 170892559Sdes if (!no_shell_flag) 1709181111Sdes channel_register_open_confirm(c->self, 1710181111Sdes ssh_session2_setup, NULL); 171160576Skris 171292559Sdes return c->self; 171376262Sgreen} 171476262Sgreen 171592559Sdesstatic int 171676262Sgreenssh_session2(void) 171776262Sgreen{ 171892559Sdes int id = -1; 171976262Sgreen 172076262Sgreen /* XXX should be pre-session */ 1721240075Sdes if (!options.control_persist) 1722240075Sdes ssh_init_stdio_forwarding(); 172376262Sgreen ssh_init_forwarding(); 172476262Sgreen 1725215116Sdes /* Start listening for multiplex clients */ 1726215116Sdes muxserver_listen(); 1727215116Sdes 1728215116Sdes /* 1729240075Sdes * If we are in control persist mode and have a working mux listen 1730240075Sdes * socket, then prepare to background ourselves and have a foreground 1731240075Sdes * client attach as a control slave. 1732240075Sdes * NB. we must save copies of the flags that we override for 1733215116Sdes * the backgrounding, since we defer attachment of the slave until 1734215116Sdes * after the connection is fully established (in particular, 1735215116Sdes * async rfwd replies have been received for ExitOnForwardFailure). 1736215116Sdes */ 1737215116Sdes if (options.control_persist && muxserver_sock != -1) { 1738215116Sdes ostdin_null_flag = stdin_null_flag; 1739215116Sdes ono_shell_flag = no_shell_flag; 1740226046Sdes orequest_tty = options.request_tty; 1741215116Sdes otty_flag = tty_flag; 1742215116Sdes stdin_null_flag = 1; 1743215116Sdes no_shell_flag = 1; 1744215116Sdes tty_flag = 0; 1745215116Sdes if (!fork_after_authentication_flag) 1746215116Sdes need_controlpersist_detach = 1; 1747215116Sdes fork_after_authentication_flag = 1; 1748215116Sdes } 1749240075Sdes /* 1750240075Sdes * ControlPersist mux listen socket setup failed, attempt the 1751240075Sdes * stdio forward setup that we skipped earlier. 1752240075Sdes */ 1753240075Sdes if (options.control_persist && muxserver_sock == -1) 1754240075Sdes ssh_init_stdio_forwarding(); 1755215116Sdes 175692559Sdes if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) 175792559Sdes id = ssh_session2_open(); 1758255767Sdes else { 1759255767Sdes packet_set_interactive( 1760255767Sdes options.control_master == SSHCTL_MASTER_NO, 1761255767Sdes options.ip_qos_interactive, options.ip_qos_bulk); 1762255767Sdes } 176376262Sgreen 1764181111Sdes /* If we don't expect to open a new session, then disallow it */ 1765192595Sdes if (options.control_master == SSHCTL_MASTER_NO && 1766192595Sdes (datafellows & SSH_NEW_OPENSSH)) { 1767181111Sdes debug("Requesting no-more-sessions@openssh.com"); 1768181111Sdes packet_start(SSH2_MSG_GLOBAL_REQUEST); 1769181111Sdes packet_put_cstring("no-more-sessions@openssh.com"); 1770181111Sdes packet_put_char(0); 1771181111Sdes packet_send(); 1772181111Sdes } 1773181111Sdes 1774157019Sdes /* Execute a local command */ 1775157019Sdes if (options.local_command != NULL && 1776157019Sdes options.permit_local_command) 1777157019Sdes ssh_local_cmd(options.local_command); 1778157019Sdes 1779215116Sdes /* 1780215116Sdes * If requested and we are not interested in replies to remote 1781215116Sdes * forwarding requests, then let ssh continue in the background. 1782215116Sdes */ 1783181111Sdes if (fork_after_authentication_flag) { 1784215116Sdes if (options.exit_on_forward_failure && 1785215116Sdes options.num_remote_forwards > 0) { 1786215116Sdes debug("deferring postauth fork until remote forward " 1787215116Sdes "confirmation received"); 1788215116Sdes } else 1789215116Sdes fork_postauth(); 1790181111Sdes } 179176262Sgreen 1792204917Sdes if (options.use_roaming) 1793204917Sdes request_roaming(); 1794204917Sdes 179592559Sdes return client_loop(tty_flag, tty_flag ? 179692559Sdes options.escape_char : SSH_ESCAPECHAR_NONE, id); 179760576Skris} 179876262Sgreen 179992559Sdesstatic void 180076262Sgreenload_public_identity_files(void) 180176262Sgreen{ 1802162856Sdes char *filename, *cp, thishost[NI_MAXHOST]; 1803181111Sdes char *pwdir = NULL, *pwname = NULL; 180498684Sdes int i = 0; 180576262Sgreen Key *public; 1806162856Sdes struct passwd *pw; 1807204917Sdes u_int n_ids; 1808204917Sdes char *identity_files[SSH_MAX_IDENTITY_FILES]; 1809204917Sdes Key *identity_keys[SSH_MAX_IDENTITY_FILES]; 1810204917Sdes#ifdef ENABLE_PKCS11 181198684Sdes Key **keys; 1812204917Sdes int nkeys; 1813204917Sdes#endif /* PKCS11 */ 181476262Sgreen 1815204917Sdes n_ids = 0; 1816264377Sdes memset(identity_files, 0, sizeof(identity_files)); 1817264377Sdes memset(identity_keys, 0, sizeof(identity_keys)); 1818204917Sdes 1819204917Sdes#ifdef ENABLE_PKCS11 1820204917Sdes if (options.pkcs11_provider != NULL && 182198684Sdes options.num_identity_files < SSH_MAX_IDENTITY_FILES && 1822204917Sdes (pkcs11_init(!options.batch_mode) == 0) && 1823204917Sdes (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL, 1824204917Sdes &keys)) > 0) { 1825204917Sdes for (i = 0; i < nkeys; i++) { 1826204917Sdes if (n_ids >= SSH_MAX_IDENTITY_FILES) { 1827204917Sdes key_free(keys[i]); 1828204917Sdes continue; 1829204917Sdes } 1830204917Sdes identity_keys[n_ids] = keys[i]; 1831204917Sdes identity_files[n_ids] = 1832204917Sdes xstrdup(options.pkcs11_provider); /* XXX */ 1833204917Sdes n_ids++; 183498684Sdes } 1835255767Sdes free(keys); 183692559Sdes } 1837204917Sdes#endif /* ENABLE_PKCS11 */ 1838162856Sdes if ((pw = getpwuid(original_real_uid)) == NULL) 1839162856Sdes fatal("load_public_identity_files: getpwuid failed"); 1840181111Sdes pwname = xstrdup(pw->pw_name); 1841181111Sdes pwdir = xstrdup(pw->pw_dir); 1842162856Sdes if (gethostname(thishost, sizeof(thishost)) == -1) 1843162856Sdes fatal("load_public_identity_files: gethostname: %s", 1844162856Sdes strerror(errno)); 1845204917Sdes for (i = 0; i < options.num_identity_files; i++) { 1846249839Sdes if (n_ids >= SSH_MAX_IDENTITY_FILES || 1847249839Sdes strcasecmp(options.identity_files[i], "none") == 0) { 1848255767Sdes free(options.identity_files[i]); 1849204917Sdes continue; 1850204917Sdes } 1851162856Sdes cp = tilde_expand_filename(options.identity_files[i], 185276262Sgreen original_real_uid); 1853181111Sdes filename = percent_expand(cp, "d", pwdir, 1854181111Sdes "u", pwname, "l", thishost, "h", host, 1855162856Sdes "r", options.user, (char *)NULL); 1856255767Sdes free(cp); 185776262Sgreen public = key_load_public(filename, NULL); 185876262Sgreen debug("identity file %s type %d", filename, 185976262Sgreen public ? public->type : -1); 1860255767Sdes free(options.identity_files[i]); 1861204917Sdes identity_files[n_ids] = filename; 1862204917Sdes identity_keys[n_ids] = public; 1863204917Sdes 1864204917Sdes if (++n_ids >= SSH_MAX_IDENTITY_FILES) 1865204917Sdes continue; 1866204917Sdes 1867204917Sdes /* Try to add the certificate variant too */ 1868204917Sdes xasprintf(&cp, "%s-cert", filename); 1869204917Sdes public = key_load_public(cp, NULL); 1870204917Sdes debug("identity file %s type %d", cp, 1871204917Sdes public ? public->type : -1); 1872204917Sdes if (public == NULL) { 1873255767Sdes free(cp); 1874204917Sdes continue; 1875204917Sdes } 1876204917Sdes if (!key_is_cert(public)) { 1877204917Sdes debug("%s: key %s type %s is not a certificate", 1878204917Sdes __func__, cp, key_type(public)); 1879204917Sdes key_free(public); 1880255767Sdes free(cp); 1881204917Sdes continue; 1882204917Sdes } 1883204917Sdes identity_keys[n_ids] = public; 1884204917Sdes /* point to the original path, most likely the private key */ 1885204917Sdes identity_files[n_ids] = xstrdup(filename); 1886204917Sdes n_ids++; 188776262Sgreen } 1888204917Sdes options.num_identity_files = n_ids; 1889204917Sdes memcpy(options.identity_files, identity_files, sizeof(identity_files)); 1890204917Sdes memcpy(options.identity_keys, identity_keys, sizeof(identity_keys)); 1891204917Sdes 1892264377Sdes explicit_bzero(pwname, strlen(pwname)); 1893255767Sdes free(pwname); 1894264377Sdes explicit_bzero(pwdir, strlen(pwdir)); 1895255767Sdes free(pwdir); 189676262Sgreen} 1897221420Sdes 1898221420Sdesstatic void 1899221420Sdesmain_sigchld_handler(int sig) 1900221420Sdes{ 1901221420Sdes int save_errno = errno; 1902221420Sdes pid_t pid; 1903221420Sdes int status; 1904221420Sdes 1905221420Sdes while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || 1906221420Sdes (pid < 0 && errno == EINTR)) 1907221420Sdes ; 1908221420Sdes 1909221420Sdes signal(sig, main_sigchld_handler); 1910221420Sdes errno = save_errno; 1911221420Sdes} 1912