The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
radclient.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: 05282cc0e0a9840b81fc4bdb435f6b44f63c76aa $
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: 05282cc0e0a9840b81fc4bdb435f6b44f63c76aa $")
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/server/packet.h>
36#include <freeradius-devel/radius/list.h>
37#include <freeradius-devel/radius/radius.h>
38#include <freeradius-devel/util/chap.h>
39#ifdef HAVE_OPENSSL_SSL_H
40#include <openssl/ssl.h>
41#include <freeradius-devel/util/md4.h>
42#endif
43
44#ifdef HAVE_GETOPT_H
45# include <getopt.h>
46#endif
47
48
49typedef struct request_s request_t; /* to shut up warnings about mschap.h */
50
51#include "smbdes.h"
52#include "mschap.h"
53
54#include "radclient.h"
55
56#define pair_update_request(_attr, _da) do { \
57 _attr = fr_pair_find_by_da(&request->request_pairs, NULL, _da); \
58 if (!_attr) { \
59 _attr = fr_pair_afrom_da(request, _da); \
60 fr_assert(_attr != NULL); \
61 fr_pair_append(&request->request_pairs, _attr); \
62 } \
63 } while (0)
64
65static int retries = 3;
66static fr_time_delta_t timeout = fr_time_delta_wrap((int64_t)5 * NSEC); /* 5 seconds */
68static char *secret = NULL;
69static bool do_output = true;
70
71static const char *attr_coa_filter_name = "User-Name";
72
74
78static int resend_count = 1;
79static int ignore_count = 0;
80static bool done = true;
81static bool print_filename = false;
82static bool blast_radius = false;
83
86
87static int sockfd;
88static int last_used_id = -1;
89
90static int ipproto = IPPROTO_UDP;
91
92static bool do_coa = false;
93static int coafd;
95static fr_rb_tree_t *coa_tree = NULL;
96
98
99static FR_DLIST_HEAD(rc_request_list) rc_request_list;
100
101static char const *radclient_version = RADIUSD_VERSION_BUILD("radclient");
102
103static fr_dict_t const *dict_freeradius;
104static fr_dict_t const *dict_radius;
105
106static const fr_dict_autoload_t radclient_dict[] = {
107 { .out = &dict_freeradius, .proto = "freeradius" },
108 { .out = &dict_radius, .proto = "radius" },
110};
111
113
117
120
128
131
133
135 { .out = &attr_cleartext_password, .name = "Password.Cleartext", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
136 { .out = &attr_ms_chap_challenge, .name = "Vendor-Specific.Microsoft.CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
137 { .out = &attr_ms_chap_password, .name = "Password.MS-CHAP", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
138 { .out = &attr_ms_chap_response, .name = "Vendor-Specific.Microsoft.CHAP-Response", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
139
140 { .out = &attr_radclient_test_name, .name = "Radclient-Test-Name", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
141 { .out = &attr_request_authenticator, .name = "Request-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
142
143 { .out = &attr_radclient_coa_filename, .name = "Radclient-CoA-Filename", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
144 { .out = &attr_radclient_coa_filter, .name = "Radclient-CoA-Filter", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
145
146 { .out = &attr_chap_password, .name = "CHAP-Password", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
147 { .out = &attr_chap_challenge, .name = "CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
148 { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
149 { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
150 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
151 { .out = &attr_proxy_state, .name = "Proxy-State", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
152 { .out = &attr_message_authenticator, .name = "Message-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
153
155};
156
157static NEVER_RETURNS void usage(void)
158{
159 fprintf(stderr, "Usage: radclient [options] server[:port] <command> [<secret>]\n");
160
161 fprintf(stderr, " <command> One of auth, acct, status, coa, disconnect or auto.\n");
162 fprintf(stderr, " -4 Use IPv4 address of server\n");
163 fprintf(stderr, " -6 Use IPv6 address of server.\n");
164 fprintf(stderr, " -A <attribute> Use named 'attribute' to match CoA requests to packets. Default is User-Name\n");
165 fprintf(stderr, " -b Mandate checks for Blast RADIUS issue (this is not set by default).\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 <confdir> Set user dictionary directory (defaults to " CONFDIR ").\n");
169 fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
170 fprintf(stderr, " -f <request>[:<expected>][:<coa_reply>][:<coa_expected>] 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, " -n <num> Send N requests/s\n");
176 fprintf(stderr, " -o <port> Set CoA listening port (defaults to 3799)\n");
177 fprintf(stderr, " -p <num> Send 'num' packets from a file in parallel.\n");
178 fprintf(stderr, " -P <proto> Use proto (tcp or udp) for transport.\n");
179 fprintf(stderr, " -r <retries> If timeout, retry sending the packet 'retries' times.\n");
180 fprintf(stderr, " -s Print out summary information of auth results.\n");
181 fprintf(stderr, " -S <file> read secret from file, not command line.\n");
182 fprintf(stderr, " -t <timeout> Wait 'timeout' seconds before retrying (may be a floating point number).\n");
183 fprintf(stderr, " -v Show program version information.\n");
184 fprintf(stderr, " -x Debugging mode.\n");
185
186 fr_exit_now(EXIT_SUCCESS);
187}
188
189/*
190 * Free a radclient struct, which may (or may not)
191 * already be in the list.
192 */
193static int _rc_request_free(rc_request_t *request)
194{
195 rc_request_list_remove(&rc_request_list, request);
196
198 (void) fr_rb_delete_by_inline_node(coa_tree, &request->node);
199 }
200
201 return 0;
202}
203
204#ifdef HAVE_OPENSSL_SSL_H
205#include <openssl/provider.h>
206
207static OSSL_PROVIDER *openssl_default_provider = NULL;
208static OSSL_PROVIDER *openssl_legacy_provider = NULL;
209
210static int openssl3_init(void)
211{
212 /*
213 * Load the default provider for most algorithms
214 */
215 openssl_default_provider = OSSL_PROVIDER_load(NULL, "default");
216 if (!openssl_default_provider) {
217 ERROR("(TLS) Failed loading default provider");
218 return -1;
219 }
220
221 /*
222 * Needed for MD4
223 *
224 * https://www.openssl.org/docs/man3.0/man7/migration_guide.html#Legacy-Algorithms
225 */
226 openssl_legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
227 if (!openssl_legacy_provider) {
228 ERROR("(TLS) Failed loading legacy provider");
229 return -1;
230 }
231
232 fr_md5_openssl_init();
233 fr_md4_openssl_init();
234
235 return 0;
236}
237
238static void openssl3_free(void)
239{
240 if (openssl_default_provider && !OSSL_PROVIDER_unload(openssl_default_provider)) {
241 ERROR("Failed unloading default provider");
242 }
243 openssl_default_provider = NULL;
244
245 if (openssl_legacy_provider && !OSSL_PROVIDER_unload(openssl_legacy_provider)) {
246 ERROR("Failed unloading legacy provider");
247 }
248 openssl_legacy_provider = NULL;
249
250 fr_md5_openssl_free();
251 fr_md4_openssl_free();
252}
253#else
254#define openssl3_init() (0)
255#define openssl3_free()
256#endif
257
259 char const *password)
260{
261 unsigned int i;
262 uint8_t *p;
263 fr_pair_t *challenge, *reply;
264 uint8_t nthash[16];
265
268
270
271 fr_pair_append(list, challenge);
272
273 MEM(p = talloc_array(challenge, uint8_t, 8));
274 fr_pair_value_memdup_buffer_shallow(challenge, p, false);
275
276 for (i = 0; i < challenge->vp_length; i++) {
277 p[i] = fr_rand();
278 }
279
281 fr_pair_append(list, reply);
282 p = talloc_zero_array(reply, uint8_t, 50); /* really reply->da->flags.length */
284
285 p[1] = 0x01; /* NT hash */
286
287 if (mschap_nt_password_hash(nthash, password) < 0) return 0;
288
289 smbdes_mschap(nthash, challenge->vp_octets, p + 26);
290 return 1;
291}
292
293
294static int getport(char const *name)
295{
296 struct servent *svp;
297
298 svp = getservbyname(name, "udp");
299 if (!svp) return 0;
300
301 return ntohs(svp->s_port);
302}
303
304/*
305 * Set a port from the request type if we don't already have one
306 */
308{
309 switch (type) {
310 default:
314 if (*port == 0) *port = getport("radius");
315 if (*port == 0) *port = FR_AUTH_UDP_PORT;
316 return;
317
319 if (*port == 0) *port = getport("radacct");
320 if (*port == 0) *port = FR_ACCT_UDP_PORT;
321 return;
322
324 if (*port == 0) *port = FR_POD_UDP_PORT;
325 return;
326
328 if (*port == 0) *port = FR_COA_UDP_PORT;
329 return;
330
332 if (*port == 0) *port = 0;
333 return;
334 }
335}
336
337/*
338 * Resolve a port to a request type
339 */
341{
342 /*
343 * getport returns 0 if the service doesn't exist
344 * so we need to return early, to avoid incorrect
345 * codes.
346 */
347 if (port == 0) return FR_RADIUS_CODE_UNDEFINED;
348
349 if ((port == getport("radius")) || (port == FR_AUTH_UDP_PORT) || (port == FR_AUTH_UDP_PORT_ALT)) {
351 }
352 if ((port == getport("radacct")) || (port == FR_ACCT_UDP_PORT) || (port == FR_ACCT_UDP_PORT_ALT)) {
354 }
356
358}
359
360
362{
363 size_t i;
364
365 if (!vp || (vp->vp_type != FR_TYPE_OCTETS)) return true;
366
367 /*
368 * If it's 17 octets, it *might* be already encoded.
369 * Or, it might just be a 17-character password (maybe UTF-8)
370 * Check it for non-printable characters. The odds of ALL
371 * of the characters being 32..255 is (1-7/8)^17, or (1/8)^17,
372 * or 1/(2^51), which is pretty much zero.
373 */
374 for (i = 0; i < vp->vp_length; i++) {
375 if (vp->vp_octets[i] < 32) {
376 return true;
377 }
378 }
379
380 return false;
381}
382
383/** Read one CoA reply and potentially a filter
384 *
385 *
386 */
388 FILE *coa_reply, char const *reply_filename, bool *coa_reply_done,
389 FILE *coa_filter, char const *filter_filename, bool *coa_filter_done)
390{
391 rc_request_t *request;
392 fr_pair_t *vp;
393
394 /*
395 * Allocate it.
396 */
397 MEM(request = talloc_zero(parent, rc_request_t));
398 MEM(request->reply = fr_packet_alloc(request, false));
399
400 /*
401 * Don't initialize src/dst IP/port, or anything else. That will be read from the network.
402 */
403 fr_pair_list_init(&request->filter);
406
407 /*
408 * Read the reply VP's.
409 */
411 &request->reply_pairs, coa_reply, coa_reply_done, true) < 0) {
412 REDEBUG("Error parsing \"%s\"", reply_filename);
413 error:
414 talloc_free(request);
415 return -1;
416 }
417
418 /*
419 * The reply can be empty. In which case we just send an empty ACK.
420 */
422 if (vp) request->reply->code = vp->vp_uint32;
423
424 /*
425 * Read in filter VP's.
426 */
427 if (coa_filter) {
429 &request->filter, coa_filter, coa_filter_done, true) < 0) {
430 REDEBUG("Error parsing \"%s\"", filter_filename);
431 goto error;
432 }
433
434 if (*coa_filter_done && !*coa_reply_done) {
435 REDEBUG("Differing number of replies/filters in %s:%s "
436 "(too many replies))", reply_filename, 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 filters))", reply_filename, filter_filename);
443 goto error;
444 }
445
446 /*
447 * This allows efficient list comparisons later
448 */
450 }
451
452 request->name = parent->name;
453
454 /*
455 * Automatically set the response code from the request code
456 * (if one wasn't already set).
457 */
458 if (request->filter_code == FR_RADIUS_CODE_UNDEFINED) {
460 }
461
462 parent->coa = request;
463
464 /*
465 * Ensure that the packet is also tracked in the CoA tree.
466 */
469 ERROR("Failed inserting packet from %s into CoA tree", request->name);
470 fr_exit_now(1);
471 }
472
473 return 0;
474}
475
476/*
477 * Initialize a radclient data structure and add it to
478 * the global linked list.
479 */
480static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files)
481{
482 FILE *packets, *filters = NULL;
483
484 fr_pair_t *vp;
485 rc_request_t *request = NULL;
486 bool packets_done = false;
487 uint64_t num = 0;
488
489 FILE *coa_reply = NULL;
490 FILE *coa_filter = NULL;
491 bool coa_reply_done = false;
492 bool coa_filter_done = false;
493
494 fr_assert(files->packets != NULL);
495
496 /*
497 * Determine where to read the VP's from.
498 */
499 if (strcmp(files->packets, "-") != 0) {
500 packets = fopen(files->packets, "r");
501 if (!packets) {
502 ERROR("Error opening %s: %s", files->packets, fr_syserror(errno));
503 return -1;
504 }
505
506 /*
507 * Read in the pairs representing the expected response.
508 */
509 if (files->filters) {
510 filters = fopen(files->filters, "r");
511 if (!filters) {
512 ERROR("Error opening %s: %s", files->filters, fr_syserror(errno));
513 goto error;
514 }
515 }
516
517 if (files->coa_reply) {
518 coa_reply = fopen(files->coa_reply, "r");
519 if (!coa_reply) {
520 ERROR("Error opening %s: %s", files->coa_reply, fr_syserror(errno));
521 goto error;
522 }
523 }
524
525 if (files->coa_filter) {
526 coa_filter = fopen(files->coa_filter, "r");
527 if (!coa_filter) {
528 ERROR("Error opening %s: %s", files->coa_filter, fr_syserror(errno));
529 goto error;
530 }
531 }
532 } else {
533 packets = stdin;
534 }
535
536 /*
537 * Loop until the file is done.
538 */
539 do {
540 char const *coa_reply_filename = NULL;
541 char const *coa_filter_filename = NULL;
542
543 /*
544 * Allocate it.
545 */
546 MEM(request = talloc_zero(ctx, rc_request_t));
547 MEM(request->packet = fr_packet_alloc(request, true));
548 request->packet->uctx = request;
549
550 request->packet->socket.inet.src_ipaddr = client_ipaddr;
551 request->packet->socket.inet.src_port = client_port;
552 request->packet->socket.inet.dst_ipaddr = server_ipaddr;
553 request->packet->socket.inet.dst_port = server_port;
554 request->packet->socket.type = (ipproto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
555
556 request->files = files;
557 request->packet->id = last_used_id;
558 request->num = num++;
559
560 fr_pair_list_init(&request->filter);
563
564 /*
565 * Read the request VP's.
566 */
568 &request->request_pairs, packets, &packets_done, true) < 0) {
569 char const *input;
570
571 if ((files->packets[0] == '-') && (files->packets[1] == '\0')) {
572 input = "stdin";
573 } else {
574 input = files->packets;
575 }
576
577 REDEBUG("Error parsing \"%s\"", input);
578 goto error;
579 }
580
581 /*
582 * Skip empty entries
583 */
584 if (fr_pair_list_empty(&request->request_pairs)) {
585 WARN("Skipping \"%s\": No Attributes", files->packets);
586 talloc_free(request);
587 continue;
588 }
589
590 /*
591 * Read in filter VP's.
592 */
593 if (filters) {
594 bool filters_done;
595
597 &request->filter, filters, &filters_done, true) < 0) {
598 REDEBUG("Error parsing \"%s\"", files->filters);
599 goto error;
600 }
601
602 if (filters_done && !packets_done) {
603 REDEBUG("Differing number of packets/filters in %s:%s "
604 "(too many requests))", files->packets, files->filters);
605 goto error;
606 }
607
608 if (!filters_done && packets_done) {
609 REDEBUG("Differing number of packets/filters in %s:%s "
610 "(too many filters))", files->packets, files->filters);
611 goto error;
612 }
613
614 vp = fr_pair_find_by_da(&request->filter, NULL, attr_packet_type);
615 if (vp) {
616 request->filter_code = vp->vp_uint32;
617 fr_pair_delete(&request->filter, vp);
618 }
619
620 /*
621 * This allows efficient list comparisons later
622 */
624 }
625
626 /*
627 * Process special attributes
628 */
629 for (vp = fr_pair_list_head(&request->request_pairs);
630 vp;
631 vp = fr_pair_list_next(&request->request_pairs, vp)) {
632 /*
633 * Allow it to set the packet type in
634 * the attributes read from the file.
635 */
636 if (vp->da == attr_packet_type) {
637 request->packet->code = vp->vp_uint32;
638 } else if (vp->da == attr_request_authenticator) {
639 if (vp->vp_length >= sizeof(request->packet->vector)) {
640 memcpy(request->packet->vector, vp->vp_octets, sizeof(request->packet->vector));
641 } else {
642 memset(request->packet->vector, 0, sizeof(request->packet->vector));
643 memcpy(request->packet->vector, vp->vp_octets, vp->vp_length);
644 }
645 } else if (vp->da == attr_cleartext_password) {
646 request->password = vp;
647 /*
648 * Keep a copy of the the password attribute.
649 */
650 } else if (vp->da == attr_chap_password) {
651 /*
652 * If it's already hex, do nothing.
653 */
654 if ((vp->vp_length == 17) && (already_hex(vp))) continue;
655
656 /*
657 * CHAP-Password is octets, so it may not be zero terminated.
658 */
660 fr_pair_value_bstrndup(request->password, vp->vp_strvalue, vp->vp_length, true);
661 } else if (vp->da == attr_ms_chap_password) {
663 fr_pair_value_bstrndup(request->password, vp->vp_strvalue, vp->vp_length, true);
664
665 } else if (vp->da == attr_radclient_test_name) {
666 request->name = vp->vp_strvalue;
667
668 /*
669 * Allow these to be dynamically specified
670 * in the request file, as well as on the
671 * command line.
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
720 switch (radclient_get_code(request->packet->socket.inet.dst_port)) {
723 break;
724
727 break;
728
729 default:
731 break;
732 }
733 break;
734
736 REDEBUG("Packet-Type must be defined,"
737 "or a well known RADIUS port");
738 goto error;
739
740 default:
741 REDEBUG("Can't determine expected reply.Packet-Type for Packet-Type %i",
742 request->packet->code);
743 goto error;
744 }
745 /*
746 * Automatically set the request code from the response code
747 * (if one wasn't already set).
748 */
749 } else if (request->packet->code == FR_RADIUS_CODE_UNDEFINED) {
750 switch (request->filter_code) {
754 break;
755
758 break;
759
763 break;
764
768 break;
769
770 default:
771 REDEBUG("Can't determine expected Packet-Type for reply.Packet-Type %i",
772 request->filter_code);
773 goto error;
774 }
775 }
776
777 /*
778 * Automatically set the dst port (if one wasn't already set).
779 */
780 if (request->packet->socket.inet.dst_port == 0) {
781 radclient_get_port(request->packet->code, &request->packet->socket.inet.dst_port);
782 if (request->packet->socket.inet.dst_port == 0) {
783 REDEBUG("Can't determine destination port");
784 goto error;
785 }
786 }
787
788 /*
789 * Read in the CoA filename and filter.
790 */
791 if (coa_reply_filename) {
792 if (coa_reply) {
793 RDEBUG("Cannot specify CoA file on both the command line and via Radclient-CoA-Filename");
794 goto error;
795 }
796
797 coa_reply = fopen(coa_reply_filename, "r");
798 if (!coa_reply) {
799 ERROR("Error opening %s: %s", coa_reply_filename, fr_syserror(errno));
800 goto error;
801 }
802
803 if (coa_filter_filename) {
804 coa_filter = fopen(coa_filter_filename, "r");
805 if (!coa_filter) {
806 ERROR("Error opening %s: %s", coa_filter_filename, fr_syserror(errno));
807 goto error;
808 }
809 } else {
810 coa_filter = NULL;
811 }
812
813 /*
814 * Read in one CoA reply and/or filter
815 */
816 if (coa_init(request,
817 coa_reply, coa_reply_filename, &coa_reply_done,
818 coa_filter, coa_filter_filename, &coa_filter_done) < 0) {
819 goto error;
820 }
821
822 fclose(coa_reply);
823 coa_reply = NULL;
824 if (coa_filter) {
825 fclose(coa_filter);
826 coa_filter = NULL;
827 }
828 do_coa = true;
829
830 } else if (coa_reply) {
831 if (coa_init(request,
832 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 */
848 rc_request_list_insert_tail(&rc_request_list, request);
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 if (request->packet->socket.inet.dst_port == 0) {
887 request->packet->socket.inet.dst_port = server_port;
888 }
889 if (request->packet->socket.inet.dst_ipaddr.af == AF_UNSPEC) {
890 if (server_ipaddr.af == AF_UNSPEC) {
891 ERROR("No server was given, and request %" PRIu64 " in file %s did not contain "
892 "Packet-Dst-IP-Address", request->num, request->files->packets);
893 return -1;
894 }
895 request->packet->socket.inet.dst_ipaddr = server_ipaddr;
896 }
897 if (request->packet->code == 0) {
898 if (packet_code == -1) {
899 ERROR("Request was \"auto\", and request %" PRIu64 " in file %s did not contain Packet-Type",
900 request->num, request->files->packets);
901 return -1;
902 }
903 request->packet->code = packet_code;
904 }
905 request->packet->socket.fd = -1;
906
907 return 0;
908}
909
910
911static int8_t request_cmp(void const *one, void const *two)
912{
913 rc_request_t const *a = one, *b = two;
914 fr_pair_t *vp1, *vp2;
915
917 vp2 = fr_pair_find_by_da(&b->request_pairs, NULL, attr_coa_match_attr);
918
919 if (!vp1) return -1;
920 if (!vp2) return +1;
921
922 return fr_value_box_cmp(&vp1->data, &vp2->data);
923}
924
925
926/*
927 * Deallocate packet ID, etc.
928 */
929static void deallocate_id(rc_request_t *request)
930{
931 if (!request || !request->packet ||
932 (request->packet->id < 0)) {
933 return;
934 }
935
936 /*
937 * One more unused RADIUS ID.
938 */
940
941 /*
942 * If we've already sent a packet, free up the old one,
943 * and ensure that the next packet has a unique
944 * authentication vector.
945 */
946 if (request->packet->data) TALLOC_FREE(request->packet->data);
947 if (request->reply) fr_packet_free(&request->reply);
948}
949
950/*
951 * Send one packet.
952 */
953static int send_one_packet(rc_request_t *request)
954{
955 fr_pair_t *vp;
956
957 fr_assert(request->done == false);
958
959#ifdef STATIC_ANALYZER
960 if (!secret) fr_exit_now(1);
961#endif
962
963 /*
964 * Remember when we have to wake up, to re-send the
965 * request, of we didn't receive a reply.
966 */
969 }
970
971 /*
972 * Haven't sent the packet yet. Initialize it.
973 */
974 if (!request->tries || request->packet->id == -1) {
975 bool rcode;
976
977 fr_assert(request->reply == NULL);
978
979 /*
980 * Didn't find a free packet ID, we're not done,
981 * we don't sleep, and we stop trying to process
982 * this packet.
983 */
984 retry:
985 request->packet->socket.inet.src_ipaddr.af = server_ipaddr.af;
986 rcode = fr_packet_list_id_alloc(packet_list, ipproto, request->packet, NULL);
987 if (!rcode) {
988 int mysockfd;
989
990 if (ipproto == IPPROTO_TCP) {
991 mysockfd = fr_socket_client_tcp(NULL, NULL,
992 &request->packet->socket.inet.dst_ipaddr,
993 request->packet->socket.inet.dst_port, false);
994 if (mysockfd < 0) {
995 fr_perror("Error opening socket");
996 return -1;
997 }
998 } else {
999 uint16_t port = 0;
1000
1001 mysockfd = fr_socket_server_udp(&client_ipaddr, &port, NULL, true);
1002 if (mysockfd < 0) {
1003 fr_perror("Error opening socket");
1004 return -1;
1005 }
1006
1007 if (fr_socket_bind(mysockfd, NULL, &client_ipaddr, &port) < 0) {
1008 fr_perror("Error binding socket");
1009 return -1;
1010 }
1011 }
1012
1014 &request->packet->socket.inet.dst_ipaddr,
1015 request->packet->socket.inet.dst_port, NULL)) {
1016 ERROR("Can't add new socket");
1017 fr_exit_now(1);
1018 }
1019 goto retry;
1020 }
1021
1022 fr_assert(request->packet->id != -1);
1023 fr_assert(request->packet->data == NULL);
1024
1025 /*
1026 * Update the password, so it can be encrypted with the
1027 * new authentication vector.
1028 */
1029 if (request->password) {
1030 if ((vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_chap_password)) != NULL) {
1031 uint8_t buffer[17];
1032 fr_pair_t *challenge;
1033
1034 /*
1035 * Use CHAP-Challenge pair if present, otherwise create CHAP-Challenge and
1036 * populate with current Request Authenticator.
1037 *
1038 * Request Authenticator is re-calculated by fr_packet_sign
1039 */
1040 challenge = fr_pair_find_by_da(&request->request_pairs, NULL, attr_chap_challenge);
1041 if (!challenge || (challenge->vp_length < 7)) {
1043 fr_pair_value_memdup(challenge, request->packet->vector, RADIUS_AUTH_VECTOR_LENGTH, false);
1044 }
1045
1047 fr_rand() & 0xff, challenge->vp_octets, challenge->vp_length,
1048 request->password->vp_strvalue,
1049 request->password->vp_length);
1050 fr_pair_value_memdup(vp, buffer, sizeof(buffer), false);
1051
1052 } else if (fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_ms_chap_password) != NULL) {
1053 mschapv1_encode(request->packet, &request->request_pairs, request->password->vp_strvalue);
1054
1055 } else {
1056 DEBUG("WARNING: No password in the request");
1057 }
1058 }
1059
1060 request->timestamp = fr_time();
1061 request->tries = 1;
1062 request->resend++;
1063
1064 } else { /* request->packet->id >= 0 */
1065 fr_time_t now = fr_time();
1066
1067 /*
1068 * FIXME: Accounting packets are never retried!
1069 * The Acct-Delay-Time attribute is updated to
1070 * reflect the delay, and the packet is re-sent
1071 * from scratch!
1072 */
1073
1074 /*
1075 * Not time for a retry, do so.
1076 */
1077 if (fr_time_delta_lt(fr_time_sub(now, request->timestamp), timeout)) {
1078 fr_time_delta_t remaining;
1079
1080 remaining = fr_time_delta_sub(timeout, fr_time_sub(now, request->timestamp));
1081
1083 fr_time_delta_gt(sleep_time, remaining)) {
1084 sleep_time = remaining;
1085 }
1086 return 0;
1087 }
1088
1089 /*
1090 * We're not trying later, maybe the packet is done.
1091 */
1092 if (request->tries == retries) {
1093 fr_assert(request->packet->id >= 0);
1094
1095 /*
1096 * Delete the request from the tree of
1097 * outstanding requests.
1098 */
1100
1101 REDEBUG("No reply from server for ID %d socket %d",
1102 request->packet->id, request->packet->socket.fd);
1103 deallocate_id(request);
1104
1105 /*
1106 * Normally we mark it "done" when we've received
1107 * the reply, but this is a special case.
1108 */
1109 if (request->resend == resend_count) {
1110 request->done = true;
1111 }
1112 stats.lost++;
1113 return -1;
1114 }
1115
1116 /*
1117 * We are trying later.
1118 */
1119 request->timestamp = now;
1120 request->tries++;
1121 }
1122
1123 /*
1124 * If there's a Message-Authenticator in the packet, AND it has a "don't send" operator, then
1125 * delete it. We manually encode the packet (which also prints out Message-Authenticator), and
1126 * then manually remove the Message-Authenticator bytes from the packet. The encoder still
1127 * prints out that it's sending Message-Authenticator, but oh well.
1128 */
1130 if (vp && (vp->op == T_OP_CMP_FALSE) && !request->packet->data &&
1132 fr_pair_delete(&request->request_pairs, vp);
1133
1134 if (fr_radius_packet_encode(request->packet, &request->request_pairs, NULL, secret) < 0) {
1135 REDEBUG("Failed to encode packet for ID %d", request->packet->id);
1136 goto error;
1137 }
1138
1139 /*
1140 * Manually re-write the packet to get rid of Message-Authenticator.
1141 */
1142 if ((request->packet->data_len >= (RADIUS_HEADER_LENGTH + 18)) &&
1144 (request->packet->data[RADIUS_HEADER_LENGTH + 1] == 18)) {
1145 memmove(request->packet->data + RADIUS_HEADER_LENGTH,
1146 request->packet->data + RADIUS_HEADER_LENGTH + 18,
1147 request->packet->data_len - 18);
1148 request->packet->data_len -= 18;
1149 fr_nbo_from_uint16(request->packet->data + 2, request->packet->data_len);
1150 }
1151
1152 if (fr_radius_packet_sign(request->packet, NULL, secret) < 0) {
1153 REDEBUG("Failed to sign packet for ID %d", request->packet->id);
1154 goto error;
1155 }
1156 }
1157
1158 /*
1159 * Send the packet.
1160 */
1161 if (fr_radius_packet_send(request->packet, &request->request_pairs, NULL, secret) < 0) {
1162 REDEBUG("Failed to send packet for ID %d", request->packet->id);
1163 error:
1164 deallocate_id(request);
1165 request->done = true;
1166 return -1;
1167 }
1168
1169 fr_radius_packet_log(&default_log, request->packet, &request->request_pairs, false);
1170
1171 return 0;
1172}
1173
1174/*
1175 * Receive a CoA packet, maybe.
1176 */
1178{
1179 fd_set set;
1180 fr_time_delta_t our_wait_time;
1181 rc_request_t *request, *parent;
1182 fr_packet_t *packet;
1184
1185#ifdef STATIC_ANALYZER
1186 if (!secret) fr_exit_now(1);
1187#endif
1188
1189 /* And wait for reply, timing out as necessary */
1190 FD_ZERO(&set);
1191 FD_SET(coafd, &set);
1192
1193 our_wait_time = !fr_time_delta_ispos(wait_time) ? fr_time_delta_from_sec(0) : wait_time;
1194
1195 /*
1196 * No packet was received.
1197 */
1198 if (select(coafd + 1, &set, NULL, NULL, &fr_time_delta_to_timeval(our_wait_time)) <= 0) return 0;
1199
1200 /*
1201 * Read a packet from a network.
1202 */
1203 packet = fr_packet_recv(NULL, coafd, 0, 200, false);
1204 if (!packet) {
1205 DEBUG("Failed reading CoA packet");
1206 return 0;
1207 }
1208
1209 /*
1210 * Fails the signature validation: not a real reply
1211 */
1212 if (fr_radius_packet_verify(packet, NULL, secret) < 0) {
1213 DEBUG("CoA verification failed");
1214 talloc_free(packet);
1215 return 0;
1216 }
1217
1218 fr_pair_list_init(&my.request_pairs);
1219
1220 /*
1221 * Decode the packet before looking up the parent, so that we can compare the pairs.
1222 */
1223 if (fr_radius_decode_simple(packet, &my.request_pairs,
1224 packet->data, packet->data_len,
1225 NULL, secret) < 0) {
1226 DEBUG("Failed decoding CoA packet");
1227 talloc_free(packet);
1228 return 0;
1229 }
1230
1231 fr_radius_packet_log(&default_log, packet, &my.request_pairs, true);
1232
1233 /*
1234 * Find a Access-Request which has the same User-Name / etc. as this CoA packet.
1235 */
1236 my.name = "receive CoA request";
1237 my.packet = packet;
1238
1240 if (!parent) {
1241 DEBUG("No matching request packet for CoA packet %u %u", packet->data[0], packet->data[1]);
1242 talloc_free(packet);
1243 return 0;
1244 }
1245 fr_assert(parent->coa);
1246
1247 request = parent->coa;
1248 request->packet = talloc_steal(request, packet);
1249
1251 fr_pair_list_append(&request->request_pairs, &my.request_pairs);
1252
1253 /*
1254 * If we had an expected response code, check to see if the
1255 * packet matched that.
1256 */
1257 if (request->packet->code != request->filter_code) {
1258 if (FR_RADIUS_PACKET_CODE_VALID(request->reply->code)) {
1259 REDEBUG("%s: Expected %s got %s", request->name, fr_radius_packet_name[request->filter_code],
1260 fr_radius_packet_name[request->packet->code]);
1261 } else {
1262 REDEBUG("%s: Expected %u got %i", request->name, request->filter_code,
1263 request->packet->code);
1264 }
1265 stats.failed++;
1266
1267 /*
1268 * Check if the contents of the packet matched the filter
1269 */
1270 } else if (fr_pair_list_empty(&request->filter)) {
1271 stats.passed++;
1272
1273 } else {
1274 fr_pair_t const *failed[2];
1275
1277 if (fr_pair_validate(failed, &request->filter, &request->request_pairs)) {
1278 RDEBUG("%s: CoA request passed filter", request->name);
1279 stats.passed++;
1280 } else {
1281 fr_pair_validate_debug(failed);
1282 REDEBUG("%s: CoA Request for failed filter", request->name);
1283 stats.failed++;
1284 }
1285 }
1286
1287 request->reply->id = request->packet->id;
1288
1289 request->reply->socket.type = SOCK_DGRAM;
1290 request->reply->socket.af = client_ipaddr.af;
1291 request->reply->socket.fd = coafd;
1292 request->reply->socket.inet.src_ipaddr = client_ipaddr;
1293 request->reply->socket.inet.src_port = coa_port;
1294 request->reply->socket.inet.dst_ipaddr = packet->socket.inet.src_ipaddr;
1295 request->reply->socket.inet.dst_port = packet->socket.inet.src_port;
1296
1297 if (!request->reply->code) switch (packet->code) {
1299 request->reply->code = FR_RADIUS_CODE_COA_ACK;
1300 break;
1301
1304 break;
1305
1306 default:
1307 RDEBUG("Failed getting reply packet type");
1308 return 0;
1309 }
1310
1311 fr_radius_packet_log(&default_log, request->reply, &request->reply_pairs, false);
1312
1313
1314 /*
1315 * Send reply.
1316 */
1317 if (fr_radius_packet_send(request->reply, &request->reply_pairs, packet, secret) < 0) {
1318 REDEBUG("Failed sending CoA reply");
1319 return 0;
1320 }
1321
1323
1324 /*
1325 * No longer waiting for a CoA packet for this request.
1326 */
1327 TALLOC_FREE(parent->coa);
1328 return 0;
1329}
1330
1331
1332/*
1333 * Do Blast RADIUS checks.
1334 *
1335 * The request is an Access-Request, and does NOT contain Proxy-State.
1336 *
1337 * The reply is a raw packet, and is NOT yet decoded.
1338 */
1339static int blast_radius_check(rc_request_t *request, fr_packet_t *reply)
1340{
1341 uint8_t *attr, *end;
1342 fr_pair_t *vp;
1343 bool have_message_authenticator = false;
1344
1345 /*
1346 * We've received a raw packet. Nothing has (as of yet) checked
1347 * anything in it other than the length, and that it's a
1348 * well-formed RADIUS packet.
1349 */
1350 switch (reply->data[0]) {
1355 if (reply->data[1] != request->packet->id) {
1356 ERROR("Invalid reply ID %d to Access-Request ID %d", reply->data[1], request->packet->id);
1357 return -1;
1358 }
1359 break;
1360
1361 default:
1362 ERROR("Invalid reply code %d to Access-Request", reply->data[0]);
1363 return -1;
1364 }
1365
1366 /*
1367 * If the reply has a Message-Authenticator, then it MIGHT be fine.
1368 */
1369 attr = reply->data + 20;
1370 end = reply->data + reply->data_len;
1371
1372 /*
1373 * It should be the first attribute, so we warn if it isn't there.
1374 *
1375 * But it's not a fatal error.
1376 */
1377 if (blast_radius && (attr[0] != FR_MESSAGE_AUTHENTICATOR)) {
1378 RDEBUG("WARNING The %s reply packet does not have Message-Authenticator as the first attribute. The packet may be vulnerable to Blast RADIUS attacks.",
1379 fr_radius_packet_name[reply->data[0]]);
1380 }
1381
1382 /*
1383 * Set up for Proxy-State checks.
1384 *
1385 * If we see a Proxy-State in the reply which we didn't send, then it's a Blast RADIUS attack.
1386 */
1388
1389 while (attr < end) {
1390 /*
1391 * Blast RADIUS work-arounds require that
1392 * Message-Authenticator is the first attribute in the
1393 * reply. Note that we don't check for it being the
1394 * first attribute, but simply that it exists.
1395 *
1396 * That check is a balance between securing the reply
1397 * packet from attacks, and not violating the RFCs which
1398 * say that there is no order to attributes in the
1399 * packet.
1400 *
1401 * However, no matter the status of the '-b' flag we
1402 * still can check for the signature of the attack, and
1403 * discard packets which are suspicious. This behavior
1404 * protects radclient from the attack, without mandating
1405 * new behavior on the server side.
1406 *
1407 * Note that we don't set the '-b' flag by default.
1408 * radclient is intended for testing / debugging, and is
1409 * not intended to be used as part of a secure login /
1410 * user checking system.
1411 */
1412 if (attr[0] == FR_MESSAGE_AUTHENTICATOR) {
1413 have_message_authenticator = true;
1414 goto next;
1415 }
1416
1417 /*
1418 * If there are Proxy-State attributes in the reply, they must
1419 * match EXACTLY the Proxy-State attributes in the request.
1420 *
1421 * Note that we don't care if there are more Proxy-States
1422 * in the request than in the reply. The Blast RADIUS
1423 * issue requires _adding_ Proxy-State attributes, and
1424 * cannot work when the server _deletes_ Proxy-State
1425 * attributes.
1426 */
1427 if (attr[0] == FR_PROXY_STATE) {
1428 if (!vp || (vp->vp_length != (size_t) (attr[1] - 2)) || (memcmp(vp->vp_octets, attr + 2, vp->vp_length) != 0)) {
1429 ERROR("Invalid reply to Access-Request ID %d - Discarding packet due to Blast RADIUS attack being detected.", request->packet->id);
1430 ERROR("We received a Proxy-State in the reply which we did not send, or which is different from what we sent.");
1431 return -1;
1432 }
1433
1435 }
1436
1437 next:
1438 attr += attr[1];
1439 }
1440
1441 /*
1442 * If "-b" is set, then we require Message-Authenticator in the reply.
1443 */
1444 if (blast_radius && !have_message_authenticator) {
1445 ERROR("The %s reply packet does not contain Message-Authenticator - discarding packet due to Blast RADIUS checks.",
1446 fr_radius_packet_name[reply->data[0]]);
1447 return -1;
1448 }
1449
1450 /*
1451 * The packet doesn't look like it's a Blast RADIUS attack. The
1452 * caller will now verify the packet signature.
1453 */
1454 return 0;
1455}
1456
1457/*
1458 * Receive one packet, maybe.
1459 */
1461{
1462 int rcode;
1463 fd_set set;
1464 fr_time_delta_t our_wait_time;
1465 rc_request_t *request;
1466 fr_packet_t *reply, *packet;
1467 volatile int max_fd;
1468
1469#ifdef STATIC_ANALYZER
1470 if (!secret) fr_exit_now(1);
1471#endif
1472
1473 /* And wait for reply, timing out as necessary */
1474 FD_ZERO(&set);
1475
1476 max_fd = fr_packet_list_fd_set(packet_list, &set);
1477 if (max_fd < 0) fr_exit_now(1); /* no sockets to listen on! */
1478
1479 our_wait_time = !fr_time_delta_ispos(wait_time) ? fr_time_delta_from_sec(0) : wait_time;
1480
1481 if (do_coa && fr_rb_num_elements(coa_tree) > 0) {
1482 FD_SET(coafd, &set);
1483 if (coafd >= max_fd) max_fd = coafd + 1;
1484 }
1485
1486 /*
1487 * See if a packet was received.
1488 */
1489retry:
1490 if (select(max_fd, &set, NULL, NULL, &fr_time_delta_to_timeval(our_wait_time)) <= 0) return 0;
1491
1492 /*
1493 * Read a CoA packet
1494 */
1495 if (FD_ISSET(coafd, &set)) {
1497 FD_CLR(coafd, &set);
1498 our_wait_time = fr_time_delta_from_sec(0);
1499 goto retry;
1500 }
1501
1502 /*
1503 * Look for the packet.
1504 */
1505 rcode = fr_packet_list_recv(packet_list, &set, NULL, &reply, RADIUS_MAX_ATTRIBUTES, false);
1506 if (rcode < 0) {
1507 ERROR("Received bad packet");
1508
1509 /*
1510 * If the packet is bad, we close the socket.
1511 * I'm not sure how to do that now, so we just
1512 * die...
1513 */
1514 if (ipproto == IPPROTO_TCP) fr_exit_now(1);
1515 return -1; /* bad packet */
1516 }
1517
1518 /*
1519 * We don't use udpfromto. So if we bind to "*", we want
1520 * to find replies sent to 192.0.2.4. Therefore, we
1521 * force all replies to have the one address we know
1522 * about, no matter what real address they were sent to.
1523 *
1524 * This only works if were not using any of the
1525 * Packet-* attributes, or running with 'auto'.
1526 */
1527 reply->socket.inet.dst_ipaddr = client_ipaddr;
1528 reply->socket.inet.dst_port = client_port;
1529
1530 /*
1531 * TCP sockets don't use recvmsg(), and thus don't get
1532 * the source IP/port. However, since they're TCP, we
1533 * know what the source IP/port is, because that's where
1534 * we connected to.
1535 */
1536 if (ipproto == IPPROTO_TCP) {
1537 reply->socket.inet.src_ipaddr = server_ipaddr;
1538 reply->socket.inet.src_port = server_port;
1539 }
1540
1542 if (!packet) {
1543 ERROR("Received reply to request we did not send. (id=%d socket %d)",
1544 reply->id, reply->socket.fd);
1545 fr_packet_free(&reply);
1546 return -1; /* got reply to packet we didn't send */
1547 }
1548 request = packet->uctx;
1549
1550 /*
1551 * We want radclient to be able to send any packet, including
1552 * imperfect ones. However, we do NOT want to be vulnerable to
1553 * the "Blast RADIUS" issue. Instead of adding command-line
1554 * flags to enable/disable similar flags to what the server
1555 * sends, we just do a few more smart checks to double-check
1556 * things.
1557 */
1558 if ((request->packet->code == FR_RADIUS_CODE_ACCESS_REQUEST) &&
1559 blast_radius_check(request, reply) < 0) {
1560 fr_packet_free(&reply);
1561 return -1;
1562 }
1563
1564 /*
1565 * Fails the signature validation: not a real reply.
1566 * FIXME: Silently drop it and listen for another packet.
1567 */
1568 if (fr_radius_packet_verify(reply, request->packet, secret) < 0) {
1569 REDEBUG("Reply verification failed");
1570 stats.lost++;
1571 goto packet_done; /* shared secret is incorrect */
1572 }
1573
1574 if (print_filename) {
1575 RDEBUG("%s response code %d", request->files->packets, reply->code);
1576 }
1577
1578 if (request->tries < ignore_count) {
1579 RDEBUG("Ignoring response %d due to -e ignore_count=%d", request->tries, ignore_count);
1580 goto packet_done;
1581 }
1582
1583 deallocate_id(request);
1584 request->reply = reply;
1585 reply = NULL;
1586
1587 /*
1588 * If this fails, we're out of memory.
1589 */
1590 if (fr_radius_decode_simple(request, &request->reply_pairs,
1591 request->reply->data, request->reply->data_len,
1592 request->packet->vector, secret) < 0) {
1593 REDEBUG("Reply decode failed");
1594 stats.lost++;
1595 goto packet_done;
1596 }
1597 PAIR_LIST_VERIFY(&request->reply_pairs);
1598 fr_radius_packet_log(&default_log, request->reply, &request->reply_pairs, true);
1599
1600 /*
1601 * Increment counters...
1602 */
1603 switch (request->reply->code) {
1608 stats.accepted++;
1609 break;
1610
1612 break;
1613
1615 stats.error++;
1616 break;
1617 default:
1618 stats.rejected++;
1619 }
1620
1621 fr_strerror_clear(); /* Clear strerror buffer */
1622
1623 /*
1624 * If we had an expected response code, check to see if the
1625 * packet matched that.
1626 */
1627 if ((request->filter_code != FR_RADIUS_CODE_UNDEFINED) && (request->reply->code != request->filter_code)) {
1628 if (FR_RADIUS_PACKET_CODE_VALID(request->reply->code)) {
1629 REDEBUG("%s: Expected %s got %s", request->name, fr_radius_packet_name[request->filter_code],
1630 fr_radius_packet_name[request->reply->code]);
1631 } else {
1632 REDEBUG("%s: Expected %u got %i", request->name, request->filter_code,
1633 request->reply->code);
1634 }
1635 stats.failed++;
1636 /*
1637 * Check if the contents of the packet matched the filter
1638 */
1639 } else if (fr_pair_list_empty(&request->filter)) {
1640 stats.passed++;
1641 } else {
1642 fr_pair_t const *failed[2];
1643
1645 if (fr_pair_validate(failed, &request->filter, &request->reply_pairs)) {
1646 RDEBUG("%s: Response passed filter", request->name);
1647 stats.passed++;
1648 } else {
1649 fr_pair_validate_debug(failed);
1650 REDEBUG("%s: Response for failed filter", request->name);
1651 stats.failed++;
1652 }
1653 }
1654
1655 if (request->resend == resend_count) {
1656 request->done = true;
1657 }
1658
1659packet_done:
1660 fr_packet_free(&request->reply);
1661 fr_packet_free(&reply); /* may be NULL */
1662
1663 return 0;
1664}
1665
1666/**
1667 *
1668 * @hidecallgraph
1669 */
1670int main(int argc, char **argv)
1671{
1672 int ret = EXIT_SUCCESS;
1673 int c;
1674 char const *confdir = CONFDIR;
1675 char const *dict_dir = DICTDIR;
1676 char filesecret[256];
1677 FILE *fp;
1678 int do_summary = false;
1679 int persec = 0;
1680 int parallel = 1;
1681 int force_af = AF_UNSPEC;
1682#ifndef NDEBUG
1683 TALLOC_CTX *autofree;
1684#endif
1685 fr_dlist_head_t filenames;
1686 rc_request_t *request;
1687
1688 /*
1689 * It's easier having two sets of flags to set the
1690 * verbosity of library calls and the verbosity of
1691 * radclient.
1692 */
1693 fr_debug_lvl = 0;
1694 fr_log_fp = stdout;
1695
1696 /*
1697 * Must be called first, so the handler is called last
1698 */
1700
1701#ifndef NDEBUG
1703
1704 if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
1705 fr_perror("radclient");
1706 fr_exit_now(EXIT_FAILURE);
1707 }
1708#endif
1709
1710 talloc_set_log_stderr();
1711
1712 rc_request_list_talloc_init(&rc_request_list);
1713
1714 fr_dlist_talloc_init(&filenames, rc_file_pair_t, entry);
1715
1716 /*
1717 * Always log to stdout
1718 */
1720 default_log.fd = STDOUT_FILENO;
1721 default_log.print_level = false;
1722
1723 while ((c = getopt(argc, argv, "46bc:A:C:d:D:e:f:Fhi:n:o:p:P:r:sS:t:vx")) != -1) switch (c) {
1724 case '4':
1725 force_af = AF_INET;
1726 break;
1727
1728 case '6':
1729 force_af = AF_INET6;
1730 break;
1731
1732 case 'A':
1733 attr_coa_filter_name = optarg;
1734 break;
1735
1736 case 'b':
1737 blast_radius = true;
1738 break;
1739
1740 case 'c':
1741 if (!isdigit((uint8_t) *optarg)) usage();
1742
1743 resend_count = atoi(optarg);
1744
1745 if (resend_count < 1) usage();
1746 break;
1747
1748 case 'C':
1749 {
1750 int tmp;
1751
1752 if (strchr(optarg, ':')) {
1754 optarg, -1, AF_UNSPEC, true, false) < 0) {
1755 fr_perror("Failed parsing source address");
1756 fr_exit_now(1);
1757 }
1758 break;
1759 }
1760
1761 tmp = atoi(optarg);
1762 if (tmp < 1 || tmp > 65535) usage();
1763
1764 client_port = (uint16_t)tmp;
1765 }
1766 break;
1767
1768 case 'D':
1769 dict_dir = optarg;
1770 break;
1771
1772 case 'd':
1773 confdir = optarg;
1774 break;
1775
1776 case 'e': /* magical extra stuff */
1777 if (strncmp(optarg, "ignore_count=", 13) == 0) {
1778 ignore_count = atoi(optarg + 13);
1779 break;
1780 }
1781 usage();
1782
1783 /*
1784 * packet,filter,coa_reply,coa_filter
1785 */
1786 case 'f':
1787 {
1788 char const *p;
1789 rc_file_pair_t *files;
1790
1791 MEM(files = talloc_zero(talloc_autofree_context(), rc_file_pair_t));
1792
1793 /*
1794 * Commas are nicer than colons.
1795 */
1796 c = ':';
1797
1798 p = strchr(optarg, c);
1799 if (!p) {
1800 c = ',';
1801 p = strchr(optarg, c);
1802 }
1803 if (!p) {
1804 files->packets = optarg;
1805 files->filters = NULL;
1806 } else {
1807 char *q;
1808
1809 MEM(files->packets = talloc_strndup(files, optarg, p - optarg));
1810 files->filters = p + 1;
1811
1812 /*
1813 * Look for CoA filename
1814 */
1815 q = strchr(files->filters, c);
1816 if (q) {
1817 do_coa = true;
1818
1819 *(q++) = '\0';
1820 files->coa_reply = q;
1821
1822 q = strchr(files->coa_reply, c);
1823 if (q) {
1824 *(q++) = '\0';
1825 files->coa_filter = q;
1826 }
1827 }
1828 }
1829 fr_dlist_insert_tail(&filenames, files);
1830 }
1831 break;
1832
1833 case 'F':
1834 print_filename = true;
1835 break;
1836
1837 case 'i':
1838 if (!isdigit((uint8_t) *optarg)) {
1839 usage();
1840 }
1841 last_used_id = atoi(optarg);
1842 if ((last_used_id < 0) || (last_used_id > 255)) {
1843 usage();
1844 }
1845 break;
1846
1847 case 'n':
1848 persec = atoi(optarg);
1849 if (persec <= 0) usage();
1850 break;
1851
1852 case 'o':
1853 coa_port = atoi(optarg);
1854 break;
1855
1856 /*
1857 * Note that sending MANY requests in
1858 * parallel can over-run the kernel
1859 * queues, and Linux will happily discard
1860 * packets. So even if the server responds,
1861 * the client may not see the reply.
1862 */
1863 case 'p':
1864 parallel = atoi(optarg);
1865 if (parallel <= 0) usage();
1866 break;
1867
1868 case 'P':
1869 if (!strcmp(optarg, "tcp")) {
1870 ipproto = IPPROTO_TCP;
1871 } else if (!strcmp(optarg, "udp")) {
1872 ipproto = IPPROTO_UDP;
1873 } else {
1874 usage();
1875 }
1876 break;
1877
1878 case 'r':
1879 if (!isdigit((uint8_t) *optarg)) usage();
1880 retries = atoi(optarg);
1881 if ((retries == 0) || (retries > 1000)) usage();
1882 break;
1883
1884 case 's':
1885 do_summary = true;
1886 break;
1887
1888 case 'S':
1889 {
1890 char *p;
1891 fp = fopen(optarg, "r");
1892 if (!fp) {
1893 ERROR("Error opening %s: %s", optarg, fr_syserror(errno));
1894 fr_exit_now(1);
1895 }
1896 if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
1897 ERROR("Error reading %s: %s", optarg, fr_syserror(errno));
1898 fr_exit_now(1);
1899 }
1900 fclose(fp);
1901
1902 /* truncate newline */
1903 p = filesecret + strlen(filesecret) - 1;
1904 while ((p >= filesecret) &&
1905 (*p < ' ')) {
1906 *p = '\0';
1907 --p;
1908 }
1909
1910 if (strlen(filesecret) < 2) {
1911 ERROR("Secret in %s is too short", optarg);
1912 fr_exit_now(1);
1913 }
1914 secret = talloc_strdup(NULL, filesecret);
1915 }
1916 break;
1917
1918 case 't':
1919 if (fr_time_delta_from_str(&timeout, optarg, strlen(optarg), FR_TIME_RES_SEC) < 0) {
1920 fr_perror("Failed parsing timeout value");
1921 fr_exit_now(EXIT_FAILURE);
1922 }
1923 break;
1924
1925 case 'v':
1926 fr_debug_lvl = 1;
1927 DEBUG("%s", radclient_version);
1928 fr_exit_now(0);
1929
1930 case 'x':
1931 fr_debug_lvl++;
1932 if (fr_debug_lvl > 1) default_log.print_level = true;
1933 break;
1934
1935 case 'h':
1936 default:
1937 usage();
1938 }
1939 argc -= (optind - 1);
1940 argv += (optind - 1);
1941
1942 if ((argc < 3) || ((secret == NULL) && (argc < 4))) {
1943 ERROR("Insufficient arguments");
1944 usage();
1945 }
1946 /*
1947 * Mismatch between the binary and the libraries it depends on
1948 */
1950 fr_perror("radclient");
1951 fr_exit_now(EXIT_FAILURE);
1952 }
1953
1954 if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) {
1955 fr_perror("radclient");
1956 fr_exit_now(EXIT_FAILURE);
1957 }
1958
1959 if (fr_radius_global_init() < 0) {
1960 fr_perror("radclient");
1961 fr_exit_now(EXIT_FAILURE);
1962 }
1963
1964 if (fr_dict_autoload(radclient_dict) < 0) {
1965 fr_perror("radclient");
1966 exit(EXIT_FAILURE);
1967 }
1968
1970 fr_perror("radclient");
1971 exit(EXIT_FAILURE);
1972 }
1973
1975 fr_log_perror(&default_log, L_ERR, __FILE__, __LINE__, NULL,
1976 "Failed to initialize the dictionaries");
1977 exit(EXIT_FAILURE);
1978 }
1979
1980 if (do_coa) {
1982 if (!attr_coa_match_attr) {
1983 ERROR("Unknown or invalid CoA filter attribute %s", attr_coa_filter_name);
1984 fr_exit_now(1);
1985 }
1986
1988 }
1990
1991 fr_strerror_clear(); /* Clear the error buffer */
1992
1993 /*
1994 * Get the request type
1995 */
1996 if (!isdigit((uint8_t) argv[2][0])) {
1998 if (packet_code == -2) {
1999 ERROR("Unrecognised request type \"%s\"", argv[2]);
2000 usage();
2001 }
2002 } else {
2003 packet_code = atoi(argv[2]);
2004 }
2005
2006 /*
2007 * Resolve hostname.
2008 */
2009 if (strcmp(argv[1], "-") != 0) {
2010 if (fr_inet_pton_port(&server_ipaddr, &server_port, argv[1], -1, force_af, true, true) < 0) {
2011 fr_perror("radclient");
2012 fr_exit_now(1);
2013 }
2014
2015 /*
2016 * Work backwards from the port to determine the packet type
2017 */
2019 }
2021
2022 /*
2023 * Add the secret.
2024 */
2025 if (argv[3]) {
2027 secret = talloc_strdup(NULL, argv[3]);
2028 }
2029
2030 /*
2031 * If no '-f' is specified, we're reading from stdin.
2032 */
2033 if (fr_dlist_num_elements(&filenames) == 0) {
2034 rc_file_pair_t *files;
2035
2036 files = talloc_zero(talloc_autofree_context(), rc_file_pair_t);
2037 files->packets = "-";
2038 if (radclient_init(files, files) < 0) fr_exit_now(1);
2039 }
2040
2041 /*
2042 * Walk over the list of filenames, creating the requests.
2043 */
2044 fr_dlist_foreach(&filenames, rc_file_pair_t, files) {
2045 if (radclient_init(files, files)) {
2046 ERROR("Failed parsing input files");
2047 fr_exit_now(1);
2048 }
2049 }
2050
2051 /*
2052 * No packets read. Die.
2053 */
2054 if (!rc_request_list_num_elements(&rc_request_list)) {
2055 ERROR("Nothing to send");
2056 fr_exit_now(1);
2057 }
2058
2059 if (openssl3_init() < 0) {
2060 fr_perror("radclient");
2061 fr_exit_now(EXIT_FAILURE);
2062 }
2063
2064 /*
2065 * Bind to the first specified IP address and port.
2066 * This means we ignore later ones.
2067 */
2068 request = rc_request_list_head(&rc_request_list);
2069
2070 if (client_ipaddr.af == AF_UNSPEC) {
2071 if (request->packet->socket.inet.src_ipaddr.af == AF_UNSPEC) {
2072 memset(&client_ipaddr, 0, sizeof(client_ipaddr));
2074 } else {
2075 client_ipaddr = request->packet->socket.inet.src_ipaddr;
2076 }
2077 }
2078
2079 if (client_port == 0) client_port = request->packet->socket.inet.src_port;
2080
2081 if (ipproto == IPPROTO_TCP) {
2082 sockfd = fr_socket_client_tcp(NULL, NULL, &server_ipaddr, server_port, false);
2083 if (sockfd < 0) {
2084 ERROR("Failed opening socket");
2085 return -1;
2086 }
2087
2088 } else {
2090 if (sockfd < 0) {
2091 fr_perror("Error opening socket");
2092 return -1;
2093 }
2094
2095 if (fr_socket_bind(sockfd, NULL, &client_ipaddr, &client_port) < 0) {
2096 fr_perror("Error binding socket");
2097 return -1;
2098 }
2099 }
2100
2101 if (do_coa) {
2103 if (coafd < 0) {
2104 fr_perror("Error opening CoA socket");
2105 return -1;
2106 }
2107
2108 if (fr_socket_bind(coafd, NULL, &client_ipaddr, &coa_port) < 0) {
2109 fr_perror("Error binding socket");
2110 return -1;
2111 }
2112 }
2113
2116 server_port, NULL)) {
2117 ERROR("Failed adding socket");
2118 fr_exit_now(1);
2119 }
2120
2121 /*
2122 * Walk over the list of packets, sanity checking
2123 * everything.
2124 */
2125 rc_request_list_foreach(&rc_request_list, this) {
2126 this->packet->socket.inet.src_ipaddr = client_ipaddr;
2127 this->packet->socket.inet.src_port = client_port;
2128 if (radclient_sane(this) != 0) {
2129 fr_exit_now(1);
2130 }
2131 }
2132
2133 /*
2134 * Walk over the packets to send, until
2135 * we're all done.
2136 *
2137 * FIXME: This currently busy-loops until it receives
2138 * all of the packets. It should really have some sort of
2139 * send packet, get time to wait, select for time, etc.
2140 * loop.
2141 */
2142 do {
2143 int n = parallel;
2144 char const *filename = NULL;
2145
2146 done = true;
2148
2149 /*
2150 * Walk over the packets, sending them.
2151 *
2152 * This essentially ends up handling
2153 * retries as well, as requests to
2154 * retry stay in the request list, and
2155 * then get sent again on the next
2156 * iteration of the outer loop.
2157 */
2158 rc_request_list_foreach(&rc_request_list, this) {
2159 /*
2160 * If there's a packet to receive,
2161 * receive it, but don't wait for a
2162 * packet.
2163 */
2165
2166 /*
2167 * This packet is done. Delete it.
2168 */
2169 if (this->done) {
2170 /*
2171 * We still have a CoA reply to
2172 * receive for this packet.
2173 */
2174 if (this->coa) {
2176 if (this->coa) continue;
2177 }
2178
2179 talloc_free(this);
2180 continue;
2181 }
2182
2183 /*
2184 * Packets from multiple '-f' are sent
2185 * in parallel.
2186 *
2187 * Packets from one file are sent in
2188 * series, unless '-p' is specified, in
2189 * which case N packets from each file
2190 * are sent in parallel.
2191 */
2192 if (this->files->packets != filename) {
2193 filename = this->files->packets;
2194 n = parallel;
2195 }
2196
2197 if (n > 0) {
2198 n--;
2199
2200 /*
2201 * Send the current packet.
2202 */
2203 if (send_one_packet(this) < 0) {
2204 talloc_free(this);
2205 break;
2206 }
2207
2208 /*
2209 * Wait a little before sending
2210 * the next packet, if told to.
2211 */
2212 if (persec) {
2213 fr_time_delta_t psec;
2214
2215 psec = (persec == 1) ? fr_time_delta_from_sec(1) : fr_time_delta_wrap(1000000 / persec);
2216
2217 /*
2218 * Don't sleep elsewhere.
2219 */
2221
2222
2223 /*
2224 * Sleep for milliseconds,
2225 * portably.
2226 *
2227 * If we get an error or
2228 * a signal, treat it like
2229 * a normal timeout.
2230 */
2231 select(0, NULL, NULL, NULL, &fr_time_delta_to_timeval(psec));
2232 }
2233
2234 /*
2235 * If we haven't sent this packet
2236 * often enough, we're not done,
2237 * and we shouldn't sleep.
2238 */
2239 if (this->resend < resend_count) {
2240 int i;
2241
2242 done = false;
2244
2245 for (i = 0; i < 4; i++) {
2246 ((uint32_t *) this->packet->vector)[i] = fr_rand();
2247 }
2248 }
2249 } else { /* haven't sent this packet, we're not done */
2250 fr_assert(this->done == false);
2251 fr_assert(this->reply == NULL);
2252 done = false;
2253 }
2254 }
2255
2256 /*
2257 * Still have outstanding requests.
2258 */
2260 done = false;
2261 } else {
2263 }
2264
2265 /*
2266 * Nothing to do until we receive a request, so
2267 * sleep until then. Once we receive one packet,
2268 * we go back, and walk through the whole list again,
2269 * sending more packets (if necessary), and updating
2270 * the sleep time.
2271 */
2274 }
2275 } while (!done);
2276
2278
2279 rc_request_list_talloc_free(&rc_request_list);
2280
2282
2284
2286
2287 if (fr_dict_autofree(radclient_dict) < 0) {
2288 fr_perror("radclient");
2289 ret = EXIT_FAILURE;
2290 }
2291
2292#ifndef NDEBUG
2294#endif
2295
2296 if (do_summary) {
2297 fr_perror("Packet summary:\n"
2298 "\tAccepted : %" PRIu64 "\n"
2299 "\tRejected : %" PRIu64 "\n"
2300 "\tLost : %" PRIu64 "\n"
2301 "\tErrored : %" PRIu64 "\n"
2302 "\tPassed filter : %" PRIu64 "\n"
2303 "\tFailed filter : %" PRIu64,
2306 stats.lost,
2307 stats.error,
2308 stats.passed,
2310 );
2311 }
2312
2313 /*
2314 * Ensure our atexit handlers run before any other
2315 * atexit handlers registered by third party libraries.
2316 */
2318
2319 if ((stats.lost > 0) || (stats.failed > 0)) return EXIT_FAILURE;
2320
2321 openssl3_free();
2322
2323 return ret;
2324}
static int const char char buffer[256]
Definition acutest.h:576
int n
Definition acutest.h:577
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:305
static TALLOC_CTX * autofree
Definition fuzzer.c:44
#define RCSID(id)
Definition build.h:512
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:334
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:1070
#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:226
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_PROTOCOL_ERROR
RFC7930 - Protocol-Error (generic NAK)
Definition defs.h:52
@ 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
#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:4897
#define fr_dict_autofree(_to_free)
Definition dict.h:915
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:3522
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2659
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
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:4389
#define fr_dict_autoload(_to_load)
Definition dict.h:912
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
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:4707
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
#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:1104
#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
void fr_bio_shutdown & my
Definition fd_errno.h:73
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:63
IPv4/6 prefix.
int packet_global_init(void)
Initialises the Net.
Definition packet.c:200
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:154
#define fr_time()
Definition event.c:60
int fr_debug_lvl
Definition log.c:41
FILE * fr_log_fp
Definition log.c:40
fr_log_t default_log
Definition log.c:306
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:742
@ L_DST_STDOUT
Log to stdout.
Definition log.h:75
@ L_ERR
Error message.
Definition log.h:53
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
fr_packet_t * fr_packet_list_find_byreply(fr_packet_list_t *pl, fr_packet_t *reply)
Definition list.c:338
void fr_packet_list_free(fr_packet_list_t *pl)
Definition list.c:279
int fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set, TALLOC_CTX *ctx, fr_packet_t **packet_p, uint32_t max_attributes, bool require_message_authenticator)
Definition list.c:687
fr_packet_list_t * fr_packet_list_create(int alloc_id)
Definition list.c:291
bool fr_packet_list_id_alloc(fr_packet_list_t *pl, int proto, fr_packet_t *request, void **pctx)
Definition list.c:410
bool fr_packet_list_yank(fr_packet_list_t *pl, fr_packet_t *request)
Definition list.c:376
bool fr_packet_list_socket_add(fr_packet_list_t *pl, int sockfd, int proto, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, void *ctx)
Definition list.c:193
uint32_t fr_packet_list_num_elements(fr_packet_list_t *pl)
Definition list.c:383
int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set)
Definition list.c:660
bool fr_packet_list_id_free(fr_packet_list_t *pl, fr_packet_t *request, bool yank)
Definition list.c:636
unsigned short uint16_t
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_OCTETS
Raw octets.
unsigned int uint32_t
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
static void fr_nbo_from_uint16(uint8_t out[static sizeof(uint16_t)], uint16_t num)
Write out an unsigned 16bit integer in wire format (big endian)
Definition nbo.h:38
#define RADIUS_HEADER_LENGTH
Definition net.h:80
#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:2962
void fr_pair_validate_debug(fr_pair_t const *failed[2])
Write an error to the library errorbuff detailing the mismatch.
Definition pair.c:2096
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:784
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:1352
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:1696
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:290
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:2131
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:2812
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:1833
void fr_pair_list_steal(TALLOC_CTX *ctx, fr_pair_list_t *list)
Steal a list of pairs to a new context.
Definition pair.c:2307
int8_t fr_pair_cmp_by_da(void const *a, void const *b)
Order attributes by their da, and tag.
Definition pair.c:1851
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:3037
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:1297
ssize_t fr_radius_decode_simple(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t *packet, size_t packet_len, uint8_t const *vector, char const *secret)
Simple wrapper for callers who just need a shared secret.
Definition base.c:1275
void fr_radius_global_free(void)
Definition base.c:1321
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
int fr_radius_packet_sign(fr_packet_t *packet, fr_packet_t const *original, char const *secret)
Sign a previously encoded packet.
Definition packet.c:150
int fr_radius_packet_verify(fr_packet_t *packet, fr_packet_t *original, char const *secret)
Verify the Request/Response Authenticator (and Message-Authenticator if present) of a packet.
Definition packet.c:129
int fr_radius_packet_send(fr_packet_t *packet, fr_pair_list_t *list, fr_packet_t const *original, char const *secret)
Reply to the request.
Definition packet.c:277
fr_packet_t * fr_packet_recv(TALLOC_CTX *ctx, int fd, int flags, uint32_t max_attributes, bool require_message_authenticator)
Receive UDP client requests, and fill in the basics of a fr_packet_t structure.
Definition packet.c:191
void fr_radius_packet_log(fr_log_t const *log, fr_packet_t *packet, fr_pair_list_t *list, bool received)
Definition packet.c:478
ssize_t fr_radius_packet_encode(fr_packet_t *packet, fr_pair_list_t *list, fr_packet_t const *original, char const *secret)
Encode a packet.
Definition packet.c:43
#define fr_assert(_expr)
Definition rad_assert.h:37
#define REDEBUG(fmt,...)
#define RDEBUG(fmt,...)
#define rc_request_list_foreach(_list_head, _iter)
#define WARN(fmt,...)
static int blast_radius_check(rc_request_t *request, fr_packet_t *reply)
Definition radclient.c:1339
static fr_rb_tree_t * coa_tree
Definition radclient.c:95
static fr_ipaddr_t client_ipaddr
Definition radclient.c:84
static fr_dict_attr_t const * attr_packet_type
Definition radclient.c:123
static fr_dict_attr_t const * attr_request_authenticator
Definition radclient.c:119
static bool blast_radius
Definition radclient.c:82
static fr_dict_attr_t const * attr_user_password
Definition radclient.c:125
static int send_one_packet(rc_request_t *request)
Definition radclient.c:953
static int getport(char const *name)
Definition radclient.c:294
static bool done
Definition radclient.c:80
static int _rc_request_free(rc_request_t *request)
Definition radclient.c:193
static uint16_t client_port
Definition radclient.c:85
static int radclient_sane(rc_request_t *request)
Definition radclient.c:884
static int recv_one_packet(fr_time_delta_t wait_time)
Definition radclient.c:1460
static fr_dict_attr_t const * attr_coa_match_attr
Definition radclient.c:132
static fr_time_delta_t sleep_time
Definition radclient.c:67
static uint16_t coa_port
Definition radclient.c:94
int main(int argc, char **argv)
Definition radclient.c:1670
static fr_dict_attr_t const * attr_chap_password
Definition radclient.c:121
static int ignore_count
Definition radclient.c:79
static fr_packet_list_t * packet_list
Definition radclient.c:97
static int resend_count
Definition radclient.c:78
static rc_stats_t stats
Definition radclient.c:73
static fr_dict_attr_t const * attr_ms_chap_response
Definition radclient.c:116
static fr_dict_attr_t const * attr_ms_chap_challenge
Definition radclient.c:114
static int last_used_id
Definition radclient.c:88
static uint16_t server_port
Definition radclient.c:75
static int packet_code
Definition radclient.c:76
static fr_dict_attr_t const * attr_chap_challenge
Definition radclient.c:122
static int recv_coa_packet(fr_time_delta_t wait_time)
Definition radclient.c:1177
static bool do_output
Definition radclient.c:69
static fr_ipaddr_t server_ipaddr
Definition radclient.c:77
#define openssl3_free()
Definition radclient.c:255
static int ipproto
Definition radclient.c:90
static int retries
Definition radclient.c:65
static fr_dict_attr_t const * attr_proxy_state
Definition radclient.c:126
static fr_dict_attr_t const * attr_cleartext_password
Definition radclient.c:112
static void deallocate_id(rc_request_t *request)
Definition radclient.c:929
static bool print_filename
Definition radclient.c:81
static bool do_coa
Definition radclient.c:92
#define openssl3_init()
Definition radclient.c:254
static fr_dict_attr_t const * attr_radclient_test_name
Definition radclient.c:118
static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files)
Definition radclient.c:480
static fr_dict_attr_t const * attr_radclient_coa_filename
Definition radclient.c:129
static int mschapv1_encode(fr_packet_t *packet, fr_pair_list_t *list, char const *password)
Definition radclient.c:258
static const fr_dict_attr_autoload_t radclient_dict_attr[]
Definition radclient.c:134
static bool already_hex(fr_pair_t *vp)
Definition radclient.c:361
static fr_dict_attr_t const * attr_user_name
Definition radclient.c:124
static char * secret
Definition radclient.c:68
static int coafd
Definition radclient.c:93
static int sockfd
Definition radclient.c:87
static void radclient_get_port(fr_radius_packet_code_t type, uint16_t *port)
Definition radclient.c:307
static fr_dict_attr_t const * attr_ms_chap_password
Definition radclient.c:115
#define pair_update_request(_attr, _da)
Definition radclient.c:56
static int8_t request_cmp(void const *one, void const *two)
Definition radclient.c:911
static const char * attr_coa_filter_name
Definition radclient.c:71
static fr_time_delta_t timeout
Definition radclient.c:66
static fr_dict_attr_t const * attr_radclient_coa_filter
Definition radclient.c:130
static NEVER_RETURNS void usage(void)
Definition radclient.c:157
static fr_radius_packet_code_t radclient_get_code(uint16_t port)
Definition radclient.c:340
static fr_dict_attr_t const * attr_message_authenticator
Definition radclient.c:127
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.
Definition radclient.c:387
Structures for the radclient utility.
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 filter we want to match
char const * packets
The file containing the request packet.
uint64_t error
Requests which received a Protocol-Error response.
#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
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:104
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition rb.c:781
void * fr_rb_remove(fr_rb_tree_t *tree, void const *data)
Remove an entry from the tree, without freeing the data.
Definition rb.c:695
bool fr_rb_delete_by_inline_node(fr_rb_tree_t *tree, fr_rb_node_t *node)
Remove node and free data (if a free function was specified)
Definition rb.c:767
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:577
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
Definition rb.h:244
static bool fr_rb_node_inline_in_tree(fr_rb_node_t const *node)
Check to see if an item is in a tree by examining its inline fr_rb_node_t.
Definition rb.h:312
bool being_freed
Prevent double frees in talloc_destructor.
Definition rb.h:94
The main red black tree structure.
Definition rb.h:71
fr_packet_t * reply
Outgoing response.
Definition request.h:254
char const *fr_packet_t * packet
< Module the request is currently being processed by.
Definition request.h:253
static char const * name
void smbdes_mschap(uint8_t const win_password[16], uint8_t const *challenge, uint8_t *response)
Definition smbdes.c:339
int fr_socket_server_udp(fr_ipaddr_t const *src_ipaddr, uint16_t *src_port, char const *port_name, bool async)
Open an IPv4/IPv6 unconnected UDP socket.
Definition socket.c:846
int fr_socket_client_tcp(char const *ifname, fr_ipaddr_t *src_ipaddr, fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async)
Establish a connected TCP socket.
Definition socket.c:708
int fr_socket_bind(int sockfd, char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port)
Bind a UDP/TCP v4/v6 socket to a given ipaddr src port, and interface.
Definition socket.c:200
fr_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
uint64_t num
The number (within the file) of the request were reading.
fr_packet_t * reply
The incoming response.
fr_pair_t * password
Password.Cleartext.
char const * name
Test name (as specified in the request).
rc_file_pair_t * files
Request and response file names.
rc_request_t * coa
CoA filter and reply.
fr_packet_t * packet
The outgoing request.
fr_pair_list_t request_pairs
fr_rb_node_t node
rbtree node data for CoA
bool done
Whether the request is complete.
fr_pair_list_t filter
If the reply passes the filter, then the request passes.
fr_pair_list_t reply_pairs
fr_radius_packet_code_t filter_code
Expected code of the response packet.
fr_time_t timestamp
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_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
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:412
#define fr_time_delta_lt(_a, _b)
Definition time.h:285
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
#define fr_time_delta_wrap(_time)
Definition time.h:152
#define fr_time_delta_ispos(_a)
Definition time.h:290
#define fr_time_delta_to_timeval(_delta)
Convert a delta to a timeval.
Definition time.h:656
#define fr_time_delta_eq(_a, _b)
Definition time.h:287
@ FR_TIME_RES_SEC
Definition time.h:50
#define NSEC
Definition time.h:379
static fr_time_delta_t fr_time_delta_sub(fr_time_delta_t a, fr_time_delta_t b)
Definition time.h:261
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition time.h:229
#define fr_time_delta_gt(_a, _b)
Definition time.h:283
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
@ T_OP_CMP_FALSE
Definition token.h:103
#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
size_t data_len
Length of packet data.
Definition packet.h:64
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:69
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
#define PAIR_LIST_VERIFY(_x)
Definition pair.h:207
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:858
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition socket.h:75
int fd
File descriptor if this is a live socket.
Definition socket.h:78
int type
SOCK_STREAM, SOCK_DGRAM, etc.
Definition socket.h:76
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
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:748