The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
radclient-ng.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 6135eef1544f1f564159c0274dbfdaa6ed66cde6 $
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: 6135eef1544f1f564159c0274dbfdaa6ed66cde6 $")
29 
30 #include <freeradius-devel/util/conf.h>
31 #include <freeradius-devel/util/syserror.h>
32 #include <freeradius-devel/util/atexit.h>
33 #include <freeradius-devel/util/pair_legacy.h>
34 #include <freeradius-devel/util/time.h>
35 #include <freeradius-devel/util/event.h>
36 #include <freeradius-devel/server/packet.h>
37 #include <freeradius-devel/radius/list.h>
38 #include <freeradius-devel/radius/radius.h>
39 #include <freeradius-devel/util/chap.h>
40 #include <freeradius-devel/radius/client.h>
41 
42 #ifdef HAVE_OPENSSL_SSL_H
43 #include <openssl/ssl.h>
44 #endif
45 #include <ctype.h>
46 
47 #ifdef HAVE_GETOPT_H
48 # include <getopt.h>
49 #endif
50 
51 #include <assert.h>
52 
53 typedef struct request_s request_t; /* to shut up warnings about mschap.h */
54 
55 #include "smbdes.h"
56 #include "mschap.h"
57 
58 #include "radclient.h"
59 
60 #define pair_update_request(_attr, _da) do { \
61  _attr = fr_pair_find_by_da(&request->request_pairs, NULL, _da); \
62  if (!_attr) { \
63  _attr = fr_pair_afrom_da(request, _da); \
64  fr_assert(_attr != NULL); \
65  fr_pair_append(&request->request_pairs, _attr); \
66  } \
67  } while (0)
68 
69 static char *secret = NULL;
70 static bool do_output = true;
71 
73 
75 static int resend_count = 1;
76 static bool print_filename = false;
77 
78 static int forced_id = -1;
79 static size_t parallel = 1;
80 static bool paused = false;
81 
83 
84 static fr_bio_fd_info_t const *fd_info = NULL;
85 
86 static fr_bio_t *bio = NULL;
87 
89 
90 static fr_bio_packet_t *client_bio = NULL;
91 
93 
94 static int ipproto = IPPROTO_UDP;
95 
97 static rc_request_t *current = NULL;
98 
99 static char const *radclient_version = RADIUSD_VERSION_BUILD("radclient");
100 
102 static fr_dict_t const *dict_radius;
103 
104 static TALLOC_CTX *autofree = NULL;
105 
108  { .out = &dict_freeradius, .proto = "freeradius" },
109  { .out = &dict_radius, .proto = "radius" },
110  { NULL }
111 };
112 
114 
118 
121 
127 
130  { .out = &attr_cleartext_password, .name = "Password.Cleartext", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
131  { .out = &attr_ms_chap_challenge, .name = "Vendor-Specific.Microsoft.CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
132  { .out = &attr_ms_chap_password, .name = "Password.MS-CHAP", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
133  { .out = &attr_ms_chap_response, .name = "Vendor-Specific.Microsoft.CHAP-Response", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
134 
135  { .out = &attr_radclient_test_name, .name = "Radclient-Test-Name", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
136  { .out = &attr_request_authenticator, .name = "Request-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
137 
138  { .out = &attr_chap_password, .name = "CHAP-Password", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
139  { .out = &attr_chap_challenge, .name = "CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
140  { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
141  { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
142  { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
143 
144  { NULL }
145 };
146 
147 static NEVER_RETURNS void usage(void)
148 {
149  fprintf(stderr, "Usage: radclient [options] server[:port] <command> [<secret>]\n");
150 
151  fprintf(stderr, " <command> One of auth, acct, status, coa, disconnect or auto.\n");
152  fprintf(stderr, " -4 Use IPv4 address of server\n");
153  fprintf(stderr, " -6 Use IPv6 address of server.\n");
154  fprintf(stderr, " -C [<client_ip>:]<client_port> Client source port and source IP address. Port values may be 1..65535\n");
155  fprintf(stderr, " -c <count> Send each packet 'count' times.\n");
156  fprintf(stderr, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
157  fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
158  fprintf(stderr, " -f <file>[:<file>] Read packets from file, not stdin.\n");
159  fprintf(stderr, " If a second file is provided, it will be used to verify responses\n");
160  fprintf(stderr, " -F Print the file name, packet number and reply code.\n");
161  fprintf(stderr, " -h Print usage help information.\n");
162  fprintf(stderr, " -i <id> Set request id to 'id'. Values may be 0..255\n");
163  fprintf(stderr, " -p <num> Send 'num' packets from a file in parallel.\n");
164  fprintf(stderr, " -P <proto> Use proto (tcp or udp) for transport.\n");
165  fprintf(stderr, " -r <retries> If timeout, retry sending the packet 'retries' times.\n");
166  fprintf(stderr, " -s Print out summary information of auth results.\n");
167  fprintf(stderr, " -S <file> read secret from file, not command line.\n");
168  fprintf(stderr, " -t <timeout> Wait 'timeout' seconds before retrying (may be a floating point number).\n");
169  fprintf(stderr, " -v Show program version information.\n");
170  fprintf(stderr, " -x Debugging mode.\n");
171 
172  fr_exit_now(EXIT_SUCCESS);
173 }
174 
175 /*
176  * Free a radclient struct, which may (or may not)
177  * already be in the list.
178  */
179 static int _rc_request_free(rc_request_t *request)
180 {
181  fr_dlist_remove(&rc_request_list, request);
182 
183  if (request->packet && (request->packet->id >= 0)) {
185  }
186 
187  return 0;
188 }
189 
190 #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L
191 # include <openssl/provider.h>
192 
193 static OSSL_PROVIDER *openssl_default_provider = NULL;
194 static OSSL_PROVIDER *openssl_legacy_provider = NULL;
195 
196 static int openssl3_init(void)
197 {
198  /*
199  * Load the default provider for most algorithms
200  */
201  openssl_default_provider = OSSL_PROVIDER_load(NULL, "default");
202  if (!openssl_default_provider) {
203  ERROR("(TLS) Failed loading default provider");
204  return -1;
205  }
206 
207  /*
208  * Needed for MD4
209  *
210  * https://www.openssl.org/docs/man3.0/man7/migration_guide.html#Legacy-Algorithms
211  */
212  openssl_legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
213  if (!openssl_legacy_provider) {
214  ERROR("(TLS) Failed loading legacy provider");
215  return -1;
216  }
217 
218  return 0;
219 }
220 
221 static void openssl3_free(void)
222 {
223  if (openssl_default_provider && !OSSL_PROVIDER_unload(openssl_default_provider)) {
224  ERROR("Failed unloading default provider");
225  }
226  openssl_default_provider = NULL;
227 
228  if (openssl_legacy_provider && !OSSL_PROVIDER_unload(openssl_legacy_provider)) {
229  ERROR("Failed unloading legacy provider");
230  }
231  openssl_legacy_provider = NULL;
232 }
233 #else
234 #define openssl3_init()
235 #define openssl3_free()
236 #endif
237 
238 static int _loop_status(UNUSED fr_time_t now, fr_time_delta_t wake, UNUSED void *ctx)
239 {
240  if (fr_time_delta_unwrap(wake) < (NSEC / 10)) return 0;
241 
242  if (fr_dlist_num_elements(&rc_request_list) != 0) return 0;
243 
244  fr_log(&default_log, L_DBG, __FILE__, __LINE__, "Main loop waking up in %pV seconds", fr_box_time_delta(wake));
245 
246  return 0;
247 }
248 
250  char const *password)
251 {
252  unsigned int i;
253  uint8_t *p;
254  fr_pair_t *challenge, *reply;
255  uint8_t nthash[16];
256 
259 
261 
262  fr_pair_append(list, challenge);
263 
264  MEM(p = talloc_array(challenge, uint8_t, 8));
265  fr_pair_value_memdup_buffer_shallow(challenge, p, false);
266 
267  for (i = 0; i < challenge->vp_length; i++) {
268  p[i] = fr_rand();
269  }
270 
272  fr_pair_append(list, reply);
273  p = talloc_zero_array(reply, uint8_t, 50); /* really reply->da->flags.length */
275 
276  p[1] = 0x01; /* NT hash */
277 
278  if (mschap_nt_password_hash(nthash, password) < 0) return 0;
279 
280  smbdes_mschap(nthash, challenge->vp_octets, p + 26);
281  return 1;
282 }
283 
284 
285 static int getport(char const *name)
286 {
287  struct servent *svp;
288 
289  svp = getservbyname(name, "udp");
290  if (!svp) return 0;
291 
292  return ntohs(svp->s_port);
293 }
294 
295 /*
296  * Set a port from the request type if we don't already have one
297  */
299 {
300  switch (type) {
301  default:
305  if (*port == 0) *port = getport("radius");
306  if (*port == 0) *port = FR_AUTH_UDP_PORT;
307  return;
308 
310  if (*port == 0) *port = getport("radacct");
311  if (*port == 0) *port = FR_ACCT_UDP_PORT;
312  return;
313 
315  if (*port == 0) *port = FR_POD_UDP_PORT;
316  return;
317 
319  if (*port == 0) *port = FR_COA_UDP_PORT;
320  return;
321 
323  if (*port == 0) *port = 0;
324  return;
325  }
326 }
327 
328 /*
329  * Resolve a port to a request type
330  */
332 {
333  /*
334  * getport returns 0 if the service doesn't exist
335  * so we need to return early, to avoid incorrect
336  * codes.
337  */
338  if (port == 0) return FR_RADIUS_CODE_UNDEFINED;
339 
340  if ((port == getport("radius")) || (port == FR_AUTH_UDP_PORT) || (port == FR_AUTH_UDP_PORT_ALT)) {
342  }
343  if ((port == getport("radacct")) || (port == FR_ACCT_UDP_PORT) || (port == FR_ACCT_UDP_PORT_ALT)) {
345  }
346  if (port == FR_COA_UDP_PORT) return FR_RADIUS_CODE_COA_REQUEST;
347 
349 }
350 
351 
352 static bool already_hex(fr_pair_t *vp)
353 {
354  size_t i;
355 
356  if (!vp || (vp->vp_type != FR_TYPE_OCTETS)) return true;
357 
358  /*
359  * If it's 17 octets, it *might* be already encoded.
360  * Or, it might just be a 17-character password (maybe UTF-8)
361  * Check it for non-printable characters. The odds of ALL
362  * of the characters being 32..255 is (1-7/8)^17, or (1/8)^17,
363  * or 1/(2^51), which is pretty much zero.
364  */
365  for (i = 0; i < vp->vp_length; i++) {
366  if (vp->vp_octets[i] < 32) {
367  return true;
368  }
369  }
370 
371  return false;
372 }
373 
374 /*
375  * Initialize a radclient data structure and add it to
376  * the global linked list.
377  */
378 static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files)
379 {
380  FILE *packets, *filters = NULL;
381 
382  fr_pair_t *vp;
383  rc_request_t *request = NULL;
384  bool packets_done = false;
385  uint64_t num = 0;
386 
387  fr_assert(files->packets != NULL);
388 
389  /*
390  * Determine where to read the VP's from.
391  */
392  if (strcmp(files->packets, "-") != 0) {
393  packets = fopen(files->packets, "r");
394  if (!packets) {
395  ERROR("Error opening %s: %s", files->packets, fr_syserror(errno));
396  return -1;
397  }
398 
399  /*
400  * Read in the pairs representing the expected response.
401  */
402  if (files->filters) {
403  filters = fopen(files->filters, "r");
404  if (!filters) {
405  ERROR("Error opening %s: %s", files->filters, fr_syserror(errno));
406  goto error;
407  }
408  }
409  } else {
410  packets = stdin;
411  }
412 
413  /*
414  * Loop until the file is done.
415  */
416  do {
417  /*
418  * Allocate it.
419  */
420  MEM(request = talloc_zero(ctx, rc_request_t));
421  MEM(request->packet = fr_packet_alloc(request, true));
422  request->packet->uctx = request;
423 
424  /*
425  * Don't set request->packet->socket. The underlying socket isn't open yet.
426  */
427 
428  request->files = files;
429  request->packet->id = -1;
430  request->num = num++;
431 
432  fr_pair_list_init(&request->filter);
433  fr_pair_list_init(&request->request_pairs);
434  fr_pair_list_init(&request->reply_pairs);
435 
436  /*
437  * Read the request VP's.
438  */
440  &request->request_pairs, packets, &packets_done) < 0) {
441  char const *input;
442 
443  if ((files->packets[0] == '-') && (files->packets[1] == '\0')) {
444  input = "stdin";
445  } else {
446  input = files->packets;
447  }
448 
449  REDEBUG("Error parsing \"%s\"", input);
450  goto error;
451  }
452 
453  /*
454  * Skip empty entries
455  */
456  if (fr_pair_list_empty(&request->request_pairs)) {
457  WARN("Skipping \"%s\": No Attributes", files->packets);
458  talloc_free(request);
459  continue;
460  }
461 
462  /*
463  * Read in filter VP's.
464  */
465  if (filters) {
466  bool filters_done;
467 
469  &request->filter, filters, &filters_done) < 0) {
470  REDEBUG("Error parsing \"%s\"", files->filters);
471  goto error;
472  }
473 
474  if (filters_done && !packets_done) {
475  REDEBUG("Differing number of packets/filters in %s:%s "
476  "(too many requests))", files->packets, files->filters);
477  goto error;
478  }
479 
480  if (!filters_done && packets_done) {
481  REDEBUG("Differing number of packets/filters in %s:%s "
482  "(too many filters))", files->packets, files->filters);
483  goto error;
484  }
485 
486  vp = fr_pair_find_by_da(&request->filter, NULL, attr_packet_type);
487  if (vp) {
488  request->filter_code = vp->vp_uint32;
489  fr_pair_delete(&request->filter, vp);
490  }
491 
492  /*
493  * This allows efficient list comparisons later
494  */
496  }
497 
498  /*
499  * Process special attributes
500  */
501  for (vp = fr_pair_list_head(&request->request_pairs);
502  vp;
503  vp = fr_pair_list_next(&request->request_pairs, vp)) {
504  /*
505  * Allow it to set the packet type in
506  * the attributes read from the file.
507  */
508  if (vp->da == attr_packet_type) {
509  request->packet->code = vp->vp_uint32;
510  } else if (vp->da == attr_request_authenticator) {
511  if (vp->vp_length > sizeof(request->packet->vector)) {
512  memcpy(request->packet->vector, vp->vp_octets, sizeof(request->packet->vector));
513  } else {
514  memset(request->packet->vector, 0, sizeof(request->packet->vector));
515  memcpy(request->packet->vector, vp->vp_octets, vp->vp_length);
516  }
517  } else if (vp->da == attr_cleartext_password) {
518  request->password = vp;
519  /*
520  * Keep a copy of the the password attribute.
521  */
522  } else if (vp->da == attr_chap_password) {
523  /*
524  * If it's already hex, do nothing.
525  */
526  if ((vp->vp_length == 17) && (already_hex(vp))) continue;
527 
528  /*
529  * CHAP-Password is octets, so it may not be zero terminated.
530  */
532  fr_pair_value_bstrndup(request->password, vp->vp_strvalue, vp->vp_length, true);
533  } else if ((vp->da == attr_user_password) ||
534  (vp->da == attr_ms_chap_password)) {
536  fr_pair_value_bstrndup(request->password, vp->vp_strvalue, vp->vp_length, true);
537 
538  } else if (vp->da == attr_radclient_test_name) {
539  request->name = vp->vp_strvalue;
540 
541  }
542  } /* loop over the VP's we read in */
543 
544  /*
545  * Use the default set on the command line
546  */
547  if (request->packet->code == FR_RADIUS_CODE_UNDEFINED) request->packet->code = packet_code;
548 
549  /*
550  * Fill in the packet header from attributes, and then
551  * re-realize the attributes.
552  */
553  fr_packet_pairs_to_packet(request->packet, &request->request_pairs);
554 
555  /*
556  * Default to the filename
557  */
558  if (!request->name) request->name = request->files->packets;
559 
560  /*
561  * Automatically set the response code from the request code
562  * (if one wasn't already set).
563  */
564  if (request->filter_code == FR_RADIUS_CODE_UNDEFINED) {
565  switch (request->packet->code) {
568  break;
569 
572  break;
573 
576  break;
577 
580  break;
581 
584  break;
585 
587  REDEBUG("Packet-Type must be defined,"
588  "or a well known RADIUS port");
589  goto error;
590 
591  default:
592  REDEBUG("Can't determine expected &reply.Packet-Type for Packet-Type %i",
593  request->packet->code);
594  goto error;
595  }
596  /*
597  * Automatically set the request code from the response code
598  * (if one wasn't already set).
599  */
600  } else if (request->packet->code == FR_RADIUS_CODE_UNDEFINED) {
601  switch (request->filter_code) {
605  break;
606 
609  break;
610 
614  break;
615 
619  break;
620 
621  default:
622  REDEBUG("Can't determine expected Packet-Type for &reply.Packet-Type %i",
623  request->filter_code);
624  goto error;
625  }
626  }
627 
628  /*
629  * Automatically set the dst port (if one wasn't already set).
630  */
631  radclient_get_port(request->packet->code, &request->packet->socket.inet.dst_port);
632  if (request->packet->socket.inet.dst_port == 0) {
633  REDEBUG("Can't determine destination port");
634  goto error;
635  }
636 
637  /*
638  * We expect different responses for Status-Server, depending on which port is being used.
639  */
640  if (request->packet->code == FR_RADIUS_CODE_STATUS_SERVER) {
641  switch (radclient_get_code(request->packet->socket.inet.dst_port)) {
644  break;
645 
648  break;
649 
650  default:
652  break;
653  }
654  }
655 
656  /*
657  * Add it to the tail of the list.
658  */
660 
661  /*
662  * Set the destructor so it removes itself from the
663  * request list when freed. We don't set this until
664  * the packet is actually in the list, else we trigger
665  * the asserts in the free callback.
666  */
667  talloc_set_destructor(request, _rc_request_free);
668  } while (!packets_done); /* loop until the file is done. */
669 
670  if (packets != stdin) fclose(packets);
671  if (filters) fclose(filters);
672 
673  /*
674  * And we're done.
675  */
676  return 0;
677 
678 error:
679  talloc_free(request);
680 
681  if (packets != stdin) fclose(packets);
682  if (filters) fclose(filters);
683 
684  return -1;
685 }
686 
687 
688 /*
689  * Sanity check each argument.
690  */
691 static int radclient_sane(rc_request_t *request)
692 {
693  request->packet->socket.inet.src_ipaddr = fd_info->socket.inet.src_ipaddr;
694  request->packet->socket.inet.src_port = fd_info->socket.inet.src_port;
695  request->packet->socket.inet.ifindex = fd_info->socket.inet.ifindex;
696 
697  if (request->packet->socket.inet.dst_port == 0) {
698  request->packet->socket.inet.dst_port = fd_config.dst_port;
699  }
700 
701  if (request->packet->socket.inet.dst_ipaddr.af == AF_UNSPEC) {
702  if (fd_config.dst_ipaddr.af == AF_UNSPEC) {
703  ERROR("No server was given, and request %" PRIu64 " in file %s did not contain "
704  "Packet-Dst-IP-Address", request->num, request->files->packets);
705  return -1;
706  }
707  request->packet->socket.inet.dst_ipaddr = fd_config.dst_ipaddr;
708  }
709 
710  if (request->packet->code == 0) {
711  if (packet_code == -1) {
712  ERROR("Request was \"auto\", and request %" PRIu64 " in file %s did not contain Packet-Type",
713  request->num, request->files->packets);
714  return -1;
715  }
716  request->packet->code = packet_code;
717  }
718 
719  request->packet->socket.fd = -1;
720 
721  return 0;
722 }
723 
724 
725 /*
726  * Send one packet.
727  */
728 static int send_one_packet(fr_bio_packet_t *client, rc_request_t *request)
729 {
730  int rcode;
731 
732  fr_assert(!request->done);
733  fr_assert(request->reply == NULL);
734 
735 #ifdef STATIC_ANALYZER
736  if (!secret) fr_exit_now(1);
737 #endif
738 
739  fr_assert(request->packet->id < 0);
740  fr_assert(request->packet->data == NULL);
741 
742  /*
743  * Update the password, so it can be encrypted with the
744  * new authentication vector.
745  */
746  if (request->password) {
747  fr_pair_t *vp;
748 
749  if ((vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_password)) != NULL) {
750  fr_pair_value_strdup(vp, request->password->vp_strvalue, false);
751 
752  } else if ((vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_chap_password)) != NULL) {
753  uint8_t buffer[17];
754  fr_pair_t *challenge;
755  uint8_t const *vector;
756 
757  /*
758  * Use Chap-Challenge pair if present,
759  * Request Authenticator otherwise.
760  */
761  challenge = fr_pair_find_by_da(&request->request_pairs, NULL, attr_chap_challenge);
762  if (challenge && (challenge->vp_length == RADIUS_AUTH_VECTOR_LENGTH)) {
763  vector = challenge->vp_octets;
764  } else {
765  vector = request->packet->vector;
766  }
767 
769  fr_rand() & 0xff, vector, RADIUS_AUTH_VECTOR_LENGTH,
770  request->password->vp_strvalue,
771  request->password->vp_length);
772  fr_pair_value_memdup(vp, buffer, sizeof(buffer), false);
773 
774  } else if (fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_ms_chap_password) != NULL) {
775  mschapv1_encode(request->packet, &request->request_pairs, request->password->vp_strvalue);
776 
777  } else {
778  DEBUG("WARNING: No password in the request");
779  }
780  }
781 
782  request->timestamp = fr_time();
783  request->tries = 1;
784 
785  /*
786  * Ensure that each Access-Request is unique.
787  */
788  if (request->packet->code == FR_RADIUS_CODE_ACCESS_REQUEST) {
789  fr_rand_buffer(request->packet->vector, sizeof(request->packet->vector));
790  }
791 
792  /*
793  * Send the current packet.
794  */
795  rcode = fr_bio_packet_write(client, request, request->packet, &request->request_pairs);
796  if (rcode < 0) {
797  /*
798  * Failed writing it. Try again later.
799  */
800  if (rcode == fr_bio_error(IO_WOULD_BLOCK)) return 0;
801 
802  REDEBUG("Failed writing packet - %s", fr_strerror());
803  return -1;
804  }
805 
806  fr_radius_packet_log(&default_log, request->packet, &request->request_pairs, false);
807 
808  return 0;
809 }
810 
811 static fr_event_update_t const pause_write[] = {
813  { 0 }
814 };
815 
816 static fr_event_update_t const resume_write[] = {
818  { 0 }
819 };
820 
821 
823  int fd_errno, UNUSED void *uctx)
824 {
825  ERROR("Failed in connection - %s", fr_syserror(fd_errno));
826  fr_exit_now(1);
827 }
828 
829 static void client_read(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
830 {
831  fr_bio_packet_t *client = uctx;
832  rc_request_t *request;
834  fr_packet_t *reply;
835  int rcode;
836 
838 
839  /*
840  * @todo list_ctx is ignored
841  */
842  rcode = fr_bio_packet_read(client, (void **) &request, &reply, client, &reply_pairs);
843  if (rcode < 0) {
844  ERROR("Failed reading packet - %s", fr_bio_strerror(rcode));
845  fr_exit_now(1);
846  }
847 
848  /*
849  * Not a RADIUS packet, or not a reply to a packet we sent.
850  */
851  if (!rcode) return;
852 
854 
855  if (print_filename) {
856  RDEBUG("%s response code %d", request->files->packets, reply->code);
857  }
858 
859  /*
860  * Increment counters...
861  */
862  switch (reply->code) {
867  stats.accepted++;
868  break;
869 
871  break;
872 
873  default:
874  stats.rejected++;
875  }
876 
877  fr_strerror_clear(); /* Clear strerror buffer */
878 
879  /*
880  * If we had an expected response code, check to see if the
881  * packet matched that.
882  */
883  if ((request->filter_code != FR_RADIUS_CODE_UNDEFINED) && (reply->code != request->filter_code)) {
884  if (FR_RADIUS_PACKET_CODE_VALID(reply->code)) {
885  REDEBUG("%s: Expected %s got %s", request->name, fr_radius_packet_name[request->filter_code],
886  fr_radius_packet_name[reply->code]);
887  } else {
888  REDEBUG("%s: Expected %u got %i", request->name, request->filter_code,
889  reply->code);
890  }
891  stats.failed++;
892  /*
893  * Check if the contents of the packet matched the filter
894  */
895  } else if (fr_pair_list_empty(&request->filter)) {
896  stats.passed++;
897  } else {
898  fr_pair_t const *failed[2];
899 
901  if (fr_pair_validate(failed, &request->filter, &reply_pairs)) {
902  RDEBUG("%s: Response passed filter", request->name);
903  stats.passed++;
904  } else {
905  fr_pair_validate_debug(failed);
906  REDEBUG("%s: Response for failed filter", request->name);
907  stats.failed++;
908  }
909  }
910 
911  /*
912  * The retry bio takes care of suppressing duplicate replies.
913  */
914  if (paused) {
916  paused = false;
917  }
918 
919  /*
920  * If we're not done, then leave this packet in the list for future resending.
921  */
922  request->done = (request->resend >= resend_count);
923  if (!request->done) {
924  /*
925  * We don't care about duplicate replies, they can go away.
926  */
927  (void) fr_radius_client_fd_bio_cancel(client, request->packet);
928  request->packet->id = -1;
929  TALLOC_FREE(request->packet->data);
930  return;
931  }
932 
933  fr_packet_free(&reply);
934 
935  /*
936  * Don't leave a dangling pointer around.
937  */
938  if (current == request) {
940  }
941 
942  talloc_free(request);
943 
944  /*
945  * There are more packets to send, then allow the writer to send them.
946  */
948  return;
949  }
950 
951  /*
952  * We're done all packets, and there's nothing more to read, stop.
953  */
954  if (!fr_radius_client_bio_outstanding(client)) {
956  }
957 }
958 
959 static void client_write(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
960 {
961  fr_bio_packet_t *client = uctx;
962  rc_request_t *request;
963 
965  fr_assert(!paused);
966 
967  if (!request) request = fr_dlist_head(&rc_request_list);
968 
969  /*
970  * Nothing more to send, stop trying to write packets.
971  */
972  if (!request) {
973  pause:
975  return;
976  }
977 
978  if (request->packet->id >= 0) {
979  paused = true;
980  goto pause;
981  }
982 
983  if (send_one_packet(client, request) < 0) fr_assert(0);
984 
985  request->resend++;
986  current = request;
987 
988  /*
989  * 0 means "don't limit requests".
990  */
991  if (parallel && (fr_radius_client_bio_outstanding(client) >= parallel)) {
992  paused = true;
993  goto pause;
994  }
995 }
996 
997 static void client_connect(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
998 {
999  fr_bio_packet_t *client = uctx;
1000 
1001  if (fr_radius_client_bio_connect(client) < 0) {
1002  ERROR("Failed connecting socket: %s", fr_strerror());
1003  fr_exit_now(1);
1004  }
1005 
1006  if (fr_event_fd_insert(autofree, NULL, el, fd, client_read, client_write, client_error, client) < 0) {
1007  fr_perror("radclient");
1008  fr_exit_now(1);
1009  }
1010 }
1011 
1012 
1013 /**
1014  *
1015  * @hidecallgraph
1016  */
1017 int main(int argc, char **argv)
1018 {
1019  int ret = EXIT_SUCCESS;
1020  int c;
1021  char const *raddb_dir = RADDBDIR;
1022  char const *dict_dir = DICTDIR;
1023  char *end;
1024  char filesecret[256];
1025  FILE *fp;
1026  int do_summary = false;
1027  fr_dlist_head_t filenames;
1028 
1029  int retries = 5;
1031 
1032  /*
1033  * It's easier having two sets of flags to set the
1034  * verbosity of library calls and the verbosity of
1035  * radclient.
1036  */
1037  fr_debug_lvl = 0;
1038  fr_log_fp = stdout;
1039 
1040  /*
1041  * Must be called first, so the handler is called last
1042  */
1044 
1046 #ifndef NDEBUG
1047  if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
1048  fr_perror("radclient");
1049  fr_exit_now(EXIT_FAILURE);
1050  }
1051 #endif
1052 
1053  talloc_set_log_stderr();
1054 
1056 
1057  fr_dlist_talloc_init(&filenames, rc_file_pair_t, entry);
1058 
1059  /*
1060  * Always log to stdout
1061  */
1063  default_log.fd = STDOUT_FILENO;
1064  default_log.print_level = false;
1065 
1066  /*
1067  * Initialize the kind of socket we want.
1068  */
1071  .socket_type = SOCK_DGRAM,
1072 
1073  .src_ipaddr = (fr_ipaddr_t) {
1074  .af = AF_INET,
1075  },
1076  .dst_ipaddr = (fr_ipaddr_t) {
1077  .af = AF_INET,
1078  },
1079 
1080  .src_port = 0,
1081  .dst_port = 1812,
1082 
1083  .interface = NULL,
1084 
1085  .path = NULL,
1086  .filename = NULL,
1087 
1088  .async = true,
1089  };
1090 
1091  /*
1092  * Initialize the client configuration.
1093  */
1095  .log = &default_log,
1096  .verify = {
1097  .require_message_authenticator = false,
1098  .max_attributes = RADIUS_MAX_ATTRIBUTES,
1099  },
1100  };
1101 
1102  /***********************************************************************
1103  *
1104  * Parse command-line options.
1105  *
1106  ***********************************************************************/
1107 
1108  while ((c = getopt(argc, argv, "46c:C:d:D:f:Fi:hp:P:r:sS:t:vx")) != -1) switch (c) {
1109  case '4':
1110  fd_config.dst_ipaddr.af = AF_INET;
1111  break;
1112 
1113  case '6':
1114  fd_config.dst_ipaddr.af = AF_INET6;
1115  break;
1116 
1117  case 'c':
1118  if (!isdigit((uint8_t) *optarg)) usage();
1119 
1120  resend_count = atoi(optarg);
1121 
1122  if (resend_count < 1) usage();
1123  break;
1124 
1125  case 'C':
1126  {
1127  int tmp;
1128 
1129  if (strchr(optarg, ':')) {
1131  optarg, -1, AF_UNSPEC, true, false) < 0) {
1132  fr_perror("Failed parsing source address");
1133  fr_exit_now(1);
1134  }
1135  break;
1136  }
1137 
1138  tmp = atoi(optarg);
1139  if (tmp < 1 || tmp > 65535) usage();
1140 
1141  fd_config.src_port = (uint16_t)tmp;
1142  }
1143  break;
1144 
1145  case 'D':
1146  dict_dir = optarg;
1147  break;
1148 
1149  case 'd':
1150  raddb_dir = optarg;
1151  break;
1152 
1153  /*
1154  * packet,filter
1155  */
1156  case 'f':
1157  {
1158  char const *p;
1159  rc_file_pair_t *files;
1160 
1161  MEM(files = talloc_zero(talloc_autofree_context(), rc_file_pair_t));
1162 
1163  /*
1164  * Commas are nicer than colons.
1165  */
1166  c = ':';
1167 
1168  p = strchr(optarg, c);
1169  if (!p) {
1170  c = ',';
1171  p = strchr(optarg, c);
1172  }
1173  if (!p) {
1174  files->packets = optarg;
1175  files->filters = NULL;
1176  } else {
1177  MEM(files->packets = talloc_strndup(files, optarg, p - optarg));
1178  files->filters = p + 1;
1179  }
1180  fr_dlist_insert_tail(&filenames, files);
1181  }
1182  break;
1183 
1184  case 'F':
1185  print_filename = true;
1186  break;
1187 
1188  case 'i':
1189  if (!isdigit((uint8_t) *optarg))
1190  usage();
1191  forced_id = atoi(optarg);
1192  if ((forced_id < 0) || (forced_id > 255)) {
1193  usage();
1194  }
1195  break;
1196 
1197  /*
1198  * Note that sending MANY requests in
1199  * parallel can over-run the kernel
1200  * queues, and Linux will happily discard
1201  * packets. So even if the server responds,
1202  * the client may not see the reply.
1203  */
1204  case 'p':
1205  parallel = strtoul(optarg, &end, 10);
1206  if (*end) usage();
1207  if (parallel > 65536) usage();
1208  break;
1209 
1210  case 'P':
1211  if (!strcmp(optarg, "tcp")) {
1212  fd_config.socket_type = SOCK_STREAM;
1213  ipproto = IPPROTO_TCP;
1214  } else if (!strcmp(optarg, "udp")) {
1215  fd_config.socket_type = SOCK_DGRAM;
1216  ipproto = IPPROTO_UDP;
1217  } else {
1218  usage();
1219  }
1220  break;
1221 
1222  case 'r':
1223  if (!isdigit((uint8_t) *optarg)) usage();
1224  retries = atoi(optarg);
1225  if ((retries == 0) || (retries > 1000)) usage();
1226  break;
1227 
1228  case 's':
1229  do_summary = true;
1230  break;
1231 
1232  case 'S':
1233  {
1234  char *p;
1235  fp = fopen(optarg, "r");
1236  if (!fp) {
1237  ERROR("Error opening %s: %s", optarg, fr_syserror(errno));
1238  fr_exit_now(1);
1239  }
1240  if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
1241  ERROR("Error reading %s: %s", optarg, fr_syserror(errno));
1242  fr_exit_now(1);
1243  }
1244  fclose(fp);
1245 
1246  /* truncate newline */
1247  p = filesecret + strlen(filesecret) - 1;
1248  while ((p >= filesecret) &&
1249  (*p < ' ')) {
1250  *p = '\0';
1251  --p;
1252  }
1253 
1254  if (strlen(filesecret) < 2) {
1255  ERROR("Secret in %s is too short", optarg);
1256  fr_exit_now(1);
1257  }
1258  secret = talloc_strdup(autofree, filesecret);
1260  client_config.verify.secret_len = talloc_array_length(secret) - 1;
1261  }
1262  break;
1263 
1264  case 't':
1265  if (fr_time_delta_from_str(&timeout, optarg, strlen(optarg), FR_TIME_RES_SEC) < 0) {
1266  fr_perror("Failed parsing timeout value");
1267  fr_exit_now(EXIT_FAILURE);
1268  }
1269  break;
1270 
1271  case 'v':
1272  fr_debug_lvl = 1;
1273  DEBUG("%s", radclient_version);
1274  fr_exit_now(0);
1275 
1276  case 'x':
1277  fr_debug_lvl++;
1278  if (fr_debug_lvl > 1) default_log.print_level = true;
1279  break;
1280 
1281  case 'h':
1282  default:
1283  usage();
1284  }
1285  argc -= (optind - 1);
1286  argv += (optind - 1);
1287 
1288  if ((argc < 3) || ((secret == NULL) && (argc < 4))) {
1289  ERROR("Insufficient arguments");
1290  usage();
1291  }
1292 
1293  /*
1294  * Get the request type
1295  */
1296  if (!isdigit((uint8_t) argv[2][0])) {
1298  if (packet_code == -2) {
1299  ERROR("Unrecognised request type \"%s\"", argv[2]);
1300  usage();
1301  }
1302  } else {
1303  packet_code = atoi(argv[2]);
1304  }
1305 
1306  fr_assert(packet_code != 0);
1308 
1309  /*
1310  * Initialize the retry configuration for this type of packet.
1311  */
1314 
1316  .irt = timeout,
1317  .mrt = fr_time_delta_from_sec(16),
1318  .mrd = fr_time_delta_from_sec(30),
1319  .mrc = retries,
1320  };
1322 
1323  /*
1324  * Resolve hostname.
1325  */
1326  if (strcmp(argv[1], "-") != 0) {
1327  if (fr_inet_pton_port(&fd_config.dst_ipaddr, &fd_config.dst_port, argv[1], -1, fd_config.dst_ipaddr.af, true, true) < 0) {
1328  fr_perror("radclient");
1329  fr_exit_now(1);
1330  }
1331 
1332  /*
1333  * Work backwards from the port to determine the packet type
1334  */
1336  }
1338 
1339  /*
1340  * Add the secret.
1341  */
1342  if (argv[3]) {
1343  secret = talloc_strdup(autofree, argv[3]);
1345  client_config.verify.secret_len = talloc_array_length(secret) - 1;
1346  }
1347 
1348  /***********************************************************************
1349  *
1350  * We're done parsing command-line options, bootstrap the various libraries, etc.
1351  *
1352  ***********************************************************************/
1353 
1355  fr_perror("radclient");
1356  fr_exit_now(EXIT_FAILURE);
1357  }
1358 
1359  if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) {
1360  fr_perror("radclient");
1361  fr_exit_now(EXIT_FAILURE);
1362  }
1363 
1364  if (fr_radius_global_init() < 0) {
1365  fr_perror("radclient");
1366  fr_exit_now(EXIT_FAILURE);
1367  }
1368 
1369  if (fr_dict_autoload(radclient_dict) < 0) {
1370  fr_perror("radclient");
1371  exit(EXIT_FAILURE);
1372  }
1373 
1375  fr_perror("radclient");
1376  exit(EXIT_FAILURE);
1377  }
1378 
1380  fr_log_perror(&default_log, L_ERR, __FILE__, __LINE__, NULL,
1381  "Failed to initialize the dictionaries");
1382  exit(EXIT_FAILURE);
1383  }
1384 
1386 
1387  openssl3_init();
1388 
1390 
1391  /***********************************************************************
1392  *
1393  * We're done bootstrapping the libraries and dictionaries, read the input files.
1394  *
1395  ***********************************************************************/
1396 
1397  /*
1398  * If no '-f' is specified, then we are reading from stdin.
1399  */
1400  if (fr_dlist_num_elements(&filenames) == 0) {
1401  rc_file_pair_t *files;
1402 
1403  files = talloc_zero(talloc_autofree_context(), rc_file_pair_t);
1404  files->packets = "-";
1405  if (radclient_init(files, files) < 0) fr_exit_now(1);
1406  }
1407 
1408  if ((forced_id >= 0) && (fr_dlist_num_elements(&filenames) > 1)) {
1409  usage();
1410  }
1411 
1412  /*
1413  * Walk over the list of filenames, creating the requests.
1414  */
1415  fr_dlist_foreach(&filenames, rc_file_pair_t, files) {
1416  if (radclient_init(files, files)) {
1417  ERROR("Failed parsing input files");
1418  fr_exit_now(1);
1419  }
1420  }
1421 
1422  /*
1423  * No packets were read. Die.
1424  */
1426  ERROR("Nothing to send");
1427  fr_exit_now(1);
1428  }
1429 
1430  /***********************************************************************
1431  *
1432  * We're done reading files, open the socket, event loop, and start sending packets.
1433  *
1434  ***********************************************************************/
1435 
1437  (fr_debug_lvl >= 2) ? _loop_status : NULL,
1438  NULL);
1439  if (!client_config.retry_cfg.el) {
1440  ERROR("Failed opening event list: %s", fr_strerror());
1441  fr_exit_now(1);
1442  }
1443 
1444  /*
1445  * Open the RADIUS client bio, and then get the information associated with it.
1446  */
1448  if (!client_bio) {
1449  ERROR("Failed opening socket: %s", fr_strerror());
1450  fr_exit_now(1);
1451  }
1452 
1454  fr_assert(client_info != NULL);
1455 
1457  fr_assert(bio != NULL);
1458 
1460  fr_assert(fd_info != NULL);
1461 
1462  if (forced_id >= 0) {
1464  fr_perror("radclient");
1465  fr_exit_now(1);
1466  }
1467  }
1468 
1469  /*
1470  * Walk over the list of packets, updating to use the correct addresses, and sanity checking them.
1471  */
1473  if (radclient_sane(this) < 0) {
1474  fr_exit_now(1);
1475  }
1476  }
1477 
1478  /*
1479  * Always bounce through a connect(), even if we don't need it.
1480  *
1481  * Once the connect() passes, we start reading from the request list, and processing packets.
1482  */
1485  fr_perror("radclient");
1486  fr_exit_now(1);
1487  }
1488 
1489  /***********************************************************************
1490  *
1491  * Run the main event loop until we either see an error, or we have sent (and received) all of the packets.
1492  *
1493  ***********************************************************************/
1495 
1496  /***********************************************************************
1497  *
1498  * We are done the event loop. Start cleaning things up.
1499  *
1500  ***********************************************************************/
1502 
1504 
1506 
1508 
1509  if (fr_dict_autofree(radclient_dict) < 0) {
1510  fr_perror("radclient");
1511  ret = EXIT_FAILURE;
1512  }
1513 
1515 
1517 
1518  if (do_summary) {
1519  fr_perror("Packet summary:\n"
1520  "\tAccepted : %" PRIu64 "\n"
1521  "\tRejected : %" PRIu64 "\n"
1522  "\tLost : %" PRIu64 "\n"
1523  "\tPassed filter : %" PRIu64 "\n"
1524  "\tFailed filter : %" PRIu64,
1525  stats.accepted,
1526  stats.rejected,
1527  stats.lost,
1528  stats.passed,
1529  stats.failed
1530  );
1531  }
1532 
1533  /*
1534  * Ensure our atexit handlers run before any other
1535  * atexit handlers registered by third party libraries.
1536  */
1538 
1539  openssl3_free();
1540 
1541  if ((stats.lost > 0) || (stats.failed > 0)) return EXIT_FAILURE;
1542 
1543  return ret;
1544 }
static int const char char buffer[256]
Definition: acutest.h:574
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 fr_bio_error(_x)
Definition: base.h:184
Definition: base.h:103
static int fr_bio_packet_read(fr_bio_packet_t *bio, void **request_ctx_p, fr_packet_t **packet_p, TALLOC_CTX *out_ctx, fr_pair_list_t *out)
Read a packet from a packet BIO.
Definition: packet.h:94
static int fr_bio_packet_write(fr_bio_packet_t *bio, void *request_ctx, fr_packet_t *packet, fr_pair_list_t *list)
Write a packet to a packet BIO.
Definition: packet.h:113
fr_retry_config_t retry_config
base retry config
Definition: retry.h:38
fr_event_list_t * el
event list
Definition: retry.h:36
#define RCSID(id)
Definition: build.h:444
#define NEVER_RETURNS
Should be placed before the function return type.
Definition: build.h:311
#define UNUSED
Definition: build.h:313
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_MAX
Maximum possible protocol code.
Definition: defs.h:53
@ 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
static int retries
Definition: dhcpclient.c:53
#define DEBUG(fmt,...)
Definition: dhcpclient.c:39
static fr_time_delta_t timeout
Definition: dhcpclient.c:54
#define fr_dict_autofree(_to_free)
Definition: dict.h:674
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
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
static void * fr_dlist_prev(fr_dlist_head_t const *list_head, void const *ptr)
Get the previous item in a list.
Definition: dlist.h:588
#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
#define fr_event_fd_insert(...)
Definition: event.h:232
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition: event.h:62
#define fr_event_filter_update(...)
Definition: event.h:224
#define FR_EVENT_RESUME(_s, _f)
Re-add the filter for a func from kevent.
Definition: event.h:110
#define FR_EVENT_SUSPEND(_s, _f)
Temporarily remove the filter for a func from kevent.
Definition: event.h:94
Callbacks for the FR_EVENT_FILTER_IO filter.
Definition: event.h:173
Structure describing a modification to a filter's state.
Definition: event.h:75
fr_bio_fd_info_t const * fr_bio_fd_info(fr_bio_t *bio)
Returns a pointer to the bio-specific information.
Definition: fd.c:1167
fr_socket_t socket
as connected socket
Definition: fd.h:108
uint16_t src_port
our port
Definition: fd.h:84
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
Definition: fd.h:64
fr_ipaddr_t dst_ipaddr
their IP address
Definition: fd.h:82
fr_bio_fd_type_t type
accept, connected, unconnected, etc.
Definition: fd.h:77
int socket_type
SOCK_STREAM or SOCK_DGRAM.
Definition: fd.h:79
uint16_t dst_port
their port
Definition: fd.h:85
fr_ipaddr_t src_ipaddr
our IP address
Definition: fd.h:81
Configuration for sockets.
Definition: fd.h:76
Run-time status of the socket.
Definition: fd.h:107
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
char const * fr_bio_strerror(ssize_t error)
Definition: base.c:197
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
fr_event_list_t * fr_event_list_alloc(TALLOC_CTX *ctx, fr_event_status_cb_t status, void *status_uctx)
Initialise a new event list.
Definition: event.c:2892
talloc_free(reap)
void fr_event_loop_exit(fr_event_list_t *el, int code)
Signal an event loop exit with the specified code.
Definition: event.c:2737
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
Definition: event.c:1253
int fr_event_loop(fr_event_list_t *el)
Run an event loop.
Definition: event.c:2759
Stores all information relating to an event list.
Definition: event.c:411
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
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
Definition: log.c:599
@ L_DST_STDOUT
Log to stdout.
Definition: log.h:78
@ L_ERR
Error message.
Definition: log.h:56
@ L_DBG
Only displayed when debugging is enabled.
Definition: log.h:59
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
Definition: packet.c:38
void fr_packet_free(fr_packet_t **packet_p)
Free a fr_packet_t.
Definition: packet.c:89
unsigned short uint16_t
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 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
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
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_radius_allow_reply(int code, bool allowed[static FR_RADIUS_CODE_MAX])
Definition: base.c:170
uint8_t const * secret
Definition: bio.h:34
bool allowed[FR_RADIUS_CODE_MAX]
allowed outgoing packet types
Definition: bio.h:39
size_t secret_len
Definition: bio.h:35
fr_radius_bio_verify_t verify
Definition: client.h:37
fr_bio_retry_config_t retry_cfg
Definition: client.h:39
fr_retry_config_t retry[FR_RADIUS_CODE_MAX]
default retry configuration for each packet type
Definition: client.h:43
bool outgoing[FR_RADIUS_CODE_MAX]
allowed outgoing packet types
Definition: client.h:41
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
static void client_connect(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
Definition: radclient-ng.c:997
static fr_dict_attr_t const * attr_packet_type
Definition: radclient-ng.c:124
static fr_dict_attr_t const * attr_request_authenticator
Definition: radclient-ng.c:120
static int send_one_packet(fr_bio_packet_t *client, rc_request_t *request)
Definition: radclient-ng.c:728
static fr_dict_attr_t const * attr_user_password
Definition: radclient-ng.c:126
static bool paused
Definition: radclient-ng.c:80
static int getport(char const *name)
Definition: radclient-ng.c:285
static char const * radclient_version
Definition: radclient-ng.c:99
static int _rc_request_free(rc_request_t *request)
Definition: radclient-ng.c:179
fr_dict_autoload_t radclient_dict[]
Definition: radclient-ng.c:107
static void client_read(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
Definition: radclient-ng.c:829
static int radclient_sane(rc_request_t *request)
Definition: radclient-ng.c:691
static TALLOC_CTX * autofree
Definition: radclient-ng.c:104
static fr_bio_fd_config_t fd_config
Definition: radclient-ng.c:82
static fr_bio_packet_t * client_bio
Definition: radclient-ng.c:90
int main(int argc, char **argv)
static fr_dict_t const * dict_freeradius
Definition: radclient-ng.c:101
static fr_dict_attr_t const * attr_chap_password
Definition: radclient-ng.c:122
static fr_radius_client_config_t client_config
Definition: radclient-ng.c:88
static int forced_id
Definition: radclient-ng.c:78
static int resend_count
Definition: radclient-ng.c:75
static fr_radius_client_bio_info_t const * client_info
Definition: radclient-ng.c:92
static rc_stats_t stats
Definition: radclient-ng.c:72
static fr_dict_attr_t const * attr_ms_chap_response
Definition: radclient-ng.c:117
static fr_event_update_t const resume_write[]
Definition: radclient-ng.c:816
static fr_dict_t const * dict_radius
Definition: radclient-ng.c:102
static fr_dict_attr_t const * attr_ms_chap_challenge
Definition: radclient-ng.c:115
static size_t parallel
Definition: radclient-ng.c:79
static int packet_code
Definition: radclient-ng.c:74
static fr_dict_attr_t const * attr_chap_challenge
Definition: radclient-ng.c:123
static bool do_output
Definition: radclient-ng.c:70
static fr_bio_t * bio
Definition: radclient-ng.c:86
#define openssl3_free()
Definition: radclient-ng.c:235
static int _loop_status(UNUSED fr_time_t now, fr_time_delta_t wake, UNUSED void *ctx)
Definition: radclient-ng.c:238
static int ipproto
Definition: radclient-ng.c:94
fr_dict_attr_autoload_t radclient_dict_attr[]
Definition: radclient-ng.c:129
static fr_dict_attr_t const * attr_cleartext_password
Definition: radclient-ng.c:113
static bool print_filename
Definition: radclient-ng.c:76
#define openssl3_init()
Definition: radclient-ng.c:234
static fr_dict_attr_t const * attr_radclient_test_name
Definition: radclient-ng.c:119
static rc_request_t * current
Definition: radclient-ng.c:97
static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files)
Definition: radclient-ng.c:378
static int mschapv1_encode(fr_packet_t *packet, fr_pair_list_t *list, char const *password)
Definition: radclient-ng.c:249
static bool already_hex(fr_pair_t *vp)
Definition: radclient-ng.c:352
static fr_dict_attr_t const * attr_user_name
Definition: radclient-ng.c:125
static void client_write(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
Definition: radclient-ng.c:959
static char * secret
Definition: radclient-ng.c:69
static fr_dlist_head_t rc_request_list
Definition: radclient-ng.c:96
static fr_bio_fd_info_t const * fd_info
Definition: radclient-ng.c:84
static void radclient_get_port(fr_radius_packet_code_t type, uint16_t *port)
Definition: radclient-ng.c:298
static fr_dict_attr_t const * attr_ms_chap_password
Definition: radclient-ng.c:116
#define pair_update_request(_attr, _da)
Definition: radclient-ng.c:60
static NEVER_RETURNS void client_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, UNUSED void *uctx)
Definition: radclient-ng.c:822
static fr_event_update_t const pause_write[]
Definition: radclient-ng.c:811
static NEVER_RETURNS void usage(void)
Definition: radclient-ng.c:147
static fr_radius_packet_code_t radclient_get_code(uint16_t port)
Definition: radclient-ng.c:331
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
uint64_t rejected
Requests to which we received a reject.
Definition: radclient.h:58
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
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
void fr_rand_buffer(void *start, size_t length)
Definition: rand.c:126
fr_packet_t * packet
Incoming request.
Definition: request.h:224
fr_packet_t * reply
Outgoing response.
Definition: request.h:225
#define reply_pairs
Convenience macro for accessing the reply list.
Definition: request.h:101
static char const * name
void smbdes_mschap(uint8_t const win_password[16], uint8_t const *challenge, uint8_t *response)
Definition: smbdes.c:339
fr_bio_packet_t * fr_radius_client_bio_alloc(TALLOC_CTX *ctx, fr_radius_client_config_t *cfg, fr_bio_fd_config_t const *fd_cfg)
Definition: client.c:37
fr_bio_t * fr_radius_client_bio_get_fd(fr_bio_packet_t *bio)
Definition: client.c:393
int fr_radius_client_fd_bio_cancel(fr_bio_packet_t *bio, fr_packet_t *packet)
Cancel one packet.
Definition: client.c:309
int fr_radius_client_bio_force_id(fr_bio_packet_t *bio, int code, int id)
Definition: client.c:415
fr_radius_client_bio_info_t const * fr_radius_client_bio_info(fr_bio_packet_t *bio)
Definition: client.c:407
size_t fr_radius_client_bio_outstanding(fr_bio_packet_t *bio)
Definition: client.c:400
int fr_radius_client_bio_connect(fr_bio_packet_t *bio)
Try to connect a socket.
Definition: client.c:444
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
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition: time.h:154
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition: time.h:588
@ FR_TIME_RES_SEC
Definition: time.h:50
#define NSEC
Definition: time.h:377
A time delta, a difference in time measured in nanoseconds.
Definition: time.h:80
"server local" time.
Definition: time.h:69
static fr_event_list_t * el
#define FR_DICTIONARY_FILE
Definition: conf.h: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
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
fr_time_delta_t irt
Initial transmission time.
Definition: retry.h:33
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
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
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554
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
#define fr_box_time_delta(_val)
Definition: value.h:336