]> andersk Git - gssapi-openssh.git/blobdiff - openssh/ssh.c
The man2html from jbasney on pkilab2 works whereas the standard one doesn't.
[gssapi-openssh.git] / openssh / ssh.c
index 35418f69335abe2c751bcdd36da4e2e48bb705e0..21f4c84e9bfb0a4cbd4267a3aacfdd4d489765fa 100644 (file)
@@ -1,3 +1,4 @@
+/* $OpenBSD: ssh.c,v 1.326 2009/07/02 02:11:47 dtucker Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -13,7 +14,7 @@
  * called by a name other than "ssh" or "Secure Shell".
  *
  * Copyright (c) 1999 Niels Provos.  All rights reserved.
- * Copyright (c) 2000, 2001, 2002 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2000, 2001, 2002, 2003 Markus Friedl.  All rights reserved.
  *
  * Modified to work with SSL by Niels Provos <provos@citi.umich.edu>
  * in Canada (German citizen).
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: ssh.c,v 1.201 2003/09/01 18:15:50 markus Exp $");
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#include <sys/resource.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include <openssl/evp.h>
 #include <openssl/err.h>
+#include "openbsd-compat/openssl-compat.h"
+#include "openbsd-compat/sys-queue.h"
 
+#include "xmalloc.h"
 #include "ssh.h"
 #include "ssh1.h"
 #include "ssh2.h"
 #include "compat.h"
 #include "cipher.h"
-#include "xmalloc.h"
 #include "packet.h"
 #include "buffer.h"
 #include "channels.h"
@@ -58,28 +88,27 @@ RCSID("$OpenBSD: ssh.c,v 1.201 2003/09/01 18:15:50 markus Exp $");
 #include "authfd.h"
 #include "authfile.h"
 #include "pathnames.h"
+#include "dispatch.h"
 #include "clientloop.h"
 #include "log.h"
 #include "readconf.h"
 #include "sshconnect.h"
-#include "tildexpand.h"
-#include "dispatch.h"
 #include "misc.h"
 #include "kex.h"
 #include "mac.h"
-#include "sshtty.h"
+#include "sshpty.h"
+#include "match.h"
+#include "msg.h"
+#include "uidswap.h"
+#include "version.h"
 
 #ifdef SMARTCARD
 #include "scard.h"
 #endif
 
-#ifdef HAVE___PROGNAME
 extern char *__progname;
-#else
-char *__progname;
-#endif
 
-/* Flag indicating whether debug mode is on.  This can be set on the command line. */
+/* Flag indicating whether debug mode is on.  May be set on the command line. */
 int debug_flag = 0;
 
 /* Flag indicating whether a tty should be allocated */
@@ -136,80 +165,57 @@ Buffer command;
 int subsystem_flag = 0;
 
 /* # of replies received for global requests */
-static int client_global_request_id = 0;
+static int remote_forward_confirms_received = 0;
 
 /* pid of proxycommand child process */
 pid_t proxy_command_pid = 0;
 
+/* mux.c */
+extern int muxserver_sock;
+extern u_int muxclient_command;
+
 /* Prints a help message to the user.  This function never returns. */
 
 static void
 usage(void)
 {
-       fprintf(stderr, "Usage: %s [options] host [command]\n", __progname);
-       fprintf(stderr, "Options:\n");
-       fprintf(stderr, "  -l user     Log in using this user name.\n");
-       fprintf(stderr, "  -n          Redirect input from " _PATH_DEVNULL ".\n");
-       fprintf(stderr, "  -F config   Config file (default: ~/%s).\n",
-            _PATH_SSH_USER_CONFFILE);
-       fprintf(stderr, "  -A          Enable authentication agent forwarding.\n");
-       fprintf(stderr, "  -a          Disable authentication agent forwarding (default).\n");
-       fprintf(stderr, "  -X          Enable X11 connection forwarding.\n");
-       fprintf(stderr, "  -x          Disable X11 connection forwarding (default).\n");
-       fprintf(stderr, "  -i file     Identity for public key authentication "
-           "(default: ~/.ssh/identity)\n");
-#ifdef SMARTCARD
-       fprintf(stderr, "  -I reader   Set smartcard reader.\n");
-#endif
-       fprintf(stderr, "  -t          Tty; allocate a tty even if command is given.\n");
-       fprintf(stderr, "  -T          Do not allocate a tty.\n");
-       fprintf(stderr, "  -v          Verbose; display verbose debugging messages.\n");
-       fprintf(stderr, "              Multiple -v increases verbosity.\n");
-       fprintf(stderr, "  -V          Display version number only.\n");
-       fprintf(stderr, "  -q          Quiet; don't display any warning messages.\n");
-       fprintf(stderr, "  -f          Fork into background after authentication.\n");
-       fprintf(stderr, "  -e char     Set escape character; ``none'' = disable (default: ~).\n");
-
-       fprintf(stderr, "  -c cipher   Select encryption algorithm\n");
-       fprintf(stderr, "  -m macs     Specify MAC algorithms for protocol version 2.\n");
-       fprintf(stderr, "  -p port     Connect to this port.  Server must be on the same port.\n");
-       fprintf(stderr, "  -L listen-port:host:port   Forward local port to remote address\n");
-       fprintf(stderr, "  -R listen-port:host:port   Forward remote port to local address\n");
-       fprintf(stderr, "              These cause %s to listen for connections on a port, and\n", __progname);
-       fprintf(stderr, "              forward them to the other side by connecting to host:port.\n");
-       fprintf(stderr, "  -D port     Enable dynamic application-level port forwarding.\n");
-       fprintf(stderr, "  -C          Enable compression.\n");
-       fprintf(stderr, "  -N          Do not execute a shell or command.\n");
-       fprintf(stderr, "  -g          Allow remote hosts to connect to forwarded ports.\n");
-       fprintf(stderr, "  -1          Force protocol version 1.\n");
-       fprintf(stderr, "  -2          Force protocol version 2.\n");
-       fprintf(stderr, "  -4          Use IPv4 only.\n");
-       fprintf(stderr, "  -6          Use IPv6 only.\n");
-       fprintf(stderr, "  -o 'option' Process the option as if it was read from a configuration file.\n");
-       fprintf(stderr, "  -s          Invoke command (mandatory) as SSH2 subsystem.\n");
-       fprintf(stderr, "  -b addr     Local IP address.\n");
-       exit(1);
+       fprintf(stderr,
+"usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n"
+"           [-D [bind_address:]port] [-e escape_char] [-F configfile]\n"
+"           [-i identity_file] [-L [bind_address:]port:host:hostport]\n"
+"           [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n"
+"           [-R [bind_address:]port:host:hostport] [-S ctl_path]\n"
+"           [-w local_tun[:remote_tun]] [user@]hostname [command]\n"
+       );
+       exit(255);
 }
 
 static int ssh_session(void);
 static int ssh_session2(void);
 static void load_public_identity_files(void);
 
