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