ssh.c 45.8 KB
Newer Older
1
/* $OpenBSD: ssh.c,v 1.381 2013/07/25 00:29:10 djm Exp $ */
Damien Miller's avatar
Damien Miller committed
2
/*
3 4 5 6 7 8 9
 * Author: Tatu Ylonen <ylo@cs.hut.fi>
 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
 *                    All rights reserved
 * Ssh client program.  This program can be used to log into a remote machine.
 * The software supports strong authentication, encryption, and forwarding
 * of X11, TCP/IP, and authentication connections.
 *
10 11 12 13 14 15 16
 * As far as I am concerned, the code I have written for this software
 * can be used freely for any purpose.  Any derived versions of this
 * software must be clearly marked as such, and if the derived work is
 * incompatible with the protocol description in the RFC file, it must be
 * called by a name other than "ssh" or "Secure Shell".
 *
 * Copyright (c) 1999 Niels Provos.  All rights reserved.
17
 * Copyright (c) 2000, 2001, 2002, 2003 Markus Friedl.  All rights reserved.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
 *
 * Modified to work with SSL by Niels Provos <provos@citi.umich.edu>
 * in Canada (German citizen).
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41
 */
Damien Miller's avatar
Damien Miller committed
42 43

#include "includes.h"
44

45 46 47 48
#include <sys/types.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
49
#include <sys/resource.h>
50
#include <sys/ioctl.h>
51
#include <sys/param.h>
52
#include <sys/socket.h>
53
#include <sys/wait.h>
54

55
#include <ctype.h>
56
#include <errno.h>
57
#include <fcntl.h>
58
#include <netdb.h>
59
#ifdef HAVE_PATHS_H
60
#include <paths.h>
61
#endif
62
#include <pwd.h>
63
#include <signal.h>
64
#include <stdarg.h>
65
#include <stddef.h>
66
#include <stdio.h>
67
#include <stdlib.h>
68
#include <string.h>
69
#include <unistd.h>
70

71 72 73
#include <netinet/in.h>
#include <arpa/inet.h>

74
#include <openssl/evp.h>
75
#include <openssl/err.h>
76
#include "openbsd-compat/openssl-compat.h"
77
#include "openbsd-compat/sys-queue.h"
Damien Miller's avatar
Damien Miller committed
78

79
#include "xmalloc.h"
Damien Miller's avatar
Damien Miller committed
80
#include "ssh.h"
81 82
#include "ssh1.h"
#include "ssh2.h"
83
#include "canohost.h"
84 85
#include "compat.h"
#include "cipher.h"
Damien Miller's avatar
Damien Miller committed
86 87
#include "packet.h"
#include "buffer.h"
88
#include "channels.h"
89
#include "key.h"
90
#include "authfd.h"
91
#include "authfile.h"
92
#include "pathnames.h"
93
#include "dispatch.h"
94
#include "clientloop.h"
95 96 97 98
#include "log.h"
#include "readconf.h"
#include "sshconnect.h"
#include "misc.h"
99 100
#include "kex.h"
#include "mac.h"
101
#include "sshpty.h"
102
#include "match.h"
103
#include "msg.h"
104
#include "uidswap.h"
105
#include "roaming.h"
106
#include "version.h"
Damien Miller's avatar
Damien Miller committed
107

108 109
#ifdef ENABLE_PKCS11
#include "ssh-pkcs11.h"
110
#endif
111

112 113
extern char *__progname;

114 115 116 117 118
/* Saves a copy of argv for setproctitle emulation */
#ifndef HAVE_SETPROCTITLE
static char **saved_av;
#endif

119
/* Flag indicating whether debug mode is on.  May be set on the command line. */
Damien Miller's avatar
Damien Miller committed
120 121
int debug_flag = 0;

122
/* Flag indicating whether a tty should be requested */
Damien Miller's avatar
Damien Miller committed
123 124
int tty_flag = 0;

Damien Miller's avatar
Damien Miller committed
125 126 127
/* don't exec a shell */
int no_shell_flag = 0;

128 129 130 131
/*
 * Flag indicating that nothing should be read from stdin.  This can be set
 * on the command line.
 */
Damien Miller's avatar
Damien Miller committed
132 133
int stdin_null_flag = 0;

134 135 136 137 138 139 140
/*
 * Flag indicating that the current process should be backgrounded and
 * a new slave launched in the foreground for ControlPersist.
 */
int need_controlpersist_detach = 0;

/* Copies of flags for ControlPersist foreground slave */
141
int ostdin_null_flag, ono_shell_flag, otty_flag, orequest_tty;
142

143 144
/*
 * Flag indicating that ssh should fork after authentication.  This is useful
145
 * so that the passphrase can be entered manually, and then ssh goes to the
146 147
 * background.
 */
Damien Miller's avatar
Damien Miller committed
148 149
int fork_after_authentication_flag = 0;

150 151 152 153
/* forward stdio to remote host and port */
char *stdio_forward_host = NULL;
int stdio_forward_port = 0;

154 155 156 157
/*
 * General data structure for command line options and options configurable
 * in configuration files.  See readconf.h.
 */
Damien Miller's avatar
Damien Miller committed
158 159
Options options;

160 161 162
/* optional user configfile */
char *config = NULL;

163 164 165 166 167
/*
 * Name of the host we are connecting to.  This is the name given on the
 * command line, or the HostName specified for the user-supplied name in a
 * configuration file.
 */
Damien Miller's avatar
Damien Miller committed
168 169 170
char *host;