+/* from muxclient.c */
+void muxclient(const char *);
+void muxserver_listen(void);
+
 /*
  * Main program for the ssh client.
  */
 int
 main(int ac, char **av)
 {
-       int i, opt, exit_status;
-       u_short fwd_port, fwd_host_port;
-       char sfwd_port[6], sfwd_host_port[6];
-       char *p, *cp, buf[256];
+       int i, r, opt, exit_status, use_syslog;
+       char *p, *cp, *line, *argv0, buf[MAXPATHLEN];
        struct stat st;
        struct passwd *pw;
-       int dummy;
+       int dummy, timeout_ms;
        extern int optind, optreset;
        extern char *optarg;
+       struct servent *sp;
+       Forward fwd;
+
+       /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+       sanitise_stdfd();
 
        __progname = ssh_get_progname(av[0]);
        init_rng();
@@ -220,7 +226,7 @@ main(int ac, char **av)
         */
        original_real_uid = getuid();
        original_effective_uid = geteuid();
+
        /*
         * Use uid-swapping to give up root privileges for the duration of
         * option processing.  We will re-instantiate the rights when we are
@@ -243,7 +249,7 @@ main(int ac, char **av)
        pw = getpwuid(original_real_uid);
        if (!pw) {
                logit("You don't exist, go away!");
-               exit(1);
+               exit(255);
        }
        /* Take a copy of the returned structure. */
        pw = pwcopy(pw);
@@ -256,15 +262,20 @@ main(int ac, char **av)
         */
        umask(022);
 
-       /* Initialize option structure to indicate that no values have been set. */
+       /*
+        * Initialize option structure to indicate that no values have been
+        * set.
+        */
        initialize_options(&options);
 
        /* Parse command-line arguments. */
        host = NULL;
+       use_syslog = 0;
+       argv0 = av[0];
 
-again:
-       while ((opt = getopt(ac, av,
-           "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVX")) != -1) {
+ again:
+       while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
+           "ACD:F:I:KL:MNO:PR:S:TVw:XYy")) != -1) {
                switch (opt) {
                case '1':
                        options.protocol = SSH_PROTO_1;
@@ -291,9 +302,24 @@ again:
                case 'X':
                        options.forward_x11 = 1;
                        break;
+               case 'y':
+                       use_syslog = 1;
+                       break;
+               case 'Y':
+                       options.forward_x11 = 1;
+                       options.forward_x11_trusted = 1;
+                       break;
                case 'g':
                        options.gateway_ports = 1;
                        break;
+               case 'O':
+                       if (strcmp(optarg, "check") == 0)
+                               muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK;
+                       else if (strcmp(optarg, "exit") == 0)
+                               muxclient_command = SSHMUX_COMMAND_TERMINATE;
+                       else
+                               fatal("Invalid multiplex command.");
+                       break;
                case 'P':       /* deprecated */
                        options.use_privileged_port = 0;
                        break;
@@ -304,12 +330,17 @@ again:
                        options.forward_agent = 1;
                        break;
                case 'k':
-                       /* ignored for backward compatibility */
+                       options.gss_deleg_creds = 0;
+                       break;
+               case 'K':
+                       options.gss_authentication = 1;
+                       options.gss_deleg_creds = 1;
                        break;
                case 'i':
                        if (stat(optarg, &st) < 0) {
                                fprintf(stderr, "Warning: Identity file %s "
-                                   "does not exist.\n", optarg);
+                                   "not accessible: %s.\n", optarg,
+                                   strerror(errno));
                                break;
                        }
                        if (options.num_identity_files >=
@@ -340,17 +371,23 @@ again:
                                        options.log_level++;
                                break;
                        }
-                       /* fallthrough */
+                       /* FALLTHROUGH */
                case 'V':
-                       fprintf(stderr,
-                           "%s, SSH protocols %d.%d/%d.%d, %s\n",
-                           SSH_VERSION,
-                           PROTOCOL_MAJOR_1, PROTOCOL_MINOR_1,
-                           PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2,
-                           SSLeay_version(SSLEAY_VERSION));
+                       fprintf(stderr, "%s, %s\n",
+                           SSH_RELEASE, SSLeay_version(SSLEAY_VERSION));
                        if (opt == 'V')
                                exit(0);
                        break;
+               case 'w':
+                       if (options.tun_open == -1)
+                               options.tun_open = SSH_TUNMODE_DEFAULT;
+                       options.tun_local = a2tun(optarg, &options.tun_remote);
+                       if (options.tun_local == SSH_TUNID_ERR) {
+                               fprintf(stderr,
+                                   "Bad tun device '%s'\n", optarg);
+                               exit(255);
+                       }
+                       break;
                case 'q':
                        options.log_level = SYSLOG_LEVEL_QUIET;
                        break;
@@ -366,14 +403,14 @@ again:
                        else {
                                fprintf(stderr, "Bad escape character '%s'.\n",
                                    optarg);
-                               exit(1);
+                               exit(255);
                        }
                        break;
                case 'c':
                        if (ciphers_valid(optarg)) {
                                /* SSH2 only */
                                options.ciphers = xstrdup(optarg);
-                               options.cipher = SSH_CIPHER_ILLEGAL;
+                               options.cipher = SSH_CIPHER_INVALID;
                        } else {
                                /* SSH1 only */
                                options.cipher = cipher_number(optarg);
@@ -381,7 +418,7 @@ again:
                                        fprintf(stderr,
                                            "Unknown cipher type '%s'\n",
                                            optarg);
-                                       exit(1);
+                                       exit(255);
                                }
                                if (options.cipher == SSH_CIPHER_3DES)
                                        options.ciphers = "3des-cbc";
@@ -397,14 +434,20 @@ again:
                        else {
                                fprintf(stderr, "Unknown mac type '%s'\n",
                                    optarg);
-                               exit(1);
+                               exit(255);
                        }
                        break;
+               case 'M':
+                       if (options.control_master == SSHCTL_MASTER_YES)
+                               options.control_master = SSHCTL_MASTER_ASK;
+                       else
+                               options.control_master = SSHCTL_MASTER_YES;
+                       break;
                case 'p':
                        options.port = a2port(optarg);
-                       if (options.port == 0) {
+                       if (options.port <= 0) {
                                fprintf(stderr, "Bad port '%s'\n", optarg);
-                               exit(1);
+                               exit(255);
                        }
                        break;
                case 'l':
@@ -412,39 +455,36 @@ again:
                        break;
 
                case 'L':
-               case 'R':
-                       if (sscanf(optarg, "%5[0123456789]:%255[^:]:%5[0123456789]",
-                           sfwd_port, buf, sfwd_host_port) != 3 &&
-                           sscanf(optarg, "%5[0123456789]/%255[^/]/%5[0123456789]",
-                           sfwd_port, buf, sfwd_host_port) != 3) {
+                       if (parse_forward(&fwd, optarg, 0, 0))
+                               add_local_forward(&options, &fwd);
+                       else {
                                fprintf(stderr,
-                                   "Bad forwarding specification '%s'\n",
+                                   "Bad local forwarding specification '%s'\n",
                                    optarg);
-                               usage();
-                               /* NOTREACHED */
+                               exit(255);
                        }
-                       if ((fwd_port = a2port(sfwd_port)) == 0 ||
-                           (fwd_host_port = a2port(sfwd_host_port)) == 0) {
+                       break;
+
+               case 'R':
+                       if (parse_forward(&fwd, optarg, 0, 1)) {
+                               add_remote_forward(&options, &fwd);
+                       } else {
                                fprintf(stderr,
-                                   "Bad forwarding port(s) '%s'\n", optarg);
-                               exit(1);
+                                   "Bad remote forwarding specification "
+                                   "'%s'\n", optarg);
+                               exit(255);
                        }
-                       if (opt == 'L')
-                               add_local_forward(&options, fwd_port, buf,
-                                   fwd_host_port);
-                       else if (opt == 'R')
-                               add_remote_forward(&options, fwd_port, buf,
-                                   fwd_host_port);
                        break;
 
                case 'D':
-                       fwd_port = a2port(optarg);
-                       if (fwd_port == 0) {
-                               fprintf(stderr, "Bad dynamic port '%s'\n",
-                                   optarg);
-                               exit(1);
+                       if (parse_forward(&fwd, optarg, 1, 0)) {
+                               add_local_forward(&options, &fwd);
+                       } else {
+                               fprintf(stderr,
+                                   "Bad dynamic forwarding specification "
+                                   "'%s'\n", optarg);
+                               exit(255);
                        }
-                       add_local_forward(&options, fwd_port, "socks", 0);
                        break;
 
                case 'C':
@@ -454,18 +494,29 @@ again:
                        no_shell_flag = 1;
                        no_tty_flag = 1;
                        break;
-               case 'T':
-                       no_tty_flag = 1;
-                       break;
                case 'o':
                        dummy = 1;
+                       line = xstrdup(optarg);
                        if (process_config_line(&options, host ? host : "",
-                           optarg, "command-line", 0, &dummy) != 0)
-                               exit(1);
+                           line, "command-line", 0, &dummy) != 0)
+                               exit(255);
+                       xfree(line);
+                       break;
+               case 'T':
+                       no_tty_flag = 1;
+                       /* ensure that the user doesn't try to backdoor a */
+                       /* null cipher switch on an interactive session */
+                       /* so explicitly disable it no matter what */
+                       options.none_switch=0;
                        break;
                case 's':
                        subsystem_flag = 1;
                        break;
+               case 'S':
+                       if (options.control_path != NULL)
+                               free(options.control_path);
+                       options.control_path = xstrdup(optarg);
+                       break;
                case 'b':
                        options.bind_address = optarg;
                        break;
@@ -531,8 +582,10 @@ again:
        }
 
        /* Cannot fork to background if no command. */
-       if (fork_after_authentication_flag && buffer_len(&command) == 0 && !no_shell_flag)
-               fatal("Cannot fork into background without a command to execute.");
+       if (fork_after_authentication_flag && buffer_len(&command) == 0 &&
+           !no_shell_flag)
+               fatal("Cannot fork into background without a command "
+                   "to execute.");
 
        /* Allocate a tty by default if no command specified. */
        if (buffer_len(&command) == 0)
@@ -542,9 +595,10 @@ again:
        if (no_tty_flag)
                tty_flag = 0;
        /* Do not allocate a tty if stdin is not a tty. */
-       if (!isatty(fileno(stdin)) && !force_tty_flag) {
+       if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) {
                if (tty_flag)
-                       logit("Pseudo-terminal will not be allocated because stdin is not a terminal.");
+                       logit("Pseudo-terminal will not be allocated because "
+                           "stdin is not a terminal.");
                tty_flag = 0;
        }
 
@@ -552,24 +606,53 @@ again:
         * Initialize "log" output.  Since we are the client all output
         * actually goes to stderr.
         */
-       log_init(av[0], options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
-           SYSLOG_FACILITY_USER, 1);
+       log_init(argv0,
+           options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
+           SYSLOG_FACILITY_USER, !use_syslog);
 
        /*
         * 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) {
-               if (!read_config_file(config, host, &options))
+               if (!read_config_file(config, host, &options, 0))
                        fatal("Can't open user config file %.100s: "
                            "%.100s", config, strerror(errno));
-       } else  {
-               snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir,
+       } else {
+           /*
+            * Since the config file parsing code aborts if it sees
+            * options it doesn't recognize, allow users to put
+            * options specific to compile-time add-ons in alternate
+            * config files so their primary config file will
+            * interoperate SSH versions that don't support those
+            * options.
+            */
+#ifdef GSSAPI
+               r = snprintf(buf, sizeof buf, "%s/%s.gssapi", pw->pw_dir,
+                   _PATH_SSH_USER_CONFFILE);
+               if (r > 0 && (size_t)r < sizeof(buf))
+                       (void)read_config_file(buf, host, &options, 1);
+#ifdef GSI
+               r = snprintf(buf, sizeof buf, "%s/%s.gsi", pw->pw_dir,
+                   _PATH_SSH_USER_CONFFILE);
+               if (r > 0 && (size_t)r < sizeof(buf))
+                       (void)read_config_file(buf, host, &options, 1);
+#endif
+#if defined(KRB5)
+               r = snprintf(buf, sizeof buf, "%s/%s.krb", pw->pw_dir,
+                   _PATH_SSH_USER_CONFFILE);
+               if (r > 0 && (size_t)r < sizeof(buf))
+                       (void)read_config_file(buf, host, &options, 1);
+#endif
+#endif
+               r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
                    _PATH_SSH_USER_CONFFILE);
