The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
base.c
Go to the documentation of this file.
1 /*
2  * This program is 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 (at
5  * 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: 7f2b086babc82fa38d572cb5648bd43c594737c8 $
19  * @file lib/bio/base.c
20  * @brief Binary IO abstractions.
21  *
22  * @copyright 2024 Network RADIUS SAS (legal@networkradius.com)
23  */
24 
25 #include <freeradius-devel/bio/bio_priv.h>
26 #include <freeradius-devel/bio/null.h>
27 #include <freeradius-devel/util/syserror.h>
28 
29 #ifndef NDEBUG
30 /** Free this bio.
31  *
32  * The bio can only be freed if it is not in any chain.
33  */
35 {
36  fr_assert(!fr_bio_prev(bio));
37  fr_assert(!fr_bio_next(bio));
38 
39  /*
40  * It's safe to free this bio.
41  */
42  return 0;
43 }
44 #endif
45 
46 /** Internal bio function which just reads from the "next" bio.
47  *
48  * It is mainly used when the current bio needs to modify the write
49  * path, but does not need to do anything on the read path.
50  */
51 ssize_t fr_bio_next_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
52 {
53  ssize_t rcode;
54  fr_bio_t *next;
55 
56  next = fr_bio_next(bio);
57  fr_assert(next != NULL);
58 
59  rcode = next->read(next, packet_ctx, buffer, size);
60  if (rcode >= 0) return rcode;
61 
62  if (rcode == fr_bio_error(IO_WOULD_BLOCK)) return rcode;
63 
64  bio->read = fr_bio_fail_read;
65  bio->write = fr_bio_fail_write;
66  return rcode;
67 }
68 
69 /** Internal bio function which just writes to the "next" bio.
70  *
71  * It is mainly used when the current bio needs to modify the read
72  * path, but does not need to do anything on the write path.
73  */
74 ssize_t fr_bio_next_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
75 {
76  ssize_t rcode;
77  fr_bio_t *next;
78 
79  next = fr_bio_next(bio);
80  fr_assert(next != NULL);
81 
82  rcode = next->write(next, packet_ctx, buffer, size);
83  if (rcode >= 0) return rcode;
84 
85  if (rcode == fr_bio_error(IO_WOULD_BLOCK)) return rcode;
86 
87  bio->read = fr_bio_fail_read;
88  bio->write = fr_bio_fail_write;
89  return rcode;
90 }
91 
92 /** Free this bio, and everything it calls.
93  *
94  * We unlink the bio chain, and then free it individually. If there's an error, the bio chain is relinked.
95  * That way the error can be addressed (somehow) and this function can be called again.
96  *
97  * Note that we do not support talloc_free() for the bio chain. Each individual bio has to be unlinked from
98  * the chain before the destructor will allow it to be freed. This functionality is by design.
99  *
100  * We want to have an API where bios are created "bottom up", so that it is impossible for an application to
101  * create an incorrect chain. However, creating the chain bottom up means that the lower bios not parented
102  * from the higher bios, and therefore talloc_free() won't free them. As a result, we need an explicit
103  * bio_free() function.
104  */
106 {
107  fr_bio_t *next = fr_bio_next(bio);
108 
109  /*
110  * We cannot free a bio in the middle of a chain. It has to be unlinked first.
111  */
112  if (fr_bio_prev(bio)) return -1;
113 
114  /*
115  * Unlink our bio, and recurse to free the next one. If we can't free it, re-chain it, but reset
116  * the read/write functions to do nothing.
117  */
118  if (next) {
119  next->entry.prev = NULL;
120  if (fr_bio_free(next) < 0) {
121  next->entry.prev = &bio->entry;
122  bio->read = fr_bio_fail_read;
123  bio->write = fr_bio_fail_write;
124  return -1;
125  }
126 
127  bio->entry.next = NULL;
128  }
129 
130  /*
131  * It's now safe to free this bio.
132  */
133  return talloc_free(bio);
134 }
135 
136 /** Shut down a set of BIOs
137  *
138  * We shut down the BIOs from the top to the bottom. This gives the TLS BIO an opportunity to
139  * call the SSL_shutdown() routine, which should then write to the FD BIO.
140  */
142 {
143  fr_bio_t *this, *first;
145 
146  fr_assert(!fr_bio_prev(bio));
147 
148  /*
149  * Find the first bio in the chain.
150  */
151  for (this = bio; fr_bio_prev(this) != NULL; this = fr_bio_prev(this)) {
152  /* nothing */
153  }
154  first = this;
155 
156  /*
157  * Walk back down the chain, calling the shutdown functions.
158  */
159  for (/* nothing */; this != NULL; this = fr_bio_next(this)) {
160  my = (fr_bio_common_t *) this;
161 
162  if (!my->priv_cb.shutdown) continue;
163 
164  /*
165  * The EOF handler said it's NOT at EOF, so we stop processing here.
166  */
167  my->priv_cb.shutdown(&my->bio);
168  my->priv_cb.shutdown = NULL;
169  }
170 
171  /*
172  * Call the application shutdown routine
173  */
174  my = (fr_bio_common_t *) first;
175 
176  if (my->cb.shutdown) my->cb.shutdown(first);
177  my->cb.shutdown = NULL;
178 
179  return 0;
180 }
181 
182 /** Like fr_bio_shutdown(), but can be called by anyone in the chain.
183  *
184  */
186 {
187  fr_bio_common_t *prev;
188 
189  while ((prev = (fr_bio_common_t *) fr_bio_prev(bio)) != NULL) {
190  bio = (fr_bio_t *) prev;
191  }
192 
193  return fr_bio_shutdown(bio);
194 }
195 
196 char const *fr_bio_strerror(ssize_t error)
197 {
198  switch (error) {
199  case fr_bio_error(NONE):
200  return "";
201 
202  case fr_bio_error(IO_WOULD_BLOCK):
203  return "IO operation would block";
204 
205  case fr_bio_error(IO):
206  return fr_syserror(errno);
207 
208  case fr_bio_error(GENERIC):
209  return fr_strerror();
210 
211  case fr_bio_error(VERIFY):
212  return "Packet fails verification";
213 
214  case fr_bio_error(BUFFER_FULL):
215  return "Output buffer is full";
216 
217  case fr_bio_error(BUFFER_TOO_SMALL):
218  return "Output buffer is too small to cache the data";
219 
220  default:
221  return "<unknown>";
222  }
223 }
224 
226 {
228 
229  if (!cb) {
230  memset(&my->cb, 0, sizeof(my->cb));
231  } else {
232  my->cb = *cb;
233  }
234 }
235 
236 /** Internal BIO function to run EOF callbacks.
237  *
238  * When a BIO hits EOF, it MUST call this function. This function will take care of changing the read()
239  * function to return nothing. It will also take care of walking back up the hierarchy, and calling any
240  * BIO EOF callbacks.
241  *
242  * Once all of the BIOs have been marked as blocked, it will call the application EOF callback.
243  */
245 {
246  fr_bio_common_t *this = (fr_bio_common_t *) bio;
247 
248  /*
249  * This BIO is at EOF. So we can't call read() any more.
250  */
251  this->bio.read = fr_bio_null_read;
252 
253  while (true) {
254  fr_bio_common_t *prev = (fr_bio_common_t *) fr_bio_prev(&this->bio);
255 
256  /*
257  * There are no more BIOs. Tell the application that the entire BIO chain is at EOF.
258  */
259  if (!prev) {
260  if (this->cb.eof) {
261  this->cb.eof(&this->bio);
262  this->cb.eof = NULL;
263  }
264  break;
265  }
266 
267  /*
268  * Go to the previous BIO. If it doesn't have an EOF handler, then keep going back up
269  * the chain until we're at the top.
270  */
271  this = prev;
272  if (!this->priv_cb.eof) continue;
273 
274  /*
275  * The EOF handler said it's NOT at EOF, so we stop processing here.
276  */
277  if (this->priv_cb.eof((fr_bio_t *) this) == 0) break;
278 
279  /*
280  * Don't run the EOF callback multiple times, and continue the loop.
281  */
282  this->priv_cb.eof = NULL;
283  }
284 }
285 
286 /** Internal BIO function to tell all BIOs that it's blocked.
287  *
288  * When a BIO blocks on write, it MUST call this function. This function will take care of walking back up
289  * the hierarchy, and calling any write_blocked callbacks.
290  *
291  * Once all of the BIOs have been marked as blocked, it will call the application write_blocked callback.
292  */
294 {
295  fr_bio_common_t *this = (fr_bio_common_t *) bio;
296  int is_blocked = 1;
297 
298  while (true) {
299  fr_bio_common_t *prev = (fr_bio_common_t *) fr_bio_prev(&this->bio);
300  int rcode;
301 
302  /*
303  * There are no more BIOs. Tell the application that the entire BIO chain is blocked.
304  */
305  if (!prev) {
306  if (this->cb.write_blocked) {
307  rcode = this->cb.write_blocked(&this->bio);
308  if (rcode < 0) return rcode;
309  is_blocked &= (rcode == 1);
310  }
311  break;
312  }
313 
314  /*
315  * Go to the previous BIO. If it doesn't have a write_blocked handler, then keep going
316  * back up the chain until we're at the top.
317  */
318  this = prev;
319  if (!this->priv_cb.write_blocked) continue;
320 
321  /*
322  * The EOF handler said it's NOT at EOF, so we stop processing here.
323  */
324  rcode = this->priv_cb.write_blocked((fr_bio_t *) this);
325  if (rcode < 0) return rcode;
326  is_blocked &= (rcode == 1);
327  }
328 
329  return is_blocked;
330 }
static int const char char buffer[256]
Definition: acutest.h:574
fr_bio_write_t _CONST write
write to the underlying bio
Definition: base.h:116
fr_bio_read_t _CONST read
read from the underlying bio
Definition: base.h:115
fr_dlist_t _CONST entry
in the linked list of multiple bios
Definition: base.h:118
static fr_bio_t * fr_bio_prev(fr_bio_t *bio)
Definition: base.h:121
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
Definition: base.h:130
#define fr_bio_error(_x)
Definition: base.h:192
Definition: base.h:112
next
Definition: dcursor.h:178
fr_dlist_t * next
Definition: dlist.h:43
fr_bio_shutdown & my
Definition: fd_errno.h:59
int fr_bio_free(fr_bio_t *bio)
Free this bio, and everything it calls.
Definition: base.c:105
int fr_bio_write_blocked(fr_bio_t *bio)
Internal BIO function to tell all BIOs that it's blocked.
Definition: base.c:293
void fr_bio_cb_set(fr_bio_t *bio, fr_bio_cb_funcs_t const *cb)
Definition: base.c:225
int fr_bio_shutdown_intermediate(fr_bio_t *bio)
Like fr_bio_shutdown(), but can be called by anyone in the chain.
Definition: base.c:185
char const * fr_bio_strerror(ssize_t error)
Definition: base.c:196
void fr_bio_eof(fr_bio_t *bio)
Internal BIO function to run EOF callbacks.
Definition: base.c:244
int fr_bio_destructor(fr_bio_t *bio)
Free this bio.
Definition: base.c:34
ssize_t fr_bio_next_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Internal bio function which just reads from the "next" bio.
Definition: base.c:51
ssize_t fr_bio_next_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
Internal bio function which just writes to the "next" bio.
Definition: base.c:74
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition: base.c:141
talloc_free(reap)
long int ssize_t
Definition: merged_model.c:24
ssize_t fr_bio_null_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
Always return 0 on read.
Definition: null.c:31
ssize_t fr_bio_fail_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
Always return error on read.
Definition: null.c:47
ssize_t fr_bio_fail_write(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
Always return 0 on write.
Definition: null.c:56
fr_assert(0)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
#define VERIFY(_x)
Definition: trie.c:130
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554