]> andersk Git - openssh.git/blobdiff - serverloop.c
- markus@cvs.openbsd.org 2010/01/15 09:24:23
[openssh.git] / serverloop.c
index 2142f38098b00ba12a88ec1bb62d29662ec4f1db..8be01c5c37c4250aab5c855f28f3ac7d51c00b51 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.150 2008/05/09 04:55:56 djm Exp $ */
+/* $OpenBSD: serverloop.c,v 1.159 2009/05/28 16:50:16 andreas Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -78,6 +78,7 @@
 #include "auth-options.h"
 #include "serverloop.h"
 #include "misc.h"
+#include "roaming.h"
 
 extern ServerOptions options;
 
@@ -105,6 +106,7 @@ static int connection_in;   /* Connection to client (input). */
 static int connection_out;     /* Connection to client (output). */
 static int connection_closed = 0;      /* Connection to client closed. */
 static u_int buffer_high;      /* "Soft" max buffer size. */
+static int no_more_sessions = 0; /* Disallow further sessions. */
 
 /*
  * This SIGCHLD kludge is used to detect when the child exits.  The server
@@ -248,7 +250,7 @@ client_alive_check(void)
        int channel_id;
 
        /* timeout, check to see how many we have had */
-       if (++keep_alive_timeouts > options.client_alive_count_max) {
+       if (packet_inc_alive_timeouts() > options.client_alive_count_max) {
                logit("Timeout, client not responding.");
                cleanup_exit(255);
        }
@@ -390,8 +392,11 @@ process_input(fd_set *readset)
 
        /* Read and buffer any input data from the client. */
        if (FD_ISSET(connection_in, readset)) {
-               len = read(connection_in, buf, sizeof(buf));
+               int cont = 0;
+               len = roaming_read(connection_in, buf, sizeof(buf), &cont);
                if (len == 0) {
+                       if (cont)
+                               return;
                        verbose("Connection closed by %.100s",
                            get_remote_ipaddr());
                        connection_closed = 1;
@@ -399,7 +404,8 @@ process_input(fd_set *readset)
                                return;
                        cleanup_exit(255);
                } else if (len < 0) {
-                       if (errno != EINTR && errno != EAGAIN) {
+                       if (errno != EINTR && errno != EAGAIN &&
+                           errno != EWOULDBLOCK) {
                                verbose("Read error from remote host "
                                    "%.100s: %.100s",
                                    get_remote_ipaddr(), strerror(errno));
@@ -417,8 +423,8 @@ process_input(fd_set *readset)
        if (!fdout_eof && FD_ISSET(fdout, readset)) {
                errno = 0;
                len = read(fdout, buf, sizeof(buf));
-               if (len < 0 && (errno == EINTR ||
-                   (errno == EAGAIN && !child_terminated))) {
+               if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
+                   errno == EWOULDBLOCK) && !child_terminated))) {
                        /* do nothing */
 #ifndef PTY_ZEROREAD
                } else if (len <= 0) {
@@ -436,8 +442,8 @@ process_input(fd_set *readset)
        if (!fderr_eof && FD_ISSET(fderr, readset)) {
                errno = 0;
                len = read(fderr, buf, sizeof(buf));
-               if (len < 0 && (errno == EINTR ||
-                   (errno == EAGAIN && !child_terminated))) {
+               if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
+                   errno == EWOULDBLOCK) && !child_terminated))) {
                        /* do nothing */
 #ifndef PTY_ZEROREAD
                } else if (len <= 0) {
@@ -468,7 +474,8 @@ process_output(fd_set *writeset)
                data = buffer_ptr(&stdin_buffer);
                dlen = buffer_len(&stdin_buffer);
                len = write(fdin, data, dlen);
-               if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
+               if (len < 0 &&
+                   (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) {
                        /* do nothing */
                } else if (len <= 0) {
                        if (fdin != fdout)
@@ -887,7 +894,7 @@ server_input_keep_alive(int type, u_int32_t seq, void *ctxt)
         * even if this was generated by something other than
         * the bogus CHANNEL_REQUEST we send for keepalives.
         */
-       keep_alive_timeouts = 0;
+       packet_set_alive_timeouts(0);
 }
 
 static void
@@ -939,7 +946,7 @@ server_request_direct_tcpip(void)
 {
        Channel *c;
        char *target, *originator;
-       int target_port, originator_port;
+       u_short target_port, originator_port;
 
        target = packet_get_string(NULL);
        target_port = packet_get_int();
@@ -997,7 +1004,7 @@ server_request_tun(void)
 #if defined(SSH_TUN_FILTER)
        if (mode == SSH_TUNMODE_POINTOPOINT)
                channel_register_filter(c->self, sys_tun_infilter,
-                   sys_tun_outfilter);
+                   sys_tun_outfilter, NULL, NULL);
 #endif
 
  done:
@@ -1013,6 +1020,12 @@ server_request_session(void)
 
        debug("input_session_request");
        packet_check_eom();
+
+       if (no_more_sessions) {
+               packet_disconnect("Possible attack: attempt to open a session "
+                   "after additional sessions disabled");
+       }
+
        /*
         * A server session has no fd to read or write until a
         * CHANNEL_REQUEST for a shell is made, so we set the type to
@@ -1086,7 +1099,7 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt)
 {
        char *rtype;
        int want_reply;
-       int success = 0;
+       int success = 0, allocated_listen_port = 0;
 
        rtype = packet_get_string(NULL);
        want_reply = packet_get_char();
@@ -1108,9 +1121,11 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt)
 
                /* check permissions */
                if (!options.allow_tcp_forwarding ||
-                   no_port_forwarding_flag
+                   no_port_forwarding_flag ||
+                   (!want_reply && listen_port == 0)
 #ifndef NO_IPPORT_RESERVED_CONCEPT
-                   || (listen_port < IPPORT_RESERVED && pw->pw_uid != 0)
+                   || (listen_port != 0 && listen_port < IPPORT_RESERVED &&
+                    pw->pw_uid != 0)
 #endif
                    ) {
                        success = 0;
@@ -1118,7 +1133,8 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt)
                } else {
                        /* Start listening on the port */
                        success = channel_setup_remote_fwd_listener(
-                           listen_address, listen_port, options.gateway_ports);
+                           listen_address, listen_port,
+                           &allocated_listen_port, options.gateway_ports);
                }
                xfree(listen_address);
        } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) {
@@ -1133,10 +1149,15 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt)
                success = channel_cancel_rport_listener(cancel_address,
                    cancel_port);
                xfree(cancel_address);
+       } else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) {
+               no_more_sessions = 1;
+               success = 1;
        }
        if (want_reply) {
                packet_start(success ?
                    SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
+               if (success && allocated_listen_port > 0)
+                       packet_put_int(allocated_listen_port);
                packet_send();
                packet_write_wait();
        }
@@ -1160,7 +1181,11 @@ server_input_channel_req(int type, u_int32_t seq, void *ctxt)
        if ((c = channel_lookup(id)) == NULL)
                packet_disconnect("server_input_channel_req: "
                    "unknown channel %d", id);
-       if (c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN)
+       if (!strcmp(rtype, "eow@openssh.com")) {
+               packet_check_eom();
+               chan_rcvd_eow(c);
+       } 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) {
                packet_start(success ?
@@ -1186,9 +1211,9 @@ server_init_dispatch_20(void)
        dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req);
        dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
        dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
-       dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &channel_input_status_confirm);
-       dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &channel_input_status_confirm);
        /* client_alive */
+       dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &server_input_keep_alive);
+       dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_keep_alive);
        dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &server_input_keep_alive);
        dispatch_set(SSH2_MSG_REQUEST_FAILURE, &server_input_keep_alive);
        /* rekeying */
This page took 1.441418 seconds and 4 git commands to generate.