Coverage Report

Created: 2026-05-11 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/tls/log.c
Line
Count
Source
1
/*
2
 *   This program is free software; you can redistribute it and/or modify
3
 *   it under the terms of the GNU General Public License as published by
4
 *   the Free Software Foundation; either version 2 of the License, or
5
 *   (at your option) any later version.
6
 *
7
 *   This program is distributed in the hope that it will be useful,
8
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 *   GNU General Public License for more details.
11
 *
12
 *   You should have received a copy of the GNU General Public License
13
 *   along with this program; if not, write to the Free Software
14
 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15
 */
16
17
/**
18
 * $Id: f2a4bedfee68dbe3fc16c8f57f824770de295f0e $
19
 *
20
 * @file tls/log.c
21
 * @brief Retrieve errors and log messages from OpenSSL's overly complex logging system.
22
 *
23
 * @copyright 2016,2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24
 * @copyright 2016 The FreeRADIUS server project
25
 */
26
RCSID("$Id: f2a4bedfee68dbe3fc16c8f57f824770de295f0e $")
27
USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
28
29
#ifdef WITH_TLS
30
0
#define LOG_PREFIX "tls"
31
32
#include <freeradius-devel/util/debug.h>
33
#include <freeradius-devel/util/atexit.h>
34
#include <freeradius-devel/tls/strerror.h>
35
#include <freeradius-devel/tls/utils.h>
36
37
#include "log.h"
38
39
/** Holds the state of a log BIO
40
 *
41
 * Most of these fields are expected to change between uses of the BIO.
42
 *
43
 * BIOs do not have indexed extension structures like other structures in OpenSSL,
44
 * so we're forced to place all information in a structure, and populate it just
45
 * prior to a BIO being used.
46
 *
47
 * These BIOs are thread local to avoid conflicts or locking issues.
48
 */
49
typedef struct {
50
  BIO     *bio;   //!< Logging bio to write to.
51
  fr_sbuff_t    sbuff;    //!< Used to aggregate line data.
52
  fr_sbuff_uctx_talloc_t  tctx;   //!< extra talloc information for the sbuff.
53
  fr_sbuff_marker_t logged_m; //!< How much data has been written.
54
55
  request_t   *request; //!< the current request.  Only used for the
56
            ///< request log BIOs.
57
  fr_log_type_t   type;   //!< The type of log messages the bio will produce.
58
  fr_log_lvl_t    lvl;    //!< Level to log message at.
59
  char const    *file;    //!< File this log bio was bound on.
60
  int     line;   //!< Line this log bio was bound on.
61
} fr_tls_log_bio_t;
62
63
/** Template for the thread local request log BIOs
64
 */
65
static BIO_METHOD *tls_request_log_meth;
66
67
/** Template for the global log BIOs
68
 */
69
static BIO_METHOD *tls_global_log_meth;
70
71
/** Counter for users of the request log bio
72
 *
73
 */
74
static _Atomic(uint32_t) tls_request_log_ref;
75
76
/** Counter for users of the global log bio
77
 *
78
 */
79
static _Atomic(uint32_t) tls_global_log_ref;
80
81
/** Thread local request log BIO
82
 */
83
static _Thread_local  fr_tls_log_bio_t  *request_log_bio;
84
85
/** Thread local global log BIO
86
 */
87
static _Thread_local  fr_tls_log_bio_t  *global_log_bio;
88
89
/** Print out the current stack of certs
90
 *
91
 * @param[in] file  File where this function is being called.
92
 * @param[in] line  Line where this function is being called.
93
 * @param[in] request Current request, may be NULL.
94
 * @param[in] log_type  The type of log message to produce L_INFO, L_ERR, L_DBG etc...
95
 * @param[in] chain The certificate chain.
96
 * @param[in] cert  The leaf certificate.
97
 */
98
void _fr_tls_chain_log(char const *file, int line,
99
           request_t *request, fr_log_type_t log_type,
100
           STACK_OF(X509) *chain, X509 *cert)