/* socket address the host resolves to */
171
struct sockaddr_storage hostaddr;
Damien Miller's avatar
Damien Miller committed
172

173
/* Private host keys. */
174
Sensitive sensitive_data;
Damien Miller's avatar
Damien Miller committed
175 176 177

/* Original real UID. */
uid_t original_real_uid;
178
uid_t original_effective_uid;
Damien Miller's avatar
Damien Miller committed
179

Damien Miller's avatar
Damien Miller committed
180 181 182
/* command to be executed */
Buffer command;

183 184 185
/* Should we execute a command or invoke a subsystem? */
int subsystem_flag = 0;

186
/* # of replies received for global requests */
187
static int remote_forward_confirms_received = 0;
188

189 190 191
/* mux.c */
extern int muxserver_sock;
extern u_int muxclient_command;
192

Damien Miller's avatar
Damien Miller committed
193 194
/* Prints a help message to the user.  This function never returns. */

195
static void
196
usage(void)
Damien Miller's avatar
Damien Miller committed
197
{
198
	fprintf(stderr,
199
"usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n"
200 201
"           [-D [bind_address:]port] [-E log_file] [-e escape_char]\n"
"           [-F configfile] [-I pkcs11] [-i identity_file]\n"
202
"           [-L [bind_address:]port:host:hostport] [-Q protocol_feature]\n"
203
"           [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n"
204
"           [-R [bind_address:]port:host:hostport] [-S ctl_path]\n"
205 206
"           [-W host:port] [-w local_tun[:remote_tun]]\n"
"           [user@]hostname [command]\n"
207
	);
208
	exit(255);
Damien Miller's avatar
Damien Miller committed
209 210
}

211 212 213
static int ssh_session(void);
static int ssh_session2(void);
static void load_public_identity_files(void);
214
static void main_sigchld_handler(int);
215 216 217 218

/* from muxclient.c */
void muxclient(const char *);
void muxserver_listen(void);
Damien Miller's avatar
Damien Miller committed
219

220 221 222 223 224 225 226 227 228
/* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */
static void
tilde_expand_paths(char **paths, u_int num_paths)
{
	u_int i;
	char *cp;

	for (i = 0; i < num_paths; i++) {
		cp = tilde_expand_filename(paths[i], original_real_uid);
229
		free(paths[i]);
230 231 232 233
		paths[i] = cp;
	}
}

234 235 236
/*
 * Main program for the ssh client.
 */
