]> andersk Git - gssapi-openssh.git/blobdiff - openssh/ssh.c
Tweak the environment variables set by the configure script for the
[gssapi-openssh.git] / openssh / ssh.c
index 0530c957fe4eee899484749f422bf95deaaefb8d..296c8a1b2c5930c06753246e54ae523f2f6fd995 100644 (file)
@@ -1,3 +1,4 @@
+/* $OpenBSD: ssh.c,v 1.301 2007/08/07 07:32:53 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: ssh.c,v 1.257 2005/12/20 04:41:07 dtucker 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/socket.h>
+#include <sys/un.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 "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 "bufaux.h"
 #include "channels.h"
 #include "key.h"
 #include "authfd.h"
@@ -72,6 +99,7 @@ RCSID("$OpenBSD: ssh.c,v 1.257 2005/12/20 04:41:07 dtucker Exp $");
 #include "msg.h"
 #include "monitor_fdpass.h"
 #include "uidswap.h"
+#include "version.h"
 
 #ifdef SMARTCARD
 #include "scard.h"
@@ -157,13 +185,12 @@ static void
 usage(void)
 {
        fprintf(stderr,
-"usage: ssh [-1246AaCfgkMNnqrsTtVvXxY] [-b bind_address] [-c cipher_spec]\n"
+"usage: ssh [-1246AaCfgKkMNnqsTtVvXxY] [-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 tunnel:tunnel] [user@]hostname [command]\n"
-"           [-r Receive Buffer Size in K]\n"
+"           [-w local_tun[:remote_tun]] [user@]hostname [command]\n"
        );
        exit(255);
 }
@@ -243,12 +270,9 @@ main(int ac, char **av)
        /* Parse command-line arguments. */
        host = NULL;
 
-       /* need to set options.tcp_rcv_buf to 0 */
-       options.tcp_rcv_buf = 0;
-
-again:
+ again:
        while ((opt = getopt(ac, av,
-           "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:MNO:PR:S:TVw:XYz")) != -1) {
+           "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) {
                switch (opt) {
                case '1':
                        options.protocol = SSH_PROTO_1;
@@ -302,6 +326,10 @@ again:
                case 'k':
                        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 "
@@ -473,11 +501,6 @@ again:
                case 'N':
                        no_shell_flag = 1;
                        no_tty_flag = 1;
-                       options.none_switch = 0;
-                       break;
-               case 'T':
-                       no_tty_flag = 1;
-                       options.none_switch = 0;
                        break;
                case 'o':
                        dummy = 1;
@@ -487,6 +510,13 @@ again:
                                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;
@@ -497,20 +527,10 @@ again:
                        break;
                case 'b':
                        options.bind_address = optarg;
-               case 'r':
-                       options.tcp_rcv_buf = atoi(optarg) * 1024;
-                       break;
-               case 'z':
-                       /* make sure we can't turn on the none_switch */
-                       /* if they try to force a no tty flag on a tty session */
-                       if (!no_tty_flag) {
-                               options.none_switch = 1;
-                       }
                        break;
                case 'F':
                        config = optarg;
                        break;
-
                default:
                        usage();
                }
@@ -602,7 +622,7 @@ again:
                if (!read_config_file(config, host, &options, 0))
                        fatal("Can't open user config file %.100s: "
                            "%.100s", config, strerror(errno));
-       } else  {
+       } else {
            /*
             * Since the config file parsing code aborts if it sees
             * options it doesn't recognize, allow users to put
@@ -658,7 +678,7 @@ 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);
        }
 
        /* Get default port if port has not been set. */
@@ -675,11 +695,15 @@ again:
                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);
                options.control_path = percent_expand(cp, "p", buf, "h", host,
-                   "r", options.user, (char *)NULL);
+                   "r", options.user, "l", thishost, (char *)NULL);
                xfree(cp);
        }
        if (mux_command != 0 && options.control_path == NULL)
@@ -712,16 +736,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 &&
@@ -835,8 +859,11 @@ ssh_init_forwarding(void)
                    options.local_forwards[i].listen_port,
                    options.local_forwards[i].connect_host,
                    options.local_forwards[i].connect_port,
-                   options.gateway_ports);
+                   options.gateway_ports, options.hpn_disabled,
+                   options.hpn_buffer_size);
        }
+       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.");
 
@@ -849,12 +876,29 @@ ssh_init_forwarding(void)
                    options.remote_forwards[i].listen_port,
                    options.remote_forwards[i].connect_host,
                    options.remote_forwards[i].connect_port);
-               channel_request_remote_forwarding(
+               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);
+                   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.");
+               }
        }
