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

📄 sshconnect.c

📁 OpenSSL Source code for SFTP, SSH, and many others
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland *                    All rights reserved * Code to connect to a remote host, and to perform the client side of the * login (authentication) dialog. * * 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". */#include "includes.h"RCSID("$OpenBSD: sshconnect.c,v 1.125 2002/06/19 00:27:55 deraadt Exp $");#include <openssl/bn.h>#include "ssh.h"#include "xmalloc.h"#include "rsa.h"#include "buffer.h"#include "packet.h"#include "uidswap.h"#include "compat.h"#include "key.h"#include "sshconnect.h"#include "hostfile.h"#include "log.h"#include "readconf.h"#include "atomicio.h"#include "misc.h"#include "readpass.h"char *client_version_string = NULL;char *server_version_string = NULL;/* import */extern Options options;extern char *__progname;extern uid_t original_real_uid;extern uid_t original_effective_uid;#ifndef INET6_ADDRSTRLEN		/* for non IPv6 machines */#define INET6_ADDRSTRLEN 46#endifstatic const char *sockaddr_ntop(struct sockaddr *sa, socklen_t salen){	static char addrbuf[NI_MAXHOST];	if (getnameinfo(sa, salen, addrbuf, sizeof(addrbuf), NULL, 0,	    NI_NUMERICHOST) != 0)		fatal("sockaddr_ntop: getnameinfo NI_NUMERICHOST failed");	return addrbuf;}/* * Connect to the given ssh server using a proxy command. */static intssh_proxy_connect(const char *host, u_short port, const char *proxy_command){	Buffer command;	const char *cp;	char *command_string;	int pin[2], pout[2];	pid_t pid;	char strport[NI_MAXSERV];	/* Convert the port number into a string. */	snprintf(strport, sizeof strport, "%hu", port);	/* Build the final command string in the buffer by making the	   appropriate substitutions to the given proxy command. */	buffer_init(&command);	for (cp = proxy_command; *cp; cp++) {		if (cp[0] == '%' && cp[1] == '%') {			buffer_append(&command, "%", 1);			cp++;			continue;		}		if (cp[0] == '%' && cp[1] == 'h') {			buffer_append(&command, host, strlen(host));			cp++;			continue;		}		if (cp[0] == '%' && cp[1] == 'p') {			buffer_append(&command, strport, strlen(strport));			cp++;			continue;		}		buffer_append(&command, cp, 1);	}	buffer_append(&command, "\0", 1);	/* Get the final command string. */	command_string = buffer_ptr(&command);	/* Create pipes for communicating with the proxy. */	if (pipe(pin) < 0 || pipe(pout) < 0)		fatal("Could not create pipes to communicate with the proxy: %.100s",		    strerror(errno));	debug("Executing proxy command: %.500s", command_string);	/* Fork and execute the proxy command. */	if ((pid = fork()) == 0) {		char *argv[10];		/* Child.  Permanently give up superuser privileges. */		seteuid(original_real_uid);		setuid(original_real_uid);		/* Redirect stdin and stdout. */		close(pin[1]);		if (pin[0] != 0) {			if (dup2(pin[0], 0) < 0)				perror("dup2 stdin");			close(pin[0]);		}		close(pout[0]);		if (dup2(pout[1], 1) < 0)			perror("dup2 stdout");		/* Cannot be 1 because pin allocated two descriptors. */		close(pout[1]);		/* Stderr is left as it is so that error messages get		   printed on the user's terminal. */		argv[0] = _PATH_BSHELL;		argv[1] = "-c";		argv[2] = command_string;		argv[3] = NULL;		/* Execute the proxy command.  Note that we gave up any		   extra privileges above. */		execv(argv[0], argv);		perror(argv[0]);		exit(1);	}	/* Parent. */	if (pid < 0)		fatal("fork failed: %.100s", strerror(errno));	/* Close child side of the descriptors. */	close(pin[0]);	close(pout[1]);	/* Free the command name. */	buffer_free(&command);	/* Set the connection file descriptors. */	packet_set_connection(pout[0], pin[1]);	/* Indicate OK return */	return 0;}/* * Creates a (possibly privileged) socket for use as the ssh connection. */static intssh_create_socket(int privileged, int family){	int sock, gaierr;	struct addrinfo hints, *res;	/*	 * If we are running as root and want to connect to a privileged	 * port, bind our own socket to a privileged port.	 */	if (privileged) {		int p = IPPORT_RESERVED - 1;		PRIV_START;		sock = rresvport_af(&p, family);		PRIV_END;		if (sock < 0)			error("rresvport: af=%d %.100s", family, strerror(errno));		else			debug("Allocated local port %d.", p);		return sock;	}	sock = socket(family, SOCK_STREAM, 0);	if (sock < 0)		error("socket: %.100s", strerror(errno));	/* Bind the socket to an alternative local IP address */	if (options.bind_address == NULL)		return sock;	memset(&hints, 0, sizeof(hints));	hints.ai_family = family;	hints.ai_socktype = SOCK_STREAM;	hints.ai_flags = AI_PASSIVE;	gaierr = getaddrinfo(options.bind_address, "0", &hints, &res);	if (gaierr) {		error("getaddrinfo: %s: %s", options.bind_address,		    gai_strerror(gaierr));		close(sock);		return -1;	}	if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {		error("bind: %s: %s", options.bind_address, strerror(errno));		close(sock);		freeaddrinfo(res);		return -1;	}	freeaddrinfo(res);	return sock;}/* * Opens a TCP/IP connection to the remote server on the given host. * The address of the remote host will be returned in hostaddr. * If port is 0, the default port will be used.  If needpriv is true, * a privileged port will be allocated to make the connection. * This requires super-user privileges if needpriv is true. * Connection_attempts specifies the maximum number of tries (one per * second).  If proxy_command is non-NULL, it specifies the command (with %h * and %p substituted for host and port, respectively) to use to contact * the daemon. * Return values: *    0 for OK *    ECONNREFUSED if we got a "Connection Refused" by the peer on any address *    ECONNABORTED if we failed without a "Connection refused" * Suitable error messages for the connection failure will already have been * printed. */intssh_connect(const char *host, struct sockaddr_storage * hostaddr,    u_short port, int family, int connection_attempts,    int needpriv, const char *proxy_command){	int gaierr;	int on = 1;	int sock = -1, attempt;	char ntop[NI_MAXHOST], strport[NI_MAXSERV];	struct addrinfo hints, *ai, *aitop;	struct linger linger;	struct servent *sp;	/*	 * Did we get only other errors than "Connection refused" (which	 * should block fallback to rsh and similar), or did we get at least	 * one "Connection refused"?	 */	int full_failure = 1;	debug("ssh_connect: needpriv %d", needpriv);	/* Get default port if port has not been set. */	if (port == 0) {		sp = getservbyname(SSH_SERVICE_NAME, "tcp");		if (sp)			port = ntohs(sp->s_port);		else			port = SSH_DEFAULT_PORT;	}	/* If a proxy command is given, connect using it. */	if (proxy_command != NULL)		return ssh_proxy_connect(host, port, proxy_command);	/* No proxy command. */	memset(&hints, 0, sizeof(hints));	hints.ai_family = family;	hints.ai_socktype = SOCK_STREAM;	snprintf(strport, sizeof strport, "%d", port);	if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)		fatal("%s: %.100s: %s", __progname, host,		    gai_strerror(gaierr));	/*	 * Try to connect several times.  On some machines, the first time	 * will sometimes fail.  In general socket code appears to behave	 * quite magically on many machines.		 */	for (attempt = 0; ;) {		if (attempt > 0)			debug("Trying again...");		/* Loop through addresses for this host, and try each one in		   sequence until the connection succeeds. */		for (ai = aitop; ai; ai = ai->ai_next) {			if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)				continue;			if (getnameinfo(ai->ai_addr, ai->ai_addrlen,			    ntop, sizeof(ntop), strport, sizeof(strport),			    NI_NUMERICHOST|NI_NUMERICSERV) != 0) {				error("ssh_connect: getnameinfo failed");				continue;			}			debug("Connecting to %.200s [%.100s] port %s.",				host, ntop, strport);			/* Create a socket for connecting. */			sock = ssh_create_socket(needpriv, ai->ai_family);			if (sock < 0)				/* Any error is already output */				continue;			if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) {				/* Successful connection. */				memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);				break;			} else {				if (errno == ECONNREFUSED)					full_failure = 0;				log("ssh: connect to address %s port %s: %s",				    sockaddr_ntop(ai->ai_addr, ai->ai_addrlen),				    strport, strerror(errno));				/*				 * Close the failed socket; there appear to				 * be some problems when reusing a socket for				 * which connect() has already returned an				 * error.				 */				close(sock);			}		}		if (ai)			break;	/* Successful connection. */		attempt++;		if (attempt >= connection_attempts)			break;		/* Sleep a moment before retrying. */		sleep(1);	}	freeaddrinfo(aitop);	/* Return failure if we didn't get a successful connection. */	if (attempt >= connection_attempts)		return full_failure ? ECONNABORTED : ECONNREFUSED;	debug("Connection established.");	/*	 * Set socket options.  We would like the socket to disappear as soon	 * as it has been closed for whatever reason.	 */	/* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */	linger.l_onoff = 1;	linger.l_linger = 5;	setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));	/* Set keepalives if requested. */	if (options.keepalives &&	    setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,	    sizeof(on)) < 0)		error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));	/* Set the connection. */	packet_set_connection(sock, sock);	return 0;}/* * Waits for the server identification string, and sends our own * identification string. */static voidssh_exchange_identification(void){	char buf[256], remote_version[256];	/* must be same size! */	int remote_major, remote_minor, i, mismatch;	int connection_in = packet_get_connection_in();	int connection_out = packet_get_connection_out();	int minor1 = PROTOCOL_MINOR_1;	/* Read other side\'s version identification. */	for (;;) {		for (i = 0; i < sizeof(buf) - 1; i++) {			int len = atomicio(read, connection_in, &buf[i], 1);			if (len < 0)				fatal("ssh_exchange_identification: read: %.100s", strerror(errno));			if (len != 1)				fatal("ssh_exchange_identification: Connection closed by remote host");			if (buf[i] == '\r') {				buf[i] = '\n';				buf[i + 1] = 0;				continue;		/**XXX wait for \n */			}			if (buf[i] == '\n') {				buf[i + 1] = 0;				break;			}		}		buf[sizeof(buf) - 1] = 0;		if (strncmp(buf, "SSH-", 4) == 0)			break;		debug("ssh_exchange_identification: %s", buf);	}	server_version_string = xstrdup(buf);	/*	 * Check that the versions match.  In future this might accept	 * several versions and set appropriate flags to handle them.	 */	if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n",	    &remote_major, &remote_minor, remote_version) != 3)		fatal("Bad remote protocol version identification: '%.100s'", buf);	debug("Remote protocol version %d.%d, remote software version %.100s",	    remote_major, remote_minor, remote_version);	compat_datafellows(remote_version);	mismatch = 0;	switch (remote_major) {	case 1:		if (remote_minor == 99 &&		    (options.protocol & SSH_PROTO_2) &&		    !(options.protocol & SSH_PROTO_1_PREFERRED)) {			enable_compat20();			break;		}		if (!(options.protocol & SSH_PROTO_1)) {			mismatch = 1;			break;		}		if (remote_minor < 3) {			fatal("Remote machine has too old SSH software version.");		} else if (remote_minor == 3 || remote_minor == 4) {			/* We speak 1.3, too. */			enable_compat13();			minor1 = 3;			if (options.forward_agent) {				log("Agent forwarding disabled for protocol 1.3");				options.forward_agent = 0;			}		}		break;	case 2:

⌨️ 快捷键说明

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