/**
 * A client-side 802.1x implementation 
 *
 * This code is released under both the GPL version 2 and BSD licenses.
 * Either license may be used.  The respective licenses are found below.
 *
 * Copyright (C) 2002 Bryan D. Payne & Nick L. Petroni Jr.
 * All Rights Reserved
 *
 * --- GPL Version 2 License ---
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * --- BSD License ---
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  - All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *       This product includes software developed by the University of
 *       Maryland at College Park and its contributors.
 *  - Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*******************************************************************
 * The driver function for a Linux application layer EAPOL 
 * implementation
 * File: eap.c
 *
 * Authors: Chris.Hessing@utah.edu
 *
 * $Id: eap.c,v 1.85 2004/08/16 23:36:27 chessing Exp $
 * $Date: 2004/08/16 23:36:27 $
 * $Log: eap.c,v $
 * Revision 1.85  2004/08/16 23:36:27  chessing
 * Cosmetic fixes and trapping of an error that popped up.
 *
 * Revision 1.84  2004/08/13 04:20:00  chessing
 *
 * Accepted fork() patch from i3keba.  (Slightly modified version of patch.)
 *
 * Revision 1.83  2004/08/10 01:59:26  chessing
 *
 * Added support for the SNMP supplicant counters defined in the IEEE 802.1X-2001 document.
 *
 * Revision 1.82  2004/07/26 18:49:21  chessing
 * Added patches to fix the last couple of bitflag problems noted in bug 995523.
 *
 * Revision 1.81  2004/07/23 04:05:49  chessing
 * Fixed a segfault problem.  Started to add rtnetlink support.
 *
 * Revision 1.80  2004/07/19 02:43:16  chessing
 *
 * Changed things to get rid of Linux specific pieces in the interface_data struct. Fixed up EAP-SIM and EAP-AKA to skip AVPs that we don't support.  (We print a mesage, and move on.)  Added the --enable-radiator-test option to configure EAP-AKA to use the test vectors included with Radiator's AKA module.  (To use this mode, no SIM card is required, but the PCSC library is still needed to build.  Also, some errors will be displayed.)
 *
 * Revision 1.79  2004/07/15 04:15:35  chessing
 *
 * True/false int values are now bit flags in a byte.  PEAP now calls back in to functions from eap.c for phase 2 methods.  This allows for any phase 1 EAP type to work.  This resulted in some major changes the functions in eap.c, and in peap_phase2.c.  PEAP has been tested using both MS-CHAPv2, and EAP-MD5 as inner types.  More types need to be tested, and enabled.
 *
 * Revision 1.78  2004/06/15 03:35:19  chessing
 *
 * New updates including fixes to LEAP (keying now works with wireless) and adding EAP-AKA.
 *
 * Revision 1.77  2004/06/15 03:22:17  chessing
 *
 * XSupplicant Release 1.0
 *
 *
 *******************************************************************/

#include <netinet/in.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#include "snmp.h"
#include "frame_structs.h"
#include "xsup_debug.h"
#include "xsup_err.h"
#include "config.h"
#include "profile.h"
#include "eap.h"
#include "cmd_handler.h"
#include "interactive.h"

// Header files for auth types we know about.
#include "eap_types/md5/eapmd5.h"
#include "eap_types/tls/eaptls.h"
#include "eap_types/ttls/eapttls.h"
#include "eap_types/mschapv2/eapmschapv2.h"
#include "eap_types/peap/eappeap.h"
#include "eap_types/leap/eapleap.h"
#include "eap_types/otp/eapotp.h"

#ifdef EAP_SIM_ENABLE
#include "winscard.h"
#include "eap_types/sim/eapsim.h"
#include "eap_types/aka/eapaka.h"
#endif

struct eap_type_handler {
  int eap_auth_type;
  char *eapname;
  int (*eap_auth_setup)(struct generic_eap_data *);
  int (*eap_auth_handlers)(struct generic_eap_data *, u_char *, int, u_char *,
			   int*);
  int (*eap_auth_get_keys)(struct interface_data *);
  int (*eap_auth_failed)(struct generic_eap_data *);
  int (*eap_auth_cleanup)(struct generic_eap_data *);
};

