eaptnc.c

来自「linux 下通过802.1认证的安装包」· C语言 代码 · 共 698 行 · 第 1/2 页

C
698
字号
/**
 * Support for Trusted Network Connect EAP method
 *
 * \file eaptnc.c
 *
 * Licensed under a dual GPL/BSD license.  (See LICENSE file for more info.)
 *
 * \author chris@open1x.org
 *
 * \todo Add error events to this file!
 *
 * $Id: eaptnc.c,v 1.2.2.30 2008/01/21 22:51:49 chessing Exp $
 * $Date: 2008/01/21 22:51:49 $
 **/

#ifdef HAVE_TNC
#include <string.h>

#ifndef WINDOWS
#include <strings.h>
#else
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include "../../stdintwin.h"
#endif

#include <stdlib.h>
#include <errno.h>
#include <libtnctncc.h>

#include "../../../lib/libxsupconfig/xsupconfig_structs.h"
#include "../../context.h"
#include "../../xsup_debug.h"
#include "../../xsup_err.h"
#include "../../frame_structs.h"
#include "../../../lib/libxsupconfig/xsupconfig.h"   
#include "../../eap_sm.h"
#include "../../xsup_common.h"
#include "eaptnc.h"
#include "../eap_type_common.h"

#ifdef USE_EFENCE
#include <efence.h>
#endif

#ifndef WINDOWS
#warning Use config data, and get rid of the #define below.
#endif

// XXX Make this configurable.
#define TNC_MAX_FRAG  900

uint32_t totalretsize = 0;

struct tnc_data *tncdatahook = NULL;    // Used to provide binding on our *SendBatch call.

static int connectionID = 0;            // Start with a connection ID of 0.

/**
 * \brief Validate the TNC flags byte to be sure that it is using a version we support, and doesn't
 *        have any of the reserved bits set.
 *
 * @param[in] flagsver   The byte that we want to verify has the proper settings for TNC.
 *
 * \retval XENONE on success
 * \retval XEINVALIDFLAGSVER on failure.
 **/
int eaptnc_check_flags_ver(uint8_t flagsver)
{
  int retval = XENONE;

  // We don't want to terminate when we find an error.  Instead, we want
  // to kick back error message for each part of the check that fails.
  if ((flagsver & TNC_VERSION_MASK) > TNC_MAX_VERSION_SUPPORTED)
    {
      debug_printf(DEBUG_NORMAL, "Invalid version number %d!  We currently "
		   "only support up to version %d.\n", 
		   (flagsver & TNC_VERSION_MASK), TNC_MAX_VERSION_SUPPORTED);
      retval = XEINVALIDFLAGSVER;
    }

  if ((flagsver & TNC_RESERVED_FLAGS) != 0)
    {
      debug_printf(DEBUG_NORMAL, "Invalid flags set for EAP-TNC!  Something "
		   "was set to 1 in bit positions 4 and/or 5.\n");
      retval = XEINVALIDFLAGSVER;
    }

  return retval;
}

/**
 *  \brief Start a TNC conversation with the server.
 *
 * @param[in] eapdata   A pointer to the EAP data that we may need to complete a TNC authentication.
 *
 * \retval XENONE on success
 * \retval !XENONE on failure
 **/
