Report generated at: Fri Nov 25 00:58:39 CET 2011
| Total number of functions | 82 | 
| Number of low risk functions | 71 | 
| Number of moderate risk functions | 7 | 
| Number of high risk functions | 4 | 
| Number of untestable functions | 0 | 
| Cyclomatic Complexity | Risk Evaluation | |
| 0 - 10 | Simple module, without much risk | |
| 11 - 20 | More complex module, moderate risk | |
| 21 - 50 | Complex module, high risk | |
| greater than 50 | Untestable module, very high risk | 
| Function Name | Modified Cyclo | Number of Statements | Number of Lines | Source File | |
| ↓ | gss_krb5_unwrap | 41 | 131 | 227 | krb5/msg.c | 
| 
OM_uint32
gss_krb5_unwrap (OM_uint32 * minor_status,
		 const gss_ctx_id_t context_handle,
		 const gss_buffer_t input_message_buffer,
		 gss_buffer_t output_message_buffer,
		 int *conf_state, gss_qop_t * qop_state)
{
  _gss_krb5_ctx_t k5 = context_handle->krb5;
  gss_buffer_desc tok;
  char *data;
  OM_uint32 sgn_alg, seal_alg;
  size_t tmplen;
  int rc;
  rc = gss_decapsulate_token (input_message_buffer, GSS_KRB5, &tok);
  if (rc != GSS_S_COMPLETE)
    return GSS_S_BAD_MIC;
  if (tok.length < 8)
    return GSS_S_BAD_MIC;
  if (memcmp (tok.value, TOK_WRAP, TOK_LEN) != 0)
    return GSS_S_BAD_MIC;
  data = tok.value;
  sgn_alg = data[2] & 0xFF;
  sgn_alg |= data[3] << 8 & 0xFF00;
  seal_alg = data[4] & 0xFF;
  seal_alg |= data[5] << 8 & 0xFF00;
  if (conf_state != NULL)
    *conf_state = seal_alg == 0xFFFF;
  if (memcmp (data + 6, "\xFF\xFF", 2) != 0)
    return GSS_S_BAD_MIC;
  switch (sgn_alg)
    {
      /* XXX implement other checksums */
    case 0:			/* DES-MD5 */
      {
	size_t padlen;
	char *pt;
	char header[8];
	char encseqno[8];
	char seqno[8];
	char cksum[8];
	char confounder[8];
	char *tmp;
	uint32_t seqnr;
	size_t outlen, i;
	/* Typical data:
	   ;; 02 01 00 00 ff ff ff ff  0c 22 1f 79 59 3d 00 cb
	   ;; d5 78 2f fb 50 d2 b8 59  fb b4 e0 9b d0 a2 fa dc
	   ;; 01 00 20 00 04 04 04 04
	   Translates into:
	   ;;   HEADER                 ENCRYPTED SEQ.NUMBER
	   ;;   DES-MAC-MD5 CKSUM      CONFOUNDER
	   ;;   PADDED DATA
	 */
	if (tok.length < 5 * 8)
	  return GSS_S_BAD_MIC;
	memcpy (header, data, 8);
	memcpy (encseqno, data + 8, 8);
	memcpy (cksum, data + 16, 8);
	memcpy (confounder, data + 24, 8);
	pt = data + 32;
	/* XXX decrypt data iff confidential option chosen */
	rc = shishi_decrypt_iv_etype (k5->sh,
				      k5->key,
				      0, SHISHI_DES_CBC_NONE,
				      cksum, 8, encseqno, 8, &tmp, &outlen);
	if (rc != SHISHI_OK)
	  return GSS_S_FAILURE;
	if (outlen != 8)
	  return GSS_S_BAD_MIC;
	memcpy (seqno, tmp, 8);
	free (tmp);
	if (memcmp (seqno + 4, k5->acceptor ? "\x00\x00\x00\x00" :
		    "\xFF\xFF\xFF\xFF", 4) != 0)
	  return GSS_S_BAD_MIC;
	seqnr = C2I (seqno);
	if (seqnr != (k5->acceptor ? k5->initseqnr : k5->acceptseqnr))
	  return GSS_S_BAD_MIC;
	if (k5->acceptor)
	  k5->initseqnr++;
	else
	  k5->acceptseqnr++;
	/* Check pad */
	padlen = data[tok.length - 1];
	if (padlen > 8)
	  return GSS_S_BAD_MIC;
	for (i = 1; i <= padlen; i++)
	  if (data[tok.length - i] != (int) padlen)
	    return GSS_S_BAD_MIC;
	/* Write header and confounder next to data */
	memcpy (data + 16, header, 8);
	memcpy (data + 24, confounder, 8);
	/* Checksum header + confounder + data + pad */
	rc = shishi_checksum (k5->sh,
			      k5->key,
			      0, SHISHI_RSA_MD5_DES_GSS,
			      data + 16, tok.length - 16, &tmp, &tmplen);
	if (rc != SHISHI_OK || tmplen != 8)
	  return GSS_S_FAILURE;
	memcpy (data + 8, tmp, tmplen);
	/* Compare checksum */
	if (tmplen != 8 || memcmp (cksum, data + 8, 8) != 0)
	  return GSS_S_BAD_MIC;
	/* Copy output data */
	output_message_buffer->length = tok.length - 8 - 8 - 8 - 8 - padlen;
	output_message_buffer->value = malloc (output_message_buffer->length);
	if (!output_message_buffer->value)
	  {
	    if (minor_status)
	      *minor_status = ENOMEM;
	    return GSS_S_FAILURE;
	  }
	memcpy (output_message_buffer->value, pt,
		tok.length - 4 * 8 - padlen);
      }
      break;
    case 4:			/* 3DES */
      {
	size_t padlen;
	char *p;
	char *t;
	char cksum[20];
	size_t outlen, i;
	uint32_t seqnr;
	if (tok.length < 8 + 8 + 20 + 8 + 8)
	  return GSS_S_BAD_MIC;
	memcpy (cksum, data + 8 + 8, 20);
	/* XXX decrypt data iff confidential option chosen */
	p = data + 8;
	rc = shishi_decrypt_iv_etype (k5->sh,
				      k5->key,
				      0, SHISHI_DES3_CBC_NONE,
				      cksum, 8, p, 8, &t, &outlen);
	if (rc != SHISHI_OK || outlen != 8)
	  return GSS_S_FAILURE;
	memcpy (p, t, 8);
	free (t);
	if (memcmp (p + 4, k5->acceptor ? "\x00\x00\x00\x00" :
		    "\xFF\xFF\xFF\xFF", 4) != 0)
	  return GSS_S_BAD_MIC;
	seqnr = C2I (p);
	if (seqnr != (k5->acceptor ? k5->initseqnr : k5->acceptseqnr))
	  return GSS_S_BAD_MIC;
	if (k5->acceptor)
	  k5->initseqnr++;
	else
	  k5->acceptseqnr++;
	/* Check pad */
	padlen = data[tok.length - 1];
	if (padlen > 8)
	  return GSS_S_BAD_MIC;
	for (i = 1; i <= padlen; i++)
	  if (data[tok.length - i] != (int) padlen)
	    return GSS_S_BAD_MIC;
	/* Write header next to confounder */
	memcpy (data + 8 + 20, data, 8);
	/* Checksum header + confounder + data + pad */
	rc = shishi_checksum (k5->sh,
			      k5->key,
			      SHISHI_KEYUSAGE_GSS_R2,
			      SHISHI_HMAC_SHA1_DES3_KD, data + 20 + 8,
			      tok.length - 20 - 8, &t, &tmplen);
	if (rc != SHISHI_OK || tmplen != 20)
	  return GSS_S_FAILURE;
	memcpy (data + 8 + 8, t, tmplen);
	free (t);
	/* Compare checksum */
	if (tmplen != 20 || memcmp (cksum, data + 8 + 8, 20) != 0)
	  return GSS_S_BAD_MIC;
	/* Copy output data */
	output_message_buffer->length = tok.length - 8 - 20 - 8 - 8 - padlen;
	output_message_buffer->value = malloc (output_message_buffer->length);
	if (!output_message_buffer->value)
	  {
	    if (minor_status)
	      *minor_status = ENOMEM;
	    return GSS_S_FAILURE;
	  }
	memcpy (output_message_buffer->value, data + 20 + 8 + 8 + 8,
		tok.length - 20 - 8 - 8 - 8 - padlen);
      }
      break;
    default:
      return GSS_S_FAILURE;
    }
  return GSS_S_COMPLETE;
}
 | |||||
