Merge branch 'vendor/OPENSSH'
[dragonfly.git] / crypto / openssh / serverloop.c
index c0aa80c..725263b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.162 2012/06/20 04:42:58 djm Exp $ */
+/* $OpenBSD: serverloop.c,v 1.172 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -61,6 +61,7 @@
 #include "packet.h"
 #include "buffer.h"
 #include "log.h"
+#include "misc.h"
 #include "servconf.h"
 #include "canohost.h"
 #include "sshpty.h"
@@ -77,7 +78,6 @@
 #include "dispatch.h"
 #include "auth-options.h"
 #include "serverloop.h"
-#include "misc.h"
 #include "roaming.h"
 
 extern ServerOptions options;
@@ -162,7 +162,7 @@ static void
 notify_parent(void)
 {
        if (notify_pipe[1] != -1)
-               write(notify_pipe[1], "", 1);
+               (void)write(notify_pipe[1], "", 1);
 }
 static void
 notify_prepare(fd_set *readset)
@@ -291,7 +291,7 @@ client_alive_check(void)
  */
 static void
 wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
-    u_int *nallocp, u_int max_time_milliseconds)
+    u_int *nallocp, u_int64_t max_time_milliseconds)
 {
        struct timeval tv, *tvp;
        int ret;
@@ -318,7 +318,8 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
        if (compat20 &&
            max_time_milliseconds == 0 && options.client_alive_interval) {
                client_alive_scheduled = 1;
-               max_time_milliseconds = options.client_alive_interval * 1000;
+               max_time_milliseconds =
+                   (u_int64_t)options.client_alive_interval * 1000;
        }
 
        if (compat20) {
@@ -579,7 +580,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
        int wait_status;        /* Status returned by wait(). */
        pid_t wait_pid;         /* pid returned by wait(). */
        int waiting_termination = 0;    /* Have displayed waiting close message. */
-       u_int max_time_milliseconds;
+       u_int64_t max_time_milliseconds;
        u_int previous_stdout_buffer_bytes;
        u_int stdout_buffer_bytes;
        int type;
@@ -710,7 +711,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
                                /* Display list of open channels. */
                                cp = channel_open_message();
                                buffer_append(&stderr_buffer, cp, strlen(cp));
-                               xfree(cp);
+                               free(cp);
                        }
                }
                max_fd = MAX(connection_in, connection_out);
@@ -724,7 +725,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
                    &nalloc, max_time_milliseconds);
 
                if (received_sigterm) {
-                       logit("Exiting on signal %d", received_sigterm);
+                       logit("Exiting on signal %d", (int)received_sigterm);
                        /* Clean up sessions, utmp, etc. */
                        cleanup_exit(255);
                }
@@ -738,10 +739,8 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
                /* Process output to the client and to program stdin. */
                process_output(writeset);
        }
-       if (readset)
-               xfree(readset);
-       if (writeset)
-               xfree(writeset);
+       free(readset);
+       free(writeset);
 
        /* Cleanup and termination code. */
 
@@ -841,8 +840,10 @@ void
 server_loop2(Authctxt *authctxt)
 {
        fd_set *readset = NULL, *writeset = NULL;
-       int rekeying = 0, max_fd, nalloc = 0;
+       int rekeying = 0, max_fd;
        double start_time, total_time;
+       u_int nalloc = 0;
+       u_int64_t rekey_timeout_ms = 0;
 
        debug("Entering interactive session for SSH2.");
        start_time = get_current_time();
@@ -872,11 +873,16 @@ server_loop2(Authctxt *authctxt)
 
                if (!rekeying && packet_not_very_much_data_to_write())
                        channel_output_poll();
+               if (options.rekey_interval > 0 && compat20 && !rekeying)
+                       rekey_timeout_ms = packet_get_rekey_timeout() * 1000;
+               else
+                       rekey_timeout_ms = 0;
+
                wait_until_can_do_something(&readset, &writeset, &max_fd,
-                   &nalloc, 0);
+                   &nalloc, rekey_timeout_ms);
 
                if (received_sigterm) {
-                       logit("Exiting on signal %d", received_sigterm);
+                       logit("Exiting on signal %d", (int)received_sigterm);
                        /* Clean up sessions, utmp, etc. */
                        cleanup_exit(255);
                }