struct eap_type_handler eaphandlers[] = {
  {EAP_TYPE_MD5, "EAP_MD5", eapmd5_setup, eapmd5_process, eapmd5_get_keys,
   eapmd5_failed, eapmd5_cleanup},
  {EAP_TYPE_TLS, "EAP_TLS", eaptls_setup, eaptls_process, eaptls_get_keys,
   eaptls_failed, eaptls_cleanup},
  {EAP_TYPE_TTLS, "EAP_TTLS", eapttls_setup, eapttls_process, eapttls_get_keys,
   eapttls_failed, eapttls_cleanup},
  {EAP_TYPE_MSCHAPV2, "EAP_MSCHAPV2", eapmschapv2_setup, eapmschapv2_process, 
   eapmschapv2_get_keys, eapmschapv2_failed, eapmschapv2_cleanup},
  {EAP_TYPE_PEAP, "EAP_PEAP", eappeap_setup, eappeap_process, eappeap_get_keys,
   eappeap_failed, eappeap_cleanup},
  {EAP_TYPE_LEAP, "EAP_LEAP", eapleap_setup, eapleap_process, eapleap_get_keys,
   eapleap_failed, eapleap_cleanup},
#ifdef EAP_SIM_ENABLE
  {EAP_TYPE_SIM, "EAP_SIM", eapsim_setup, eapsim_process, eapsim_get_keys, 
   eapsim_failed, eapsim_cleanup},
  {EAP_TYPE_AKA, "EAP_AKA", eapaka_setup, eapaka_process, eapaka_get_keys,
   eapaka_failed, eapaka_cleanup},
#endif
  {EAP_TYPE_OTP, "EAP_OTP", eapotp_setup, eapotp_process, eapotp_get_keys,
   NULL, eapotp_cleanup},
  {EAP_TYPE_GTC, "EAP_GTC", eapotp_setup, eapotp_process, eapotp_get_keys,
   NULL, eapotp_cleanup},
  {NO_EAP_AUTH, NULL, NULL, NULL, NULL, NULL, NULL}
};

/***************************************************
 *
 * Initalize anything needed for EAP.
 *
 ***************************************************/
void eap_init(struct interface_data *thisint)
{

}

/***************************************************
 *
 * Look through the EAP array, and see if we can find the index to the
 * EAP method in question.
 *
 ***************************************************/
int eap_find_type(int eap_type)
{
  int eapmethod;

  // Determine which authenticator in our array is the right one.
  eapmethod = 0;

  while ((eaphandlers[eapmethod].eap_auth_type != NO_EAP_AUTH) &&
	 (eaphandlers[eapmethod].eap_auth_type != eap_type))
    {
      eapmethod++;
    }
     
  if (eaphandlers[eapmethod].eap_auth_type == NO_EAP_AUTH) 
    {
      debug_printf(DEBUG_NORMAL, 
		   "No EAP Type Handler found for EAP Type %d!\n",
		   eap_type);
    }
  
  return eapmethod;
}

/***************************************************
 *
 * Cleanup the active EAP type, and anything else that we set up for using
 * EAP.
 *
 ***************************************************/
void eap_cleanup(struct generic_eap_data **clearmethod)
{
  int searchval;
  struct generic_eap_data *activemethod;

  if ((!clearmethod) || (!(*clearmethod))) 
    {
      debug_printf(DEBUG_NORMAL, "There was no active method in eap_cleanup()!\n");
      return;
    }

  activemethod = *clearmethod;

  debug_printf(DEBUG_EVERYTHING, "Calling EAP-Cleanup!\n");
  searchval = 0;

  if (activemethod->eapNum != 0)
    {
      searchval = eap_find_type(activemethod->eapNum);

      if (eaphandlers[searchval].eap_auth_type != NO_EAP_AUTH)
	{
	  (*eaphandlers[searchval].eap_auth_cleanup)(activemethod);
	  activemethod->eapNum = 0;
	} else {
	  debug_printf(DEBUG_NORMAL, "Couldn't clean up after active EAP type! (Type : %d)\n",activemethod->eapNum);
	  debug_printf(DEBUG_NORMAL, "This shouldn't be possible!  Please report it to the XSupplicant list!\n");
	}

      if (activemethod->identity != NULL)
	{
	  free(activemethod->identity);
	  activemethod->identity = NULL;
	}

      if (*clearmethod != NULL)
	{
	  free(*clearmethod);
	  *clearmethod = NULL;
	}
    }
}


