LD=@LD@
CFLAGS=@CFLAGS@
CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@
-LIBS=@LIBS@
+LIBS=@LIBS@ -lpthread
SSHDLIBS=@SSHDLIBS@
LIBEDIT=@LIBEDIT@
AR=@AR@
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 \
+/* $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.
*
*/
#include "includes.h"
-RCSID("$OpenBSD: atomicio.c,v 1.10 2001/05/08 22:48:07 markus Exp $");
+
+#include <sys/param.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+#include <string.h>
+#include <unistd.h>
#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;
+}
#include "dispatch.h"
#include "pathnames.h"
#include "buffer.h"
+#include "canohost.h"
#ifdef GSSAPI
#include "ssh-gss.h"
extern Authmethod method_gssapi_compat;
#endif
+static int log_flag = 0;
+
+
Authmethod *authmethods[] = {
&method_none,
&method_pubkey,
debug("userauth-request for user %s service %s method %s",
user[0] ? user : "<implicit>", 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)
/* 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);
/* 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];
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);
}
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;
}
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);
}
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);
--- /dev/null
+/*
+ * OpenSSH Multi-threaded AES-CTR Cipher
+ *
+ * Author: Benjamin Bennett <ben@psc.edu>
+ * 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 <markus@openbsd.org>
+ *
+ * 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 <sys/types.h>
+
+#include <stdarg.h>
+#include <string.h>
+
+#include <openssl/evp.h>
+
+#include "xmalloc.h"
+#include "log.h"
+
+/* compatibility with old or broken OpenSSL versions */
+#include "openbsd-compat/openssl-compat.h"
+
+#ifndef USE_BUILTIN_RIJNDAEL
+#include <openssl/aes.h>
+#endif
+
+#include <pthread.h>
+
+/*-------------------- 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;
+};
+
+/* <friedl>
+ * 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);
+}
+
+/* <friedl> */
+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);
+}
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 {
{ "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
#include "match.h"
#include "dispatch.h"
#include "monitor.h"
+#include "canohost.h"
#ifdef GSSAPI
#include "ssh-gss.h"
int nenc, nmac, ncomp;
u_int mode, ctos, need;
int first_kex_follows, type;
+ int log_flag = 0;
int auth_flag;
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],
/*
* Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
*/
-static void
+static int
packet_send2_wrapped(void)
{
u_char type, *cp, *macbuf = NULL;
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;
memcpy(&p->payload, &outgoing_packet, sizeof(Buffer));
buffer_init(&outgoing_packet);
TAILQ_INSERT_TAIL(&outgoing, p, next);
- return;
+ return(sizeof(Buffer));
}
}
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) {
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);
}
/*
/* 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);
}
/*
* 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));
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. */
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);
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);
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. */
/* 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
} else {
/* Buffer any received data. */
packet_process_incoming(buf, len);
+ fdout_bytes += len;
}
}
if (compat20)
} 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. */
}
/* Send any buffered packet data to the client. */
if (FD_ISSET(connection_out, writeset))
- packet_write_poll();
+ stdin_bytes += packet_write_poll();
}
/*
{
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;
/* 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
}
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);
#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