int eaptnc_do_start(eap_type_data *eapdata)
{
	context *ctx = NULL;

  // A start message should contain a single byte that contains the start
  // flag, and a version flag.  So, we should make sure that there isn't
  // anything extra before we continue.

  if (eap_type_common_get_eap_length(eapdata->eapReqData) > 
      (sizeof(struct eap_header)+1))
    {
      debug_printf(DEBUG_NORMAL, "The start message from the authenticator "
		   "contained data beyond the start flag.  This is not "
		   "allowed!\n");
      return XEGENERROR;
    }
 
  if (eapdata->eap_data != NULL)
  {
	  debug_printf(DEBUG_NORMAL, "EAP data hook is unavailable!  (Did the previous EAP method "
			"free it?\n");
	  return XEGENERROR;
  }

  // Otherwise, create our structure.
  eapdata->eap_data = Malloc(sizeof(struct tnc_data));
  if (eapdata->eap_data == NULL)
  {
	  debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to store TNC stucture!!\n");
	  return XEMALLOC;
  }

  tncdatahook = (struct tnc_data *)eapdata->eap_data;

  ctx = event_core_get_active_ctx();
  if (ctx == NULL)
  {
	  debug_printf(DEBUG_NORMAL, "Attempted to start a TNC session with an invalid context!?\n");
	  return XEGENERROR;
  }

  // Remember the TNC connection ID, so that we can operate on the right context if the IMC
  // asks us to do something.
  if (ctx->tnc_connID == -1) ctx->tnc_connID = connectionID;

  if (libtnc_tncc_BeginSession(ctx->tnc_connID) != TNC_RESULT_SUCCESS)
    {
      debug_printf(DEBUG_NORMAL, "(EAP-TNC) Failed to start TNC session!\n");
      return XETNCLIBFAILURE;
    }

  connectionID++;

  debug_printf(DEBUG_NORMAL, "(EAP-TNC) Started IMC Handshake.\n");
  return XENONE;
}

/**
 * \brief Process a bulk TNC data request.  (Basically, anything that isn't a TNC start message.)
 *
 * @param[in] eapdata   A pointer to EAP data that may be needed to complete a TNC session.
 *
 * \retval XENONE on success
 * \retval !XENONE on failure
 **/