@@ -897,10 +903,8 @@ server_loop2(Authctxt *authctxt)
        }
        collect_children();
 
-       if (readset)
-               xfree(readset);
-       if (writeset)
-               xfree(writeset);
+       free(readset);
+       free(writeset);
 
        /* free all channels, no more reads and writes */
        channel_free_all();
@@ -939,8 +943,8 @@ server_input_stdin_data(int type, u_int32_t seq, void *ctxt)
        data = packet_get_string(&data_len);
        packet_check_eom();
        buffer_append(&stdin_buffer, data, data_len);
-       memset(data, 0, data_len);
-       xfree(data);
+       explicit_bzero(data, data_len);
+       free(data);
 }
 
 static void
@@ -973,7 +977,7 @@ server_input_window_size(int type, u_int32_t seq, void *ctxt)
 static Channel *
 server_request_direct_tcpip(void)
 {
-       Channel *c;
+       Channel *c = NULL;
        char *target, *originator;
        u_short target_port, originator_port;
 
@@ -986,12 +990,51 @@ server_request_direct_tcpip(void)
        debug("server_request_direct_tcpip: originator %s port %d, target %s "
            "port %d", originator, originator_port, target, target_port);
 
-       /* XXX check permission */
-       c = channel_connect_to(target, target_port,
-           "direct-tcpip", "direct-tcpip");
+       /* XXX fine grained permissions */
+       if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 &&
+           !no_port_forwarding_flag) {
+               c = channel_connect_to_port(target, target_port,
+                   "direct-tcpip", "direct-tcpip");
+       } else {
+               logit("refused local port forward: "
+                   "originator %s port %d, target %s port %d",
+                   originator, originator_port, target, target_port);
+       }
 
-       xfree(originator);
-       xfree(target);
+       free(originator);
+       free(target);
+
+       return c;
+}
+
+static Channel *
+server_request_direct_streamlocal(void)
+{
+       Channel *c = NULL;
+       char *target, *originator;
+       u_short originator_port;
+
+       target = packet_get_string(NULL);
+       originator = packet_get_string(NULL);
+       originator_port = packet_get_int();
+       packet_check_eom();
+
+       debug("server_request_direct_streamlocal: originator %s port %d, target %s",
+           originator, originator_port, target);
+
+       /* XXX fine grained permissions */
+       if ((options.allow_streamlocal_forwarding & FORWARD_LOCAL) != 0 &&
+           !no_port_forwarding_flag) {
+               c = channel_connect_to_path(target,
+                   "direct-streamlocal@openssh.com", "direct-streamlocal");
+       } else {
+               logit("refused streamlocal port forward: "
+                   "originator %s port %d, target %s",
+                   originator, originator_port, target);
+       }
+
+       free(originator);
+       free(target);
 
        return c;
 }
@@ -1099,6 +1142,8 @@ server_input_channel_open(int type, u_int32_t seq, void *ctxt)
                c = server_request_session();
        } else if (strcmp(ctype, "direct-tcpip") == 0) {
                c = server_request_direct_tcpip();
+       } else if (strcmp(ctype, "direct-streamlocal@openssh.com") == 0) {
+               c = server_request_direct_streamlocal();
        } else if (strcmp(ctype, "tun@openssh.com") == 0) {
                c = server_request_tun();
        }
@@ -1126,7 +1171,7 @@ server_input_channel_open(int type, u_int32_t seq, void *ctxt)
                }
                packet_send();
        }
-       xfree(ctype);
+       free(ctype);
 }
 
 static void
@@ -1143,47 +1188,74 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt)
        /* -R style forwarding */
        if (strcmp(rtype, "tcpip-forward") == 0) {
                struct passwd *pw;
-               char *listen_address;
-               u_short listen_port;
+               struct Forward fwd;
 
                pw = the_authctxt->pw;
                if (pw == NULL || !the_authctxt->valid)
                        fatal("server_input_global_request: no/invalid user");
-               listen_address = packet_get_string(NULL);
-               listen_port = (u_short)packet_get_int();
+               memset(&fwd, 0, sizeof(fwd));
+               fwd.listen_host = packet_get_string(NULL);
+               fwd.listen_port = (u_short)packet_get_int();
                debug("server_input_global_request: tcpip-forward listen %s port %d",
-                   listen_address, listen_port);
+                   fwd.listen_host, fwd.listen_port);
 
                /* check permissions */
