From fa7499cc6ff64268191a9f17bb35c28908ea4a40 Mon Sep 17 00:00:00 2001 From: basney Date: Thu, 13 Mar 2008 16:26:37 +0000 Subject: [PATCH] update to http://www.psc.edu/networking/projects/hpn-ssh/openssh-4.7p1-hpn13v1.diff.gz --- openssh/Makefile.in | 4 +- openssh/atomicio.c | 107 +++++++-- openssh/auth2.c | 9 + openssh/buffer.c | 4 +- openssh/channels.c | 10 +- openssh/channels.h | 2 +- openssh/cipher-ctr-mt.c | 473 ++++++++++++++++++++++++++++++++++++++++ openssh/cipher.c | 7 +- openssh/kex.c | 16 ++ openssh/packet.c | 35 +-- openssh/packet.h | 6 +- openssh/serverloop.c | 33 ++- openssh/sshd.c | 3 + openssh/version.h | 2 +- 14 files changed, 665 insertions(+), 46 deletions(-) create mode 100644 openssh/cipher-ctr-mt.c diff --git a/openssh/Makefile.in b/openssh/Makefile.in index 7a38906..cac0ba5 100644 --- a/openssh/Makefile.in +++ b/openssh/Makefile.in @@ -43,7 +43,7 @@ CC=@CC@ LD=@LD@ CFLAGS=@CFLAGS@ CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ -LIBS=@LIBS@ +LIBS=@LIBS@ -lpthread SSHDLIBS=@SSHDLIBS@ LIBEDIT=@LIBEDIT@ AR=@AR@ @@ -65,7 +65,7 @@ TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keys LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \ canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \ - cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \ + cipher-bf1.o cipher-ctr.o cipher-ctr-mt.o cipher-3des1.o cleanup.o \ compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \ log.o match.o md-sha256.o moduli.o nchan.o packet.o \ readpass.o rsa.o ttymodes.o xmalloc.o \ diff --git a/openssh/atomicio.c b/openssh/atomicio.c index 47161eb..62ee402 100644 --- a/openssh/atomicio.c +++ b/openssh/atomicio.c @@ -1,4 +1,7 @@ +/* $OpenBSD: atomicio.c,v 1.25 2007/06/25 12:02:27 dtucker Exp $ */ /* + * Copyright (c) 2006 Damien Miller. All rights reserved. + * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. * All rights reserved. * @@ -24,38 +27,116 @@ */ #include "includes.h" -RCSID("$OpenBSD: atomicio.c,v 1.10 2001/05/08 22:48:07 markus Exp $"); + +#include +#include + +#include +#ifdef HAVE_POLL_H +#include +#endif +#include +#include #include "atomicio.h" /* - * ensure all of data on socket comes through. f==read || f==write + * ensure all of data on socket comes through. f==read || f==vwrite */ -ssize_t -atomicio(f, fd, _s, n) - ssize_t (*f) (); - int fd; - void *_s; - size_t n; +size_t +atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) { char *s = _s; - ssize_t res, pos = 0; + size_t pos = 0; + ssize_t res; + struct pollfd pfd; + pfd.fd = fd; + pfd.events = f == read ? POLLIN : POLLOUT; while (n > pos) { res = (f) (fd, s + pos, n - pos); switch (res) { case -1: + if (errno == EINTR) + continue; #ifdef EWOULDBLOCK - if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) + if (errno == EAGAIN || errno == EWOULDBLOCK) { #else - if (errno == EINTR || errno == EAGAIN) + if (errno == EAGAIN) { #endif + (void)poll(&pfd, 1, -1); continue; + } + return 0; case 0: - return (res); + errno = EPIPE; + return pos; default: - pos += res; + pos += (size_t)res; } } return (pos); } + +/* + * ensure all of data on socket comes through. f==readv || f==writev + */ +size_t +atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd, + const struct iovec *_iov, int iovcnt) +{ + size_t pos = 0, rem; + ssize_t res; + struct iovec iov_array[IOV_MAX], *iov = iov_array; + struct pollfd pfd; + + if (iovcnt > IOV_MAX) { + errno = EINVAL; + return 0; + } + /* Make a copy of the iov array because we may modify it below */ + memcpy(iov, _iov, iovcnt * sizeof(*_iov)); + + pfd.fd = fd; + pfd.events = f == readv ? POLLIN : POLLOUT; + for (; iovcnt > 0 && iov[0].iov_len > 0;) { + res = (f) (fd, iov, iovcnt); + switch (res) { + case -1: + if (errno == EINTR) + continue; +#ifdef EWOULDBLOCK + if (errno == EAGAIN || errno == EWOULDBLOCK) { +#else + if (errno == EAGAIN) { +#endif + (void)poll(&pfd, 1, -1); + continue; + } + return 0; + case 0: + errno = EPIPE; + return pos; + default: + rem = (size_t)res; + pos += rem; + /* skip completed iov entries */ + while (iovcnt > 0 && rem >= iov[0].iov_len) { + rem -= iov[0].iov_len; + iov++; + iovcnt--; + } + /* This shouldn't happen... */ + if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) { + errno = EFAULT; + return 0; + } + if (iovcnt == 0) + break; + /* update pointer in partially complete iov */ + iov[0].iov_base = ((char *)iov[0].iov_base) + rem; + iov[0].iov_len -= rem; + } + } + return pos; +} diff --git a/openssh/auth2.c b/openssh/auth2.c index 76724f4..ff7d639 100644 --- a/openssh/auth2.c +++ b/openssh/auth2.c @@ -44,6 +44,7 @@ #include "dispatch.h" #include "pathnames.h" #include "buffer.h" +#include "canohost.h" #ifdef GSSAPI #include "ssh-gss.h" @@ -70,6 +71,9 @@ extern Authmethod method_gssapi; extern Authmethod method_gssapi_compat; #endif +static int log_flag = 0; + + Authmethod *authmethods[] = { &method_none, &method_pubkey, @@ -178,6 +182,11 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) debug("userauth-request for user %s service %s method %s", user[0] ? user : "", service, method); + if (!log_flag) { + logit("SSH: Server;Ltype: Authname;Remote: %s-%d;Name: %s", + get_remote_ipaddr(), get_remote_port(), user); + log_flag = 1; + } debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); if ((style = strchr(user, ':')) != NULL) diff --git a/openssh/buffer.c b/openssh/buffer.c index cb0b620..1c04cab 100644 --- a/openssh/buffer.c +++ b/openssh/buffer.c @@ -127,7 +127,9 @@ restart: /* Increase the size of the buffer and retry. */ newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ); - if (newlen > BUFFER_MAX_LEN_HPN) + /* need it to be slightly larger than the MAX LEN for this */ + /* still investigating *why* but this works for now -cjr */ + if (newlen > (BUFFER_MAX_LEN_HPN + BUFFER_MAX_LEN)) fatal("buffer_append_space: alloc %u not supported", newlen); buffer->buf = xrealloc(buffer->buf, 1, newlen); diff --git a/openssh/channels.c b/openssh/channels.c index 39dd930..2ef1af9 100644 --- a/openssh/channels.c +++ b/openssh/channels.c @@ -1903,11 +1903,12 @@ channel_after_select(fd_set *readset, fd_set *writeset) /* If there is data to send to the connection, enqueue some of it now. */ -void +int channel_output_poll(void) { Channel *c; u_int i, len; + int packet_length = 0; for (i = 0; i < channels_alloc; i++) { c = channels[i]; @@ -1947,7 +1948,7 @@ channel_output_poll(void) packet_start(SSH2_MSG_CHANNEL_DATA); packet_put_int(c->remote_id); packet_put_string(data, dlen); - packet_send(); + packet_length = packet_send(); c->remote_window -= dlen + 4; xfree(data); } @@ -1977,7 +1978,7 @@ channel_output_poll(void) SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA); packet_put_int(c->remote_id); packet_put_string(buffer_ptr(&c->input), len); - packet_send(); + packet_length = packet_send(); buffer_consume(&c->input, len); c->remote_window -= len; } @@ -2012,12 +2013,13 @@ channel_output_poll(void) packet_put_int(c->remote_id); packet_put_int(SSH2_EXTENDED_DATA_STDERR); packet_put_string(buffer_ptr(&c->extended), len); - packet_send(); + packet_length = packet_send(); buffer_consume(&c->extended, len); c->remote_window -= len; debug2("channel %d: sent ext data %d", c->self, len); } } + return (packet_length); } diff --git a/openssh/channels.h b/openssh/channels.h index c018fb7..da37281 100644 --- a/openssh/channels.h +++ b/openssh/channels.h @@ -197,7 +197,7 @@ void channel_input_window_adjust(int, u_int32_t, void *); void channel_prepare_select(fd_set **, fd_set **, int *, u_int*, int); void channel_after_select(fd_set *, fd_set *); -void channel_output_poll(void); +int channel_output_poll(void); int channel_not_very_much_buffered_data(void); void channel_close_all(void); diff --git a/openssh/cipher-ctr-mt.c b/openssh/cipher-ctr-mt.c new file mode 100644 index 0000000..abe39ff --- /dev/null +++ b/openssh/cipher-ctr-mt.c @@ -0,0 +1,473 @@ +/* + * OpenSSH Multi-threaded AES-CTR Cipher + * + * Author: Benjamin Bennett + * Copyright (c) 2008 Pittsburgh Supercomputing Center. All rights reserved. + * + * Based on original OpenSSH AES-CTR cipher. Small portions remain unchanged, + * Copyright (c) 2003 Markus Friedl + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "includes.h" + +#include + +#include +#include + +#include + +#include "xmalloc.h" +#include "log.h" + +/* compatibility with old or broken OpenSSL versions */ +#include "openbsd-compat/openssl-compat.h" + +#ifndef USE_BUILTIN_RIJNDAEL +#include +#endif + +#include + +/*-------------------- TUNABLES --------------------*/ +/* Number of pregen threads to use */ +#define CIPHER_THREADS 2 + +/* Number of keystream queues */ +#define NUMKQ (CIPHER_THREADS + 2) + +/* Length of a keystream queue */ +#define KQLEN 4096 + +/* Processor cacheline length */ +#define CACHELINE_LEN 64 + +/* Collect thread stats and print at cancellation when in debug mode */ +// #define CIPHER_THREAD_STATS + +/* Use single-byte XOR instead of 8-byte XOR */ +// #define CIPHER_BYTE_XOR +/*-------------------- END TUNABLES --------------------*/ + + +const EVP_CIPHER *evp_aes_ctr_mt(void); + +#ifdef CIPHER_THREAD_STATS +/* + * Struct to collect thread stats + */ +struct thread_stats { + u_int fills; + u_int skips; + u_int waits; + u_int drains; +}; + +/* + * Debug print the thread stats + * Use with pthread_cleanup_push for displaying at thread cancellation + */ +static void +thread_loop_stats(void *x) +{ + struct thread_stats *s = x; + + debug("tid %lu - %u fills, %u skips, %u waits", pthread_self(), + s->fills, s->skips, s->waits); +} + + #define STATS_STRUCT(s) struct thread_stats s + #define STATS_INIT(s) { memset(&s, 0, sizeof(s)); } + #define STATS_FILL(s) { s.fills++; } + #define STATS_SKIP(s) { s.skips++; } + #define STATS_WAIT(s) { s.waits++; } + #define STATS_DRAIN(s) { s.drains++; } +#else + #define STATS_STRUCT(s) + #define STATS_INIT(s) + #define STATS_FILL(s) + #define STATS_SKIP(s) + #define STATS_WAIT(s) + #define STATS_DRAIN(s) +#endif + +/* Keystream Queue state */ +enum { + KQINIT, + KQEMPTY, + KQFILLING, + KQFULL, + KQDRAINING +}; + +/* Keystream Queue struct */ +struct kq { + u_char keys[KQLEN][AES_BLOCK_SIZE]; + u_char ctr[AES_BLOCK_SIZE]; + u_char pad0[CACHELINE_LEN]; + volatile int qstate; + pthread_mutex_t lock; + pthread_cond_t cond; + u_char pad1[CACHELINE_LEN]; +}; + +/* Context struct */ +struct ssh_aes_ctr_ctx +{ + struct kq q[NUMKQ]; + AES_KEY aes_ctx; + STATS_STRUCT(stats); + u_char aes_counter[AES_BLOCK_SIZE]; + pthread_t tid[CIPHER_THREADS]; + int state; + int qidx; + int ridx; +}; + +/* + * increment counter 'ctr', + * the counter is of size 'len' bytes and stored in network-byte-order. + * (LSB at ctr[len-1], MSB at ctr[0]) + */ +static void +ssh_ctr_inc(u_char *ctr, u_int len) +{ + int i; + + for (i = len - 1; i >= 0; i--) + if (++ctr[i]) /* continue on overflow */ + return; +} + +/* + * Add num to counter 'ctr' + */ +static void +ssh_ctr_add(u_char *ctr, uint32_t num, u_int len) +{ + int i; + uint16_t n; + + for (n = 0, i = len - 1; i >= 0 && (num || n); i--) { + n = ctr[i] + (num & 0xff) + n; + num >>= 8; + ctr[i] = n & 0xff; + n >>= 8; + } +} + +/* + * Threads may be cancelled in a pthread_cond_wait, we must free the mutex + */ +static void +thread_loop_cleanup(void *x) +{ + pthread_mutex_unlock((pthread_mutex_t *)x); +} + +/* + * The life of a pregen thread: + * Find empty keystream queues and fill them using their counter. + * When done, update counter for the next fill. + */ +static void * +thread_loop(void *x) +{ + AES_KEY key; + STATS_STRUCT(stats); + struct ssh_aes_ctr_ctx *c = x; + struct kq *q; + int i; + int qidx; + + /* Threads stats on cancellation */ + STATS_INIT(stats); +#ifdef CIPHER_THREAD_STATS + pthread_cleanup_push(thread_loop_stats, &stats); +#endif + + /* Thread local copy of AES key */ + memcpy(&key, &c->aes_ctx, sizeof(key)); + + /* + * Handle the special case of startup, one thread must fill + * the first KQ then mark it as draining. Lock held throughout. + */ + if (pthread_equal(pthread_self(), c->tid[0])) { + q = &c->q[0]; + pthread_mutex_lock(&q->lock); + if (q->qstate == KQINIT) { + for (i = 0; i < KQLEN; i++) { + AES_encrypt(q->ctr, q->keys[i], &key); + ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE); + } + ssh_ctr_add(q->ctr, KQLEN * (NUMKQ - 1), AES_BLOCK_SIZE); + q->qstate = KQDRAINING; + STATS_FILL(stats); + pthread_cond_broadcast(&q->cond); + } + pthread_mutex_unlock(&q->lock); + } + else + STATS_SKIP(stats); + + /* + * Normal case is to find empty queues and fill them, skipping over + * queues already filled by other threads and stopping to wait for + * a draining queue to become empty. + * + * Multiple threads may be waiting on a draining queue and awoken + * when empty. The first thread to wake will mark it as filling, + * others will move on to fill, skip, or wait on the next queue. + */ + for (qidx = 1;; qidx = (qidx + 1) % NUMKQ) { + /* Check if I was cancelled, also checked in cond_wait */ + pthread_testcancel(); + + /* Lock queue and block if its draining */ + q = &c->q[qidx]; + pthread_mutex_lock(&q->lock); + pthread_cleanup_push(thread_loop_cleanup, &q->lock); + while (q->qstate == KQDRAINING || q->qstate == KQINIT) { + STATS_WAIT(stats); + pthread_cond_wait(&q->cond, &q->lock); + } + pthread_cleanup_pop(0); + + /* If filling or full, somebody else got it, skip */ + if (q->qstate != KQEMPTY) { + pthread_mutex_unlock(&q->lock); + STATS_SKIP(stats); + continue; + } + + /* + * Empty, let's fill it. + * Queue lock is relinquished while we do this so others + * can see that it's being filled. + */ + q->qstate = KQFILLING; + pthread_mutex_unlock(&q->lock); + for (i = 0; i < KQLEN; i++) { + AES_encrypt(q->ctr, q->keys[i], &key); + ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE); + } + + /* Re-lock, mark full and signal consumer */ + pthread_mutex_lock(&q->lock); + ssh_ctr_add(q->ctr, KQLEN * (NUMKQ - 1), AES_BLOCK_SIZE); + q->qstate = KQFULL; + STATS_FILL(stats); + pthread_cond_signal(&q->cond); + pthread_mutex_unlock(&q->lock); + } + +#ifdef CIPHER_THREAD_STATS + /* Stats */ + pthread_cleanup_pop(1); +#endif + + return NULL; +} + +static int +ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, + u_int len) +{ + struct ssh_aes_ctr_ctx *c; + struct kq *q, *oldq; + int ridx; + u_char *buf; + + if (len == 0) + return (1); + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) + return (0); + + q = &c->q[c->qidx]; + ridx = c->ridx; + + /* src already padded to block multiple */ + while (len > 0) { + buf = q->keys[ridx]; + +#ifdef CIPHER_BYTE_XOR + dest[0] = src[0] ^ buf[0]; + dest[1] = src[1] ^ buf[1]; + dest[2] = src[2] ^ buf[2]; + dest[3] = src[3] ^ buf[3]; + dest[4] = src[4] ^ buf[4]; + dest[5] = src[5] ^ buf[5]; + dest[6] = src[6] ^ buf[6]; + dest[7] = src[7] ^ buf[7]; + dest[8] = src[8] ^ buf[8]; + dest[9] = src[9] ^ buf[9]; + dest[10] = src[10] ^ buf[10]; + dest[11] = src[11] ^ buf[11]; + dest[12] = src[12] ^ buf[12]; + dest[13] = src[13] ^ buf[13]; + dest[14] = src[14] ^ buf[14]; + dest[15] = src[15] ^ buf[15]; +#else + *(uint64_t *)dest = *(uint64_t *)src ^ *(uint64_t *)buf; + *(uint64_t *)(dest + 8) = *(uint64_t *)(src + 8) ^ + *(uint64_t *)(buf + 8); +#endif + + dest += 16; + src += 16; + len -= 16; + ssh_ctr_inc(ctx->iv, AES_BLOCK_SIZE); + + /* Increment read index, switch queues on rollover */ + if ((ridx = (ridx + 1) % KQLEN) == 0) { + oldq = q; + + /* Mark next queue draining, may need to wait */ + c->qidx = (c->qidx + 1) % NUMKQ; + q = &c->q[c->qidx]; + pthread_mutex_lock(&q->lock); + while (q->qstate != KQFULL) { + STATS_WAIT(c->stats); + pthread_cond_wait(&q->cond, &q->lock); + } + q->qstate = KQDRAINING; + pthread_mutex_unlock(&q->lock); + + /* Mark consumed queue empty and signal producers */ + pthread_mutex_lock(&oldq->lock); + oldq->qstate = KQEMPTY; + STATS_DRAIN(c->stats); + pthread_cond_broadcast(&oldq->cond); + pthread_mutex_unlock(&oldq->lock); + } + } + c->ridx = ridx; + return (1); +} + +#define HAVE_NONE 0 +#define HAVE_KEY 1 +#define HAVE_IV 2 +static int +ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, + int enc) +{ + struct ssh_aes_ctr_ctx *c; + int i; + + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { + c = xmalloc(sizeof(*c)); + + c->state = HAVE_NONE; + for (i = 0; i < NUMKQ; i++) { + pthread_mutex_init(&c->q[i].lock, NULL); + pthread_cond_init(&c->q[i].cond, NULL); + } + + STATS_INIT(c->stats); + + EVP_CIPHER_CTX_set_app_data(ctx, c); + } + + if (c->state == (HAVE_KEY | HAVE_IV)) { + /* Cancel pregen threads */ + for (i = 0; i < CIPHER_THREADS; i++) + pthread_cancel(c->tid[i]); + for (i = 0; i < CIPHER_THREADS; i++) + pthread_join(c->tid[i], NULL); + /* Start over getting key & iv */ + c->state = HAVE_NONE; + } + + if (key != NULL) { + AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8, + &c->aes_ctx); + c->state |= HAVE_KEY; + } + + if (iv != NULL) { + memcpy(ctx->iv, iv, AES_BLOCK_SIZE); + c->state |= HAVE_IV; + } + + if (c->state == (HAVE_KEY | HAVE_IV)) { + /* Clear queues */ + memcpy(c->q[0].ctr, ctx->iv, AES_BLOCK_SIZE); + c->q[0].qstate = KQINIT; + for (i = 1; i < NUMKQ; i++) { + memcpy(c->q[i].ctr, ctx->iv, AES_BLOCK_SIZE); + ssh_ctr_add(c->q[i].ctr, i * KQLEN, AES_BLOCK_SIZE); + c->q[i].qstate = KQEMPTY; + } + c->qidx = 0; + c->ridx = 0; + + /* Start threads */ + for (i = 0; i < CIPHER_THREADS; i++) { + pthread_create(&c->tid[i], NULL, thread_loop, c); + } + pthread_mutex_lock(&c->q[0].lock); + while (c->q[0].qstate != KQDRAINING) + pthread_cond_wait(&c->q[0].cond, &c->q[0].lock); + pthread_mutex_unlock(&c->q[0].lock); + + } + return (1); +} + +static int +ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) +{ + struct ssh_aes_ctr_ctx *c; + int i; + + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) { +#ifdef CIPHER_THREAD_STATS + debug("main thread: %u drains, %u waits", c->stats.drains, + c->stats.waits); +#endif + /* Cancel pregen threads */ + for (i = 0; i < CIPHER_THREADS; i++) + pthread_cancel(c->tid[i]); + for (i = 0; i < CIPHER_THREADS; i++) + pthread_join(c->tid[i], NULL); + + memset(c, 0, sizeof(*c)); + xfree(c); + EVP_CIPHER_CTX_set_app_data(ctx, NULL); + } + return (1); +} + +/* */ +const EVP_CIPHER * +evp_aes_ctr_mt(void) +{ + static EVP_CIPHER aes_ctr; + + memset(&aes_ctr, 0, sizeof(EVP_CIPHER)); + aes_ctr.nid = NID_undef; + aes_ctr.block_size = AES_BLOCK_SIZE; + aes_ctr.iv_len = AES_BLOCK_SIZE; + aes_ctr.key_len = 16; + aes_ctr.init = ssh_aes_ctr_init; + aes_ctr.cleanup = ssh_aes_ctr_cleanup; + aes_ctr.do_cipher = ssh_aes_ctr; +#ifndef SSH_OLD_EVP + aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV; +#endif + return (&aes_ctr); +} diff --git a/openssh/cipher.c b/openssh/cipher.c index ddbf97c..7551292 100644 --- a/openssh/cipher.c +++ b/openssh/cipher.c @@ -55,6 +55,7 @@ extern const EVP_CIPHER *evp_ssh1_bf(void); extern const EVP_CIPHER *evp_ssh1_3des(void); extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); extern const EVP_CIPHER *evp_aes_128_ctr(void); +extern const EVP_CIPHER *evp_aes_ctr_mt(void); extern void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, u_int); struct Cipher { @@ -81,9 +82,9 @@ struct Cipher { { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, EVP_aes_256_cbc }, { "rijndael-cbc@lysator.liu.se", SSH_CIPHER_SSH2, 16, 32, 0, EVP_aes_256_cbc }, - { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, evp_aes_128_ctr }, - { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, evp_aes_128_ctr }, - { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, evp_aes_128_ctr }, + { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, evp_aes_ctr_mt }, + { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, evp_aes_ctr_mt }, + { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, evp_aes_ctr_mt }, #ifdef USE_CIPHER_ACSS { "acss@openssh.org", SSH_CIPHER_SSH2, 16, 5, 0, EVP_acss }, #endif diff --git a/openssh/kex.c b/openssh/kex.c index d2fa829..2633171 100644 --- a/openssh/kex.c +++ b/openssh/kex.c @@ -48,6 +48,7 @@ #include "match.h" #include "dispatch.h" #include "monitor.h" +#include "canohost.h" #ifdef GSSAPI #include "ssh-gss.h" @@ -395,6 +396,7 @@ kex_choose_conf(Kex *kex) int nenc, nmac, ncomp; u_int mode, ctos, need; int first_kex_follows, type; + int log_flag = 0; int auth_flag; @@ -439,6 +441,20 @@ kex_choose_conf(Kex *kex) newkeys->enc.name, newkeys->mac.name, newkeys->comp.name); + /* client starts withctos = 0 && log flag = 0 and no log*/ + /* 2nd client pass ctos=1 and flag = 1 so no log*/ + /* server starts with ctos =1 && log_flag = 0 so log */ + /* 2nd sever pass ctos = 1 && log flag = 1 so no log*/ + /* -cjr*/ + if (ctos && !log_flag) { + logit("SSH: Server;Ltype: Kex;Remote: %s-%d;Enc: %s;MAC: %s;Comp: %s", + get_remote_ipaddr(), + get_remote_port(), + newkeys->enc.name, + newkeys->mac.name, + newkeys->comp.name); + } + log_flag = 1; } choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], diff --git a/openssh/packet.c b/openssh/packet.c index ff83651..cab44bc 100644 --- a/openssh/packet.c +++ b/openssh/packet.c @@ -710,7 +710,7 @@ packet_enable_delayed_compress(void) /* * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) */ -static void +static int packet_send2_wrapped(void) { u_char type, *cp, *macbuf = NULL; @@ -822,11 +822,13 @@ packet_send2_wrapped(void) set_newkeys(MODE_OUT); else if (type == SSH2_MSG_USERAUTH_SUCCESS && server_side) packet_enable_delayed_compress(); + return(packet_length); } -static void +static int packet_send2(void) { + static int packet_length = 0; static int rekeying = 0; struct packet *p; u_char type, *cp; @@ -844,7 +846,7 @@ packet_send2(void) memcpy(&p->payload, &outgoing_packet, sizeof(Buffer)); buffer_init(&outgoing_packet); TAILQ_INSERT_TAIL(&outgoing, p, next); - return; + return(sizeof(Buffer)); } } @@ -852,7 +854,7 @@ packet_send2(void) if (type == SSH2_MSG_KEXINIT) rekeying = 1; - packet_send2_wrapped(); + packet_length = packet_send2_wrapped(); /* after a NEWKEYS message we can send the complete queue */ if (type == SSH2_MSG_NEWKEYS) { @@ -865,19 +867,22 @@ packet_send2(void) sizeof(Buffer)); TAILQ_REMOVE(&outgoing, p, next); xfree(p); - packet_send2_wrapped(); + packet_length += packet_send2_wrapped(); } } + return(packet_length); } -void +int packet_send(void) { + int packet_len = 0; if (compat20) - packet_send2(); + packet_len = packet_send2(); else packet_send1(); DBG(debug("packet_send done")); + return(packet_len); } /* @@ -1415,21 +1420,23 @@ packet_disconnect(const char *fmt,...) /* Checks if there is any buffered output, and tries to write some of the output. */ -void +int packet_write_poll(void) { - int len = buffer_len(&output); + int len = 0; + len = buffer_len(&output); if (len > 0) { len = write(connection_out, buffer_ptr(&output), len); if (len <= 0) { if (errno == EAGAIN) - return; + return (0); else fatal("Write failed: %.100s", strerror(errno)); } buffer_consume(&output, len); } + return(len); } /* @@ -1437,14 +1444,15 @@ packet_write_poll(void) * written. */ -void +int packet_write_wait(void) { fd_set *setp; + u_int bytes_sent = 0; setp = (fd_set *)xcalloc(howmany(connection_out + 1, NFDBITS), sizeof(fd_mask)); - packet_write_poll(); + bytes_sent += packet_write_poll(); while (packet_have_data_to_write()) { memset(setp, 0, howmany(connection_out + 1, NFDBITS) * sizeof(fd_mask)); @@ -1452,9 +1460,10 @@ packet_write_wait(void) while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 && (errno == EAGAIN || errno == EINTR)) ; - packet_write_poll(); + bytes_sent += packet_write_poll(); } xfree(setp); + return (bytes_sent); } /* Returns true if there is buffered data to write to the connection. */ diff --git a/openssh/packet.h b/openssh/packet.h index 4a7b529..caf8c46 100644 --- a/openssh/packet.h +++ b/openssh/packet.h @@ -47,7 +47,7 @@ void packet_put_bignum2(BIGNUM * value); void packet_put_string(const void *buf, u_int len); void packet_put_cstring(const char *str); void packet_put_raw(const void *buf, u_int len); -void packet_send(void); +int packet_send(void); int packet_read(void); void packet_read_expect(int type); @@ -75,8 +75,8 @@ void packet_set_state(int, u_int32_t, u_int64_t, u_int32_t); int packet_get_ssh1_cipher(void); void packet_set_iv(int, u_char *); -void packet_write_poll(void); -void packet_write_wait(void); +int packet_write_poll(void); +int packet_write_wait(void); int packet_have_data_to_write(void); int packet_not_very_much_data_to_write(void); diff --git a/openssh/serverloop.c b/openssh/serverloop.c index 289f806..e66e0a9 100644 --- a/openssh/serverloop.c +++ b/openssh/serverloop.c @@ -92,10 +92,10 @@ static int fdin; /* Descriptor for stdin (for writing) */ static int fdout; /* Descriptor for stdout (for reading); May be same number as fdin. */ static int fderr; /* Descriptor for stderr. May be -1. */ -static long stdin_bytes = 0; /* Number of bytes written to stdin. */ -static long stdout_bytes = 0; /* Number of stdout bytes sent to client. */ -static long stderr_bytes = 0; /* Number of stderr bytes sent to client. */ -static long fdout_bytes = 0; /* Number of stdout bytes read from program. */ +static u_long stdin_bytes = 0; /* Number of bytes written to stdin. */ +static u_long stdout_bytes = 0; /* Number of stdout bytes sent to client. */ +static u_long stderr_bytes = 0; /* Number of stderr bytes sent to client. */ +static u_long fdout_bytes = 0; /* Number of stdout bytes read from program. */ static int stdin_eof = 0; /* EOF message received from client. */ static int fdout_eof = 0; /* EOF encountered reading from fdout. */ static int fderr_eof = 0; /* EOF encountered readung from fderr. */ @@ -119,6 +119,20 @@ static volatile sig_atomic_t received_sigterm = 0; /* prototypes */ static void server_init_dispatch(void); +/* + * Returns current time in seconds from Jan 1, 1970 with the maximum + * available resolution. + */ + +static double +get_current_time(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; +} + + /* * we write to this pipe if a SIGCHLD is caught in order to avoid * the race between select() and child_terminated @@ -408,6 +422,7 @@ process_input(fd_set *readset) } else { /* Buffer any received data. */ packet_process_incoming(buf, len); + fdout_bytes += len; } } if (compat20) @@ -430,6 +445,7 @@ process_input(fd_set *readset) } else { buffer_append(&stdout_buffer, buf, len); fdout_bytes += len; + debug ("FD out now: %ld", fdout_bytes); } } /* Read and buffer any available stderr data from the program. */ @@ -496,7 +512,7 @@ process_output(fd_set *writeset) } /* Send any buffered packet data to the client. */ if (FD_ISSET(connection_out, writeset)) - packet_write_poll(); + stdin_bytes += packet_write_poll(); } /* @@ -813,8 +829,10 @@ server_loop2(Authctxt *authctxt) { fd_set *readset = NULL, *writeset = NULL; int rekeying = 0, max_fd, nalloc = 0; + double start_time, total_time; debug("Entering interactive session for SSH2."); + start_time = get_current_time(); mysignal(SIGCHLD, sigchld_handler); child_terminated = 0; @@ -876,6 +894,11 @@ server_loop2(Authctxt *authctxt) /* free remaining sessions, e.g. remove wtmp entries */ session_destroy_all(NULL); + total_time = get_current_time() - start_time; + logit("SSH: Server;LType: Throughput;Remote: %s-%d;IN: %lu;OUT: %lu;Duration: %.1f;tPut_in: %.1f;tPut_out: %.1f", + get_remote_ipaddr(), get_remote_port(), + stdin_bytes, fdout_bytes, total_time, stdin_bytes / total_time, + fdout_bytes / total_time); } static void diff --git a/openssh/sshd.c b/openssh/sshd.c index 3be9a48..0a3a549 100644 --- a/openssh/sshd.c +++ b/openssh/sshd.c @@ -477,6 +477,9 @@ sshd_exchange_identification(int sock_in, int sock_out) } debug("Client protocol version %d.%d; client software version %.100s", remote_major, remote_minor, remote_version); + logit("SSH: Server;Ltype: Version;Remote: %s-%d;Protocol: %d.%d;Client: %.100s", + get_remote_ipaddr(), get_remote_port(), + remote_major, remote_minor, remote_version); compat_datafellows(remote_version); diff --git a/openssh/version.h b/openssh/version.h index 4920906..a4c9f79 100644 --- a/openssh/version.h +++ b/openssh/version.h @@ -23,6 +23,6 @@ #define SSH_VERSION "OpenSSH_4.7" #define SSH_PORTABLE "p1" -#define SSH_HPN "-hpn12v20" +#define SSH_HPN "-hpn13v1" #define SSH_RELEASE SSH_VERSION SSH_PORTABLE SSH_HPN \ NCSA_VERSION GSI_VERSION KRB5_VERSION MGLUE_VERSION -- 2.45.1