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