X-Git-Url: http://andersk.mit.edu/gitweb/gssapi-openssh.git/blobdiff_plain/a7213e650521b1d30dd258aef112591b6f5f7827..4509933ca13b41d35539f3dd9cbcda2d76660cfc:/openssh/serverloop.c?ds=sidebyside diff --git a/openssh/serverloop.c b/openssh/serverloop.c index 5eb5fd5..1331dd8 100644 --- a/openssh/serverloop.c +++ b/openssh/serverloop.c @@ -1,3 +1,4 @@ +/* $OpenBSD: serverloop.c,v 1.148 2008/02/22 20:44:02 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -35,7 +36,25 @@ */ #include "includes.h" -RCSID("$OpenBSD: serverloop.c,v 1.124 2005/12/13 15:03:02 reyk Exp $"); + +#include +#include +#include +#include +#ifdef HAVE_SYS_TIME_H +# include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include #include "xmalloc.h" #include "packet.h" @@ -48,13 +67,16 @@ RCSID("$OpenBSD: serverloop.c,v 1.124 2005/12/13 15:03:02 reyk Exp $"); #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; @@ -70,10 +92,10 @@ static int fdin; /* Descriptor for stdin (for writing) */ static int fdout; /* Descriptor for stdout (for reading); May be same number as fdin. */ static int fderr; /* Descriptor for stderr. May be -1. */ -static long stdin_bytes = 0; /* Number of bytes written to stdin. */ -static long stdout_bytes = 0; /* Number of stdout bytes sent to client. */ -static long stderr_bytes = 0; /* Number of stderr bytes sent to client. */ -static long fdout_bytes = 0; /* Number of stdout bytes read from program. */ +static u_long stdin_bytes = 0; /* Number of bytes written to stdin. */ +static u_long stdout_bytes = 0; /* Number of stdout bytes sent to client. */ +static u_long stderr_bytes = 0; /* Number of stderr bytes sent to client. */ +static u_long fdout_bytes = 0; /* Number of stdout bytes read from program. */ static int stdin_eof = 0; /* EOF message received from client. */ static int fdout_eof = 0; /* EOF encountered reading from fdout. */ static int fderr_eof = 0; /* EOF encountered readung from fderr. */ @@ -82,7 +104,6 @@ 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; /* * This SIGCHLD kludge is used to detect when the child exits. The server @@ -97,6 +118,20 @@ static volatile sig_atomic_t received_sigterm = 0; /* prototypes */ static void server_init_dispatch(void); +/* + * Returns current time in seconds from Jan 1, 1970 with the maximum + * available resolution. + */ + +static double +get_current_time(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; +} + + /* * we write to this pipe if a SIGCHLD is caught in order to avoid * the race between select() and child_terminated @@ -142,11 +177,11 @@ notify_done(fd_set *readset) debug2("notify_done: reading"); } +/*ARGSUSED*/ static void sigchld_handler(int sig) { int save_errno = errno; - debug("Received SIGCHLD."); child_terminated = 1; #ifndef _UNICOS mysignal(SIGCHLD, sigchld_handler); @@ -155,6 +190,7 @@ sigchld_handler(int sig) errno = save_errno; } +/*ARGSUSED*/ static void sigterm_handler(int sig) { @@ -225,8 +261,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", @@ -255,6 +293,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, @@ -292,6 +331,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) @@ -337,8 +377,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); } @@ -348,7 +396,7 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, * in buffers and processed later. */ static void -process_input(fd_set * readset) +process_input(fd_set *readset) { int len; char buf[16384]; @@ -373,6 +421,7 @@ process_input(fd_set * readset) } else { /* Buffer any received data. */ packet_process_incoming(buf, len); + fdout_bytes += len; } } if (compat20) @@ -380,22 +429,37 @@ process_input(fd_set * readset) /* Read and buffer any available stdout data from the program. */ 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 && !child_terminated))) { /* do nothing */ +#ifndef PTY_ZEROREAD } else if (len <= 0) { +#else + } else if ((!isatty(fdout) && len <= 0) || + (isatty(fdout) && (len < 0 || (len == 0 && errno != 0)))) { +#endif fdout_eof = 1; } else { buffer_append(&stdout_buffer, buf, len); fdout_bytes += len; + debug ("FD out now: %ld", fdout_bytes); } } /* Read and buffer any available stderr data from the program. */ 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 && !child_terminated))) { /* do nothing */ +#ifndef PTY_ZEROREAD } else if (len <= 0) { +#else + } else if ((!isatty(fderr) && len <= 0) || + (isatty(fderr) && (len < 0 || (len == 0 && errno != 0)))) { +#endif fderr_eof = 1; } else { buffer_append(&stderr_buffer, buf, len); @@ -407,7 +471,7 @@ process_input(fd_set * readset) * Sends data from internal buffers to client program stdin. */ static void -process_output(fd_set * writeset) +process_output(fd_set *writeset) { struct termios tio; u_char *data; @@ -447,7 +511,7 @@ process_output(fd_set * writeset) } /* Send any buffered packet data to the client. */ if (FD_ISSET(connection_out, writeset)) - packet_write_poll(); + stdin_bytes += packet_write_poll(); } /* @@ -749,6 +813,7 @@ collect_children(void) sigaddset(&nset, SIGCHLD); sigprocmask(SIG_BLOCK, &nset, &oset); if (child_terminated) { + debug("Received SIGCHLD."); while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || (pid < 0 && errno == EINTR)) if (pid > 0) @@ -763,8 +828,10 @@ server_loop2(Authctxt *authctxt) { fd_set *readset = NULL, *writeset = NULL; int rekeying = 0, max_fd, nalloc = 0; + double start_time, total_time; debug("Entering interactive session for SSH2."); + start_time = get_current_time(); mysignal(SIGCHLD, sigchld_handler); child_terminated = 0; @@ -826,6 +893,11 @@ server_loop2(Authctxt *authctxt) /* free remaining sessions, e.g. remove wtmp entries */ session_destroy_all(NULL); + total_time = get_current_time() - start_time; + logit("SSH: Server;LType: Throughput;Remote: %s-%d;IN: %lu;OUT: %lu;Duration: %.1f;tPut_in: %.1f;tPut_out: %.1f", + get_remote_ipaddr(), get_remote_port(), + stdin_bytes, fdout_bytes, total_time, stdin_bytes / total_time, + fdout_bytes / total_time); } static void @@ -837,7 +909,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 @@ -873,10 +945,10 @@ server_input_eof(int type, u_int32_t seq, void *ctxt) static void server_input_window_size(int type, u_int32_t seq, void *ctxt) { - int row = packet_get_int(); - int col = packet_get_int(); - int xpixel = packet_get_int(); - int ypixel = packet_get_int(); + u_int row = packet_get_int(); + u_int col = packet_get_int(); + u_int xpixel = packet_get_int(); + u_int ypixel = packet_get_int(); debug("Window change received."); packet_check_eom(); @@ -908,9 +980,9 @@ server_request_direct_tcpip(void) if (sock < 0) return NULL; if (options.hpn_disabled) - c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING, - sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, - CHAN_TCP_PACKET_DEFAULT, 0, "direct-tcpip", 1); + c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING, + sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, + CHAN_TCP_PACKET_DEFAULT, 0, "direct-tcpip", 1); else c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING, sock, sock, -1, options.hpn_buffer_size, @@ -942,7 +1014,7 @@ server_request_tun(void) tun = packet_get_int(); if (forced_tun_device != -1) { - if (tun != SSH_TUNID_ANY && forced_tun_device != tun) + if (tun != SSH_TUNID_ANY && forced_tun_device != tun) goto done; tun = forced_tun_device; } @@ -950,8 +1022,8 @@ server_request_tun(void) if (sock < 0) goto done; if (options.hpn_disabled) - c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1, - CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); + c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); else c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1, options.hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); @@ -1097,6 +1169,7 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) success = channel_cancel_rport_listener(cancel_address, cancel_port); + xfree(cancel_address); } if (want_reply) { packet_start(success ? @@ -1106,6 +1179,7 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) } xfree(rtype); } + static void server_input_channel_req(int type, u_int32_t seq, void *ctxt) {