version 1.119.2.1, 2006/02/03 03:01:56 |
version 1.119.2.2, 2006/10/06 03:19:32 |
|
|
|
/* $OpenBSD$ */ |
/* |
/* |
* Author: Tatu Ylonen <ylo@cs.hut.fi> |
* Author: Tatu Ylonen <ylo@cs.hut.fi> |
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
*/ |
|
|
#include "includes.h" |
#include <sys/types.h> |
RCSID("$OpenBSD$"); |
|
|
|
#include <sys/queue.h> |
#include <sys/queue.h> |
|
#include <sys/socket.h> |
|
#include <sys/time.h> |
|
#include <sys/param.h> |
|
|
|
#include <netinet/in_systm.h> |
|
#include <netinet/in.h> |
|
#include <netinet/ip.h> |
|
|
|
#include <errno.h> |
|
#include <stdarg.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <unistd.h> |
|
#include <signal.h> |
|
|
#include "xmalloc.h" |
#include "xmalloc.h" |
#include "buffer.h" |
#include "buffer.h" |
#include "packet.h" |
#include "packet.h" |
#include "bufaux.h" |
|
#include "crc32.h" |
#include "crc32.h" |
#include "getput.h" |
|
|
|
#include "compress.h" |
#include "compress.h" |
#include "deattack.h" |
#include "deattack.h" |
#include "channels.h" |
#include "channels.h" |
|
|
#include "compat.h" |
#include "compat.h" |
#include "ssh1.h" |
#include "ssh1.h" |
#include "ssh2.h" |
#include "ssh2.h" |
|
|
#include "cipher.h" |
#include "cipher.h" |
|
#include "key.h" |
#include "kex.h" |
#include "kex.h" |
#include "mac.h" |
#include "mac.h" |
#include "log.h" |
#include "log.h" |
|
|
|
|
return (cipher_get_keyiv_len(cc)); |
return (cipher_get_keyiv_len(cc)); |
} |
} |
|
|
void |
void |
packet_set_iv(int mode, u_char *dat) |
packet_set_iv(int mode, u_char *dat) |
{ |
{ |
|
|
|
|
cipher_set_keyiv(cc, dat); |
cipher_set_keyiv(cc, dat); |
} |
} |
|
|
int |
int |
packet_get_ssh1_cipher(void) |
packet_get_ssh1_cipher(void) |
{ |
{ |
|
|
|
|
buffer_append(&outgoing_packet, &ch, 1); |
buffer_append(&outgoing_packet, &ch, 1); |
} |
} |
|
|
void |
void |
packet_put_int(u_int value) |
packet_put_int(u_int value) |
{ |
{ |
buffer_put_int(&outgoing_packet, value); |
buffer_put_int(&outgoing_packet, value); |
} |
} |
|
|
void |
void |
packet_put_string(const void *buf, u_int len) |
packet_put_string(const void *buf, u_int len) |
{ |
{ |
buffer_put_string(&outgoing_packet, buf, len); |
buffer_put_string(&outgoing_packet, buf, len); |
} |
} |
|
|
void |
void |
packet_put_cstring(const char *str) |
packet_put_cstring(const char *str) |
{ |
{ |
buffer_put_cstring(&outgoing_packet, str); |
buffer_put_cstring(&outgoing_packet, str); |
} |
} |
|
|
void |
void |
packet_put_raw(const void *buf, u_int len) |
packet_put_raw(const void *buf, u_int len) |
{ |
{ |
buffer_append(&outgoing_packet, buf, len); |
buffer_append(&outgoing_packet, buf, len); |
} |
} |
|
|
void |
void |
packet_put_bignum(BIGNUM * value) |
packet_put_bignum(BIGNUM * value) |
{ |
{ |
buffer_put_bignum(&outgoing_packet, value); |
buffer_put_bignum(&outgoing_packet, value); |
} |
} |
|
|
void |
void |
packet_put_bignum2(BIGNUM * value) |
packet_put_bignum2(BIGNUM * value) |
{ |
{ |
|
|
/* Add check bytes. */ |
/* Add check bytes. */ |
checksum = ssh_crc32(buffer_ptr(&outgoing_packet), |
checksum = ssh_crc32(buffer_ptr(&outgoing_packet), |
buffer_len(&outgoing_packet)); |
buffer_len(&outgoing_packet)); |
PUT_32BIT(buf, checksum); |
put_u32(buf, checksum); |
buffer_append(&outgoing_packet, buf, 4); |
buffer_append(&outgoing_packet, buf, 4); |
|
|
#ifdef PACKET_DEBUG |
#ifdef PACKET_DEBUG |
|
|
#endif |
#endif |
|
|
/* Append to output. */ |
/* Append to output. */ |
PUT_32BIT(buf, len); |
put_u32(buf, len); |
buffer_append(&output, buf, 4); |
buffer_append(&output, buf, 4); |
cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); |
cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); |
cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet), |
cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet), |
|
|
|
|
/* |
/* |
* Delayed compression for SSH2 is enabled after authentication: |
* Delayed compression for SSH2 is enabled after authentication: |
* This happans on the server side after a SSH2_MSG_USERAUTH_SUCCESS is sent, |
* This happens on the server side after a SSH2_MSG_USERAUTH_SUCCESS is sent, |
* and on the client side after a SSH2_MSG_USERAUTH_SUCCESS is received. |
* and on the client side after a SSH2_MSG_USERAUTH_SUCCESS is received. |
*/ |
*/ |
static void |
static void |
|
|
/* packet_length includes payload, padding and padding length field */ |
/* packet_length includes payload, padding and padding length field */ |
packet_length = buffer_len(&outgoing_packet) - 4; |
packet_length = buffer_len(&outgoing_packet) - 4; |
cp = buffer_ptr(&outgoing_packet); |
cp = buffer_ptr(&outgoing_packet); |
PUT_32BIT(cp, packet_length); |
put_u32(cp, packet_length); |
cp[4] = padlen; |
cp[4] = padlen; |
DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen)); |
DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen)); |
|
|
|
|
buffer_len(&outgoing_packet)); |
buffer_len(&outgoing_packet)); |
/* append unencrypted MAC */ |
/* append unencrypted MAC */ |
if (mac && mac->enabled) |
if (mac && mac->enabled) |
buffer_append(&output, (char *)macbuf, mac->mac_len); |
buffer_append(&output, macbuf, mac->mac_len); |
#ifdef PACKET_DEBUG |
#ifdef PACKET_DEBUG |
fprintf(stderr, "encrypted: "); |
fprintf(stderr, "encrypted: "); |
buffer_dump(&output); |
buffer_dump(&output); |
|
|
char buf[8192]; |
char buf[8192]; |
DBG(debug("packet_read()")); |
DBG(debug("packet_read()")); |
|
|
setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) * |
setp = (fd_set *)xcalloc(howmany(connection_in+1, NFDBITS), |
sizeof(fd_mask)); |
sizeof(fd_mask)); |
|
|
/* Since we are blocking, ensure that all written packets have been sent. */ |
/* Since we are blocking, ensure that all written packets have been sent. */ |
|
|
return SSH_MSG_NONE; |
return SSH_MSG_NONE; |
/* Get length of incoming packet. */ |
/* Get length of incoming packet. */ |
cp = buffer_ptr(&input); |
cp = buffer_ptr(&input); |
len = GET_32BIT(cp); |
len = get_u32(cp); |
if (len < 1 + 2 + 2 || len > 256 * 1024) |
if (len < 1 + 2 + 2 || len > 256 * 1024) |
packet_disconnect("Bad packet length %u.", len); |
packet_disconnect("Bad packet length %u.", len); |
padded_len = (len + 8) & ~7; |
padded_len = (len + 8) & ~7; |
|
|
* (C)1998 CORE-SDI, Buenos Aires Argentina |
* (C)1998 CORE-SDI, Buenos Aires Argentina |
* Ariel Futoransky(futo@core-sdi.com) |
* Ariel Futoransky(futo@core-sdi.com) |
*/ |
*/ |
if (!receive_context.plaintext && |
if (!receive_context.plaintext) { |
detect_attack(buffer_ptr(&input), padded_len, NULL) == DEATTACK_DETECTED) |
switch (detect_attack(buffer_ptr(&input), padded_len)) { |
packet_disconnect("crc32 compensation attack: network attack detected"); |
case DEATTACK_DETECTED: |
|
packet_disconnect("crc32 compensation attack: " |
|
"network attack detected"); |
|
case DEATTACK_DOS_DETECTED: |
|
packet_disconnect("deattack denial of " |
|
"service detected"); |
|
} |
|
} |
|
|
/* Decrypt data to incoming_packet. */ |
/* Decrypt data to incoming_packet. */ |
buffer_clear(&incoming_packet); |
buffer_clear(&incoming_packet); |
|
|
len, buffer_len(&incoming_packet)); |
len, buffer_len(&incoming_packet)); |
|
|
cp = (u_char *)buffer_ptr(&incoming_packet) + len - 4; |
cp = (u_char *)buffer_ptr(&incoming_packet) + len - 4; |
stored_checksum = GET_32BIT(cp); |
stored_checksum = get_u32(cp); |
if (checksum != stored_checksum) |
if (checksum != stored_checksum) |
packet_disconnect("Corrupted check bytes on input."); |
packet_disconnect("Corrupted check bytes on input."); |
buffer_consume_end(&incoming_packet, 4); |
buffer_consume_end(&incoming_packet, 4); |
|
|
cipher_crypt(&receive_context, cp, buffer_ptr(&input), |
cipher_crypt(&receive_context, cp, buffer_ptr(&input), |
block_size); |
block_size); |
cp = buffer_ptr(&incoming_packet); |
cp = buffer_ptr(&incoming_packet); |
packet_length = GET_32BIT(cp); |
packet_length = get_u32(cp); |
if (packet_length < 1 + 4 || packet_length > 256 * 1024) { |
if (packet_length < 1 + 4 || packet_length > 256 * 1024) { |
#ifdef PACKET_DEBUG |
#ifdef PACKET_DEBUG |
buffer_dump(&incoming_packet); |
buffer_dump(&incoming_packet); |
|
|
break; |
break; |
default: |
default: |
return type; |
return type; |
break; |
|
} |
} |
} else { |
} else { |
type = packet_read_poll1(); |
type = packet_read_poll1(); |
|
|
if (type) |
if (type) |
DBG(debug("received packet type %d", type)); |
DBG(debug("received packet type %d", type)); |
return type; |
return type; |
break; |
|
} |
} |
} |
} |
} |
} |
|
|
{ |
{ |
fd_set *setp; |
fd_set *setp; |
|
|
setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) * |
setp = (fd_set *)xcalloc(howmany(connection_out + 1, NFDBITS), |
sizeof(fd_mask)); |
sizeof(fd_mask)); |
packet_write_poll(); |
packet_write_poll(); |
while (packet_have_data_to_write()) { |
while (packet_have_data_to_write()) { |
|
|
/* Only set socket options if using a socket. */ |
/* Only set socket options if using a socket. */ |
if (!packet_connection_is_on_socket()) |
if (!packet_connection_is_on_socket()) |
return; |
return; |
if (interactive) |
set_nodelay(connection_in); |
set_nodelay(connection_in); |
|
packet_set_tos(interactive); |
packet_set_tos(interactive); |
} |
} |
|
|
|
|
for (i = 0; i < nbytes; i++) { |
for (i = 0; i < nbytes; i++) { |
if (i % 4 == 0) |
if (i % 4 == 0) |
rnd = arc4random(); |
rnd = arc4random(); |
packet_put_char(rnd & 0xff); |
packet_put_char((u_char)rnd & 0xff); |
rnd >>= 8; |
rnd >>= 8; |
} |
} |
} |
} |