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