-               (void)read_config_file(buf, host, &options);
+               if (r > 0 && (size_t)r < sizeof(buf))
+                       (void)read_config_file(buf, host, &options, 1);
 
                /* Read systemwide configuration file after use config. */
-               (void)read_config_file(_PATH_HOST_CONFIG_FILE, host, &options);
+               (void)read_config_file(_PATH_HOST_CONFIG_FILE, host,
+                   &options, 0);
        }
 
        /* Fill configuration defaults. */
@@ -578,12 +661,37 @@ again:
        channel_set_af(options.address_family);
 
        /* reinit */
-       log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 1);
+       log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog);
 
        seed_rng();
 
-       if (options.user == NULL)
+       if (options.user == NULL) {
                options.user = xstrdup(pw->pw_name);
+               options.implicit = 1;
+       }
+        else options.implicit = 0;
+
+       /* 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;
+       }
+
+       if (options.local_command != NULL) {
+               char thishost[NI_MAXHOST];
+
+               if (gethostname(thishost, sizeof(thishost)) == -1)
+                       fatal("gethostname: %s", strerror(errno));
+               snprintf(buf, sizeof(buf), "%d", options.port);
+               debug3("expanding LocalCommand: %s", options.local_command);
+               cp = options.local_command;
+               options.local_command = percent_expand(cp, "d", pw->pw_dir,
+                   "h", options.hostname? options.hostname : host,
+                    "l", thishost, "n", host, "r", options.user, "p", buf,
+                    "u", pw->pw_name, (char *)NULL);
+               debug3("expanded LocalCommand: %s", options.local_command);
+               xfree(cp);
+       }
 
        if (options.hostname != NULL)
                host = options.hostname;
@@ -592,23 +700,54 @@ again:
        if (options.host_key_alias != NULL) {
                for (p = options.host_key_alias; *p; p++)
                        if (isupper(*p))
-                               *p = tolower(*p);
+                               *p = (char)tolower(*p);
        }
 
        if (options.proxy_command != NULL &&
-           strcmp(options.proxy_command, "none") == 0)
+           strcmp(options.proxy_command, "none") == 0) {
+               xfree(options.proxy_command);
                options.proxy_command = NULL;
+       }
+       if (options.control_path != NULL &&
+           strcmp(options.control_path, "none") == 0) {
+               xfree(options.control_path);
+               options.control_path = NULL;
+       }
+
+       if (options.control_path != NULL) {
+               char thishost[NI_MAXHOST];
+
+               if (gethostname(thishost, sizeof(thishost)) == -1)
+                       fatal("gethostname: %s", strerror(errno));
+               snprintf(buf, sizeof(buf), "%d", options.port);
+               cp = tilde_expand_filename(options.control_path,
+                   original_real_uid);
+               xfree(options.control_path);
+               options.control_path = percent_expand(cp, "p", buf, "h", host,
+                   "r", options.user, "l", thishost, (char *)NULL);
+               xfree(cp);
+       }
+       if (muxclient_command != 0 && options.control_path == NULL)
+               fatal("No ControlPath specified for \"-O\" command");
+       if (options.control_path != NULL)
+               muxclient(options.control_path);
+
+       timeout_ms = options.connection_timeout * 1000;
 
        /* Open a connection to the remote host. */
        if (ssh_connect(host, &hostaddr, options.port,
-           options.address_family, options.connection_attempts,
+           options.address_family, options.connection_attempts, &timeout_ms,
+           options.tcp_keep_alive, 
 #ifdef HAVE_CYGWIN
            options.use_privileged_port,
 #else
            original_effective_uid == 0 && options.use_privileged_port,
 #endif
            options.proxy_command) != 0)
