version 1.1.1.7, 2013/03/29 14:52:43 |
version 1.1.1.8, 2013/11/08 17:58:11 |
|
|
/* $OpenBSD: packet.c,v 1.181 2013/02/10 23:35:24 djm Exp $ */ |
/* $OpenBSD: packet.c,v 1.188.2.1 2013/11/08 01:33:56 djm Exp $ */ |
/* |
/* |
* 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 |
|
|
#include <string.h> |
#include <string.h> |
#include <unistd.h> |
#include <unistd.h> |
#include <signal.h> |
#include <signal.h> |
|
#include <time.h> |
|
|
#include "xmalloc.h" |
#include "xmalloc.h" |
#include "buffer.h" |
#include "buffer.h" |
Line 161 struct session_state { |
|
Line 162 struct session_state { |
|
Newkeys *newkeys[MODE_MAX]; |
Newkeys *newkeys[MODE_MAX]; |
struct packet_state p_read, p_send; |
struct packet_state p_read, p_send; |
|
|
|
/* Volume-based rekeying */ |
u_int64_t max_blocks_in, max_blocks_out; |
u_int64_t max_blocks_in, max_blocks_out; |
u_int32_t rekey_limit; |
u_int32_t rekey_limit; |
|
|
|
/* Time-based rekeying */ |
|
time_t rekey_interval; /* how often in seconds */ |
|
time_t rekey_time; /* time of last rekeying */ |
|
|
/* Session key for protocol v1 */ |
/* Session key for protocol v1 */ |
u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; |
u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; |
u_int ssh1_keylen; |
u_int ssh1_keylen; |
Line 211 alloc_session_state(void) |
|
Line 217 alloc_session_state(void) |
|
void |
void |
packet_set_connection(int fd_in, int fd_out) |
packet_set_connection(int fd_in, int fd_out) |
{ |
{ |
Cipher *none = cipher_by_name("none"); |
const Cipher *none = cipher_by_name("none"); |
|
|
if (none == NULL) |
if (none == NULL) |
fatal("packet_set_connection: cannot load cipher 'none'"); |
fatal("packet_set_connection: cannot load cipher 'none'"); |
Line 536 packet_start_compression(int level) |
|
Line 542 packet_start_compression(int level) |
|
void |
void |
packet_set_encryption_key(const u_char *key, u_int keylen, int number) |
packet_set_encryption_key(const u_char *key, u_int keylen, int number) |
{ |
{ |
Cipher *cipher = cipher_by_number(number); |
const Cipher *cipher = cipher_by_number(number); |
|
|
if (cipher == NULL) |
if (cipher == NULL) |
fatal("packet_set_encryption_key: unknown cipher number %d", number); |
fatal("packet_set_encryption_key: unknown cipher number %d", number); |
Line 749 set_newkeys(int mode) |
|
Line 755 set_newkeys(int mode) |
|
memset(enc->iv, 0, enc->iv_len); |
memset(enc->iv, 0, enc->iv_len); |
memset(enc->key, 0, enc->key_len); |
memset(enc->key, 0, enc->key_len); |
memset(mac->key, 0, mac->key_len); |
memset(mac->key, 0, mac->key_len); |
xfree(enc->name); |
free(enc->name); |
xfree(enc->iv); |
free(enc->iv); |
xfree(enc->key); |
free(enc->key); |
xfree(mac->name); |
free(mac->name); |
xfree(mac->key); |
free(mac->key); |
xfree(comp->name); |
free(comp->name); |
xfree(active_state->newkeys[mode]); |
free(active_state->newkeys[mode]); |
} |
} |
active_state->newkeys[mode] = kex_get_newkeys(mode); |
active_state->newkeys[mode] = kex_get_newkeys(mode); |
if (active_state->newkeys[mode] == NULL) |
if (active_state->newkeys[mode] == NULL) |
Line 979 packet_send2(void) |
|
Line 985 packet_send2(void) |
|
(type == SSH2_MSG_SERVICE_REQUEST) || |
(type == SSH2_MSG_SERVICE_REQUEST) || |
(type == SSH2_MSG_SERVICE_ACCEPT)) { |
(type == SSH2_MSG_SERVICE_ACCEPT)) { |
debug("enqueue packet: %u", type); |
debug("enqueue packet: %u", type); |
p = xmalloc(sizeof(*p)); |
p = xcalloc(1, sizeof(*p)); |
p->type = type; |
p->type = type; |
memcpy(&p->payload, &active_state->outgoing_packet, |
memcpy(&p->payload, &active_state->outgoing_packet, |
sizeof(Buffer)); |
sizeof(Buffer)); |
Line 998 packet_send2(void) |
|
Line 1004 packet_send2(void) |
|
/* after a NEWKEYS message we can send the complete queue */ |
/* after a NEWKEYS message we can send the complete queue */ |
if (type == SSH2_MSG_NEWKEYS) { |
if (type == SSH2_MSG_NEWKEYS) { |
active_state->rekeying = 0; |
active_state->rekeying = 0; |
|
active_state->rekey_time = monotime(); |
while ((p = TAILQ_FIRST(&active_state->outgoing))) { |
while ((p = TAILQ_FIRST(&active_state->outgoing))) { |
type = p->type; |
type = p->type; |
debug("dequeue packet: %u", type); |
debug("dequeue packet: %u", type); |
Line 1005 packet_send2(void) |
|
Line 1012 packet_send2(void) |
|
memcpy(&active_state->outgoing_packet, &p->payload, |
memcpy(&active_state->outgoing_packet, &p->payload, |
sizeof(Buffer)); |
sizeof(Buffer)); |
TAILQ_REMOVE(&active_state->outgoing, p, next); |
TAILQ_REMOVE(&active_state->outgoing, p, next); |
xfree(p); |
free(p); |
packet_send2_wrapped(); |
packet_send2_wrapped(); |
} |
} |
} |
} |
Line 1030 packet_send(void) |
|
Line 1037 packet_send(void) |
|
int |
int |
packet_read_seqnr(u_int32_t *seqnr_p) |
packet_read_seqnr(u_int32_t *seqnr_p) |
{ |
{ |
int type, len, ret, ms_remain, cont; |
int type, len, ret, cont, ms_remain = 0; |
fd_set *setp; |
fd_set *setp; |
char buf[8192]; |
char buf[8192]; |
struct timeval timeout, start, *timeoutp = NULL; |
struct timeval timeout, start, *timeoutp = NULL; |
Line 1055 packet_read_seqnr(u_int32_t *seqnr_p) |
|
Line 1062 packet_read_seqnr(u_int32_t *seqnr_p) |
|
packet_check_eom(); |
packet_check_eom(); |
/* If we got a packet, return it. */ |
/* If we got a packet, return it. */ |
if (type != SSH_MSG_NONE) { |
if (type != SSH_MSG_NONE) { |
xfree(setp); |
free(setp); |
return type; |
return type; |
} |
} |
/* |
/* |
Line 1441 packet_read_poll_seqnr(u_int32_t *seqnr_ |
|
Line 1448 packet_read_poll_seqnr(u_int32_t *seqnr_ |
|
packet_get_char(); |
packet_get_char(); |
msg = packet_get_string(NULL); |
msg = packet_get_string(NULL); |
debug("Remote: %.900s", msg); |
debug("Remote: %.900s", msg); |
xfree(msg); |
free(msg); |
msg = packet_get_string(NULL); |
msg = packet_get_string(NULL); |
xfree(msg); |
free(msg); |
break; |
break; |
case SSH2_MSG_DISCONNECT: |
case SSH2_MSG_DISCONNECT: |
reason = packet_get_int(); |
reason = packet_get_int(); |
msg = packet_get_string(NULL); |
msg = packet_get_string(NULL); |
error("Received disconnect from %s: %u: %.400s", |
/* Ignore normal client exit notifications */ |
|
do_log2(active_state->server_side && |
|
reason == SSH2_DISCONNECT_BY_APPLICATION ? |
|
SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR, |
|
"Received disconnect from %s: %u: %.400s", |
get_remote_ipaddr(), reason, msg); |
get_remote_ipaddr(), reason, msg); |
xfree(msg); |
free(msg); |
cleanup_exit(255); |
cleanup_exit(255); |
break; |
break; |
case SSH2_MSG_UNIMPLEMENTED: |
case SSH2_MSG_UNIMPLEMENTED: |
Line 1464 packet_read_poll_seqnr(u_int32_t *seqnr_ |
|
Line 1475 packet_read_poll_seqnr(u_int32_t *seqnr_ |
|
} else { |
} else { |
type = packet_read_poll1(); |
type = packet_read_poll1(); |
switch (type) { |
switch (type) { |
|
case SSH_MSG_NONE: |
|
return SSH_MSG_NONE; |
case SSH_MSG_IGNORE: |
case SSH_MSG_IGNORE: |
break; |
break; |
case SSH_MSG_DEBUG: |
case SSH_MSG_DEBUG: |
msg = packet_get_string(NULL); |
msg = packet_get_string(NULL); |
debug("Remote: %.900s", msg); |
debug("Remote: %.900s", msg); |
xfree(msg); |
free(msg); |
break; |
break; |
case SSH_MSG_DISCONNECT: |
case SSH_MSG_DISCONNECT: |
msg = packet_get_string(NULL); |
msg = packet_get_string(NULL); |
Line 1478 packet_read_poll_seqnr(u_int32_t *seqnr_ |
|
Line 1491 packet_read_poll_seqnr(u_int32_t *seqnr_ |
|
cleanup_exit(255); |
cleanup_exit(255); |
break; |
break; |
default: |
default: |
if (type) |
DBG(debug("received packet type %d", type)); |
DBG(debug("received packet type %d", type)); |
|
return type; |
return type; |
} |
} |
} |
} |
|
|
packet_write_wait(void) |
packet_write_wait(void) |
{ |
{ |
fd_set *setp; |
fd_set *setp; |
int ret, ms_remain; |
int ret, ms_remain = 0; |
struct timeval start, timeout, *timeoutp = NULL; |
struct timeval start, timeout, *timeoutp = NULL; |
|
|
setp = (fd_set *)xcalloc(howmany(active_state->connection_out + 1, |
setp = (fd_set *)xcalloc(howmany(active_state->connection_out + 1, |
Line 1753 packet_write_wait(void) |
|
Line 1765 packet_write_wait(void) |
|
} |
} |
packet_write_poll(); |
packet_write_poll(); |
} |
} |
xfree(setp); |
free(setp); |
} |
} |
|
|
/* Returns true if there is buffered data to write to the connection. */ |
/* Returns true if there is buffered data to write to the connection. */ |
Line 1907 packet_need_rekeying(void) |
|
Line 1919 packet_need_rekeying(void) |
|
(active_state->max_blocks_out && |
(active_state->max_blocks_out && |
(active_state->p_send.blocks > active_state->max_blocks_out)) || |
(active_state->p_send.blocks > active_state->max_blocks_out)) || |
(active_state->max_blocks_in && |
(active_state->max_blocks_in && |
(active_state->p_read.blocks > active_state->max_blocks_in)); |
(active_state->p_read.blocks > active_state->max_blocks_in)) || |
|
(active_state->rekey_interval != 0 && active_state->rekey_time + |
|
active_state->rekey_interval <= monotime()); |
} |
} |
|
|
void |
void |
packet_set_rekey_limit(u_int32_t bytes) |
packet_set_rekey_limits(u_int32_t bytes, time_t seconds) |
{ |
{ |
|
debug3("rekey after %lld bytes, %d seconds", (long long)bytes, |
|
(int)seconds); |
active_state->rekey_limit = bytes; |
active_state->rekey_limit = bytes; |
|
active_state->rekey_interval = seconds; |
|
/* |
|
* We set the time here so that in post-auth privsep slave we count |
|
* from the completion of the authentication. |
|
*/ |
|
active_state->rekey_time = monotime(); |
|
} |
|
|
|
time_t |
|
packet_get_rekey_timeout(void) |
|
{ |
|
time_t seconds; |
|
|
|
seconds = active_state->rekey_time + active_state->rekey_interval - |
|
monotime(); |
|
return (seconds <= 0 ? 1 : seconds); |
} |
} |
|
|
void |
void |