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

📄 clientloop.c

📁 OpenSSL Source code for SFTP, SSH, and many others
💻 C
📖 第 1 页 / 共 3 页
字号:
		if (len < 0 && (errno == EAGAIN || errno == EINTR))			len = 0;		if (len < 0) {			/* An error has encountered.  Perhaps there is a network problem. */			snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n",				 host, strerror(errno));			buffer_append(&stderr_buffer, buf, strlen(buf));			quit_pending = 1;			return;		}		packet_process_incoming(buf, len);	}}static voidprocess_cmdline(void){	void (*handler)(int);	char *s, *cmd;	u_short fwd_port, fwd_host_port;	char buf[1024], sfwd_port[6], sfwd_host_port[6];	int local = 0;	leave_raw_mode();	handler = signal(SIGINT, SIG_IGN);	cmd = s = read_passphrase("\r\nssh> ", RP_ECHO);	if (s == NULL)		goto out;	while (*s && isspace(*s))		s++;	if (*s == 0)		goto out;	if (strlen(s) < 2 || s[0] != '-' || !(s[1] == 'L' || s[1] == 'R')) {		log("Invalid command.");		goto out;	}	if (s[1] == 'L')		local = 1;	if (!local && !compat20) {		log("Not supported for SSH protocol version 1.");		goto out;	}	s += 2;	while (*s && isspace(*s))		s++;	if (sscanf(s, "%5[0-9]:%255[^:]:%5[0-9]",	    sfwd_port, buf, sfwd_host_port) != 3 &&	    sscanf(s, "%5[0-9]/%255[^/]/%5[0-9]",	    sfwd_port, buf, sfwd_host_port) != 3) {		log("Bad forwarding specification.");		goto out;	}	if ((fwd_port = a2port(sfwd_port)) == 0 ||	    (fwd_host_port = a2port(sfwd_host_port)) == 0) {		log("Bad forwarding port(s).");		goto out;	}	if (local) {		if (channel_setup_local_fwd_listener(fwd_port, buf,		    fwd_host_port, options.gateway_ports) < 0) {			log("Port forwarding failed.");			goto out;		}	} else		channel_request_remote_forwarding(fwd_port, buf,		    fwd_host_port);	log("Forwarding port.");out:	signal(SIGINT, handler);	enter_raw_mode();	if (cmd)		xfree(cmd);}/* process the characters one by one */static intprocess_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len){	char string[1024];	pid_t pid;	int bytes = 0;	u_int i;	u_char ch;	char *s;	for (i = 0; i < len; i++) {		/* Get one character at a time. */		ch = buf[i];		if (escape_pending) {			/* We have previously seen an escape character. */			/* Clear the flag now. */			escape_pending = 0;			/* Process the escaped character. */			switch (ch) {			case '.':				/* Terminate the connection. */				snprintf(string, sizeof string, "%c.\r\n", escape_char);				buffer_append(berr, string, strlen(string));				quit_pending = 1;				return -1;			case 'Z' - 64:				/* Suspend the program. */				/* Print a message to that effect to the user. */				snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char);				buffer_append(berr, string, strlen(string));				/* Restore terminal modes and suspend. */				client_suspend_self(bin, bout, berr);				/* We have been continued. */				continue;			case 'R':				if (compat20) {					if (datafellows & SSH_BUG_NOREKEY)						log("Server does not support re-keying");					else						need_rekeying = 1;				}				continue;			case '&':				/*				 * Detach the program (continue to serve connections,				 * but put in background and no more new connections).				 */				/* Restore tty modes. */				leave_raw_mode();				/* Stop listening for new connections. */				channel_stop_listening();				snprintf(string, sizeof string,				    "%c& [backgrounded]\n", escape_char);				buffer_append(berr, string, strlen(string));				/* Fork into background. */				pid = fork();				if (pid < 0) {					error("fork: %.100s", strerror(errno));					continue;				}				if (pid != 0) {	/* This is the parent. */					/* The parent just exits. */					exit(0);				}				/* The child continues serving connections. */				if (compat20) {					buffer_append(bin, "\004", 1);					/* fake EOF on stdin */					return -1;				} else if (!stdin_eof) {					/*					 * Sending SSH_CMSG_EOF alone does not always appear					 * to be enough.  So we try to send an EOF character					 * first.					 */					packet_start(SSH_CMSG_STDIN_DATA);					packet_put_string("\004", 1);					packet_send();					/* Close stdin. */					stdin_eof = 1;					if (buffer_len(bin) == 0) {						packet_start(SSH_CMSG_EOF);						packet_send();					}				}				continue;			case '?':				snprintf(string, sizeof string,"%c?\r\n\Supported escape sequences:\r\n\~.  - terminate connection\r\n\~C  - open a command line\r\n\~R  - Request rekey (SSH protocol 2 only)\r\n\~^Z - suspend ssh\r\n\~#  - list forwarded connections\r\n\~&  - background ssh (when waiting for connections to terminate)\r\n\~?  - this message\r\n\~~  - send the escape character by typing it twice\r\n\(Note that escapes are only recognized immediately after newline.)\r\n",					 escape_char);				buffer_append(berr, string, strlen(string));				continue;			case '#':				snprintf(string, sizeof string, "%c#\r\n", escape_char);				buffer_append(berr, string, strlen(string));				s = channel_open_message();				buffer_append(berr, s, strlen(s));				xfree(s);				continue;			case 'C':				process_cmdline();				continue;			default:				if (ch != escape_char) {					buffer_put_char(bin, escape_char);					bytes++;				}				/* Escaped characters fall through here */				break;			}		} else {			/*			 * The previous character was not an escape char. Check if this			 * is an escape.			 */			if (last_was_cr && ch == escape_char) {				/* It is. Set the flag and continue to next character. */				escape_pending = 1;				continue;			}		}		/*		 * Normal character.  Record whether it was a newline,		 * and append it to the buffer.		 */		last_was_cr = (ch == '\r' || ch == '\n');		buffer_put_char(bin, ch);		bytes++;	}	return bytes;}static voidclient_process_input(fd_set * readset){	int len;	char buf[8192];	/* Read input from stdin. */	if (FD_ISSET(fileno(stdin), readset)) {		/* Read as much as possible. */		len = read(fileno(stdin), buf, sizeof(buf));		if (len < 0 && (errno == EAGAIN || errno == EINTR))			return;		/* we'll try again later */		if (len <= 0) {			/*			 * Received EOF or error.  They are treated			 * similarly, except that an error message is printed			 * if it was an error condition.			 */			if (len < 0) {				snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));				buffer_append(&stderr_buffer, buf, strlen(buf));			}			/* Mark that we have seen EOF. */			stdin_eof = 1;			/*			 * Send an EOF message to the server unless there is			 * data in the buffer.  If there is data in the			 * buffer, no message will be sent now.  Code			 * elsewhere will send the EOF when the buffer			 * becomes empty if stdin_eof is set.			 */			if (buffer_len(&stdin_buffer) == 0) {				packet_start(SSH_CMSG_EOF);				packet_send();			}		} else if (escape_char == SSH_ESCAPECHAR_NONE) {			/*			 * Normal successful read, and no escape character.			 * Just append the data to buffer.			 */			buffer_append(&stdin_buffer, buf, len);		} else {			/*			 * Normal, successful read.  But we have an escape character			 * and have to process the characters one by one.			 */			if (process_escapes(&stdin_buffer, &stdout_buffer,			    &stderr_buffer, buf, len) == -1)				return;		}	}}static voidclient_process_output(fd_set * writeset){	int len;	char buf[100];	/* Write buffered output to stdout. */	if (FD_ISSET(fileno(stdout), writeset)) {		/* Write as much data as possible. */		len = write(fileno(stdout), buffer_ptr(&stdout_buffer),		    buffer_len(&stdout_buffer));		if (len <= 0) {			if (errno == EINTR || errno == EAGAIN)				len = 0;			else {				/*				 * An error or EOF was encountered.  Put an				 * error message to stderr buffer.				 */				snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno));				buffer_append(&stderr_buffer, buf, strlen(buf));				quit_pending = 1;				return;			}		}		/* Consume printed data from the buffer. */		buffer_consume(&stdout_buffer, len);		stdout_bytes += len;	}	/* Write buffered output to stderr. */	if (FD_ISSET(fileno(stderr), writeset)) {		/* Write as much data as possible. */		len = write(fileno(stderr), buffer_ptr(&stderr_buffer),		    buffer_len(&stderr_buffer));		if (len <= 0) {			if (errno == EINTR || errno == EAGAIN)				len = 0;			else {				/* EOF or error, but can't even print error message. */				quit_pending = 1;				return;			}		}		/* Consume printed characters from the buffer. */		buffer_consume(&stderr_buffer, len);		stderr_bytes += len;	}}/* * Get packets from the connection input buffer, and process them as long as * there are packets available. * * Any unknown packets received during the actual * session cause the session to terminate.  This is * intended to make debugging easier since no * confirmations are sent.  Any compatible protocol * extensions must be negotiated during the * preparatory phase. */static voidclient_process_buffered_input_packets(void){	dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL);}/* scan buf[] for '~' before sending data to the peer */static intsimple_escape_filter(Channel *c, char *buf, int len){	/* XXX we assume c->extended is writeable */	return process_escapes(&c->input, &c->output, &c->extended, buf, len);}static voidclient_channel_closed(int id, void *arg){	if (id != session_ident)		error("client_channel_closed: id %d != session_ident %d",		    id, session_ident);	channel_cancel_cleanup(id);	session_closed = 1;	if (in_raw_mode())		leave_raw_mode();}/* * Implements the interactive session with the server.  This is called after * the user has been authenticated, and a command has been started on the * remote host.  If escape_char != SSH_ESCAPECHAR_NONE, it is the character * used as an escape character for terminating or suspending the session. */intclient_loop(int have_pty, int escape_char_arg, int ssh2_chan_id){	fd_set *readset = NULL, *writeset = NULL;	double start_time, total_time;	int max_fd = 0, max_fd2 = 0, len, rekeying = 0, nalloc = 0;	char buf[100];	debug("Entering interactive session.");	start_time = get_current_time();	/* Initialize variables. */	escape_pending = 0;	last_was_cr = 1;	exit_status = -1;	stdin_eof = 0;	buffer_high = 64 * 1024;	connection_in = packet_get_connection_in();	connection_out = packet_get_connection_out();	max_fd = MAX(connection_in, connection_out);	if (!compat20) {		/* enable nonblocking unless tty */		if (!isatty(fileno(stdin)))			set_nonblock(fileno(stdin));		if (!isatty(fileno(stdout)))			set_nonblock(fileno(stdout));		if (!isatty(fileno(stderr)))			set_nonblock(fileno(stderr));		max_fd = MAX(max_fd, fileno(stdin));		max_fd = MAX(max_fd, fileno(stdout));		max_fd = MAX(max_fd, fileno(stderr));	}	stdin_bytes = 0;	stdout_bytes = 0;	stderr_bytes = 0;	quit_pending = 0;	escape_char = escape_char_arg;	/* Initialize buffers. */	buffer_init(&stdin_buffer);	buffer_init(&stdout_buffer);	buffer_init(&stderr_buffer);	client_init_dispatch();	/* Set signal handlers to restore non-blocking mode.  */	signal(SIGINT, signal_handler);	signal(SIGQUIT, signal_handler);	signal(SIGTERM, signal_handler);	if (have_pty)		signal(SIGWINCH, window_change_handler);	if (have_pty)		enter_raw_mode();	if (compat20) {		session_ident = ssh2_chan_id;		if (escape_char != SSH_ESCAPECHAR_NONE)			channel_register_filter(session_ident,			    simple_escape_filter);		if (session_ident != -1)			channel_register_cleanup(session_ident,			    client_channel_closed);	} else {		/* Check if we should immediately send eof on stdin. */		client_check_initial_eof_on_stdin();	}	/* Main loop of the client for the interactive session mode. */	while (!quit_pending) {		/* Process buffered packets sent by the server. */		client_process_buffered_input_packets();

⌨️ 快捷键说明

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