The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
unit_test_tls.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 * $Id: 57ea0bacf592519657600199da53e554812a8b5c $
18 *
19 * @file unit_test_tls.c
20 * @brief TLS server test framework
21 *
22 * This program loads the "tls" protocol and reads two top-level sections
23 * from unit_test_tls.conf. The "tls" section supplies the TLS server
24 * context, and takes exactly the items that a TLS configuration takes
25 * anywhere else in the server. The "unit_test_tls" section supplies what
26 * steers the test program itself, which is the address of the listening TCP
27 * socket and whether a client certificate is required.
28 *
29 * One connection is accepted, and the TLS handshake for that connection is
30 * run to completion.
31 *
32 * The handshake runs on a persistent asynchronous interpreter, the same way
33 * radiusd runs one. A persistent interpreter keeps the handshake state
34 * across the several rounds of a single connection.
35 *
36 * The "virtual_server" item in the "tls" section names a virtual server.
37 * That virtual server supplies the "verify certificate", "load session",
38 * "store session" and "clear session" sections which the handshake calls.
39 *
40 * To run the test, start unit_test_tls with the test configuration, then
41 * connect to the listening socket:
42 *
43 * @code
44 * ./scripts/bin/unit_test_tls -d src/tests/tls -X
45 *
46 * openssl s_client -connect 127.0.0.1:2083 \
47 * -cert raddb/certs/rsa/client.pem \
48 * -key raddb/certs/rsa/client.key -pass pass:whatever \
49 * -CAfile raddb/certs/rsa/ca.pem
50 * @endcode
51 *
52 * src/tests/tls/unit_test_tls.conf documents every configuration item.
53 *
54 * @copyright 2025 The FreeRADIUS server project
55 */
56RCSID("$Id: 57ea0bacf592519657600199da53e554812a8b5c $")
57
58#include <freeradius-devel/server/base.h>
59#include <freeradius-devel/server/module_rlm.h>
60
61#include <freeradius-devel/io/listen.h>
62#include <freeradius-devel/io/thread.h>
63
64#include <freeradius-devel/tls/base.h>
65#include <freeradius-devel/tls/strerror.h>
66#include <freeradius-devel/tls/version.h>
67#include <freeradius-devel/tls/connection.h>
68
69#include <freeradius-devel/unlang/base.h>
70#include <freeradius-devel/unlang/function.h>
71#include <freeradius-devel/unlang/interpret.h>
72
73#include <freeradius-devel/util/socket.h>
74
75#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
76
77#ifdef HAVE_GETOPT_H
78# include <getopt.h>
79#endif
80
81#define EXIT_WITH_FAILURE \
82do { \
83 ret = EXIT_FAILURE; \
84 goto cleanup; \
85} while (0)
86
87char const *radiusd_version = RADIUSD_VERSION_BUILD("unit_test_tls");
88
90static fr_dict_t const *dict_tls;
91
94 { .out = &dict_freeradius, .proto = "freeradius" },
95 { .out = &dict_tls, .proto = "tls" },
97};
98
99/** The "unit_test_tls" section
100 *
101 * These items steer the test program, and have nothing to do with TLS itself.
102 * Keeping them out of the "tls" section leaves that section holding only what
103 * fr_tls_conf_parse_server() understands.
104 */
105typedef struct {
106 fr_ipaddr_t ipaddr; //!< Address of the listening socket. Server mode only.
107 uint16_t port; //!< Port of the listening socket, and the default
108 ///< port for -s.
109 bool require_client_certificate; //!< Whether the client has to present a certificate.
111
116
117 { FR_CONF_OFFSET("port", unit_test_tls_conf_t, port) },
118
119 { FR_CONF_OFFSET("require_client_certificate", unit_test_tls_conf_t, require_client_certificate),
120 .dflt = "no" },
121
123};
124
125/** State of the test program
126 *
127 * The interpreter and the runnable heap live for the whole of the connection.
128 * A TLS handshake takes several rounds, and each round may yield while a
129 * virtual server section runs. The interpreter and the runnable heap
130 * therefore cannot be allocated once per round.
131 */
132typedef struct {
133 fr_event_list_t *el; //!< Event list everything runs on.
134 unlang_interpret_t *intp; //!< Interpreter for the connection.
135 fr_heap_t *runnable; //!< Requests the interpreter has marked runnable.
136 int yielded; //!< How many requests are currently yielded.
137
138 unit_test_tls_conf_t conf; //!< Parsed "unit_test_tls" section.
139 SSL_CTX *ssl_ctx; //!< Context built from the "tls" section.
140
141 fr_tls_connection_t *conn; //!< State of the connection being run.
142
143 unsigned int count; //!< How many connections to run.
144 bool alert; //!< Reject the peer with a TLS alert, see -A.
145 bool reject; //!< Reject the session once the handshake
146 ///< succeeds, see -R.
147 unsigned int connections; //!< How many connections have been run so far.
148 fr_ipaddr_t server_ipaddr; //!< Server named by -s.
149 uint16_t server_port; //!< Port from -s, or from the configuration.
150
151 int sockfd; //!< Listening socket.
152 int fd; //!< Accepted or connected socket.
153 fr_event_fd_t *ef; //!< Read event for fd.
154
155 bool done; //!< Set once the connection has a result.
156 int ret; //!< Exit status.
158
159static void usage(main_config_t const *config, int status);
160
161/*
162 * Interpreter callbacks.
163 *
164 * The callbacks below mirror the set in
165 * src/lib/unlang/interpret_synchronous.c and src/lib/io/coord_pair.c. The
166 * one difference is that a post-event handler drains the runnable heap,
167 * rather than a loop inside the caller, so the event loop decides when
168 * each request runs.
169 */
170
171/** Schedule a request, once
172 *
173 * A request reaches the heap from two directions: the interpreter creating it,
174 * and the interpreter marking it runnable again. Inserting a request which is
175 * already on the heap puts it there twice, and popping it then returns a
176 * request which the heap still holds, which the interpreter refuses to run.
177 */
179{
180 if (fr_heap_entry_inserted(request->runnable)) return;
181
182 fr_heap_insert(&utt->runnable, request);
183}
184
185/** An internal request created by the interpreter has to run on ours
186 *
187 * The subrequests created for the "verify certificate" section and for the
188 * session cache sections reach this callback.
189 *
190 * fr_tls_call_push() pushes each of them as a detachable subrequest, which
191 * the parent waits on rather than running inline, so the subrequest has to be
192 * scheduled here or nothing ever runs it.
193 */
194static void _request_init_internal(request_t *request, void *uctx)
195{
196 unit_test_tls_t *utt = talloc_get_type_abort(uctx, unit_test_tls_t);
197
198 RDEBUG3("Initialising internal request");
199
200 unlang_interpret_set(request, utt->intp);
201
202 /*
203 * interpret_child_init() calls this, and nothing else schedules
204 * the child, so a subrequest which is not put on the heap here
205 * never runs at all.
206 */
207 tls_runnable_insert(utt, request);
208}
209
210static void _request_done_external(request_t *request, UNUSED rlm_rcode_t rcode, UNUSED void *uctx)
211{
212 RDEBUG3("Done external request");
213
214 /*
215 * main() allocated the request, and the request has to survive
216 * until the connection is done with, so this callback does not
217 * free the request.
218 */
219}
220
221static void _request_done_internal(request_t *request, UNUSED rlm_rcode_t rcode, UNUSED void *uctx)
222{
223 RDEBUG3("Done internal request");
224
225 /* The code which created the internal request frees the request */
226}
227
228static void _request_done_detached(request_t *request, UNUSED rlm_rcode_t rcode, UNUSED void *uctx)
229{
230 RDEBUG3("Done detached request");
231
232 /*
233 * Nothing else can free a detached request, so this callback
234 * frees the detached request.
235 */
236 talloc_free(request);
237}
238
239static void _request_detach(request_t *request, UNUSED void *uctx)
240{
241 RDEBUG3("Request detached");
242
243 if (request_detach(request) < 0) RPEDEBUG("Failed detaching request");
244}
245
246static void _request_yield(request_t *request, void *uctx)
247{
248 unit_test_tls_t *utt = talloc_get_type_abort(uctx, unit_test_tls_t);
249
250 utt->yielded++;
251
252 RDEBUG3("Request yielded");
253}
254
255static void _request_resume(request_t *request, UNUSED void *uctx)
256{
257 RDEBUG3("Request resumed");
258}
259
260static void _request_runnable(request_t *request, void *uctx)
261{
262 unit_test_tls_t *utt = talloc_get_type_abort(uctx, unit_test_tls_t);
263
264 fr_assert(utt->yielded > 0);
265 utt->yielded--;
266
267 tls_runnable_insert(utt, request);
268}
269
270static bool _request_scheduled(request_t const *request, UNUSED void *uctx)
271{
272 return fr_heap_entry_inserted(request->runnable);
273}
274
275/** Stop the event loop, recording why
276 *
277 * The connection carries the result, so the exit status is decided here
278 * rather than by the state machine. A process exit status is this program's
279 * notion of a result, and no part of a TLS connection should have to know
280 * about one.
281 */
282static void tls_request_finished(void *uctx, fr_tls_connection_t *conn)
283{
284 unit_test_tls_t *utt = talloc_get_type_abort(uctx, unit_test_tls_t);
285
286 if (utt->done) return;
287
288 utt->done = true;
289 utt->ret = conn->failed ? EXIT_FAILURE : EXIT_SUCCESS;
290
291 fr_event_loop_exit(utt->el, 1);
292}
293
294/** Record a failure this program cannot recover from, and stop
295 *
296 * tls_request_finished() reads the result from the connection, so a failure
297 * has to reach the connection before the callback runs.
298 */
300{
301 utt->conn->failed = true;
302 tls_request_finished(utt, utt->conn);
303}
304
305/** Write whatever OpenSSL has produced out to the connection
306 *
307 * The TLS session reads and writes memory BIOs, which are OpenSSL's in-memory
308 * I/O buffers, and never a socket. Writing each record to the socket is
309 * therefore the caller's job. The EAP code in src/lib/eap/tls.c writes
310 * records the same way.
311 */
312static int tls_connection_write(void *uctx, fr_tls_connection_t *conn)
313{
314 unit_test_tls_t *utt = talloc_get_type_abort(uctx, unit_test_tls_t);
315 fr_tls_session_t *tls_session = conn->tls_session;
316
317 /*
318 * dirty_out is a cursor over the BIO's own buffer, so the
319 * octets waiting to go out are already contiguous, and write()
320 * takes them where they lie. Nothing here touches the BIO
321 * between taking the pointer and using it, which is what the
322 * pointer rule in src/lib/tls/bio.h asks of a caller.
323 */
324 while (fr_dbuff_remaining(tls_session->dirty_out) > 0) {
325 ssize_t slen;
326
327 slen = write(utt->fd, fr_dbuff_current(tls_session->dirty_out),
328 fr_dbuff_remaining(tls_session->dirty_out));
329 if (slen < 0) {
330 if (errno == EINTR) continue;
331
332 ERROR("Failed writing to connection: %s", fr_syserror(errno));
333 return -1;
334 }
335
336 if (slen == 0) {
337 ERROR("Wrote no data to connection");
338 return -1;
339 }
340
341 /*
342 * A short write leaves the rest where it is, and the
343 * next pass takes a fresh pointer for what is left.
344 */
345 fr_dbuff_advance(tls_session->dirty_out, (size_t) slen);
346
347 DEBUG3("Wrote %zd bytes to the connection", slen);
348 }
349
350 return 0;
351}
352
353/** A record arrived on the connection, so hand the record to the connection
354 *
355 * Reading the socket is all this program does here. Everything the record
356 * means to TLS is fr_tls_connection_recv()'s business.
357 */
358static void _tls_connection_read(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
359{
360 unit_test_tls_t *utt = talloc_get_type_abort(uctx, unit_test_tls_t);
361 uint8_t buf[SSL3_RT_MAX_PLAIN_LENGTH];
362 ssize_t slen;
363
364 if (utt->done) return;
365
366 slen = read(fd, buf, sizeof(buf));
367 if (slen < 0) {
368 if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK)) return;
369
370 ERROR("Failed reading from connection: %s", fr_syserror(errno));
372 return;
373 }
374
375 if (slen == 0) {
376 ERROR("Connection closed by the peer before the handshake completed");
378 return;
379 }
380
381 /*
382 * Reject the peer now that a record has arrived, so that the
383 * alert goes out in place of the first record this end would
384 * otherwise have sent. Raising the alert any earlier races the
385 * peer: the round which sends the alert can run before the
386 * peer's first record has arrived, and the alert is then sent
387 * into an empty handshake and lost.
388 */
389 if (utt->alert && (utt->connections == utt->count)) {
390 utt->alert = false;
391
392 if (fr_tls_session_alert(utt->conn->request, utt->conn->tls_session,
393 SSL3_AL_FATAL, SSL_AD_ACCESS_DENIED) < 0) {
394 ERROR("Failed raising the TLS alert");
396 return;
397 }
398 }
399
400 fr_tls_connection_recv(utt->conn, buf, (size_t) slen);
401}
402
403/** The connection failed at the socket level
404 *
405 */
406static void _tls_connection_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
407{
408 unit_test_tls_t *utt = talloc_get_type_abort(uctx, unit_test_tls_t);
409
410 ERROR("Error on connection: %s", fr_syserror(fd_errno));
412}
413
414/** Drain the runnable heap once per pass of the event loop
415 *
416 * A handshake round yields whenever the round runs a virtual server section.
417 * When that section finishes, unlang_interpret_mark_runnable() puts the
418 * request on the runnable heap, and this drains the heap again.
419 */
421{
422 unit_test_tls_t *utt = talloc_get_type_abort(uctx, unit_test_tls_t);
423 request_t *request;
424
425 while (fr_heap_pop((void **)&request, &utt->runnable) == 0) {
426 if (!request) break;
427
429
430 /*
431 * Only the connection's own request advances the
432 * handshake. A subrequest returns the subrequest's
433 * result through the interpreter.
434 */
435 if (request == utt->conn->request) {
436 fr_tls_connection_process(utt->conn);
437
438 /*
439 * Stand in for an application which rejects a
440 * session after the handshake succeeded. The
441 * handshake has finished, so OpenSSL has asked
442 * for the session to be cached, and the
443 * connection is about to run its cache
444 * operations. Failing it here makes those
445 * operations a deny and a clear rather than a
446 * store, which is what rlm_eap_tls does when
447 * policy rejects.
448 */
449 if (utt->reject && (utt->connections == utt->count) &&
450 fr_tls_session_is_init_finished(utt->conn->tls_session)) {
451 INFO("Rejecting the session after a successful handshake");
452 utt->conn->failed = true;
453 }
454 }
455
456 if (utt->done) return;
457 }
458}
459
460/** Open the listening socket described by the "unit_test_tls" section
461 *
462 */
464{
465 int sockfd;
466 fr_ipaddr_t ipaddr = utt->conf.ipaddr;
467 uint16_t port = utt->conf.port;
468
469 /*
470 * The items are not marked as required, because a client has no
471 * listening socket, and so needs neither of them.
472 */
473 if ((ipaddr.af == AF_UNSPEC) || !port) {
474 ERROR("Both 'ipaddr' and 'port' must be set in the 'unit_test_tls' section "
475 "when listening for a connection");
476 return -1;
477 }
478
479 sockfd = fr_socket_server_tcp(&ipaddr, &port, NULL, false);
480 if (sockfd < 0) {
481 PERROR("Failed opening TCP socket");
482 return -1;
483 }
484
485 if (fr_socket_bind(sockfd, NULL, &ipaddr, &port) < 0) {
486 PERROR("Failed binding TCP socket");
487 close(sockfd);
488 return -1;
489 }
490
491 if (listen(sockfd, 8) < 0) {
492 ERROR("Failed listening on TCP socket: %s", fr_syserror(errno));
493 close(sockfd);
494 return -1;
495 }
496
497 INFO("Listening on %pV port %u", fr_box_ipaddr(ipaddr), port);
498
499 utt->sockfd = sockfd;
500
501 return 0;
502}
503
504/** Connect to the server named by -s
505 *
506 */
508{
509 int fd;
511
512 fr_inet_ntop(buffer, sizeof(buffer), &utt->server_ipaddr);
513
514 fd = fr_socket_client_tcp(NULL, NULL, &utt->server_ipaddr, utt->server_port, false);
515 if (fd < 0) {
516 PERROR("Failed connecting to %s port %u", buffer, utt->server_port);
517 return -1;
518 }
519
520 INFO("Connected to %s port %u", buffer, utt->server_port);
521
522 utt->fd = fd;
523
524 return 0;
525}
526
527/** Build an internal client.
528 *
529 * unit_test_tls accepts packets from anywhere (for now), and doesn't read "client" configuration sections.
530 *
531 * The client is built by allocating a CONF_SECTION rather than by filling in #fr_client_t manually, which
532 * allows fields to be examined by `%request.client()`.
533 *
534 * "proto = tls" sets both the protocol and tls_required. It also fixes the
535 * secret at "radsec", so that is the secret set here.
536 */
537static fr_client_t *tls_client_alloc(TALLOC_CTX *ctx, fr_ipaddr_t const *ipaddr)
538{
539 CONF_SECTION *cs;
540 fr_client_t *client;
542
543 /*
544 * Written without a prefix, the way a person would write it in
545 * a "client" section. The "ipaddr" item is a COMBO_IP_PREFIX,
546 * so a bare host address parses as a /32 or a /128.
547 */
548 fr_inet_ntop(buffer, sizeof(buffer), ipaddr);
549
550 MEM(cs = cf_section_alloc(ctx, NULL, "client", "unit_test_tls"));
552 MEM(cf_pair_alloc(cs, "proto", "tls", T_OP_EQ, T_BARE_WORD, T_BARE_WORD));
553 MEM(cf_pair_alloc(cs, "secret", "radsec", T_OP_EQ, T_BARE_WORD, T_DOUBLE_QUOTED_STRING));
554 MEM(cf_pair_alloc(cs, "shortname", "unit_test_tls", T_OP_EQ, T_BARE_WORD, T_DOUBLE_QUOTED_STRING));
555 MEM(cf_pair_alloc(cs, "nas_type", "test", T_OP_EQ, T_BARE_WORD, T_DOUBLE_QUOTED_STRING));
556
557 client = client_afrom_cs(ctx, cs, NULL, 0);
558 if (!client) {
559 PERROR("Failed creating the client for %s", buffer);
560 talloc_free(cs);
561 return NULL;
562 }
563
564 /*
565 * The client has to outlive the section it was built from,
566 * because %request.client() reads the section.
567 */
568 talloc_steal(client, cs);
569
570 return client;
571}
572
573/** Build the request the handshake runs under
574 *
575 * The TLS code reads the control list for TLS-Session-Cert-File and
576 * TLS-Session-Require-Client-Certificate, and writes the negotiated version
577 * and cipher suite into the session-state list, so a real request is needed.
578 */
579static request_t *tls_request_alloc(TALLOC_CTX *ctx, int fd)
580{
581 request_t *request;
582 struct sockaddr_storage sa;
583 socklen_t salen;
584
585 static uint64_t number = 0;
586
587 request = request_local_alloc_internal(ctx, NULL);
588 if (!request) return NULL;
589
590 if (!request->packet) request->packet = fr_packet_alloc(request, false);
591 if (!request->reply) request->reply = fr_packet_alloc(request, false);
592
593 request->packet->timestamp = fr_time();
594
595 request->packet->socket.type = SOCK_STREAM;
596 request->packet->socket.fd = fd;
597
598 salen = sizeof(sa);
599 if (getpeername(fd, (struct sockaddr *) &sa, &salen) == 0) {
600 (void) fr_ipaddr_from_sockaddr(&request->packet->socket.inet.src_ipaddr,
601 &request->packet->socket.inet.src_port, &sa, salen);
602 request->packet->socket.af = request->packet->socket.inet.src_ipaddr.af;
603 }
604
605 salen = sizeof(sa);
606 if (getsockname(fd, (struct sockaddr *) &sa, &salen) == 0) {
607 (void) fr_ipaddr_from_sockaddr(&request->packet->socket.inet.dst_ipaddr,
608 &request->packet->socket.inet.dst_port, &sa, salen);
609 }
610
611 /*
612 * The client is the far end of the connection we just accepted.
613 */
614 request->client = tls_client_alloc(request, &request->packet->socket.inet.src_ipaddr);
615 if (!request->client) {
616 talloc_free(request);
617 return NULL;
618 }
619
620 request->number = number++;
621 request->name = talloc_typed_asprintf(request, "%" PRIu64, request->number);
622 request->master_state = REQUEST_ACTIVE;
623
624 request->log.dst = talloc_zero(request, log_dst_t);
625 request->log.dst->func = vlog_request;
626 request->log.dst->uctx = &default_log;
627 request->log.dst->lvl = fr_debug_lvl;
628
629 request->log.lvl = fr_debug_lvl;
630 request->async = talloc_zero(request, fr_async_t);
631 request->async->request = request;
632
633 if (fr_packet_pairs_from_packet(request->request_ctx, &request->request_pairs, request->packet) < 0) {
634 ERROR("Failed converting connection addresses to attributes");
635 talloc_free(request);
636 return NULL;
637 }
638
639 return request;
640}
641
642/** Add the connection to the event loop, and get it moving
643 *
644 * Runs from inside the event loop, see tls_connection_run().
645 */
646static void _tls_connection_start(fr_event_list_t *el, void *uctx)
647{
648 unit_test_tls_t *utt = talloc_get_type_abort(uctx, unit_test_tls_t);
649
650 /*
651 * Nothing polls. A handshake round starts when a record arrives,
652 * and a yielded round resumes when the interpreter marks the
653 * request runnable.
654 */
655 if (fr_event_fd_insert(utt, &utt->ef, el, utt->fd, _tls_connection_read, NULL, _tls_connection_error, utt) < 0) {
656 PERROR("Failed adding the connection to the event loop");
658 return;
659 }
660
661 /*
662 * Run `new session { ... }` and, for a client, `load session`.
663 * A server then waits for the ClientHello. A client has to send
664 * it.
665 */
666 fr_tls_connection_wake(utt->conn);
667}
668
669/** Run one connection from the first byte to the last
670 *
671 * Everything which belongs to a single connection is allocated here and freed
672 * again at the end, so that the next connection starts clean. What survives
673 * is what the cache needs: the interpreter, the modules, and so the sessions
674 * a policy stored.
675 */
677{
678 int ret = -1;
679 fr_event_user_t *ev = NULL;
680 request_t *stale;
681
682 utt->connections++;
683
684 utt->conn->state = TLS_CONNECTION_NEW_SESSION;
685 utt->conn->pending = utt->conn->failed = utt->conn->idle = false;
686 utt->conn->request = NULL;
687 utt->conn->tls_session = NULL;
688
689 utt->done = false;
690 utt->ret = EXIT_SUCCESS;
691 utt->fd = -1;
692 utt->ef = NULL;
693
694 /*
695 * Get a connection, one way or the other.
696 */
697 if (utt->conn->client) {
698 if (tls_socket_connect(utt) < 0) return -1;
699 } else {
700 INFO("Waiting for a connection");
701
702 utt->fd = accept(utt->sockfd, NULL, NULL);
703 if (utt->fd < 0) {
704 ERROR("Failed accepting connection: %s", fr_syserror(errno));
705 return -1;
706 }
707 }
708
709 utt->conn->request = tls_request_alloc(utt, utt->fd);
710 if (!utt->conn->request) goto finish;
711
712 unlang_interpret_set(utt->conn->request, utt->intp);
713
714 /*
715 * Both roles run the same handshake driver. Passing the request
716 * to fr_tls_session_alloc_client() is what gives a client the
717 * memory BIOs and the certificate validation callback which the
718 * driver needs, see src/lib/tls/session.c.
719 */
720 if (utt->conn->client) {
721 utt->conn->tls_session = fr_tls_session_alloc_client(utt->conn->request, utt->ssl_ctx, utt->conn->request);
722 } else {
723 INFO("Accepted connection from %pV",
724 fr_box_ipaddr(utt->conn->request->packet->socket.inet.src_ipaddr));
725
726 utt->conn->tls_session = fr_tls_session_alloc_server(utt->conn->request, utt->ssl_ctx, utt->conn->request,
728 }
729
730 if (!utt->conn->tls_session) {
731 PERROR("Failed creating the TLS session");
732 goto finish;
733 }
734
735 /*
736 * Start the request with a new session, then run the
737 * interpreter once so that the first frame yields.
738 * unlang_interpret_mark_runnable() acts only on a
739 * yielded frame.
740 */
741 if (fr_tls_connection_push(utt->conn) < 0) {
742 PERROR("Failed starting new TLS connection");
743 goto finish;
744 }
745
746 (void) unlang_interpret(utt->conn->request, UNLANG_REQUEST_RESUME);
747
748 if (fr_event_post_insert(utt->el, _tls_runnable, utt) < 0) {
749 PERROR("Failed adding the runnable handler to the event loop");
750 goto finish;
751 }
752
753 /*
754 * The connection is started from inside the event loop rather
755 * than here. Ending the previous connection left the loop
756 * flagged as exiting, and fr_event_fd_insert() refuses to add a
757 * socket to a loop in that state. fr_event_loop() clears the
758 * flag as it starts, so a user event which fires immediately is
759 * the first point at which the socket can be added.
760 */
761 if (fr_event_user_insert(utt, utt->el, &ev, true, _tls_connection_start, utt) < 0) {
762 PERROR("Failed scheduling the start of the connection");
763 goto finish;
764 }
765
766 (void) fr_event_loop(utt->el);
767
768 ret = 0;
769
770finish:
771 if (utt->ef) {
772 (void) fr_event_fd_delete(utt->el, utt->fd, FR_EVENT_FILTER_IO);
773 utt->ef = NULL;
774 }
775 (void) fr_event_post_delete(utt->el, _tls_runnable, utt);
776
777 /*
778 * The connection frame is still yielded, so cancel the request to
779 * unwind the stack before the request is freed.
780 */
781 if (utt->conn->request) unlang_interpret_signal(utt->conn->request, FR_SIGNAL_CANCEL);
782
783 /*
784 * Empty the heap before the requests on it are freed. Popping
785 * clears each entry's index, so nothing is left pointing at
786 * memory the request pool is about to hand out again.
787 */
788 while (fr_heap_pop((void **)&stale, &utt->runnable) == 0) {
789 if (!stale) break;
790 }
791 utt->yielded = 0;
792
793 TALLOC_FREE(utt->conn->tls_session);
794 TALLOC_FREE(utt->conn->request);
795
796 if (utt->fd >= 0) {
797 close(utt->fd);
798 utt->fd = -1;
799 }
800
801 return ret;
802}
803
804int main(int argc, char *argv[])
805{
806 int ret = EXIT_SUCCESS;
807 int c;
808 char const *receipt_file = NULL;
809 char const *server = NULL;
810 unsigned int count = 1;
811 bool alert = false;
812 bool reject = false;
813 unsigned int i;
814
815 TALLOC_CTX *autofree;
816 TALLOC_CTX *thread_ctx;
817
818 char *p;
820
821 fr_dict_t *dict = NULL;
822 fr_dict_t const *dict_check;
823
824 virtual_server_t const *vs;
825 CONF_SECTION *tls_cs;
826 CONF_SECTION *utt_cs;
827
828 unit_test_tls_t *utt = NULL;
829
830 /*
831 * Must be called first, so the handler is called last
832 */
834
836 thread_ctx = talloc_new(autofree);
837
839 if (!config) {
840 fr_perror("unit_test_tls");
841 fr_exit_now(EXIT_FAILURE);
842 }
843
844 p = strrchr(argv[0], FR_DIR_SEP);
845 if (!p) {
846 main_config_name_set_default(config, argv[0], false);
847 } else {
849 }
850
852
853 if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0], PANIC_ACTION_SIGNALS) < 0) {
854 fr_perror("%s", config->name);
855 fr_exit_now(EXIT_FAILURE);
856 }
857#ifdef NDEBUG
859#endif
860
861 fr_debug_lvl = 0;
863
864 /*
865 * The tests should have only IPs, not host names.
866 */
868
869 /*
870 * We always log to stdout.
871 */
873 default_log.fd = STDOUT_FILENO;
875
876 /* Process the options. */
877 while ((c = getopt(argc, argv, "Ac:Cd:D:hMn:r:Rs:xX")) != -1) {
878 switch (c) {
879 case 'A':
880 alert = true;
881 break;
882
883 case 'R':
884 reject = true;
885 break;
886
887 case 'c':
888 count = (unsigned int) atoi(optarg);
889 if (!count) {
890 fprintf(stderr, "Invalid value \"%s\" for -c\n", optarg);
891 fr_exit_now(EXIT_FAILURE);
892 }
893 break;
894
895 case 'C':
896 check_config = true;
897 break;
898
899 case 'd':
901 break;
902
903 case 'D':
905 break;
906
907 case 'h':
908 usage(config, EXIT_SUCCESS);
909 break;
910
911 case 'M':
912 talloc_enable_leak_report();
913 break;
914
915 case 'n':
916 config->name = optarg;
917 break;
918
919 case 'r':
920 receipt_file = optarg;
921 break;
922
923 case 's':
924 server = optarg;
925 break;
926
927 case 'X':
928 fr_debug_lvl += 2;
930 break;
931
932 case 'x':
933 fr_debug_lvl++;
934 if (fr_debug_lvl > 2) default_log.print_level = true;
935 break;
936
937 default:
938 usage(config, EXIT_FAILURE);
939 break;
940 }
941 }
942
943 if (receipt_file && (fr_unlink(receipt_file) < 0)) {
944 fr_perror("%s", config->name);
946 }
947
948 /*
949 * A mismatch between the OpenSSL headers used at build time and the
950 * linked OpenSSL library makes this program exit now, rather than
951 * crash later.
952 */
954
955 /*
956 * fr_openssl_init() must be called before *ANY* OpenSSL functions are
957 * used, which is why
958 * fr_openssl_init() is called so early.
959 */
960 if (fr_openssl_init() < 0) EXIT_WITH_FAILURE;
961
963
964 /*
965 * Mismatch between the binary and the libraries it links against
966 */
968 fr_perror("%s", config->name);
970 }
971
972 /*
973 * Initialise the dynamic loader infrastructure, which the config
974 * file parser uses.
975 */
976 modules_init(config->lib_dir);
977
978 if (!fr_dict_global_ctx_init(NULL, true, config->dict_dir)) {
979 fr_perror("%s", config->name);
981 }
982
984 fr_perror("%s", config->name);
986 }
987
988 if (fr_tls_dict_init() < 0) EXIT_WITH_FAILURE;
989
990 /*
991 * Load the custom dictionary
992 */
993 if (fr_dict_read(dict, config->confdir, FR_DICTIONARY_FILE) == -1) {
994 PERROR("Failed to initialize the dictionaries");
996 }
997
999 fr_perror("%s", config->name);
1001 }
1002
1003 if (request_global_init() < 0) {
1004 fr_perror("%s", config->name);
1006 }
1007
1008 /*
1009 * The triggers are run-time expansions, so the triggers need the
1010 * main event loop.
1011 */
1012 if (main_loop_init() < 0) {
1013 PERROR("Failed initialising main event loop");
1015 }
1016
1017 if (unlang_global_init() < 0) {
1018 fr_perror("%s", config->name);
1020 }
1021
1022 if (modules_rlm_init() < 0) {
1023 fr_perror("%s", config->name);
1025 }
1026
1027 if (virtual_servers_init() < 0) {
1028 fr_perror("%s", config->name);
1030 }
1031
1033
1034 MEM(utt = talloc_zero(autofree, unit_test_tls_t));
1035 utt->sockfd = utt->fd = -1;
1036 utt->ret = EXIT_SUCCESS;
1037 utt->count = count;
1038 utt->alert = alert;
1039 utt->reject = reject;
1040
1041 /*
1042 * `utt` is the argument both callbacks take, so the state
1043 * machine stops the event loop and writes to the socket
1044 * without reading any field of `utt`. See fr_tls_connection_t
1045 * for why the two callbacks exist.
1046 */
1047 MEM(utt->conn = talloc_zero(utt, fr_tls_connection_t));
1048 utt->conn->uctx = utt;
1049 utt->conn->finished = tls_request_finished;
1050 utt->conn->write = tls_connection_write;
1051
1052 /*
1053 * The settings which steer the test program, and which are
1054 * nothing to do with TLS.
1055 *
1056 * These are parsed before server_init(), so that a mistake in
1057 * them is reported before the modules and virtual servers are
1058 * brought up. The "tls" section cannot be parsed this early,
1059 * see below.
1060 */
1061 utt_cs = cf_section_find(config->root_cs, "unit_test_tls", NULL);
1062 if (!utt_cs) {
1063 ERROR("Cannot find a top-level 'unit_test_tls { ... }' section in %s.conf", config->name);
1065 }
1066
1068
1069 if (cf_section_parse(utt, &utt->conf, utt_cs) < 0) {
1070 cf_log_perr(utt_cs, "Failed parsing the 'unit_test_tls' section");
1072 }
1073
1074 /*
1075 * -s turns the program around: instead of listening for a
1076 * connection, it makes one.
1077 */
1078 if (server) {
1079 utt->conn->client = true;
1080
1081 if (fr_inet_pton_port(&utt->server_ipaddr, &utt->server_port, server,
1082 -1, AF_UNSPEC, true, false) < 0) {
1083 PERROR("Invalid value \"%s\" for -s", server);
1085 }
1086
1087 /*
1088 * fr_inet_pton_port() clears the port before it starts,
1089 * so a missing port is zero here, and not the default.
1090 */
1091 if (!utt->server_port) utt->server_port = utt->conf.port;
1092
1093 if (!utt->server_port) {
1094 ERROR("No port given in -s, and no 'port' in the 'unit_test_tls' section");
1096 }
1097 }
1098
1099 /*
1100 * Bootstrap and instantiate the virtual servers and the modules
1101 * the virtual servers use. The "tls" section names a virtual
1102 * server, so server_init() has to run before that section is
1103 * parsed.
1104 */
1105 if (server_init(config->root_cs, config->confdir, dict) < 0) EXIT_WITH_FAILURE;
1106
1107 vs = virtual_server_find("tls");
1108 if (!vs) {
1109 ERROR("Cannot find virtual server 'tls'");
1111 }
1112
1113 dict_check = virtual_server_dict_by_name("tls");
1114 if (!dict_check || !fr_dict_compatible(dict_check, dict_tls)) {
1115 ERROR("Virtual server 'tls' must have 'namespace = tls'");
1117 }
1118
1119 /*
1120 * The TLS configuration is a top-level section, not part of a
1121 * "listen" section. A "listen" section would need a transport
1122 * and a proto_tls module, and there is no proto_tls.
1123 *
1124 * This has to run after server_init(). The "virtual_server"
1125 * item in the section is resolved by virtual_server_cf_parse(),
1126 * which needs the virtual servers to exist already.
1127 */
1128 if (utt->conn->client) {
1129 tls_cs = cf_section_find(config->root_cs, "tls", "client");
1130 if (!tls_cs) {
1131 ERROR("Cannot find a top-level 'tls client { ... }' section in %s.conf",
1132 config->name);
1134 }
1135
1136 utt->conn->tls_conf = fr_tls_conf_parse_client(tls_cs);
1137 } else {
1138 /*
1139 * Prefer 'tls server', so that one file can hold the
1140 * configuration for both roles. Fall back to a plain
1141 * 'tls' section, which is what a file with only a
1142 * server in it will have.
1143 */
1144 tls_cs = cf_section_find(config->root_cs, "tls", "server");
1145 if (!tls_cs) tls_cs = cf_section_find(config->root_cs, "tls", NULL);
1146 if (!tls_cs) {
1147 ERROR("Cannot find a top-level 'tls server { ... }' or 'tls { ... }' section in %s.conf",
1148 config->name);
1150 }
1151
1152 utt->conn->tls_conf = fr_tls_conf_parse_server(tls_cs);
1153 }
1154
1155 if (!utt->conn->tls_conf) {
1156 cf_log_perr(tls_cs, "Failed parsing the TLS configuration");
1158 }
1159
1160 utt->ssl_ctx = fr_tls_ctx_alloc(utt->conn->tls_conf, utt->conn->client);
1161 if (!utt->ssl_ctx) {
1162 cf_log_perr(tls_cs, "Failed creating the TLS context");
1164 }
1165
1166 /*
1167 * The configuration parsed without error, so exit with success.
1168 */
1169 if (check_config) {
1170 DEBUG("Configuration appears to be OK");
1171 goto cleanup;
1172 }
1173
1174 utt->el = main_loop_event_list();
1175 fr_assert(utt->el != NULL);
1176
1178
1179 /*
1180 * Simulate thread-specific instantiation
1181 */
1183 if (fr_thread_instantiate(thread_ctx, utt->el) < 0) {
1184 fr_perror("%s", config->name);
1186 }
1187
1188 if (modules_rlm_coord_attach(utt->el) < 0) {
1189 fr_perror("%s", config->name);
1191 }
1192
1193 if (fr_coord_pre_event_insert(utt->el) < 0) {
1194 fr_strerror_const("Failed adding coordinator pre-check to event list");
1196 }
1197
1198 if (fr_coord_post_event_insert(utt->el) < 0) {
1199 fr_strerror_const("Failed adding coordinator post-check to event list");
1201 }
1202
1203 /*
1204 * Set the panic action (if required)
1205 */
1206 {
1207 char const *panic_action = NULL;
1208
1209 panic_action = getenv("PANIC_ACTION");
1210 if (!panic_action) panic_action = config->panic_action;
1211
1213 fr_perror("%s", config->name);
1215 }
1216 }
1217
1218 setlinebuf(stdout); /* line buffered output */
1219
1220 /*
1221 * One interpreter, one runnable heap and one request for the
1222 * whole connection. The unit_test_tls_t documentation says why.
1223 */
1224 MEM(utt->runnable = fr_heap_talloc_alloc(utt, fr_pointer_cmp, request_t, runnable, 0));
1225
1226 utt->intp = unlang_interpret_init(utt, utt->el,
1228 .init_internal = _request_init_internal,
1229
1230 .done_external = _request_done_external,
1231 .done_internal = _request_done_internal,
1232 .done_detached = _request_done_detached,
1233
1234 .detach = _request_detach,
1235 .yield = _request_yield,
1236 .resume = _request_resume,
1237 .mark_runnable = _request_runnable,
1238 .scheduled = _request_scheduled,
1239 }, utt);
1240 if (!utt->intp) {
1241 fr_perror("%s", config->name);
1243 }
1244
1245 /*
1246 * Subrequests created by the TLS code inherit the thread default,
1247 * so the thread default has to point at the connection's
1248 * interpreter.
1249 */
1251
1252 /*
1253 * A server has one listening socket for every connection it
1254 * accepts, so it is opened once, here.
1255 */
1256 if (!utt->conn->client && (tls_socket_open(utt) < 0)) EXIT_WITH_FAILURE;
1257
1258 for (i = 0; i < utt->count; i++) {
1260
1261 if (utt->ret != EXIT_SUCCESS) break;
1262 }
1263
1264 ret = utt->ret;
1265
1266cleanup:
1267 if (utt) {
1268 /*
1269 * tls_connection_run() cleans up everything which belongs
1270 * to one connection. What is left here is what outlives
1271 * them.
1272 */
1273 if (utt->ssl_ctx) SSL_CTX_free(utt->ssl_ctx);
1274
1275 if (utt->sockfd >= 0) close(utt->sockfd);
1276 }
1277
1279
1280 /*
1281 * Detach from coordinators.
1282 */
1283 if (utt && utt->el && (modules_rlm_coord_detach() > 0)) {
1284 if (unlikely(fr_coord_close_event_insert(utt->el) < 0)) {
1285 ERROR("Failed setting up coordinator close events");
1286 }
1287 fr_event_loop(utt->el);
1288 }
1289
1290 /*
1291 * Free thread data
1292 */
1293 talloc_free(thread_ctx);
1294
1296
1298
1299 if (utt && utt->el) fr_event_list_reap_signal(utt->el, fr_time_delta_from_sec(5), SIGKILL);
1300
1302
1304
1305 server_free();
1306
1307 /*
1308 * Virtual servers need to be freed before modules
1309 * as state entries containing data with module-specific
1310 * destructors may exist.
1311 */
1313
1315
1317
1318 fr_tls_dict_free();
1319
1321
1322 if (fr_dict_free(&dict, __FILE__) < 0) {
1323 fr_perror("unit_test_tls - dict");
1324 ret = EXIT_FAILURE;
1325 }
1326
1327 fr_openssl_free();
1328
1329 if (receipt_file && (ret == EXIT_SUCCESS) && (fr_touch(NULL, receipt_file, 0644, true, 0755) <= 0)) {
1330 fr_perror("unit_test_tls");
1331 ret = EXIT_FAILURE;
1332 }
1333
1334 if (talloc_free(autofree) < 0) {
1335 fr_perror("unit_test_tls - autofree");
1336 ret = EXIT_FAILURE;
1337 }
1338
1339 /*
1340 * Ensure our atexit handlers run before any other
1341 * atexit handlers registered by third party libraries.
1342 */
1344
1345 return ret;
1346}
1347
1348/*
1349 * Display the syntax for starting this program.
1350 */
1351static NEVER_RETURNS void usage(main_config_t const *config, int status)
1352{
1353 FILE *output = status ? stderr : stdout;
1354
1355 fprintf(output, "Usage: %s [options]\n", config->name);
1356 fprintf(output, "Options:\n");
1357 fprintf(output, " -A Reject the peer with a fatal TLS alert on the last connection,\n");
1358 fprintf(output, " rather than completing the handshake. With -c 2 the first\n");
1359 fprintf(output, " connection fills the session cache, so the alert then has a\n");
1360 fprintf(output, " session to clear. Used to test the alert and clear paths.\n");
1361 fprintf(output, " -R Reject the session once the handshake has succeeded on the last\n");
1362 fprintf(output, " connection, as policy would. The cached session is then cleared\n");
1363 fprintf(output, " rather than stored. With -c 2 the first connection fills the\n");
1364 fprintf(output, " cache and the second resumes from it before being rejected, so\n");
1365 fprintf(output, " the clear then has a loaded session to remove.\n");
1366 fprintf(output, " -c <count> Run <count> connections, one after another. Session resumption\n");
1367 fprintf(output, " needs two: one to fill the cache, one to resume from it.\n");
1368 fprintf(output, " -C Check configuration and exit.\n");
1369 fprintf(output, " -d <confdir> Configuration file directory. (defaults to " CONFDIR ").\n");
1370 fprintf(output, " -D <dict_dir> Dictionary files are in \"dict_dir/*\".\n");
1371 fprintf(output, " -h Print this help message.\n");
1372 fprintf(output, " -M Enable talloc leak reporting.\n");
1373 fprintf(output, " -n <name> Read ${confdir}/name.conf instead of ${confdir}/unit_test_tls.conf.\n");
1374 fprintf(output, " -r <receipt_file> Create <receipt_file> when the program exits successfully.\n");
1375 fprintf(output, " -s <server[:port]> Connect to <server> as a TLS client, instead of listening\n");
1376 fprintf(output, " for a connection. Reads the 'tls client' section. The port\n");
1377 fprintf(output, " defaults to 'port' from the 'unit_test_tls' section.\n");
1378 fprintf(output, " -X Turn on full debugging.\n");
1379 fprintf(output, " -x Turn on additional debugging. (-xx gives more debugging).\n");
1380
1381 fr_exit_now(status);
1382}
static int const char char buffer[256]
Definition acutest.h:576
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
Definition atexit.c:179
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
Definition atexit.c:310
#define fr_atexit_thread_trigger_all(...)
Definition atexit.h:236
#define RCSID(id)
Definition build.h:560
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:382
#define unlikely(_x)
Definition build.h:455
#define UNUSED
Definition build.h:384
bool check_config
Definition cf_file.c:61
int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs)
Parse a configuration section into user-supplied variables.
Definition cf_parse.c:1288
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:673
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:280
#define cf_section_rules_push(_cs, _rule)
Definition cf_parse.h:705
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:238
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:610
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
Allocate a CONF_PAIR.
Definition cf_util.c:1445
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1205
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:350
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition cf_util.h:201
TALLOC_CTX * autofree
Definition common.c:29
fr_dict_t * dict
Definition common.c:31
int fr_coords_create(TALLOC_CTX *ctx, fr_event_list_t *el)
Start coordinators in single threaded mode.
Definition coord.c:621
void fr_coords_destroy(void)
Clean up coordinators in single threaded mode.
Definition coord.c:603
int fr_coord_close_event_insert(fr_event_list_t *el)
Definition coord.c:905
int fr_coord_post_event_insert(fr_event_list_t *el)
Insert instance specific post-event callbacks.
Definition coord.c:861
int fr_coord_pre_event_insert(fr_event_list_t *el)
Insert instance specific pre-event callbacks.
Definition coord.c:836
#define fr_dbuff_advance(_dbuff_or_marker, _len)
Advance 'current' position in dbuff or marker by _len bytes.
Definition dbuff.h:1112
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:954
#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:786
static char panic_action[512]
The command to execute when panicking.
Definition debug.c:66
void fr_disable_null_tracking_on_free(TALLOC_CTX *ctx)
Disable the null tracking context when a talloc chunk is freed.
Definition debug.c:1034
void fr_talloc_fault_setup(void)
Register talloc fault handlers.
Definition debug.c:1050
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program, unsigned long fault_signals)
Registers signal handlers to execute panic_action on fatal signal.
Definition debug.c:1074
#define PANIC_ACTION_SIGNALS
Definition debug.h:133
#define MEM(x)
Definition debug.h:38
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:272
void dependency_version_print(void)
Definition dependency.c:364
#define ERROR(fmt,...)
Definition dhcpclient.c:40
static int sockfd
Definition dhcpclient.c:55
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
static NEVER_RETURNS void usage(void)
Definition dhcpclient.c:113
#define fr_dict_autofree(_to_free)
Definition dict.h:937
int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir, char const *dependent))
(Re-)Initialize the special internal dictionary
bool fr_dict_compatible(fr_dict_t const *dict1, fr_dict_t const *dict2)
See if two dictionaries have the same end parent.
Definition dict_util.c:2951
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:329
int fr_dict_read(fr_dict_t *dict, char const *dict_dir, char const *filename))
Read supplementary attribute definitions into an existing dictionary.
int fr_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition dict_util.c:4466
#define fr_dict_autoload(_to_load)
Definition dict.h:934
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:335
fr_dict_gctx_t * fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir))
Initialise the global protocol hashes.
Definition dict_util.c:4850
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:328
#define fr_event_fd_insert(...)
Definition event.h:247
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:83
#define fr_event_user_insert(_ctx, _el, _ev_p, _trigger, _callback, _uctx)
Definition event.h:281
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
Definition heap.c:149
int fr_heap_pop(void **out, fr_heap_t **hp)
Remove a node from the heap.
Definition heap.c:359
static bool fr_heap_entry_inserted(fr_heap_index_t heap_idx)
Check if an entry is inserted into a heap.
Definition heap.h:126
#define fr_heap_talloc_alloc(_ctx, _cmp, _talloc_type, _field, _init)
Creates a heap that verifies elements are of a specific talloc type.
Definition heap.h:117
The main heap structure.
Definition heap.h:68
talloc_free(hp)
int fr_ipaddr_from_sockaddr(fr_ipaddr_t *ipaddr, uint16_t *port, struct sockaddr_storage const *sa, socklen_t salen)
Convert sockaddr to our internal ip address representation.
Definition inet.c:1448
bool fr_hostname_lookups
hostname -> IP lookups?
Definition inet.c:52
int fr_inet_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Parses IPv4/6 address + port, to fr_ipaddr_t and integer (port)
Definition inet.c:944
char * fr_inet_ntop(char out[static FR_IPADDR_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
Print the address portion of a fr_ipaddr_t.
Definition inet.c:1025
bool fr_reverse_lookups
IP -> hostname lookups?
Definition inet.c:51
#define FR_IPADDR_STRLEN
Like INET6_ADDRSTRLEN but includes space for the textual Zone ID.
Definition inet.h:89
int af
Address family.
Definition inet.h:64
IPv4/6 prefix.
rlm_rcode_t unlang_interpret(request_t *request, bool running)
Run the interpreter for a current request.
Definition interpret.c:1302
void unlang_interpret_set(request_t *request, unlang_interpret_t *intp)
Set a specific interpreter for a request.
Definition interpret.c:2519
void unlang_interpret_set_thread_default(unlang_interpret_t *intp)
Set the default interpreter for this thread.
Definition interpret.c:2550
unlang_interpret_t * unlang_interpret_init(TALLOC_CTX *ctx, fr_event_list_t *el, unlang_request_func_t *funcs, void *uctx)
Initialize a unlang compiler / interpret.
Definition interpret.c:2478
void unlang_interpret_signal(request_t *request, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition interpret.c:1789
#define UNLANG_REQUEST_RESUME
Definition interpret.h:48
External functions provided by the owner of the interpret.
Definition interpret.h:116
int server_init(CONF_SECTION *cs, char const *conf_dir, fr_dict_t *dict)
Initialize src/lib/server/.
Definition base.c:42
void server_free(void)
Free src/lib/server/.
Definition base.c:137
Describes a host allowed to send packets to the server.
Definition client.h:80
void vlog_request(fr_log_type_t type, fr_log_lvl_t lvl, request_t *request, char const *file, int line, char const *fmt, va_list ap, void *uctx)
Send a log message to its destination, possibly including fields from the request.
Definition log.c:293
#define PERROR(_fmt,...)
Definition log.h:233
#define DEBUG3(_fmt,...)
Definition log.h:271
#define RDEBUG3(fmt,...)
Definition log.h:360
#define RPEDEBUG(fmt,...)
Definition log.h:393
Definition log.h:70
int fr_packet_pairs_from_packet(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_packet_t const *packet)
Allocate a "Net." struct with src/dst host and port.
Definition packet.c:91
int unlang_global_init(void)
Definition base.c:158
int fr_event_post_delete(fr_event_list_t *el, fr_event_post_cb_t callback, void *uctx)
Delete a post-event callback from the event list.
Definition event.c:2051
#define fr_time()
Definition event.c:60
unsigned int fr_event_list_reap_signal(fr_event_list_t *el, fr_time_delta_t timeout, int signal)
Send a signal to all the processes we have in our reap list, and reap them.
Definition event.c:1717
void fr_event_loop_exit(fr_event_list_t *el, int code)
Signal an event loop exit with the specified code.
Definition event.c:2383
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
Definition event.c:1203
int fr_event_loop(fr_event_list_t *el)
Run an event loop.
Definition event.c:2405
int fr_event_post_insert(fr_event_list_t *el, fr_event_post_cb_t callback, void *uctx)
Add a post-event callback to the event list.
Definition event.c:2028
A file descriptor/filter event.
Definition event.c:260
Stores all information relating to an event list.
Definition event.c:377
Callbacks for kevent() user events.
Definition event.c:341
int fr_unlink(char const *filename)
Remove a regular file from the filesystem.
Definition file.c:366
ssize_t fr_touch(int *fd_out, char const *filename, mode_t mode, bool mkdir, mode_t dir_mode)
Create an empty file.
Definition file.c:322
int fr_debug_lvl
Definition log.c:41
fr_log_t default_log
Definition log.c:308
@ L_DST_STDOUT
Log to stdout.
Definition log.h:75
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
Definition packet.c:38
Minimal data structure to use the new code.
Definition listen.h:63
int main_config_free(main_config_t **config)
main_config_t * main_config_alloc(TALLOC_CTX *ctx)
Allocate a main_config_t struct, setting defaults.
void main_config_name_set_default(main_config_t *config, char const *name, bool overwrite_config)
Set the server name.
int main_config_init(main_config_t *config)
void main_config_confdir_set(main_config_t *config, char const *name)
Set the global radius config directory.
void main_config_dict_dir_set(main_config_t *config, char const *name)
Set the global dictionary directory.
Main server configuration.
Definition main_config.h:59
fr_event_list_t * main_loop_event_list(void)
Return the main loop event list.
Definition main_loop.c:173
int main_loop_init(void)
Initialise the main event loop, setting up signal handlers.
Definition main_loop.c:262
void main_loop_free(void)
Definition main_loop.c:198
unsigned short uint16_t
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
long int ssize_t
unsigned char uint8_t
fr_cmp_ret_t fr_pointer_cmp(void const *a, void const *b)
Compares two pointers.
Definition misc.c:449
int modules_rlm_coord_attach(fr_event_list_t *el)
Runs the coord_attach method of all registered backend modules.
Definition module_rlm.c:992
int modules_rlm_free(void)
Cleanup all global structures.
int modules_rlm_coord_detach(void)
Runs the coord_detach method of all registered backend modules.
Definition module_rlm.c:999
int modules_rlm_init(void)
Initialise the module list structure.
static const conf_parser_t config[]
Definition base.c:162
#define fr_assert(_expr)
Definition rad_assert.h:37
#define INFO(fmt,...)
Definition radict.c:63
static bool cleanup
Definition radsniff.c:59
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:44
int request_global_init(void)
Definition request.c:598
int request_detach(request_t *child)
Unlink a subrequest from its parent.
Definition request.c:544
#define request_local_alloc_internal(_ctx, _args)
Allocate a new internal request outside of the request pool.
Definition request.h:344
@ REQUEST_ACTIVE
Request is active (running or runnable)
Definition request.h:89
void fr_schedule_worker_id_set(int id)
Explicitly set the worker id for the current thread.
Definition schedule.c:120
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
int fr_socket_server_tcp(fr_ipaddr_t const *src_ipaddr, uint16_t *src_port, char const *port_name, bool async)
Open an IPv4/IPv6 TCP socket.
Definition socket.c:945
int fr_socket_client_tcp(char const *ifname, fr_ipaddr_t *src_ipaddr, fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async)
Establish a connected TCP socket.
Definition socket.c:708
int fr_socket_bind(int sockfd, char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port)
Bind a UDP/TCP v4/v6 socket to a given ipaddr src port, and interface.
Definition socket.c:200
fr_client_t * client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *server_cs, size_t extra)
Allocate a new client from a config section.
Definition client.c:736
void modules_init(char const *lib_dir)
Perform global initialisation for modules.
Definition module.c:1981
return count
Definition module.c:155
fr_log_dst_t dst
Log destination.
Definition log.h:94
int fd
File descriptor to write messages to.
Definition log.h:109
bool print_level
sometimes we don't want log levels printed
Definition log.h:103
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition talloc.c:546
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:55
int fr_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
Instantiate thread-specific data for modules, virtual servers, xlats, unlang, and TLS.
Definition thread.c:165
int fr_time_start(void)
Initialize the local time.
Definition time.c:157
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
"server local" time.
Definition time.h:69
int fr_openssl_version_consistent(void)
Definition version.c:246
@ T_BARE_WORD
Definition token.h:118
@ T_OP_EQ
Definition token.h:81
@ T_DOUBLE_QUOTED_STRING
Definition token.h:119
static char const * receipt_file
static fr_event_list_t * el
static void _request_yield(request_t *request, void *uctx)
unsigned int count
How many connections to run.
static void _request_done_external(request_t *request, UNUSED rlm_rcode_t rcode, UNUSED void *uctx)
int main(int argc, char *argv[])
static void _tls_runnable(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
Drain the runnable heap once per pass of the event loop.
unit_test_tls_conf_t conf
Parsed "unit_test_tls" section.
static void _request_resume(request_t *request, UNUSED void *uctx)
SSL_CTX * ssl_ctx
Context built from the "tls" section.
static void tls_request_finished(void *uctx, fr_tls_connection_t *conn)
Stop the event loop, recording why.
bool alert
Reject the peer with a TLS alert, see -A.
uint16_t port
Port of the listening socket, and the default port for -s.
static void _request_runnable(request_t *request, void *uctx)
static fr_client_t * tls_client_alloc(TALLOC_CTX *ctx, fr_ipaddr_t const *ipaddr)
Build an internal client.
static void _request_done_internal(request_t *request, UNUSED rlm_rcode_t rcode, UNUSED void *uctx)
int fd
Accepted or connected socket.
fr_event_list_t * el
Event list everything runs on.
static bool _request_scheduled(request_t const *request, UNUSED void *uctx)
static void _tls_connection_read(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
A record arrived on the connection, so hand the record to the connection.
static fr_dict_t const * dict_freeradius
static fr_dict_t const * dict_tls
static void tls_request_failed(unit_test_tls_t *utt)
Record a failure this program cannot recover from, and stop.
static void tls_runnable_insert(unit_test_tls_t *utt, request_t *request)
Schedule a request, once.
static void _request_detach(request_t *request, UNUSED void *uctx)
int yielded
How many requests are currently yielded.
fr_tls_connection_t * conn
State of the connection being run.
static void _tls_connection_start(fr_event_list_t *el, void *uctx)
Add the connection to the event loop, and get it moving.
static int tls_connection_write(void *uctx, fr_tls_connection_t *conn)
Write whatever OpenSSL has produced out to the connection.
bool require_client_certificate
Whether the client has to present a certificate.
fr_ipaddr_t ipaddr
Address of the listening socket. Server mode only.
fr_ipaddr_t server_ipaddr
Server named by -s.
static int tls_socket_connect(unit_test_tls_t *utt)
Connect to the server named by -s.
fr_dict_autoload_t unit_test_tls_dict[]
bool reject
Reject the session once the handshake succeeds, see -R.
int ret
Exit status.
char const * radiusd_version
unlang_interpret_t * intp
Interpreter for the connection.
static void _tls_connection_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
The connection failed at the socket level.
fr_event_fd_t * ef
Read event for fd.
fr_heap_t * runnable
Requests the interpreter has marked runnable.
#define EXIT_WITH_FAILURE
static int tls_socket_open(unit_test_tls_t *utt)
Open the listening socket described by the "unit_test_tls" section.
int sockfd
Listening socket.
static request_t * tls_request_alloc(TALLOC_CTX *ctx, int fd)
Build the request the handshake runs under.
unsigned int connections
How many connections have been run so far.
static void _request_done_detached(request_t *request, UNUSED rlm_rcode_t rcode, UNUSED void *uctx)
bool done
Set once the connection has a result.
static const conf_parser_t unit_test_tls_config[]
static void _request_init_internal(request_t *request, void *uctx)
An internal request created by the interpreter has to run on ours.
static int tls_connection_run(unit_test_tls_t *utt)
Run one connection from the first byte to the last.
uint16_t server_port
Port from -s, or from the configuration.
The "unit_test_tls" section.
State of the test program.
#define FR_DICTIONARY_FILE
Definition conf.h:6
#define FR_DICTIONARY_INTERNAL_DIR
Definition conf.h:7
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:737
#define fr_strerror_const(_msg)
Definition strerror.h:223
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition version.c:40
#define RADIUSD_VERSION_BUILD(_x)
Create a version string for a utility in the suite of FreeRADIUS utilities.
Definition version.h:58
#define RADIUSD_MAGIC_NUMBER
Definition version.h:81
#define fr_box_ipaddr(_val)
Definition value.h:342
fr_dict_t const * virtual_server_dict_by_name(char const *virtual_server)
Return the namespace for the named virtual server.
virtual_server_t const * virtual_server_find(char const *name)
Return virtual server matching the specified name.
int virtual_servers_init(void)
Performs global initialisation for the virtual server code.
int virtual_servers_free(void)