-               exit(1);
+               exit(255);
+
+       if (timeout_ms > 0)
+               debug3("timeout: %d ms remain after connect", timeout_ms);
 
        /*
         * If we successfully made the connection, load the host private key
@@ -624,16 +763,16 @@ again:
        if (options.rhosts_rsa_authentication ||
            options.hostbased_authentication) {
                sensitive_data.nkeys = 3;
-               sensitive_data.keys = xmalloc(sensitive_data.nkeys *
+               sensitive_data.keys = xcalloc(sensitive_data.nkeys,
                    sizeof(Key));
 
                PRIV_START;
                sensitive_data.keys[0] = key_load_private_type(KEY_RSA1,
-                   _PATH_HOST_KEY_FILE, "", NULL);
+                   _PATH_HOST_KEY_FILE, "", NULL, NULL);
                sensitive_data.keys[1] = key_load_private_type(KEY_DSA,
-                   _PATH_HOST_DSA_KEY_FILE, "", NULL);
+                   _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL);
                sensitive_data.keys[2] = key_load_private_type(KEY_RSA,
-                   _PATH_HOST_RSA_KEY_FILE, "", NULL);
+                   _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL);
                PRIV_END;
 
                if (options.hostbased_authentication == 1 &&
@@ -654,15 +793,18 @@ again:
         * user's home directory if it happens to be on a NFS volume where
         * root is mapped to nobody.
         */
-       seteuid(original_real_uid);
-       setuid(original_real_uid);
+       if (original_effective_uid == 0) {
+               PRIV_START;
+               permanently_set_uid(pw);
+       }
 
        /*
         * Now that we are back to our own permissions, create ~/.ssh
-        * directory if it doesn\'t already exist.
+        * directory if it doesn't already exist.
         */
