示例#1
0
int
ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
	static gss_name_t saved_name = GSS_C_NO_NAME;
	static OM_uint32 saved_lifetime = 0;
	static gss_OID saved_mech = GSS_C_NO_OID;
	static gss_name_t name;
	static OM_uint32 last_call = 0;
	OM_uint32 lifetime, now, major, minor;
	int equal;
	gss_cred_usage_t usage = GSS_C_INITIATE;
	
	now = time(NULL);

	if (ctxt) {
		debug("Rekey has happened - updating saved versions");

		if (saved_name != GSS_C_NO_NAME)
			gss_release_name(&minor, &saved_name);

		major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
		    &saved_name, &saved_lifetime, NULL, NULL);

		if (!GSS_ERROR(major)) {
			saved_mech = ctxt->oid;
		        saved_lifetime+= now;
		} else {
			/* Handle the error */
		}
		return 0;
	}

	if (now - last_call < 10)
		return 0;

	last_call = now;

	if (saved_mech == GSS_C_NO_OID)
		return 0;
	
	major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, 
	    &name, &lifetime, NULL, NULL);
	if (major == GSS_S_CREDENTIALS_EXPIRED)
		return 0;
	else if (GSS_ERROR(major))
		return 0;

	major = gss_compare_name(&minor, saved_name, name, &equal);
	gss_release_name(&minor, &name);
	if (GSS_ERROR(major))
		return 0;

	if (equal && (saved_lifetime < lifetime + now - 10))
		return 1;

	return 0;
}
示例#2
0
OM_uint32
get_cred_lifetime(const gss_cred_id_t credential_handle)
{
	OM_uint32        major_status = 0;
	OM_uint32        minor_status = 0;
	gss_name_t       name = NULL;
	OM_uint32        lifetime;
	gss_OID_set      mechanisms;
	gss_cred_usage_t cred_usage;

	major_status = gss_inquire_cred(
			&minor_status,
			credential_handle,
			&name,
			&lifetime,
			&cred_usage,
			&mechanisms);

	if (major_status != GSS_S_COMPLETE)
	{
		globus_gss_assist_display_status(
				stderr,
				"Error acquiring credentials",
				major_status,
				minor_status,
				0);
		return(-1);
	}
	return(lifetime);
			
}
示例#3
0
OM_uint32 gssi_inquire_cred(OM_uint32 *minor_status,
                            gss_cred_id_t cred_handle,
                            gss_name_t *name,
                            OM_uint32 *lifetime,
                            gss_cred_usage_t *cred_usage,
                            gss_OID_set *mechanisms)
{
    struct gpp_cred_handle *cred = NULL;
    struct gpp_name_handle *gpname = NULL;
    OM_uint32 maj, min;

    GSSI_TRACE();

    if (cred_handle == GSS_C_NO_CREDENTIAL) {
        maj = gppint_get_def_creds(&min, gpp_get_behavior(), NULL,
                                   GSS_C_INITIATE, &cred);
        if (maj != GSS_S_COMPLETE) {
            goto done;
        }
    } else {
        cred = (struct gpp_cred_handle *)cred_handle;
    }

    if (name) {
        gpname = calloc(1, sizeof(struct gpp_name_handle));
        if (!gpname) {
            min = ENOMEM;
            maj = GSS_S_FAILURE;
            goto done;
        }
    }

    if (cred->local) {
        maj = gss_inquire_cred(&min, cred->local,
                               gpname ? &gpname->local : NULL,
                               lifetime, cred_usage, mechanisms);
    } else if (cred->remote) {
        maj = gpm_inquire_cred(&min, cred->remote,
                               gpname ? &gpname->remote : NULL,
                               lifetime, cred_usage, mechanisms);
    } else {
        min = 0;
        maj = GSS_S_FAILURE;
    }

done:
    *minor_status = gpp_map_error(min);
    if (cred_handle == GSS_C_NO_CREDENTIAL) {
        gssi_release_cred(&min, (gss_cred_id_t*)&cred);
    }
    if (name && maj == GSS_S_COMPLETE) {
        *name = (gss_name_t)gpname;
    } else {
        free(gpname);
    }
    return maj;
}
示例#4
0
static void
log_cred(const gss_cred_id_t cred) {
	OM_uint32 gret, minor, lifetime;
	gss_name_t gname;
	gss_buffer_desc gbuffer;
	gss_cred_usage_t usage;
	const char *usage_text;
	char buf[1024];

	gret = gss_inquire_cred(&minor, cred, &gname, &lifetime, &usage, NULL);
	if (gret != GSS_S_COMPLETE) {
		gss_log(3, "failed gss_inquire_cred: %s",
			gss_error_tostring(gret, minor, buf, sizeof(buf)));
		return;
	}

	gret = gss_display_name(&minor, gname, &gbuffer, NULL);
	if (gret != GSS_S_COMPLETE)
		gss_log(3, "failed gss_display_name: %s",
			gss_error_tostring(gret, minor, buf, sizeof(buf)));
	else {
		switch (usage) {
		case GSS_C_BOTH:
			usage_text = "GSS_C_BOTH";
			break;
		case GSS_C_INITIATE:
			usage_text = "GSS_C_INITIATE";
			break;
		case GSS_C_ACCEPT:
			usage_text = "GSS_C_ACCEPT";
			break;
		default:
			usage_text = "???";
		}
		gss_log(3, "gss cred: \"%s\", %s, %lu", (char *)gbuffer.value,
			usage_text, (unsigned long)lifetime);
	}

	if (gret == GSS_S_COMPLETE) {
		if (gbuffer.length != 0) {
			gret = gss_release_buffer(&minor, &gbuffer);
			if (gret != GSS_S_COMPLETE)
				gss_log(3, "failed gss_release_buffer: %s",
					gss_error_tostring(gret, minor, buf,
							   sizeof(buf)));
		}
	}

	gret = gss_release_name(&minor, &gname);
	if (gret != GSS_S_COMPLETE)
		gss_log(3, "failed gss_release_name: %s",
			gss_error_tostring(gret, minor, buf, sizeof(buf)));
}
static OM_uint32
acceptor_approved(void *userptr,
		  gss_name_t target_name, 
		  const gss_cred_id_t cred_handle,
		  gss_OID mech)
{
    OM_uint32 junk, ret;
    gss_OID_set oidset;

    if (cred_handle) {
	int present = 0;

	ret = gss_inquire_cred(&junk,
			       cred_handle,
			       NULL,
			       NULL,
			       NULL,
			       &oidset);
	if (ret != GSS_S_COMPLETE)
	    return ret;

	ret = gss_test_oid_set_member(&junk, mech, oidset, &present);
	gss_release_oid_set(&junk, &oidset);
	
	if (ret != GSS_S_COMPLETE || present == 0)
	    return GSS_S_FAILURE;

    } else {
	gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;

	if (target_name == GSS_C_NO_NAME)
	    return GSS_S_COMPLETE;
	
	gss_create_empty_oid_set(&junk, &oidset);
	gss_add_oid_set_member(&junk, mech, &oidset);

	ret = gss_acquire_cred(&junk, target_name, GSS_C_INDEFINITE, oidset,
			       GSS_C_ACCEPT, &cred, NULL, NULL);
	gss_release_oid_set(&junk, &oidset);
	if (ret != GSS_S_COMPLETE)
	    return ret;
	gss_release_cred(&junk, &cred);
    }

    return GSS_S_COMPLETE;
}
OM_uint32 gss_inquire_cred_by_mech (
            OM_uint32 * minor_status,
            const gss_cred_id_t cred_handle,
            const gss_OID mech_type,
            gss_name_t * name,
            OM_uint32 * initiator_lifetime,
            OM_uint32 * acceptor_lifetime,
            gss_cred_usage_t * cred_usage
    )
{
    OM_uint32 ret;
    OM_uint32 lifetime;

    if (gss_oid_equal(mech_type, GSS_C_NO_OID) == 0 &&
	gss_oid_equal(mech_type, GSS_KRB5_MECHANISM) == 0) {
	*minor_status = EINVAL;
	return GSS_S_BAD_MECH;
    }    

    ret = gss_inquire_cred (minor_status,
			    cred_handle,
			    name,
			    &lifetime,
			    cred_usage,
			    NULL);
    
    if (ret == 0 && cred_handle != GSS_C_NO_CREDENTIAL) {
	gss_cred_usage_t usage;

	HEIMDAL_MUTEX_lock(&cred_handle->cred_id_mutex);
	usage = cred_handle->usage;
	HEIMDAL_MUTEX_unlock(&cred_handle->cred_id_mutex);

	if (initiator_lifetime) {
	    if (usage == GSS_C_INITIATE || usage == GSS_C_BOTH)
		*initiator_lifetime = lifetime;
	}
	if (acceptor_lifetime) {
	    if (usage == GSS_C_ACCEPT || usage == GSS_C_BOTH)
		*acceptor_lifetime = lifetime;
	}
    }

    return ret;
}
示例#7
0
OM_uint32 _gss_spnego_inquire_cred
           (OM_uint32 * minor_status,
            const gss_cred_id_t cred_handle,
            gss_name_t * name,
            OM_uint32 * lifetime,
            gss_cred_usage_t * cred_usage,
            gss_OID_set * mechanisms
           )
{
    gssspnego_cred cred;
    spnego_name sname = NULL;
    OM_uint32 ret;

    if (cred_handle == GSS_C_NO_CREDENTIAL) {
	*minor_status = 0;
	return GSS_S_NO_CRED;
    }

    if (name) {
	sname = calloc(1, sizeof(*sname));
	if (sname == NULL) {
	    *minor_status = ENOMEM;
	    return GSS_S_FAILURE;
	}
    }

    cred = (gssspnego_cred)cred_handle;

    ret = gss_inquire_cred(minor_status,
			   cred->negotiated_cred_id,
			   sname ? &sname->mech : NULL,
			   lifetime,
			   cred_usage,
			   mechanisms);
    if (ret) {
	if (sname)
	    free(sname);
	return ret;
    }
    if (name)
	*name = (gss_name_t)sname;

    return ret;
}
示例#8
0
文件: gsi.c 项目: ddk50/gfarm_v2
int
gfarmGssNewCredentialName(gss_name_t *outputNamePtr, gss_cred_id_t cred,
    OM_uint32 *majStatPtr, OM_uint32 *minStatPtr)
{
    OM_uint32 majStat;
    OM_uint32 minStat;

    majStat = gss_inquire_cred(&minStat, cred, outputNamePtr,
			       NULL,	/* lifetime */
			       NULL,	/* usage */
			       NULL	/* supported mech */);
    if (majStatPtr != NULL) {
	*majStatPtr = majStat;
    }
    if (minStatPtr != NULL) {
	*minStatPtr = minStat;
    }
    return majStat == GSS_S_COMPLETE ? 1 : -1;
}
示例#9
0
文件: sncgss.c 项目: Aribaaa/osxsnc
uint32_t
sapgss_acquire_cred(
    uint32_t *minor_status,
    gss_name_t desired_name,
    uint32_t time_req,
    sapgss_OID_set desired_mechs,
    gss_cred_usage_t cred_usage,
    gss_cred_id_t *output_cred_handle,
    sapgss_OID_set *actual_mechs,
    uint32_t *time_rec)
{
    gss_OID_set desired_mechs_loc;
    gss_OID_set actual_mechs_loc;
    uint32_t major_status, dummy;
    int ret;
    
    memset(&desired_mechs_loc, 0, sizeof(desired_mechs_loc));
    memset(&actual_mechs_loc, 0, sizeof(actual_mechs_loc));
    ret = gss_OID_set_sap_to_loc(desired_mechs, &desired_mechs_loc);
    if (ret != 0) {
	*minor_status = ret;
	return GSS_S_FAILURE;
    }
    major_status = gss_acquire_cred(minor_status, desired_name, time_req,
				    desired_mechs_loc, cred_usage,
				    output_cred_handle, &actual_mechs_loc,
				    time_rec);
    /* Meet the gss_OID_set_sap_to_loc contract and free desired_mechs_loc */
    gss_OID_set_loc_release(&desired_mechs_loc);
    /* Must inquire_cred to force resolution for the krb5 mech */
    if (major_status != 0)
	return major_status;
    (void)gss_inquire_cred(&dummy, *output_cred_handle,
				    NULL, NULL, NULL, &actual_mechs_loc);
    ret = gss_OID_set_loc_to_sap(actual_mechs_loc, actual_mechs);
    if (ret != 0) {
	*minor_status = ret;
	return GSS_S_FAILURE;
    }
    return major_status;
}
示例#10
0
文件: sncgss.c 项目: Aribaaa/osxsnc
uint32_t
sapgss_inquire_cred(
    uint32_t *minor_status,
    gss_cred_id_t cred_handle,
    gss_name_t *name,
    uint32_t *lifetime,
    gss_cred_usage_t *cred_usage,
    sapgss_OID_set *mechanisms)
{
    gss_OID_set mechanisms_loc;
    uint32_t major_status;
    int ret;

    major_status = gss_inquire_cred(minor_status, cred_handle, name, lifetime,
				    cred_usage, &mechanisms_loc);
    ret = gss_OID_set_loc_to_sap(mechanisms_loc, mechanisms);
    if (ret != 0) {
	*minor_status = ret;
	return GSS_S_FAILURE;
    }
    return major_status;
}
示例#11
0
文件: gss.c 项目: B1NG0/cifs
static void
smb_gss_add_cred(struct smb_gss_cred_list *list, gss_OID oid, gss_cred_id_t cred)
{
	gss_buffer_desc buf;
	gss_name_t name;
	uint32_t M, m;
	uint32_t ltime;
	struct smb_gss_cred_list_entry *ep;
	
	if (cred == GSS_C_NO_CREDENTIAL)
		return;
	
	M = gss_inquire_cred(&m, cred, &name, &ltime, NULL, NULL);
	if (M != GSS_S_COMPLETE)
		goto out;
	if (ltime != GSS_C_INDEFINITE && ltime == 0)
		goto out;
	M = gss_display_name(&m, name, &buf, NULL);
	(void) gss_release_name(&m, &name);
	if (M != GSS_S_COMPLETE)
		goto out;
	
	ep = calloc(1, sizeof (struct smb_gss_cred_list_entry));
	if (ep) {
		ep->expire = ltime;
		ep->mech = oid;
		asprintf(&ep->principal, "%.*s", (int)buf.length, (char *)buf.value);
		if (ep->principal) {
			TAILQ_INSERT_TAIL(list, ep, next);
		} else {
			free(ep);
		}
	}
	(void) gss_release_buffer(&m, &buf);
	
out:
	(void)gss_release_cred(&m, &cred);
}
示例#12
0
文件: gss.c 项目: B1NG0/cifs
char *
smb_gss_principal_from_cred(void *smb_cred)
{
	gss_cred_id_t cred = (gss_cred_id_t)smb_cred;
	gss_buffer_desc buf;
	gss_name_t name;
	uint32_t M, m;
	char *principal = NULL;
	
	if (cred == GSS_C_NO_CREDENTIAL)
		return (NULL);
	M = gss_inquire_cred(&m, cred, &name, NULL, NULL, NULL);
	if (M != GSS_S_COMPLETE)
		return (NULL);
	M = gss_display_name(&m, name, &buf, NULL);
	(void) gss_release_name(&m, &name);
	if (M == GSS_S_COMPLETE) {
		asprintf(&principal, "%.*s", (int)buf.length, (char *)buf.value);
		(void) gss_release_buffer(&m, &buf);
	}
	
	return (principal);
}
示例#13
0
文件: t_s4u.c 项目: Akasurde/krb5
static void
init_accept_sec_context(gss_cred_id_t claimant_cred_handle,
                        gss_cred_id_t verifier_cred_handle,
                        gss_cred_id_t *deleg_cred_handle)
{
    OM_uint32 major, minor, flags;
    gss_name_t source_name = GSS_C_NO_NAME, target_name = GSS_C_NO_NAME;
    gss_ctx_id_t initiator_context, acceptor_context;
    gss_OID mech = GSS_C_NO_OID;

    *deleg_cred_handle = GSS_C_NO_CREDENTIAL;

    major = gss_inquire_cred(&minor, verifier_cred_handle, &target_name, NULL,
                             NULL, NULL);
    check_gsserr("gss_inquire_cred", major, minor);

    display_canon_name("Target name", target_name, &mech_krb5);

    mech = use_spnego ? &mech_spnego : &mech_krb5;
    display_oid("Target mech", mech);

    flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
    establish_contexts(mech, claimant_cred_handle, verifier_cred_handle,
                       target_name, flags, &initiator_context,
                       &acceptor_context, &source_name, &mech,
                       deleg_cred_handle);

    display_canon_name("Source name", source_name, &mech_krb5);
    display_oid("Source mech", mech);
    enumerate_attributes(source_name, 1);

    (void)gss_release_name(&minor, &source_name);
    (void)gss_release_name(&minor, &target_name);
    (void)gss_delete_sec_context(&minor, &initiator_context, NULL);
    (void)gss_delete_sec_context(&minor, &acceptor_context, NULL);
}
示例#14
0
/* returns 0 on success and other values on failure */
int req_gssauthenuser (struct batch_request *preq, int sock)
  {
  static time_t lastcredstime = 0;
  static char *service_name = NULL;
  static gss_cred_id_t server_creds = GSS_C_NO_CREDENTIAL;
  static time_t credlifetime = 0;

  if (service_name == NULL)
      asprintf(&service_name,"host@%s",server_host);

  time_t now = time((time_t *)NULL);

  gss_ctx_id_t context;
  gss_cred_id_t client_creds;
  gss_buffer_desc client_name;
  OM_uint32 majstat, ret_flags, lifetime;

  log_event(PBSEVENT_ERROR | PBSEVENT_FORCE, PBS_EVENTCLASS_SERVER, LOG_ERR, __func__, "Entered encrypted communication.");
  int status;

  /* if credentials are old, try to get new ones. If we can't, keep the old
     ones since they're probably still valid and hope that
     we can get new credentials next time */
  if (now - lastcredstime > credlifetime)
    {
    gss_cred_id_t new_creds;

    /* if we can't get new creds, try again in a few minutes */
    if (pbsgss_server_acquire_creds(service_name,&new_creds) != PBSGSS_OK)
      {
      log_event(PBSEVENT_SECURITY | PBSEVENT_FORCE,PBS_EVENTCLASS_SERVER, LOG_ERR,
                __func__,"Unable to acquire fresh KRB5 pbs server credentials.");
      lastcredstime = now + 120; // try again in 2 minutes
      }
    else
      {
      /* if we got new creds, free the old ones and use the new ones */
      lastcredstime = now;
      snprintf(log_buffer,LOG_BUF_SIZE,"Refreshing KRB5 pbs server credentials at %ld\n",(long)now);
      log_event(PBSEVENT_DEBUG | PBSEVENT_FORCE, PBS_EVENTCLASS_SERVER, LOG_DEBUG, __func__, log_buffer);

      if (server_creds != GSS_C_NO_CREDENTIAL)
        gss_release_cred(&ret_flags,&server_creds);

      server_creds = new_creds;
      /* fetch information about the fresh credentials */
      majstat = gss_inquire_cred(&ret_flags,server_creds, NULL,&lifetime,NULL,NULL);
      if (majstat == GSS_S_COMPLETE)
        {
        if (lifetime == GSS_C_INDEFINITE)
          {
          credlifetime = DEFAULT_CREDENTIAL_LIFETIME;
          snprintf(log_buffer,LOG_BUF_SIZE,"KRB5 pbs server credentials received with indefinite lifetime, using %d.\n",DEFAULT_CREDENTIAL_LIFETIME);
          log_event(PBSEVENT_DEBUG | PBSEVENT_FORCE, PBS_EVENTCLASS_SERVER, LOG_DEBUG, __func__, log_buffer);
          }
        else
          {
          snprintf(log_buffer,LOG_BUF_SIZE,"KRB5 pbs server credentials received with lifetime as %u.\n",lifetime);
          log_event(PBSEVENT_DEBUG | PBSEVENT_FORCE, PBS_EVENTCLASS_SERVER, LOG_DEBUG, __func__, log_buffer);
          credlifetime = lifetime;
          }
        }
      else
        {
        /* could not read information from credential */
        credlifetime = 0;
        }
      }
    }

  if ((status = pbsgss_server_establish_context(sock, server_creds, NULL, &context, &client_name, &ret_flags)) != PBSGSS_OK)
    {
    snprintf(log_buffer,LOG_BUF_SIZE,"Unable to establish a secure context : %d",status);
    log_event(PBSEVENT_SECURITY | PBSEVENT_FORCE, PBS_EVENTCLASS_SERVER,LOG_ERR,__func__,log_buffer);
    return -1;
    }

  if (context == GSS_C_NO_CONTEXT)
    {
    log_event(PBSEVENT_DEBUG | PBSEVENT_FORCE, PBS_EVENTCLASS_SERVER, LOG_INFO, __func__, "Received an unauthenticated connection.");
    return -1;
    }

  free(svr_conn[sock].cn_principal);

  svr_conn[sock].cn_principal = malloc(client_name.length + 1);
  memcpy(svr_conn[sock].cn_principal,client_name.value,client_name.length);
  svr_conn[sock].cn_principal[client_name.length] = '\0';

  free(client_name.value);

  svr_conn[sock].cn_authen = PBS_NET_CONN_GSSAPIAUTH | PBS_NET_CONN_AUTHENTICATED;
  if (!(ret_flags & GSS_C_INTEG_FLAG))
    {
    log_event(PBSEVENT_DEBUG | PBSEVENT_FORCE, PBS_EVENTCLASS_SERVER, LOG_ERR, __func__, "Integrity protection not available on connection.");
    return -1;
    }

  pbsgss_save_sec_context(&context,ret_flags,sock); // TODO Handle error

  if ((status = gss_conn_credent(preq,sock)) < 0)
    {
    log_event(PBSEVENT_DEBUG | PBSEVENT_FORCE, PBS_EVENTCLASS_SERVER, LOG_ERR, __func__, "Couldn't propagate connection credentials.");
    return -1;
    }

  return 0;
  }