-               if (!options.allow_tcp_forwarding ||
+               if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 ||
                    no_port_forwarding_flag ||
-                   (!want_reply && listen_port == 0)
+                   (!want_reply && fwd.listen_port == 0)
 #ifndef NO_IPPORT_RESERVED_CONCEPT
-                   || (listen_port != 0 && listen_port < IPPORT_RESERVED &&
-                    pw->pw_uid != 0)
+                   || (fwd.listen_port != 0 && fwd.listen_port < IPPORT_RESERVED &&
+                   pw->pw_uid != 0)
 #endif
                    ) {
                        success = 0;
                        packet_send_debug("Server has disabled port forwarding.");
                } else {
                        /* Start listening on the port */
-                       success = channel_setup_remote_fwd_listener(
-                           listen_address, listen_port,
-                           &allocated_listen_port, options.gateway_ports);
+                       success = channel_setup_remote_fwd_listener(&fwd,
+                           &allocated_listen_port, &options.fwd_opts);
                }
-               xfree(listen_address);
+               free(fwd.listen_host);
        } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) {
-               char *cancel_address;
-               u_short cancel_port;
+               struct Forward fwd;
 
-               cancel_address = packet_get_string(NULL);
-               cancel_port = (u_short)packet_get_int();
+               memset(&fwd, 0, sizeof(fwd));
+               fwd.listen_host = packet_get_string(NULL);
+               fwd.listen_port = (u_short)packet_get_int();
                debug("%s: cancel-tcpip-forward addr %s port %d", __func__,
-                   cancel_address, cancel_port);
+                   fwd.listen_host, fwd.listen_port);
+
+               success = channel_cancel_rport_listener(&fwd);
+               free(fwd.listen_host);
+       } else if (strcmp(rtype, "streamlocal-forward@openssh.com") == 0) {
+               struct Forward fwd;
+
+               memset(&fwd, 0, sizeof(fwd));
+               fwd.listen_path = packet_get_string(NULL);
+               debug("server_input_global_request: streamlocal-forward listen path %s",
+                   fwd.listen_path);
+
+               /* check permissions */
+               if ((options.allow_streamlocal_forwarding & FORWARD_REMOTE) == 0
+                   || no_port_forwarding_flag) {
+                       success = 0;
+                       packet_send_debug("Server has disabled port forwarding.");
+               } else {
+                       /* Start listening on the socket */
+                       success = channel_setup_remote_fwd_listener(
+                           &fwd, NULL, &options.fwd_opts);
+               }
+               free(fwd.listen_path);
+       } else if (strcmp(rtype, "cancel-streamlocal-forward@openssh.com") == 0) {
+               struct Forward fwd;
+
+               memset(&fwd, 0, sizeof(fwd));
+               fwd.listen_path = packet_get_string(NULL);
+               debug("%s: cancel-streamlocal-forward path %s", __func__,
+                   fwd.listen_path);
 
-               success = channel_cancel_rport_listener(cancel_address,
-                   cancel_port);
-               xfree(cancel_address);
+               success = channel_cancel_rport_listener(&fwd);
+               free(fwd.listen_path);
        } else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) {
                no_more_sessions = 1;
                success = 1;
@@ -1196,7 +1268,7 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt)
                packet_send();
                packet_write_wait();
        }
-       xfree(rtype);
+       free(rtype);
 }
 
 static void
@@ -1222,13 +1294,13 @@ server_input_channel_req(int type, u_int32_t seq, void *ctxt)
        } else if ((c->type == SSH_CHANNEL_LARVAL ||
            c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0)
                success = session_input_channel_req(c, rtype);
-       if (reply) {
+       if (reply && !(c->flags & CHAN_CLOSE_SENT)) {
                packet_start(success ?
                    SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
                packet_put_int(c->remote_id);
                packet_send();
        }
-       xfree(rtype);
+       free(rtype);
 }
 
 static void