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