From 95f1eccc45470eefc565e2d58694cba940857df3 Mon Sep 17 00:00:00 2001 From: damien Date: Mon, 13 Dec 1999 23:47:15 +0000 Subject: [PATCH] - OpenBSD CVS Changes - [canohost.c] fix get_remote_port() and friends for sshd -i; Holger.Trapp@Informatik.TU-Chemnitz.DE - [mpaux.c] make code simpler. no need for memcpy. niels@ ok - [pty.c] namebuflen not sizeof namebuflen; bnd@ep-ag.com via djm@mindrot.org fix proto; markus - [ssh.1] typo; mark.baushke@solipsa.com - [channels.c ssh.c ssh.h sshd.c] type conflict for 'extern Type *options' in channels.c; dot@dotat.at - [sshconnect.c] move checking of hostkey into own function. - [version.h] OpenSSH-1.2.1 --- ChangeLog | 19 ++++ canohost.c | 28 +++++- channels.c | 18 ++-- mpaux.c | 10 +-- pty.c | 3 +- ssh.1 | 4 +- ssh.c | 3 +- ssh.h | 4 +- sshconnect.c | 244 ++++++++++++++++++++++++++++----------------------- sshd.c | 34 +++---- version.h | 2 +- 11 files changed, 220 insertions(+), 149 deletions(-) diff --git a/ChangeLog b/ChangeLog index 28032d24..07966017 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +19991214 + - OpenBSD CVS Changes + - [canohost.c] + fix get_remote_port() and friends for sshd -i; + Holger.Trapp@Informatik.TU-Chemnitz.DE + - [mpaux.c] + make code simpler. no need for memcpy. niels@ ok + - [pty.c] + namebuflen not sizeof namebuflen; bnd@ep-ag.com via djm@mindrot.org + fix proto; markus + - [ssh.1] + typo; mark.baushke@solipsa.com + - [channels.c ssh.c ssh.h sshd.c] + type conflict for 'extern Type *options' in channels.c; dot@dotat.at + - [sshconnect.c] + move checking of hostkey into own function. + - [version.h] + OpenSSH-1.2.1 + 19991211 - Fix compilation on systems with AFS. Reported by aloomis@glue.umd.edu diff --git a/canohost.c b/canohost.c index 48a7bfdc..5890a127 100644 --- a/canohost.c +++ b/canohost.c @@ -143,6 +143,28 @@ check_ip_options: static char *canonical_host_name = NULL; static char *canonical_host_ip = NULL; +/* Returns 1 if remote host is connected via socket, 0 if not. */ + +int +peer_connection_is_on_socket() +{ + struct sockaddr_in from; + int fromlen; + int in = packet_get_connection_in(); + int out = packet_get_connection_out(); + + /* filedescriptors in and out are the same, so it's a socket */ + if (in == out) + return 1; + fromlen = sizeof(from); + memset(&from, 0, sizeof(from)); + if (getpeername(in, (struct sockaddr *) & from, &fromlen) < 0) + return 0; + if (from.sin_family != AF_INET && from.sin_family != AF_INET6) + return 0; + return 1; +} + /* * Return the canonical name of the host in the other side of the current * connection. The host name is cached, so it is efficient to call this @@ -157,7 +179,7 @@ get_canonical_hostname() return canonical_host_name; /* Get the real hostname if socket; otherwise return UNKNOWN. */ - if (packet_get_connection_in() == packet_get_connection_out()) + if (peer_connection_is_on_socket()) canonical_host_name = get_remote_hostname(packet_get_connection_in()); else canonical_host_name = xstrdup("UNKNOWN"); @@ -181,7 +203,7 @@ get_remote_ipaddr() return canonical_host_ip; /* If not a socket, return UNKNOWN. */ - if (packet_get_connection_in() != packet_get_connection_out()) { + if (!peer_connection_is_on_socket()) { canonical_host_ip = xstrdup("UNKNOWN"); return canonical_host_ip; } @@ -232,7 +254,7 @@ get_remote_port() * If the connection is not a socket, return 65535. This is * intentionally chosen to be an unprivileged port number. */ - if (packet_get_connection_in() != packet_get_connection_out()) + if (!peer_connection_is_on_socket()) return 65535; /* Get client socket. */ diff --git a/channels.c b/channels.c index 0d8fb54b..01fbb9d3 100644 --- a/channels.c +++ b/channels.c @@ -877,11 +877,10 @@ channel_open_message() void channel_request_local_forwarding(u_short port, const char *host, - u_short host_port) + u_short host_port, int gateway_ports) { int ch, sock, on = 1; struct sockaddr_in sin; - extern Options options; struct linger linger; if (strlen(host) > sizeof(channels[0].path) - 1) @@ -895,7 +894,7 @@ channel_request_local_forwarding(u_short port, const char *host, /* Initialize socket address. */ memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; - if (options.gateway_ports == 1) + if (gateway_ports == 1) sin.sin_addr.s_addr = htonl(INADDR_ANY); else sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); @@ -983,9 +982,11 @@ channel_input_port_forward_request(int is_root) if (port < IPPORT_RESERVED && !is_root) packet_disconnect("Requested forwarding of port %d but user is not root.", port); - - /* Initiate forwarding. */ - channel_request_local_forwarding(port, hostname, host_port); + /* + * Initiate forwarding, + * bind port to localhost only (gateway ports == 0). + */ + channel_request_local_forwarding(port, hostname, host_port, 0); /* Free the argument string. */ xfree(hostname); @@ -1116,16 +1117,15 @@ fail: */ char * -x11_create_display_inet(int screen_number) +x11_create_display_inet(int screen_number, int x11_display_offset) { - extern ServerOptions options; int display_number, sock; u_short port; struct sockaddr_in sin; char buf[512]; char hostname[MAXHOSTNAMELEN]; - for (display_number = options.x11_display_offset; + for (display_number = x11_display_offset; display_number < MAX_DISPLAYS; display_number++) { port = 6000 + display_number; diff --git a/mpaux.c b/mpaux.c index 331089ae..3a235023 100644 --- a/mpaux.c +++ b/mpaux.c @@ -35,17 +35,17 @@ compute_session_id(unsigned char session_id[16], BIGNUM* host_key_n, BIGNUM* session_key_n) { - unsigned int host_key_bits = BN_num_bits(host_key_n); - unsigned int session_key_bits = BN_num_bits(session_key_n); - unsigned int bytes = (host_key_bits + 7) / 8 + (session_key_bits + 7) / 8 + 8; + unsigned int host_key_bytes = BN_num_bytes(host_key_n); + unsigned int session_key_bytes = BN_num_bytes(session_key_n); + unsigned int bytes = host_key_bytes + session_key_bytes; unsigned char *buf = xmalloc(bytes); MD5_CTX md; BN_bn2bin(host_key_n, buf); - BN_bn2bin(session_key_n, buf + (host_key_bits + 7) / 8); - memcpy(buf + (host_key_bits + 7) / 8 + (session_key_bits + 7) / 8, cookie, 8); + BN_bn2bin(session_key_n, buf + host_key_bytes); MD5_Init(&md); MD5_Update(&md, buf, bytes); + MD5_Update(&md, cookie, 8); MD5_Final(session_id, &md); memset(buf, 0, bytes); xfree(buf); diff --git a/pty.c b/pty.c index 4103e6df..fe31251c 100644 --- a/pty.c +++ b/pty.c @@ -16,6 +16,7 @@ #include "includes.h" RCSID("$Id$"); +#include #include "pty.h" #include "ssh.h" @@ -163,7 +164,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen) *ptyfd = open(buf, O_RDWR | O_NOCTTY); if (*ptyfd < 0) continue; - snprintf(namebuf, sizeof namebuflen, "/dev/tty%c%c", + snprintf(namebuf, namebuflen, "/dev/tty%c%c", ptymajors[i / num_minors], ptyminors[i % num_minors]); /* Open the slave side. */ diff --git a/ssh.1 b/ssh.1 index 2b89fbb6..d972038e 100644 --- a/ssh.1 +++ b/ssh.1 @@ -351,7 +351,7 @@ per-host basis in the configuration file. Use a non-privileged port for outgoing connections. This can be used if your firewall does not permit connections from privileged ports. -Note that this option turns of +Note that this option turns off .Cm RhostsAuthentication and .Cm RhostsRSAAuthentication . @@ -720,7 +720,7 @@ The default is .Dq yes . Note that setting this option to .Dq no -turns of +turns off .Cm RhostsAuthentication and .Cm RhostsRSAAuthentication . diff --git a/ssh.c b/ssh.c index 51d5117a..e84e9ed5 100644 --- a/ssh.c +++ b/ssh.c @@ -732,7 +732,8 @@ main(int ac, char **av) options.local_forwards[i].host_port); channel_request_local_forwarding(options.local_forwards[i].port, options.local_forwards[i].host, - options.local_forwards[i].host_port); + options.local_forwards[i].host_port, + options.gateway_ports); } /* Initiate remote TCP/IP port forwardings. */ diff --git a/ssh.h b/ssh.h index 0ec608f0..3bcb2e07 100644 --- a/ssh.h +++ b/ssh.h @@ -589,7 +589,7 @@ char *channel_open_message(void); */ void channel_request_local_forwarding(u_short port, const char *host, - u_short remote_port); + u_short remote_port, int gateway_ports); /* * Initiate forwarding of connections to port "port" on remote host through @@ -633,7 +633,7 @@ char *x11_create_display(int screen); * Returns a suitable value for the DISPLAY variable, or NULL if an error * occurs. */ -char *x11_create_display_inet(int screen); +char *x11_create_display_inet(int screen, int x11_display_offset); /* * This is called when SSH_SMSG_X11_OPEN is received. The packet contains diff --git a/sshconnect.c b/sshconnect.c index 3526cccc..85a57d0a 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -156,8 +156,10 @@ ssh_create_socket(uid_t original_real_uid, int privileged) fatal("rresvport: %.100s", strerror(errno)); debug("Allocated local port %d.", p); } else { - /* Just create an ordinary socket on arbitrary port. We - use the user's uid to create the socket. */ + /* + * Just create an ordinary socket on arbitrary port. We use + * the user's uid to create the socket. + */ temporarily_use_uid(original_real_uid); sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) @@ -209,9 +211,11 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr, /* No host lookup made yet. */ hp = NULL; - /* 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. */ + /* + * 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; attempt < connection_attempts; attempt++) { if (attempt > 0) debug("Trying again..."); @@ -1087,39 +1091,21 @@ read_yes_or_no(const char *prompt, int defval) } /* - * Starts a dialog with the server, and authenticates the current user on the - * server. This does not need any extra privileges. The basic connection - * to the server must already have been established before this is called. - * User is the remote user; if it is NULL, the current local user name will - * be used. Anonymous indicates that no rhosts authentication will be used. - * If login fails, this function prints an error and never returns. - * This function does not require super-user privileges. + * check whether the supplied host key is valid, return only if ok. */ + void -ssh_login(int host_key_valid, - RSA *own_host_key, - const char *orighost, - struct sockaddr_in *hostaddr, - uid_t original_real_uid) +check_host_key(char *host, + struct sockaddr_in *hostaddr, + RSA *host_key) { - int i, type; - struct passwd *pw; - BIGNUM *key; - RSA *host_key, *file_key; - RSA *public_key; - int bits, rbits; - unsigned char session_key[SSH_SESSION_KEY_LENGTH]; - const char *server_user, *local_user; - char *cp, *host, *ip = NULL; + RSA *file_key; + char *ip = NULL; char hostline[1000], *hostp; - unsigned char check_bytes[8]; - unsigned int supported_ciphers, supported_authentications, protocol_flags; HostStatus host_status; HostStatus ip_status; int host_ip_differ = 0; int local = (ntohl(hostaddr->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; - int payload_len, clen, sum_len = 0; - u_int32_t rand = 0; /* * Turn off check_host_ip for proxy connects, since @@ -1131,88 +1117,14 @@ ssh_login(int host_key_valid, if (options.check_host_ip) ip = xstrdup(inet_ntoa(hostaddr->sin_addr)); - /* Convert the user-supplied hostname into all lowercase. */ - host = xstrdup(orighost); - for (cp = host; *cp; cp++) - if (isupper(*cp)) - *cp = tolower(*cp); - - /* Exchange protocol version identification strings with the server. */ - ssh_exchange_identification(); - - /* Put the connection into non-blocking mode. */ - packet_set_nonblocking(); - - /* Get local user name. Use it as server user if no user name was given. */ - pw = getpwuid(original_real_uid); - if (!pw) - fatal("User id %d not found from user database.", original_real_uid); - local_user = xstrdup(pw->pw_name); - server_user = options.user ? options.user : local_user; - - debug("Waiting for server public key."); - - /* Wait for a public key packet from the server. */ - packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY); - - /* Get check bytes from the packet. */ - for (i = 0; i < 8; i++) - check_bytes[i] = packet_get_char(); - - /* Get the public key. */ - public_key = RSA_new(); - bits = packet_get_int();/* bits */ - public_key->e = BN_new(); - packet_get_bignum(public_key->e, &clen); - sum_len += clen; - public_key->n = BN_new(); - packet_get_bignum(public_key->n, &clen); - sum_len += clen; - - rbits = BN_num_bits(public_key->n); - if (bits != rbits) { - log("Warning: Server lies about size of server public key: " - "actual size is %d bits vs. announced %d.", rbits, bits); - log("Warning: This may be due to an old implementation of ssh."); - } - /* Get the host key. */ - host_key = RSA_new(); - bits = packet_get_int();/* bits */ - host_key->e = BN_new(); - packet_get_bignum(host_key->e, &clen); - sum_len += clen; - host_key->n = BN_new(); - packet_get_bignum(host_key->n, &clen); - sum_len += clen; - - rbits = BN_num_bits(host_key->n); - if (bits != rbits) { - log("Warning: Server lies about size of server host key: " - "actual size is %d bits vs. announced %d.", rbits, bits); - log("Warning: This may be due to an old implementation of ssh."); - } - /* Store the host key from the known host file in here so that we - can compare it with the key for the IP address. */ + /* + * Store the host key from the known host file in here so that we can + * compare it with the key for the IP address. + */ file_key = RSA_new(); file_key->n = BN_new(); file_key->e = BN_new(); - /* Get protocol flags. */ - protocol_flags = packet_get_int(); - packet_set_protocol_flags(protocol_flags); - - supported_ciphers = packet_get_int(); - supported_authentications = packet_get_int(); - - debug("Received server public key (%d bits) and host key (%d bits).", - BN_num_bits(public_key->n), BN_num_bits(host_key->n)); - - packet_integrity_check(payload_len, - 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4, - SSH_SMSG_PUBLIC_KEY); - - compute_session_id(session_id, check_bytes, host_key->n, public_key->n); - /* * Check if the host key is present in the user\'s list of known * hosts or in the systemwide list. @@ -1372,9 +1284,121 @@ ssh_login(int host_key_valid, */ break; } - if (options.check_host_ip) xfree(ip); +} + +/* + * Starts a dialog with the server, and authenticates the current user on the + * server. This does not need any extra privileges. The basic connection + * to the server must already have been established before this is called. + * User is the remote user; if it is NULL, the current local user name will + * be used. Anonymous indicates that no rhosts authentication will be used. + * If login fails, this function prints an error and never returns. + * This function does not require super-user privileges. + */ +void +ssh_login(int host_key_valid, + RSA *own_host_key, + const char *orighost, + struct sockaddr_in *hostaddr, + uid_t original_real_uid) +{ + int i, type; + struct passwd *pw; + BIGNUM *key; + RSA *host_key; + RSA *public_key; + int bits, rbits; + unsigned char session_key[SSH_SESSION_KEY_LENGTH]; + const char *server_user, *local_user; + char *host, *cp; + unsigned char check_bytes[8]; + unsigned int supported_ciphers, supported_authentications; + unsigned int server_flags, client_flags; + int payload_len, clen, sum_len = 0; + u_int32_t rand = 0; + + /* Convert the user-supplied hostname into all lowercase. */ + host = xstrdup(orighost); + for (cp = host; *cp; cp++) + if (isupper(*cp)) + *cp = tolower(*cp); + + /* Exchange protocol version identification strings with the server. */ + ssh_exchange_identification(); + + /* Put the connection into non-blocking mode. */ + packet_set_nonblocking(); + + /* Get local user name. Use it as server user if no user name was given. */ + pw = getpwuid(original_real_uid); + if (!pw) + fatal("User id %d not found from user database.", original_real_uid); + local_user = xstrdup(pw->pw_name); + server_user = options.user ? options.user : local_user; + + debug("Waiting for server public key."); + + /* Wait for a public key packet from the server. */ + packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY); + + /* Get check bytes from the packet. */ + for (i = 0; i < 8; i++) + check_bytes[i] = packet_get_char(); + + /* Get the public key. */ + public_key = RSA_new(); + bits = packet_get_int();/* bits */ + public_key->e = BN_new(); + packet_get_bignum(public_key->e, &clen); + sum_len += clen; + public_key->n = BN_new(); + packet_get_bignum(public_key->n, &clen); + sum_len += clen; + + rbits = BN_num_bits(public_key->n); + if (bits != rbits) { + log("Warning: Server lies about size of server public key: " + "actual size is %d bits vs. announced %d.", rbits, bits); + log("Warning: This may be due to an old implementation of ssh."); + } + /* Get the host key. */ + host_key = RSA_new(); + bits = packet_get_int();/* bits */ + host_key->e = BN_new(); + packet_get_bignum(host_key->e, &clen); + sum_len += clen; + host_key->n = BN_new(); + packet_get_bignum(host_key->n, &clen); + sum_len += clen; + + rbits = BN_num_bits(host_key->n); + if (bits != rbits) { + log("Warning: Server lies about size of server host key: " + "actual size is %d bits vs. announced %d.", rbits, bits); + log("Warning: This may be due to an old implementation of ssh."); + } + + /* Get protocol flags. */ + server_flags = packet_get_int(); + packet_set_protocol_flags(server_flags); + + supported_ciphers = packet_get_int(); + supported_authentications = packet_get_int(); + + debug("Received server public key (%d bits) and host key (%d bits).", + BN_num_bits(public_key->n), BN_num_bits(host_key->n)); + + packet_integrity_check(payload_len, + 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4, + SSH_SMSG_PUBLIC_KEY); + + check_host_key(host, hostaddr, host_key); + + client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN; + + compute_session_id(session_id, check_bytes, host_key->n, public_key->n); /* Generate a session key. */ arc4random_stir(); @@ -1465,7 +1489,7 @@ ssh_login(int host_key_valid, packet_put_bignum(key); /* Send protocol flags. */ - packet_put_int(SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN); + packet_put_int(client_flags); /* Send the packet now. */ packet_send(); diff --git a/sshd.c b/sshd.c index d50f7fd7..3fdc1e0d 100644 --- a/sshd.c +++ b/sshd.c @@ -960,7 +960,7 @@ do_connection() unsigned char check_bytes[8]; char *user; unsigned int cipher_type, auth_mask, protocol_flags; - int plen, slen; + int plen, slen, ulen; u_int32_t rand = 0; /* @@ -1139,11 +1139,8 @@ do_connection() packet_read_expect(&plen, SSH_CMSG_USER); /* Get the user name. */ - { - int ulen; - user = packet_get_string(&ulen); - packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER); - } + user = packet_get_string(&ulen); + packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER); /* Destroy the private and public keys. They will no longer be needed. */ RSA_free(public_key); @@ -1646,15 +1643,22 @@ do_fake_authloop(char *user) #ifdef SKEY int dlen; char *password, *skeyinfo; - if (options.password_authentication && - options.skey_authentication == 1 && - type == SSH_CMSG_AUTH_PASSWORD && - (password = packet_get_string(&dlen)) != NULL && - dlen == 5 && - strncasecmp(password, "s/key", 5) == 0 && + /* Try to send a fake s/key challenge. */ + if (options.skey_authentication == 1 && (skeyinfo = skey_fake_keyinfo(user)) != NULL) { - /* Send a fake s/key challenge. */ - packet_send_debug(skeyinfo); + if (type == SSH_CMSG_AUTH_TIS) { + packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); + packet_put_string(skeyinfo, strlen(skeyinfo)); + packet_send(); + packet_write_wait(); + continue; + } else if (type == SSH_CMSG_AUTH_PASSWORD && + options.password_authentication && + (password = packet_get_string(&dlen)) != NULL && + dlen == 5 && + strncasecmp(password, "s/key", 5) == 0 ) { + packet_send_debug(skeyinfo); + } } #endif if (attempt > AUTH_FAIL_MAX) @@ -1836,7 +1840,7 @@ do_authenticated(struct passwd * pw) screen = packet_get_int(); else screen = 0; - display = x11_create_display_inet(screen); + display = x11_create_display_inet(screen, options.x11_display_offset); if (!display) goto fail; diff --git a/version.h b/version.h index 8d2fc5c2..9c7aa2a6 100644 --- a/version.h +++ b/version.h @@ -1 +1 @@ -#define SSH_VERSION "OpenSSH-1.2" +#define SSH_VERSION "OpenSSH-1.2.1" -- 2.45.1