The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
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: 4941e7b4173dd095f2e927afaccbfd195472e31e $
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: 4941e7b4173dd095f2e927afaccbfd195472e31e $")
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#include <freeradius-devel/util/md4.h>
45#endif
46
47#ifdef HAVE_GETOPT_H
48# include <getopt.h>
49#endif
50
51
52typedef struct request_s request_t; /* to shut up warnings about mschap.h */
53
54#include "smbdes.h"
55#include "mschap.h"
56
57#include "radclient-ng.h"
58
59#define pair_update_request(_attr, _da) do { \
60 _attr = fr_pair_find_by_da(&request->request_pairs, NULL, _da); \
61 if (!_attr) { \
62 _attr = fr_pair_afrom_da(request, _da); \
63 fr_assert(_attr != NULL); \
64 fr_pair_append(&request->request_pairs, _attr); \
65 } \
66 } while (0)
67
68static char *secret = NULL;
69static bool do_output = true;
70
71static const char *attr_coa_filter_name = "User-Name";
72
74
76static int resend_count = 1;
77static bool print_filename = false;
78
79static int forced_id = -1;
80static size_t parallel = 1;
81static bool paused = false;
82
84
86
88
90
91
92static bool do_coa = false;
93//static int coafd;
95static fr_rb_tree_t *coa_tree = NULL;
96
97static FR_DLIST_HEAD(rc_request_list) rc_request_list;
98static rc_request_t *current = NULL;
99
100static char const *radclient_version = RADIUSD_VERSION_BUILD("radclient");
101
102static fr_dict_t const *dict_freeradius;
103static fr_dict_t const *dict_radius;
104
105static TALLOC_CTX *autofree = NULL;
106
107extern fr_dict_autoload_t radclient_dict[];
108fr_dict_autoload_t radclient_dict[] = {
109 { .out = &dict_freeradius, .proto = "freeradius" },
110 { .out = &dict_radius, .proto = "radius" },
112};
113
115
119
122
128
131
133
136 { .out = &attr_cleartext_password, .name = "Password.Cleartext", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
137 { .out = &attr_ms_chap_challenge, .name = "Vendor-Specific.Microsoft.CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
138 { .out = &attr_ms_chap_password, .name = "Password.MS-CHAP", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
139 { .out = &attr_ms_chap_response, .name = "Vendor-Specific.Microsoft.CHAP-Response", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
140
141 { .out = &attr_radclient_test_name, .name = "Radclient-Test-Name", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
142 { .out = &attr_request_authenticator, .name = "Request-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
143
144 { .out = &attr_radclient_coa_filename, .name = "Radclient-CoA-Filename", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
145 { .out = &attr_radclient_coa_filter, .name = "Radclient-CoA-Filter", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
146
147 { .out = &attr_chap_password, .name = "CHAP-Password", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
148 { .out = &attr_chap_challenge, .name = "CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
149 { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
150 { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
151 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
152
154};
155
156static NEVER_RETURNS void usage(void)
157{
158 fprintf(stderr, "Usage: radclient [options] server[:port] <command> [<secret>]\n");
159
160 fprintf(stderr, " <command> One of auth, acct, status, coa, disconnect or auto.\n");
161 fprintf(stderr, " -4 Use IPv4 address of server\n");
162 fprintf(stderr, " -6 Use IPv6 address of server.\n");
163 fprintf(stderr, " -A <attribute> Use named 'attribute' to match CoA requests to packets. Default is User-Name\n");
164 fprintf(stderr, " -C [<client_ip>:]<client_port> Client source port and source IP address. Port values may be 1..65535\n");
165 fprintf(stderr, " -c <count> Send each packet 'count' times.\n");
166 fprintf(stderr, " -d <confdir> Set user dictionary directory (defaults to " CONFDIR ").\n");
167 fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
168 fprintf(stderr, " -f <file>[:<file>] Read packets from file, not stdin.\n");
169 fprintf(stderr, " If a second file is provided, it will be used to verify responses\n");
170 fprintf(stderr, " -F Print the file name, packet number and reply code.\n");
171 fprintf(stderr, " -h Print usage help information.\n");
172 fprintf(stderr, " -i <id> Set request id to 'id'. Values may be 0..255\n");
173 fprintf(stderr, " -o <port> Set CoA listening port (defaults to 3799)\n");
174 fprintf(stderr, " -p <num> Send 'num' packets from a file in parallel.\n");
175 fprintf(stderr, " -P <proto> Use proto (tcp or udp) for transport.\n");
176 fprintf(stderr, " -r <retries> If timeout, retry sending the packet 'retries' times.\n");
177 fprintf(stderr, " -s Print out summary information of auth results.\n");
178 fprintf(stderr, " -S <file> read secret from file, not command line.\n");
179 fprintf(stderr, " -t <timeout> Wait 'timeout' seconds before retrying (may be a floating point number).\n");
180 fprintf(stderr, " -v Show program version information.\n");
181 fprintf(stderr, " -x Debugging mode.\n");
182
183 fr_exit_now(EXIT_SUCCESS);
184}
185
186/*
187 * Free a radclient struct, which may (or may not)
188 * already be in the list.
189 */
191{
192 rc_request_list_remove(&rc_request_list, request);
193
194 if (do_coa) {
195 (void) fr_rb_delete(coa_tree, &request->node);
196 // @todo - cancel incoming CoA packet/
197 }
198
199 if (request->packet && (request->packet->id >= 0)) {
201 }
202
203 return 0;
204}
205
206#ifdef HAVE_OPENSSL_SSL_H
207#include <openssl/provider.h>
208
209static OSSL_PROVIDER *openssl_default_provider = NULL;
210static OSSL_PROVIDER *openssl_legacy_provider = NULL;
211
212static int openssl3_init(void)
213{
214 /*
215 * Load the default provider for most algorithms
216 */
217 openssl_default_provider = OSSL_PROVIDER_load(NULL, "default");
218 if (!openssl_default_provider) {
219 ERROR("(TLS) Failed loading default provider");
220 return -1;
221 }
222
223 /*
224 * Needed for MD4
225 *
226 * https://www.openssl.org/docs/man3.0/man7/migration_guide.html#Legacy-Algorithms
227 */
228 openssl_legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
229 if (!openssl_legacy_provider) {
230 ERROR("(TLS) Failed loading legacy provider");
231 return -1;
232 }
233
234 fr_md5_openssl_init();
235 fr_md4_openssl_init();
236
237 return 0;
238}
239
240static void openssl3_free(void)
241{
242 if (openssl_default_provider && !OSSL_PROVIDER_unload(openssl_default_provider)) {
243 ERROR("Failed unloading default provider");
244 }
245 openssl_default_provider = NULL;
246
247 if (openssl_legacy_provider && !OSSL_PROVIDER_unload(openssl_legacy_provider)) {
248 ERROR("Failed unloading legacy provider");
249 }
250 openssl_legacy_provider = NULL;
251
252 fr_md5_openssl_free();
253 fr_md4_openssl_free();
254}
255#else
256static int openssl3_init(void)
257{
258 return 0;
259}
260
261static void openssl3_free(void)
262{
263}
264#endif
265
266static int _loop_status(UNUSED fr_time_t now, fr_time_delta_t wake, UNUSED void *ctx)
267{
268 if (fr_time_delta_unwrap(wake) < (NSEC / 10)) return 0;
269
270 if (rc_request_list_num_elements(&rc_request_list) != 0) return 0;
271
272 fr_log(&default_log, L_DBG, __FILE__, __LINE__, "Main loop waking up in %pV seconds", fr_box_time_delta(wake));
273
274 return 0;
275}
276
278 char const *password)
279{
280 unsigned int i;
281 uint8_t *p;
282 fr_pair_t *challenge, *reply;
283 uint8_t nthash[16];
284
287
289
290 fr_pair_append(list, challenge);
291
292 MEM(p = talloc_array(challenge, uint8_t, 8));
293 fr_pair_value_memdup_buffer_shallow(challenge, p, false);
294
295 for (i = 0; i < challenge->vp_length; i++) {
296 p[i] = fr_rand();
297 }
298
300 fr_pair_append(list, reply);
301 p = talloc_zero_array(reply, uint8_t, 50); /* really reply->da->flags.length */
303
304 p[1] = 0x01; /* NT hash */
305
306 if (mschap_nt_password_hash(nthash, password) < 0) return 0;
307
308 smbdes_mschap(nthash, challenge->vp_octets, p + 26);
309 return 1;
310}
311
312
313static int getport(char const *name)
314{
315 struct servent *svp;
316
317 svp = getservbyname(name, "udp");
318 if (!svp) return 0;
319
320 return ntohs(svp->s_port);
321}
322
323/*
324 * Set a port from the request type if we don't already have one
325 */
327{
328 switch (type) {
329 default:
333 if (*port == 0) *port = getport("radius");
334 if (*port == 0) *port = FR_AUTH_UDP_PORT;
335 return;
336
338 if (*port == 0) *port = getport("radacct");
339 if (*port == 0) *port = FR_ACCT_UDP_PORT;
340 return;
341
343 if (*port == 0) *port = FR_POD_UDP_PORT;
344 return;
345
347 if (*port == 0) *port = FR_COA_UDP_PORT;
348 return;
349
351 if (*port == 0) *port = 0;
352 return;
353 }
354}
355
356/*
357 * Resolve a port to a request type
358 */
360{
361 /*
362 * getport returns 0 if the service doesn't exist
363 * so we need to return early, to avoid incorrect
364 * codes.
365 */
366 if (port == 0) return FR_RADIUS_CODE_UNDEFINED;
367
368 if ((port == getport("radius")) || (port == FR_AUTH_UDP_PORT) || (port == FR_AUTH_UDP_PORT_ALT)) {
370 }
371 if ((port == getport("radacct")) || (port == FR_ACCT_UDP_PORT) || (port == FR_ACCT_UDP_PORT_ALT)) {
373 }
375
377}
378
379
381{
382 size_t i;
383
384 if (!vp || (vp->vp_type != FR_TYPE_OCTETS)) return true;
385
386 /*
387 * If it's 17 octets, it *might* be already encoded.
388 * Or, it might just be a 17-character password (maybe UTF-8)
389 * Check it for non-printable characters. The odds of ALL
390 * of the characters being 32..255 is (1-7/8)^17, or (1/8)^17,
391 * or 1/(2^51), which is pretty much zero.
392 */
393 for (i = 0; i < vp->vp_length; i++) {
394 if (vp->vp_octets[i] < 32) {
395 return true;
396 }
397 }
398
399 return false;
400}
401
402/** Read one CoA reply and potentially a filter
403 *
404 */
406 FILE *coa_reply, char const *reply_filename, bool *coa_reply_done,
407 FILE *coa_filter, char const *filter_filename, bool *coa_filter_done)
408{
410 fr_pair_t *vp;
411
412 /*
413 * Allocate it.
414 */
415 MEM(request = talloc_zero(parent, rc_request_t));
416 MEM(request->reply = fr_packet_alloc(request, false));
417
418 /*
419 * Don't initialize src/dst IP/port, or anything else. That will be read from the network.
420 */
421 fr_pair_list_init(&request->filter);
422 fr_pair_list_init(&request->request_pairs);
423 fr_pair_list_init(&request->reply_pairs);
424
425 /*
426 * Read the reply VP's.
427 */
429 &request->reply_pairs, coa_reply, coa_reply_done, true) < 0) {
430 REDEBUG("Error parsing \"%s\"", reply_filename);
431 error:
433 return -1;
434 }
435
436 /*
437 * The reply can be empty. In which case we just send an empty ACK.
438 */
439 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_packet_type);
440 if (vp) request->reply->code = vp->vp_uint32;
441
442 /*
443 * Read in filter VP's.
444 */
445 if (coa_filter) {
447 &request->filter, coa_filter, coa_filter_done, true) < 0) {
448 REDEBUG("Error parsing \"%s\"", filter_filename);
449 goto error;
450 }
451
452 if (*coa_filter_done && !*coa_reply_done) {
453 REDEBUG("Differing number of replies/filters in %s:%s "
454 "(too many replies))", reply_filename, filter_filename);
455 goto error;
456 }
457
458 if (!*coa_filter_done && *coa_reply_done) {
459 REDEBUG("Differing number of replies/filters in %s:%s "
460 "(too many filters))", reply_filename, filter_filename);
461 goto error;
462 }
463
464 /*
465 * This allows efficient list comparisons later
466 */
468 }
469
470 request->name = parent->name;
471
472 /*
473 * Automatically set the response code from the request code
474 * (if one wasn't already set).
475 */
476 if (request->filter_code == FR_RADIUS_CODE_UNDEFINED) {
477 request->filter_code = FR_RADIUS_CODE_COA_REQUEST;
478 }
479
480 parent->coa = request;
481
482 /*
483 * Ensure that the packet is also tracked in the CoA tree.
484 */
486 if (fr_rb_insert(coa_tree, parent) != 0) {
487 ERROR("Failed inserting packet from %s into CoA tree", request->name);
488 fr_exit_now(EXIT_FAILURE);
489 }
490
491 return 0;
492}
493
494/*
495 * Initialize a radclient data structure and add it to
496 * the global linked list.
497 */
498static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files)
499{
500 FILE *packets, *filters = NULL;
501 bool read_from_stdin;
502
503 fr_pair_t *vp;
504 rc_request_t *request = NULL;
505 bool packets_done = false;
506 uint64_t num = 0;
507
508 FILE *coa_reply = NULL;
509 FILE *coa_filter = NULL;
510 bool coa_reply_done = false;
511 bool coa_filter_done = false;
512
513 fr_assert(files->packets != NULL);
514
515 /*
516 * Determine where to read the VP's from.
517 */
518 read_from_stdin = (strcmp(files->packets, "-") == 0);
519 if (!read_from_stdin) {
520 packets = fopen(files->packets, "r");
521 if (!packets) {
522 ERROR("Error opening %s: %s", files->packets, fr_syserror(errno));
523 return -1;
524 }
525
526 /*
527 * Read in the pairs representing the expected response.
528 */
529 if (files->filters) {
530 filters = fopen(files->filters, "r");
531 if (!filters) {
532 ERROR("Error opening %s: %s", files->filters, fr_syserror(errno));
533 goto error;
534 }
535 }
536
537 if (files->coa_reply) {
538 coa_reply = fopen(files->coa_reply, "r");
539 if (!coa_reply) {
540 ERROR("Error opening %s: %s", files->coa_reply, fr_syserror(errno));
541 goto error;
542 }
543 }
544
545 if (files->coa_filter) {
546 coa_filter = fopen(files->coa_filter, "r");
547 if (!coa_filter) {
548 ERROR("Error opening %s: %s", files->coa_filter, fr_syserror(errno));
549 goto error;
550 }
551 }
552 } else {
553 packets = stdin;
554 }
555
556 /*
557 * Loop until the file is done.
558 */
559 do {
560 char const *coa_reply_filename = NULL;
561 char const *coa_filter_filename = NULL;
562
563 /*
564 * Allocate it.
565 */
566 MEM(request = talloc_zero(ctx, rc_request_t));
567 MEM(request->packet = fr_packet_alloc(request, true));
568 request->packet->uctx = request;
569
570 /*
571 * Don't set request->packet->socket. The underlying socket isn't open yet.
572 */
573
574 request->files = files;
575 request->packet->id = -1;
576 request->num = num++;
577
578 fr_pair_list_init(&request->filter);
579 fr_pair_list_init(&request->request_pairs);
580 fr_pair_list_init(&request->reply_pairs);
581
582 /*
583 * Read the request VP's.
584 */
586 &request->request_pairs, packets, &packets_done, true) < 0) {
587 char const *input;
588
589 if ((files->packets[0] == '-') && (files->packets[1] == '\0')) {
590 input = "stdin";
591 } else {
592 input = files->packets;
593 }
594
595 REDEBUG("Error parsing \"%s\"", input);
596 goto error;
597 }
598
599 /*
600 * Skip empty entries
601 */
602 if (fr_pair_list_empty(&request->request_pairs)) {
603 WARN("Skipping \"%s\": No Attributes", files->packets);
605 continue;
606 }
607
608 /*
609 * Read in filter VP's.
610 */
611 if (filters) {
612 bool filters_done;
613
615 &request->filter, filters, &filters_done, true) < 0) {
616 REDEBUG("Error parsing \"%s\"", files->filters);
617 goto error;
618 }
619
620 if (filters_done && !packets_done) {
621 REDEBUG("Differing number of packets/filters in %s:%s "
622 "(too many requests)", files->packets, files->filters);
623 goto error;
624 }
625
626 if (!filters_done && packets_done) {
627 REDEBUG("Differing number of packets/filters in %s:%s "
628 "(too many filters)", files->packets, files->filters);
629 goto error;
630 }
631
633 if (vp) {
634 if (!FR_RADIUS_PACKET_CODE_VALID(vp->vp_uint32)) {
635 REDEBUG("Invalid filter code %u in %s:%s", vp->vp_uint32,
636 files->packets, files->filters);
637 goto error;
638 }
639
640 request->filter_code = vp->vp_uint32;
641 fr_pair_delete(&request->filter, vp);
642 }
643
644 /*
645 * This allows efficient list comparisons later
646 */
648 }
649
650 /*
651 * Process special attributes
652 */
653 for (vp = fr_pair_list_head(&request->request_pairs);
654 vp;
655 vp = fr_pair_list_next(&request->request_pairs, vp)) {
656 /*
657 * Allow it to set the packet type in
658 * the attributes read from the file.
659 */
660 if (vp->da == attr_packet_type) {
661 if (!FR_RADIUS_PACKET_CODE_VALID(vp->vp_uint32)) {
662 REDEBUG("Invalid Packet-Type %u in %s", vp->vp_uint32, files->packets);
663 goto error;
664 }
665
666 request->packet->code = vp->vp_uint32;
667 } else if (vp->da == attr_request_authenticator) {
668 if (vp->vp_length > sizeof(request->packet->vector)) {
669 memcpy(request->packet->vector, vp->vp_octets, sizeof(request->packet->vector));
670 } else {
671 memset(request->packet->vector, 0, sizeof(request->packet->vector));
672 memcpy(request->packet->vector, vp->vp_octets, vp->vp_length);
673 }
674 } else if (vp->da == attr_cleartext_password) {
675 request->password = vp;
676 /*
677 * Keep a copy of the the password attribute.
678 */
679 } else if (vp->da == attr_chap_password) {
680 /*
681 * If it's already hex, do nothing.
682 */
683 if ((vp->vp_length == 17) && (already_hex(vp))) continue;
684
685 /*
686 * CHAP-Password is octets, so it may not be zero terminated.
687 */
689 fr_pair_value_bstrndup(request->password, vp->vp_strvalue, vp->vp_length, true);
690 } else if (vp->da == attr_ms_chap_password) {
692 fr_pair_value_bstrndup(request->password, vp->vp_strvalue, vp->vp_length, true);
693
694 } else if (vp->da == attr_radclient_test_name) {
695 request->name = vp->vp_strvalue;
696
697 /*
698 * Allow these to be dynamically specified
699 * in the request file, as well as on the
700 * command line.
701 */
702 } else if (vp->da == attr_radclient_coa_filename) {
703 coa_reply_filename = vp->vp_strvalue;
704
705 } else if (vp->da == attr_radclient_coa_filter) {
706 coa_filter_filename = vp->vp_strvalue;
707 }
708 } /* loop over the VP's we read in */
709
710 /*
711 * Use the default set on the command line
712 */
713 if (request->packet->code == FR_RADIUS_CODE_UNDEFINED) request->packet->code = packet_code;
714
715 /*
716 * Fill in the packet header from attributes, and then
717 * re-realize the attributes.
718 */
719 fr_packet_net_from_pairs(request->packet, &request->request_pairs);
720
721 /*
722 * Default to the filename
723 */
724 if (!request->name) request->name = request->files->packets;
725
726 /*
727 * Automatically set the response code from the request code
728 * (if one wasn't already set).
729 */
730 if (request->filter_code == FR_RADIUS_CODE_UNDEFINED) {
731 switch (request->packet->code) {
734 break;
735
738 break;
739
741 request->filter_code = FR_RADIUS_CODE_COA_ACK;
742 break;
743
746 break;
747
749 request->filter_code = FR_RADIUS_CODE_UNDEFINED;
750 break;
751
753 REDEBUG("Packet-Type must be defined,"
754 "or a well known RADIUS port");
755 goto error;
756
757 default:
758 REDEBUG("Can't determine expected reply.Packet-Type for Packet-Type %u",
759 request->packet->code);
760 goto error;
761 }
762 /*
763 * Automatically set the request code from the response code
764 * (if one wasn't already set).
765 */
766 } else if (request->packet->code == FR_RADIUS_CODE_UNDEFINED) {
767 switch (request->filter_code) {
771 break;
772
775 break;
776
780 break;
781
784 request->packet->code = FR_RADIUS_CODE_COA_REQUEST;
785 break;
786
787 default:
788 REDEBUG("Can't determine expected Packet-Type for reply.Packet-Type %u",
789 request->filter_code);
790 goto error;
791 }
792 }
793
794 /*
795 * Automatically set the dst port (if one wasn't already set).
796 */
797 radclient_get_port(request->packet->code, &request->packet->socket.inet.dst_port);
798 if (request->packet->socket.inet.dst_port == 0) {
799 REDEBUG("Can't determine destination port");
800 goto error;
801 }
802
803 /*
804 * We expect different responses for Status-Server, depending on which port is being used.
805 */
806 if (request->packet->code == FR_RADIUS_CODE_STATUS_SERVER) {
807 switch (radclient_get_code(request->packet->socket.inet.dst_port)) {
810 break;
811
814 break;
815
816 default:
817 request->filter_code = FR_RADIUS_CODE_UNDEFINED;
818 break;
819 }
820 }
821
822 /*
823 * Read in the CoA filename and filter.
824 */
825 if (coa_reply_filename) {
826 if (coa_reply) {
827 RDEBUG("Cannot specify CoA file on both the command line and via Radclient-CoA-Filename");
828 goto error;
829 }
830
831 coa_reply = fopen(coa_reply_filename, "r");
832 if (!coa_reply) {
833 ERROR("Error opening %s: %s", coa_reply_filename, fr_syserror(errno));
834 goto error;
835 }
836
837 if (coa_filter_filename) {
838 coa_filter = fopen(coa_filter_filename, "r");
839 if (!coa_filter) {
840 ERROR("Error opening %s: %s", coa_filter_filename, fr_syserror(errno));
841 goto error;
842 }
843 } else {
844 coa_filter = NULL;
845 }
846
847 /*
848 * Read in one CoA reply and/or filter
849 */
850 if (coa_init(request,
851 coa_reply, coa_reply_filename, &coa_reply_done,
852 coa_filter, coa_filter_filename, &coa_filter_done) < 0) {
853 goto error;
854 }
855
856 fclose(coa_reply);
857 coa_reply = NULL;
858 if (coa_filter) {
859 fclose(coa_filter);
860 coa_filter = NULL;
861 }
862 do_coa = true;
863
864 } else if (coa_reply) {
865 if (coa_init(request,
866 coa_reply, coa_reply_filename, &coa_reply_done,
867 coa_filter, coa_filter_filename, &coa_filter_done) < 0) {
868 goto error;
869 }
870
871 if (coa_reply_done != packets_done) {
872 REDEBUG("Differing number of packets in input file and coa_reply in %s:%s ",
873 files->packets, files->coa_reply);
874 goto error;
875
876 }
877 }
878
879 /*
880 * Add it to the tail of the list.
881 */
882 rc_request_list_insert_tail(&rc_request_list, request);
883
884 /*
885 * Set the destructor so it removes itself from the
886 * request list when freed. We don't set this until
887 * the packet is actually in the list, else we trigger
888 * the asserts in the free callback.
889 */
890 talloc_set_destructor(request, _rc_request_free);
891 } while (!packets_done); /* loop until the file is done. */
892
893 if (!read_from_stdin) fclose(packets);
894 if (filters) fclose(filters);
895 if (coa_reply) fclose(coa_reply);
896 if (coa_filter) fclose(coa_filter);
897
898 /*
899 * And we're done.
900 */
901 return 0;
902
903error:
905
906 if (!read_from_stdin) fclose(packets);
907 if (filters) fclose(filters);
908 if (coa_reply) fclose(coa_reply);
909 if (coa_filter) fclose(coa_filter);
910
911 return -1;
912}
913
914
915/*
916 * Sanity check each argument.
917 */
919{
920 request->packet->socket.inet.src_ipaddr = client_info->fd_info->socket.inet.src_ipaddr;
921 request->packet->socket.inet.src_port = client_info->fd_info->socket.inet.src_port;
922 request->packet->socket.inet.ifindex = client_info->fd_info->socket.inet.ifindex;
923
924 if (request->packet->socket.inet.dst_port == 0) {
925 request->packet->socket.inet.dst_port = fd_config.dst_port;
926 }
927
928 if (request->packet->socket.inet.dst_ipaddr.af == AF_UNSPEC) {
929 if (fd_config.dst_ipaddr.af == AF_UNSPEC) {
930 ERROR("No server was given, and request %" PRIu64 " in file %s did not contain "
931 "Packet-Dst-IP-Address", request->num, request->files->packets);
932 return -1;
933 }
934 request->packet->socket.inet.dst_ipaddr = fd_config.dst_ipaddr;
935 }
936
937 if (request->packet->code == 0) {
938 if (packet_code == -1) {
939 ERROR("Request was \"auto\", and request %" PRIu64 " in file %s did not contain Packet-Type",
940 request->num, request->files->packets);
941 return -1;
942 }
943 request->packet->code = packet_code;
944 }
945
946 request->packet->socket.fd = -1;
947
948 return 0;
949}
950
951
952static fr_cmp_ret_t request_cmp(void const *one, void const *two)
953{
954 rc_request_t const *a = one, *b = two;
955 fr_pair_t *vp1, *vp2;
956
958 vp2 = fr_pair_find_by_da(&b->request_pairs, NULL, attr_coa_match_attr);
959
960 if (!vp1) return CMP_LT;
961 if (!vp2) return CMP_GT;
962
963 return fr_value_box_cmp(&vp1->data, &vp2->data);
964}
965
967{
968 /*
969 * Don't leave a dangling pointer around.
970 */
971 if (current == request) {
972 current = rc_request_list_prev(&rc_request_list, current);
973 }
974
976
977 /*
978 * There are more packets to send, then allow the writer to send them.
979 */
980 if (rc_request_list_num_elements(&rc_request_list) != 0) {
981 return;
982 }
983
984 /*
985 * We're done all packets, and there's nothing more to read, stop.
986 */
987 if (fr_radius_client_bio_outstanding(client) == 0) {
989
991 }
992}
993
995{
996 rc_request_t *request = packet->uctx;
997
998 DEBUG("Timeout - resending packet");
999
1000 // @todo - log the updated Acct-Delay-Time from the packet?
1001
1002 fr_radius_packet_log(&default_log, request->packet, &request->request_pairs, false);
1003}
1004
1006{
1007 rc_request_t *request = packet->uctx;
1008
1009 ERROR("No reply to packet");
1010
1011 cleanup(client, request);
1012}
1013
1014
1015/*
1016 * Send one packet.
1017 */
1019{
1020 int rcode;
1021
1022 fr_assert(!request->done);
1023 fr_assert(request->reply == NULL);
1024
1025#ifdef STATIC_ANALYZER
1026 if (!secret) fr_exit_now(EXIT_FAILURE);
1027#endif
1028
1029 fr_assert(request->packet->id < 0);
1030 fr_assert(request->packet->data == NULL);
1031
1032 /*
1033 * Update the password, so it can be encrypted with the
1034 * new authentication vector.
1035 */
1036 if (request->password) {
1037 fr_pair_t *vp;
1038
1039 if ((vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_chap_password)) != NULL) {
1040 uint8_t buffer[17];
1041 fr_pair_t *challenge;
1042
1043 /*
1044 * Use CHAP-Challenge pair if present, otherwise create CHAP-Challenge and
1045 * populate with current Request Authenticator.
1046 *
1047 * Request Authenticator is re-calculated by fr_radius_packet_sign
1048 */
1049 challenge = fr_pair_find_by_da(&request->request_pairs, NULL, attr_chap_challenge);
1050 if (!challenge || (challenge->vp_length < 7)) {
1052 fr_pair_value_memdup(challenge, request->packet->vector, RADIUS_AUTH_VECTOR_LENGTH, false);
1053 }
1054
1056 fr_rand() & 0xff, challenge->vp_octets, challenge->vp_length,
1057 request->password->vp_strvalue,
1058 request->password->vp_length);
1059 fr_pair_value_memdup(vp, buffer, sizeof(buffer), false);
1060
1061 } else if (fr_pair_find_by_da_nested(&request->request_pairs, attr_ms_chap_password) != NULL) {
1062 mschapv1_encode(request->packet, &request->request_pairs, request->password->vp_strvalue);
1063
1064 } else {
1065 DEBUG("WARNING: No password in the request");
1066 }
1067 }
1068
1069 request->timestamp = fr_time();
1070 request->tries = 1;
1071
1072 /*
1073 * Ensure that each Access-Request is unique.
1074 */
1075 if (request->packet->code == FR_RADIUS_CODE_ACCESS_REQUEST) {
1076 fr_rand_buffer(request->packet->vector, sizeof(request->packet->vector));
1077 }
1078
1079 /*
1080 * Send the current packet.
1081 */
1082 rcode = fr_bio_packet_write(client, request, request->packet, &request->request_pairs);
1083 if (rcode < 0) {
1084 /*
1085 * Failed writing it. Try again later.
1086 */
1087 if (rcode == fr_bio_error(IO_WOULD_BLOCK)) return 0;
1088
1089 REDEBUG("Failed writing packet - %s", fr_strerror());
1090 return -1;
1091 }
1092
1093 fr_radius_packet_log(&default_log, request->packet, &request->request_pairs, false);
1094
1095 return 0;
1096}
1097
1100 { 0 }
1101};
1102
1105 { 0 }
1106};
1107
1108
1110{
1112
1114 return fr_bio_error(GENERIC);
1115 }
1116
1117 return 0;
1118}
1119
1121{
1123
1125 return fr_bio_error(GENERIC);
1126 }
1127
1128 return 1;
1129}
1130
1131
1133{
1134 ERROR("Failed connecting to server");
1135
1136 /*
1137 * Cleanly close the BIO, so that we exercise the shutdown path.
1138 */
1139 fr_assert(bio == client_bio);
1140 TALLOC_FREE(bio);
1141
1142 fr_exit_now(EXIT_FAILURE);
1143}
1144
1145
1147 int fd_errno, void *uctx)
1148{
1149 fr_bio_packet_t *client = uctx;
1150
1151 ERROR("Failed in connection - %s", fr_syserror(fd_errno));
1152
1153 /*
1154 * Cleanly close the BIO, so that we exercise the shutdown path.
1155 */
1156 fr_assert(client == client_bio);
1157 TALLOC_FREE(client);
1158
1159 fr_exit_now(EXIT_FAILURE);
1160}
1161
1162static void client_read(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
1163{
1164 fr_bio_packet_t *client = uctx;
1168 int rcode;
1169
1171
1172 /*
1173 * Read one packet.
1174 */
1175 rcode = fr_bio_packet_read(client, (void **) &request, &reply, client, &reply_pairs);
1176 if (rcode < 0) {
1177 ERROR("Failed reading packet - %s", fr_bio_strerror(rcode));
1178 fr_exit_now(EXIT_FAILURE);
1179 }
1180
1181 /*
1182 * Not a RADIUS packet, or not a reply to a packet we sent.
1183 */
1184 if (!rcode) return;
1185
1187
1188 if (print_filename) {
1189 RDEBUG("%s response code %u", request->files->packets, reply->code);
1190 }
1191
1192 /*
1193 * Increment counters...
1194 */
1195 switch (reply->code) {
1200 stats.accepted++;
1201 break;
1202
1204 break;
1205
1206 default:
1207 stats.rejected++;
1208 }
1209
1210 fr_strerror_clear(); /* Clear strerror buffer */
1211
1212 /*
1213 * If we had an expected response code, check to see if the
1214 * packet matched that.
1215 */
1216 if ((request->filter_code != FR_RADIUS_CODE_UNDEFINED) && (reply->code != request->filter_code)) {
1218 REDEBUG("%s: Expected %s got %s", request->name, fr_radius_packet_name[request->filter_code],
1220 } else {
1221 REDEBUG("%s: Expected %u got %u", request->name, request->filter_code,
1222 reply->code);
1223 }
1224 stats.failed++;
1225 /*
1226 * Check if the contents of the packet matched the filter
1227 */
1228 } else if (fr_pair_list_empty(&request->filter)) {
1229 stats.passed++;
1230 } else {
1231 fr_pair_t const *failed[2];
1232
1234 if (fr_pair_validate(failed, &request->filter, &reply_pairs)) {
1235 RDEBUG("%s: Response passed filter", request->name);
1236 stats.passed++;
1237 } else {
1238 fr_pair_validate_debug(failed);
1239 REDEBUG("%s: Response for failed filter", request->name);
1240 stats.failed++;
1241 }
1242 }
1243
1244 /*
1245 * The retry bio takes care of suppressing duplicate replies.
1246 */
1247 if (paused) {
1249 fr_perror("radclient");
1250 fr_exit_now(EXIT_FAILURE);
1251 }
1252 paused = false;
1253 }
1254
1255 /*
1256 * If we're not done, then leave this packet in the list for future resending.
1257 */
1258 request->done = (request->resend >= resend_count);
1259 if (!request->done) {
1260 /*
1261 * We don't care about duplicate replies, they can go away.
1262 */
1263 (void) fr_radius_client_fd_bio_cancel(client, request->packet);
1264 request->packet->id = -1;
1265 TALLOC_FREE(request->packet->data);
1266 return;
1267 }
1268
1270
1271 cleanup(client, request);
1272}
1273
1274static void client_write(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
1275{
1276 fr_bio_packet_t *client = uctx;
1278
1279 request = rc_request_list_next(&rc_request_list, current);
1280 fr_assert(!paused);
1281
1282 if (!request) request = rc_request_list_head(&rc_request_list);
1283
1284 /*
1285 * Nothing more to send, stop trying to write packets.
1286 */
1287 if (!request) {
1288 pause:
1290 fr_perror("radclient");
1291 fr_exit_now(EXIT_FAILURE);
1292 }
1293 return;
1294 }
1295
1296 /*
1297 * No more packets to send, we pause the read.
1298 */
1299 if (request->packet->id >= 0) {
1300 paused = true;
1301 goto pause;
1302 }
1303
1304 if (send_one_packet(client, request) < 0) {
1305 fr_perror("radclient");
1306 fr_exit_now(EXIT_FAILURE);
1307 }
1308
1309 request->resend++;
1310 current = request;
1311
1312 /*
1313 * 0 means "don't limit requests".
1314 */
1316 paused = true;
1317 goto pause;
1318 }
1319}
1320
1322{
1323 fr_radius_client_bio_info_t const *info;
1324
1325 info = fr_radius_client_bio_info(client);
1326
1327 if (fr_event_fd_insert(autofree, NULL, info->retry_info->el, info->fd_info->socket.fd,
1328 client_read, client_write, client_error, client) < 0) {
1329 fr_perror("radclient");
1330 fr_exit_now(EXIT_FAILURE);
1331 }
1332}
1333
1334
1335/**
1336 *
1337 * @hidecallgraph
1338 */
1339int main(int argc, char **argv)
1340{
1341 int ret = EXIT_SUCCESS;
1342 int c;
1343 char const *confdir = CONFDIR;
1344 char const *dict_dir = DICTDIR;
1345 char *end;
1346 char filesecret[256];
1347 FILE *fp;
1348 int do_summary = false;
1349 fr_dlist_head_t filenames;
1350
1351 int retries = 5;
1353
1354 /*
1355 * It's easier having two sets of flags to set the
1356 * verbosity of library calls and the verbosity of
1357 * radclient.
1358 */
1359 fr_debug_lvl = 0;
1360 fr_log_fp = stdout;
1361
1362 /*
1363 * Must be called first, so the handler is called last
1364 */
1366
1367 fr_time_start();
1368
1370 if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0], PANIC_ACTION_SIGNALS) < 0) {
1371 fr_perror("radclient");
1372 fr_exit_now(EXIT_FAILURE);
1373 }
1374
1375#ifdef STATIC_ANALYZER
1376 /*
1377 * clang scan thinks that fr_fault_setup() will set autofree=NULL.
1378 */
1379 if (!autofree) fr_exit_now(EXIT_FAILURE);
1380#endif
1381
1382 talloc_set_log_stderr();
1383
1384 rc_request_list_talloc_init(&rc_request_list);
1385
1386 fr_dlist_talloc_init(&filenames, rc_file_pair_t, entry);
1387
1388 /*
1389 * Always log to stdout
1390 */
1392 default_log.fd = STDOUT_FILENO;
1393 default_log.print_level = false;
1394
1395 /*
1396 * Initialize the kind of socket we want.
1397 */
1400 .socket_type = SOCK_DGRAM,
1401 .transport_type = FR_BIO_FD_TRANSPORT_UDP,
1402
1403 .src_ipaddr = (fr_ipaddr_t) {
1404 .af = AF_INET,
1405 },
1406 .dst_ipaddr = (fr_ipaddr_t) {
1407 .af = AF_INET,
1408 },
1409
1410 .src_port = 0,
1411 .dst_port = 1812,
1412
1413 .interface = NULL,
1414
1415 .path = NULL,
1416 .filename = NULL,
1417
1418 .async = true,
1419 };
1420
1421 /*
1422 * Initialize the client configuration.
1423 */
1425 .log = &default_log,
1426 .verify = {
1427 .require_message_authenticator = false,
1428 .max_attributes = RADIUS_MAX_ATTRIBUTES,
1429 .max_packet_size = 4096,
1430 },
1431 };
1432
1433 /***********************************************************************
1434 *
1435 * Parse command-line options.
1436 *
1437 ***********************************************************************/
1438
1439 while ((c = getopt(argc, argv, "46A:c:C:d:D:f:Fi:ho:p:P:r:sS:t:vx")) != -1) switch (c) {
1440 case '4':
1441 fd_config.dst_ipaddr.af = AF_INET;
1442 break;
1443
1444 case '6':
1445 fd_config.dst_ipaddr.af = AF_INET6;
1446 break;
1447
1448 case 'A':
1449 attr_coa_filter_name = optarg;
1450 break;
1451
1452 case 'c':
1453 if (!isdigit((uint8_t) *optarg)) usage();
1454
1455 resend_count = atoi(optarg);
1456
1457 if (resend_count < 1) usage();
1458 break;
1459
1460 case 'C':
1461 {
1462 int tmp;
1463
1464 if (strchr(optarg, ':')) {
1466 optarg, -1, AF_UNSPEC, true, false) < 0) {
1467 fr_perror("Failed parsing source address");
1468 fr_exit_now(EXIT_FAILURE);
1469 }
1470 break;
1471 }
1472
1473 tmp = atoi(optarg);
1474 if (tmp < 1 || tmp > 65535) usage();
1475
1477 }
1478 break;
1479
1480 case 'D':
1481 dict_dir = optarg;
1482 break;
1483
1484 case 'd':
1485 confdir = optarg;
1486 break;
1487
1488 /*
1489 * packet,filter
1490 */
1491 case 'f':
1492 {
1493 char const *p;
1494 rc_file_pair_t *files;
1495
1496 MEM(files = talloc_zero(talloc_autofree_context(), rc_file_pair_t));
1497
1498 /*
1499 * Commas are nicer than colons.
1500 */
1501 c = ':';
1502
1503 p = strchr(optarg, c);
1504 if (!p) {
1505 c = ',';
1506 p = strchr(optarg, c);
1507 }
1508 if (!p) {
1509 files->packets = optarg;
1510 files->filters = NULL;
1511 } else {
1512 MEM(files->packets = talloc_strndup(files, optarg, p - optarg));
1513 files->filters = p + 1;
1514 }
1515 fr_dlist_insert_tail(&filenames, files);
1516 }
1517 break;
1518
1519 case 'F':
1520 print_filename = true;
1521 break;
1522
1523 case 'i':
1524 if (!isdigit((uint8_t) *optarg)) {
1525 usage();
1526 }
1527 forced_id = atoi(optarg);
1528 if ((forced_id < 0) || (forced_id > 255)) {
1529 usage();
1530 }
1531 break;
1532
1533 case 'o':
1534 coa_port = atoi(optarg);
1535 if ((coa_port <= 0) || (coa_port > UINT16_MAX)) usage();
1536 break;
1537
1538 /*
1539 * Note that sending MANY requests in
1540 * parallel can over-run the kernel
1541 * queues, and Linux will happily discard
1542 * packets. So even if the server responds,
1543 * the client may not see the reply.
1544 */
1545 case 'p':
1546 parallel = strtoul(optarg, &end, 10);
1547 if (*end) usage();
1548 if (parallel > 65536) usage();
1549 break;
1550
1551 case 'P':
1552 if (!strcmp(optarg, "tcp")) {
1553 fd_config.socket_type = SOCK_STREAM;
1555 } else if (!strcmp(optarg, "udp")) {
1556 fd_config.socket_type = SOCK_DGRAM;
1558 } else {
1559 usage();
1560 }
1561 break;
1562
1563 case 'r':
1564 if (!isdigit((uint8_t) *optarg)) usage();
1565 retries = atoi(optarg);
1566 if ((retries == 0) || (retries > 1000)) usage();
1567 break;
1568
1569 case 's':
1570 do_summary = true;
1571 break;
1572
1573 case 'S':
1574 {
1575 char *p;
1576 fp = fopen(optarg, "r");
1577 if (!fp) {
1578 ERROR("Error opening %s: %s", optarg, fr_syserror(errno));
1579 fr_exit_now(EXIT_FAILURE);
1580 }
1581 if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
1582 ERROR("Error reading %s: %s", optarg, fr_syserror(errno));
1583 fr_exit_now(EXIT_FAILURE);
1584 }
1585 fclose(fp);
1586
1587 /* truncate newline */
1588 p = filesecret + strlen(filesecret) - 1;
1589 while ((p >= filesecret) &&
1590 (*p < ' ')) {
1591 *p = '\0';
1592 --p;
1593 }
1594
1595 if (strlen(filesecret) < 2) {
1596 ERROR("Secret in %s is too short", optarg);
1597 fr_exit_now(EXIT_FAILURE);
1598 }
1599 secret = talloc_strdup(autofree, filesecret);
1602 }
1603 break;
1604
1605 case 't':
1606 if (fr_time_delta_from_str(&timeout, optarg, strlen(optarg), FR_TIME_RES_SEC) < 0) {
1607 fr_perror("Failed parsing timeout value");
1608 fr_exit_now(EXIT_FAILURE);
1609 }
1610 break;
1611
1612 case 'v':
1613 fr_debug_lvl = 1;
1614 DEBUG("%s", radclient_version);
1615 fr_exit_now(0);
1616
1617 case 'x':
1618 fr_debug_lvl++;
1619 if (fr_debug_lvl > 1) default_log.print_level = true;
1620 break;
1621
1622 case 'h':
1623 default:
1624 usage();
1625 }
1626 argc -= (optind - 1);
1627 argv += (optind - 1);
1628
1629 if ((argc < 3) || ((secret == NULL) && (argc < 4))) {
1630 ERROR("Insufficient arguments");
1631 usage();
1632 }
1633
1634 /*
1635 * Get the request type
1636 */
1637 if (!isdigit((uint8_t) argv[2][0])) {
1639 if (packet_code == -2) {
1640 ERROR("Unrecognised request type \"%s\"", argv[2]);
1641 usage();
1642 }
1643 } else {
1644 packet_code = atoi(argv[2]);
1645 }
1646
1647 /*
1648 * "auto" is FR_RADIUS_CODE_UNDEFINED, and the code is then
1649 * chosen from the destination port.
1650 */
1652 ERROR("Invalid request type \"%s\"", argv[2]);
1653 usage();
1654 }
1655
1656 /*
1657 * Initialize the retry configuration for this type of packet.
1658 */
1661
1663 .irt = timeout,
1664 .mrt = fr_time_delta_from_sec(16),
1665 .mrd = (retries == 1) ? timeout : fr_time_delta_from_sec(30),
1666 .mrc = retries,
1667 };
1669
1670 /*
1671 * Resolve hostname.
1672 */
1673 if (strcmp(argv[1], "-") != 0) {
1674 if (fr_inet_pton_port(&fd_config.dst_ipaddr, &fd_config.dst_port, argv[1], -1, fd_config.dst_ipaddr.af, true, true) < 0) {
1675 fr_perror("radclient");
1676 fr_exit_now(EXIT_FAILURE);
1677 }
1678
1679 /*
1680 * Work backwards from the port to determine the packet type
1681 */
1683 }
1685
1686 /*
1687 * Add the secret.
1688 */
1689 if (argv[3]) {
1690 secret = talloc_strdup(autofree, argv[3]);
1693 }
1694
1695 /***********************************************************************
1696 *
1697 * We're done parsing command-line options, bootstrap the various libraries, etc.
1698 *
1699 ***********************************************************************/
1700
1702 fr_perror("radclient");
1703 fr_exit_now(EXIT_FAILURE);
1704 }
1705
1706 if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) {
1707 fr_perror("radclient");
1708 fr_exit_now(EXIT_FAILURE);
1709 }
1710
1711 if (fr_radius_global_init() < 0) {
1712 fr_perror("radclient");
1713 fr_exit_now(EXIT_FAILURE);
1714 }
1715
1716 if (fr_dict_autoload(radclient_dict) < 0) {
1717 fr_perror("radclient");
1718 exit(EXIT_FAILURE);
1719 }
1720
1722 fr_perror("radclient");
1723 exit(EXIT_FAILURE);
1724 }
1725
1727 fr_log_perror(&default_log, L_ERR, __FILE__, __LINE__, NULL,
1728 "Failed to initialize the dictionaries");
1729 exit(EXIT_FAILURE);
1730 }
1731
1732 if (do_coa) {
1734 if (!attr_coa_match_attr) {
1735 ERROR("Unknown or invalid CoA filter attribute %s", optarg);
1736 fr_exit_now(EXIT_FAILURE);
1737 }
1738
1739 /*
1740 * If there's no attribute given to match CoA to requests, use User-Name
1741 */
1743
1745 }
1747
1748 openssl3_init();
1749
1751
1752 /***********************************************************************
1753 *
1754 * We're done bootstrapping the libraries and dictionaries, read the input files.
1755 *
1756 ***********************************************************************/
1757
1758 /*
1759 * If no '-f' is specified, then we are reading from stdin.
1760 */
1761 if (fr_dlist_num_elements(&filenames) == 0) {
1762 rc_file_pair_t *files;
1763
1764 files = talloc_zero(talloc_autofree_context(), rc_file_pair_t);
1765 files->packets = "-";
1766 if (radclient_init(files, files) < 0) fr_exit_now(EXIT_FAILURE);
1767 }
1768
1769 if ((forced_id >= 0) && (fr_dlist_num_elements(&filenames) > 1)) {
1770 usage();
1771 }
1772
1773 /*
1774 * Walk over the list of filenames, creating the requests.
1775 */
1776 fr_dlist_foreach(&filenames, rc_file_pair_t, files) {
1777 if (radclient_init(files, files)) {
1778 ERROR("Failed parsing input files");
1779 fr_exit_now(EXIT_FAILURE);
1780 }
1781 }
1782
1783 /*
1784 * No packets were read. Die.
1785 */
1786 if (!rc_request_list_num_elements(&rc_request_list)) {
1787 ERROR("Nothing to send");
1788 fr_exit_now(EXIT_FAILURE);
1789 }
1790
1791 /***********************************************************************
1792 *
1793 * We're done reading files, open the socket, event loop, and start sending packets.
1794 *
1795 ***********************************************************************/
1796
1798 (fr_debug_lvl >= 2) ? _loop_status : NULL,
1799 NULL);
1800 if (!client_config.el) {
1801 ERROR("Failed opening event list: %s", fr_strerror());
1802 fr_exit_now(EXIT_FAILURE);
1803 }
1805
1806 /*
1807 * Set callbacks so that the socket is automatically
1808 * paused or resumed when the socket becomes writeable.
1809 */
1812 .failed = client_bio_failed,
1813
1814 .write_blocked = client_bio_write_pause,
1815 .write_resume = client_bio_write_resume,
1816
1817 .retry = (fr_debug_lvl > 0) ? client_packet_retry_log : NULL,
1818 .release = client_packet_release,
1819 };
1820
1821#ifdef STATIC_ANALYZER
1822 if (!autofree) fr_exit_now(EXIT_FAILURE);
1823#endif
1824
1825 /*
1826 * Open the RADIUS client bio, and then get the information associated with it.
1827 */
1829 if (!client_bio) {
1830 ERROR("Failed opening socket: %s", fr_strerror());
1831 fr_exit_now(EXIT_FAILURE);
1832 }
1833
1835 fr_assert(client_info != NULL);
1836
1837 if (forced_id >= 0) {
1839 fr_perror("radclient");
1840 fr_exit_now(EXIT_FAILURE);
1841 }
1842 }
1843
1844 if (do_coa) {
1845 // allocate a dedup server bio
1846 }
1847
1848 /*
1849 * Walk over the list of packets, updating to use the correct addresses, and sanity checking them.
1850 */
1851 rc_request_list_foreach(&rc_request_list, this) {
1852 if (radclient_sane(this) < 0) {
1853 fr_exit_now(EXIT_FAILURE);
1854 }
1855 }
1856
1857 /*
1858 * Always bounce through a connect(), even if we don't need it.
1859 *
1860 * Once the connect() passes, we start reading from the request list, and processing packets.
1861 */
1864 fr_perror("radclient");
1865 fr_exit_now(EXIT_FAILURE);
1866 }
1867
1868 /***********************************************************************
1869 *
1870 * Run the main event loop until we either see an error, or we have sent (and received) all of the packets.
1871 *
1872 ***********************************************************************/
1874
1875 /***********************************************************************
1876 *
1877 * We are done the event loop. Start cleaning things up.
1878 *
1879 ***********************************************************************/
1880 rc_request_list_talloc_free(&rc_request_list);
1881
1883
1885
1886 if (fr_dict_autofree(radclient_dict) < 0) {
1887 fr_perror("radclient");
1888 ret = EXIT_FAILURE;
1889 }
1890
1892
1894
1895 if (do_summary) {
1896 fr_perror("Packet summary:\n"
1897 "\tAccepted : %" PRIu64 "\n"
1898 "\tRejected : %" PRIu64 "\n"
1899 "\tLost : %" PRIu64 "\n"
1900 "\tPassed filter : %" PRIu64 "\n"
1901 "\tFailed filter : %" PRIu64,
1904 stats.lost,
1905 stats.passed,
1907 );
1908 }
1909
1910 /*
1911 * Ensure our atexit handlers run before any other
1912 * atexit handlers registered by third party libraries.
1913 */
1915
1916 openssl3_free();
1917
1918 if ((stats.lost > 0) || (stats.failed > 0)) return EXIT_FAILURE;
1919
1920 return ret;
1921}
static int const char char buffer[256]
Definition acutest.h:641
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_bio_error(_x)
Definition base.h:200
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
static uint8_t request[4]
static uint8_t reply[4]
#define RCSID(id)
Definition build.h:603
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:413
#define UNUSED
Definition build.h:415
fr_cmp_ret_t
Result of an ordering comparison.
Definition build.h:113
@ CMP_GT
a > b
Definition build.h:117
@ CMP_LT
a < b
Definition build.h:115
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
TALLOC_CTX * autofree
Definition common.c:29
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:1071
#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
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_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:40
static fr_dict_t const * dict_freeradius
Definition dhcpclient.c:78
static int retries
Definition dhcpclient.c:52
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition dict_util.c:5040
#define fr_dict_autofree(_to_free)
Definition dict.h:937
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:3600
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2717
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:316
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_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:4532
#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 an attribute which must be present for the module to function.
Definition dict.h:315
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:328
#define fr_dlist_foreach(_list_head, _type, _iter)
Iterate over the contents of a list.
Definition dlist.h:98
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
Definition dlist.h:921
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:360
#define FR_DLIST_HEAD(_name)
Expands to the type name used for the head wrapper structure.
Definition dlist.h:1143
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:257
Head of a doubly linked list.
Definition dlist.h:51
#define fr_event_fd_insert(...)
Definition event.h:247
#define fr_event_filter_update(...)
Definition event.h:239
#define FR_EVENT_RESUME(_s, _f)
Re-add the filter for a func from kevent.
Definition event.h:131
#define FR_EVENT_SUSPEND(_s, _f)
Temporarily remove the filter for a func from kevent.
Definition event.h:115
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:83
Callbacks for the FR_EVENT_FILTER_IO filter.
Definition event.h:188
Structure describing a modification to a filter's state.
Definition event.h:96
fr_socket_t socket
as connected socket
Definition fd.h:145
uint16_t src_port
our port
Definition fd.h:104
fr_ipaddr_t dst_ipaddr
their IP address
Definition fd.h:102
fr_bio_fd_type_t type
accept, connected, unconnected, etc.
Definition fd.h:93
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
Definition fd.h:63
@ FR_BIO_FD_TRANSPORT_TCP
TCP over IPv4 or IPv6.
Definition fd.h:79
@ FR_BIO_FD_TRANSPORT_UDP
UDP over IPv4 or IPv6.
Definition fd.h:80
int socket_type
SOCK_STREAM or SOCK_DGRAM.
Definition fd.h:95
uint16_t dst_port
their port
Definition fd.h:105
fr_bio_fd_transport_t transport_type
which transport, as a number instead of a name
Definition fd.h:97
fr_ipaddr_t src_ipaddr
our IP address
Definition fd.h:101
Configuration for sockets.
Definition fd.h:92
talloc_free(hp)
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
int af
Address family.
Definition inet.h:64
IPv4/6 prefix.
char const * fr_bio_strerror(ssize_t error)
Definition base.c:225
int packet_global_init(void)
Initialises the Net.
Definition packet.c:208
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:162
#define fr_time()
Definition event.c:58
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:2551
void fr_event_loop_exit(fr_event_list_t *el, int code)
Signal an event loop exit with the specified code.
Definition event.c:2398
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:1204
int fr_event_loop(fr_event_list_t *el)
Run an event loop.
Definition event.c:2420
Stores all information relating to an event list.
Definition event.c:375
int fr_debug_lvl
Definition log.c:41
FILE * fr_log_fp
Definition log.c:40
fr_log_t default_log
Definition log.c:308
#define fr_log(_log, _lvl, _file, _line, _fmt,...)
Definition log.h:172
#define fr_log_perror(_log, _type, _file, _line, _rules, _fmt,...)
Definition log.h:187
@ L_DST_STDOUT
Log to stdout.
Definition log.h:75
@ L_ERR
Error message.
Definition log.h:53
@ L_DBG
Only displayed when debugging is enabled.
Definition log.h:56
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:2897
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, 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:782
void fr_pair_validate_debug(fr_pair_t const *failed[2])
Write an error to the library errorbuff detailing the mismatch.
Definition pair.c:2069
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:707
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:1297
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:1641
fr_cmp_ret_t fr_pair_cmp_by_da(void const *a, void const *b)
Order attributes by their da.
Definition pair.c:1796
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:284
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:2104
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:47
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:2747
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:1778
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:2972
int fr_pair_list_afrom_file(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *out, FILE *fp, bool *pfiledone, bool allow_exec)
Read valuepairs from the fp up to End-Of-File.
int fr_radius_global_init(void)
Definition base.c:1313
int fr_radius_allow_reply(fr_radius_packet_code_t code, bool allowed[static FR_RADIUS_CODE_MAX])
Definition base.c:230
void fr_radius_global_free(void)
Definition base.c:1337
fr_table_num_sorted_t const fr_radius_request_name_table[]
Definition base.c:104
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
Definition base.c:115
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:487
#define fr_assert(_expr)
Definition rad_assert.h:37
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 int _rc_request_free(rc_request_t *request)
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 fr_bio_fd_config_t fd_config
static fr_dict_attr_t const * attr_coa_match_attr
static fr_bio_packet_t * client_bio
int main(int argc, char **argv)
static fr_dict_attr_t const * attr_chap_password
static fr_radius_client_config_t client_config
static int openssl3_init(void)
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_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
static int _loop_status(UNUSED fr_time_t now, fr_time_delta_t wake, UNUSED void *ctx)
static fr_cmp_ret_t request_cmp(void const *one, void const *two)
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
static fr_dict_attr_t const * attr_radclient_test_name
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 void radclient_get_port(fr_radius_packet_code_t type, uint16_t *port)
static void openssl3_free(void)
static fr_dict_attr_t const * attr_ms_chap_password
#define pair_update_request(_attr, _da)
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)
Read one CoA reply and potentially a filter.
#define REDEBUG(fmt,...)
#define RDEBUG(fmt,...)
#define rc_request_list_foreach(_list_head, _iter)
#define WARN(fmt,...)
uint64_t accepted
Requests to which we received a accept.
uint64_t rejected
Requests to which we received a reject.
uint64_t lost
Requests to which we received no response.
uint64_t failed
Requests which failed a filter.
char const * coa_filter
file containing the CoA filter we want to match
uint64_t passed
Requests which passed a filter.
char const * filters
The file containing the definition of the packet we want to match.
char const * coa_reply
file containing the CoA reply we want to send
char const * packets
The file containing the request packet.
#define RADIUS_MAX_ATTRIBUTES
Definition radius.h:39
#define FR_RADIUS_PACKET_CODE_VALID(_x)
Definition radius.h:51
static fr_dict_t const * dict_radius
Definition radsniff.c:93
static bool cleanup
Definition radsniff.c:59
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:128
void fr_rand_buffer(void *start, size_t length)
Definition rand.c:148
int 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:767
int fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:637
#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:203
The main red black tree structure.
Definition rb.h:71
char const *fr_packet_t * packet
< Module the request is currently being processed by.
Definition request.h:252
#define reply_pairs
Convenience macro for accessing the reply list.
Definition request.h:128
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:688
int fr_radius_client_fd_bio_cancel(fr_bio_packet_t *bio, fr_packet_t *packet)
Cancel one packet.
Definition client.c:553
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
size_t fr_radius_client_bio_outstanding(fr_bio_packet_t *bio)
Definition client.c:638
int fr_radius_client_bio_force_id(fr_bio_packet_t *bio, fr_radius_packet_code_t code, int id)
Definition client.c:658
fr_radius_client_bio_info_t const * fr_radius_client_bio_info(fr_bio_packet_t *bio)
Definition client.c:650
fr_aka_sim_id_type_t type
fr_pair_t * vp
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
fr_pair_list_t request_pairs
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:685
#define talloc_strndup(_ctx, _str, _len)
Definition talloc.h:150
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:55
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
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:430
int fr_time_start(void)
Initialize the local time.
Definition time.c:157
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:599
@ 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:6
void * uctx
Definition packet.h:79
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
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:69
int 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_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition pair_inline.c:42
static fr_slen_t parent
Definition pair.h:864
fr_time_delta_t irt
Initial transmission time.
Definition retry.h:33
int fd
File descriptor if this is a live socket.
Definition socket.h:86
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:558
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:737
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:581
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
fr_cmp_ret_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:770
#define fr_box_time_delta(_val)
Definition value.h:397