Fix DEBUG_THREADS when lock is acquired in __constructor__
[asterisk/asterisk.git] / main / libasteriskssl.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009-2012, Digium, Inc.
5  *
6  * Russell Bryant <russell@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*!
20  * \file
21  * \brief Common OpenSSL support code
22  *
23  * \author Russell Bryant <russell@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #ifdef HAVE_OPENSSL
35 #include <openssl/ssl.h>
36 #include <openssl/err.h>
37 #endif
38
39 #include <dlfcn.h>
40
41 #include "asterisk/_private.h" /* ast_ssl_init() */
42
43 #include "asterisk/utils.h"
44 #include "asterisk/lock.h"
45
46 #ifdef HAVE_OPENSSL
47
48 #define get_OpenSSL_function(func) do { real_##func = dlsym(RTLD_NEXT, __stringify(func)); } while(0)
49
50 static int startup_complete;
51
52 static ast_mutex_t *ssl_locks;
53
54 static int ssl_num_locks;
55
56 static unsigned long ssl_threadid(void)
57 {
58         return (unsigned long) pthread_self();
59 }
60
61 static void ssl_lock(int mode, int n, const char *file, int line)
62 {
63         if (n < 0 || n >= ssl_num_locks) {
64                 ast_log(LOG_ERROR, "OpenSSL is full of LIES!!! - "
65                                 "ssl_num_locks '%d' - n '%d'\n",
66                                 ssl_num_locks, n);
67                 return;
68         }
69
70         if (mode & CRYPTO_LOCK) {
71                 ast_mutex_lock(&ssl_locks[n]);
72         } else {
73                 ast_mutex_unlock(&ssl_locks[n]);
74         }
75 }
76
77 int SSL_library_init(void)
78 {
79 #if defined(AST_DEVMODE)
80         if (startup_complete) {
81                 ast_debug(1, "Called after startup... ignoring!\n");
82         }
83 #endif
84         return 1;
85 }
86
87 void SSL_load_error_strings(void)
88 {
89 #if defined(AST_DEVMODE)
90         if (startup_complete) {
91                 ast_debug(1, "Called after startup... ignoring!\n");
92         }
93 #endif
94 }
95
96 void ERR_load_SSL_strings(void)
97 {
98 #if defined(AST_DEVMODE)
99         if (startup_complete) {
100                 ast_debug(1, "Called after startup... ignoring!\n");
101         }
102 #endif
103 }
104
105 void ERR_load_crypto_strings(void)
106 {
107 #if defined(AST_DEVMODE)
108         if (startup_complete) {
109                 ast_debug(1, "Called after startup... ignoring!\n");
110         }
111 #endif
112 }
113
114 void ERR_load_BIO_strings(void)
115 {
116 #if defined(AST_DEVMODE)
117         if (startup_complete) {
118                 ast_debug(1, "Called after startup... ignoring!\n");
119         }
120 #endif
121 }
122
123 void CRYPTO_set_id_callback(unsigned long (*func)(void))
124 {
125 #if defined(AST_DEVMODE)
126         if (startup_complete) {
127                 ast_debug(1, "Called after startup... ignoring!\n");
128         }
129 #endif
130 }
131
132 void CRYPTO_set_locking_callback(void (*func)(int mode,int type, const char *file, int line))
133 {
134 #if defined(AST_DEVMODE)
135         if (startup_complete) {
136                 ast_debug(1, "Called after startup... ignoring!\n");
137         }
138 #endif
139 }
140
141 void ERR_free_strings(void)
142 {
143         /* we can't allow this to be called, ever */
144 }
145
146 #endif /* HAVE_OPENSSL */
147
148 /*!
149  * \internal
150  * \brief Common OpenSSL initialization for all of Asterisk.
151  */
152 int ast_ssl_init(void)
153 {
154 #ifdef HAVE_OPENSSL
155         unsigned int i;
156         int (*real_SSL_library_init)(void);
157         void (*real_CRYPTO_set_id_callback)(unsigned long (*)(void));
158         void (*real_CRYPTO_set_locking_callback)(void (*)(int, int, const char *, int));
159         void (*real_SSL_load_error_strings)(void);
160         void (*real_ERR_load_SSL_strings)(void);
161         void (*real_ERR_load_BIO_strings)(void);
162         const char *errstr;
163
164         /* clear any previous dynamic linker errors */
165         dlerror();
166         get_OpenSSL_function(SSL_library_init);
167         if ((errstr = dlerror()) != NULL) {
168                 ast_debug(1, "unable to get real address of SSL_library_init: %s\n", errstr);
169                 /* there is no way to continue in this situation... SSL will
170                  * likely be broken in this process
171                  */
172                 return -1;
173         } else {
174                 real_SSL_library_init();
175         }
176
177         /* Make OpenSSL usage thread-safe. */
178
179         dlerror();
180         get_OpenSSL_function(CRYPTO_set_id_callback);
181         if ((errstr = dlerror()) != NULL) {
182                 ast_debug(1, "unable to get real address of CRYPTO_set_id_callback: %s\n", errstr);
183                 /* there is no way to continue in this situation... SSL will
184                  * likely be broken in this process
185                  */
186                 return -1;
187         } else {
188                 real_CRYPTO_set_id_callback(ssl_threadid);
189         }
190
191         dlerror();
192         get_OpenSSL_function(CRYPTO_set_locking_callback);
193         if ((errstr = dlerror()) != NULL) {
194                 ast_debug(1, "unable to get real address of CRYPTO_set_locking_callback: %s\n", errstr);
195                 /* there is no way to continue in this situation... SSL will
196                  * likely be broken in this process
197                  */
198                 return -1;
199         } else {
200                 ssl_num_locks = CRYPTO_num_locks();
201                 if (!(ssl_locks = ast_calloc(ssl_num_locks, sizeof(ssl_locks[0])))) {
202                         return -1;
203                 }
204                 for (i = 0; i < ssl_num_locks; i++) {
205                         ast_mutex_init(&ssl_locks[i]);
206                 }
207                 real_CRYPTO_set_locking_callback(ssl_lock);
208         }
209
210         /* after this point, we don't check for errors from the dlsym() calls,
211          * under the assumption that if the ones above were successful, all
212          * the rest will be too. this assumption holds as long as OpenSSL still
213          * provides all of these functions.
214          */
215
216         get_OpenSSL_function(SSL_load_error_strings);
217         real_SSL_load_error_strings();
218
219         get_OpenSSL_function(ERR_load_SSL_strings);
220         real_ERR_load_SSL_strings();
221
222         get_OpenSSL_function(ERR_load_BIO_strings);
223         real_ERR_load_BIO_strings();
224
225         startup_complete = 1;
226
227 #endif /* HAVE_OPENSSL */
228         return 0;
229 }
230