| ↓ | gss_krb5_accept_sec_context | 30 | 100 | 190 | krb5/context.c | 
| 
OM_uint32
gss_krb5_accept_sec_context (OM_uint32 * minor_status,
			     gss_ctx_id_t * context_handle,
			     const gss_cred_id_t acceptor_cred_handle,
			     const gss_buffer_t input_token_buffer,
			     const gss_channel_bindings_t input_chan_bindings,
			     gss_name_t * src_name,
			     gss_OID * mech_type,
			     gss_buffer_t output_token,
			     OM_uint32 * ret_flags,
			     OM_uint32 * time_rec,
			     gss_cred_id_t * delegated_cred_handle)
{
  gss_buffer_desc in;
  gss_ctx_id_t cx;
  _gss_krb5_ctx_t cxk5;
  _gss_krb5_cred_t crk5;
  OM_uint32 tmp_min_stat;
  int rc;
  if (minor_status)
    *minor_status = 0;
  if (ret_flags)
    *ret_flags = 0;
  if (!acceptor_cred_handle)
    /* XXX support GSS_C_NO_CREDENTIAL: acquire_cred() default server */
    return GSS_S_NO_CRED;
  if (*context_handle)
    return GSS_S_FAILURE;
  crk5 = acceptor_cred_handle->krb5;
  cx = calloc (sizeof (*cx), 1);
  if (!cx)
    {
      if (minor_status)
	*minor_status = ENOMEM;
      return GSS_S_FAILURE;
    }
  cxk5 = calloc (sizeof (*cxk5), 1);
  if (!cxk5)
    {
      free (cx);
      if (minor_status)
	*minor_status = ENOMEM;
      return GSS_S_FAILURE;
    }
  cx->mech = GSS_KRB5;
  cx->krb5 = cxk5;
  /* XXX cx->peer?? */
  *context_handle = cx;
  cxk5->sh = crk5->sh;
  cxk5->key = crk5->key;
  cxk5->acceptor = 1;
  rc = shishi_ap (cxk5->sh, &cxk5->ap);
  if (rc != SHISHI_OK)
    return GSS_S_FAILURE;
  rc = gss_decapsulate_token (input_token_buffer, GSS_KRB5, &in);
  if (rc != GSS_S_COMPLETE)
    return GSS_S_BAD_MIC;
  if (in.length < TOK_LEN)
    {
      gss_release_buffer (&tmp_min_stat, &in);
      return GSS_S_BAD_MIC;
    }
  if (memcmp (in.value, TOK_AP_REQ, TOK_LEN) != 0)
    {
      gss_release_buffer (&tmp_min_stat, &in);
      return GSS_S_BAD_MIC;
    }
  rc = shishi_ap_req_der_set (cxk5->ap, (char *) in.value + TOK_LEN,
			      in.length - TOK_LEN);
  gss_release_buffer (&tmp_min_stat, &in);
  if (rc != SHISHI_OK)
    return GSS_S_FAILURE;
  rc = shishi_ap_req_process (cxk5->ap, crk5->key);
  if (rc != SHISHI_OK)
    {
      if (minor_status)
	*minor_status = GSS_KRB5_S_G_VALIDATE_FAILED;
      return GSS_S_FAILURE;
    }
  rc = shishi_authenticator_seqnumber_get (cxk5->sh,
					   shishi_ap_authenticator (cxk5->ap),
					   &cxk5->initseqnr);
  if (rc != SHISHI_OK)
    return GSS_S_FAILURE;
  rc = _gss_krb5_checksum_parse (minor_status,
				 context_handle, input_chan_bindings);
  if (rc != GSS_S_COMPLETE)
    return GSS_S_FAILURE;
  cxk5->tkt = shishi_ap_tkt (cxk5->ap);
  cxk5->key = shishi_ap_key (cxk5->ap);
  if (shishi_apreq_mutual_required_p (crk5->sh, shishi_ap_req (cxk5->ap)))
    {
      Shishi_asn1 aprep;
      char *der;
      size_t len;
      rc = shishi_ap_rep_asn1 (cxk5->ap, &aprep);
      if (rc != SHISHI_OK)
	{
	  printf ("Error creating AP-REP: %s\n", shishi_strerror (rc));
	  return GSS_S_FAILURE;
	}
      rc = shishi_encapreppart_seqnumber_get (cxk5->sh,
					      shishi_ap_encapreppart
					      (cxk5->ap), &cxk5->acceptseqnr);
      if (rc != SHISHI_OK)
	{
	  /* A strict 1964 implementation would return
	     GSS_S_DEFECTIVE_TOKEN here.  gssapi-cfx permit absent
	     sequence number, though. */
	  cxk5->acceptseqnr = 0;
	}
      rc = shishi_asn1_to_der (crk5->sh, aprep, &der, &len);
      if (rc != SHISHI_OK)
	{
	  printf ("Error der encoding aprep: %s\n", shishi_strerror (rc));
	  return GSS_S_FAILURE;
	}
      rc = _gss_encapsulate_token_prefix (TOK_AP_REP, TOK_LEN,
					  der, len,
					  GSS_KRB5->elements,
					  GSS_KRB5->length,
					  &output_token->value,
					  &output_token->length);
      if (rc != 0)
	return GSS_S_FAILURE;
      if (ret_flags)
	*ret_flags = GSS_C_MUTUAL_FLAG;
    }
  else
    {
      output_token->value = NULL;
      output_token->length = 0;
    }
  if (src_name)
    {
      gss_name_t p;
      p = malloc (sizeof (*p));
      if (!p)
	{
	  if (minor_status)
	    *minor_status = ENOMEM;
	  return GSS_S_FAILURE;
	}
      rc = shishi_encticketpart_client (cxk5->sh,
					shishi_tkt_encticketpart (cxk5->tkt),
					&p->value, &p->length);
      if (rc != SHISHI_OK)
	return GSS_S_FAILURE;
      p->type = GSS_KRB5_NT_PRINCIPAL_NAME;
      *src_name = p;
    }
  /* PROT_READY is not mentioned in 1964/gssapi-cfx but we support
     it anyway. */
  if (ret_flags)
    *ret_flags |= GSS_C_PROT_READY_FLAG;
  if (minor_status)
    *minor_status = 0;
  return GSS_S_COMPLETE;
}
 | |||||