Damien Miller's avatar
Damien Miller committed
237 238 239
int
main(int ac, char **av)
{
240
	int i, r, opt, exit_status, use_syslog;
241
	char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg, *logfile;
242
	char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
243
	struct stat st;
244
	struct passwd *pw;
245
	int dummy, timeout_ms;
246
	extern int optind, optreset;
247
	extern char *optarg;
248

249
	struct servent *sp;
250
	Forward fwd;
251

252 253 254
	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
	sanitise_stdfd();

255
	__progname = ssh_get_progname(av[0]);
256

257 258 259 260 261 262 263 264 265 266 267
#ifndef HAVE_SETPROCTITLE
	/* Prepare for later setproctitle emulation */
	/* Save argv so it isn't clobbered by setproctitle() emulation */
	saved_av = xcalloc(ac + 1, sizeof(*saved_av));
	for (i = 0; i < ac; i++)
		saved_av[i] = xstrdup(av[i]);
	saved_av[i] = NULL;
	compat_init_setproctitle(ac, av);
	av = saved_av;
#endif

268 269 270 271 272 273
	/*
	 * Discard other fds that are hanging around. These can cause problem
	 * with backgrounded ssh processes started by ControlPersist.
	 */
	closefrom(STDERR_FILENO + 1);

274 275 276 277
	/*
	 * Save the original real uid.  It will be needed later (uid-swapping
	 * may clobber the real uid).
	 */
278 279
	original_real_uid = getuid();
	original_effective_uid = geteuid();
280

281 282 283 284 285 286 287 288
	/*
	 * Use uid-swapping to give up root privileges for the duration of
	 * option processing.  We will re-instantiate the rights when we are
	 * ready to create the privileged port, and will permanently drop
	 * them when the port has been created (actually, when the connection
	 * has been made, as we may need to create the port several times).
	 */
	PRIV_END;
289

290
#ifdef HAVE_SETRLIMIT
291 292 293 294 295 296
	/* If we are installed setuid root be careful to not drop core. */
	if (original_real_uid != original_effective_uid) {
		struct rlimit rlim;
		rlim.rlim_cur = rlim.rlim_max = 0;
		if (setrlimit(RLIMIT_CORE, &rlim) < 0)
			fatal("setrlimit failed: %.100s", strerror(errno));
Damien Miller's avatar
Damien Miller committed
297
	}
298
#endif
299 300 301
	/* Get user data. */
	pw = getpwuid(original_real_uid);
	if (!pw) {
302
		logit("No user exists for uid %lu", (u_long)original_real_uid);
303
		exit(255);
304 305 306 307
	}
	/* Take a copy of the returned structure. */
	pw = pwcopy(pw);

308 309 310 311 312 313
	/*
	 * Set our umask to something reasonable, as some files are created
	 * with the default umask.  This will make them world-readable but
	 * writable only by the owner, which is ok for all files for which we
	 * don't set the modes explicitly.
	 */
314 315
	umask(022);

316 317 318 319
	/*
	 * Initialize option structure to indicate that no values have been
	 * set.
	 */
320 321 322 323
	initialize_options(&options);

	/* Parse command-line arguments. */
	host = NULL;
324
	use_syslog = 0;
325
	logfile = NULL;
326
	argv0 = av[0];
327

328
 again:
329
	while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
330
	    "ACD:E:F:I:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
331
		switch (opt) {
332 333 334
		case '1':
			options.protocol = SSH_PROTO_1;
			break;
335 336 337
		case '2':
			options.protocol = SSH_PROTO_2;
			break;
338
		case '4':
339
			options.address_family = AF_INET;
340 341
			break;
		case '6':
342
			options.address_family = AF_INET6;
343
			break;
344 345 346 347 348 349 350 351 352 353 354 355 356
		case 'n':
			stdin_null_flag = 1;
			break;
		case 'f':
			fork_after_authentication_flag = 1;
			stdin_null_flag = 1;
			break;
		case 'x':
			options.forward_x11 = 0;
			break;
		case 'X':
			options.forward_x11 = 1;
			break;
357 358 359
		case 'y':
			use_syslog = 1;
			break;
360 361 362
		case 'E':
			logfile = xstrdup(optarg);
			break;
363 364 365 366
		case 'Y':
			options.forward_x11 = 1;
			options.forward_x11_trusted = 1;
			break;
367 368 369
		case 'g':
			options.gateway_ports = 1;
			break;
370
		case 'O':
371 372 373 374 375
			if (stdio_forward_host != NULL)
				fatal("Cannot specify multiplexing "
				    "command with -W");
			else if (muxclient_command != 0)
				fatal("Multiplexing command already specified");
376
			if (strcmp(optarg, "check") == 0)
377
				muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK;
378 379
			else if (strcmp(optarg, "forward") == 0)
				muxclient_command = SSHMUX_COMMAND_FORWARD;
380
			else if (strcmp(optarg, "exit") == 0)
381
				muxclient_command = SSHMUX_COMMAND_TERMINATE;
382 383
			else if (strcmp(optarg, "stop") == 0)
				muxclient_command = SSHMUX_COMMAND_STOP;
384 385
			else if (strcmp(optarg, "cancel") == 0)
				muxclient_command = SSHMUX_COMMAND_CANCEL_FWD;
386 387 388
			else
				fatal("Invalid multiplex command.");
			break;
389
		case 'P':	/* deprecated */
390 391
			options.use_privileged_port = 0;
			break;
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
		case 'Q':	/* deprecated */
			cp = NULL;
			if (strcasecmp(optarg, "cipher") == 0)
				cp = cipher_alg_list();
			else if (strcasecmp(optarg, "mac") == 0)
				cp = mac_alg_list();
			else if (strcasecmp(optarg, "kex") == 0)
				cp = kex_alg_list();
			else if (strcasecmp(optarg, "key") == 0)
				cp = key_alg_list();
			if (cp == NULL)
				fatal("Unsupported query \"%s\"", optarg);
			printf("%s\n", cp);
			free(cp);
			exit(0);
			break;
408 409 410
		case 'a':
			options.forward_agent = 0;
			break;
411 412 413
		case 'A':
			options.forward_agent = 1;
			break;
414
		case 'k':
415
			options.gss_deleg_creds = 0;
416
			break;
417 418 419 420
		case 'K':
			options.gss_authentication = 1;
			options.gss_deleg_creds = 1;
			break;
421 422
		case 'i':
			if (stat(optarg, &st) < 0) {
Damien Miller's avatar
Damien Miller committed
423
				fprintf(stderr, "Warning: Identity file %s "
424 425
				    "not accessible: %s.\n", optarg,
				    strerror(errno));
426 427
				break;
			}
428
			add_identity_file(&options, NULL, optarg, 1);
429
			break;
430
		case 'I':
431 432
#ifdef ENABLE_PKCS11
			options.pkcs11_provider = xstrdup(optarg);
433
#else
434
			fprintf(stderr, "no support for PKCS#11.\n");
435
#endif
436
			break;
437
		case 't':
438 439 440 441
			if (options.request_tty == REQUEST_TTY_YES)
				options.request_tty = REQUEST_TTY_FORCE;
			else
				options.request_tty = REQUEST_TTY_YES;
442 443
			break;
		case 'v':
444
			if (debug_flag == 0) {
445 446
				debug_flag = 1;
				options.log_level = SYSLOG_LEVEL_DEBUG1;
447 448 449 450
			} else {
				if (options.log_level < SYSLOG_LEVEL_DEBUG3)
					options.log_level++;
			}
451
			break;
452
		case 'V':
453
			fprintf(stderr, "%s, %s\n",
454
			    SSH_RELEASE, SSLeay_version(SSLEAY_VERSION));
455 456 457
			if (opt == 'V')
				exit(0);
			break;
458
		case 'w':
459 460
			if (options.tun_open == -1)
				options.tun_open = SSH_TUNMODE_DEFAULT;
461
			options.tun_local = a2tun(optarg, &options.tun_remote);
462
			if (options.tun_local == SSH_TUNID_ERR) {
463 464
				fprintf(stderr,
				    "Bad tun device '%s'\n", optarg);
465
				exit(255);
466 467
			}
			break;
468
		case 'W':
469 470 471 472
			if (stdio_forward_host != NULL)
				fatal("stdio forward already specified");
			if (muxclient_command != 0)
				fatal("Cannot specify stdio forward with -O");
473 474 475
			if (parse_forward(&fwd, optarg, 1, 0)) {
				stdio_forward_host = fwd.listen_host;
				stdio_forward_port = fwd.listen_port;
476
				free(fwd.connect_host);
477 478 479 480 481 482
			} else {
				fprintf(stderr,
				    "Bad stdio forwarding specification '%s'\n",
				    optarg);
				exit(255);
			}
483
			options.request_tty = REQUEST_TTY_NO;
484 485 486 487
			no_shell_flag = 1;
			options.clear_forwardings = 1;
			options.exit_on_forward_failure = 1;
			break;
488 489 490 491 492
		case 'q':
			options.log_level = SYSLOG_LEVEL_QUIET;
			break;
		case 'e':
			if (optarg[0] == '^' && optarg[2] == 0 &&
Damien Miller's avatar
Damien Miller committed
493 494
			    (u_char) optarg[1] >= 64 &&
			    (u_char) optarg[1] < 128)
495
				options.escape_char = (u_char) optarg[1] & 31;
496
			else if (strlen(optarg) == 1)
497
				options.escape_char = (u_char) optarg[0];
498
			else if (strcmp(optarg, "none") == 0)
499
				options.escape_char = SSH_ESCAPECHAR_NONE;
500
			else {
Damien Miller's avatar
Damien Miller committed
501 502
				fprintf(stderr, "Bad escape character '%s'.\n",
				    optarg);
503
				exit(255);
504 505 506
			}
			break;
		case 'c':
507 508 509
			if (ciphers_valid(optarg)) {
				/* SSH2 only */
				options.ciphers = xstrdup(optarg);
510
				options.cipher = SSH_CIPHER_INVALID;
511 512
			} else {
				/* SSH1 only */
513 514
				options.cipher = cipher_number(optarg);
				if (options.cipher == -1) {
Damien Miller's avatar
Damien Miller committed
515 516 517
					fprintf(stderr,
					    "Unknown cipher type '%s'\n",
					    optarg);
518
					exit(255);
519
				}
Damien Miller's avatar
Damien Miller committed
520
				if (options.cipher == SSH_CIPHER_3DES)
521
					options.ciphers = "3des-cbc";
Damien Miller's avatar
Damien Miller committed
522
				else if (options.cipher == SSH_CIPHER_BLOWFISH)
523
					options.ciphers = "blowfish-cbc";
Damien Miller's avatar
Damien Miller committed
524
				else
525
					options.ciphers = (char *)-1;
526 527
			}
			break;
528 529 530 531
		case 'm':
			if (mac_valid(optarg))
				options.macs = xstrdup(optarg);
			else {
Damien Miller's avatar
Damien Miller committed
532 533
				fprintf(stderr, "Unknown mac type '%s'\n",
				    optarg);
534
				exit(255);
535 536
			}
			break;
537
		case 'M':
538 539 540 541
			if (options.control_master == SSHCTL_MASTER_YES)
				options.control_master = SSHCTL_MASTER_ASK;
			else
				options.control_master = SSHCTL_MASTER_YES;
542
			break;
543
		case 'p':
544
			options.port = a2port(optarg);
545
			if (options.port <= 0) {
546
				fprintf(stderr, "Bad port '%s'\n", optarg);
547
				exit(255);
548
			}
549 550 551 552
			break;
		case 'l':
			options.user = optarg;
			break;
553 554

		case 'L':
555
			if (parse_forward(&fwd, optarg, 0, 0))
556 557
				add_local_forward(&options, &fwd);
			else {
Damien Miller's avatar
Damien Miller committed
558
				fprintf(stderr,
559
				    "Bad local forwarding specification '%s'\n",
Damien Miller's avatar
Damien Miller committed
560
				    optarg);
561
				exit(255);
562
			}
563 564 565
			break;

		case 'R':
566
			if (parse_forward(&fwd, optarg, 0, 1)) {
567 568
				add_remote_forward(&options, &fwd);
			} else {
Damien Miller's avatar
Damien Miller committed
569
				fprintf(stderr,
570 571
				    "Bad remote forwarding specification "
				    "'%s'\n", optarg);
572
				exit(255);
573 574
			}
			break;
575 576

		case 'D':
577
			if (parse_forward(&fwd, optarg, 1, 0)) {
578
				add_local_forward(&options, &fwd);
579
			} else {
580 581 582
				fprintf(stderr,
				    "Bad dynamic forwarding specification "
				    "'%s'\n", optarg);
583
				exit(255);
584
			}
585 586
			break;

587 588 589
		case 'C':
			options.compression = 1;
			break;
Damien Miller's avatar
Damien Miller committed
590 591
		case 'N':
			no_shell_flag = 1;
592
			options.request_tty = REQUEST_TTY_NO;
Damien Miller's avatar
Damien Miller committed
593 594
			break;
		case 'T':
595
			options.request_tty = REQUEST_TTY_NO;
Damien Miller's avatar
Damien Miller committed
596
			break;
597 598
		case 'o':
			dummy = 1;
599
			line = xstrdup(optarg);
Damien Miller's avatar
Damien Miller committed
600
			if (process_config_line(&options, host ? host : "",
601 602
			    line, "command-line", 0, &dummy, SSHCONF_USERCONF)
			    != 0)
603
				exit(255);
604
			free(line);
605
			break;
606 607 608
		case 's':
			subsystem_flag = 1;
			break;
609 610 611 612 613
		case 'S':
			if (options.control_path != NULL)
				free(options.control_path);
			options.control_path = xstrdup(optarg);
			break;
614 615 616
		case 'b':
			options.bind_address = optarg;
			break;
617 618 619
		case 'F':
			config = optarg;
			break;
620 621 622 623 624
		default:
			usage();
		}
	}

