Merge tag 'release_3_0_14' into tr-integ
[freeradius.git] / src / modules / rlm_eap / radeapclient.c
1 /*
2  * radeapclient.c       EAP specific radius packet debug tool.
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl>
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  */
24
25 RCSID("$Id$")
26
27 #include <freeradius-devel/libradius.h>
28
29 #include <ctype.h>
30 #include <assert.h>
31
32 #if HAVE_GETOPT_H
33 #       include <getopt.h>
34 #endif
35
36 #include <freeradius-devel/conf.h>
37 #include <freeradius-devel/radpaths.h>
38 #include <freeradius-devel/md5.h>
39
40 #include "eap_types.h"
41 #include "eap_sim.h"
42
43 extern int sha1_data_problems;
44
45 #define USEC 1000000
46
47 static uint32_t parallel = 1;
48 static unsigned int retries = 3;
49 static float timeout = 5;
50 static struct timeval tv_timeout;
51 static char const *secret = NULL;
52 static int do_output = 1;
53 static int do_summary = 0;
54 static int totalapp = 0;
55 static int totaldeny = 0;
56 static char filesecret[256];
57 static char const *radius_dir = NULL;
58 static char const *progname = "radeapclient";
59 /* fr_randctx randctx; */
60
61 main_config_t main_config;
62 char const *radiusd_version = "";
63
64 #ifdef WITH_TLS
65 #include <freeradius-devel/tls.h>
66 #endif
67
68 log_lvl_t rad_debug_lvl = 0;
69
70 //TODO: move structures to a header file.
71
72 typedef struct rc_input_vps_list rc_input_vps_list_t;
73 typedef struct rc_input_vps rc_input_vps_t;
74 typedef struct rc_transaction rc_transaction_t;
75
76 /** Structure which contains EAP context, necessary to perform the full EAP transaction.
77  */
78 typedef struct rc_eap_sim_context {
79         struct eapsim_keys keys;
80 } rc_eap_sim_context_t;
81
82 typedef struct rc_eap_md5_context {
83         int tried;
84 } rc_eap_md5_context_t;
85
86 typedef struct rc_eap_context {
87         int eap_type;   //!< contains the EAP-Type
88         char password[256];     //!< copy of User-Password (or CHAP-Password).
89         union {
90                 rc_eap_sim_context_t sim;
91                 rc_eap_md5_context_t md5;
92         } eap;
93 } rc_eap_context_t;
94
95
96 /** Structure which holds a list of available input vps.
97  */
98 struct rc_input_vps_list {
99         rc_input_vps_t *head;
100         rc_input_vps_t *tail;
101         uint32_t size;
102 };
103
104 /** Structure which holds an input vps entry (read from file or stdin),
105  *  and linkage to previous / next entries.
106  */
107 struct rc_input_vps {
108         uint32_t num;   //!< The number (within the file) of the input we're reading.
109
110         VALUE_PAIR *vps_in;     //!< the list of attribute/value pairs.
111
112         rc_input_vps_list_t *list;      //!< the list to which this entry belongs (NULL for an unchained entry).
113
114         rc_input_vps_t *prev;
115         rc_input_vps_t *next;
116 };
117
118
119 /** Structure which holds a transaction: sent packet, reply received...
120  */
121 struct rc_transaction {
122         uint32_t id;    //!< id of transaction (0 for the first one).
123
124         uint32_t num_packet;    //!< number of packets sent for this transaction.
125
126         RADIUS_PACKET *packet;
127         RADIUS_PACKET *reply;
128
129         rc_input_vps_t *input_vps;
130
131         rc_eap_context_t *eap_context;
132
133         uint32_t tries;
134
135         fr_event_t *event;      //!< armed event (if any).
136
137         char            password[256];
138         char const      *name;  //!< Test name (as specified in the request).
139 };
140
141
142 static TALLOC_CTX *autofree;
143 static uint32_t num_trans = 0; //!< number of transactions initialized.
144 static uint32_t num_started = 0; //!< number of transactions started.
145 static uint32_t num_ongoing = 0; //!< number of ongoing transactions.
146 static uint32_t num_finished = 0; //!< number of finished transactions.
147
148 static rc_input_vps_list_t rc_vps_list_in; //!< list of available input vps entries.
149 static fr_packet_list_t *pl = NULL;     //!< list of outgoing packets.
150 static unsigned int num_sockets = 0;    //!< number of allocated sockets.
151 static fr_event_list_t *ev_list = NULL; //!< list of armed events.
152
153 static int force_af = AF_UNSPEC;
154 static int ipproto = IPPROTO_UDP;
155 static fr_ipaddr_t server_ipaddr;
156 static bool server_addr_init = false;
157 static uint16_t server_port = 0;
158 static int packet_code = PW_CODE_UNDEFINED;
159
160 static int rc_map_eap_methods(RADIUS_PACKET *req);
161 static void rc_unmap_eap_methods(RADIUS_PACKET *rep);
162 static int rc_map_eapsim_types(RADIUS_PACKET *r);
163 static int rc_unmap_eapsim_types(RADIUS_PACKET *r);
164
165 static void rc_get_port(PW_CODE type, uint16_t *port);
166 static void rc_evprep_packet_timeout(rc_transaction_t *trans);
167 static void rc_deallocate_id(rc_transaction_t *trans);
168
169
170 static void NEVER_RETURNS usage(void)
171 {
172         fprintf(stdout, "Usage: radeapclient [options] server[:port] <command> [<secret>]\n");
173
174         fprintf(stdout, "  <command>              One of auth, acct, status, coa, disconnect or auto.\n");
175         fprintf(stdout, "  -4                     Use IPv4 address of server\n");
176         fprintf(stdout, "  -6                     Use IPv6 address of server.\n");
177         fprintf(stdout, "  -d <raddb>             Set user dictionary directory (defaults to " RADDBDIR ").\n");
178         fprintf(stdout, "  -D <dictdir>           Set main dictionary directory (defaults to " DICTDIR ").\n");
179         fprintf(stdout, "  -f <file>              Read packets from file, not stdin.\n");
180         fprintf(stdout, "  -h                     Print usage help information.\n");
181         fprintf(stdout, "  -p <num>               Send 'num' packets in parallel.\n");
182         fprintf(stdout, "  -q                     Do not print anything out.\n");
183         fprintf(stdout, "  -r <retries>           If timeout, retry sending the packet 'retries' times.\n");
184         fprintf(stdout, "  -s                     Print out summary information of auth results.\n");
185         fprintf(stdout, "  -S <file>              read secret from file, not command line.\n");
186         fprintf(stdout, "  -t <timeout>           Wait 'timeout' seconds before retrying (may be a floating point number).\n");
187         fprintf(stdout, "  -v                     Show program version information.\n");
188         fprintf(stdout, "  -x                     Debugging mode.\n");
189
190         exit(1);
191 }
192
193 static const FR_NAME_NUMBER rc_request_types[] = {
194         { "auth",       PW_CODE_ACCESS_REQUEST },
195         { "challenge",  PW_CODE_ACCESS_CHALLENGE },
196         { "acct",       PW_CODE_ACCOUNTING_REQUEST },
197         { "status",     PW_CODE_STATUS_SERVER },
198         { "disconnect", PW_CODE_DISCONNECT_REQUEST },
199         { "coa",        PW_CODE_COA_REQUEST },
200         { "auto",       PW_CODE_UNDEFINED },
201
202         { NULL, 0}
203 };
204
205 int rad_virtual_server(REQUEST UNUSED *request)
206 {
207   /*We're not the server so we cannot do this*/
208   abort();
209 }
210
211 /** Convert a float to struct timeval.
212  */
213 static void rc_float_to_timeval(struct timeval *tv, float f_val)
214 {
215         tv->tv_sec = (time_t)f_val;
216         uint64_t usec = (uint64_t)(f_val * USEC) - (tv->tv_sec * USEC);
217         tv->tv_usec = usec;
218 }
219
220 /** Add an allocated rc_input_vps_t entry to the tail of the list.
221  */
222  static void rc_add_vps_entry(rc_input_vps_list_t *list, rc_input_vps_t *entry)
223 {
224         if (!list || !entry) return;
225
226         if (!list->head) {
227                 assert(list->tail == NULL);
228                 list->head = entry;
229                 entry->prev = NULL;
230         } else {
231                 assert(list->tail != NULL);
232                 assert(list->tail->next == NULL);
233                 list->tail->next = entry;
234                 entry->prev = list->tail;
235         }
236         list->tail = entry;
237         entry->next = NULL;
238         entry->list = list;
239         list->size ++;
240 }
241
242 /** Remove a selected rc_input_vps_t entry from its current list.
243  */
244 static rc_input_vps_t *rc_yank_vps_entry(rc_input_vps_t *entry)
245 {
246         if (!entry) return NULL;
247
248         if (!entry->list) return entry; /* not in a list, nothing to do. Just return the entry. */
249
250         rc_input_vps_t *prev, *next;
251
252         prev = entry->prev;
253         next = entry->next;
254
255         rc_input_vps_list_t *list = entry->list;
256
257         assert(list->head != NULL); /* entry belongs to a list, so the list can't be empty. */
258         assert(list->tail != NULL); /* same. */
259
260         if (prev) {
261                 assert(list->head != entry); /* if entry has a prev, then entry can't be head. */
262                 prev->next = next;
263         }
264         else {
265                 assert(list->head == entry); /* if entry has no prev, then entry must be head. */
266                 list->head = next;
267         }
268
269         if (next) {
270                 assert(list->tail != entry); /* if entry has a next, then entry can't be tail. */
271                 next->prev = prev;
272         }
273         else {
274                 assert(list->tail == entry); /* if entry has no next, then entry must be tail. */
275                 list->tail = prev;
276         }
277
278         entry->list = NULL;
279         entry->prev = NULL;
280         entry->next = NULL;
281         list->size --;
282         return entry;
283 }
284
285 /** Load input entries (list of vps) from a file or stdin, and add them to the list.
286  *  They will be used to initiate transactions.
287  */
288 static int rc_load_input(TALLOC_CTX *ctx, char const *filename, rc_input_vps_list_t *list, uint32_t max_entries)
289 {
290         FILE *file_in = NULL;
291         bool file_done = false;
292         rc_input_vps_t *request;
293         char const *input;
294         uint32_t input_num = 0;
295
296         /* Determine where to read the VP's from. */
297         if (filename && strcmp(filename, "-") != 0) {
298                 DEBUG2("Opening input file: %s", filename);
299                 file_in = fopen(filename, "r");
300                 if (!file_in) {
301                         ERROR("Error opening %s: %s", filename, strerror(errno));
302                         return 0;
303                 }
304                 input = filename;
305         } else {
306                 DEBUG2("Reading input vps from stdin");
307                 file_in = stdin;
308                 input = "stdin";
309         }
310
311         /* Loop over the file (or stdin). */
312         do {
313                 input_num ++;
314                 MEM(request = talloc_zero(ctx, rc_input_vps_t));
315
316                 if (fr_pair_list_afrom_file(request, &request->vps_in, file_in, &file_done) < 0) {
317                         ERROR("Error parsing entry %u from input: %s", input_num, input);
318                         talloc_free(request);
319                         break;
320                 }
321                 if (NULL == request->vps_in) {
322                         /* Last line might be empty, in this case fr_pair_list_afrom_file will return a NULL vps pointer. Silently ignore this. */
323                         talloc_free(request);
324                         break;
325                 }
326
327                 /* Add that to the list */
328                 rc_add_vps_entry(list, request);
329
330                 request->num = list->size;
331
332                 if (max_entries && list->size >= max_entries) {
333                         /* Only load what we need. */
334                         break;
335                 }
336         } while (!file_done);
337
338         if (file_in != stdin) fclose(file_in);
339
340         /* And we're done. */
341         DEBUG("Read %d element(s) from input: %s", list->size, input);
342         return 1;
343 }
344
345 /** Perform packet initialization for a transaction.
346  */
347 static int rc_init_packet(rc_transaction_t *trans)
348 {
349         if (!trans || !trans->packet) return 0;
350
351         RADIUS_PACKET *packet = trans->packet;
352         vp_cursor_t cursor;
353         VALUE_PAIR *vp;
354
355         /*
356          *      Process special attributes
357          */
358         for (vp = fr_cursor_init(&cursor, &packet->vps);
359                  vp;
360                  vp = fr_cursor_next(&cursor)) {
361                 /*
362                  *      Double quoted strings get marked up as xlat expansions,
363                  *      but we don't support that in request.
364                  */
365                 if (vp->type == VT_XLAT) {
366                         vp->type = VT_DATA;
367                         vp->vp_strvalue = vp->value.xlat;
368                         vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
369                 }
370
371                 if (!vp->da->vendor) switch (vp->da->attr) {
372                 default:
373                         break;
374
375                 /*
376                  *      Allow it to set the packet type in
377                  *      the attributes read from the file.
378                  */
379                 case PW_PACKET_TYPE:
380                         packet->code = vp->vp_integer;
381                         break;
382
383                 case PW_PACKET_DST_PORT:
384                         packet->dst_port = (vp->vp_integer & 0xffff);
385                         break;
386
387                 case PW_PACKET_DST_IP_ADDRESS:
388                         packet->dst_ipaddr.af = AF_INET;
389                         packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
390                         packet->dst_ipaddr.prefix = 32;
391                         break;
392
393                 case PW_PACKET_DST_IPV6_ADDRESS:
394                         packet->dst_ipaddr.af = AF_INET6;
395                         packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
396                         packet->dst_ipaddr.prefix = 128;
397                         break;
398
399                 case PW_PACKET_SRC_PORT:
400                         if ((vp->vp_integer < 1024) ||
401                                 (vp->vp_integer > 65535)) {
402                                 DEBUG("Invalid value '%u' for Packet-Src-Port", vp->vp_integer);
403                         } else {
404                                 packet->src_port = (vp->vp_integer & 0xffff);
405                         }
406                         break;
407
408                 case PW_PACKET_SRC_IP_ADDRESS:
409                         packet->src_ipaddr.af = AF_INET;
410                         packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
411                         packet->src_ipaddr.prefix = 32;
412                         break;
413
414                 case PW_PACKET_SRC_IPV6_ADDRESS:
415                         packet->src_ipaddr.af = AF_INET6;
416                         packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
417                         packet->src_ipaddr.prefix = 128;
418                         break;
419
420                 case PW_DIGEST_REALM:
421                 case PW_DIGEST_NONCE:
422                 case PW_DIGEST_METHOD:
423                 case PW_DIGEST_URI:
424                 case PW_DIGEST_QOP:
425                 case PW_DIGEST_ALGORITHM:
426                 case PW_DIGEST_BODY_DIGEST:
427                 case PW_DIGEST_CNONCE:
428                 case PW_DIGEST_NONCE_COUNT:
429                 case PW_DIGEST_USER_NAME:
430                 /* overlapping! */
431                 {
432                         DICT_ATTR const *da;
433                         uint8_t *p, *q;
434
435                         p = talloc_array(vp, uint8_t, vp->vp_length + 2);
436
437                         memcpy(p + 2, vp->vp_octets, vp->vp_length);
438                         p[0] = vp->da->attr - PW_DIGEST_REALM + 1;
439                         vp->vp_length += 2;
440                         p[1] = vp->vp_length;
441
442                         da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0);
443                         if (!da) {
444                                 ERROR("Attribute 'Digest-Attributes' not found by value");
445                                 exit(1);
446                         }
447                         vp->da = da;
448
449                         /*
450                          *      Re-do fr_pair_value_memsteal ourselves,
451                          *      because we play games with
452                          *      vp->da, and fr_pair_value_memsteal goes
453                          *      to GREAT lengths to sanitize
454                          *      and fix and change and
455                          *      double-check the various
456                          *      fields.
457                          */
458                         memcpy(&q, &vp->vp_octets, sizeof(q));
459                         talloc_free(q);
460
461                         vp->vp_octets = talloc_steal(vp, p);
462                         vp->type = VT_DATA;
463
464                         VERIFY_VP(vp);
465                 }
466                         break;
467
468                 /*
469                  *      Keep a copy of the the password attribute.
470                  */
471                 case PW_CLEARTEXT_PASSWORD:
472                 case PW_USER_PASSWORD:
473                 case PW_CHAP_PASSWORD:
474                 case PW_MS_CHAP_PASSWORD:
475                         strlcpy(trans->password, vp->vp_strvalue, sizeof(trans->password));
476                         break;
477
478                 case PW_RADCLIENT_TEST_NAME:
479                         trans->name = vp->vp_strvalue;
480                         break;
481                 }
482         } /* loop over the VP's we read in */
483
484         if (packet->dst_port == 0) packet->dst_port = server_port;
485
486         if (packet->dst_ipaddr.af == AF_UNSPEC) {
487                 if (!server_addr_init) {
488                         DEBUG("No server was given, and input entry %u did not contain Packet-Dst-IP-Address, ignored.", trans->input_vps->num);
489                         return 0;
490                 }
491                 packet->dst_ipaddr = server_ipaddr;
492         }
493
494         /* Use the default set on the command line. */
495         if (packet->code == PW_CODE_UNDEFINED) {
496                 if (packet_code == PW_CODE_UNDEFINED) {
497                         DEBUG("No packet type was given, and input entry %u did not contain Packet-Type, ignored.", trans->input_vps->num);
498                         return 0;
499                 }
500                 packet->code = packet_code;
501         }
502
503         /* Automatically set the dst port (if one wasn't already set). */
504         if (packet->dst_port == 0) {
505                 rc_get_port(packet->code, &packet->dst_port);
506                 if (packet->dst_port == 0) {
507                         DEBUG("Can't determine destination port for input entry %u, ignored.", trans->input_vps->num);
508                         return 0;
509                 }
510         }
511
512         packet->sockfd = -1;
513
514         /* Done. */
515         return 1;
516 }
517
518 /** Map EAP methods and build EAP-Message (if EAP is involved).
519  *  Also allocate the EAP context.
520  */
521 static void rc_build_eap_context(rc_transaction_t *trans)
522 {
523         if (!trans || !trans->packet) return;
524
525         RADIUS_PACKET *packet = trans->packet;
526
527         /* Build EAP-Message (if EAP is involved. Otherwise, do nothing). */
528         int eap_type = rc_map_eap_methods(packet);
529
530         if (eap_type) {
531                 if (!trans->eap_context) {
532                         MEM(trans->eap_context = talloc_zero(trans, rc_eap_context_t));
533                 }
534                 trans->eap_context->eap_type = eap_type;
535
536                 /*
537                  *      Keep a copy of the the User-Password or CHAP-Password.
538                  *      Note: this is not useful for EAP-SIM, but we cannot know what kind
539                  *      of challenge the server will issue.
540                  */
541                 VALUE_PAIR *vp;
542                 vp = fr_pair_find_by_num(packet->vps, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
543                 if (!vp) vp = fr_pair_find_by_num(packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
544                 if (!vp) vp = fr_pair_find_by_num(packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
545                 if (vp) {
546                         strlcpy(trans->eap_context->password, vp->vp_strvalue, sizeof(trans->eap_context->password));
547                 }
548         }
549 }
550
551 /** Grab an element from the input list. Initialize a new transaction context, using this element.
552  */
553 static rc_transaction_t *rc_init_transaction(TALLOC_CTX *ctx)
554 {
555         if (!rc_vps_list_in.head || rc_vps_list_in.size == 0) {
556                 /* Empty list, can't create a new transaction. */
557                 return NULL;
558         }
559
560         rc_input_vps_t *vps_entry = rc_vps_list_in.head;
561
562         rc_yank_vps_entry(vps_entry); /* This cannot fail (we checked the list beforehand.) */
563
564         /* We grabbed an vps entry, now we can initialize a new transaction. */
565         rc_transaction_t *trans;
566         MEM(trans = talloc_zero(ctx, rc_transaction_t));
567
568         trans->input_vps = vps_entry;
569         trans->id = num_trans ++;
570
571         talloc_steal(trans, vps_entry); /* It's ours now. */
572
573         RADIUS_PACKET *packet;
574         MEM(packet = rad_alloc(trans, 1));
575         trans->packet = packet;
576
577         /* Fill in the packet value pairs. */
578         packet->vps = fr_pair_list_copy(packet, vps_entry->vps_in);
579
580         /* Initialize the transaction packet. */
581         if (!rc_init_packet(trans)) {
582                 /* Failed... */
583                 talloc_free(trans);
584                 return NULL;
585         }
586
587         /* Update transactions counters. */
588         num_started ++;
589         num_ongoing ++;
590
591         return trans;
592 }
593
594 /** Terminate a transaction.
595  */
596 static void rc_finish_transaction(rc_transaction_t *trans)
597 {
598         if (!trans) return;
599
600         if (trans->event) fr_event_delete(ev_list, &trans->event);
601         rc_deallocate_id(trans);
602         talloc_free(trans);
603
604         /* Update transactions counters. */
605         num_ongoing --;
606         num_finished ++;
607
608         DEBUG4("pl: %d, ev: %d, in: %d", fr_packet_list_num_outgoing(pl), fr_event_list_num_elements(ev_list), rc_vps_list_in.size);
609 }
610
611
612 static uint16_t getport(char const *name)
613 {
614         struct  servent         *svp;
615
616         svp = getservbyname(name, "udp");
617         if (!svp) return 0;
618
619         return ntohs(svp->s_port);
620 }
621
622
623 static void rc_cleanresp(RADIUS_PACKET *resp)
624 {
625         VALUE_PAIR *vpnext, *vp, **last;
626
627         /*
628          * maybe should just copy things we care about, or keep
629          * a copy of the original input and start from there again?
630          */
631         fr_pair_delete_by_num(&resp->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
632         fr_pair_delete_by_num(&resp->vps, PW_EAP_TYPE_BASE+PW_EAP_IDENTITY, 0, TAG_ANY);
633
634         last = &resp->vps;
635         for (vp = *last; vp != NULL; vp = vpnext)
636         {
637                 vpnext = vp->next;
638
639                 if ((vp->da->attr > PW_EAP_TYPE_BASE &&
640                     vp->da->attr <= PW_EAP_TYPE_BASE+256) ||
641                    (vp->da->attr > PW_EAP_SIM_BASE &&
642                     vp->da->attr <= PW_EAP_SIM_BASE+256))
643                 {
644                         *last = vpnext;
645                         talloc_free(vp);
646                 } else {
647                         last = &vp->next;
648                 }
649         }
650 }
651
652 /*
653  * we got an EAP-Request/Sim/Start message in a legal state.
654  *
655  * pick a supported version, put it into the reply, and insert a nonce.
656  */
657 static int rc_process_eap_start(rc_eap_context_t *eap_context,
658                                 RADIUS_PACKET *req, RADIUS_PACKET *rep)
659 {
660         VALUE_PAIR *vp, *newvp;
661         VALUE_PAIR *anyidreq_vp, *fullauthidreq_vp, *permanentidreq_vp;
662         uint16_t const *versions;
663         uint16_t selectedversion;
664         unsigned int i,versioncount;
665
666         /* form new response clear of any EAP stuff */
667         rc_cleanresp(rep);
668
669         if ((vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_VERSION_LIST, 0, TAG_ANY)) == NULL) {
670                 ERROR("illegal start message has no VERSION_LIST");
671                 return 0;
672         }
673
674         versions = (uint16_t const *) vp->vp_strvalue;
675
676         /* verify that the attribute length is big enough for a length field */
677         if (vp->vp_length < 4)
678         {
679                 ERROR("start message has illegal VERSION_LIST. Too short: %u", (unsigned int) vp->vp_length);
680                 return 0;
681         }
682
683         versioncount = ntohs(versions[0])/2;
684         /* verify that the attribute length is big enough for the given number
685          * of versions present.
686          */
687         if ((unsigned)vp->vp_length <= (versioncount*2 + 2))
688         {
689                 ERROR("start message is too short. Claimed %d versions does not fit in %u bytes", versioncount, (unsigned int) vp->vp_length);
690                 return 0;
691         }
692
693         /*
694          * record the versionlist for the MK calculation.
695          */
696         eap_context->eap.sim.keys.versionlistlen = versioncount*2;
697         memcpy(eap_context->eap.sim.keys.versionlist, (unsigned char const *)(versions+1),
698                eap_context->eap.sim.keys.versionlistlen);
699
700         /* walk the version list, and pick the one we support, which
701          * at present, is 1, EAP_SIM_VERSION.
702          */
703         selectedversion=0;
704         for (i=0; i < versioncount; i++)
705         {
706                 if (ntohs(versions[i+1]) == EAP_SIM_VERSION)
707                 {
708                         selectedversion=EAP_SIM_VERSION;
709                         break;
710                 }
711         }
712         if (selectedversion == 0)
713         {
714                 ERROR("eap-sim start message. No compatible version found. We need %d", EAP_SIM_VERSION);
715                 for (i=0; i < versioncount; i++)
716                 {
717                         ERROR("\tfound version %d",
718                                 ntohs(versions[i+1]));
719                 }
720         }
721
722         /*
723          * now make sure that we have only FULLAUTH_ID_REQ.
724          * I think that it actually might not matter - we can answer in
725          * anyway we like, but it is illegal to have more than one
726          * present.
727          */
728         anyidreq_vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_ANY_ID_REQ, 0, TAG_ANY);
729         fullauthidreq_vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_FULLAUTH_ID_REQ, 0, TAG_ANY);
730         permanentidreq_vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_PERMANENT_ID_REQ, 0, TAG_ANY);
731
732         if (!fullauthidreq_vp ||
733            anyidreq_vp != NULL ||
734            permanentidreq_vp != NULL) {
735                 ERROR("start message has %sanyidreq, %sfullauthid and %spermanentid. Illegal combination.",
736                         (anyidreq_vp != NULL ? "a ": "no "),
737                         (fullauthidreq_vp != NULL ? "a ": "no "),
738                         (permanentidreq_vp != NULL ? "a ": "no "));
739                 return 0;
740         }
741
742         /* okay, we have just any_id_req there, so fill in response */
743
744         /* mark the subtype as being EAP-SIM/Response/Start */
745         newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_SUBTYPE, 0);
746         newvp->vp_integer = EAPSIM_START;
747         fr_pair_replace(&(rep->vps), newvp);
748
749         /* insert selected version into response. */
750         {
751                 uint16_t no_versions;
752
753                 no_versions = htons(selectedversion);
754
755                 newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_SELECTED_VERSION, 0);
756                 fr_pair_value_memcpy(newvp, (uint8_t *) &no_versions, 2);
757                 fr_pair_replace(&(rep->vps), newvp);
758
759                 /* record the selected version */
760                 memcpy(eap_context->eap.sim.keys.versionselect, &no_versions, 2);
761         }
762
763         vp = newvp = NULL;
764
765         {
766                 uint32_t nonce[4];
767                 uint8_t *p;
768                 /*
769                  * insert a nonce_mt that we make up.
770                  */
771                 nonce[0]=fr_rand();
772                 nonce[1]=fr_rand();
773                 nonce[2]=fr_rand();
774                 nonce[3]=fr_rand();
775
776                 newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_NONCE_MT, 0);
777
778                 p = talloc_zero_array(newvp, uint8_t, 18); /* 18 = 16 bytes of nonce + padding */
779                 memcpy(&p[2], nonce, 16);
780                 fr_pair_value_memsteal(newvp, p);
781
782                 fr_pair_replace(&(rep->vps), newvp);
783
784                 /* also keep a copy of the nonce! */
785                 memcpy(eap_context->eap.sim.keys.nonce_mt, nonce, 16);
786         }
787
788         {
789                 uint16_t idlen;
790                 uint8_t *p;
791                 uint16_t no_idlen;
792
793                 /*
794                  * insert the identity here.
795                  */
796                 vp = fr_pair_find_by_num(rep->vps, PW_USER_NAME, 0, TAG_ANY);
797                 if (!vp)
798                 {
799                         ERROR("eap-sim: We need to have a User-Name attribute!");
800                         return 0;
801                 }
802                 newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_IDENTITY, 0);
803
804                 idlen = strlen(vp->vp_strvalue);
805                 p = talloc_zero_array(newvp, uint8_t, idlen + 2);
806                 no_idlen = htons(idlen);
807                 memcpy(p, &no_idlen, 2);
808                 memcpy(p + 2, vp->vp_strvalue, idlen);
809                 fr_pair_value_memsteal(newvp, p);
810
811                 fr_pair_replace(&(rep->vps), newvp);
812
813                 /* record it */
814                 memcpy(eap_context->eap.sim.keys.identity, vp->vp_strvalue, idlen);
815                 eap_context->eap.sim.keys.identitylen = idlen;
816         }
817
818         return 1;
819 }
820
821 /*
822  * we got an EAP-Request/Sim/Challenge message in a legal state.
823  *
824  * use the RAND challenge to produce the SRES result, and then
825  * use that to generate a new MAC.
826  *
827  * for the moment, we ignore the RANDs, then just plug in the SRES
828  * values.
829  *
830  */
831 static int rc_process_eap_challenge(rc_eap_context_t *eap_context,
832                                     RADIUS_PACKET *req, RADIUS_PACKET *rep)
833 {
834         VALUE_PAIR *newvp;
835         VALUE_PAIR *mac, *randvp;
836         VALUE_PAIR *sres1,*sres2,*sres3;
837         VALUE_PAIR *Kc1, *Kc2, *Kc3;
838         uint8_t calcmac[20];
839
840         /* look for the AT_MAC and the challenge data */
841         mac   = fr_pair_find_by_num(req->vps, PW_EAP_SIM_MAC, 0, TAG_ANY);
842         randvp= fr_pair_find_by_num(req->vps, PW_EAP_SIM_RAND, 0, TAG_ANY);
843         if (!mac || !randvp) {
844                 ERROR("challenge message needs to contain RAND and MAC");
845                 return 0;
846         }
847
848         /*
849          * compare RAND with randX, to verify this is the right response
850          * to this challenge.
851          */
852         {
853           VALUE_PAIR *randcfgvp[3];
854           uint8_t const *randcfg[3];
855
856           randcfg[0] = &randvp->vp_octets[2];
857           randcfg[1] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE];
858           randcfg[2] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE*2];
859
860           randcfgvp[0] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND1, 0, TAG_ANY);
861           randcfgvp[1] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND2, 0, TAG_ANY);
862           randcfgvp[2] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND3, 0, TAG_ANY);
863
864           if (!randcfgvp[0] ||
865              !randcfgvp[1] ||
866              !randcfgvp[2]) {
867             ERROR("needs to have rand1, 2 and 3 set.");
868             return 0;
869           }
870
871           if (memcmp(randcfg[0], randcfgvp[0]->vp_octets, EAPSIM_RAND_SIZE)!=0 ||
872              memcmp(randcfg[1], randcfgvp[1]->vp_octets, EAPSIM_RAND_SIZE)!=0 ||
873              memcmp(randcfg[2], randcfgvp[2]->vp_octets, EAPSIM_RAND_SIZE)!=0) {
874             int rnum,i,j;
875
876             ERROR("one of rand 1,2,3 didn't match");
877             for (rnum = 0; rnum < 3; rnum++) {
878               ERROR("received   rand %d: ", rnum);
879               j=0;
880               for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
881                 if (j==4) {
882                   DEBUG("_");
883                   j=0;
884                 }
885                 j++;
886
887                 ERROR("%02x", randcfg[rnum][i]);
888               }
889               ERROR("configured rand %d: ", rnum);
890               j=0;
891               for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
892                 if (j==4) {
893                   DEBUG("_");
894                   j=0;
895                 }
896                 j++;
897
898                 ERROR("%02x", randcfgvp[rnum]->vp_octets[i]);
899               }
900             }
901             return 0;
902           }
903         }
904
905         /*
906          * now dig up the sres values from the response packet,
907          * which were put there when we read things in.
908          *
909          * Really, they should be calculated from the RAND!
910          *
911          */
912         sres1 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_SRES1, 0, TAG_ANY);
913         sres2 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_SRES2, 0, TAG_ANY);
914         sres3 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_SRES3, 0, TAG_ANY);
915
916         if (!sres1 ||
917            !sres2 ||
918            !sres3) {
919                 ERROR("needs to have sres1, 2 and 3 set.");
920                 return 0;
921         }
922         memcpy(eap_context->eap.sim.keys.sres[0], sres1->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[0]));
923         memcpy(eap_context->eap.sim.keys.sres[1], sres2->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[1]));
924         memcpy(eap_context->eap.sim.keys.sres[2], sres3->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[2]));
925
926         Kc1 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_KC1, 0, TAG_ANY);
927         Kc2 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_KC2, 0, TAG_ANY);
928         Kc3 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_KC3, 0, TAG_ANY);
929
930         if (!Kc1 ||
931            !Kc2 ||
932            !Kc3) {
933                 ERROR("needs to have Kc1, 2 and 3 set.");
934                 return 0;
935         }
936         memcpy(eap_context->eap.sim.keys.Kc[0], Kc1->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[0]));
937         memcpy(eap_context->eap.sim.keys.Kc[1], Kc2->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[1]));
938         memcpy(eap_context->eap.sim.keys.Kc[2], Kc3->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[2]));
939
940         /* all set, calculate keys */
941         eapsim_calculate_keys(&eap_context->eap.sim.keys);
942
943         if (rad_debug_lvl) {
944           eapsim_dump_mk(&eap_context->eap.sim.keys);
945         }
946
947         /* verify the MAC, now that we have all the keys. */
948         if (eapsim_checkmac(NULL, req->vps, eap_context->eap.sim.keys.K_aut,
949                            eap_context->eap.sim.keys.nonce_mt, sizeof(eap_context->eap.sim.keys.nonce_mt),
950                            calcmac)) {
951                 DEBUG("MAC check succeed");
952         } else {
953                 int i, j;
954                 j=0;
955                 DEBUG("calculated MAC (");
956                 for (i = 0; i < 20; i++) {
957                         if (j==4) {
958                                 printf("_");
959                                 j=0;
960                         }
961                         j++;
962
963                         DEBUG("%02x", calcmac[i]);
964                 }
965                 DEBUG("did not match");
966                 return 0;
967         }
968
969         /* form new response clear of any EAP stuff */
970         rc_cleanresp(rep);
971
972         /* mark the subtype as being EAP-SIM/Response/Start */
973         newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_SUBTYPE, 0);
974         newvp->vp_integer = EAPSIM_CHALLENGE;
975         fr_pair_replace(&(rep->vps), newvp);
976
977         {
978                 uint8_t *p;
979                 /*
980                  * fill the SIM_MAC with a field that will in fact get appended
981                  * to the packet before the MAC is calculated
982                  */
983                 newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_MAC, 0);
984
985                 p = talloc_zero_array(newvp, uint8_t, EAPSIM_SRES_SIZE*3);
986                 memcpy(p+EAPSIM_SRES_SIZE * 0, sres1->vp_strvalue, EAPSIM_SRES_SIZE);
987                 memcpy(p+EAPSIM_SRES_SIZE * 1, sres2->vp_strvalue, EAPSIM_SRES_SIZE);
988                 memcpy(p+EAPSIM_SRES_SIZE * 2, sres3->vp_strvalue, EAPSIM_SRES_SIZE);
989                 fr_pair_value_memsteal(newvp, p);
990
991                 fr_pair_replace(&(rep->vps), newvp);
992         }
993
994         newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_KEY, 0);
995         fr_pair_value_memcpy(newvp, eap_context->eap.sim.keys.K_aut, EAPSIM_AUTH_SIZE);
996
997         fr_pair_replace(&(rep->vps), newvp);
998
999         return 1;
1000 }
1001
1002 /*
1003  * this code runs the EAP-SIM client state machine.
1004  * the *request* is from the server.
1005  * the *reponse* is to the server.
1006  *
1007  */
1008 static int rc_respond_eap_sim(rc_eap_context_t *eap_context,
1009                            RADIUS_PACKET *req, RADIUS_PACKET *resp)
1010 {
1011         enum eapsim_clientstates state, newstate;
1012         enum eapsim_subtype subtype;
1013         VALUE_PAIR *vp, *statevp, *radstate, *eapid;
1014         char statenamebuf[32], subtypenamebuf[32];
1015
1016         if ((radstate = fr_pair_list_copy_by_num(NULL, req->vps, PW_STATE, 0, TAG_ANY)) == NULL)
1017         {
1018                 return 0;
1019         }
1020
1021         if ((eapid = fr_pair_list_copy_by_num(NULL, req->vps, PW_EAP_ID, 0, TAG_ANY)) == NULL)
1022         {
1023                 return 0;
1024         }
1025
1026         /* first, dig up the state from the request packet, setting
1027          * ourselves to be in EAP-SIM-Start state if there is none.
1028          */
1029
1030         if ((statevp = fr_pair_find_by_num(resp->vps, PW_EAP_SIM_STATE, 0, TAG_ANY)) == NULL)
1031         {
1032                 /* must be initial request */
1033                 statevp = fr_pair_afrom_num(resp, PW_EAP_SIM_STATE, 0);
1034                 statevp->vp_integer = EAPSIM_CLIENT_INIT;
1035                 fr_pair_replace(&(resp->vps), statevp);
1036         }
1037         state = statevp->vp_integer;
1038
1039         /*
1040          * map the attributes, and authenticate them.
1041          */
1042         rc_unmap_eapsim_types(req);
1043
1044         if ((vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_SUBTYPE, 0, TAG_ANY)) == NULL)
1045         {
1046                 return 0;
1047         }
1048         subtype = vp->vp_integer;
1049
1050         /*
1051          * look for the appropriate state, and process incoming message
1052          */
1053         switch (state) {
1054         case EAPSIM_CLIENT_INIT:
1055                 switch (subtype) {
1056                 case EAPSIM_START:
1057                         newstate = rc_process_eap_start(eap_context, req, resp);
1058                         break;
1059
1060                 case EAPSIM_CHALLENGE:
1061                 case EAPSIM_NOTIFICATION:
1062                 case EAPSIM_REAUTH:
1063                 default:
1064                         ERROR("sim in state %s message %s is illegal. Reply dropped.",
1065                                 sim_state2name(state, statenamebuf, sizeof(statenamebuf)),
1066                                 sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf)));
1067                         /* invalid state, drop message */
1068                         return 0;
1069                 }
1070                 break;
1071
1072         case EAPSIM_CLIENT_START:
1073                 switch (subtype) {
1074                 case EAPSIM_START:
1075                         /* NOT SURE ABOUT THIS ONE, retransmit, I guess */
1076                         newstate = rc_process_eap_start(eap_context, req, resp);
1077                         break;
1078
1079                 case EAPSIM_CHALLENGE:
1080                         newstate = rc_process_eap_challenge(eap_context, req, resp);
1081                         break;
1082
1083                 default:
1084                         ERROR("sim in state %s message %s is illegal. Reply dropped.",
1085                                 sim_state2name(state, statenamebuf, sizeof(statenamebuf)),
1086                                 sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf)));
1087                         /* invalid state, drop message */
1088                         return 0;
1089                 }
1090                 break;
1091
1092
1093         default:
1094                 ERROR("sim in illegal state %s",
1095                         sim_state2name(state, statenamebuf, sizeof(statenamebuf)));
1096                 return 0;
1097         }
1098
1099         /* copy the eap state object in */
1100         fr_pair_replace(&(resp->vps), eapid);
1101
1102         /* update stete info, and send new packet */
1103         rc_map_eapsim_types(resp);
1104
1105         /* copy the radius state object in */
1106         fr_pair_replace(&(resp->vps), radstate);
1107
1108         statevp->vp_integer = newstate;
1109         return 1;
1110 }
1111
1112 static int rc_respond_eap_md5(rc_eap_context_t *eap_context,
1113                               RADIUS_PACKET *req, RADIUS_PACKET *rep)
1114 {
1115         VALUE_PAIR *vp, *id, *state;
1116         size_t valuesize;
1117         uint8_t identifier;
1118         uint8_t const *value;
1119         FR_MD5_CTX      context;
1120         uint8_t    response[16];
1121
1122         rc_cleanresp(rep);
1123
1124         if ((state = fr_pair_list_copy_by_num(NULL, req->vps, PW_STATE, 0, TAG_ANY)) == NULL)
1125         {
1126                 ERROR("no state attribute found");
1127                 return 0;
1128         }
1129
1130         if ((id = fr_pair_list_copy_by_num(NULL, req->vps, PW_EAP_ID, 0, TAG_ANY)) == NULL)
1131         {
1132                 ERROR("no EAP-ID attribute found");
1133                 return 0;
1134         }
1135         identifier = id->vp_integer;
1136
1137         if ((vp = fr_pair_find_by_num(req->vps, PW_EAP_TYPE_BASE+PW_EAP_MD5, 0, TAG_ANY)) == NULL)
1138         {
1139                 ERROR("no EAP-MD5 attribute found");
1140                 return 0;
1141         }
1142
1143         /* got the details of the MD5 challenge */
1144         valuesize = vp->vp_octets[0];
1145         value = &vp->vp_octets[1];
1146
1147         /* sanitize items */
1148         if (valuesize > vp->vp_length)
1149         {
1150                 ERROR("md5 valuesize if too big (%u > %u)",
1151                         (unsigned int) valuesize, (unsigned int) vp->vp_length);
1152                 return 0;
1153         }
1154
1155         /* now do the CHAP operation ourself, rather than build the
1156          * buffer. We could also call rad_chap_encode, but it wants
1157          * a CHAP-Challenge, which we don't want to bother with.
1158          */
1159         fr_md5_init(&context);
1160         fr_md5_update(&context, &identifier, 1);
1161         fr_md5_update(&context, (uint8_t *) eap_context->password, strlen(eap_context->password));
1162         fr_md5_update(&context, value, valuesize);
1163         fr_md5_final(response, &context);
1164
1165         {
1166                 uint8_t *p;
1167                 uint8_t lg_response;
1168
1169                 vp = fr_pair_afrom_num(rep, PW_EAP_TYPE_BASE+PW_EAP_MD5, 0);
1170                 vp->vp_length = 17;
1171
1172                 p = talloc_zero_array(vp, uint8_t, 17);
1173                 lg_response = 16;
1174                 memcpy(p, &lg_response, 1);
1175                 memcpy(p + 1, response, 16);
1176                 fr_pair_value_memsteal(vp, p);
1177         }
1178         fr_pair_replace(&(rep->vps), vp);
1179
1180         fr_pair_replace(&(rep->vps), id);
1181
1182         /* copy the state object in */
1183         fr_pair_replace(&(rep->vps), state);
1184
1185         return 1;
1186 }
1187
1188
1189 /** Allocate a new socket, and add it to the packet list.
1190  */
1191 static void rc_add_socket(fr_ipaddr_t *src_ipaddr, uint16_t src_port, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port)
1192 {
1193         int mysockfd;
1194
1195         /* Trace what we're doing. */
1196         char src_addr[15+1] = "";
1197         char dst_addr[15+1] = "";
1198         inet_ntop(AF_INET, &(src_ipaddr->ipaddr.ip4addr.s_addr), src_addr, sizeof(src_addr));
1199         inet_ntop(AF_INET, &(dst_ipaddr->ipaddr.ip4addr.s_addr), dst_addr, sizeof(dst_addr));
1200
1201         INFO("Adding new socket: src: %s:%d, dst: %s:%d", src_addr, src_port, dst_addr, dst_port);
1202
1203         mysockfd = fr_socket(src_ipaddr, src_port);
1204         if (mysockfd < 0) {
1205                 ERROR("Failed to create new socket: %s", fr_strerror());
1206                 exit(1);
1207         }
1208
1209         if (!fr_packet_list_socket_add(pl, mysockfd, ipproto, dst_ipaddr, dst_port, NULL)) {
1210                 ERROR("Failed to add new socket: %s", fr_strerror());
1211                 exit(1);
1212         }
1213
1214         num_sockets ++;
1215         DEBUG("Added new socket: %d (num sockets: %d)", mysockfd, num_sockets);
1216 }
1217
1218 /** Send one packet for a transaction.
1219  */
1220 static int rc_send_one_packet(rc_transaction_t *trans, RADIUS_PACKET **packet_p)
1221 {
1222         if (!trans || !packet_p || !*packet_p) return -1;
1223
1224         assert(pl != NULL);
1225
1226         RADIUS_PACKET *packet = *packet_p;
1227
1228         if (packet->id == -1) {
1229                 /* Haven't sent the packet yet.  Initialize it. */
1230                 bool rcode;
1231                 int i;
1232
1233                 rc_build_eap_context(trans); /* In case of EAP, build EAP-Message and initialize EAP context. */
1234
1235                 assert(trans->reply == NULL);
1236
1237                 trans->tries = 0;
1238                 packet->src_ipaddr.af = server_ipaddr.af;
1239                 int nb_sock_add = 0;
1240                 while (1) {
1241                         /* Allocate a RADIUS packet ID from a suitable socket of the packet list. */
1242                         rcode = fr_packet_list_id_alloc(pl, ipproto, packet_p, NULL);
1243
1244                         if (rcode) { /* Got an ID. */
1245                                 break;
1246                         }
1247                         if (nb_sock_add >= 1) {
1248                                 ERROR("Added %d new socket(s), but still could not get an ID (currently: %d outgoing requests).",
1249                                         nb_sock_add, fr_packet_list_num_outgoing(pl));
1250                                 exit(1);
1251                         }
1252
1253                         /* Could not find a free packet ID. Allocate a new socket, then try again. */
1254                         rc_add_socket(&packet->src_ipaddr, packet->src_port, &packet->dst_ipaddr, packet->dst_port);
1255
1256                         nb_sock_add ++;
1257                 }
1258
1259                 assert(packet->id != -1);
1260                 assert(packet->data == NULL);
1261
1262                 for (i = 0; i < 4; i++) {
1263                         ((uint32_t *) packet->vector)[i] = fr_rand();
1264                 }
1265         }
1266
1267         /*
1268          *      Send the packet.
1269          */
1270         DEBUG("Transaction: %u, sending packet: %u (id: %u)...", trans->id, trans->num_packet, packet->id);
1271
1272         gettimeofday(&packet->timestamp, NULL); /* set outgoing packet timestamp. */
1273
1274         if (rad_send(packet, NULL, secret) < 0) {
1275                 ERROR("Failed to send packet (sockfd: %d, id: %d): %s",
1276                         packet->sockfd, packet->id, fr_strerror());
1277         }
1278
1279         trans->num_packet ++;
1280         trans->tries ++;
1281
1282         if (fr_debug_lvl > 0) fr_packet_header_print(fr_log_fp, packet, false);
1283         if (fr_debug_lvl > 0) vp_printlist(fr_log_fp, packet->vps);
1284
1285         return 1;
1286 }
1287
1288 /** Send current packet of a transaction. Arm timeout event.
1289  */
1290 static int rc_send_transaction_packet(rc_transaction_t *trans, RADIUS_PACKET **packet_p)
1291 // note: we need a 'RADIUS_PACKET **' for fr_packet_list_id_alloc.
1292 {
1293         if (!trans || !packet_p || !*packet_p) return -1;
1294
1295         int ret = rc_send_one_packet(trans, packet_p);
1296         if (ret == 1) {
1297                 /* Send successful: arm the timeout callback. */
1298                 rc_evprep_packet_timeout(trans);
1299         }
1300         return ret;
1301 }
1302
1303 /** Deallocate RADIUS packet ID.
1304  */
1305 static void rc_deallocate_id(rc_transaction_t *trans)
1306 {
1307         if (!trans || !trans->packet ||
1308             (trans->packet->id < 0)) {
1309                 return;
1310         }
1311
1312         RADIUS_PACKET *packet = trans->packet;
1313
1314         DEBUG2("Deallocating (sockfd: %d, id: %d)", packet->sockfd, packet->id);
1315
1316         /*
1317          *      One more unused RADIUS ID.
1318          */
1319         fr_packet_list_id_free(pl, packet, true);
1320         /* note: "true" means automatically yank, so we must *not* yank ourselves before calling (otherwise, it does nothing)
1321          * so, *don't*: fr_packet_list_yank(pl, request->packet); */
1322
1323         /* free more stuff to ensure next allocate won't be stuck on a "full" socket. */
1324         packet->id = -1;
1325         packet->sockfd = -1;
1326         packet->src_ipaddr.af = AF_UNSPEC;
1327         packet->src_port = 0;
1328
1329         /*
1330          *      If we've already sent a packet, free up the old one,
1331          *      and ensure that the next packet has a unique
1332          *      authentication vector.
1333          */
1334         if (packet->data) {
1335                 talloc_free(packet->data);
1336                 packet->data = NULL;
1337         }
1338
1339         if (trans->reply) rad_free(&trans->reply);
1340 }
1341
1342 /** Receive one packet, maybe.
1343  */
1344 static int rc_recv_one_packet(struct timeval *tv_wait_time)
1345 {
1346         fd_set set;
1347         struct timeval tv;
1348         rc_transaction_t *trans;
1349         RADIUS_PACKET *reply, **packet_p;
1350         volatile int max_fd;
1351         bool ongoing_trans = false;
1352         char buffer[128];
1353
1354         /* Wait for reply, timing out as necessary */
1355         FD_ZERO(&set);
1356
1357         max_fd = fr_packet_list_fd_set(pl, &set);
1358         if (max_fd < 0) {
1359                 /* no sockets to listen on! */
1360                 return 0;
1361         }
1362
1363         if (NULL == tv_wait_time) {
1364                 timerclear(&tv);
1365         } else {
1366                 tv.tv_sec = tv_wait_time->tv_sec;
1367                 tv.tv_usec = tv_wait_time->tv_usec;
1368         }
1369
1370         if (select(max_fd, &set, NULL, NULL, &tv) <= 0) {
1371                 /* No packet was received. */
1372                 return 0;
1373         }
1374
1375         /*
1376          *      Receive the reply.
1377          */
1378         reply = fr_packet_list_recv(pl, &set);
1379         if (!reply) {
1380                 ERROR("Received bad packet: %s", fr_strerror());
1381                 return -1;      /* bad packet */
1382         }
1383
1384         /*
1385          *      Look for the packet which matches the reply.
1386          */
1387         reply->src_ipaddr = server_ipaddr;
1388         reply->src_port = server_port;
1389
1390         /*
1391          * Note: this only works if all packets have the same destination (IP, port).
1392          * We should handle a list of destinations. But we don't. radclient doesn't do it either).
1393          */
1394
1395         packet_p = fr_packet_list_find_byreply(pl, reply);
1396
1397         if (!packet_p) {
1398                 /* got reply to packet we didn't send.
1399                  * (or maybe we sent it, got no response, freed the ID. Then server responds to first request.)
1400                  */
1401                 DEBUG("No outstanding request was found for reply from %s, port %d (sockfd: %d, id: %d)",
1402                         inet_ntop(reply->src_ipaddr.af, &reply->src_ipaddr.ipaddr, buffer, sizeof(buffer)),
1403                         reply->src_port, reply->sockfd, reply->id);
1404                 rad_free(&reply);
1405                 return -1;
1406         }
1407
1408         trans = fr_packet2myptr(rc_transaction_t, packet, packet_p);
1409
1410         if (trans->event) fr_event_delete(ev_list, &trans->event);
1411
1412         /*
1413          *      Fails the signature validation: not a valid reply.
1414          */
1415         if (rad_verify(reply, trans->packet, secret) < 0) {
1416                 /* shared secret is incorrect.
1417                  * (or maybe this is a response to another packet we sent, for which we got no response,
1418                  * freed the ID, then reused it. Then server responds to first packet.)
1419                  */
1420                 DEBUG("Conflicting response authenticator for reply from %s (sockfd: %d, id: %d)",
1421                         inet_ntop(reply->src_ipaddr.af, &reply->src_ipaddr.ipaddr, buffer, sizeof(buffer)),
1422                         reply->sockfd, reply->id);
1423
1424                 goto packet_done;
1425         }
1426
1427         /* Set reply destination = packet source. */
1428         reply->dst_ipaddr = trans->packet->src_ipaddr;
1429         reply->dst_port = trans->packet->src_port;
1430
1431         trans->reply = reply;
1432         reply = NULL;
1433
1434         if (rad_decode(trans->reply, trans->packet, secret) != 0) {
1435                 /* This can fail if packet contains too many attributes. */
1436                 DEBUG("Failed decoding reply");
1437                 goto packet_done;
1438         }
1439
1440         gettimeofday(&trans->reply->timestamp, NULL); /* set received packet timestamp. */
1441
1442         if (trans->eap_context) {
1443                 /* Call unmap before packet print (so we can see the decoded EAP stuff). */
1444                 rc_unmap_eap_methods(trans->reply);
1445         }
1446
1447         DEBUG("Transaction: %u, received packet (id: %u).", trans->id, trans->reply->id);
1448
1449         if (fr_debug_lvl > 0) fr_packet_header_print(fr_log_fp, trans->reply, true);
1450         if (fr_debug_lvl > 0) vp_printlist(fr_log_fp, trans->reply->vps);
1451
1452         if (!trans->eap_context) {
1453                 goto packet_done;
1454         }
1455
1456         /* now look for the code type. */
1457         VALUE_PAIR *vp, *vpnext;
1458         for (vp = trans->reply->vps; vp != NULL; vp = vpnext) {
1459                 vpnext = vp->next;
1460
1461                 switch (vp->da->attr) {
1462                 default:
1463                         break;
1464
1465                 case PW_EAP_TYPE_BASE + PW_EAP_MD5:
1466                         if (rc_respond_eap_md5(trans->eap_context, trans->reply, trans->packet) && trans->eap_context->eap.md5.tried < 3)
1467                         {
1468                                 /* answer the challenge from server. */
1469                                 trans->eap_context->eap.md5.tried ++;
1470                                 rc_deallocate_id(trans);
1471                                 rc_send_transaction_packet(trans, &trans->packet);
1472                                 ongoing_trans = true; // don't free the transaction yet.
1473                         }
1474                         goto packet_done;
1475
1476                 case PW_EAP_TYPE_BASE + PW_EAP_SIM:
1477                         if (rc_respond_eap_sim(trans->eap_context, trans->reply, trans->packet)) {
1478                                 /* answer the challenge from server. */
1479                                 rc_deallocate_id(trans);
1480                                 rc_send_transaction_packet(trans, &trans->packet);
1481                                 ongoing_trans = true; // don't free the transaction yet.
1482                         }
1483                         goto packet_done;
1484                 }
1485         }
1486
1487         goto eap_done;
1488
1489 eap_done:
1490         /* EAP transaction ends here (no more requests from EAP server). */
1491
1492         /*
1493          * success: if we have EAP-Code = Success, and reply is an Access-Accept.
1494          */
1495         if (trans->reply->code != PW_CODE_ACCESS_ACCEPT) {
1496                 DEBUG("EAP transaction finished, but reply is not an Access-Accept");
1497                 goto packet_done;
1498         }
1499         vp = fr_pair_find_by_num(trans->reply->vps, PW_EAP_CODE, 0, TAG_ANY);
1500         if ( (!vp) || (vp->vp_integer != 3) ) {
1501                 DEBUG("EAP transaction finished, but reply does not contain EAP-Code = Success");
1502                 goto packet_done;
1503         }
1504         goto packet_done;
1505
1506 packet_done:
1507
1508         /* Basic statistics (salvaged from old code). TODO: something better. */
1509         if (trans->reply) {
1510                 if (trans->reply->code == PW_CODE_ACCESS_ACCEPT) {
1511                         totalapp ++;
1512                 } else if (trans->reply->code == PW_CODE_ACCESS_REJECT) {
1513                         totaldeny ++;
1514                 }
1515         }
1516
1517         rad_free(&trans->reply);
1518         rad_free(&reply);       /* may be NULL */
1519
1520         if (!ongoing_trans) {
1521                 rc_deallocate_id(trans);
1522                 rc_finish_transaction(trans);
1523         }
1524
1525         return 1;
1526 }
1527
1528 /** Event callback: packet timeout.
1529  */
1530 static void rc_evcb_packet_timeout(void *ctx)
1531 {
1532         rc_transaction_t *trans = ctx;
1533         if (!trans || !trans->packet) return;
1534
1535         DEBUG("Timeout for transaction: %d, tries (so far): %d (max: %d)", trans->id, trans->tries, retries);
1536
1537         if (trans->event) fr_event_delete(ev_list, &trans->event);
1538
1539         if (trans->tries < retries) {
1540                 /* Try again. */
1541                 rc_send_transaction_packet(trans, &trans->packet);
1542         } else {
1543                 DEBUG("No response for transaction: %d, giving up", trans->id);
1544                 rc_finish_transaction(trans);
1545         }
1546 }
1547
1548 /** Prepare event: packet timeout.
1549  */
1550 static void rc_evprep_packet_timeout(rc_transaction_t *trans)
1551 {
1552         struct timeval tv_event;
1553         gettimeofday(&tv_event, NULL);
1554         timeradd(&tv_event, &tv_timeout, &tv_event);
1555
1556         if (!fr_event_insert(ev_list, rc_evcb_packet_timeout, (void *)trans, &tv_event, &trans->event)) {
1557                 ERROR("Failed to insert event");
1558                 exit(1);
1559         }
1560 }
1561
1562 /** Trigger all armed events for which time is reached.
1563  */
1564 static int rc_loop_events(void)
1565 {
1566         struct timeval when;
1567         uint32_t nb_processed = 0;
1568
1569         if (!fr_event_list_num_elements(ev_list)) return 0;
1570
1571         while (1) {
1572                 gettimeofday(&when, NULL);
1573                 if (!fr_event_run(ev_list, &when)) {
1574                         /* no more. */
1575                         break;
1576                 }
1577                 nb_processed ++;
1578         }
1579         return nb_processed;
1580 }
1581
1582 /** Receive loop.
1583  *  Handle incoming packets, until nothing more is received.
1584  */
1585 static int dhb_loop_recv(void)
1586 {
1587         uint32_t nb_received = 0;
1588         while (rc_recv_one_packet(NULL) > 0) {
1589                 nb_received ++;
1590         }
1591         return nb_received;
1592 }
1593
1594 /** Loop starting new transactions, until a limit is reached
1595  *  (max parallelism, or no more input available.)
1596  */
1597 static int rc_loop_start_transactions(void)
1598 {
1599         int nb_started = 0;
1600
1601         while (1) {
1602                 if (num_ongoing >= parallel) break;
1603
1604                 /* Try to initialize a new transaction. */
1605                 rc_transaction_t *trans = rc_init_transaction(autofree);
1606                 if (!trans) break;
1607
1608                 nb_started ++;
1609                 rc_send_transaction_packet(trans, &trans->packet);
1610         }
1611         return nb_started;
1612 }
1613
1614 /** Main loop: Handle events. Receive and process responses. Start new transactions.
1615  *  Until we're done.
1616  */
1617 static void rc_main_loop(void)
1618 {
1619         while (1) {
1620                 /* Handle events. */
1621                 rc_loop_events();
1622
1623                 /* Receive and process response until no more are received (don't wait). */
1624                 dhb_loop_recv();
1625
1626                 /* Start new transactions and send the associated packet. */
1627                 rc_loop_start_transactions();
1628
1629                 /* Check if we're done. */
1630                 if ( (rc_vps_list_in.size == 0)
1631                         && (fr_packet_list_num_outgoing(pl) == 0) ) {
1632                         break;
1633                 }
1634         }
1635         INFO("Main loop: done.");
1636 }
1637
1638
1639 void set_radius_dir(TALLOC_CTX *ctx, char const *path)
1640 {
1641         if (radius_dir) {
1642                 char *p;
1643
1644                 memcpy(&p, &radius_dir, sizeof(p));
1645                 talloc_free(p);
1646                 radius_dir = NULL;
1647         }
1648         if (path) radius_dir = talloc_strdup(ctx, path);
1649 }
1650
1651
1652 /** Set a port from the request type if we don't already have one.
1653  */
1654 static void rc_get_port(PW_CODE type, uint16_t *port)
1655 {
1656         switch (type) {
1657         default:
1658         case PW_CODE_ACCESS_REQUEST:
1659         case PW_CODE_ACCESS_CHALLENGE:
1660         case PW_CODE_STATUS_SERVER:
1661                 if (*port == 0) *port = getport("radius");
1662                 if (*port == 0) *port = PW_AUTH_UDP_PORT;
1663                 return;
1664
1665         case PW_CODE_ACCOUNTING_REQUEST:
1666                 if (*port == 0) *port = getport("radacct");
1667                 if (*port == 0) *port = PW_ACCT_UDP_PORT;
1668                 return;
1669
1670         case PW_CODE_DISCONNECT_REQUEST:
1671                 if (*port == 0) *port = PW_POD_UDP_PORT;
1672                 return;
1673
1674         case PW_CODE_COA_REQUEST:
1675                 if (*port == 0) *port = PW_COA_UDP_PORT;
1676                 return;
1677
1678         case PW_CODE_UNDEFINED:
1679                 if (*port == 0) *port = 0;
1680                 return;
1681         }
1682 }
1683
1684 /** Resolve a port to a request type.
1685  */
1686 static PW_CODE rc_get_code(uint16_t port)
1687 {
1688         /*
1689          *      getport returns 0 if the service doesn't exist
1690          *      so we need to return early, to avoid incorrect
1691          *      codes.
1692          */
1693         if (port == 0) return PW_CODE_UNDEFINED;
1694
1695         if ((port == getport("radius")) || (port == PW_AUTH_UDP_PORT) || (port == PW_AUTH_UDP_PORT_ALT)) {
1696                 return PW_CODE_ACCESS_REQUEST;
1697         }
1698         if ((port == getport("radacct")) || (port == PW_ACCT_UDP_PORT) || (port == PW_ACCT_UDP_PORT_ALT)) {
1699                 return PW_CODE_ACCOUNTING_REQUEST;
1700         }
1701         if (port == PW_COA_UDP_PORT) return PW_CODE_COA_REQUEST;
1702         if (port == PW_POD_UDP_PORT) return PW_CODE_DISCONNECT_REQUEST;
1703
1704         return PW_CODE_UNDEFINED;
1705 }
1706
1707 /** Resolve server hostname.
1708  */
1709 static void rc_resolve_hostname(char *server_arg)
1710 {
1711         if (force_af == AF_UNSPEC) force_af = AF_INET;
1712         server_ipaddr.af = force_af;
1713         if (strcmp(server_arg, "-") != 0) {
1714                 char *p;
1715                 char const *hostname = server_arg;
1716                 char const *portname = server_arg;
1717                 char buffer[256];
1718
1719                 if (*server_arg == '[') { /* IPv6 URL encoded */
1720                         p = strchr(server_arg, ']');
1721                         if ((size_t) (p - server_arg) >= sizeof(buffer)) {
1722                                 usage();
1723                         }
1724
1725                         memcpy(buffer, server_arg + 1, p - server_arg - 1);
1726                         buffer[p - server_arg - 1] = '\0';
1727
1728                         hostname = buffer;
1729                         portname = p + 1;
1730
1731                 }
1732                 p = strchr(portname, ':');
1733                 if (p && (strchr(p + 1, ':') == NULL)) {
1734                         *p = '\0';
1735                         portname = p + 1;
1736                 } else {
1737                         portname = NULL;
1738                 }
1739
1740                 if (ip_hton(&server_ipaddr, force_af, hostname, false) < 0) {
1741                         ERROR("%s: Failed to find IP address for host %s: %s", progname, hostname, strerror(errno));
1742                         exit(1);
1743                 }
1744                 server_addr_init = true;
1745
1746                 /* Strip port from hostname if needed. */
1747                 if (portname) server_port = atoi(portname);
1748
1749                 /*
1750                  *      Work backwards from the port to determine the packet type
1751                  */
1752                 if (packet_code == PW_CODE_UNDEFINED) packet_code = rc_get_code(server_port);
1753         }
1754         rc_get_port(packet_code, &server_port);
1755 }
1756
1757 int main(int argc, char **argv)
1758 {
1759         char *p;
1760         int c;
1761         char *filename = NULL;
1762         FILE *fp;
1763
1764         static fr_log_t radclient_log = {
1765                 .colourise = true,
1766                 .fd = STDOUT_FILENO,
1767                 .dst = L_DST_STDOUT,
1768                 .file = NULL,
1769                 .debug_file = NULL,
1770         };
1771
1772         radlog_init(&radclient_log, false);
1773
1774         /*
1775          *      We probably don't want to free the talloc autofree context
1776          *      directly, so we'll allocate a new context beneath it, and
1777          *      free that before any leak reports.
1778          */
1779         autofree = talloc_init("main");
1780
1781         fr_debug_lvl = 0;
1782         fr_log_fp = stdout;
1783
1784         set_radius_dir(autofree, RADIUS_DIR);
1785
1786         while ((c = getopt(argc, argv, "46c:d:D:f:hp:qst:r:S:xXv")) != EOF)
1787         {
1788                 switch (c) {
1789                 case '4':
1790                         force_af = AF_INET;
1791                         break;
1792                 case '6':
1793                         force_af = AF_INET6;
1794                         break;
1795                 case 'd':
1796                         set_radius_dir(autofree, optarg);
1797                         break;
1798                 case 'D':
1799                         main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg);
1800                         break;
1801                 case 'f':
1802                         filename = optarg;
1803                         break;
1804                 case 'p':
1805                         parallel = atoi(optarg);
1806                         if (parallel == 0) parallel = 1;
1807                         if (parallel > 65536) parallel = 65536;
1808                         break;
1809                 case 'q':
1810                         do_output = 0;
1811                         break;
1812                 case 'x':
1813                         rad_debug_lvl++;
1814                         fr_debug_lvl++;
1815                         break;
1816
1817                 case 'X':
1818 #if 0
1819                   sha1_data_problems = 1; /* for debugging only */
1820 #endif
1821                   break;
1822
1823                 case 'r':
1824                         if (!isdigit((int) *optarg))
1825                                 usage();
1826                         retries = atoi(optarg);
1827                         break;
1828                 case 's':
1829                         do_summary = 1;
1830                         break;
1831                 case 't':
1832                         if (!isdigit((int) *optarg))
1833                                 usage();
1834                         timeout = atof(optarg);
1835                         break;
1836                 case 'v':
1837                         printf("$Id$ built on "__DATE__ "at "__TIME__ "");
1838                         exit(0);
1839
1840                 case 'S':
1841                        fp = fopen(optarg, "r");
1842                        if (!fp) {
1843                                ERROR("Error opening %s: %s",
1844                                        optarg, fr_syserror(errno));
1845                                exit(1);
1846                        }
1847                        if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
1848                                ERROR("Error reading %s: %s",
1849                                        optarg, fr_syserror(errno));
1850                                exit(1);
1851                        }
1852                        fclose(fp);
1853
1854                        /* truncate newline */
1855                        p = filesecret + strlen(filesecret) - 1;
1856                        while ((p >= filesecret) &&
1857                               (*p < ' ')) {
1858                                *p = '\0';
1859                                --p;
1860                        }
1861
1862                        if (strlen(filesecret) < 2) {
1863                                ERROR("Secret in %s is too short", optarg);
1864                                exit(1);
1865                        }
1866                        secret = filesecret;
1867                        break;
1868                 case 'h':
1869                 default:
1870                         usage();
1871                 }
1872         }
1873         argc -= (optind - 1);
1874         argv += (optind - 1);
1875
1876         if ((argc < 3)  ||
1877             ((!secret) && (argc < 4))) {
1878                 usage();
1879         }
1880
1881         /* Prepare the timeout. */
1882         rc_float_to_timeval(&tv_timeout, timeout);
1883
1884         if (!main_config.dictionary_dir) {
1885                 main_config.dictionary_dir = DICTDIR;
1886         }
1887
1888         /*
1889          *      Read the distribution dictionaries first, then
1890          *      the ones in raddb.
1891          */
1892         DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, RADIUS_DICTIONARY);
1893         if (dict_init(main_config.dictionary_dir, RADIUS_DICTIONARY) != 0) {
1894                 ERROR("Errors reading dictionary: %s", fr_strerror());
1895                 exit(1);
1896         }
1897
1898         /*
1899          *      It's OK if this one doesn't exist.
1900          */
1901         int rcode = dict_read(radius_dir, RADIUS_DICTIONARY);
1902         if (rcode == -1) {
1903                 ERROR("Errors reading %s/%s: %s", radius_dir, RADIUS_DICTIONARY, fr_strerror());
1904                 exit(1);
1905         }
1906
1907         /*
1908          *      We print this after reading it.  That way if
1909          *      it doesn't exist, it's OK, and we don't print
1910          *      anything.
1911          */
1912         if (rcode == 0) {
1913                 DEBUG2("Including dictionary file %s/%s", radius_dir, RADIUS_DICTIONARY);
1914         }
1915
1916         /*
1917          *      Get the request type
1918          */
1919         if (!isdigit((int) argv[2][0])) {
1920                 packet_code = fr_str2int(rc_request_types, argv[2], -2);
1921                 if (packet_code == -2) {
1922                         ERROR("Unrecognised request type \"%s\"", argv[2]);
1923                         usage();
1924                 }
1925         } else {
1926                 packet_code = atoi(argv[2]);
1927         }
1928
1929         /*
1930          *      Resolve hostname.
1931          */
1932         rc_resolve_hostname(argv[1]);
1933
1934         /*
1935          *      Add the secret.
1936          */
1937         if (argv[3]) secret = argv[3];
1938
1939         /*
1940          *      Read input data vp(s) from the file (or stdin).
1941          */
1942         INFO("Loading input data...");
1943         if (!rc_load_input(autofree, filename, &rc_vps_list_in, 0)
1944             || rc_vps_list_in.size == 0) {
1945                 ERROR("No valid input. Nothing to send.");
1946                 exit(EXIT_FAILURE);
1947         }
1948         INFO("Loaded: %d input element(s).", rc_vps_list_in.size);
1949
1950         /* Initialize the packets list. */
1951         MEM(pl = fr_packet_list_create(1));
1952
1953         /* Initialize the events list. */
1954         ev_list = fr_event_list_create(autofree, NULL);
1955         if (!ev_list) {
1956                 ERROR("Failed to create event list");
1957                 exit(1);
1958         }
1959
1960         /*
1961          *      Start main loop.
1962          */
1963         rc_main_loop();
1964
1965         if (do_summary) {
1966                 INFO("\n\t   Total approved auths:  %d", totalapp);
1967                 INFO("\t     Total denied auths:  %d", totaldeny);
1968         }
1969
1970         talloc_free(autofree);
1971
1972         return 0;
1973 }
1974
1975 /** Given a radius request with some attributes in the EAP range, build
1976  *  them all into a single EAP-Message body.
1977  *
1978  *  If there are multiple eligibles EAP-Type, the first one is picked.
1979  *  Function returns 0 if no EAP is involved, or the EAP-Type otherwise.
1980  */
1981 static int rc_map_eap_methods(RADIUS_PACKET *req)
1982 {
1983         VALUE_PAIR *vp, *vpnext;
1984         int id, eapcode;
1985         int eap_method = 0;
1986
1987         eap_packet_t *pt_ep = talloc_zero(req, eap_packet_t);
1988
1989         vp = fr_pair_find_by_num(req->vps, PW_EAP_ID, 0, TAG_ANY);
1990         if (!vp) {
1991                 id = ((int)getpid() & 0xff);
1992         } else {
1993                 id = vp->vp_integer;
1994         }
1995
1996         vp = fr_pair_find_by_num(req->vps, PW_EAP_CODE, 0, TAG_ANY);
1997         if (!vp) {
1998                 eapcode = PW_EAP_REQUEST;
1999         } else {
2000                 eapcode = vp->vp_integer;
2001         }
2002
2003         for (vp = req->vps; vp != NULL; vp = vpnext) {
2004                 /* save it in case it changes! */
2005                 vpnext = vp->next;
2006
2007                 if (vp->da->attr >= PW_EAP_TYPE_BASE &&
2008                    vp->da->attr < PW_EAP_TYPE_BASE+256) {
2009                         break;
2010                 }
2011         }
2012
2013         if (!vp) {
2014                 return 0;
2015         }
2016
2017         eap_method = vp->da->attr - PW_EAP_TYPE_BASE;
2018
2019         switch (eap_method) {
2020         case PW_EAP_IDENTITY:
2021         case PW_EAP_NOTIFICATION:
2022         case PW_EAP_NAK:
2023         case PW_EAP_MD5:
2024         case PW_EAP_OTP:
2025         case PW_EAP_GTC:
2026         case PW_EAP_TLS:
2027         case PW_EAP_LEAP:
2028         case PW_EAP_TTLS:
2029         case PW_EAP_PEAP:
2030         default:
2031                 /*
2032                  * no known special handling, it is just encoded as an
2033                  * EAP-message with the given type.
2034                  */
2035
2036                 /* nuke any existing EAP-Messages */
2037                 fr_pair_delete_by_num(&req->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
2038
2039                 pt_ep->code = eapcode;
2040                 pt_ep->id = id;
2041                 pt_ep->type.num = eap_method;
2042                 pt_ep->type.length = vp->vp_length;
2043
2044                 pt_ep->type.data = talloc_memdup(vp, vp->vp_octets, vp->vp_length);
2045                 talloc_set_type(pt_ep->type.data, uint8_t);
2046
2047                 eap_basic_compose(req, pt_ep);
2048         }
2049
2050         return eap_method;
2051 }
2052
2053 /*
2054  * given a radius request with an EAP-Message body, decode it specific
2055  * attributes.
2056  */
2057 static void rc_unmap_eap_methods(RADIUS_PACKET *rep)
2058 {
2059         VALUE_PAIR *eap1;
2060         eap_packet_raw_t *e;
2061         int len;
2062         int type;
2063
2064         if (!rep) return;
2065
2066         /* find eap message */
2067         e = eap_vp2packet(NULL, rep->vps);
2068         if (!e) {
2069                 ERROR("%s", fr_strerror());
2070                 return;
2071         }
2072         /* create EAP-ID and EAP-CODE attributes to start */
2073         eap1 = fr_pair_afrom_num(rep, PW_EAP_ID, 0);
2074         eap1->vp_integer = e->id;
2075         fr_pair_add(&(rep->vps), eap1);
2076
2077         eap1 = fr_pair_afrom_num(rep, PW_EAP_CODE, 0);
2078         eap1->vp_integer = e->code;
2079         fr_pair_add(&(rep->vps), eap1);
2080
2081         switch (e->code) {
2082         default:
2083         case PW_EAP_SUCCESS:
2084         case PW_EAP_FAILURE:
2085                 /* no data */
2086                 break;
2087
2088         case PW_EAP_REQUEST:
2089         case PW_EAP_RESPONSE:
2090                 /* there is a type field, which we use to create
2091                  * a new attribute */
2092
2093                 /* the length was decode already into the attribute
2094                  * length, and was checked already. Network byte
2095                  * order, just pull it out using math.
2096                  */
2097                 len = e->length[0]*256 + e->length[1];
2098
2099                 /* verify the length is big enough to hold type */
2100                 if (len < 5)
2101                 {
2102                         talloc_free(e);
2103                         return;
2104                 }
2105
2106                 type = e->data[0];
2107
2108                 type += PW_EAP_TYPE_BASE;
2109                 len -= 5;
2110
2111                 if (len > MAX_STRING_LEN) {
2112                         len = MAX_STRING_LEN;
2113                 }
2114
2115                 eap1 = fr_pair_afrom_num(rep, type, 0);
2116                 fr_pair_value_memcpy(eap1, e->data + 1, len);
2117
2118                 fr_pair_add(&(rep->vps), eap1);
2119                 break;
2120         }
2121
2122         talloc_free(e);
2123         return;
2124 }
2125
2126 static int rc_map_eapsim_types(RADIUS_PACKET *r)
2127 {
2128         int ret;
2129
2130         eap_packet_t *pt_ep = talloc_zero(r, eap_packet_t);
2131
2132         ret = map_eapsim_basictypes(r, pt_ep);
2133
2134         if (ret != 1) {
2135                 return ret;
2136         }
2137
2138         eap_basic_compose(r, pt_ep);
2139
2140         return 1;
2141 }
2142
2143 static int rc_unmap_eapsim_types(RADIUS_PACKET *r)
2144 {
2145         VALUE_PAIR           *esvp;
2146         uint8_t *eap_data;
2147         int rcode_unmap;
2148
2149         esvp = fr_pair_find_by_num(r->vps, PW_EAP_TYPE_BASE+PW_EAP_SIM, 0, TAG_ANY);
2150         if (!esvp) {
2151                 ERROR("eap: EAP-Sim attribute not found");
2152                 return 0;
2153         }
2154
2155         eap_data = talloc_memdup(esvp, esvp->vp_octets, esvp->vp_length);
2156         talloc_set_type(eap_data, uint8_t);
2157
2158         rcode_unmap = unmap_eapsim_basictypes(r, eap_data, esvp->vp_length);
2159
2160         talloc_free(eap_data);
2161         return rcode_unmap;
2162 }
2163