X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/b184239338f791a39b3c4cbd4b224ae2a78d7348..9b4b86c2134a67e76ed043f67481cd5da84511a8:/serverloop.c diff --git a/serverloop.c b/serverloop.c index 14baecae..6a3ae166 100644 --- a/serverloop.c +++ b/serverloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: serverloop.c,v 1.137 2006/07/06 16:03:53 stevesk Exp $ */ +/* $OpenBSD: serverloop.c,v 1.154 2008/12/02 19:08:59 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -38,15 +38,25 @@ #include "includes.h" #include +#include #include #include +#ifdef HAVE_SYS_TIME_H +# include +#endif #include +#include +#include #include #include +#include #include +#include +#include +#include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "packet.h" #include "buffer.h" @@ -58,13 +68,16 @@ #include "compat.h" #include "ssh1.h" #include "ssh2.h" +#include "key.h" +#include "cipher.h" +#include "kex.h" +#include "hostfile.h" #include "auth.h" #include "session.h" #include "dispatch.h" #include "auth-options.h" #include "serverloop.h" #include "misc.h" -#include "kex.h" extern ServerOptions options; @@ -92,7 +105,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 client_alive_timeouts = 0; +static int no_more_sessions = 0; /* Disallow further sessions. */ /* * This SIGCHLD kludge is used to detect when the child exits. The server @@ -236,8 +249,10 @@ client_alive_check(void) int channel_id; /* timeout, check to see how many we have had */ - if (++client_alive_timeouts > options.client_alive_count_max) - packet_disconnect("Timeout, your session not responding."); + if (++keep_alive_timeouts > options.client_alive_count_max) { + logit("Timeout, client not responding."); + cleanup_exit(255); + } /* * send a bogus global/channel request with "wantreply", @@ -266,6 +281,7 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, struct timeval tv, *tvp; int ret; int client_alive_scheduled = 0; + int program_alive_scheduled = 0; /* * if using client_alive, set the max timeout accordingly, @@ -303,6 +319,7 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, * the client, try to get some more data from the program. */ if (packet_not_very_much_data_to_write()) { + program_alive_scheduled = child_terminated; if (!fdout_eof) FD_SET(fdout, *readsetp); if (!fderr_eof) @@ -348,8 +365,16 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, memset(*writesetp, 0, *nallocp); if (errno != EINTR) error("select: %.100s", strerror(errno)); - } else if (ret == 0 && client_alive_scheduled) - client_alive_check(); + } else { + if (ret == 0 && client_alive_scheduled) + client_alive_check(); + if (!compat20 && program_alive_scheduled && fdin_is_tty) { + if (!fdout_eof) + FD_SET(fdout, *readsetp); + if (!fderr_eof) + FD_SET(fderr, *readsetp); + } + } notify_done(*readsetp); } @@ -375,7 +400,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)); @@ -393,7 +419,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)) { + if (len < 0 && (errno == EINTR || ((errno == EAGAIN || + errno == EWOULDBLOCK) && !child_terminated))) { /* do nothing */ #ifndef PTY_ZEROREAD } else if (len <= 0) { @@ -411,7 +438,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)) { + if (len < 0 && (errno == EINTR || ((errno == EAGAIN || + errno == EWOULDBLOCK) && !child_terminated))) { /* do nothing */ #ifndef PTY_ZEROREAD } else if (len <= 0) { @@ -442,7 +470,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) @@ -861,7 +890,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. */ - client_alive_timeouts = 0; + keep_alive_timeouts = 0; } static void @@ -912,7 +941,6 @@ static Channel * server_request_direct_tcpip(void) { Channel *c; - int sock; char *target, *originator; int target_port, originator_port; @@ -922,18 +950,16 @@ server_request_direct_tcpip(void) originator_port = packet_get_int(); packet_check_eom(); - debug("server_request_direct_tcpip: originator %s port %d, target %s port %d", - originator, originator_port, target, target_port); + debug("server_request_direct_tcpip: originator %s port %d, target %s " + "port %d", originator, originator_port, target, target_port); /* XXX check permission */ - sock = channel_connect_to(target, target_port); - xfree(target); + c = channel_connect_to(target, target_port, + "direct-tcpip", "direct-tcpip"); + xfree(originator); - if (sock < 0) - return NULL; - c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING, - sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, - CHAN_TCP_PACKET_DEFAULT, 0, "direct-tcpip", 1); + xfree(target); + return c; } @@ -974,7 +1000,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: @@ -990,6 +1016,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 @@ -1110,6 +1142,9 @@ 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 ? @@ -1137,7 +1172,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 ? @@ -1164,6 +1203,7 @@ server_init_dispatch_20(void) dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request); /* 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);