| ↓ | gss_display_status | 23 | 67 | 157 | error.c | 
| 
OM_uint32
gss_display_status (OM_uint32 * minor_status,
		    OM_uint32 status_value,
		    int status_type,
		    const gss_OID mech_type,
		    OM_uint32 * message_context, gss_buffer_t status_string)
{
  size_t i;
  bindtextdomain (PACKAGE PO_SUFFIX, LOCALEDIR);
  if (minor_status)
    *minor_status = 0;
  if (message_context)
    status_value &= ~*message_context;
  switch (status_type)
    {
    case GSS_C_GSS_CODE:
      if (message_context)
	{
	  *message_context |=
	    GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET;
	  if ((status_value & ~*message_context) == 0)
	    *message_context = 0;
	}
      switch (GSS_ROUTINE_ERROR (status_value))
	{
	case 0:
	  break;
	case GSS_S_BAD_MECH:
	case GSS_S_BAD_NAME:
	case GSS_S_BAD_NAMETYPE:
	case GSS_S_BAD_BINDINGS:
	case GSS_S_BAD_STATUS:
	case GSS_S_BAD_SIG:
	case GSS_S_NO_CRED:
	case GSS_S_NO_CONTEXT:
	case GSS_S_DEFECTIVE_TOKEN:
	case GSS_S_DEFECTIVE_CREDENTIAL:
	case GSS_S_CREDENTIALS_EXPIRED:
	case GSS_S_CONTEXT_EXPIRED:
	case GSS_S_FAILURE:
	case GSS_S_BAD_QOP:
	case GSS_S_UNAUTHORIZED:
	case GSS_S_UNAVAILABLE:
	case GSS_S_DUPLICATE_ELEMENT:
	case GSS_S_NAME_NOT_MN:
	  status_string->value =
	    strdup (_(gss_routine_errors
		      [(GSS_ROUTINE_ERROR (status_value) >>
			GSS_C_ROUTINE_ERROR_OFFSET) - 1].text));
	  if (!status_string->value)
	    {
	      if (minor_status)
		*minor_status = ENOMEM;
	      return GSS_S_FAILURE;
	    }
	  status_string->length = strlen (status_string->value);
	  return GSS_S_COMPLETE;
	  break;
	default:
	  return GSS_S_BAD_STATUS;
	  break;
	}
      if (message_context)
	{
	  *message_context |=
	    GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET;
	  if ((status_value & ~*message_context) == 0)
	    *message_context = 0;
	}
      switch (GSS_CALLING_ERROR (status_value))
	{
	case 0:
	  break;
	case GSS_S_CALL_INACCESSIBLE_READ:
	case GSS_S_CALL_INACCESSIBLE_WRITE:
	case GSS_S_CALL_BAD_STRUCTURE:
	  status_string->value =
	    strdup (_(gss_calling_errors
		      [(GSS_CALLING_ERROR (status_value) >>
			GSS_C_CALLING_ERROR_OFFSET) - 1].text));
	  if (!status_string->value)
	    {
	      if (minor_status)
		*minor_status = ENOMEM;
	      return GSS_S_FAILURE;
	    }
	  status_string->length = strlen (status_string->value);
	  return GSS_S_COMPLETE;
	  break;
	default:
	  return GSS_S_BAD_STATUS;
	  break;
	}
      for (i = 0; i < sizeof (gss_supplementary_errors) /
	   sizeof (gss_supplementary_errors[0]); i++)
	if (gss_supplementary_errors[i].err &
	    GSS_SUPPLEMENTARY_INFO (status_value))
	  {
	    status_string->value =
	      strdup (_(gss_supplementary_errors[i].text));
	    if (!status_string->value)
	      {
		if (minor_status)
		  *minor_status = ENOMEM;
		return GSS_S_FAILURE;
	      }
	    status_string->length = strlen (status_string->value);
	    *message_context |= gss_supplementary_errors[i].err;
	    if ((status_value & ~*message_context) == 0)
	      *message_context = 0;
	    return GSS_S_COMPLETE;
	  }
      if (GSS_SUPPLEMENTARY_INFO (status_value))
	return GSS_S_BAD_STATUS;
      if (message_context)
	*message_context = 0;
      status_string->value = strdup (_("No error"));
      if (!status_string->value)
	{
	  if (minor_status)
	    *minor_status = ENOMEM;
	  return GSS_S_FAILURE;
	}
      status_string->length = strlen (status_string->value);
      break;
    case GSS_C_MECH_CODE:
      {
	_gss_mech_api_t mech;
	mech = _gss_find_mech (mech_type);
	return mech->display_status (minor_status, status_value, status_type,
				     mech_type, message_context,
				     status_string);
      }
      break;
    default:
      return GSS_S_BAD_STATUS;
    }
  return GSS_S_COMPLETE;
}
 | |||||