Damien Miller's avatar
Damien Miller committed
625 626 627
	ac -= optind;
	av += optind;

628
	if (ac > 0 && !host) {
629
		if (strrchr(*av, '@')) {
Damien Miller's avatar
Damien Miller committed
630
			p = xstrdup(*av);
631
			cp = strrchr(p, '@');
Damien Miller's avatar
Damien Miller committed
632 633 634 635 636 637 638
			if (cp == NULL || cp == p)
				usage();
			options.user = p;
			*cp = '\0';
			host = ++cp;
		} else
			host = *av;
639 640
		if (ac > 1) {
			optind = optreset = 1;
Damien Miller's avatar
Damien Miller committed
641 642
			goto again;
		}
643
		ac--, av++;
Damien Miller's avatar
Damien Miller committed
644 645
	}

646 647
	/* Check that we got a host name. */
	if (!host)
Damien Miller's avatar
Damien Miller committed
648
		usage();
649

650
	OpenSSL_add_all_algorithms();
651
	ERR_load_crypto_strings();
652

653 654 655
	/* Initialize the command to execute on remote host. */
	buffer_init(&command);

656 657 658 659 660
	/*
	 * Save the command to execute on the remote host in a buffer. There
	 * is no limit on the length of the command, except by the maximum
	 * packet size.  Also sets the tty flag if there is no command.
	 */
