The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
radclient-ng.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: 8be4f61b752a38f44c59b428a66fe8945ed65347 $
19 *
20 * @file src/bin/radclient.c
21 * @brief General radius client and debug tool.
22 *
23 * @copyright 2000,2006,2014 The FreeRADIUS server project
24 * @copyright 2000 Miquel van Smoorenburg (miquels@cistron.nl)
25 * @copyright 2000 Alan DeKok (aland@freeradius.org)
26 */
27
28RCSID("$Id: 8be4f61b752a38f44c59b428a66fe8945ed65347 $")
29
30#include <freeradius-devel/util/conf.h>
31#include <freeradius-devel/util/syserror.h>
32#include <freeradius-devel/util/atexit.h>
33#include <freeradius-devel/util/pair_legacy.h>
34#include <freeradius-devel/util/time.h>
35#include <freeradius-devel/util/event.h>
36#include <freeradius-devel/server/packet.h>
37#include <freeradius-devel/radius/list.h>
38#include <freeradius-devel/radius/radius.h>
39#include <freeradius-devel/util/chap.h>
40#include <freeradius-devel/radius/client.h>
41
42#ifdef HAVE_OPENSSL_SSL_H
43#include <openssl/ssl.h>
44#endif
45#include <ctype.h>
46
47#ifdef HAVE_GETOPT_H
48# include <getopt.h>
49#endif
50
51#include <assert.h>
52
53typedef struct request_s request_t; /* to shut up warnings about mschap.h */
54
55#include "smbdes.h"
56#include "mschap.h"
57
58#include "radclient.h"
59
60#define pair_update_request(_attr, _da) do { \
61 _attr = fr_pair_find_by_da(&request->request_pairs, NULL, _da); \
62 if (!_attr) { \
63 _attr = fr_pair_afrom_da(request, _da); \
64 fr_assert(_attr != NULL); \
65 fr_pair_append(&request->request_pairs, _attr); \
66 } \
67 } while (0)
68
69static char *secret = NULL;
70static bool do_output = true;
71
72static const char *attr_coa_filter_name = "User-Name";
73
75
77static int resend_count = 1;
78static bool print_filename = false;
79
80static int forced_id = -1;
81static size_t parallel = 1;
82static bool paused = false;
83
85
87
89
91
92static int ipproto = IPPROTO_UDP;
93
94static bool do_coa = false;
95//static int coafd;
97static fr_rb_tree_t *coa_tree = NULL;
98
100static rc_request_t *current = NULL;
101
102static char const *radclient_version = RADIUSD_VERSION_BUILD("radclient");
103
105static fr_dict_t const *dict_radius;
106
107static TALLOC_CTX *autofree = NULL;
108
111 { .out = &dict_freeradius, .proto = "freeradius" },
112 { .out = &dict_radius, .proto = "radius" },
113 { NULL }
114};
115
117
121
124
130
133
134static fr_dict_attr_t const *attr_coa_filter = NULL;
135
138 { .out = &attr_cleartext_password, .name = "Password.Cleartext", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
139 { .out = &attr_ms_chap_challenge, .name = "Vendor-Specific.Microsoft.CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
140 { .out = &attr_ms_chap_password, .name = "Password.MS-CHAP", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
141 { .out = &attr_ms_chap_response, .name = "Vendor-Specific.Microsoft.CHAP-Response", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
142
143 { .out = &attr_radclient_test_name, .name = "Radclient-Test-Name", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
144 { .out = &attr_request_authenticator, .name = "Request-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
145
146 { .out = &attr_radclient_coa_filename, .name = "Radclient-CoA-Filename", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
147 { .out = &attr_radclient_coa_filter, .name = "Radclient-CoA-Filter", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
148
149 { .out = &attr_chap_password, .name = "CHAP-Password", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
150 { .out = &attr_chap_challenge, .name = "CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
151 { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
152 { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
153 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
154
155 { NULL }
156};
157
158static NEVER_RETURNS void usage(void)
159{
160 fprintf(stderr, "Usage: radclient [options] server[:port] <command> [<secret>]\n");
161
162 fprintf(stderr, " <command> One of auth, acct, status, coa, disconnect or auto.\n");
163 fprintf(stderr, " -4 Use IPv4 address of server\n");
164 fprintf(stderr, " -6 Use IPv6 address of server.\n");
165 fprintf(stderr, " -A <attribute> Use named 'attribute' to match CoA requests to packets. Default is User-Name\n");
166 fprintf(stderr, " -C [<client_ip>:]<client_port> Client source port and source IP address. Port values may be 1..65535\n");
167 fprintf(stderr, " -c <count> Send each packet 'count' times.\n");
168 fprintf(stderr, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
169 fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
170 fprintf(stderr, " -f <file>[:<file>] Read packets from file, not stdin.\n");
171 fprintf(stderr, " If a second file is provided, it will be used to verify responses\n");
172 fprintf(stderr, " -F Print the file name, packet number and reply code.\n");
173 fprintf(stderr, " -h Print usage help information.\n");
174 fprintf(stderr, " -i <id> Set request id to 'id'. Values may be 0..255\n");
175 fprintf(stderr, " -o <port> Set CoA listening port (defaults to 3799)\n");
176 fprintf(stderr, " -p <num> Send 'num' packets from a file in parallel.\n");
177 fprintf(stderr, " -P <proto> Use proto (tcp or udp) for transport.\n");
178 fprintf(stderr, " -r <retries> If timeout, retry sending the packet 'retries' times.\n");
179 fprintf(stderr, " -s Print out summary information of auth results.\n");
180 fprintf(stderr, " -S <file> read secret from file, not command line.\n");
181 fprintf(stderr, " -t <timeout> Wait 'timeout' seconds before retrying (may be a floating point number).\n");
182 fprintf(stderr, " -v Show program version information.\n");
183 fprintf(stderr, " -x Debugging mode.\n");
184
185 fr_exit_now(EXIT_SUCCESS);
186}
187
188/*
189 * Free a radclient struct, which may (or may not)
190 * already be in the list.
191 */
192static int _rc_request_free(rc_request_t *request)
193{
195
196 if (do_coa) {
197 (void) fr_rb_delete(coa_tree, &request->node);
198 // @todo - cancel incoming CoA packet/
199 }
200
201 if (request->packet && (request->packet->id >= 0)) {
203 }
204
205 return 0;
206}
207
208#ifdef HAVE_OPENSSL_SSL_H
209#include <openssl/provider.h>
210
211static OSSL_PROVIDER *openssl_default_provider = NULL;
212static OSSL_PROVIDER *openssl_legacy_provider = NULL;
213
214static int openssl3_init(void)
215{
216 /*
217 * Load the default provider for most algorithms
218 */
219 openssl_default_provider = OSSL_PROVIDER_load(NULL, "default");
220 if (!openssl_default_provider) {
221 ERROR("(TLS) Failed loading default provider");
222 return -1;
223 }
224
225 /*
226 * Needed for MD4
227 *
228 * https://www.openssl.org/docs/man3.0/man7/migration_guide.html#Legacy-Algorithms
229 */
230 openssl_legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
231 if (!openssl_legacy_provider) {
232 ERROR("(TLS) Failed loading legacy provider");
233 return -1;
234 }
235
236 return 0;
237}
238
239static void openssl3_free(void)
240{
241 if (openssl_default_provider && !OSSL_PROVIDER_unload(openssl_default_provider)) {
242 ERROR("Failed unloading default provider");
243 }
244 openssl_default_provider = NULL;
245
246 if (openssl_legacy_provider && !OSSL_PROVIDER_unload(openssl_legacy_provider)) {
247 ERROR("Failed unloading legacy provider");
248 }
249 openssl_legacy_provider = NULL;
250}
251#else
252#define openssl3_init()
253#define openssl3_free()
254#endif
255
256static int _loop_status(UNUSED fr_time_t now, fr_time_delta_t wake, UNUSED void *ctx)
257{
258 if (fr_time_delta_unwrap(wake) < (NSEC / 10)) return 0;
259
260 if (fr_dlist_num_elements(&rc_request_list) != 0) return 0;
261
262 fr_log(&default_log, L_DBG, __FILE__, __LINE__, "Main loop waking up in %pV seconds", fr_box_time_delta(wake));
263
264 return 0;
265}
266
268 char const *password)
269{
270 unsigned int i;
271 uint8_t *p;
272 fr_pair_t *challenge, *reply;
273 uint8_t nthash[16];
274
277
279
280 fr_pair_append(list, challenge);
281
282 MEM(p = talloc_array(challenge, uint8_t, 8));
283 fr_pair_value_memdup_buffer_shallow(challenge, p, false);
284
285 for (i = 0; i < challenge->vp_length; i++) {
286 p[i] = fr_rand();
287 }
288
290 fr_pair_append(list, reply);
291 p = talloc_zero_array(reply, uint8_t, 50); /* really reply->da->flags.length */
293
294 p[1] = 0x01; /* NT hash */
295
296 if (mschap_nt_password_hash(nthash, password) < 0) return 0;
297
298 smbdes_mschap(nthash, challenge->vp_octets, p + 26);
299 return 1;
300}
301
302
303static int getport(char const *name)
304{
305 struct servent *svp;
306
307 svp = getservbyname(name, "udp");
308 if (!svp) return 0;
309
310 return ntohs(svp->s_port);
311}
312
313/*
314 * Set a port from the request type if we don't already have one
315 */
317{
318 switch (type) {
319 default:
323 if (*port == 0) *port = getport("radius");
324 if (*port == 0) *port = FR_AUTH_UDP_PORT;
325 return;
326
328 if (*port == 0) *port = getport("radacct");
329 if (*port == 0) *port = FR_ACCT_UDP_PORT;
330 return;
331
333 if (*port == 0) *port = FR_POD_UDP_PORT;
334 return;
335
337 if (*port == 0) *port = FR_COA_UDP_PORT;
338 return;
339
341 if (*port == 0) *port = 0;
342 return;
343 }
344}
345
346/*
347 * Resolve a port to a request type
348 */
350{
351 /*
352 * getport returns 0 if the service doesn't exist
353 * so we need to return early, to avoid incorrect
354 * codes.
355 */
356 if (port == 0) return FR_RADIUS_CODE_UNDEFINED;
357
358 if ((port == getport("radius")) || (port == FR_AUTH_UDP_PORT) || (port == FR_AUTH_UDP_PORT_ALT)) {
360 }
361 if ((port == getport("radacct")) || (port == FR_ACCT_UDP_PORT) || (port == FR_ACCT_UDP_PORT_ALT)) {
363 }
365
367}
368
369
371{
372 size_t i;
373
374 if (!vp || (vp->vp_type != FR_TYPE_OCTETS)) return true;
375
376 /*
377 * If it's 17 octets, it *might* be already encoded.
378 * Or, it might just be a 17-character password (maybe UTF-8)
379 * Check it for non-printable characters. The odds of ALL
380 * of the characters being 32..255 is (1-7/8)^17, or (1/8)^17,
381 * or 1/(2^51), which is pretty much zero.
382 */
383 for (i = 0; i < vp->vp_length; i++) {
384 if (vp->vp_octets[i] < 32) {
385 return true;
386 }
387 }
388
389 return false;
390}
391
392/*
393 * Read one CoA reply and possibly filter
394 */
395static int coa_init(rc_request_t *parent, FILE *coa_reply, char const *reply_filename, bool *coa_reply_done, FILE *coa_filter, char const *filter_filename, bool *coa_filter_done)
396{
397 rc_request_t *request;
398 fr_pair_t *vp;
399
400 /*
401 * Allocate it.
402 */
403 MEM(request = talloc_zero(parent, rc_request_t));
404 MEM(request->reply = fr_packet_alloc(request, false));
405
406 /*
407 * Don't initialize src/dst IP/port, or anything else. That will be read from the network.
408 */
409 fr_pair_list_init(&request->filter);
412
413 /*
414 * Read the reply VP's.
415 */
417 &request->reply_pairs, coa_reply, coa_reply_done) < 0) {
418 REDEBUG("Error parsing \"%s\"", reply_filename);
419 error:
420 talloc_free(request);
421 return -1;
422 }
423
424 /*
425 * The reply can be empty. In which case we just send an empty ACK.
426 */
428 if (vp) request->reply->code = vp->vp_uint32;
429
430 /*
431 * Read in filter VP's.
432 */
433 if (coa_filter) {
435 &request->filter, coa_filter, coa_filter_done) < 0) {
436 REDEBUG("Error parsing \"%s\"", filter_filename);
437 goto error;
438 }
439
440 if (*coa_filter_done && !*coa_reply_done) {
441 REDEBUG("Differing number of replies/filters in %s:%s "
442 "(too many replies))", reply_filename, filter_filename);
443 goto error;
444 }
445
446 if (!*coa_filter_done && *coa_reply_done) {
447 REDEBUG("Differing number of replies/filters in %s:%s "
448 "(too many filters))", reply_filename, filter_filename);
449 goto error;
450 }
451
452 /*
453 * This allows efficient list comparisons later
454 */
456 }
457
458 request->name = parent->name;
459
460 /*
461 * Automatically set the response code from the request code
462 * (if one wasn't already set).
463 */
464 if (request->filter_code == FR_RADIUS_CODE_UNDEFINED) {
466 }
467
468 parent->coa = request;
469
470 /*
471 * Ensure that the packet is also tracked in the CoA tree.
472 */
475 ERROR("Failed inserting packet from %s into CoA tree", request->name);
476 fr_exit_now(EXIT_FAILURE);
477 }
478
479 return 0;
480}
481
482/*
483 * Initialize a radclient data structure and add it to
484 * the global linked list.
485 */
486static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files)
487{
488 FILE *packets, *filters = NULL;
489
490 fr_pair_t *vp;
491 rc_request_t *request = NULL;
492 bool packets_done = false;
493 uint64_t num = 0;
494
495 FILE *coa_reply = NULL;
496 FILE *coa_filter = NULL;
497 bool coa_reply_done = false;
498 bool coa_filter_done = false;
499
500 fr_assert(files->packets != NULL);
501
502 /*
503 * Determine where to read the VP's from.
504 */
505 if (strcmp(files->packets, "-") != 0) {
506 packets = fopen(files->packets, "r");
507 if (!packets) {
508 ERROR("Error opening %s: %s", files->packets, fr_syserror(errno));
509 return -1;
510 }
511
512 /*
513 * Read in the pairs representing the expected response.
514 */
515 if (files->filters) {
516 filters = fopen(files->filters, "r");
517 if (!filters) {
518 ERROR("Error opening %s: %s", files->filters, fr_syserror(errno));
519 goto error;
520 }
521 }
522
523 if (files->coa_reply) {
524 coa_reply = fopen(files->coa_reply, "r");
525 if (!coa_reply) {
526 ERROR("Error opening %s: %s", files->coa_reply, fr_syserror(errno));
527 goto error;
528 }
529 }
530
531 if (files->coa_filter) {
532 coa_filter = fopen(files->coa_filter, "r");
533 if (!coa_filter) {
534 ERROR("Error opening %s: %s", files->coa_filter, fr_syserror(errno));
535 goto error;
536 }
537 }
538 } else {
539 packets = stdin;
540 }
541
542 /*
543 * Loop until the file is done.
544 */
545 do {
546 char const *coa_reply_filename = NULL;
547 char const *coa_filter_filename = NULL;
548
549 /*
550 * Allocate it.
551 */
552 MEM(request = talloc_zero(ctx, rc_request_t));
553 MEM(request->packet = fr_packet_alloc(request, true));
554 request->packet->uctx = request;
555
556 /*
557 * Don't set request->packet->socket. The underlying socket isn't open yet.
558 */
559
560 request->files = files;
561 request->packet->id = -1;
562 request->num = num++;
563
564 fr_pair_list_init(&request->filter);
567
568 /*
569 * Read the request VP's.
570 */
572 &request->request_pairs, packets, &packets_done) < 0) {
573 char const *input;
574
575 if ((files->packets[0] == '-') && (files->packets[1] == '\0')) {
576 input = "stdin";
577 } else {
578 input = files->packets;
579 }
580
581 REDEBUG("Error parsing \"%s\"", input);
582 goto error;
583 }
584
585 /*
586 * Skip empty entries
587 */
588 if (fr_pair_list_empty(&request->request_pairs)) {
589 WARN("Skipping \"%s\": No Attributes", files->packets);
590 talloc_free(request);
591 continue;
592 }
593
594 /*
595 * Read in filter VP's.
596 */
597 if (filters) {
598 bool filters_done;
599
601 &request->filter, filters, &filters_done) < 0) {
602 REDEBUG("Error parsing \"%s\"", files->filters);
603 goto error;
604 }
605
606 if (filters_done && !packets_done) {
607 REDEBUG("Differing number of packets/filters in %s:%s "
608 "(too many requests))", files->packets, files->filters);
609 goto error;
610 }
611
612 if (!filters_done && packets_done) {
613 REDEBUG("Differing number of packets/filters in %s:%s "
614 "(too many filters))", files->packets, files->filters);
615 goto error;
616 }
617
618 vp = fr_pair_find_by_da(&request->filter, NULL, attr_packet_type);
619 if (vp) {
620 request->filter_code = vp->vp_uint32;
621 fr_pair_delete(&request->filter, vp);
622 }
623
624 /*
625 * This allows efficient list comparisons later
626 */
628 }
629
630 /*
631 * Process special attributes
632 */
633 for (vp = fr_pair_list_head(&request->request_pairs);
634 vp;
635 vp = fr_pair_list_next(&request->request_pairs, vp)) {
636 /*
637 * Allow it to set the packet type in
638 * the attributes read from the file.
639 */
640 if (vp->da == attr_packet_type) {
641 request->packet->code = vp->vp_uint32;
642 } else if (vp->da == attr_request_authenticator) {
643 if (vp->vp_length > sizeof(request->packet->vector)) {
644 memcpy(request->packet->vector, vp->vp_octets, sizeof(request->packet->vector));
645 } else {
646 memset(request->packet->vector, 0, sizeof(request->packet->vector));
647 memcpy(request->packet->vector, vp->vp_octets, vp->vp_length);
648 }
649 } else if (vp->da == attr_cleartext_password) {
650 request->password = vp;
651 /*
652 * Keep a copy of the the password attribute.
653 */
654 } else if (vp->da == attr_chap_password) {
655 /*
656 * If it's already hex, do nothing.
657 */
658 if ((vp->vp_length == 17) && (already_hex(vp))) continue;
659
660 /*
661 * CHAP-Password is octets, so it may not be zero terminated.
662 */
664 fr_pair_value_bstrndup(request->password, vp->vp_strvalue, vp->vp_length, true);
665 } else if ((vp->da == attr_user_password) ||
668 fr_pair_value_bstrndup(request->password, vp->vp_strvalue, vp->vp_length, true);
669
670 } else if (vp->da == attr_radclient_test_name) {
671 request->name = vp->vp_strvalue;
672
673 } else if (vp->da == attr_radclient_coa_filename) {
674 coa_reply_filename = vp->vp_strvalue;
675
676 } else if (vp->da == attr_radclient_coa_filter) {
677 coa_filter_filename = vp->vp_strvalue;
678 }
679 } /* loop over the VP's we read in */
680
681 /*
682 * Use the default set on the command line
683 */
684 if (request->packet->code == FR_RADIUS_CODE_UNDEFINED) request->packet->code = packet_code;
685
686 /*
687 * Fill in the packet header from attributes, and then
688 * re-realize the attributes.
689 */
690 fr_packet_net_from_pairs(request->packet, &request->request_pairs);
691
692 /*
693 * Default to the filename
694 */
695 if (!request->name) request->name = request->files->packets;
696
697 /*
698 * Automatically set the response code from the request code
699 * (if one wasn't already set).
700 */
701 if (request->filter_code == FR_RADIUS_CODE_UNDEFINED) {
702 switch (request->packet->code) {
705 break;
706
709 break;
710
713 break;
714
717 break;
718
721 break;
722
724 REDEBUG("Packet-Type must be defined,"
725 "or a well known RADIUS port");
726 goto error;
727
728 default:
729 REDEBUG("Can't determine expected &reply.Packet-Type for Packet-Type %i",
730 request->packet->code);
731 goto error;
732 }
733 /*
734 * Automatically set the request code from the response code
735 * (if one wasn't already set).
736 */
737 } else if (request->packet->code == FR_RADIUS_CODE_UNDEFINED) {
738 switch (request->filter_code) {
742 break;
743
746 break;
747
751 break;
752
756 break;
757
758 default:
759 REDEBUG("Can't determine expected Packet-Type for &reply.Packet-Type %i",
760 request->filter_code);
761 goto error;
762 }
763 }
764
765 /*
766 * Automatically set the dst port (if one wasn't already set).
767 */
768 radclient_get_port(request->packet->code, &request->packet->socket.inet.dst_port);
769 if (request->packet->socket.inet.dst_port == 0) {
770 REDEBUG("Can't determine destination port");
771 goto error;
772 }
773
774 /*
775 * We expect different responses for Status-Server, depending on which port is being used.
776 */
777 if (request->packet->code == FR_RADIUS_CODE_STATUS_SERVER) {
778 switch (radclient_get_code(request->packet->socket.inet.dst_port)) {
781 break;
782
785 break;
786
787 default:
789 break;
790 }
791 }
792
793 /*
794 * Read in the CoA filename and filter.
795 */
796 if (coa_reply_filename) {
797 if (coa_reply) {
798 RDEBUG("Cannot specify CoA file on both the command line and via Radclient-CoA-Filename");
799 goto error;
800 }
801
802 coa_reply = fopen(coa_reply_filename, "r");
803 if (!coa_reply) {
804 ERROR("Error opening %s: %s", coa_reply_filename, fr_syserror(errno));
805 goto error;
806 }
807
808 if (coa_filter_filename) {
809 coa_filter = fopen(coa_filter_filename, "r");
810 if (!coa_filter) {
811 ERROR("Error opening %s: %s", coa_filter_filename, fr_syserror(errno));
812 goto error;
813 }
814 } else {
815 coa_filter = NULL;
816 }
817
818 if (coa_init(request, coa_reply, coa_reply_filename, &coa_reply_done,
819 coa_filter, coa_filter_filename, &coa_filter_done) < 0) {
820 goto error;
821 }
822
823 fclose(coa_reply);
824 coa_reply = NULL;
825 if (coa_filter) {
826 fclose(coa_filter);
827 coa_filter = NULL;
828 }
829 do_coa = true;
830
831 } else if (coa_reply) {
832 if (coa_init(request, coa_reply, coa_reply_filename, &coa_reply_done,
833 coa_filter, coa_filter_filename, &coa_filter_done) < 0) {
834 goto error;
835 }
836
837 if (coa_reply_done != packets_done) {
838 REDEBUG("Differing number of packets in input file and coa_reply in %s:%s ",
839 files->packets, files->coa_reply);
840 goto error;
841
842 }
843 }
844
845 /*
846 * Add it to the tail of the list.
847 */
849
850 /*
851 * Set the destructor so it removes itself from the
852 * request list when freed. We don't set this until
853 * the packet is actually in the list, else we trigger
854 * the asserts in the free callback.
855 */
856 talloc_set_destructor(request, _rc_request_free);
857 } while (!packets_done); /* loop until the file is done. */
858
859 if (packets != stdin) fclose(packets);
860 if (filters) fclose(filters);
861 if (coa_reply) fclose(coa_reply);
862 if (coa_filter) fclose(coa_filter);
863
864 /*
865 * And we're done.
866 */
867 return 0;
868
869error:
870 talloc_free(request);
871
872 if (packets != stdin) fclose(packets);
873 if (filters) fclose(filters);
874 if (coa_reply) fclose(coa_reply);
875 if (coa_filter) fclose(coa_filter);
876
877 return -1;
878}
879
880
881/*
882 * Sanity check each argument.
883 */
884static int radclient_sane(rc_request_t *request)
885{
886 request->packet->socket.inet.src_ipaddr = client_info->fd_info->socket.inet.src_ipaddr;
887 request->packet->socket.inet.src_port = client_info->fd_info->socket.inet.src_port;
888 request->packet->socket.inet.ifindex = client_info->fd_info->socket.inet.ifindex;
889
890 if (request->packet->socket.inet.dst_port == 0) {
891 request->packet->socket.inet.dst_port = fd_config.dst_port;
892 }
893
894 if (request->packet->socket.inet.dst_ipaddr.af == AF_UNSPEC) {
895 if (fd_config.dst_ipaddr.af == AF_UNSPEC) {
896 ERROR("No server was given, and request %" PRIu64 " in file %s did not contain "
897 "Packet-Dst-IP-Address", request->num, request->files->packets);
898 return -1;
899 }
900 request->packet->socket.inet.dst_ipaddr = fd_config.dst_ipaddr;
901 }
902
903 if (request->packet->code == 0) {
904 if (packet_code == -1) {
905 ERROR("Request was \"auto\", and request %" PRIu64 " in file %s did not contain Packet-Type",
906 request->num, request->files->packets);
907 return -1;
908 }
909 request->packet->code = packet_code;
910 }
911
912 request->packet->socket.fd = -1;
913
914 return 0;
915}
916
917
918static int8_t request_cmp(void const *one, void const *two)
919{
920 rc_request_t const *a = one, *b = two;
921 fr_pair_t *vp1, *vp2;
922
924 vp2 = fr_pair_find_by_da(&b->request_pairs, NULL, attr_coa_filter);
925
926 if (!vp1) return -1;
927 if (!vp2) return +1;
928
929 return fr_value_box_cmp(&vp1->data, &vp2->data);
930}
931
932static void cleanup(fr_bio_packet_t *client, rc_request_t *request)
933{
934 /*
935 * Don't leave a dangling pointer around.
936 */
937 if (current == request) {
939 }
940
941 talloc_free(request);
942
943 /*
944 * There are more packets to send, then allow the writer to send them.
945 */
947 return;
948 }
949
950 /*
951 * We're done all packets, and there's nothing more to read, stop.
952 */
953 if (fr_radius_client_bio_outstanding(client) == 0) {
955
957 }
958}
959
961{
962 rc_request_t *request = packet->uctx;
963
964 DEBUG("Timeout - resending packet");
965
966 // @todo - log the updated Acct-Delay-Time from the packet?
967
968 fr_radius_packet_log(&default_log, request->packet, &request->request_pairs, false);
969}
970
972{
973 rc_request_t *request = packet->uctx;
974
975 ERROR("No reply to packet");
976
977 cleanup(client, request);
978}
979
980
981/*
982 * Send one packet.
983 */
984static int send_one_packet(fr_bio_packet_t *client, rc_request_t *request)
985{
986 int rcode;
987
988 fr_assert(!request->done);
989 fr_assert(request->reply == NULL);
990
991#ifdef STATIC_ANALYZER
992 if (!secret) fr_exit_now(EXIT_FAILURE);
993#endif
994
995 fr_assert(request->packet->id < 0);
996 fr_assert(request->packet->data == NULL);
997
998 /*
999 * Update the password, so it can be encrypted with the
1000 * new authentication vector.
1001 */
1002 if (request->password) {
1003 fr_pair_t *vp;
1004
1005 if ((vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_password)) != NULL) {
1006 fr_pair_value_strdup(vp, request->password->vp_strvalue, false);
1007
1008 } else if ((vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_chap_password)) != NULL) {
1009 uint8_t buffer[17];
1010 fr_pair_t *challenge;
1011 uint8_t const *vector;
1012
1013 /*
1014 * Use Chap-Challenge pair if present,
1015 * Request Authenticator otherwise.
1016 */
1017 challenge = fr_pair_find_by_da(&request->request_pairs, NULL, attr_chap_challenge);
1018 if (challenge && (challenge->vp_length == RADIUS_AUTH_VECTOR_LENGTH)) {
1019 vector = challenge->vp_octets;
1020 } else {
1021 vector = request->packet->vector;
1022 }
1023
1025 fr_rand() & 0xff, vector, RADIUS_AUTH_VECTOR_LENGTH,
1026 request->password->vp_strvalue,
1027 request->password->vp_length);
1028 fr_pair_value_memdup(vp, buffer, sizeof(buffer), false);
1029
1030 } else if (fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_ms_chap_password) != NULL) {
1031 mschapv1_encode(request->packet, &request->request_pairs, request->password->vp_strvalue);
1032
1033 } else {
1034 DEBUG("WARNING: No password in the request");
1035 }
1036 }
1037
1038 request->timestamp = fr_time();
1039 request->tries = 1;
1040
1041 /*
1042 * Ensure that each Access-Request is unique.
1043 */
1044 if (request->packet->code == FR_RADIUS_CODE_ACCESS_REQUEST) {
1045 fr_rand_buffer(request->packet->vector, sizeof(request->packet->vector));
1046 }
1047
1048 /*
1049 * Send the current packet.
1050 */
1051 rcode = fr_bio_packet_write(client, request, request->packet, &request->request_pairs);
1052 if (rcode < 0) {
1053 /*
1054 * Failed writing it. Try again later.
1055 */
1056 if (rcode == fr_bio_error(IO_WOULD_BLOCK)) return 0;
1057
1058 REDEBUG("Failed writing packet - %s", fr_strerror());
1059 return -1;
1060 }
1061
1062 fr_radius_packet_log(&default_log, request->packet, &request->request_pairs, false);
1063
1064 return 0;
1065}
1066
1069 { 0 }
1070};
1071
1074 { 0 }
1075};
1076
1077
1079{
1081
1083 return fr_bio_error(GENERIC);
1084 }
1085
1086 return 0;
1087}
1088
1090{
1092
1094 return fr_bio_error(GENERIC);
1095 }
1096
1097 return 1;
1098}
1099
1100
1102{
1103 ERROR("Failed connecting to server");
1104
1105 /*
1106 * Cleanly close the BIO, so that we exercise the shutdown path.
1107 */
1108 fr_assert(bio == client_bio);
1109 TALLOC_FREE(bio);
1110
1111 fr_exit_now(EXIT_FAILURE);
1112}
1113
1114
1116 int fd_errno, void *uctx)
1117{
1118 fr_bio_packet_t *client = uctx;
1119
1120 ERROR("Failed in connection - %s", fr_syserror(fd_errno));
1121
1122 /*
1123 * Cleanly close the BIO, so that we exercise the shutdown path.
1124 */
1125 fr_assert(client == client_bio);
1126 TALLOC_FREE(client);
1127
1128 fr_exit_now(EXIT_FAILURE);
1129}
1130
1131static void client_read(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
1132{
1133 fr_bio_packet_t *client = uctx;
1134 rc_request_t *request;
1136 fr_packet_t *reply;
1137 int rcode;
1138
1140
1141 /*
1142 * Read one packet.
1143 */
1144 rcode = fr_bio_packet_read(client, (void **) &request, &reply, client, &reply_pairs);
1145 if (rcode < 0) {
1146 ERROR("Failed reading packet - %s", fr_bio_strerror(rcode));
1147 fr_exit_now(EXIT_FAILURE);
1148 }
1149
1150 /*
1151 * Not a RADIUS packet, or not a reply to a packet we sent.
1152 */
1153 if (!rcode) return;
1154
1156
1157 if (print_filename) {
1158 RDEBUG("%s response code %d", request->files->packets, reply->code);
1159 }
1160
1161 /*
1162 * Increment counters...
1163 */
1164 switch (reply->code) {
1169 stats.accepted++;
1170 break;
1171
1173 break;
1174
1175 default:
1176 stats.rejected++;
1177 }
1178
1179 fr_strerror_clear(); /* Clear strerror buffer */
1180
1181 /*
1182 * If we had an expected response code, check to see if the
1183 * packet matched that.
1184 */
1185 if ((request->filter_code != FR_RADIUS_CODE_UNDEFINED) && (reply->code != request->filter_code)) {
1186 if (FR_RADIUS_PACKET_CODE_VALID(reply->code)) {
1187 REDEBUG("%s: Expected %s got %s", request->name, fr_radius_packet_name[request->filter_code],
1188 fr_radius_packet_name[reply->code]);
1189 } else {
1190 REDEBUG("%s: Expected %u got %i", request->name, request->filter_code,
1191 reply->code);
1192 }
1193 stats.failed++;
1194 /*
1195 * Check if the contents of the packet matched the filter
1196 */
1197 } else if (fr_pair_list_empty(&request->filter)) {
1198 stats.passed++;
1199 } else {
1200 fr_pair_t const *failed[2];
1201
1203 if (fr_pair_validate(failed, &request->filter, &reply_pairs)) {
1204 RDEBUG("%s: Response passed filter", request->name);
1205 stats.passed++;
1206 } else {
1207 fr_pair_validate_debug(failed);
1208 REDEBUG("%s: Response for failed filter", request->name);
1209 stats.failed++;
1210 }
1211 }
1212
1213 /*
1214 * The retry bio takes care of suppressing duplicate replies.
1215 */
1216 if (paused) {
1218 fr_perror("radclient");
1219 fr_exit_now(EXIT_FAILURE);
1220 }
1221 paused = false;
1222 }
1223
1224 /*
1225 * If we're not done, then leave this packet in the list for future resending.
1226 */
1227 request->done = (request->resend >= resend_count);
1228 if (!request->done) {
1229 /*
1230 * We don't care about duplicate replies, they can go away.
1231 */
1232 (void) fr_radius_client_fd_bio_cancel(client, request->packet);
1233 request->packet->id = -1;
1234 TALLOC_FREE(request->packet->data);
1235 return;
1236 }
1237
1238 fr_packet_free(&reply);
1239
1240 cleanup(client, request);
1241}
1242
1243static void client_write(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
1244{
1245 fr_bio_packet_t *client = uctx;
1246 rc_request_t *request;
1247
1249 fr_assert(!paused);
1250
1251 if (!request) request = fr_dlist_head(&rc_request_list);
1252
1253 /*
1254 * Nothing more to send, stop trying to write packets.
1255 */
1256 if (!request) {
1257 pause:
1259 fr_perror("radclient");
1260 fr_exit_now(EXIT_FAILURE);
1261 }
1262 return;
1263 }
1264
1265 /*
1266 * No more packets to send, we pause the read.
1267 */
1268 if (request->packet->id >= 0) {
1269 paused = true;
1270 goto pause;
1271 }
1272
1273 if (send_one_packet(client, request) < 0) {
1274 fr_perror("radclient");
1275 fr_exit_now(EXIT_FAILURE);
1276 }
1277
1278 request->resend++;
1279 current = request;
1280
1281 /*
1282 * 0 means "don't limit requests".
1283 */
1285 paused = true;
1286 goto pause;
1287 }
1288}
1289
1291{
1292 fr_radius_client_bio_info_t const *info;
1293
1294 info = fr_radius_client_bio_info(client);
1295
1296 if (fr_event_fd_insert(autofree, NULL, info->retry_info->el, info->fd_info->socket.fd,
1297 client_read, client_write, client_error, client) < 0) {
1298 fr_perror("radclient");
1299 fr_exit_now(EXIT_FAILURE);
1300 }
1301}
1302
1303
1304/**
1305 *
1306 * @hidecallgraph
1307 */
1308int main(int argc, char **argv)
1309{
1310 int ret = EXIT_SUCCESS;
1311 int c;
1312 char const *raddb_dir = RADDBDIR;
1313 char const *dict_dir = DICTDIR;
1314 char *end;
1315 char filesecret[256];
1316 FILE *fp;
1317 int do_summary = false;
1318 fr_dlist_head_t filenames;
1319
1320 int retries = 5;
1322
1323 /*
1324 * It's easier having two sets of flags to set the
1325 * verbosity of library calls and the verbosity of
1326 * radclient.
1327 */
1328 fr_debug_lvl = 0;
1329 fr_log_fp = stdout;
1330
1331 /*
1332 * Must be called first, so the handler is called last
1333 */
1335
1336 fr_time_start();
1337
1339#ifndef NDEBUG
1340 if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
1341 fr_perror("radclient");
1342 fr_exit_now(EXIT_FAILURE);
1343 }
1344#endif
1345
1346#ifdef STATIC_ANALYZER
1347 /*
1348 * clang scan thinks that fr_fault_setup() will set autofree=NULL.
1349 */
1350 if (!autofree) fr_exit_now(EXIT_FAILURE);
1351#endif
1352
1353 talloc_set_log_stderr();
1354
1356
1357 fr_dlist_talloc_init(&filenames, rc_file_pair_t, entry);
1358
1359 /*
1360 * Always log to stdout
1361 */
1363 default_log.fd = STDOUT_FILENO;
1364 default_log.print_level = false;
1365
1366 /*
1367 * Initialize the kind of socket we want.
1368 */
1371 .socket_type = SOCK_DGRAM,
1372
1373 .src_ipaddr = (fr_ipaddr_t) {
1374 .af = AF_INET,
1375 },
1376 .dst_ipaddr = (fr_ipaddr_t) {
1377 .af = AF_INET,
1378 },
1379
1380 .src_port = 0,
1381 .dst_port = 1812,
1382
1383 .interface = NULL,
1384
1385 .path = NULL,
1386 .filename = NULL,
1387
1388 .async = true,
1389 };
1390
1391 /*
1392 * Initialize the client configuration.
1393 */
1395 .log = &default_log,
1396 .verify = {
1397 .require_message_authenticator = false,
1398 .max_attributes = RADIUS_MAX_ATTRIBUTES,
1399 .max_packet_size = 4096,
1400 },
1401 };
1402
1403 /***********************************************************************
1404 *
1405 * Parse command-line options.
1406 *
1407 ***********************************************************************/
1408
1409 while ((c = getopt(argc, argv, "46A:c:C:d:D:f:Fi:ho:p:P:r:sS:t:vx")) != -1) switch (c) {
1410 case '4':
1411 fd_config.dst_ipaddr.af = AF_INET;
1412 break;
1413
1414 case '6':
1415 fd_config.dst_ipaddr.af = AF_INET6;
1416 break;
1417
1418 case 'A':
1419 attr_coa_filter_name = optarg;
1420 break;
1421
1422 case 'c':
1423 if (!isdigit((uint8_t) *optarg)) usage();
1424
1425 resend_count = atoi(optarg);
1426
1427 if (resend_count < 1) usage();
1428 break;
1429
1430 case 'C':
1431 {
1432 int tmp;
1433
1434 if (strchr(optarg, ':')) {
1436 optarg, -1, AF_UNSPEC, true, false) < 0) {
1437 fr_perror("Failed parsing source address");
1438 fr_exit_now(EXIT_FAILURE);
1439 }
1440 break;
1441 }
1442
1443 tmp = atoi(optarg);
1444 if (tmp < 1 || tmp > 65535) usage();
1445
1447 }
1448 break;
1449
1450 case 'D':
1451 dict_dir = optarg;
1452 break;
1453
1454 case 'd':
1455 raddb_dir = optarg;
1456 break;
1457
1458 /*
1459 * packet,filter
1460 */
1461 case 'f':
1462 {
1463 char const *p;
1464 rc_file_pair_t *files;
1465
1466 MEM(files = talloc_zero(talloc_autofree_context(), rc_file_pair_t));
1467
1468 /*
1469 * Commas are nicer than colons.
1470 */
1471 c = ':';
1472
1473 p = strchr(optarg, c);
1474 if (!p) {
1475 c = ',';
1476 p = strchr(optarg, c);
1477 }
1478 if (!p) {
1479 files->packets = optarg;
1480 files->filters = NULL;
1481 } else {
1482 MEM(files->packets = talloc_strndup(files, optarg, p - optarg));
1483 files->filters = p + 1;
1484 }
1485 fr_dlist_insert_tail(&filenames, files);
1486 }
1487 break;
1488
1489 case 'F':
1490 print_filename = true;
1491 break;
1492
1493 case 'i':
1494 if (!isdigit((uint8_t) *optarg))
1495 usage();
1496 forced_id = atoi(optarg);
1497 if ((forced_id < 0) || (forced_id > 255)) {
1498 usage();
1499 }
1500 break;
1501
1502 case 'o':
1503 coa_port = atoi(optarg);
1504 if (!coa_port || (coa_port > 65535)) usage();
1505 break;
1506
1507 /*
1508 * Note that sending MANY requests in
1509 * parallel can over-run the kernel
1510 * queues, and Linux will happily discard
1511 * packets. So even if the server responds,
1512 * the client may not see the reply.
1513 */
1514 case 'p':
1515 parallel = strtoul(optarg, &end, 10);
1516 if (*end) usage();
1517 if (parallel > 65536) usage();
1518 break;
1519
1520 case 'P':
1521 if (!strcmp(optarg, "tcp")) {
1522 fd_config.socket_type = SOCK_STREAM;
1523 ipproto = IPPROTO_TCP;
1524 } else if (!strcmp(optarg, "udp")) {
1525 fd_config.socket_type = SOCK_DGRAM;
1526 ipproto = IPPROTO_UDP;
1527 } else {
1528 usage();
1529 }
1530 break;
1531
1532 case 'r':
1533 if (!isdigit((uint8_t) *optarg)) usage();
1534 retries = atoi(optarg);
1535 if ((retries == 0) || (retries > 1000)) usage();
1536 break;
1537
1538 case 's':
1539 do_summary = true;
1540 break;
1541
1542 case 'S':
1543 {
1544 char *p;
1545 fp = fopen(optarg, "r");
1546 if (!fp) {
1547 ERROR("Error opening %s: %s", optarg, fr_syserror(errno));
1548 fr_exit_now(EXIT_FAILURE);
1549 }
1550 if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
1551 ERROR("Error reading %s: %s", optarg, fr_syserror(errno));
1552 fr_exit_now(EXIT_FAILURE);
1553 }
1554 fclose(fp);
1555
1556 /* truncate newline */
1557 p = filesecret + strlen(filesecret) - 1;
1558 while ((p >= filesecret) &&
1559 (*p < ' ')) {
1560 *p = '\0';
1561 --p;
1562 }
1563
1564 if (strlen(filesecret) < 2) {
1565 ERROR("Secret in %s is too short", optarg);
1566 fr_exit_now(EXIT_FAILURE);
1567 }
1568 secret = talloc_strdup(autofree, filesecret);
1570 client_config.verify.secret_len = talloc_array_length(secret) - 1;
1571 }
1572 break;
1573
1574 case 't':
1575 if (fr_time_delta_from_str(&timeout, optarg, strlen(optarg), FR_TIME_RES_SEC) < 0) {
1576 fr_perror("Failed parsing timeout value");
1577 fr_exit_now(EXIT_FAILURE);
1578 }
1579 break;
1580
1581 case 'v':
1582 fr_debug_lvl = 1;
1583 DEBUG("%s", radclient_version);
1584 fr_exit_now(0);
1585
1586 case 'x':
1587 fr_debug_lvl++;
1588 if (fr_debug_lvl > 1) default_log.print_level = true;
1589 break;
1590
1591 case 'h':
1592 default:
1593 usage();
1594 }
1595 argc -= (optind - 1);
1596 argv += (optind - 1);
1597
1598 if ((argc < 3) || ((secret == NULL) && (argc < 4))) {
1599 ERROR("Insufficient arguments");
1600 usage();
1601 }
1602
1603 /*
1604 * Get the request type
1605 */
1606 if (!isdigit((uint8_t) argv[2][0])) {
1608 if (packet_code == -2) {
1609 ERROR("Unrecognised request type \"%s\"", argv[2]);
1610 usage();
1611 }
1612 } else {
1613 packet_code = atoi(argv[2]);
1614 }
1615
1616 fr_assert(packet_code != 0);
1618
1619 /*
1620 * Initialize the retry configuration for this type of packet.
1621 */
1624
1626 .irt = timeout,
1627 .mrt = fr_time_delta_from_sec(16),
1628 .mrd = (retries == 1) ? timeout : fr_time_delta_from_sec(30),
1629 .mrc = retries,
1630 };
1632
1633 /*
1634 * Resolve hostname.
1635 */
1636 if (strcmp(argv[1], "-") != 0) {
1637 if (fr_inet_pton_port(&fd_config.dst_ipaddr, &fd_config.dst_port, argv[1], -1, fd_config.dst_ipaddr.af, true, true) < 0) {
1638 fr_perror("radclient");
1639 fr_exit_now(EXIT_FAILURE);
1640 }
1641
1642 /*
1643 * Work backwards from the port to determine the packet type
1644 */
1646 }
1648
1649 /*
1650 * Add the secret.
1651 */
1652 if (argv[3]) {
1653 secret = talloc_strdup(autofree, argv[3]);
1655 client_config.verify.secret_len = talloc_array_length(secret) - 1;
1656 }
1657
1658 /***********************************************************************
1659 *
1660 * We're done parsing command-line options, bootstrap the various libraries, etc.
1661 *
1662 ***********************************************************************/
1663
1665 fr_perror("radclient");
1666 fr_exit_now(EXIT_FAILURE);
1667 }
1668
1669 if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) {
1670 fr_perror("radclient");
1671 fr_exit_now(EXIT_FAILURE);
1672 }
1673
1674 if (fr_radius_global_init() < 0) {
1675 fr_perror("radclient");
1676 fr_exit_now(EXIT_FAILURE);
1677 }
1678
1680 fr_perror("radclient");
1681 exit(EXIT_FAILURE);
1682 }
1683
1685 fr_perror("radclient");
1686 exit(EXIT_FAILURE);
1687 }
1688
1690 fr_log_perror(&default_log, L_ERR, __FILE__, __LINE__, NULL,
1691 "Failed to initialize the dictionaries");
1692 exit(EXIT_FAILURE);
1693 }
1694
1695 if (do_coa) {
1697 if (!attr_coa_filter) {
1698 ERROR("Unknown or invalid CoA filter attribute %s", optarg);
1699 fr_exit_now(EXIT_FAILURE);
1700 }
1701
1702 /*
1703 * If there's no attribute given to match CoA to requests, use User-Name
1704 */
1706
1708 }
1710
1711 openssl3_init();
1712
1714
1715 /***********************************************************************
1716 *
1717 * We're done bootstrapping the libraries and dictionaries, read the input files.
1718 *
1719 ***********************************************************************/
1720
1721 /*
1722 * If no '-f' is specified, then we are reading from stdin.
1723 */
1724 if (fr_dlist_num_elements(&filenames) == 0) {
1725 rc_file_pair_t *files;
1726
1727 files = talloc_zero(talloc_autofree_context(), rc_file_pair_t);
1728 files->packets = "-";
1729 if (radclient_init(files, files) < 0) fr_exit_now(EXIT_FAILURE);
1730 }
1731
1732 if ((forced_id >= 0) && (fr_dlist_num_elements(&filenames) > 1)) {
1733 usage();
1734 }
1735
1736 /*
1737 * Walk over the list of filenames, creating the requests.
1738 */
1739 fr_dlist_foreach(&filenames, rc_file_pair_t, files) {
1740 if (radclient_init(files, files)) {
1741 ERROR("Failed parsing input files");
1742 fr_exit_now(EXIT_FAILURE);
1743 }
1744 }
1745
1746 /*
1747 * No packets were read. Die.
1748 */
1750 ERROR("Nothing to send");
1751 fr_exit_now(EXIT_FAILURE);
1752 }
1753
1754 /***********************************************************************
1755 *
1756 * We're done reading files, open the socket, event loop, and start sending packets.
1757 *
1758 ***********************************************************************/
1759
1761 (fr_debug_lvl >= 2) ? _loop_status : NULL,
1762 NULL);
1763 if (!client_config.el) {
1764 ERROR("Failed opening event list: %s", fr_strerror());
1765 fr_exit_now(EXIT_FAILURE);
1766 }
1768
1769 /*
1770 * Set callbacks so that the socket is automatically
1771 * paused or resumed when the socket becomes writeable.
1772 */
1775 .failed = client_bio_failed,
1776
1777 .write_blocked = client_bio_write_pause,
1778 .write_resume = client_bio_write_resume,
1779
1780 .retry = (fr_debug_lvl > 0) ? client_packet_retry_log : NULL,
1781 .release = client_packet_release,
1782 };
1783
1784#ifdef STATIC_ANALYZER
1785 if (!autofree) fr_exit_now(EXIT_FAILURE);
1786#endif
1787
1788 /*
1789 * Open the RADIUS client bio, and then get the information associated with it.
1790 */
1792 if (!client_bio) {
1793 ERROR("Failed opening socket: %s", fr_strerror());
1794 fr_exit_now(EXIT_FAILURE);
1795 }
1796
1798 fr_assert(client_info != NULL);
1799
1800 if (forced_id >= 0) {
1802 fr_perror("radclient");
1803 fr_exit_now(EXIT_FAILURE);
1804 }
1805 }
1806
1807 if (do_coa) {
1808 // allocate a dedup server bio
1809 }
1810
1811 /*
1812 * Walk over the list of packets, updating to use the correct addresses, and sanity checking them.
1813 */
1815 if (radclient_sane(this) < 0) {
1816 fr_exit_now(EXIT_FAILURE);
1817 }
1818 }
1819
1820 /*
1821 * Always bounce through a connect(), even if we don't need it.
1822 *
1823 * Once the connect() passes, we start reading from the request list, and processing packets.
1824 */
1827 fr_perror("radclient");
1828 fr_exit_now(EXIT_FAILURE);
1829 }
1830
1831 /***********************************************************************
1832 *
1833 * Run the main event loop until we either see an error, or we have sent (and received) all of the packets.
1834 *
1835 ***********************************************************************/
1837
1838 /***********************************************************************
1839 *
1840 * We are done the event loop. Start cleaning things up.
1841 *
1842 ***********************************************************************/
1844
1846
1848
1850 fr_perror("radclient");
1851 ret = EXIT_FAILURE;
1852 }
1853
1855
1857
1858 if (do_summary) {
1859 fr_perror("Packet summary:\n"
1860 "\tAccepted : %" PRIu64 "\n"
1861 "\tRejected : %" PRIu64 "\n"
1862 "\tLost : %" PRIu64 "\n"
1863 "\tPassed filter : %" PRIu64 "\n"
1864 "\tFailed filter : %" PRIu64,
1867 stats.lost,
1868 stats.passed,
1870 );
1871 }
1872
1873 /*
1874 * Ensure our atexit handlers run before any other
1875 * atexit handlers registered by third party libraries.
1876 */
1878
1879 openssl3_free();
1880
1881 if ((stats.lost > 0) || (stats.failed > 0)) return EXIT_FAILURE;
1882
1883 return ret;
1884}
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:160
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
Definition atexit.c:286
#define fr_bio_error(_x)
Definition base.h:192
static int fr_bio_packet_read(fr_bio_packet_t *my, void **pctx_p, fr_packet_t **packet_p, TALLOC_CTX *out_ctx, fr_pair_list_t *out)
Read a packet from a packet BIO.
Definition packet.h:119
fr_bio_packet_callback_t connected
Definition packet.h:71
static int fr_bio_packet_write(fr_bio_packet_t *my, void *pctx, fr_packet_t *packet, fr_pair_list_t *list)
Write a packet to a packet BIO.
Definition packet.h:138
fr_event_list_t * el
event list
Definition retry.h:51
fr_retry_config_t retry_config
base retry config
Definition retry.h:47
fr_event_list_t * el
event list
Definition retry.h:45
#define RCSID(id)
Definition build.h:483
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:313
#define UNUSED
Definition build.h:315
void fr_chap_encode(uint8_t out[static 1+FR_CHAP_CHALLENGE_LENGTH], uint8_t id, uint8_t const *challenge, size_t challenge_len, char const *password, size_t password_len)
Encode a CHAP password.
Definition chap.c:34
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
Definition debug.c:1242
#define MEM(x)
Definition debug.h:36
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:234
fr_radius_packet_code_t
RADIUS packet codes.
Definition defs.h:31
@ FR_RADIUS_CODE_ACCESS_CHALLENGE
RFC2865 - Access-Challenge.
Definition defs.h:43
@ FR_RADIUS_CODE_ACCESS_REQUEST
RFC2865 - Access-Request.
Definition defs.h:33
@ FR_RADIUS_CODE_DISCONNECT_REQUEST
RFC3575/RFC5176 - Disconnect-Request.
Definition defs.h:46
@ FR_RADIUS_CODE_MAX
Maximum possible protocol code.
Definition defs.h:53
@ FR_RADIUS_CODE_DISCONNECT_ACK
RFC3575/RFC5176 - Disconnect-Ack (positive)
Definition defs.h:47
@ FR_RADIUS_CODE_STATUS_SERVER
RFC2865/RFC5997 - Status Server (request)
Definition defs.h:44
@ FR_RADIUS_CODE_COA_REQUEST
RFC3575/RFC5176 - CoA-Request.
Definition defs.h:49
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
Definition defs.h:34
@ FR_RADIUS_CODE_ACCOUNTING_RESPONSE
RFC2866 - Accounting-Response.
Definition defs.h:37
@ FR_RADIUS_CODE_COA_NAK
RFC3575/RFC5176 - CoA-Nak (not willing to perform)
Definition defs.h:51
@ FR_RADIUS_CODE_UNDEFINED
Packet code has not been set.
Definition defs.h:32
@ FR_RADIUS_CODE_COA_ACK
RFC3575/RFC5176 - CoA-Ack (positive)
Definition defs.h:50
@ FR_RADIUS_CODE_DISCONNECT_NAK
RFC3575/RFC5176 - Disconnect-Nak (not willing to perform)
Definition defs.h:48
@ FR_RADIUS_CODE_ACCOUNTING_REQUEST
RFC2866 - Accounting-Request.
Definition defs.h:36
@ FR_RADIUS_CODE_ACCESS_REJECT
RFC2865 - Access-Reject.
Definition defs.h:35
#define FR_COA_UDP_PORT
Definition defs.h:63
#define FR_AUTH_UDP_PORT
Definition defs.h:57
#define FR_ACCT_UDP_PORT_ALT
Definition defs.h:60
#define FR_AUTH_UDP_PORT_ALT
Definition defs.h:58
#define FR_POD_UDP_PORT
Definition defs.h:61
#define FR_ACCT_UDP_PORT
Definition defs.h:59
#define ERROR(fmt,...)
Definition dhcpclient.c:41
static int retries
Definition dhcpclient.c:53
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
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:4392
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition dict_util.c:4585
#define fr_dict_autofree(_to_free)
Definition dict.h:853
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition dict_util.c:3263
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2400
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:268
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:281
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition dict_util.c:4090
#define fr_dict_autoload(_to_load)
Definition dict.h:850
int fr_dict_read(fr_dict_t *dict, char const *dict_dir, char const *filename)
Read supplementary attribute definitions into an existing dictionary.
Specifies an attribute which must be present for the module to function.
Definition dict.h:267
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:280
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition dlist.h:486
#define fr_dlist_foreach(_list_head, _type, _iter)
Iterate over the contents of a list.
Definition dlist.h:94
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition dlist.h:638
static void fr_dlist_talloc_free(fr_dlist_head_t *head)
Free all items in a doubly linked list (with talloc)
Definition dlist.h:908
static void * fr_dlist_prev(fr_dlist_head_t const *list_head, void const *ptr)
Get the previous item in a list.
Definition dlist.h:588
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
Definition dlist.h:939
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition dlist.h:378
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:275
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition dlist.h:555
Head of a doubly linked list.
Definition dlist.h:51
#define fr_event_fd_insert(...)
Definition event.h:232
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:62
#define fr_event_filter_update(...)
Definition event.h:224
#define FR_EVENT_RESUME(_s, _f)
Re-add the filter for a func from kevent.
Definition event.h:110
#define FR_EVENT_SUSPEND(_s, _f)
Temporarily remove the filter for a func from kevent.
Definition event.h:94
Callbacks for the FR_EVENT_FILTER_IO filter.
Definition event.h:173
Structure describing a modification to a filter's state.
Definition event.h:75
fr_socket_t socket
as connected socket
Definition fd.h:125
uint16_t src_port
our port
Definition fd.h:91
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
Definition fd.h:68
fr_ipaddr_t dst_ipaddr
their IP address
Definition fd.h:89
fr_bio_fd_type_t type
accept, connected, unconnected, etc.
Definition fd.h:82
int socket_type
SOCK_STREAM or SOCK_DGRAM.
Definition fd.h:84
uint16_t dst_port
their port
Definition fd.h:92
fr_ipaddr_t src_ipaddr
our IP address
Definition fd.h:88
Configuration for sockets.
Definition fd.h:81
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:937
int af
Address family.
Definition inet.h:64
IPv4/6 prefix.
char const * fr_bio_strerror(ssize_t error)
Definition base.c:196
int packet_global_init(void)
Initialises the Net.
Definition packet.c:185
void fr_packet_net_from_pairs(fr_packet_t *packet, fr_pair_list_t const *list)
Convert pairs to information in a packet.
Definition packet.c:139
talloc_free(reap)
fr_event_list_t * fr_event_list_alloc(TALLOC_CTX *ctx, fr_event_status_cb_t status, void *status_uctx)
Initialise a new event list.
Definition event.c:2899
void fr_event_loop_exit(fr_event_list_t *el, int code)
Signal an event loop exit with the specified code.
Definition event.c:2744
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:1260
int fr_event_loop(fr_event_list_t *el)
Run an event loop.
Definition event.c:2766
Stores all information relating to an event list.
Definition event.c:411
int fr_debug_lvl
Definition log.c:43
FILE * fr_log_fp
Definition log.c:42
fr_log_t default_log
Definition log.c:291
void fr_log_perror(fr_log_t const *log, fr_log_type_t type, char const *file, int line, fr_log_perror_format_t const *rules, char const *fmt,...)
Drain any outstanding messages from the fr_strerror buffers.
Definition log.c:709
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
Definition log.c:583
@ L_DST_STDOUT
Log to stdout.
Definition log.h:78
@ L_ERR
Error message.
Definition log.h:56
@ L_DBG
Only displayed when debugging is enabled.
Definition log.h:59
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
Definition packet.c:38
void fr_packet_free(fr_packet_t **packet_p)
Free a fr_packet_t.
Definition packet.c:89
unsigned short uint16_t
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_OCTETS
Raw octets.
unsigned char uint8_t
int mschap_nt_password_hash(uint8_t out[static NT_DIGEST_LENGTH], char const *password)
Converts Unicode password to 16-byte NT hash with MD4.
Definition mschap.c:52
#define RADIUS_AUTH_VECTOR_LENGTH
Definition net.h:89
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition pair.c:2981
void fr_pair_validate_debug(fr_pair_t const *failed[2])
Write an error to the library errorbuff detailing the mismatch.
Definition pair.c:2093
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree.
Definition pair.c:770
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
Definition pair.c:2634
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:693
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1345
int fr_pair_delete_by_da(fr_pair_list_t *list, fr_dict_attr_t const *da)
Delete matching pairs from the specified list.
Definition pair.c:1689
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:283
bool fr_pair_validate(fr_pair_t const *failed[2], fr_pair_list_t *filter, fr_pair_list_t *list)
Uses fr_pair_cmp to verify all fr_pair_ts in list match the filter defined by check.
Definition pair.c:2128
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
Definition pair.c:2784
int fr_pair_delete(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list and free.
Definition pair.c:1826
int8_t fr_pair_cmp_by_da(void const *a, void const *b)
Order attributes by their da, and tag.
Definition pair.c:1844
int fr_pair_value_memdup_buffer_shallow(fr_pair_t *vp, uint8_t const *src, bool tainted)
Assign a talloced buffer to a "octets" type value pair.
Definition pair.c:3056
int fr_pair_list_afrom_file(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *out, FILE *fp, bool *pfiledone)
Read valuepairs from the fp up to End-Of-File.
int fr_radius_global_init(void)
Definition base.c:1218
void fr_radius_global_free(void)
Definition base.c:1241
fr_table_num_sorted_t const fr_radius_request_name_table[]
Definition base.c:101
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
Definition base.c:112
int fr_radius_allow_reply(int code, bool allowed[static FR_RADIUS_CODE_MAX])
Definition base.c:227
uint8_t const * secret
Definition bio.h:34
bool allowed[FR_RADIUS_CODE_MAX]
allowed outgoing packet types
Definition bio.h:40
size_t secret_len
Definition bio.h:35
fr_radius_bio_verify_t verify
Definition client.h:38
fr_event_list_t * el
Definition client.h:35
fr_bio_retry_info_t const * retry_info
Definition client.h:67
fr_bio_retry_config_t retry_cfg
Definition client.h:40
fr_retry_config_t retry[FR_RADIUS_CODE_MAX]
default retry configuration for each packet type
Definition client.h:51
fr_bio_fd_info_t const * fd_info
Definition client.h:57
fr_bio_packet_cb_funcs_t packet_cb_cfg
Definition client.h:42
bool outgoing[FR_RADIUS_CODE_MAX]
allowed outgoing packet types
Definition client.h:49
void fr_radius_packet_log(fr_log_t const *log, fr_packet_t *packet, fr_pair_list_t *list, bool received)
Definition packet.c:491
#define fr_assert(_expr)
Definition rad_assert.h:38
static fr_rb_tree_t * coa_tree
static fr_dict_attr_t const * attr_packet_type
static fr_dict_attr_t const * attr_request_authenticator
static int send_one_packet(fr_bio_packet_t *client, rc_request_t *request)
static fr_dict_attr_t const * attr_user_password
static bool paused
static int getport(char const *name)
static void client_packet_release(fr_bio_packet_t *client, fr_packet_t *packet)
static char const * radclient_version
static int _rc_request_free(rc_request_t *request)
fr_dict_autoload_t radclient_dict[]
static void client_read(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
static int radclient_sane(rc_request_t *request)
static TALLOC_CTX * autofree
static fr_bio_fd_config_t fd_config
static fr_bio_packet_t * client_bio
int main(int argc, char **argv)
static fr_dict_t const * dict_freeradius
static fr_dict_attr_t const * attr_chap_password
static fr_radius_client_config_t client_config
static int forced_id
static int resend_count
static fr_radius_client_bio_info_t const * client_info
static int client_bio_write_pause(fr_bio_packet_t *bio)
static rc_stats_t stats
static fr_dict_attr_t const * attr_ms_chap_response
static fr_event_update_t const resume_write[]
static fr_dict_t const * dict_radius
static fr_dict_attr_t const * attr_ms_chap_challenge
static NEVER_RETURNS void client_bio_failed(fr_bio_packet_t *bio)
static size_t parallel
static int packet_code
static fr_dict_attr_t const * attr_chap_challenge
static void client_bio_connected(fr_bio_packet_t *client)
static bool do_output
#define openssl3_free()
static int _loop_status(UNUSED fr_time_t now, fr_time_delta_t wake, UNUSED void *ctx)
static int ipproto
fr_dict_attr_autoload_t radclient_dict_attr[]
static fr_dict_attr_t const * attr_cleartext_password
static int client_bio_write_resume(fr_bio_packet_t *bio)
static bool print_filename
static bool do_coa
#define openssl3_init()
static fr_dict_attr_t const * attr_radclient_test_name
static rc_request_t * current
static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files)
static void client_packet_retry_log(UNUSED fr_bio_packet_t *client, fr_packet_t *packet)
static fr_dict_attr_t const * attr_radclient_coa_filename
static NEVER_RETURNS void client_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
static int mschapv1_encode(fr_packet_t *packet, fr_pair_list_t *list, char const *password)
static bool already_hex(fr_pair_t *vp)
static fr_dict_attr_t const * attr_user_name
static void client_write(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
static char * secret
static fr_dlist_head_t rc_request_list
static fr_dict_attr_t const * attr_coa_filter
static void radclient_get_port(fr_radius_packet_code_t type, uint16_t *port)
static fr_dict_attr_t const * attr_ms_chap_password
#define pair_update_request(_attr, _da)
static int8_t request_cmp(void const *one, void const *two)
static int coa_port
static const char * attr_coa_filter_name
static fr_dict_attr_t const * attr_radclient_coa_filter
static fr_event_update_t const pause_write[]
static NEVER_RETURNS void usage(void)
static fr_radius_packet_code_t radclient_get_code(uint16_t port)
static int coa_init(rc_request_t *parent, FILE *coa_reply, char const *reply_filename, bool *coa_reply_done, FILE *coa_filter, char const *filter_filename, bool *coa_filter_done)
Structures for the radclient utility.
#define REDEBUG(fmt,...)
Definition radclient.h:52
uint64_t num
The number (within the file) of the request were reading.
Definition radclient.h:76
#define RDEBUG(fmt,...)
Definition radclient.h:53
fr_pair_t * password
Password.Cleartext.
Definition radclient.h:85
uint64_t accepted
Requests to which we received a accept.
Definition radclient.h:57
fr_packet_t * reply
The incoming response.
Definition radclient.h:89
fr_pair_list_t request_pairs
Definition radclient.h:91
char const * coa_reply
file containing the CoA filter we want to match
Definition radclient.h:70
uint64_t rejected
Requests to which we received a reject.
Definition radclient.h:58
fr_rb_node_t node
rbtree node data for CoA
Definition radclient.h:83
char const * packets
The file containing the request packet.
Definition radclient.h:66
uint64_t lost
Requests to which we received no response.
Definition radclient.h:59
bool done
Whether the request is complete.
Definition radclient.h:99
char const * coa_filter
file containing the CoA filter we want to match
Definition radclient.h:69
fr_pair_list_t filter
If the reply passes the filter, then the request passes.
Definition radclient.h:94
uint64_t failed
Requests which failed a filter.
Definition radclient.h:61
fr_pair_list_t reply_pairs
Definition radclient.h:92
uint64_t passed
Requests which passed a filter.
Definition radclient.h:60
fr_radius_packet_code_t filter_code
Expected code of the response packet.
Definition radclient.h:95
fr_time_t timestamp
Definition radclient.h:86
char const * name
Test name (as specified in the request).
Definition radclient.h:101
#define WARN(fmt,...)
Definition radclient.h:47
char const * filters
The file containing the definition of the packet we want to match.
Definition radclient.h:67
fr_packet_t * packet
The outgoing request.
Definition radclient.h:88
rc_file_pair_t * files
Request and response file names.
Definition radclient.h:80
#define RADIUS_MAX_ATTRIBUTES
Definition radius.h:40
#define FR_RADIUS_PACKET_CODE_VALID(_x)
Definition radius.h:52
static bool cleanup
Definition radsniff.c:60
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:105
void fr_rand_buffer(void *start, size_t length)
Definition rand.c:125
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
Definition rb.c:741
#define fr_rb_talloc_alloc(_ctx, _type, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
Definition rb.h:205
The main red black tree structure.
Definition rb.h:73
fr_packet_t * reply
Outgoing response.
Definition request.h:225
char const *fr_packet_t * packet
< Module the request is currently being processed by.
Definition request.h:224
#define reply_pairs
Convenience macro for accessing the reply list.
Definition request.h:101
static char const * name
void smbdes_mschap(uint8_t const win_password[16], uint8_t const *challenge, uint8_t *response)
Definition smbdes.c:339
void fr_radius_client_bio_connect(NDEBUG_UNUSED fr_event_list_t *el, NDEBUG_UNUSED int fd, UNUSED int flags, void *uctx)
Definition client.c:701
int fr_radius_client_fd_bio_cancel(fr_bio_packet_t *bio, fr_packet_t *packet)
Cancel one packet.
Definition client.c:566
fr_bio_packet_t * fr_radius_client_bio_alloc(TALLOC_CTX *ctx, fr_radius_client_config_t *cfg, fr_bio_fd_config_t const *fd_cfg)
Definition client.c:50
int fr_radius_client_bio_force_id(fr_bio_packet_t *bio, int code, int id)
Definition client.c:671
size_t fr_radius_client_bio_outstanding(fr_bio_packet_t *bio)
Definition client.c:651
fr_radius_client_bio_info_t const * fr_radius_client_bio_info(fr_bio_packet_t *bio)
Definition client.c:663
fr_aka_sim_id_type_t type
fr_pair_t * vp
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
fr_log_dst_t dst
Log destination.
Definition log.h:97
int fd
File descriptor to write messages to.
Definition log.h:112
bool print_level
sometimes we don't want log levels printed
Definition log.h:106
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:653
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:51
fr_slen_t fr_time_delta_from_str(fr_time_delta_t *out, char const *in, size_t inlen, fr_time_res_t hint)
Create fr_time_delta_t from a string.
Definition time.c:449
int fr_time_start(void)
Initialize the local time.
Definition time.c:150
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition time.h:154
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
@ FR_TIME_RES_SEC
Definition time.h:50
#define NSEC
Definition time.h:379
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
static fr_event_list_t * el
#define FR_DICTIONARY_FILE
Definition conf.h:7
void * uctx
Definition packet.h:79
unsigned int code
Packet code (type).
Definition packet.h:61
fr_socket_t socket
This packet was received on.
Definition packet.h:57
int id
Packet ID (used to link requests/responses).
Definition packet.h:60
uint8_t * data
Packet data (body).
Definition packet.h:63
uint8_t vector[RADIUS_AUTH_VECTOR_LENGTH]
RADIUS authentication vector.
Definition packet.h:69
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
void fr_pair_list_sort(fr_pair_list_t *list, fr_cmp_t cmp)
Sort a doubly linked list of fr_pair_ts using merge sort.
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
Definition pair_inline.c:70
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition pair_inline.c:43
static fr_slen_t parent
Definition pair.h:851
fr_time_delta_t irt
Initial transmission time.
Definition retry.h:33
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition socket.h:78
int fd
File descriptor if this is a live socket.
Definition socket.h:81
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:554
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:733
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:577
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
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:676
#define fr_box_time_delta(_val)
Definition value.h:343