| ↓ | gss_krb5_wrap | 22 | 112 | 213 | krb5/msg.c | 
| 
OM_uint32
gss_krb5_wrap (OM_uint32 * minor_status,
	       const gss_ctx_id_t context_handle,
	       int conf_req_flag,
	       gss_qop_t qop_req,
	       const gss_buffer_t input_message_buffer,
	       int *conf_state, gss_buffer_t output_message_buffer)
{
  _gss_krb5_ctx_t k5 = context_handle->krb5;
  size_t padlength;
  gss_buffer_desc data;
  char *p;
  size_t tmplen;
  int rc;
  switch (shishi_key_type (k5->key))
    {
      /* XXX implement other checksums */
    case SHISHI_DES_CBC_MD5:
      {
	char header[8];
	char seqno[8];
	char *eseqno;
	char *cksum;
	char confounder[8];
	/* Typical data:
	   ;; 02 01 00 00 ff ff ff ff  0c 22 1f 79 59 3d 00 cb
	   ;; d5 78 2f fb 50 d2 b8 59  fb b4 e0 9b d0 a2 fa dc
	   ;; 01 00 20 00 04 04 04 04
	   Translates into:
	   ;;   HEADER                 ENCRYPTED SEQ.NUMBER
	   ;;   DES-MAC-MD5 CKSUM      CONFOUNDER
	   ;;   PADDED DATA
	 */
	padlength = 8 - input_message_buffer->length % 8;
	data.length = 4 * 8 + input_message_buffer->length + padlength;
	p = malloc (data.length);
	if (!p)
	  {
	    if (minor_status)
	      *minor_status = ENOMEM;
	    return GSS_S_FAILURE;
	  }
	/* XXX encrypt data iff confidential option chosen */
	/* Setup header and confounder */
	memcpy (header, TOK_WRAP, 2);	/* TOK_ID: Wrap 0201 */
	memcpy (header + 2, "\x00\x00", 2);	/* SGN_ALG: DES-MAC-MD5 */
	memcpy (header + 4, "\xFF\xFF", 2);	/* SEAL_ALG: none */
	memcpy (header + 6, "\xFF\xFF", 2);	/* filler */
	rc = shishi_randomize (k5->sh, 0, confounder, 8);
	if (rc != SHISHI_OK)
	  return GSS_S_FAILURE;
	/* Compute checksum over header, confounder, input string, and pad */
	memcpy (p, header, 8);
	memcpy (p + 8, confounder, 8);
	memcpy (p + 16, input_message_buffer->value,
		input_message_buffer->length);
	memset (p + 16 + input_message_buffer->length,
		(int) padlength, padlength);
	rc = shishi_checksum (k5->sh,
			      k5->key,
			      0, SHISHI_RSA_MD5_DES_GSS,
			      p,
			      16 + input_message_buffer->length + padlength,
			      &cksum, &tmplen);
	if (rc != SHISHI_OK || tmplen != 8)
	  return GSS_S_FAILURE;
	/* seq_nr */
	if (k5->acceptor)
	  {
	    seqno[0] = k5->acceptseqnr & 0xFF;
	    seqno[1] = k5->acceptseqnr >> 8 & 0xFF;
	    seqno[2] = k5->acceptseqnr >> 16 & 0xFF;
	    seqno[3] = k5->acceptseqnr >> 24 & 0xFF;
	    memset (seqno + 4, 0xFF, 4);
	  }
	else
	  {
	    seqno[0] = k5->initseqnr & 0xFF;
	    seqno[1] = k5->initseqnr >> 8 & 0xFF;
	    seqno[2] = k5->initseqnr >> 16 & 0xFF;
	    seqno[3] = k5->initseqnr >> 24 & 0xFF;
	    memset (seqno + 4, 0, 4);
	  }
	rc = shishi_encrypt_iv_etype (k5->sh, k5->key, 0,
				      SHISHI_DES_CBC_NONE, cksum, 8,
				      seqno, 8, &eseqno, &tmplen);
	if (rc != SHISHI_OK || tmplen != 8)
	  return GSS_S_FAILURE;
	/* put things in place */
	memcpy (p, header, 8);
	memcpy (p + 8, eseqno, 8);
	free (eseqno);
	memcpy (p + 16, cksum, 8);
	free (cksum);
	memcpy (p + 24, confounder, 8);
	memcpy (p + 32, input_message_buffer->value,
		input_message_buffer->length);
	memset (p + 32 + input_message_buffer->length,
		(int) padlength, padlength);
	data.value = p;
	rc = gss_encapsulate_token (&data, GSS_KRB5, output_message_buffer);
	if (rc != GSS_S_COMPLETE)
	  return GSS_S_FAILURE;
	if (k5->acceptor)
	  k5->acceptseqnr++;
	else
	  k5->initseqnr++;
      }
      break;
    case SHISHI_DES3_CBC_HMAC_SHA1_KD:
      {
	char *tmp;
	padlength = 8 - input_message_buffer->length % 8;
	data.length = 8 + 8 + 20 + 8 + input_message_buffer->length
	  + padlength;
	p = malloc (data.length);
	if (!p)
	  {
	    if (minor_status)
	      *minor_status = ENOMEM;
	    return GSS_S_FAILURE;
	  }
	/* XXX encrypt data iff confidential option chosen */
	/* Compute checksum over header, confounder, input string, and pad */
	memcpy (p, TOK_WRAP, 2);	/* TOK_ID: Wrap */
	memcpy (p + 2, "\x04\x00", 2);	/* SGN_ALG: 3DES */
	memcpy (p + 4, "\xFF\xFF", 2);	/* SEAL_ALG: none */
	memcpy (p + 6, "\xFF\xFF", 2);	/* filler */
	rc = shishi_randomize (k5->sh, 0, p + 8, 8);
	if (rc != SHISHI_OK)
	  return GSS_S_FAILURE;
	memcpy (p + 16, input_message_buffer->value,
		input_message_buffer->length);
	memset (p + 16 + input_message_buffer->length,
		(int) padlength, padlength);
	rc = shishi_checksum (k5->sh,
			      k5->key,
			      SHISHI_KEYUSAGE_GSS_R2,
			      SHISHI_HMAC_SHA1_DES3_KD, p,
			      16 + input_message_buffer->length + padlength,
			      &tmp, &tmplen);
	if (rc != SHISHI_OK || tmplen != 20)
	  return GSS_S_FAILURE;
	memcpy (p + 16, tmp, tmplen);
	memcpy (p + 36, p + 8, 8);
	/* seq_nr */
	if (k5->acceptor)
	  {
	    (p + 8)[0] = k5->acceptseqnr & 0xFF;
	    (p + 8)[1] = k5->acceptseqnr >> 8 & 0xFF;
	    (p + 8)[2] = k5->acceptseqnr >> 16 & 0xFF;
	    (p + 8)[3] = k5->acceptseqnr >> 24 & 0xFF;
	    memset (p + 8 + 4, 0xFF, 4);
	  }
	else
	  {
	    (p + 8)[0] = k5->initseqnr & 0xFF;
	    (p + 8)[1] = k5->initseqnr >> 8 & 0xFF;
	    (p + 8)[2] = k5->initseqnr >> 16 & 0xFF;
	    (p + 8)[3] = k5->initseqnr >> 24 & 0xFF;
	    memset (p + 8 + 4, 0, 4);
	  }
	rc = shishi_encrypt_iv_etype (k5->sh, k5->key, 0, SHISHI_DES3_CBC_NONE, p + 16, 8,	/* cksum */
				      p + 8, 8, &tmp, &tmplen);
	if (rc != SHISHI_OK || tmplen != 8)
	  return GSS_S_FAILURE;
	memcpy (p + 8, tmp, tmplen);
	free (tmp);
	memcpy (p + 8 + 8 + 20 + 8, input_message_buffer->value,
		input_message_buffer->length);
	memset (p + 8 + 8 + 20 + 8 + input_message_buffer->length,
		(int) padlength, padlength);
	data.value = p;
	rc = gss_encapsulate_token (&data, GSS_KRB5, output_message_buffer);
	if (rc != GSS_S_COMPLETE)
	  return GSS_S_FAILURE;
	if (k5->acceptor)
	  k5->acceptseqnr++;
	else
	  k5->initseqnr++;
	break;
      }
    default:
      return GSS_S_FAILURE;
    }
  return GSS_S_COMPLETE;
}
 | |||||
