Turn session caching in EAP back on in preparation for 3.0.14 upgrade
[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_USER_PASSWORD:
472                 case PW_CHAP_PASSWORD:
473                 case PW_MS_CHAP_PASSWORD:
474                         strlcpy(trans->password, vp->vp_strvalue, sizeof(trans->password));
475                         break;
476
477                 case PW_RADCLIENT_TEST_NAME:
478                         trans->name = vp->vp_strvalue;
479                         break;
480                 }
481         } /* loop over the VP's we read in */
482
483         if (packet->dst_port == 0) packet->dst_port = server_port;
484
485         if (packet->dst_ipaddr.af == AF_UNSPEC) {
486                 if (!server_addr_init) {
487                         DEBUG("No server was given, and input entry %u did not contain Packet-Dst-IP-Address, ignored.", trans->input_vps->num);
488                         return 0;
489                 }
490                 packet->dst_ipaddr = server_ipaddr;
491         }
492
493         /* Use the default set on the command line. */
494         if (packet->code == PW_CODE_UNDEFINED) {
495                 if (packet_code == PW_CODE_UNDEFINED) {
496                         DEBUG("No packet type was given, and input entry %u did not contain Packet-Type, ignored.", trans->input_vps->num);
497                         return 0;
498                 }
499                 packet->code = packet_code;
500         }
501
502         /* Automatically set the dst port (if one wasn't already set). */
503         if (packet->dst_port == 0) {
504                 rc_get_port(packet->code, &packet->dst_port);
505                 if (packet->dst_port == 0) {
506                         DEBUG("Can't determine destination port for input entry %u, ignored.", trans->input_vps->num);
507                         return 0;
508                 }
509         }
510
511         packet->sockfd = -1;
512
513         /* Done. */
514         return 1;
515 }
516
517 /** Map EAP methods and build EAP-Message (if EAP is involved).
518  *  Also allocate the EAP context.
519  */
520 static void rc_build_eap_context(rc_transaction_t *trans)
521 {
522         if (!trans || !trans->packet) return;
523
524         RADIUS_PACKET *packet = trans->packet;
525
526         /* Build EAP-Message (if EAP is involved. Otherwise, do nothing). */
527         int eap_type = rc_map_eap_methods(packet);
528
529         if (eap_type) {
530                 if (!trans->eap_context) {
531                         MEM(trans->eap_context = talloc_zero(trans, rc_eap_context_t));
532                 }
533                 trans->eap_context->eap_type = eap_type;
534
535                 /*
536                  *      Keep a copy of the the User-Password or CHAP-Password.
537                  *      Note: this is not useful for EAP-SIM, but we cannot know what kind
538                  *      of challenge the server will issue.
539                  */
540                 VALUE_PAIR *vp;
541                 vp = fr_pair_find_by_num(packet->vps, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
542                 if (!vp) vp = fr_pair_find_by_num(packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
543                 if (!vp) vp = fr_pair_find_by_num(packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
544                 if (vp) {
545                         strlcpy(trans->eap_context->password, vp->vp_strvalue, sizeof(trans->eap_context->password));
546                 }
547         }
548 }
549
550 /** Grab an element from the input list. Initialize a new transaction context, using this element.
551  */
552 static rc_transaction_t *rc_init_transaction(TALLOC_CTX *ctx)
553 {
554         if (!rc_vps_list_in.head || rc_vps_list_in.size == 0) {
555                 /* Empty list, can't create a new transaction. */
556                 return NULL;
557         }
558
559         rc_input_vps_t *vps_entry = rc_vps_list_in.head;
560
561         rc_yank_vps_entry(vps_entry); /* This cannot fail (we checked the list beforehand.) */
562
563         /* We grabbed an vps entry, now we can initialize a new transaction. */
564         rc_transaction_t *trans;
565         MEM(trans = talloc_zero(ctx, rc_transaction_t));
566
567         trans->input_vps = vps_entry;
568         trans->id = num_trans ++;
569
570         talloc_steal(trans, vps_entry); /* It's ours now. */
571
572         RADIUS_PACKET *packet;
573         MEM(packet = rad_alloc(trans, 1));
574         trans->packet = packet;
575
576         /* Fill in the packet value pairs. */
577         packet->vps = fr_pair_list_copy(packet, vps_entry->vps_in);
578
579         /* Initialize the transaction packet. */
580         if (!rc_init_packet(trans)) {
581                 /* Failed... */
582                 talloc_free(trans);
583                 return NULL;
584         }
585
586         /* Update transactions counters. */
587         num_started ++;
588         num_ongoing ++;
589
590         return trans;
591 }
592
593 /** Terminate a transaction.
594  */
595 static void rc_finish_transaction(rc_transaction_t *trans)
596 {
597         if (!trans) return;
598
599         if (trans->event) fr_event_delete(ev_list, &trans->event);
600         rc_deallocate_id(trans);
601         talloc_free(trans);
602
603         /* Update transactions counters. */
604         num_ongoing --;
605         num_finished ++;
606
607         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);
608 }
609
610
611 static uint16_t getport(char const *name)
612 {
613         struct  servent         *svp;
614
615         svp = getservbyname(name, "udp");
616         if (!svp) return 0;
617
618         return ntohs(svp->s_port);
619 }
620
621
622 static void rc_cleanresp(RADIUS_PACKET *resp)
623 {
624         VALUE_PAIR *vpnext, *vp, **last;
625
626         /*
627          * maybe should just copy things we care about, or keep
628          * a copy of the original input and start from there again?
629          */
630         fr_pair_delete_by_num(&resp->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
631         fr_pair_delete_by_num(&resp->vps, PW_EAP_TYPE_BASE+PW_EAP_IDENTITY, 0, TAG_ANY);
632
633         last = &resp->vps;
634         for (vp = *last; vp != NULL; vp = vpnext)
635         {
636                 vpnext = vp->next;
637
638                 if ((vp->da->attr > PW_EAP_TYPE_BASE &&
639                     vp->da->attr <= PW_EAP_TYPE_BASE+256) ||
640                    (vp->da->attr > PW_EAP_SIM_BASE &&
641                     vp->da->attr <= PW_EAP_SIM_BASE+256))
642                 {
643                         *last = vpnext;
644                         talloc_free(vp);
645                 } else {
646                         last = &vp->next;
647                 }
648         }
649 }
650
651 /*
652  * we got an EAP-Request/Sim/Start message in a legal state.
653  *
654  * pick a supported version, put it into the reply, and insert a nonce.
655  */
656 static int rc_process_eap_start(rc_eap_context_t *eap_context,
657                                 RADIUS_PACKET *req, RADIUS_PACKET *rep)
658 {
659         VALUE_PAIR *vp, *newvp;
660         VALUE_PAIR *anyidreq_vp, *fullauthidreq_vp, *permanentidreq_vp;
661         uint16_t const *versions;
662         uint16_t selectedversion;
663         unsigned int i,versioncount;
664
665         /* form new response clear of any EAP stuff */
666         rc_cleanresp(rep);
667
668         if ((vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_VERSION_LIST, 0, TAG_ANY)) == NULL) {
669                 ERROR("illegal start message has no VERSION_LIST");
670                 return 0;
671         }
672
673         versions = (uint16_t const *) vp->vp_strvalue;
674
675         /* verify that the attribute length is big enough for a length field */
676         if (vp->vp_length < 4)
677         {
678                 ERROR("start message has illegal VERSION_LIST. Too short: %u", (unsigned int) vp->vp_length);
679                 return 0;
680         }
681
682         versioncount = ntohs(versions[0])/2;
683         /* verify that the attribute length is big enough for the given number
684          * of versions present.
685          */
686         if ((unsigned)vp->vp_length <= (versioncount*2 + 2))
687         {
688                 ERROR("start message is too short. Claimed %d versions does not fit in %u bytes", versioncount, (unsigned int) vp->vp_length);
689                 return 0;
690         }
691
692         /*
693          * record the versionlist for the MK calculation.
694          */
695         eap_context->eap.sim.keys.versionlistlen = versioncount*2;
696         memcpy(eap_context->eap.sim.keys.versionlist, (unsigned char const *)(versions+1),
697                eap_context->eap.sim.keys.versionlistlen);
698
699         /* walk the version list, and pick the one we support, which
700          * at present, is 1, EAP_SIM_VERSION.
701          */
702         selectedversion=0;
703         for (i=0; i < versioncount; i++)
704         {
705                 if (ntohs(versions[i+1]) == EAP_SIM_VERSION)
706                 {
707                         selectedversion=EAP_SIM_VERSION;
708                         break;
709                 }
710         }
711         if (selectedversion == 0)
712         {
713                 ERROR("eap-sim start message. No compatible version found. We need %d", EAP_SIM_VERSION);
714                 for (i=0; i < versioncount; i++)
715                 {
716                         ERROR("\tfound version %d",
717                                 ntohs(versions[i+1]));
718                 }
719         }
720
721         /*
722          * now make sure that we have only FULLAUTH_ID_REQ.
723          * I think that it actually might not matter - we can answer in
724          * anyway we like, but it is illegal to have more than one
725          * present.
726          */
727         anyidreq_vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_ANY_ID_REQ, 0, TAG_ANY);
728         fullauthidreq_vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_FULLAUTH_ID_REQ, 0, TAG_ANY);
729         permanentidreq_vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_PERMANENT_ID_REQ, 0, TAG_ANY);
730
731         if (!fullauthidreq_vp ||
732            anyidreq_vp != NULL ||
733            permanentidreq_vp != NULL) {
734                 ERROR("start message has %sanyidreq, %sfullauthid and %spermanentid. Illegal combination.",
735                         (anyidreq_vp != NULL ? "a ": "no "),
736                         (fullauthidreq_vp != NULL ? "a ": "no "),
737                         (permanentidreq_vp != NULL ? "a ": "no "));
738                 return 0;
739         }
740
741         /* okay, we have just any_id_req there, so fill in response */
742
743         /* mark the subtype as being EAP-SIM/Response/Start */
744         newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_SUBTYPE, 0);
745         newvp->vp_integer = EAPSIM_START;
746         fr_pair_replace(&(rep->vps), newvp);
747
748         /* insert selected version into response. */
749         {
750                 uint16_t no_versions;
751
752                 no_versions = htons(selectedversion);
753
754                 newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_SELECTED_VERSION, 0);
755                 fr_pair_value_memcpy(newvp, (uint8_t *) &no_versions, 2);
756                 fr_pair_replace(&(rep->vps), newvp);
757
758                 /* record the selected version */
759                 memcpy(eap_context->eap.sim.keys.versionselect, &no_versions, 2);
760         }
761
762         vp = newvp = NULL;
763
764         {
765                 uint32_t nonce[4];
766                 uint8_t *p;
767                 /*
768                  * insert a nonce_mt that we make up.
769                  */
770                 nonce[0]=fr_rand();
771                 nonce[1]=fr_rand();
772                 nonce[2]=fr_rand();
773                 nonce[3]=fr_rand();
774
775                 newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_NONCE_MT, 0);
776
777                 p = talloc_zero_array(newvp, uint8_t, 18); /* 18 = 16 bytes of nonce + padding */
778                 memcpy(&p[2], nonce, 16);
779                 fr_pair_value_memsteal(newvp, p);
780
781                 fr_pair_replace(&(rep->vps), newvp);
782
783                 /* also keep a copy of the nonce! */
784                 memcpy(eap_context->eap.sim.keys.nonce_mt, nonce, 16);
785         }
786
787         {
788                 uint16_t idlen;
789                 uint8_t *p;
790                 uint16_t no_idlen;
791
792                 /*
793                  * insert the identity here.
794                  */
795                 vp = fr_pair_find_by_num(rep->vps, PW_USER_NAME, 0, TAG_ANY);
796                 if (!vp)
797                 {
798                         ERROR("eap-sim: We need to have a User-Name attribute!");
799                         return 0;
800                 }
801                 newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_IDENTITY, 0);
802
803                 idlen = strlen(vp->vp_strvalue);
804                 p = talloc_zero_array(newvp, uint8_t, idlen + 2);
805                 no_idlen = htons(idlen);
806                 memcpy(p, &no_idlen, 2);
807                 memcpy(p + 2, vp->vp_strvalue, idlen);
808                 fr_pair_value_memsteal(newvp, p);
809
810                 fr_pair_replace(&(rep->vps), newvp);
811
812                 /* record it */
813                 memcpy(eap_context->eap.sim.keys.identity, vp->vp_strvalue, idlen);
814                 eap_context->eap.sim.keys.identitylen = idlen;
815         }
816
817         return 1;
818 }
819
820 /*
821  * we got an EAP-Request/Sim/Challenge message in a legal state.
822  *
823  * use the RAND challenge to produce the SRES result, and then
824  * use that to generate a new MAC.
825  *
826  * for the moment, we ignore the RANDs, then just plug in the SRES
827  * values.
828  *
829  */
830 static int rc_process_eap_challenge(rc_eap_context_t *eap_context,
831                                     RADIUS_PACKET *req, RADIUS_PACKET *rep)
832 {
833         VALUE_PAIR *newvp;
834         VALUE_PAIR *mac, *randvp;
835         VALUE_PAIR *sres1,*sres2,*sres3;
836         VALUE_PAIR *Kc1, *Kc2, *Kc3;
837         uint8_t calcmac[20];
838
839         /* look for the AT_MAC and the challenge data */
840         mac   = fr_pair_find_by_num(req->vps, PW_EAP_SIM_MAC, 0, TAG_ANY);
841         randvp= fr_pair_find_by_num(req->vps, PW_EAP_SIM_RAND, 0, TAG_ANY);
842         if (!mac || !randvp) {
843                 ERROR("challenge message needs to contain RAND and MAC");
844                 return 0;
845         }
846
847         /*
848          * compare RAND with randX, to verify this is the right response
849          * to this challenge.
850          */
851         {
852           VALUE_PAIR *randcfgvp[3];
853           uint8_t const *randcfg[3];
854
855           randcfg[0] = &randvp->vp_octets[2];
856           randcfg[1] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE];
857           randcfg[2] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE*2];
858
859           randcfgvp[0] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND1, 0, TAG_ANY);
860           randcfgvp[1] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND2, 0, TAG_ANY);
861           randcfgvp[2] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND3, 0, TAG_ANY);
862
863           if (!randcfgvp[0] ||
864              !randcfgvp[1] ||
865              !randcfgvp[2]) {
866             ERROR("needs to have rand1, 2 and 3 set.");
867             return 0;
868           }
869
870           if (memcmp(randcfg[0], randcfgvp[0]->vp_octets, EAPSIM_RAND_SIZE)!=0 ||
871              memcmp(randcfg[1], randcfgvp[1]->vp_octets, EAPSIM_RAND_SIZE)!=0 ||
872              memcmp(randcfg[2], randcfgvp[2]->vp_octets, EAPSIM_RAND_SIZE)!=0) {
873             int rnum,i,j;
874
875             ERROR("one of rand 1,2,3 didn't match");
876             for (rnum = 0; rnum < 3; rnum++) {
877               ERROR("received   rand %d: ", rnum);
878               j=0;
879               for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
880                 if (j==4) {
881                   DEBUG("_");
882                   j=0;
883                 }
884                 j++;
885
886                 ERROR("%02x", randcfg[rnum][i]);
887               }
888               ERROR("configured rand %d: ", rnum);
889               j=0;
890               for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
891                 if (j==4) {
892                   DEBUG("_");
893                   j=0;
894                 }
895                 j++;
896
897                 ERROR("%02x", randcfgvp[rnum]->vp_octets[i]);
898               }
899             }
900             return 0;
901           }
902         }
903
904         /*
905          * now dig up the sres values from the response packet,
906          * which were put there when we read things in.
907          *
908          * Really, they should be calculated from the RAND!
909          *
910          */
911         sres1 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_SRES1, 0, TAG_ANY);
912         sres2 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_SRES2, 0, TAG_ANY);
913         sres3 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_SRES3, 0, TAG_ANY);
914
915         if (!sres1 ||
916            !sres2 ||
917            !sres3) {
918                 ERROR("needs to have sres1, 2 and 3 set.");
919                 return 0;
920         }
921         memcpy(eap_context->eap.sim.keys.sres[0], sres1->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[0]));
922         memcpy(eap_context->eap.sim.keys.sres[1], sres2->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[1]));
923         memcpy(eap_context->eap.sim.keys.sres[2], sres3->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[2]));
924
925         Kc1 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_KC1, 0, TAG_ANY);
926         Kc2 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_KC2, 0, TAG_ANY);
927         Kc3 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_KC3, 0, TAG_ANY);
928
929         if (!Kc1 ||
930            !Kc2 ||
931            !Kc3) {
932                 ERROR("needs to have Kc1, 2 and 3 set.");
933                 return 0;
934         }
935         memcpy(eap_context->eap.sim.keys.Kc[0], Kc1->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[0]));
936         memcpy(eap_context->eap.sim.keys.Kc[1], Kc2->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[1]));
937         memcpy(eap_context->eap.sim.keys.Kc[2], Kc3->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[2]));
938
939         /* all set, calculate keys */
940         eapsim_calculate_keys(&eap_context->eap.sim.keys);
941
942         if (rad_debug_lvl) {
943           eapsim_dump_mk(&eap_context->eap.sim.keys);
944         }
945
946         /* verify the MAC, now that we have all the keys. */
947         if (eapsim_checkmac(NULL, req->vps, eap_context->eap.sim.keys.K_aut,
948                            eap_context->eap.sim.keys.nonce_mt, sizeof(eap_context->eap.sim.keys.nonce_mt),
949                            calcmac)) {
950                 DEBUG("MAC check succeed");
951         } else {
952                 int i, j;
953                 j=0;
954                 DEBUG("calculated MAC (");
955                 for (i = 0; i < 20; i++) {
956                         if (j==4) {
957                                 printf("_");
958                                 j=0;
959                         }
960                         j++;
961
962                         DEBUG("%02x", calcmac[i]);
963                 }
964                 DEBUG("did not match");
965                 return 0;
966         }
967
968         /* form new response clear of any EAP stuff */
969         rc_cleanresp(rep);
970
971         /* mark the subtype as being EAP-SIM/Response/Start */
972         newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_SUBTYPE, 0);
973         newvp->vp_integer = EAPSIM_CHALLENGE;
974         fr_pair_replace(&(rep->vps), newvp);
975
976         {
977                 uint8_t *p;
978                 /*
979                  * fill the SIM_MAC with a field that will in fact get appended
980                  * to the packet before the MAC is calculated
981                  */
982                 newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_MAC, 0);
983
984                 p = talloc_zero_array(newvp, uint8_t, EAPSIM_SRES_SIZE*3);
985                 memcpy(p+EAPSIM_SRES_SIZE * 0, sres1->vp_strvalue, EAPSIM_SRES_SIZE);
986                 memcpy(p+EAPSIM_SRES_SIZE * 1, sres2->vp_strvalue, EAPSIM_SRES_SIZE);
987                 memcpy(p+EAPSIM_SRES_SIZE * 2, sres3->vp_strvalue, EAPSIM_SRES_SIZE);
988                 fr_pair_value_memsteal(newvp, p);
989
990                 fr_pair_replace(&(rep->vps), newvp);
991         }
992
993         newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_KEY, 0);
994         fr_pair_value_memcpy(newvp, eap_context->eap.sim.keys.K_aut, EAPSIM_AUTH_SIZE);
995
996         fr_pair_replace(&(rep->vps), newvp);
997
998         return 1;
999 }
1000
1001 /*
1002  * this code runs the EAP-SIM client state machine.
1003  * the *request* is from the server.
1004  * the *reponse* is to the server.
1005  *
1006  */
1007 static int rc_respond_eap_sim(rc_eap_context_t *eap_context,
1008                            RADIUS_PACKET *req, RADIUS_PACKET *resp)
1009 {
1010         enum eapsim_clientstates state, newstate;
1011         enum eapsim_subtype subtype;
1012         VALUE_PAIR *vp, *statevp, *radstate, *eapid;
1013         char statenamebuf[32], subtypenamebuf[32];
1014
1015         if ((radstate = fr_pair_list_copy_by_num(NULL, req->vps, PW_STATE, 0, TAG_ANY)) == NULL)
1016         {
1017                 return 0;
1018         }
1019
1020         if ((eapid = fr_pair_list_copy_by_num(NULL, req->vps, PW_EAP_ID, 0, TAG_ANY)) == NULL)
1021         {
1022                 return 0;
1023         }
1024
1025         /* first, dig up the state from the request packet, setting
1026          * ourselves to be in EAP-SIM-Start state if there is none.
1027          */
1028
1029         if ((statevp = fr_pair_find_by_num(resp->vps, PW_EAP_SIM_STATE, 0, TAG_ANY)) == NULL)
1030         {
1031                 /* must be initial request */
1032                 statevp = fr_pair_afrom_num(resp, PW_EAP_SIM_STATE, 0);
1033                 statevp->vp_integer = EAPSIM_CLIENT_INIT;
1034                 fr_pair_replace(&(resp->vps), statevp);
1035         }
1036         state = statevp->vp_integer;
1037
1038         /*
1039          * map the attributes, and authenticate them.
1040          */
1041         rc_unmap_eapsim_types(req);
1042
1043         if ((vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_SUBTYPE, 0, TAG_ANY)) == NULL)
1044         {
1045                 return 0;
1046         }
1047         subtype = vp->vp_integer;
1048
1049         /*
1050          * look for the appropriate state, and process incoming message
1051          */
1052         switch (state) {
1053         case EAPSIM_CLIENT_INIT:
1054                 switch (subtype) {
1055                 case EAPSIM_START:
1056                         newstate = rc_process_eap_start(eap_context, req, resp);
1057                         break;
1058
1059                 case EAPSIM_CHALLENGE:
1060                 case EAPSIM_NOTIFICATION:
1061                 case EAPSIM_REAUTH:
1062                 default:
1063                         ERROR("sim in state %s message %s is illegal. Reply dropped.",
1064                                 sim_state2name(state, statenamebuf, sizeof(statenamebuf)),
1065                                 sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf)));
1066                         /* invalid state, drop message */
1067                         return 0;
1068                 }
1069                 break;
1070
1071         case EAPSIM_CLIENT_START:
1072                 switch (subtype) {
1073                 case EAPSIM_START:
1074                         /* NOT SURE ABOUT THIS ONE, retransmit, I guess */
1075                         newstate = rc_process_eap_start(eap_context, req, resp);
1076                         break;
1077
1078                 case EAPSIM_CHALLENGE:
1079                         newstate = rc_process_eap_challenge(eap_context, req, resp);
1080                         break;
1081
1082                 default:
1083                         ERROR("sim in state %s message %s is illegal. Reply dropped.",
1084                                 sim_state2name(state, statenamebuf, sizeof(statenamebuf)),
1085                                 sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf)));
1086                         /* invalid state, drop message */
1087                         return 0;
1088                 }
1089                 break;
1090
1091
1092         default:
1093                 ERROR("sim in illegal state %s",
1094                         sim_state2name(state, statenamebuf, sizeof(statenamebuf)));
1095                 return 0;
1096         }
1097
1098         /* copy the eap state object in */
1099         fr_pair_replace(&(resp->vps), eapid);
1100
1101         /* update stete info, and send new packet */
1102         rc_map_eapsim_types(resp);
1103
1104         /* copy the radius state object in */
1105         fr_pair_replace(&(resp->vps), radstate);
1106
1107         statevp->vp_integer = newstate;
1108         return 1;
1109 }
1110
1111 static int rc_respond_eap_md5(rc_eap_context_t *eap_context,
1112                               RADIUS_PACKET *req, RADIUS_PACKET *rep)
1113 {
1114         VALUE_PAIR *vp, *id, *state;
1115         size_t valuesize;
1116         uint8_t identifier;
1117         uint8_t const *value;
1118         FR_MD5_CTX      context;
1119         uint8_t    response[16];
1120
1121         rc_cleanresp(rep);
1122
1123         if ((state = fr_pair_list_copy_by_num(NULL, req->vps, PW_STATE, 0, TAG_ANY)) == NULL)
1124         {
1125                 ERROR("no state attribute found");
1126                 return 0;
1127         }
1128
1129         if ((id = fr_pair_list_copy_by_num(NULL, req->vps, PW_EAP_ID, 0, TAG_ANY)) == NULL)
1130         {
1131                 ERROR("no EAP-ID attribute found");
1132                 return 0;
1133         }
1134         identifier = id->vp_integer;
1135
1136         if ((vp = fr_pair_find_by_num(req->vps, PW_EAP_TYPE_BASE+PW_EAP_MD5, 0, TAG_ANY)) == NULL)
1137         {
1138                 ERROR("no EAP-MD5 attribute found");
1139                 return 0;
1140         }
1141
1142         /* got the details of the MD5 challenge */
1143         valuesize = vp->vp_octets[0];
1144         value = &vp->vp_octets[1];
1145
1146         /* sanitize items */
1147         if (valuesize > vp->vp_length)
1148         {
1149                 ERROR("md5 valuesize if too big (%u > %u)",
1150                         (unsigned int) valuesize, (unsigned int) vp->vp_length);
1151                 return 0;
1152         }
1153
1154         /* now do the CHAP operation ourself, rather than build the
1155          * buffer. We could also call rad_chap_encode, but it wants
1156          * a CHAP-Challenge, which we don't want to bother with.
1157          */
1158         fr_md5_init(&context);
1159         fr_md5_update(&context, &identifier, 1);
1160         fr_md5_update(&context, (uint8_t *) eap_context->password, strlen(eap_context->password));
1161         fr_md5_update(&context, value, valuesize);
1162         fr_md5_final(response, &context);
1163
1164         {
1165                 uint8_t *p;
1166                 uint8_t lg_response;
1167
1168                 vp = fr_pair_afrom_num(rep, PW_EAP_TYPE_BASE+PW_EAP_MD5, 0);
1169                 vp->vp_length = 17;
1170
1171                 p = talloc_zero_array(vp, uint8_t, 17);
1172                 lg_response = 16;
1173                 memcpy(p, &lg_response, 1);
1174                 memcpy(p + 1, response, 16);
1175                 fr_pair_value_memsteal(vp, p);
1176         }
1177         fr_pair_replace(&(rep->vps), vp);
1178
1179         fr_pair_replace(&(rep->vps), id);
1180
1181         /* copy the state object in */
1182         fr_pair_replace(&(rep->vps), state);
1183
1184         return 1;
1185 }
1186
1187
1188 /** Allocate a new socket, and add it to the packet list.
1189  */
1190 static void rc_add_socket(fr_ipaddr_t *src_ipaddr, uint16_t src_port, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port)
1191 {
1192         int mysockfd;
1193
1194         /* Trace what we're doing. */
1195         char src_addr[15+1] = "";
1196         char dst_addr[15+1] = "";
1197         inet_ntop(AF_INET, &(src_ipaddr->ipaddr.ip4addr.s_addr), src_addr, sizeof(src_addr));
1198         inet_ntop(AF_INET, &(dst_ipaddr->ipaddr.ip4addr.s_addr), dst_addr, sizeof(dst_addr));
1199
1200         INFO("Adding new socket: src: %s:%d, dst: %s:%d", src_addr, src_port, dst_addr, dst_port);
1201
1202         mysockfd = fr_socket(src_ipaddr, src_port);
1203         if (mysockfd < 0) {
1204                 ERROR("Failed to create new socket: %s", fr_strerror());
1205                 exit(1);
1206         }
1207
1208         if (!fr_packet_list_socket_add(pl, mysockfd, ipproto, dst_ipaddr, dst_port, NULL)) {
1209                 ERROR("Failed to add new socket: %s", fr_strerror());
1210                 exit(1);
1211         }
1212
1213         num_sockets ++;
1214         DEBUG("Added new socket: %d (num sockets: %d)", mysockfd, num_sockets);
1215 }
1216
1217 /** Send one packet for a transaction.
1218  */
1219 static int rc_send_one_packet(rc_transaction_t *trans, RADIUS_PACKET **packet_p)
1220 {
1221         if (!trans || !packet_p || !*packet_p) return -1;
1222
1223         assert(pl != NULL);
1224
1225         RADIUS_PACKET *packet = *packet_p;
1226
1227         if (packet->id == -1) {
1228                 /* Haven't sent the packet yet.  Initialize it. */
1229                 bool rcode;
1230                 int i;
1231
1232                 rc_build_eap_context(trans); /* In case of EAP, build EAP-Message and initialize EAP context. */
1233
1234                 assert(trans->reply == NULL);
1235
1236                 trans->tries = 0;
1237                 packet->src_ipaddr.af = server_ipaddr.af;
1238                 int nb_sock_add = 0;
1239                 while (1) {
1240                         /* Allocate a RADIUS packet ID from a suitable socket of the packet list. */
1241                         rcode = fr_packet_list_id_alloc(pl, ipproto, packet_p, NULL);
1242
1243                         if (rcode) { /* Got an ID. */
1244                                 break;
1245                         }
1246                         if (nb_sock_add >= 1) {
1247                                 ERROR("Added %d new socket(s), but still could not get an ID (currently: %d outgoing requests).",
1248                                         nb_sock_add, fr_packet_list_num_outgoing(pl));
1249                                 exit(1);
1250                         }
1251
1252                         /* Could not find a free packet ID. Allocate a new socket, then try again. */
1253                         rc_add_socket(&packet->src_ipaddr, packet->src_port, &packet->dst_ipaddr, packet->dst_port);
1254
1255                         nb_sock_add ++;
1256                 }
1257
1258                 assert(packet->id != -1);
1259                 assert(packet->data == NULL);
1260
1261                 for (i = 0; i < 4; i++) {
1262                         ((uint32_t *) packet->vector)[i] = fr_rand();
1263                 }
1264         }
1265
1266         /*
1267          *      Send the packet.
1268          */
1269         DEBUG("Transaction: %u, sending packet: %u (id: %u)...", trans->id, trans->num_packet, packet->id);
1270
1271         gettimeofday(&packet->timestamp, NULL); /* set outgoing packet timestamp. */
1272
1273         if (rad_send(packet, NULL, secret) < 0) {
1274                 ERROR("Failed to send packet (sockfd: %d, id: %d): %s",
1275                         packet->sockfd, packet->id, fr_strerror());
1276         }
1277
1278         trans->num_packet ++;
1279         trans->tries ++;
1280
1281         if (fr_debug_lvl > 0) fr_packet_header_print(fr_log_fp, packet, false);
1282         if (fr_debug_lvl > 0) vp_printlist(fr_log_fp, packet->vps);
1283
1284         return 1;
1285 }
1286
1287 /** Send current packet of a transaction. Arm timeout event.
1288  */
1289 static int rc_send_transaction_packet(rc_transaction_t *trans, RADIUS_PACKET **packet_p)
1290 // note: we need a 'RADIUS_PACKET **' for fr_packet_list_id_alloc.
1291 {
1292         if (!trans || !packet_p || !*packet_p) return -1;
1293
1294         int ret = rc_send_one_packet(trans, packet_p);
1295         if (ret == 1) {
1296                 /* Send successful: arm the timeout callback. */
1297                 rc_evprep_packet_timeout(trans);
1298         }
1299         return ret;
1300 }
1301
1302 /** Deallocate RADIUS packet ID.
1303  */
1304 static void rc_deallocate_id(rc_transaction_t *trans)
1305 {
1306         if (!trans || !trans->packet ||
1307             (trans->packet->id < 0)) {
1308                 return;
1309         }
1310
1311         RADIUS_PACKET *packet = trans->packet;
1312
1313         DEBUG2("Deallocating (sockfd: %d, id: %d)", packet->sockfd, packet->id);
1314
1315         /*
1316          *      One more unused RADIUS ID.
1317          */
1318         fr_packet_list_id_free(pl, packet, true);
1319         /* note: "true" means automatically yank, so we must *not* yank ourselves before calling (otherwise, it does nothing)
1320          * so, *don't*: fr_packet_list_yank(pl, request->packet); */
1321
1322         /* free more stuff to ensure next allocate won't be stuck on a "full" socket. */
1323         packet->id = -1;
1324         packet->sockfd = -1;
1325         packet->src_ipaddr.af = AF_UNSPEC;
1326         packet->src_port = 0;
1327
1328         /*
1329          *      If we've already sent a packet, free up the old one,
1330          *      and ensure that the next packet has a unique
1331          *      authentication vector.
1332          */
1333         if (packet->data) {
1334                 talloc_free(packet->data);
1335                 packet->data = NULL;
1336         }
1337
1338         if (trans->reply) rad_free(&trans->reply);
1339 }
1340
1341 /** Receive one packet, maybe.
1342  */
1343 static int rc_recv_one_packet(struct timeval *tv_wait_time)
1344 {
1345         fd_set set;
1346         struct timeval tv;
1347         rc_transaction_t *trans;
1348         RADIUS_PACKET *reply, **packet_p;
1349         volatile int max_fd;
1350         bool ongoing_trans = false;
1351         char buffer[128];
1352
1353         /* Wait for reply, timing out as necessary */
1354         FD_ZERO(&set);
1355
1356         max_fd = fr_packet_list_fd_set(pl, &set);
1357         if (max_fd < 0) {
1358                 /* no sockets to listen on! */
1359                 return 0;
1360         }
1361
1362         if (NULL == tv_wait_time) {
1363                 timerclear(&tv);
1364         } else {
1365                 tv.tv_sec = tv_wait_time->tv_sec;
1366                 tv.tv_usec = tv_wait_time->tv_usec;
1367         }
1368
1369         if (select(max_fd, &set, NULL, NULL, &tv) <= 0) {
1370                 /* No packet was received. */
1371                 return 0;
1372         }
1373
1374         /*
1375          *      Receive the reply.
1376          */
1377         reply = fr_packet_list_recv(pl, &set);
1378         if (!reply) {
1379                 ERROR("Received bad packet: %s", fr_strerror());
1380                 return -1;      /* bad packet */
1381         }
1382
1383         /*
1384          *      Look for the packet which matches the reply.
1385          */
1386         reply->src_ipaddr = server_ipaddr;
1387         reply->src_port = server_port;
1388
1389         /*
1390          * Note: this only works if all packets have the same destination (IP, port).
1391          * We should handle a list of destinations. But we don't. radclient doesn't do it either).
1392          */
1393
1394         packet_p = fr_packet_list_find_byreply(pl, reply);
1395
1396         if (!packet_p) {
1397                 /* got reply to packet we didn't send.
1398                  * (or maybe we sent it, got no response, freed the ID. Then server responds to first request.)
1399                  */
1400                 DEBUG("No outstanding request was found for reply from %s, port %d (sockfd: %d, id: %d)",
1401                         inet_ntop(reply->src_ipaddr.af, &reply->src_ipaddr.ipaddr, buffer, sizeof(buffer)),
1402                         reply->src_port, reply->sockfd, reply->id);
1403                 rad_free(&reply);
1404                 return -1;
1405         }
1406
1407         trans = fr_packet2myptr(rc_transaction_t, packet, packet_p);
1408
1409         if (trans->event) fr_event_delete(ev_list, &trans->event);
1410
1411         /*
1412          *      Fails the signature validation: not a valid reply.
1413          */
1414         if (rad_verify(reply, trans->packet, secret) < 0) {
1415                 /* shared secret is incorrect.
1416                  * (or maybe this is a response to another packet we sent, for which we got no response,
1417                  * freed the ID, then reused it. Then server responds to first packet.)
1418                  */
1419                 DEBUG("Conflicting response authenticator for reply from %s (sockfd: %d, id: %d)",
1420                         inet_ntop(reply->src_ipaddr.af, &reply->src_ipaddr.ipaddr, buffer, sizeof(buffer)),
1421                         reply->sockfd, reply->id);
1422
1423                 goto packet_done;
1424         }
1425
1426         /* Set reply destination = packet source. */
1427         reply->dst_ipaddr = trans->packet->src_ipaddr;
1428         reply->dst_port = trans->packet->src_port;
1429
1430         trans->reply = reply;
1431         reply = NULL;
1432
1433         if (rad_decode(trans->reply, trans->packet, secret) != 0) {
1434                 /* This can fail if packet contains too many attributes. */
1435                 DEBUG("Failed decoding reply");
1436                 goto packet_done;
1437         }
1438
1439         gettimeofday(&trans->reply->timestamp, NULL); /* set received packet timestamp. */
1440
1441         if (trans->eap_context) {
1442                 /* Call unmap before packet print (so we can see the decoded EAP stuff). */
1443                 rc_unmap_eap_methods(trans->reply);
1444         }
1445
1446         DEBUG("Transaction: %u, received packet (id: %u).", trans->id, trans->reply->id);
1447
1448         if (fr_debug_lvl > 0) fr_packet_header_print(fr_log_fp, trans->reply, true);
1449         if (fr_debug_lvl > 0) vp_printlist(fr_log_fp, trans->reply->vps);
1450
1451         if (!trans->eap_context) {
1452                 goto packet_done;
1453         }
1454
1455         /* now look for the code type. */
1456         VALUE_PAIR *vp, *vpnext;
1457         for (vp = trans->reply->vps; vp != NULL; vp = vpnext) {
1458                 vpnext = vp->next;
1459
1460                 switch (vp->da->attr) {
1461                 default:
1462                         break;
1463
1464                 case PW_EAP_TYPE_BASE + PW_EAP_MD5:
1465                         if (rc_respond_eap_md5(trans->eap_context, trans->reply, trans->packet) && trans->eap_context->eap.md5.tried < 3)
1466                         {
1467                                 /* answer the challenge from server. */
1468                                 trans->eap_context->eap.md5.tried ++;
1469                                 rc_deallocate_id(trans);
1470                                 rc_send_transaction_packet(trans, &trans->packet);
1471                                 ongoing_trans = true; // don't free the transaction yet.
1472                         }
1473                         goto packet_done;
1474
1475                 case PW_EAP_TYPE_BASE + PW_EAP_SIM:
1476                         if (rc_respond_eap_sim(trans->eap_context, trans->reply, trans->packet)) {
1477                                 /* answer the challenge from server. */
1478                                 rc_deallocate_id(trans);
1479                                 rc_send_transaction_packet(trans, &trans->packet);
1480                                 ongoing_trans = true; // don't free the transaction yet.
1481                         }
1482                         goto packet_done;
1483                 }
1484         }
1485
1486         goto eap_done;
1487
1488 eap_done:
1489         /* EAP transaction ends here (no more requests from EAP server). */
1490
1491         /*
1492          * success: if we have EAP-Code = Success, and reply is an Access-Accept.
1493          */
1494         if (trans->reply->code != PW_CODE_ACCESS_ACCEPT) {
1495                 DEBUG("EAP transaction finished, but reply is not an Access-Accept");
1496                 goto packet_done;
1497         }
1498         vp = fr_pair_find_by_num(trans->reply->vps, PW_EAP_CODE, 0, TAG_ANY);
1499         if ( (!vp) || (vp->vp_integer != 3) ) {
1500                 DEBUG("EAP transaction finished, but reply does not contain EAP-Code = Success");
1501                 goto packet_done;
1502         }
1503         goto packet_done;
1504
1505 packet_done:
1506
1507         /* Basic statistics (salvaged from old code). TODO: something better. */
1508         if (trans->reply) {
1509                 if (trans->reply->code == PW_CODE_ACCESS_ACCEPT) {
1510                         totalapp ++;
1511                 } else if (trans->reply->code == PW_CODE_ACCESS_REJECT) {
1512                         totaldeny ++;
1513                 }
1514         }
1515
1516         rad_free(&trans->reply);
1517         rad_free(&reply);       /* may be NULL */
1518
1519         if (!ongoing_trans) {
1520                 rc_deallocate_id(trans);
1521                 rc_finish_transaction(trans);
1522         }
1523
1524         return 1;
1525 }
1526
1527 /** Event callback: packet timeout.
1528  */
1529 static void rc_evcb_packet_timeout(void *ctx)
1530 {
1531         rc_transaction_t *trans = ctx;
1532         if (!trans || !trans->packet) return;
1533
1534         DEBUG("Timeout for transaction: %d, tries (so far): %d (max: %d)", trans->id, trans->tries, retries);
1535
1536         if (trans->event) fr_event_delete(ev_list, &trans->event);
1537
1538         if (trans->tries < retries) {
1539                 /* Try again. */
1540                 rc_send_transaction_packet(trans, &trans->packet);
1541         } else {
1542                 DEBUG("No response for transaction: %d, giving up", trans->id);
1543                 rc_finish_transaction(trans);
1544         }
1545 }
1546
1547 /** Prepare event: packet timeout.
1548  */
1549 static void rc_evprep_packet_timeout(rc_transaction_t *trans)
1550 {
1551         struct timeval tv_event;
1552         gettimeofday(&tv_event, NULL);
1553         timeradd(&tv_event, &tv_timeout, &tv_event);
1554
1555         if (!fr_event_insert(ev_list, rc_evcb_packet_timeout, (void *)trans, &tv_event, &trans->event)) {
1556                 ERROR("Failed to insert event");
1557                 exit(1);
1558         }
1559 }
1560
1561 /** Trigger all armed events for which time is reached.
1562  */
1563 static int rc_loop_events(void)
1564 {
1565         struct timeval when;
1566         uint32_t nb_processed = 0;
1567
1568         if (!fr_event_list_num_elements(ev_list)) return 0;
1569
1570         while (1) {
1571                 gettimeofday(&when, NULL);
1572                 if (!fr_event_run(ev_list, &when)) {
1573                         /* no more. */
1574                         break;
1575                 }
1576                 nb_processed ++;
1577         }
1578         return nb_processed;
1579 }
1580
1581 /** Receive loop.
1582  *  Handle incoming packets, until nothing more is received.
1583  */
1584 static int dhb_loop_recv(void)
1585 {
1586         uint32_t nb_received = 0;
1587         while (rc_recv_one_packet(NULL) > 0) {
1588                 nb_received ++;
1589         }
1590         return nb_received;
1591 }
1592
1593 /** Loop starting new transactions, until a limit is reached
1594  *  (max parallelism, or no more input available.)
1595  */
1596 static int rc_loop_start_transactions(void)
1597 {
1598         int nb_started = 0;
1599
1600         while (1) {
1601                 if (num_ongoing >= parallel) break;
1602
1603                 /* Try to initialize a new transaction. */
1604                 rc_transaction_t *trans = rc_init_transaction(autofree);
1605                 if (!trans) break;
1606
1607                 nb_started ++;
1608                 rc_send_transaction_packet(trans, &trans->packet);
1609         }
1610         return nb_started;
1611 }
1612
1613 /** Main loop: Handle events. Receive and process responses. Start new transactions.
1614  *  Until we're done.
1615  */
1616 static void rc_main_loop(void)
1617 {
1618         while (1) {
1619                 /* Handle events. */
1620                 rc_loop_events();
1621
1622                 /* Receive and process response until no more are received (don't wait). */
1623                 dhb_loop_recv();
1624
1625                 /* Start new transactions and send the associated packet. */
1626                 rc_loop_start_transactions();
1627
1628                 /* Check if we're done. */
1629                 if ( (rc_vps_list_in.size == 0)
1630                         && (fr_packet_list_num_outgoing(pl) == 0) ) {
1631                         break;
1632                 }
1633         }
1634         INFO("Main loop: done.");
1635 }
1636
1637
1638 void set_radius_dir(TALLOC_CTX *ctx, char const *path)
1639 {
1640         if (radius_dir) {
1641                 char *p;
1642
1643                 memcpy(&p, &radius_dir, sizeof(p));
1644                 talloc_free(p);
1645                 radius_dir = NULL;
1646         }
1647         if (path) radius_dir = talloc_strdup(ctx, path);
1648 }
1649
1650
1651 /** Set a port from the request type if we don't already have one.
1652  */
1653 static void rc_get_port(PW_CODE type, uint16_t *port)
1654 {
1655         switch (type) {
1656         default:
1657         case PW_CODE_ACCESS_REQUEST:
1658         case PW_CODE_ACCESS_CHALLENGE:
1659         case PW_CODE_STATUS_SERVER:
1660                 if (*port == 0) *port = getport("radius");
1661                 if (*port == 0) *port = PW_AUTH_UDP_PORT;
1662                 return;
1663
1664         case PW_CODE_ACCOUNTING_REQUEST:
1665                 if (*port == 0) *port = getport("radacct");
1666                 if (*port == 0) *port = PW_ACCT_UDP_PORT;
1667                 return;
1668
1669         case PW_CODE_DISCONNECT_REQUEST:
1670                 if (*port == 0) *port = PW_POD_UDP_PORT;
1671                 return;
1672
1673         case PW_CODE_COA_REQUEST:
1674                 if (*port == 0) *port = PW_COA_UDP_PORT;
1675                 return;
1676
1677         case PW_CODE_UNDEFINED:
1678                 if (*port == 0) *port = 0;
1679                 return;
1680         }
1681 }
1682
1683 /** Resolve a port to a request type.
1684  */
1685 static PW_CODE rc_get_code(uint16_t port)
1686 {
1687         /*
1688          *      getport returns 0 if the service doesn't exist
1689          *      so we need to return early, to avoid incorrect
1690          *      codes.
1691          */
1692         if (port == 0) return PW_CODE_UNDEFINED;
1693
1694         if ((port == getport("radius")) || (port == PW_AUTH_UDP_PORT) || (port == PW_AUTH_UDP_PORT_ALT)) {
1695                 return PW_CODE_ACCESS_REQUEST;
1696         }
1697         if ((port == getport("radacct")) || (port == PW_ACCT_UDP_PORT) || (port == PW_ACCT_UDP_PORT_ALT)) {
1698                 return PW_CODE_ACCOUNTING_REQUEST;
1699         }
1700         if (port == PW_COA_UDP_PORT) return PW_CODE_COA_REQUEST;
1701         if (port == PW_POD_UDP_PORT) return PW_CODE_DISCONNECT_REQUEST;
1702
1703         return PW_CODE_UNDEFINED;
1704 }
1705
1706 /** Resolve server hostname.
1707  */
1708 static void rc_resolve_hostname(char *server_arg)
1709 {
1710         if (force_af == AF_UNSPEC) force_af = AF_INET;
1711         server_ipaddr.af = force_af;
1712         if (strcmp(server_arg, "-") != 0) {
1713                 char *p;
1714                 char const *hostname = server_arg;
1715                 char const *portname = server_arg;
1716                 char buffer[256];
1717
1718                 if (*server_arg == '[') { /* IPv6 URL encoded */
1719                         p = strchr(server_arg, ']');
1720                         if ((size_t) (p - server_arg) >= sizeof(buffer)) {
1721                                 usage();
1722                         }
1723
1724                         memcpy(buffer, server_arg + 1, p - server_arg - 1);
1725                         buffer[p - server_arg - 1] = '\0';
1726
1727                         hostname = buffer;
1728                         portname = p + 1;
1729
1730                 }
1731                 p = strchr(portname, ':');
1732                 if (p && (strchr(p + 1, ':') == NULL)) {
1733                         *p = '\0';
1734                         portname = p + 1;
1735                 } else {
1736                         portname = NULL;
1737                 }
1738
1739                 if (ip_hton(&server_ipaddr, force_af, hostname, false) < 0) {
1740                         ERROR("%s: Failed to find IP address for host %s: %s", progname, hostname, strerror(errno));
1741                         exit(1);
1742                 }
1743                 server_addr_init = true;
1744
1745                 /* Strip port from hostname if needed. */
1746                 if (portname) server_port = atoi(portname);
1747
1748                 /*
1749                  *      Work backwards from the port to determine the packet type
1750                  */
1751                 if (packet_code == PW_CODE_UNDEFINED) packet_code = rc_get_code(server_port);
1752         }
1753         rc_get_port(packet_code, &server_port);
1754 }
1755
1756 int main(int argc, char **argv)
1757 {
1758         char *p;
1759         int c;
1760         char *filename = NULL;
1761         FILE *fp;
1762
1763         static fr_log_t radclient_log = {
1764                 .colourise = true,
1765                 .fd = STDOUT_FILENO,
1766                 .dst = L_DST_STDOUT,
1767                 .file = NULL,
1768                 .debug_file = NULL,
1769         };
1770
1771         radlog_init(&radclient_log, false);
1772
1773         /*
1774          *      We probably don't want to free the talloc autofree context
1775          *      directly, so we'll allocate a new context beneath it, and
1776          *      free that before any leak reports.
1777          */
1778         autofree = talloc_init("main");
1779
1780         fr_debug_lvl = 0;
1781         fr_log_fp = stdout;
1782
1783         set_radius_dir(autofree, RADIUS_DIR);
1784
1785         while ((c = getopt(argc, argv, "46c:d:D:f:hp:qst:r:S:xXv")) != EOF)
1786         {
1787                 switch (c) {
1788                 case '4':
1789                         force_af = AF_INET;
1790                         break;
1791                 case '6':
1792                         force_af = AF_INET6;
1793                         break;
1794                 case 'd':
1795                         set_radius_dir(autofree, optarg);
1796                         break;
1797                 case 'D':
1798                         main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg);
1799                         break;
1800                 case 'f':
1801                         filename = optarg;
1802                         break;
1803                 case 'p':
1804                         parallel = atoi(optarg);
1805                         if (parallel == 0) parallel = 1;
1806                         if (parallel > 65536) parallel = 65536;
1807                         break;
1808                 case 'q':
1809                         do_output = 0;
1810                         break;
1811                 case 'x':
1812                         rad_debug_lvl++;
1813                         fr_debug_lvl++;
1814                         break;
1815
1816                 case 'X':
1817 #if 0
1818                   sha1_data_problems = 1; /* for debugging only */
1819 #endif
1820                   break;
1821
1822                 case 'r':
1823                         if (!isdigit((int) *optarg))
1824                                 usage();
1825                         retries = atoi(optarg);
1826                         break;
1827                 case 's':
1828                         do_summary = 1;
1829                         break;
1830                 case 't':
1831                         if (!isdigit((int) *optarg))
1832                                 usage();
1833                         timeout = atof(optarg);
1834                         break;
1835                 case 'v':
1836                         printf("$Id$ built on "__DATE__ "at "__TIME__ "");
1837                         exit(0);
1838
1839                 case 'S':
1840                        fp = fopen(optarg, "r");
1841                        if (!fp) {
1842                                ERROR("Error opening %s: %s",
1843                                        optarg, fr_syserror(errno));
1844                                exit(1);
1845                        }
1846                        if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
1847                                ERROR("Error reading %s: %s",
1848                                        optarg, fr_syserror(errno));
1849                                exit(1);
1850                        }
1851                        fclose(fp);
1852
1853                        /* truncate newline */
1854                        p = filesecret + strlen(filesecret) - 1;
1855                        while ((p >= filesecret) &&
1856                               (*p < ' ')) {
1857                                *p = '\0';
1858                                --p;
1859                        }
1860
1861                        if (strlen(filesecret) < 2) {
1862                                ERROR("Secret in %s is too short", optarg);
1863                                exit(1);
1864                        }
1865                        secret = filesecret;
1866                        break;
1867                 case 'h':
1868                 default:
1869                         usage();
1870                 }
1871         }
1872         argc -= (optind - 1);
1873         argv += (optind - 1);
1874
1875         if ((argc < 3)  ||
1876             ((!secret) && (argc < 4))) {
1877                 usage();
1878         }
1879
1880         /* Prepare the timeout. */
1881         rc_float_to_timeval(&tv_timeout, timeout);
1882
1883         if (!main_config.dictionary_dir) {
1884                 main_config.dictionary_dir = DICTDIR;
1885         }
1886
1887         /*
1888          *      Read the distribution dictionaries first, then
1889          *      the ones in raddb.
1890          */
1891         DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, RADIUS_DICTIONARY);
1892         if (dict_init(main_config.dictionary_dir, RADIUS_DICTIONARY) != 0) {
1893                 ERROR("Errors reading dictionary: %s", fr_strerror());
1894                 exit(1);
1895         }
1896
1897         /*
1898          *      It's OK if this one doesn't exist.
1899          */
1900         int rcode = dict_read(radius_dir, RADIUS_DICTIONARY);
1901         if (rcode == -1) {
1902                 ERROR("Errors reading %s/%s: %s", radius_dir, RADIUS_DICTIONARY, fr_strerror());
1903                 exit(1);
1904         }
1905
1906         /*
1907          *      We print this after reading it.  That way if
1908          *      it doesn't exist, it's OK, and we don't print
1909          *      anything.
1910          */
1911         if (rcode == 0) {
1912                 DEBUG2("Including dictionary file %s/%s", radius_dir, RADIUS_DICTIONARY);
1913         }
1914
1915         /*
1916          *      Get the request type
1917          */
1918         if (!isdigit((int) argv[2][0])) {
1919                 packet_code = fr_str2int(rc_request_types, argv[2], -2);
1920                 if (packet_code == -2) {
1921                         ERROR("Unrecognised request type \"%s\"", argv[2]);
1922                         usage();
1923                 }
1924         } else {
1925                 packet_code = atoi(argv[2]);
1926         }
1927
1928         /*
1929          *      Resolve hostname.
1930          */
1931         rc_resolve_hostname(argv[1]);
1932
1933         /*
1934          *      Add the secret.
1935          */
1936         if (argv[3]) secret = argv[3];
1937
1938         /*
1939          *      Read input data vp(s) from the file (or stdin).
1940          */
1941         INFO("Loading input data...");
1942         if (!rc_load_input(autofree, filename, &rc_vps_list_in, 0)
1943             || rc_vps_list_in.size == 0) {
1944                 ERROR("No valid input. Nothing to send.");
1945                 exit(EXIT_FAILURE);
1946         }
1947         INFO("Loaded: %d input element(s).", rc_vps_list_in.size);
1948
1949         /* Initialize the packets list. */
1950         MEM(pl = fr_packet_list_create(1));
1951
1952         /* Initialize the events list. */
1953         ev_list = fr_event_list_create(autofree, NULL);
1954         if (!ev_list) {
1955                 ERROR("Failed to create event list");
1956                 exit(1);
1957         }
1958
1959         /*
1960          *      Start main loop.
1961          */
1962         rc_main_loop();
1963
1964         if (do_summary) {
1965                 INFO("\n\t   Total approved auths:  %d", totalapp);
1966                 INFO("\t     Total denied auths:  %d", totaldeny);
1967         }
1968
1969         talloc_free(autofree);
1970
1971         return 0;
1972 }
1973
1974 /** Given a radius request with some attributes in the EAP range, build
1975  *  them all into a single EAP-Message body.
1976  *
1977  *  If there are multiple eligibles EAP-Type, the first one is picked.
1978  *  Function returns 0 if no EAP is involved, or the EAP-Type otherwise.
1979  */
1980 static int rc_map_eap_methods(RADIUS_PACKET *req)
1981 {
1982         VALUE_PAIR *vp, *vpnext;
1983         int id, eapcode;
1984         int eap_method = 0;
1985
1986         eap_packet_t *pt_ep = talloc_zero(req, eap_packet_t);
1987
1988         vp = fr_pair_find_by_num(req->vps, PW_EAP_ID, 0, TAG_ANY);
1989         if (!vp) {
1990                 id = ((int)getpid() & 0xff);
1991         } else {
1992                 id = vp->vp_integer;
1993         }
1994
1995         vp = fr_pair_find_by_num(req->vps, PW_EAP_CODE, 0, TAG_ANY);
1996         if (!vp) {
1997                 eapcode = PW_EAP_REQUEST;
1998         } else {
1999                 eapcode = vp->vp_integer;
2000         }
2001
2002         for (vp = req->vps; vp != NULL; vp = vpnext) {
2003                 /* save it in case it changes! */
2004                 vpnext = vp->next;
2005
2006                 if (vp->da->attr >= PW_EAP_TYPE_BASE &&
2007                    vp->da->attr < PW_EAP_TYPE_BASE+256) {
2008                         break;
2009                 }
2010         }
2011
2012         if (!vp) {
2013                 return 0;
2014         }
2015
2016         eap_method = vp->da->attr - PW_EAP_TYPE_BASE;
2017
2018         switch (eap_method) {
2019         case PW_EAP_IDENTITY:
2020         case PW_EAP_NOTIFICATION:
2021         case PW_EAP_NAK:
2022         case PW_EAP_MD5:
2023         case PW_EAP_OTP:
2024         case PW_EAP_GTC:
2025         case PW_EAP_TLS:
2026         case PW_EAP_LEAP:
2027         case PW_EAP_TTLS:
2028         case PW_EAP_PEAP:
2029         default:
2030                 /*
2031                  * no known special handling, it is just encoded as an
2032                  * EAP-message with the given type.
2033                  */
2034
2035                 /* nuke any existing EAP-Messages */
2036                 fr_pair_delete_by_num(&req->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
2037
2038                 pt_ep->code = eapcode;
2039                 pt_ep->id = id;
2040                 pt_ep->type.num = eap_method;
2041                 pt_ep->type.length = vp->vp_length;
2042
2043                 pt_ep->type.data = talloc_memdup(vp, vp->vp_octets, vp->vp_length);
2044                 talloc_set_type(pt_ep->type.data, uint8_t);
2045
2046                 eap_basic_compose(req, pt_ep);
2047         }
2048
2049         return eap_method;
2050 }
2051
2052 /*
2053  * given a radius request with an EAP-Message body, decode it specific
2054  * attributes.
2055  */
2056 static void rc_unmap_eap_methods(RADIUS_PACKET *rep)
2057 {
2058         VALUE_PAIR *eap1;
2059         eap_packet_raw_t *e;
2060         int len;
2061         int type;
2062
2063         if (!rep) return;
2064
2065         /* find eap message */
2066         e = eap_vp2packet(NULL, rep->vps);
2067         if (!e) {
2068                 ERROR("%s", fr_strerror());
2069                 return;
2070         }
2071         /* create EAP-ID and EAP-CODE attributes to start */
2072         eap1 = fr_pair_afrom_num(rep, PW_EAP_ID, 0);
2073         eap1->vp_integer = e->id;
2074         fr_pair_add(&(rep->vps), eap1);
2075
2076         eap1 = fr_pair_afrom_num(rep, PW_EAP_CODE, 0);
2077         eap1->vp_integer = e->code;
2078         fr_pair_add(&(rep->vps), eap1);
2079
2080         switch (e->code) {
2081         default:
2082         case PW_EAP_SUCCESS:
2083         case PW_EAP_FAILURE:
2084                 /* no data */
2085                 break;
2086
2087         case PW_EAP_REQUEST:
2088         case PW_EAP_RESPONSE:
2089                 /* there is a type field, which we use to create
2090                  * a new attribute */
2091
2092                 /* the length was decode already into the attribute
2093                  * length, and was checked already. Network byte
2094                  * order, just pull it out using math.
2095                  */
2096                 len = e->length[0]*256 + e->length[1];
2097
2098                 /* verify the length is big enough to hold type */
2099                 if (len < 5)
2100                 {
2101                         talloc_free(e);
2102                         return;
2103                 }
2104
2105                 type = e->data[0];
2106
2107                 type += PW_EAP_TYPE_BASE;
2108                 len -= 5;
2109
2110                 if (len > MAX_STRING_LEN) {
2111                         len = MAX_STRING_LEN;
2112                 }
2113
2114                 eap1 = fr_pair_afrom_num(rep, type, 0);
2115                 fr_pair_value_memcpy(eap1, e->data + 1, len);
2116
2117                 fr_pair_add(&(rep->vps), eap1);
2118                 break;
2119         }
2120
2121         talloc_free(e);
2122         return;
2123 }
2124
2125 static int rc_map_eapsim_types(RADIUS_PACKET *r)
2126 {
2127         int ret;
2128
2129         eap_packet_t *pt_ep = talloc_zero(r, eap_packet_t);
2130
2131         ret = map_eapsim_basictypes(r, pt_ep);
2132
2133         if (ret != 1) {
2134                 return ret;
2135         }
2136
2137         eap_basic_compose(r, pt_ep);
2138
2139         return 1;
2140 }
2141
2142 static int rc_unmap_eapsim_types(RADIUS_PACKET *r)
2143 {
2144         VALUE_PAIR           *esvp;
2145         uint8_t *eap_data;
2146         int rcode_unmap;
2147
2148         esvp = fr_pair_find_by_num(r->vps, PW_EAP_TYPE_BASE+PW_EAP_SIM, 0, TAG_ANY);
2149         if (!esvp) {
2150                 ERROR("eap: EAP-Sim attribute not found");
2151                 return 0;
2152         }
2153
2154         eap_data = talloc_memdup(esvp, esvp->vp_octets, esvp->vp_length);
2155         talloc_set_type(eap_data, uint8_t);
2156
2157         rcode_unmap = unmap_eapsim_basictypes(r, eap_data, esvp->vp_length);
2158
2159         talloc_free(eap_data);
2160         return rcode_unmap;
2161 }
2162