extern int wpa_keying;

static int wpa_keying_material(struct interface_data *thisint)
{
	int s, ret = 0;
	struct sockaddr_un addr;

	if (!wpa_keying)
		return 0;

	if (thisint->keyingMaterial == NULL)
		return -1;

	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
	if (s < 0) {
		perror("socket");
		return -1;
	}

	debug_printf(DEBUG_NORMAL, "Sending master key to wpa_supplicant.\n");

	memset(&addr, 0, sizeof(addr));
	addr.sun_family = AF_LOCAL;
	addr.sun_path[0] = '\0';
	snprintf(addr.sun_path + 1, sizeof(addr.sun_path) - 1,
		 "wpa_supplicant");
	if (sendto(s, thisint->keyingMaterial, 32, 0,
		   (struct sockaddr *) &addr, sizeof(addr)) < 0) {
		perror("send");
		ret = -1;
	}
	close(s);

	return ret;
}

/*******************************************
 *
 * We got an EAP-Notify message.  Parse, and display it for now.
 *
 *******************************************/
void eap_do_notify(struct interface_data *thisint, char *inframe, int insize)
{
  struct eap_header *myeap;
  char myval[255];

  if ((!thisint) || (!inframe))
    {
      debug_printf(DEBUG_EVERYTHING, "Got a Notify, but nothing to process!\n");
      return;
    }

  myeap = (struct eap_header *)&inframe[OFFSET_TO_EAP];

  bzero(&myval[0], 255);
  
  // We need to determine how long the string that we were returned is.
  // So, take the EAP length value, and subtract 5 to account for the EAP
  // header.
  strncpy(&myval[0], &inframe[OFFSET_TO_DATA], (ntohs(myeap->eap_length)-5));

  debug_printf(DEBUG_NORMAL, "EAP Notification : %s\n", &myval[0]);
}

/*******************************************
 *
 * Process the EAP piece of the packet, determine what type of EAP packet it is
 * and set state machine variables accordingly.  The variables set will
 * cause the state machine to know what to do next.
 *
 *******************************************/