示例#15
0
_PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, 
						  struct tevent_context *event_ctx,
						  struct loadparm_context *lp_ctx,
						  struct gssapi_creds_container **_gcc,
						  const char **error_string)
{
	int ret = 0;
	OM_uint32 maj_stat, min_stat;
	struct gssapi_creds_container *gcc;
	struct ccache_container *ccache;
#ifdef SAMBA4_USES_HEIMDAL
	gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
#endif
	krb5_enctype *etypes = NULL;

	if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold && 
	    cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
		bool expired = false;
		OM_uint32 lifetime = 0;
		gss_cred_usage_t usage = 0;
		maj_stat = gss_inquire_cred(&min_stat, cred->client_gss_creds->creds, 
					    NULL, &lifetime, &usage, NULL);
		if (maj_stat == GSS_S_CREDENTIALS_EXPIRED) {
			DEBUG(3, ("Credentials for %s expired, must refresh credentials cache\n", cli_credentials_get_principal(cred, cred)));
			expired = true;
		} else if (maj_stat == GSS_S_COMPLETE && lifetime < 300) {
			DEBUG(3, ("Credentials for %s will expire shortly (%u sec), must refresh credentials cache\n", cli_credentials_get_principal(cred, cred), lifetime));
			expired = true;
		} else if (maj_stat != GSS_S_COMPLETE) {
			*error_string = talloc_asprintf(cred, "inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n",
							gssapi_error_string(cred, maj_stat, min_stat, NULL));
			return EINVAL;
		}
		if (expired) {
			cli_credentials_unconditionally_invalidate_client_gss_creds(cred);
		} else {
			DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n", 
				  cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
		
			*_gcc = cred->client_gss_creds;
			return 0;
		}
	}

	ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
					 &ccache, error_string);
	if (ret) {
		if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) {
			DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", *error_string));
		} else {
			DEBUG(4, ("Failed to get kerberos credentials: %s\n", *error_string));
		}
		return ret;
	}

	gcc = talloc(cred, struct gssapi_creds_container);
	if (!gcc) {
		(*error_string) = error_message(ENOMEM);
		return ENOMEM;
	}

	maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, 
					&gcc->creds);
	if ((maj_stat == GSS_S_FAILURE) && (min_stat == (OM_uint32)KRB5_CC_END || min_stat == (OM_uint32) KRB5_CC_NOTFOUND)) {
		/* This CCACHE is no good.  Ensure we don't use it again */
		cli_credentials_unconditionally_invalidate_ccache(cred);

		/* Now try again to get a ccache */
		ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
						 &ccache, error_string);
		if (ret) {
			DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret)));
			return ret;
		}

		maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
						&gcc->creds);

	}

	if (maj_stat) {
		talloc_free(gcc);
		if (min_stat) {
			ret = min_stat;
		} else {
			ret = EINVAL;
		}
		(*error_string) = talloc_asprintf(cred, "gss_krb5_import_cred failed: %s", error_message(ret));
		return ret;
	}


	/*
	 * transfer the enctypes from the smb_krb5_context to the gssapi layer
	 *
	 * We use 'our' smb_krb5_context to do the AS-REQ and it is possible
	 * to configure the enctypes via the krb5.conf.
	 *
	 * And the gss_init_sec_context() creates it's own krb5_context and
	 * the TGS-REQ had all enctypes in it and only the ones configured
	 * and used for the AS-REQ, so it wasn't possible to disable the usage
	 * of AES keys.
	 */
	min_stat = get_kerberos_allowed_etypes(ccache->smb_krb5_context->krb5_context,
					       &etypes);
	if (min_stat == 0) {
		OM_uint32 num_ktypes;

		for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++);

		maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds,
							   num_ktypes,
							   (int32_t *) etypes);
		SAFE_FREE(etypes);
		if (maj_stat) {
			talloc_free(gcc);
			if (min_stat) {
				ret = min_stat;
			} else {
				ret = EINVAL;
			}
			(*error_string) = talloc_asprintf(cred, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret));
			return ret;
		}
	}

#ifdef SAMBA4_USES_HEIMDAL /* MIT lacks GSS_KRB5_CRED_NO_CI_FLAGS_X */

	/* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */
	maj_stat = gss_set_cred_option(&min_stat, &gcc->creds,
				       GSS_KRB5_CRED_NO_CI_FLAGS_X,
				       &empty_buffer);
	if (maj_stat) {
		talloc_free(gcc);
		if (min_stat) {
			ret = min_stat;
		} else {
			ret = EINVAL;
		}
		(*error_string) = talloc_asprintf(cred, "gss_set_cred_option failed: %s", error_message(ret));
		return ret;
	}
#endif
	cred->client_gss_creds_obtained = cred->ccache_obtained;
	talloc_set_destructor(gcc, free_gssapi_creds);
	cred->client_gss_creds = gcc;
	*_gcc = gcc;
	return 0;
}
/**
 * @ingroup globus_gss_assist_context
 * This is a asynchronous version of the
 * globus_gss_assist_init_sec_context() function. Instead of looping
 * itself it passes in and out the read and written buffers and
 * the calling application is responsible for doing the I/O directly.
 *
 * @param minor_status
 *        GSSAPI return code.  The new minor status is a globus_result_t
 *        cast to a OM_uint32.  If an error occurred (GSS_ERROR(major_status))
 *        the minor_status is a globus error object id.  The error object
 *        can be obtained via globus_error_get and should be destroyed
 *        with globus_object_free when no longer needed.  If no error
 *        occurred, the minor status is equal to GLOBUS_SUCCESS.
 * @param cred_handle
 *        the cred handle obtained by acquire_cred.
 * @param context_handle
 *        pointer to returned context. 
 * @param target_name_char
 *        char string representation of the
 *        server to be contacted. 
 * @param req_flags
 *        request flags, such as GSS_C_DELEG_FLAG for delegation
 *        and the GSS_C_MUTUAL_FLAG for mutual authentication. 
 * @param ret_flags
 *        Pointer to which services are available after
 *        the connection is established. Maybe NULL if not wanted. 
 * @param input_buffer
 *        pointer to a buffer received from peer. Should
 *        be NULL on first call.
 * @param input_buffer_len
 *        length of the buffer input_buffer. Should
 *        be zero on first call.
 * @param output_bufferp
 *        pointer to a pointer which will be filled in
 *        with a pointer to a allocated block of memory. If
 *        non-NULL the contents of this block should be written
 *        to the peer where they will be fed into the
 *        gss_assist_init_sec_context_async() function.
 * @param output_buffer_lenp
 *        pointer to an integer which will be filled
 *        in with the length of the allocated output buffer
 *        pointed to by *output_bufferp.
 * @return
 *        GSS_S_COMPLETE on successful completion when this function does not
 *        need to be called again.
 *
 *        GSS_S_CONTINUE_NEEDED when *output_bufferp should be sent to the
 *        peer and a new input_buffer read and this function called again.
 *     
 *        Other gss errors on failure.
 */
