/*
 * Processes input from the client and the program.  Input data is stored
 * in buffers and processed later.
 */
static void
process_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 %.100s",
			    get_remote_ipaddr());
			connection_closed = 1;
			if (compat20)
				return;
			fatal_cleanup();
		} else if (len < 0) {
			if (errno != EINTR && errno != EAGAIN) {
				verbose("Read error from remote host "
				    "%.100s: %.100s",
				    get_remote_ipaddr(), strerror(errno));
				fatal_cleanup();
			}
		} else {
			/* Buffer any received data. */
			packet_process_incoming(buf, len);
		}
	}
	if (compat20)
		return;

	/* 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 && (errno == EINTR || errno == EAGAIN)) {
			/* do nothing */
		} else if (len <= 0) {
			fdout_eof = 1;
		} else {
			buffer_append(&stdout_buffer, buf, len);
			fdout_bytes += len;
		}
	}
	/* 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 && (errno == EINTR || errno == EAGAIN)) {
			/* do nothing */
		} else if (len <= 0) {
			fderr_eof = 1;
		} else {
			buffer_append(&stderr_buffer, buf, len);
		}
	}
}
Exemple #2
0
static int
get_sock_port(int sock, int local)
{
	struct sockaddr_storage from;
	socklen_t fromlen;
	char strport[NI_MAXSERV];

	/* Get IP address of client. */
	fromlen = sizeof(from);
	memset(&from, 0, sizeof(from));
	if (local) {
		if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
			error("getsockname failed: %.100s", strerror(errno));
			return 0;
		}
	} else {
		if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) {
			debug("getpeername failed: %.100s", strerror(errno));
			fatal_cleanup();
		}
	}
	/* Return port number. */
	if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
	    strport, sizeof(strport), NI_NUMERICSERV) != 0)
		fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
	return atoi(strport);
}
void
fatal(const char *fmt,...)
{
	va_list args;
	va_start(args, fmt);
	do_log(SYSLOG_LEVEL_FATAL, fmt, args);
	va_end(args);
	fatal_cleanup();
}
Exemple #4
0
ok_t
_log_fatal(char *file, int line, char *msg)
{
	extern void fatal_cleanup();

	_log(file, line, "FATAL", msg );
	fatal_cleanup();
	return NG;
}
Exemple #5
0
static void ATTR_NORETURN
cleanup(int signum)
{
	FATAL(SYSTEM, "receive signal %d\n", signum);
	switch (signum) {
		case SIGPIPE:
			sigpipe_arised = TRUE;
			break;
		default:
			break;
	}
	fatal_cleanup();
}
Exemple #6
0
const char *
get_remote_ipaddr(void)
{
	static char *canonical_host_ip = NULL;

	/* Check whether we have cached the ipaddr. */
	if (canonical_host_ip == NULL) {
		if (packet_connection_is_on_socket()) {
			canonical_host_ip =
			    get_peer_ipaddr(packet_get_connection_in());
			if (canonical_host_ip == NULL)
				fatal_cleanup();
		} else {
			/* If not on socket, return UNKNOWN. */
			canonical_host_ip = xstrdup("UNKNOWN");
		}
	}
	return canonical_host_ip;
}
Exemple #7
0
static void
mm_record_login(Session *s, struct passwd *pw)
{
	socklen_t fromlen;
	struct sockaddr_storage from;

	/*
	 * Get IP address of client. If the connection is not a socket, let
	 * the address be 0.0.0.0.
	 */
	memset(&from, 0, sizeof(from));
	fromlen = sizeof(from);
	if (packet_connection_is_on_socket()) {
		if (getpeername(packet_get_connection_in(),
			(struct sockaddr *) & from, &fromlen) < 0) {
			debug("getpeername: %.100s", strerror(errno));
			fatal_cleanup();
		}
	}
	/* Record that there was a login on that tty from the remote host. */
	record_login(s->pid, s->tty, pw->pw_name, pw->pw_uid,
	    get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping),
	    (struct sockaddr *)&from, fromlen);
}
Exemple #8
0
void
mm_request_receive(int socket, Buffer *m)
{
	u_char buf[4];
	u_int msg_len;
	ssize_t res;

	debug3("%s entering", __func__);

	res = atomicio(read, socket, buf, sizeof(buf));
	if (res != sizeof(buf)) {
		if (res == 0)
			fatal_cleanup();
		fatal("%s: read: %ld", __func__, (long)res);
	}
	msg_len = GET_32BIT(buf);
	if (msg_len > 256 * 1024)
		fatal("%s: read: bad msg_len %d", __func__, msg_len);
	buffer_clear(m);
	buffer_append_space(m, msg_len);
	res = atomicio(read, socket, buffer_ptr(m), msg_len);
	if (res != msg_len)
		fatal("%s: read: %ld != msg_len", __func__, (long)res);
}
int
auth_krb4(Authctxt *authctxt, KTEXT auth, char **client, KTEXT reply)
{
	AUTH_DAT adat = {0};
	Key_schedule schedule;
	struct sockaddr_in local, foreign;
	char instance[INST_SZ];
	socklen_t slen;
	u_int cksum;
	int r, s;

	s = packet_get_connection_in();

	slen = sizeof(local);
	memset(&local, 0, sizeof(local));
	if (getsockname(s, (struct sockaddr *) & local, &slen) < 0)
		debug("getsockname failed: %.100s", strerror(errno));
	slen = sizeof(foreign);
	memset(&foreign, 0, sizeof(foreign));
	if (getpeername(s, (struct sockaddr *) & foreign, &slen) < 0) {
		debug("getpeername failed: %.100s", strerror(errno));
		fatal_cleanup();
	}
	instance[0] = '*';
	instance[1] = 0;

	/* Get the encrypted request, challenge, and session key. */
	if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance,
	    0, &adat, ""))) {
		debug("Kerberos v4 krb_rd_req: %.100s", krb_err_txt[r]);
		return (0);
	}
	des_key_sched((des_cblock *) adat.session, schedule);

	*client = xmalloc(MAX_K_NAME_SZ);
	(void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname,
	    *adat.pinst ? "." : "", adat.pinst, adat.prealm);

	/* Check ~/.klogin authorization now. */
	if (kuserok(&adat, authctxt->user) != KSUCCESS) {
		log("Kerberos v4 .klogin authorization failed for %s to "
		    "account %s", *client, authctxt->user);
		xfree(*client);
		*client = NULL;
		return (0);
	}
	/* Increment the checksum, and return it encrypted with the
	   session key. */
	cksum = adat.checksum + 1;
	cksum = htonl(cksum);

	/* If we can't successfully encrypt the checksum, we send back an
	   empty message, admitting our failure. */
	if ((r = krb_mk_priv((u_char *) & cksum, reply->dat, sizeof(cksum) + 1,
	    schedule, &adat.session, &local, &foreign)) < 0) {
		debug("Kerberos v4 mk_priv: (%d) %s", r, krb_err_txt[r]);
		reply->dat[0] = 0;
		reply->length = 0;
	} else
		reply->length = r;

	/* Clear session key. */
	memset(&adat.session, 0, sizeof(&adat.session));
	return (1);
}
Exemple #10
0
static char *
get_remote_hostname(int socket, int verify_reverse_mapping)
{
	struct sockaddr_storage from;
	int i, res;
	socklen_t fromlen;
	struct addrinfo hints, *ai, *aitop;
	char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST];

	/* Get IP address of client. */
	fromlen = sizeof(from);
	memset(&from, 0, sizeof(from));
	if (getpeername(socket, (struct sockaddr *) &from, &fromlen) < 0) {
		debug("getpeername failed: %.100s", strerror(errno));
		fatal_cleanup();
	}

	if ((res = getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
	    NULL, 0, NI_NUMERICHOST)) != 0)
		fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed: %d", res);

