Line data Source code
1 : // Copyright (c) 2012-2022 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 along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 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 : snapdev::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 : snapdev::NOT_USED(file, line);
120 :
121 0 : if(g_locks == nullptr)
122 : {
123 0 : throw 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 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 OPENSSL_VERSION_NUMBER < 0x1010100fL
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 : #if OPENSSL_VERSION_NUMBER < 0x30000020L
257 : // this function is not necessary in newer versions of OpenSSL
258 : //
259 0 : ERR_load_SSL_strings();
260 : #endif
261 0 : SSL_load_error_strings();
262 :
263 : // TODO: define a way to only define safe algorithms?
264 : // (it looks like we can force TLSv1.2 below at least)
265 : //
266 0 : OpenSSL_add_all_algorithms();
267 :
268 : // TBD: need a PRNG seeding before creating a new SSL context?
269 :
270 : // then initialize the library so it works in a multithreaded
271 : // environment
272 : //
273 0 : crypto_thread_setup();
274 : }
275 :
276 :
277 : /** \brief Clean up the BIO environment.
278 : *
279 : * This function cleans up the BIO environment.
280 : *
281 : * \note
282 : * This function is here mainly for documentation rather than to get called.
283 : * Whenever you exit a process that uses the BIO calls it will leak
284 : * a few things. To make the process really spanking clean, you want
285 : * to call this function before exit(3). You have to make sure that
286 : * you call this function only after every single BIO object was
287 : * closed and none must be opened after this call.
288 : */
289 0 : void bio_cleanup()
290 : {
291 : #if OPENSSL_VERSION_NUMBER < 0x1010100fL
292 : // this function is not necessary in newer versions of OpenSSL
293 : //
294 : ERR_remove_state(0);
295 : #endif
296 :
297 : EVP_cleanup();
298 : CRYPTO_cleanup_all_ex_data();
299 : ERR_free_strings();
300 0 : }
301 :
302 :
303 : /** \brief Get all the error messages and output them in our logs.
304 : *
305 : * This function reads all existing errors from the OpenSSL library
306 : * and send them to our logs.
307 : *
308 : * \return The number of errors that the function found.
309 : */
310 0 : int bio_log_errors()
311 : {
312 : // allow for up to 5 errors in one go, but we have a HUGE problem
313 : // at this time as in some cases the same error is repeated forever
314 : //
315 0 : for(int count(0);; ++count)
316 : {
317 0 : char const * filename(nullptr);
318 0 : int line(0);
319 0 : char const * data(nullptr);
320 0 : int flags(0);
321 0 : char const * func_name(nullptr);
322 : #if OPENSSL_VERSION_NUMBER < 0x30000020L
323 0 : unsigned long bio_errno(ERR_get_error_line_data(&filename, &line, &data, &flags));
324 : #else
325 : unsigned long bio_errno(ERR_get_error_all(&filename, &line, &func_name, &data, &flags));
326 : #endif
327 0 : if(bio_errno == 0)
328 : {
329 : // no more errors
330 : //
331 0 : return count;
332 : }
333 :
334 : // get corresponding messages too
335 : //
336 : // Note: current OpenSSL documentation on Ubuntu says errmsg[]
337 : // should be at least 120 characters BUT the code actually
338 : // use a limit of 256...
339 : //
340 0 : char errmsg[256];
341 0 : ERR_error_string_n(bio_errno, errmsg, sizeof(errmsg) / sizeof(errmsg[0]));
342 : // WARNING: the ERR_error_string() function is NOT multi-thread safe
343 :
344 : #pragma GCC diagnostic push
345 : #pragma GCC diagnostic ignored "-Wold-style-cast"
346 0 : int const lib_num(ERR_GET_LIB(bio_errno));
347 : #if OPENSSL_VERSION_NUMBER < 0x30000020L
348 0 : int const func_num(ERR_GET_FUNC(bio_errno));
349 : #endif
350 : #pragma GCC diagnostic pop
351 0 : char const * lib_name(ERR_lib_error_string(lib_num));
352 : #if OPENSSL_VERSION_NUMBER < 0x30000020L
353 0 : func_name = ERR_func_error_string(func_num);
354 : #endif
355 0 : int const reason_num(ERR_GET_REASON(bio_errno));
356 0 : char const * reason(ERR_reason_error_string(reason_num));
357 :
358 0 : if(lib_name == nullptr)
359 : {
360 0 : lib_name = "<no libname>";
361 : }
362 0 : if(func_name == nullptr)
363 : {
364 0 : func_name = "<no funcname>";
365 : }
366 0 : if(reason == nullptr)
367 : {
368 0 : reason = "<no reason>";
369 : }
370 :
371 : // the format used by the OpenSSL library is as follow:
372 : //
373 : // [pid]:error:[error code]:[library name]:[function name]:[reason string]:[file name]:[line]:[optional text message]
374 : //
375 : // we do not duplicate the [pid] and "error" but include all the
376 : // other fields
377 : //
378 0 : SNAP_LOG_ERROR
379 0 : << "OpenSSL: ["
380 0 : << bio_errno // should be shown in hex...
381 0 : << "/"
382 : << lib_num
383 0 : << "|"
384 : << reason_num
385 : << "]:["
386 : << lib_name
387 : << "]:["
388 : << func_name
389 : << "]:["
390 : << reason
391 : << "]:["
392 : << filename
393 0 : << "]:["
394 : << line
395 : << "]:["
396 0 : << ((flags & ERR_TXT_STRING) != 0 && data != nullptr ? data : "(no details)")
397 : << "]"
398 : << SNAP_LOG_SEND;
399 0 : }
400 : }
401 :
402 :
403 : /** \brief Free a BIO object.
404 : *
405 : * This deleter is used to make sure that the BIO object gets freed
406 : * whenever the object holding it gets destroyed.
407 : *
408 : * Note that deleting a BIO connection calls shutdown() and close()
409 : * on the socket. In other words, it hangs up.
410 : *
411 : * \param[in] bio The BIO object to be freed.
412 : */
413 0 : void bio_deleter(BIO * bio)
414 : {
415 : // IMPORTANT NOTE:
416 : //
417 : // The BIO_free_all() calls shutdown() on the socket. This is not
418 : // acceptable in a normal Unix application that makes use of fork().
419 : // So... instead we ask the BIO interface to not close the socket,
420 : // and instead we close it ourselves. This means the shutdown()
421 : // never gets called.
422 : //
423 0 : BIO_set_close(bio, BIO_NOCLOSE);
424 :
425 0 : int c;
426 : #pragma GCC diagnostic push
427 : #pragma GCC diagnostic ignored "-Wold-style-cast"
428 0 : BIO_get_fd(bio, &c);
429 : #pragma GCC diagnostic pop
430 0 : if(c != -1)
431 : {
432 0 : close(c);
433 : }
434 :
435 0 : BIO_free_all(bio);
436 0 : }
437 :
438 :
439 : /** \brief Free an SSL_CTX object.
440 : *
441 : * This deleter is used to make sure that the SSL_CTX object gets
442 : * freed whenever the object holding it gets destroyed.
443 : *
444 : * \param[in] ssl_ctx The SSL context to delete.
445 : */
446 0 : void ssl_ctx_deleter(SSL_CTX * ssl_ctx)
447 : {
448 0 : SSL_CTX_free(ssl_ctx);
449 0 : }
450 :
451 :
452 : }
453 : // namespace detail
454 :
455 :
456 :
457 :
458 :
459 :
460 :
461 :
462 :
463 :
464 :
465 :
466 :
467 :
468 : } // namespace ed
469 : // vim: ts=4 sw=4 et
|