| ↓ | gss_init_sec_context | 16 | 38 | 88 | context.c | 
| 
OM_uint32
gss_init_sec_context (OM_uint32 * minor_status,
		      const gss_cred_id_t initiator_cred_handle,
		      gss_ctx_id_t * context_handle,
		      const gss_name_t target_name,
		      const gss_OID mech_type,
		      OM_uint32 req_flags,
		      OM_uint32 time_req,
		      const gss_channel_bindings_t input_chan_bindings,
		      const gss_buffer_t input_token,
		      gss_OID * actual_mech_type,
		      gss_buffer_t output_token,
		      OM_uint32 * ret_flags, OM_uint32 * time_rec)
{
  OM_uint32 maj_stat;
  _gss_mech_api_t mech;
  int freecontext = 0;
  if (output_token)
    {
      output_token->length = 0;
      output_token->value = NULL;
    }
  if (ret_flags)
    *ret_flags = 0;
  if (!context_handle)
    {
      if (minor_status)
	*minor_status = 0;
      return GSS_S_NO_CONTEXT | GSS_S_CALL_INACCESSIBLE_READ;
    }
  if (output_token == GSS_C_NO_BUFFER)
    {
      if (minor_status)
	*minor_status = 0;
      return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
    }
  if (*context_handle == GSS_C_NO_CONTEXT)
    mech = _gss_find_mech (mech_type);
  else
    mech = _gss_find_mech ((*context_handle)->mech);
  if (mech == NULL)
    {
      if (minor_status)
	*minor_status = 0;
      return GSS_S_BAD_MECH;
    }
  if (actual_mech_type)
    *actual_mech_type = mech->mech;
  if (*context_handle == GSS_C_NO_CONTEXT)
    {
      *context_handle = calloc (sizeof (**context_handle), 1);
      if (!*context_handle)
	{
	  if (minor_status)
	    *minor_status = ENOMEM;
	  return GSS_S_FAILURE;
	}
      (*context_handle)->mech = mech->mech;
      freecontext = 1;
    }
  maj_stat = mech->init_sec_context (minor_status,
				     initiator_cred_handle,
				     context_handle,
				     target_name,
				     mech_type,
				     req_flags,
				     time_req,
				     input_chan_bindings,
				     input_token,
				     actual_mech_type,
				     output_token, ret_flags, time_rec);
  if (GSS_ERROR (maj_stat) && freecontext)
    {
      free (*context_handle);
      *context_handle = GSS_C_NO_CONTEXT;
    }
  return maj_stat;
}
 | |||||