void eap_process_header(struct interface_data *thisint, char *inframe, 
			int insize)
{
  struct eap_header *myeap;

  if ((!thisint) || (!inframe))
    {
      debug_printf(DEBUG_NORMAL, "Nothing to do in eap_process_header()!\n");
      return;
    }

  if (!thisint->statemachine)
    {
      debug_printf(DEBUG_NORMAL, "Statemachine not initialized in eap_process_header()!\n");
      return;
    }

  memcpy(thisint->snmp->dot1xSuppLastEapolFrameSource, (char *)&inframe[6], 6);

  myeap = (struct eap_header *)&inframe[OFFSET_TO_EAP];

  switch (myeap->eap_code)
    {
    case EAP_REQUEST:
      thisint->statemachine->previousId = thisint->statemachine->receivedId;
      thisint->statemachine->receivedId = myeap->eap_identifier;

      switch (myeap->eap_type)
	{
	case EAP_TYPE_IDENTITY:
	  debug_printf(DEBUG_EVERYTHING, "Got EAP-Request-Identification.\n");
	  thisint->snmp->dot1xSuppEapolReqIdFramesRx++;
	  thisint->statemachine->reqId = TRUE;
	  break;
	  
	case EAP_TYPE_NOTIFY:
	  debug_printf(DEBUG_EVERYTHING, "Got an EAP-Notify.\n");
	  
	  // Process an EAP Notification
	  eap_do_notify(thisint, inframe, insize);
	  break;
	  
	default:
	  debug_printf(DEBUG_EVERYTHING, "Got EAP-Request-Authentication.\n");
	  thisint->snmp->dot1xSuppEapolReqFramesRx++;
	  if (ntohs(myeap->eap_length) <= 4)
	    {
	      debug_printf(DEBUG_NORMAL, "Got invalid EAP packet, ignoring!\n");
	      thisint->snmp->dot1xSuppEapLengthErrorFramesRx++;
	    } else {
	      thisint->statemachine->reqAuth = TRUE;
	    }
	  break;
	}
      break;

    case EAP_RESPONSE:
      debug_printf(DEBUG_EVERYTHING, "Got EAP-Response, ignoring(?).\n");
      if (myeap->eap_type == EAP_TYPE_LEAP) {
	debug_printf(DEBUG_EVERYTHING, "Got LEAP Response Packet.  Ready for AP verification!\n");
	thisint->statemachine->reqAuth = TRUE;
      }
      break;

    case EAP_SUCCESS:
      debug_printf(DEBUG_EVERYTHING, "Got EAP-Success!\n");

      if (thisint->userdata == NULL)
	{
	  debug_printf(DEBUG_NORMAL, "Invalid userdata after success packet recv!\n");
	  break;
	}

      if (thisint->userdata->activemethod == NULL)
	{
	  debug_printf(DEBUG_NORMAL, "Invalid activemethod after success packet recv!\n");
	  break;
	}

      thisint->snmp->eapol_success_rx++;
      if (thisint->userdata->activemethod->eapNum == EAP_TYPE_LEAP) {
      	thisint->statemachine->reqAuth = TRUE;
	myeap->eap_type = EAP_TYPE_LEAP;
      } else {
	debug_printf(DEBUG_NORMAL, "Authenticated!\n");
	thisint->statemachine->eapSuccess = TRUE;
      }

      // Here, we need to execute any commands that are needed after
      // a successful authentication.
      if (TEST_FLAG(thisint->flags, FIRSTAUTH))
	{
	  if (cmd_handler_exec(thisint, config_get_first_auth_cmd()))
	    exit(0);
	  UNSET_FLAG(thisint->flags, FIRSTAUTH);
	} else {
	  if (cmd_handler_exec(thisint, config_get_reauth_cmd()))
	    exit(0);
	}

      // And get our keying material
      eap_get_keying_material(thisint);
      wpa_keying_material(thisint);

      // Finally, dump the SNMP scoreboard if we need to.
      snmp_dump_stats(thisint);
      break;

    case EAP_FAILURE:
      debug_printf(DEBUG_EVERYTHING, "Got EAP-Failure!\n");
      debug_printf(DEBUG_NORMAL, "Failure!\n");
      thisint->snmp->eapol_fail_rx++;
      thisint->statemachine->eapFail = TRUE;
      eap_do_fail(thisint->userdata->activemethod);
      
      // Dump the SNMP scoreboard if we need to.
      snmp_dump_stats(thisint);
      break;
    }
}

/**********************************************************************
 *
 * For certain EAP methods, such as SIM and AKA, we can populate the ID
 * based on something other than the config file.  (Such as a smartcard.)
 * 
 **********************************************************************/
void eap_prepopulate_id(struct interface_data *thisint)
{
#ifdef EAP_SIM_ENABLE

  if ((!thisint) || (!thisint->userdata) || (!thisint->userdata->methods))
    {
      debug_printf(DEBUG_NORMAL, "Interface Data struct is invalid in eap_prepopulate_id()!\n");
      return;
    }

  // If we have SIM enabled, there is no username, and the primary EAP method
  // is SIM, then ask the SIM card for it's IMSI to use as the username.
  if ((thisint->userdata->identity == NULL) && 
      (thisint->userdata->methods->method_num == EAP_TYPE_SIM))
    {
      thisint->userdata->identity = (char *)malloc(50);
      if (thisint->userdata->identity == NULL)
	{
	  debug_printf(DEBUG_NORMAL, "Couldn't allocate memory for identity!\n");
	  return;
	}
      eapsim_get_username(thisint);
    }

  // Same is true for AKA.
  if ((thisint->userdata->identity == NULL) &&
      (thisint->userdata->methods->method_num == EAP_TYPE_AKA))
    {
      thisint->userdata->identity = (char *)malloc(50);
      if (thisint->userdata->identity == NULL)
	{
	  debug_printf(DEBUG_NORMAL, "Couldn't allocate memory for identity!\n");
	  return;
	}
      eapaka_get_username(thisint);
    }
#endif
}

/************************************************
 *
 * Process an EAP Request ID, and respond with the username information that
 * we have configured.  (If nothing is configured, we should ignore the
 * packet, and just return.  Returning an outsize of 0 means that we are
 * ignoring things.)
 *
 ************************************************/
