eaptnc.c

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

C
698
字号
      debug_printf(DEBUG_AUTHTYPES, "(EAP-TNC) Process bulk data\n");
      retval = eaptnc_do_bulk_data(eapdata);
    }

  return retval;
}

/**
 * \brief Verify that we have everything we need to run TNC.
 *
 * @param[in] eapdata   A pointer to EAP data that may be needed to complete a TNC session.
 **/
void eaptnc_check(eap_type_data *eapdata)
{
	if (eapdata->eap_data != NULL)
		tncdatahook = (struct tnc_data *)eapdata->eap_data;
}

/**
 * \brief Process a TNC request.
 *
 * @param[in] eapdata   A pointer to EAP data that may be needed to complete this TNC session.
 **/
void eaptnc_process(eap_type_data *eapdata)
{
  uint16_t retval = 0, eapsize = 0;
  struct eap_header *eaphdr;
  uint8_t *tnc_data;

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

  if (!xsup_assert((eapdata->eapReqData != NULL), 
		   "eapdata->eapReqData != NULL", FALSE))
    {
      eapdata->ignore = TRUE;
      eapdata->decision = EAP_FAIL;
      return;
    }

  eaphdr = (struct eap_header *)eapdata->eapReqData;

  eapsize = ntohs(eaphdr->eap_length) - sizeof(struct eap_header);

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

  // The code, identifier, length, and type should be stripped at this point.
  // So start by validating the Flags/Ver byte, and process from there.
  retval = eaptnc_check_flags_ver(tnc_data[0]);
  if (retval != XENONE) return;

  // This is overkill for now, but since there is a version, we implement
  // this now, so we can expand it later.
  switch ((tnc_data[0] & TNC_VERSION_MASK))
    {
    case 1:
      // Process a version 1 request.
      retval = eaptnc_process_version_1(eapdata, tnc_data, eapsize);
      break;

    default:
      debug_printf(DEBUG_NORMAL, "Unknown TNC version in request! (Version %d)\n",
		  (tnc_data[0] & TNC_VERSION_MASK));

	  eap_type_common_fail(eapdata);
      break;
    }
}

/**
 *  \brief Build a TNC response.
 *
 * @param[in] eapdata   A pointer to EAP data that may be needed to complete a TNC session.
 *
 * \retval ptr to the resulting EAP packet that is to be sent to the authenticator.
 * \retval NULL on failure
 **/