| ↓ | gss_krb5_init_sec_context | 16 | 38 | 107 | krb5/context.c | 
| 
OM_uint32
gss_krb5_init_sec_context (OM_uint32 * minor_status,
			   const gss_cred_id_t initiator_cred_handle,
			   gss_ctx_id_t * context_handle,
			   const gss_name_t target_name,
			   const gss_OID mech_type,
			   OM_uint32 req_flags,
			   OM_uint32 time_req,
			   const gss_channel_bindings_t input_chan_bindings,
			   const gss_buffer_t input_token,
			   gss_OID * actual_mech_type,
			   gss_buffer_t output_token,
			   OM_uint32 * ret_flags, OM_uint32 * time_rec)
{
  gss_ctx_id_t ctx = *context_handle;
  _gss_krb5_ctx_t k5 = ctx->krb5;
  OM_uint32 maj_stat;
  int rc;
  if (minor_status)
    *minor_status = 0;
  if (initiator_cred_handle)
    {
      /* We only support the default initiator.  See k5internal.h for
         adding a Shishi_tkt to the credential structure.  I'm not sure
         what the use would be -- user-to-user authentication perhaps?
         Later: if you have tickets for foo@BAR and bar@FOO, it may be
         useful to call gss_acquire_cred first to chose which one to
         initiate the context with.  Not many applications need this. */
      return GSS_S_NO_CRED;
    }
  if (k5 == NULL)
    {
      k5 = ctx->krb5 = calloc (sizeof (*k5), 1);
      if (!k5)
	{
	  if (minor_status)
	    *minor_status = ENOMEM;
	  return GSS_S_FAILURE;
	}
      rc = shishi_init (&k5->sh);
      if (rc != SHISHI_OK)
	return GSS_S_FAILURE;
    }
  if (!k5->reqdone)
    {
      maj_stat = init_request (minor_status,
			       initiator_cred_handle,
			       context_handle,
			       target_name,
			       mech_type,
			       req_flags,
			       time_req,
			       input_chan_bindings,
			       input_token,
			       actual_mech_type,
			       output_token, ret_flags, time_rec);
      if (GSS_ERROR (maj_stat))
	return maj_stat;
      k5->flags = req_flags & (	/* GSS_C_DELEG_FLAG | */
				GSS_C_MUTUAL_FLAG |
				GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG |
				GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);
      /* PROT_READY is not mentioned in 1964/gssapi-cfx but we support
         it anyway. */
      k5->flags |= GSS_C_PROT_READY_FLAG;
      if (ret_flags)
	*ret_flags = k5->flags;
      k5->key = shishi_ap_key (k5->ap);
      k5->reqdone = 1;
    }
  else if (k5->reqdone && k5->flags & GSS_C_MUTUAL_FLAG && !k5->repdone)
    {
      maj_stat = init_reply (minor_status,
			     initiator_cred_handle,
			     context_handle,
			     target_name,
			     mech_type,
			     req_flags,
			     time_req,
			     input_chan_bindings,
			     input_token,
			     actual_mech_type,
			     output_token, ret_flags, time_rec);
      if (GSS_ERROR (maj_stat))
	return maj_stat;
      if (ret_flags)
	*ret_flags = k5->flags;
      k5->repdone = 1;
    }
  else
    maj_stat = GSS_S_FAILURE;
  if (time_rec)
    *time_rec = gss_krb5_tktlifetime (k5->tkt);
  return maj_stat;
}
 | |||||
| ↓ | gss_krb5_canonicalize_name | 14 | 40 | 83 | krb5/name.c | 
| 
OM_uint32
gss_krb5_canonicalize_name (OM_uint32 * minor_status,
			    const gss_name_t input_name,
			    const gss_OID mech_type, gss_name_t * output_name)
{
  OM_uint32 maj_stat;
  if (minor_status)
    *minor_status = 0;
  /* We consider (a zero terminated) GSS_KRB5_NT_PRINCIPAL_NAME the
     canonical mechanism name type.  Convert everything into it.  */
  if (gss_oid_equal (input_name->type, GSS_C_NT_EXPORT_NAME))
    {
      if (input_name->length > 15)
	{
	  *output_name = malloc (sizeof (**output_name));
	  if (!*output_name)
	    {
	      if (minor_status)
		*minor_status = ENOMEM;
	      return GSS_S_FAILURE;
	    }
	  (*output_name)->type = GSS_KRB5_NT_PRINCIPAL_NAME;
	  (*output_name)->length = input_name->length - 15;
	  (*output_name)->value = malloc ((*output_name)->length + 1);
	  if (!(*output_name)->value)
	    {
	      free (*output_name);
	      if (minor_status)
		*minor_status = ENOMEM;
	      return GSS_S_FAILURE;
	    }
	  memcpy ((*output_name)->value, input_name->value + 15,
		  (*output_name)->length);
	  (*output_name)->value[(*output_name)->length] = '\0';
	}
      else
	{
	  return GSS_S_BAD_NAME;
	}
    }
  else if (gss_oid_equal (input_name->type, GSS_C_NT_HOSTBASED_SERVICE))
    {
      char *p;
      /* We don't support service-names without hostname part because
         we can't compute a canonicalized name of the local host.
         Calling gethostname does not give a canonicalized name. */
      if (!memchr (input_name->value, '@', input_name->length))
	{
	  *minor_status = GSS_KRB5_S_G_BAD_SERVICE_NAME;
	  return GSS_S_COMPLETE;
	}
      /* We don't do DNS name canoncalization since that is
         insecure. */
      maj_stat = gss_duplicate_name (minor_status, input_name, output_name);
      if (GSS_ERROR (maj_stat))
	return maj_stat;
      (*output_name)->type = GSS_KRB5_NT_PRINCIPAL_NAME;
      p = memchr ((*output_name)->value, '@', (*output_name)->length);
      if (p)
	*p = '/';
    }
  else if (gss_oid_equal (input_name->type, GSS_KRB5_NT_PRINCIPAL_NAME))
    {
      maj_stat = gss_duplicate_name (minor_status, input_name, output_name);
      if (GSS_ERROR (maj_stat))
	return maj_stat;
    }
  else
    {
      *output_name = GSS_C_NO_NAME;
      return GSS_S_BAD_NAMETYPE;
    }
  return GSS_S_COMPLETE;
}
 | |||||