void eap_request_id(char *identity, int eapid, char *outframe, 
		    int *eapsize)
{
  struct eap_header *myeap;
  char *username_ofs;

  if ((!identity) || (!outframe) || (!eapsize))
    {
      debug_printf(DEBUG_NORMAL, "Invalid parameters passed to eap_request_id()!\n");
      return;
    }

  myeap = (struct eap_header *)outframe;

  myeap->eap_code = EAP_RESPONSE;
  myeap->eap_identifier = eapid; 

  if (identity == NULL)
    {
      debug_printf(DEBUG_NORMAL, "No identity has been specified!  Authentication will not happen!\n");
      return;
    }

  *eapsize = (strlen(identity)+sizeof(struct eap_header)-1);
  myeap->eap_length = htons(*eapsize);
  myeap->eap_type = EAP_TYPE_IDENTITY;

  username_ofs = (char *)&outframe[sizeof(struct eap_header)-1];
  strncpy(username_ofs, identity, strlen(identity));
}

/************************************************
 *
 * Create/update the active method struct.
 *
 ************************************************/
int eap_create_active_method(struct generic_eap_data **activemethod,
			     char *identity, char *tempPwd)
{
  struct generic_eap_data *mymethod;

  if (activemethod == NULL)
    {
      debug_printf(DEBUG_NORMAL, "Invalid pointer passed to eap_create_active_method!\n");
      return XEMALLOC;
    }

  mymethod = *activemethod;

  if (mymethod == NULL)
    {
      *activemethod = (struct generic_eap_data *)malloc(sizeof(struct generic_eap_data));
      mymethod = *activemethod;

      if (mymethod == NULL)
	{
	  debug_printf(DEBUG_NORMAL, "Couldn't allocate memory in eap_create_active_method()!\n");
	  return XEMALLOC;
	}

      memset(mymethod, 0, sizeof(struct generic_eap_data));

      mymethod->eap_conf_data = NULL;
      mymethod->eap_data = NULL;
      mymethod->staleFrame = NULL;
      mymethod->staleSize = 0;
   
      mymethod->identity = (char *)malloc(strlen(identity)+1);
      
      if (mymethod->identity == NULL)
	{
	  debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to copy identity!\n");
	} else {
	  strcpy(mymethod->identity, identity);
	}
    }

  mymethod->tempPwd = tempPwd;

  return XENONE;
}

/************************************************
 *
 * Process an authentication request.  Based on the information in the packet,
 * we call the correct EAP type.  We return an error if it is an EAP type
 * that we don't know.
 *
 ************************************************/
