/*
*/
/*
* Copyright (C) 2006,2008 by the Massachusetts Institute of Technology.
* All rights reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
*/
/*
* A module that implements the spnego security mechanism.
* It is used to negotiate the security mechanism between
* 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
* * 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 <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <k5-int.h>
#include <krb5.h>
#include <mglueP.h>
#include "gssapiP_spnego.h"
#include "gssapiP_generic.h"
#include <gssapi_err_generic.h>
#include <locale.h>
/*
* SUNW17PACresync
* MIT has diff names for these GSS utilities. Solaris needs to change
* Revisit for full 1.7 resync.
*/
/* der routines defined in libgss */
extern unsigned int gssint_der_length_size(OM_uint32);
/* private routines for spnego_mechanism */
static spnego_token_t make_spnego_token(char *);
static gss_buffer_desc make_err_msg(char *);
static int g_token_size(gss_OID_const, unsigned int);
static int g_make_token_header(gss_OID_const, unsigned int,
unsigned char **, unsigned int);
static int g_verify_token_header(gss_OID_const, unsigned int *,
unsigned char **,
int, unsigned int);
static int g_verify_neg_token_init(unsigned char **, unsigned int);
static gss_buffer_t get_input_token(unsigned char **, unsigned int);
static void release_spnego_ctx(spnego_gss_ctx_id_t *);
static void check_spnego_options(spnego_gss_ctx_id_t);
static spnego_gss_ctx_id_t create_spnego_ctx(void);
static int put_input_token(unsigned char **, gss_buffer_t, unsigned int);
static int put_mech_oid(unsigned char **, gss_OID_const, unsigned int);
static int put_negResult(unsigned char **, OM_uint32, unsigned int);
static OM_uint32
static OM_uint32
static OM_uint32
gss_OID_set *, send_token_flag *);
static OM_uint32
gss_buffer_t *, gss_buffer_t *,
OM_uint32 *, send_token_flag *);
static OM_uint32
gss_buffer_t *, gss_buffer_t *,
OM_uint32 *, send_token_flag *);
static OM_uint32
OM_uint32 *, send_token_flag *);
static OM_uint32
OM_uint32 *, send_token_flag *);
static OM_uint32
static OM_uint32
gss_buffer_t *, gss_buffer_t *,
OM_uint32 *, send_token_flag *);
static OM_uint32
OM_uint32 *, send_token_flag *);
static OM_uint32
OM_uint32 *, send_token_flag *);
static gss_OID
OM_uint32 *);
static int
g_get_tag_and_length(unsigned char **, int, unsigned int, unsigned int *);
static int
int,
static int
static OM_uint32
gss_buffer_t *);
static OM_uint32
get_negTokenResp(OM_uint32 *, unsigned char *, unsigned int,
static int
/* SPNEGO oid structure */
};
};
/* encoded OID octet string for NTLMSSP security mechanism */
};
static int put_neg_hints(unsigned char **, gss_buffer_t, unsigned int);
static OM_uint32
#ifdef _GSS_STATIC_LINK
int gss_spnegoint_lib_init(void);
void gss_spnegoint_lib_fini(void);
#else
gss_mechanism gss_mech_initialize(void);
#endif /* _GSS_STATIC_LINK */
/*
* The Mech OID for SPNEGO:
* { iso(1) org(3) dod(6) internet(1) security(5)
* mechanism(5) spnego(2) }
*/
{
NULL, /* context */
#ifndef LEAN_CLIENT
#else
NULL,
#endif /* LEAN_CLIENT */
NULL, /* gss_process_context_token */
glue_spnego_gss_delete_sec_context, /* gss_delete_sec_context */
spnego_gss_get_mic, /* gss_get_mic */
spnego_gss_verify_mic, /* gss_verify_mic */
/* EXPORT DELETE START */ /* CRYPT DELETE START */
NULL, /* seal */
/* EXPORT DELETE END */ /* CRYPT DELETE END */
/* EXPORT DELETE START */ /* CRYPT DELETE START */
NULL, /* unseal */
/* EXPORT DELETE END */ /* CRYPT DELETE END */
NULL, /* gss_indicate_mechs */
glue_spnego_gss_import_name, /* glue */
NULL, /* gss_inquire_cred */
NULL, /* gss_add_cred */
#ifndef LEAN_CLIENT
glue_spnego_gss_export_sec_context, /* gss_export_sec_context */
glue_spnego_gss_import_sec_context, /* gss_import_sec_context */
#else
NULL, /* gss_export_sec_context */
NULL, /* gss_import_sec_context */
#endif /* LEAN_CLIENT */
NULL, /* gss_inquire_cred_by_mech */
NULL, /* gss_internal_release_oid */
NULL, /* pname */
NULL, /* userok */
NULL, /* gss_export_name */
/* EXPORT DELETE START */
/* CRYPT DELETE START */
#if 0
/* CRYPT DELETE END */
NULL, /* seal */
NULL, /* unseal */
/* CRYPT DELETE START */
#endif
/* CRYPT DELETE END */
/* EXPORT DELETE END */
NULL, /* sign */
NULL, /* verify */
NULL, /* gss_store_cred */
spnego_gss_inquire_sec_context_by_oid, /* gss_inquire_sec_context_by_oid */
NULL, /* gss_inquire_cred_by_oid */
NULL, /* gss_set_sec_context_option */
NULL, /* gssspi_set_cred_option */
NULL, /* gssspi_mech_invoke */
/* EXPORT DELETE START */ /* CRYPT DELETE START */
NULL, /* wrap_aead */
NULL, /* unwrap_aead */
NULL, /* gss_wrap_iov */
NULL, /* gss_unwrap_iov */
NULL, /* gss_wrap_iov_length */
/* EXPORT DELETE END */ /* CRYPT DELETE END */
NULL, /* complete_auth_token */
NULL, /* gss_acquire_cred_impersonate_name */
NULL, /* display_name_ext */
NULL, /* gss_inquire_name */
NULL, /* gss_get_name_attribute */
NULL, /* gss_set_name_attribute */
NULL, /* gss_delete_name_attribute */
NULL, /* gss_export_name_composite */
NULL, /* gss_map_name_to_any */
NULL, /* gss_release_any_name_mapping */
NULL, /* gss_pseudo_random */
NULL, /* set_neg_mechs */
};
#ifdef _GSS_STATIC_LINK
#include "mglueP.h"
static
int gss_spnegomechglue_init(void)
{
return gssint_register_mechinfo(&mech_spnego);
}
#else
/* Entry point for libgss */
gss_mech_initialize(void)
{
int err;
if (err) {
"SPNEGO gss_mech_initialize: error message TSD key register fail");
return (NULL);
}
return (&spnego_mechanism);
}
#if 0 /* SUNW17PACresync */
int gss_krb5int_lib_init(void)
#endif
#endif /* _GSS_STATIC_LINK */
static
int gss_spnegoint_lib_init(void)
{
#ifdef _GSS_STATIC_LINK
return gss_spnegomechglue_init();
#else
int err;
if (err) {
"SPNEGO gss_mech_initialize: error message TSD key register fail: err=%d",
err);
return err;
}
return 0;
#endif
}
#pragma fini(gss_spnegoint_lib_fini)
static void gss_spnegoint_lib_fini(void)
{
}
/*ARGSUSED*/
{
return(spnego_gss_acquire_cred(minor_status,
time_rec));
}
/*ARGSUSED*/
{
dsyslog("Entering spnego_gss_acquire_cred\n");
if (actual_mechs)
*actual_mechs = NULL;
if (time_rec)
*time_rec = 0;
/*
* If the user did not specify a list of mechs,
* use get_available_mechs to collect a list of
* mechs for which creds are available.
*/
if (desired_mechs == GSS_C_NULL_OID_SET) {
} else {
/*
* The caller gave a specific list of mechanisms,
* so just get whatever creds are available.
* gss_acquire_creds will return the subset of mechs for
* which the given 'output_cred_handle' is valid.
*/
time_rec);
}
}
dsyslog("Leaving spnego_gss_acquire_cred\n");
return (status);
}
/*ARGSUSED*/
{
}
/*ARGSUSED*/
{
dsyslog("Entering spnego_gss_release_cred\n");
return (GSS_S_CALL_INACCESSIBLE_WRITE);
*minor_status = 0;
if (*cred_handle == GSS_C_NO_CREDENTIAL)
return (GSS_S_COMPLETE);
dsyslog("Leaving spnego_gss_release_cred\n");
return (status);
}
static void
{
(const gss_OID)&spnego_oids[0]);
}
static spnego_gss_ctx_id_t
create_spnego_ctx(void)
{
malloc(sizeof (spnego_gss_ctx_id_rec));
if (spnego_ctx == NULL) {
return (NULL);
}
spnego_ctx->mic_reqd = 0;
spnego_ctx->mic_sent = 0;
spnego_ctx->mic_rcvd = 0;
spnego_ctx->mech_complete = 0;
spnego_ctx->nego_done = 0;
return (spnego_ctx);
}
/*
* mechListMIC, and to consistency-check the MIC state.
*/
static OM_uint32
{
ret = GSS_S_FAILURE;
if (mic_in != GSS_C_NO_BUFFER) {
/* Reject MIC if we've already received a MIC. */
return GSS_S_DEFECTIVE_TOKEN;
}
/*
* If the peer sends the final mechanism token, it
* must send the MIC with that token if the
* negotiation requires MICs.
*/
return GSS_S_DEFECTIVE_TOKEN;
}
if (ret != GSS_S_COMPLETE) {
return ret;
}
}
if (*mic_out == GSS_C_NO_BUFFER) {
/*
* We sent a MIC on the previous pass; we
* shouldn't be sending a mechanism token.
*/
*tokflag = NO_TOKEN_SEND;
} else {
}
} else if (*negState == ACCEPT_COMPLETE) {
} else {
}
return ret;
}
/*
*/
static OM_uint32
{
ret = GSS_S_FAILURE;
if (mic_in != GSS_C_NO_BUFFER) {
&sc->DER_mechTypes,
if (ret != GSS_S_COMPLETE) {
return ret;
}
/* If we got a MIC, we must send a MIC. */
}
&sc->DER_mechTypes,
&tmpmic);
if (ret != GSS_S_COMPLETE) {
*tokflag = NO_TOKEN_SEND;
return ret;
}
if (*mic_out == GSS_C_NO_BUFFER) {
*tokflag = NO_TOKEN_SEND;
return GSS_S_FAILURE;
}
}
return GSS_S_COMPLETE;
}
/*
* Initial call to spnego_gss_init_sec_context().
*/
static OM_uint32
{
/* determine negotiation mech set */
if (cred == GSS_C_NO_CREDENTIAL) {
} else {
/*
* Use the list of mechs included in the cred that we
* were given.
*/
}
if (ret != GSS_S_COMPLETE)
return ret;
sc = create_spnego_ctx();
return GSS_S_FAILURE;
/*
* need to pull the first mech from mechSet to do first
* gss_init_sec_context()
*/
&sc->internal_mech);
if (ret != GSS_S_COMPLETE) {
goto cleanup;
}
ret = GSS_S_FAILURE;
goto cleanup;
}
/*
* The actual context is not yet determined, set the output
* context handle to refer to the spnego context itself.
*/
return ret;
}
/*
* Called by second and later calls to spnego_gss_init_sec_context()
* to decode reply and update state.
*/
static OM_uint32
{
unsigned char *ptr;
if (ret != GSS_S_COMPLETE)
goto cleanup;
if (acc_negState == ACCEPT_DEFECTIVE_TOKEN &&
supportedMech == GSS_C_NO_OID &&
*responseToken == GSS_C_NO_BUFFER &&
*mechListMIC == GSS_C_NO_BUFFER) {
/* Reject "empty" token. */
}
if (acc_negState == REJECT) {
/* Solaris SPNEGO */
"SPNEGO failed to negotiate a mechanism: server rejected request"));
*tokflag = NO_TOKEN_SEND;
ret = GSS_S_FAILURE;
goto cleanup;
}
/*
* nego_done is false for the first call to init_ctx_cont()
*/
} else if (!sc->mech_complete &&
*responseToken == GSS_C_NO_BUFFER) {
/*
* mech not finished and mech token missing
*/
} else {
*tokflag = NO_TOKEN_SEND;
}
if (supportedMech != GSS_C_NO_OID)
return ret;
}
/*
* Consistency checking and mechanism negotiation handling for second
* call of spnego_gss_init_sec_context(). Call init_ctx_reselect() to
* update internal state if acceptor has counter-proposed.
*/
static OM_uint32
{
/*
* Both supportedMech and negState must be present in first
* acceptor token.
*/
if (supportedMech == GSS_C_NO_OID) {
return GSS_S_DEFECTIVE_TOKEN;
}
if (acc_negState == ACCEPT_DEFECTIVE_TOKEN) {
/* Solaris SPNEGO */
"SPNEGO failed to negotiate a mechanism: defective token"));
return GSS_S_DEFECTIVE_TOKEN;
}
/*
* If the mechanism we sent is not the mechanism returned from
* the server, we need to handle the server's counter
* proposal. There is a bug in SAMBA servers that always send
* the old Kerberos mech OID, even though we sent the new one.
* So we will treat all the Kerberos mech OIDS as the same.
*/
if (!(is_kerb_mech(supportedMech) &&
} else if (*responseToken == GSS_C_NO_BUFFER) {
if (sc->mech_complete) {
/*
* Mech completed on first call to its
* init_sec_context(). Acceptor sends no mech
* token.
*/
*tokflag = NO_TOKEN_SEND;
} else {
/*
* Reject missing mech token when optimistic
* mech selected.
*/
}
} else if (sc->mech_complete) {
/* Reject spurious mech token. */
} else {
}
return ret;
}
/*
* Handle acceptor's counter-proposal of an alternative mechanism.
*/
static OM_uint32
{
&sc->internal_mech);
if (ret != GSS_S_COMPLETE) {
*tokflag = NO_TOKEN_SEND;
return ret;
}
if (*responseToken != GSS_C_NO_BUFFER) {
/* Reject spurious mech token. */
return GSS_S_DEFECTIVE_TOKEN;
}
/*
* Windows 2003 and earlier don't correctly send a
* negState of request-mic when counter-proposing a
* mechanism. They probably don't handle mechListMICs
* properly either.
*/
if (acc_negState != REQUEST_MIC)
return GSS_S_DEFECTIVE_TOKEN;
sc->mech_complete = 0;
*negState = REQUEST_MIC;
return GSS_S_CONTINUE_NEEDED;
}
/*
* Wrap call to mechanism gss_init_sec_context() and update state
* accordingly.
*/
static OM_uint32
{
&sc->ctx_handle,
&sc->actual_mech,
time_rec);
if (ret == GSS_S_COMPLETE) {
/*
* If this isn't the first time we've been called,
* we're done unless a MIC needs to be
*/
if (*send_token == CONT_TOKEN_SEND &&
mechtok_out->length == 0 &&
if (mechtok_out->length == 0) {
}
} else {
}
} else if (ret != GSS_S_CONTINUE_NEEDED) {
if (*send_token == INIT_TOKEN_SEND) {
/* Don't output token on error if first call. */
} else {
}
}
return ret;
}
/*ARGSUSED*/
{
return(spnego_gss_init_sec_context(
time_rec));
}
/*ARGSUSED*/
{
/*
* send_token is used to indicate in later steps
* what type of token, if any should be sent or processed.
* NO_TOKEN_SEND = no token should be sent
* INIT_TOKEN_SEND = initial token will be sent
* CONT_TOKEN_SEND = continuing tokens to be sent
* CHECK_MIC = no token to be sent, but have a MIC to check.
*/
dsyslog("Entering init_sec_context\n");
if (minor_status != NULL)
*minor_status = 0;
if (output_token != GSS_C_NO_BUFFER) {
output_token->length = 0;
}
if (minor_status == NULL ||
output_token == GSS_C_NO_BUFFER ||
context_handle == NULL)
return GSS_S_CALL_INACCESSIBLE_WRITE;
if (actual_mech != NULL)
if (*context_handle == GSS_C_NO_CONTEXT) {
if (ret != GSS_S_CONTINUE_NEEDED) {
goto cleanup;
}
} else {
if (HARD_ERROR(ret)) {
goto cleanup;
}
}
/* Solaris SPNEGO */
if (!spnego_ctx->mech_complete) {
&negState, &send_token);
}
(mechtok_out.length != 0),
&negState, &send_token);
}
if (send_token == INIT_TOKEN_SEND) {
0,
output_token) < 0) {
ret = GSS_S_FAILURE;
}
} else if (send_token != NO_TOKEN_SEND) {
output_token) < 0) {
ret = GSS_S_FAILURE;
}
}
if (ret == GSS_S_COMPLETE) {
/*
* Now, switch the output context to refer to the
* negotiated mechanism's context.
*/
if (actual_mech != NULL)
} else if (ret != GSS_S_CONTINUE_NEEDED) {
if (spnego_ctx != NULL) {
}
}
if (mechtok_in != GSS_C_NO_BUFFER) {
}
if (mechListMIC_in != GSS_C_NO_BUFFER) {
}
if (mechListMIC_out != GSS_C_NO_BUFFER) {
}
if (mechSet != GSS_C_NO_OID_SET) {
}
return ret;
} /* init_sec_context */
/* We don't want to import KRB5 headers here */
{ 9, "\052\206\110\206\367\022\001\002\002" };
{ 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
unsigned int buflen)
{
int ret;
/* if token length is 0, we do not want to send */
if (input_token->length == 0)
return (0);
return (-1);
input_token->length)))
return (ret);
return (0);
}
/*
* NegHints ::= SEQUENCE {
* hintName [0] GeneralString OPTIONAL,
* hintAddress [1] OCTET STRING OPTIONAL
* }
*/
static int
{
unsigned int tlen = 0;
unsigned int hintNameSize = 0;
unsigned int negHintsSize = 0;
unsigned char *ptr;
unsigned char *t;
if (cred != GSS_C_NO_CREDENTIAL) {
cred,
&hintName,
NULL,
NULL,
NULL);
if (major_status != GSS_S_COMPLETE)
return (major_status);
}
if (hintName == GSS_C_NO_NAME) {
if (code != 0) {
*minor_status = code;
return (GSS_S_FAILURE);
}
/* this breaks mutual authentication but Samba relies on it */
if (code != 0) {
*minor_status = code;
return (GSS_S_FAILURE);
}
&hintName);
if (major_status != GSS_S_COMPLETE) {
return (major_status);
}
}
hintNameBuf.length = 0;
if (major_status != GSS_S_COMPLETE) {
return (major_status);
}
&hintNameType);
if (major_status != GSS_S_COMPLETE) {
/* Solaris SPNEGO */
return (major_status);
}
/*
* Now encode the name hint into a NegHints ASN.1 type
*/
/* Length of DER encoded GeneralString */
hintNameSize = tlen;
/* Length of DER encoded hintName */
negHintsSize = tlen;
if (t == NULL) {
*minor_status = ENOMEM;
goto errout;
}
ptr = t;
goto errout;
*ptr++ = GENERAL_STRING;
goto errout;
*minor_status = ENOMEM;
goto errout;
}
t = NULL; /* don't free */
*minor_status = 0;
if (t != NULL) {
free(t);
}
return (major_status);
}
static OM_uint32
{
*minor_status = 0;
/* Solaris SPNEGO */
if (cred != GSS_C_NO_CREDENTIAL) {
if (ret != GSS_S_COMPLETE) {
goto cleanup;
}
} else {
if (ret != GSS_S_COMPLETE) {
goto cleanup;
}
}
if (ret != GSS_S_COMPLETE) {
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();
ret = GSS_S_FAILURE;
goto cleanup;
}
ret = GSS_S_FAILURE;
goto cleanup;
}
return ret;
}
/*
* Solaris SPNEGO
* mechoidset2str()
* Input an OID set of mechs and output a string like so:
* '{ x y z } (mechname0), { a b c } (mechname1) ...'.
* On error return NULL.
* Caller needs to free returned string.
*/
static char *
{
int i, l;
char *s = NULL;
if (!mechset)
return NULL;
/* No need to free mech_name. */
if (i > 0)
break;
}
/* Add '{ x y x ... }'. */
break;
}
/* Add '(mech name)'. */
break;
break;
break;
}
/* Even if we have buf overflow, let's output what we got so far. */
if (l > 0) {
s = malloc(l + 1);
if (!s)
return NULL;
}
}
return s ? s : NULL;
}
/*
* Set negState to REJECT if the token is defective, else
* ACCEPT_INCOMPLETE or REQUEST_MIC, depending on whether initiator's
* preferred mechanism is supported.
*/
static OM_uint32
{
der_mechTypes.length = 0;
*minor_status = 0;
if (ret != GSS_S_COMPLETE) {
goto cleanup;
}
if (cred != GSS_C_NO_CREDENTIAL) {
if (ret != GSS_S_COMPLETE) {
goto cleanup;
}
} else {
if (ret != GSS_S_COMPLETE) {
goto cleanup;
}
}
/*
* Select the best match between the list of mechs
* that the initiator requested and the list that
* the acceptor will support.
*/
negState);
/* Solaris SPNEGO: Spruce-up error msg */
"SPNEGO failed to negotiate a mechanism: client requested mech set '%s'"),
}
if (mechTypesStr)
/*
* We save error here cuz the tmp ctx goes away (very) soon.
* So callers of acc_ctx_new() should NOT call it again.
*/
if (tmpsc)
goto cleanup;
}
} else
sc = create_spnego_ctx();
ret = GSS_S_FAILURE;
goto cleanup;
}
der_mechTypes.length = 0;
if (*negState == REQUEST_MIC)
if (der_mechTypes.length != 0)
return ret;
}
static OM_uint32
{
unsigned int len;
*minstat = 0;
return GSS_S_DEFECTIVE_TOKEN;
/*
* Attempt to work with old Sun SPNEGO.
*/
if (ret) {
return GSS_S_DEFECTIVE_TOKEN;
}
}
return GSS_S_DEFECTIVE_TOKEN;
}
if (ret != GSS_S_COMPLETE)
goto cleanup;
if (*responseToken == GSS_C_NO_BUFFER &&
*mechListMIC == GSS_C_NO_BUFFER) {
goto cleanup;
}
if (supportedMech != GSS_C_NO_OID) {
goto cleanup;
}
if (supportedMech != GSS_C_NO_OID) {
}
return ret;
}
/*
* Verify that mech OID is either exactly the same as the negotiated
* mech OID, or is a mech OID supported by the negotiated mech. MS
* implementations can list a most preferred mech using an incorrect
* krb5 OID while emitting a krb5 initiator mech token having the
* correct krb5 mech OID.
*/
static OM_uint32
{
int present = 0;
return GSS_S_COMPLETE;
/*
* SUNW17PACresync
* If both mechs are kerb, we are done.
*/
return GSS_S_COMPLETE;
}
{
/*
* Solaris SPNEGO
* Spruce-up error msg.
*/
/* No need to free mnamestr. */
sc->internal_mech);
&oidstr_sc);
"SPNEGO failed to negotiate a mechanism: unsupported mech OID ('%s') in the token. Negotiated mech OID is '%s' (%s)"),
if (!maj)
if (!maj_sc)
}
return GSS_S_BAD_MECH;
}
if (ret != GSS_S_COMPLETE) {
*tokflag = NO_TOKEN_SEND;
goto cleanup;
}
if (ret != GSS_S_COMPLETE)
goto cleanup;
if (!present) {
{
/*
* Solaris SPNEGO
* Spruce-up error msg.
*/
/* No need to free mnamestr. */
const char *mnamestr =
"SPNEGO failed to negotiate a mechanism: negotiated mech OID '%s' (%s) not found in mechset ('%s') of token mech"),
if (!maj)
if (mech_set_str)
}
}
return ret;
}
#ifndef LEAN_CLIENT
/*
* Wrap call to gss_accept_sec_context() and update state
* accordingly.
*/
static OM_uint32
{
/*
* mechoid is an alias; don't free it.
*/
if (ret != GSS_S_COMPLETE) {
*tokflag = NO_TOKEN_SEND;
return ret;
}
if (ret != GSS_S_COMPLETE)
return ret;
}
&sc->ctx_handle,
cred,
&sc->internal_name,
if (ret == GSS_S_COMPLETE) {
#ifdef MS_BUG_TEST
/*
* Force MIC to be not required even if we previously
* requested a MIC.
*/
}
#endif
} else {
}
} else if (ret != GSS_S_CONTINUE_NEEDED) {
}
return ret;
}
/*ARGSUSED*/
{
return(spnego_gss_accept_sec_context(
}
/*ARGSUSED*/
{
if (minor_status != NULL)
*minor_status = 0;
if (output_token != GSS_C_NO_BUFFER) {
output_token->length = 0;
}
if (minor_status == NULL ||
output_token == GSS_C_NO_BUFFER ||
context_handle == NULL) {
return GSS_S_CALL_INACCESSIBLE_WRITE;
}
if (input_token == GSS_C_NO_BUFFER) {
return GSS_S_CALL_INACCESSIBLE_READ;
}
*time_rec = 0;
*ret_flags = 0;
if (delegated_cred_handle != NULL)
if (input_token->length == 0) {
&mic_out,
&negState,
&return_token);
if (ret != GSS_S_COMPLETE)
goto cleanup;
sendTokenInit = 1;
} else {
/* Can set negState to REQUEST_MIC */
&mechtok_in, &mic_in,
&negState, &return_token);
if (ret != GSS_S_COMPLETE)
goto cleanup;
}
} else {
/* Can set negState to ACCEPT_INCOMPLETE */
if (ret != GSS_S_COMPLETE)
goto cleanup;
}
/*
* Handle mechtok_in and mic_in only if they are
* present in input_token. If neither is present, whether
* this is an error depends on whether this is the first
* round-trip. RET is set to a default value according to
* whether it is the first round-trip.
*/
&negState, &return_token);
} else if (negState == REQUEST_MIC) {
}
/* Solaris SPNEGO */
(mechtok_out.length != 0),
&negState, &return_token);
}
if (tmpret < 0)
ret = GSS_S_FAILURE;
} else if (return_token != NO_TOKEN_SEND &&
return_token != CHECK_MIC) {
if (tmpret < 0)
ret = GSS_S_FAILURE;
}
if (ret == GSS_S_COMPLETE) {
}
} else if (ret != GSS_S_CONTINUE_NEEDED) {
}
}
if (mechtok_in != GSS_C_NO_BUFFER) {
}
if (mic_in != GSS_C_NO_BUFFER) {
}
if (mic_out != GSS_C_NO_BUFFER) {
}
return ret;
}
#endif /* LEAN_CLIENT */
/*ARGSUSED*/
int status_type,
{
return (spnego_gss_display_status(minor_status,
}
/*ARGSUSED*/
int status_type,
{
dsyslog("Entering display_status\n");
*message_context = 0;
switch (status_value) {
/* CSTYLED */
break;
/* CSTYLED */
break;
/* CSTYLED */
break;
/* CSTYLED */
/* CSTYLED */
break;
default:
/*
* Solaris SPNEGO
* If mech_spnego calls mech_krb5 (via libgss) and an
* error occurs there, give it a shot.
*/
/* CSTYLED */
return(krb5_gss_display_status2(minor_status,
}
dsyslog("Leaving display_status\n");
return (GSS_S_COMPLETE);
}
/*ARGSUSED*/
{
return(spnego_gss_import_name(minor_status,
output_name));
}
/*ARGSUSED*/
{
dsyslog("Entering import_name\n");
dsyslog("Leaving import_name\n");
return (status);
}
/*ARGSUSED*/
{
}
/*ARGSUSED*/
{
dsyslog("Entering release_name\n");
dsyslog("Leaving release_name\n");
return (status);
}
/*ARGSUSED*/
const gss_name_t name1,
const gss_name_t name2,
int *name_equal)
{
return(spnego_gss_compare_name(minor_status,
name_equal));
}
/*ARGSUSED*/
const gss_name_t name1,
const gss_name_t name2,
int *name_equal)
{
dsyslog("Entering compare_name\n");
dsyslog("Leaving compare_name\n");
return (status);
}
/*ARGSUSED*/
{
return(spnego_gss_display_name(
}
/*ARGSUSED*/
{
dsyslog("Entering display_name\n");
dsyslog("Leaving display_name\n");
return (status);
}
/*ARGSUSED*/
{
name_types));
}
/*ARGSUSED*/
{
dsyslog("Entering inquire_names_for_mech\n");
/*
* We only know how to handle our own mechanism.
*/
if ((mechanism != GSS_C_NULL_OID) &&
*minor_status = 0;
return (GSS_S_FAILURE);
}
if (major == GSS_S_COMPLETE) {
/* Now add our members. */
name_types)) == GSS_S_COMPLETE) &&
name_types)) == GSS_S_COMPLETE) &&
name_types)) == GSS_S_COMPLETE)) {
}
if (major != GSS_S_COMPLETE)
}
dsyslog("Leaving inquire_names_for_mech\n");
return (major);
}
int *conf_state,
{
return (ret);
}
int conf_req_flag,
int *conf_state,
{
return (ret);
}
const gss_ctx_id_t context_handle,
const gss_buffer_t token_buffer)
{
return (ret);
}
{
}
{
if (context_handle == NULL)
return (GSS_S_FAILURE);
/*
* If this is still an SPNEGO mech, release it locally.
*/
(void) release_spnego_ctx(ctx);
/* SUNW17PACresync - MIT 1.7 bug (and our fix) */
if (output_token) {
output_token->length = 0;
}
} else {
}
return (ret);
}
const gss_ctx_id_t context_handle,
{
return(spnego_gss_context_time(minor_status,
time_rec));
}
const gss_ctx_id_t context_handle,
{
time_rec);
return (ret);
}
#ifndef LEAN_CLIENT
{
}
{
return (ret);
}
const gss_buffer_t interprocess_token,
{
}
const gss_buffer_t interprocess_token,
{
return (ret);
}
#endif /* LEAN_CLIENT */
const gss_ctx_id_t context_handle,
int *locally_initiated,
int *opened)
{
return(spnego_gss_inquire_context(
opened));
}
const gss_ctx_id_t context_handle,
int *locally_initiated,
int *opened)
{
opened);
return (ret);
}
const gss_ctx_id_t context_handle,
int conf_req_flag,
{
}
const gss_ctx_id_t context_handle,
int conf_req_flag,
{
return (ret);
}
const gss_ctx_id_t context_handle,
const gss_buffer_t message_buffer,
{
return (ret);
}
const gss_ctx_id_t context_handle,
const gss_buffer_t msg_buffer,
const gss_buffer_t token_buffer,
{
return (ret);
}
const gss_ctx_id_t context_handle,
const gss_OID desired_object,
{
data_set);
return (ret);
}
/*
* SUNW17PACresync
* These GSS funcs not needed yet, so disable them.
* Revisit for full 1.7 resync.
*/
#if 0
const gss_OID desired_object,
const gss_buffer_t value)
{
value);
return (ret);
}
int conf_req_flag,
int *conf_state,
{
return (ret);
}
int *conf_state,
{
return (ret);
}
int conf_req_flag,
int *conf_state,
int iov_count)
{
iov,
return (ret);
}
int *conf_state,
int iov_count)
{
iov,
return (ret);
}
int conf_req_flag,
int *conf_state,
int iov_count)
{
iov,
return (ret);
}
const gss_ctx_id_t context_handle,
{
return (ret);
}
#endif /* 0 */
/*
* We will release everything but the ctx_handle so that it
* not be called until after the ctx_handle memory is assigned to
*/
static void
{
(void) gss_release_buffer(&minor_stat,
&context->DER_mechTypes);
(void) generic_gss_release_oid(&minor_stat,
&context->internal_mech);
}
/* Solaris SPNEGO */
}
}
/*
* Can't use gss_indicate_mechs by itself to get available mechs for
* SPNEGO because it will also return the SPNEGO mech and we do not
* want to consider SPNEGO as an available security mech for
* negotiation. For this reason, get_available_mechs will return
* all available mechs except SPNEGO.
*
* If a ptr to a creds list is given, this function will attempt
* to acquire creds for the creds given and trim the list of
* returned mechanisms to only those for which creds are valid.
*
*/
static OM_uint32
{
unsigned int i;
int found = 0;
if (major_status != GSS_S_COMPLETE) {
return (major_status);
}
if (major_status != GSS_S_COMPLETE) {
return (major_status);
}
/*
* Solaris SPNEGO: gss_indicate_mechs is stupid as
* it never inferences any of the related OIDs of the
* mechanisms configured, e.g. KRB5_OLD, KRB5_WRONG.
* We add KRB5_WRONG here so that old MS clients can
* negotiate this mechanism, which allows extensions
* in Kerberos (clock skew adjustment, refresh ccache).
*/
extern gss_OID_desc * const gss_mech_krb5_wrong;
}
rmechs);
if (major_status == GSS_S_COMPLETE)
found++;
}
}
/*
* Add NTLMSSP OID to the mech OID set only if MS_INTEROP env var
* has been set.
*
* This is a requirement until NTLMSSP is implemented as a GSS-API
* plugin.
*/
&ntlmssp_oid, rmechs);
if (major_status == GSS_S_COMPLETE)
found++;
}
/*
* If the caller wanted a list of creds returned,
* trim the list of mechanisms down to only those
* for which the creds are valid.
*/
/*
* Drop the old list in favor of the new
* "trimmed" list.
*/
if (major_status == GSS_S_COMPLETE) {
(void) gssint_copy_oid_set(&tmpmin,
}
}
if (major_status == GSS_S_COMPLETE)
}
return (major_status);
}
/* following are token creation and reading routines */
/*
* If buff_in is not pointing to a MECH_OID, then return NULL and do not
* advance the buffer, otherwise, decode the mech_oid from the buffer and
* place in gss_OID.
*/
static gss_OID
{
return (NULL);
(*buff_in)++;
return (NULL);
if (status != GSS_S_COMPLETE) {
}
return (mech_out);
}
/*
* der encode the given mechanism oid into buf_out, advancing the
* buffer pointer.
*/
static int
{
return (-1);
return (0);
}
/*
* verify that buff_in points to an octet string, if it does not,
* return NULL and don't advance the pointer. If it is an octet string
* decode buff_in into a gss_buffer_t and return it, advancing the
* buffer pointer.
*/
static gss_buffer_t
{
unsigned int bytes;
if (**buff_in != OCTET_STRING)
return (NULL);
(*buff_in)++;
if (input_token == NULL)
return (NULL);
return (NULL);
}
return (NULL);
}
return (input_token);
}
/*
* 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 an octet string
* and place in buf_out, advancing buf_out.
*/
static int
unsigned int buflen)
{
int ret;
/* if token length is 0, we do not want to send */
if (input_token->length == 0)
return (0);
return (-1);
*(*buf_out)++ = OCTET_STRING;
input_token->length)))
return (ret);
return (0);
}
/*
* verify that buff_in points to a sequence of der encoding. The mech
* set is the only sequence of encoded object in the token, so if it is
* a sequence of encoding, decode the mechset into a gss_OID_set and
* return it, advancing the buffer pointer.
*/
static gss_OID_set
unsigned int buff_length)
{
unsigned char *start;
int i;
if (**buff_in != SEQUENCE_OF)
return (NULL);
(*buff_in)++;
if (length < 0) /* SUNW17PACresync - MIT17 lacks this check */
return (NULL);
if (major_status != GSS_S_COMPLETE)
return (NULL);
temp, &returned_mechSet);
if (major_status == GSS_S_COMPLETE) {
}
}
}
return (returned_mechSet);
}
/*
* Encode mechSet into buf.
*/
static int
{
unsigned char *ptr;
unsigned int i;
/*
* 0x06 [DER LEN] [OID]
*/
ilen += 1 +
}
/*
* 0x30 [DER LEN]
*/
return -1;
*ptr++ = SEQUENCE_OF;
return -1;
return -1;
}
}
return 0;
}
/*
* Verify that buff_in is pointing to a BIT_STRING with the correct
* length and padding for the req_flags. If it is, decode req_flags
* and return them, otherwise, return NULL.
*/
static OM_uint32
{
unsigned int len;
return (0);
return GSS_S_DEFECTIVE_TOKEN;
if (*(*buff_in)++ != BIT_STRING)
return GSS_S_DEFECTIVE_TOKEN;
if (*(*buff_in)++ != BIT_STRING_LENGTH)
return GSS_S_DEFECTIVE_TOKEN;
if (*(*buff_in)++ != BIT_STRING_PADDING)
return GSS_S_DEFECTIVE_TOKEN;
return (0);
}
static OM_uint32
{
unsigned int len;
*minor_status = 0;
der_mechSet->length = 0;
*req_flags = 0;
return GSS_S_FAILURE;
if (err) {
*minor_status = err;
return GSS_S_FAILURE;
}
if (*minor_status) {
return GSS_S_FAILURE;
}
/* alias into input_token */
return GSS_S_FAILURE;
return GSS_S_FAILURE;
if (err != GSS_S_COMPLETE) {
return err;
}
if (*mechtok == GSS_C_NO_BUFFER) {
return GSS_S_FAILURE;
}
}
if (*mechListMIC == GSS_C_NO_BUFFER) {
return GSS_S_FAILURE;
}
}
return GSS_S_COMPLETE;
}
static OM_uint32
{
unsigned int len;
int tmplen;
return GSS_S_DEFECTIVE_TOKEN;
if (tmplen < 0)
return GSS_S_DEFECTIVE_TOKEN;
}
if (REMAIN < 1)
tag = 0;
else
if (tmplen < 0)
return GSS_S_DEFECTIVE_TOKEN;
return GSS_S_DEFECTIVE_TOKEN;
if (len != ENUMERATION_LENGTH)
return GSS_S_DEFECTIVE_TOKEN;
if (REMAIN < 1)
return GSS_S_DEFECTIVE_TOKEN;
if (REMAIN < 1)
tag = 0;
else
}
if (tmplen < 0)
return GSS_S_DEFECTIVE_TOKEN;
if (*supportedMech == GSS_C_NO_OID)
return GSS_S_DEFECTIVE_TOKEN;
if (REMAIN < 1)
tag = 0;
else
}
if (tmplen < 0)
return GSS_S_DEFECTIVE_TOKEN;
if (*responseToken == GSS_C_NO_BUFFER)
return GSS_S_DEFECTIVE_TOKEN;
if (REMAIN < 1)
tag = 0;
else
}
if (tmplen < 0)
return GSS_S_DEFECTIVE_TOKEN;
if (*mechListMIC == GSS_C_NO_BUFFER)
return GSS_S_DEFECTIVE_TOKEN;
}
return GSS_S_COMPLETE;
}
/*
* der encode the passed negResults as an ENUMERATED type and
* place it in buf_out, advancing the buffer.
*/
static int
unsigned int buflen)
{
if (buflen < 3)
return (-1);
*(*buf_out)++ = ENUMERATED;
*(*buf_out)++ = ENUMERATION_LENGTH;
return (0);
}
/*
* This routine compares the recieved mechset to the mechset that
* this server can support. It looks sequentially through the mechset
* and the first one that matches what the server can support is
* chosen as the negotiated mechanism. If one is found, negResult
* is set to ACCEPT_INCOMPLETE if it's the first mech, REQUEST_MIC if
* it's not the first mech, otherwise we return NULL and negResult
* is set to REJECT.
*
* NOTE: There is currently no way to specify a preference order of
* mechanisms supported by the acceptor.
*/
static gss_OID
{
int present;
unsigned int i;
/*
* Solaris SPNEGO: MIT compares against MS' wrong OID, but
* we actually want to select it if the client supports, as this
* will enable features on MS clients that allow credential
* refresh on rekeying and caching system times from servers.
*/
#if 0
/* Accept wrong mechanism OID from MS clients */
#endif
if (!present)
continue;
if (i == 0)
else
*negResult = REQUEST_MIC;
if (status != GSS_S_COMPLETE) {
return (NULL);
}
return (returned_mech);
}
/* Solaris SPNEGO */
return (NULL);
}
/*
* the next two routines make a token buffer suitable for
* spnego_gss_display_status. These currently take the string
* in name and place it in the token. Eventually, if
* spnego_gss_display_status returns valid error messages,
* these routines will be changes to return the error string.
*/
static spnego_token_t
{
}
static gss_buffer_desc
{
} else {
}
return (buffer);
}
/*
* Create the client side spnego token passed back to gss_init_sec_context
* and eventually up to the application program and over to the server.
*
* Use DER rules, definite length method per RFC 2478
*/
static int
int negHintsCompat,
{
int ret = 0;
unsigned int negTokenInitSize = 0;
unsigned int negTokenInitSeqSize = 0;
unsigned int negTokenInitContSize = 0;
unsigned int rspTokenSize = 0;
unsigned int mechListTokenSize = 0;
unsigned int micTokenSize = 0;
unsigned char *t;
unsigned char *ptr;
if (outbuf == GSS_C_NO_BUFFER)
return (-1);
/* calculate the data length */
/*
* 0xa0 [DER LEN] [mechTypes]
*/
mechListTokenSize = 1 +
/*
* If a token from gss_init_sec_context exists,
* add the length of the token + the ASN.1 overhead
*/
/*
* Encoded in final output as:
* 0xa2 [DER LEN] 0x04 [DER LEN] [DATA]
* -----s--------|--------s2----------
*/
rspTokenSize = 1 +
}
if (mechListMIC) {
/*
* Encoded in final output as:
* 0xa3 [DER LEN] 0x04 [DER LEN] [DATA]
* --s-- -----tlen------------
*/
micTokenSize = 1 +
dataLen += 1 +
}
/*
* Add size of DER encoding
* [ SEQUENCE { MechTypeList | ReqFLags | Token | mechListMIC } ]
* 0x30 [DER_LEN] [data]
*
*/
/*
* negTokenInitSize indicates the bytes needed to
* hold the ASN.1 encoding of the entire NegTokenInit
* SEQUENCE.
* 0xa0 [DER_LEN] + data
*
*/
negTokenInitSize = 1 +
if (t == NULL) {
return (-1);
}
ptr = t;
/* create the message */
goto errout;
goto errout;
goto errout;
goto errout;
/* We already encoded the MechSetList */
goto errout;
goto errout;
}
if (mechListMIC != GSS_C_NO_BUFFER) {
goto errout;
if (negHintsCompat) {
if (ret)
goto errout;
goto errout;
}
if (ret != 0) {
if (t)
free(t);
t = NULL;
tlen = 0;
}
return (ret);
}
/*
* create the server side spnego token passed back to
* gss_accept_sec_context and eventually up to the application program
* and over to the client.
*/
static int
{
unsigned int tlen = 0;
unsigned int ret = 0;
unsigned int NegTokenTargSize = 0;
unsigned int NegTokenSize = 0;
unsigned int rspTokenSize = 0;
unsigned int micTokenSize = 0;
unsigned int dataLen = 0;
unsigned char *t;
unsigned char *ptr;
if (outbuf == GSS_C_NO_BUFFER)
return (GSS_S_DEFECTIVE_TOKEN);
/*
* ASN.1 encoding of the negResult
* ENUMERATED type is 3 bytes
* ENUMERATED TAG, Length, Value,
* Plus 2 bytes for the CONTEXT id and length.
*/
dataLen = 5;
/*
* calculate data length
*
* If this is the initial token, include length of
* mech_type and the negotiation result fields.
*/
if (sendtoken == INIT_TOKEN_SEND) {
int mechlistTokenSize;
/*
* 1 byte for the CONTEXT ID(0xa0),
* 1 byte for the OID ID(0x06)
* 1 byte for OID Length field
* Plus the rest... (OID Length, OID value)
*/
}
/* Length of the inner token */
dataLen += rspTokenSize;
/* Length of the outer token */
}
if (mechListMIC != NULL) {
/* Length of the inner token */
dataLen += micTokenSize;
/* Length of the outer token */
}
/*
* Add size of DER encoded:
* NegTokenTarg [ SEQUENCE ] of
* NegResult[0] ENUMERATED {
* accept_completed(0),
* accept_incomplete(1),
* reject(2) }
* supportedMech [1] MechType OPTIONAL,
* responseToken [2] OCTET STRING OPTIONAL,
* mechListMIC [3] OCTET STRING OPTIONAL
*
* size = data->length + MechListMic + SupportedMech len +
* Result Length + ASN.1 overhead
*/
/*
* NegotiationToken [ CHOICE ]{
* negTokenInit [0] NegTokenInit,
* negTokenTarg [1] NegTokenTarg }
*/
if (t == NULL) {
goto errout;
}
ptr = t;
/*
* Indicate that we are sending CHOICE 1
* (NegTokenTarg)
*/
goto errout;
}
goto errout;
}
/*
* First field of the NegTokenTarg SEQUENCE
* is the ENUMERATED NegResult.
*/
goto errout;
}
goto errout;
}
if (sendtoken == INIT_TOKEN_SEND) {
/*
* Next, is the Supported MechType
*/
&ptr,
goto errout;
}
goto errout;
}
}
goto errout;
}
goto errout;
}
}
if (mechListMIC != NULL) {
goto errout;
}
goto errout;
}
}
if (ret != GSS_S_COMPLETE) {
if (t)
free(t);
} else {
}
return (ret);
}
/* determine size of token */
static int
{
int hdrsize;
/*
* Initialize the header size to the
* MECH_OID byte + the bytes needed to indicate the
* length of the OID + the OID itself.
*
* 0x06 [MECHLENFIELD] MECHDATA
*/
/*
* Now add the bytes needed for the initial header
* token bytes:
* 0x60 + [DER_LEN] + HDRSIZE
*/
}
/*
* generate token header.
*
* Use DER Definite Length method per RFC2478
* Use of indefinite length encoding will not be compatible
* with Microsoft or others that actually follow the spec.
*/
static int
unsigned int body_size,
unsigned char **buf,
unsigned int totallen)
{
int ret = 0;
unsigned int hdrsize;
unsigned char *p = *buf;
return (ret);
return (ret);
return (0);
}
/*
* NOTE: This checks that the length returned by
* gssint_get_der_length() is not greater than the number of octets
* remaining, even though gssint_get_der_length() already checks, in
* theory.
*/
static int
{
unsigned int encoded_len;
unsigned int tmplen = 0;
*outlen = 0;
ptr++;
&encoded_len);
if (tmplen < 0) {
ret = -1;
ret = -1;
} else
ret = 0;
}
return (ret);
}
static int
{
unsigned int seqsize;
int ret = 0;
unsigned int bytes;
/*
* Verify this is a NegotiationToken type token
* - check for a0(context specific identifier)
* - get length and verify that enoughd ata exists
*/
return (G_BAD_TOK_HEADER);
/*
* Verify the next piece, it should identify this as
* a strucure of type NegTokenInit.
*/
return (G_BAD_TOK_HEADER);
/*
* Make sure we have the entire buffer as described
*/
return (G_BAD_TOK_HEADER);
} else {
return (G_BAD_TOK_HEADER);
}
/*
* Verify that the first blob is a sequence of mechTypes
*/
return (G_BAD_TOK_HEADER);
/*
* Make sure we have the entire buffer as described
*/
return (G_BAD_TOK_HEADER);
} else {
return (G_BAD_TOK_HEADER);
}
/*
* At this point, *buf should be at the beginning of the
* DER encoded list of mech types that are to be negotiated.
*/
return (ret);
}
/* verify token header. */
static int
unsigned int *body_size,
unsigned char **buf_in,
int tok_type,
unsigned int toksize)
{
int seqsize;
int ret = 0;
unsigned int bytes;
if (toksize-- < 1)
return (G_BAD_TOK_HEADER);
return (G_BAD_TOK_HEADER);
return (G_BAD_TOK_HEADER);
return (G_BAD_TOK_HEADER);
if (toksize-- < 1)
return (G_BAD_TOK_HEADER);
return (G_BAD_TOK_HEADER);
if (toksize-- < 1)
return (G_BAD_TOK_HEADER);
return (G_BAD_TOK_HEADER);
else
ret = G_WRONG_MECH;
/*
* G_WRONG_MECH is not returned immediately because it's more important
* to return G_BAD_TOK_HEADER if the token header is in fact bad
*/
if (toksize < 2)
return (G_BAD_TOK_HEADER);
else
toksize -= 2;
if (!ret) {
}
return (ret);
}
/*
* Return non-zero if the oid is one of the kerberos mech oids,
* otherwise return zero.
*
* N.B. There are 3 oids that represent the kerberos mech:
* RFC-specified GSS_MECH_KRB5_OID,
* Old pre-RFC GSS_MECH_KRB5_OLD_OID,
* Incorrect MS GSS_MECH_KRB5_WRONG_OID
*/
static int
{
int answer = 0;
extern const gss_OID_set_desc * const gss_mech_set_krb5_both;
(void) gss_test_oid_set_member(&minor,
return (answer);
}