src/mn-ssl.c (4221B) - raw
1 /* 2 * Mail Notification 3 * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 #include <errno.h> 21 #include <glib.h> 22 #include <glib/gi18n.h> 23 24 typedef GMutex CRYPTO_dynlock_value; 25 26 #include <openssl/ssl.h> 27 #include <openssl/crypto.h> 28 #include <openssl/err.h> 29 #include "mn-ssl.h" 30 31 static gboolean attempted = FALSE; 32 static SSL_CTX *ctx = NULL; 33 static char *init_error = NULL; 34 35 static int num_locks; 36 static GMutex **locks; 37 38 /* a general purpose global SSL lock */ 39 G_LOCK_DEFINE(mn_ssl); 40 41 static void 42 locking_cb (int mode, int n, const char *file, int line) 43 { 44 g_assert(n >= 0 && n < num_locks); 45 46 if ((mode & CRYPTO_LOCK) != 0) 47 g_mutex_lock(locks[n]); 48 else 49 g_mutex_unlock(locks[n]); 50 } 51 52 static unsigned long 53 id_cb (void) 54 { 55 return (unsigned long) g_thread_self(); 56 } 57 58 static struct CRYPTO_dynlock_value * 59 dynlock_create_cb (const char *file, int line) 60 { 61 return (struct CRYPTO_dynlock_value *) g_mutex_new(); 62 } 63 64 static void 65 dynlock_locking_cb (int mode, 66 struct CRYPTO_dynlock_value *lock, 67 const char *file, 68 int line) 69 { 70 if ((mode & CRYPTO_LOCK) != 0) 71 g_mutex_lock((GMutex *) lock); 72 else 73 g_mutex_unlock((GMutex *) lock); 74 } 75 76 static void 77 dynlock_destroy_cb (struct CRYPTO_dynlock_value *lock, 78 const char *file, 79 int line) 80 { 81 g_mutex_free((GMutex *) lock); 82 } 83 84 static void 85 init_threading (void) 86 { 87 int i; 88 89 num_locks = CRYPTO_num_locks(); 90 91 locks = g_new(GMutex *, num_locks); 92 for (i = 0; i < num_locks; i++) 93 locks[i] = g_mutex_new(); 94 95 CRYPTO_set_locking_callback(locking_cb); 96 CRYPTO_set_id_callback(id_cb); 97 98 CRYPTO_set_dynlock_create_callback(dynlock_create_cb); 99 CRYPTO_set_dynlock_lock_callback(dynlock_locking_cb); 100 CRYPTO_set_dynlock_destroy_callback(dynlock_destroy_cb); 101 } 102 103 SSL_CTX * 104 mn_ssl_init (GError **err) 105 { 106 /* 107 * SSL_CTX_new() will fail the second time it is called, so we just 108 * keep the same context for the whole application lifetime. 109 */ 110 111 G_LOCK(mn_ssl); 112 if (! attempted) 113 { 114 SSL_library_init(); 115 SSL_load_error_strings(); 116 117 init_threading(); 118 119 ctx = SSL_CTX_new(SSLv23_client_method()); 120 if (ctx) 121 { 122 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 123 SSL_CTX_set_default_verify_paths(ctx); /* #19578 */ 124 } 125 else 126 init_error = g_strdup(mn_ssl_get_error()); 127 128 attempted = TRUE; 129 } 130 131 if (! ctx) 132 { 133 g_assert(init_error != NULL); 134 g_set_error(err, 0, 0, "%s", init_error); 135 } 136 G_UNLOCK(mn_ssl); 137 138 return ctx; 139 } 140 141 const char * 142 mn_ssl_get_error (void) 143 { 144 static GStaticPrivate buf_key = G_STATIC_PRIVATE_INIT; 145 char *buf; 146 147 /* 148 * We use a per-thread buffer so that the caller does not have to 149 * free the returned string. 150 */ 151 152 buf = g_static_private_get(&buf_key); 153 if (! buf) 154 { 155 buf = g_new(char, 120); /* the size is specified by the manpage */ 156 g_static_private_set(&buf_key, buf, g_free); 157 } 158 159 return ERR_error_string(ERR_get_error(), buf); 160 } 161 162 const char * 163 mn_ssl_get_io_error (const SSL *ssl, int ret) 164 { 165 g_return_val_if_fail(ssl != NULL, NULL); 166 167 switch (SSL_get_error(ssl, ret)) 168 { 169 case SSL_ERROR_SYSCALL: 170 if (ERR_peek_error() == 0) 171 switch (ret) 172 { 173 case 0: 174 return "EOF"; 175 176 case -1: 177 /* 178 * This assumes that a UNIX BIO is in use (it is always 179 * the case in MN). 180 */ 181 return g_strerror(errno); 182 } 183 else 184 return mn_ssl_get_error(); 185 break; 186 187 case SSL_ERROR_SSL: 188 return mn_ssl_get_error(); 189 } 190 191 return _("unknown SSL/TLS error"); 192 }