Line data Source code
1 : // Copyright (c) 2012-2021 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/eventdispatcher
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program; if not, write to the Free Software
18 : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 :
20 : /** \file
21 : * \brief Event dispatch class.
22 : *
23 : * Class used to handle events.
24 : */
25 :
26 : // make sure we use OpenSSL with multi-thread support
27 : // (TODO: move to .cpp once we have the impl!)
28 : #define OPENSSL_THREAD_DEFINES
29 :
30 : // self
31 : //
32 : #include "eventdispatcher/tcp_private.h"
33 :
34 : #include "eventdispatcher/exception.h"
35 :
36 :
37 : // cppthread lib
38 : //
39 : #include <cppthread/guard.h>
40 : #include <cppthread/mutex.h>
41 : #include <cppthread/thread.h>
42 :
43 :
44 : // snaplogger lib
45 : //
46 : #include <snaplogger/message.h>
47 :
48 :
49 : // snapdev lib
50 : //
51 : #include <snapdev/not_used.h>
52 :
53 :
54 : // OpenSSL lib
55 : //
56 : #include <openssl/bio.h>
57 : #include <openssl/err.h>
58 : #include <openssl/ssl.h>
59 :
60 :
61 : // last include
62 : //
63 : #include <snapdev/poison.h>
64 :
65 :
66 :
67 :
68 : #ifndef OPENSSL_THREADS
69 : #error "OPENSSL_THREADS is not defined. Event Dispatcher requires OpenSSL to support multi-threading."
70 : #endif
71 :
72 : namespace ed
73 : {
74 :
75 :
76 : namespace detail
77 : {
78 :
79 :
80 :
81 : /** \brief The vector of locks.
82 : *
83 : * This function is initialized by the crypto_thread_setup().
84 : *
85 : * It is defined as a pointer in case someone was to try to access this
86 : * pointer before entering main().
87 : */
88 : cppthread::mutex::direct_vector_t * g_locks = nullptr;
89 :
90 :
91 : /** \brief Retrieve the system thread identifier.
92 : *
93 : * This function is used by the OpenSSL library to attach an internal thread
94 : * identifier (\p tid) to a system thread identifier.
95 : *
96 : * \param[in] tid The crypto internal thread identifier.
97 : */
98 0 : void pthreads_thread_id(CRYPTO_THREADID * tid)
99 : {
100 : // on 19.04 the macro does not use tid
101 : //
102 0 : snap::NOT_USED(tid);
103 :
104 : CRYPTO_THREADID_set_numeric(tid, cppthread::gettid());
105 0 : }
106 :
107 :
108 : /** \brief Handle locks and unlocks.
109 : *
110 : * This function is a callback used to lock and unlock mutexes as required.
111 : *
112 : * \param[in] mode Whether lock or unlock in read or write mode.
113 : * \param[in] type The "type" of lock (i.e. the index).
114 : * \param[in] file The filename of the source asking for a lock/unlock.
115 : * \param[in] line The line number in file where the call was made.
116 : */
117 0 : void pthreads_locking_callback(int mode, int type, char const * file, int line)
118 : {
119 0 : snap::NOT_USED(file, line);
120 :
121 0 : if(g_locks == nullptr)
122 : {
123 0 : throw event_dispatcher_initialization_missing("g_locks was not initialized");
124 : }
125 :
126 : /*
127 : # ifdef undef
128 : BIO_printf(bio_err, "thread=%4d mode=%s lock=%s %s:%d\n",
129 : CRYPTO_thread_id(),
130 : (mode & CRYPTO_LOCK) ? "l" : "u",
131 : (type & CRYPTO_READ) ? "r" : "w", file, line);
132 : # endif
133 : if (CRYPTO_LOCK_SSL_CERT == type)
134 : BIO_printf(bio_err,"(t,m,f,l) %ld %d %s %d\n",
135 : CRYPTO_thread_id(),
136 : mode,file,line);
137 : */
138 :
139 : // Note: at this point we ignore READ | WRITE because we do not have
140 : // such a concept with a simple mutex; we could take those in
141 : // account with a semaphore though.
142 : //
143 0 : if((mode & CRYPTO_LOCK) != 0)
144 : {
145 0 : (*g_locks)[type].lock();
146 : }
147 : else
148 : {
149 0 : (*g_locks)[type].unlock();
150 : }
151 0 : }
152 :
153 :
154 : /** \brief This function is called once on initialization.
155 : *
156 : * This function is called when the bio_initialize() function. It is
157 : * expected that the bio_initialize() function is called once by the
158 : * main thread before any other thread has a chance to do so.
159 : */
160 0 : void crypto_thread_setup()
161 : {
162 0 : cppthread::guard g(*cppthread::g_system_mutex);
163 :
164 0 : if(g_locks != nullptr)
165 : {
166 : throw event_dispatcher_initialization_error(
167 : "crypto_thread_setup() called for the second time."
168 : " This usually means two threads are initializing"
169 0 : " the BIO environment simultaneously.");
170 : }
171 :
172 0 : g_locks = new cppthread::mutex::direct_vector_t(CRYPTO_num_locks());
173 :
174 : CRYPTO_THREADID_set_callback(pthreads_thread_id);
175 : CRYPTO_set_locking_callback(pthreads_locking_callback);
176 0 : }
177 :
178 :
179 : /** \brief This function cleans up the thread setup.
180 : *
181 : * This function could be called to clean up the setup created to support
182 : * multiple threads running with the OpenSSL library.
183 : *
184 : * \note
185 : * At this time this function never gets called. So we have a small leak
186 : * but that's only on a quit.
187 : */
188 0 : void thread_cleanup()
189 : {
190 : CRYPTO_set_locking_callback(nullptr);
191 :
192 0 : delete g_locks;
193 0 : g_locks = nullptr;
194 0 : }
195 :
196 :
197 : /** \brief This function cleans up the error state of a thread.
198 : *
199 : * Whenever the OpenSSL system runs in a thread, it may create a
200 : * state to save various information, especially its error queue.
201 : *
202 : * \sa cleanup_on_thread_exit()
203 : */
204 0 : void per_thread_cleanup()
205 : {
206 : #if __cplusplus < 201700
207 : // this function is not necessary in newer versions of OpenSSL
208 : //
209 : ERR_remove_thread_state(nullptr);
210 : #endif
211 0 : }
212 :
213 :
214 :
215 :
216 :
217 :
218 :
219 : /** \brief Whether the bio_initialize() function was already called.
220 : *
221 : * This flag is used to know whether the bio_initialize() function was
222 : * already called. Only the bio_initialize() function is expected to
223 : * make use of this flag. Other functions should simply call the
224 : * bio_initialize() function (future versions may include addition
225 : * flags or use various bits in an integer instead.)
226 : */
227 : bool g_bio_initialized = false;
228 :
229 :
230 : /** \brief Initialize the BIO library.
231 : *
232 : * This function is called by the BIO implementations to initialize the
233 : * BIO library as required. It can be called any number of times. The
234 : * initialization will happen only once.
235 : */
236 0 : void bio_initialize()
237 : {
238 0 : cppthread::guard g(*cppthread::g_system_mutex);
239 :
240 : // already initialized?
241 : //
242 0 : if(g_bio_initialized)
243 : {
244 0 : return;
245 : }
246 0 : g_bio_initialized = true;
247 :
248 : // Make sure the SSL library gets initialized
249 : //
250 0 : SSL_library_init();
251 :
252 : // TBD: should we call the load string functions only when we
253 : // are about to generate the first error?
254 : //
255 0 : ERR_load_crypto_strings();
256 0 : ERR_load_SSL_strings();
257 0 : SSL_load_error_strings();
258 :
259 : // TODO: define a way to only define safe algorithms?
260 : // (it looks like we can force TLSv1.2 below at least)
261 : //
262 0 : OpenSSL_add_all_algorithms();
263 :
264 : // TBD: need a PRNG seeding before creating a new SSL context?
265 :
266 : // then initialize the library so it works in a multithreaded
267 : // environment
268 : //
269 0 : crypto_thread_setup();
270 : }
271 :
272 :
273 : /** \brief Clean up the BIO environment.
274 : *
275 : * This function cleans up the BIO environment.
276 : *
277 : * \note
278 : * This function is here mainly for documentation rather than to get called.
279 : * Whenever you exit a process that uses the BIO calls it will leak
280 : * a few things. To make the process really spanking clean, you want
281 : * to call this function before exit(3). You have to make sure that
282 : * you call this function only after every single BIO object was
283 : * closed and none must be opened after this call.
284 : */
285 0 : void bio_cleanup()
286 : {
287 : #if __cplusplus < 201700
288 : // this function is not necessary in newer versions of OpenSSL
289 : //
290 : ERR_remove_state(0);
291 : #endif
292 :
293 : EVP_cleanup();
294 : CRYPTO_cleanup_all_ex_data();
295 : ERR_free_strings();
296 0 : }
297 :
298 :
299 : /** \brief Get all the error messages and output them in our logs.
300 : *
301 : * This function reads all existing errors from the OpenSSL library
302 : * and send them to our logs.
303 : *
304 : * \param[in] sni Whether SNI is ON (true) or OFF (false).
305 : */
306 0 : int bio_log_errors()
307 : {
308 : // allow for up to 5 errors in one go, but we have a HUGE problem
309 : // at this time as in some cases the same error is repeated forever
310 : //
311 0 : for(int i(0);; ++i)
312 : {
313 0 : char const * filename(nullptr);
314 0 : int line(0);
315 0 : char const * data(nullptr);
316 0 : int flags(0);
317 0 : unsigned long bio_errno(ERR_get_error_line_data(&filename, &line, &data, &flags));
318 0 : if(bio_errno == 0)
319 : {
320 : // no more errors
321 : //
322 0 : return i;
323 : }
324 :
325 : // get corresponding messages too
326 : //
327 : // Note: current OpenSSL documentation on Ubuntu says errmsg[]
328 : // should be at least 120 characters BUT the code actually
329 : // use a limit of 256...
330 : //
331 0 : char errmsg[256];
332 0 : ERR_error_string_n(bio_errno, errmsg, sizeof(errmsg) / sizeof(errmsg[0]));
333 : // WARNING: the ERR_error_string() function is NOT multi-thread safe
334 :
335 : #pragma GCC diagnostic push
336 : #pragma GCC diagnostic ignored "-Wold-style-cast"
337 0 : int const lib_num(ERR_GET_LIB(bio_errno));
338 0 : int const func_num(ERR_GET_FUNC(bio_errno));
339 : #pragma GCC diagnostic pop
340 0 : char const * lib_name(ERR_lib_error_string(lib_num));
341 0 : char const * func_name(ERR_func_error_string(func_num));
342 0 : int const reason_num(ERR_GET_REASON(bio_errno));
343 0 : char const * reason(ERR_reason_error_string(reason_num));
344 :
345 0 : if(lib_name == nullptr)
346 : {
347 0 : lib_name = "<no libname>";
348 : }
349 0 : if(func_name == nullptr)
350 : {
351 0 : func_name = "<no funcname>";
352 : }
353 0 : if(reason == nullptr)
354 : {
355 0 : reason = "<no reason>";
356 : }
357 :
358 : // the format used by the OpenSSL library is as follow:
359 : //
360 : // [pid]:error:[error code]:[library name]:[function name]:[reason string]:[file name]:[line]:[optional text message]
361 : //
362 : // we do not duplicate the [pid] and "error" but include all the
363 : // other fields
364 : //
365 0 : SNAP_LOG_ERROR
366 0 : << "OpenSSL: ["
367 0 : << bio_errno // should be shown in hex...
368 0 : << "/"
369 : << lib_num
370 0 : << "|"
371 : << func_num
372 0 : << "|"
373 : << reason_num
374 : << "]:["
375 : << lib_name
376 : << "]:["
377 : << func_name
378 : << "]:["
379 : << reason
380 : << "]:["
381 : << filename
382 0 : << "]:["
383 : << line
384 : << "]:["
385 0 : << ((flags & ERR_TXT_STRING) != 0 && data != nullptr ? data : "(no details)")
386 : << "]"
387 : << SNAP_LOG_SEND;
388 0 : }
389 : }
390 :
391 :
392 : /** \brief Free a BIO object.
393 : *
394 : * This deleter is used to make sure that the BIO object gets freed
395 : * whenever the object holding it gets destroyed.
396 : *
397 : * Note that deleting a BIO connection calls shutdown() and close()
398 : * on the socket. In other words, it hangs up.
399 : *
400 : * \param[in] bio The BIO object to be freed.
401 : */
402 0 : void bio_deleter(BIO * bio)
403 : {
404 : // IMPORTANT NOTE:
405 : //
406 : // The BIO_free_all() calls shutdown() on the socket. This is not
407 : // acceptable in a normal Unix application that makes use of fork().
408 : // So... instead we ask the BIO interface to not close the socket,
409 : // and instead we close it ourselves. This means the shutdown()
410 : // never gets called.
411 : //
412 0 : BIO_set_close(bio, BIO_NOCLOSE);
413 :
414 0 : int c;
415 : #pragma GCC diagnostic push
416 : #pragma GCC diagnostic ignored "-Wold-style-cast"
417 0 : BIO_get_fd(bio, &c);
418 : #pragma GCC diagnostic pop
419 0 : if(c != -1)
420 : {
421 0 : close(c);
422 : }
423 :
424 0 : BIO_free_all(bio);
425 0 : }
426 :
427 :
428 : /** \brief Free an SSL_CTX object.
429 : *
430 : * This deleter is used to make sure that the SSL_CTX object gets
431 : * freed whenever the object holding it gets destroyed.
432 : */
433 0 : void ssl_ctx_deleter(SSL_CTX * ssl_ctx)
434 : {
435 0 : SSL_CTX_free(ssl_ctx);
436 0 : }
437 :
438 :
439 : }
440 : // namespace detail
441 :
442 :
443 :
444 :
445 :
446 :
447 :
448 :
449 :
450 :
451 :
452 :
453 :
454 :
455 : } // namespace ed
456 : // vim: ts=4 sw=4 et
|