int eaptnc_do_bulk_data(eap_type_data *eapdata)
{
  int retval = XENONE;
  int err = 0;
  uint8_t *dataptr = NULL;
  uint16_t datalen = 0;
  uint32_t value32 = 0;
  uint32_t expected = 0;
  uint8_t *tosend = NULL;
  struct tnc_data *tnc = NULL;
  context *ctx = NULL;

  if (!xsup_assert((eapdata != NULL), "eapdata != NULL", FALSE))
    return XEGENERROR;

  if (!xsup_assert((eapdata->eap_data != NULL), "eapdata->eap_data != NULL", FALSE))
	return XEGENERROR;

  if (!xsup_assert((eapdata->eapReqData != NULL), 
		   "eapdata->eapReqData != NULL", FALSE))
    return XEGENERROR;

  ctx = event_core_get_active_ctx();
  if (ctx == NULL)
  {
	  debug_printf(DEBUG_NORMAL, "Attempted to start a TNC bulk data transfer with an invalid context!?\n");
	  return XEGENERROR;
  }

  tnc = (struct tnc_data *)eapdata->eap_data;

  datalen = eap_type_common_get_eap_length(eapdata->eapReqData);
  datalen -= sizeof(struct eap_header);

  dataptr = &eapdata->eapReqData[sizeof(struct eap_header)];

  if (eap_type_common_get_eap_length(eapdata->eapReqData) <= (sizeof(struct eap_header)+1))
    {
		if (((dataptr[0] & TNC_MASK_OUT_VER) == 0x00) && (tnc->tncoutqueue == NULL))
		{
			debug_printf(DEBUG_NORMAL, "The server ACKed our ACK?\n");
			eap_type_common_fail(eapdata);
			return XEGENERROR;
		}
    }

  if (dataptr[0] & TNC_LENGTH_FLAG)
    {
      dataptr++;
      datalen--;
      
      memcpy(&value32, dataptr, sizeof(uint32_t));
      value32 = ntohl(value32);
      
      debug_printf(DEBUG_AUTHTYPES, "Expecting %d byte(s) of data from "
		   "TNC authenticator.\n", value32);

	  tnc->expected_in = value32;
      
      dataptr += 4;
      datalen -= 4;
    }
  else
    {
      // Skip the flags byte.
      dataptr++;
      datalen--;
    }

  // Starting at the current position of dataptr, and going to dataptr+datalen
  // is the next block of data we need.
  if (tnc->tncinqueue == NULL)
    {
		if (queue_create(&tnc->tncinqueue) != 0)
		{
			debug_printf(DEBUG_NORMAL, "Couldn't create TNC queue!\n");
			return XEMALLOC;
		}
    }

  if (datalen > 0)
  {
	err = queue_enqueue(&tnc->tncinqueue, dataptr, datalen);
	if (err != 0)
	{
		debug_printf(DEBUG_NORMAL, "Couldn't enqueue new incoming TNC data! (Error : %d)\n", err);
	  return XEMALLOC;
	}
  }
  else
  {
	  debug_printf(DEBUG_AUTHTYPES, "TNC appears to be an ACK.\n");
  }

  dataptr = &eapdata->eapReqData[sizeof(struct eap_header)];

  if (!(dataptr[0] & TNC_MORE_FLAG))
    {
      // There is nothing more that will be sent to us (in this block).
      // Check that we have enough data.  If we don't have exactly the right
      // amount, display a message, and continue.
		err = queue_get_size(&tnc->tncinqueue, &value32);
		if (err != 0)
		{
			debug_printf(DEBUG_NORMAL, "Couldn't determine queue depth! (Error : %d)\n", err);
			return XEGENERROR;
		}

		if (value32 < tnc->expected_in)
		{
		  debug_printf(DEBUG_NORMAL, "There is less data in the TNC buffer "
			       "than we expected.  It is likely that TNC will "
				   "fail.  (Expected : %d   Got : %d)\n", tnc->expected_in, value32);
		}

		// Remember what we expected.
		expected = value32;

		if (queue_dequeue(&tnc->tncinqueue, &tosend, &value32) != 0)
		{
			debug_printf(DEBUG_AUTHTYPES, "Couldn't dequeue any data for TNC!\n");
			return XEGENERROR;
		}

		if (expected != value32)  // Uhh...  This shouldn't be possible!
		{
			debug_printf(DEBUG_NORMAL, "Failed to dequeue as much data as the queue claimed it had! (Expected %d, got %d)\n", expected, value32);
			FREE(tosend);
			return XEGENERROR;
		}

      // We have an XML block to send.
      if (libtnc_tncc_ReceiveBatch(ctx->tnc_connID, tosend, value32) != TNC_RESULT_SUCCESS)
	{
	  debug_printf(DEBUG_NORMAL, "Couldn't send TNC batch to libtnc!\n");
	  if (queue_destroy(&tnc->tncinqueue) != 0)
	  {
		  debug_printf(DEBUG_NORMAL, "Couldn't destroy used queue!\n");
	  }

	  FREE(tosend);
	  return XEGENERROR;
	}

	  FREE(tosend);

	  if (queue_queue_done(&tnc->tncinqueue) == 1)
	  {
		  queue_destroy(&tnc->tncinqueue);
		  tnc->expected_in = 0;
	  }
      
   }

  return retval;
}

/**
 * \brief Process a version 1 TNC request.
 *
 *  Right now, there is only 1 version of TNC.  But, since a version is included it is reasonable that
 *  there may be other versions developed.  If there are, we should be able to integrate them easily.
 *
 * @param[in] eapdata   A pointer to EAP data that may be needed to complete a TNC session.
 * @param[in] eapreq   A pointer to a buffer containing the EAP request message.
 * @param[in] size   The size of the EAP request message.
 *
 * \retval XENONE on success
 * \retval !XENONE on failure
 **/
uint16_t eaptnc_process_version_1(eap_type_data *eapdata, uint8_t *eapreq,
				  uint16_t size)
{
  int retval = XENONE;

  if (eapreq[0] & TNC_START_FLAG)
    {
      // Process a start message.
      debug_printf(DEBUG_AUTHTYPES, "(EAP-TNC) Process Start\n");
      retval = eaptnc_do_start(eapdata);
    }
  else
    {
      // Process a bulk data frame.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?