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