| ↓ | gss_add_oid_set_member | 13 | 29 | 56 | misc.c | 
| 
OM_uint32
gss_add_oid_set_member (OM_uint32 * minor_status,
			const gss_OID member_oid, gss_OID_set * oid_set)
{
  OM_uint32 major_stat;
  int present;
  if (!member_oid || member_oid->length == 0 || member_oid->elements == NULL)
    {
      if (minor_status)
	*minor_status = 0;
      return GSS_S_FAILURE;
    }
  major_stat = gss_test_oid_set_member (minor_status, member_oid,
					*oid_set, &present);
  if (GSS_ERROR (major_stat))
    return major_stat;
  if (present)
    {
      if (minor_status)
	*minor_status = 0;
      return GSS_S_COMPLETE;
    }
  if ((*oid_set)->count + 1 == 0)	/* integer overflow */
    {
      if (minor_status)
	*minor_status = 0;
      return GSS_S_FAILURE;
    }
  (*oid_set)->count++;
  {
    gss_OID tmp;
    tmp = realloc ((*oid_set)->elements, (*oid_set)->count *
		   sizeof (*(*oid_set)->elements));
    if (!tmp)
      {
	if (minor_status)
	  *minor_status = ENOMEM;
	return GSS_S_FAILURE;
      }
    (*oid_set)->elements = tmp;
  }
  major_stat = _gss_copy_oid (minor_status, member_oid,
			      (*oid_set)->elements + ((*oid_set)->count - 1));
  if (GSS_ERROR (major_stat))
    return major_stat;
  return GSS_S_COMPLETE;
}
 | |||||
| ↓ | acquire_cred1 | 12 | 34 | 68 | krb5/cred.c | 
| 
static OM_uint32
acquire_cred1 (OM_uint32 * minor_status,
	       const gss_name_t desired_name,
	       OM_uint32 time_req,
	       const gss_OID_set desired_mechs,
	       gss_cred_usage_t cred_usage,
	       gss_cred_id_t * output_cred_handle,
	       gss_OID_set * actual_mechs, OM_uint32 * time_rec)
{
  gss_name_t name = desired_name;
  _gss_krb5_cred_t k5 = (*output_cred_handle)->krb5;
  OM_uint32 maj_stat;
  if (desired_name == GSS_C_NO_NAME)
    {
      gss_buffer_desc buf = { 4, (char *) "host" };
      maj_stat = gss_import_name (minor_status, &buf,
				  GSS_C_NT_HOSTBASED_SERVICE, &name);
      if (GSS_ERROR (maj_stat))
	return maj_stat;
    }
  maj_stat = gss_krb5_canonicalize_name (minor_status, name,
					 GSS_KRB5, &k5->peerptr);
  if (GSS_ERROR (maj_stat))
    return maj_stat;
  if (desired_name == GSS_C_NO_NAME)
    {
      maj_stat = gss_release_name (minor_status, &name);
      if (GSS_ERROR (maj_stat))
	return maj_stat;
    }
  if (shishi_init_server (&k5->sh) != SHISHI_OK)
    return GSS_S_FAILURE;
  {
    char *p;
    p = malloc (k5->peerptr->length + 1);
    if (!p)
      {
	if (minor_status)
	  *minor_status = ENOMEM;
	return GSS_S_FAILURE;
      }
    memcpy (p, k5->peerptr->value, k5->peerptr->length);
    p[k5->peerptr->length] = 0;
    k5->key = shishi_hostkeys_for_serverrealm (k5->sh, p, NULL);
    free (p);
  }
  if (!k5->key)
    {
      if (minor_status)
	*minor_status = GSS_KRB5_S_KG_KEYTAB_NOMATCH;
      return GSS_S_NO_CRED;
    }
  if (time_rec)
    *time_rec = GSS_C_INDEFINITE;
  return GSS_S_COMPLETE;
}
 | |||||
| ↓ | _gss_krb5_checksum_parse | 11 | 39 | 72 | krb5/checksum.c | 
| 
OM_uint32
_gss_krb5_checksum_parse (OM_uint32 * minor_status,
			  gss_ctx_id_t * context_handle,
			  const gss_channel_bindings_t input_chan_bindings)
{
  gss_ctx_id_t ctx = *context_handle;
  _gss_krb5_ctx_t k5 = ctx->krb5;
  char *out = NULL;
  size_t len = 0;
  int rc;
  char *md5hash;
  if (shishi_ap_authenticator_cksumtype (k5->ap) != 0x8003)
    {
      if (minor_status)
	*minor_status = GSS_KRB5_S_G_VALIDATE_FAILED;
      return GSS_S_FAILURE;
    }
  rc = shishi_ap_authenticator_cksumdata (k5->ap, out, &len);
  if (rc != SHISHI_TOO_SMALL_BUFFER)
    return GSS_S_FAILURE;
  out = malloc (len);
  if (!out)
    {
      if (minor_status)
	*minor_status = ENOMEM;
      return GSS_S_FAILURE;
    }
  rc = shishi_ap_authenticator_cksumdata (k5->ap, out, &len);
  if (rc != SHISHI_OK)
    {
      free (out);
      return GSS_S_FAILURE;
    }
  if (memcmp (out, "\x10\x00\x00\x00", 4) != 0)
    {
      free (out);
      return GSS_S_DEFECTIVE_TOKEN;
    }
  if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS)
    {
      rc = hash_cb (minor_status, context_handle,
		    input_chan_bindings, &md5hash);
      if (rc != GSS_S_COMPLETE)
	{
	  free (out);
	  return GSS_S_DEFECTIVE_TOKEN;
	}
      rc = memcmp (&out[4], md5hash, 16);
      free (md5hash);
    }
  else
    {
      char zeros[16];
      memset (&zeros[0], 0, sizeof zeros);
      rc = memcmp (&out[4], zeros, 16);
    }
  free (out);
  if (rc != 0)
    return GSS_S_DEFECTIVE_TOKEN;
  return GSS_S_COMPLETE;
}
 | |||||
| ↓ | gss_inquire_saslname_for_mech | 11 | 24 | 47 | saslname.c | 
| 
OM_uint32
gss_inquire_saslname_for_mech (OM_uint32 * minor_status,
			       const gss_OID desired_mech,
			       gss_buffer_t sasl_mech_name,
			       gss_buffer_t mech_name,
			       gss_buffer_t mech_description)
{
  _gss_mech_api_t m;
  if (!desired_mech)
    {
      if (minor_status)
	*minor_status = 0;
      return GSS_S_CALL_INACCESSIBLE_READ;
    }
  m = _gss_find_mech_no_default (desired_mech);
  if (!m)
    {
      if (minor_status)
	*minor_status = 0;
      return GSS_S_BAD_MECH;
    }
  bindtextdomain (PACKAGE PO_SUFFIX, LOCALEDIR);
  if (dup_data (minor_status, sasl_mech_name,
		m->sasl_name, 0) != GSS_S_COMPLETE)
    return GSS_S_FAILURE;
  if (dup_data (minor_status, mech_name, m->mech_name, 0) != GSS_S_COMPLETE)
    {
      if (sasl_mech_name)
	free (sasl_mech_name->value);
      return GSS_S_FAILURE;
    }
  if (dup_data (minor_status, mech_description,
		m->mech_description, 1) != GSS_S_COMPLETE)
    {
      if (sasl_mech_name)
	free (sasl_mech_name->value);
      if (mech_name)
	free (mech_name->value);
      return GSS_S_FAILURE;
    }
  return GSS_S_COMPLETE;
}
 | |||||