-       snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
-       if (stat(buf, &st) < 0)
+       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)
                if (mkdir(buf, 0700) < 0)
                        error("Could not create directory '%.200s'.", buf);
 
@@ -682,8 +824,9 @@ again:
 
        signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */
 
-       /* Log into the remote system.  This never returns if the login fails. */
-       ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, pw);
+       /* Log into the remote system.  Never returns if the login fails. */
+       ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr,
+           pw, timeout_ms);
 
        /* We no longer need the private host keys.  Clear them now. */
        if (sensitive_data.nkeys != 0) {
@@ -711,8 +854,11 @@ again:
        exit_status = compat20 ? ssh_session2() : ssh_session();
        packet_close();
 
+       if (options.control_path != NULL && muxserver_sock != -1)
+               unlink(options.control_path);
+
        /*
-        * Send SIGHUP to proxy command if used. We don't wait() in 
+        * Send SIGHUP to proxy command if used. We don't wait() in
         * case it hangs and instead rely on init to reap the child
         */
        if (proxy_command_pid > 1)
@@ -721,67 +867,37 @@ again:
        return exit_status;
 }
 
+/* Callback for remote forward global requests */
 static void
-x11_get_proto(char **_proto, char **_data)
+ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
 {
-       char line[512];
-       static char proto[512], data[512];
-       FILE *f;
-       int got_data = 0, i;
-       char *display;
-       struct stat st;
+       Forward *rfwd = (Forward *)ctxt;
 
-       *_proto = proto;
-       *_data = data;
-       proto[0] = data[0] = '\0';
-       if (!options.xauth_location ||
-           (stat(options.xauth_location, &st) == -1)) {
-               debug("No xauth program.");
-       } else {
-               if ((display = getenv("DISPLAY")) == NULL) {
-                       debug("x11_get_proto: DISPLAY not set");
-                       return;
-               }
-               /* Try to get Xauthority information for the display. */
-               if (strncmp(display, "localhost:", 10) == 0)
-                       /*
-                        * Handle FamilyLocal case where $DISPLAY does
-                        * not match an authorization entry.  For this we
-                        * just try "xauth list unix:displaynum.screennum".
-                        * XXX: "localhost" match to determine FamilyLocal
-                        *      is not perfect.
-                        */
-                       snprintf(line, sizeof line, "%s list unix:%s 2>"
-                           _PATH_DEVNULL, options.xauth_location, display+10);
+       /* XXX verbose() on failure? */
+       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);
+       if (type == SSH2_MSG_REQUEST_SUCCESS && rfwd->listen_port == 0) {
+               logit("Allocated port %u for remote forward to %s:%d",
+                       packet_get_int(),
+                       rfwd->connect_host, rfwd->connect_port);
+       }
+       
+       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
-                       snprintf(line, sizeof line, "%s list %.200s 2>"
-                           _PATH_DEVNULL, options.xauth_location, display);
-               debug2("x11_get_proto: %s", line);
-               f = popen(line, "r");
-               if (f && fgets(line, sizeof(line), f) &&
-                   sscanf(line, "%*s %511s %511s", proto, data) == 2)
-                       got_data = 1;
-               if (f)
-                       pclose(f);
+                       logit("Warning: remote port forwarding failed for "
+                           "listen port %d", rfwd->listen_port);
        }
-       /*
-        * If we didn't get authentication data, just make up some
-        * data.  The forwarding code will check the validity of the
-        * response anyway, and substitute this data.  The X11
-        * server, however, will ignore this fake data and use
-        * whatever authentication mechanisms it was using otherwise
-        * for the local connection.
-        */
-       if (!got_data) {
-               u_int32_t rand = 0;
-
-               logit("Warning: No xauth data; using fake authentication data for X11 forwarding.");
-               strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto);
-               for (i = 0; i < 16; i++) {
-                       if (i % 4 == 0)
-                               rand = arc4random();
-                       snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff);
-                       rand >>= 8;
+       if (++remote_forward_confirms_received == options.num_remote_forwards) {
+               debug("All remote forwarding requests processed");
+               if (fork_after_authentication_flag) {
+                       fork_after_authentication_flag = 0;
+                       if (daemon(1, 1) < 0)
+                               fatal("daemon() failed: %.200s",
+                                   strerror(errno));
                }
        }
 }
@@ -794,37 +910,67 @@ ssh_init_forwarding(void)
 
        /* Initiate local TCP/IP port forwardings. */
        for (i = 0; i < options.num_local_forwards; i++) {
-               debug("Connections to local port %d forwarded to remote address %.200s:%d",
-                   options.local_forwards[i].port,
-                   options.local_forwards[i].host,
-                   options.local_forwards[i].host_port);
+               debug("Local connections to %.200s:%d forwarded to remote "
+                   "address %.200s:%d",
+                   (options.local_forwards[i].listen_host == NULL) ?
+                   (options.gateway_ports ? "*" : "LOCALHOST") :
+                   options.local_forwards[i].listen_host,
+                   options.local_forwards[i].listen_port,
+                   options.local_forwards[i].connect_host,
+                   options.local_forwards[i].connect_port);
                success += channel_setup_local_fwd_listener(
-                   options.local_forwards[i].port,
-                   options.local_forwards[i].host,
-                   options.local_forwards[i].host_port,
+                   options.local_forwards[i].listen_host,
+                   options.local_forwards[i].listen_port,
+                   options.local_forwards[i].connect_host,
+                   options.local_forwards[i].connect_port,
                    options.gateway_ports);
        }
