]> andersk Git - openssh.git/blobdiff - ssh.c
- djm@cvs.openbsd.org 2010/01/30 02:54:53
[openssh.git] / ssh.c
diff --git a/ssh.c b/ssh.c
index 96bfed9d50a94d6f2170d7fed8bd7fef4bc44e82..97afdcfeeb2144f2b8108493ff06b386345db7f2 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.316 2008/06/12 04:24:06 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.332 2010/01/26 01:28:35 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -48,6 +48,7 @@
 #endif
 #include <sys/resource.h>
 #include <sys/ioctl.h>
+#include <sys/param.h>
 #include <sys/socket.h>
 
 #include <ctype.h>
 #include "match.h"
 #include "msg.h"
 #include "uidswap.h"
+#include "roaming.h"
 #include "version.h"
 
 #ifdef SMARTCARD
@@ -131,6 +133,10 @@ int stdin_null_flag = 0;
  */
 int fork_after_authentication_flag = 0;
 
+/* forward stdio to remote host and port */
+char *stdio_forward_host = NULL;
+int stdio_forward_port = 0;
+
 /*
  * General data structure for command line options and options configurable
  * in configuration files.  See readconf.h.
@@ -179,12 +185,13 @@ static void
 usage(void)
 {
        fprintf(stderr,
-"usage: ssh [-1246AaCfgKkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec]\n"
+"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"
+"           [-W host:port] [-w local_tun[:remote_tun]]\n"
+"           [user@]hostname [command]\n"
        );
        exit(255);
 }
@@ -203,8 +210,8 @@ void muxserver_listen(void);
 int
 main(int ac, char **av)
 {
-       int i, opt, exit_status;
-       char *p, *cp, *line, 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, timeout_ms;
@@ -269,10 +276,12 @@ main(int ac, char **av)
 
        /* 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:qstvx"
-           "ACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) {
+           "ACD:F:I:KL:MNO:PR:S:TVw:W:XYy")) != -1) {
                switch (opt) {
                case '1':
                        options.protocol = SSH_PROTO_1;
@@ -299,6 +308,9 @@ main(int ac, char **av)
                case 'X':
                        options.forward_x11 = 1;
                        break;
+               case 'y':
+                       use_syslog = 1;
+                       break;
                case 'Y':
                        options.forward_x11 = 1;
                        options.forward_x11_trusted = 1;
@@ -307,6 +319,11 @@ main(int ac, char **av)
                        options.gateway_ports = 1;
                        break;
                case 'O':
+                       if (stdio_forward_host != NULL)
+                               fatal("Cannot specify multiplexing "
+                                   "command with -W");
+                       else if (muxclient_command != 0)
+                               fatal("Multiplexing command already specified");
                        if (strcmp(optarg, "check") == 0)
                                muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK;
                        else if (strcmp(optarg, "exit") == 0)
@@ -382,6 +399,26 @@ main(int ac, char **av)
                                exit(255);
                        }
                        break;
+               case 'W':
+                       if (stdio_forward_host != NULL)
+                               fatal("stdio forward already specified");
+                       if (muxclient_command != 0)
+                               fatal("Cannot specify stdio forward with -O");
+                       if (parse_forward(&fwd, optarg, 1, 0)) {
+                               stdio_forward_host = fwd.listen_host;
+                               stdio_forward_port = fwd.listen_port;
+                               xfree(fwd.connect_host);
+                       } else {
+                               fprintf(stderr,
+                                   "Bad stdio forwarding specification '%s'\n",
+                                   optarg);
+                               exit(255);
+                       }
+                       no_tty_flag = 1;
+                       no_shell_flag = 1;
+                       options.clear_forwardings = 1;
+                       options.exit_on_forward_failure = 1;
+                       break;
                case 'q':
                        options.log_level = SYSLOG_LEVEL_QUIET;
                        break;
@@ -439,7 +476,7 @@ main(int ac, char **av)
                        break;
                case 'p':
                        options.port = a2port(optarg);
-                       if (options.port == 0) {
+                       if (options.port <= 0) {
                                fprintf(stderr, "Bad port '%s'\n", optarg);
                                exit(255);
                        }
@@ -449,7 +486,7 @@ main(int ac, char **av)
                        break;
 
                case 'L':
-                       if (parse_forward(&fwd, optarg))
+                       if (parse_forward(&fwd, optarg, 0, 0))
                                add_local_forward(&options, &fwd);
                        else {
                                fprintf(stderr,
@@ -460,7 +497,7 @@ main(int ac, char **av)
                        break;
 
                case 'R':
-                       if (parse_forward(&fwd, optarg)) {
+                       if (parse_forward(&fwd, optarg, 0, 1)) {
                                add_remote_forward(&options, &fwd);
                        } else {
                                fprintf(stderr,
@@ -471,30 +508,14 @@ main(int ac, char **av)
                        break;
 
                case 'D':
-                       cp = p = xstrdup(optarg);
-                       memset(&fwd, '\0', sizeof(fwd));
-                       fwd.connect_host = "socks";
-                       if ((fwd.listen_host = hpdelim(&cp)) == NULL) {
-                               fprintf(stderr, "Bad dynamic forwarding "
-                                   "specification '%.100s'\n", optarg);
-                               exit(255);
-                       }
-                       if (cp != NULL) {
-                               fwd.listen_port = a2port(cp);
-                               fwd.listen_host =
-                                   cleanhostname(fwd.listen_host);
+                       if (parse_forward(&fwd, optarg, 1, 0)) {
+                               add_local_forward(&options, &fwd);
                        } else {
-                               fwd.listen_port = a2port(fwd.listen_host);
-                               fwd.listen_host = NULL;
-                       }
-
-                       if (fwd.listen_port == 0) {
-                               fprintf(stderr, "Bad dynamic port '%s'\n",
-                                   optarg);
+                               fprintf(stderr,
+                                   "Bad dynamic forwarding specification "
+                                   "'%s'\n", optarg);
                                exit(255);
                        }
-                       add_local_forward(&options, &fwd);
-                       xfree(p);
                        break;
 
                case 'C':
@@ -537,7 +558,7 @@ main(int ac, char **av)
        ac -= optind;
        av += optind;
 
-       if (ac > 0 && !host && **av != '-') {
+       if (ac > 0 && !host) {
                if (strrchr(*av, '@')) {
                        p = xstrdup(*av);
                        cp = strrchr(p, '@');
@@ -612,9 +633,9 @@ main(int ac, char **av)
         * Initialize "log" output.  Since we are the client all output
         * actually goes to stderr.
         */
