Exemple #1
0
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);
}
Exemple #3
0
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);
    }
}
Exemple #6
0
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;
}
Exemple #8
0
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;
}
Exemple #10
0
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;
}
Exemple #11
0
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);
Exemple #16
0
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;
}
Exemple #17
0
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;
}
Exemple #18
0
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;
}
Exemple #19
0
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;
}
Exemple #20
0
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 */
}