+
+       /* 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
@@ -914,10 +958,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);
@@ -1035,9 +1079,16 @@ client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt)
            options.remote_forwards[i].listen_port,
            options.remote_forwards[i].connect_host,
            options.remote_forwards[i].connect_port);
-       if (type == SSH2_MSG_REQUEST_FAILURE)
-               logit("Warning: remote port forwarding failed for listen "
-                   "port %d", options.remote_forwards[i].listen_port);
+       if (type == SSH2_MSG_REQUEST_FAILURE) {
+               if (options.exit_on_forward_failure)
+                       fatal("Error: remote port forwarding failed for "
+                           "listen port %d",
+                           options.remote_forwards[i].listen_port);
+               else
+                       logit("Warning: remote port forwarding failed for "
+                           "listen port %d",
+                           options.remote_forwards[i].listen_port);
+       }
 }
 
 static void
@@ -1066,7 +1117,7 @@ ssh_control_listener(void)
                fatal("%s socket(): %s", __func__, strerror(errno));
 
        old_umask = umask(0177);
-       if (bind(control_fd, (struct sockaddr*)&addr, addr_len) == -1) {
+       if (bind(control_fd, (struct sockaddr *)&addr, addr_len) == -1) {
                control_fd = -1;
                if (errno == EINVAL || errno == EADDRINUSE)
                        fatal("ControlSocket %s already exists",
@@ -1110,33 +1161,6 @@ ssh_session2_setup(int id, void *arg)
                packet_send();
        }
 
-       if (options.tun_open != SSH_TUNMODE_NO) {
-               Channel *c;
-               int fd;
-
-               debug("Requesting tun.");
-               if ((fd = tun_open(options.tun_local,
-                   options.tun_open)) >= 0) {
-                       c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1,
-                           CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
-                           0, "tun", 1);
-                       c->datagram = 1;
-#if defined(SSH_TUN_FILTER)
-                       if (options.tun_open == SSH_TUNMODE_POINTOPOINT)
-                               channel_register_filter(c->self, sys_tun_infilter,
-                                   sys_tun_outfilter);
-#endif
-                       packet_start(SSH2_MSG_CHANNEL_OPEN);
-                       packet_put_cstring("tun@openssh.com");
-                       packet_put_int(c->self);
-                       packet_put_int(c->local_window_max);
-                       packet_put_int(c->local_maxpacket);
-                       packet_put_int(options.tun_open);
-                       packet_put_int(options.tun_remote);
-                       packet_send();
-               }
-       }
-
        client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),
            NULL, fileno(stdin), &command, environ, &ssh_subsystem_reply);
 
@@ -1149,6 +1173,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);
@@ -1169,7 +1196,67 @@ 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(options.hpn_disabled)
+       {
+               options.hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT;
+       }
+       else if (datafellows & SSH_BUG_LARGEWINDOW) 
+       {
+               debug("HPN to Non-HPN Connection");
+               if (options.hpn_buffer_size < 0)
+                       options.hpn_buffer_size = 2*1024*1024;
+       } 
+       else 
+       {
+               if (options.hpn_buffer_size < 0)
+                       options.hpn_buffer_size = BUFFER_MAX_LEN_HPN;
+
+               /*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);
+               if (options.tcp_rcv_buf_poll <= 0) 
+               {
+                       options.hpn_buffer_size = MIN(socksize,options.hpn_buffer_size);
+                       debug ("MIN of TCP RWIN and HPNBufferSize: %d", options.hpn_buffer_size);
+               } 
+               else
+               {
+                       if (options.tcp_rcv_buf > 0) 
+                               options.hpn_buffer_size = MIN(options.tcp_rcv_buf, options.hpn_buffer_size);
+                               debug ("MIN of TCPRcvBuf and HPNBufferSize: %d", options.hpn_buffer_size);
+               }
+               
+       }
+
+       debug("Final hpn_buffer_size = %d", options.hpn_buffer_size);
+
+       window = options.hpn_buffer_size;
+
        packetmax = CHAN_SES_PACKET_DEFAULT;
        if (tty_flag) {
                window = 4*CHAN_SES_PACKET_DEFAULT;
@@ -1181,8 +1268,9 @@ ssh_session2_open(void)
            window, packetmax, CHAN_EXTENDED_WRITE,
            "client-session", /*nonblock*/0);
 
-       if (!tty_flag && (!(datafellows & SSH_BUG_LARGEWINDOW))) {
+       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);
 
@@ -1200,7 +1288,6 @@ ssh_session2(void)
 
        /* XXX should be pre-session */
        ssh_init_forwarding();
-       ssh_control_listener();
 
        if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
                id = ssh_session2_open();
@@ -1210,6 +1297,9 @@ ssh_session2(void)
            options.permit_local_command)
                ssh_local_cmd(options.local_command);
 
+       /* Start listening for multiplex clients */
+       ssh_control_listener();
+
        /* If requested, let ssh continue in the background. */
        if (fork_after_authentication_flag)
                if (daemon(1, 1) < 0)
@@ -1222,15 +1312,16 @@ ssh_session2(void)
 static void
 load_public_identity_files(void)
 {
-       char *filename;
+       char *filename, *cp, thishost[NI_MAXHOST];
        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++;
@@ -1248,9 +1339,18 @@ load_public_identity_files(void)
                xfree(keys);
        }
 #endif /* SMARTCARD */