Damien Miller's avatar
Damien Miller committed
661
	if (!ac) {
662
		/* No command specified - execute shell on a tty. */
663
		if (subsystem_flag) {
Damien Miller's avatar
Damien Miller committed
664 665
			fprintf(stderr,
			    "You must specify a subsystem to invoke.\n");
666 667
			usage();
		}
668
	} else {
Damien Miller's avatar
Damien Miller committed
669 670 671
		/* A command has been specified.  Store it into the buffer. */
		for (i = 0; i < ac; i++) {
			if (i)
672 673 674
				buffer_append(&command, " ", 1);
			buffer_append(&command, av[i], strlen(av[i]));
		}
Damien Miller's avatar
Damien Miller committed
675
	}
676 677

	/* Cannot fork to background if no command. */
678 679 680 681
	if (fork_after_authentication_flag && buffer_len(&command) == 0 &&
	    !no_shell_flag)
		fatal("Cannot fork into background without a command "
		    "to execute.");
682

683 684
	/*
	 * Initialize "log" output.  Since we are the client all output
685
	 * goes to stderr unless otherwise specified by -y or -E.
686
	 */
687 688 689 690
	if (use_syslog && logfile != NULL)
		fatal("Can't specify both -y and -E");
	if (logfile != NULL) {
		log_redirect_stderr_to(logfile);
691
		free(logfile);
692
	}
693
	log_init(argv0,
694
	    options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
695
	    SYSLOG_FACILITY_USER, !use_syslog);
696

697 698 699
	if (debug_flag)
		logit("%s, %s", SSH_VERSION, SSLeay_version(SSLEAY_VERSION));

700 701 702 703 704
	/*
	 * Read per-user configuration file.  Ignore the system wide config
	 * file if the user specifies a config file on the command line.
	 */
	if (config != NULL) {
705 706
		if (strcasecmp(config, "none") != 0 &&
		    !read_config_file(config, host, &options, SSHCONF_USERCONF))
707 708
			fatal("Can't open user config file %.100s: "
			    "%.100s", config, strerror(errno));
709
	} else {
710
		r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
711
		    _PATH_SSH_USER_CONFFILE);
712
		if (r > 0 && (size_t)r < sizeof(buf))
713 714
			(void)read_config_file(buf, host, &options,
			     SSHCONF_CHECKPERM|SSHCONF_USERCONF);
715

716
		/* Read systemwide configuration file after user config. */
717
		(void)read_config_file(_PATH_HOST_CONFIG_FILE, host,
718
		    &options, 0);
719
	}
720 721 722 723

	/* Fill configuration defaults. */
	fill_default_options(&options);

724 725
	channel_set_af(options.address_family);

726
	/* reinit */
727
	log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog);
728

729 730 731 732 733 734 735 736 737 738 739 740 741 742
	if (options.request_tty == REQUEST_TTY_YES ||
	    options.request_tty == REQUEST_TTY_FORCE)
		tty_flag = 1;

	/* Allocate a tty by default if no command specified. */
	if (buffer_len(&command) == 0)
		tty_flag = options.request_tty != REQUEST_TTY_NO;

	/* Force no tty */
	if (options.request_tty == REQUEST_TTY_NO || muxclient_command != 0)
		tty_flag = 0;
	/* Do not allocate a tty if stdin is not a tty. */
	if ((!isatty(fileno(stdin)) || stdin_null_flag) &&
	    options.request_tty != REQUEST_TTY_FORCE) {
743
		if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
744 745 746 747 748
			logit("Pseudo-terminal will not be allocated because "
			    "stdin is not a terminal.");
		tty_flag = 0;
	}

749 750
	seed_rng();

751 752 753
	if (options.user == NULL)
		options.user = xstrdup(pw->pw_name);

754 755 756 757 758 759
	/* Get default port if port has not been set. */
	if (options.port == 0) {
		sp = getservbyname(SSH_SERVICE_NAME, "tcp");
		options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
	}

760 761
	/* preserve host name given on command line for %n expansion */
	host_arg = host;
762 763 764 765 766
	if (options.hostname != NULL) {
		host = percent_expand(options.hostname,
		    "h", host, (char *)NULL);
	}