+       if (i > 0 && success != i && options.exit_on_forward_failure)
+               fatal("Could not request local forwarding.");
        if (i > 0 && success == 0)
                error("Could not request local forwarding.");
 
        /* Initiate remote TCP/IP port forwardings. */
        for (i = 0; i < options.num_remote_forwards; i++) {
-               debug("Connections to remote port %d forwarded to local address %.200s:%d",
-                   options.remote_forwards[i].port,
-                   options.remote_forwards[i].host,
-                   options.remote_forwards[i].host_port);
-               channel_request_remote_forwarding(
-                   options.remote_forwards[i].port,
-                   options.remote_forwards[i].host,
-                   options.remote_forwards[i].host_port);
+               debug("Remote connections from %.200s:%d forwarded to "
+                   "local address %.200s:%d",
+                   (options.remote_forwards[i].listen_host == NULL) ?
+                   "LOCALHOST" : options.remote_forwards[i].listen_host,
+                   options.remote_forwards[i].listen_port,
+                   options.remote_forwards[i].connect_host,
+                   options.remote_forwards[i].connect_port);
+               if (channel_request_remote_forwarding(
+                   options.remote_forwards[i].listen_host,
+                   options.remote_forwards[i].listen_port,
+                   options.remote_forwards[i].connect_host,
+                   options.remote_forwards[i].connect_port) < 0) {
+                       if (options.exit_on_forward_failure)
+                               fatal("Could not request remote forwarding.");
+                       else
+                               logit("Warning: Could not request remote "
+                                   "forwarding.");
+               }
+               client_register_global_confirm(ssh_confirm_remote_forward,
+                   &options.remote_forwards[i]);
        }
+
+       /* Initiate tunnel forwarding. */
+       if (options.tun_open != SSH_TUNMODE_NO) {
+               if (client_request_tun_fwd(options.tun_open,
+                   options.tun_local, options.tun_remote) == -1) {
+                       if (options.exit_on_forward_failure)
+                               fatal("Could not request tunnel forwarding.");
+                       else
+                               error("Could not request tunnel forwarding.");
+               }
+       }                       
 }
 
 static void
 check_agent_present(void)
 {
        if (options.forward_agent) {
-               /* Clear agent forwarding if we don\'t have an agent. */
+               /* Clear agent forwarding if we don't have an agent. */
                if (!ssh_agent_present())
                        options.forward_agent = 0;
        }
@@ -838,13 +984,17 @@ ssh_session(void)
        int have_tty = 0;
        struct winsize ws;
        char *cp;
+       const char *display;
 
        /* Enable compression if requested. */
        if (options.compression) {
-               debug("Requesting compression at level %d.", options.compression_level);
+               debug("Requesting compression at level %d.",
+                   options.compression_level);
 
-               if (options.compression_level < 1 || options.compression_level > 9)
-                       fatal("Compression level must be from 1 (fast) to 9 (slow, best).");
+               if (options.compression_level < 1 ||
+                   options.compression_level > 9)
+                       fatal("Compression level must be from 1 (fast) to "
+                           "9 (slow, best).");
 
                /* Send the request. */
                packet_start(SSH_CMSG_REQUEST_COMPRESSION);
@@ -857,7 +1007,8 @@ ssh_session(void)
                else if (type == SSH_SMSG_FAILURE)
                        logit("Warning: Remote host refused compression.");
                else
-                       packet_disconnect("Protocol error waiting for compression response.");
+                       packet_disconnect("Protocol error waiting for "
+                           "compression response.");
        }
        /* Allocate a pseudo tty if appropriate. */
        if (tty_flag) {
@@ -876,10 +1027,10 @@ ssh_session(void)
                /* Store window size in the packet. */
                if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
                        memset(&ws, 0, sizeof(ws));
-               packet_put_int(ws.ws_row);
-               packet_put_int(ws.ws_col);
-               packet_put_int(ws.ws_xpixel);
-               packet_put_int(ws.ws_ypixel);
+               packet_put_int((u_int)ws.ws_row);
+               packet_put_int((u_int)ws.ws_col);
+               packet_put_int((u_int)ws.ws_xpixel);
+               packet_put_int((u_int)ws.ws_ypixel);
 
                /* Store tty modes in the packet. */
                tty_make_modes(fileno(stdin), NULL);
@@ -894,18 +1045,23 @@ ssh_session(void)
                        interactive = 1;
                        have_tty = 1;
                } else if (type == SSH_SMSG_FAILURE)
-                       logit("Warning: Remote host failed or refused to allocate a pseudo tty.");
+                       logit("Warning: Remote host failed or refused to "
+                           "allocate a pseudo tty.");
                else
-                       packet_disconnect("Protocol error waiting for pty request response.");
+                       packet_disconnect("Protocol error waiting for pty "
+                           "request response.");
        }
        /* Request X11 forwarding if enabled and DISPLAY is set. */
-       if (options.forward_x11 && getenv("DISPLAY") != NULL) {
+       display = getenv("DISPLAY");
+       if (options.forward_x11 && display != NULL) {
                char *proto, *data;
                /* Get reasonable local authentication information. */
-               x11_get_proto(&proto, &data);
+               client_x11_get_proto(display, options.xauth_location,
+                   options.forward_x11_trusted, &proto, &data);
                /* Request forwarding with authentication spoofing. */
-               debug("Requesting X11 forwarding with authentication spoofing.");
-               x11_request_forwarding_with_spoofing(0, proto, data);
+               debug("Requesting X11 forwarding with authentication "
+                   "spoofing.");
+               x11_request_forwarding_with_spoofing(0, display, proto, data);
 
                /* Read response from the server. */
                type = packet_read();
@@ -914,7 +1070,8 @@ ssh_session(void)
                } else if (type == SSH_SMSG_FAILURE) {
                        logit("Warning: Remote host denied X11 forwarding.");
                } else {
-                       packet_disconnect("Protocol error waiting for X11 forwarding");
+                       packet_disconnect("Protocol error waiting for X11 "
+                           "forwarding");
                }
        }
        /* Tell the packet module whether this is an interactive session. */
@@ -937,10 +1094,22 @@ ssh_session(void)
        /* Initiate port forwardings. */
        ssh_init_forwarding();
 