uint8_t *eaptnc_buildResp(eap_type_data *eapdata)
{
  uint8_t *resdata = NULL, *resdataptr = NULL, *retdata = NULL, *dataptr = NULL, *dequeue_data = NULL;
  struct eap_header *eaphdr = NULL;
  uint32_t value32 = 0, cpysize = 0, extra = 0, totalsize = 0, queuesize = 0, res_size = 0, retlen = 0;
  uint16_t value16 = 0;
  struct tnc_data *tnc = NULL;
  uint8_t *tosend = NULL;
  int maxsize = TNC_MAX_FRAG;
  int more = 0;
  int athead = 0;

  if (eapdata == NULL) return NULL;

  if (eapdata->eap_data == NULL) return NULL;

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

  // XXX Need to set a way to specify a fragment size.
  resdata = Malloc(1010);
  if (resdata == NULL)
    {
      debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to store TNC "
		   "result fragment.\n");
      return NULL;
    }

  resdataptr = resdata;

  // Build an EAP header.
  eaphdr = (struct eap_header *)resdata;
  
  eaphdr->eap_code = EAP_RESPONSE_PKT;
  eaphdr->eap_identifier = eap_type_common_get_eap_reqid(eapdata->eapReqData);
  eaphdr->eap_type = EAP_TYPE_TNC;

  resdataptr += sizeof(struct eap_header);

  // Otherwise, return some data from the buffer.
  if (tnc->tncoutqueue == NULL)
    {
      // Send an ACK.
      debug_printf(DEBUG_AUTHTYPES, "(EAP-TNC) ACKing.\n");
      eaphdr->eap_length = htons(sizeof(struct eap_header)+1);
      resdataptr[0] = 0x00 | TNC_MAX_VERSION_SUPPORTED;    // TNC-ACK.
      return resdata;
    }

  FREE(resdata);  // This memory was only needed if we sent an ACK.

  if (queue_get_size(&tnc->tncoutqueue, &queuesize) < 0)
	  {
		  debug_printf(DEBUG_NORMAL, "Error getting queue depth!\n");
		  return NULL;
	  }

  athead = queue_at_head(&tnc->tncoutqueue);

  if (queuesize == 0)
    {
      debug_printf(DEBUG_AUTHTYPES, "No data left to send.\n");
      return NULL;
    }

	  res_size = maxsize - 6;  // Leave room in case we need to slap a length header on.

	  more = queue_dequeue(&tnc->tncoutqueue, &dequeue_data, &res_size);

  	  if (more < 0) 
	  {
		  debug_printf(DEBUG_NORMAL, "Couldn't get more fragments to send to authenticator.\n");
		  return NULL;  
	  }

	  // If we are at the head of the list, we need to send a length.
	  if (athead == TRUE) 
	  {
		retdata = Malloc(res_size + 5 + sizeof(struct eap_header));
		if (retdata == NULL) 
		{
			FREE(dequeue_data);
			return NULL;
		}

		dataptr = (uint8_t *)&retdata[5];
		retdata[0] = TNC_LENGTH_FLAG;  // Length is included in this message.
		cpysize = res_size;
		retlen = htonl(queuesize);
		memcpy(&retdata[1], &retlen, sizeof(uint32_t));
		res_size+=5;
	  }
	  else
	  {
		  retdata = Malloc(res_size+1+sizeof(struct eap_header));
		  if (retdata == NULL) 
		  {
			  FREE(dequeue_data);
			  return NULL;
		  }

		  cpysize = res_size;
		  dataptr = (uint8_t *)&retdata[1];
		  res_size++;
	  }

	  // If more == TRUE then we have more fragments, and need to include that indication
	  if (more == TRUE) 
	  {
		  retdata[0] |= TNC_MORE_FLAG;
	  }

	  memcpy(dataptr, dequeue_data, cpysize);

	  FREE(dequeue_data);

	  if (queue_queue_done(&tnc->tncoutqueue) != 0)
	  {
		  debug_printf(DEBUG_TLS_CORE, "Finished with queue... Freeing.\n");
		  if (queue_destroy(&tnc->tncoutqueue) != 0)
		  {
			  debug_printf(DEBUG_NORMAL, "Couldn't destroy queue data!  (We will probably leak memory.)\n");
		  }
	  }

  retdata[0] |= TNC_MAX_VERSION_SUPPORTED;

  resdata = malloc(res_size + sizeof(struct eap_header));
  if (resdata == NULL) return NULL;

  eaphdr = (struct eap_header *)resdata;
  
  eaphdr->eap_code = EAP_RESPONSE_PKT;
  eaphdr->eap_identifier = eap_type_common_get_eap_reqid(eapdata->eapReqData);
  eaphdr->eap_type = EAP_TYPE_TNC;

  resdataptr = resdata;
  resdataptr += sizeof(struct eap_header);

  value16 = res_size+sizeof(struct eap_header);
  eaphdr->eap_length = htons(value16);

  memcpy(&resdata[sizeof(struct eap_header)], retdata, res_size);

  FREE(retdata);

  debug_printf(DEBUG_AUTHTYPES, "TNC returns (%d) : \n", res_size+sizeof(struct eap_header));
  debug_hex_dump(DEBUG_AUTHTYPES, resdata, res_size + sizeof(struct eap_header));

  eapdata->methodState = MAY_CONT;
  eapdata->decision = COND_SUCC;
  eapdata->ignore = FALSE;
  
  return resdata;
}

