Hi all!
I do not know openssh patch policy so I am just sending
the patch to the mailing list. Sorry for inconvenience.
Ssh-agent seems to be too slow if you need to access thousands of
servers. This is a simple patch to enable threading in ssh2 authentication.
Patch adds "-p numthreads" option and defaults to the number of
processors.
I've tested it as I could, but unfortunately I could check it
only in Linux environment. Though it shouldn't break anything.
Bye. Alex.
-------------- next part --------------
Index: Makefile.in
==================================================================RCS file:
/cvs/openssh/Makefile.in,v
retrieving revision 1.325
diff -u -r1.325 Makefile.in
--- Makefile.in 5 Aug 2011 20:15:18 -0000 1.325
+++ Makefile.in 11 Mar 2012 18:27:13 -0000
@@ -149,8 +149,8 @@
ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o
$(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
-ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o
- $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat
$(LIBS)
+ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o
ssh-openssl-thread-locking.o
+ $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o ssh-openssl-thread-locking.o
$(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
Index: configure.ac
==================================================================RCS file:
/cvs/openssh/configure.ac,v
retrieving revision 1.487
diff -u -r1.487 configure.ac
--- configure.ac 23 Feb 2012 23:40:43 -0000 1.487
+++ configure.ac 11 Mar 2012 18:27:16 -0000
@@ -2440,6 +2440,83 @@
AC_MSG_ERROR([OpenSSH has no source of random numbers. Please configure
OpenSSL with an entropy source or re-run configure using one of the
--with-prngd-port or --with-prngd-socket options])
fi
+AC_MSG_CHECKING([whether openssh has thread support compiled-in])
+AC_COMPILE_IFELSE([
+ AC_LANG_PROGRAM(
+ [[
+ #define OPENSSL_THREAD_DEFINES
+ #include <openssl/opensslconf.h>
+ ]] , [[
+ #if defined(OPENSSL_THREADS)
+ return 1;
+ #else
+ Must_not_compile 1 2 3;
+ #endif
+ ]]
+ )
+ ] , [
+ AC_MSG_RESULT([yes])
+ have_openssl_threads=yes;
+ ] , [
+ AC_MSG_RESULT([no - threading could not be used])
+ ]
+)
+
+AC_ARG_WITH([pthread],
+ [ --with-pthread Use pthread],
+ [
+ if test "x$withval" = "xno" ; then
+ AC_MSG_CHECKING([whether pthread support enabled])
+ AC_MSG_RESULT([no])
+ ssh_agent_options="threading:no"
+ elif test "x$withval" = "xyes"; then
+ AC_CHECK_LIB(pthread, pthread_create,,
+ [
+ AC_MSG_ERROR([pthread library not found])
+ ]
+ )
+ if test "$have_openssl_threads" ; then
+ true;
+ else
+ AC_MSG_ERROR([Openssl doesn't have thread support. Threading could not
be used.])
+ fi
+
+ ssh_agent_options="threading:yes"
+ else
+ AC_MSG_ERROR([--with-pthread value must be 'yes' or 'no',
but not '$withval'])
+ fi
+ ],
+ [
+ AC_CHECK_LIB(pthread, pthread_create)
+
+ if test "$ac_cv_lib_pthread_pthread_create" -a
"$have_openssl_threads" ; then
+ ssh_agent_options="threading:yes"
+ fi
+ ]
+)
+
+if test "x$ssh_agent_options" = "xthreading:yes" ; then
+ AC_MSG_CHECKING([sysconf(_SC_NPROCESSORS_CONF)])
+ AC_COMPILE_IFELSE([
+ AC_LANG_PROGRAM(
+ [[
+ #include <unistd.h>
+ ]] , [[
+ sysconf(_SC_NPROCESSORS_CONF);
+ ]]
+ )
+ ] , [
+ AC_DEFINE([HAVE___SC_NPROCESSORS_CONF],[],[Whether
sysconf(_SC_NPROCESSORS_CONF) is supported.])
+ AC_MSG_RESULT([yes])
+ ssh_agent_options="$ssh_agent_options nthreads:auto"
+ ] , [
+ AC_MSG_RESULT([no])
+ AC_MSG_WARN([ssh-agent: do not use threading by default])
+ ssh_agent_options="$ssh_agent_options nthreads:manual,default=0"
+ ]
+ )
+fi
+
# Check for PAM libs
PAM_MSG="no"
AC_ARG_WITH([pam],
@@ -4285,6 +4362,7 @@
echo " BSD Auth support: $BSD_AUTH_MSG"
echo " Random number source: $RAND_MSG"
echo " Privsep sandbox style: $SANDBOX_STYLE"
+echo " ssh-agent: $ssh_agent_options"
echo ""
Index: ssh-agent.1
==================================================================RCS file:
/cvs/openssh/ssh-agent.1,v
retrieving revision 1.53
diff -u -r1.53 ssh-agent.1
--- ssh-agent.1 1 Dec 2010 00:50:35 -0000 1.53
+++ ssh-agent.1 11 Mar 2012 18:27:16 -0000
@@ -102,6 +102,12 @@
.Xr ssh-add 1
overrides this value.
Without this option the default maximum lifetime is forever.
+.It Fl p Ar numthreads
+Start given number of ssh2 auth threads. Defaults to number of processors if
+.Pa sysconf(_SC_NPROCESSORS_CONF)
+is supported by the environment or to 0. 0 means "single-threaded
mode".
+
+This option is unavailable if threading is not compiled in.
.El
.Pp
If a commandline is given, this is executed as a subprocess of the agent.
Index: ssh-agent.c
==================================================================RCS file:
/cvs/openssh/ssh-agent.c,v
retrieving revision 1.194
diff -u -r1.194 ssh-agent.c
--- ssh-agent.c 3 Jun 2011 04:14:16 -0000 1.194
+++ ssh-agent.c 11 Mar 2012 18:27:17 -0000
@@ -13,6 +13,8 @@
*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
+ * Threading support by Alexander Alekseev <alex at alemate.ru>
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -58,6 +60,9 @@
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
+#ifdef HAVE_LIBPTHREAD
+#include "ssh-openssl-thread-locking.h"
+#endif
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
@@ -88,6 +93,9 @@
AUTH_UNUSED,
AUTH_SOCKET,
AUTH_CONNECTION
+#ifdef HAVE_LIBPTHREAD
+ , AUTH_INUSE
+#endif
} sock_type;
typedef struct {
@@ -137,6 +145,50 @@
/* Default lifetime (0 == forever) */
static int lifetime = 0;
+#ifdef HAVE_LIBPTHREAD
+
+#define MAX_THREADS 20
+
+#define REQ_QUEUE_LEN (MAX_THREADS * 2)
+
+typedef void (*AuthWorker)(SocketEntry*);
+
+struct AuthRequestQueueEntry {
+ AuthWorker worker;
+ SocketEntry *e;
+};
+
+struct AuthRequestQueue {
+ struct AuthRequestQueueEntry queue[REQ_QUEUE_LEN];
+ int first;
+ int used;
+ int inprogress; /* operated by get() */
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+};
+
+struct Thread {
+ pthread_t tid;
+ pthread_mutex_t lock; /* is locked while thread is serving request. Used as
barrier. */
+ struct AuthRequestQueue* queue;
+};
+
+struct TPool {
+ struct Thread threads[MAX_THREADS];
+ size_t num_threads;
+ struct AuthRequestQueue queue;
+};
+
+struct TPool tpool;
+
+void tpool_barrier(struct TPool*);
+
+#else
+
+#define tpool_barrier(a) do {} while(0)
+
+#endif
+
static void
close_socket(SocketEntry *e)
{
@@ -154,7 +206,7 @@
int i;
for (i = 0; i <=2; i++) {
- TAILQ_INIT(&idtable[i].idlist);
+ TAILQ_INIT(&(idtable[i].idlist));
idtable[i].nentries = 0;
}
}
@@ -355,6 +407,224 @@
datafellows = odatafellows;
}
+#ifdef HAVE_LIBPTHREAD
+
+int
+req_queue_init(struct AuthRequestQueue* q, int inprogress_initial)
+{
+ memset(q, 0, sizeof(struct AuthRequestQueue));
+
+ if (pthread_mutex_init(&(q->lock), 0)) {
+ error("pthread_mutex_init(queue): %s", strerror(errno));
+ return -1;
+ }
+ if (pthread_cond_init(&(q->cond), 0)) {
+ error("pthread_cond_init(queue): %s", strerror(errno));
+ return -1;
+ }
+ q->inprogress = inprogress_initial;
+ return 0;
+}
+
+int
+req_queue_enqueue(struct AuthRequestQueue* q, AuthWorker worker, SocketEntry
*e)
+{
+ int off;
+
+ pthread_mutex_lock(&(q->lock));
+
+ while (q->used >= REQ_QUEUE_LEN) {
+ if (pthread_cond_wait(&(q->cond), &(q->lock))) {
+ error("pthread_cond_wait(enqueue): %s", strerror(errno));
+ pthread_mutex_unlock(&(q->lock));
+ return -1;
+ }
+ }
+ off = q->first + q->used;
+ if (off >= REQ_QUEUE_LEN) {
+ off -= REQ_QUEUE_LEN;
+ }
+ q->queue[off].worker = worker;
+ q->queue[off].e = e;
+
+ if (q->used == 0) {
+ if (pthread_cond_signal(&(q->cond))) {
+ error("pthread_cond_signal(enqueue): %s", strerror(errno));
+ }
+ }
+ q->used++;
+ pthread_mutex_unlock(&(q->lock));
+ return 0;
+}
+
+void thread_lock(struct Thread* t);
+void thread_unlock(struct Thread* t);
+
+int
+req_queue_unlock_thread_get_and_lock_thread(struct Thread* t, AuthWorker*
out_worker, SocketEntry** out_e)
+{
+
+ struct AuthRequestQueue* q = t->queue;
+
+ pthread_mutex_lock(&(q->lock));
+ thread_unlock(t);
+
+ if (q->inprogress > 0) {
+ q->inprogress--;
+ }
+
+ while (q->used <= 0) {
+ if (pthread_cond_wait(&(q->cond), &(q->lock))) {
+ error("pthread_cond_wait(get): %s", strerror(errno));
+ thread_lock(t);
+ pthread_mutex_unlock(&(q->lock));
+ return -1;
+ }
+ }
+ *out_worker = q->queue[q->first].worker;
+ *out_e = q->queue[q->first].e;
+
+ q->first++;
+
+ if (q->first >= REQ_QUEUE_LEN) {
+ q->first = 0;
+ }
+
+ if (q->used >= REQ_QUEUE_LEN) {
+ if (pthread_cond_signal(&(q->cond))) {
+ error("pthread_cond_signal(get): %s", strerror(errno));
+ }
+ }
+ q->used--;
+ q->inprogress++;
+
+ thread_lock(t);
+ pthread_mutex_unlock(&(q->lock));
+ return 0;
+}
+
+/* Returns number of threads currently working plus number of requests in queue
+ * Returns -1 on error. */
+int
+req_queue_still_unserved(struct AuthRequestQueue* q)
+{
+ int retval;
+ if (pthread_mutex_lock(&(q->lock))) {
+ error("pthread_mutex_lock(queue): %s", strerror(errno));
+ return -1;
+ }
+ retval = q->inprogress + q->used;
+ pthread_mutex_unlock(&(q->lock));
+ return retval;
+}
+
+void*
+auth_thread_run(struct Thread* t)
+{
+ SocketEntry* e;
+ AuthWorker worker;
+
+ thread_lock(t);
+ while(1) {
+ if (req_queue_unlock_thread_get_and_lock_thread(t, &worker, &e)) {
+ sleep(1);
+ } else {
+ worker(e);
+ if (e->type == AUTH_INUSE) {
+ e->type = AUTH_CONNECTION;
+ }
+ }
+ }
+ return NULL;
+}
+
+int
+thread_init(struct Thread* t)
+{
+ if (pthread_mutex_init(&(t->lock), 0)) {
+ error("pthread_mutex_init(thread): %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+void
+thread_lock(struct Thread* t)
+{
+ while (pthread_mutex_lock(&(t->lock))) {
+ if (errno != EINTR) {
+ error("pthread_mutex_lock(thread): %s", strerror(errno));
+ sleep(1);
+ }
+ }
+}
+
+void
+thread_unlock(struct Thread* t)
+{
+ pthread_mutex_unlock(&(t->lock));
+}
+
+void tpool_barrier(struct TPool* p)
+{
+ size_t i;
+
+ debug("tpool_barrier called");
+ for(i = 0; i < p->num_threads; ++i) {
+ thread_lock(&(p->threads[i]));
+ thread_unlock(&(p->threads[i]));
+ }
+}
+
+typedef void* (*PThreadThreadFunction)(void*);
+int
+tpool_init(struct TPool* p, int numthreads)
+{
+ int i;
+
+ memset(p, 0, sizeof(struct TPool));
+
+ if (req_queue_init(&(p->queue), numthreads)) {
+ return -1;
+ }
+
+ if (numthreads > MAX_THREADS) {
+ numthreads = MAX_THREADS;
+ }
+ for(i = 0; i < numthreads; i++) {
+ struct Thread* thr = &(p->threads[i]);
+ if (thread_init(thr)) {
+ return -1;
+ }
+ thr->queue = &(p->queue);
+ if (pthread_create(&(thr->tid), 0,
(PThreadThreadFunction)auth_thread_run, thr)) {
+ error("pthread_create: %s", strerror(errno));
+ return -1;
+ }
+ }
+ p->num_threads = numthreads;
+
+ openssl_thread_locks_setup();
+ return 0;
+}
+
+#endif
+
+static void
+schedule_sign_request2(SocketEntry *e)
+{
+#ifndef HAVE_LIBPTHREAD
+ process_sign_request2(e);
+#else
+ if (tpool.num_threads) {
+ e->type = AUTH_INUSE;
+ req_queue_enqueue(&(tpool.queue), process_sign_request2, e);
+ } else {
+ process_sign_request2(e);
+ }
+#endif
+}
+
/* shared */
static void
process_remove_identity(SocketEntry *e, int version)
@@ -397,8 +667,11 @@
"internal error: tab->nentries %d",
tab->nentries);
TAILQ_REMOVE(&tab->idlist, id, next);
- free_identity(id);
tab->nentries--;
+
+ tpool_barrier(&tpool);
+
+ free_identity(id);
success = 1;
}
key_free(key);
@@ -418,6 +691,10 @@
for (id = TAILQ_FIRST(&tab->idlist); id;
id = TAILQ_FIRST(&tab->idlist)) {
TAILQ_REMOVE(&tab->idlist, id, next);
+ tab->nentries--;
+
+ tpool_barrier(&tpool);
+
free_identity(id);
}
@@ -447,8 +724,11 @@
if (now >= id->death) {
debug("expiring key '%s'", id->comment);
TAILQ_REMOVE(&tab->idlist, id, next);
- free_identity(id);
tab->nentries--;
+
+ tpool_barrier(&tpool);
+
+ free_identity(id);
} else
deadline = (deadline == 0) ? id->death :
MIN(deadline, id->death);
@@ -776,8 +1056,11 @@
nxt = TAILQ_NEXT(id, next);
if (!strcmp(provider, id->provider)) {
TAILQ_REMOVE(&tab->idlist, id, next);
- free_identity(id);
tab->nentries--;
+
+ tpool_barrier(&tpool);
+
+ free_identity(id);
}
}
}
@@ -861,7 +1144,7 @@
break;
/* ssh2 */
case SSH2_AGENTC_SIGN_REQUEST:
- process_sign_request2(e);
+ schedule_sign_request2(e);
break;
case SSH2_AGENTC_REQUEST_IDENTITIES:
process_request_identities(e, 2);
@@ -943,6 +1226,10 @@
break;
case AUTH_UNUSED:
break;
+#ifdef HAVE_LIBPTHREAD
+ case AUTH_INUSE:
+ break;
+#endif
default:
fatal("Unknown socket type %d", sockets[i].type);
break;
@@ -981,6 +1268,13 @@
if (parent_alive_interval != 0)
deadline = (deadline == 0) ? parent_alive_interval :
MIN(deadline, parent_alive_interval);
+#ifdef HAVE_LIBPTHREAD
+ if (req_queue_still_unserved(&(tpool.queue))) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 10000; /* 1/100 of a second */
+ *tvpp = &tv;
+ } else
+#endif
if (deadline == 0) {
*tvpp = NULL;
} else {
@@ -1062,6 +1356,10 @@
process_message(&sockets[i]);
}
break;
+#ifdef HAVE_LIBPTHREAD
+ case AUTH_INUSE:
+ break;
+#endif
default:
fatal("Unknown type %d", sockets[i].type);
}
@@ -1120,6 +1418,9 @@
fprintf(stderr, " -d Debug mode.\n");
fprintf(stderr, " -a socket Bind agent socket to given name.\n");
fprintf(stderr, " -t life Default identity lifetime
(seconds).\n");
+#ifdef HAVE_LIBPTHREAD
+ fprintf(stderr, " -p numthr Number of authenticate threads. 0 - do not
use separate threads.\n");
+#endif
exit(1);
}
@@ -1142,6 +1443,9 @@
char pidstrbuf[1 + 3 * sizeof pid];
struct timeval *tvp = NULL;
size_t len;
+#ifdef HAVE_LIBPTHREAD
+ int numthreads = -1;
+#endif
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
@@ -1160,7 +1464,7 @@
__progname = ssh_get_progname(av[0]);
seed_rng();
- while ((ch = getopt(ac, av, "cdksa:t:")) != -1) {
+ while ((ch = getopt(ac, av, "cdksa:t:p:")) != -1) {
switch (ch) {
case 'c':
if (s_flag)
@@ -1189,6 +1493,22 @@
usage();
}
break;
+ case 'p':
+#ifdef HAVE_LIBPTHREAD
+ numthreads = atoi(optarg);
+ if ((numthreads <= 0) && strcmp(optarg, "0")) {
+ fprintf(stderr, "Invalid numthreads\n");
+ usage();
+ }
+ if (numthreads > MAX_THREADS) {
+ fprintf(stderr, "Number of threads is limited to %u. Recompile to
increase.\n", MAX_THREADS);
+ usage();
+ }
+#else
+ fprintf(stderr, "Threading support not compiled in. \"-p
numthreads\" not supported.\n");
+ usage();
+#endif
+ break;
default:
usage();
}
@@ -1355,6 +1675,27 @@
signal(SIGTERM, cleanup_handler);
nalloc = 0;
+#ifdef HAVE_LIBPTHREAD
+ if (numthreads == -1) {
+#ifdef HAVE___SC_NPROCESSORS_CONF
+ numthreads = sysconf(_SC_NPROCESSORS_CONF);
+ if (numthreads == -1) {
+ error("sysconf(_SC_NPROCESSORS_CONF): %s", strerror(errno));
+ error("Defaults to single-thread mode.");
+ numthreads = 0;
+ } else if (numthreads == 1) {
+ numthreads = 0;
+ }
+#else
+ numthreads = 0; /* Single thread. */
+#endif /* HAVE___SC_NPROCESSORS_CONF */
+ }
+
+ if (tpool_init(&tpool, numthreads)) {
+ error("Failed to init threads pool.");
+ cleanup_exit(1);
+ }
+#endif
while (1) {
prepare_select(&readsetp, &writesetp, &max_fd, &nalloc,
&tvp);
result = select(max_fd + 1, readsetp, writesetp, NULL, tvp);
--- ssh-openssl-thread-locking.c 2012-03-11 00:00:00.000000000 +0000
+++ ssh-openssl-thread-locking.c 2012-03-11 21:37:10.000000000 +0400
@@ -0,0 +1,132 @@
+/* This code is taken from openssl distribution crypto/threads/mttest.c */
+/* Non-pthreads code is removed. */
+/* */
+/* */
+/* */
+/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay at cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh at cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay at cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the
library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an
acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh at
cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include "includes.h"
+
+#include "ssh-openssl-thread-locking.h"
+
+#include <openssl/crypto.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_LIBPTHREAD
+
+static pthread_mutex_t *lock_cs;
+static long *lock_count;
+
+void pthreads_locking_callback(int mode, int type, char *file, int line);
+unsigned long pthreads_thread_id(void);
+
+void openssl_thread_locks_setup(void)
+ {
+ int i;
+
+ lock_cs=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
+ lock_count=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
+ for (i=0; i<CRYPTO_num_locks(); i++)
+ {
+ lock_count[i]=0;
+ pthread_mutex_init(&(lock_cs[i]),NULL);
+ }
+
+ CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);
+ CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);
+ }
+
+void openssl_thread_locks_cleanup(void)
+ {
+ int i;
+
+ CRYPTO_set_locking_callback(NULL);
+ for (i=0; i<CRYPTO_num_locks(); i++)
+ {
+ pthread_mutex_destroy(&(lock_cs[i]));
+ }
+ OPENSSL_free(lock_cs);
+ OPENSSL_free(lock_count);
+
+ }
+
+void pthreads_locking_callback(int mode, int type, char *file, int line)
+ {
+ if (mode & CRYPTO_LOCK)
+ {
+ pthread_mutex_lock(&(lock_cs[type]));
+ lock_count[type]++;
+ }
+ else
+ {
+ pthread_mutex_unlock(&(lock_cs[type]));
+ }
+ }
+
+unsigned long pthreads_thread_id(void)
+ {
+ unsigned long ret;
+
+ ret=(unsigned long)pthread_self();
+ return(ret);
+ }
+
+#endif
--- ssh-openssl-thread-locking.h 2012-03-11 00:00:00.000000000 +0000
+++ ssh-openssl-thread-locking.h 2012-03-11 21:23:23.000000000 +0400
@@ -0,0 +1,75 @@
+/* This code is taken from openssl distribution crypto/threads/mttest.c */
+/* Non-pthreads code is removed. */
+/* */
+/* */
+/* */
+/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay at cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh at cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay at cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the
library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an
acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh at
cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef SSH_OPENSSL_THREAD_LOCKING_INCLUDED
+#define SSH_OPENSSL_THREAD_LOCKING_INCLUDED
+
+#include <pthread.h>
+
+#ifdef HAVE_LIBPTHREAD
+
+void openssl_thread_locks_setup(void);
+void openssl_thread_locks_cleanup(void);
+
+#endif
+
+#endif