All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
radclient.c
Go to the documentation of this file.
1 /*
2  * radclient.c General radius packet debug tool.
3  *
4  * Version: $Id: 3a883511de47a3c75f60dc9a88ad40b88f62797f $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006,2014 The FreeRADIUS server project
21  * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
22  * Copyright 2000 Alan DeKok <aland@ox.org>
23  */
24 
25 RCSID("$Id: 3a883511de47a3c75f60dc9a88ad40b88f62797f $")
26 
27 #include <freeradius-devel/radclient.h>
28 #include <freeradius-devel/conf.h>
29 #include <ctype.h>
30 
31 #ifdef HAVE_GETOPT_H
32 # include <getopt.h>
33 #endif
34 
35 #include <assert.h>
36 
37 typedef struct REQUEST REQUEST; /* to shut up warnings about mschap.h */
38 
39 #include "smbdes.h"
40 #include "mschap.h"
41 
42 static int retries = 3;
43 static float timeout = 5;
44 static char const *secret = NULL;
45 static bool do_output = true;
46 
48 
49 static uint16_t server_port = 0;
52 static int resend_count = 1;
53 static bool done = true;
54 static bool print_filename = false;
55 
57 static uint16_t client_port = 0;
58 
59 static int sockfd;
60 static int last_used_id = -1;
61 
62 #ifdef WITH_TCP
63 static char const *proto = NULL;
64 #endif
65 static int ipproto = IPPROTO_UDP;
66 
67 static rbtree_t *filename_tree = NULL;
68 static fr_packet_list_t *pl = NULL;
69 
70 static int sleep_time = -1;
71 
72 static rc_request_t *request_head = NULL;
74 
75 static char const *radclient_version = "radclient version " RADIUSD_VERSION_STRING
76 #ifdef RADIUSD_VERSION_COMMIT
77 " (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
78 #endif
79 ", built on " __DATE__ " at " __TIME__;
80 
81 static void NEVER_RETURNS usage(void)
82 {
83  fprintf(stderr, "Usage: radclient [options] server[:port] <command> [<secret>]\n");
84 
85  fprintf(stderr, " <command> One of auth, acct, status, coa, disconnect or auto.\n");
86  fprintf(stderr, " -4 Use IPv4 address of server\n");
87  fprintf(stderr, " -6 Use IPv6 address of server.\n");
88  fprintf(stderr, " -c <count> Send each packet 'count' times.\n");
89  fprintf(stderr, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
90  fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
91  fprintf(stderr, " -f <file>[:<file>] Read packets from file, not stdin.\n");
92  fprintf(stderr, " If a second file is provided, it will be used to verify responses\n");
93  fprintf(stderr, " -F Print the file name, packet number and reply code.\n");
94  fprintf(stderr, " -h Print usage help information.\n");
95  fprintf(stderr, " -i <id> Set request id to 'id'. Values may be 0..255\n");
96  fprintf(stderr, " -n <num> Send N requests/s\n");
97  fprintf(stderr, " -p <num> Send 'num' packets from a file in parallel.\n");
98  fprintf(stderr, " -q Do not print anything out.\n");
99  fprintf(stderr, " -r <retries> If timeout, retry sending the packet 'retries' times.\n");
100  fprintf(stderr, " -s Print out summary information of auth results.\n");
101  fprintf(stderr, " -S <file> read secret from file, not command line.\n");
102  fprintf(stderr, " -t <timeout> Wait 'timeout' seconds before retrying (may be a floating point number).\n");
103  fprintf(stderr, " -v Show program version information.\n");
104  fprintf(stderr, " -x Debugging mode.\n");
105 
106 #ifdef WITH_TCP
107  fprintf(stderr, " -P <proto> Use proto (tcp or udp) for transport.\n");
108 #endif
109 
110  exit(1);
111 }
112 
113 /*
114  * Free a radclient struct, which may (or may not)
115  * already be in the list.
116  */
117 static int _rc_request_free(rc_request_t *request)
118 {
119  rc_request_t *prev, *next;
120 
121  prev = request->prev;
122  next = request->next;
123 
124  if (prev) {
125  assert(request_head != request);
126  prev->next = next;
127  } else if (request_head) {
128  assert(request_head == request);
129  request_head = next;
130  }
131 
132  if (next) {
133  assert(rc_request_tail != request);
134  next->prev = prev;
135  } else if (rc_request_tail) {
136  assert(rc_request_tail == request);
137  rc_request_tail = prev;
138  }
139 
140  return 0;
141 }
142 
144  char const *password)
145 {
146  unsigned int i;
147  uint8_t *p;
148  VALUE_PAIR *challenge, *reply;
149  uint8_t nthash[16];
150 
153 
155  if (!challenge) {
156  return 0;
157  }
158 
159  fr_pair_add(request, challenge);
160  challenge->vp_length = 8;
161  challenge->vp_octets = p = talloc_array(challenge, uint8_t, challenge->vp_length);
162  for (i = 0; i < challenge->vp_length; i++) {
163  p[i] = fr_rand();
164  }
165 
167  if (!reply) {
168  return 0;
169  }
170 
171  fr_pair_add(request, reply);
172  reply->vp_length = 50;
173  reply->vp_octets = p = talloc_array(reply, uint8_t, reply->vp_length);
174  memset(p, 0, reply->vp_length);
175 
176  p[1] = 0x01; /* NT hash */
177 
178  if (mschap_ntpwdhash(nthash, password) < 0) {
179  return 0;
180  }
181 
182  smbdes_mschap(nthash, challenge->vp_octets, p + 26);
183  return 1;
184 }
185 
186 
187 static int getport(char const *name)
188 {
189  struct servent *svp;
190 
191  svp = getservbyname(name, "udp");
192  if (!svp) return 0;
193 
194  return ntohs(svp->s_port);
195 }
196 
197 /*
198  * Set a port from the request type if we don't already have one
199  */
200 static void radclient_get_port(PW_CODE type, uint16_t *port)
201 {
202  switch (type) {
203  default:
207  if (*port == 0) *port = getport("radius");
208  if (*port == 0) *port = PW_AUTH_UDP_PORT;
209  return;
210 
212  if (*port == 0) *port = getport("radacct");
213  if (*port == 0) *port = PW_ACCT_UDP_PORT;
214  return;
215 
217  if (*port == 0) *port = PW_POD_UDP_PORT;
218  return;
219 
220  case PW_CODE_COA_REQUEST:
221  if (*port == 0) *port = PW_COA_UDP_PORT;
222  return;
223 
224  case PW_CODE_UNDEFINED:
225  if (*port == 0) *port = 0;
226  return;
227  }
228 }
229 
230 /*
231  * Resolve a port to a request type
232  */
233 static PW_CODE radclient_get_code(uint16_t port)
234 {
235  /*
236  * getport returns 0 if the service doesn't exist
237  * so we need to return early, to avoid incorrect
238  * codes.
239  */
240  if (port == 0) return PW_CODE_UNDEFINED;
241 
242  if ((port == getport("radius")) || (port == PW_AUTH_UDP_PORT) || (port == PW_AUTH_UDP_PORT_ALT)) {
243  return PW_CODE_ACCESS_REQUEST;
244  }
245  if ((port == getport("radacct")) || (port == PW_ACCT_UDP_PORT) || (port == PW_ACCT_UDP_PORT_ALT)) {
247  }
248  if (port == PW_COA_UDP_PORT) return PW_CODE_COA_REQUEST;
249  if (port == PW_POD_UDP_PORT) return PW_CODE_DISCONNECT_REQUEST;
250 
251  return PW_CODE_UNDEFINED;
252 }
253 
254 
255 static bool already_hex(VALUE_PAIR *vp)
256 {
257  size_t i;
258 
259  if (!vp || (vp->da->type != PW_TYPE_OCTETS)) return true;
260 
261  /*
262  * If it's 17 octets, it *might* be already encoded.
263  * Or, it might just be a 17-character password (maybe UTF-8)
264  * Check it for non-printable characters. The odds of ALL
265  * of the characters being 32..255 is (1-7/8)^17, or (1/8)^17,
266  * or 1/(2^51), which is pretty much zero.
267  */
268  for (i = 0; i < vp->vp_length; i++) {
269  if (vp->vp_octets[i] < 32) {
270  return true;
271  }
272  }
273 
274  return false;
275 }
276 
277 
278 /*
279  * Initialize a radclient data structure and add it to
280  * the global linked list.
281  */
282 static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files)
283 {
284  FILE *packets, *filters = NULL;
285 
286  vp_cursor_t cursor;
287  VALUE_PAIR *vp;
288  rc_request_t *request;
289  bool packets_done = false;
290  uint64_t num = 0;
291 
292  assert(files->packets != NULL);
293 
294  /*
295  * Determine where to read the VP's from.
296  */
297  if (strcmp(files->packets, "-") != 0) {
298  packets = fopen(files->packets, "r");
299  if (!packets) {
300  ERROR("Error opening %s: %s", files->packets, strerror(errno));
301  return 0;
302  }
303 
304  /*
305  * Read in the pairs representing the expected response.
306  */
307  if (files->filters) {
308  filters = fopen(files->filters, "r");
309  if (!filters) {
310  ERROR("Error opening %s: %s", files->filters, strerror(errno));
311  fclose(packets);
312  return 0;
313  }
314  }
315  } else {
316  packets = stdin;
317  }
318 
319 
320  /*
321  * Loop until the file is done.
322  */
323  do {
324  /*
325  * Allocate it.
326  */
327  request = talloc_zero(ctx, rc_request_t);
328  if (!request) {
329  ERROR("Out of memory");
330  goto error;
331  }
332 
333  request->packet = fr_radius_alloc(request, true);
334  if (!request->packet) {
335  ERROR("Out of memory");
336  goto error;
337  }
338 
339 #ifdef WITH_TCP
340  request->packet->src_ipaddr = client_ipaddr;
341  request->packet->src_port = client_port;
342  request->packet->dst_ipaddr = server_ipaddr;
343  request->packet->dst_port = server_port;
344  request->packet->proto = ipproto;
345 #endif
346 
347  request->files = files;
348  request->packet->id = -1; /* allocate when sending */
349  request->num = num++;
350 
351  /*
352  * Read the request VP's.
353  */
354  if (fr_pair_list_afrom_file(request->packet, &request->packet->vps, packets, &packets_done) < 0) {
355  char const *input;
356 
357  if ((files->packets[0] == '-') && (files->packets[1] == '\0')) {
358  input = "stdin";
359  } else {
360  input = files->packets;
361  }
362 
363  REDEBUG("Error parsing \"%s\"", input);
364  goto error;
365  }
366 
367  /*
368  * Skip empty entries
369  */
370  if (!request->packet->vps) {
371  talloc_free(request);
372  continue;
373  }
374 
375  /*
376  * Read in filter VP's.
377  */
378  if (filters) {
379  bool filters_done;
380 
381  if (fr_pair_list_afrom_file(request, &request->filter, filters, &filters_done) < 0) {
382  REDEBUG("Error parsing \"%s\"", files->filters);
383  goto error;
384  }
385 
386  if (filters_done && !packets_done) {
387  REDEBUG("Differing number of packets/filters in %s:%s "
388  "(too many requests))", files->packets, files->filters);
389  goto error;
390  }
391 
392  if (!filters_done && packets_done) {
393  REDEBUG("Differing number of packets/filters in %s:%s "
394  "(too many filters))", files->packets, files->filters);
395  goto error;
396  }
397 
398  /*
399  * xlat expansions aren't supported here
400  */
401  for (vp = fr_cursor_init(&cursor, &request->filter);
402  vp;
403  vp = fr_cursor_next(&cursor)) {
404  if (vp->type == VT_XLAT) {
405  vp->type = VT_DATA;
406  vp->vp_strvalue = vp->xlat;
407  vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
408  }
409 
410  if (vp->da->vendor == 0 ) switch (vp->da->attr) {
411  case PW_RESPONSE_PACKET_TYPE:
412  case PW_PACKET_TYPE:
413  fr_cursor_remove(&cursor); /* so we don't break the filter */
414  request->filter_code = vp->vp_integer;
415  talloc_free(vp);
416 
417  default:
418  break;
419  }
420  }
421 
422  /*
423  * This allows efficient list comparisons later
424  */
426  }
427 
428  /*
429  * Process special attributes
430  */
431  for (vp = fr_cursor_init(&cursor, &request->packet->vps);
432  vp;
433  vp = fr_cursor_next(&cursor)) {
434  /*
435  * Double quoted strings get marked up as xlat expansions,
436  * but we don't support that in request.
437  */
438  if (vp->type == VT_XLAT) {
439  vp->type = VT_DATA;
440  vp->vp_strvalue = vp->xlat;
441  vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
442  }
443 
444  if (!vp->da->vendor) switch (vp->da->attr) {
445  default:
446  break;
447 
448  /*
449  * Allow it to set the packet type in
450  * the attributes read from the file.
451  */
452  case PW_PACKET_TYPE:
453  request->packet->code = vp->vp_integer;
454  break;
455 
456  case PW_RESPONSE_PACKET_TYPE:
457  request->filter_code = vp->vp_integer;
458  break;
459 
460  case PW_PACKET_DST_PORT:
461  request->packet->dst_port = (vp->vp_integer & 0xffff);
462  break;
463 
464  case PW_PACKET_DST_IP_ADDRESS:
465  request->packet->dst_ipaddr.af = AF_INET;
466  request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
467  request->packet->dst_ipaddr.prefix = 32;
468  break;
469 
470  case PW_PACKET_DST_IPV6_ADDRESS:
471  request->packet->dst_ipaddr.af = AF_INET6;
472  request->packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
473  request->packet->dst_ipaddr.prefix = 128;
474  break;
475 
476  case PW_PACKET_SRC_PORT:
477  if ((vp->vp_integer < 1024) ||
478  (vp->vp_integer > 65535)) {
479  ERROR("Invalid value '%u' for Packet-Src-Port", vp->vp_integer);
480  goto error;
481  }
482  request->packet->src_port = (vp->vp_integer & 0xffff);
483  break;
484 
485  case PW_PACKET_SRC_IP_ADDRESS:
486  request->packet->src_ipaddr.af = AF_INET;
487  request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
488  request->packet->src_ipaddr.prefix = 32;
489  break;
490 
491  case PW_PACKET_SRC_IPV6_ADDRESS:
492  request->packet->src_ipaddr.af = AF_INET6;
493  request->packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
494  request->packet->src_ipaddr.prefix = 128;
495  break;
496 
497  case PW_DIGEST_REALM:
498  case PW_DIGEST_NONCE:
499  case PW_DIGEST_METHOD:
500  case PW_DIGEST_URI:
501  case PW_DIGEST_QOP:
502  case PW_DIGEST_ALGORITHM:
503  case PW_DIGEST_BODY_DIGEST:
504  case PW_DIGEST_CNONCE:
505  case PW_DIGEST_NONCE_COUNT:
506  case PW_DIGEST_USER_NAME:
507  /* overlapping! */
508  {
509  fr_dict_attr_t const *da;
510  uint8_t *p, *q;
511 
512  p = talloc_array(vp, uint8_t, vp->vp_length + 2);
513 
514  memcpy(p + 2, vp->vp_octets, vp->vp_length);
515  p[0] = vp->da->attr - PW_DIGEST_REALM + 1;
516  vp->vp_length += 2;
517  p[1] = vp->vp_length;
518 
520  if (!da) {
521  ERROR("Out of memory");
522  goto error;
523  }
524  vp->da = da;
525 
526  /*
527  * Re-do fr_pair_value_memsteal ourselves,
528  * because we play games with
529  * vp->da, and fr_pair_value_memsteal goes
530  * to GREAT lengths to sanitize
531  * and fix and change and
532  * double-check the various
533  * fields.
534  */
535  memcpy(&q, &vp->vp_octets, sizeof(q));
536  talloc_free(q);
537 
538  vp->vp_octets = talloc_steal(vp, p);
539  vp->type = VT_DATA;
540 
541  VERIFY_VP(vp);
542  }
543  break;
544 
545  /*
546  * Cache this for later.
547  */
548  case PW_CLEARTEXT_PASSWORD:
549  request->password = vp;
550  break;
551 
552  /*
553  * Keep a copy of the the password attribute.
554  */
555  case PW_CHAP_PASSWORD:
556  /*
557  * If it's already hex, do nothing.
558  */
559  if ((vp->vp_length == 17) &&
560  (already_hex(vp))) break;
561 
562  /*
563  * CHAP-Password is octets, so it may not be zero terminated.
564  */
565  request->password = fr_pair_make(request->packet, &request->packet->vps, "Cleartext-Password",
566  "", T_OP_EQ);
567  fr_pair_value_bstrncpy(request->password, vp->vp_strvalue, vp->vp_length);
568  break;
569 
570  case PW_USER_PASSWORD:
571  case PW_MS_CHAP_PASSWORD:
572  request->password = fr_pair_make(request->packet, &request->packet->vps, "Cleartext-Password",
573  vp->vp_strvalue, T_OP_EQ);
574  break;
575 
576  case PW_RADCLIENT_TEST_NAME:
577  request->name = vp->vp_strvalue;
578  break;
579  }
580  } /* loop over the VP's we read in */
581 
582  /*
583  * Use the default set on the command line
584  */
585  if (request->packet->code == PW_CODE_UNDEFINED) request->packet->code = packet_code;
586 
587  /*
588  * Default to the filename
589  */
590  if (!request->name) request->name = request->files->packets;
591 
592  /*
593  * Automatically set the response code from the request code
594  * (if one wasn't already set).
595  */
596  if (request->filter_code == PW_CODE_UNDEFINED) {
597  switch (request->packet->code) {
600  break;
601 
604  break;
605 
606  case PW_CODE_COA_REQUEST:
607  request->filter_code = PW_CODE_COA_ACK;
608  break;
609 
612  break;
613 
615  switch (radclient_get_code(request->packet->dst_port)) {
618  break;
619 
622  break;
623 
624  default:
625  request->filter_code = PW_CODE_UNDEFINED;
626  break;
627  }
628  break;
629 
630  case PW_CODE_UNDEFINED:
631  REDEBUG("Both Packet-Type and Response-Packet-Type undefined, specify at least one, "
632  "or a well known RADIUS port");
633  goto error;
634 
635  default:
636  REDEBUG("Can't determine expected Response-Packet-Type for Packet-Type %i",
637  request->packet->code);
638  goto error;
639  }
640  /*
641  * Automatically set the request code from the response code
642  * (if one wasn't already set).
643  */
644  } else if (request->packet->code == PW_CODE_UNDEFINED) {
645  switch (request->filter_code) {
648  request->packet->code = PW_CODE_ACCESS_REQUEST;
649  break;
650 
653  break;
654 
658  break;
659 
660  case PW_CODE_COA_ACK:
661  case PW_CODE_COA_NAK:
662  request->packet->code = PW_CODE_COA_REQUEST;
663  break;
664 
665  default:
666  REDEBUG("Can't determine expected Packet-Type for Response-Packet-Type %i",
667  request->filter_code);
668  goto error;
669  }
670  }
671 
672  /*
673  * Automatically set the dst port (if one wasn't already set).
674  */
675  if (request->packet->dst_port == 0) {
676  radclient_get_port(request->packet->code, &request->packet->dst_port);
677  if (request->packet->dst_port == 0) {
678  REDEBUG("Can't determine destination port");
679  goto error;
680  }
681  }
682 
683  /*
684  * Add it to the tail of the list.
685  */
686  if (!request_head) {
687  assert(rc_request_tail == NULL);
688  request_head = request;
689  request->prev = NULL;
690  } else {
691  assert(rc_request_tail->next == NULL);
692  rc_request_tail->next = request;
693  request->prev = rc_request_tail;
694  }
695  rc_request_tail = request;
696  request->next = NULL;
697 
698  /*
699  * Set the destructor so it removes itself from the
700  * request list when freed. We don't set this until
701  * the packet is actually in the list, else we trigger
702  * the asserts in the free callback.
703  */
704  talloc_set_destructor(request, _rc_request_free);
705  } while (!packets_done); /* loop until the file is done. */
706 
707  if (packets != stdin) fclose(packets);
708  if (filters) fclose(filters);
709 
710  /*
711  * And we're done.
712  */
713  return 1;
714 
715 error:
716  talloc_free(request);
717 
718  if (packets != stdin) fclose(packets);
719  if (filters) fclose(filters);
720 
721  return 0;
722 }
723 
724 
725 /*
726  * Sanity check each argument.
727  */
728 static int radclient_sane(rc_request_t *request)
729 {
730  if (request->packet->dst_port == 0) {
731  request->packet->dst_port = server_port;
732  }
733  if (request->packet->dst_ipaddr.af == AF_UNSPEC) {
734  if (server_ipaddr.af == AF_UNSPEC) {
735  ERROR("No server was given, and request %" PRIu64 " in file %s did not contain "
736  "Packet-Dst-IP-Address", request->num, request->files->packets);
737  return -1;
738  }
739  request->packet->dst_ipaddr = server_ipaddr;
740  }
741  if (request->packet->code == 0) {
742  if (packet_code == -1) {
743  ERROR("Request was \"auto\", and request %" PRIu64 " in file %s did not contain Packet-Type",
744  request->num, request->files->packets);
745  return -1;
746  }
747  request->packet->code = packet_code;
748  }
749  request->packet->sockfd = -1;
750 
751  return 0;
752 }
753 
754 
755 /*
756  * For request handling.
757  */
758 static int filename_cmp(void const *one, void const *two)
759 {
760  int cmp;
761 
762  rc_file_pair_t const *a = one;
763  rc_file_pair_t const *b = two;
764 
765  cmp = strcmp(a->packets, b->packets);
766  if (cmp != 0) return cmp;
767 
768  return strcmp(a->filters, b->filters);
769 }
770 
771 static int filename_walk(UNUSED void *context, void *data)
772 {
773  rc_file_pair_t *files = data;
774 
775  /*
776  * Read request(s) from the file.
777  */
778  if (!radclient_init(files, files)) return -1; /* stop walking */
779 
780  return 0;
781 }
782 
783 
784 /*
785  * Deallocate packet ID, etc.
786  */
787 static void deallocate_id(rc_request_t *request)
788 {
789  if (!request || !request->packet ||
790  (request->packet->id < 0)) {
791  return;
792  }
793 
794  /*
795  * One more unused RADIUS ID.
796  */
797  fr_packet_list_id_free(pl, request->packet, true);
798 
799  /*
800  * If we've already sent a packet, free up the old one,
801  * and ensure that the next packet has a unique
802  * authentication vector.
803  */
804  if (request->packet->data) TALLOC_FREE(request->packet->data);
805  if (request->reply) fr_radius_free(&request->reply);
806 }
807 
808 /*
809  * Send one packet.
810  */
811 static int send_one_packet(rc_request_t *request)
812 {
813  assert(request->done == false);
814 
815  /*
816  * Remember when we have to wake up, to re-send the
817  * request, of we didn't receive a reply.
818  */
819  if ((sleep_time == -1) || (sleep_time > (int) timeout)) sleep_time = (int) timeout;
820 
821  /*
822  * Haven't sent the packet yet. Initialize it.
823  */
824  if (request->packet->id == -1) {
825  int i;
826  bool rcode;
827 
828  assert(request->reply == NULL);
829 
830  /*
831  * Didn't find a free packet ID, we're not done,
832  * we don't sleep, and we stop trying to process
833  * this packet.
834  */
835  retry:
836  request->packet->src_ipaddr.af = server_ipaddr.af;
837  rcode = fr_packet_list_id_alloc(pl, ipproto, &request->packet, NULL);
838  if (!rcode) {
839  int mysockfd;
840 
841 #ifdef WITH_TCP
842  if (proto) {
843  mysockfd = fr_socket_client_tcp(NULL,
844  &request->packet->dst_ipaddr,
845  request->packet->dst_port, false);
846  } else
847 #endif
848  mysockfd = fr_socket(&client_ipaddr, 0);
849  if (mysockfd < 0) {
850  ERROR("Failed opening socket");
851  exit(1);
852  }
853  if (!fr_packet_list_socket_add(pl, mysockfd, ipproto,
854  &request->packet->dst_ipaddr,
855  request->packet->dst_port, NULL)) {
856  ERROR("Can't add new socket");
857  exit(1);
858  }
859  goto retry;
860  }
861 
862  assert(request->packet->id != -1);
863  assert(request->packet->data == NULL);
864 
865  for (i = 0; i < 4; i++) {
866  ((uint32_t *) request->packet->vector)[i] = fr_rand();
867  }
868 
869  /*
870  * Update the password, so it can be encrypted with the
871  * new authentication vector.
872  */
873  if (request->password) {
874  VALUE_PAIR *vp;
875 
876  if ((vp = fr_pair_find_by_num(request->packet->vps, 0, PW_USER_PASSWORD, TAG_ANY)) != NULL) {
877  fr_pair_value_strcpy(vp, request->password->vp_strvalue);
878 
879  } else if ((vp = fr_pair_find_by_num(request->packet->vps, 0, PW_CHAP_PASSWORD, TAG_ANY)) != NULL) {
880  uint8_t buffer[17];
881 
882  fr_radius_encode_chap_password(buffer, request->packet, fr_rand() & 0xff, request->password);
883  fr_pair_value_memcpy(vp, buffer, 17);
884 
885  } else if (fr_pair_find_by_num(request->packet->vps, 0, PW_MS_CHAP_PASSWORD, TAG_ANY) != NULL) {
886  mschapv1_encode(request->packet, &request->packet->vps, request->password->vp_strvalue);
887 
888  } else {
889  DEBUG("WARNING: No password in the request");
890  }
891  }
892 
893  request->timestamp = time(NULL);
894  request->tries = 1;
895  request->resend++;
896 
897  } else { /* request->packet->id >= 0 */
898  time_t now = time(NULL);
899 
900  /*
901  * FIXME: Accounting packets are never retried!
902  * The Acct-Delay-Time attribute is updated to
903  * reflect the delay, and the packet is re-sent
904  * from scratch!
905  */
906 
907  /*
908  * Not time for a retry, do so.
909  */
910  if ((now - request->timestamp) < timeout) {
911  /*
912  * When we walk over the tree sending
913  * packets, we update the minimum time
914  * required to sleep.
915  */
916  if ((sleep_time == -1) ||
917  (sleep_time > (now - request->timestamp))) {
918  sleep_time = now - request->timestamp;
919  }
920  return 0;
921  }
922 
923  /*
924  * We're not trying later, maybe the packet is done.
925  */
926  if (request->tries == retries) {
927  assert(request->packet->id >= 0);
928 
929  /*
930  * Delete the request from the tree of
931  * outstanding requests.
932  */
933  fr_packet_list_yank(pl, request->packet);
934 
935  REDEBUG("No reply from server for ID %d socket %d",
936  request->packet->id, request->packet->sockfd);
937  deallocate_id(request);
938 
939  /*
940  * Normally we mark it "done" when we've received
941  * the reply, but this is a special case.
942  */
943  if (request->resend == resend_count) {
944  request->done = true;
945  }
946  stats.lost++;
947  return -1;
948  }
949 
950  /*
951  * We are trying later.
952  */
953  request->timestamp = now;
954  request->tries++;
955  }
956 
957  /*
958  * Send the packet.
959  */
960  if (fr_radius_send(request->packet, NULL, secret) < 0) {
961  REDEBUG("Failed to send packet for ID %d", request->packet->id);
962  deallocate_id(request);
963  request->done = true;
964  return -1;
965  }
966 
967  fr_packet_header_print(fr_log_fp, request->packet, false);
968  if (fr_debug_lvl > 0) fr_pair_list_fprint(fr_log_fp, request->packet->vps);
969 
970  return 0;
971 }
972 
973 /*
974  * Receive one packet, maybe.
975  */
976 static int recv_one_packet(int wait_time)
977 {
978  fd_set set;
979  struct timeval tv;
980  rc_request_t *request;
981  RADIUS_PACKET *reply, **packet_p;
982  volatile int max_fd;
983 
984  /* And wait for reply, timing out as necessary */
985  FD_ZERO(&set);
986 
987  max_fd = fr_packet_list_fd_set(pl, &set);
988  if (max_fd < 0) exit(1); /* no sockets to listen on! */
989 
990  tv.tv_sec = (wait_time <= 0) ? 0 : wait_time;
991  tv.tv_usec = 0;
992 
993  /*
994  * No packet was received.
995  */
996  if (select(max_fd, &set, NULL, NULL, &tv) <= 0) return 0;
997 
998  /*
999  * Look for the packet.
1000  */
1001  reply = fr_packet_list_recv(pl, &set);
1002  if (!reply) {
1003  ERROR("Received bad packet");
1004 #ifdef WITH_TCP
1005  /*
1006  * If the packet is bad, we close the socket.
1007  * I'm not sure how to do that now, so we just
1008  * die...
1009  */
1010  if (proto) exit(1);
1011 #endif
1012  return -1; /* bad packet */
1013  }
1014 
1015  /*
1016  * We don't use udpfromto. So if we bind to "*", we want
1017  * to find replies sent to 192.0.2.4. Therefore, we
1018  * force all replies to have the one address we know
1019  * about, no matter what real address they were sent to.
1020  *
1021  * This only works if were not using any of the
1022  * Packet-* attributes, or running with 'auto'.
1023  */
1024  reply->dst_ipaddr = client_ipaddr;
1025  reply->dst_port = client_port;
1026 
1027 #ifdef WITH_TCP
1028 
1029  /*
1030  * TCP sockets don't use recvmsg(), and thus don't get
1031  * the source IP/port. However, since they're TCP, we
1032  * know what the source IP/port is, because that's where
1033  * we connected to.
1034  */
1035  if (ipproto == IPPROTO_TCP) {
1036  reply->src_ipaddr = server_ipaddr;
1037  reply->src_port = server_port;
1038  }
1039 #endif
1040 
1041  packet_p = fr_packet_list_find_byreply(pl, reply);
1042  if (!packet_p) {
1043  ERROR("Received reply to request we did not send. (id=%d socket %d)",
1044  reply->id, reply->sockfd);
1045  fr_radius_free(&reply);
1046  return -1; /* got reply to packet we didn't send */
1047  }
1048  request = fr_packet2myptr(rc_request_t, packet, packet_p);
1049 
1050  /*
1051  * Fails the signature validation: not a real reply.
1052  * FIXME: Silently drop it and listen for another packet.
1053  */
1054  if (fr_radius_verify(reply, request->packet, secret) < 0) {
1055  REDEBUG("Reply verification failed");
1056  stats.lost++;
1057  goto packet_done; /* shared secret is incorrect */
1058  }
1059 
1060  if (print_filename) {
1061  RDEBUG("%s response code %d", request->files->packets, reply->code);
1062  }
1063 
1064  deallocate_id(request);
1065  request->reply = reply;
1066  reply = NULL;
1067 
1068  /*
1069  * If this fails, we're out of memory.
1070  */
1071  if (fr_radius_decode(request->reply, request->packet, secret) != 0) {
1072  REDEBUG("Reply decode failed");
1073  stats.lost++;
1074  goto packet_done;
1075  }
1076 
1077  fr_packet_header_print(fr_log_fp, request->reply, true);
1078  if (fr_debug_lvl > 0) fr_pair_list_fprint(fr_log_fp, request->reply->vps);
1079 
1080  /*
1081  * Increment counters...
1082  */
1083  switch (request->reply->code) {
1084  case PW_CODE_ACCESS_ACCEPT:
1086  case PW_CODE_COA_ACK:
1088  stats.accepted++;
1089  break;
1090 
1092  break;
1093 
1094  default:
1095  stats.rejected++;
1096  }
1097 
1098  /*
1099  * If we had an expected response code, check to see if the
1100  * packet matched that.
1101  */
1102  if ((request->filter_code != PW_CODE_UNDEFINED) && (request->reply->code != request->filter_code)) {
1103  if (is_radius_code(request->reply->code)) {
1104  REDEBUG("%s: Expected %s got %s", request->name, fr_packet_codes[request->filter_code],
1105  fr_packet_codes[request->reply->code]);
1106  } else {
1107  REDEBUG("%s: Expected %u got %i", request->name, request->filter_code,
1108  request->reply->code);
1109  }
1110  stats.failed++;
1111  /*
1112  * Check if the contents of the packet matched the filter
1113  */
1114  } else if (!request->filter) {
1115  stats.passed++;
1116  } else {
1117  VALUE_PAIR const *failed[2];
1118 
1119  fr_pair_list_sort(&request->reply->vps, fr_pair_cmp_by_da_tag);
1120  if (fr_pair_validate(failed, request->filter, request->reply->vps)) {
1121  RDEBUG("%s: Response passed filter", request->name);
1122  stats.passed++;
1123  } else {
1124  fr_pair_validate_debug(request, failed);
1125  REDEBUG("%s: Response for failed filter", request->name);
1126  stats.failed++;
1127  }
1128  }
1129 
1130  if (request->resend == resend_count) {
1131  request->done = true;
1132  }
1133 
1134 packet_done:
1135 fr_radius_free(&request->reply);
1136  fr_radius_free(&reply); /* may be NULL */
1137 
1138  return 0;
1139 }
1140 
1141 int main(int argc, char **argv)
1142 {
1143  int c;
1144  char const *radius_dir = RADDBDIR;
1145  char const *dict_dir = DICTDIR;
1146  char filesecret[256];
1147  FILE *fp;
1148  int do_summary = false;
1149  int persec = 0;
1150  int parallel = 1;
1151  rc_request_t *this;
1152  int force_af = AF_UNSPEC;
1153  fr_dict_t *dict = NULL;
1154 
1155  /*
1156  * It's easier having two sets of flags to set the
1157  * verbosity of library calls and the verbosity of
1158  * radclient.
1159  */
1160  fr_debug_lvl = 0;
1161  fr_log_fp = stdout;
1162 
1163 #ifndef NDEBUG
1164  if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
1165  fr_perror("radclient");
1166  exit(EXIT_FAILURE);
1167  }
1168 #endif
1169 
1170  talloc_set_log_stderr();
1171 
1172  filename_tree = rbtree_create(NULL, filename_cmp, NULL, 0);
1173  if (!filename_tree) {
1174  oom:
1175  ERROR("Out of memory");
1176  exit(1);
1177  }
1178 
1179  while ((c = getopt(argc, argv, "46c:d:D:f:Fhi:n:p:qr:sS:t:vx"
1180 #ifdef WITH_TCP
1181  "P:"
1182 #endif
1183  )) != EOF) switch (c) {
1184  case '4':
1185  force_af = AF_INET;
1186  break;
1187 
1188  case '6':
1189  force_af = AF_INET6;
1190  break;
1191 
1192  case 'c':
1193  if (!isdigit((int) *optarg))
1194  usage();
1195  resend_count = atoi(optarg);
1196  break;
1197 
1198  case 'D':
1199  dict_dir = optarg;
1200  break;
1201 
1202  case 'd':
1203  radius_dir = optarg;
1204  break;
1205 
1206  case 'f':
1207  {
1208  char const *p;
1209  rc_file_pair_t *files;
1210 
1211  files = talloc(talloc_autofree_context(), rc_file_pair_t);
1212  if (!files) goto oom;
1213 
1214  p = strchr(optarg, ':');
1215  if (p) {
1216  files->packets = talloc_strndup(files, optarg, p - optarg);
1217  if (!files->packets) goto oom;
1218  files->filters = p + 1;
1219  } else {
1220  files->packets = optarg;
1221  files->filters = NULL;
1222  }
1223  rbtree_insert(filename_tree, (void *) files);
1224  }
1225  break;
1226 
1227  case 'F':
1228  print_filename = true;
1229  break;
1230 
1231  case 'i': /* currently broken */
1232  if (!isdigit((int) *optarg))
1233  usage();
1234  last_used_id = atoi(optarg);
1235  if ((last_used_id < 0) || (last_used_id > 255)) {
1236  usage();
1237  }
1238  break;
1239 
1240  case 'n':
1241  persec = atoi(optarg);
1242  if (persec <= 0) usage();
1243  break;
1244 
1245  /*
1246  * Note that sending MANY requests in
1247  * parallel can over-run the kernel
1248  * queues, and Linux will happily discard
1249  * packets. So even if the server responds,
1250  * the client may not see the reply.
1251  */
1252  case 'p':
1253  parallel = atoi(optarg);
1254  if (parallel <= 0) usage();
1255  break;
1256 
1257 #ifdef WITH_TCP
1258  case 'P':
1259  proto = optarg;
1260  if (strcmp(proto, "tcp") != 0) {
1261  if (strcmp(proto, "udp") == 0) {
1262  proto = NULL;
1263  } else {
1264  usage();
1265  }
1266  } else {
1267  ipproto = IPPROTO_TCP;
1268  }
1269  break;
1270 
1271 #endif
1272 
1273  case 'q':
1274  do_output = false;
1275  fr_log_fp = NULL; /* no output from you, either! */
1276  break;
1277 
1278  case 'r':
1279  if (!isdigit((int) *optarg)) usage();
1280  retries = atoi(optarg);
1281  if ((retries == 0) || (retries > 1000)) usage();
1282  break;
1283 
1284  case 's':
1285  do_summary = true;
1286  break;
1287 
1288  case 'S':
1289  {
1290  char *p;
1291  fp = fopen(optarg, "r");
1292  if (!fp) {
1293  ERROR("Error opening %s: %s", optarg, fr_syserror(errno));
1294  exit(1);
1295  }
1296  if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
1297  ERROR("Error reading %s: %s", optarg, fr_syserror(errno));
1298  exit(1);
1299  }
1300  fclose(fp);
1301 
1302  /* truncate newline */
1303  p = filesecret + strlen(filesecret) - 1;
1304  while ((p >= filesecret) &&
1305  (*p < ' ')) {
1306  *p = '\0';
1307  --p;
1308  }
1309 
1310  if (strlen(filesecret) < 2) {
1311  ERROR("Secret in %s is too short", optarg);
1312  exit(1);
1313  }
1314  secret = filesecret;
1315  }
1316  break;
1317 
1318  case 't':
1319  if (!isdigit((int) *optarg))
1320  usage();
1321  timeout = atof(optarg);
1322  break;
1323 
1324  case 'v':
1325  fr_debug_lvl = 1;
1326  DEBUG("%s", radclient_version);
1327  exit(0);
1328 
1329  case 'x':
1330  fr_debug_lvl++;
1331  break;
1332 
1333  case 'h':
1334  default:
1335  usage();
1336  }
1337  argc -= (optind - 1);
1338  argv += (optind - 1);
1339 
1340  if ((argc < 3) || ((secret == NULL) && (argc < 4))) {
1341  ERROR("Insufficient arguments");
1342  usage();
1343  }
1344  /*
1345  * Mismatch between the binary and the libraries it depends on
1346  */
1348  fr_perror("radclient");
1349  return 1;
1350  }
1351 
1352  if (fr_dict_init(NULL, &dict, dict_dir, RADIUS_DICTIONARY, "radius") < 0) {
1353  fr_perror("radclient");
1354  return 1;
1355  }
1356 
1357  if (fr_dict_read(dict, radius_dir, RADIUS_DICTIONARY) == -1) {
1358  fr_perror("radclient");
1359  return 1;
1360  }
1361  fr_strerror(); /* Clear the error buffer */
1362 
1363  /*
1364  * Get the request type
1365  */
1366  if (!isdigit((int) argv[2][0])) {
1367  packet_code = fr_str2int(fr_request_types, argv[2], -2);
1368  if (packet_code == -2) {
1369  ERROR("Unrecognised request type \"%s\"", argv[2]);
1370  usage();
1371  }
1372  } else {
1373  packet_code = atoi(argv[2]);
1374  }
1375 
1376  /*
1377  * Resolve hostname.
1378  */
1379  if (strcmp(argv[1], "-") != 0) {
1380  if (fr_inet_pton_port(&server_ipaddr, &server_port, argv[1], -1, force_af, true, true) < 0) {
1381  ERROR("%s", fr_strerror());
1382  exit(1);
1383  }
1384 
1385  /*
1386  * Work backwards from the port to determine the packet type
1387  */
1388  if (packet_code == PW_CODE_UNDEFINED) packet_code = radclient_get_code(server_port);
1389  }
1390  radclient_get_port(packet_code, &server_port);
1391 
1392  /*
1393  * Add the secret.
1394  */
1395  if (argv[3]) secret = argv[3];
1396 
1397  /*
1398  * If no '-f' is specified, we're reading from stdin.
1399  */
1400  if (rbtree_num_elements(filename_tree) == 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)) {
1406  exit(1);
1407  }
1408  }
1409 
1410  /*
1411  * Walk over the list of filenames, creating the requests.
1412  */
1413  if (rbtree_walk(filename_tree, RBTREE_IN_ORDER, filename_walk, NULL) != 0) {
1414  ERROR("Failed parsing input files");
1415  exit(1);
1416  }
1417 
1418  /*
1419  * No packets read. Die.
1420  */
1421  if (!request_head) {
1422  ERROR("Nothing to send");
1423  exit(1);
1424  }
1425 
1426  /*
1427  * Bind to the first specified IP address and port.
1428  * This means we ignore later ones.
1429  */
1430  if (request_head->packet->src_ipaddr.af == AF_UNSPEC) {
1431  memset(&client_ipaddr, 0, sizeof(client_ipaddr));
1432  client_ipaddr.af = server_ipaddr.af;
1433  } else {
1434  client_ipaddr = request_head->packet->src_ipaddr;
1435  }
1436 
1437  client_port = request_head->packet->src_port;
1438 
1439 #ifdef WITH_TCP
1440  if (proto) {
1441  sockfd = fr_socket_client_tcp(NULL, &server_ipaddr, server_port, false);
1442  } else
1443 #endif
1444  sockfd = fr_socket(&client_ipaddr, client_port);
1445  if (sockfd < 0) {
1446  ERROR("Error opening socket");
1447  exit(1);
1448  }
1449 
1450  pl = fr_packet_list_create(1);
1451  if (!pl) {
1452  ERROR("Out of memory");
1453  exit(1);
1454  }
1455 
1456  if (!fr_packet_list_socket_add(pl, sockfd, ipproto, &server_ipaddr,
1457  server_port, NULL)) {
1458  ERROR("Out of memory");
1459  exit(1);
1460  }
1461 
1462  /*
1463  * Walk over the list of packets, sanity checking
1464  * everything.
1465  */
1466  for (this = request_head; this != NULL; this = this->next) {
1467  this->packet->src_ipaddr = client_ipaddr;
1468  this->packet->src_port = client_port;
1469  if (radclient_sane(this) != 0) {
1470  exit(1);
1471  }
1472  }
1473 
1474  /*
1475  * Walk over the packets to send, until
1476  * we're all done.
1477  *
1478  * FIXME: This currently busy-loops until it receives
1479  * all of the packets. It should really have some sort of
1480  * send packet, get time to wait, select for time, etc.
1481  * loop.
1482  */
1483  do {
1484  int n = parallel;
1485  rc_request_t *next;
1486  char const *filename = NULL;
1487 
1488  done = true;
1489  sleep_time = -1;
1490 
1491  /*
1492  * Walk over the packets, sending them.
1493  */
1494 
1495  for (this = request_head; this != NULL; this = next) {
1496  next = this->next;
1497 
1498  /*
1499  * If there's a packet to receive,
1500  * receive it, but don't wait for a
1501  * packet.
1502  */
1503  recv_one_packet(0);
1504 
1505  /*
1506  * This packet is done. Delete it.
1507  */
1508  if (this->done) {
1509  talloc_free(this);
1510  continue;
1511  }
1512 
1513  /*
1514  * Packets from multiple '-f' are sent
1515  * in parallel.
1516  *
1517  * Packets from one file are sent in
1518  * series, unless '-p' is specified, in
1519  * which case N packets from each file
1520  * are sent in parallel.
1521  */
1522  if (this->files->packets != filename) {
1523  filename = this->files->packets;
1524  n = parallel;
1525  }
1526 
1527  if (n > 0) {
1528  n--;
1529 
1530  /*
1531  * Send the current packet.
1532  */
1533  if (send_one_packet(this) < 0) {
1534  talloc_free(this);
1535  break;
1536  }
1537 
1538  /*
1539  * Wait a little before sending
1540  * the next packet, if told to.
1541  */
1542  if (persec) {
1543  struct timeval tv;
1544 
1545  /*
1546  * Don't sleep elsewhere.
1547  */
1548  sleep_time = 0;
1549 
1550  if (persec == 1) {
1551  tv.tv_sec = 1;
1552  tv.tv_usec = 0;
1553  } else {
1554  tv.tv_sec = 0;
1555  tv.tv_usec = 1000000/persec;
1556  }
1557 
1558  /*
1559  * Sleep for milliseconds,
1560  * portably.
1561  *
1562  * If we get an error or
1563  * a signal, treat it like
1564  * a normal timeout.
1565  */
1566  select(0, NULL, NULL, NULL, &tv);
1567  }
1568 
1569  /*
1570  * If we haven't sent this packet
1571  * often enough, we're not done,
1572  * and we shouldn't sleep.
1573  */
1574  if (this->resend < resend_count) {
1575  done = false;
1576  sleep_time = 0;
1577  }
1578  } else { /* haven't sent this packet, we're not done */
1579  assert(this->done == false);
1580  assert(this->reply == NULL);
1581  done = false;
1582  }
1583  }
1584 
1585  /*
1586  * Still have outstanding requests.
1587  */
1588  if (fr_packet_list_num_elements(pl) > 0) {
1589  done = false;
1590  } else {
1591  sleep_time = 0;
1592  }
1593 
1594  /*
1595  * Nothing to do until we receive a request, so
1596  * sleep until then. Once we receive one packet,
1597  * we go back, and walk through the whole list again,
1598  * sending more packets (if necessary), and updating
1599  * the sleep time.
1600  */
1601  if (!done && (sleep_time > 0)) {
1602  recv_one_packet(sleep_time);
1603  }
1604  } while (!done);
1605 
1606  rbtree_free(filename_tree);
1607  fr_packet_list_free(pl);
1608  while (request_head) TALLOC_FREE(request_head);
1609  talloc_free(dict);
1610 
1611  if (do_summary) {
1612  DEBUG("Packet summary:\n"
1613  "\tAccepted : %" PRIu64 "\n"
1614  "\tRejected : %" PRIu64 "\n"
1615  "\tLost : %" PRIu64 "\n"
1616  "\tPassed filter : %" PRIu64 "\n"
1617  "\tFailed filter : %" PRIu64,
1618  stats.accepted,
1619  stats.rejected,
1620  stats.lost,
1621  stats.passed,
1622  stats.failed
1623  );
1624  }
1625 
1626  if ((stats.lost > 0) || (stats.failed > 0)) {
1627  exit(1);
1628  }
1629  exit(0);
1630 }
#define PW_MSCHAP_CHALLENGE
Definition: radius.h:213
char const * name
Test name (as specified in the request).
Definition: radclient.h:88
VALUE_PAIR has a single value.
Definition: pair.h:101
static char const * dict_dir
Definition: radwho.c:53
int sockfd
Socket this packet was read from.
Definition: libradius.h:147
static int sockfd
Definition: radclient.c:59
FILE * fr_log_fp
Definition: radius.c:81
void fr_pair_list_fprint(FILE *, VALUE_PAIR const *vp)
Print a list of attributes and enumv.
Definition: pair.c:2266
static bool already_hex(VALUE_PAIR *vp)
Definition: radclient.c:255
VALUE_PAIR * password
Cleartext-Password.
Definition: radclient.h:76
int id
Packet ID (used to link requests/responses).
Definition: libradius.h:154
int fr_radius_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original, char const *secret)
Calculate/check digest, and decode radius attributes.
Definition: radius.c:1485
void rbtree_free(rbtree_t *tree)
Definition: rbtree.c:84
static bool print_filename
Definition: radclient.c:54
static char const * radius_dir
Path to raddb directory.
Definition: mainconfig.c:88
int fr_socket_client_tcp(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, bool async)
Establish a connected TCP socket.
Definition: socket.c:167
RFC2865 - Access-Challenge.
Definition: radius.h:102
uint64_t lost
Requests to which we received no response.
Definition: radclient.h:55
bool fr_packet_list_id_free(fr_packet_list_t *pl, RADIUS_PACKET *request, bool yank)
Definition: packet.c:830
static void NEVER_RETURNS usage(void)
Definition: radclient.c:81
int fr_dict_read(fr_dict_t *dict, char const *dir, char const *filename)
Definition: dict.c:2291
Dictionary attribute.
Definition: dict.h:77
VALUE_PAIR * fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int attr)
Create a new valuepair.
Definition: pair.c:106
static char const * radclient_version
Definition: radclient.c:75
char const * fr_packet_codes[FR_MAX_PACKET_CODE]
Definition: radius.c:101
static int mschapv1_encode(RADIUS_PACKET *packet, VALUE_PAIR **request, char const *password)
Definition: radclient.c:143
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: radius.c:1621
static struct cmp * cmp
Definition: pair.c:45
fr_ipaddr_t src_ipaddr
Src IP address of packet.
Definition: libradius.h:149
RADIUS_PACKET ** fr_packet_list_find_byreply(fr_packet_list_t *pl, RADIUS_PACKET *reply)
Definition: packet.c:514
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition: inet.h:47
static char const * name
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:632
static void deallocate_id(rc_request_t *request)
Definition: radclient.c:787
static int last_used_id
Definition: radclient.c:60
#define VERIFY_VP(_x)
Definition: pair.h:44
bool done
Whether the request is complete.
Definition: radclient.h:86
#define UNUSED
Definition: libradius.h:134
void fr_pair_validate_debug(TALLOC_CTX *ctx, VALUE_PAIR const *failed[2])
Write an error to the library errorbuff detailing the mismatch.
Definition: pair.c:1068
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
#define PW_AUTH_UDP_PORT_ALT
Definition: radius.h:115
static PW_CODE radclient_get_code(uint16_t port)
Definition: radclient.c:233
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
Definition: cursor.c:60
int fr_radius_send(RADIUS_PACKET *, RADIUS_PACKET const *, char const *secret)
Reply to the request.
Definition: radius.c:506
VALUE_PAIR * password
Cached password VALUE_PAIR from request RADIUS_PACKET.
Definition: radiusd.h:223
static float timeout
Definition: radclient.c:43
valuepair value must be xlat expanded when it's added to VALUE_PAIR tree.
Definition: pair.h:102
Definition: token.h:46
uint8_t * data
Packet data (body).
Definition: libradius.h:160
RFC3575/RFC5176 - Disconnect-Ack (positive)
Definition: radius.h:106
static char filesecret[256]
Definition: radeapclient.c:73
uint16_t dst_port
DST Port of packet.
Definition: libradius.h:152
static int filename_cmp(void const *one, void const *two)
Definition: radclient.c:758
uint16_t src_port
Src port of packet.
Definition: libradius.h:151
fr_ipaddr_t dst_ipaddr
Dst IP address of packet.
Definition: libradius.h:150
int fr_debug_lvl
Definition: misc.c:40
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
static int force_af
Definition: radeapclient.c:222
RFC2866 - Accounting-Response.
Definition: radius.h:96
static char const * proto
Definition: radclient.c:63
FR_NAME_NUMBER const fr_request_types[]
Definition: radius.c:52
int fr_fault_setup(char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
Definition: debug.c:890
#define VENDORPEC_MICROSOFT
Definition: radius.h:200
RFC2865 - Access-Reject.
Definition: radius.h:94
RFC3575/RFC5176 - CoA-Ack (positive)
Definition: radius.h:109
int af
Address family.
Definition: inet.h:42
Vendors and attribute names.
Definition: dict.c:61
#define PW_DIGEST_ATTRIBUTES
Definition: radius.h:165
PW_CODE filter_code
Expected code of the response packet.
Definition: radclient.h:82
static bool do_output
Definition: radclient.c:45
RFC2865 - Access-Request.
Definition: radius.h:92
static int send_one_packet(rc_request_t *request)
Definition: radclient.c:811
int fr_str2int(FR_NAME_NUMBER const *table, char const *name, int def)
Definition: token.c:451
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: log.c:238
char const * packets
The file containing the request packet.
Definition: radclient.h:61
static int sleep_time
Definition: radclient.c:70
int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set)
Definition: packet.c:874
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition: version.c:38
#define PW_COA_UDP_PORT
Definition: radius.h:120
rc_request_t * next
Definition: radclient.h:72
#define DEBUG(fmt,...)
Definition: log.h:175
int main(int argc, char **argv)
Definition: radclient.c:1141
rbtree_t * rbtree_create(TALLOC_CTX *ctx, rb_comparator_t compare, rb_free_t node_free, int flags)
Create a new RED-BLACK tree.
Definition: rbtree.c:112
int fr_radius_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original, char const *secret)
Verify the Request/Response Authenticator (and Message-Authenticator if present) of a packet...
Definition: radius.c:1144
void fr_pair_value_strcpy(VALUE_PAIR *vp, char const *src)
Copy data into an "string" data type.
Definition: pair.c:2013
uint64_t passed
Requests which passed a filter.
Definition: radclient.h:56
void fr_packet_header_print(FILE *fp, RADIUS_PACKET *packet, bool received)
Definition: packet.c:962
static rc_stats_t stats
Definition: radclient.c:47
int mschap_ntpwdhash(uint8_t *out, char const *password)
Converts Unicode password to 16-byte NT hash with MD4.
Definition: mschap.c:52
void fr_pair_add(VALUE_PAIR **head, VALUE_PAIR *vp)
Add a VP to the end of the list.
Definition: pair.c:659
static bool do_summary
Definition: radeapclient.c:72
RFC2866 - Accounting-Request.
Definition: radius.h:95
#define STRINGIFY(x)
Definition: build.h:34
RADIUS_PACKET * fr_radius_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new RADIUS_PACKET.
Definition: radius.c:1651
static int resend_count
Definition: radclient.c:52
void void fr_perror(char const *,...) CC_HINT(format(printf
unsigned int attr
Attribute number.
Definition: dict.h:79
static bool done
Definition: radclient.c:53
int fr_radius_encode_chap_password(uint8_t *output, RADIUS_PACKET *packet, int id, VALUE_PAIR *password)
union fr_ipaddr_t::@1 ipaddr
RFC3575/RFC5176 - CoA-Nak (not willing to perform)
Definition: radius.h:110
unsigned int code
Packet code (type).
Definition: libradius.h:155
int rbtree_walk(rbtree_t *tree, rb_order_t order, rb_walker_t compare, void *context)
Definition: rbtree.c:693
RFC2865 - Access-Accept.
Definition: radius.h:93
#define RADIUS_DICTIONARY
Definition: conf.h:7
unsigned int vendor
Vendor that defines this attribute.
Definition: dict.h:78
static int retries
Definition: radclient.c:42
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
RADIUS_PACKET * reply
Outgoing response.
Definition: radiusd.h:225
int8_t fr_pair_cmp_by_da_tag(void const *a, void const *b)
Definition: pair.c:815
rc_file_pair_t * files
Request and response file names.
Definition: radclient.h:74
bool fr_pair_validate(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE_PAIR *list)
Uses fr_pair_cmp to verify all VALUE_PAIRs in list match the filter defined by check.
Definition: pair.c:1117
#define PW_ACCT_UDP_PORT_ALT
Definition: radius.h:117
static int _rc_request_free(rc_request_t *request)
Definition: radclient.c:117
fr_packet_list_t * fr_packet_list_create(int alloc_id)
Definition: packet.c:464
RFC3575/RFC5176 - CoA-Request.
Definition: radius.h:108
uint8_t vector[AUTH_VECTOR_LEN]
RADIUS authentication vector.
Definition: libradius.h:157
int tries
Definition: radclient.h:85
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
time_t timestamp
Definition: radclient.h:77
uint32_t fr_packet_list_num_elements(fr_packet_list_t *pl)
Definition: packet.c:584
bool fr_packet_list_yank(fr_packet_list_t *pl, RADIUS_PACKET *request)
Definition: packet.c:571
void fr_pair_delete_by_num(VALUE_PAIR **head, unsigned int vendor, unsigned int attr, int8_t tag)
Delete matching pairs.
Definition: pair.c:797
int resend
Definition: radclient.h:84
Packet code has not been set.
Definition: radius.h:91
Structure which holds global statistics information.
Definition: radclient.h:52
static int filename_walk(UNUSED void *context, void *data)
Definition: radclient.c:771
#define PW_POD_UDP_PORT
Definition: radius.h:118
VALUE_PAIR * filter
If the reply passes the filter, then the request passes.
Definition: radclient.h:81
uint8_t data[]
Definition: eap_pwd.h:625
static int recv_one_packet(int wait_time)
Definition: radclient.c:976
uint64_t failed
Requests which failed a fitler.
Definition: radclient.h:57
static fr_ipaddr_t client_ipaddr
Definition: radclient.c:56
#define TAG_ANY
Definition: pair.h:191
static fr_ipaddr_t server_ipaddr
Definition: radclient.c:51
void fr_pair_list_sort(VALUE_PAIR **vps, fr_cmp_t cmp)
Sort a linked list of VALUE_PAIRs using merge sort.
Definition: pair.c:1036
value_type_t type
Type of pointer in value union.
Definition: pair.h:132
void fr_packet_list_free(fr_packet_list_t *pl)
Definition: packet.c:452
int fr_socket(fr_ipaddr_t *ipaddr, uint16_t port)
Definition: packet.c:136
bool fr_packet_list_id_alloc(fr_packet_list_t *pl, int proto, RADIUS_PACKET **request_p, void **pctx)
Definition: packet.c:611
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
Definition: cursor.c:263
int fr_pair_list_afrom_file(TALLOC_CTX *ctx, VALUE_PAIR **out, FILE *fp, bool *pfiledone)
Definition: pair.c:1333
void fr_radius_free(RADIUS_PACKET **)
Free a RADIUS_PACKET.
Definition: radius.c:1727
uint64_t accepted
Requests to which we received a accept.
Definition: radclient.h:53
RADIUS_PACKET * packet
The outgoing request.
Definition: radclient.h:79
RADIUS_PACKET * reply
The incoming response.
Definition: radclient.h:80
static void radclient_get_port(PW_CODE type, uint16_t *port)
Definition: radclient.c:200
static uint32_t parallel
Definition: radeapclient.c:64
bool rbtree_insert(rbtree_t *tree, void *data)
Definition: rbtree.c:329
char const * filters
The file containing the definition of the packet we want to match.
Definition: radclient.h:62
static rc_request_t * request_head
Definition: radclient.c:72
static fr_packet_list_t * pl
Definition: radclient.c:68
#define PW_MSCHAP_RESPONSE
Definition: radius.h:208
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
static char const * secret
Definition: radclient.c:44
#define REDEBUG(fmt,...)
Definition: log.h:254
#define PW_AUTH_UDP_PORT
Definition: radius.h:114
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
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: packet.c:356
static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files)
Definition: radclient.c:282
VALUE_PAIR * fr_cursor_remove(vp_cursor_t *cursor)
Remove the current pair.
Definition: cursor.c:433
static uint16_t client_port
Definition: radclient.c:57
RFC2865/RFC5997 - Status Server (request)
Definition: radius.h:103
IPv4/6 prefix.
Definition: inet.h:41
static int packet_code
Definition: radclient.c:50
PW_CODE
RADIUS packet codes.
Definition: radius.h:90
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
void fr_pair_value_bstrncpy(VALUE_PAIR *vp, void const *src, size_t len)
Copy data into an "string" data type.
Definition: pair.c:2043
static int getport(char const *name)
Definition: radclient.c:187
fr_dict_attr_t const * fr_dict_attr_by_num(fr_dict_t *dict, unsigned int vendor, unsigned int attr)
Lookup a fr_dict_attr_t by its vendor and attribute numbers.
Definition: dict.c:3519
#define NEVER_RETURNS
Definition: libradius.h:133
void smbdes_mschap(uint8_t const win_password[16], uint8_t const *challenge, uint8_t *response)
Definition: smbdes.c:338
#define PW_ACCT_UDP_PORT
Definition: radius.h:116
PW_TYPE type
Value type.
Definition: dict.h:80
RFC3575/RFC5176 - Disconnect-Nak (not willing to perform)
Definition: radius.h:107
rc_request_t * prev
Definition: radclient.h:71
#define RCSID(id)
Definition: build.h:135
uint64_t num
The number (within the file) of the request were reading.
Definition: radclient.h:69
VALUE_PAIR * fr_pair_make(TALLOC_CTX *ctx, VALUE_PAIR **vps, char const *attribute, char const *value, FR_TOKEN op)
Create a VALUE_PAIR from ASCII strings.
Definition: pair.c:338
static int ipproto
Definition: radclient.c:65
static int radclient_sane(rc_request_t *request)
Definition: radclient.c:728
#define RDEBUG(fmt,...)
Definition: log.h:243
static rbtree_t * filename_tree
Definition: radclient.c:67
#define ERROR(fmt,...)
Definition: log.h:145
#define is_radius_code(_x)
Definition: libradius.h:372
RADIUS_PACKET * fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set)
Definition: packet.c:901
Raw octets.
Definition: radius.h:38
#define fr_packet2myptr(TYPE, MEMBER, PTR)
Definition: packet.h:77
void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t len)
Copy data into an "octets" data type.
Definition: pair.c:1905
int fr_dict_init(TALLOC_CTX *ctx, fr_dict_t **out, char const *dir, char const *fn, char const *name)
(re)initialize a protocol dictionary
Definition: dict.c:2148
static rc_request_t * rc_request_tail
Definition: radclient.c:73
#define RADIUSD_MAGIC_NUMBER
Definition: libradius.h:51
uint64_t rejected
Requests to which we received a reject.
Definition: radclient.h:54
RFC3575/RFC5176 - Disconnect-Request.
Definition: radius.h:105
uint32_t rbtree_num_elements(rbtree_t *tree)
Definition: rbtree.c:727
static uint16_t server_port
Definition: radclient.c:49