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