Many "unsigned char" to "uint8_t" and "int" to "size_t", so
[freeradius.git] / src / modules / rlm_eap / types / rlm_eap_peap / peap.c
1 /*
2  * peap.c  contains the interfaces that are called from eap
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 2003 Alan DeKok <aland@freeradius.org>
21  *   Copyright 2006 The FreeRADIUS server project
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include "eap_peap.h"
28
29 /*
30  *      Send protected EAP-Failure
31  *
32  *       Result-TLV = Failure
33  */
34 static int eappeap_failure(EAP_HANDLER *handler, tls_session_t *tls_session)
35 {
36         uint8_t tlv_packet[11];
37
38         DEBUG2("  rlm_eap_peap: FAILURE");
39
40         tlv_packet[0] = PW_EAP_REQUEST;
41         tlv_packet[1] = handler->eap_ds->response->id +1;
42         tlv_packet[2] = 0;
43         tlv_packet[3] = 11;     /* length of this packet */
44         tlv_packet[4] = PW_EAP_TLV;
45         tlv_packet[5] = 0x80;
46         tlv_packet[6] = EAP_TLV_ACK_RESULT;
47         tlv_packet[7] = 0;
48         tlv_packet[8] = 2;      /* length of the data portion */
49         tlv_packet[9] = 0;
50         tlv_packet[10] = EAP_TLV_FAILURE;
51
52         (tls_session->record_plus)(&tls_session->clean_in, tlv_packet, 11);
53
54         /*
55          *      FIXME: Check the return code.
56          */
57         tls_handshake_send(tls_session);
58
59         return 1;
60 }
61
62
63 /*
64  *      Send protected EAP-Success
65  *
66  *       Result-TLV = Success
67  */
68 static int eappeap_success(EAP_HANDLER *handler, tls_session_t *tls_session)
69 {
70         uint8_t tlv_packet[11];
71
72         DEBUG2("  rlm_eap_peap: SUCCESS");
73
74         tlv_packet[0] = PW_EAP_REQUEST;
75         tlv_packet[1] = handler->eap_ds->response->id +1;
76         tlv_packet[2] = 0;
77         tlv_packet[3] = 11;     /* length of this packet */
78         tlv_packet[4] = PW_EAP_TLV;
79         tlv_packet[5] = 0x80;   /* mandatory AVP */
80         tlv_packet[6] = EAP_TLV_ACK_RESULT;
81         tlv_packet[7] = 0;
82         tlv_packet[8] = 2;      /* length of the data portion */
83         tlv_packet[9] = 0;
84         tlv_packet[10] = EAP_TLV_SUCCESS;
85
86         (tls_session->record_plus)(&tls_session->clean_in, tlv_packet, 11);
87
88         /*
89          *      FIXME: Check the return code.
90          */
91         tls_handshake_send(tls_session);
92
93         return 1;
94 }
95
96
97 /*
98  *      Verify the tunneled EAP message.
99  */
100 static int eapmessage_verify(const uint8_t *data, unsigned int data_len)
101 {
102         const eap_packet_t *eap_packet = (const eap_packet_t *) data;
103         uint8_t eap_type;
104         char identity[256];
105
106         if (!data || (data_len <= 1)) {
107                 return 0;
108         }
109
110         eap_type = *data;
111         switch (eap_type) {
112         case PW_EAP_IDENTITY:
113                 memcpy(identity, data + 1, data_len - 1);
114                 identity[data_len - 1] = '\0';
115                 DEBUG2("  rlm_eap_peap: Identity - %s", identity);
116                 return 1;
117                 break;
118
119                 /*
120                  *      If the first byte of the packet is
121                  *      EAP-Response, and the EAP data is a TLV,
122                  *      then it looks OK...
123                  */
124         case PW_EAP_RESPONSE:
125                 if (eap_packet->data[0] == PW_EAP_TLV) {
126                         DEBUG2("  rlm_eap_peap: Received EAP-TLV response.");
127                         return 1;
128                 }
129                 DEBUG2("  rlm_eap_peap: Got something weird.");
130                 break;
131
132
133                 /*
134                  *      We normally do Microsoft MS-CHAPv2 (26), versus
135                  *      Cisco MS-CHAPv2 (29).
136                  */
137         case PW_EAP_MSCHAPV2:
138         default:
139                 DEBUG2("  rlm_eap_peap: EAP type %s",
140                        eaptype_type2name(eap_type,
141                                          identity, sizeof(identity)));
142                 return 1;
143                 break;
144         }
145
146         return 0;
147 }
148
149 /*
150  *      Convert a pseudo-EAP packet to a list of VALUE_PAIR's.
151  */
152 static VALUE_PAIR *eap2vp(EAP_DS *eap_ds,
153                           const uint8_t *data, size_t data_len)
154 {
155         size_t total;
156         VALUE_PAIR *vp = NULL, *head, **tail;
157
158         vp = paircreate(PW_EAP_MESSAGE, PW_TYPE_OCTETS);
159         if (!vp) {
160                 DEBUG2("  rlm_eap_peap: Failure in creating VP");
161                 return NULL;
162         }
163
164         total = data_len;
165         if (total > 249) total = 249;
166
167         /*
168          *      Hand-build an EAP packet from the crap in PEAP version 0.
169          */
170         vp->vp_octets[0] = PW_EAP_RESPONSE;
171         vp->vp_octets[1] = eap_ds->response->id;
172         vp->vp_octets[2] = 0;
173         vp->vp_octets[3] = EAP_HEADER_LEN + total;
174
175         memcpy(vp->vp_octets + EAP_HEADER_LEN, data, total);
176         vp->length = EAP_HEADER_LEN + total;
177
178         head = vp;
179         while (total < data_len) {
180                 int vp_len;
181
182                 tail = &(vp->next);
183
184                 vp = paircreate(PW_EAP_MESSAGE, PW_TYPE_OCTETS);
185                 if (!vp) {
186                         DEBUG2("  rlm_eap_peap: Failure in creating VP");
187                         pairfree(&head);
188                         return NULL;
189                 }
190                 vp_len = (data_len - total);
191                 if (vp_len > 253) vp_len = 253;
192
193                 memcpy(vp->vp_octets, data + total, vp_len);
194                 vp->length = vp_len;
195                 
196                 total += vp_len;
197         }
198
199         return head;
200 }
201
202
203 /*
204  *      Convert a list of VALUE_PAIR's to an EAP packet, through the
205  *      simple expedient of dumping the EAP message
206  */
207 static int vp2eap(tls_session_t *tls_session, VALUE_PAIR *vp)
208 {
209         /*
210          *      Skip the id, code, and length.  Just write the EAP
211          *      type & data to the client.
212          */
213 #ifndef NDEBUG
214         if (debug_flag > 2) {
215                 size_t i, total;
216                 VALUE_PAIR *this;
217
218                 total = 0;
219
220                 for (this = vp; this != NULL; this = this->next) {
221                         int start = 0;
222
223                         if (this == vp) start = EAP_HEADER_LEN;
224                         
225                         for (i = start; i < vp->length; i++) {
226                                 if ((total & 0x0f) == 0) printf("  PEAP tunnel data out %04x: ", total);
227
228                                 printf("%02x ", vp->vp_octets[i]);
229                                 
230                                 if ((total & 0x0f) == 0x0f) printf("\n");
231                                 total++;
232                         }
233                 }
234                 if ((total & 0x0f) != 0) printf("\n");
235         }
236 #endif
237
238         /*
239          *      Send the EAP data, WITHOUT the header.
240          */
241         (tls_session->record_plus)(&tls_session->clean_in,
242                                    vp->vp_octets + EAP_HEADER_LEN,
243                                    vp->length - EAP_HEADER_LEN);
244         
245         /*
246          *      Send the rest of the EAP data.
247          */
248         for (vp = vp->next; vp != NULL; vp = vp->next) {
249                 (tls_session->record_plus)(&tls_session->clean_in,
250                                            vp->vp_octets, vp->length);
251         }
252
253         tls_handshake_send(tls_session);
254
255         return 1;
256 }
257
258
259 /*
260  *      See if there's a TLV in the response.
261  */
262 static int eappeap_check_tlv(const uint8_t *data)
263 {
264         const eap_packet_t *eap_packet = (const eap_packet_t *) data;
265
266         /*
267          *      Look for success or failure.
268          */
269         if ((eap_packet->code == PW_EAP_RESPONSE) &&
270             (eap_packet->data[0] == PW_EAP_TLV)) {
271                 if (data[10] == EAP_TLV_SUCCESS) {
272                         return 1;
273                 }
274
275                 if (data[10] == EAP_TLV_FAILURE) {
276                         DEBUG2("  rlm_eap_peap: Client rejected our response.  The password is probably incorrect.");
277                         return 0;
278                 }
279         }
280
281         return 0;
282 }
283
284
285 /*
286  *      Use a reply packet to determine what to do.
287  */
288 static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session,
289                          UNUSED REQUEST *request, RADIUS_PACKET *reply)
290 {
291         int rcode = RLM_MODULE_REJECT;
292         VALUE_PAIR *vp;
293         peap_tunnel_t *t = tls_session->opaque;
294
295 #ifndef NDEBUG
296         if (debug_flag > 0) {
297                 printf("  PEAP: Processing from tunneled session code %p %d\n",
298                        reply, reply->code);
299
300                 for (vp = reply->vps; vp != NULL; vp = vp->next) {
301                         putchar('\t');vp_print(stdout, vp);putchar('\n');
302                 }
303         }
304 #endif
305
306         switch (reply->code) {
307         case PW_AUTHENTICATION_ACK:
308                 DEBUG2("  PEAP: Tunneled authentication was successful.");
309                 t->status = PEAP_STATUS_SENT_TLV_SUCCESS;
310                 eappeap_success(handler, tls_session);
311                 rcode = RLM_MODULE_HANDLED;
312
313                 /*
314                  *      If we've been told to use the attributes from
315                  *      the reply, then do so.
316                  *
317                  *      WARNING: This may leak information about the
318                  *      tunneled user!
319                  */
320                 if (t->use_tunneled_reply) {
321                         DEBUG2("  Saving tunneled attributes for later");
322
323                         /*
324                          *      Clean up the tunneled reply.
325                          */
326                         pairdelete(&reply->vps, PW_PROXY_STATE);
327                         pairdelete(&reply->vps, PW_EAP_MESSAGE);
328                         pairdelete(&reply->vps, PW_MESSAGE_AUTHENTICATOR);
329
330                         t->accept_vps = reply->vps;
331                         reply->vps = NULL;
332                 }
333                 break;
334
335         case PW_AUTHENTICATION_REJECT:
336                 DEBUG2("  PEAP: Tunneled authentication was rejected.");
337                 t->status = PEAP_STATUS_SENT_TLV_FAILURE;
338                 eappeap_failure(handler, tls_session);
339                 rcode = RLM_MODULE_HANDLED;
340                 break;
341
342         case PW_ACCESS_CHALLENGE:
343                 DEBUG2("  PEAP: Got tunneled Access-Challenge");
344
345                 /*
346                  *      Keep the State attribute, if necessary.
347                  *
348                  *      Get rid of the old State, too.
349                  */
350                 pairfree(&t->state);
351                 pairmove2(&t->state, &(reply->vps), PW_STATE);
352
353                 /*
354                  *      PEAP takes only EAP-Message attributes inside
355                  *      of the tunnel.  Any Reply-Message in the
356                  *      Access-Challenge is ignored.
357                  */
358                 vp = NULL;
359                 pairmove2(&vp, &(reply->vps), PW_EAP_MESSAGE);
360
361                 /*
362                  *      Handle EAP-MSCHAP-V2, where Access-Accept's
363                  *      from the home server may contain MS-CHAP-Success,
364                  *      which the module turns into challenges, so that
365                  *      the client may respond to the challenge with
366                  *      an "ack" packet.
367                  */
368                 if (t->home_access_accept && t->use_tunneled_reply) {
369                         DEBUG2("  Saving tunneled attributes for later");
370
371                         /*
372                          *      Clean up the tunneled reply.
373                          */
374                         pairdelete(&reply->vps, PW_PROXY_STATE);
375                         pairdelete(&reply->vps, PW_MESSAGE_AUTHENTICATOR);
376
377                         t->accept_vps = reply->vps;
378                         reply->vps = NULL;
379                 }
380
381                 /*
382                  *      Handle the ACK, by tunneling any necessary reply
383                  *      VP's back to the client.
384                  */
385                 if (vp) {
386                         vp2eap(tls_session, vp);
387                         pairfree(&vp);
388                 }
389
390                 rcode = RLM_MODULE_HANDLED;
391                 break;
392
393         default:
394                 DEBUG2("  PEAP: Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);
395                 rcode = RLM_MODULE_REJECT;
396                 break;
397         }
398
399         return rcode;
400 }
401
402
403 /*
404  *      Do post-proxy processing,
405  */
406 static int eappeap_postproxy(EAP_HANDLER *handler, void *data)
407 {
408         int rcode;
409         tls_session_t *tls_session = (tls_session_t *) data;
410         REQUEST *fake;
411
412         DEBUG2("  PEAP: Passing reply from proxy back into the tunnel.");
413
414         /*
415          *      If there was a fake request associated with the proxied
416          *      request, do more processing of it.
417          */
418         fake = (REQUEST *) request_data_get(handler->request,
419                                             handler->request->proxy,
420                                             REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK);
421
422         /*
423          *      Do the callback, if it exists, and if it was a success.
424          */
425         if (fake && (handler->request->proxy_reply->code == PW_AUTHENTICATION_ACK)) {
426                 VALUE_PAIR *vp;
427                 REQUEST *request = handler->request;
428                 peap_tunnel_t *t = tls_session->opaque;
429
430                 t->home_access_accept = TRUE;
431
432                 /*
433                  *      Terrible hacks.
434                  */
435                 rad_assert(fake->packet == NULL);
436                 fake->packet = request->proxy;
437                 request->proxy = NULL;
438
439                 rad_assert(fake->reply == NULL);
440                 fake->reply = request->proxy_reply;
441                 request->proxy_reply = NULL;
442
443                 /*
444                  *      Perform a post-auth stage, which will get the EAP
445                  *      handler, too...
446                  */
447                 fake->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
448                 DEBUG2("  PEAP: Passing reply back for EAP-MS-CHAP-V2 %p %d",
449                        fake, fake->reply->code);
450                 rcode = module_post_proxy(0, fake);
451
452                 /*
453                  *      FIXME: If rcode returns fail, do something
454                  *      intelligent...
455                  */
456                 DEBUG2("  POST-PROXY %d", rcode);
457                 rcode = rad_postauth(fake);
458                 DEBUG2("  POST-AUTH %d", rcode);
459
460 #ifndef NDEBUG
461                 if (debug_flag > 0) {
462                         printf("  PEAP: Final reply from tunneled session code %d\n",
463                                fake->reply->code);
464
465                         for (vp = fake->reply->vps; vp != NULL; vp = vp->next) {
466                                 putchar('\t');vp_print(stdout, vp);putchar('\n');
467                         }
468                 }
469 #endif
470
471                 /*
472                  *      Terrible hacks.
473                  */
474                 request->proxy = fake->packet;
475                 fake->packet = NULL;
476                 request->proxy_reply = fake->reply;
477                 fake->reply = NULL;
478
479                 /*
480                  *      And we're done with this request.
481                  */
482
483                 switch (rcode) {
484                 case RLM_MODULE_FAIL:
485                         request_free(&fake);
486                         eaptls_fail(handler->eap_ds, 0);
487                         return 0;
488                         break;
489
490                 default:  /* Don't Do Anything */
491                         DEBUG2(" PEAP: Got reply %d",
492                                request->proxy_reply->code);
493                         break;
494                 }
495         }
496         request_free(&fake);    /* robust if fake == NULL */
497
498         /*
499          *      If there was no EAP-Message in the reply packet, then
500          *      we know that we're supposed to re-run the "authenticate"
501          *      stage, in order to get the right kind of handling...
502          */
503
504         /*
505          *      Process the reply from the home server.
506          */
507
508         rcode = process_reply(handler, tls_session, handler->request,
509                               handler->request->proxy_reply);
510
511         /*
512          *      The proxy code uses the reply from the home server as
513          *      the basis for the reply to the NAS.  We don't want that,
514          *      so we toss it, after we've had our way with it.
515          */
516         pairfree(&handler->request->proxy_reply->vps);
517
518         switch (rcode) {
519         case RLM_MODULE_REJECT:
520                 DEBUG2("  PEAP: Reply was rejected");
521                 eaptls_fail(handler->eap_ds, 0);
522                 return 0;
523
524         case RLM_MODULE_HANDLED:
525                 DEBUG2("  PEAP: Reply was handled");
526                 eaptls_request(handler->eap_ds, tls_session);
527                 return 1;
528
529         case RLM_MODULE_OK:
530                 DEBUG2("  PEAP: Reply was OK");
531                 eaptls_success(handler->eap_ds, 0);
532                 eaptls_gen_mppe_keys(&handler->request->reply->vps,
533                                      tls_session->ssl,
534                                      "client EAP encryption");
535                 return 1;
536
537         default:
538                 DEBUG2("  PEAP: Reply was unknown.");
539                 break;
540         }
541
542         eaptls_fail(handler->eap_ds, 0);
543         return 0;
544 }
545
546 /*
547  *      Free a request.
548  */
549 static void my_request_free(void *data)
550 {
551         REQUEST *request = (REQUEST *)data;
552
553         request_free(&request);
554 }
555
556
557 /*
558  *      Process the pseudo-EAP contents of the tunneled data.
559  */
560 int eappeap_process(EAP_HANDLER *handler, tls_session_t *tls_session)
561 {
562         int err;
563         peap_tunnel_t *t = tls_session->opaque;
564         REQUEST *fake;
565         VALUE_PAIR *vp;
566         int rcode = RLM_MODULE_REJECT;
567         const uint8_t   *data;
568         unsigned int data_len;
569 #ifndef NDEBUG
570         size_t i;
571 #endif
572
573         REQUEST *request = handler->request;
574         EAP_DS *eap_ds = handler->eap_ds;
575
576         /*
577          *      FIXME: if the SSL session says "want read", or
578          *      similar, leave the data in the clean_out buffer.  This
579          *      lets the application data be sent across multiple
580          *      fragments.
581          */
582         err = tls_handshake_recv(tls_session);
583         if (!err) {
584                 DEBUG2(" rlm_eap_peap: Failed in SSL");
585                 return RLM_MODULE_REJECT;
586         }
587
588         /*
589          *      Just look at the buffer directly, without doing
590          *      record_minus.
591          */
592         data_len = tls_session->clean_out.used;
593         data = tls_session->clean_out.data;
594
595 #ifndef NDEBUG
596         if (debug_flag > 2) {
597                 for (i = 0; i < data_len; i++) {
598                         if ((i & 0x0f) == 0) printf("  PEAP tunnel data in %04x: ", i);
599
600                         printf("%02x ", data[i]);
601
602                         if ((i & 0x0f) == 0x0f) printf("\n");
603                 }
604                 if ((data_len & 0x0f) != 0) printf("\n");
605         }
606 #endif
607
608         if (!eapmessage_verify(data, data_len)) {
609                 return RLM_MODULE_REJECT;
610         }
611
612         DEBUG2("  rlm_eap_peap: Tunneled data is valid.");
613
614         /*
615          *      If we authenticated the user, then it's OK.
616          */
617         if (t->status == PEAP_STATUS_SENT_TLV_SUCCESS) {
618                 if (eappeap_check_tlv(data)) {
619                         DEBUG2("  rlm_eap_peap: Success");
620                         return RLM_MODULE_OK;
621                 }
622
623                 return RLM_MODULE_REJECT;
624
625         } else if (t->status == PEAP_STATUS_SENT_TLV_FAILURE) {
626                 DEBUG2("  rlm_eap_peap:  Had sent TLV failure.  User was rejected earlier in this session.");
627                 return RLM_MODULE_REJECT;
628         }
629
630         fake = request_alloc_fake(request);
631
632         rad_assert(fake->packet->vps == NULL);
633
634         fake->packet->vps = eap2vp(eap_ds, data, data_len);
635         if (!fake->packet->vps) {
636                 request_free(&fake);
637                 DEBUG2("  rlm_eap_peap: Unable to convert tunneled EAP packet to internal server data structures");
638                 return PW_AUTHENTICATION_REJECT;
639         }
640
641 #ifndef NDEBUG
642         if (debug_flag > 0) {
643           printf("  PEAP: Got tunneled EAP-Message\n");
644
645           for (vp = fake->packet->vps; vp != NULL; vp = vp->next) {
646             putchar('\t');vp_print(stdout, vp);putchar('\n');
647           }
648         }
649 #endif
650
651         /*
652          *      Tell the request that it's a fake one.
653          */
654         vp = pairmake("Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);
655         if (vp) {
656                 pairadd(&fake->packet->vps, vp);
657         }
658
659         /*
660          *      Update other items in the REQUEST data structure.
661          */
662         if (!t->username) {
663                 /*
664                  *      There's no User-Name in the tunneled session,
665                  *      so we add one here, by pulling it out of the
666                  *      EAP-Identity packet.
667                  */
668                 if ((data[0] == PW_EAP_IDENTITY) && (data_len > 1)) {
669                         t->username = pairmake("User-Name", "", T_OP_EQ);
670                         rad_assert(t->username != NULL);
671
672                         memcpy(t->username->vp_strvalue, data + 1, data_len - 1);
673                         t->username->length = data_len - 1;
674                         t->username->vp_strvalue[t->username->length] = 0;
675                         DEBUG2("  PEAP: Got tunneled identity of %s", t->username->vp_strvalue);
676
677                         /*
678                          *      If there's a default EAP type,
679                          *      set it here.
680                          */
681                         if (t->default_eap_type != 0) {
682                                 DEBUG2("  PEAP: Setting default EAP type for tunneled EAP session.");
683                                 vp = pairmake("EAP-Type", "0", T_OP_EQ);
684                                 vp->vp_integer = t->default_eap_type;
685                                 pairadd(&fake->config_items, vp);
686                         }
687                 }
688         } /* else there WAS a t->username */
689
690         if (t->username) {
691                 vp = paircopy(t->username);
692                 pairadd(&fake->packet->vps, vp);
693                 fake->username = pairfind(fake->packet->vps, PW_USER_NAME);
694                 DEBUG2("  PEAP: Setting User-Name to %s",
695                        fake->username->vp_strvalue);
696         }
697
698         /*
699          *      Add the State attribute, too, if it exists.
700          */
701         if (t->state) {
702                 DEBUG2("  PEAP: Adding old state with %02x %02x",
703                        t->state->vp_octets[0], t->state->vp_octets[1]);
704                 vp = paircopy(t->state);
705                 if (vp) pairadd(&fake->packet->vps, vp);
706         }
707
708         /*
709          *      If this is set, we copy SOME of the request attributes
710          *      from outside of the tunnel to inside of the tunnel.
711          *
712          *      We copy ONLY those attributes which do NOT already
713          *      exist in the tunneled request.
714          *
715          *      This code is copied from ../rlm_eap_ttls/ttls.c
716          */
717         if (t->copy_request_to_tunnel) {
718                 VALUE_PAIR *copy;
719
720                 for (vp = request->packet->vps; vp != NULL; vp = vp->next) {
721                         /*
722                          *      The attribute is a server-side thingy,
723                          *      don't copy it.
724                          */
725                         if ((vp->attribute > 255) &&
726                             (((vp->attribute >> 16) & 0xffff) == 0)) {
727                                 continue;
728                         }
729
730                         /*
731                          *      The outside attribute is already in the
732                          *      tunnel, don't copy it.
733                          *
734                          *      This works for BOTH attributes which
735                          *      are originally in the tunneled request,
736                          *      AND attributes which are copied there
737                          *      from below.
738                          */
739                         if (pairfind(fake->packet->vps, vp->attribute)) {
740                                 continue;
741                         }
742
743                         /*
744                          *      Some attributes are handled specially.
745                          */
746                         switch (vp->attribute) {
747                                 /*
748                                  *      NEVER copy Message-Authenticator,
749                                  *      EAP-Message, or State.  They're
750                                  *      only for outside of the tunnel.
751                                  */
752                         case PW_USER_NAME:
753                         case PW_USER_PASSWORD:
754                         case PW_CHAP_PASSWORD:
755                         case PW_CHAP_CHALLENGE:
756                         case PW_PROXY_STATE:
757                         case PW_MESSAGE_AUTHENTICATOR:
758                         case PW_EAP_MESSAGE:
759                         case PW_STATE:
760                                 continue;
761                                 break;
762
763                                 /*
764                                  *      By default, copy it over.
765                                  */
766                         default:
767                                 break;
768                         }
769
770                         /*
771                          *      Don't copy from the head, we've already
772                          *      checked it.
773                          */
774                         copy = paircopy2(vp, vp->attribute);
775                         pairadd(&fake->packet->vps, copy);
776                 }
777         }
778
779         if ((vp = pairfind(request->config_items, PW_VIRTUAL_SERVER)) != NULL) {
780                 fake->server = vp->vp_strvalue;
781
782         } else if (t->virtual_server) {
783                 fake->server = t->virtual_server;
784
785         } /* else fake->server == request->server */
786
787 #ifndef NDEBUG
788         if (debug_flag > 0) {
789                 printf("  PEAP: Sending tunneled request\n");
790
791                 for (vp = fake->packet->vps; vp != NULL; vp = vp->next) {
792                         putchar('\t');vp_print(stdout, vp);putchar('\n');
793                 }
794
795                 printf("server %s {\n", fake->server);
796         }
797 #endif
798
799         /*
800          *      Call authentication recursively, which will
801          *      do PAP, CHAP, MS-CHAP, etc.
802          */
803         rad_authenticate(fake);
804
805         /*
806          *      Note that we don't do *anything* with the reply
807          *      attributes.
808          */
809 #ifndef NDEBUG
810         if (debug_flag > 0) {
811                 printf("} # server %s\n", fake->server);
812
813                 printf("  PEAP: Got tunneled reply RADIUS code %d\n",
814                  fake->reply->code);
815
816                 for (vp = fake->reply->vps; vp != NULL; vp = vp->next) {
817                         putchar('\t');vp_print(stdout, vp);putchar('\n');
818                 }
819         }
820 #endif
821
822         /*
823          *      Decide what to do with the reply.
824          */
825         switch (fake->reply->code) {
826         case 0:                 /* No reply code, must be proxied... */
827                 vp = pairfind(fake->config_items, PW_PROXY_TO_REALM);
828
829                 if (vp) {
830                         eap_tunnel_data_t *tunnel;
831
832                         /*
833                          *      The tunneled request was NOT handled,
834                          *      it has to be proxied.  This means that
835                          *      the "authenticate" stage was never
836                          *      performed.
837                          *
838                          *      If we are told to NOT proxy the
839                          *      tunneled request as EAP, then this
840                          *      means that we've got to decode it,
841                          *      which means that we MUST run the
842                          *      "authenticate" portion by hand, here.
843                          *
844                          *      Once the tunneled EAP session is ALMOST
845                          *      done, THEN we proxy it...
846                          */
847                         if (!t->proxy_tunneled_request_as_eap) {
848                                 fake->options |= RAD_REQUEST_OPTION_PROXY_EAP;
849
850                                 /*
851                                  *      Hmm... should we check for
852                                  *      Auth-Type & EAP-Message here?
853                                  */
854
855
856                                 /*
857                                  *      Run the EAP authentication.
858                                  */
859                                 DEBUG2("  PEAP: Calling authenticate in order to initiate tunneled EAP session.");
860                                 rcode = module_authenticate(PW_AUTHTYPE_EAP, fake);
861                                 if (rcode == RLM_MODULE_OK) {
862                                         /*
863                                          *      Authentication succeeded! Rah!
864                                          */
865                                         fake->reply->code = PW_AUTHENTICATION_ACK;
866                                         goto do_process;
867                                 }
868
869                                 if (rcode != RLM_MODULE_HANDLED) {
870                                         DEBUG2("  PEAP: Can't handle the return code %d", rcode);
871                                         rcode = RLM_MODULE_REJECT;
872                                         goto done;
873                                 }
874
875                                 /*
876                                  *      The module decided it wasn't
877                                  *      done.  Handle it like normal.
878                                  */
879                                 if ((fake->options & RAD_REQUEST_OPTION_PROXY_EAP) == 0) {
880                                         DEBUG2("    PEAP: Cancelling proxy to realm %s until the tunneled EAP session has been established", vp->vp_strvalue);
881                                         goto do_process;
882                                 }
883
884                                 /*
885                                  *      The module has decoded the
886                                  *      EAP-Message into another set
887                                  *      of attributes.
888                                  */
889                                 pairdelete(&fake->packet->vps,
890                                            PW_EAP_MESSAGE);
891                         }
892
893                         DEBUG2("  PEAP: Tunneled authentication will be proxied to %s", vp->vp_strvalue);
894
895                         /*
896                          *      Tell the original request that it's going
897                          *      to be proxied.
898                          */
899                         pairmove2(&(request->config_items),
900                                   &(fake->config_items),
901                                   PW_PROXY_TO_REALM);
902
903                         /*
904                          *      Seed the proxy packet with the
905                          *      tunneled request.
906                          */
907                         rad_assert(request->proxy == NULL);
908                         request->proxy = fake->packet;
909                         fake->packet = NULL;
910                         rad_free(&fake->reply);
911                         fake->reply = NULL;
912
913                         /*
914                          *      Set up the callbacks for the tunnel
915                          */
916                         tunnel = rad_malloc(sizeof(*tunnel));
917                         memset(tunnel, 0, sizeof(*tunnel));
918
919                         tunnel->tls_session = tls_session;
920                         tunnel->callback = eappeap_postproxy;
921
922                         /*
923                          *      Associate the callback with the request.
924                          */
925                         rcode = request_data_add(request,
926                                                  request->proxy,
927                                                  REQUEST_DATA_EAP_TUNNEL_CALLBACK,
928                                                  tunnel, free);
929                         rad_assert(rcode == 0);
930
931                         /*
932                          *      We're not proxying it as EAP, so we've got
933                          *      to do the callback later.
934                          */
935                         if ((fake->options & RAD_REQUEST_OPTION_PROXY_EAP) != 0) {
936                                 DEBUG2("  PEAP: Remembering to do EAP-MS-CHAP-V2 post-proxy.");
937
938                                 /*
939                                  *      rlm_eap.c has taken care of associating
940                                  *      the handler with the fake request.
941                                  *
942                                  *      So we associate the fake request with
943                                  *      this request.
944                                  */
945                                 rcode = request_data_add(request,
946                                                          request->proxy,
947                                                          REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK,
948                                                          fake, my_request_free);
949                                 rad_assert(rcode == 0);
950
951                                 /*
952                                  *      Do NOT free the fake request!
953                                  */
954                                 return RLM_MODULE_UPDATED;
955                         }
956
957                         /*
958                          *      Didn't authenticate the packet, but
959                          *      we're proxying it.
960                          */
961                         rcode = RLM_MODULE_UPDATED;
962
963                 } else {
964                         DEBUG2("  PEAP: Unknown RADIUS packet type %d: rejecting tunneled user", fake->reply->code);
965                         rcode = RLM_MODULE_REJECT;
966                 }
967                 break;
968
969         default:
970         do_process:
971                 rcode = process_reply(handler, tls_session, request,
972                                       fake->reply);
973                 break;
974         }
975
976  done:
977         request_free(&fake);
978
979         return rcode;
980 }