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; }
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); }
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; }
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; }
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; }
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; }
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; }
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; }
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, <ime, 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); }
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); }
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); }
/* 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; }
_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; }
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; }
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; } }
/** @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; }
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); }
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; }
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; }
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; }
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); }
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); }