OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_sec_context_by_oid (OM_uint32 * minor_status, gss_const_ctx_id_t context_handle, const gss_OID desired_object, gss_buffer_set_t *data_set) { gssspnego_ctx ctx; *minor_status = 0; if (context_handle == GSS_C_NO_CONTEXT) { return GSS_S_NO_CONTEXT; } ctx = (gssspnego_ctx)context_handle; if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { return GSS_S_NO_CONTEXT; } return gss_inquire_sec_context_by_oid(minor_status, ctx->negotiated_ctx_id, desired_object, data_set); }
OM_uint32 gssi_inquire_sec_context_by_oid(OM_uint32 *minor_status, const gss_ctx_id_t context_handle, const gss_OID desired_object, gss_buffer_set_t *data_set) { struct gpp_context_handle *ctx; OM_uint32 maj, min; GSSI_TRACE(); ctx = (struct gpp_context_handle *)context_handle; if (!ctx) { return GSS_S_CALL_INACCESSIBLE_READ; } /* for now we have support only for some specific known * mechanisms for which we can export/import the context */ if (ctx->remote && !ctx->local) { maj = gpp_remote_to_local_ctx(&min, &ctx->remote, &ctx->local); if (maj != GSS_S_COMPLETE) { *minor_status = gpp_map_error(min); return maj; } } return gss_inquire_sec_context_by_oid(minor_status, ctx->local, desired_object, data_set); }
static NTSTATUS SMBGssGetSessionKey( gss_ctx_id_t Context, PBYTE* ppSessionKey, PDWORD pdwSessionKeyLength ) { NTSTATUS status = STATUS_SUCCESS; PBYTE pSessionKey = NULL; DWORD dwSessionKeyLength = 0; OM_uint32 gssMajor = GSS_S_COMPLETE; OM_uint32 gssMinor = 0; gss_buffer_set_t sessionKey = NULL; gssMajor = gss_inquire_sec_context_by_oid( &gssMinor, Context, GSS_C_INQ_SSPI_SESSION_KEY, &sessionKey); if (gssMajor != GSS_S_COMPLETE) { smb_display_status("gss_inquire_sec_context_by_oid", gssMajor, gssMinor); // TODO - error code conversion status = gssMajor; BAIL_ON_LWIO_ERROR(status); } // The key is in element 0 and the key type OID is in element 1 if (!sessionKey || (sessionKey->count < 1) || !sessionKey->elements[0].value || (0 == sessionKey->elements[0].length)) { LWIO_ASSERT_MSG(FALSE, "Invalid session key"); status = STATUS_ASSERTION_FAILURE; BAIL_ON_LWIO_ERROR(status); } status = LW_RTL_ALLOCATE(&pSessionKey, BYTE, sessionKey->elements[0].length); BAIL_ON_LWIO_ERROR(status); memcpy(pSessionKey, sessionKey->elements[0].value, sessionKey->elements[0].length); dwSessionKeyLength = sessionKey->elements[0].length; cleanup: gss_release_buffer_set(&gssMinor, &sessionKey); *ppSessionKey = pSessionKey; *pdwSessionKeyLength = dwSessionKeyLength; return status; error: LWIO_SAFE_FREE_MEMORY(pSessionKey); dwSessionKeyLength = 0; goto cleanup; }
OM_uint32 KRB5_CALLCONV gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle, OM_uint32 version, void **kctx) { unsigned char oid_buf[GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH + 6]; gss_OID_desc req_oid; OM_uint32 major_status, minor; gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; if (kctx == NULL) return GSS_S_CALL_INACCESSIBLE_WRITE; *kctx = NULL; req_oid.elements = oid_buf; req_oid.length = sizeof(oid_buf); major_status = generic_gss_oid_compose(minor_status, GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID, GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT_OID_LENGTH, (int)version, &req_oid); if (GSS_ERROR(major_status)) return major_status; major_status = gss_inquire_sec_context_by_oid(minor_status, *context_handle, &req_oid, &data_set); if (GSS_ERROR(major_status)) return major_status; if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1 || data_set->elements[0].length != sizeof(void *)) { *minor_status = EINVAL; return GSS_S_FAILURE; } *kctx = *((void **)data_set->elements[0].value); /* Clean up the context state (it is an error for * someone to attempt to use this context again) */ (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL); *context_handle = GSS_C_NO_CONTEXT; generic_gss_release_buffer_set(&minor, &data_set); return GSS_S_COMPLETE; }
void _gss_spnego_fixup_ntlm(gssspnego_ctx ctx) { if (gss_oid_equal(ctx->negotiated_mech_type, GSS_NTLM_MECHANISM)) { gss_buffer_set_t buffer_set = GSS_C_NO_BUFFER_SET; OM_uint32 junk; gss_inquire_sec_context_by_oid(&junk, ctx->negotiated_ctx_id, GSS_C_NTLM_RESET_KEYS, &buffer_set); gss_release_buffer_set(&junk, &buffer_set); } }
OM_uint32 gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status, gss_ctx_id_t context_handle, time_t *authtime) { gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; OM_uint32 maj_stat; if (context_handle == GSS_C_NO_CONTEXT) { *minor_status = EINVAL; return GSS_S_FAILURE; } maj_stat = gss_inquire_sec_context_by_oid (minor_status, context_handle, GSS_KRB5_GET_AUTHTIME_X, &data_set); if (maj_stat) return maj_stat; if (data_set == GSS_C_NO_BUFFER_SET) { gss_release_buffer_set(minor_status, &data_set); *minor_status = EINVAL; return GSS_S_FAILURE; } if (data_set->count != 1) { gss_release_buffer_set(minor_status, &data_set); *minor_status = EINVAL; return GSS_S_FAILURE; } if (data_set->elements[0].length != 4) { gss_release_buffer_set(minor_status, &data_set); *minor_status = EINVAL; return GSS_S_FAILURE; } { unsigned char *buf = data_set->elements[0].value; *authtime = (buf[3] <<24) | (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0); } gss_release_buffer_set(minor_status, &data_set); *minor_status = 0; return GSS_S_COMPLETE; }
/* * This API should go away and be replaced with an accessor * into a gss_name_t. */ OM_uint32 KRB5_CALLCONV gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status, gss_ctx_id_t context_handle, int ad_type, gss_buffer_t ad_data) { gss_OID_desc req_oid; unsigned char oid_buf[GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH + 6]; OM_uint32 major_status; gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; if (ad_data == NULL) return GSS_S_CALL_INACCESSIBLE_WRITE; req_oid.elements = oid_buf; req_oid.length = sizeof(oid_buf); major_status = generic_gss_oid_compose(minor_status, GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID, GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH, ad_type, &req_oid); if (GSS_ERROR(major_status)) return major_status; major_status = gss_inquire_sec_context_by_oid(minor_status, context_handle, (gss_OID)&req_oid, &data_set); if (major_status != GSS_S_COMPLETE) { return major_status; } if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { return GSS_S_FAILURE; } ad_data->length = data_set->elements[0].length; ad_data->value = data_set->elements[0].value; data_set->elements[0].length = 0; data_set->elements[0].value = NULL; data_set->count = 0; gss_release_buffer_set(minor_status, &data_set); return GSS_S_COMPLETE; }
OM_uint32 ntlm_gss_inquire_sec_context_by_oid( OM_uint32 *minor_status, const gss_ctx_id_t context_handle, const gss_OID desired_object, gss_buffer_set_t *data_set) { OM_uint32 ret; ret = gss_inquire_sec_context_by_oid(minor_status, context_handle, desired_object, data_set); return (ret); }
int _gss_spnego_require_mechlist_mic(gssspnego_ctx ctx) { gss_buffer_set_t buffer_set = GSS_C_NO_BUFFER_SET; int require_mic; OM_uint32 minor; require_mic = 1; /* Acceptor requested it: mandatory to honour */ if (ctx->flags.peer_require_mic) return 1; /* Protocol can't handle mechListMIC (HTTP Negotiate) */ if (ctx->flags.protocol_require_no_mic) return 0; /* * Check whether peer indicated implicit support for updated SPNEGO * (eg. in the Kerberos case by using CFX) */ if (gss_inquire_sec_context_by_oid(&minor, ctx->negotiated_ctx_id, GSS_C_PEER_HAS_UPDATED_SPNEGO, &buffer_set) == GSS_S_COMPLETE) { require_mic = 1; gss_release_buffer_set(&minor, &buffer_set); } /* * Don't require mic for NTLM because * - Windows servers to have negTokenResp.negResult set for the acceptor to send the mic. * - SnowLeopard smb server can't handle it * So if we are the initiator and using NTLM, don't send the acceptor status. */ if (ctx->flags.local && gss_oid_equal(ctx->negotiated_mech_type, GSS_NTLM_MECHANISM)) require_mic = 0; /* Safe-to-omit MIC rules follow */ if (gss_oid_equal(ctx->negotiated_mech_type, ctx->preferred_mech_type)) { ctx->flags.safe_omit = 1; } else if (gss_oid_equal(ctx->negotiated_mech_type, &_gss_spnego_krb5_mechanism_oid_desc) && gss_oid_equal(ctx->preferred_mech_type, &_gss_spnego_mskrb_mechanism_oid_desc)) { ctx->flags.safe_omit = 1; } return require_mic; }
OM_uint32 GSSAPI_CALLCONV _gss_spnego_require_mechlist_mic(OM_uint32 *minor_status, gssspnego_ctx ctx, int *require_mic) { gss_buffer_set_t buffer_set = GSS_C_NO_BUFFER_SET; OM_uint32 minor; *minor_status = 0; *require_mic = 0; if (ctx == NULL) { return GSS_S_COMPLETE; } if (ctx->require_mic) { /* Acceptor requested it: mandatory to honour */ *require_mic = 1; return GSS_S_COMPLETE; } /* * Check whether peer indicated implicit support for updated SPNEGO * (eg. in the Kerberos case by using CFX) */ if (gss_inquire_sec_context_by_oid(&minor, ctx->negotiated_ctx_id, GSS_C_PEER_HAS_UPDATED_SPNEGO, &buffer_set) == GSS_S_COMPLETE) { *require_mic = 1; gss_release_buffer_set(&minor, &buffer_set); } /* Safe-to-omit MIC rules follow */ if (*require_mic) { if (gss_oid_equal(ctx->negotiated_mech_type, ctx->preferred_mech_type)) { *require_mic = 0; } else if (gss_oid_equal(ctx->negotiated_mech_type, &_gss_spnego_krb5_mechanism_oid_desc) && gss_oid_equal(ctx->preferred_mech_type, &_gss_spnego_mskrb_mechanism_oid_desc)) { *require_mic = 0; } } return GSS_S_COMPLETE; }
OM_uint32 gss_krb5_get_tkt_flags(OM_uint32 *minor_status, gss_ctx_id_t context_handle, OM_uint32 *tkt_flags) { OM_uint32 major_status; gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; if (context_handle == GSS_C_NO_CONTEXT) { *minor_status = EINVAL; return GSS_S_FAILURE; } major_status = gss_inquire_sec_context_by_oid (minor_status, context_handle, GSS_KRB5_GET_TKT_FLAGS_X, &data_set); if (major_status) return major_status; if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1 || data_set->elements[0].length < 4) { gss_release_buffer_set(minor_status, &data_set); *minor_status = EINVAL; return GSS_S_FAILURE; } { const u_char *p = data_set->elements[0].value; *tkt_flags = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); } gss_release_buffer_set(minor_status, &data_set); return GSS_S_COMPLETE; }
OM_uint32 KRB5_CALLCONV gss_krb5_get_tkt_flags(OM_uint32 *minor_status, gss_ctx_id_t context_handle, krb5_flags *ticket_flags) { static const gss_OID_desc req_oid = { GSS_KRB5_GET_TKT_FLAGS_OID_LENGTH, GSS_KRB5_GET_TKT_FLAGS_OID }; OM_uint32 major_status; gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; if (ticket_flags == NULL) return GSS_S_CALL_INACCESSIBLE_WRITE; major_status = gss_inquire_sec_context_by_oid(minor_status, context_handle, (gss_OID)&req_oid, &data_set); if (major_status != GSS_S_COMPLETE) return major_status; if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1 || data_set->elements[0].length != sizeof(*ticket_flags)) { *minor_status = EINVAL; return GSS_S_FAILURE; } *ticket_flags = *((krb5_flags *)data_set->elements[0].value); gss_release_buffer_set(minor_status, &data_set); *minor_status = 0; return GSS_S_COMPLETE; }
OM_uint32 KRB5_CALLCONV gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status, gss_ctx_id_t context_handle, krb5_timestamp *authtime) { static const gss_OID_desc req_oid = { GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID }; OM_uint32 major_status; gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; if (authtime == NULL) return GSS_S_CALL_INACCESSIBLE_WRITE; major_status = gss_inquire_sec_context_by_oid(minor_status, context_handle, (gss_OID)&req_oid, &data_set); if (major_status != GSS_S_COMPLETE) return major_status; if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1 || data_set->elements[0].length != sizeof(*authtime)) { *minor_status = EINVAL; return GSS_S_FAILURE; } *authtime = *((krb5_timestamp *)data_set->elements[0].value); gss_release_buffer_set(minor_status, &data_set); *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 time_rec; gss_buffer_desc send_tok; gss_buffer_desc recv_tok; gss_buffer_desc * token_ptr; gss_buffer_desc oid_buffer; gss_buffer_set_desc oid_buffers; gss_buffer_set_t inquire_buffers; gss_OID name_type; gss_OID mech_type; gss_OID_set_desc oid_set; gss_name_t target_name; gss_ctx_id_t init_context; gss_ctx_id_t accept_context; gss_ctx_id_desc * init_context_handle; 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 * subject = "/O=Grid/O=Globus/OU=mcs.anl.gov/CN=Samuel Meder"; char * error_str; char * buf; /* 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; name_type = GSS_C_NT_USER_NAME; delegated_cred = GSS_C_NO_CREDENTIAL; accept_maj_stat = GSS_S_CONTINUE_NEEDED; ret_flags = 0; oid_buffer.value = malloc(EXT_SIZE); oid_buffer.length = EXT_SIZE; buf = (char *) oid_buffer.value; memset(buf,'A',EXT_SIZE); buf[EXT_SIZE-1]='\0'; oid_buffers.count = 1; oid_buffers.elements = &oid_buffer; oid_set.count = 1; oid_set.elements = gss_restrictions_extension; send_tok.value = subject; send_tok.length = strlen(subject) + 1; /* 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_gss_assist_display_status_str(&error_str, NULL, maj_stat, min_stat, 0); printf("\nLINE %d ERROR: %s\n\n", __LINE__, error_str); exit(1); } /* import the subject name */ maj_stat = gss_import_name(&min_stat, &send_tok, name_type, &target_name); 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); exit(1); } /* 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); printf("\nLINE %d ERROR: %s\n\n", __LINE__, error_str); exit(1); } 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, GSS_C_NO_CREDENTIAL); 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); printf("\nLINE %d ERROR: %s\n\n", __LINE__, error_str); exit(1); } 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); printf("\nLINE %d ERROR: %s\n\n", __LINE__, error_str); exit(1); } } 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, &oid_set, &oid_buffers, token_ptr, 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); printf("\nLINE %d ERROR: %s\n\n", __LINE__, error_str); exit(1); } while(1) { accept_maj_stat=gss_accept_delegation(&min_stat, accept_context, GSS_C_NO_OID_SET, GSS_C_NO_BUFFER_SET, &send_tok, 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); printf("\nLINE %d ERROR: %s\n\n", __LINE__, error_str); exit(1); } 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, &oid_set, &oid_buffers, &recv_tok, 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); printf("\nLINE %d ERROR: %s\n\n", __LINE__, error_str); exit(1); } } 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_gss_assist_display_status_str(&error_str, NULL, init_maj_stat, min_stat, 0); printf("\nLINE %d ERROR: %s\n\n", __LINE__, error_str); exit(1); } 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); printf("\nLINE %d ERROR: %s\n\n", __LINE__, error_str); exit(1); } printf("%s:%d: Successfully exported/imported the delegated credential\n", __FILE__, __LINE__); free(oid_buffer.value); oid_buffer.value = (void *) &oid_set; oid_buffer.length = 1; /* Tell the GSS that we will handle restriction extensions */ /* This is a post GT 2.0 feature */ maj_stat = gss_set_sec_context_option( &min_stat, &del_init_context, (gss_OID) GSS_APPLICATION_WILL_HANDLE_EXTENSIONS, &oid_buffer); 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); exit(1); } maj_stat = gss_set_sec_context_option( &min_stat, &del_accept_context, (gss_OID) GSS_APPLICATION_WILL_HANDLE_EXTENSIONS, &oid_buffer); 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); exit(1); } /* 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); printf("\nLINE %d ERROR: %s\n\n", __LINE__, error_str); exit(1); } while(1) { 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, GSS_C_NO_CREDENTIAL); 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); printf("\nLINE %d ERROR: %s\n\n", __LINE__, error_str); exit(1); } 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); printf("\nLINE %d ERROR: %s\n\n", __LINE__, error_str); exit(1); } } /* got sec context based on delegated cred now */ printf("%s:%d: Successfully established security context with delegated credential\n", __FILE__, __LINE__); /* Extract and print the restrictions extension from the security * context. * This is a post GT 2.0 feature. */ maj_stat = gss_inquire_sec_context_by_oid(&min_stat, del_accept_context, gss_restrictions_extension, &inquire_buffers); if(maj_stat != GSS_S_COMPLETE) { globus_gss_assist_display_status_str(&error_str, NULL, init_maj_stat, min_stat, 0); printf("\nLINE %d ERROR: %s\n\n", __LINE__, error_str); exit(1); } printf("%s:%d: Security context contains restriction extension %s\n", __FILE__, __LINE__, (char *) inquire_buffers->elements[0].value); }
static int GSI_SOCKET_get_peer_cert_chain(GSI_SOCKET *self, X509 **cert, STACK_OF(X509) **cert_chain) { OM_uint32 major_status = 0; OM_uint32 minor_status = 0; gss_buffer_set_t buffer_set = NULL; int i; *cert = NULL; *cert_chain = NULL; major_status = gss_inquire_sec_context_by_oid(&minor_status, self->gss_context, gss_ext_x509_cert_chain_oid, &buffer_set); if (major_status != GSS_S_COMPLETE) { GSI_SOCKET_set_error_string(self, "gsi_inquire_sec_context_by_oid() failed in GSI_SOCKET_get_peer_cert_chain()"); return GSI_SOCKET_ERROR; } *cert_chain = sk_X509_new_null(); for (i = 0; i < buffer_set->count; i++) { const unsigned char *p; X509 *c; p = buffer_set->elements[i].value; c = d2i_X509(NULL, &p, buffer_set->elements[i].length);
static OM_uint32 gsskrb5_extract_key(OM_uint32 *minor_status, gss_ctx_id_t context_handle, const gss_OID oid, krb5_keyblock **keyblock) { krb5_error_code ret; gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; OM_uint32 major_status; krb5_context context = NULL; krb5_storage *sp = NULL; if (context_handle == GSS_C_NO_CONTEXT) { ret = EINVAL; return GSS_S_FAILURE; } ret = krb5_init_context(&context); if(ret) { *minor_status = ret; return GSS_S_FAILURE; } major_status = gss_inquire_sec_context_by_oid (minor_status, context_handle, oid, &data_set); if (major_status) return major_status; if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { gss_release_buffer_set(minor_status, &data_set); *minor_status = EINVAL; return GSS_S_FAILURE; } sp = krb5_storage_from_mem(data_set->elements[0].value, data_set->elements[0].length); if (sp == NULL) { ret = ENOMEM; goto out; } *keyblock = calloc(1, sizeof(**keyblock)); if (keyblock == NULL) { ret = ENOMEM; goto out; } ret = krb5_ret_keyblock(sp, *keyblock); out: gss_release_buffer_set(minor_status, &data_set); if (sp) krb5_storage_free(sp); if (ret && keyblock) { krb5_free_keyblock(context, *keyblock); *keyblock = NULL; } if (context) krb5_free_context(context); *minor_status = ret; if (ret) return GSS_S_FAILURE; return GSS_S_COMPLETE; }
NTSTATUS gssapi_obtain_pac_blob(TALLOC_CTX *mem_ctx, gss_ctx_id_t gssapi_context, gss_name_t gss_client_name, DATA_BLOB *pac_blob) { NTSTATUS status; OM_uint32 gss_maj, gss_min; #ifdef HAVE_GSS_GET_NAME_ATTRIBUTE /* * gss_get_name_attribute() in MIT krb5 1.10.0 can return unintialized pac_display_buffer * and later gss_release_buffer() will crash on attempting to release it. * * So always initialize the buffer descriptors. * * See following links for more details: * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=658514 * http://krbdev.mit.edu/rt/Ticket/Display.html?user=guest&pass=guest&id=7087 */ gss_buffer_desc pac_buffer = { .value = NULL, .length = 0 }; gss_buffer_desc pac_display_buffer = { .value = NULL, .length = 0 }; gss_buffer_desc pac_name = { .value = discard_const("urn:mspac:"), .length = sizeof("urn:mspac:")-1 }; int more = -1; int authenticated = false; int complete = false; gss_maj = gss_get_name_attribute( &gss_min, gss_client_name, &pac_name, &authenticated, &complete, &pac_buffer, &pac_display_buffer, &more); if (gss_maj != 0) { gss_OID oid = discard_const(gss_mech_krb5); DBG_NOTICE("obtaining PAC via GSSAPI gss_get_name_attribute " "failed: %s\n", gssapi_error_string(mem_ctx, gss_maj, gss_min, oid)); return NT_STATUS_ACCESS_DENIED; } else if (authenticated && complete) { /* The PAC blob is returned directly */ *pac_blob = data_blob_talloc(mem_ctx, pac_buffer.value, pac_buffer.length); if (!pac_blob->data) { status = NT_STATUS_NO_MEMORY; } else { status = NT_STATUS_OK; } gss_maj = gss_release_buffer(&gss_min, &pac_buffer); gss_maj = gss_release_buffer(&gss_min, &pac_display_buffer); return status; } else { DEBUG(0, ("obtaining PAC via GSSAPI failed: authenticated: %s, complete: %s, more: %s\n", authenticated ? "true" : "false", complete ? "true" : "false", more ? "true" : "false")); return NT_STATUS_ACCESS_DENIED; } #elif defined(HAVE_GSS_INQUIRE_SEC_CONTEXT_BY_OID) gss_OID_desc pac_data_oid = { .elements = discard_const(EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID), .length = EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH }; gss_buffer_set_t set = GSS_C_NO_BUFFER_SET; /* If we didn't have the routine to get a verified, validated * PAC (supplied only by MIT at the time of writing), then try * with the Heimdal OID (fetches the PAC directly and always * validates) */ gss_maj = gss_inquire_sec_context_by_oid( &gss_min, gssapi_context, &pac_data_oid, &set); /* First check for the error MIT gives for an unknown OID */ if (gss_maj == GSS_S_UNAVAILABLE) { DEBUG(1, ("unable to obtain a PAC against this GSSAPI library. " "GSSAPI secured connections are available only with Heimdal or MIT Kerberos >= 1.8\n")); } else if (gss_maj != 0) { DEBUG(2, ("obtaining PAC via GSSAPI gss_inqiure_sec_context_by_oid (Heimdal OID) failed: %s\n", gssapi_error_string(mem_ctx, gss_maj, gss_min, gss_mech_krb5))); } else { if (set == GSS_C_NO_BUFFER_SET) { DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown " "data in results.\n")); return NT_STATUS_INTERNAL_ERROR; } /* The PAC blob is returned directly */ *pac_blob = data_blob_talloc(mem_ctx, set->elements[0].value, set->elements[0].length); if (!pac_blob->data) { status = NT_STATUS_NO_MEMORY; } else { status = NT_STATUS_OK; } gss_maj = gss_release_buffer_set(&gss_min, &set); return status; } #else DEBUG(1, ("unable to obtain a PAC against this GSSAPI library. " "GSSAPI secured connections are available only with Heimdal or MIT Kerberos >= 1.8\n")); #endif return NT_STATUS_ACCESS_DENIED; } NTSTATUS gssapi_get_session_key(TALLOC_CTX *mem_ctx, gss_ctx_id_t gssapi_context, DATA_BLOB *session_key, uint32_t *keytype) { OM_uint32 gss_min, gss_maj; gss_buffer_set_t set = GSS_C_NO_BUFFER_SET; gss_maj = gss_inquire_sec_context_by_oid( &gss_min, gssapi_context, &gse_sesskey_inq_oid, &set); if (gss_maj) { DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n", gssapi_error_string(mem_ctx, gss_maj, gss_min, discard_const_p(struct gss_OID_desc_struct, gss_mech_krb5)))); return NT_STATUS_NO_USER_SESSION_KEY; } if ((set == GSS_C_NO_BUFFER_SET) || (set->count == 0)) { #ifdef HAVE_GSSKRB5_GET_SUBKEY krb5_keyblock *subkey; gss_maj = gsskrb5_get_subkey(&gss_min, gssapi_context, &subkey); if (gss_maj != 0) { DEBUG(1, ("NO session key for this mech\n")); return NT_STATUS_NO_USER_SESSION_KEY; } if (session_key) { *session_key = data_blob_talloc(mem_ctx, KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey)); } if (keytype) { *keytype = KRB5_KEY_TYPE(subkey); } krb5_free_keyblock(NULL /* should be krb5_context */, subkey); return NT_STATUS_OK; #else DEBUG(0, ("gss_inquire_sec_context_by_oid didn't return any session key (and no alternative method available)\n")); return NT_STATUS_NO_USER_SESSION_KEY; #endif } if (session_key) { *session_key = data_blob_talloc(mem_ctx, set->elements[0].value, set->elements[0].length); } if (keytype) { int diflen, i; const uint8_t *p; *keytype = 0; if (set->count < 2) { #ifdef HAVE_GSSKRB5_GET_SUBKEY krb5_keyblock *subkey; gss_maj = gsskrb5_get_subkey(&gss_min, gssapi_context, &subkey); if (gss_maj == 0) { *keytype = KRB5_KEY_TYPE(subkey); krb5_free_keyblock(NULL /* should be krb5_context */, subkey); } #endif gss_maj = gss_release_buffer_set(&gss_min, &set); return NT_STATUS_OK; } else if (memcmp(set->elements[1].value, gse_sesskeytype_oid.elements, gse_sesskeytype_oid.length) != 0) { /* Perhaps a non-krb5 session key */ gss_maj = gss_release_buffer_set(&gss_min, &set); return NT_STATUS_OK; } p = (const uint8_t *)set->elements[1].value + gse_sesskeytype_oid.length; diflen = set->elements[1].length - gse_sesskeytype_oid.length; if (diflen <= 0) { gss_maj = gss_release_buffer_set(&gss_min, &set); return NT_STATUS_INVALID_PARAMETER; } for (i = 0; i < diflen; i++) { *keytype = (*keytype << 7) | (p[i] & 0x7f); if (i + 1 != diflen && (p[i] & 0x80) == 0) { gss_maj = gss_release_buffer_set(&gss_min, &set); return NT_STATUS_INVALID_PARAMETER; } } } gss_maj = gss_release_buffer_set(&gss_min, &set); return NT_STATUS_OK; } char *gssapi_error_string(TALLOC_CTX *mem_ctx, OM_uint32 maj_stat, OM_uint32 min_stat, const gss_OID mech) { OM_uint32 disp_min_stat, disp_maj_stat; gss_buffer_desc maj_error_message; gss_buffer_desc min_error_message; char *maj_error_string, *min_error_string; OM_uint32 msg_ctx = 0; char *ret; maj_error_message.value = NULL; min_error_message.value = NULL; maj_error_message.length = 0; min_error_message.length = 0; disp_maj_stat = gss_display_status(&disp_min_stat, maj_stat, GSS_C_GSS_CODE, mech, &msg_ctx, &maj_error_message); if (disp_maj_stat != 0) { maj_error_message.value = NULL; maj_error_message.length = 0; } disp_maj_stat = gss_display_status(&disp_min_stat, min_stat, GSS_C_MECH_CODE, mech, &msg_ctx, &min_error_message); if (disp_maj_stat != 0) { min_error_message.value = NULL; min_error_message.length = 0; } maj_error_string = talloc_strndup(mem_ctx, (char *)maj_error_message.value, maj_error_message.length); min_error_string = talloc_strndup(mem_ctx, (char *)min_error_message.value, min_error_message.length); ret = talloc_asprintf(mem_ctx, "%s: %s", maj_error_string, min_error_string); talloc_free(maj_error_string); talloc_free(min_error_string); gss_release_buffer(&disp_min_stat, &maj_error_message); gss_release_buffer(&disp_min_stat, &min_error_message); return ret; }
OM_uint32 gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle, OM_uint32 version, void **rctx) { krb5_context context = NULL; krb5_error_code ret; gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; OM_uint32 major_status; gss_krb5_lucid_context_v1_t *ctx = NULL; krb5_storage *sp = NULL; uint32_t num; if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT || version != 1) { ret = EINVAL; return GSS_S_FAILURE; } major_status = gss_inquire_sec_context_by_oid (minor_status, *context_handle, GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X, &data_set); if (major_status) return major_status; if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { gss_release_buffer_set(minor_status, &data_set); *minor_status = EINVAL; return GSS_S_FAILURE; } ret = krb5_init_context(&context); if (ret) goto out; ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) { ret = ENOMEM; goto out; } sp = krb5_storage_from_mem(data_set->elements[0].value, data_set->elements[0].length); if (sp == NULL) { ret = ENOMEM; goto out; } ret = krb5_ret_uint32(sp, &num); if (ret) goto out; if (num != 1) { ret = EINVAL; goto out; } ctx->version = 1; /* initiator */ ret = krb5_ret_uint32(sp, &ctx->initiate); if (ret) goto out; /* endtime */ ret = krb5_ret_uint32(sp, &ctx->endtime); if (ret) goto out; /* send_seq */ ret = krb5_ret_uint32(sp, &num); if (ret) goto out; ctx->send_seq = ((uint64_t)num) << 32; ret = krb5_ret_uint32(sp, &num); if (ret) goto out; ctx->send_seq |= num; /* recv_seq */ ret = krb5_ret_uint32(sp, &num); if (ret) goto out; ctx->recv_seq = ((uint64_t)num) << 32; ret = krb5_ret_uint32(sp, &num); if (ret) goto out; ctx->recv_seq |= num; /* protocol */ ret = krb5_ret_uint32(sp, &ctx->protocol); if (ret) goto out; if (ctx->protocol == 0) { krb5_keyblock key; /* sign_alg */ ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg); if (ret) goto out; /* seal_alg */ ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg); if (ret) goto out; /* ctx_key */ ret = krb5_ret_keyblock(sp, &key); if (ret) goto out; ret = set_key(&key, &ctx->rfc1964_kd.ctx_key); krb5_free_keyblock_contents(context, &key); if (ret) goto out; } else if (ctx->protocol == 1) { krb5_keyblock key; /* acceptor_subkey */ ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey); if (ret) goto out; /* ctx_key */ ret = krb5_ret_keyblock(sp, &key); if (ret) goto out; ret = set_key(&key, &ctx->cfx_kd.ctx_key); krb5_free_keyblock_contents(context, &key); if (ret) goto out; /* acceptor_subkey */ if (ctx->cfx_kd.have_acceptor_subkey) { ret = krb5_ret_keyblock(sp, &key); if (ret) goto out; ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey); krb5_free_keyblock_contents(context, &key); if (ret) goto out; } } else { ret = EINVAL; goto out; } *rctx = ctx; out: gss_release_buffer_set(minor_status, &data_set); if (sp) krb5_storage_free(sp); if (context) krb5_free_context(context); if (ret) { if (ctx) gss_krb5_free_lucid_sec_context(NULL, ctx); *minor_status = ret; return GSS_S_FAILURE; } *minor_status = 0; return GSS_S_COMPLETE; }
OM_uint32 gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status, gss_ctx_id_t context_handle, int ad_type, gss_buffer_t ad_data) { gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET; OM_uint32 maj_stat; gss_OID_desc oid_flat; heim_oid baseoid, oid; size_t size; if (context_handle == GSS_C_NO_CONTEXT) { *minor_status = EINVAL; return GSS_S_FAILURE; } /* All this to append an integer to an oid... */ if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements, GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length, &baseoid, NULL) != 0) { *minor_status = EINVAL; return GSS_S_FAILURE; } oid.length = baseoid.length + 1; oid.components = calloc(oid.length, sizeof(*oid.components)); if (oid.components == NULL) { der_free_oid(&baseoid); *minor_status = ENOMEM; return GSS_S_FAILURE; } memcpy(oid.components, baseoid.components, baseoid.length * sizeof(*baseoid.components)); der_free_oid(&baseoid); oid.components[oid.length - 1] = ad_type; oid_flat.length = der_length_oid(&oid); oid_flat.elements = malloc(oid_flat.length); if (oid_flat.elements == NULL) { free(oid.components); *minor_status = ENOMEM; return GSS_S_FAILURE; } if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1, oid_flat.length, &oid, &size) != 0) { free(oid.components); free(oid_flat.elements); *minor_status = EINVAL; return GSS_S_FAILURE; } if (oid_flat.length != size) abort(); free(oid.components); /* FINALLY, we have the OID */ maj_stat = gss_inquire_sec_context_by_oid (minor_status, context_handle, &oid_flat, &data_set); free(oid_flat.elements); if (maj_stat) return maj_stat; if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) { gss_release_buffer_set(minor_status, &data_set); *minor_status = EINVAL; return GSS_S_FAILURE; } ad_data->value = malloc(data_set->elements[0].length); if (ad_data->value == NULL) { gss_release_buffer_set(minor_status, &data_set); *minor_status = ENOMEM; return GSS_S_FAILURE; } ad_data->length = data_set->elements[0].length; memcpy(ad_data->value, data_set->elements[0].value, ad_data->length); gss_release_buffer_set(minor_status, &data_set); *minor_status = 0; return GSS_S_COMPLETE; }
int globus_i_gram_get_tg_gateway_user( gss_ctx_id_t context, globus_gsi_cred_handle_t peer_cred, char ** gateway_user) { #if HAVE_LIBXML2 OM_uint32 maj_stat, min_stat; gss_buffer_set_t data_set; ASN1_UTF8STRING * asn1_str; char * assertion_string; unsigned char * p; long pl; xmlDocPtr doc; xmlXPathContextPtr xpath_ctx; xmlXPathObjectPtr xresult; int rc; ASN1_OBJECT * asn1_desired_object = NULL; int cert_count; int found_index; int chain_index; X509 *cert; X509_EXTENSION * extension; ASN1_OCTET_STRING *asn1_oct_string; STACK_OF(X509) *chain = NULL; *gateway_user = NULL; if (context == GSS_C_NO_CONTEXT && peer_cred != NULL) { globus_result_t result; /* This basically duplicates the gss_inquire_sec_context_by_oid(), but * instead uses a gsi credential object */ rc = GLOBUS_SUCCESS; asn1_desired_object = ASN1_OBJECT_new(); if (asn1_desired_object == NULL) { rc = GLOBUS_GRAM_PROTOCOL_ERROR_MALLOC_FAILED; goto no_extension_in_cred_chain; } asn1_desired_object->length = globus_l_saml_oid_desc.length; asn1_desired_object->data = globus_l_saml_oid_desc.elements; result = globus_gsi_cred_get_cert_chain(peer_cred, &chain); if (result != GLOBUS_SUCCESS) { char * msg; msg = globus_error_print_friendly( globus_error_peek(result)); globus_gram_protocol_error_7_hack_replace_message( msg); free(msg); rc = GLOBUS_GRAM_PROTOCOL_ERROR_AUTHORIZATION; goto no_extension_in_cred_chain; } cert_count = sk_X509_num(chain); found_index = -1; for (chain_index = 0; chain_index < cert_count; chain_index++) { cert = sk_X509_value(chain, chain_index); found_index = X509_get_ext_by_OBJ(cert, asn1_desired_object, found_index); if (found_index >= 0) { extension = X509_get_ext(cert, found_index); if (extension == NULL) { rc = GLOBUS_GRAM_PROTOCOL_ERROR_AUTHORIZATION; globus_gram_protocol_error_7_hack_replace_message( "Unable to extract SAML assertion extension from certificate chain"); goto no_extension_in_cred_chain; } asn1_oct_string = X509_EXTENSION_get_data(extension); if (asn1_oct_string == NULL) { rc = GLOBUS_GRAM_PROTOCOL_ERROR_AUTHORIZATION; globus_gram_protocol_error_7_hack_replace_message( "Unable to extract SAML assertion extension from certificate chain"); goto no_extension_in_cred_chain; } p = asn1_oct_string->data; asn1_str = d2i_ASN1_UTF8STRING(NULL, (void *)&p, asn1_oct_string->length); if (asn1_str == NULL) { rc = GLOBUS_GRAM_PROTOCOL_ERROR_AUTHORIZATION; globus_gram_protocol_error_7_hack_replace_message( "Unable to convert SAML assertion text from DER to UTF8"); goto no_extension_in_cred_chain; } assertion_string = malloc(asn1_str->length + 1); if (assertion_string == NULL) { rc = GLOBUS_GRAM_PROTOCOL_ERROR_MALLOC_FAILED; goto no_extension_in_cred_chain; } memcpy(assertion_string, asn1_str->data, asn1_str->length); assertion_string[asn1_str->length] = 0; break; } } if (chain_index == cert_count) { goto no_extension_in_cred_chain; } } else if (context == GSS_C_NO_CONTEXT) { rc = GLOBUS_SUCCESS; goto no_context; } else { maj_stat = gss_inquire_sec_context_by_oid( &min_stat, context, globus_saml_oid, &data_set); if (GSS_ERROR(maj_stat)) { globus_gram_protocol_error_7_hack_replace_message( "Error extracting SAML assertion"); rc = GLOBUS_GRAM_PROTOCOL_ERROR_AUTHORIZATION; goto inquire_failed; } /* We'll process only the first SAML assertion bound in the X.509 chain */ if (data_set->count < 1) { rc = GLOBUS_SUCCESS; goto empty_data_set; } p = data_set->elements[0].value; pl = data_set->elements[0].length; /* Convert DER-Encoded string to UTF8 */ asn1_str = d2i_ASN1_UTF8STRING(NULL, (void *) &p, pl); if (!asn1_str) { globus_gram_protocol_error_7_hack_replace_message( "Error decoding SAML assertion"); rc = GLOBUS_GRAM_PROTOCOL_ERROR_AUTHORIZATION; goto utfstring_failed; } assertion_string = malloc(asn1_str->length + 1); if (assertion_string == NULL) { rc = GLOBUS_GRAM_PROTOCOL_ERROR_MALLOC_FAILED; goto assertion_string_malloc_failed; } memcpy(assertion_string, asn1_str->data, asn1_str->length); assertion_string[asn1_str->length] = 0; } /* Parse SAML assertion */ doc = xmlParseDoc(BAD_CAST assertion_string); if (doc == NULL) { globus_gram_protocol_error_7_hack_replace_message( "Error parsing SAML assertion"); rc = GLOBUS_GRAM_PROTOCOL_ERROR_AUTHORIZATION; goto parse_assertion_failed; } xmlXPathInit(); /* Use XPATH to extract Issuer */ xpath_ctx = xmlXPathNewContext(doc); if (xpath_ctx == NULL) { rc = GLOBUS_GRAM_PROTOCOL_ERROR_MALLOC_FAILED; goto xpath_ctx_init_failed; } rc = xmlXPathRegisterNs( xpath_ctx, (xmlChar *) "s", (xmlChar *) "urn:oasis:names:tc:SAML:1.0:assertion"); if (rc != 0) { rc = GLOBUS_GRAM_PROTOCOL_ERROR_MALLOC_FAILED; goto xpath_register_ns_failed; } xresult = xmlXPathEvalExpression( (const xmlChar *) "string(/s:Assertion/@Issuer)", xpath_ctx); if (xresult == NULL) { globus_gram_protocol_error_7_hack_replace_message( "Error processing SAML assertion: no \"Issuer\" attribute"); rc = GLOBUS_GRAM_PROTOCOL_ERROR_AUTHORIZATION; goto xpath_eval_issuer_failed; } if (! globus_l_tg_saml_assertion_is_self_issued( context, (const char *) xresult->stringval)) { /* Ignore non-self issued assertions */ rc = GLOBUS_SUCCESS; goto non_self_issued; } xmlXPathFreeObject(xresult); /* Use XPATH to extract the sender-vouches, self-issued, TG principal name * Subject attribute from the Assertion's AuthenticationStatement */ xresult = xmlXPathEvalExpression( (const xmlChar *) "string(/s:Assertion/s:AuthenticationStatement/s:Subject[string(s:SubjectConfirmation/s:ConfirmationMethod) = 'urn:oasis:names:tc:SAML:1.0:cm:sender-vouches' and s:NameIdentifier/@Format = 'http://teragrid.org/names/nameid-format/principalname']/s:NameIdentifier[1])", xpath_ctx); if (xresult == NULL) { globus_gram_protocol_error_7_hack_replace_message( "Error processing SAML assertion: no teragrid principal"); rc = GLOBUS_GRAM_PROTOCOL_ERROR_AUTHORIZATION; goto get_gateway_name_failed; } if (xresult != NULL && xresult->stringval != NULL && *(xresult->stringval) != 0) { *gateway_user = strdup((char *) xresult->stringval); } get_gateway_name_failed: non_self_issued: if (xresult != NULL) { xmlXPathFreeObject(xresult); } xpath_eval_issuer_failed: xpath_register_ns_failed: xmlXPathFreeContext(xpath_ctx); xpath_ctx_init_failed: xmlFreeDoc(doc); parse_assertion_failed: free(assertion_string); assertion_string_malloc_failed: ASN1_UTF8STRING_free(asn1_str); utfstring_failed: empty_data_set: gss_release_buffer_set(&min_stat, &data_set); inquire_failed: no_extension_in_cred_chain: no_context: if (asn1_desired_object != NULL) { ASN1_OBJECT_free(asn1_desired_object); } if (chain != NULL) { sk_X509_free(chain); } return rc; #else *gateway_user = NULL; return GLOBUS_SUCCESS; #endif /* HAVE_LIBXML2 */ }