OM_uint32
globus_gss_assist_init_sec_context_async(
    OM_uint32 *                         minor_status,
    const gss_cred_id_t                 cred_handle,
    gss_ctx_id_t *                      context_handle,
    char *                              target_name_char,
    OM_uint32                           req_flags,
    OM_uint32 *                         ret_flags,
    void *                              input_buffer,
    size_t                              input_buffer_len,
    void **                             output_bufferp,
    size_t *                            output_buffer_lenp)
{
    OM_uint32                           major_status = GSS_S_COMPLETE;
    OM_uint32                           minor_status1 = 0;
    OM_uint32                           minor_status2 = 0;
    gss_buffer_desc                     input_token_desc = GSS_C_EMPTY_BUFFER;
    gss_buffer_t                        input_token = &input_token_desc;
    gss_buffer_desc                     output_token_desc = GSS_C_EMPTY_BUFFER;
    gss_buffer_t                        output_token = &output_token_desc;
    gss_name_t                          target_name = GSS_C_NO_NAME;
    gss_OID                             target_name_type = GSS_C_NO_OID;
    gss_OID                             mech_type = GSS_C_NO_OID;
    OM_uint32                           time_req = 0;
    OM_uint32                           time_rec = 0;
    gss_channel_bindings_t              input_chan_bindings = 
        GSS_C_NO_CHANNEL_BINDINGS;
    gss_OID *                           actual_mech_type = NULL;
    gss_buffer_desc                     tmp_buffer_desc = GSS_C_EMPTY_BUFFER;
    gss_buffer_t                        tmp_buffer      = &tmp_buffer_desc;
    globus_result_t                     result = GLOBUS_SUCCESS;
    static char *                       _function_name_ =
        "globus_gss_assist_init_sec_context_async";
    GLOBUS_I_GSI_GSS_ASSIST_DEBUG_ENTER;

    /* Set up our input token from passed buffer */
    if ((input_buffer != NULL) && (input_buffer_len != 0))
    {
        input_token_desc.length = input_buffer_len;
        input_token_desc.value = input_buffer;
    }

    /* Do initialization first time through the loop */

    /* This will not work if the context handle has been initialized
       before the first call. Don't know how to fix it since I can't
       access fields in the handle outside the GSS API. - Sam
    */
    if (*context_handle == GSS_C_NO_CONTEXT)
    {
        if(ret_flags)
        {
            *ret_flags = 0;
        }
    }

    /* supply the service name to the gss-api
     * If NULL, then we want user_to_user
     * so get it from the cred
     */

    if (target_name_char)
    {
        if(!strncmp("GSI-NO-TARGET",target_name_char,13))
        {
            target_name = GSS_C_NO_NAME;
        }
        else
        {
            tmp_buffer->value = target_name_char;
            tmp_buffer->length = strlen(target_name_char);

            /* 
             * A gss_nt_service_name is of the form service@FQDN
             * At least the Globus gssapi, and the Kerberos gssapi 
             * use the same form. We will check for 
             * two special forms here: host@FQDN and ftp@FQDN
             * This could be another parameter to the gss_assist
             * instead. 
             */
          
            if (strchr(target_name_char, '@') &&
                !strstr(target_name_char, "CN="))
            { 
                target_name_type = gss_nt_service_name;
            }
          
            major_status = gss_import_name(&minor_status1,
                                           tmp_buffer,
                                           target_name_type,
                                           &target_name);
        }
    }
    else
    {

        major_status = gss_inquire_cred(&minor_status1,
                                        cred_handle,
                                        &target_name,
                                        NULL,
                                        NULL,
                                        NULL);
    }

    if (major_status == GSS_S_COMPLETE)
    {
        GLOBUS_I_GSI_GSS_ASSIST_DEBUG_FPRINTF(
            4, (globus_i_gsi_gss_assist_debug_fstream,
                _GASL("req_flags: %8.8x  input_token length: %u\n"),
                (unsigned int) req_flags,
                input_token->length));

        major_status = gss_init_sec_context(&minor_status1,
                                            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);
        GLOBUS_I_GSI_GSS_ASSIST_DEBUG_FPRINTF(
            4, (globus_i_gsi_gss_assist_debug_fstream,
                _GASL("major: %8.8x minor: %8.8x ret_flags: %8.8x\n"
                "output_token length: %u context_handle: %p\n"),
                (unsigned int) major_status, 
                (unsigned int) minor_status1, 
                (unsigned int) ((ret_flags) ? *ret_flags : -1),
                output_token->length, 
                *context_handle));

        if (output_token->length != 0)
        {
            *output_bufferp = output_token->value;
            *output_buffer_lenp = output_token->length;
            /* These will now be freed by the caller */
        }
        else
        {    
            *output_bufferp = NULL;
            *output_buffer_lenp = 0;
        }

        if (GSS_ERROR(major_status))
        {
            if (*context_handle != GSS_C_NO_CONTEXT)
                gss_delete_sec_context(&minor_status2,
                                       context_handle,
                                       GSS_C_NO_BUFFER);
        }

    }

    if (target_name != GSS_C_NO_NAME)
    {
        gss_release_name(&minor_status2,&target_name);
    }


    result = (globus_result_t) minor_status1;
    if(result != GLOBUS_SUCCESS)
    {
        GLOBUS_GSI_GSS_ASSIST_ERROR_CHAIN_RESULT(
            result,
            GLOBUS_GSI_GSS_ASSIST_ERROR_WITH_INIT);
    }
    *minor_status = (OM_uint32) result;

    GLOBUS_I_GSI_GSS_ASSIST_DEBUG_EXIT;
    return major_status;
}
示例#17
0
文件: compat.c 项目: Henauxg/minix
OM_uint32 GSSAPI_CALLCONV
_gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status,
				   gss_name_t target_name,
				   OM_uint32 (*func)(gss_name_t, gss_OID),
				   int includeMSCompatOID,
				   const gss_cred_id_t cred_handle,
				   MechTypeList *mechtypelist,
				   gss_OID *preferred_mech)
{
    gss_OID_set supported_mechs = GSS_C_NO_OID_SET;
    gss_OID first_mech = GSS_C_NO_OID;
    OM_uint32 ret;
    size_t i;

    mechtypelist->len = 0;
    mechtypelist->val = NULL;

    if (cred_handle) {
	ret = gss_inquire_cred(minor_status,
			       cred_handle,
			       NULL,
			       NULL,
			       NULL,
			       &supported_mechs);
    } else {
	ret = gss_indicate_mechs(minor_status, &supported_mechs);
    }

    if (ret != GSS_S_COMPLETE) {
	return ret;
    }

    if (supported_mechs->count == 0) {
	*minor_status = ENOENT;
	gss_release_oid_set(minor_status, &supported_mechs);
	return GSS_S_FAILURE;
    }

    ret = (*func)(target_name, GSS_KRB5_MECHANISM);
    if (ret == GSS_S_COMPLETE) {
	ret = add_mech_type(GSS_KRB5_MECHANISM,
			    includeMSCompatOID,
			    mechtypelist);
	if (!GSS_ERROR(ret))
	    first_mech = GSS_KRB5_MECHANISM;
    }
    ret = GSS_S_COMPLETE;

    for (i = 0; i < supported_mechs->count; i++) {
	OM_uint32 subret;
	if (gss_oid_equal(&supported_mechs->elements[i], GSS_SPNEGO_MECHANISM))
	    continue;
	if (gss_oid_equal(&supported_mechs->elements[i], GSS_KRB5_MECHANISM))
	    continue;

	subret = (*func)(target_name, &supported_mechs->elements[i]);
	if (subret != GSS_S_COMPLETE)
	    continue;

	ret = add_mech_type(&supported_mechs->elements[i],
			    includeMSCompatOID,
			    mechtypelist);
	if (ret != 0) {
	    *minor_status = ret;
	    ret = GSS_S_FAILURE;
	    break;
	}
	if (first_mech == GSS_C_NO_OID)
	    first_mech = &supported_mechs->elements[i];
    }

    if (mechtypelist->len == 0) {
	gss_release_oid_set(minor_status, &supported_mechs);
	*minor_status = 0;
	return GSS_S_BAD_MECH;
    }

    if (preferred_mech != NULL) {
	ret = gss_duplicate_oid(minor_status, first_mech, preferred_mech);
	if (ret != GSS_S_COMPLETE)
	    free_MechTypeList(mechtypelist);
    }
    gss_release_oid_set(minor_status, &supported_mechs);

    return ret;
}
示例#18
0
static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, 
				     TALLOC_CTX *out_mem_ctx,
				     struct tevent_context *ev,
				     const DATA_BLOB in, DATA_BLOB *out)
{
	struct gensec_gssapi_state *gensec_gssapi_state
		= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
	NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
	OM_uint32 maj_stat, min_stat;
	OM_uint32 min_stat2;
	gss_buffer_desc input_token = { 0, NULL };
	gss_buffer_desc output_token = { 0, NULL };

	gss_OID gss_oid_p = NULL;
	OM_uint32 time_req = 0;
	OM_uint32 time_rec = 0;
	struct timeval tv;

	time_req = gensec_setting_int(gensec_security->settings,
				      "gensec_gssapi", "requested_life_time",
				      time_req);

	input_token.length = in.length;
	input_token.value = in.data;

	switch (gensec_gssapi_state->sasl_state) {
	case STAGE_GSS_NEG:
	{
		switch (gensec_security->gensec_role) {
		case GENSEC_CLIENT:
		{
#ifdef SAMBA4_USES_HEIMDAL
			struct gsskrb5_send_to_kdc send_to_kdc;
			krb5_error_code ret;
#endif

			nt_status = gensec_gssapi_client_creds(gensec_security, ev);
			if (!NT_STATUS_IS_OK(nt_status)) {
				return nt_status;
			}

#ifdef SAMBA4_USES_HEIMDAL
			send_to_kdc.func = smb_krb5_send_and_recv_func;
			send_to_kdc.ptr = ev;

			min_stat = gsskrb5_set_send_to_kdc(&send_to_kdc);
			if (min_stat) {
				DEBUG(1,("gensec_gssapi_update: gsskrb5_set_send_to_kdc failed\n"));
				return NT_STATUS_INTERNAL_ERROR;
			}
#endif
			maj_stat = gss_init_sec_context(&min_stat, 
							gensec_gssapi_state->client_cred->creds,
							&gensec_gssapi_state->gssapi_context, 
							gensec_gssapi_state->server_name, 
							gensec_gssapi_state->gss_oid,
							gensec_gssapi_state->gss_want_flags, 
							time_req,
							gensec_gssapi_state->input_chan_bindings,
							&input_token, 
							&gss_oid_p,
							&output_token, 
							&gensec_gssapi_state->gss_got_flags, /* ret flags */
							&time_rec);
			if (gss_oid_p) {
				gensec_gssapi_state->gss_oid = gss_oid_p;
			}

#ifdef SAMBA4_USES_HEIMDAL
			send_to_kdc.func = smb_krb5_send_and_recv_func;
			send_to_kdc.ptr = NULL;

			ret = gsskrb5_set_send_to_kdc(&send_to_kdc);
			if (ret) {
				DEBUG(1,("gensec_gssapi_update: gsskrb5_set_send_to_kdc failed\n"));
				return NT_STATUS_INTERNAL_ERROR;
			}
#endif
			break;
		}
		case GENSEC_SERVER:
		{
			maj_stat = gss_accept_sec_context(&min_stat, 
							  &gensec_gssapi_state->gssapi_context, 
							  gensec_gssapi_state->server_cred->creds,
							  &input_token, 
							  gensec_gssapi_state->input_chan_bindings,
							  &gensec_gssapi_state->client_name, 
							  &gss_oid_p,
							  &output_token, 
							  &gensec_gssapi_state->gss_got_flags, 
							  &time_rec,
							  &gensec_gssapi_state->delegated_cred_handle);
			if (gss_oid_p) {
				gensec_gssapi_state->gss_oid = gss_oid_p;
			}
			break;
		}
		default:
			return NT_STATUS_INVALID_PARAMETER;
			
		}

		gensec_gssapi_state->gss_exchange_count++;

		if (maj_stat == GSS_S_COMPLETE) {
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat2, &output_token);
			
			if (gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG &&
			    gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
				DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
			} else {
				DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
			}

			tv = timeval_current_ofs(time_rec, 0);
			gensec_gssapi_state->expire_time = timeval_to_nttime(&tv);

			/* We may have been invoked as SASL, so there
			 * is more work to do */
			if (gensec_gssapi_state->sasl) {
				gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_NEG;
				return NT_STATUS_MORE_PROCESSING_REQUIRED;
			} else {
				gensec_gssapi_state->sasl_state = STAGE_DONE;

				if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
					DEBUG(5, ("GSSAPI Connection will be cryptographically sealed\n"));
				} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
					DEBUG(5, ("GSSAPI Connection will be cryptographically signed\n"));
				} else {
					DEBUG(5, ("GSSAPI Connection will have no cryptographic protection\n"));
				}

				return NT_STATUS_OK;
			}
		} else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat2, &output_token);
			
			return NT_STATUS_MORE_PROCESSING_REQUIRED;
		} else if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
			gss_cred_id_t creds = NULL;
			gss_name_t name;
			gss_buffer_desc buffer;
			OM_uint32 lifetime = 0;
			gss_cred_usage_t usage;
			const char *role = NULL;
			DEBUG(0, ("GSS %s Update(krb5)(%d) Update failed, credentials expired during GSSAPI handshake!\n",
				  role,
				  gensec_gssapi_state->gss_exchange_count));

			
			switch (gensec_security->gensec_role) {
			case GENSEC_CLIENT:
				creds = gensec_gssapi_state->client_cred->creds;
				role = "client";
				break;
			case GENSEC_SERVER:
				creds = gensec_gssapi_state->server_cred->creds;
				role = "server";
				break;
			}

			maj_stat = gss_inquire_cred(&min_stat, 
						    creds,
						    &name, &lifetime, &usage, NULL);

			if (maj_stat == GSS_S_COMPLETE) {
				const char *usage_string = NULL;
				switch (usage) {
				case GSS_C_BOTH:
					usage_string = "GSS_C_BOTH";
					break;
				case GSS_C_ACCEPT:
					usage_string = "GSS_C_ACCEPT";
					break;
				case GSS_C_INITIATE:
					usage_string = "GSS_C_INITIATE";
					break;
				}
				maj_stat = gss_display_name(&min_stat, name, &buffer, NULL);
				if (maj_stat) {
					buffer.value = NULL;
					buffer.length = 0;
				}
				if (lifetime > 0) {
					DEBUG(0, ("GSSAPI gss_inquire_cred indicates expiry of %*.*s in %u sec for %s\n", 
						  (int)buffer.length, (int)buffer.length, (char *)buffer.value, 
						  lifetime, usage_string));
				} else {
					DEBUG(0, ("GSSAPI gss_inquire_cred indicates %*.*s has already expired for %s\n", 
						  (int)buffer.length, (int)buffer.length, (char *)buffer.value, 
						  usage_string));
				}
				gss_release_buffer(&min_stat, &buffer);
				gss_release_name(&min_stat, &name);
			} else if (maj_stat != GSS_S_COMPLETE) {
				DEBUG(0, ("inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n",
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
			}
			return NT_STATUS_INVALID_PARAMETER;
		} else if (smb_gss_oid_equal(gensec_gssapi_state->gss_oid,
					     gss_mech_krb5)) {
			switch (min_stat) {
			case KRB5KRB_AP_ERR_TKT_NYV:
				DEBUG(1, ("Error with ticket to contact %s: possible clock skew between us and the KDC or target server: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_TIME_DIFFERENCE_AT_DC; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5KRB_AP_ERR_TKT_EXPIRED:
				DEBUG(1, ("Error with ticket to contact %s: ticket is expired, possible clock skew between us and the KDC or target server: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5_KDC_UNREACH:
				DEBUG(3, ("Cannot reach a KDC we require in order to obtain a ticket to %s: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_NO_LOGON_SERVERS; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
				DEBUG(3, ("Server %s is not registered with our KDC: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5KRB_AP_ERR_MSG_TYPE:
				/* garbage input, possibly from the auto-mech detection */
				return NT_STATUS_INVALID_PARAMETER;
			default:
				DEBUG(1, ("GSS %s Update(krb5)(%d) Update failed: %s\n",
					  gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
					  gensec_gssapi_state->gss_exchange_count,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_LOGON_FAILURE;
			}
		} else {
			DEBUG(1, ("GSS %s Update(%d) failed: %s\n",
				  gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
				  gensec_gssapi_state->gss_exchange_count,
				  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
			return NT_STATUS_LOGON_FAILURE;
		}
		break;
	}

	/* These last two stages are only done if we were invoked as SASL */
	case STAGE_SASL_SSF_NEG:
	{
		switch (gensec_security->gensec_role) {
		case GENSEC_CLIENT:
		{
			uint8_t maxlength_proposed[4]; 
			uint8_t maxlength_accepted[4]; 
			uint8_t security_supported;
			int conf_state;
			gss_qop_t qop_state;
			input_token.length = in.length;
			input_token.value = in.data;

			/* As a client, we have just send a
			 * zero-length blob to the server (after the
			 * normal GSSAPI exchange), and it has replied
			 * with it's SASL negotiation */
			
			maj_stat = gss_unwrap(&min_stat, 
					      gensec_gssapi_state->gssapi_context, 
					      &input_token,
					      &output_token, 
					      &conf_state,
					      &qop_state);
			if (GSS_ERROR(maj_stat)) {
				DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n", 
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_ACCESS_DENIED;
			}
			
			if (output_token.length < 4) {
				return NT_STATUS_INVALID_PARAMETER;
			}

			memcpy(maxlength_proposed, output_token.value, 4);
			gss_release_buffer(&min_stat, &output_token);

			/* first byte is the proposed security */
			security_supported = maxlength_proposed[0];
			maxlength_proposed[0] = '\0';
			
			/* Rest is the proposed max wrap length */
			gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_proposed, 0), 
								     gensec_gssapi_state->max_wrap_buf_size);
			gensec_gssapi_state->sasl_protection = 0;
			if (security_supported & NEG_SEAL) {
				if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
					gensec_gssapi_state->sasl_protection |= NEG_SEAL;
				}
			}
			if (security_supported & NEG_SIGN) {
				if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
					gensec_gssapi_state->sasl_protection |= NEG_SIGN;
				}
			}
			if (security_supported & NEG_NONE) {
				gensec_gssapi_state->sasl_protection |= NEG_NONE;
			}
			if (gensec_gssapi_state->sasl_protection == 0) {
				DEBUG(1, ("Remote server does not support unprotected connections\n"));
				return NT_STATUS_ACCESS_DENIED;
			}

			/* Send back the negotiated max length */

			RSIVAL(maxlength_accepted, 0, gensec_gssapi_state->max_wrap_buf_size);

			maxlength_accepted[0] = gensec_gssapi_state->sasl_protection;
			
			input_token.value = maxlength_accepted;
			input_token.length = sizeof(maxlength_accepted);

			maj_stat = gss_wrap(&min_stat, 
					    gensec_gssapi_state->gssapi_context, 
					    false,
					    GSS_C_QOP_DEFAULT,
					    &input_token,
					    &conf_state,
					    &output_token);
			if (GSS_ERROR(maj_stat)) {
				DEBUG(1, ("GSS Update(SSF_NEG): GSS Wrap failed: %s\n", 
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_ACCESS_DENIED;
			}
			
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat, &output_token);

			/* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
			gensec_gssapi_state->sasl_state = STAGE_DONE;

			if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
				DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically sealed\n"));
			} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
				DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically signed\n"));
			} else {
				DEBUG(3, ("SASL/GSSAPI Connection to server will have no cryptographically protection\n"));
			}

			return NT_STATUS_OK;
		}
		case GENSEC_SERVER:
		{
			uint8_t maxlength_proposed[4]; 
			uint8_t security_supported = 0x0;
			int conf_state;

			/* As a server, we have just been sent a zero-length blob (note this, but it isn't fatal) */
			if (in.length != 0) {
				DEBUG(1, ("SASL/GSSAPI: client sent non-zero length starting SASL negotiation!\n"));
			}
			
			/* Give the client some idea what we will support */
			  
			RSIVAL(maxlength_proposed, 0, gensec_gssapi_state->max_wrap_buf_size);
			/* first byte is the proposed security */
			maxlength_proposed[0] = '\0';
			
			gensec_gssapi_state->sasl_protection = 0;
			if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
				security_supported |= NEG_SEAL;
			} 
			if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
				security_supported |= NEG_SIGN;
			}
			if (security_supported == 0) {
				/* If we don't support anything, this must be 0 */
				RSIVAL(maxlength_proposed, 0, 0x0);
			}

			/* TODO:  We may not wish to support this */
			security_supported |= NEG_NONE;
			maxlength_proposed[0] = security_supported;
			
			input_token.value = maxlength_proposed;
			input_token.length = sizeof(maxlength_proposed);

			maj_stat = gss_wrap(&min_stat, 
					    gensec_gssapi_state->gssapi_context, 
					    false,
					    GSS_C_QOP_DEFAULT,
					    &input_token,
					    &conf_state,
					    &output_token);
			if (GSS_ERROR(maj_stat)) {
				DEBUG(1, ("GSS Update(SSF_NEG): GSS Wrap failed: %s\n", 
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_ACCESS_DENIED;
			}
			
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat, &output_token);

			gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_ACCEPT;
			return NT_STATUS_MORE_PROCESSING_REQUIRED;
		}
		default:
  			return NT_STATUS_INVALID_PARAMETER;
			
		}
	}
	/* This is s server-only stage */
	case STAGE_SASL_SSF_ACCEPT:
	{
		uint8_t maxlength_accepted[4]; 
		uint8_t security_accepted;
		int conf_state;
		gss_qop_t qop_state;
		input_token.length = in.length;
		input_token.value = in.data;
			
		maj_stat = gss_unwrap(&min_stat, 
				      gensec_gssapi_state->gssapi_context, 
				      &input_token,
				      &output_token, 
				      &conf_state,
				      &qop_state);
		if (GSS_ERROR(maj_stat)) {
			DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n", 
				  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
			return NT_STATUS_ACCESS_DENIED;
		}
			
		if (output_token.length < 4) {
			return NT_STATUS_INVALID_PARAMETER;
		}

		memcpy(maxlength_accepted, output_token.value, 4);
		gss_release_buffer(&min_stat, &output_token);
		
		/* first byte is the proposed security */
		security_accepted = maxlength_accepted[0];
		maxlength_accepted[0] = '\0';

		/* Rest is the proposed max wrap length */
		gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_accepted, 0), 
							     gensec_gssapi_state->max_wrap_buf_size);

		gensec_gssapi_state->sasl_protection = 0;
		if (security_accepted & NEG_SEAL) {
			if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
				DEBUG(1, ("Remote client wanted seal, but gensec refused\n"));
				return NT_STATUS_ACCESS_DENIED;
			}
			gensec_gssapi_state->sasl_protection |= NEG_SEAL;
		}
		if (security_accepted & NEG_SIGN) {
			if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
				DEBUG(1, ("Remote client wanted sign, but gensec refused\n"));
				return NT_STATUS_ACCESS_DENIED;
			}
			gensec_gssapi_state->sasl_protection |= NEG_SIGN;
		}
		if (security_accepted & NEG_NONE) {
			gensec_gssapi_state->sasl_protection |= NEG_NONE;
		}

		/* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
		gensec_gssapi_state->sasl_state = STAGE_DONE;
		if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
			DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically sealed\n"));
		} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
			DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically signed\n"));
		} else {
			DEBUG(5, ("SASL/GSSAPI Connection from client will have no cryptographic protection\n"));
		}

		*out = data_blob(NULL, 0);
		return NT_STATUS_OK;	
	}
	default:
		return NT_STATUS_INVALID_PARAMETER;
	}
}
示例#19
0
/** @brief returns the OIDs of the mechs that have usable credentials
 */
static int ssh_gssapi_match(ssh_session session, gss_OID_set *valid_oids)
{
    OM_uint32 maj_stat, min_stat, lifetime;
    gss_OID_set actual_mechs;
    gss_buffer_desc namebuf;
    gss_name_t client_id = GSS_C_NO_NAME;
    gss_OID oid;
    unsigned int i;
    char *ptr;
    int ret;

    if (session->gssapi->client.client_deleg_creds == NULL) {
        if (session->opts.gss_client_identity != NULL) {
            namebuf.value = (void *)session->opts.gss_client_identity;
            namebuf.length = strlen(session->opts.gss_client_identity);

            maj_stat = gss_import_name(&min_stat, &namebuf,
                                       GSS_C_NT_USER_NAME, &client_id);
            if (GSS_ERROR(maj_stat)) {
                ret = SSH_ERROR;
                goto end;
            }
        }

        maj_stat = gss_acquire_cred(&min_stat, client_id, GSS_C_INDEFINITE,
                                    GSS_C_NO_OID_SET, GSS_C_INITIATE,
                                    &session->gssapi->client.creds,
                                    &actual_mechs, NULL);
        if (GSS_ERROR(maj_stat)) {
            ret = SSH_ERROR;
            goto end;
        }
    } else {
        session->gssapi->client.creds =
                                    session->gssapi->client.client_deleg_creds;

        maj_stat = gss_inquire_cred(&min_stat, session->gssapi->client.creds,
                                    &client_id, NULL, NULL, &actual_mechs);
        if (GSS_ERROR(maj_stat)) {
            ret = SSH_ERROR;
            goto end;
        }
    }

    gss_create_empty_oid_set(&min_stat, valid_oids);

    /* double check each single cred */
    for (i = 0; i < actual_mechs->count; i++) {
        /* check lifetime is not 0 or skip */
        lifetime = 0;
        oid = &actual_mechs->elements[i];
        maj_stat = gss_inquire_cred_by_mech(&min_stat,
                                            session->gssapi->client.creds,
                                            oid, NULL, &lifetime, NULL, NULL);
        if (maj_stat == GSS_S_COMPLETE && lifetime > 0) {
            gss_add_oid_set_member(&min_stat, oid, valid_oids);
            ptr = ssh_get_hexa(oid->elements, oid->length);
            SSH_LOG(SSH_LOG_DEBUG, "GSSAPI valid oid %d : %s\n", i, ptr);
            SAFE_FREE(ptr);
        }
    }

    ret = SSH_OK;

end:
    gss_release_name(&min_stat, &client_id);
    return ret;
}
/**
 * @ingroup globus_gss_assist_context
 * Initialize a GSSAPI security connection. Used by the client.  
 * The context_handle is returned, and there is one for each
 * connection.  This routine will take cake of the looping
 * and token processing, using the supplied get_token and
 * send_token routines. 
 * 
 * @param minor_status
 *        GSSAPI return code.  The new minor_status is a globus_result_t
 *        cast to an OM_uint32.  If the call was successful, the minor
 *        status is equivalent to GLOBUS_SUCCESS.  Otherwise, it is a
 *        globus error object ID that can be passed to globus_error_get
 *        to get the error object.  The error object needs to be freed
 *        with globus_object_free.
 * @param cred_handle
 *        the cred handle obtained by acquire_cred.
 * @param context_handle
 *        pointer to returned context. 
 * @param target_name_char
 *        char string representation of the
 *        server to be contacted. 
 * @param req_flags
 *        request flags, such as GSS_C_DELEG_FLAG for delegation
 *        and the GSS_C_MUTUAL_FLAG for mutual authentication. 
 * @param ret_flags
 *        Pointer to which services are available after
 *        the connection is established. Maybe NULL if not wanted. 
 *
 * The following are particular to this assist routine:
 *
 * @param token_status
 *        the assist routine's get/send token status 
 * @param gss_assist_get_token 
 *        function pointer for getting the token
 * @param gss_assist_get_context
 *        first argument passed to the 
 *        gss_assist_get_token function
 * @param gss_assist_send_token
 *        function pointer for setting the token
 * @param gss_assist_send_context
 *        first argument passed to the 
 *        gss_assist_set_token function pointer
 *
 * @return
 *        The major status
 */
OM_uint32
globus_gss_assist_init_sec_context(
    OM_uint32 *                         minor_status,
    const gss_cred_id_t                 cred_handle,
    gss_ctx_id_t *                      context_handle,
    char *                              target_name_char,
    OM_uint32                           req_flags,
    OM_uint32 *                         ret_flags,
    int *                               token_status,
    int                                 (*gss_assist_get_token)(void *, void **, size_t *), 
    void *                              gss_assist_get_context,
    int                                 (*gss_assist_send_token)(void *, void *, size_t),
    void *                              gss_assist_send_context)
{
    int                                 context_established = 0;
    OM_uint32                           major_status = GSS_S_COMPLETE;
    OM_uint32                           minor_status1 = 0;
    OM_uint32                           minor_status2 = 0;
    gss_buffer_desc                     input_token_desc = GSS_C_EMPTY_BUFFER;
    gss_buffer_t                        input_token = &input_token_desc;
    gss_buffer_desc                     output_token_desc = GSS_C_EMPTY_BUFFER;
    gss_buffer_t                        output_token = &output_token_desc;
    gss_name_t                          target_name = GSS_C_NO_NAME;
    gss_OID                             target_name_type = GSS_C_NO_OID;
    gss_OID                             mech_type = GSS_C_NO_OID;
    OM_uint32                           time_req = 0;
    OM_uint32                           time_rec = 0;
    gss_channel_bindings_t              input_chan_bindings = 
        GSS_C_NO_CHANNEL_BINDINGS;
    gss_OID *                           actual_mech_type = NULL;
    gss_buffer_desc                     tmp_buffer_desc = GSS_C_EMPTY_BUFFER;
    gss_buffer_t                        tmp_buffer = &tmp_buffer_desc;
    globus_result_t                     result = GLOBUS_SUCCESS;
    static char *                       _function_name_ =
        "globus_gss_assist_init_sec_context";
    GLOBUS_I_GSI_GSS_ASSIST_DEBUG_ENTER;
    
    /*
     * should not set context_handle to NULL since it may have been
     * allocated by a call to set_sec_context_option
     */
    
    /*    *context_handle = GSS_C_NO_CONTEXT; */
    if(ret_flags)
    {
        *ret_flags = 0;
    }

    /* supply the service name to the gss-api
     * If NULL, then we want user_to_user
     * so get it from the cred
     */

    if (target_name_char)
    {
        if(!strncmp("GSI-NO-TARGET", target_name_char, 13))
        {
            target_name = GSS_C_NO_NAME;
        }
        else
        {
            tmp_buffer->value = target_name_char;
            tmp_buffer->length = strlen(target_name_char);
          
            /* 
             * A gss_nt_service_name is of the form service@FQDN
             * At least the Globus GSSAPI, and the Kerberos GSSAPI 
             * use the same form. We will check for 
             * two special forms here: host@FQDN and ftp@FQDN
             * This could be another parameter to the gss_assist
             * instead. 
             */

            if (strchr(target_name_char,'@') && 
                !strstr(target_name_char,"CN="))
            { 
                target_name_type = gss_nt_service_name;
            }

            major_status = gss_import_name(&minor_status1,
                                           tmp_buffer,
                                           target_name_type,
                                           &target_name);
        }        
    }
    else
    {
        major_status = gss_inquire_cred(&minor_status1,
                                        cred_handle,
                                        &target_name,
                                        NULL,
                                        NULL,
                                        NULL);
    }

    if (major_status == GSS_S_COMPLETE)
    {
        while (!context_established)
        {
            GLOBUS_I_GSI_GSS_ASSIST_DEBUG_FPRINTF(
                4, (globus_i_gsi_gss_assist_debug_fstream,
                    _GASL("req_flags: %8.8x  input_token length: %u\n"),
                    (unsigned int) req_flags, 
                    input_token->length));
            
            major_status = gss_init_sec_context(&minor_status1,
                                                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);

            GLOBUS_I_GSI_GSS_ASSIST_DEBUG_FPRINTF(
                4, (globus_i_gsi_gss_assist_debug_fstream,
                    _GASL("major:%8.8x  minor:%8.8x  ret_flags: %8.8x\n "
                    "output_token length: %u  context_handle: %p\n"),
                    (unsigned int) major_status, 
                    (unsigned int) minor_status1, 
                    (unsigned int) ((ret_flags) ? *ret_flags : -1),
                    output_token->length,
                    *context_handle));

            if (input_token->length > 0)
            {
                free(input_token->value);
                input_token->length = 0;
            }

            if (output_token->length != 0)
            {
                if ((*token_status = gss_assist_send_token(
                         gss_assist_send_context, 
                         output_token->value,
                         output_token->length)) != 0)
                {
                    major_status = 
                        GSS_S_DEFECTIVE_TOKEN | GSS_S_CALL_INACCESSIBLE_WRITE;
                }

                gss_release_buffer(&minor_status2,
                                   output_token);
            }

            if (GSS_ERROR(major_status))
            {
                if (*context_handle != GSS_C_NO_CONTEXT)
                {
                    gss_delete_sec_context(&minor_status2,
                                           context_handle,
                                           GSS_C_NO_BUFFER);
                }
                break;
            }
            
            if (major_status & GSS_S_CONTINUE_NEEDED)
            {
                if ((*token_status =  gss_assist_get_token(
                         gss_assist_get_context,
                         &input_token->value,
                         &input_token->length)) != 0)
                {
                    major_status = 
                        GSS_S_DEFECTIVE_TOKEN | GSS_S_CALL_INACCESSIBLE_READ;
                    break;
                }

            }
            else
            {
                context_established = 1;
            }
        } /* end of GSS loop */
    }

    if (input_token->length > 0)
    {
        free(input_token->value); /* alloc done by g_get_token */
        input_token->value = NULL;
        input_token->length = 0;
    }

    if (target_name != GSS_C_NO_NAME)
    {
        gss_release_name(&minor_status2,&target_name);
    }

    result = (globus_result_t) minor_status1;
    if(result != GLOBUS_SUCCESS)
    {
        GLOBUS_GSI_GSS_ASSIST_ERROR_CHAIN_RESULT(
            result,
            GLOBUS_GSI_GSS_ASSIST_ERROR_WITH_INIT);
    }
    *minor_status = (OM_uint32) result;

    GLOBUS_I_GSI_GSS_ASSIST_DEBUG_EXIT;
    return major_status;
}
示例#21
0
文件: t_s4u.c 项目: Akasurde/krb5
static void
constrained_delegate(gss_OID_set desired_mechs, gss_name_t target,
                     gss_cred_id_t delegated_cred_handle,
                     gss_cred_id_t verifier_cred_handle)
{
    OM_uint32 major, minor;
    gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT;
    gss_name_t cred_name = GSS_C_NO_NAME;
    OM_uint32 time_rec, lifetime;
    gss_cred_usage_t usage;
    gss_buffer_desc token;
    gss_OID_set mechs;

    printf("Constrained delegation tests follow\n");
    printf("-----------------------------------\n\n");

    if (gss_inquire_cred(&minor, verifier_cred_handle, &cred_name,
                         &lifetime, &usage, NULL) == GSS_S_COMPLETE) {
        display_canon_name("Proxy name", cred_name, &mech_krb5);
        (void)gss_release_name(&minor, &cred_name);
    }
    display_canon_name("Target name", target, &mech_krb5);
    if (gss_inquire_cred(&minor, delegated_cred_handle, &cred_name,
                         &lifetime, &usage, &mechs) == GSS_S_COMPLETE) {
        display_canon_name("Delegated name", cred_name, &mech_krb5);
        display_oid("Delegated mech", &mechs->elements[0]);
        (void)gss_release_name(&minor, &cred_name);
    }

    printf("\n");

    major = gss_init_sec_context(&minor, delegated_cred_handle,
                                 &initiator_context, target,
                                 mechs ? &mechs->elements[0] : &mech_krb5,
                                 GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
                                 GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS,
                                 GSS_C_NO_BUFFER, NULL, &token, NULL,
                                 &time_rec);
    check_gsserr("gss_init_sec_context", major, minor);

    (void)gss_release_buffer(&minor, &token);
    (void)gss_delete_sec_context(&minor, &initiator_context, NULL);

    /* Ensure a second call does not acquire new ticket. */
    major = gss_init_sec_context(&minor, delegated_cred_handle,
                                 &initiator_context, target,
                                 mechs ? &mechs->elements[0] : &mech_krb5,
                                 GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
                                 GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS,
                                 GSS_C_NO_BUFFER, NULL, &token, NULL,
                                 &time_rec);
    check_gsserr("gss_init_sec_context", major, minor);

    (void)gss_release_buffer(&minor, &token);
    (void)gss_delete_sec_context(&minor, &initiator_context, NULL);
    (void)gss_release_oid_set(&minor, &mechs);

    /* We expect three tickets: our TGT, the evidence ticket, and the ticket to
     * the target service. */
    check_ticket_count(delegated_cred_handle, 3);
}
示例#22
0
uint32_t gp_export_gssx_cred(uint32_t *min, struct gp_call_ctx *gpcall,
                             gss_cred_id_t *in, gssx_cred *out)
{
    uint32_t ret_maj;
    uint32_t ret_min;
    gss_name_t name = NULL;
    uint32_t lifetime;
    gss_cred_usage_t cred_usage;
    gss_OID_set mechanisms = NULL;
    uint32_t initiator_lifetime;
    uint32_t acceptor_lifetime;
    struct gssx_cred_element *el;
    int ret;
    int i, j;
    struct gp_creds_handle *handle = NULL;
    gss_buffer_desc token = GSS_C_EMPTY_BUFFER;

    ret_maj = gss_inquire_cred(&ret_min, *in,
                               &name, &lifetime, &cred_usage, &mechanisms);
    if (ret_maj) {
        goto done;
    }

    ret_maj = gp_conv_name_to_gssx(&ret_min, name, &out->desired_name);
    if (ret_maj) {
        goto done;
    }
    gss_release_name(&ret_min, &name);
    name = NULL;

    out->elements.elements_len = mechanisms->count;
    out->elements.elements_val = calloc(out->elements.elements_len,
                                        sizeof(gssx_cred_element));
    if (!out->elements.elements_val) {
        ret_maj = GSS_S_FAILURE;
        ret_min = ENOMEM;
        goto done;
    }

    for (i = 0, j = 0; i < mechanisms->count; i++, j++) {

        el = &out->elements.elements_val[j];

        ret_maj = gss_inquire_cred_by_mech(&ret_min, *in,
                                           &mechanisms->elements[i],
                                           &name,
                                           &initiator_lifetime,
                                           &acceptor_lifetime,
                                           &cred_usage);
        if (ret_maj) {
            gp_log_failure(&mechanisms->elements[i], ret_maj, ret_min);

            /* temporarily skip any offender */
            out->elements.elements_len--;
            j--;
            continue;
#if 0
            ret = EINVAL;
            goto done;
#endif
        }

        ret_maj = gp_conv_name_to_gssx(&ret_min, name, &el->MN);
        if (ret_maj) {
            goto done;
        }
        gss_release_name(&ret_min, &name);
        name = NULL;

        ret = gp_conv_oid_to_gssx(&mechanisms->elements[i], &el->mech);
        if (ret) {
            ret_maj = GSS_S_FAILURE;
            ret_min = ret;
            goto done;
        }
        el->cred_usage = gp_conv_gssx_to_cred_usage(cred_usage);

        el->initiator_time_rec = initiator_lifetime;
        el->acceptor_time_rec = acceptor_lifetime;
    }

    handle = gp_service_get_creds_handle(gpcall->service);
    if (!handle) {
        ret_maj = GSS_S_FAILURE;
        ret_min = EINVAL;
        goto done;
    }

    ret_maj = gss_export_cred(&ret_min, *in, &token);
    if (ret_maj) {
        goto done;
    }

    ret = gp_encrypt_buffer(handle->context, &handle->key,
                            token.length, token.value,
                            &out->cred_handle_reference);
    if (ret) {
        ret_maj = GSS_S_FAILURE;
        ret_min = ret;
        goto done;
    }
    out->needs_release = false;
    /* now we have serialized creds in the hands of the client.
     * we can safey free them here so that we can remain sateless and
     * not leak memory */
    gss_release_cred(&ret_min, in);

    ret_maj = GSS_S_COMPLETE;
    ret_min = 0;

done:
    *min = ret_min;
    gss_release_name(&ret_min, &name);
    gss_release_oid_set(&ret_min, &mechanisms);
    return ret_maj;
}
示例#23
0
int gw_em_mad_check_credentials(char *info)
{
    int rc;
    gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
    OM_uint32 major_status; 
    OM_uint32 minor_status;
    OM_uint32 lifetime;
    time_t goodtill;
    static time_t last_goodtill = 0;
    char goodtill_str[26];
    
    info[0] = '\0';
    
    /* (Re)adquire credentials */
    major_status = globus_gss_assist_acquire_cred(&minor_status,
            GSS_C_INITIATE,
            &gss_cred);

    if (major_status != GSS_S_COMPLETE) 
    {
        sprintf(info, "Error loading credentials");
        return 1;
    } 

    gss_inquire_cred(&minor_status, gss_cred, NULL, &lifetime, NULL, NULL);
    goodtill = time(NULL) + lifetime;

#ifdef GWSOLARIS
    ctime_r(&(goodtill), goodtill_str, sizeof(char)*26);
#else
    ctime_r(&(goodtill), goodtill_str);
#endif

    goodtill_str[24]='\0';
    
    printf("TIMER - SUCCESS Credential is valid until %s\n", goodtill_str);
    
    if (last_goodtill == 0)
    {
        last_goodtill = goodtill;
    }
    else if (goodtill > last_goodtill)
    {
        rc = globus_gram_client_set_credentials(gss_cred);

        if (rc != 0)
        {
            sprintf(info, "Error setting credentials");
            return 1;
        }

        printf("TIMER - SUCCESS Refreshing credentials until %s\n",
                goodtill_str);
        
        last_goodtill = goodtill;
        rc = gw_em_mad_refresh(gss_cred, info);

        if (rc != 0)
        {
            return 1;
        }
    }

    return 0;
}   
示例#24
0
OM_uint32 GSSAPI_CALLCONV
_gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status,
				   gss_name_t target_name,
				   OM_uint32 (*func)(void *, gss_name_t, const gss_cred_id_t, gss_OID),
				   void *userctx,
				   int includeMSCompatOID,
				   const gss_cred_id_t cred_handle,
				   MechTypeList *mechtypelist,
				   gss_OID *preferred_mech)
{
    gss_OID_set supported_mechs = GSS_C_NO_OID_SET;
    gss_OID first_mech = GSS_C_NO_OID;
    OM_uint32 ret, junk;
    int present = 0;
    size_t i;

    mechtypelist->len = 0;
    mechtypelist->val = NULL;

    if (cred_handle) {
	ret = gss_inquire_cred(minor_status,
			       cred_handle,
			       NULL,
			       NULL,
			       NULL,
			       &supported_mechs);
    } else {
	ret = gss_indicate_mechs(minor_status, &supported_mechs);
    }

    if (ret != GSS_S_COMPLETE) {
	return ret;
    }

    if (supported_mechs->count == 0) {
	*minor_status = ENOENT;
	gss_release_oid_set(minor_status, &supported_mechs);
	return GSS_S_FAILURE;
    }

    /*
     * Propose Kerberos mech first if we have Kerberos credentials/supported mechs
     */

    ret = gss_test_oid_set_member(&junk, GSS_KRB5_MECHANISM, supported_mechs, &present);
    if (ret == GSS_S_COMPLETE && present) {
	ret = (*func)(userctx, target_name, cred_handle, GSS_KRB5_MECHANISM);
	if (ret == GSS_S_COMPLETE) {
	    ret = add_mech_type(GSS_KRB5_MECHANISM,
				includeMSCompatOID,
				mechtypelist);
	    if (!GSS_ERROR(ret)) {
		if (includeMSCompatOID)
		    first_mech = &_gss_spnego_mskrb_mechanism_oid_desc;
		else
		    first_mech = GSS_KRB5_MECHANISM;
	    }
#ifdef __APPLE_PRIVATE__
	    (void)add_mech_type(GSS_APPL_LKDC_SUPPORTED, 0, mechtypelist);
#endif
	}
    }
    ret = GSS_S_COMPLETE;

    /*
     * Now lets, check all other mechs
     */

    for (i = 0; i < supported_mechs->count; i++) {
	OM_uint32 subret;
	if (gss_oid_equal(&supported_mechs->elements[i], GSS_SPNEGO_MECHANISM))
	    continue;
	if (gss_oid_equal(&supported_mechs->elements[i], GSS_KRB5_MECHANISM))
	    continue;
	if (gss_oid_equal(&supported_mechs->elements[i], GSS_NETLOGON_MECHANISM))
	    continue;

	subret = (*func)(userctx, target_name, cred_handle, &supported_mechs->elements[i]);
	if (subret != GSS_S_COMPLETE)
	    continue;

	ret = add_mech_type(&supported_mechs->elements[i],
			    includeMSCompatOID,
			    mechtypelist);
	if (ret != 0) {
	    *minor_status = ret;
	    ret = GSS_S_FAILURE;
	    break;
	}
	if (first_mech == GSS_C_NO_OID)
	    first_mech = &supported_mechs->elements[i];
    }

    if (mechtypelist->len == 0) {
	gss_release_oid_set(minor_status, &supported_mechs);
	*minor_status = 0;
	return GSS_S_BAD_MECH;
    }

    if (preferred_mech != NULL) {
	ret = gss_duplicate_oid(minor_status, first_mech, preferred_mech);
	if (ret != GSS_S_COMPLETE)
	    free_MechTypeList(mechtypelist);
    }
    gss_release_oid_set(minor_status, &supported_mechs);

    return ret;
}
示例#25
0
gss_client_response *authenticate_gss_server_init(const char *service, bool constrained_delegation, const char *username, gss_server_state *state)
{
    OM_uint32 maj_stat;
    OM_uint32 min_stat;
    gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER;
    int ret = AUTH_GSS_COMPLETE;
    gss_client_response *response = NULL;
    gss_cred_usage_t usage = GSS_C_ACCEPT;

    state->context = GSS_C_NO_CONTEXT;
    state->server_name = GSS_C_NO_NAME;
    state->client_name = GSS_C_NO_NAME;
    state->server_creds = GSS_C_NO_CREDENTIAL;
    state->client_creds = GSS_C_NO_CREDENTIAL;
    state->username = NULL;
    state->targetname = NULL;
    state->response = NULL;
    state->constrained_delegation = constrained_delegation;
    state->delegated_credentials_cache = NULL;
    
    // Server name may be empty which means we aren't going to create our own creds
    size_t service_len = strlen(service);
    if (service_len != 0)
    {
        // Import server name first
        name_token.length = strlen(service);
        name_token.value = (char *)service;
        
        maj_stat = gss_import_name(&min_stat, &name_token, GSS_C_NT_HOSTBASED_SERVICE, &state->server_name);
        
        if (GSS_ERROR(maj_stat))
        {
            response = gss_error(__func__, "gss_import_name", maj_stat, min_stat);
            response->return_code = AUTH_GSS_ERROR;
            goto end;
        }
        
        if (state->constrained_delegation)
        {
            usage = GSS_C_BOTH;
        }

        // Get credentials
        maj_stat = gss_acquire_cred(&min_stat, state->server_name, GSS_C_INDEFINITE,
                                    GSS_C_NO_OID_SET, usage, &state->server_creds, NULL, NULL);

        if (GSS_ERROR(maj_stat))
        {
            response = gss_error(__func__, "gss_acquire_cred", maj_stat, min_stat);
            response->return_code = AUTH_GSS_ERROR;
            goto end;
        }
    }
    
    // If a username was passed, perform the S4U2Self protocol transition to acquire
    // a credentials from that user as if we had done gss_accept_sec_context.
    // In this scenario, the passed username is assumed to be already authenticated
    // by some external mechanism, and we are here to "bootstrap" some gss credentials.
    // In authenticate_gss_server_step we will bypass the actual authentication step.
    if (username != NULL)
    {
	gss_name_t gss_username;

	name_token.length = strlen(username);
	name_token.value = (char *)username;

	maj_stat = gss_import_name(&min_stat, &name_token, GSS_C_NT_USER_NAME, &gss_username);
	if (GSS_ERROR(maj_stat))
	{
	    response = gss_error(__func__, "gss_import_name", maj_stat, min_stat);
	    response->return_code = AUTH_GSS_ERROR;
	    goto end;
	}

	maj_stat = gss_acquire_cred_impersonate_name(&min_stat,
		state->server_creds,
		gss_username,
		GSS_C_INDEFINITE,
		GSS_C_NO_OID_SET,
		GSS_C_INITIATE,
		&state->client_creds,
		NULL,
		NULL);

	if (GSS_ERROR(maj_stat))
	{
	    response = gss_error(__func__, "gss_acquire_cred_impersonate_name", maj_stat, min_stat);
	    response->return_code = AUTH_GSS_ERROR;
	}

	gss_release_name(&min_stat, &gss_username);

	if (response != NULL)
	{
	    goto end;
	}

	// because the username MAY be a "local" username,
	// we want get the canonical name from the acquired creds.
	maj_stat = gss_inquire_cred(&min_stat, state->client_creds, &state->client_name, NULL, NULL, NULL);
	if (GSS_ERROR(maj_stat))
	{
	    response = gss_error(__func__, "gss_inquire_cred", maj_stat, min_stat);
	    response->return_code = AUTH_GSS_ERROR;
	    goto end;
	}
    }

end:
    if(response == NULL) {
      response = calloc(1, sizeof(gss_client_response));
      if(response == NULL) die1("Memory allocation failed");
      response->return_code = ret;
    }

    // Return the response
    return response;
}
GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gss_acquire_cred_with_password(OM_uint32 *minor_status,
			       const gss_name_t desired_name,
			       const gss_buffer_t password,
			       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)
{
    OM_uint32 major_status, tmp_minor;

    if (desired_mechs == GSS_C_NO_OID_SET) {
	major_status = _gss_acquire_cred_ext(minor_status,
					     desired_name,
					     GSS_C_CRED_PASSWORD,
					     password,
					     time_req,
					     GSS_C_NO_OID,
					     cred_usage,
					     output_cred_handle);
	if (GSS_ERROR(major_status))
	    return major_status;
    } else {
	size_t i;
	struct _gss_cred *new_cred;

	new_cred = calloc(1, sizeof(*new_cred));
	if (new_cred == NULL) {
	    *minor_status = ENOMEM;
	    return GSS_S_FAILURE;
	}
	HEIM_SLIST_INIT(&new_cred->gc_mc);

	for (i = 0; i < desired_mechs->count; i++) {
	    struct _gss_cred *tmp_cred = NULL;
	    struct _gss_mechanism_cred *mc;

	    major_status = _gss_acquire_cred_ext(minor_status,
						 desired_name,
						 GSS_C_CRED_PASSWORD,
						 password,
						 time_req,
						 &desired_mechs->elements[i],
						 cred_usage,
						 (gss_cred_id_t *)&tmp_cred);
	    if (GSS_ERROR(major_status))
		continue;

	    mc = HEIM_SLIST_FIRST(&tmp_cred->gc_mc);
	    if (mc) {
		HEIM_SLIST_REMOVE_HEAD(&tmp_cred->gc_mc, gmc_link);
		HEIM_SLIST_INSERT_HEAD(&new_cred->gc_mc, mc, gmc_link);
	    }

	    gss_release_cred(&tmp_minor, (gss_cred_id_t *)&tmp_cred);
	}

	if (!HEIM_SLIST_FIRST(&new_cred->gc_mc)) {
	    free(new_cred);
	    *minor_status = 0;
	    return GSS_S_NO_CRED;
	}

	*output_cred_handle = (gss_cred_id_t)new_cred;
    }

    if (actual_mechs != NULL || time_rec != NULL) {
	major_status = gss_inquire_cred(minor_status,
					*output_cred_handle,
					NULL,
					time_rec,
					NULL,
					actual_mechs);
	if (GSS_ERROR(major_status)) {
	    gss_release_cred(&tmp_minor, output_cred_handle);
	    return major_status;
	}
    }

    *minor_status = 0;
    return GSS_S_COMPLETE;
}
int main()
{
    OM_uint32                           init_maj_stat;
    OM_uint32                           accept_maj_stat;
    OM_uint32                           maj_stat;
    OM_uint32                           min_stat;
    OM_uint32                           ret_flags;
    OM_uint32                           req_flags = 0;
    OM_uint32                           time_rec;
    gss_buffer_desc                     send_tok;
    gss_buffer_desc                     recv_tok;
    gss_buffer_desc *                   token_ptr;
    gss_OID                             mech_type;
    gss_name_t                          target_name;
    gss_ctx_id_t                        init_context;
    gss_ctx_id_t                        accept_context;
    gss_ctx_id_t                        del_init_context;
    gss_ctx_id_t                        del_accept_context;
    gss_cred_id_t                       delegated_cred;
    gss_cred_id_t                       imported_cred;
    gss_cred_id_t                       cred_handle;
    char *                              error_str;
    globus_result_t                     result;
    globus_gsi_cert_utils_cert_type_t   cert_type;
    int                                 rc = EXIT_SUCCESS;

    printf("1..1\n");
    /* Activate Modules */
    globus_module_activate(GLOBUS_GSI_GSSAPI_MODULE);

    /* Initialize variables */
    
    token_ptr = GSS_C_NO_BUFFER;
    init_context = GSS_C_NO_CONTEXT;
    accept_context = GSS_C_NO_CONTEXT;
    del_init_context = GSS_C_NO_CONTEXT;
    del_accept_context = GSS_C_NO_CONTEXT;
    delegated_cred = GSS_C_NO_CREDENTIAL;
    accept_maj_stat = GSS_S_CONTINUE_NEEDED;
    ret_flags = 0;
    req_flags |= GSS_C_GLOBUS_LIMITED_DELEG_PROXY_FLAG;


    /* acquire the credential */

    maj_stat = gss_acquire_cred(&min_stat,
                                NULL,
                                GSS_C_INDEFINITE,
                                GSS_C_NO_OID_SET,
                                GSS_C_BOTH,
                                &cred_handle,
                                NULL,
                                NULL);

    if(maj_stat != GSS_S_COMPLETE)
    {
        globus_gsi_gssapi_test_print_error(stderr, maj_stat, min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    
    /* get the subject name */
    
    maj_stat = gss_inquire_cred(&min_stat, 
                                cred_handle,
                                &target_name,
                                NULL,
                                NULL,
                                NULL);

    if(maj_stat != GSS_S_COMPLETE)
    {
        globus_gsi_gssapi_test_print_error(stderr, maj_stat, min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }


    /* set up the first security context */
    
    init_maj_stat = gss_init_sec_context(&min_stat,
                                         cred_handle,
                                         &init_context,
                                         target_name,
                                         GSS_C_NULL_OID,
                                         0,
                                         0,
                                         GSS_C_NO_CHANNEL_BINDINGS,
                                         token_ptr,
                                         NULL,
                                         &send_tok,
                                         NULL,
                                         NULL);


    if(init_maj_stat != GSS_S_CONTINUE_NEEDED)
    {
        globus_gsi_gssapi_test_print_error(stderr, init_maj_stat, min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    while(1)
    {
        
        accept_maj_stat=gss_accept_sec_context(&min_stat,
                                               &accept_context,
                                               GSS_C_NO_CREDENTIAL,
                                               &send_tok, 
                                               GSS_C_NO_CHANNEL_BINDINGS,
                                               NULL,
                                               &mech_type,
                                               &recv_tok,
                                               &ret_flags,
                                               /* ignore time_rec */
                                               NULL, 
                                               NULL);

        if(accept_maj_stat != GSS_S_COMPLETE &&
           accept_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gsi_gssapi_test_print_error(stderr, accept_maj_stat, min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
        else if(accept_maj_stat == GSS_S_COMPLETE)
        {
            break;
        }

        init_maj_stat = gss_init_sec_context(&min_stat,
                                             GSS_C_NO_CREDENTIAL,
                                             &init_context,
                                             target_name,
                                             GSS_C_NULL_OID,
                                             0,
                                             0,
                                             GSS_C_NO_CHANNEL_BINDINGS,
                                             &recv_tok,
                                             NULL,
                                             &send_tok,
                                             NULL,
                                             NULL);
        
        
        if(init_maj_stat != GSS_S_COMPLETE &&
           init_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gsi_gssapi_test_print_error(stderr, init_maj_stat, min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
    }

    printf("# %s:%d: Successfully established initial security context\n",
           __FILE__,
           __LINE__);


    /* delegate our credential over the initial security context and
     * insert a restriction extension into the delegated credential.
     * This is a post GT 2.0 feature.
     */


    init_maj_stat = gss_init_delegation(&min_stat,
                                        init_context,
                                        cred_handle,
                                        GSS_C_NO_OID,
                                        GSS_C_NO_OID_SET,
                                        GSS_C_NO_BUFFER_SET,
                                        token_ptr,
                                        req_flags,
                                        0,
                                        &send_tok);
    

    if(init_maj_stat != GSS_S_COMPLETE &&
       init_maj_stat != GSS_S_CONTINUE_NEEDED)
    {
        globus_gsi_gssapi_test_print_error(stderr, init_maj_stat, min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    while(1)
    {
        accept_maj_stat=gss_accept_delegation(&min_stat,
                                              accept_context,
                                              GSS_C_NO_OID_SET,
                                              GSS_C_NO_BUFFER_SET,
                                              &send_tok,
                                              req_flags,
                                              0,
                                              &time_rec,
                                              &delegated_cred,
                                              &mech_type,
                                              &recv_tok);
        
        if(accept_maj_stat != GSS_S_COMPLETE &&
           accept_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gsi_gssapi_test_print_error(stderr, accept_maj_stat, min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
        else if(accept_maj_stat == GSS_S_COMPLETE)
        {
            break;
        }

        init_maj_stat = gss_init_delegation(&min_stat,
                                            init_context,
                                            cred_handle,
                                            GSS_C_NO_OID,
                                            GSS_C_NO_OID_SET,
                                            GSS_C_NO_BUFFER_SET,
                                            &recv_tok,
                                            req_flags,
                                            0,
                                            &send_tok);


        if(init_maj_stat != GSS_S_COMPLETE &&
           init_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gsi_gssapi_test_print_error(stderr, init_maj_stat, min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
    }
    
    printf("# %s:%d: Successfully delegated credential\n",
           __FILE__,
           __LINE__);

    /* export and import the delegated credential */
    /* this can be done both to a buffer and to a file */
    /* New in GT 2.0 */

    maj_stat = gss_export_cred(&min_stat,
                               delegated_cred,
                               GSS_C_NO_OID,
                               0,
                               &send_tok);

    if(maj_stat != GSS_S_COMPLETE)
    {
        globus_gsi_gssapi_test_print_error(stderr, maj_stat, min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    
    maj_stat = gss_import_cred(&min_stat,
                               &imported_cred,
                               GSS_C_NO_OID,
                               0,
                               &send_tok,
                               0,
                               &time_rec);


    if(maj_stat != GSS_S_COMPLETE)
    {
        globus_gsi_gssapi_test_print_error(stderr, maj_stat, min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    printf("# %s:%d: Successfully exported/imported the delegated credential\n",
           __FILE__,
           __LINE__);

    /* set up another security context using the delegated credential */
    
    init_maj_stat = gss_init_sec_context(&min_stat,
                                         imported_cred,
                                         &del_init_context,
                                         target_name,
                                         GSS_C_NULL_OID,
                                         0,
                                         0,
                                         GSS_C_NO_CHANNEL_BINDINGS,
                                         token_ptr,
                                         NULL,
                                         &send_tok,
                                         NULL,
                                         NULL);


    if(init_maj_stat != GSS_S_COMPLETE &&
       init_maj_stat != GSS_S_CONTINUE_NEEDED)
    {
        globus_gsi_gssapi_test_print_error(stderr, init_maj_stat, min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }


    
    while(1)
    {
        accept_maj_stat=gss_accept_sec_context(&min_stat,
                                               &del_accept_context,
                                               imported_cred,
                                               &send_tok, 
                                               GSS_C_NO_CHANNEL_BINDINGS,
                                               NULL,
                                               &mech_type,
                                               &recv_tok,
                                               &ret_flags,
                                               /* ignore time_rec */
                                               NULL, 
                                               NULL);

        if(accept_maj_stat != GSS_S_COMPLETE &&
           accept_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gsi_gssapi_test_print_error(stderr, accept_maj_stat, min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
        else if(accept_maj_stat == GSS_S_COMPLETE)
        {
            break;
        }
        
        init_maj_stat = gss_init_sec_context(&min_stat,
                                             imported_cred,
                                             &del_init_context,
                                             target_name,
                                             GSS_C_NULL_OID,
                                             0,
                                             0,
                                             GSS_C_NO_CHANNEL_BINDINGS,
                                             &recv_tok,
                                             NULL,
                                             &send_tok,
                                             NULL,
                                             NULL);
        
        
        if(init_maj_stat != GSS_S_COMPLETE &&
           init_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gsi_gssapi_test_print_error(stderr, init_maj_stat, min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
    }

    /* got sec context based on delegated cred now */
    printf("# %s:%d: Successfully established security context with delegated credential\n",
           __FILE__,
           __LINE__);

    /* Verify that the delegated credential is a limited proxy */
    result = globus_gsi_cred_get_cert_type(
        ((gss_cred_id_desc *)imported_cred)->cred_handle,
        &cert_type);
    if(result != GLOBUS_SUCCESS)
    {
        char *                          error_str;
        globus_object_t *               error_obj;

        error_obj = globus_error_get(result);
        error_str = globus_error_print_chain(error_obj);
        fprintf(stderr, "%s", error_str);
        globus_libc_free(error_str);
        globus_object_free(error_obj);
        rc = EXIT_FAILURE;
        goto fail;
    }

    if (! GLOBUS_GSI_CERT_UTILS_IS_LIMITED_PROXY(cert_type))
    {
        fprintf(stderr,
                "Invalid certificate type. Expected a limited proxy, got %d\n",
                (int) cert_type);
        rc = EXIT_FAILURE;
        goto fail;
    }

fail:
    printf("%s gssapi_limited_delegation_test\n",
            (rc==EXIT_SUCCESS) ? "ok" : "not ok");
    globus_module_deactivate_all();
    
    exit(rc);    
}
int main()
{
    OM_uint32                           init_maj_stat;
    OM_uint32                           accept_maj_stat;
    OM_uint32                           maj_stat;
    OM_uint32                           min_stat;
    OM_uint32                           ret_flags;
    OM_uint32                           req_flags = 0;
    OM_uint32                           time_rec;
    gss_buffer_desc                     send_tok;
    gss_buffer_desc                     recv_tok;
    gss_buffer_desc *                   token_ptr;
    gss_OID                             mech_type;
    gss_name_t                          target_name;
    gss_ctx_id_t                        init_context;
    gss_ctx_id_t                        accept_context;
    gss_ctx_id_t                        del_init_context;
    gss_ctx_id_t                        del_accept_context;
    gss_cred_id_t                       delegated_cred;
    gss_cred_id_t                       imported_cred;
    gss_cred_id_t                       cred_handle;
    char *                              error_str;
    int                                 rc = EXIT_SUCCESS;

    printf("1..1\n");
    /* Initialize variables */
    
    token_ptr = GSS_C_NO_BUFFER;
    init_context = GSS_C_NO_CONTEXT;
    accept_context = GSS_C_NO_CONTEXT;
    del_init_context = GSS_C_NO_CONTEXT;
    del_accept_context = GSS_C_NO_CONTEXT;
    delegated_cred = GSS_C_NO_CREDENTIAL;
    accept_maj_stat = GSS_S_CONTINUE_NEEDED;
    ret_flags = 0;
    req_flags |= GSS_C_GLOBUS_SSL_COMPATIBLE;

    /* Activate Modules */
    globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE);
    globus_module_activate(GLOBUS_GSI_GSSAPI_MODULE);

    maj_stat = gss_acquire_cred(&min_stat,
                                NULL,
                                GSS_C_INDEFINITE,
                                GSS_C_NO_OID_SET,
                                GSS_C_BOTH,
                                &cred_handle,
                                NULL,
                                NULL);

    if(maj_stat != GSS_S_COMPLETE)
    {
        globus_gss_assist_display_status_str(&error_str,
                                             NULL,
                                             maj_stat,
                                             min_stat,
                                             0);
        printf("\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
        globus_print_error((globus_result_t) min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    
    /* get the subject name */
    
    maj_stat = gss_inquire_cred(&min_stat, 
                                cred_handle,
                                &target_name,
                                NULL,
                                NULL,
                                NULL);

    if(maj_stat != GSS_S_COMPLETE)
    {
        globus_gss_assist_display_status_str(&error_str,
                                             NULL,
                                             maj_stat,
                                             min_stat,
                                             0);
        fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
        globus_print_error((globus_result_t) min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }


    /* set up the first security context */
    
    init_maj_stat = gss_init_sec_context(&min_stat,
                                         cred_handle,
                                         &init_context,
                                         target_name,
                                         GSS_C_NULL_OID,
                                         0,
                                         0,
                                         GSS_C_NO_CHANNEL_BINDINGS,
                                         token_ptr,
                                         NULL,
                                         &send_tok,
                                         NULL,
                                         NULL);


    if(init_maj_stat != GSS_S_CONTINUE_NEEDED)
    {
        globus_gss_assist_display_status_str(&error_str,
                                             NULL,
                                             init_maj_stat,
                                             min_stat,
                                             0);
        fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
        globus_print_error((globus_result_t) min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    while(1)
    {
        
        accept_maj_stat=gss_accept_sec_context(&min_stat,
                                               &accept_context,
                                               GSS_C_NO_CREDENTIAL,
                                               &send_tok, 
                                               GSS_C_NO_CHANNEL_BINDINGS,
                                               NULL,
                                               &mech_type,
                                               &recv_tok,
                                               &ret_flags,
                                               /* ignore time_rec */
                                               NULL, 
                                               NULL);

        if(accept_maj_stat != GSS_S_COMPLETE &&
           accept_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gss_assist_display_status_str(&error_str,
                                                 NULL,
                                                 init_maj_stat,
                                                 min_stat,
                                                 0);
            fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
            globus_print_error((globus_result_t) min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
        else if(accept_maj_stat == GSS_S_COMPLETE)
        {
            break;
        }

        init_maj_stat = gss_init_sec_context(&min_stat,
                                             GSS_C_NO_CREDENTIAL,
                                             &init_context,
                                             target_name,
                                             GSS_C_NULL_OID,
                                             0,
                                             0,
                                             GSS_C_NO_CHANNEL_BINDINGS,
                                             &recv_tok,
                                             NULL,
                                             &send_tok,
                                             NULL,
                                             NULL);
        
        
        if(init_maj_stat != GSS_S_COMPLETE &&
           init_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gss_assist_display_status_str(&error_str,
                                                 NULL,
                                                 init_maj_stat,
                                                 min_stat,
                                                 0);
            fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
            globus_print_error((globus_result_t) min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
    }

    printf("# %s:%d: Successfully established initial security context\n",
           __FILE__,
           __LINE__);


    init_maj_stat = gss_init_delegation(&min_stat,
                                        init_context,
                                        cred_handle,
                                        GSS_C_NO_OID,
                                        GSS_C_NO_OID_SET,
                                        GSS_C_NO_BUFFER_SET,
                                        token_ptr,
                                        req_flags,
                                        0,
                                        &send_tok);
    

    if(init_maj_stat != GSS_S_COMPLETE &&
       init_maj_stat != GSS_S_CONTINUE_NEEDED)
    {
        globus_gss_assist_display_status_str(&error_str,
                                             NULL,
                                             init_maj_stat,
                                             min_stat,
                                             0);
        fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
        globus_print_error((globus_result_t) min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    internal_release_buffer(&recv_tok);
    maj_stat = gss_wrap(&min_stat,
                        init_context,
                        0,
                        GSS_C_QOP_DEFAULT,
                        &send_tok,
                        NULL,
                        &recv_tok);

    if(maj_stat != GSS_S_COMPLETE)
    {
        globus_gss_assist_display_status_str(&error_str,
                                             NULL,
                                             maj_stat,
                                             min_stat,
                                             0);
        fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
        globus_print_error((globus_result_t) min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }
    
    while(1)
    {

        internal_release_buffer(&send_tok);
        maj_stat = gss_unwrap(&min_stat,
                              accept_context,
                              &recv_tok,
                              &send_tok,
                              NULL,
                              NULL);
            
        if(maj_stat != GSS_S_COMPLETE)
        {
            globus_gss_assist_display_status_str(&error_str,
                                                 NULL,
                                                 maj_stat,
                                                 min_stat,
                                                 0);
            fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
            globus_print_error((globus_result_t) min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }

        internal_release_buffer(&recv_tok);
        accept_maj_stat=gss_accept_delegation(&min_stat,
                                              accept_context,
                                              GSS_C_NO_OID_SET,
                                              GSS_C_NO_BUFFER_SET,
                                              &send_tok,
                                              req_flags,
                                              0,
                                              &time_rec,
                                              &delegated_cred,
                                              &mech_type,
                                              &recv_tok);
        
        if(accept_maj_stat != GSS_S_COMPLETE &&
           accept_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gss_assist_display_status_str(&error_str,
                                                 NULL,
                                                 init_maj_stat,
                                                 min_stat,
                                                 0);
            fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
            globus_print_error((globus_result_t) min_stat);

            rc = EXIT_FAILURE;
            goto fail;
        }
        else if(accept_maj_stat == GSS_S_COMPLETE)
        {
            break;
        }

        internal_release_buffer(&send_tok);
        maj_stat = gss_wrap(&min_stat,
                            accept_context,
                            0,
                            GSS_C_QOP_DEFAULT,
                            &recv_tok,
                            NULL,
                            &send_tok);
                        
    
        if(maj_stat != GSS_S_COMPLETE)
        {
            globus_gss_assist_display_status_str(&error_str,
                                                 NULL,
                                                 maj_stat,
                                                 min_stat,
                                                 0);
            fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
            globus_print_error((globus_result_t) min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }

        internal_release_buffer(&recv_tok);
        maj_stat = gss_unwrap(&min_stat,
                              init_context,
                              &send_tok,
                              &recv_tok,
                              NULL,
                              NULL);
        
    
        if(maj_stat != GSS_S_COMPLETE)
        {
            globus_gss_assist_display_status_str(&error_str,
                                                 NULL,
                                                 maj_stat,
                                                 min_stat,
                                                 0);
            fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
            globus_print_error((globus_result_t) min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }

        internal_release_buffer(&send_tok);
        init_maj_stat = gss_init_delegation(&min_stat,
                                            init_context,
                                            cred_handle,
                                            GSS_C_NO_OID,
                                            GSS_C_NO_OID_SET,
                                            GSS_C_NO_BUFFER_SET,
                                            &recv_tok,
                                            req_flags,
                                            0,
                                            &send_tok);


        if(init_maj_stat != GSS_S_COMPLETE &&
           init_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gss_assist_display_status_str(&error_str,
                                                 NULL,
                                                 init_maj_stat,
                                                 min_stat,
                                                 0);
            fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
            globus_print_error((globus_result_t) min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }

        internal_release_buffer(&recv_tok);
        maj_stat = gss_wrap(&min_stat,
                            init_context,
                            0,
                            GSS_C_QOP_DEFAULT,
                            &send_tok,
                            NULL,
                            &recv_tok);
        
        
        if(maj_stat != GSS_S_COMPLETE)
        {
            globus_gss_assist_display_status_str(&error_str,
                                                 NULL,
                                                 maj_stat,
                                                 min_stat,
                                                 0);
            fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
            globus_print_error((globus_result_t) min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
    }
    
    printf("# %s:%d: Successfully delegated credential\n",
           __FILE__,
           __LINE__);

    /* export and import the delegated credential */
    /* this can be done both to a buffer and to a file */
    /* New in GT 2.0 */

    internal_release_buffer(&send_tok);
    maj_stat = gss_export_cred(&min_stat,
                               delegated_cred,
                               GSS_C_NO_OID,
                               0,
                               &send_tok);

    if(maj_stat != GSS_S_COMPLETE)
    {
        globus_gss_assist_display_status_str(&error_str,
                                             NULL,
                                             init_maj_stat,
                                             min_stat,
                                             0);
        fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
        globus_print_error((globus_result_t) min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    maj_stat = gss_import_cred(&min_stat,
                               &imported_cred,
                               GSS_C_NO_OID,
                               0,
                               &send_tok,
                               0,
                               &time_rec);


    if(maj_stat != GSS_S_COMPLETE)
    {
        globus_gss_assist_display_status_str(&error_str,
                                             NULL,
                                             init_maj_stat,
                                             min_stat,
                                             0);
        fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
        globus_print_error((globus_result_t) min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }

    internal_release_buffer(&send_tok);

    printf("# %s:%d: Successfully exported/imported the delegated credential\n",
           __FILE__,
           __LINE__);

    /* set up another security context using the delegated credential */
    
    init_maj_stat = gss_init_sec_context(&min_stat,
                                         imported_cred,
                                         &del_init_context,
                                         target_name,
                                         GSS_C_NULL_OID,
                                         0,
                                         0,
                                         GSS_C_NO_CHANNEL_BINDINGS,
                                         token_ptr,
                                         NULL,
                                         &send_tok,
                                         NULL,
                                         NULL);


    if(init_maj_stat != GSS_S_COMPLETE &&
       init_maj_stat != GSS_S_CONTINUE_NEEDED)
    {
        globus_gss_assist_display_status_str(&error_str,
                                             NULL,
                                             init_maj_stat,
                                             min_stat,
                                             0);
        fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
        globus_print_error((globus_result_t) min_stat);
        rc = EXIT_FAILURE;
        goto fail;
    }
    
    while(1)
    {
        internal_release_buffer(&recv_tok);

        accept_maj_stat=gss_accept_sec_context(&min_stat,
                                               &del_accept_context,
                                               imported_cred,
                                               &send_tok, 
                                               GSS_C_NO_CHANNEL_BINDINGS,
                                               &target_name,
                                               &mech_type,
                                               &recv_tok,
                                               &ret_flags,
                                               /* ignore time_rec */
                                               NULL, 
                                               NULL);

        if(accept_maj_stat != GSS_S_COMPLETE &&
           accept_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gss_assist_display_status_str(&error_str,
                                                 NULL,
                                                 init_maj_stat,
                                                 min_stat,
                                                 0);
            fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
            globus_print_error((globus_result_t) min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
        else if(accept_maj_stat == GSS_S_COMPLETE)
        {
            break;
        }

        init_maj_stat = gss_init_sec_context(&min_stat,
                                             imported_cred,
                                             &del_init_context,
                                             target_name,
                                             GSS_C_NULL_OID,
                                             0,
                                             0,
                                             GSS_C_NO_CHANNEL_BINDINGS,
                                             &recv_tok,
                                             NULL,
                                             &send_tok,
                                             NULL,
                                             NULL);
        
        
        if(init_maj_stat != GSS_S_COMPLETE &&
           init_maj_stat != GSS_S_CONTINUE_NEEDED)
        {
            globus_gss_assist_display_status_str(&error_str,
                                                 NULL,
                                                 init_maj_stat,
                                                 min_stat,
                                                 0);
            fprintf(stderr, "\nLINE %d ERROR: %s\n\n", __LINE__, error_str);
            globus_print_error((globus_result_t) min_stat);
            rc = EXIT_FAILURE;
            goto fail;
        }
    }

    /* got sec context based on delegated cred now */

    printf("# %s:%d: Successfully established security context with delegated credential\n",
           __FILE__,
           __LINE__);

fail:
    printf("%s gssapi_delegation_compat_test\n", 
            (rc == EXIT_SUCCESS) ? "ok" : "not ok");
    globus_module_deactivate_all();

    exit(rc);
}
static void
copy_import(void)
{
    gss_cred_id_t cred1, cred2;
    OM_uint32 maj_stat, min_stat;
    gss_name_t name1, name2;
    OM_uint32 lifetime1, lifetime2;
    gss_cred_usage_t usage1, usage2;
    gss_OID_set mechs1, mechs2;
    krb5_ccache id;
    krb5_error_code ret;
    krb5_context context;
    int equal;

    maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME, GSS_C_INDEFINITE,
				GSS_C_NO_OID_SET, GSS_C_INITIATE,
				&cred1, NULL, NULL);
    if (maj_stat != GSS_S_COMPLETE)
	errx(1, "gss_acquire_cred");

    maj_stat = gss_inquire_cred(&min_stat, cred1, &name1, &lifetime1,
				&usage1, &mechs1);
    if (maj_stat != GSS_S_COMPLETE)
	errx(1, "gss_inquire_cred");

    ret = krb5_init_context(&context);
    if (ret)
	errx(1, "krb5_init_context");

    ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id);
    if (ret)
	krb5_err(context, 1, ret, "krb5_cc_new_unique");

    maj_stat = gss_krb5_copy_ccache(&min_stat, cred1, id);
    if (maj_stat != GSS_S_COMPLETE)
	errx(1, "gss_krb5_copy_ccache");

    maj_stat = gss_krb5_import_cred(&min_stat, id, NULL, NULL, &cred2);
    if (maj_stat != GSS_S_COMPLETE)
	errx(1, "gss_krb5_import_cred");

    maj_stat = gss_inquire_cred(&min_stat, cred2, &name2, &lifetime2,
				&usage2, &mechs2);
    if (maj_stat != GSS_S_COMPLETE)
	errx(1, "gss_inquire_cred 2");

    maj_stat = gss_compare_name(&min_stat, name1, name2, &equal);
    if (maj_stat != GSS_S_COMPLETE)
	errx(1, "gss_compare_name");
    if (!equal)
	errx(1, "names not equal");

    if (lifetime1 != lifetime2)
	errx(1, "lifetime not equal %lu != %lu",
	     (unsigned long)lifetime1, (unsigned long)lifetime2);

    if (usage1 != usage2) {
	/* as long any of them is both are everything it ok */
	if (usage1 != GSS_C_BOTH && usage2 != GSS_C_BOTH)
	    errx(1, "usages disjoined");
    }

    gss_release_name(&min_stat, &name2);
    gss_release_oid_set(&min_stat, &mechs2);

    maj_stat = gss_inquire_cred(&min_stat, cred2, &name2, &lifetime2,
				&usage2, &mechs2);
    if (maj_stat != GSS_S_COMPLETE)
	errx(1, "gss_inquire_cred");

    maj_stat = gss_compare_name(&min_stat, name1, name2, &equal);
    if (maj_stat != GSS_S_COMPLETE)
	errx(1, "gss_compare_name");
    if (!equal)
	errx(1, "names not equal");

    if (lifetime1 != lifetime2)
	errx(1, "lifetime not equal %lu != %lu",
	     (unsigned long)lifetime1, (unsigned long)lifetime2);

    gss_release_cred(&min_stat, &cred1);
    gss_release_cred(&min_stat, &cred2);

    gss_release_name(&min_stat, &name1);
    gss_release_name(&min_stat, &name2);

#if 0
    compare(mechs1, mechs2);
#endif

    gss_release_oid_set(&min_stat, &mechs1);
    gss_release_oid_set(&min_stat, &mechs2);

    krb5_cc_destroy(context, id);
    krb5_free_context(context);
}
示例#30
0
OM_uint32 gss_acquire_cred
           (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_cred_id_t handle;
    OM_uint32 ret;

    if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {
	*minor_status = GSS_KRB5_S_G_BAD_USAGE;
	return GSS_S_FAILURE;
    }

    GSSAPI_KRB5_INIT ();

    *output_cred_handle = NULL;
    if (time_rec)
	*time_rec = 0;
    if (actual_mechs)
	*actual_mechs = GSS_C_NO_OID_SET;

    if (desired_mechs) {
	int present = 0;

	ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
				      desired_mechs, &present); 
	if (ret)
	    return ret;
	if (!present) {
	    *minor_status = 0;
	    return GSS_S_BAD_MECH;
	}
    }

    handle = (gss_cred_id_t)malloc(sizeof(*handle));
    if (handle == GSS_C_NO_CREDENTIAL) {
	*minor_status = ENOMEM;
        return (GSS_S_FAILURE);
    }

    memset(handle, 0, sizeof (*handle));
    HEIMDAL_MUTEX_init(&handle->cred_id_mutex);

    if (desired_name != GSS_C_NO_NAME) {
	ret = gss_duplicate_name(minor_status, desired_name,
	    &handle->principal);
	if (ret != GSS_S_COMPLETE) {
	    HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
	    free(handle);
	    return (ret);
	}
    }
    if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
	ret = acquire_initiator_cred(minor_status, desired_name, time_req,
	    desired_mechs, cred_usage, handle, actual_mechs, time_rec);
    	if (ret != GSS_S_COMPLETE) {
	    HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
	    krb5_free_principal(gssapi_krb5_context, handle->principal);
	    free(handle);
	    return (ret);
	}
    }
    if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) {
	ret = acquire_acceptor_cred(minor_status, desired_name, time_req,
	    desired_mechs, cred_usage, handle, actual_mechs, time_rec);
	if (ret != GSS_S_COMPLETE) {
	    HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
	    krb5_free_principal(gssapi_krb5_context, handle->principal);
	    free(handle);
	    return (ret);
	}
    }
    ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
    if (ret == GSS_S_COMPLETE)
    	ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
				 &handle->mechanisms);
    if (ret == GSS_S_COMPLETE)
    	ret = gss_inquire_cred(minor_status, handle, NULL, time_rec, NULL,
			   actual_mechs);
    if (ret != GSS_S_COMPLETE) {
	if (handle->mechanisms != NULL)
	    gss_release_oid_set(NULL, &handle->mechanisms);
	HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
	krb5_free_principal(gssapi_krb5_context, handle->principal);
	free(handle);
	return (ret);
    } 
    *minor_status = 0;
    if (time_rec) {
	ret = gssapi_lifetime_left(minor_status,
				   handle->lifetime,
				   time_rec);

	if (ret)
	    return ret;
    }
    handle->usage = cred_usage;
    *output_cred_handle = handle;
    return (GSS_S_COMPLETE);
}