Expired Krb5 TGT prevents GSSAPI from calling SPNEGO plugins

Adam Bernstein abernstein at vmware.com
Tue Mar 1 14:00:02 EST 2016


_*BACKGROUND*_*:*
VMware vcenter product initial configuration uses a GSSAPI plugin 
implementing the Secure Remote Password (SRP) protocol. This is a 
"bootstrap" authentication protocol, used to store initial 
authentication identities in our LDAP directory, and other operations 
requiring security. During configuration, DCE/RPC secured by GSSAPI/SRP 
is used. Once configured, DCE/RPC secured by GSSAPI/KRB5 is used. We are 
using MIT Kerberos version 1.14.


_*ISSUE:*_
During development, we discovered an expired Kerberos credentials cache 
causes GSSAPI krb5_gss_inquire_cred() to fail with the error 
GSS_S_CREDENTIALS_EXPIRED. This prevents SPNEGO from attempting 
authentication with plugin mechanisms configured in /etc/gss/mech.

To reproduce this problem, the current user must have a Kerberos 
credentials cache containing an expired krbtgt. For example, see the 
below expired credentials cache:

# /opt/likewise/bin/klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: sles11-test2.testlab15.com at VSPHERE.LOCAL

Valid starting       Expires              Service principal
02/24/2016 16:28:36  02/24/2016 16:34:34 krbtgt/VSPHERE.LOCAL at VSPHERE.LOCAL

GSSAPI authentication with SRP is not possible for the user 
"sles11-test2.testlab15.com at VSPHERE.LOCAL" when this expired ticket 
exists. After deleting this expired cache, SPNEGO authentication 
proceeds to SRP.


_*PROPOSED SOLUTION:*_
Attached is a patch for gssapi/mechglue/g_inq_cred.c : gss_inq_cred() 
which fixes this issue.

The strategy used in this patch is rather than returning the error 
GSS_S_CREDENTIALS_EXPIRED, skip adding the Kerberos mech OID to the 
"mechs" OID set.

When krb5_gss_inquire_cred() returns GSS_S_CREDENTIALS_EXPIRED, 
mech_offset is set to 1. The assumption made here is the Kerberos mech 
OID always exists and is always first in the union_cred->mechs array. 
When GSS_S_CREDENTIALS_EXPIRED is returned, the Kerberos OID is not 
added to the mechs OID set.

Should "mechanisms" be NULL, the original behavior of returning an empty 
OID set is preserved, unless krb5_gss_inquire_cred() failed with 
GSS_S_CREDENTIALS_EXPIRED, then that error is returned.

Note: The patch does properly preserve tab/space indentation. Depending 
on your email reader, this may not appear to be true.

Please consider accepting the following patch for inclusion in the next 
release of MIT Kerberos.

Thanks,
Adam
====
Adam Bernstein
Staff Engineer, VMware
abernstein at vmware.com
500 108th Ave NE, Bellevue WA, 98004



-------------- next part --------------
==== //public/vmware-likewise-open-6-1/likewise-stable/likewise-v6.1/likewise-open/krb5/src/lib/gssapi/mechglue/g_inq_cred.c#3 - /mnt/hgfs/abernstein/workspaces/panda/vmware-likewise-open-6-1/likewise-stable/likewise-v6.1/likewise-open/krb5/src/lib/gssapi/mechglue/g_inq_cred.c ====
***************
*** 51,56 ****
--- 51,58 ----
  
  {
      OM_uint32		status, temp_minor_status;
+     OM_uint32		status2 = 0;
+     OM_uint32		mech_offset = 0;
      gss_union_cred_t	union_cred;
      gss_mechanism	mech;
      gss_cred_id_t	mech_cred;
***************
*** 100,110 ****
      status = mech->gss_inquire_cred(minor_status, mech_cred,
  				    name ? &mech_name : NULL,
  				    lifetime, cred_usage, NULL);
!     if (status != GSS_S_COMPLETE) {
  	map_error(minor_status, mech);
  	return(status);
      }
  
      if (name) {
  	/* Convert mech_name into a union_name equivalent. */
  	status = gssint_convert_name_to_union_name(&temp_minor_status,
--- 102,117 ----
      status = mech->gss_inquire_cred(minor_status, mech_cred,
  				    name ? &mech_name : NULL,
  				    lifetime, cred_usage, NULL);
!     if (status != GSS_S_COMPLETE && status != GSS_S_CREDENTIALS_EXPIRED) {
  	map_error(minor_status, mech);
  	return(status);
      }
  
+     status2 = status;
+     if (status2 == GSS_S_CREDENTIALS_EXPIRED) {
+         mech_offset = 1;
+     }
+ 
      if (name) {
  	/* Convert mech_name into a union_name equivalent. */
  	status = gssint_convert_name_to_union_name(&temp_minor_status,
***************
*** 122,134 ****
       */
  
      if(mechanisms != NULL) {
! 	if (union_cred) {
  	    status = gssint_make_public_oid_set(minor_status,
! 						union_cred->mechs_array,
! 						union_cred->count, &mechs);
  	    if (GSS_ERROR(status))
  		goto error;
  	} else {
  	    status = gss_create_empty_oid_set(minor_status, &mechs);
  	    if (GSS_ERROR(status))
  		goto error;
--- 129,145 ----
       */
  
      if(mechanisms != NULL) {
! 	if (union_cred && (union_cred->count - mech_offset) > 0) {
  	    status = gssint_make_public_oid_set(minor_status,
! 						&union_cred->mechs_array[mech_offset],
! 						union_cred->count - mech_offset, &mechs);
  	    if (GSS_ERROR(status))
  		goto error;
  	} else {
+             if (status2 == GSS_S_CREDENTIALS_EXPIRED) {
+ 		status = GSS_S_CREDENTIALS_EXPIRED;
+ 		goto error;
+             }
  	    status = gss_create_empty_oid_set(minor_status, &mechs);
  	    if (GSS_ERROR(status))
  		goto error;


More information about the krbdev mailing list