1/*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * eap.c - Extensible Authentication Protocol.
25 *
26 * Redistribution and use in source and binary forms are permitted
27 * provided that the above copyright notice and this paragraph are
28 * duplicated in all such forms and that any documentation,
29 * advertising materials, and other materials related to such
30 * distribution and use acknowledge that the software was developed
31 * by Gregory M. Christy.  The name of the author may not be used to
32 * endorse or promote products derived from this software without
33 * specific prior written permission.
34 *
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
36 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
37 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
38 */
39
40#define RCSID	"$Id: eap.c,v 1.25 2005/12/13 06:30:15 lindak Exp $"
41
42#include <stdio.h>
43#include <string.h>
44#include <stdlib.h>
45#include <sys/types.h>
46#include <sys/time.h>
47#include <pthread.h>
48#include <unistd.h>
49
50#include "pppd.h"
51#include "eap.h"
52#include "fsm.h"
53#include "lcp.h"
54#include "chap_ms.h" // for mppe keys
55
56#ifndef lint
57static const char rcsid[] = RCSID;
58#endif
59
60
61static int eaploadplugin(char **argv);
62int sys_eaploadplugin(char *arg, eap_ext *eap);
63
64/*
65 * Command-line options.
66 */
67static option_t eap_option_list[] = {
68    { "eap-restart", o_int, &eap[0].timeouttime,
69      "Set timeout for EAP" },
70    { "eap-max-challenge", o_int, &eap[0].max_transmits,
71      "Set max #xmits for challenge" },
72    { "eap-interval", o_int, &eap[0].req_interval,
73      "Set interval for rechallenge" },
74    { "eapplugin", o_special, (void *)eaploadplugin,
75      "Load an eap plug-in module into pppd", OPT_PRIV | OPT_A2LIST },
76    { NULL }
77};
78
79/*
80 * Protocol entry points.
81 */
82static void EapInit __P((int));
83static void EapLowerUp __P((int));
84static void EapLowerDown __P((int));
85static void EapInput __P((int, u_char *, int));
86static void EapProtocolReject __P((int));
87static int  EapPrintPkt __P((u_char *, int,
88			      void (*) __P((void *, char *, ...)), void *));
89
90struct protent eap_protent = {
91    PPP_EAP,
92    EapInit,
93    EapInput,
94    EapProtocolReject,
95    EapLowerUp,
96    EapLowerDown,
97    NULL,
98    NULL,
99    EapPrintPkt,
100    NULL,
101    1,
102    "EAP",
103    NULL,
104    eap_option_list,
105    NULL,
106    NULL,
107    NULL,
108#ifdef __APPLE__
109    NULL,
110    NULL,
111    NULL,
112    NULL
113#endif
114};
115
116eap_state eap[NUM_PPP];		/* EAP state; one for each unit */
117
118eap_ext *eap_extensions = NULL;	/* eap extensions list */
119
120static void EapChallengeTimeout __P((void *));
121static void EapReceiveRequest __P((eap_state *, u_char *, int, u_char *, int, int));
122static void EapRechallenge __P((void *));
123static void EapReceiveResponse __P((eap_state *, u_char *, int, u_char *, int, int));
124static void EapReceiveSuccess __P((eap_state *, u_char *, int, u_char *, int, int));
125static void EapReceiveFailure __P((eap_state *, u_char *, int, u_char *, int, int));
126static void EapSendIdentityRequest __P((eap_state *));
127static eap_ext * EapSupportedType(int type);
128static int EAPServerProcess(eap_state *, u_int16_t, u_char *, int);
129static int EAPClientProcess(eap_state *, u_int16_t, u_char *, int);
130static void EAPClientAction(eap_state *);
131static void EAPServerAction(eap_state *);
132static void EAPInput_fd(void);
133
134
135/*
136 * EapInit - Initialize a EAP unit.
137 */
138static void
139EapInit(unit)
140    int unit;
141{
142    eap_state *cstate = &eap[unit];
143
144    BZERO(cstate, sizeof(*cstate));
145    cstate->unit = unit;
146    cstate->clientstate = EAPCS_INITIAL;
147    cstate->serverstate = EAPSS_INITIAL;
148    cstate->timeouttime = EAP_DEFTIMEOUT;
149    cstate->max_transmits = EAP_DEFTRANSMITS;
150    cstate->client_ext_ui_fds[0] = -1;
151    cstate->client_ext_ui_fds[1] = -1;
152}
153
154
155/*
156 * EapAuthWithPeer - Authenticate us with our peer (start client).
157 *
158 */
159void
160EapAuthWithPeer(unit, our_name)
161    int unit;
162    char *our_name;
163{
164    eap_state *cstate = &eap[unit];
165
166
167	if (username[0] == 0) {
168		/*
169			no identity, get it from a plugin
170		*/
171
172		eap_ext 	*eap;
173
174		for (eap = eap_extensions; eap; eap = eap->next) {
175		   if (eap->identity
176				&& (eap->identity(username, sizeof(username)) == EAP_NO_ERROR))
177				break;
178		}
179	}
180
181    cstate->our_identity = username;
182    cstate->username = username;
183    cstate->password = passwd;
184
185    if (cstate->clientstate == EAPCS_INITIAL ||
186	cstate->clientstate == EAPCS_PENDING) {
187	/* lower layer isn't up - wait until later */
188	cstate->clientstate = EAPCS_PENDING;
189	return;
190    }
191
192    /*
193     * We get here as a result of LCP coming up.
194     * So even if EAP was open before, we will
195     * have to re-authenticate ourselves.
196     */
197    cstate->clientstate = EAPCS_LISTEN;
198}
199
200
201/*
202 * EapAuthPeer - Authenticate our peer (start server).
203 */
204void
205EapAuthPeer(unit, our_name)
206    int unit;
207    char *our_name;
208{
209    eap_state *cstate = &eap[unit];
210
211    cstate->our_identity = user;
212    cstate->username = 0;
213    cstate->password = 0;
214
215    cstate->req_type = EAP_TYPE_IDENTITY;
216    cstate->req_transmits = 0;
217    cstate->req_id = 1;
218
219    if (cstate->serverstate == EAPSS_INITIAL ||
220	cstate->serverstate == EAPSS_PENDING) {
221	/* lower layer isn't up - wait until later */
222	cstate->serverstate = EAPSS_PENDING;
223	return;
224    }
225
226    EapSendIdentityRequest(cstate);
227    cstate->serverstate = EAPSS_INITIAL_CHAL;
228}
229
230
231/*
232 * EapChallengeTimeout - Timeout expired on sending challenge.
233 */
234static void
235EapChallengeTimeout(arg)
236    void *arg;
237{
238    eap_state *cstate = (eap_state *) arg;
239
240    /* if we aren't sending challenges, don't worry.  then again we */
241    /* probably shouldn't be here either */
242    if (cstate->serverstate != EAPSS_INITIAL_CHAL &&
243	cstate->serverstate != EAPSS_RECHALLENGE)
244	return;
245
246    if (cstate->req_transmits >= cstate->max_transmits) {
247	/* give up on peer */
248	error("Peer failed to respond to EAP challenge");
249	cstate->serverstate = EAPSS_BADAUTH;
250	auth_peer_fail(cstate->unit, PPP_EAP);
251	return;
252    }
253
254    if (cstate->req_type == EAP_TYPE_IDENTITY)
255        EapSendIdentityRequest(cstate);		/* Re-send challenge */
256    else
257        EAPServerProcess(cstate, EAP_NOTIFICATION_TIMEOUT, 0, 0);
258}
259
260
261/*
262 * EapRechallenge - Time to challenge the peer again.
263 */
264static void
265EapRechallenge(arg)
266    void *arg;
267{
268    eap_state  	*cstate = (eap_state *) arg;
269
270    /* if we aren't sending a response, don't worry. */
271    if (cstate->serverstate != EAPSS_OPEN)
272	return;
273
274    cstate->req_id++;
275    cstate->req_transmits = 0;
276
277    EAPServerProcess(cstate, EAP_NOTIFICATION_RESTART, 0, 0);
278
279    cstate->serverstate = EAPSS_RECHALLENGE;
280}
281
282/*
283 * EapLostSuccess - EAP success has been lost.
284 *
285 * Simulate an EAP success packet .
286 */
287void
288EapLostSuccess(unit)
289    int unit;
290{
291    eap_state *cstate = &eap[unit];
292    u_char inpacket[EAP_HEADERLEN];
293	u_char *inp = inpacket;
294
295    PUTCHAR(EAP_SUCCESS, inp);		/* simulate success */
296    PUTCHAR(cstate->resp_id, inp);  /* id must match the last response we sent */
297    PUTSHORT(EAP_HEADERLEN, inp);
298
299	EapReceiveSuccess(cstate, inpacket, EAP_HEADERLEN, inp, cstate->resp_id, 0);
300}
301
302/*
303 * EapLostFailure - EAP failure has been lost.
304 *
305 * Simulate an EAP failure packet .
306 */
307void
308EapLostFailure(unit)
309    int unit;
310{
311    eap_state *cstate = &eap[unit];
312    u_char inpacket[EAP_HEADERLEN];
313	u_char *inp = inpacket;
314
315    PUTCHAR(EAP_FAILURE, inp);		/* simulate failure */
316    PUTCHAR(cstate->resp_id, inp);  /* id must match the last response we sent */
317    PUTSHORT(EAP_HEADERLEN, inp);
318
319	EapReceiveFailure(cstate, inpacket, EAP_HEADERLEN, inp, cstate->resp_id, 0);
320}
321
322/*
323 * EapLowerUp - The lower layer is up.
324 *
325 * Start up if we have pending requests.
326 */
327static void
328EapLowerUp(unit)
329    int unit;
330{
331    eap_state *cstate = &eap[unit];
332
333    if (cstate->clientstate == EAPCS_INITIAL)
334	cstate->clientstate = EAPCS_CLOSED;
335    else if (cstate->clientstate == EAPCS_PENDING)
336	cstate->clientstate = EAPCS_LISTEN;
337
338    if (cstate->serverstate == EAPSS_INITIAL)
339	cstate->serverstate = EAPSS_CLOSED;
340    else if (cstate->serverstate == EAPSS_PENDING) {
341        EapSendIdentityRequest(cstate);
342	cstate->serverstate = EAPSS_INITIAL_CHAL;
343    }
344}
345
346
347/*
348 * EapLowerDown - The lower layer is down.
349 *
350 * Cancel all timeouts.
351 */
352static void
353EapLowerDown(unit)
354    int unit;
355{
356    eap_state *cstate = &eap[unit];
357
358    /* Timeout(s) pending?  Cancel if so. */
359    if (cstate->serverstate == EAPSS_INITIAL_CHAL ||
360	cstate->serverstate == EAPSS_RECHALLENGE)
361	UNTIMEOUT(EapChallengeTimeout, cstate);
362    else if (cstate->serverstate == EAPSS_OPEN
363	     && cstate->req_interval != 0)
364	UNTIMEOUT(EapRechallenge, cstate);
365
366    cstate->clientstate = EAPCS_INITIAL;
367    cstate->serverstate = EAPSS_INITIAL;
368
369    if (cstate->client_ext) {
370        cstate->client_ext->dispose(cstate->client_ext_ctx);
371        free (cstate->client_ext_input);
372        free (cstate->client_ext_output);
373        cstate->client_ext = 0;
374        cstate->client_ext_ctx = 0;
375        cstate->client_ext_input = 0;
376        cstate->client_ext_output = 0;
377    }
378
379    if (cstate->server_ext) {
380        cstate->server_ext->dispose(cstate->server_ext_ctx);
381        free (cstate->server_ext_input);
382        free (cstate->server_ext_output);
383        cstate->server_ext = 0;
384        cstate->server_ext_ctx = 0;
385        cstate->server_ext_input = 0;
386        cstate->server_ext_output = 0;
387    }
388}
389
390
391/*
392 * EapProtocolReject - Peer doesn't grok EAP.
393 */
394static void
395EapProtocolReject(unit)
396    int unit;
397{
398    eap_state *cstate = &eap[unit];
399
400    if (cstate->serverstate != EAPSS_INITIAL &&
401	cstate->serverstate != EAPSS_CLOSED)
402	auth_peer_fail(unit, PPP_EAP);
403    if (cstate->clientstate != EAPCS_INITIAL &&
404	cstate->clientstate != EAPCS_CLOSED)
405	auth_withpeer_fail(unit, PPP_EAP);
406    EapLowerDown(unit);		/* shutdown eap */
407}
408
409/*
410 * EapInput - Input EAP packet.
411 */
412static void
413EapInput(unit, inpacket, packet_len)
414    int unit;
415    u_char *inpacket;
416    int packet_len;
417{
418    eap_state *cstate = &eap[unit];
419    u_char *inp;
420    u_char code, id;
421    int len;
422
423    /*
424     * Parse header (code, id and length).
425     * If packet too short, drop it.
426     */
427    inp = inpacket;
428    if (packet_len < EAP_HEADERLEN) {
429	EAPDEBUG(("EapInput: rcvd short header."));
430	return;
431    }
432    GETCHAR(code, inp);
433    GETCHAR(id, inp);
434    GETSHORT(len, inp);
435    if (len < EAP_HEADERLEN) {
436	EAPDEBUG(("EapInput: rcvd illegal length."));
437	return;
438    }
439    if (len > packet_len) {
440	EAPDEBUG(("EapInput: rcvd short packet."));
441	return;
442    }
443    len -= EAP_HEADERLEN;
444
445    /*
446     * Action depends on code (as in fact it usually does :-).
447     */
448   switch (code) {
449    case EAP_REQUEST:
450	EapReceiveRequest(cstate, inpacket, packet_len, inp, id, len);
451	break;
452
453    case EAP_RESPONSE:
454	EapReceiveResponse(cstate, inpacket, packet_len, inp, id, len);
455	break;
456
457    case EAP_FAILURE:
458	EapReceiveFailure(cstate, inpacket, packet_len, inp, id, len);
459	break;
460
461    case EAP_SUCCESS:
462	EapReceiveSuccess(cstate, inpacket, packet_len, inp, id, len);
463	break;
464
465    default:				/* Need code reject? */
466	warning("Unknown EAP code (%d) received.", code);
467	break;
468    }
469}
470
471/*
472 * EapSendIdentityRequest - Send an Request for Identity.
473 */
474static void
475EapSendIdentityRequest(cstate)
476    eap_state *cstate;
477{
478    u_char *outp;
479    int outlen = 0;
480
481    outlen = EAP_HEADERLEN + sizeof (u_char);
482    outp = outpacket_buf;
483    MAKEHEADER(outp, PPP_EAP);		/* paste in a EAP header */
484    PUTCHAR(EAP_REQUEST, outp);
485    PUTCHAR(cstate->req_id, outp);
486    PUTSHORT(outlen, outp);
487    PUTCHAR(cstate->req_type, outp);
488
489    output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
490
491    TIMEOUT(EapChallengeTimeout, cstate, cstate->timeouttime);
492    ++cstate->req_transmits;
493}
494
495/*
496 * EAPAllowedAddr - check with the plugin if the address is OK.
497 */
498int
499EAPAllowedAddr(unit, addr)
500    int unit;
501    u_int32_t addr;
502{
503    // always say OK for now.
504    return 1;
505}
506
507/*
508 * EapExtAdd - add a new eap type handler.
509 */
510int
511EapExtAdd(eap_ext *newext)
512{
513    eap_ext *eap, *last;
514
515    for (last = eap = eap_extensions; eap; last = eap, eap = eap->next) {
516        if (eap->type == newext->type)
517            return 1; // already exists
518    }
519
520	if (last)
521		last->next = newext;
522	else
523		eap_extensions = newext;
524	newext->next = NULL;
525    return 0;
526}
527
528/*
529 * EapSupportedType - check if an eap type is supported with the specified flags.
530 */
531static
532eap_ext * EapSupportedType(int type)
533{
534    eap_ext 	*eap;
535    u_int32_t	flags = 0;
536
537
538    for (eap = eap_extensions; eap; eap = eap->next) {
539       if (eap->type == type
540            && (eap->flags & flags) == flags)
541            return eap;
542    }
543
544    return 0;
545}
546
547/*
548 * EapReceiveRequest - Receive Challenge and send Response.
549 */
550static void
551EapReceiveRequest(cstate, inpacket, packet_len, inp, id, len)
552    eap_state *cstate;
553    u_char *inpacket;
554    int packet_len;
555    u_char *inp;
556    int id;
557    int len;
558{
559    int req, err, outlen;
560    u_char *outp;
561    struct eap_ext	*eap;
562
563    if (cstate->clientstate == EAPCS_CLOSED ||
564	cstate->clientstate == EAPCS_PENDING) {
565	EAPDEBUG(("EapReceiveRequest: in state %d", cstate->clientstate));
566	return;
567    }
568
569    if (len < 1) {
570	EAPDEBUG(("EapReceiveRequest: rcvd short packet."));
571	return;
572    }
573
574    GETCHAR(req, inp);
575    len -= 1;
576
577    switch (req) {
578        case EAP_TYPE_IDENTITY:
579            outlen = EAP_HEADERLEN + sizeof(char) + strlen(cstate->our_identity);
580            outp = outpacket_buf;
581            MAKEHEADER(outp, PPP_EAP);
582            PUTCHAR(EAP_RESPONSE, outp);	/* we are a response */
583            PUTCHAR(id, outp);	/* copy id from request packet */
584            PUTSHORT(outlen, outp);	/* packet length */
585            PUTCHAR(req, outp);		/* copy type from request packet */
586            BCOPY(cstate->our_identity, outp, outlen - EAP_HEADERLEN - sizeof(char)); /* append the response */
587
588            /* send the packet */
589            output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
590            break;
591
592        case EAP_TYPE_NOTIFICATION:
593
594			/* print the remote message */
595			PRINTMSG(inp, len);
596
597            /* send an empty response */
598			outlen = EAP_HEADERLEN;
599            outp = outpacket_buf;
600            MAKEHEADER(outp, PPP_EAP);
601            PUTCHAR(EAP_RESPONSE, outp);	/* we are a response */
602            PUTCHAR(id, outp);	/* copy id from request packet */
603            PUTSHORT(outlen, outp);	/* packet length */
604            /* send the packet */
605            output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
606            break;
607
608        case EAP_TYPE_NAK:
609            break;
610
611        default:
612            if (cstate->client_ext) {
613                /* if a request was already received, check that we get the same type */
614                if (cstate->client_ext->type != req) {
615                    error("EAP received an unexpected request for type %d", req);
616                    break;
617                }
618            }
619            else {
620                /* first time, create client eap extension context */
621                eap = EapSupportedType(req);
622                if (eap == NULL) {
623					error("EAP refuse to authenticate using type %d", req);
624
625					/* send a NAK with the type we support */
626					if (eap_extensions) {
627						error("EAP send NAK requesting type %d", eap_extensions->type);
628						outlen = EAP_HEADERLEN + sizeof(char) + sizeof(char);
629						outp = outpacket_buf;
630						MAKEHEADER(outp, PPP_EAP);
631						PUTCHAR(EAP_RESPONSE, outp);	/* we are a response */
632						PUTCHAR(id, outp);	/* copy id from request packet */
633						PUTSHORT(outlen, outp);	/* packet length */
634						PUTCHAR(EAP_TYPE_NAK, outp);		/* type NAK */
635						PUTCHAR(eap_extensions->type, outp);		/* copy the type we prefer */
636
637						/* send the packet */
638						output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
639					}
640                    break;
641                }
642
643                /* init client context on first request */
644                /* we don't necessarily know peer_name at this point */
645                cstate->client_ext = eap;
646
647                cstate->client_ext_input = (EAP_Input *)malloc(sizeof(EAP_Input));
648                cstate->client_ext_output = (EAP_Output *)malloc(sizeof(EAP_Output));
649                if (cstate->client_ext_input == 0 || cstate->client_ext_output == 0)
650                    novm("Couldn't allocate memory for EAP Plugin data");
651
652                /* this part is initialized only once */
653                cstate->client_ext_input->size = sizeof(EAP_Input);
654                cstate->client_ext_output->size = sizeof(EAP_Output);
655                cstate->client_ext_input->mode = 0; // client mode
656                cstate->client_ext_input->initial_id = 0; // no sense in client mode
657                cstate->client_ext_input->mtu = netif_get_mtu(cstate->unit);
658                cstate->client_ext_input->identity = cstate->our_identity;
659                cstate->client_ext_input->username = cstate->username;
660                cstate->client_ext_input->password = cstate->password;
661                cstate->client_ext_input->log_debug = dbglog;
662                cstate->client_ext_input->log_error = error;
663
664                /* this part depends on the message */
665            	cstate->client_ext_input->notification = EAP_NOTIFICATION_NONE; // no notification in the init message
666                cstate->client_ext_input->data = cstate->client_ext->plugin; // bundle ref
667                cstate->client_ext_input->data_len = 0;
668
669                err = cstate->client_ext->init(cstate->client_ext_input, &cstate->client_ext_ctx);
670                if (err) {
671                    error("EAP cannot initialize plugin for %s (request type %d)", eap->name ? eap->name : "???", req);
672					auth_withpeer_fail(cstate->unit, PPP_EAP);
673                    break;
674                }
675            }
676
677            /* process the request */
678            EAPClientProcess(cstate, EAP_NOTIFICATION_PACKET, inpacket, packet_len);
679
680    }
681
682}
683
684/*
685 * EapReceiveResponse - Receive and process response.
686 */
687static void
688EapReceiveResponse(cstate, inpacket, packet_len,  inp, id, len)
689    eap_state *cstate;
690    u_char *inpacket;
691    int packet_len;
692    u_char *inp;
693    int id;
694    int len;
695{
696    u_char type, auth_type;
697    int  err;
698    eap_ext	*eap = NULL, *last_eap;
699
700    if (cstate->serverstate == EAPSS_CLOSED ||
701	cstate->serverstate == EAPSS_PENDING) {
702	EAPDEBUG(("EapReceiveResponse: in state %d", cstate->serverstate));
703	return;
704    }
705
706    if (id != cstate->req_id)
707	return;			/* doesn't match ID of last challenge */
708
709    if (len < 1) {
710	EAPDEBUG(("EapReceiveResponse: rcvd short packet."));
711	return;
712    }
713
714    GETCHAR(type, inp);		/* get type */
715    len -= 1;
716    if ((type != EAP_TYPE_NAK && cstate->req_type && type != cstate->req_type)
717		|| (type == EAP_TYPE_NAK && cstate->server_ext == 0)) {
718	EAPDEBUG(("EapReceiveResponse: type doesn't match our request."));
719	return;			/* doesn't match type of last challenge */
720    }
721
722    UNTIMEOUT(EapChallengeTimeout, cstate);
723
724    switch (type) {
725
726        case EAP_TYPE_IDENTITY:
727
728            if (len >= MAX_NAME_LENGTH)
729                len = MAX_NAME_LENGTH - 1;
730
731            BCOPY(inp, cstate->peer_identity, len);
732            cstate->peer_identity[len] = 0;
733
734            /* XXX : Lookup to find out the protocol to use based on identity */
735
736			/* use the first plugin available */
737			eap = eap_extensions;
738
739            if (eap == NULL) {
740                error("No EAP server protocol available");
741				cstate->serverstate = EAPSS_BADAUTH;
742				auth_peer_fail(cstate->unit, PPP_EAP);
743                break;
744            }
745
746			/* no break */
747
748        case EAP_TYPE_NAK:
749
750			if (type == EAP_TYPE_NAK) {
751
752				GETCHAR(auth_type, inp);		/* get authentication type */
753				len -= 1;
754
755				last_eap = cstate->server_ext;
756
757                /* check if we support the type desired by the client */
758                eap = EapSupportedType(auth_type);
759                if (eap == NULL && last_eap->type == 0) {
760					/* if we don't support the specfic type, but are currently doing type 0 (eap radius proxy)
761						then just process the NAK */
762					EAPServerProcess(cstate, EAP_NOTIFICATION_PACKET, inpacket, packet_len);
763					break;
764				}
765
766				/* free previous selected eap module */
767				cstate->server_ext->dispose(cstate->server_ext_ctx);
768				free (cstate->server_ext_input);
769				free (cstate->server_ext_output);
770				cstate->server_ext = 0;
771				cstate->server_ext_ctx = 0;
772				cstate->server_ext_input = 0;
773				cstate->server_ext_output = 0;
774
775				if (eap == NULL) {
776
777					/* if not supported, then use next in list */
778					eap = last_eap->next;
779					if (eap == NULL) {
780						error("Server and client disagree on EAP type");
781						cstate->serverstate = EAPSS_BADAUTH;
782						auth_peer_fail(cstate->unit, PPP_EAP);
783						break;
784					}
785                }
786			}
787
788            cstate->server_ext = eap;
789            cstate->req_type = eap->type;
790
791            cstate->server_ext_input = (EAP_Input *)malloc(sizeof(EAP_Input));
792            cstate->server_ext_output = (EAP_Output *)malloc(sizeof(EAP_Output));
793            if (cstate->server_ext_input == 0 || cstate->server_ext_output == 0)
794                novm("Couldn't allocate memory for EAP Plugin data");
795
796            /* this part is initialized only once */
797            cstate->server_ext_input->size = sizeof(EAP_Input);
798            cstate->server_ext_output->size = sizeof(EAP_Output);
799            cstate->server_ext_input->mode = 1; // server mode
800            cstate->server_ext_input->initial_id = cstate->req_id + 1;
801            cstate->server_ext_input->mtu = netif_get_mtu(cstate->unit);
802            cstate->server_ext_input->identity = cstate->peer_identity;
803            cstate->server_ext_input->username = 0; /* irrelevant in server mode */
804            cstate->server_ext_input->password = 0; /* irrelevant in server mode */
805            cstate->server_ext_input->log_debug = dbglog;
806            cstate->server_ext_input->log_error = error;
807
808            /* this part depends on the message */
809            cstate->server_ext_input->notification = EAP_NOTIFICATION_NONE; // no notification in the init message
810            cstate->server_ext_input->data = cstate->server_ext->plugin;
811            cstate->server_ext_input->data_len = 0;
812
813            err = cstate->server_ext->init(cstate->server_ext_input, &cstate->server_ext_ctx);
814            if (err) {
815                error("EAP cannot initialize plugin for %s (request type %d)", eap->name ? eap->name : "???", cstate->req_type);
816                break;
817            }
818
819            /* now, start conversation */
820            EAPServerProcess(cstate, EAP_NOTIFICATION_START, 0, 0);
821            break;
822
823        default:
824
825            EAPServerProcess(cstate, EAP_NOTIFICATION_PACKET, inpacket, packet_len);
826    }
827}
828
829/*
830 * EapReceiveSuccess - Receive Success
831 */
832static void
833EapReceiveSuccess(cstate, inpacket, packet_len, inp, id, len)
834    eap_state *cstate;
835    u_char *inpacket;
836    int packet_len;
837    u_char *inp;
838    u_char id;
839    int len;
840{
841
842    if (cstate->clientstate == EAPCS_OPEN)
843	/* presumably an answer to a duplicate response */
844	return;
845
846    EAPClientProcess(cstate, EAP_NOTIFICATION_PACKET, inpacket, packet_len);
847}
848
849
850/*
851 * EapReceiveFailure - Receive failure.
852 */
853static void
854EapReceiveFailure(cstate, inpacket, packet_len, inp, id, len)
855    eap_state *cstate;
856    u_char *inpacket;
857    int packet_len;
858    u_char *inp;
859    u_char id;
860    int len;
861{
862
863    EAPClientProcess(cstate, EAP_NOTIFICATION_PACKET, inpacket, packet_len);
864}
865
866/*
867 * EAPClientProcess - Process a packet in a client context.
868 */
869static int
870EAPClientProcess(eap_state *cstate, u_int16_t notification, u_char *inpacket, int packet_len)
871{
872    int err;
873
874    if (cstate->client_ext == 0)
875        /* ignore the request */
876    	return 0;
877
878    /* setup in and out structures */
879    cstate->client_ext_input->notification = notification;
880    cstate->client_ext_input->data = inpacket;
881    cstate->client_ext_input->data_len = packet_len;
882    cstate->client_ext_output->action = EAP_ACTION_NONE;
883    cstate->client_ext_output->data = 0;
884    cstate->client_ext_output->data_len = 0;
885    cstate->client_ext_output->username = 0;
886
887    err = cstate->client_ext->process(cstate->client_ext_ctx, cstate->client_ext_input, cstate->client_ext_output);
888    if (err) {
889        error("EAP error while processing packet for %s (request type %d, error %d)",
890                cstate->client_ext->name ? cstate->client_ext->name : "???", cstate->client_ext->type, err);
891        return -1;
892    }
893
894    EAPClientAction(cstate);
895    return 0;
896}
897
898/*
899 * EAPClientGetAttributes - get client specific attributes.
900 */
901static void
902EAPClientGetAttributes(cstate)
903    eap_state *cstate;
904{
905    EAP_Attribute attribute;
906    int err;
907    char *str;
908
909    /* let's see it we have mppe keys */
910    if (cstate->client_ext->attribute == 0)
911        return;
912
913    attribute.type = EAP_ATTRIBUTE_MPPE_SEND_KEY;
914    err = cstate->client_ext->attribute(cstate->client_ext_ctx, &attribute);
915    if (err) {
916        str = "MPPE_SEND_KEY";
917        goto bad;
918    }
919
920    bcopy(attribute.data, mppe_send_key, MIN(attribute.data_len, MPPE_MAX_KEY_LEN));
921
922    attribute.type = EAP_ATTRIBUTE_MPPE_RECV_KEY;
923    err = cstate->client_ext->attribute(cstate->client_ext_ctx, &attribute);
924    if (err) {
925        str = "MPPE_RECV_KEY";
926        goto bad;
927    }
928
929    bcopy(attribute.data, mppe_recv_key, MIN(attribute.data_len, MPPE_MAX_KEY_LEN));
930
931    return;
932
933bad:
934    dbglog("EAP plugin %s (type %d) does not have %s attribute",
935        cstate->client_ext->name ? cstate->client_ext->name : "???", cstate->client_ext->type, str);
936
937}
938
939/*
940 * EAPInput_fd - called when activity occurs on a file descriptor,
941 * so eap has a chance to test its file descriptors.
942 */
943void EAPInput_fd(void)
944{
945    int unit = 0;
946    eap_state *cstate = &eap[unit];
947    char	result;
948
949    if (cstate->client_ext_ui_fds[0] != -1 && is_ready_fd(cstate->client_ext_ui_fds[0])) {
950
951        result = 0;
952        read(cstate->client_ext_ui_fds[0], &result, 1);
953
954        wait_input_hook = 0;
955        remove_fd(cstate->client_ext_ui_fds[0]);
956        close(cstate->client_ext_ui_fds[0]);
957        close(cstate->client_ext_ui_fds[1]);
958        cstate->client_ext_ui_fds[0] = -1;
959        cstate->client_ext_ui_fds[1] = -1;
960
961        if (result == -1) {
962            error("EAP error while requesting user input for %s (request type %d)",
963                    cstate->client_ext->name ? cstate->client_ext->name : "???", cstate->client_ext->type);
964            return;
965        }
966
967        EAPClientProcess(cstate, EAP_NOTIFICATION_DATA_FROM_UI, cstate->client_ext_ui_data, cstate->client_ext_ui_data_len);
968    }
969}
970
971/*
972 * EAPClientUIThread - XXX User interface thread.
973 */
974void *EAPClientUIThread(void *arg)
975{
976    int 	unit = (uintptr_t)arg;
977    eap_state 	*cstate = &eap[unit];
978    char	result = -1;
979    int 	err;
980
981    if (pthread_detach(pthread_self()) == 0) {
982
983        if (cstate->client_ext->interactive_ui) {
984            err = cstate->client_ext->interactive_ui(cstate->client_ext_ui_data, cstate->client_ext_ui_data_len,
985                            &cstate->client_ext_ui_data, &cstate->client_ext_ui_data_len);
986            if (err == 0)
987                result = 0;
988        }
989    }
990
991    write(eap->client_ext_ui_fds[1], &result, 1);
992    return 0;
993}
994
995/*
996 * EAPClientInvokeUI - Perform the action in the client context.
997 */
998static int
999EAPClientInvokeUI(cstate)
1000    eap_state *cstate;
1001{
1002    if (pipe(cstate->client_ext_ui_fds) < 0) {
1003        error("EAP failed to create pipe for User Interface...\n");
1004        return -1;
1005    }
1006
1007    if (pthread_create(&cstate->client_ui_thread, NULL, EAPClientUIThread, (void*)(uintptr_t)cstate->unit)) {
1008        error("EAP failed to create thread for client User Interface...\n");
1009        close(cstate->client_ext_ui_fds[0]);
1010        close(cstate->client_ext_ui_fds[1]);
1011        return -1;
1012    }
1013
1014    wait_input_hook = EAPInput_fd;
1015    add_fd(cstate->client_ext_ui_fds[0]);
1016    return 0;
1017}
1018
1019/*
1020 * EAPClientAction - Perform the action in the client context.
1021 */
1022static void
1023EAPClientAction(cstate)
1024    eap_state *cstate;
1025{
1026    EAP_Output *eap_out = cstate->client_ext_output;
1027    u_char *outp;
1028
1029    switch (eap_out->action) {
1030        case EAP_ACTION_NONE:
1031            break;
1032
1033        case EAP_ACTION_SEND_WITH_TIMEOUT:
1034        case EAP_ACTION_SEND_AND_DONE:
1035            // irrelevant for client
1036            break;
1037
1038        case EAP_ACTION_SEND:
1039            if (eap_out->data == 0 ||
1040                eap_out->data_len < EAP_HEADERLEN ||
1041                eap_out->data_len > PPP_MRU) {
1042                error("EAP plugin tries to send a packet with with incorrect data");
1043                break;
1044            }
1045
1046            outp = outpacket_buf;
1047            MAKEHEADER(outp, PPP_EAP);		/* paste in a EAP header */
1048            BCOPY(eap_out->data, outp, eap_out->data_len);
1049
1050			cstate->resp_id = outp[1]; 	/* let's copy the id for future use */
1051
1052            if (cstate->client_ext->free)
1053                cstate->client_ext->free(cstate->client_ext_ctx, eap_out);
1054
1055            /* send the packet */
1056            output(cstate->unit, outpacket_buf, eap_out->data_len + PPP_HDRLEN);
1057            break;
1058
1059        case EAP_ACTION_INVOKE_UI:
1060            cstate->client_ext_ui_data = eap_out->data;
1061            cstate->client_ext_ui_data_len = eap_out->data_len;
1062            EAPClientInvokeUI(cstate);
1063            break;
1064
1065        case EAP_ACTION_ACCESS_GRANTED:
1066            EAPClientGetAttributes(cstate);
1067            cstate->clientstate = EAPCS_OPEN;
1068            auth_withpeer_success(cstate->unit, PPP_EAP, 0);
1069            break;
1070
1071        case EAP_ACTION_ACCESS_DENIED:
1072            error("EAP authentication failed");
1073            auth_withpeer_fail(cstate->unit, PPP_EAP);
1074            break;
1075
1076        case EAP_ACTION_CANCEL:
1077            auth_withpeer_cancelled(cstate->unit, PPP_EAP);
1078            break;
1079
1080    }
1081}
1082
1083/*
1084 * EAPServerProcess - Process a packet in a client context.
1085 */
1086static int
1087EAPServerProcess(eap_state *cstate, u_int16_t notification, u_char *inpacket, int packet_len)
1088{
1089    int err;
1090
1091    if (cstate->server_ext == 0)
1092        /* ignore the call */
1093    	return 0;
1094
1095    /* setup in and out structures */
1096    cstate->server_ext_input->notification = notification;
1097    cstate->server_ext_input->data = inpacket;
1098    cstate->server_ext_input->data_len = packet_len;
1099    cstate->server_ext_output->action = EAP_ACTION_NONE;
1100    cstate->server_ext_output->data = 0;
1101    cstate->server_ext_output->data_len = 0;
1102    cstate->server_ext_output->username = 0;
1103
1104    err = cstate->server_ext->process(cstate->server_ext_ctx, cstate->server_ext_input, cstate->server_ext_output);
1105    if (err) {
1106        error("EAP error while processing packet for %s (request type %d, error %d)",
1107                cstate->server_ext->name ? cstate->server_ext->name : "???", cstate->server_ext->type, err);
1108        return -1;
1109    }
1110
1111    EAPServerAction(cstate);
1112    return 0;
1113}
1114
1115/*
1116 * EAPServerGetAttributes - get server specific attributes.
1117 */
1118static void
1119EAPServerGetAttributes(cstate)
1120    eap_state *cstate;
1121{
1122    EAP_Attribute attribute;
1123    int err;
1124    char *str;
1125
1126    /* let's see it we have mppe keys */
1127    if (cstate->server_ext->attribute == 0)
1128        return;
1129
1130    attribute.type = EAP_ATTRIBUTE_MPPE_SEND_KEY;
1131    err = cstate->server_ext->attribute(cstate->server_ext_ctx, &attribute);
1132    if (err) {
1133        str = "MPPE_SEND_KEY";
1134        goto bad;
1135    }
1136
1137    bcopy(attribute.data, mppe_send_key, MIN(attribute.data_len, MPPE_MAX_KEY_LEN));
1138
1139    attribute.type = EAP_ATTRIBUTE_MPPE_RECV_KEY;
1140    err = cstate->server_ext->attribute(cstate->server_ext_ctx, &attribute);
1141    if (err) {
1142        str = "MPPE_RECV_KEY";
1143        goto bad;
1144    }
1145
1146    bcopy(attribute.data, mppe_recv_key, MIN(attribute.data_len, MPPE_MAX_KEY_LEN));
1147
1148    return;
1149
1150bad:
1151    dbglog("EAP plugin %s (type %d) does not have %s attribute",
1152        cstate->server_ext->name ? cstate->server_ext->name : "???", cstate->server_ext->type, str);
1153
1154}
1155
1156/*
1157 * EAPClientAction - Perform the action in the client context.
1158 */
1159static void
1160EAPServerAction(cstate)
1161    eap_state *cstate;
1162{
1163
1164    EAP_Output *eap_out = cstate->server_ext_output;
1165    u_char code, *outp;
1166    int old_state;
1167    char *name;
1168
1169    switch (eap_out->action) {
1170        case EAP_ACTION_NONE:
1171            break;
1172
1173        case EAP_ACTION_SEND_WITH_TIMEOUT:
1174        case EAP_ACTION_SEND_AND_DONE:
1175        case EAP_ACTION_SEND:
1176            if (eap_out->data == 0 ||
1177                eap_out->data_len < EAP_HEADERLEN ||
1178                eap_out->data_len > PPP_MRU) {
1179                error("EAP plugin tries to send a packet with with incorrect data");
1180                break;
1181            }
1182            outp = outpacket_buf;
1183            MAKEHEADER(outp, PPP_EAP);		/* paste in a EAP header */
1184            BCOPY(eap_out->data, outp, eap_out->data_len);
1185
1186            code = outp[0];
1187            cstate->req_transmits = 0;
1188            cstate->req_id = outp[1]; 	/* let's copy the id for future use */
1189
1190            if (cstate->server_ext->free)
1191                cstate->server_ext->free(cstate->server_ext_ctx, eap_out);
1192
1193            /* send the packet */
1194            output(cstate->unit, outpacket_buf, eap_out->data_len + PPP_HDRLEN);
1195
1196            if (eap_out->action == EAP_ACTION_SEND_WITH_TIMEOUT)
1197                TIMEOUT(EapChallengeTimeout, cstate, cstate->timeouttime);
1198            ++cstate->req_transmits;
1199
1200            if (eap_out->action == EAP_ACTION_SEND_AND_DONE) {
1201
1202                /*
1203                * If we have received a duplicate or bogus Response,
1204                * we have to send the same answer (Success/Failure)
1205                * as we did for the first Response we saw.
1206                * The packet we are sending is a result of this retransmission,
1207                * so nothing more to do.
1208                */
1209                if (cstate->serverstate == EAPSS_OPEN
1210                    || cstate->serverstate == EAPSS_BADAUTH)
1211                    break;
1212
1213                /*
1214                * the eap server plugin is done. Let's see what is the result code.
1215                * the plugin can return a username to override the identity
1216                */
1217                name = eap_out->username ? eap_out->username : cstate->peer_identity;
1218
1219                if (code == EAP_SUCCESS) {
1220                    UNTIMEOUT(EapChallengeTimeout, cstate);
1221                    old_state = cstate->serverstate;
1222                    cstate->serverstate = EAPSS_OPEN;
1223                    if (old_state == EAPSS_INITIAL_CHAL) {
1224                        EAPServerGetAttributes(cstate);
1225                        auth_peer_success(cstate->unit, PPP_EAP, 0, (u_char*)name, strlen(name));
1226                    }
1227                    if (cstate->req_interval != 0)
1228                        TIMEOUT(EapRechallenge, cstate, cstate->req_interval);
1229
1230                    notice("EAP peer authentication succeeded for %s", name);
1231                }
1232                else
1233                {
1234                    UNTIMEOUT(EapChallengeTimeout, cstate);
1235                    error("EAP peer authentication failed for remote host %s", name);
1236                    cstate->serverstate = EAPSS_BADAUTH;
1237                    auth_peer_fail(cstate->unit, PPP_EAP);
1238                }
1239            }
1240            break;
1241
1242        case EAP_ACTION_INVOKE_UI:
1243        case EAP_ACTION_ACCESS_GRANTED:
1244        case EAP_ACTION_ACCESS_DENIED:
1245        case EAP_ACTION_CANCEL:
1246            // no used for server
1247            break;
1248    }
1249}
1250
1251/*
1252 * EapPrintPkt - print the contents of a EAP packet.
1253 */
1254static char *EapCodenames[] = {
1255    "Request", "Response", "Success", "Failure"
1256};
1257static char *EapRequestnames[] = {
1258    "Identity", "Notification", "Nak"
1259};
1260
1261static int
1262EapPrintPkt(p, plen, printer, arg)
1263    u_char *p;
1264    int plen;
1265    void (*printer) __P((void *, char *, ...));
1266    void *arg;
1267{
1268    int code, id, len, req;
1269    int clen;
1270    u_char x;
1271    eap_ext	*eap;
1272
1273    if (plen < EAP_HEADERLEN)
1274	return 0;
1275    GETCHAR(code, p);
1276    GETCHAR(id, p);
1277    GETSHORT(len, p);
1278    if (len < EAP_HEADERLEN || len > plen)
1279	return 0;
1280
1281    if (code >= 1 && code <= sizeof(EapCodenames) / sizeof(char *))
1282	printer(arg, " %s", EapCodenames[code-1]);
1283    else
1284	printer(arg, " code=0x%x", code);
1285    printer(arg, " id=0x%x", id);
1286    len -= EAP_HEADERLEN;
1287    switch (code) {
1288    case EAP_REQUEST:
1289    case EAP_RESPONSE:
1290	if (len < 1)
1291	    break;
1292        GETCHAR(req, p);
1293        if (req >= 1 && req <= sizeof(EapRequestnames) / sizeof(char *))
1294            printer(arg, " %s ", EapRequestnames[req-1]);
1295        else if ((eap = EapSupportedType(req)))
1296            printer(arg, " %s ", eap->name ? eap->name : "???");
1297        else
1298            printer(arg, " type=0x%x ", req);
1299        len -= 1;
1300        if (len == 0)
1301            break;
1302        switch (req) {
1303            case EAP_TYPE_IDENTITY:
1304            case EAP_TYPE_NOTIFICATION:
1305                printer(arg, "<");
1306                print_string((char *)p, len, printer, arg);
1307                printer(arg, ">");
1308                break;
1309            default :
1310                eap = EapSupportedType(req);
1311                if (eap && eap->print_packet) {
1312                    eap->print_packet(printer, arg, code, (char*)p, len);
1313                }
1314                else {
1315                    printer(arg, "<");
1316                    clen = len;
1317                    for (; clen > 0; clen--) {
1318                        GETCHAR(x, p);
1319                        printer(arg, "%.2x", x);
1320                    }
1321                    printer(arg, ">");
1322                }
1323        }
1324	break;
1325    case EAP_FAILURE:
1326    case EAP_SUCCESS:
1327	printer(arg, " ");
1328	print_string((char *)p, len, printer, arg);
1329	break;
1330    default:
1331	for (clen = len; clen > 0; --clen) {
1332	    GETCHAR(x, p);
1333	    printer(arg, " %.2x", x);
1334	}
1335    }
1336
1337    return len + EAP_HEADERLEN + 1;
1338}
1339
1340/*
1341 * EapGetClientSecret - get the secret for a given name.
1342 */
1343int
1344EapGetClientSecret(void *cookie, u_char *our_name, u_char *peer_name, u_char *secret, int *secretlen)
1345{
1346    eap_state *cstate = (eap_state *)cookie;
1347
1348    /* get secret for authenticating ourselves with the specified host */
1349    if (!get_secret(cstate->unit, our_name, peer_name, secret, secretlen, 0)) {
1350        *secretlen = 0;		/* assume null secret if can't find one */
1351        warning("No EAP secret found for authenticating us to %s", peer_name);
1352        return 1;
1353    }
1354    return 0;
1355}
1356
1357/*
1358 * EapGetServerSecret - get the secret for a given name.
1359 */
1360int
1361EapGetServerSecret(void *cookie, u_char *our_name, u_char *peer_name, u_char *secret, int *secretlen)
1362{
1363    eap_state *cstate = (eap_state *)cookie;
1364
1365    /* get secret for authenticating ourselves with the specified host */
1366    if (!get_secret(cstate->unit, our_name, peer_name, secret, secretlen, 1)) {
1367        *secretlen = 0;		/* assume null secret if can't find one */
1368        warning("No EAP secret found for authenticating %s", peer_name);
1369        return 1;
1370    }
1371    return 0;
1372}
1373
1374/*
1375 * eaploadplugin - load the eap plugin
1376 */
1377static int
1378eaploadplugin(argv)
1379    char **argv;
1380{
1381    char *arg = *argv;
1382    int err;
1383    eap_ext *eap;
1384
1385    eap = (eap_ext *)malloc(sizeof(eap_ext));
1386    if (eap == 0)
1387        novm("Couldn't allocate memory for EAP plugin");
1388
1389	bzero(eap, sizeof(eap_ext));
1390
1391    err = sys_eaploadplugin(*argv, eap);
1392    if (err) {
1393	option_error("Couldn't load EAP plugin %s", arg);
1394		// continue without loading plugin
1395        return 1;
1396    }
1397
1398    if (eap->init == 0 || eap->dispose == 0 || eap->process == 0) {
1399	option_error("EAP plugin %s has no Init() Dispose() or Process() function", arg);
1400        return 0;
1401    }
1402
1403    if (EapSupportedType(eap->type)) {
1404	option_error("EAP plugin %s is trying to use an already loaded EAP type %d", arg, eap->type);
1405        return 0;
1406    }
1407
1408    EapExtAdd(eap);
1409    //info("Plugin %s loaded.", arg);
1410
1411    return 1;
1412}
1413
1414