101
0
{
102
  /*
103
   *  Dump to the thread local buffer
104
   */
105
0
  fr_strerror_clear();
106
0
  _fr_tls_strerror_push_chain(file, line, chain, cert);
107
0
  if (request) {
108
0
    log_request_perror(log_type, L_DBG_LVL_OFF, request, file, line, NULL);
109
0
  } else {
110
0
    fr_perror(NULL);
111
0
  }
112
0
}
113
114
/** Print out the current stack of certs
115
 *
116
 * @param[in] file  File where this function is being called.
117
 * @param[in] line  Line where this function is being called.
118
 * @param[in] request Current request, may be NULL.
119
 * @param[in] log_type  The type of log message to produce L_INFO, L_ERR, L_DBG etc...
120
 * @param[in] chain The certificate chain.
121
 * @param[in] cert  The leaf certificate.
122
 * @param[in] marker  The certificate we want to mark.
123
 */
124
void _fr_tls_chain_marker_log(char const *file, int line,
125
            request_t *request, fr_log_type_t log_type,
126
            STACK_OF(X509) *chain, X509 *cert, X509 *marker)
127
0
{
128
  /*
129
   *  Dump to the thread local buffer
130
   */
131
0
  fr_strerror_clear();
132
0
  _fr_tls_strerror_push_chain_marker(file, line, chain, cert, marker);
133
0
  if (request) {
134
0
    log_request_perror(log_type, L_DBG_LVL_OFF, request, file, line, NULL);
135
0
  } else {
136
0
    fr_perror(NULL);
137
0
  }
138
0
}
139
140
/** Print out the current stack of X509 objects (certificates only)
141
 *
142
 * @param[in] file    File where this function is being called.
143
 * @param[in] line    Line where this function is being called.
144
 * @param[in] request   Current request, may be NULL.
145
 * @param[in] log_type    The type of log message to produce L_INFO, L_ERR, L_DBG etc...
146
 * @param[in] objects   A stack of X509 objects
147
 */
148
void _fr_tls_x509_objects_log(char const *file, int line,
149
            request_t *request, fr_log_type_t log_type,
150
            STACK_OF(X509_OBJECT) *objects)
151
0
{
152
153
0
  fr_strerror_clear();
154
0
  _fr_tls_strerror_push_x509_objects(file, line, objects);
155
0
  if (request) {
156
0
    log_request_perror(log_type, L_DBG_LVL_OFF, request, file, line, NULL);
157
0
  } else {
158
0
    fr_perror(NULL);
159
0
  }
160
0
}
161
162
/** Print errors raised by OpenSSL I/O functions
163
 *
164
 * Drains the thread local OpenSSL error queue, and prints out errors
165
 * based on the SSL handle and the return code of the I/O  function.
166
 *
167
 * OpenSSL lists I/O functions to be:
168
 *   - SSL_connect
169
 *   - SSL_accept
170
 *   - SSL_do_handshake
171
 *   - SSL_read
172
 *   - SSL_peek
173
 *   - SSL_write
174
 *
175
 * @param request The current request (may be NULL).
176
 * @param err   returned from SSL_get_error().
177
 * @param fmt   Error message describing the operation being attempted.
178
 * @param ...   Arguments for msg.
179
 * @return
180
 *  - 0 TLS session may still be viable.
181
 *  - -1 TLS session cannot continue.
182
 */