int eap_request_auth(struct generic_eap_data *activemethod,
		     struct config_eap_method *eapConfig,
		     char *inframe, int insize, char *outframe, int *eapsize)
{
  struct eap_header *myouteap, *myineap;
  int eapmethod, done, valideap, working_eap_type, eapinsize = 0;
  struct config_eap_method *start=NULL, *cur=NULL, *newmethod = NULL;
  char *tosendframe;
  int retVal = XENONE;

  if ((!outframe) || (!eapsize))   
    {
      debug_printf(DEBUG_NORMAL, "Invalid parameter passed in to eap_request_auth()!\n");
      return XEMALLOC;
    }

  eapmethod = 0;
  done = FALSE;
  valideap = FALSE;

  if (inframe != NULL)
    {
      myineap = (struct eap_header *)inframe;
      tosendframe = (char *)&inframe[sizeof(struct eap_header)-1];
      working_eap_type = myineap->eap_type;
    } else {
      myineap = NULL;
      working_eap_type = activemethod->eapNum;
      tosendframe = NULL;
    }

  myouteap = (struct eap_header *)outframe;

  // Make sure we have valid method data.
  if (eapConfig == NULL)
    {
      debug_printf(DEBUG_NORMAL, "No EAP methods available in eap_request_auth()!\n");
      return XEMALLOC;
    }

  // Check to make sure that the type requested is in our list of valid
  // types.
  
  start = eapConfig;
  cur = start;

  while ((cur != NULL) && (cur->method_num != working_eap_type))
    {
      cur = cur->next;
    }

  // If we have a type that matches, then go ahead...
  if (cur != NULL)
    {
      valideap = TRUE;
      newmethod = cur;
      activemethod->eap_conf_data = newmethod->method_data;
    } else {
      valideap = FALSE;
      activemethod->eap_conf_data = NULL;
    }

  // If the requested EAP type isn't valid, then send a NAK.
  if ((valideap == FALSE) && (inframe != NULL) && (ntohs(myineap->eap_length)>4))
    {
      debug_printf(DEBUG_STATE, "Unsupported EAP type requested. (%d)  Sending NAK!\n",myineap->eap_type);
      myouteap->eap_code = EAP_RESPONSE;
      myouteap->eap_identifier = myineap->eap_identifier;
      myouteap->eap_length = htons(6);
      myouteap->eap_type = EAP_TYPE_NAK;

      if (eapConfig == NULL)
	{
	  debug_printf(DEBUG_NORMAL, "There are no authentication methods defined for this interface!  Make sure you have at least one valid EAP type defined in your configuration.\n");
	  return XEBADCONFIG;
	}

      outframe[sizeof(struct eap_header)-1] = eapConfig->method_num;
      *eapsize = 6;
      return *eapsize;
    }

  // Now, determine which authenticator in our array is the right one.
  eapmethod = eap_find_type(working_eap_type);

  if (eaphandlers[eapmethod].eap_auth_type == NO_EAP_AUTH)
    {
      // We got an error.
      return XEINVALIDEAP;
    }

  // If we had an EAP type before, and we have changed this time through,
  // make sure we call the cleanup methods.
  if ((activemethod->eapNum > 0) && 
      (activemethod->eapNum != eaphandlers[eapmethod].eap_auth_type))
    {
      debug_printf(DEBUG_AUTHTYPES, "EAP Type Changed!  Cleaning up old type!\n");
      eap_clear_active_method(activemethod);
    }

  // If this is a new EAP type, call the setup method.
  if (activemethod->eapNum == 0)
    {
      (*eaphandlers[eapmethod].eap_auth_setup)(activemethod);
      activemethod->eapNum = eaphandlers[eapmethod].eap_auth_type;

      if (activemethod->eap_data == NULL)
	{
	  debug_printf(DEBUG_AUTHTYPES, "This EAP type didn't set up any state information!?\n");
	}
    } 

  // If we were passed a frame, then record the ID, otherwise leave it the
  // same as it was before.  (Assume we are still working on processing the
  // last frame.)
  if (myineap != NULL)
    {
      activemethod->eapid = myineap->eap_identifier;
    }

  if (inframe != NULL)
    {
      eapinsize = ntohs(myineap->eap_length)-5;
    }

  if (activemethod != NULL)
    {
      if ((activemethod->staleFrame != NULL) && (inframe == NULL))
	{
	  debug_printf(DEBUG_AUTHTYPES, "Attempting to repost stale buffer.\n");
	  tosendframe = (char *)malloc(activemethod->staleSize);
	  if (tosendframe == NULL)
	    {
	      debug_printf(DEBUG_NORMAL, "Failed to malloc memory for temporary frame buffer!\n");
	      return XEMALLOC;
	    }
	  memcpy(tosendframe, activemethod->staleFrame, 
		 activemethod->staleSize);
	}
    }

  if (tosendframe == NULL)
    {
      debug_printf(DEBUG_AUTHTYPES, "No data in frame, returning.\n");
      return XENONE;
    }

  (*eaphandlers[eapmethod].eap_auth_handlers)(activemethod, tosendframe,
					      eapinsize, 
					      &outframe[sizeof(struct eap_header)-1], 
					      eapsize);

  // See if an EAP type requested a password.
  if (activemethod->need_password == 1)
    {
      debug_printf(DEBUG_AUTHTYPES, "Saving current frame!\n");

      interactive_store_frame(tosendframe, eapinsize, activemethod);

      debug_printf(DEBUG_AUTHTYPES, "Requesting password from GUI!\n");

      interactive_gui_prompt(activemethod->intName, activemethod->tempPwd, 
			     activemethod->eaptype, activemethod->eapchallenge);

      *eapsize = 0;
      free(activemethod->eaptype);
      activemethod->eaptype = NULL;
      free(activemethod->eapchallenge);
      activemethod->eapchallenge = NULL;
      activemethod->need_password = 0;
      return XENONE;
    } else {
      // We have used this packet, so remove it from the stale frame buffer.
      if (activemethod->staleFrame != NULL)
	{
	  debug_printf(DEBUG_AUTHTYPES, "Clearing out stale buffer!\n");
	  free(activemethod->staleFrame);
	  activemethod->staleFrame = NULL;
	  activemethod->staleSize = 0;
	}
    }

  if ((tosendframe != NULL) && (inframe == NULL))
  {
    if (tosendframe != NULL)
      {
	debug_printf(DEBUG_AUTHTYPES, "tosendframe isn't the same as inframe!  Purging!\n");
	free(tosendframe);
	tosendframe = NULL;
      }
  }

  // If we are using LEAP, we need to make some extra calls here.
  if (eaphandlers[eapmethod].eap_auth_type == EAP_TYPE_LEAP)
    {
      if (eapleap_done(activemethod) == 1)
	{
	  retVal = 2;
	}
    }

  if (*eapsize > 0)
    {
      *eapsize = *eapsize + (sizeof(struct eap_header)-1);
      myouteap->eap_length = htons(*eapsize);
      if (eaphandlers[eapmethod].eap_auth_type == EAP_TYPE_LEAP &&
	  myineap->eap_code == EAP_SUCCESS) {
	myouteap->eap_code = EAP_REQUEST;
	myouteap->eap_identifier = myineap->eap_identifier;
      } else {
	myouteap->eap_code = EAP_RESPONSE;
	myouteap->eap_identifier = myineap->eap_identifier;
      }
      myouteap->eap_type = activemethod->eapNum;
    } 

  return retVal;
}