| init_request | 10 | 38 | 81 | krb5/context.c | |
| hash_cb | 10 | 36 | 61 | krb5/checksum.c | |
| gss_acquire_cred | 10 | 27 | 63 | cred.c | |
| gss_duplicate_name | 10 | 26 | 42 | name.c | |
| inquire_cred | 10 | 21 | 40 | krb5/cred.c | |
| _gss_decapsulate_token | 9 | 33 | 51 | asn1.c | |
| gss_krb5_acquire_cred | 9 | 25 | 53 | krb5/cred.c | |
| gss_krb5_display_status | 9 | 24 | 68 | krb5/error.c | |
| gss_delete_sec_context | 8 | 22 | 43 | context.c | |
| gss_import_name | 8 | 21 | 37 | name.c | |
| gss_release_cred | 8 | 21 | 36 | cred.c | |
| gss_inquire_cred_by_mech | 8 | 20 | 51 | cred.c | |
| gss_display_name | 8 | 17 | 30 | name.c | |
| gss_compare_name | 7 | 9 | 20 | name.c | |
| _gss_find_mech_by_saslname | 7 | 9 | 17 | meta.c | |
| init_reply | 7 | 24 | 58 | krb5/context.c | |
| gss_decapsulate_token | 7 | 21 | 36 | asn1.c | |
| _gss_asn1_get_length_der | 7 | 20 | 43 | asn1.c | |
| gss_accept_sec_context | 7 | 15 | 51 | context.c | |
| _gss_copy_oid | 7 | 14 | 25 | misc.c | |
| _gss_krb5_checksum_pack | 6 | 25 | 124 | krb5/checksum.c | |
| _gss_inquire_mechs_for_name3 | 6 | 17 | 30 | name.c | |
| gss_export_name | 6 | 16 | 33 | name.c | |
| gss_inquire_cred | 6 | 16 | 36 | cred.c | |
| gss_inquire_mechs_for_name | 6 | 15 | 30 | name.c | |
| _gss_asn1_length_der | 6 | 15 | 32 | asn1.c | |
| gss_test_oid_set_member | 6 | 14 | 28 | misc.c | |
| gss_inquire_mech_for_saslname | 6 | 13 | 27 | saslname.c | |
| gss_inquire_names_for_mech | 5 | 17 | 29 | name.c | |
| gss_release_oid_set | 5 | 14 | 20 | misc.c | |
| gss_context_time | 5 | 11 | 23 | context.c | |
| gss_get_mic | 5 | 11 | 26 | msg.c | |
| gss_krb5_delete_sec_context | 5 | 11 | 21 | krb5/context.c | |
| gss_unwrap | 5 | 11 | 27 | msg.c | |
| dup_data | 5 | 11 | 21 | saslname.c | |
| gss_wrap | 5 | 11 | 28 | msg.c | |
| gss_encapsulate_token | 5 | 11 | 26 | asn1.c | |
| gss_verify_mic | 5 | 11 | 26 | msg.c | |
| gss_krb5_context_time | 5 | 10 | 23 | krb5/context.c | |
| gss_release_name | 5 | 10 | 20 | name.c | |
| _gss_encapsulate_token_prefix | 4 | 25 | 39 | asn1.c | |
| gss_krb5_export_name | 4 | 20 | 32 | krb5/name.c | |
| _gss_inquire_mechs_for_name1 | 4 | 12 | 22 | name.c | |
| _gss_inquire_mechs_for_name2 | 4 | 11 | 22 | name.c | |
| gss_indicate_mechs | 4 | 11 | 20 | misc.c | |
| _gss_indicate_mechs1 | 4 | 11 | 18 | meta.c | |
| gss_create_empty_oid_set | 4 | 10 | 18 | misc.c | |
| gss_oid_equal | 4 | 1 | 8 | oid.c | |
| gss_krb5_release_cred | 3 | 9 | 16 | krb5/cred.c | |
| gss_krb5_tktlifetime | 3 | 8 | 16 | krb5/utils.c | |
| _gss_find_mech_no_default | 3 | 7 | 11 | meta.c | |
| gss_canonicalize_name | 3 | 7 | 18 | name.c | |
| gss_release_buffer | 3 | 7 | 15 | misc.c | |
| _gss_find_mech | 3 | 4 | 12 | meta.c | |
| gss_check_version | 3 | 3 | 8 | version.c | |
| gss_krb5_inquire_cred_by_mech | 2 | 5 | 19 | krb5/cred.c | |
| gss_userok | 2 | 1 | 7 | ext.c | |
| pack_uint32 | 1 | 4 | 8 | krb5/checksum.c | |
| gss_process_context_token | 1 | 1 | 7 | context.c | |
| gss_unseal | 1 | 1 | 11 | obsolete.c | |
| gss_seal | 1 | 1 | 12 | obsolete.c | |
| gss_krb5_verify_mic | 1 | 1 | 8 | krb5/msg.c | |
| gss_verify | 1 | 1 | 9 | obsolete.c | |
| gss_krb5_get_mic | 1 | 1 | 9 | krb5/msg.c | |
| gss_add_cred | 1 | 1 | 14 | cred.c | |
| gss_sign | 1 | 1 | 9 | obsolete.c | |
| gss_krb5_inquire_cred | 1 | 1 | 11 | krb5/cred.c | |
| gss_import_sec_context | 1 | 1 | 7 | context.c | |
| gss_export_sec_context | 1 | 1 | 7 | context.c | |
| gss_wrap_size_limit | 1 | 1 | 9 | context.c | |
| gss_inquire_context | 1 | 1 | 11 | context.c | |