183
int fr_tls_log_io_error(request_t *request, int err, char const *fmt, ...)
184
0
{
185
0
  static fr_table_num_ordered_t const ssl_io_error_table[] = {
186
0
    { L("SSL_ERROR_NONE"),     SSL_ERROR_NONE      },
187
0
    { L("SSL_ERROR_ZERO_RETURN"),    SSL_ERROR_ZERO_RETURN   },
188
0
    { L("SSL_ERROR_WANT_READ"),    SSL_ERROR_WANT_READ   },
189
0
    { L("SSL_ERROR_WANT_WRITE"),   SSL_ERROR_WANT_WRITE    },
190
0
    { L("SSL_ERROR_WANT_CONNECT"),   SSL_ERROR_WANT_CONNECT    },
191
0
    { L("SSL_ERROR_WANT_ACCEPT"),    SSL_ERROR_WANT_ACCEPT   },
192
0
    { L("SSL_ERROR_WANT_X509_LOOKUP"), SSL_ERROR_WANT_X509_LOOKUP  },
193
0
    { L("SSL_ERROR_WANT_ASYNC"),   SSL_ERROR_WANT_ASYNC    },
194
0
    { L("SSL_ERROR_WANT_ASYNC_JOB"), SSL_ERROR_WANT_ASYNC_JOB  },
195
0
    { L("SSL_ERROR_WANT_CLIENT_HELLO_CB"), SSL_ERROR_WANT_CLIENT_HELLO_CB  },
196
0
    { L("SSL_ERROR_SYSCALL"),    SSL_ERROR_SYSCALL   },
197
0
    { L("SSL_ERROR_SSL"),      SSL_ERROR_SSL     }
198
0
  };
199
0
  static size_t ssl_io_error_table_len = NUM_ELEMENTS(ssl_io_error_table);
200
201
0
  va_list ap;
202
0
  char *msg = NULL;
203
204
0
  switch (err) {
205
  /*
206
   *  These seem to be harmless and already "dealt
207
   *  with" by our non-blocking environment. NB:
208
   *  "ZERO_RETURN" is the clean "error"
209
   *  indicating a successfully closed SSL
210
   *  tunnel. We let this happen because our IO
211
   *  loop should not appear to have broken on
212
   *  this condition - and outside the IO loop, the
213
   *  "shutdown" state is checked.
214
   *
215
   *  Don't print anything if we ignore the error.
216
   */
217
0
  case SSL_ERROR_NONE:
218
0
  case SSL_ERROR_WANT_READ:
219
0
  case SSL_ERROR_WANT_WRITE:
220
0
  case SSL_ERROR_WANT_X509_LOOKUP:
221
0
  case SSL_ERROR_ZERO_RETURN:
222
0
    if (DEBUG_ENABLED2 || RDEBUG_ENABLED2) {
223
0
      va_start(ap, fmt);
224
0
      msg = fr_vasprintf(NULL, fmt, ap);
225
0
      va_end(ap);
226
227
0
      ROPTIONAL(RDEBUG2, DEBUG2, "%s - %s (%i)",
228
0
          msg, fr_table_str_by_value(ssl_io_error_table, err, "<UNKNOWN>"), err);
229
0
      talloc_free(msg);
230
0
    }
231
0
    break;
232
233
  /*
234
   *  These seem to be indications of a genuine
235
   *  error that should result in the SSL tunnel
236
   *  being regarded as "dead".
237
   */
238
0
  case SSL_ERROR_SYSCALL:
239
0
    va_start(ap, fmt);
240
0
    msg = fr_vasprintf(NULL, fmt, ap);
241
0
    va_end(ap);
242
243
0
    ROPTIONAL(REDEBUG, ERROR, "%s - System call (I/O) error - %s (%i)",
244
0
        msg, fr_table_str_by_value(ssl_io_error_table, err, "<UNKNOWN>"), err);
245
246
0
    talloc_free(msg);
247
0
    return -1;
248
249
  /*
250
   *  Docs say a more verbose error is available
251
   *  in the normal error stack.
252
   */
253
0
  case SSL_ERROR_SSL:
254
0
    va_start(ap, fmt);
255
0
    (void)fr_tls_strerror_vprintf(fmt, ap);
256
0
    va_end(ap);
257
258
0
    ROPTIONAL(RPERROR, PERROR, "");
259
0
    return -1;
260
261
  /*
262
   *  For any other errors that (a) exist, and (b)
263
   *  crop up - we need to interpret what to do with
264
   *  them - so "politely inform" the caller that
265
   *  the code needs updating here.
266
   */
267
0
  default:
268
0
    va_start(ap, fmt);
269
0
    msg = fr_vasprintf(NULL, fmt, ap);
270
0
    va_end(ap);
271
272
0
    ROPTIONAL(REDEBUG, ERROR, "%s - TLS session error - %s (%i)",
273
0
        msg, fr_table_str_by_value(ssl_io_error_table, err, "<UNKNOWN>"), err);
274
275
0
    talloc_free(msg);
276
277
0
    return -1;
278
0
  }
279
280
0
  return 0;
281
0
}
282
283
284
/** Print errors in the TLS thread local error stack
285
 *
286
 * Drains the thread local OpenSSL error queue, and prints out errors.
287
 *
288
 * @param[in] request The current request (may be NULL).
289
 * @param[in] msg Error message describing the operation being attempted.
290
 * @param[in] ... Arguments for msg.
291
 * @return the number of errors drained from the stack.
292
 */
293
int fr_tls_log(request_t *request, char const *msg, ...)
294
0
{
295
0
  va_list ap;
296
0
  int ret;
297
298
0
  va_start(ap, msg);
299
0
  ret = fr_tls_strerror_vprintf(msg, ap);
300
0
  va_end(ap);
301
302
0
  ROPTIONAL(RPERROR, PERROR, "");
303
304
0
  return ret;
305
0
}
306
307
/** Clear errors in the TLS thread local error stack
308
 *
309
 */
310
void fr_tls_log_clear(void)
311
0
{
312
0
  while (ERR_get_error() != 0);
313
0
}
314
315
/** Increment the bio meth reference counter
316
 *
317
 */
318
static int tls_log_request_bio_create_cb(BIO *bio)
319
0
{
320
0
  atomic_fetch_add(&tls_request_log_ref, 1);
321
0
  BIO_set_init(bio, 1);
322
0
  return 1;
323
0
}
324
325
/** Converts BIO_write() calls to request log calls
326
 *
327
 * This callback is used to glue the output of OpenSSL functions into request log calls.
328
 *
329
 * @param[in] bio that was written to.
330
 * @param[in] in  data being written to BIO.
331
 * @param[in] len Length of data being written.
332
 */
333
static int tls_log_request_bio_write_cb(BIO *bio, char const *in, int len)
334
0
{
335
0
  fr_tls_log_bio_t  *lb = talloc_get_type_abort(BIO_get_data(bio), fr_tls_log_bio_t);
336
0
  request_t   *request = talloc_get_type_abort(lb->request, request_t);
337
0
  log_request_func_t  func;
338
0
  fr_slen_t   slen;
339
0
  char      *le;
340
341
  /*
342
   *  Pick the right logging function based on the type
343
   */
344
0
  if ((lb->type == L_ERR) || (lb->type == L_DBG_ERR) || (lb->type == L_DBG_ERR_REQ)) {
345
0
    func = log_request_error;
346
0
  } else {
347
0
    func = log_request;
348
0
  }
349
350
  /*
351
   *  OpenSSL feeds us data in fragments so we need
352
   *  to aggregate it, then look for new line chars
353
   *  as an indication we need to print the line.
354
   */
355
0
  slen = fr_sbuff_in_bstrncpy(&lb->sbuff, in, len);
356
0
  if (unlikely(slen < 0)) {
357
    /*
358
     *  We failed to copy the data into the buffer
359
     *  so we can't do anything with it.
360
     */
361
0
    REDEBUG2("Failed copying %u bytes into TLS log aggregation buffer, "
362
0
       "needed %zu more bytes", len, (size_t)(-(slen)));
363
0
    return 0;
364
0
  }
365
366
  /*
367
   *  Split incoming data on new lines
368
   */
369
0
  while (fr_sbuff_behind(&lb->logged_m)) {
370
0
    le = memchr(fr_sbuff_current(&lb->logged_m), '\n',
371
0
          fr_sbuff_current(&lb->sbuff) - fr_sbuff_current(&lb->logged_m));
372
    /*
373
     *  Wait until we have a complete line
374
     */
375
0
    if (le == NULL) break;
376
377
    /*
378
     *  Skip empty lines
379
     */
380
0
    if ((le - fr_sbuff_current(&lb->logged_m)) > 0) {
381
0
      func(lb->type, lb->lvl, request, __FILE__, __LINE__, "%pV",
382
0
           fr_box_strvalue_len(fr_sbuff_current(&lb->logged_m),
383
0
                 le - fr_sbuff_current(&lb->logged_m)));
384
0
    }
385
386
0
    fr_sbuff_set(&lb->logged_m, le + 1);
387
0
  }
388
389
  /*
390
   *  Clear out printed data
391
   */
392
0
  fr_sbuff_shift(&lb->sbuff, fr_sbuff_used(&lb->logged_m), false);
393
394
0
  return len; /* Amount of data written */
395
0
}
396
397
/** Converts BIO_puts() calls to request log calls
398
 *
399
 * This callback is used to glue the output of OpenSSL functions into request log calls.
400
 *
401
 * @param[in] bio that was written to.
402
 * @param[in] in  data being written to BIO.
403
 */
404
static int tls_log_request_bio_puts_cb(BIO *bio, char const *in)
405
0
{
406
0
  return tls_log_request_bio_write_cb(bio, in, strlen(in));
407
0
}
408
409
/** Decrement the bio meth reference counter
410
 *
411
 */
412
static int tls_log_request_bio_free_cb(BIO *bio)
413
0
{
414
0
  atomic_fetch_sub(&tls_request_log_ref, 1);
415
0
  BIO_set_init(bio, 0);
416
0
  return 1;
417
0
}
418
419
/** Increment the bio meth reference counter
420
 *
421
 */
422
static int tls_log_global_bio_create_cb(BIO *bio)
423
0
{
424
0
  atomic_fetch_add(&tls_global_log_ref, 1);
425
0
  BIO_set_init(bio, 1);
426
0
  return 1;
427
0
}
428
429
/** Converts BIO_write() calls to global log calls
430
 *
431
 * This callback is used to glue the output of OpenSSL functions into global log calls.
432
 *
433
 * @param[in] bio that was written to.
434
 * @param[in] in  data being written to BIO.
435
 * @param[in] len Length of data being written.
436
 */
437
static int tls_log_global_bio_write_cb(BIO *bio, char const *in, int len)
438
0
{
439
0
  fr_tls_log_bio_t  *lb = talloc_get_type_abort(BIO_get_data(bio), fr_tls_log_bio_t);
440
0
  char      *le;
441
442
  /*
443
   *  OpenSSL feeds us data in fragments so we need
444
   *  to aggregate it, then look for new line chars
445
   *  as an indication we need to print the line.
446
   */
447
0
  if (fr_sbuff_in_bstrncpy(&lb->sbuff, in, len) < 0) return 0;
448
449
  /*
450
   *  Split incoming data on new lines
451
   */
452
0
  while (fr_sbuff_behind(&lb->logged_m)) {
453
0
    le = memchr(fr_sbuff_current(&lb->logged_m), '\n',
454
0
          fr_sbuff_current(&lb->sbuff) - fr_sbuff_current(&lb->logged_m));
455
    /*
456
     *  Wait until we have a complete line
457
     */
458
0
    if (le == NULL) break;
459
460
    /*
461
     *  Skip empty lines
462
     */
463
0
    if ((le - fr_sbuff_current(&lb->logged_m)) > 0) {
464
0
      if (fr_debug_lvl >= lb->lvl) fr_log(&default_log, lb->type, __FILE__, __LINE__,
465
0
                  "%pV",
466
0
                  fr_box_strvalue_len(fr_sbuff_current(&lb->logged_m),
467
0
                    le - fr_sbuff_current(&lb->logged_m)));
468
0
    }
469
470
0
    fr_sbuff_set(&lb->logged_m, le + 1);
471
0
  }
472
473
  /*
474
   *  Clear out printed data
475
   */
476
0
  fr_sbuff_shift(&lb->sbuff, fr_sbuff_used(&lb->logged_m), false);
477
478
0
  return len; /* Amount of data written */
479
0
}
480
481
/** Converts BIO_puts() calls to global log calls
482
 *
483
 * This callback is used to glue the output of OpenSSL functions into global log calls.
484
 *
485
 * @param[in] bio that was written to.
486
 * @param[in] in  data being written to BIO.
487
 */
488
static int tls_log_global_bio_puts_cb(BIO *bio, char const *in)
489
0
{
490
0
  return tls_log_global_bio_write_cb(bio, in, strlen(in));
491
0
}
492
493
/** Decrement the bio meth reference counter
494
 *
495
 */
496
static int tls_log_global_bio_free_cb(BIO *bio)
497
0
{
498
0
  atomic_fetch_sub(&tls_global_log_ref, 1);
499
0
  BIO_set_init(bio, 0);
500
0
  return 1;
501
0
}
502
503
/** Frees a logging bio and its underlying OpenSSL BIO *
504
 *
505
 */
506
static int _fr_tls_log_bio_free(void *log_bio)
507
0
{
508
0
  fr_tls_log_bio_t  *our_log_bio = talloc_get_type_abort(log_bio, fr_tls_log_bio_t);
509
510
0
  BIO_free(our_log_bio->bio);
511
0
  our_log_bio->bio = NULL;
512
0
  return talloc_free(our_log_bio);
513
0
}
514
515
/** Return a request log BIO to use with OpenSSL logging functions
516
 *
517
 * @note The contents of the BIO will only be written to the logging system on finding
518
 *       a new line.  If data remains in the BIO when it is re-initialised (this function
519
 *       is called again), that data will be discarded.
520
 *
521
 * @note The returned BIO should be assumed to be invalid if the request yields.
522
 *
523
 * @param[in] file  of caller.
524
 * @param[in] line  of caller.
525
 * @param[in] request to temporarily associate with logging BIO.
526
 * @param[in] type  to temporarily assign to logging bio.
527
 * @param[in] lvl to temporarily assign to logging bio.
528
 * @return A thread local BIO to pass to OpenSSL logging functions.
529
 */
530
BIO *_fr_tls_request_log_bio(char const *file, int line, request_t *request, fr_log_type_t type, fr_log_lvl_t lvl)
531
0
{
532
0
  if (unlikely(!request_log_bio)) {
533
0
    fr_tls_log_bio_t  *lb;
534
535
0
    MEM(lb = talloc(NULL, fr_tls_log_bio_t));
536
0
    *lb = (fr_tls_log_bio_t) {
537
0
      .bio = BIO_new(tls_request_log_meth),
538
0
      .request = request,
539
0
      .type = type,
540
0
      .lvl = lvl,
541
0
      .file = file,
542
0
      .line = line
543
0
    };
544
0
    MEM(lb->bio);
545
0
    BIO_set_data(lb->bio, lb);  /* So we can retrieve the fr_tls_lb_t in the callbacks */
546
0
    fr_sbuff_init_talloc(lb, &lb->sbuff, &lb->tctx, 1024, 10 * 1024); /* start 1k, max 10k */
547
0
    fr_atexit_thread_local(request_log_bio, _fr_tls_log_bio_free, lb);
548
0
    fr_sbuff_marker(&lb->logged_m, &lb->sbuff);
549
0
    return lb->bio;
550
0
  }
551
0
  fr_sbuff_reset_talloc(&request_log_bio->sbuff); /* Reset to initial size */
552
0
  fr_sbuff_marker(&request_log_bio->logged_m, &request_log_bio->sbuff);
553
0
  request_log_bio->request = request;
554
0
  request_log_bio->type = type;
555
0
  request_log_bio->lvl = lvl;
556
0
  request_log_bio->file = file;
557
0
  request_log_bio->line = line;
558
559
0
  return request_log_bio->bio;
560
0
}
561
562
/** Return a global log BIO to use with OpenSSL logging functions
563
 *
564
 * @note The contents of the BIO will only be written to the logging system on finding
565
 *       a new line.  If data remains in the BIO when it is re-initialised (this function
566
 *       is called again), that data will be discarded.
567
 *
568
 * @note The returned BIO should be assumed to be invalid if the current request yields.
569
 *
570
 * @param[in] file  of caller.
571
 * @param[in] line  of caller.
572
 * @param[in] type  to temporarily assign to logging bio.
573
 * @param[in] lvl to temporarily assign to logging bio.
574
 * @return A thread local BIO to pass to OpenSSL logging functions.
575
 */
576
BIO *_fr_tls_global_log_bio(char const *file, int line, fr_log_type_t type, fr_log_lvl_t lvl)
577
0
{
578
0
  if (unlikely(!global_log_bio)) {
579
0
    fr_tls_log_bio_t  *lb;
580
581
0
    MEM(lb = talloc(NULL, fr_tls_log_bio_t));
582
0
    *lb = (fr_tls_log_bio_t) {
583
0
      .bio = BIO_new(tls_global_log_meth),
584
0
      .type = type,
585
0
      .lvl = lvl,
586
0
      .file = file,
587
0
      .line = line
588
0
    };
589
0
    MEM(lb->bio);
590
0
    BIO_set_data(lb->bio, lb);  /* So we can retrieve the fr_tls_lb_t in the callbacks */
591
0
    fr_sbuff_init_talloc(lb, &lb->sbuff, &lb->tctx, 1024, 10 * 1024); /* start 1k, max 10k */
592
0
    fr_atexit_thread_local(global_log_bio, _fr_tls_log_bio_free, lb);
593
0
    fr_sbuff_marker(&lb->logged_m, &lb->sbuff);
594
0
    return lb->bio;
595
0
  }
596
597
0
  fr_sbuff_reset_talloc(&global_log_bio->sbuff);  /* Reset to initial size */
598
0
  fr_sbuff_marker(&global_log_bio->logged_m, &global_log_bio->sbuff);
599
0
  global_log_bio->type = type;
600
0
  global_log_bio->lvl = lvl;
601
0
  global_log_bio->file = file;
602
0
  global_log_bio->line = line;
603
604
0
  return global_log_bio->bio;
605
0
}
606
607
/** Initialise the BIO logging meths which are used to create thread local logging BIOs
608
 *
609
 */
610
int fr_tls_log_init(void)
611
0
{
612
  /*
613
   *  As per the boringSSL documentation
614
   *
615
   *  BIO_TYPE_START is the first user-allocated |BIO| type.
616
   *  No pre-defined type, flag bits aside, may exceed this
617
   *  value.
618
   *
619
   *  The low byte here defines the BIO ID, and the high byte
620
   *  defines its capabilities.
621
   */
622
0
  tls_request_log_meth = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK, "fr_tls_request_log");
623
0
  if (unlikely(!tls_request_log_meth)) return -1;
624
625
0
  BIO_meth_set_create(tls_request_log_meth, tls_log_request_bio_create_cb);
626
0
  BIO_meth_set_write(tls_request_log_meth, tls_log_request_bio_write_cb);
627
0
  BIO_meth_set_puts(tls_request_log_meth, tls_log_request_bio_puts_cb);
628
0
  BIO_meth_set_destroy(tls_request_log_meth, tls_log_request_bio_free_cb);
629
630
0
  tls_global_log_meth = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK, "fr_tls_global_log");
631
0
  if (unlikely(!tls_global_log_meth)) {
632
0
    BIO_meth_free(tls_request_log_meth);
633
0
    tls_request_log_meth = NULL;
634
0
    return -1;
635
0
  }
636
637
0
  BIO_meth_set_create(tls_global_log_meth, tls_log_global_bio_create_cb);
638
0
  BIO_meth_set_write(tls_global_log_meth, tls_log_global_bio_write_cb);
639
0
  BIO_meth_set_puts(tls_global_log_meth, tls_log_global_bio_puts_cb);
640
0
  BIO_meth_set_destroy(tls_global_log_meth, tls_log_global_bio_free_cb);
641
642
0
  return 0;
643
0
}
644
645
/** Free the global log method templates
646
 *
647
 */
648
void fr_tls_log_free(void)
649
0
{
650
  /*
651
   *  These must be freed first else
652
   *      we get crashes in the OpenSSL
653
   *  code when we try to free them.
654
   */
655
0
  fr_assert_msg(atomic_load(&tls_request_log_ref) == 0, "request log BIO refs remaining %u", atomic_load(&tls_request_log_ref));
656
0
  fr_assert_msg(atomic_load(&tls_global_log_ref) == 0, "global log BIO refs remaining %u", atomic_load(&tls_global_log_ref));
657
658
0
  if (tls_request_log_meth) {
659
0
    BIO_meth_free(tls_request_log_meth);
660
0
    tls_request_log_meth = NULL;
661
0
  }
662
663
0
  if (tls_global_log_meth) {
664
0
    BIO_meth_free(tls_global_log_meth);
665
    tls_global_log_meth = NULL;
666
0
  }
667
0
}
668
#endif /* WITH_TLS */