#ifdef IPV4_IN_IPV6
	if (from.ss_family == AF_INET6) {
		struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)&from;

		(void) inet_ntop_native(from.ss_family,
				from6->sin6_addr.s6_addr,
				ntop, sizeof(ntop));
	}
#endif /* IPV4_IN_IPV6 */

	if (!verify_reverse_mapping)
		return xstrdup(ntop);

	debug3("Trying to reverse map address %.100s.", ntop);
	/* Map the IP address to a host name. */
	if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
	    NULL, 0, NI_NAMEREQD) != 0) {
		/* Host name not found.  Use ip address. */
		return xstrdup(ntop);
	}

	/* Got host name. */
	name[sizeof(name) - 1] = '\0';
	/*
	 * Convert it to all lowercase (which is expected by the rest
	 * of this software).
	 */
	for (i = 0; name[i]; i++)
		if (isupper(name[i]))
			name[i] = tolower(name[i]);

	/*
	 * Map it back to an IP address and check that the given
	 * address actually is an address of this host.  This is
	 * necessary because anyone with access to a name server can
	 * define arbitrary names for an IP address. Mapping from
	 * name to IP address can be trusted better (but can still be
	 * fooled if the intruder has access to the name server of
	 * the domain).
	 */
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = from.ss_family;
	hints.ai_socktype = SOCK_STREAM;
	if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
		log("reverse mapping checking getaddrinfo for %.700s "
		    "failed - POSSIBLE BREAKIN ATTEMPT!", name);
		return xstrdup(ntop);
	}
	/* Look for the address from the list of addresses. */
	for (ai = aitop; ai; ai = ai->ai_next) {
		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
		    sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
		    (strcmp(ntop, ntop2) == 0))
				break;
	}
	freeaddrinfo(aitop);
	/* If we reached the end of the list, the address was not there. */
	if (!ai) {
		/* Address not found for the host name. */
		log("Address %.100s maps to %.600s, but this does not "
		    "map back to the address - POSSIBLE BREAKIN ATTEMPT!",
		    ntop, name);
		return xstrdup(ntop);
	}
	return xstrdup(name);
}
static void
sshd_exchange_identification(int sock_in, int sock_out)
{
	int i, mismatch;
	int remote_major, remote_minor;
	int major, minor;
	char *s;
	char buf[256];			/* Must not be larger than remote_version. */
	char remote_version[256];	/* Must be at least as big as buf. */

	if ((options.protocol & SSH_PROTO_1) &&
	    (options.protocol & SSH_PROTO_2)) {
		major = PROTOCOL_MAJOR_1;
		minor = 99;
	} else if (options.protocol & SSH_PROTO_2) {
		major = PROTOCOL_MAJOR_2;
		minor = PROTOCOL_MINOR_2;
	} else {
		major = PROTOCOL_MAJOR_1;
		minor = PROTOCOL_MINOR_1;
	}
	snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", major, minor, SSH_VERSION);
	server_version_string = xstrdup(buf);

	if (client_version_string == NULL) {
		/* Send our protocol version identification. */
		if (atomicio(write, sock_out, server_version_string,
		    strlen(server_version_string))
		    != strlen(server_version_string)) {
			log("Could not write ident string to %s", get_remote_ipaddr());
			fatal_cleanup();
		}

		/* Read other sides version identification. */
		memset(buf, 0, sizeof(buf));
		for (i = 0; i < sizeof(buf) - 1; i++) {
			if (atomicio(read, sock_in, &buf[i], 1) != 1) {
				log("Did not receive identification string from %s",
				    get_remote_ipaddr());
				fatal_cleanup();
			}
			if (buf[i] == '\r') {
				buf[i] = 0;
				/* Kludge for F-Secure Macintosh < 1.0.2 */
				if (i == 12 &&
				    strncmp(buf, "SSH-1.5-W1.0", 12) == 0)
					break;
				continue;
			}
			if (buf[i] == '\n') {
				buf[i] = 0;
				break;
			}
		}
		buf[sizeof(buf) - 1] = 0;
		client_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(client_version_string, "SSH-%d.%d-%[^\n]\n",
	    &remote_major, &remote_minor, remote_version) != 3) {
		s = "Protocol mismatch.\n";
		(void) atomicio(write, sock_out, s, strlen(s));
		close(sock_in);
		close(sock_out);
		log("Bad protocol version identification '%.100s' from %s",
		    client_version_string, get_remote_ipaddr());
		fatal_cleanup();
	}
	debug("Client protocol version %d.%d; client software version %.100s",
	    remote_major, remote_minor, remote_version);

	compat_datafellows(remote_version);

	if (datafellows & SSH_BUG_SCANNER) {
		log("scanned from %s with %s.  Don't panic.",
		    get_remote_ipaddr(), client_version_string);
		fatal_cleanup();
	}

	mismatch = 0;
	switch (remote_major) {
	case 1:
		if (remote_minor == 99) {
			if (options.protocol & SSH_PROTO_2)
				enable_compat20();
			else
				mismatch = 1;
			break;
		}
		if (!(options.protocol & SSH_PROTO_1)) {
			mismatch = 1;
			break;
		}
		if (remote_minor < 3) {
			packet_disconnect("Your ssh version is too old and "
			    "is no longer supported.  Please install a newer version.");
		} else if (remote_minor == 3) {
			/* note that this disables agent-forwarding */
			enable_compat13();
		}
		break;
	case 2:
		if (options.protocol & SSH_PROTO_2) {
			enable_compat20();
			break;
		}
		/* FALLTHROUGH */
	default:
		mismatch = 1;
		break;
	}
	chop(server_version_string);
	debug("Local version string %.200s", server_version_string);

	if (mismatch) {
		s = "Protocol major versions differ.\n";
		(void) atomicio(write, sock_out, s, strlen(s));
		close(sock_in);
		close(sock_out);
		log("Protocol major versions differ for %s: %.200s vs. %.200s",
		    get_remote_ipaddr(),
		    server_version_string, client_version_string);
		fatal_cleanup();
	}
}