The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
bio.c
Go to the documentation of this file.
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: 0dbce7c55c8e394c112e091ee1ef2aa172b823cc $
19 *
20 * @file tls/bio.c
21 * @brief Custom BIOs to pass to OpenSSL's functions
22 *
23 * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 */
25RCSID("$Id: 0dbce7c55c8e394c112e091ee1ef2aa172b823cc $")
26USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
27
28#ifdef WITH_TLS
29#include <freeradius-devel/util/atexit.h>
30
31#include "bio.h"
32
33/** Holds the state of a talloc aggregation 'write' BIO
34 *
35 * With these BIOs OpenSSL is the producer, and we're the consumer.
36 */
37struct fr_tls_bio_dbuff_s {
38 BIO *bio; //!< Logging bio to write to.
39 fr_dbuff_t dbuff_in; //!< dbuff used to write data to our talloced buffer.
40 fr_dbuff_t dbuff_out; //!< dbuff used to read data from our talloced buffer.
41 fr_dbuff_uctx_talloc_t tctx; //!< extra talloc information for the dbuff.
42 bool free_buff; //!< Free the talloced buffer when this structure is freed.
43
44 size_t *datagram; //!< array of lengths of the datagrams to be sent.
45 size_t datagram_head; //!< Index of the next datagram to send
46 size_t datagram_used; //!< How many datagrams need to be sent after "head".
47};
48
49/** Record where a write ended
50 *
51 * @param[in] bd to record the boundary on.
52 * @param[in] len of the write.
53 * @return
54 * - 0 on success, or when datagram mode is not enabled.
55 * - -1 when the queue is full.
56 */
57static int tls_bio_dbuff_datagram_push(fr_tls_bio_dbuff_t *bd, size_t len)
58{
59 if (!bd->datagram) return 0;
60
61 /*
62 * Empty queues always start at zero.
63 */
64 fr_assert((bd->datagram_used > 0) || (bd->datagram_head == 0));
65
66 if ((bd->datagram_head + bd->datagram_used) == FR_TLS_MAX_DATAGRAMS) {
67 if (bd->datagram_head == 0) return -1;
68
69 memmove(&bd->datagram[0], &bd->datagram[bd->datagram_head],
70 bd->datagram_used * sizeof(bd->datagram[0]));
71 bd->datagram_head = 0;
72 }
73
74 bd->datagram[bd->datagram_head + bd->datagram_used] = len;
75 bd->datagram_used++;
76
77 return 0;
78}
79
80/** Template for the thread local request log BIOs
81 */
82static BIO_METHOD *tls_bio_talloc_meth;
83
84/** Thread local aggregation BIO
85 */
86static _Thread_local fr_tls_bio_dbuff_t *tls_bio_talloc_agg;
87
88/** Aggregates BIO_write() calls into a talloc'd buffer
89 *
90 * @param[in] bio that was written to.
91 * @param[in] in data being written to BIO.
92 * @param[in] len Length of data being written.
93 */
94static int _tls_bio_talloc_write_cb(BIO *bio, char const *in, int len)
95{
96 fr_tls_bio_dbuff_t *bd = talloc_get_type_abort(BIO_get_data(bio), fr_tls_bio_dbuff_t);
97 ssize_t slen;
98
99 fr_assert_msg(bd->dbuff_in.buff, "BIO not initialised");
100
101 /*
102 * Shift out any data which has been read
103 * since we were last called.
104 */
105 fr_dbuff_shift(&bd->dbuff_in, fr_dbuff_used(&bd->dbuff_out));
106
107 slen = fr_dbuff_in_memcpy_partial(&bd->dbuff_in, (uint8_t const *)in, (size_t)len);
108 if (!bd->datagram) return (int) slen;
109
110 /*
111 * We buffer either all of a datagram, or none of it.
112 *
113 * The buffer extends on demand, so a short copy here means the
114 * allocation failed.
115 */
116 if (slen != (ssize_t) len) return -1;
117
118 if (tls_bio_dbuff_datagram_push(bd, (size_t) len) < 0) return -1;
119
120 return (int) slen;
121}
122
123/** Aggregates BIO_puts() calls into a talloc'd buffer
124 *
125 * @param[in] bio that was written to.
126 * @param[in] in data being written to BIO.
127 */
128static int _tls_bio_talloc_puts_cb(BIO *bio, char const *in)
129{
130 return _tls_bio_talloc_write_cb(bio, in, strlen(in));
131}
132
133/** Serves BIO_read() from a talloced buffer
134 *
135 * @param[in] bio performing the read operation.
136 * @param[out] buf to write data to.
137 * @param[in] size of data to write (maximum).
138 * @return The amount of data written.
139 */
140static int _tls_bio_talloc_read_cb(BIO *bio, char *buf, int size)
141{
142 fr_tls_bio_dbuff_t *bd = talloc_get_type_abort(BIO_get_data(bio), fr_tls_bio_dbuff_t);
143 size_t to_copy;
144 ssize_t slen;
145
146 fr_assert_msg(bd->dbuff_out.buff, "BIO not initialised");
147
148 /*
149 * An empty buffer means "nothing yet", not "end of stream".
150 */
151 if (fr_dbuff_remaining(&bd->dbuff_out) == 0) {
152 BIO_set_retry_read(bio);
153 return -1;
154 }
155 BIO_clear_retry_flags(bio);
156
157 to_copy = fr_dbuff_remaining(&bd->dbuff_out);
158 if (to_copy > (size_t)size) to_copy = (size_t)size;
159
160 slen = fr_dbuff_out_memcpy((uint8_t *)buf, &bd->dbuff_out, to_copy);
161 if (!fr_cond_assert(slen >= 0)) { /* Shouldn't happen */
162 buf[0] = '\0';
163 return (int)slen;
164 }
165
166 fr_dbuff_shift(&bd->dbuff_in, (size_t)slen); /* Shift contents */
167
168 return (int)slen;
169}
170
171/** Serves BIO_gets() from a talloced buffer
172 *
173 * Writes all data up to size, or up to and including the next \n to
174 * the provided buffer.
175 *
176 * @param[in] bio performing the gets operation.
177 * @param[out] buf to write data to.
178 * @param[in] size of data to write (maximum).
179 * @return The amount of data written.
180 */
181static int _tls_bio_talloc_gets_cb(BIO *bio, char *buf, int size)
182{
183 fr_tls_bio_dbuff_t *bd = talloc_get_type_abort(BIO_get_data(bio), fr_tls_bio_dbuff_t);
184 size_t to_copy;
185 uint8_t *p;
186 ssize_t slen;
187
188 fr_assert_msg(bd->dbuff_out.buff, "BIO not initialised");
189
190 /*
191 * Deal with stupid corner case
192 */
193 if (unlikely(size == 1)) {
194 buf[0] = '\0';
195 return 0;
196 } else if (unlikely(size == 0)) {
197 return 0;
198 }
199
200 /*
201 * Copy up to the next line, or the end of the buffer
202 */
203 p = memchr(fr_dbuff_current(&bd->dbuff_out), '\n', fr_dbuff_remaining(&bd->dbuff_out));
204 if (!p) {
205 to_copy = fr_dbuff_remaining(&bd->dbuff_out);
206 } else {
207 to_copy = (p - fr_dbuff_current(&bd->dbuff_out)) + 1; /* Preserve the \n as per BIO_read() man page */
208 }
209
210 if (to_copy >= (size_t)size) to_copy = (size_t)size - 1; /* Space for \0 */
211
212 slen = fr_dbuff_out_memcpy((uint8_t *)buf, &bd->dbuff_out, to_copy);
213 if (!fr_cond_assert(slen >= 0)) { /* Shouldn't happen */
214 buf[0] = '\0';
215 return (int)slen;
216 }
217
218 buf[to_copy] = '\0';
219 fr_dbuff_shift(&bd->dbuff_in, (size_t)slen); /* Shift contents */
220
221 return (int)to_copy;
222}
223
224/** Detach both dbuffs from the shared backing buffer
225 *
226 * The in/out dbuffs are bound to the same talloc buffer, so when the buffer
227 * is freed, or ownership is handed to a caller, both dbuffs must forget the
228 * buffer together. A stale sibling pointer double-frees in the destructor,
229 * or trips the "BIO not finalised" assert on reuse.
230 */
231static inline CC_HINT(always_inline) void tls_bio_dbuff_detach(fr_tls_bio_dbuff_t *bd)
232{
233 bd->dbuff_in.buff = NULL;
234 bd->dbuff_out.buff = NULL;
235}
236
237/** Finalise a talloc aggregation buffer, returning the underlying talloc array holding the data
238 *
239 * @return
240 * - NULL if the aggregation buffer wasn't initialised.
241 * - A talloc_array holding the aggregated data.
242 */
243uint8_t *fr_tls_bio_dbuff_finalise(fr_tls_bio_dbuff_t *bd)
244{
245 uint8_t *buff;
246
247 if (unlikely(!bd)) return NULL;
248 if (unlikely(!bd->dbuff_in.buff)) return NULL;
249
250 fr_dbuff_trim_talloc(&bd->dbuff_in, SIZE_MAX);
251
252 buff = bd->dbuff_in.buff;
253 tls_bio_dbuff_detach(bd);
254 return buff;
255}
256
257/** Finalise a talloc aggregation buffer, returning the underlying talloc array holding the data
258 *
259 * @return
260 * - NULL if the aggregation buffer wasn't initialised.
261 * - A talloc_array holding the aggregated data.
262 */
263char *fr_tls_bio_dbuff_finalise_bstr(fr_tls_bio_dbuff_t *bd)
264{
265 uint8_t *buff;
266
267 if (unlikely(!bd)) return NULL;
268 if (unlikely(!bd->dbuff_in.buff)) return NULL;
269
270 if (fr_dbuff_in_bytes(&bd->dbuff_in, 0x00) <= 0) return NULL;
271 fr_dbuff_trim_talloc(&bd->dbuff_in, SIZE_MAX);
272
273 buff = bd->dbuff_in.buff;
274 tls_bio_dbuff_detach(bd);
275 talloc_set_type(buff, char);
276
277 return (char *)buff;
278}
279
280/* Reset pointer positions for in/out
281 *
282 * Leaves the underlying buffer intact to avoid useless free/malloc.
283 *
284 * Only the producer is reset, as the the consumer has taken nothing.
285 * Use fr_tls_bio_dbuff_clear() when the consumer has already read
286 * part of the buffer.
287 */
288void fr_tls_bio_dbuff_reset(fr_tls_bio_dbuff_t *bd)
289{
290 fr_dbuff_set_to_start(&bd->dbuff_in);
291
292 bd->datagram_head = bd->datagram_used = 0;
293}
294
295/** Do datagram-specific initialization of a TLS BIO.
296 *
297 * The dbuff is a byte stream, which is fine for stream transport. In
298 * contrast, datagram transport has to send each "chunk" of text
299 * separately. Each chunk is limited by the configured MTU.
300 *
301 * Once this is enabled, every write records its length, and the caller walks
302 * the lengths with fr_tls_bio_dbuff_datagram_len() and
303 * fr_tls_bio_dbuff_datagram_sent().
304 *
305 * Datagram mode cannot be turned off again. Nothing needs to, and a buffer
306 * which already holds boundaries has no sensible way to discard them while
307 * keeping the data they describe.
308 *
309 * @param[in] bd to record boundaries on.
310 * @return
311 * - 0 on success, including when datagram mode was already enabled.
312 * - -1 on failure.
313 */
314int fr_tls_bio_dbuff_datagram_init(fr_tls_bio_dbuff_t *bd)
315{
316 if (bd->datagram) return 0;
317
318 bd->datagram = talloc_array(bd, size_t, FR_TLS_MAX_DATAGRAMS);
319 if (unlikely(!bd->datagram)) return -1;
320
321 /*
322 * fr_tls_bio_dbuff_alloc() talloc_zero()s the structure, and
323 * datagram mode cannot be turned off again, so the indices are
324 * already zero on the one call which gets this far.
325 */
326 fr_assert((bd->datagram_head == 0) && (bd->datagram_used == 0));
327
328 return 0;
329}
330
331/** Return the size of the datagram at the start of the dbuff.
332 *
333 * @param[in] bd to read.
334 * @return
335 * - the length of the next datagram.
336 * - 0 if no whole datagram is waiting, or datagram mode is not enabled.
337 */
338size_t fr_tls_bio_dbuff_datagram_len(fr_tls_bio_dbuff_t *bd)
339{
340 if (!bd->datagram || (bd->datagram_used == 0)) return 0;
341
342 return bd->datagram[bd->datagram_head];
343}
344
345/** The datagram was sent, discard the data.
346 *
347 * @param[in] bd to advance.
348 */
349void fr_tls_bio_dbuff_datagram_sent(fr_tls_bio_dbuff_t *bd)
350{
351 if (!bd->datagram || (bd->datagram_used == 0)) return;
352
353 bd->datagram_head++;
354 bd->datagram_used--;
355
356 /*
357 * Nothing is left, so the next write starts from the beginning
358 * rather than from wherever the last one finished.
359 */
360 if (bd->datagram_used == 0) bd->datagram_head = 0;
361}
362
363/** Discard the contents, and return both cursors to the start
364 *
365 * When the producer writes more data, the consumers end pointer is
366 * updated. Resetting the the producer would mean leaving the
367 * consumers end pointer dangling. We therefore reset the consumer
368 * first, and then the producer.
369 *
370 * Leave the underlying buffer intact to avoid useless free/malloc.
371 */
372void fr_tls_bio_dbuff_clear(fr_tls_bio_dbuff_t *bd)
373{
374 fr_dbuff_set_to_start(&bd->dbuff_out);
375 fr_dbuff_set_to_start(&bd->dbuff_in);
376
377 bd->datagram_head = bd->datagram_used = 0;
378}
379
380/** Free the underlying BIO, and the buffer if it wasn't finalised
381 *
382 */
383static int _fr_tls_bio_dbuff_free(fr_tls_bio_dbuff_t *bd)
384{
385 BIO_free(bd->bio);
386 if (bd->free_buff) fr_dbuff_free_talloc(&bd->dbuff_out);
387
388 return 0;
389}
390
391/** Return the output dbuff
392 *
393 */
394fr_dbuff_t *fr_tls_bio_dbuff_out(fr_tls_bio_dbuff_t *bd)
395{
396 return &bd->dbuff_out;
397}
398
399/** Return the input dbuff
400 *
401 */
402fr_dbuff_t *fr_tls_bio_dbuff_in(fr_tls_bio_dbuff_t *bd)
403{
404 return &bd->dbuff_in;
405}
406
407/** Allocate a new BIO/talloc buffer
408 *
409 * @param[out] out Where to write a pointer to the #fr_tls_bio_dbuff_t.
410 * When this structure is freed the underlying BIO *
411 * will also be freed. May be NULL.
412 * @param[in] bio_ctx to allocate the BIO and wrapper struct in. May be NULL.
413 * @param[in] buff_ctx to allocate the expanding buffer in. May be NULL.
414 * @param[in] init how much memory to allocate initially.
415 * @param[in] max the maximum amount of memory to allocate (0 for unlimited).
416 * @param[in] free_buff free the talloced buffer when the #fr_tls_bio_dbuff_t is
417 * freed.
418 * @return
419 * - A new BIO - Do not free manually, free the #fr_tls_bio_dbuff_t or
420 * the ctx containing it instead.
421 */
422BIO *fr_tls_bio_dbuff_alloc(fr_tls_bio_dbuff_t **out, TALLOC_CTX *bio_ctx, TALLOC_CTX *buff_ctx,
423 size_t init, size_t max, bool free_buff)
424{
425 fr_tls_bio_dbuff_t *bd;
426
427 MEM(bd = talloc_zero(bio_ctx, fr_tls_bio_dbuff_t));
428 MEM(bd->bio = BIO_new(tls_bio_talloc_meth));
429 BIO_set_data(bd->bio, bd);
430
431 /*
432 * Initialise the dbuffs
433 */
434 MEM(fr_dbuff_init_talloc(buff_ctx, &bd->dbuff_out, &bd->tctx, init, max)); /* Where we read from */
435 bd->dbuff_in = FR_DBUFF_BIND_END_ABS(&bd->dbuff_out); /* Where we write to */
436 bd->dbuff_out.is_const = 1;
437 bd->free_buff = free_buff;
438
439 talloc_set_destructor(bd, _fr_tls_bio_dbuff_free);
440
441 if (out) *out = bd;
442
443 return bd->bio;
444}
445
446/** Finalise a talloc aggregation buffer, returning the underlying talloc array holding the data
447 *
448 * @return
449 * - NULL if the aggregation buffer wasn't initialised.
450 * - A talloc_array holding the aggregated data.
451 */
452uint8_t *fr_tls_bio_dbuff_thread_local_finalise(void)
453{
454 return fr_tls_bio_dbuff_finalise(tls_bio_talloc_agg);
455}
456
457/** Finalise a talloc aggregation buffer, returning the underlying talloc array holding the data
458 *
459 * This variant adds an additional \0 byte, and sets the talloc chunk type to char.
460 *
461 * @return
462 * - NULL if the aggregation buffer wasn't initialised.
463 * - A talloc_array holding the aggregated data.
464 */
465char *fr_tls_bio_dbuff_thread_local_finalise_bstr(void)
466{
467 return fr_tls_bio_dbuff_finalise_bstr(tls_bio_talloc_agg);
468}
469
470/** Discard any data in a talloc aggregation buffer
471 *
472 * fr_tls_bio_dbuff_thread_local must be called again before using the BIO
473 */
474void fr_tls_bio_dbuff_thread_local_clear(void)
475{
476 fr_tls_bio_dbuff_t *bd = tls_bio_talloc_agg;
477
478 if (unlikely(!bd)) return;
479 if (unlikely(!bd->dbuff_in.buff)) return;
480
481 fr_dbuff_free_talloc(&bd->dbuff_in);
482 tls_bio_dbuff_detach(bd);
483}
484
485/** Frees the thread local TALLOC bio and its underlying OpenSSL BIO *
486 *
487 */
488static int _fr_tls_bio_dbuff_thread_local_free(void *bio_talloc_agg)
489{
490 fr_tls_bio_dbuff_t *our_bio_talloc_agg = talloc_get_type_abort(bio_talloc_agg, fr_tls_bio_dbuff_t);
491
492 return talloc_free(our_bio_talloc_agg); /* Frees the #fr_tls_bio_dbuff_t and BIO */
493}
494
495/** Return a BIO which will aggregate data in an expandable talloc buffer
496 *
497 * @note Only one of these BIOs may be in use at a given time.
498 *
499 * @param[in] init how much memory to allocate initially.
500 * @param[in] max the maximum amount of memory to allocate (0 for unlimited).
501 * @return A thread local BIO to pass to OpenSSL logging functions.
502 */
503BIO *fr_tls_bio_dbuff_thread_local(TALLOC_CTX *ctx, size_t init, size_t max)
504{
505 fr_tls_bio_dbuff_t *bd = tls_bio_talloc_agg;
506
507 if (unlikely(!bd)) {
508 fr_tls_bio_dbuff_alloc(&bd, NULL, ctx, init, max, true);
509 fr_atexit_thread_local(tls_bio_talloc_agg, _fr_tls_bio_dbuff_thread_local_free, bd);
510
511 return bd->bio;
512 }
513
514 fr_assert_msg(!tls_bio_talloc_agg->dbuff_out.buff, "BIO not finalised");
515 MEM(fr_dbuff_init_talloc(ctx, &bd->dbuff_out, &bd->tctx, init, max)); /* Where we read from */
516 bd->dbuff_in = FR_DBUFF_BIND_END_ABS(&bd->dbuff_out); /* Where we write to */
517
518 return tls_bio_talloc_agg->bio;
519}
520
521/** Respond to BIO queries about ctrl cmds.
522 *
523 * A handshake driven through this BIO asks only BIO_CTRL_PUSH and
524 * BIO_CTRL_POP. The data controls are answered anyway, because it
525 * costs nothing to do so, and a caller could request them.
526 */
527static long _tls_bio_talloc_ctrl_cb(BIO *bio, int cmd, UNUSED long num, UNUSED void *ptr)
528{
529 fr_tls_bio_dbuff_t *bd = talloc_get_type_abort(BIO_get_data(bio), fr_tls_bio_dbuff_t);
530
531 switch (cmd) {
532 case BIO_CTRL_PENDING:
533 return (long) fr_dbuff_remaining(&bd->dbuff_out);
534
535 case BIO_CTRL_WPENDING:
536 return 0;
537
538 case BIO_CTRL_FLUSH:
539 return 1;
540
541 case BIO_CTRL_RESET:
542 fr_tls_bio_dbuff_reset(bd);
543 return 1;
544
545 case BIO_CTRL_EOF:
546 return 0;
547
548 default:
549 return 0;
550 }
551}
552
553/** Initialise the BIO logging meths which are used to create thread local logging BIOs
554 *
555 */
556int fr_tls_bio_init(void)
557{
558 /*
559 * As per the boringSSL documentation
560 *
561 * BIO_TYPE_START is the first user-allocated |BIO| type.
562 * No pre-defined type, flag bits aside, may exceed this
563 * value.
564 *
565 * The low byte here defines the BIO ID, and the high byte
566 * defines its capabilities.
567 */
568 tls_bio_talloc_meth = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK, "fr_tls_bio_dbuff_t");
569 if (unlikely(!tls_bio_talloc_meth)) return -1;
570
571 /*
572 * If BIO_meth_set_create is ever used here be sure to call
573 * BIO_set_init(bio, 1); in the create callbacks else all
574 * operations on the BIO will fail.
575 */
576 BIO_meth_set_write(tls_bio_talloc_meth, _tls_bio_talloc_write_cb);
577 BIO_meth_set_puts(tls_bio_talloc_meth, _tls_bio_talloc_puts_cb);
578 BIO_meth_set_read(tls_bio_talloc_meth, _tls_bio_talloc_read_cb);
579 BIO_meth_set_gets(tls_bio_talloc_meth, _tls_bio_talloc_gets_cb);
580 BIO_meth_set_ctrl(tls_bio_talloc_meth, _tls_bio_talloc_ctrl_cb);
581
582 return 0;
583}
584
585/** Free the global log method templates
586 *
587 */
588void fr_tls_bio_free(void)
589{
590 if (tls_bio_talloc_meth) {
591 BIO_meth_free(tls_bio_talloc_meth);
592 tls_bio_talloc_meth = NULL;
593 }
594}
595#endif /* WITH_TLS */
#define _Thread_local
Definition atexit.h:213
#define fr_atexit_thread_local(_name, _free, _uctx)
Definition atexit.h:224
#define USES_APPLE_DEPRECATED_API
Definition build.h:590
#define RCSID(id)
Definition build.h:603
#define unlikely(_x)
Definition build.h:486
#define UNUSED
Definition build.h:415
int fr_dbuff_trim_talloc(fr_dbuff_t *dbuff, size_t len)
Trim a talloced dbuff to the minimum length required to represent the contained string.
Definition dbuff.c:297
size_t fr_dbuff_shift(fr_dbuff_t *dbuff, size_t shift)
Shift the contents of the dbuff, returning the number of bytes we managed to shift.
Definition dbuff.c:116
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition dbuff.h:819
static void fr_dbuff_free_talloc(fr_dbuff_t *dbuff)
Free the talloc buffer associated with a dbuff.
Definition dbuff.h:495
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:963
#define fr_dbuff_set_to_start(_dbuff_or_marker)
Reset the 'current' position of the dbuff or marker to the 'start' of the buffer.
Definition dbuff.h:1208
#define fr_dbuff_out_memcpy(_out, _dbuff_or_marker, _outlen)
Copy exactly _outlen bytes from the dbuff.
Definition dbuff.h:1785
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
Definition dbuff.h:795
#define fr_dbuff_in_bytes(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker.
Definition dbuff.h:1518
#define fr_dbuff_in_memcpy_partial(_out, _in, _inlen)
Copy at most _inlen bytes into the dbuff.
Definition dbuff.h:1491
#define FR_DBUFF_BIND_END_ABS(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:268
static fr_dbuff_t * fr_dbuff_init_talloc(TALLOC_CTX *ctx, fr_dbuff_t *dbuff, fr_dbuff_uctx_talloc_t *tctx, size_t init, size_t max)
Initialise a special dbuff which automatically extends as additional data is written.
Definition dbuff.h:453
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:177
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:248
#define MEM(x)
Definition debug.h:38
talloc_free(hp)
long int ssize_t
unsigned char uint8_t
unsigned long int size_t
#define fr_assert(_expr)
Definition rad_assert.h:37
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:37
init
Enter the EAP-IDENTITY state.
static fr_sbuff_err_t char size_t fr_sbuff_t * in
Definition value.h:1061
static fr_sbuff_err_t char size_t fr_sbuff_t size_t max
Definition value.h:1061
static fr_sbuff_err_t char ** out
Definition value.h:1061
static fr_sbuff_err_t char size_t * len
Definition value.h:1061