gssapi: credential store extensions (#451)
Implement the GSS-API credential store API extensions defined by MIT here: https://k5wiki.kerberos.org/wiki/Projects/Credential_Store_extensions Note: we kill off gss_acquire_cred_ext() here. This was never a public API, although mechanisms could have implemented it and I briefly used it in my BrowserID prototype mechanism. gss_acquire_cred_ext_from() occupies the place in the dispatch table where gss_acquire_cred_ext() used to, but this structure was never visible outside Heimdal (i.e. it is only used by internal mechanisms); (Mechanisms that need to accept arbitrary key/value dictionaries from applications should now implement gss_acquire_cred_from().)
This commit is contained in:

committed by
Nico Williams

parent
a7d42cdf6b
commit
e0bb9c10ca
@@ -33,6 +33,44 @@
|
||||
|
||||
#include "gsskrb5_locl.h"
|
||||
|
||||
/*
|
||||
* Find an element in a cred store. Returns GSS_S_COMPLETE if the cred store
|
||||
* is absent or well formed, irrespective of whether the element exists. The
|
||||
* caller should check for *value != NULL before using; values are typically
|
||||
* optional, hence this behavior. (The caller should validate the return
|
||||
* value at least once though, to check it is well-formed.)
|
||||
*/
|
||||
OM_uint32
|
||||
__gsskrb5_cred_store_find(OM_uint32 *minor_status,
|
||||
gss_const_key_value_set_t cred_store,
|
||||
const char *key,
|
||||
const char **value)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
*value = NULL;
|
||||
|
||||
if (cred_store == GSS_C_NO_CRED_STORE)
|
||||
return GSS_S_COMPLETE;
|
||||
else if (cred_store->count == 0) {
|
||||
*minor_status = GSS_KRB5_S_G_BAD_USAGE;
|
||||
return GSS_S_NO_CRED;
|
||||
}
|
||||
|
||||
for (i = 0; i < cred_store->count; i++) {
|
||||
if (strcmp(key, cred_store->elements[i].key) == 0) {
|
||||
if (*value) {
|
||||
*value = NULL;
|
||||
*minor_status = GSS_KRB5_S_G_BAD_USAGE;
|
||||
return GSS_S_DUPLICATE_ELEMENT;
|
||||
}
|
||||
*value = cred_store->elements[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
return GSS_S_COMPLETE;
|
||||
}
|
||||
|
||||
OM_uint32
|
||||
__gsskrb5_ccache_lifetime(OM_uint32 *minor_status,
|
||||
krb5_context context,
|
||||
@@ -58,13 +96,21 @@ __gsskrb5_ccache_lifetime(OM_uint32 *minor_status,
|
||||
|
||||
|
||||
static krb5_error_code
|
||||
get_system_keytab(krb5_context context, krb5_keytab *keytab)
|
||||
get_system_keytab(krb5_context context,
|
||||
gss_const_key_value_set_t cred_store,
|
||||
krb5_keytab *keytab)
|
||||
{
|
||||
krb5_error_code kret;
|
||||
const char *cs_ktname;
|
||||
OM_uint32 tmp;
|
||||
|
||||
__gsskrb5_cred_store_find(&tmp, cred_store, "keytab", &cs_ktname);
|
||||
|
||||
HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
|
||||
|
||||
if (_gsskrb5_keytab != NULL) {
|
||||
if (cs_ktname)
|
||||
kret = krb5_kt_resolve(context, cs_ktname, keytab);
|
||||
else if (_gsskrb5_keytab != NULL) {
|
||||
char *name = NULL;
|
||||
|
||||
kret = krb5_kt_get_full_name(context, _gsskrb5_keytab, &name);
|
||||
@@ -82,15 +128,26 @@ get_system_keytab(krb5_context context, krb5_keytab *keytab)
|
||||
|
||||
static krb5_error_code
|
||||
get_client_keytab(krb5_context context,
|
||||
gss_const_key_value_set_t cred_store,
|
||||
krb5_const_principal principal,
|
||||
krb5_keytab *keytab)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
char *name = NULL;
|
||||
const char *cs_ktname;
|
||||
OM_uint32 tmp;
|
||||
|
||||
__gsskrb5_cred_store_find(&tmp, cred_store, "client_keytab", &cs_ktname);
|
||||
|
||||
if (cs_ktname)
|
||||
ret = krb5_kt_resolve(context, cs_ktname, keytab);
|
||||
else {
|
||||
char *name = NULL;
|
||||
ret = _krb5_kt_client_default_name(context, &name);
|
||||
if (ret == 0)
|
||||
ret = krb5_kt_resolve(context, name, keytab);
|
||||
krb5_xfree(name);
|
||||
}
|
||||
|
||||
ret = _krb5_kt_client_default_name(context, &name);
|
||||
if (ret == 0)
|
||||
ret = krb5_kt_resolve(context, name, keytab);
|
||||
if (ret == 0 && principal) {
|
||||
krb5_keytab_entry entry;
|
||||
|
||||
@@ -99,14 +156,31 @@ get_client_keytab(krb5_context context,
|
||||
if (ret == 0)
|
||||
krb5_kt_free_entry(context, &entry);
|
||||
}
|
||||
krb5_xfree(name);
|
||||
|
||||
if (ret)
|
||||
ret = get_system_keytab(context, keytab);
|
||||
ret = get_system_keytab(context, GSS_C_NO_CRED_STORE, keytab);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_boolean
|
||||
is_valid_password_cred_store(gss_const_key_value_set_t cred_store)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (cred_store == GSS_C_NO_CRED_STORE)
|
||||
return TRUE;
|
||||
|
||||
/* XXX don't check keytab, someday we will allow password+acceptor creds */
|
||||
for (i = 0; i < cred_store->count; i++) {
|
||||
if (strcmp(cred_store->elements[i].key, "ccache") == 0 ||
|
||||
strcmp(cred_store->elements[i].key, "client_keytab") == 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function produces a cred with a MEMORY ccache containing a TGT
|
||||
* acquired with a password.
|
||||
@@ -116,8 +190,9 @@ acquire_cred_with_password(OM_uint32 *minor_status,
|
||||
krb5_context context,
|
||||
const char *password,
|
||||
OM_uint32 time_req,
|
||||
gss_const_OID desired_mech,
|
||||
gss_OID_set desired_mechs,
|
||||
gss_cred_usage_t cred_usage,
|
||||
gss_const_key_value_set_t cred_store,
|
||||
gsskrb5_cred handle)
|
||||
{
|
||||
OM_uint32 ret = GSS_S_FAILURE;
|
||||
@@ -128,6 +203,11 @@ acquire_cred_with_password(OM_uint32 *minor_status,
|
||||
time_t now;
|
||||
OM_uint32 left;
|
||||
|
||||
if (!is_valid_password_cred_store(cred_store)) {
|
||||
*minor_status = GSS_KRB5_S_G_BAD_PASSWORD_CRED_STORE;
|
||||
return GSS_S_NO_CRED;
|
||||
}
|
||||
|
||||
if (cred_usage == GSS_C_ACCEPT) {
|
||||
/*
|
||||
* TODO: Here we should eventually support user2user (when we get
|
||||
@@ -212,11 +292,12 @@ static OM_uint32
|
||||
acquire_initiator_cred(OM_uint32 *minor_status,
|
||||
krb5_context context,
|
||||
OM_uint32 time_req,
|
||||
gss_const_OID desired_mech,
|
||||
gss_OID_set desired_mechs,
|
||||
gss_cred_usage_t cred_usage,
|
||||
gss_const_key_value_set_t cred_store,
|
||||
gsskrb5_cred handle)
|
||||
{
|
||||
OM_uint32 ret = GSS_S_FAILURE;
|
||||
OM_uint32 ret;
|
||||
krb5_creds cred;
|
||||
krb5_get_init_creds_opt *opt;
|
||||
krb5_principal def_princ = NULL;
|
||||
@@ -225,11 +306,19 @@ acquire_initiator_cred(OM_uint32 *minor_status,
|
||||
krb5_keytab keytab = NULL;
|
||||
krb5_error_code kret = 0;
|
||||
OM_uint32 left;
|
||||
const char *cs_ccache_name;
|
||||
time_t lifetime = 0;
|
||||
time_t now;
|
||||
|
||||
memset(&cred, 0, sizeof(cred));
|
||||
|
||||
ret = __gsskrb5_cred_store_find(minor_status, cred_store,
|
||||
"ccache", &cs_ccache_name);
|
||||
if (GSS_ERROR(ret))
|
||||
return ret;
|
||||
|
||||
ret = GSS_S_FAILURE;
|
||||
|
||||
/*
|
||||
* Get current time early so we can set handle->endtime to a value that
|
||||
* cannot accidentally be past the real endtime. We need a variant of
|
||||
@@ -239,7 +328,8 @@ acquire_initiator_cred(OM_uint32 *minor_status,
|
||||
|
||||
/*
|
||||
* First look for a ccache that has the desired_name (which may be
|
||||
* the default credential name).
|
||||
* the default credential name), unless a specific credential cache
|
||||
* was included in cred_store.
|
||||
*
|
||||
* If we don't have an unexpired credential, acquire one with a
|
||||
* keytab.
|
||||
@@ -250,7 +340,7 @@ acquire_initiator_cred(OM_uint32 *minor_status,
|
||||
* If we don't have any such ccache, then use a MEMORY ccache.
|
||||
*/
|
||||
|
||||
if (handle->principal != NULL) {
|
||||
if (handle->principal != NULL && cs_ccache_name == NULL) {
|
||||
/*
|
||||
* Not default credential case. See if we can find a ccache in
|
||||
* the cccol for the desired_name.
|
||||
@@ -277,7 +367,10 @@ acquire_initiator_cred(OM_uint32 *minor_status,
|
||||
* Either desired_name was GSS_C_NO_NAME (default cred) or
|
||||
* krb5_cc_cache_match() failed (or found expired).
|
||||
*/
|
||||
kret = krb5_cc_default(context, &def_ccache);
|
||||
if (cs_ccache_name)
|
||||
kret = krb5_cc_resolve(context, cs_ccache_name, &def_ccache);
|
||||
else
|
||||
kret = krb5_cc_default(context, &def_ccache);
|
||||
if (kret != 0)
|
||||
goto try_keytab;
|
||||
kret = krb5_cc_get_lifetime(context, def_ccache, &lifetime);
|
||||
@@ -319,7 +412,7 @@ try_keytab:
|
||||
if (kret)
|
||||
goto end;
|
||||
}
|
||||
kret = get_client_keytab(context, handle->principal, &keytab);
|
||||
kret = get_client_keytab(context, cred_store, handle->principal, &keytab);
|
||||
if (kret)
|
||||
goto end;
|
||||
|
||||
@@ -398,8 +491,9 @@ static OM_uint32
|
||||
acquire_acceptor_cred(OM_uint32 * minor_status,
|
||||
krb5_context context,
|
||||
OM_uint32 time_req,
|
||||
gss_const_OID desired_mech,
|
||||
gss_OID_set desired_mechs,
|
||||
gss_cred_usage_t cred_usage,
|
||||
gss_const_key_value_set_t cred_store,
|
||||
gsskrb5_cred handle)
|
||||
{
|
||||
OM_uint32 ret;
|
||||
@@ -407,7 +501,7 @@ acquire_acceptor_cred(OM_uint32 * minor_status,
|
||||
|
||||
ret = GSS_S_FAILURE;
|
||||
|
||||
kret = get_system_keytab(context, &handle->keytab);
|
||||
kret = get_system_keytab(context, cred_store, &handle->keytab);
|
||||
if (kret)
|
||||
goto end;
|
||||
|
||||
@@ -449,18 +543,23 @@ end:
|
||||
return (ret);
|
||||
}
|
||||
|
||||
OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred
|
||||
|
||||
OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_from
|
||||
(OM_uint32 * minor_status,
|
||||
gss_const_name_t desired_name,
|
||||
OM_uint32 time_req,
|
||||
const gss_OID_set desired_mechs,
|
||||
gss_OID_set desired_mechs,
|
||||
gss_cred_usage_t cred_usage,
|
||||
gss_const_key_value_set_t cred_store,
|
||||
gss_cred_id_t * output_cred_handle,
|
||||
gss_OID_set * actual_mechs,
|
||||
OM_uint32 * time_rec
|
||||
gss_OID_set *actual_mechs,
|
||||
OM_uint32 *time_rec
|
||||
)
|
||||
{
|
||||
krb5_context context;
|
||||
gsskrb5_cred handle;
|
||||
OM_uint32 ret;
|
||||
const char *password = NULL;
|
||||
|
||||
if (desired_mechs) {
|
||||
int present = 0;
|
||||
@@ -475,43 +574,6 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred
|
||||
}
|
||||
}
|
||||
|
||||
ret = _gsskrb5_acquire_cred_ext(minor_status,
|
||||
desired_name,
|
||||
GSS_C_NO_OID,
|
||||
NULL,
|
||||
time_req,
|
||||
GSS_KRB5_MECHANISM,
|
||||
cred_usage,
|
||||
output_cred_handle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
ret = _gsskrb5_inquire_cred(minor_status, *output_cred_handle,
|
||||
NULL, time_rec, NULL, actual_mechs);
|
||||
if (ret) {
|
||||
OM_uint32 tmp;
|
||||
_gsskrb5_release_cred(&tmp, output_cred_handle);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext
|
||||
(OM_uint32 * minor_status,
|
||||
gss_const_name_t desired_name,
|
||||
gss_const_OID credential_type,
|
||||
const void *credential_data,
|
||||
OM_uint32 time_req,
|
||||
gss_const_OID desired_mech,
|
||||
gss_cred_usage_t cred_usage,
|
||||
gss_cred_id_t * output_cred_handle
|
||||
)
|
||||
{
|
||||
krb5_context context;
|
||||
gsskrb5_cred handle;
|
||||
OM_uint32 ret;
|
||||
|
||||
cred_usage &= GSS_C_OPTION_MASK;
|
||||
|
||||
if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE &&
|
||||
@@ -520,6 +582,11 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
ret = __gsskrb5_cred_store_find(minor_status, cred_store,
|
||||
"password", &password);
|
||||
if (GSS_ERROR(ret))
|
||||
return ret;
|
||||
|
||||
GSSAPI_KRB5_INIT(&context);
|
||||
|
||||
*output_cred_handle = GSS_C_NO_CREDENTIAL;
|
||||
@@ -542,57 +609,24 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext
|
||||
}
|
||||
}
|
||||
|
||||
if (credential_type != GSS_C_NO_OID &&
|
||||
gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) {
|
||||
/* Acquire a cred with a password */
|
||||
gss_const_buffer_t pwbuf = credential_data;
|
||||
char *pw;
|
||||
|
||||
if (pwbuf == NULL) {
|
||||
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
|
||||
free(handle);
|
||||
*minor_status = KRB5_NOCREDS_SUPPLIED; /* see below */
|
||||
return GSS_S_CALL_INACCESSIBLE_READ;
|
||||
}
|
||||
|
||||
/* NUL-terminate the password, if it wasn't already */
|
||||
pw = strndup(pwbuf->value, pwbuf->length);
|
||||
if (pw == NULL) {
|
||||
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
|
||||
free(handle);
|
||||
*minor_status = krb5_enomem(context);
|
||||
return GSS_S_CALL_INACCESSIBLE_READ;
|
||||
}
|
||||
ret = acquire_cred_with_password(minor_status, context, pw, time_req,
|
||||
desired_mech, cred_usage, handle);
|
||||
free(pw);
|
||||
if (password) {
|
||||
ret = acquire_cred_with_password(minor_status, context, password, time_req,
|
||||
desired_mechs, cred_usage, cred_store, handle);
|
||||
if (ret != GSS_S_COMPLETE) {
|
||||
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
|
||||
krb5_free_principal(context, handle->principal);
|
||||
free(handle);
|
||||
return (ret);
|
||||
}
|
||||
} else if (credential_type != GSS_C_NO_OID) {
|
||||
/*
|
||||
* _gss_acquire_cred_ext() called with something other than a password.
|
||||
*
|
||||
* Not supported.
|
||||
*
|
||||
* _gss_acquire_cred_ext() is not a supported public interface, so
|
||||
* we don't have to try too hard as to minor status codes here.
|
||||
*/
|
||||
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
|
||||
free(handle);
|
||||
*minor_status = ENOTSUP;
|
||||
return GSS_S_FAILURE;
|
||||
} else {
|
||||
/*
|
||||
* Acquire a credential from the background credential store (ccache,
|
||||
* keytab).
|
||||
* Acquire a credential from the specified or background credential
|
||||
* store (ccache, keytab).
|
||||
*/
|
||||
if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
|
||||
ret = acquire_initiator_cred(minor_status, context, time_req,
|
||||
desired_mech, cred_usage, handle);
|
||||
desired_mechs, cred_usage,
|
||||
cred_store, handle);
|
||||
if (ret != GSS_S_COMPLETE) {
|
||||
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
|
||||
krb5_free_principal(context, handle->principal);
|
||||
@@ -602,7 +636,8 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext
|
||||
}
|
||||
if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) {
|
||||
ret = acquire_acceptor_cred(minor_status, context, time_req,
|
||||
desired_mech, cred_usage, handle);
|
||||
desired_mechs, cred_usage,
|
||||
cred_store, handle);
|
||||
if (ret != GSS_S_COMPLETE) {
|
||||
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
|
||||
krb5_free_principal(context, handle->principal);
|
||||
@@ -615,6 +650,10 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext
|
||||
if (ret == GSS_S_COMPLETE)
|
||||
ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
|
||||
&handle->mechanisms);
|
||||
handle->usage = cred_usage;
|
||||
if (ret == GSS_S_COMPLETE)
|
||||
ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)handle,
|
||||
NULL, time_rec, NULL, actual_mechs);
|
||||
if (ret != GSS_S_COMPLETE) {
|
||||
if (handle->mechanisms != NULL)
|
||||
gss_release_oid_set(NULL, &handle->mechanisms);
|
||||
@@ -623,7 +662,6 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext
|
||||
free(handle);
|
||||
return (ret);
|
||||
}
|
||||
handle->usage = cred_usage;
|
||||
*minor_status = 0;
|
||||
*output_cred_handle = (gss_cred_id_t)handle;
|
||||
return (GSS_S_COMPLETE);
|
||||
|
@@ -33,14 +33,15 @@
|
||||
|
||||
#include "gsskrb5_locl.h"
|
||||
|
||||
OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred (
|
||||
OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred_from (
|
||||
OM_uint32 *minor_status,
|
||||
gss_const_cred_id_t input_cred_handle,
|
||||
gss_cred_id_t input_cred_handle,
|
||||
gss_const_name_t desired_name,
|
||||
const gss_OID desired_mech,
|
||||
gss_cred_usage_t cred_usage,
|
||||
OM_uint32 initiator_time_req,
|
||||
OM_uint32 acceptor_time_req,
|
||||
gss_const_key_value_set_t cred_store,
|
||||
gss_cred_id_t *output_cred_handle,
|
||||
gss_OID_set *actual_mechs,
|
||||
OM_uint32 *initiator_time_rec,
|
||||
@@ -75,13 +76,14 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred (
|
||||
heim_assert(output_cred_handle != NULL,
|
||||
"internal error in _gsskrb5_add_cred()");
|
||||
|
||||
major = _gsskrb5_acquire_cred(minor_status, desired_name,
|
||||
min(initiator_time_req,
|
||||
acceptor_time_req),
|
||||
GSS_C_NO_OID_SET,
|
||||
cred_usage,
|
||||
output_cred_handle,
|
||||
actual_mechs, &lifetime);
|
||||
major = _gsskrb5_acquire_cred_from(minor_status, desired_name,
|
||||
min(initiator_time_req,
|
||||
acceptor_time_req),
|
||||
GSS_C_NO_OID_SET,
|
||||
cred_usage,
|
||||
cred_store,
|
||||
output_cred_handle,
|
||||
actual_mechs, &lifetime);
|
||||
if (major != GSS_S_COMPLETE)
|
||||
goto failure;
|
||||
|
||||
|
@@ -53,12 +53,13 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_duplicate_cred (
|
||||
|
||||
if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
|
||||
/* Duplicate the default credential */
|
||||
return _gsskrb5_acquire_cred(minor_status, GSS_C_NO_NAME,
|
||||
GSS_C_INDEFINITE,
|
||||
GSS_C_NO_OID_SET,
|
||||
GSS_C_BOTH,
|
||||
output_cred_handle,
|
||||
NULL, NULL);
|
||||
return _gsskrb5_acquire_cred_from(minor_status, GSS_C_NO_NAME,
|
||||
GSS_C_INDEFINITE,
|
||||
GSS_C_NO_OID_SET,
|
||||
GSS_C_BOTH,
|
||||
GSS_C_NO_CRED_STORE,
|
||||
output_cred_handle,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
/* Duplicate the input credential */
|
||||
|
@@ -339,7 +339,7 @@ static gssapi_mech_interface_desc krb5_mech = {
|
||||
"kerberos 5",
|
||||
{9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") },
|
||||
0,
|
||||
_gsskrb5_acquire_cred,
|
||||
NULL, /* gm_acquire_cred */
|
||||
_gsskrb5_release_cred,
|
||||
_gsskrb5_init_sec_context,
|
||||
_gsskrb5_accept_sec_context,
|
||||
@@ -360,7 +360,7 @@ static gssapi_mech_interface_desc krb5_mech = {
|
||||
_gsskrb5_inquire_cred,
|
||||
_gsskrb5_inquire_context,
|
||||
_gsskrb5_wrap_size_limit,
|
||||
_gsskrb5_add_cred,
|
||||
NULL, /* gm_add_cred */
|
||||
_gsskrb5_inquire_cred_by_mech,
|
||||
_gsskrb5_export_sec_context,
|
||||
_gsskrb5_import_sec_context,
|
||||
@@ -376,10 +376,10 @@ static gssapi_mech_interface_desc krb5_mech = {
|
||||
_gk_wrap_iov,
|
||||
_gk_unwrap_iov,
|
||||
_gk_wrap_iov_length,
|
||||
_gsskrb5_store_cred,
|
||||
NULL, /* gm_store_cred */
|
||||
_gsskrb5_export_cred,
|
||||
_gsskrb5_import_cred,
|
||||
_gsskrb5_acquire_cred_ext,
|
||||
_gsskrb5_acquire_cred_from,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -397,6 +397,8 @@ static gssapi_mech_interface_desc krb5_mech = {
|
||||
NULL, /* gm_delete_name_attribute */
|
||||
NULL, /* gm_export_name_composite */
|
||||
_gsskrb5_duplicate_cred,
|
||||
_gsskrb5_add_cred_from,
|
||||
_gsskrb5_store_cred_into,
|
||||
NULL /* gm_compat */
|
||||
};
|
||||
|
||||
|
@@ -17,6 +17,8 @@ error_code G_BAD_MSG_CTX, "Message context invalid"
|
||||
error_code G_WRONG_SIZE, "Buffer is the wrong size"
|
||||
error_code G_BAD_USAGE, "Credential usage type is unknown"
|
||||
error_code G_UNKNOWN_QOP, "Unknown quality of protection specified"
|
||||
error_code G_UNKNOWN_CRED_STORE_ELEMENT, "Credential store contained unknown elements"
|
||||
error_code G_BAD_PASSWORD_CRED_STORE, "Credential store cannot contain both a password and a credentials cache or client keytab"
|
||||
|
||||
index 128
|
||||
|
||||
|
@@ -80,14 +80,15 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred
|
||||
* function.
|
||||
*/
|
||||
/* Get the info for the default ACCEPT credential */
|
||||
aret = _gsskrb5_acquire_cred(&aminor,
|
||||
GSS_C_NO_NAME,
|
||||
GSS_C_INDEFINITE,
|
||||
GSS_C_NO_OID_SET,
|
||||
GSS_C_ACCEPT,
|
||||
&aqcred_accept,
|
||||
NULL,
|
||||
NULL);
|
||||
aret = _gsskrb5_acquire_cred_from(&aminor,
|
||||
GSS_C_NO_NAME,
|
||||
GSS_C_INDEFINITE,
|
||||
GSS_C_NO_OID_SET,
|
||||
GSS_C_ACCEPT,
|
||||
GSS_C_NO_CRED_STORE,
|
||||
&aqcred_accept,
|
||||
NULL,
|
||||
NULL);
|
||||
if (aret == GSS_S_COMPLETE) {
|
||||
aret = _gsskrb5_inquire_cred(&aminor,
|
||||
aqcred_accept,
|
||||
@@ -116,14 +117,15 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred
|
||||
}
|
||||
|
||||
/* Get the info for the default INITIATE credential */
|
||||
ret = _gsskrb5_acquire_cred(minor_status,
|
||||
GSS_C_NO_NAME,
|
||||
GSS_C_INDEFINITE,
|
||||
GSS_C_NO_OID_SET,
|
||||
GSS_C_INITIATE,
|
||||
&aqcred_init,
|
||||
NULL,
|
||||
NULL);
|
||||
ret = _gsskrb5_acquire_cred_from(minor_status,
|
||||
GSS_C_NO_NAME,
|
||||
GSS_C_INDEFINITE,
|
||||
GSS_C_NO_OID_SET,
|
||||
GSS_C_INITIATE,
|
||||
GSS_C_NO_CRED_STORE,
|
||||
&aqcred_init,
|
||||
NULL,
|
||||
NULL);
|
||||
if (ret == GSS_S_COMPLETE) {
|
||||
ret = _gsskrb5_inquire_cred(minor_status,
|
||||
aqcred_init,
|
||||
|
@@ -34,23 +34,25 @@
|
||||
#include "gsskrb5_locl.h"
|
||||
|
||||
OM_uint32 GSSAPI_CALLCONV
|
||||
_gsskrb5_store_cred(OM_uint32 *minor_status,
|
||||
gss_cred_id_t input_cred_handle,
|
||||
gss_cred_usage_t cred_usage,
|
||||
const gss_OID desired_mech,
|
||||
OM_uint32 overwrite_cred,
|
||||
OM_uint32 default_cred,
|
||||
gss_OID_set *elements_stored,
|
||||
gss_cred_usage_t *cred_usage_stored)
|
||||
_gsskrb5_store_cred_into(OM_uint32 *minor_status,
|
||||
gss_const_cred_id_t input_cred_handle,
|
||||
gss_cred_usage_t cred_usage,
|
||||
const gss_OID desired_mech,
|
||||
OM_uint32 overwrite_cred,
|
||||
OM_uint32 default_cred,
|
||||
gss_const_key_value_set_t cred_store,
|
||||
gss_OID_set *elements_stored,
|
||||
gss_cred_usage_t *cred_usage_stored)
|
||||
{
|
||||
krb5_context context;
|
||||
krb5_error_code ret;
|
||||
gsskrb5_cred cred;
|
||||
krb5_ccache id = NULL;
|
||||
krb5_ccache def_ccache = NULL;
|
||||
const char *def_type = NULL;
|
||||
time_t exp_current;
|
||||
time_t exp_new;
|
||||
const char *cs_ccache_name = NULL;
|
||||
OM_uint32 major_status;
|
||||
|
||||
*minor_status = 0;
|
||||
|
||||
@@ -89,38 +91,47 @@ _gsskrb5_store_cred(OM_uint32 *minor_status,
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
ret = krb5_cc_default(context, &def_ccache);
|
||||
if (ret == 0) {
|
||||
def_type = krb5_cc_get_type(context, def_ccache);
|
||||
krb5_cc_close(context, def_ccache);
|
||||
if (cred_store != GSS_C_NO_CRED_STORE) {
|
||||
major_status = __gsskrb5_cred_store_find(minor_status, cred_store,
|
||||
"ccache", &cs_ccache_name);
|
||||
if (major_status == GSS_S_COMPLETE && cs_ccache_name == NULL) {
|
||||
*minor_status = GSS_KRB5_S_G_UNKNOWN_CRED_STORE_ELEMENT;
|
||||
major_status = GSS_S_NO_CRED;
|
||||
}
|
||||
if (GSS_ERROR(major_status)) {
|
||||
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
|
||||
return major_status;
|
||||
}
|
||||
}
|
||||
def_ccache = NULL;
|
||||
|
||||
/* write out cred to credential cache */
|
||||
ret = krb5_cc_cache_match(context, cred->principal, &id);
|
||||
if (ret) {
|
||||
if (default_cred) {
|
||||
ret = krb5_cc_default(context, &id);
|
||||
if (ret) {
|
||||
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
|
||||
*minor_status = ret;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
} else {
|
||||
if (def_type == NULL ||
|
||||
!krb5_cc_support_switch(context, def_type)) {
|
||||
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
|
||||
*minor_status = 0; /* XXX */
|
||||
return GSS_S_NO_CRED; /* XXX */
|
||||
}
|
||||
ret = krb5_cc_new_unique(context, def_type, NULL, &id);
|
||||
if (ret) {
|
||||
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
|
||||
*minor_status = ret;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
overwrite_cred = 1;
|
||||
}
|
||||
if (cs_ccache_name)
|
||||
ret = krb5_cc_resolve(context, cs_ccache_name, &id);
|
||||
else {
|
||||
krb5_ccache def_ccache = NULL;
|
||||
|
||||
if (krb5_cc_default(context, &def_ccache) == 0) {
|
||||
def_type = krb5_cc_get_type(context, def_ccache);
|
||||
krb5_cc_close(context, def_ccache);
|
||||
}
|
||||
|
||||
/* write out cred to credential cache */
|
||||
ret = krb5_cc_cache_match(context, cred->principal, &id);
|
||||
if (ret) {
|
||||
if (default_cred)
|
||||
ret = krb5_cc_default(context, &id);
|
||||
else if (def_type &&
|
||||
krb5_cc_support_switch(context, def_type)) {
|
||||
ret = krb5_cc_new_unique(context, def_type, NULL, &id);
|
||||
overwrite_cred = 1;
|
||||
} else
|
||||
ret = 0; /* == GSS_C_NO_CRED */
|
||||
}
|
||||
}
|
||||
|
||||
if (ret || id == NULL) {
|
||||
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
|
||||
*minor_status = ret;
|
||||
return ret == 0 ? GSS_S_NO_CRED : GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
if (!overwrite_cred) {
|
||||
|
Reference in New Issue
Block a user