+       if ((pw = getpwuid(original_real_uid)) == NULL)
+               fatal("load_public_identity_files: getpwuid failed");
+       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", pw->pw_dir,
+                   "u", pw->pw_name, "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);
@@ -1276,14 +1376,14 @@ control_client_sigrelay(int signo)
 static int
 env_permitted(char *env)
 {
-       int i;
+       int i, ret;
        char name[1024], *cp;
 
-       strlcpy(name, env, sizeof(name));
-       if ((cp = strchr(name, '=')) == NULL)
+       if ((cp = strchr(env, '=')) == NULL || cp == env)
                return (0);
-
-       *cp = '\0';
+       ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env);
+       if (ret <= 0 || (size_t)ret >= sizeof(name))
+               fatal("env_permitted: name '%.100s...' too long", env);
 
        for (i = 0; i < options.num_send_env; i++)
                if (match_pattern(name, options.send_env[i]))
@@ -1296,7 +1396,7 @@ static void
 control_client(const char *path)
 {
        struct sockaddr_un addr;
-       int i, r, fd, sock, exitval, num_env, addr_len;
+       int i, r, fd, sock, exitval[2], num_env, addr_len;
        Buffer m;
        char *term;
        extern char **environ;
@@ -1328,29 +1428,29 @@ control_client(const char *path)
        if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
                fatal("%s socket(): %s", __func__, strerror(errno));
 
-       if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1) {
+       if (connect(sock, (struct sockaddr *)&addr, addr_len) == -1) {
                if (mux_command != SSHMUX_COMMAND_OPEN) {
                        fatal("Control socket connect(%.100s): %s", path,
                            strerror(errno));
                }
                if (errno == ENOENT)
-                       debug("Control socket \"%.100s\" does not exist", path);
+                       debug("Control socket \"%.100s\" does not exist", path);
                else {
-                       error("Control socket connect(%.100s): %s", path,
+                       error("Control socket connect(%.100s): %s", path,
                            strerror(errno));
                }
-               close(sock);
-               return;
-       }
-
-       if (stdin_null_flag) {
-               if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1)
-                       fatal("open(/dev/null): %s", strerror(errno));
-               if (dup2(fd, STDIN_FILENO) == -1)
-                       fatal("dup2: %s", strerror(errno));
-               if (fd > STDERR_FILENO)
-                       close(fd);
-       }
+               close(sock);
+               return;
+       }
+
+       if (stdin_null_flag) {
+               if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1)
+                       fatal("open(/dev/null): %s", strerror(errno));
+               if (dup2(fd, STDIN_FILENO) == -1)
+                       fatal("dup2: %s", strerror(errno));
+               if (fd > STDERR_FILENO)
+                       close(fd);
+       }
 
        term = getenv("TERM");
 
@@ -1445,29 +1545,44 @@ control_client(const char *path)
        if (tty_flag)
                enter_raw_mode();
 
-       /* Stick around until the controlee closes the client_fd */
-       exitval = 0;
-       for (;!control_client_terminate;) {
-               r = read(sock, &exitval, sizeof(exitval));
+       /*
+        * Stick around until the controlee closes the client_fd.
+        * Before it does, it is expected to write this process' exit
+        * value (one int). This process must read the value and wait for
+        * the closure of the client_fd; if this one closes early, the 
+        * multiplex master will terminate early too (possibly losing data).
+        */
+       exitval[0] = 0;
+       for (i = 0; !control_client_terminate && i < (int)sizeof(exitval);) {
+               r = read(sock, (char *)exitval + i, sizeof(exitval) - i);
                if (r == 0) {
                        debug2("Received EOF from master");
                        break;
                }
-               if (r > 0)
-                       debug2("Received exit status from master %d", exitval);
-               if (r == -1 && errno != EINTR)
+               if (r == -1) {
+                       if (errno == EINTR)
+                               continue;
                        fatal("%s: read %s", __func__, strerror(errno));
+               }
+               i += r;
        }
 
-       if (control_client_terminate)
-               debug2("Exiting on signal %d", control_client_terminate);
-
        close(sock);
-
        leave_raw_mode();
+       if (i > (int)sizeof(int))
+               fatal("%s: master returned too much data (%d > %lu)",
+                   __func__, i, sizeof(int));
+       if (control_client_terminate) {
+               debug2("Exiting on signal %d", control_client_terminate);
+               exitval[0] = 255;
+       } else if (i < (int)sizeof(int)) {
+               debug2("Control master terminated unexpectedly");
+               exitval[0] = 255;
+       } else
+               debug2("Received exit status from master %d", exitval[0]);
 
        if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
-               fprintf(stderr, "Connection to master closed.\r\n");
+               fprintf(stderr, "Shared connection to %s closed.\r\n", host);
 
-       exit(exitval);
+       exit(exitval[0]);
 }
This page took 0.094163 seconds and 4 git commands to generate.