/**
 * \brief Check to see if keys are available.  (For EAP-TNC there NEVER will be!)
 *
 *  There will never be keying material available from the current 
 *  incarnation of this standard!
 *
 * @param[in] eapdata   The EAP data that may be needed to complete a TNC session.
 *
 * \retval FALSE since TNC should *NEVER* be used as a phase 1 method, and should *NEVER* have keying material.
 **/
uint8_t eaptnc_isKeyAvailable(eap_type_data *eapdata)
{
  return FALSE;
}

/**
 * \brief Return any EAP specific keying material.  (None will be returned because TNC doesn't generate
 *        any, and it isn't a valid phase 1 method.)
 *
 * @param[in] eapdata   A pointer to EAP specific data that may be used to complete a TNC session.
 * 
 * \retval NULL since keying material will *NEVER* be generated!
 **/
uint8_t *eaptnc_getKey(eap_type_data *eapdata)
{
  debug_printf(DEBUG_NORMAL, "EAP-TNC was asked to provide keying material! "
	       "If you ever see this message, then there is something badly "
	       "broken in the code!  Please report it along with a full "
	       "debug output!\n");
  return NULL;
}

/**
 *  \brief Clean up any memory that was used by EAP TNC.
 *
 * @param[in] eapdata   A pointer to a buffer that we would have used to store EAP specific data.  This
 *                      buffer is what we need to clean up.
 **/
void eaptnc_deinit(eap_type_data *eapdata)
{
	struct tnc_data *tnc = NULL;

	debug_printf(DEBUG_AUTHTYPES, "(EAP-TNC) Deinit.\n");

	if (eapdata == NULL) return;

	if (eapdata->eap_data == NULL) return;

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

	if (tnc->tncinqueue != NULL)
	{
		if (queue_destroy(&tnc->tncinqueue) != 0)
		{
			debug_printf(DEBUG_NORMAL, "Couldn't clean up incoming queue!\n");
		}
	}

	if (tnc->tncoutqueue != NULL)
	{
		if (queue_destroy(&tnc->tncoutqueue) != 0)
		{
			debug_printf(DEBUG_NORMAL, "Couldn't clean up outgoing queue!\n");
		}
	}

	tnc->expected_in = 0;

	FREE(eapdata->eap_data);
	tnc = NULL;

	tncdatahook = NULL;
}

/**
 * \brief Callback used by TNCC when it has a finished batch that is ready to 
 *        be sent.
 *
 * @param[in] connectionID   The connectionID used by the IMC to keep track of the connection.
 * @param[in] messageBuffer   The message that should be sent to the server.
 * @param[in] messageLength   The length of the buffer pointed to by messageBuffer.
 *
 * \retval TNC_RESULT_FATAL on error
 * \retval TNC_RESULT_SUCCESS on success
 *
 **/
TNC_Result TNC_TNCC_SendBatch(
			      /*in*/ TNC_ConnectionID connectionID,
			      /*in*/ const char* messageBuffer,
			      /*in*/ size_t messageLength)
{
	if (tncdatahook == NULL)
	{
		debug_printf(DEBUG_NORMAL, "TNC data hook not available.\n");
		return TNC_RESULT_FATAL;
	}

	if (tncdatahook->tncoutqueue == NULL)
	{
		if (queue_create(&tncdatahook->tncoutqueue) != 0)
		{
			debug_printf(DEBUG_NORMAL, "Couldn't create outbound queue!\n");
			return TNC_RESULT_FATAL;
		}
	}

	if (queue_enqueue(&tncdatahook->tncoutqueue, (uint8_t *)messageBuffer, messageLength) != 0)
	{
		debug_printf(DEBUG_NORMAL, "Couldn't enqueue data in outbound queue.\n");
		return TNC_RESULT_FATAL;
	}

	return TNC_RESULT_SUCCESS;
}

#endif /* HAVE_TNC */

⌨️ 快捷键说明

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