⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serverloop.c

📁 OpenSSL Source code for SFTP, SSH, and many others
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland *                    All rights reserved * 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, 2001 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"RCSID("$OpenBSD: serverloop.c,v 1.102 2002/06/11 05:46:20 mpech Exp $");#include "xmalloc.h"#include "packet.h"#include "buffer.h"#include "log.h"#include "servconf.h"#include "sshpty.h"#include "channels.h"#include "compat.h"#include "ssh1.h"#include "ssh2.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;/* XXX */extern Kex *xxx_kex;static Authctxt *xxx_authctxt;static Buffer stdin_buffer;	/* Buffer for stdin data. */static Buffer stdout_buffer;	/* Buffer for stdout data. */static Buffer stderr_buffer;	/* Buffer for stderr data. */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 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. */static int fdin_is_tty = 0;	/* fdin points to a tty. */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 * will exit after that, as soon as forwarded connections have terminated. */static volatile sig_atomic_t child_terminated = 0;	/* The child has terminated. *//* prototypes */static void server_init_dispatch(void);/* * we write to this pipe if a SIGCHLD is caught in order to avoid * the race between select() and child_terminated */static int notify_pipe[2];static voidnotify_setup(void){	if (pipe(notify_pipe) < 0) {		error("pipe(notify_pipe) failed %s", strerror(errno));	} else if ((fcntl(notify_pipe[0], F_SETFD, 1) == -1) ||	    (fcntl(notify_pipe[1], F_SETFD, 1) == -1)) {		error("fcntl(notify_pipe, F_SETFD) failed %s", strerror(errno));		close(notify_pipe[0]);		close(notify_pipe[1]);	} else {		set_nonblock(notify_pipe[0]);		set_nonblock(notify_pipe[1]);		return;	}	notify_pipe[0] = -1;	/* read end */	notify_pipe[1] = -1;	/* write end */}static voidnotify_parent(void){	if (notify_pipe[1] != -1)		write(notify_pipe[1], "", 1);}static voidnotify_prepare(fd_set *readset){	if (notify_pipe[0] != -1)		FD_SET(notify_pipe[0], readset);}static voidnotify_done(fd_set *readset){	char c;	if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset))		while (read(notify_pipe[0], &c, 1) != -1)			debug2("notify_done: reading");}static voidsigchld_handler(int sig){	int save_errno = errno;	debug("Received SIGCHLD.");	child_terminated = 1;	mysignal(SIGCHLD, sigchld_handler);	notify_parent();	errno = save_errno;}/* * Make packets from buffered stderr data, and buffer it for sending * to the client. */static voidmake_packets_from_stderr_data(void){	int len;	/* Send buffered stderr data to the client. */	while (buffer_len(&stderr_buffer) > 0 &&	    packet_not_very_much_data_to_write()) {		len = buffer_len(&stderr_buffer);		if (packet_is_interactive()) {			if (len > 512)				len = 512;		} else {			/* Keep the packets at reasonable size. */			if (len > packet_get_maxsize())				len = packet_get_maxsize();		}		packet_start(SSH_SMSG_STDERR_DATA);		packet_put_string(buffer_ptr(&stderr_buffer), len);		packet_send();		buffer_consume(&stderr_buffer, len);		stderr_bytes += len;	}}/* * Make packets from buffered stdout data, and buffer it for sending to the * client. */static voidmake_packets_from_stdout_data(void){	int len;	/* Send buffered stdout data to the client. */	while (buffer_len(&stdout_buffer) > 0 &&	    packet_not_very_much_data_to_write()) {		len = buffer_len(&stdout_buffer);		if (packet_is_interactive()) {			if (len > 512)				len = 512;		} else {			/* Keep the packets at reasonable size. */			if (len > packet_get_maxsize())				len = packet_get_maxsize();		}		packet_start(SSH_SMSG_STDOUT_DATA);		packet_put_string(buffer_ptr(&stdout_buffer), len);		packet_send();		buffer_consume(&stdout_buffer, len);		stdout_bytes += len;	}}static voidclient_alive_check(void){	static int had_channel = 0;	int id;	id = channel_find_open();	if (id == -1) {		if (!had_channel)			return;		packet_disconnect("No open channels after timeout!");	}	had_channel = 1;	/* 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.");	/*	 * send a bogus channel request with "wantreply",	 * we should get back a failure	 */	channel_request_start(id, "keepalive@openssh.com", 1);	packet_send();}/* * Sleep in select() until we can do something.  This will initialize the * select masks.  Upon return, the masks will indicate which descriptors * have data or can accept data.  Optionally, a maximum time can be specified * for the duration of the wait (0 = infinite). */static voidwait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,    int *nallocp, u_int max_time_milliseconds){	struct timeval tv, *tvp;	int ret;	int client_alive_scheduled = 0;	/*	 * if using client_alive, set the max timeout accordingly,	 * and indicate that this particular timeout was for client	 * alive by setting the client_alive_scheduled flag.	 *	 * this could be randomized somewhat to make traffic	 * analysis more difficult, but we're not doing it yet.	 */	if (compat20 &&	    max_time_milliseconds == 0 && options.client_alive_interval) {		client_alive_scheduled = 1;		max_time_milliseconds = options.client_alive_interval * 1000;	}	/* Allocate and update select() masks for channel descriptors. */	channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 0);	if (compat20) {#if 0		/* wrong: bad condition XXX */		if (channel_not_very_much_buffered_data())#endif		FD_SET(connection_in, *readsetp);	} else {		/*		 * 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, *readsetp);		/*		 * 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, *readsetp);			if (!fderr_eof)				FD_SET(fderr, *readsetp);		}		/*		 * 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, *writesetp);	}	notify_prepare(*readsetp);	/*	 * If we have buffered packet data going to the client, mark that	 * descriptor.	 */	if (packet_have_data_to_write())		FD_SET(connection_out, *writesetp);	/*	 * If child has terminated and there is enough buffer space to read	 * from it, then read as much as is available and exit.	 */	if (child_terminated && packet_not_very_much_data_to_write())		if (max_time_milliseconds == 0 || client_alive_scheduled)			max_time_milliseconds = 100;	if (max_time_milliseconds == 0)		tvp = NULL;	else {		tv.tv_sec = max_time_milliseconds / 1000;		tv.tv_usec = 1000 * (max_time_milliseconds % 1000);		tvp = &tv;	}	/* Wait for something to happen, or the timeout to expire. */	ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);	if (ret == -1) {		memset(*readsetp, 0, *nallocp);		memset(*writesetp, 0, *nallocp);		if (errno != EINTR)			error("select: %.100s", strerror(errno));	} else if (ret == 0 && client_alive_scheduled)		client_alive_check();	notify_done(*readsetp);}/* * Processes input from the client and the program.  Input data is stored * in buffers and processed later. */static voidprocess_input(fd_set * readset){	int len;	char buf[16384];	/* Read and buffer any input data from the client. */	if (FD_ISSET(connection_in, readset)) {		len = read(connection_in, buf, sizeof(buf));		if (len == 0) {			verbose("Connection closed by remote host.");			connection_closed = 1;			if (compat20)				return;			fatal_cleanup();		} else if (len < 0) {			if (errno != EINTR && errno != EAGAIN) {				verbose("Read error from remote host: %.100s", strerror(errno));				fatal_cleanup();			}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -