Coverage Report

Created: 2026-09-28 06:27

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: b4d40b2750dfdea3cf3a112fd62e696586dd63d1 $
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: b4d40b2750dfdea3cf3a112fd62e696586dd63d1 $")
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
  ssize_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 - buffer is too small.", len);
362
0
    return 0;
363
0
  }
364
365
  /*
366
   *  Split incoming data on new lines
367
   */
368
0
  while (fr_sbuff_behind(&lb->logged_m)) {
369
0
    le = memchr(fr_sbuff_current(&lb->logged_m), '\n',
370
0
          fr_sbuff_current(&lb->sbuff) - fr_sbuff_current(&lb->logged_m));
371
    /*
372
     *  Wait until we have a complete line
373
     */
374
0
    if (le == NULL) break;
375
376
    /*
377
     *  Skip empty lines
378
     */
379
0
    if ((le - fr_sbuff_current(&lb->logged_m)) > 0) {
380
0
      func(lb->type, lb->lvl, request, __FILE__, __LINE__, "%pV",
381
0
           fr_box_strvalue_len(fr_sbuff_current(&lb->logged_m),
382
0
                 le - fr_sbuff_current(&lb->logged_m)));
383
0
    }
384
385
0
    fr_sbuff_set(&lb->logged_m, le + 1);
386
0
  }
387
388
  /*
389
   *  Clear out printed data
390
   */
391
0
  fr_sbuff_shift(&lb->sbuff, fr_sbuff_used(&lb->logged_m), false);
392
393
0
  return len; /* Amount of data written */
394
0
}
395
396
/** Converts BIO_puts() calls to request log calls
397
 *
398
 * This callback is used to glue the output of OpenSSL functions into request log calls.
399
 *
400
 * @param[in] bio that was written to.
401
 * @param[in] in  data being written to BIO.
402
 */
403
static int tls_log_request_bio_puts_cb(BIO *bio, char const *in)
404
0
{
405
0
  return tls_log_request_bio_write_cb(bio, in, strlen(in));
406
0
}
407
408
/** Decrement the bio meth reference counter
409
 *
410
 */
411
static int tls_log_request_bio_free_cb(BIO *bio)
412
0
{
413
0
  atomic_fetch_sub(&tls_request_log_ref, 1);
414
0
  BIO_set_init(bio, 0);
415
0
  return 1;
416
0
}
417
418
/** Increment the bio meth reference counter
419
 *
420
 */
421
static int tls_log_global_bio_create_cb(BIO *bio)
422
0
{
423
0
  atomic_fetch_add(&tls_global_log_ref, 1);
424
0
  BIO_set_init(bio, 1);
425
0
  return 1;
426
0
}
427
428
/** Converts BIO_write() calls to global log calls
429
 *
430
 * This callback is used to glue the output of OpenSSL functions into global log calls.
431
 *
432
 * @param[in] bio that was written to.
433
 * @param[in] in  data being written to BIO.
434
 * @param[in] len Length of data being written.
435
 */
436
static int tls_log_global_bio_write_cb(BIO *bio, char const *in, int len)
437
0
{
438
0
  fr_tls_log_bio_t  *lb = talloc_get_type_abort(BIO_get_data(bio), fr_tls_log_bio_t);
439
0
  char      *le;
440
441
  /*
442
   *  OpenSSL feeds us data in fragments so we need
443
   *  to aggregate it, then look for new line chars
444
   *  as an indication we need to print the line.
445
   */
446
0
  if (fr_sbuff_in_bstrncpy(&lb->sbuff, in, len) < 0) return 0;
447
448
  /*
449
   *  Split incoming data on new lines
450
   */
451
0
  while (fr_sbuff_behind(&lb->logged_m)) {
452
0
    le = memchr(fr_sbuff_current(&lb->logged_m), '\n',
453
0
          fr_sbuff_current(&lb->sbuff) - fr_sbuff_current(&lb->logged_m));
454
    /*
455
     *  Wait until we have a complete line
456
     */
457
0
    if (le == NULL) break;
458
459
    /*
460
     *  Skip empty lines
461
     */
462
0
    if ((le - fr_sbuff_current(&lb->logged_m)) > 0) {
463
0
      if (fr_debug_lvl >= lb->lvl) fr_log(&default_log, lb->type, __FILE__, __LINE__,
464
0
                  "%pV",
465
0
                  fr_box_strvalue_len(fr_sbuff_current(&lb->logged_m),
466
0
                    le - fr_sbuff_current(&lb->logged_m)));
467
0
    }
468
469
0
    fr_sbuff_set(&lb->logged_m, le + 1);
470
0
  }
471
472
  /*
473
   *  Clear out printed data
474
   */
475
0
  fr_sbuff_shift(&lb->sbuff, fr_sbuff_used(&lb->logged_m), false);
476
477
0
  return len; /* Amount of data written */
478
0
}
479
480
/** Converts BIO_puts() calls to global log calls
481
 *
482
 * This callback is used to glue the output of OpenSSL functions into global log calls.
483
 *
484
 * @param[in] bio that was written to.
485
 * @param[in] in  data being written to BIO.
486
 */
487
static int tls_log_global_bio_puts_cb(BIO *bio, char const *in)
488
0
{
489
0
  return tls_log_global_bio_write_cb(bio, in, strlen(in));
490
0
}
491
492
/** Decrement the bio meth reference counter
493
 *
494
 */
495
static int tls_log_global_bio_free_cb(BIO *bio)
496
0
{
497
0
  atomic_fetch_sub(&tls_global_log_ref, 1);
498
0
  BIO_set_init(bio, 0);
499
0
  return 1;
500
0
}
501
502
/** Frees a logging bio and its underlying OpenSSL BIO *
503
 *
504
 */
505
static int _fr_tls_log_bio_free(void *log_bio)
506
0
{
507
0
  fr_tls_log_bio_t  *our_log_bio = talloc_get_type_abort(log_bio, fr_tls_log_bio_t);
508
509
0
  BIO_free(our_log_bio->bio);
510
0
  our_log_bio->bio = NULL;
511
0
  return talloc_free(our_log_bio);
512
0
}
513
514
/** Return a request log BIO to use with OpenSSL logging functions
515
 *
516
 * @note The contents of the BIO will only be written to the logging system on finding
517
 *       a new line.  If data remains in the BIO when it is re-initialised (this function
518
 *       is called again), that data will be discarded.
519
 *
520
 * @note The returned BIO should be assumed to be invalid if the request yields.
521
 *
522
 * @param[in] file  of caller.
523
 * @param[in] line  of caller.
524
 * @param[in] request to temporarily associate with logging BIO.
525
 * @param[in] type  to temporarily assign to logging bio.
526
 * @param[in] lvl to temporarily assign to logging bio.
527
 * @return A thread local BIO to pass to OpenSSL logging functions.
528
 */
529
BIO *_fr_tls_request_log_bio(char const *file, int line, request_t *request, fr_log_type_t type, fr_log_lvl_t lvl)
530
0
{
531
0
  if (unlikely(!request_log_bio)) {
532
0
    fr_tls_log_bio_t  *lb;
533
534
0
    MEM(lb = talloc(NULL, fr_tls_log_bio_t));
535
0
    *lb = (fr_tls_log_bio_t) {
536
0
      .bio = BIO_new(tls_request_log_meth),
537
0
      .request = request,
538
0
      .type = type,
539
0
      .lvl = lvl,
540
0
      .file = file,
541
0
      .line = line
542
0
    };
543
0
    MEM(lb->bio);
544
0
    BIO_set_data(lb->bio, lb);  /* So we can retrieve the fr_tls_lb_t in the callbacks */
545
0
    fr_sbuff_init_talloc(lb, &lb->sbuff, &lb->tctx, 1024, 10 * 1024); /* start 1k, max 10k */
546
0
    fr_atexit_thread_local(request_log_bio, _fr_tls_log_bio_free, lb);
547
0
    fr_sbuff_marker(&lb->logged_m, &lb->sbuff);
548
0
    return lb->bio;
549
0
  }
550
0
  fr_sbuff_reset_talloc(&request_log_bio->sbuff); /* Reset to initial size */
551
0
  fr_sbuff_marker(&request_log_bio->logged_m, &request_log_bio->sbuff);
552
0
  request_log_bio->request = request;
553
0
  request_log_bio->type = type;
554
0
  request_log_bio->lvl = lvl;
555
0
  request_log_bio->file = file;
556
0
  request_log_bio->line = line;
557
558
0
  return request_log_bio->bio;
559
0
}
560
561
/** Return a global log BIO to use with OpenSSL logging functions
562
 *
563
 * @note The contents of the BIO will only be written to the logging system on finding
564
 *       a new line.  If data remains in the BIO when it is re-initialised (this function
565
 *       is called again), that data will be discarded.
566
 *
567
 * @note The returned BIO should be assumed to be invalid if the current request yields.
568
 *
569
 * @param[in] file  of caller.
570
 * @param[in] line  of caller.
571
 * @param[in] type  to temporarily assign to logging bio.
572
 * @param[in] lvl to temporarily assign to logging bio.
573
 * @return A thread local BIO to pass to OpenSSL logging functions.
574
 */
575
BIO *_fr_tls_global_log_bio(char const *file, int line, fr_log_type_t type, fr_log_lvl_t lvl)
576
0
{
577
0
  if (unlikely(!global_log_bio)) {
578
0
    fr_tls_log_bio_t  *lb;
579
580
0
    MEM(lb = talloc(NULL, fr_tls_log_bio_t));
581
0
    *lb = (fr_tls_log_bio_t) {
582
0
      .bio = BIO_new(tls_global_log_meth),
583
0
      .type = type,
584
0
      .lvl = lvl,
585
0
      .file = file,
586
0
      .line = line
587
0
    };
588
0
    MEM(lb->bio);
589
0
    BIO_set_data(lb->bio, lb);  /* So we can retrieve the fr_tls_lb_t in the callbacks */
590
0
    fr_sbuff_init_talloc(lb, &lb->sbuff, &lb->tctx, 1024, 10 * 1024); /* start 1k, max 10k */
591
0
    fr_atexit_thread_local(global_log_bio, _fr_tls_log_bio_free, lb);
592
0
    fr_sbuff_marker(&lb->logged_m, &lb->sbuff);
593
0
    return lb->bio;
594
0
  }
595
596
0
  fr_sbuff_reset_talloc(&global_log_bio->sbuff);  /* Reset to initial size */
597
0
  fr_sbuff_marker(&global_log_bio->logged_m, &global_log_bio->sbuff);
598
0
  global_log_bio->type = type;
599
0
  global_log_bio->lvl = lvl;
600
0
  global_log_bio->file = file;
601
0
  global_log_bio->line = line;
602
603
0
  return global_log_bio->bio;
604
0
}
605
606
/** Initialise the BIO logging meths which are used to create thread local logging BIOs
607
 *
608
 */
609
int fr_tls_log_init(void)
610
0
{
611
  /*
612
   *  As per the boringSSL documentation
613
   *
614
   *  BIO_TYPE_START is the first user-allocated |BIO| type.
615
   *  No pre-defined type, flag bits aside, may exceed this
616
   *  value.
617
   *
618
   *  The low byte here defines the BIO ID, and the high byte
619
   *  defines its capabilities.
620
   */
621
0
  tls_request_log_meth = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK, "fr_tls_request_log");
622
0
  if (unlikely(!tls_request_log_meth)) return -1;
623
624
0
  BIO_meth_set_create(tls_request_log_meth, tls_log_request_bio_create_cb);
625
0
  BIO_meth_set_write(tls_request_log_meth, tls_log_request_bio_write_cb);
626
0
  BIO_meth_set_puts(tls_request_log_meth, tls_log_request_bio_puts_cb);
627
0
  BIO_meth_set_destroy(tls_request_log_meth, tls_log_request_bio_free_cb);
628
629
0
  tls_global_log_meth = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK, "fr_tls_global_log");
630
0
  if (unlikely(!tls_global_log_meth)) {
631
0
    BIO_meth_free(tls_request_log_meth);
632
0
    tls_request_log_meth = NULL;
633
0
    return -1;
634
0
  }
635
636
0
  BIO_meth_set_create(tls_global_log_meth, tls_log_global_bio_create_cb);
637
0
  BIO_meth_set_write(tls_global_log_meth, tls_log_global_bio_write_cb);
638
0
  BIO_meth_set_puts(tls_global_log_meth, tls_log_global_bio_puts_cb);
639
0
  BIO_meth_set_destroy(tls_global_log_meth, tls_log_global_bio_free_cb);
640
641
0
  return 0;
642
0
}
643
644
/** Free the global log method templates
645
 *
646
 */
647
void fr_tls_log_free(void)
648
0
{
649
  /*
650
   *  These must be freed first else
651
   *      we get crashes in the OpenSSL
652
   *  code when we try to free them.
653
   */
654
0
  fr_assert_msg(atomic_load(&tls_request_log_ref) == 0, "request log BIO refs remaining %u", atomic_load(&tls_request_log_ref));
655
0
  fr_assert_msg(atomic_load(&tls_global_log_ref) == 0, "global log BIO refs remaining %u", atomic_load(&tls_global_log_ref));
656
657
0
  if (tls_request_log_meth) {
658
0
    BIO_meth_free(tls_request_log_meth);
659
0
    tls_request_log_meth = NULL;
660
0
  }
661
662
0
  if (tls_global_log_meth) {
663
0
    BIO_meth_free(tls_global_log_meth);
664
    tls_global_log_meth = NULL;
665
0
  }
666
0
}
667
#endif /* WITH_TLS */