blob: ed4ceaf43a769188b036fe0f7f1190911c0dc96d [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001/*
2
3ssh.c
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved
9
10Created: Sat Mar 18 16:36:11 1995 ylo
11
12Ssh client program. This program can be used to log into a remote machine.
13The software supports strong authentication, encryption, and forwarding
14of X11, TCP/IP, and authentication connections.
15
16Modified to work with SSL by Niels Provos <provos@citi.umich.edu> in Canada.
17
18*/
19
20#include "includes.h"
Damien Miller01ab4a21999-10-28 15:23:30 +100021RCSID("$Id: ssh.c,v 1.3 1999/10/28 05:23:30 damien Exp $");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100022
23#include "xmalloc.h"
24#include "ssh.h"
25#include "packet.h"
26#include "buffer.h"
27#include "authfd.h"
28#include "readconf.h"
29#include "uidswap.h"
30
31/* Flag indicating whether debug mode is on. This can be set on the
32 command line. */
33int debug_flag = 0;
34
35/* Flag indicating whether quiet mode is on. */
36int quiet_flag = 0;
37
38/* Flag indicating whether to allocate a pseudo tty. This can be set on the
39 command line, and is automatically set if no command is given on the command
40 line. */
41int tty_flag = 0;
42
43/* Flag indicating that nothing should be read from stdin. This can be set
44 on the command line. */
45int stdin_null_flag = 0;
46
47/* Flag indicating that ssh should fork after authentication. This is useful
48 so that the pasphrase can be entered manually, and then ssh goes to the
49 background. */
50int fork_after_authentication_flag = 0;
51
52/* General data structure for command line options and options configurable
53 in configuration files. See readconf.h. */
54Options options;
55
56/* Name of the host we are connecting to. This is the name given on the
57 command line, or the HostName specified for the user-supplied name
58 in a configuration file. */
59char *host;
60
61/* socket address the host resolves to */
62struct sockaddr_in hostaddr;
63
64/* Flag to indicate that we have received a window change signal which has
65 not yet been processed. This will cause a message indicating the new
66 window size to be sent to the server a little later. This is volatile
67 because this is updated in a signal handler. */
68volatile int received_window_change_signal = 0;
69
70/* Value of argv[0] (set in the main program). */
71char *av0;
72
73/* Flag indicating whether we have a valid host private key loaded. */
74int host_private_key_loaded = 0;
75
76/* Host private key. */
77RSA *host_private_key = NULL;
78
79/* Original real UID. */
80uid_t original_real_uid;
81
82/* Prints a help message to the user. This function never returns. */
83
84void
85usage()
86{
87 fprintf(stderr, "Usage: %s [options] host [command]\n", av0);
88 fprintf(stderr, "Options:\n");
89 fprintf(stderr, " -l user Log in using this user name.\n");
90 fprintf(stderr, " -n Redirect input from /dev/null.\n");
91 fprintf(stderr, " -a Disable authentication agent forwarding.\n");
92#ifdef AFS
93 fprintf(stderr, " -k Disable Kerberos ticket and AFS token forwarding.\n");
94#endif /* AFS */
95 fprintf(stderr, " -x Disable X11 connection forwarding.\n");
96 fprintf(stderr, " -i file Identity for RSA authentication (default: ~/.ssh/identity).\n");
97 fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n");
98 fprintf(stderr, " -v Verbose; display verbose debugging messages.\n");
99 fprintf(stderr, " -V Display version number only.\n");
100 fprintf(stderr, " -P Don't allocate a privileged port.\n");
101 fprintf(stderr, " -q Quiet; don't display any warning messages.\n");
102 fprintf(stderr, " -f Fork into background after authentication.\n");
103 fprintf(stderr, " -e char Set escape character; ``none'' = disable (default: ~).\n");
104
105 fprintf(stderr, " -c cipher Select encryption algorithm: "
106 "``3des'', "
107 "``blowfish''\n");
108 fprintf(stderr, " -p port Connect to this port. Server must be on the same port.\n");
109 fprintf(stderr, " -L listen-port:host:port Forward local port to remote address\n");
110 fprintf(stderr, " -R listen-port:host:port Forward remote port to local address\n");
111 fprintf(stderr, " These cause %s to listen for connections on a port, and\n", av0);
112 fprintf(stderr, " forward them to the other side by connecting to host:port.\n");
113 fprintf(stderr, " -C Enable compression.\n");
114 fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n");
115 fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n");
116 exit(1);
117}
118
119/* Connects to the given host using rsh (or prints an error message and exits
120 if rsh is not available). This function never returns. */
121
122void
123rsh_connect(char *host, char *user, Buffer *command)
124{
125 char *args[10];
126 int i;
127
128 log("Using rsh. WARNING: Connection will not be encrypted.");
129 /* Build argument list for rsh. */
130 i = 0;
131 args[i++] = _PATH_RSH;
132 args[i++] = host; /* may have to come after user on some systems */
133 if (user)
134 {
135 args[i++] = "-l";
136 args[i++] = user;
137 }
138 if (buffer_len(command) > 0)
139 {
140 buffer_append(command, "\0", 1);
141 args[i++] = buffer_ptr(command);
142 }
143 args[i++] = NULL;
144 if (debug_flag)
145 {
146 for (i = 0; args[i]; i++)
147 {
148 if (i != 0)
149 fprintf(stderr, " ");
150 fprintf(stderr, "%s", args[i]);
151 }
152 fprintf(stderr, "\n");
153 }
154 execv(_PATH_RSH, args);
155 perror(_PATH_RSH);
156 exit(1);
157}
158
159/* Main program for the ssh client. */
160
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000161int
162main(int ac, char **av)
163{
164 int i, opt, optind, type, exit_status, ok, fwd_port, fwd_host_port, authfd;
165 char *optarg, *cp, buf[256];
166 Buffer command;
167 struct winsize ws;
168 struct stat st;
169 struct passwd *pw, pwcopy;
170 int interactive = 0, dummy;
171 uid_t original_effective_uid;
172 int plen;
173
174 /* Save the original real uid. It will be needed later (uid-swapping may
175 clobber the real uid). */
176 original_real_uid = getuid();
177 original_effective_uid = geteuid();
178
179 /* If we are installed setuid root be careful to not drop core. */
180 if (original_real_uid != original_effective_uid)
181 {
182 struct rlimit rlim;
183 rlim.rlim_cur = rlim.rlim_max = 0;
184 if (setrlimit(RLIMIT_CORE, &rlim) < 0)
185 fatal("setrlimit failed: %.100s", strerror(errno));
186 }
187
188 /* Use uid-swapping to give up root privileges for the duration of option
189 processing. We will re-instantiate the rights when we are ready to
190 create the privileged port, and will permanently drop them when the
191 port has been created (actually, when the connection has been made, as
192 we may need to create the port several times). */
193 temporarily_use_uid(original_real_uid);
194
195 /* Set our umask to something reasonable, as some files are created with
196 the default umask. This will make them world-readable but writable
197 only by the owner, which is ok for all files for which we don't set
198 the modes explicitly. */
199 umask(022);
200
201 /* Save our own name. */
202 av0 = av[0];
203
204 /* Initialize option structure to indicate that no values have been set. */
205 initialize_options(&options);
206
207 /* Parse command-line arguments. */
208 host = NULL;
209
210 /* If program name is not one of the standard names, use it as host name. */
211 if (strchr(av0, '/'))
212 cp = strrchr(av0, '/') + 1;
213 else
214 cp = av0;
215 if (strcmp(cp, "rsh") != 0 && strcmp(cp, "ssh") != 0 &&
Damien Miller7f6ea021999-10-28 13:25:17 +1000216 strcmp(cp, "openssh") != 0 && strcmp(cp, "openlogin") != 0 &&
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000217 strcmp(cp, "rlogin") != 0 && strcmp(cp, "slogin") != 0)
218 host = cp;
219
220 for (optind = 1; optind < ac; optind++)
221 {
222 if (av[optind][0] != '-')
223 {
224 if (host)
225 break;
226 if ((cp = strchr(av[optind], '@'))) {
227 options.user = av[optind];
228 *cp = '\0';
229 host = ++cp;
230 }
231 else
232 host = av[optind];
233 continue;
234 }
235 opt = av[optind][1];
236 if (!opt)
237 usage();
238 if (strchr("eilcpLRo", opt)) /* options with arguments */
239 {
240 optarg = av[optind] + 2;
241 if (strcmp(optarg, "") == 0)
242 {
243 if (optind >= ac - 1)
244 usage();
245 optarg = av[++optind];
246 }
247 }
248 else
249 {
250 if (av[optind][2])
251 usage();
252 optarg = NULL;
253 }
254 switch (opt)
255 {
256 case 'n':
257 stdin_null_flag = 1;
258 break;
259
260 case 'f':
261 fork_after_authentication_flag = 1;
262 stdin_null_flag = 1;
263 break;
264
265 case 'x':
266 options.forward_x11 = 0;
267 break;
268
269 case 'X':
270 options.forward_x11 = 1;
271 break;
272
273 case 'g':
274 options.gateway_ports = 1;
275 break;
276
277 case 'P':
278 options.use_privileged_port = 0;
279 break;
280
281 case 'a':
282 options.forward_agent = 0;
283 break;
284#ifdef AFS
285 case 'k':
286 options.kerberos_tgt_passing = 0;
287 options.afs_token_passing = 0;
288 break;
289#endif
290 case 'i':
291 if (stat(optarg, &st) < 0)
292 {
293 fprintf(stderr, "Warning: Identity file %s does not exist.\n",
294 optarg);
295 break;
296 }
297 if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES)
298 fatal("Too many identity files specified (max %d)",
299 SSH_MAX_IDENTITY_FILES);
300 options.identity_files[options.num_identity_files++] =
301 xstrdup(optarg);
302 break;
303
304 case 't':
305 tty_flag = 1;
306 break;
307
308 case 'v':
309 case 'V':
310 debug_flag = 1;
311 fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n",
312 SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR);
313 fprintf(stderr, "Compiled with SSL.\n");
314 if (opt == 'V')
315 exit(0);
316 break;
317
318 case 'q':
319 quiet_flag = 1;
320 break;
321
322 case 'e':
323 if (optarg[0] == '^' && optarg[2] == 0 &&
324 (unsigned char)optarg[1] >= 64 && (unsigned char)optarg[1] < 128)
325 options.escape_char = (unsigned char)optarg[1] & 31;
326 else
327 if (strlen(optarg) == 1)
328 options.escape_char = (unsigned char)optarg[0];
329 else
330 if (strcmp(optarg, "none") == 0)
331 options.escape_char = -2;
332 else
333 {
334 fprintf(stderr, "Bad escape character '%s'.\n", optarg);
335 exit(1);
336 }
337 break;
338
339 case 'c':
340 options.cipher = cipher_number(optarg);
341 if (options.cipher == -1)
342 {
343 fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
344 exit(1);
345 }
346 break;
347
348 case 'p':
349 options.port = atoi(optarg);
350 if (options.port < 1 || options.port > 65535)
351 {
352 fprintf(stderr, "Bad port %s.\n", optarg);
353 exit(1);
354 }
355 break;
356
357 case 'l':
358 options.user = optarg;
359 break;
360
361 case 'R':
362 if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf,
363 &fwd_host_port) != 3)
364 {
365 fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
366 usage();
367 /*NOTREACHED*/
368 }
369 add_remote_forward(&options, fwd_port, buf, fwd_host_port);
370 break;
371
372 case 'L':
373 if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf,
374 &fwd_host_port) != 3)
375 {
376 fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
377 usage();
378 /*NOTREACHED*/
379 }
380 add_local_forward(&options, fwd_port, buf, fwd_host_port);
381 break;
382
383 case 'C':
384 options.compression = 1;
385 break;
386
387 case 'o':
388 dummy = 1;
389 process_config_line(&options, host ? host : "", optarg,
390 "command-line", 0, &dummy);
391 break;
392
393 default:
394 usage();
395 }
396 }
397
398 /* Check that we got a host name. */
399 if (!host)
400 usage();
401
402 /* check if RSA support exists */
403 if (rsa_alive() == 0) {
404 extern char *__progname;
405
406 fprintf(stderr,
407 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
408 __progname);
409 exit(1);
410 }
411
412 /* Initialize the command to execute on remote host. */
413 buffer_init(&command);
414
415 /* Save the command to execute on the remote host in a buffer. There is
416 no limit on the length of the command, except by the maximum packet
417 size. Also sets the tty flag if there is no command. */
418 if (optind == ac)
419 {
420 /* No command specified - execute shell on a tty. */
421 tty_flag = 1;
422 }
423 else
424 {
425 /* A command has been specified. Store it into the buffer. */
426 for (i = optind; i < ac; i++)
427 {
428 if (i > optind)
429 buffer_append(&command, " ", 1);
430 buffer_append(&command, av[i], strlen(av[i]));
431 }
432 }
433
434 /* Cannot fork to background if no command. */
435 if (fork_after_authentication_flag && buffer_len(&command) == 0)
436 fatal("Cannot fork into background without a command to execute.");
437
438 /* Allocate a tty by default if no command specified. */
439 if (buffer_len(&command) == 0)
440 tty_flag = 1;
441
442 /* Do not allocate a tty if stdin is not a tty. */
443 if (!isatty(fileno(stdin)))
444 {
445 if (tty_flag)
446 fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n");
447 tty_flag = 0;
448 }
449
450 /* Get user data. */
451 pw = getpwuid(original_real_uid);
452 if (!pw)
453 {
454 fprintf(stderr, "You don't exist, go away!\n");
455 exit(1);
456 }
457
458 /* Take a copy of the returned structure. */
459 memset(&pwcopy, 0, sizeof(pwcopy));
460 pwcopy.pw_name = xstrdup(pw->pw_name);
461 pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
462 pwcopy.pw_uid = pw->pw_uid;
463 pwcopy.pw_gid = pw->pw_gid;
464 pwcopy.pw_dir = xstrdup(pw->pw_dir);
465 pwcopy.pw_shell = xstrdup(pw->pw_shell);
466 pw = &pwcopy;
467
468 /* Initialize "log" output. Since we are the client all output actually
469 goes to the terminal. */
470 log_init(av[0], 1, debug_flag, quiet_flag, SYSLOG_FACILITY_USER);
471
472 /* Read per-user configuration file. */
473 snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_CONFFILE);
474 read_config_file(buf, host, &options);
475
476 /* Read systemwide configuration file. */
477 read_config_file(HOST_CONFIG_FILE, host, &options);
478
479 /* Fill configuration defaults. */
480 fill_default_options(&options);
481 if (options.user == NULL)
482 options.user = xstrdup(pw->pw_name);
483
484 if (options.hostname != NULL)
485 host = options.hostname;
486
487 /* Find canonic host name. */
488 if (strchr(host, '.') == 0)
489 {
490 struct hostent *hp = gethostbyname(host);
491 if (hp != 0)
492 {
493 if (strchr(hp->h_name, '.') != 0)
494 host = xstrdup(hp->h_name);
495 else if (hp->h_aliases != 0
496 && hp->h_aliases[0] != 0
497 && strchr(hp->h_aliases[0], '.') != 0)
498 host = xstrdup(hp->h_aliases[0]);
499 }
500 }
501
502 /* Disable rhosts authentication if not running as root. */
503 if (original_effective_uid != 0)
504 {
505 options.rhosts_authentication = 0;
506 options.rhosts_rsa_authentication = 0;
507 }
508
509 /* If using rsh has been selected, exec it now (without trying anything
510 else). Note that we must release privileges first. */
511 if (options.use_rsh)
512 {
513 /* Restore our superuser privileges. This must be done before
514 permanently setting the uid. */
515 restore_uid();
516
517 /* Switch to the original uid permanently. */
518 permanently_set_uid(original_real_uid);
519
520 /* Execute rsh. */
521 rsh_connect(host, options.user, &command);
522 fatal("rsh_connect returned");
523 }
524
525 /* Restore our superuser privileges. */
526 restore_uid();
527
528 /* Open a connection to the remote host. This needs root privileges if
529 rhosts_{rsa_}authentication is true. */
530
531 if (!options.use_privileged_port)
532 {
533 options.rhosts_authentication = 0;
534 options.rhosts_rsa_authentication = 0;
535 }
536
537 ok = ssh_connect(host, &hostaddr, options.port, options.connection_attempts,
538 !options.rhosts_authentication &&
539 !options.rhosts_rsa_authentication,
540 original_real_uid, options.proxy_command);
541
542 /* If we successfully made the connection, load the host private key in
543 case we will need it later for combined rsa-rhosts authentication.
544 This must be done before releasing extra privileges, because the file
545 is only readable by root. */
546 if (ok)
547 {
548 host_private_key = RSA_new();
549 if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
550 host_private_key_loaded = 1;
551 }
552
553 /* Get rid of any extra privileges that we may have. We will no longer need
554 them. Also, extra privileges could make it very hard to read identity
555 files and other non-world-readable files from the user's home directory
556 if it happens to be on a NFS volume where root is mapped to nobody. */
557 permanently_set_uid(original_real_uid);
558
559 /* Now that we are back to our own permissions, create ~/.ssh directory
560 if it doesn\'t already exist. */
561 snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR);
562 if (stat(buf, &st) < 0)
563 if (mkdir(buf, 0755) < 0)
564 error("Could not create directory '%.200s'.", buf);
565
566 /* Check if the connection failed, and try "rsh" if appropriate. */
567 if (!ok)
568 {
569 if (options.port != 0)
570 log("Secure connection to %.100s on port %d refused%.100s.",
571 host, options.port,
572 options.fallback_to_rsh ? "; reverting to insecure method" : "");
573 else
574 log("Secure connection to %.100s refused%.100s.", host,
575 options.fallback_to_rsh ? "; reverting to insecure method" : "");
576
577 if (options.fallback_to_rsh)
578 {
579 rsh_connect(host, options.user, &command);
580 fatal("rsh_connect returned");
581 }
582 exit(1);
583 }
584
585 /* Expand ~ in options.identity_files. */
586 for (i = 0; i < options.num_identity_files; i++)
587 options.identity_files[i] =
588 tilde_expand_filename(options.identity_files[i], original_real_uid);
589
590 /* Expand ~ in known host file names. */
591 options.system_hostfile = tilde_expand_filename(options.system_hostfile,
592 original_real_uid);
593 options.user_hostfile = tilde_expand_filename(options.user_hostfile,
594 original_real_uid);
595
596 /* Log into the remote system. This never returns if the login fails. */
597 ssh_login(host_private_key_loaded, host_private_key,
598 host, &hostaddr, &options, original_real_uid);
599
600 /* We no longer need the host private key. Clear it now. */
601 if (host_private_key_loaded)
602 RSA_free(host_private_key); /* Destroys contents safely */
603
604 /* Close connection cleanly after attack. */
605 cipher_attack_detected = packet_disconnect;
606
607 /* If requested, fork and let ssh continue in the background. */
608 if (fork_after_authentication_flag)
609 {
610 int ret = fork();
611 if (ret == -1)
612 fatal("fork failed: %.100s", strerror(errno));
613 if (ret != 0)
614 exit(0);
615 setsid();
616 }
617
618 /* Enable compression if requested. */
619 if (options.compression)
620 {
621 debug("Requesting compression at level %d.", options.compression_level);
622
623 if (options.compression_level < 1 || options.compression_level > 9)
624 fatal("Compression level must be from 1 (fast) to 9 (slow, best).");
625
626 /* Send the request. */
627 packet_start(SSH_CMSG_REQUEST_COMPRESSION);
628 packet_put_int(options.compression_level);
629 packet_send();
630 packet_write_wait();
631 type = packet_read(&plen);
632 if (type == SSH_SMSG_SUCCESS)
633 packet_start_compression(options.compression_level);
634 else if (type == SSH_SMSG_FAILURE)
635 log("Warning: Remote host refused compression.");
636 else
637 packet_disconnect("Protocol error waiting for compression response.");
638 }
639
640 /* Allocate a pseudo tty if appropriate. */
641 if (tty_flag)
642 {
643 debug("Requesting pty.");
644
645 /* Start the packet. */
646 packet_start(SSH_CMSG_REQUEST_PTY);
647
648 /* Store TERM in the packet. There is no limit on the length of the
649 string. */
650 cp = getenv("TERM");
651 if (!cp)
652 cp = "";
653 packet_put_string(cp, strlen(cp));
654
655 /* Store window size in the packet. */
656 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
657 memset(&ws, 0, sizeof(ws));
658 packet_put_int(ws.ws_row);
659 packet_put_int(ws.ws_col);
660 packet_put_int(ws.ws_xpixel);
661 packet_put_int(ws.ws_ypixel);
662
663 /* Store tty modes in the packet. */
664 tty_make_modes(fileno(stdin));
665
666 /* Send the packet, and wait for it to leave. */
667 packet_send();
668 packet_write_wait();
669
670 /* Read response from the server. */
671 type = packet_read(&plen);
672 if (type == SSH_SMSG_SUCCESS)
673 interactive = 1;
674 else if (type == SSH_SMSG_FAILURE)
675 log("Warning: Remote host failed or refused to allocate a pseudo tty.");
676 else
677 packet_disconnect("Protocol error waiting for pty request response.");
678 }
679
680 /* Request X11 forwarding if enabled and DISPLAY is set. */
681 if (options.forward_x11 && getenv("DISPLAY") != NULL)
682 {
683 char line[512], proto[512], data[512];
684 FILE *f;
685 int forwarded = 0, got_data = 0, i;
686
687#ifdef XAUTH_PATH
688 /* Try to get Xauthority information for the display. */
689 snprintf(line, sizeof line, "%.100s list %.200s 2>/dev/null",
690 XAUTH_PATH, getenv("DISPLAY"));
691 f = popen(line, "r");
692 if (f && fgets(line, sizeof(line), f) &&
693 sscanf(line, "%*s %s %s", proto, data) == 2)
694 got_data = 1;
695 if (f)
696 pclose(f);
697#endif /* XAUTH_PATH */
698 /* If we didn't get authentication data, just make up some data. The
699 forwarding code will check the validity of the response anyway, and
700 substitute this data. The X11 server, however, will ignore this
701 fake data and use whatever authentication mechanisms it was using
702 otherwise for the local connection. */
703 if (!got_data)
704 {
705 u_int32_t rand = 0;
706
707 strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto);
708 for (i = 0; i < 16; i++) {
709 if (i % 4 == 0)
710 rand = arc4random();
711 snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff);
712 rand >>= 8;
713 }
714 }
715
716 /* Got local authentication reasonable information. Request forwarding
717 with authentication spoofing. */
718 debug("Requesting X11 forwarding with authentication spoofing.");
719 x11_request_forwarding_with_spoofing(proto, data);
720
721 /* Read response from the server. */
722 type = packet_read(&plen);
723 if (type == SSH_SMSG_SUCCESS)
724 {
725 forwarded = 1;
726 interactive = 1;
727 }
728 else if (type == SSH_SMSG_FAILURE)
729 log("Warning: Remote host denied X11 forwarding.");
730 else
731 packet_disconnect("Protocol error waiting for X11 forwarding");
732 }
733
734 /* Tell the packet module whether this is an interactive session. */
735 packet_set_interactive(interactive, options.keepalives);
736
737 /* Clear agent forwarding if we don\'t have an agent. */
738 authfd = ssh_get_authentication_socket();
739 if (authfd < 0)
740 options.forward_agent = 0;
741 else
742 ssh_close_authentication_socket(authfd);
743
744 /* Request authentication agent forwarding if appropriate. */
745 if (options.forward_agent)
746 {
747 debug("Requesting authentication agent forwarding.");
748 auth_request_forwarding();
749
750 /* Read response from the server. */
751 type = packet_read(&plen);
752 packet_integrity_check(plen, 0, type);
753 if (type != SSH_SMSG_SUCCESS)
754 log("Warning: Remote host denied authentication agent forwarding.");
755 }
756
757 /* Initiate local TCP/IP port forwardings. */
758 for (i = 0; i < options.num_local_forwards; i++)
759 {
760 debug("Connections to local port %d forwarded to remote address %.200s:%d",
761 options.local_forwards[i].port, options.local_forwards[i].host,
762 options.local_forwards[i].host_port);
763 channel_request_local_forwarding(options.local_forwards[i].port,
764 options.local_forwards[i].host,
765 options.local_forwards[i].host_port);
766 }
767
768 /* Initiate remote TCP/IP port forwardings. */
769 for (i = 0; i < options.num_remote_forwards; i++)
770 {
771 debug("Connections to remote port %d forwarded to local address %.200s:%d",
772 options.remote_forwards[i].port, options.remote_forwards[i].host,
773 options.remote_forwards[i].host_port);
774 channel_request_remote_forwarding(options.remote_forwards[i].port,
775 options.remote_forwards[i].host,
776 options.remote_forwards[i].host_port);
777 }
778
779 /* If a command was specified on the command line, execute the command now.
780 Otherwise request the server to start a shell. */
781 if (buffer_len(&command) > 0)
782 {
783 int len = buffer_len(&command);
784 if (len > 900)
785 len = 900;
786 debug("Sending command: %.*s", len, buffer_ptr(&command));
787 packet_start(SSH_CMSG_EXEC_CMD);
788 packet_put_string(buffer_ptr(&command), buffer_len(&command));
789 packet_send();
790 packet_write_wait();
791 }
792 else
793 {
794 debug("Requesting shell.");
795 packet_start(SSH_CMSG_EXEC_SHELL);
796 packet_send();
797 packet_write_wait();
798 }
799
800 /* Enter the interactive session. */
801 exit_status = client_loop(tty_flag, tty_flag ? options.escape_char : -1);
802
803 /* Close the connection to the remote host. */
804 packet_close();
805
806 /* Exit with the status returned by the program on the remote side. */
807 exit(exit_status);
808}