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