Fix initial loading problem with res_curl
[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_crypto_strings)(void);
162         void (*real_ERR_load_BIO_strings)(void);
163         const char *errstr;
164
165         /* clear any previous dynamic linker errors */
166         dlerror();
167         get_OpenSSL_function(SSL_library_init);
168         if ((errstr = dlerror()) != NULL) {
169                 ast_debug(1, "unable to get real address of SSL_library_init: %s\n", errstr);
170                 /* there is no way to continue in this situation... SSL will
171                  * likely be broken in this process
172                  */
173                 return -1;
174         } else {
175                 real_SSL_library_init();
176         }
177
178         /* Make OpenSSL usage thread-safe. */
179
180         dlerror();
181         get_OpenSSL_function(CRYPTO_set_id_callback);
182         if ((errstr = dlerror()) != NULL) {
183                 ast_debug(1, "unable to get real address of CRYPTO_set_id_callback: %s\n", errstr);
184                 /* there is no way to continue in this situation... SSL will
185                  * likely be broken in this process
186                  */
187                 return -1;
188         } else {
189                 real_CRYPTO_set_id_callback(ssl_threadid);
190         }
191
192         dlerror();
193         get_OpenSSL_function(CRYPTO_set_locking_callback);
194         if ((errstr = dlerror()) != NULL) {
195                 ast_debug(1, "unable to get real address of CRYPTO_set_locking_callback: %s\n", errstr);
196                 /* there is no way to continue in this situation... SSL will
197                  * likely be broken in this process
198                  */
199                 return -1;
200         } else {
201                 ssl_num_locks = CRYPTO_num_locks();
202                 if (!(ssl_locks = ast_calloc(ssl_num_locks, sizeof(ssl_locks[0])))) {
203                         return -1;
204                 }
205                 for (i = 0; i < ssl_num_locks; i++) {
206                         ast_mutex_init(&ssl_locks[i]);
207                 }
208                 real_CRYPTO_set_locking_callback(ssl_lock);
209         }
210
211         /* after this point, we don't check for errors from the dlsym() calls,
212          * under the assumption that if the ones above were successful, all
213          * the rest will be too. this assumption holds as long as OpenSSL still
214          * provides all of these functions.
215          */
216
217         get_OpenSSL_function(SSL_load_error_strings);
218         real_SSL_load_error_strings();
219
220         get_OpenSSL_function(ERR_load_SSL_strings);
221         real_ERR_load_SSL_strings();
222
223         get_OpenSSL_function(ERR_load_crypto_strings);
224         real_ERR_load_crypto_strings();
225
226         get_OpenSSL_function(ERR_load_BIO_strings);
227         real_ERR_load_BIO_strings();
228
229 #if 0
230         /* currently this is just another call to SSL_library_init, so we don't call it */
231         OpenSSL_add_all_algorithms();
232 #endif
233
234         startup_complete = 1;
235
236 #endif /* HAVE_OPENSSL */
237         return 0;
238 }
239