-       log_init(av[0],
+       log_init(argv0,
            options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
-           SYSLOG_FACILITY_USER, 1);
+           SYSLOG_FACILITY_USER, !use_syslog);
 
        /*
         * Read per-user configuration file.  Ignore the system wide config
@@ -625,9 +646,10 @@ main(int ac, char **av)
                        fatal("Can't open user config file %.100s: "
                            "%.100s", config, strerror(errno));
        } else {
-               snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir,
+               r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
                    _PATH_SSH_USER_CONFFILE);
-               (void)read_config_file(buf, host, &options, 1);
+               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,
@@ -640,13 +662,35 @@ main(int ac, char **av)
        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)
                options.user = xstrdup(pw->pw_name);
 
+       /* 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;
 
@@ -657,12 +701,6 @@ main(int ac, char **av)
                                *p = (char)tolower(*p);
        }
 
-       /* 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.proxy_command != NULL &&
            strcmp(options.proxy_command, "none") == 0) {
                xfree(options.proxy_command);
@@ -762,9 +800,9 @@ main(int ac, char **av)
         * Now that we are back to our own permissions, create ~/.ssh
         * directory if it doesn't already exist.
         */
-       snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir,
+       r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir,
            strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
-       if (stat(buf, &st) < 0)
+       if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0)
                if (mkdir(buf, 0700) < 0)
                        error("Could not create directory '%.200s'.", buf);
 
@@ -833,9 +871,16 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
 {
        Forward *rfwd = (Forward *)ctxt;
 
+       /* 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 "
@@ -844,9 +889,43 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
                        logit("Warning: remote port forwarding failed for "
                            "listen port %d", rfwd->listen_port);
        }
-       if (++remote_forward_confirms_received == options.num_remote_forwards)
+       if (++remote_forward_confirms_received == options.num_remote_forwards) {
                debug("All remote forwarding requests processed");
-               /* XXX fork-after-authentication */
+               if (fork_after_authentication_flag) {
+                       fork_after_authentication_flag = 0;
+                       if (daemon(1, 1) < 0)
+                               fatal("daemon() failed: %.200s",
+                                   strerror(errno));
+               }
+       }
+}
+
+static void
+client_cleanup_stdio_fwd(int id, void *arg)
+{
+       debug("stdio forwarding: done");
+       cleanup_exit(0);
+}
+
+static int
+client_setup_stdio_fwd(const char *host_to_connect, u_short port_to_connect)
+{
+       Channel *c;
+       int in, out;
+
+       debug3("client_setup_stdio_fwd %s:%d", host_to_connect,
+           port_to_connect);
+
+       in = dup(STDIN_FILENO);
+       out = dup(STDOUT_FILENO);
+       if (in < 0 || out < 0)
+               fatal("channel_connect_stdio_fwd: dup() in/out failed");
+
+       if ((c = channel_connect_stdio_fwd(host_to_connect, port_to_connect,
+           in, out)) == NULL)
+               return 0;
+       channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0);
+       return 1;
 }
 
 static void
@@ -855,6 +934,15 @@ ssh_init_forwarding(void)
        int success = 0;
        int i;
 
+       if (stdio_forward_host != NULL) {
+               if (!compat20) {
+                       fatal("stdio forwarding require Protocol 2");
+               }
+               if (!client_setup_stdio_fwd(stdio_forward_host,
+                   stdio_forward_port))
+                       fatal("Failed to connect in stdio forward mode.");
+       }
+
        /* Initiate local TCP/IP port forwardings. */
        for (i = 0; i < options.num_local_forwards; i++) {
                debug("Local connections to %.200s:%d forwarded to remote "
@@ -1046,10 +1134,17 @@ ssh_session(void)
            options.permit_local_command)
                ssh_local_cmd(options.local_command);
 
-       /* If requested, let ssh continue in the background. */
-       if (fork_after_authentication_flag)
+       /*
+        * 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
@@ -1171,7 +1266,8 @@ ssh_session2(void)
                id = ssh_session2_open();
 
        /* If we don't expect to open a new session, then disallow it */
-       if (options.control_master == SSHCTL_MASTER_NO) {
+       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");
@@ -1188,9 +1284,14 @@ ssh_session2(void)
        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));
+       }
+
+       if (options.use_roaming)
+               request_roaming();
 
        return client_loop(tty_flag, tty_flag ?
            options.escape_char : SSH_ESCAPECHAR_NONE, id);
This page took 0.053789 seconds and 4 git commands to generate.