767 768 769 770 771
	if (gethostname(thishost, sizeof(thishost)) == -1)
		fatal("gethostname: %s", strerror(errno));
	strlcpy(shorthost, thishost, sizeof(shorthost));
	shorthost[strcspn(thishost, ".")] = '\0';
	snprintf(portstr, sizeof(portstr), "%d", options.port);
772

773
	if (options.local_command != NULL) {
774 775 776
		debug3("expanding LocalCommand: %s", options.local_command);
		cp = options.local_command;
		options.local_command = percent_expand(cp, "d", pw->pw_dir,
777
		    "h", host, "l", thishost, "n", host_arg, "r", options.user,
778 779
		    "p", portstr, "u", pw->pw_name, "L", shorthost,
		    (char *)NULL);
780
		debug3("expanded LocalCommand: %s", options.local_command);
781
		free(cp);
782 783
	}

784 785 786 787
	/* force lowercase for hostkey matching */
	if (options.host_key_alias != NULL) {
		for (p = options.host_key_alias; *p; p++)
			if (isupper(*p))
788
				*p = (char)tolower(*p);
789 790
	}

791
	if (options.proxy_command != NULL &&
792
	    strcmp(options.proxy_command, "none") == 0) {
793
		free(options.proxy_command);
794
		options.proxy_command = NULL;
795
	}
796
	if (options.control_path != NULL &&
797
	    strcmp(options.control_path, "none") == 0) {
798
		free(options.control_path);
799
		options.control_path = NULL;
800
	}
801

802
	if (options.control_path != NULL) {
803 804
		cp = tilde_expand_filename(options.control_path,
		    original_real_uid);
805
		free(options.control_path);
806 807 808 809
		options.control_path = percent_expand(cp, "h", host,
		    "l", thishost, "n", host_arg, "r", options.user,
		    "p", portstr, "u", pw->pw_name, "L", shorthost,
		    (char *)NULL);
810
		free(cp);
811
	}
812
	if (muxclient_command != 0 && options.control_path == NULL)
813
		fatal("No ControlPath specified for \"-O\" command");
814
	if (options.control_path != NULL)
815
		muxclient(options.control_path);
816

817 818
	timeout_ms = options.connection_timeout * 1000;

819
	/* Open a connection to the remote host. */
820
	if (ssh_connect(host, &hostaddr, options.port,
821 822
	    options.address_family, options.connection_attempts, &timeout_ms,
	    options.tcp_keep_alive, 
823 824 825
#ifdef HAVE_CYGWIN
	    options.use_privileged_port,
#else
826
	    original_effective_uid == 0 && options.use_privileged_port,
827
#endif
828
	    options.proxy_command) != 0)
829
		exit(255);
830

831 832 833
	if (timeout_ms > 0)
		debug3("timeout: %d ms remain after connect", timeout_ms);

834 835 836 837 838
	/*
	 * If we successfully made the connection, load the host private key
	 * in case we will need it later for combined rsa-rhosts
	 * authentication. This must be done before releasing extra
	 * privileges, because the file is only readable by root.
839 840
	 * If we cannot access the private keys, load the public keys
	 * instead and try to execute the ssh-keysign helper instead.
841
	 */
842 843
	sensitive_data.nkeys = 0;
	sensitive_data.keys = NULL;
844
	sensitive_data.external_keysign = 0;
845 846
	if (options.rhosts_rsa_authentication ||
	    options.hostbased_authentication) {
847
		sensitive_data.nkeys = 7;
848
		sensitive_data.keys = xcalloc(sensitive_data.nkeys,
849
		    sizeof(Key));
850 851
		for (i = 0; i < sensitive_data.nkeys; i++)
			sensitive_data.keys[i] = NULL;
852 853

		PRIV_START;
854
		sensitive_data.keys[0] = key_load_private_type(KEY_RSA1,
855
		    _PATH_HOST_KEY_FILE, "", NULL, NULL);
856 857
		sensitive_data.keys[1] = key_load_private_cert(KEY_DSA,
		    _PATH_HOST_DSA_KEY_FILE, "", NULL);
858
#ifdef OPENSSL_HAS_ECC
859 860
		sensitive_data.keys[2] = key_load_private_cert(KEY_ECDSA,
		    _PATH_HOST_ECDSA_KEY_FILE, "", NULL);
861
#endif
862
		sensitive_data.keys[3] = key_load_private_cert(KEY_RSA,
863
		    _PATH_HOST_RSA_KEY_FILE, "", NULL);
864
		sensitive_data.keys[4] = key_load_private_type(KEY_DSA,
865
		    _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL);
866
#ifdef OPENSSL_HAS_ECC
867 868
		sensitive_data.keys[5] = key_load_private_type(KEY_ECDSA,
		    _PATH_HOST_ECDSA_KEY_FILE, "", NULL, NULL);
869
#endif
870
		sensitive_data.keys[6] = key_load_private_type(KEY_RSA,
871
		    _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL);
872
		PRIV_END;
873

874 875
		if (options.hostbased_authentication == 1 &&
		    sensitive_data.keys[0] == NULL &&
876 877 878
		    sensitive_data.keys[4] == NULL &&
		    sensitive_data.keys[5] == NULL &&
		    sensitive_data.keys[6] == NULL) {
879 880
			sensitive_data.keys[1] = key_load_cert(
			    _PATH_HOST_DSA_KEY_FILE);
881
#ifdef OPENSSL_HAS_ECC
882
			sensitive_data.keys[2] = key_load_cert(
883
			    _PATH_HOST_ECDSA_KEY_FILE);
884
#endif
885
			sensitive_data.keys[3] = key_load_cert(
886 887
			    _PATH_HOST_RSA_KEY_FILE);
			sensitive_data.keys[4] = key_load_public(
888
			    _PATH_HOST_DSA_KEY_FILE, NULL);
889
#ifdef OPENSSL_HAS_ECC
890 891
			sensitive_data.keys[5] = key_load_public(
			    _PATH_HOST_ECDSA_KEY_FILE, NULL);
892
#endif
893
			sensitive_data.keys[6] = key_load_public(
894 895 896
			    _PATH_HOST_RSA_KEY_FILE, NULL);
			sensitive_data.external_keysign = 1;
		}
897
	}