-       /* If requested, let ssh continue in the background. */
-       if (fork_after_authentication_flag)
+       /* Execute a local command */
+       if (options.local_command != NULL &&
+           options.permit_local_command)
+               ssh_local_cmd(options.local_command);
+
+       /*
+        * If requested and we are not interested in replies to remote
+        * forwarding requests, then let ssh continue in the background.
+        */
+       if (fork_after_authentication_flag &&
+           (!options.exit_on_forward_failure ||
+           options.num_remote_forwards == 0)) {
+               fork_after_authentication_flag = 0;
                if (daemon(1, 1) < 0)
                        fatal("daemon() failed: %.200s", strerror(errno));
+       }
 
        /*
         * If a command was specified on the command line, execute the
@@ -950,7 +1119,8 @@ ssh_session(void)
                int len = buffer_len(&command);
                if (len > 900)
                        len = 900;
-               debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command));
+               debug("Sending command: %.*s", len,
+                   (u_char *)buffer_ptr(&command));
                packet_start(SSH_CMSG_EXEC_CMD);
                packet_put_string(buffer_ptr(&command), buffer_len(&command));
                packet_send();
@@ -967,82 +1137,24 @@ ssh_session(void)
            options.escape_char : SSH_ESCAPECHAR_NONE, 0);
 }
 
-static void
-client_subsystem_reply(int type, u_int32_t seq, void *ctxt)
-{
-       int id, len;
-
-       id = packet_get_int();
-       len = buffer_len(&command);
-       if (len > 900)
-               len = 900;
-       packet_check_eom();
-       if (type == SSH2_MSG_CHANNEL_FAILURE)
-               fatal("Request for subsystem '%.*s' failed on channel %d",
-                   len, (u_char *)buffer_ptr(&command), id);
-}
-
-void
-client_global_request_reply(int type, u_int32_t seq, void *ctxt)
-{
-       int i;
-
-       i = client_global_request_id++;
-       if (i >= options.num_remote_forwards) {
-               debug("client_global_request_reply: too many replies %d > %d",
-                   i, options.num_remote_forwards);
-               return;
-       }
-       debug("remote forward %s for: listen %d, connect %s:%d",
-           type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
-           options.remote_forwards[i].port,
-           options.remote_forwards[i].host,
-           options.remote_forwards[i].host_port);
-       if (type == SSH2_MSG_REQUEST_FAILURE)
-               logit("Warning: remote port forwarding failed for listen port %d",
-                   options.remote_forwards[i].port);
-}
-
 /* request pty/x11/agent/tcpfwd/shell for channel */
 static void
 ssh_session2_setup(int id, void *arg)
 {
-       int len;
-       int interactive = 0;
-       struct termios tio;
-
-       debug2("ssh_session2_setup: id %d", id);
-
-       if (tty_flag) {
-               struct winsize ws;
-               char *cp;
-               cp = getenv("TERM");
-               if (!cp)
-                       cp = "";
-               /* Store window size in the packet. */
-               if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
-                       memset(&ws, 0, sizeof(ws));
+       extern char **environ;
+       const char *display;
+       int interactive = tty_flag;
 
-               channel_request_start(id, "pty-req", 0);
-               packet_put_cstring(cp);
-               packet_put_int(ws.ws_col);
-               packet_put_int(ws.ws_row);
-               packet_put_int(ws.ws_xpixel);
-               packet_put_int(ws.ws_ypixel);
-               tio = get_saved_tio();
-               tty_make_modes(/*ignored*/ 0, &tio);
-               packet_send();
-               interactive = 1;
-               /* XXX wait for reply */
-       }
-       if (options.forward_x11 &&
-           getenv("DISPLAY") != NULL) {
+       display = getenv("DISPLAY");
+       if (options.forward_x11 && display != NULL) {
                char *proto, *data;
                /* Get reasonable local authentication information. */
-               x11_get_proto(&proto, &data);
+               client_x11_get_proto(display, options.xauth_location,
+                   options.forward_x11_trusted, &proto, &data);
                /* Request forwarding with authentication spoofing. */
-               debug("Requesting X11 forwarding with authentication spoofing.");
-               x11_request_forwarding_with_spoofing(id, proto, data);
+               debug("Requesting X11 forwarding with authentication "
+                   "spoofing.");
+               x11_request_forwarding_with_spoofing(id, display, proto, data);
                interactive = 1;
                /* XXX wait for reply */
        }
@@ -1054,27 +1166,8 @@ ssh_session2_setup(int id, void *arg)
                packet_send();
        }
 
-       len = buffer_len(&command);
-       if (len > 0) {
-               if (len > 900)
-                       len = 900;
-               if (subsystem_flag) {
-                       debug("Sending subsystem: %.*s", len, (u_char *)buffer_ptr(&command));
-                       channel_request_start(id, "subsystem", /*want reply*/ 1);
-                       /* register callback for reply */
-                       /* XXX we assume that client_loop has already been called */
-                       dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &client_subsystem_reply);
-                       dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &client_subsystem_reply);
-               } else {
-                       debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command));
-                       channel_request_start(id, "exec", 0);
-               }
-               packet_put_string(buffer_ptr(&command), buffer_len(&command));
-               packet_send();
-       } else {
-               channel_request_start(id, "shell", 0);
-               packet_send();
-       }
+       client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),
+           NULL, fileno(stdin), &command, environ);
 
        packet_set_interactive(interactive);
 }
