From ac5ef6112fc0c42a8181d3b834d50f44ad097016 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Thu, 11 Nov 2010 15:11:47 -0500 Subject: [PATCH] Since libssh2 isn't thread safe, protect each session reference with a mutex. --- src/ssh.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/src/ssh.c b/src/ssh.c index 07813213..957f18dd 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -16,6 +16,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA */ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include @@ -28,18 +32,18 @@ #include #include #include - -#ifdef HAVE_CONFIG_H -#include -#endif +#include #ifdef WITH_LIBPTH #include #endif +#include "types.h" #include "misc.h" #include "ssh.h" +static pthread_mutex_t ssh_mutex = PTHREAD_MUTEX_INITIALIZER; + static gpg_error_t ssh_connect_finalize(pwm_t *pwm); static void ssh_deinit(pwmd_tcp_conn_t *conn) @@ -47,6 +51,8 @@ static void ssh_deinit(pwmd_tcp_conn_t *conn) if (!conn) return; + pthread_mutex_lock(&ssh_mutex); + if (conn->channel) { libssh2_channel_close(conn->channel); libssh2_channel_free(conn->channel); @@ -64,6 +70,7 @@ static void ssh_deinit(pwmd_tcp_conn_t *conn) conn->session = NULL; conn->channel = NULL; + pthread_mutex_unlock(&ssh_mutex); _free_ssh_conn(conn); } @@ -78,8 +85,11 @@ static int read_hook(assuan_context_t ctx, assuan_fd_t fd, void *data, #else *ret = recv((int)fd, data, len, 0); #endif - else + else { + pthread_mutex_lock(&ssh_mutex); *ret = libssh2_channel_read(pwm->tcp_conn->channel, data, len); + pthread_mutex_unlock(&ssh_mutex); + } return *ret >= 0 ? 1 : 0; } @@ -95,8 +105,11 @@ static int write_hook(assuan_context_t ctx, assuan_fd_t fd, const void *data, #else *ret = send((int)fd, data, len, 0); #endif - else + else { + pthread_mutex_lock(&ssh_mutex); *ret = libssh2_channel_write(pwm->tcp_conn->channel, data, len); + pthread_mutex_unlock(&ssh_mutex); + } return *ret >= 0 ? 1 : 0; } @@ -462,9 +475,11 @@ gpg_error_t _setup_ssh_auth(pwm_t *pwm) int n; pwm->tcp_conn->state = SSH_AUTH; + pthread_mutex_lock(&ssh_mutex); n = libssh2_userauth_publickey_fromfile(pwm->tcp_conn->session, pwm->tcp_conn->username, pwm->tcp_conn->identity_pub, pwm->tcp_conn->identity, NULL); + pthread_mutex_unlock(&ssh_mutex); if (n == LIBSSH2_ERROR_EAGAIN) return GPG_ERR_EAGAIN; @@ -483,9 +498,11 @@ gpg_error_t _setup_ssh_authlist(pwm_t *pwm) int n; pwm->tcp_conn->state = SSH_AUTHLIST; + pthread_mutex_lock(&ssh_mutex); userauth = libssh2_userauth_list(pwm->tcp_conn->session, pwm->tcp_conn->username, strlen(pwm->tcp_conn->username)); n = libssh2_session_last_errno(pwm->tcp_conn->session); + pthread_mutex_unlock(&ssh_mutex); if (!userauth && n == LIBSSH2_ERROR_EAGAIN) return GPG_ERR_EAGAIN; @@ -513,8 +530,10 @@ static void add_knownhost(pwm_t *pwm, const char *host, const char *key, buf = pwmd_strdup(host); char *tbuf = pwmd_strdup_printf("%li", time(NULL)); + pthread_mutex_lock(&ssh_mutex); libssh2_knownhost_addc(pwm->tcp_conn->kh, buf, NULL, key, len, tbuf, strlen(tbuf), type, dst); + pthread_mutex_unlock(&ssh_mutex); pwmd_free(tbuf); pwmd_free(buf); } @@ -523,11 +542,15 @@ static gpg_error_t check_known_hosts(pwm_t *pwm) { size_t len; int type; - const char *key = libssh2_session_hostkey(pwm->tcp_conn->session, &len, &type); + const char *key; gpg_error_t rc = 0; int n; struct libssh2_knownhost *kh; + pthread_mutex_lock(&ssh_mutex); + key = libssh2_session_hostkey(pwm->tcp_conn->session, &len, &type); + pthread_mutex_unlock(&ssh_mutex); + while (!libssh2_knownhost_get(pwm->tcp_conn->kh, &kh, NULL)) libssh2_knownhost_del(pwm->tcp_conn->kh, kh); @@ -650,8 +673,11 @@ static gpg_error_t verify_hostkey(pwm_t *pwm) size_t outlen; char *buf; - if (!pwm->tcp_conn->kh) + if (!pwm->tcp_conn->kh) { + pthread_mutex_lock(&ssh_mutex); pwm->tcp_conn->kh = libssh2_knownhost_init(pwm->tcp_conn->session); + pthread_mutex_unlock(&ssh_mutex); + } if (!pwm->tcp_conn->kh) return GPG_ERR_ENOMEM; @@ -724,9 +750,11 @@ gpg_error_t _setup_ssh_channel(pwm_t *pwm) gpg_error_t rc = 0; pwm->tcp_conn->state = SSH_CHANNEL; + pthread_mutex_lock(&ssh_mutex); pwm->tcp_conn->channel = libssh2_channel_open_session(pwm->tcp_conn->session); n = libssh2_session_last_errno(pwm->tcp_conn->session); + pthread_mutex_unlock(&ssh_mutex); if (!pwm->tcp_conn->channel && n == LIBSSH2_ERROR_EAGAIN) return GPG_ERR_EAGAIN; @@ -747,7 +775,9 @@ gpg_error_t _setup_ssh_shell(pwm_t *pwm) gpg_error_t rc; pwm->tcp_conn->state = SSH_SHELL; + pthread_mutex_lock(&ssh_mutex); n = libssh2_channel_shell(pwm->tcp_conn->channel); + pthread_mutex_unlock(&ssh_mutex); if (n == LIBSSH2_ERROR_EAGAIN) return GPG_ERR_EAGAIN; @@ -798,7 +828,9 @@ gpg_error_t _setup_ssh_init(pwm_t *pwm) goto done; pwm->tcp_conn->state = SSH_INIT; + pthread_mutex_lock(&ssh_mutex); n = libssh2_session_startup(pwm->tcp_conn->session, pwm->tcp_conn->fd); + pthread_mutex_unlock(&ssh_mutex); if (n == LIBSSH2_ERROR_EAGAIN) return GPG_ERR_EAGAIN; @@ -816,16 +848,22 @@ gpg_error_t _setup_ssh_session(pwm_t *pwm) { gpg_error_t rc; + pthread_mutex_lock(&ssh_mutex); + if (!pwm->tcp_conn->session) pwm->tcp_conn->session = libssh2_session_init_ex(ssh_malloc, ssh_free, - ssh_realloc, NULL); + ssh_realloc, NULL); + + pthread_mutex_unlock(&ssh_mutex); if (!pwm->tcp_conn->session) { rc = gpg_error_from_errno(ENOMEM); goto fail; } + pthread_mutex_lock(&ssh_mutex); libssh2_session_set_blocking(pwm->tcp_conn->session, 0); + pthread_mutex_unlock(&ssh_mutex); return _setup_ssh_init(pwm); fail: -- 2.11.4.GIT