898 899 900 901 902 903 904
	/*
	 * Get rid of any extra privileges that we may have.  We will no
	 * longer need them.  Also, extra privileges could make it very hard
	 * to read identity files and other non-world-readable files from the
	 * user's home directory if it happens to be on a NFS volume where
	 * root is mapped to nobody.
	 */
905 906 907 908
	if (original_effective_uid == 0) {
		PRIV_START;
		permanently_set_uid(pw);
	}
909

910 911
	/*
	 * Now that we are back to our own permissions, create ~/.ssh
912
	 * directory if it doesn't already exist.
913
	 */
914 915 916 917
	if (config == NULL) {
		r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir,
		    strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
		if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) {
918
#ifdef WITH_SELINUX
919
			ssh_selinux_setfscreatecon(buf);
920
#endif
921 922 923
			if (mkdir(buf, 0700) < 0)
				error("Could not create directory '%.200s'.",
				    buf);
924
#ifdef WITH_SELINUX
925
			ssh_selinux_setfscreatecon(NULL);
926
#endif
927
		}
928
	}
929 930 931 932
	/* load options.identity_files */
	load_public_identity_files();

	/* Expand ~ in known host file names. */
933 934 935
	tilde_expand_paths(options.system_hostfiles,
	    options.num_system_hostfiles);
	tilde_expand_paths(options.user_hostfiles, options.num_user_hostfiles);
936

937
	signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */
938
	signal(SIGCHLD, main_sigchld_handler);
939

940
	/* Log into the remote system.  Never returns if the login fails. */
941
	ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr,
942
	    options.port, pw, timeout_ms);
943

944 945 946 947 948 949 950
	if (packet_connection_is_on_socket()) {
		verbose("Authenticated to %s ([%s]:%d).", host,
		    get_remote_ipaddr(), get_remote_port());
	} else {
		verbose("Authenticated to %s (via proxy).", host);
	}

951 952 953 954 955 956 957 958 959 960
	/* We no longer need the private host keys.  Clear them now. */
	if (sensitive_data.nkeys != 0) {
		for (i = 0; i < sensitive_data.nkeys; i++) {
			if (sensitive_data.keys[i] != NULL) {
				/* Destroys contents safely */
				debug3("clear hostkey %d", i);
				key_free(sensitive_data.keys[i]);
				sensitive_data.keys[i] = NULL;
			}
		}
961
		free(sensitive_data.keys);
962
	}
963
	for (i = 0; i < options.num_identity_files; i++) {
964 965
		free(options.identity_files[i]);
		options.identity_files[i] = NULL;
966 967 968 969 970
		if (options.identity_keys[i]) {
			key_free(options.identity_keys[i]);
			options.identity_keys[i] = NULL;
		}
	}
971

Damien Miller's avatar
Damien Miller committed
972 973
	exit_status = compat20 ? ssh_session2() : ssh_session();
	packet_close();
974

975
	if (options.control_path != NULL && muxserver_sock != -1)
976 977
		unlink(options.control_path);

978 979
	/* Kill ProxyCommand if it is running. */
	ssh_kill_proxy_command();
980

Damien Miller's avatar
Damien Miller committed
981 982 983
	return exit_status;
}

984 985 986 987
static void
control_persist_detach(void)
{
	pid_t pid;
988
	int devnull;
989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005

	debug("%s: backgrounding master process", __func__);

 	/*
 	 * master (current process) into the background, and make the
 	 * foreground process a client of the backgrounded master.
 	 */
	switch ((pid = fork())) {
	case -1:
		fatal("%s: fork: %s", __func__, strerror(errno));
	case 0:
		/* Child: master process continues mainloop */
 		break;
 	default:
		/* Parent: set up mux slave to connect to backgrounded master */
		debug2("%s: background process is %ld", __func__, (long)pid);
		stdin_null_flag = ostdin_null_flag;
1006
		options.request_tty = orequest_tty;
1007 1008 1009
		tty_flag = otty_flag;
 		close(muxserver_sock);
 		muxserver_sock = -1;
1010
		options.control_master = SSHCTL_MASTER_NO;
1011 1012 1013 1014
 		muxclient(options.control_path);
		/* muxclient() doesn't return on success. */
 		fatal("Failed to connect to new control master");
 	}
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
	if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
		error("%s: open(\"/dev/null\"): %s", __func__,
		    strerror(errno));
	} else {
		if (dup2(devnull, STDIN_FILENO) == -1 ||
		    dup2(devnull, STDOUT_FILENO) == -1)
			error("%s: dup2: %s", __func__, strerror(errno));
		if (devnull > STDERR_FILENO)
			close(devnull);
	}
1025
	daemon(1, 1);
1026
	setproctitle("%s [mux]", options.control_path);
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
}

