Line data Source code
1 : // Copyright (c) 2012-2019 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 Data handled by each lock.
82 : // *
83 : // * This function holds the data handled on a per lock basis.
84 : // * Even if your daemon is not using multiple threads, this
85 : // * is likely to kick in.
86 : // */
87 : //class crypto_lock_t
88 : //{
89 : //public:
90 : // typedef std::vector<crypto_lock_t> vector_t;
91 : //
92 : // crypto_lock_t()
93 : // {
94 : // pthread_mutex_init(&f_mutex, nullptr);
95 : // }
96 : //
97 : // ~crypto_lock_t()
98 : // {
99 : // pthread_mutex_destroy(&f_mutex);
100 : // }
101 : //
102 : // void lock()
103 : // {
104 : // pthread_mutex_lock(&f_mutex);
105 : // }
106 : //
107 : // void unlock()
108 : // {
109 : // pthread_mutex_unlock(&f_mutex);
110 : // }
111 : //
112 : //private:
113 : // pthread_mutex_t f_mutex = pthread_mutex_t();
114 : //};
115 :
116 :
117 : /** \brief The vector of locks.
118 : *
119 : * This function is initialized by the crypto_thread_setup().
120 : *
121 : * It is defined as a pointer in case someone was to try to access this
122 : * pointer before entering main().
123 : */
124 : //crypto_lock_t::vector_t * g_locks = nullptr;
125 : cppthread::mutex::direct_vector_t * g_locks = nullptr;
126 :
127 :
128 : /** \brief Retrieve the system thread identifier.
129 : *
130 : * This function is used by the OpenSSL library to attach an internal thread
131 : * identifier (\p tid) to a system thread identifier.
132 : *
133 : * \param[in] tid The crypto internal thread identifier.
134 : */
135 0 : void pthreads_thread_id(CRYPTO_THREADID * tid)
136 : {
137 : // on 19.04 the macro does not use tid
138 : //
139 0 : snap::NOTUSED(tid);
140 :
141 0 : CRYPTO_THREADID_set_numeric(tid, cppthread::gettid());
142 0 : }
143 :
144 :
145 : /** \brief Handle locks and unlocks.
146 : *
147 : * This function is a callback used to lock and unlock mutexes as required.
148 : *
149 : * \param[in] mode Whether lock or unlock in read or write mode.
150 : * \param[in] type The "type" of lock (i.e. the index).
151 : * \param[in] file The filename of the source asking for a lock/unlock.
152 : * \param[in] line The line number in file where the call was made.
153 : */
154 0 : void pthreads_locking_callback(int mode, int type, char const * file, int line)
155 : {
156 0 : snap::NOTUSED(file);
157 0 : snap::NOTUSED(line);
158 :
159 0 : if(g_locks == nullptr)
160 : {
161 0 : throw event_dispatcher_initialization_missing("g_locks was not initialized");
162 : }
163 :
164 : /*
165 : # ifdef undef
166 : BIO_printf(bio_err, "thread=%4d mode=%s lock=%s %s:%d\n",
167 : CRYPTO_thread_id(),
168 : (mode & CRYPTO_LOCK) ? "l" : "u",
169 : (type & CRYPTO_READ) ? "r" : "w", file, line);
170 : # endif
171 : if (CRYPTO_LOCK_SSL_CERT == type)
172 : BIO_printf(bio_err,"(t,m,f,l) %ld %d %s %d\n",
173 : CRYPTO_thread_id(),
174 : mode,file,line);
175 : */
176 :
177 : // Note: at this point we ignore READ | WRITE because we do not have
178 : // such a concept with a simple mutex; we could take those in
179 : // account with a semaphore though.
180 : //
181 0 : if((mode & CRYPTO_LOCK) != 0)
182 : {
183 0 : (*g_locks)[type].lock();
184 : }
185 : else
186 : {
187 0 : (*g_locks)[type].unlock();
188 : }
189 0 : }
190 :
191 :
192 : /** \brief This function is called once on initialization.
193 : *
194 : * This function is called when the bio_initialize() function. It is
195 : * expected that the bio_initialize() function is called once by the
196 : * main thread before any other thread has a chance to do so.
197 : */
198 0 : void crypto_thread_setup()
199 : {
200 0 : cppthread::guard g(*cppthread::g_system_mutex);
201 :
202 0 : if(g_locks != nullptr)
203 : {
204 : throw event_dispatcher_initialization_error(
205 : "crypto_thread_setup() called for the second time."
206 : " This usually means two threads are initializing"
207 0 : " the BIO environment simultaneously.");
208 : }
209 :
210 0 : g_locks = new cppthread::mutex::direct_vector_t(CRYPTO_num_locks());
211 :
212 0 : CRYPTO_THREADID_set_callback(pthreads_thread_id);
213 0 : CRYPTO_set_locking_callback(pthreads_locking_callback);
214 0 : }
215 :
216 :
217 : /** \brief This function cleans up the thread setup.
218 : *
219 : * This function could be called to clean up the setup created to support
220 : * multiple threads running with the OpenSSL library.
221 : *
222 : * \note
223 : * At this time this function never gets called. So we have a small leak
224 : * but that's only on a quit.
225 : */
226 0 : void thread_cleanup()
227 : {
228 0 : CRYPTO_set_locking_callback(nullptr);
229 :
230 0 : delete g_locks;
231 0 : g_locks = nullptr;
232 0 : }
233 :
234 :
235 : /** \brief This function cleans up the error state of a thread.
236 : *
237 : * Whenever the OpenSSL system runs in a thread, it may create a
238 : * state to save various information, especially its error queue.
239 : *
240 : * \sa cleanup_on_thread_exit()
241 : */
242 0 : void per_thread_cleanup()
243 : {
244 : #if __cplusplus < 201700
245 : // this function is not necessary in newer versions of OpenSSL
246 : //
247 0 : ERR_remove_thread_state(nullptr);
248 : #endif
249 0 : }
250 :
251 :
252 :
253 :
254 :
255 :
256 :
257 : /** \brief Whether the bio_initialize() function was already called.
258 : *
259 : * This flag is used to know whether the bio_initialize() function was
260 : * already called. Only the bio_initialize() function is expected to
261 : * make use of this flag. Other functions should simply call the
262 : * bio_initialize() function (future versions may include addition
263 : * flags or use various bits in an integer instead.)
264 : */
265 : bool g_bio_initialized = false;
266 :
267 :
268 : /** \brief Initialize the BIO library.
269 : *
270 : * This function is called by the BIO implementations to initialize the
271 : * BIO library as required. It can be called any number of times. The
272 : * initialization will happen only once.
273 : */
274 0 : void bio_initialize()
275 : {
276 0 : cppthread::guard g(*cppthread::g_system_mutex);
277 :
278 : // already initialized?
279 : //
280 0 : if(g_bio_initialized)
281 : {
282 0 : return;
283 : }
284 0 : g_bio_initialized = true;
285 :
286 : // Make sure the SSL library gets initialized
287 : //
288 0 : SSL_library_init();
289 :
290 : // TBD: should we call the load string functions only when we
291 : // are about to generate the first error?
292 : //
293 0 : ERR_load_crypto_strings();
294 0 : ERR_load_SSL_strings();
295 0 : SSL_load_error_strings();
296 :
297 : // TODO: define a way to only define safe algorithms?
298 : // (it looks like we can force TLSv1.2 below at least)
299 : //
300 0 : OpenSSL_add_all_algorithms();
301 :
302 : // TBD: need a PRNG seeding before creating a new SSL context?
303 :
304 : // then initialize the library so it works in a multithreaded
305 : // environment
306 : //
307 0 : crypto_thread_setup();
308 : }
309 :
310 :
311 : /** \brief Clean up the BIO environment.
312 : *
313 : * This function cleans up the BIO environment.
314 : *
315 : * \note
316 : * This function is here mainly for documentation rather than to get called.
317 : * Whenever you exit a process that uses the BIO calls it will leak
318 : * a few things. To make the process really spanking clean, you want
319 : * to call this function before exit(3). You have to make sure that
320 : * you call this function only after every single BIO object was
321 : * closed and none must be opened after this call.
322 : */
323 0 : void bio_cleanup()
324 : {
325 : #if __cplusplus < 201700
326 : // this function is not necessary in newer versions of OpenSSL
327 : //
328 0 : ERR_remove_state(0);
329 : #endif
330 :
331 0 : EVP_cleanup();
332 0 : CRYPTO_cleanup_all_ex_data();
333 0 : ERR_free_strings();
334 0 : }
335 :
336 :
337 : /** \brief Get all the error messages and output them in our logs.
338 : *
339 : * This function reads all existing errors from the OpenSSL library
340 : * and send them to our logs.
341 : *
342 : * \param[in] sni Whether SNI is ON (true) or OFF (false).
343 : */
344 0 : int bio_log_errors()
345 : {
346 : // allow for up to 5 errors in one go, but we have a HUGE problem
347 : // at this time as in some cases the same error is repeated forever
348 : //
349 0 : for(int i(0);; ++i)
350 : {
351 0 : char const * filename(nullptr);
352 0 : int line(0);
353 0 : char const * data(nullptr);
354 0 : int flags(0);
355 0 : unsigned long bio_errno(ERR_get_error_line_data(&filename, &line, &data, &flags));
356 0 : if(bio_errno == 0)
357 : {
358 : // no more errors
359 : //
360 0 : return i;
361 : }
362 :
363 : // get corresponding messages too
364 : //
365 : // Note: current OpenSSL documentation on Ubuntu says errmsg[]
366 : // should be at least 120 characters BUT the code actually
367 : // use a limit of 256...
368 : //
369 : char errmsg[256];
370 0 : ERR_error_string_n(bio_errno, errmsg, sizeof(errmsg) / sizeof(errmsg[0]));
371 : // WARNING: the ERR_error_string() function is NOT multi-thread safe
372 :
373 : #pragma GCC diagnostic push
374 : #pragma GCC diagnostic ignored "-Wold-style-cast"
375 0 : int const lib_num(ERR_GET_LIB(bio_errno));
376 0 : int const func_num(ERR_GET_FUNC(bio_errno));
377 : #pragma GCC diagnostic pop
378 0 : char const * lib_name(ERR_lib_error_string(lib_num));
379 0 : char const * func_name(ERR_func_error_string(func_num));
380 0 : int const reason_num(ERR_GET_REASON(bio_errno));
381 0 : char const * reason(ERR_reason_error_string(reason_num));
382 :
383 0 : if(lib_name == nullptr)
384 : {
385 0 : lib_name = "<no libname>";
386 : }
387 0 : if(func_name == nullptr)
388 : {
389 0 : func_name = "<no funcname>";
390 : }
391 0 : if(reason == nullptr)
392 : {
393 0 : reason = "<no reason>";
394 : }
395 :
396 : // the format used by the OpenSSL library is as follow:
397 : //
398 : // [pid]:error:[error code]:[library name]:[function name]:[reason string]:[file name]:[line]:[optional text message]
399 : //
400 : // we do not duplicate the [pid] and "error" but include all the
401 : // other fields
402 : //
403 : SNAP_LOG_ERROR
404 0 : << "OpenSSL: ["
405 0 : << bio_errno // should be shown in hex...
406 0 : << "/"
407 0 : << lib_num
408 0 : << "|"
409 0 : << func_num
410 0 : << "|"
411 0 : << reason_num
412 0 : << "]:["
413 0 : << lib_name
414 0 : << "]:["
415 0 : << func_name
416 0 : << "]:["
417 0 : << reason
418 0 : << "]:["
419 0 : << filename
420 0 : << "]:["
421 0 : << line
422 0 : << "]:["
423 0 : << ((flags & ERR_TXT_STRING) != 0 && data != nullptr ? data : "(no details)")
424 0 : << "]";
425 : }
426 : }
427 :
428 :
429 : /** \brief Free a BIO object.
430 : *
431 : * This deleter is used to make sure that the BIO object gets freed
432 : * whenever the object holding it gets destroyed.
433 : *
434 : * Note that deleting a BIO connection calls shutdown() and close()
435 : * on the socket. In other words, it hangs up.
436 : *
437 : * \param[in] bio The BIO object to be freed.
438 : */
439 0 : void bio_deleter(BIO * bio)
440 : {
441 : // IMPORTANT NOTE:
442 : //
443 : // The BIO_free_all() calls shutdown() on the socket. This is not
444 : // acceptable in a normal Unix application that makes use of fork().
445 : // So... instead we ask the BIO interface to not close the socket,
446 : // and instead we close it ourselves. This means the shutdown()
447 : // never gets called.
448 : //
449 0 : BIO_set_close(bio, BIO_NOCLOSE);
450 :
451 : int c;
452 : #pragma GCC diagnostic push
453 : #pragma GCC diagnostic ignored "-Wold-style-cast"
454 0 : BIO_get_fd(bio, &c);
455 : #pragma GCC diagnostic pop
456 0 : if(c != -1)
457 : {
458 0 : close(c);
459 : }
460 :
461 0 : BIO_free_all(bio);
462 0 : }
463 :
464 :
465 : /** \brief Free an SSL_CTX object.
466 : *
467 : * This deleter is used to make sure that the SSL_CTX object gets
468 : * freed whenever the object holding it gets destroyed.
469 : */
470 0 : void ssl_ctx_deleter(SSL_CTX * ssl_ctx)
471 : {
472 0 : SSL_CTX_free(ssl_ctx);
473 0 : }
474 :
475 :
476 : }
477 : // namespace detail
478 :
479 :
480 :
481 :
482 :
483 :
484 :
485 :
486 :
487 :
488 :
489 :
490 :
491 :
492 : } // namespace ed
493 : // vim: ts=4 sw=4 et
|