summaryrefslogtreecommitdiffstats
path: root/src/lib/gssapi/spnego/spnego_mech.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/gssapi/spnego/spnego_mech.c')
-rw-r--r--src/lib/gssapi/spnego/spnego_mech.c714
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) {