X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/a306f2dd74b7488671decc385f82830c98f4a0d3..22d89d24e31f308cfaf0407fd29451f042ebb8d6:/serverloop.c diff --git a/serverloop.c b/serverloop.c index 1e031873..50e89aee 100644 --- a/serverloop.c +++ b/serverloop.c @@ -2,12 +2,36 @@ * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved - * Created: Sun Sep 10 00:30:37 1995 ylo * Server main loop for handling the interactive session. - */ -/* + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + * * SSH2 support by Markus Friedl. * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" @@ -23,6 +47,7 @@ #include "ssh2.h" #include "session.h" #include "dispatch.h" +#include "auth-options.h" static Buffer stdin_buffer; /* Buffer for stdin data. */ static Buffer stdout_buffer; /* Buffer for stdout data. */ @@ -85,7 +110,6 @@ sigchld_handler2(int sig) int save_errno = errno; debug("Received SIGCHLD."); child_terminated = 1; - signal(SIGCHLD, sigchld_handler2); errno = save_errno; } @@ -165,33 +189,37 @@ retry_select: /* Initialize select() masks. */ FD_ZERO(readset); + FD_ZERO(writeset); - /* - * Read packets from the client unless we have too much buffered - * stdin or channel data. - */ if (compat20) { - // wrong: bad conditionXXX + /* wrong: bad condition XXX */ if (channel_not_very_much_buffered_data()) FD_SET(connection_in, readset); } else { - if (buffer_len(&stdin_buffer) < 4096 && + /* + * Read packets from the client unless we have too much + * buffered stdin or channel data. + */ + if (buffer_len(&stdin_buffer) < buffer_high && channel_not_very_much_buffered_data()) FD_SET(connection_in, readset); + /* + * If there is not too much data already buffered going to + * the client, try to get some more data from the program. + */ + if (packet_not_very_much_data_to_write()) { + if (!fdout_eof) + FD_SET(fdout, readset); + if (!fderr_eof) + FD_SET(fderr, readset); + } + /* + * If we have buffered data, try to write some of that data + * to the program. + */ + if (fdin != -1 && buffer_len(&stdin_buffer) > 0) + FD_SET(fdin, writeset); } - - /* - * If there is not too much data already buffered going to the - * client, try to get some more data from the program. - */ - if (!compat20 && packet_not_very_much_data_to_write()) { - if (!fdout_eof) - FD_SET(fdout, readset); - if (!fderr_eof) - FD_SET(fderr, readset); - } - FD_ZERO(writeset); - /* Set masks for channel descriptors. */ channel_prepare_select(readset, writeset); @@ -202,11 +230,6 @@ retry_select: if (packet_have_data_to_write()) FD_SET(connection_out, writeset); - /* If we have buffered data, try to write some of that data to the - program. */ - if (!compat20 && fdin != -1 && buffer_len(&stdin_buffer) > 0) - FD_SET(fdin, writeset); - /* Update the maximum descriptor number if appropriate. */ if (channel_max_fd() > max_fd) max_fd = channel_max_fd(); @@ -259,20 +282,15 @@ process_input(fd_set * readset) if (len == 0) { verbose("Connection closed by remote host."); fatal_cleanup(); + } else if (len < 0) { + if (errno != EINTR && errno != EAGAIN) { + verbose("Read error from remote host: %.100s", strerror(errno)); + fatal_cleanup(); + } + } else { + /* Buffer any received data. */ + packet_process_incoming(buf, len); } - /* - * There is a kernel bug on Solaris that causes select to - * sometimes wake up even though there is no data available. - */ - if (len < 0 && errno == EAGAIN) - len = 0; - - if (len < 0) { - verbose("Read error from remote host: %.100s", strerror(errno)); - fatal_cleanup(); - } - /* Buffer any received data. */ - packet_process_incoming(buf, len); } if (compat20) return; @@ -280,9 +298,11 @@ process_input(fd_set * readset) /* Read and buffer any available stdout data from the program. */ if (!fdout_eof && FD_ISSET(fdout, readset)) { len = read(fdout, buf, sizeof(buf)); - if (len <= 0) + if (len < 0 && (errno == EINTR || errno == EAGAIN)) { + /* do nothing */ + } else if (len <= 0) { fdout_eof = 1; - else { + } else { buffer_append(&stdout_buffer, buf, len); fdout_bytes += len; } @@ -290,10 +310,13 @@ process_input(fd_set * readset) /* Read and buffer any available stderr data from the program. */ if (!fderr_eof && FD_ISSET(fderr, readset)) { len = read(fderr, buf, sizeof(buf)); - if (len <= 0) + if (len < 0 && (errno == EINTR || errno == EAGAIN)) { + /* do nothing */ + } else if (len <= 0) { fderr_eof = 1; - else + } else { buffer_append(&stderr_buffer, buf, len); + } } } @@ -309,7 +332,9 @@ process_output(fd_set * writeset) if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) { len = write(fdin, buffer_ptr(&stdin_buffer), buffer_len(&stdin_buffer)); - if (len <= 0) { + if (len < 0 && (errno == EINTR || errno == EAGAIN)) { + /* do nothing */ + } else if (len <= 0) { #ifdef USE_PIPES close(fdin); #else @@ -363,7 +388,7 @@ drain_output() void process_buffered_input_packets() { - dispatch_run(DISPATCH_NONBLOCK, NULL); + dispatch_run(DISPATCH_NONBLOCK, NULL, NULL); } /* @@ -376,6 +401,7 @@ process_buffered_input_packets() void server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) { + fd_set readset, writeset; int wait_status; /* Status returned by wait(). */ pid_t wait_pid; /* pid returned by wait(). */ int waiting_termination = 0; /* Have displayed waiting close message. */ @@ -396,6 +422,14 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) fdin = fdin_arg; fdout = fdout_arg; fderr = fderr_arg; + + /* nonblocking IO */ + set_nonblock(fdin); + set_nonblock(fdout); + /* we don't have stderr for interactive terminal sessions, see below */ + if (fderr != -1) + set_nonblock(fderr); + connection_in = packet_get_connection_in(); connection_out = packet_get_connection_out(); @@ -436,7 +470,6 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) /* Main loop of the server for the interactive session mode. */ for (;;) { - fd_set readset, writeset; /* Process buffered packets from the client. */ process_buffered_input_packets(); @@ -640,6 +673,9 @@ server_loop2(void) while ((pid = waitpid(-1, &status, WNOHANG)) > 0) session_close_by_pid(pid, status); child_terminated = 0; + signal(SIGCHLD, sigchld_handler2); + if (used_sessions() == 0) + break; } channel_after_select(&readset, &writeset); process_input(&readset); @@ -652,7 +688,7 @@ server_loop2(void) } void -server_input_stdin_data(int type, int plen) +server_input_stdin_data(int type, int plen, void *ctxt) { char *data; unsigned int data_len; @@ -669,7 +705,7 @@ server_input_stdin_data(int type, int plen) } void -server_input_eof(int type, int plen) +server_input_eof(int type, int plen, void *ctxt) { /* * Eof from the client. The stdin descriptor to the @@ -682,7 +718,7 @@ server_input_eof(int type, int plen) } void -server_input_window_size(int type, int plen) +server_input_window_size(int type, int plen, void *ctxt) { int row = packet_get_int(); int col = packet_get_int(); @@ -707,18 +743,28 @@ input_direct_tcpip(void) originator = packet_get_string(NULL); originator_port = packet_get_int(); packet_done(); + + debug("open direct-tcpip: from %s port %d to %s port %d", + originator, originator_port, target, target_port); + /* XXX check permission */ + if (no_port_forwarding_flag) { + xfree(target); + xfree(originator); + return -1; + } sock = channel_connect_to(target, target_port); xfree(target); xfree(originator); if (sock < 0) return -1; return channel_new("direct-tcpip", SSH_CHANNEL_OPEN, - sock, sock, -1, 4*1024, 32*1024, 0, xstrdup("direct-tcpip")); + sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, + CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip")); } void -server_input_channel_open(int type, int plen) +server_input_channel_open(int type, int plen, void *ctxt) { Channel *c = NULL; char *ctype; @@ -733,7 +779,7 @@ server_input_channel_open(int type, int plen) rwindow = packet_get_int(); rmaxpack = packet_get_int(); - debug("channel_input_open: ctype %s rchan %d win %d max %d", + debug("server_input_channel_open: ctype %s rchan %d win %d max %d", ctype, rchan, rwindow, rmaxpack); if (strcmp(ctype, "session") == 0) { @@ -747,7 +793,8 @@ server_input_channel_open(int type, int plen) * CHANNEL_REQUEST messages is registered. */ id = channel_new(ctype, SSH_CHANNEL_LARVAL, - -1, -1, -1, 0, 32*1024, 0, xstrdup("server-session")); + -1, -1, -1, 0, CHAN_SES_PACKET_DEFAULT, + 0, xstrdup("server-session")); if (session_open(id) == 1) { channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST, session_input_channel_req, (void *)0); @@ -758,7 +805,6 @@ server_input_channel_open(int type, int plen) channel_free(id); } } else if (strcmp(ctype, "direct-tcpip") == 0) { - debug("open direct-tcpip"); id = input_direct_tcpip(); if (id >= 0) c = channel_lookup(id);