@@ -1085,6 +1178,9 @@ ssh_session2_open(void)
 {
        Channel *c;
        int window, packetmax, in, out, err;
+       int sock;
+       int socksize;
+       int socksizelen = sizeof(int);
 
        if (stdin_null_flag) {
                in = open(_PATH_DEVNULL, O_RDONLY);
@@ -1105,9 +1201,75 @@ ssh_session2_open(void)
        if (!isatty(err))
                set_nonblock(err);
 
-       window = CHAN_SES_WINDOW_DEFAULT;
+       /* we need to check to see if what they want to do about buffer */
+       /* sizes here. In a hpn to nonhpn connection we want to limit */
+       /* the window size to something reasonable in case the far side */
+       /* has the large window bug. In hpn to hpn connection we want to */
+       /* use the max window size but allow the user to override it */
+       /* lastly if they disabled hpn then use the ssh std window size */
+
+       /* so why don't we just do a getsockopt() here and set the */
+       /* ssh window to that? In the case of a autotuning receive */
+       /* window the window would get stuck at the initial buffer */
+       /* size generally less than 96k. Therefore we need to set the */
+       /* maximum ssh window size to the maximum hpn buffer size */
+       /* unless the user has specifically set the tcprcvbufpoll */
+       /* to no. In which case we *can* just set the window to the */
+       /* minimum of the hpn buffer size and tcp receive buffer size */
+       
+       if (tty_flag)
+               options.hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT;
+       else
+               options.hpn_buffer_size = 2*1024*1024;
+
+       if (datafellows & SSH_BUG_LARGEWINDOW) 
+       {
+               debug("HPN to Non-HPN Connection");
+       } 
+       else 
+       {
+               if (options.tcp_rcv_buf_poll <= 0) 
+               {
+                       sock = socket(AF_INET, SOCK_STREAM, 0);
+                       getsockopt(sock, SOL_SOCKET, SO_RCVBUF, 
+                                  &socksize, &socksizelen);
+                       close(sock);
+                       debug("socksize %d", socksize);
+                       options.hpn_buffer_size = socksize;
+                       debug ("HPNBufferSize set to TCP RWIN: %d", options.hpn_buffer_size);
+               } 
+               else
+               {
+                       if (options.tcp_rcv_buf > 0) 
+                       {
+                               /*create a socket but don't connect it */
+                               /* we use that the get the rcv socket size */
+                               sock = socket(AF_INET, SOCK_STREAM, 0);
+                               /* if they are using the tcp_rcv_buf option */
+                               /* attempt to set the buffer size to that */
+                               if (options.tcp_rcv_buf) 
+                                       setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&options.tcp_rcv_buf, 
+                                                  sizeof(options.tcp_rcv_buf));
+                               getsockopt(sock, SOL_SOCKET, SO_RCVBUF, 
+                                          &socksize, &socksizelen);
+                               close(sock);
+                               debug("socksize %d", socksize);
+                               options.hpn_buffer_size = socksize;
+                               debug ("HPNBufferSize set to user TCPRcvBuf: %d", options.hpn_buffer_size);
+                       }
+               }
+               
+       }
+
+       debug("Final hpn_buffer_size = %d", options.hpn_buffer_size);
+
+       window = options.hpn_buffer_size;
+
+       channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size);
+
        packetmax = CHAN_SES_PACKET_DEFAULT;
        if (tty_flag) {
+               window = 4*CHAN_SES_PACKET_DEFAULT;
                window >>= 1;
                packetmax >>= 1;
        }
@@ -1115,12 +1277,16 @@ ssh_session2_open(void)
            "session", SSH_CHANNEL_OPENING, in, out, err,
            window, packetmax, CHAN_EXTENDED_WRITE,
            "client-session", /*nonblock*/0);
-
+       if ((options.tcp_rcv_buf_poll > 0) && (!options.hpn_disabled)) {
+               c->dynamic_window = 1;
+               debug ("Enabled Dynamic Window Scaling\n");
+       }
        debug3("ssh_session2_open: channel_new: %d", c->self);
 
        channel_send_open(c->self);
        if (!no_shell_flag)
-               channel_register_confirm(c->self, ssh_session2_setup);
+               channel_register_open_confirm(c->self,
+                   ssh_session2_setup, NULL);
 
        return c->self;
 }
@@ -1136,10 +1302,30 @@ ssh_session2(void)
        if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
                id = ssh_session2_open();
 
+       /* If we don't expect to open a new session, then disallow it */
+       if (options.control_master == SSHCTL_MASTER_NO &&
+           (datafellows & SSH_NEW_OPENSSH)) {
+               debug("Requesting no-more-sessions@openssh.com");
+               packet_start(SSH2_MSG_GLOBAL_REQUEST);
+               packet_put_cstring("no-more-sessions@openssh.com");
+               packet_put_char(0);
+               packet_send();
+       }
+
+       /* Execute a local command */
+       if (options.local_command != NULL &&
+           options.permit_local_command)
+               ssh_local_cmd(options.local_command);
+
+       /* Start listening for multiplex clients */
+       muxserver_listen();
+
        /* If requested, let ssh continue in the background. */
-       if (fork_after_authentication_flag)
+       if (fork_after_authentication_flag) {
+               fork_after_authentication_flag = 0;
                if (daemon(1, 1) < 0)
                        fatal("daemon() failed: %.200s", strerror(errno));
+       }
 
        return client_loop(tty_flag, tty_flag ?
            options.escape_char : SSH_ESCAPECHAR_NONE, id);
@@ -1148,21 +1334,25 @@ ssh_session2(void)
 static void
 load_public_identity_files(void)
 {
-       char *filename;
+       char *filename, *cp, thishost[NI_MAXHOST];
+       char *pwdir = NULL, *pwname = NULL;
        int i = 0;
        Key *public;
+       struct passwd *pw;
 #ifdef SMARTCARD
        Key **keys;
 
        if (options.smartcard_device != NULL &&
            options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
-           (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL ) {
+           (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL) {
                int count = 0;
                for (i = 0; keys[i] != NULL; i++) {
                        count++;
-                       memmove(&options.identity_files[1], &options.identity_files[0],
+                       memmove(&options.identity_files[1],
+                           &options.identity_files[0],
                            sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1));
-                       memmove(&options.identity_keys[1], &options.identity_keys[0],
+                       memmove(&options.identity_keys[1],
+                           &options.identity_keys[0],
                            sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1));
                        options.num_identity_files++;
                        options.identity_keys[0] = keys[i];
@@ -1174,9 +1364,20 @@ load_public_identity_files(void)
                xfree(keys);
        }
 #endif /* SMARTCARD */
+       if ((pw = getpwuid(original_real_uid)) == NULL)
+               fatal("load_public_identity_files: getpwuid failed");
+       pwname = xstrdup(pw->pw_name);
+       pwdir = xstrdup(pw->pw_dir);
+       if (gethostname(thishost, sizeof(thishost)) == -1)
+               fatal("load_public_identity_files: gethostname: %s",
+                   strerror(errno));
        for (; i < options.num_identity_files; i++) {
-               filename = tilde_expand_filename(options.identity_files[i],
+               cp = tilde_expand_filename(options.identity_files[i],
                    original_real_uid);
+               filename = percent_expand(cp, "d", pwdir,
+                   "u", pwname, "l", thishost, "h", host,
+                   "r", options.user, (char *)NULL);
+               xfree(cp);
                public = key_load_public(filename, NULL);
                debug("identity file %s type %d", filename,
                    public ? public->type : -1);
@@ -1184,4 +1385,8 @@ load_public_identity_files(void)
                options.identity_files[i] = filename;
                options.identity_keys[i] = public;
        }
+       bzero(pwname, strlen(pwname));
+       xfree(pwname);
+       bzero(pwdir, strlen(pwdir));
+       xfree(pwdir);
 }
This page took 0.119093 seconds and 4 git commands to generate.