diff options
Diffstat (limited to 'src/lib/gssapi/spnego/spnego_mech.c')
-rw-r--r-- | src/lib/gssapi/spnego/spnego_mech.c | 714 |
1 files changed, 633 insertions, 81 deletions
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c index f3cb5919b4..44aea26436 100644 --- a/src/lib/gssapi/spnego/spnego_mech.c +++ b/src/lib/gssapi/spnego/spnego_mech.c @@ -32,9 +32,37 @@ * peers using the GSS-API. * */ - +/* + * Copyright (c) 2006-2008, Novell, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * The copyright holder's name is not used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ /* #pragma ident "@(#)spnego_mech.c 1.7 04/09/28 SMI" */ +#include <sys/param.h> +#include <unistd.h> #include <assert.h> #include <stdio.h> #include <stdlib.h> @@ -135,7 +163,9 @@ static int g_get_tag_and_length(unsigned char **, int, unsigned int, unsigned int *); static int -make_spnego_tokenInit_msg(spnego_gss_ctx_id_t, gss_buffer_t, +make_spnego_tokenInit_msg(spnego_gss_ctx_id_t, + int, + gss_buffer_t, OM_uint32, gss_buffer_t, send_token_flag, gss_buffer_t); static int @@ -165,6 +195,12 @@ static const gss_OID_set_desc spnego_oidsets[] = { }; const gss_OID_set_desc * const gss_mech_set_spnego = spnego_oidsets+0; +static int make_NegHints(OM_uint32 *, gss_cred_id_t, gss_buffer_t *); +static int put_neg_hints(unsigned char **, gss_buffer_t, unsigned int); +static OM_uint32 +acc_ctx_hints(OM_uint32 *, gss_ctx_id_t *, gss_cred_id_t, + gss_buffer_t *, OM_uint32 *, send_token_flag *); + /* * The Mech OID for SPNEGO: * { iso(1) org(3) dod(6) internet(1) security(5) @@ -172,7 +208,6 @@ const gss_OID_set_desc * const gss_mech_set_spnego = spnego_oidsets+0; */ static struct gss_config spnego_mechanism = { - 400, "spnego", {SPNEGO_OID_LENGTH, SPNEGO_OID}, NULL, spnego_gss_acquire_cred, @@ -186,13 +221,13 @@ static struct gss_config spnego_mechanism = NULL, /* gss_process_context_token */ spnego_gss_delete_sec_context, /* gss_delete_sec_context */ spnego_gss_context_time, /* gss_context_time */ - spnego_gss_sign, /* gss_sign */ - spnego_gss_verify, /* gss_verify */ - spnego_gss_seal, /* gss_seal */ - spnego_gss_unseal, /* gss_unseal */ + spnego_gss_get_mic, /* gss_get_mic */ + spnego_gss_verify_mic, /* gss_verify_mic */ + spnego_gss_wrap, /* gss_wrap */ + spnego_gss_unwrap, /* gss_unwrap */ spnego_gss_display_status, NULL, /* gss_indicate_mechs */ - NULL, /* gss_compare_name */ + spnego_gss_compare_name, spnego_gss_display_name, spnego_gss_import_name, spnego_gss_release_name, @@ -212,24 +247,63 @@ static struct gss_config spnego_mechanism = spnego_gss_wrap_size_limit, /* gss_wrap_size_limit */ NULL, /* gss_export_name */ NULL, /* gss_store_cred */ + NULL, /* gss_import_name_object */ + NULL, /* gss_export_name_object */ + spnego_gss_inquire_sec_context_by_oid, /* gss_inquire_sec_context_by_oid */ + NULL, /* gss_inquire_cred_by_oid */ + spnego_gss_set_sec_context_option, /* gss_set_sec_context_option */ + NULL, /* gssspi_set_cred_option */ + NULL, /* gssspi_mech_invoke */ + spnego_gss_wrap_aead, + spnego_gss_unwrap_aead, + spnego_gss_wrap_iov, + spnego_gss_unwrap_iov, + spnego_gss_wrap_iov_length, + spnego_gss_complete_auth_token }; -static gss_mechanism spnego_mech_configs[] = { - &spnego_mechanism, NULL -}; +#ifdef _GSS_STATIC_LINK +#include "mglueP.h" + +static int gss_spnegomechglue_init(void) +{ + struct gss_mech_config mech_spnego; -#define gssint_get_mech_configs spnego_gss_get_mech_configs + memset(&mech_spnego, 0, sizeof(mech_spnego)); + mech_spnego.mech = &spnego_mechanism; + mech_spnego.mechNameStr = "spnego"; + mech_spnego.mech_type = GSS_C_NO_OID; -gss_mechanism * -gssint_get_mech_configs(void) + return gssint_register_mechinfo(&mech_spnego); +} +#else +gss_mechanism KRB5_CALLCONV +gss_mech_initialize(void) +{ + return (&spnego_mechanism); +} + +MAKE_INIT_FUNCTION(gss_krb5int_lib_init); +MAKE_FINI_FUNCTION(gss_krb5int_lib_fini); +int gss_krb5int_lib_init(void) +#endif /* _GSS_STATIC_LINK */ + +int gss_spnegoint_lib_init(void) +{ +#ifdef _GSS_STATIC_LINK + return gss_spnegomechglue_init(); +#else + return 0; +#endif +} + +void gss_spnegoint_lib_fini(void) { - return spnego_mech_configs; } /*ARGSUSED*/ OM_uint32 -spnego_gss_acquire_cred(void *ctx, - OM_uint32 *minor_status, +spnego_gss_acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name, OM_uint32 time_req, gss_OID_set desired_mechs, @@ -282,8 +356,7 @@ spnego_gss_acquire_cred(void *ctx, /*ARGSUSED*/ OM_uint32 -spnego_gss_release_cred(void *ctx, - OM_uint32 *minor_status, +spnego_gss_release_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle) { OM_uint32 status; @@ -570,10 +643,15 @@ init_ctx_cont(OM_uint32 *minor_status, gss_ctx_id_t *ctx, gss_buffer_t buf, * mech not finished and mech token missing */ ret = GSS_S_DEFECTIVE_TOKEN; - } else { + } else if (sc->mic_reqd && + (sc->ctx_flags & GSS_C_INTEG_FLAG)) { *negState = ACCEPT_INCOMPLETE; *tokflag = CONT_TOKEN_SEND; ret = GSS_S_CONTINUE_NEEDED; + } else { + *negState = ACCEPT_COMPLETE; + *tokflag = NO_TOKEN_SEND; + ret = GSS_S_COMPLETE; } cleanup: if (supportedMech != GSS_C_NO_OID) @@ -745,6 +823,7 @@ init_ctx_call_init(OM_uint32 *minor_status, * generated/handled. */ if (*send_token == CONT_TOKEN_SEND && + mechtok_out->length == 0 && (!sc->mic_reqd || !(sc->ctx_flags & GSS_C_INTEG_FLAG))) { @@ -771,7 +850,7 @@ init_ctx_call_init(OM_uint32 *minor_status, /*ARGSUSED*/ OM_uint32 -spnego_gss_init_sec_context(void *ct, +spnego_gss_init_sec_context( OM_uint32 *minor_status, gss_cred_id_t claimant_cred_handle, gss_ctx_id_t *context_handle, @@ -858,11 +937,11 @@ spnego_gss_init_sec_context(void *ct, cleanup: if (send_token == INIT_TOKEN_SEND) { if (make_spnego_tokenInit_msg(spnego_ctx, + 0, mechListMIC_out, req_flags, &mechtok_out, send_token, output_token) < 0) { - ret = GSS_S_FAILURE; } } else if (send_token != NO_TOKEN_SEND) { @@ -882,6 +961,8 @@ cleanup: *context_handle = (gss_ctx_id_t)spnego_ctx->ctx_handle; if (actual_mech != NULL) *actual_mech = spnego_ctx->actual_mech; + if (ret_flags != NULL) + *ret_flags = spnego_ctx->ctx_flags; release_spnego_ctx(&spnego_ctx); } else if (ret != GSS_S_CONTINUE_NEEDED) { if (spnego_ctx != NULL) { @@ -910,6 +991,265 @@ cleanup: return ret; } /* init_sec_context */ +/* We don't want to import KRB5 headers here */ +static const gss_OID_desc gss_mech_krb5_oid = + { 9, "\052\206\110\206\367\022\001\002\002" }; +static const gss_OID_desc gss_mech_krb5_wrong_oid = + { 9, "\052\206\110\202\367\022\001\002\002" }; + +/* + * verify that the input token length is not 0. If it is, just return. + * If the token length is greater than 0, der encode as a sequence + * and place in buf_out, advancing buf_out. + */ + +static int +put_neg_hints(unsigned char **buf_out, gss_buffer_t input_token, + unsigned int buflen) +{ + int ret; + + /* if token length is 0, we do not want to send */ + if (input_token->length == 0) + return (0); + + if (input_token->length > buflen) + return (-1); + + *(*buf_out)++ = SEQUENCE; + if ((ret = gssint_put_der_length(input_token->length, buf_out, + input_token->length))) + return (ret); + TWRITE_STR(*buf_out, input_token->value, input_token->length); + return (0); +} + +/* + * NegHints ::= SEQUENCE { + * hintName [0] GeneralString OPTIONAL, + * hintAddress [1] OCTET STRING OPTIONAL + * } + */ + +#define HOST_PREFIX "host@" +#define HOST_PREFIX_LEN (sizeof(HOST_PREFIX) - 1) + +static int +make_NegHints(OM_uint32 *minor_status, + gss_cred_id_t cred, gss_buffer_t *outbuf) +{ + gss_buffer_desc hintNameBuf; + gss_name_t hintName = GSS_C_NO_NAME; + gss_name_t hintKerberosName; + gss_OID hintNameType; + OM_uint32 major_status; + OM_uint32 minor; + unsigned int tlen = 0; + unsigned int hintNameSize = 0; + unsigned int negHintsSize = 0; + unsigned char *ptr; + unsigned char *t; + + *outbuf = GSS_C_NO_BUFFER; + + if (cred != GSS_C_NO_CREDENTIAL) { + major_status = gss_inquire_cred(minor_status, + cred, + &hintName, + NULL, + NULL, + NULL); + if (major_status != GSS_S_COMPLETE) + return (major_status); + } + + if (hintName == GSS_C_NO_NAME) { + krb5_error_code code; + krb5int_access kaccess; + char hostname[HOST_PREFIX_LEN + MAXHOSTNAMELEN + 1] = HOST_PREFIX; + + code = krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION); + if (code != 0) { + *minor_status = code; + return (GSS_S_FAILURE); + } + + /* this breaks mutual authentication but Samba relies on it */ + code = (*kaccess.clean_hostname)(NULL, NULL, + &hostname[HOST_PREFIX_LEN], + MAXHOSTNAMELEN); + if (code != 0) { + *minor_status = code; + return (GSS_S_FAILURE); + } + + hintNameBuf.value = hostname; + hintNameBuf.length = strlen(hostname); + + major_status = gss_import_name(minor_status, + &hintNameBuf, + GSS_C_NT_HOSTBASED_SERVICE, + &hintName); + if (major_status != GSS_S_COMPLETE) { + return (major_status); + } + } + + hintNameBuf.value = NULL; + hintNameBuf.length = 0; + + major_status = gss_canonicalize_name(minor_status, + hintName, + (gss_OID)&gss_mech_krb5_oid, + &hintKerberosName); + if (major_status != GSS_S_COMPLETE) { + gss_release_name(&minor, &hintName); + return (major_status); + } + gss_release_name(&minor, &hintName); + + major_status = gss_display_name(minor_status, + hintKerberosName, + &hintNameBuf, + &hintNameType); + if (major_status != GSS_S_COMPLETE) { + gss_release_name(&minor, &hintName); + return (major_status); + } + gss_release_name(&minor, &hintKerberosName); + + /* + * Now encode the name hint into a NegHints ASN.1 type + */ + major_status = GSS_S_FAILURE; + + /* Length of DER encoded GeneralString */ + tlen = 1 + gssint_der_length_size(hintNameBuf.length) + + hintNameBuf.length; + hintNameSize = tlen; + + /* Length of DER encoded hintName */ + tlen += 1 + gssint_der_length_size(hintNameSize); + negHintsSize = tlen; + + t = (unsigned char *)malloc(tlen); + if (t == NULL) { + *minor_status = ENOMEM; + goto errout; + } + + ptr = t; + + *ptr++ = CONTEXT | 0x00; /* hintName identifier */ + if (gssint_put_der_length(hintNameSize, + &ptr, tlen - (int)(ptr-t))) + goto errout; + + *ptr++ = GENERAL_STRING; + if (gssint_put_der_length(hintNameBuf.length, + &ptr, tlen - (int)(ptr-t))) + goto errout; + + memcpy(ptr, hintNameBuf.value, hintNameBuf.length); + ptr += hintNameBuf.length; + + *outbuf = (gss_buffer_t)malloc(sizeof(gss_buffer_desc)); + if (*outbuf == NULL) { + *minor_status = ENOMEM; + goto errout; + } + (*outbuf)->value = (void *)t; + (*outbuf)->length = ptr - t; + + t = NULL; /* don't free */ + + *minor_status = 0; + major_status = GSS_S_COMPLETE; + +errout: + if (t != NULL) { + free(t); + } + + gss_release_buffer(&minor, &hintNameBuf); + + return (major_status); +} + +static OM_uint32 +acc_ctx_hints(OM_uint32 *minor_status, + gss_ctx_id_t *ctx, + gss_cred_id_t cred, + gss_buffer_t *mechListMIC, + OM_uint32 *negState, + send_token_flag *return_token) +{ + OM_uint32 tmpmin, ret; + gss_OID_set supported_mechSet; + spnego_gss_ctx_id_t sc = NULL; + + *mechListMIC = GSS_C_NO_BUFFER; + supported_mechSet = GSS_C_NO_OID_SET; + *return_token = ERROR_TOKEN_SEND; + *negState = REJECT; + *minor_status = 0; + + *ctx = GSS_C_NO_CONTEXT; + ret = GSS_S_DEFECTIVE_TOKEN; + + if (cred != GSS_C_NO_CREDENTIAL) { + ret = gss_inquire_cred(minor_status, cred, NULL, NULL, + NULL, &supported_mechSet); + if (ret != GSS_S_COMPLETE) { + *return_token = NO_TOKEN_SEND; + goto cleanup; + } + } else { + ret = get_available_mechs(minor_status, GSS_C_NO_NAME, + GSS_C_ACCEPT, NULL, + &supported_mechSet); + if (ret != GSS_S_COMPLETE) { + *return_token = NO_TOKEN_SEND; + goto cleanup; + } + } + + ret = make_NegHints(minor_status, cred, mechListMIC); + if (ret != GSS_S_COMPLETE) { + *return_token = NO_TOKEN_SEND; + goto cleanup; + } + + /* + * Select the best match between the list of mechs + * that the initiator requested and the list that + * the acceptor will support. + */ + sc = create_spnego_ctx(); + if (sc == NULL) { + ret = GSS_S_FAILURE; + *return_token = NO_TOKEN_SEND; + goto cleanup; + } + if (put_mech_set(supported_mechSet, &sc->DER_mechTypes) < 0) { + ret = GSS_S_FAILURE; + *return_token = NO_TOKEN_SEND; + goto cleanup; + } + sc->internal_mech = GSS_C_NO_OID; + + *negState = ACCEPT_INCOMPLETE; + *return_token = INIT_TOKEN_SEND; + sc->firstpass = 1; + *ctx = (gss_ctx_id_t)sc; + ret = GSS_S_COMPLETE; + +cleanup: + gss_release_oid_set(&tmpmin, &supported_mechSet); + + return ret; +} + /* * Set negState to REJECT if the token is defective, else * ACCEPT_INCOMPLETE or REQUEST_MIC, depending on whether initiator's @@ -932,6 +1272,7 @@ acc_ctx_new(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc = NULL; *ctx = GSS_C_NO_CONTEXT; + ret = GSS_S_DEFECTIVE_TOKEN; der_mechTypes.length = 0; der_mechTypes.value = NULL; @@ -976,7 +1317,12 @@ acc_ctx_new(OM_uint32 *minor_status, ret = GSS_S_BAD_MECH; goto cleanup; } - sc = create_spnego_ctx(); + sc = (spnego_gss_ctx_id_t)*ctx; + if (sc != NULL) { + gss_release_buffer(&tmpmin, &sc->DER_mechTypes); + assert(mech_wanted != GSS_C_NO_OID); + } else + sc = create_spnego_ctx(); if (sc == NULL) { ret = GSS_S_FAILURE; *return_token = NO_TOKEN_SEND; @@ -1101,7 +1447,7 @@ acc_ctx_vfy_oid(OM_uint32 *minor_status, *tokflag = ERROR_TOKEN_SEND; return GSS_S_BAD_MECH; } - ret = mech->gss_indicate_mechs(NULL, minor_status, &mech_set); + ret = mech->gss_indicate_mechs(minor_status, &mech_set); if (ret != GSS_S_COMPLETE) { *tokflag = NO_TOKEN_SEND; map_error(minor_status, mech); @@ -1138,18 +1484,20 @@ acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc, OM_uint32 ret; gss_OID_desc mechoid; - /* - * mechoid is an alias; don't free it. - */ - ret = gssint_get_mech_type(&mechoid, mechtok_in); - if (ret != GSS_S_COMPLETE) { - *tokflag = NO_TOKEN_SEND; - return ret; + if (sc->ctx_handle == GSS_C_NO_CONTEXT) { + /* + * mechoid is an alias; don't free it. + */ + ret = gssint_get_mech_type(&mechoid, mechtok_in); + if (ret != GSS_S_COMPLETE) { + *tokflag = NO_TOKEN_SEND; + return ret; + } + ret = acc_ctx_vfy_oid(minor_status, sc, &mechoid, + negState, tokflag); + if (ret != GSS_S_COMPLETE) + return ret; } - ret = acc_ctx_vfy_oid(minor_status, sc, &mechoid, - negState, tokflag); - if (ret != GSS_S_COMPLETE) - return ret; ret = gss_accept_sec_context(minor_status, &sc->ctx_handle, @@ -1196,7 +1544,7 @@ acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc, /*ARGSUSED*/ OM_uint32 -spnego_gss_accept_sec_context(void *ct, +spnego_gss_accept_sec_context( OM_uint32 *minor_status, gss_ctx_id_t *context_handle, gss_cred_id_t verifier_cred_handle, @@ -1209,12 +1557,13 @@ spnego_gss_accept_sec_context(void *ct, OM_uint32 *time_rec, gss_cred_id_t *delegated_cred_handle) { - OM_uint32 ret, tmpret, tmpmin, negState; + OM_uint32 ret, tmpmin, negState; send_token_flag return_token; gss_buffer_t mechtok_in, mic_in, mic_out; gss_buffer_desc mechtok_out = GSS_C_EMPTY_BUFFER; spnego_gss_ctx_id_t sc = NULL; OM_uint32 mechstat = GSS_S_FAILURE; + int sendTokenInit = 0; mechtok_in = mic_in = mic_out = GSS_C_NO_BUFFER; @@ -1233,7 +1582,8 @@ spnego_gss_accept_sec_context(void *ct, if (input_token == GSS_C_NO_BUFFER) return GSS_S_CALL_INACCESSIBLE_READ; - if (*context_handle == GSS_C_NO_CONTEXT) { + sc = (spnego_gss_ctx_id_t)*context_handle; + if (sc == NULL || sc->internal_mech == GSS_C_NO_OID) { if (src_name != NULL) *src_name = GSS_C_NO_NAME; if (mech_type != NULL) @@ -1244,14 +1594,27 @@ spnego_gss_accept_sec_context(void *ct, *ret_flags = 0; if (delegated_cred_handle != NULL) *delegated_cred_handle = GSS_C_NO_CREDENTIAL; - /* Can set negState to REQUEST_MIC */ - ret = acc_ctx_new(minor_status, input_token, - context_handle, verifier_cred_handle, - &mechtok_in, &mic_in, - &negState, &return_token); - if (ret != GSS_S_COMPLETE) - goto cleanup; - ret = GSS_S_CONTINUE_NEEDED; + if (input_token->length == 0) { + sendTokenInit = 1; + ret = acc_ctx_hints(minor_status, + context_handle, + verifier_cred_handle, + &mic_out, + &negState, + &return_token); + if (ret != GSS_S_COMPLETE) + goto cleanup; + ret = GSS_S_CONTINUE_NEEDED; + } else { + /* Can set negState to REQUEST_MIC */ + ret = acc_ctx_new(minor_status, input_token, + context_handle, verifier_cred_handle, + &mechtok_in, &mic_in, + &negState, &return_token); + if (ret != GSS_S_COMPLETE) + goto cleanup; + ret = GSS_S_CONTINUE_NEEDED; + } } else { /* Can set negState to ACCEPT_INCOMPLETE */ ret = acc_ctx_cont(minor_status, input_token, @@ -1290,13 +1653,27 @@ spnego_gss_accept_sec_context(void *ct, } cleanup: if (return_token != NO_TOKEN_SEND && return_token != CHECK_MIC) { - tmpret = make_spnego_tokenTarg_msg(negState, sc->internal_mech, - &mechtok_out, mic_out, - return_token, - output_token); - if (tmpret != GSS_S_COMPLETE) { - ret = tmpret; + /* For acceptor-sends-first send a tokenInit */ + int tmpret; + + assert(sc != NULL); + + if (sendTokenInit) { + tmpret = make_spnego_tokenInit_msg(sc, + 1, + mic_out, + 0, + GSS_C_NO_BUFFER, + return_token, + output_token); + } else { + tmpret = make_spnego_tokenTarg_msg(negState, sc->internal_mech, + &mechtok_out, mic_out, + return_token, + output_token); } + if (tmpret < 0) + ret = GSS_S_FAILURE; } if (ret == GSS_S_COMPLETE) { *context_handle = (gss_ctx_id_t)sc->ctx_handle; @@ -1326,7 +1703,7 @@ cleanup: /*ARGSUSED*/ OM_uint32 -spnego_gss_display_status(void *ctx, +spnego_gss_display_status( OM_uint32 *minor_status, OM_uint32 status_value, int status_type, @@ -1371,7 +1748,7 @@ spnego_gss_display_status(void *ctx, /*ARGSUSED*/ OM_uint32 -spnego_gss_import_name(void *ctx, +spnego_gss_import_name( OM_uint32 *minor_status, gss_buffer_t input_name_buffer, gss_OID input_name_type, @@ -1390,7 +1767,7 @@ spnego_gss_import_name(void *ctx, /*ARGSUSED*/ OM_uint32 -spnego_gss_release_name(void *ctx, +spnego_gss_release_name( OM_uint32 *minor_status, gss_name_t *input_name) { @@ -1406,7 +1783,25 @@ spnego_gss_release_name(void *ctx, /*ARGSUSED*/ OM_uint32 -spnego_gss_display_name(void *ctx, +spnego_gss_compare_name( + OM_uint32 *minor_status, + const gss_name_t name1, + const gss_name_t name2, + int *name_equal) +{ + OM_uint32 status = GSS_S_COMPLETE; + dsyslog("Entering compare_name\n"); + + status = gss_compare_name(minor_status, name1, name2, name_equal); + + dsyslog("Leaving compare_name\n"); + return (status); +} + +/*ARGSUSED*/ +/*ARGSUSED*/ +OM_uint32 +spnego_gss_display_name( OM_uint32 *minor_status, gss_name_t input_name, gss_buffer_t output_name_buffer, @@ -1425,7 +1820,7 @@ spnego_gss_display_name(void *ctx, /*ARGSUSED*/ OM_uint32 -spnego_gss_inquire_names_for_mech(void *ctx, +spnego_gss_inquire_names_for_mech( OM_uint32 *minor_status, gss_OID mechanism, gss_OID_set *name_types) @@ -1468,16 +1863,16 @@ spnego_gss_inquire_names_for_mech(void *ctx, } OM_uint32 -spnego_gss_unseal(void *context, +spnego_gss_unwrap( OM_uint32 *minor_status, gss_ctx_id_t context_handle, gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int *conf_state, - int *qop_state) + gss_qop_t *qop_state) { OM_uint32 ret; - ret = gss_unseal(minor_status, + ret = gss_unwrap(minor_status, context_handle, input_message_buffer, output_message_buffer, @@ -1488,17 +1883,17 @@ spnego_gss_unseal(void *context, } OM_uint32 -spnego_gss_seal(void *context, +spnego_gss_wrap( OM_uint32 *minor_status, gss_ctx_id_t context_handle, int conf_req_flag, - int qop_req, + gss_qop_t qop_req, gss_buffer_t input_message_buffer, int *conf_state, gss_buffer_t output_message_buffer) { OM_uint32 ret; - ret = gss_seal(minor_status, + ret = gss_wrap(minor_status, context_handle, conf_req_flag, qop_req, @@ -1510,7 +1905,7 @@ spnego_gss_seal(void *context, } OM_uint32 -spnego_gss_process_context_token(void *context, +spnego_gss_process_context_token( OM_uint32 *minor_status, const gss_ctx_id_t context_handle, const gss_buffer_t token_buffer) @@ -1524,7 +1919,7 @@ spnego_gss_process_context_token(void *context, } OM_uint32 -spnego_gss_delete_sec_context(void *context, +spnego_gss_delete_sec_context( OM_uint32 *minor_status, gss_ctx_id_t *context_handle, gss_buffer_t output_token) @@ -1552,7 +1947,7 @@ spnego_gss_delete_sec_context(void *context, } OM_uint32 -spnego_gss_context_time(void *context, +spnego_gss_context_time( OM_uint32 *minor_status, const gss_ctx_id_t context_handle, OM_uint32 *time_rec) @@ -1565,7 +1960,7 @@ spnego_gss_context_time(void *context, } #ifndef LEAN_CLIENT OM_uint32 -spnego_gss_export_sec_context(void *context, +spnego_gss_export_sec_context( OM_uint32 *minor_status, gss_ctx_id_t *context_handle, gss_buffer_t interprocess_token) @@ -1578,7 +1973,7 @@ spnego_gss_export_sec_context(void *context, } OM_uint32 -spnego_gss_import_sec_context(void *context, +spnego_gss_import_sec_context( OM_uint32 *minor_status, const gss_buffer_t interprocess_token, gss_ctx_id_t *context_handle) @@ -1592,7 +1987,7 @@ spnego_gss_import_sec_context(void *context, #endif /* LEAN_CLIENT */ OM_uint32 -spnego_gss_inquire_context(void *context, +spnego_gss_inquire_context( OM_uint32 *minor_status, const gss_ctx_id_t context_handle, gss_name_t *src_name, @@ -1619,7 +2014,7 @@ spnego_gss_inquire_context(void *context, } OM_uint32 -spnego_gss_wrap_size_limit(void *context, +spnego_gss_wrap_size_limit( OM_uint32 *minor_status, const gss_ctx_id_t context_handle, int conf_req_flag, @@ -1638,15 +2033,15 @@ spnego_gss_wrap_size_limit(void *context, } OM_uint32 -spnego_gss_sign(void *context, +spnego_gss_get_mic( OM_uint32 *minor_status, const gss_ctx_id_t context_handle, - int qop_req, + gss_qop_t qop_req, const gss_buffer_t message_buffer, gss_buffer_t message_token) { OM_uint32 ret; - ret = gss_sign(minor_status, + ret = gss_get_mic(minor_status, context_handle, qop_req, message_buffer, @@ -1655,19 +2050,164 @@ spnego_gss_sign(void *context, } OM_uint32 -spnego_gss_verify(void *context, +spnego_gss_verify_mic( OM_uint32 *minor_status, const gss_ctx_id_t context_handle, const gss_buffer_t msg_buffer, const gss_buffer_t token_buffer, - int *qop_state) + gss_qop_t *qop_state) { OM_uint32 ret; ret = gss_verify_mic(minor_status, context_handle, msg_buffer, token_buffer, - (gss_qop_t *)qop_state); /* XXX */ + qop_state); + return (ret); +} + +OM_uint32 +spnego_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); +} + +OM_uint32 +spnego_gss_set_sec_context_option( + OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + const gss_OID desired_object, + const gss_buffer_t value) +{ + OM_uint32 ret; + ret = gss_set_sec_context_option(minor_status, + context_handle, + desired_object, + value); + return (ret); +} + +OM_uint32 +spnego_gss_wrap_aead(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + gss_buffer_t input_assoc_buffer, + gss_buffer_t input_payload_buffer, + int *conf_state, + gss_buffer_t output_message_buffer) +{ + OM_uint32 ret; + ret = gss_wrap_aead(minor_status, + context_handle, + conf_req_flag, + qop_req, + input_assoc_buffer, + input_payload_buffer, + conf_state, + output_message_buffer); + + return (ret); +} + +OM_uint32 +spnego_gss_unwrap_aead(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_buffer_t input_message_buffer, + gss_buffer_t input_assoc_buffer, + gss_buffer_t output_payload_buffer, + int *conf_state, + gss_qop_t *qop_state) +{ + OM_uint32 ret; + ret = gss_unwrap_aead(minor_status, + context_handle, + input_message_buffer, + input_assoc_buffer, + output_payload_buffer, + conf_state, + qop_state); + return (ret); +} + +OM_uint32 +spnego_gss_wrap_iov(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 ret; + ret = gss_wrap_iov(minor_status, + context_handle, + conf_req_flag, + qop_req, + conf_state, + iov, + iov_count); + return (ret); +} + +OM_uint32 +spnego_gss_unwrap_iov(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 ret; + ret = gss_unwrap_iov(minor_status, + context_handle, + conf_state, + qop_state, + iov, + iov_count); + return (ret); +} + +OM_uint32 +spnego_gss_wrap_iov_length(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 ret; + ret = gss_wrap_iov_length(minor_status, + context_handle, + conf_req_flag, + qop_req, + conf_state, + iov, + iov_count); + return (ret); +} + + +OM_uint32 +spnego_gss_complete_auth_token( + OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + gss_buffer_t input_message_buffer) +{ + OM_uint32 ret; + ret = gss_complete_auth_token(minor_status, + context_handle, + input_message_buffer); return (ret); } @@ -2237,8 +2777,14 @@ negotiate_mech_type(OM_uint32 *minor_status, unsigned int i; for (i = 0; i < mechset->count; i++) { - gss_test_oid_set_member(minor_status, &mechset->elements[i], - supported_mechSet, &present); + gss_OID mech_oid = &mechset->elements[i]; + + /* Accept wrong mechanism OID from MS clients */ + if (mech_oid->length == gss_mech_krb5_wrong_oid.length && + memcmp(mech_oid->elements, gss_mech_krb5_wrong_oid.elements, mech_oid->length) == 0) + mech_oid = (gss_OID)&gss_mech_krb5_oid;; + + gss_test_oid_set_member(minor_status, mech_oid, supported_mechSet, &present); if (!present) continue; @@ -2298,6 +2844,7 @@ make_err_msg(char *name) */ static int make_spnego_tokenInit_msg(spnego_gss_ctx_id_t spnego_ctx, + int negHintsCompat, gss_buffer_t mechListMIC, OM_uint32 req_flags, gss_buffer_t data, send_token_flag sendtoken, gss_buffer_t outbuf) @@ -2405,7 +2952,7 @@ make_spnego_tokenInit_msg(spnego_gss_ctx_id_t spnego_ctx, tlen - (int)(ptr-t)))) goto errout; - *ptr++ = CONTEXT; /* MechTypeList identifier */ + *ptr++ = CONTEXT | 0x00; /* MechTypeList identifier */ if ((ret = gssint_put_der_length(spnego_ctx->DER_mechTypes.length, &ptr, tlen - (int)(ptr-t)))) goto errout; @@ -2433,7 +2980,12 @@ make_spnego_tokenInit_msg(spnego_gss_ctx_id_t spnego_ctx, &ptr, tlen - (int)(ptr - t)))) goto errout; - if ((ret = put_input_token(&ptr, mechListMIC, + if (negHintsCompat) { + ret = put_neg_hints(&ptr, mechListMIC, + tlen - (int)(ptr - t)); + if (ret) + goto errout; + } else if ((ret = put_input_token(&ptr, mechListMIC, tlen - (int)(ptr - t)))) goto errout; } @@ -2716,7 +3268,7 @@ g_get_tag_and_length(unsigned char **buf, int tag, unsigned char *ptr = *buf; int ret = -1; /* pessimists, assume failure ! */ unsigned int encoded_len; - int tmplen = 0; + unsigned int tmplen = 0; *outlen = 0; if (buflen > 1 && *ptr == tag) { |