/* Do fork() after authentication. Used by "ssh -f" */
static void
fork_postauth(void)
{
	if (need_controlpersist_detach)
		control_persist_detach();
	debug("forking to background");
	fork_after_authentication_flag = 0;
	if (daemon(1, 1) < 0)
		fatal("daemon() failed: %.200s", strerror(errno));
}

1041 1042 1043 1044 1045 1046
/* Callback for remote forward global requests */
static void
ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
{
	Forward *rfwd = (Forward *)ctxt;

1047
	/* XXX verbose() on failure? */
1048 1049 1050
	debug("remote forward %s for: listen %d, connect %s:%d",
	    type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
	    rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
	if (rfwd->listen_port == 0) {
		if (type == SSH2_MSG_REQUEST_SUCCESS) {
			rfwd->allocated_port = packet_get_int();
			logit("Allocated port %u for remote forward to %s:%d",
			    rfwd->allocated_port,
			    rfwd->connect_host, rfwd->connect_port);
			channel_update_permitted_opens(rfwd->handle,
			    rfwd->allocated_port);
		} else {
			channel_update_permitted_opens(rfwd->handle, -1);
		}
1062 1063
	}
	
1064 1065 1066 1067 1068 1069 1070 1071
	if (type == SSH2_MSG_REQUEST_FAILURE) {
		if (options.exit_on_forward_failure)
			fatal("Error: remote port forwarding failed for "
			    "listen port %d", rfwd->listen_port);
		else
			logit("Warning: remote port forwarding failed for "
			    "listen port %d", rfwd->listen_port);
	}
1072
	if (++remote_forward_confirms_received == options.num_remote_forwards) {
1073
		debug("All remote forwarding requests processed");
1074 1075
		if (fork_after_authentication_flag)
			fork_postauth();
1076
	}
1077 1078
}

1079 1080 1081 1082 1083 1084 1085
static void
client_cleanup_stdio_fwd(int id, void *arg)
{
	debug("stdio forwarding: done");
	cleanup_exit(0);
}

1086 1087
static void
ssh_init_stdio_forwarding(void)
1088 1089
{
	Channel *c;
1090
	int in, out;
1091

1092 1093 1094 1095
	if (stdio_forward_host == NULL)
		return;
	if (!compat20) 
		fatal("stdio forwarding require Protocol 2");
1096

1097
	debug3("%s: %s:%d", __func__, stdio_forward_host, stdio_forward_port);
1098

1099 1100 1101 1102 1103 1104
	if ((in = dup(STDIN_FILENO)) < 0 ||
	    (out = dup(STDOUT_FILENO)) < 0)
		fatal("channel_connect_stdio_fwd: dup() in/out failed");
	if ((c = channel_connect_stdio_fwd(stdio_forward_host,
	    stdio_forward_port, in, out)) == NULL)
		fatal("%s: channel_connect_stdio_fwd failed", __func__);
1105 1106 1107
	channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0);
}

1108
static void
1109 1110
ssh_init_forwarding(void)
{
1111
	int success = 0;
1112
	int i;
1113

1114 1115
	/* Initiate local TCP/IP port forwardings. */
	for (i = 0; i < options.num_local_forwards; i++) {
1116 1117
		debug("Local connections to %.200s:%d forwarded to remote "
		    "address %.200s:%d",
1118 1119
		    (options.local_forwards[i].listen_host == NULL) ?
		    (options.gateway_ports ? "*" : "LOCALHOST") :
1120 1121 1122 1123
		    options.local_forwards[i].listen_host,
		    options.local_forwards[i].listen_port,
		    options.local_forwards[i].connect_host,
		    options.local_forwards[i].connect_port);
1124
		success += channel_setup_local_fwd_listener(
1125 1126 1127 1128
		    options.local_forwards[i].listen_host,
		    options.local_forwards[i].listen_port,
		    options.local_forwards[i].connect_host,
		    options.local_forwards[i].connect_port,
1129 1130
		    options.gateway_ports);
	}
1131 1132
	if (i > 0 && success != i && options.exit_on_forward_failure)
		fatal("Could not request local forwarding.");
1133 1134
	if (i > 0 && success == 0)
		error("Could not request local forwarding.");
1135 1136 1137

	/* Initiate remote TCP/IP port forwardings. */
	for (i = 0; i < options.num_remote_forwards; i++) {
1138 1139
		debug("Remote connections from %.200s:%d forwarded to "
		    "local address %.200s:%d",
1140
		    (options.remote_forwards[i].listen_host == NULL) ?
1141
		    "LOCALHOST" : options.remote_forwards[i].listen_host,
1142 1143 1144
		    options.remote_forwards[i].listen_port,
		    options.remote_forwards[i].connect_host,
		    options.remote_forwards[i].connect_port);
1145 1146
		options.remote_forwards[i].handle =
		    channel_request_remote_forwarding(
1147 1148 1149
		    options.remote_forwards[i].listen_host,
		    options.remote_forwards[i].listen_port,
		    options.remote_forwards[i].connect_host,
1150 1151
		    options.remote_forwards[i].connect_port);
		if (options.remote_forwards[i].handle < 0) {
1152 1153 1154 1155 1156
			if (options.exit_on_forward_failure)
				fatal("Could not request remote forwarding.");
			else
				logit("Warning: Could not request remote "
				    "forwarding.");
1157 1158 1159
		} else {
			client_register_global_confirm(ssh_confirm_remote_forward,
			    &options.remote_forwards[i]);
1160
		}
1161
	}
1162