/************************************************************************
 *
 * Clear the active EAP type.  This will be called when the EAP type we are
 * using has changed, or we have encountered another event (such as an
 * essid change) that should require a completely new authentication!
 *
 ************************************************************************/
int eap_clear_active_method(struct generic_eap_data *activemethod)
{
  int eapmethod = 0;

  // First, make sure we have something to clean up.
  if (activemethod == NULL)
    {
      debug_printf(DEBUG_AUTHTYPES, "There was nothing to clean up in eap_clear active_method!\n");
      return XENONE;
    }

  eapmethod = eap_find_type(activemethod->eapNum);

  (*eaphandlers[eapmethod].eap_auth_cleanup)(activemethod);
  activemethod->eapNum = 0;

  return XENONE;
}

/*************************************************
 *
 * Ask the EAP method to give us keying material.
 *
 *************************************************/
int eap_get_keying_material(struct interface_data *thisint)
{
  int eapmethod = 0;

  if ((!thisint) || (!thisint->userdata))
    {
      debug_printf(DEBUG_NORMAL, "Invalid interface structure in eap_get_keying_material()!\n");
      return XEMALLOC;
    }

  if (thisint->userdata->activemethod == NULL)
    {
      debug_printf(DEBUG_AUTHTYPES, "The EAP type doesn't seem to exist anymore!\n");
      return XENONE;
    }

  eapmethod = eap_find_type(thisint->userdata->activemethod->eapNum);

  if (eaphandlers[eapmethod].eap_auth_type == NO_EAP_AUTH)
    {
      debug_printf(DEBUG_NORMAL, "Couldn't find an EAP type handler to clean up from!\n");
      debug_printf(DEBUG_NORMAL, "We will probably leak memory!\n");
      return XENONE;
    }

  (*eaphandlers[eapmethod].eap_auth_get_keys)(thisint);

  return XENONE;
}

/************************************************************************
 *
 * Notify the eap method that the attempt has failed.  This should be used
 * for things such as destroying a password that has failed, so it will be
 * requested again.  Or, for resetting a context in the case of TLS based
 * authentication methods.
 *
 ************************************************************************/
int eap_do_fail(struct generic_eap_data *activemethod)
{
  int eapmethod = 0;

  // Make sure that we have something to clear.
  if (activemethod == NULL)
    {
      debug_printf(DEBUG_AUTHTYPES, "There was no method defined for executing a failure!\n");
      return XENONE;
    }

  eapmethod = eap_find_type(activemethod->eapNum);

  if (eaphandlers[eapmethod].eap_auth_type == NO_EAP_AUTH)
    {
      debug_printf(DEBUG_NORMAL, "Couldn't find an EAP type handler to notify of the failure!\n");
      return XENONE;
    }

  if (eaphandlers[eapmethod].eap_auth_failed == NULL) 
    {
      debug_printf(DEBUG_AUTHTYPES, "EAP handler didn't have a failure method!\n");
      return XENONE;
    }

  (*eaphandlers[eapmethod].eap_auth_failed)(activemethod);

  return XENONE;
}
