frobbing the contents.
Also added krb5_gss_validate_cred_1, which is like krb5_gss_validate_cred but
for internal use. It lets the caller supply the krb5_context instead of
creating yet another one locally, and leaves the new credential mutex locked on
a successful return so that the caller doesn't have to reacquire it. More
functions should be changed to use this internally, but it's a performance
issue; I don't think it's a correctness or thread-safety issue.
* gssapiP_krb5.h (struct _krb5_gss_cred_id_rec): Add a mutex.
(krb5_gss_validate_cred_1): Declare.
* accept_sec_context.c (rd_and_store_for_creds): Initialize mutex.
* acquire_cred.c (krb5_gss_acquire_cred): Initialize mutex.
* add_cred.c (krb5_gss_add_cred): Create the krb5 context earlier. Call
krb5_gss_validate_cred_1. Make sure the mutex is locked.
* copy_ccache.c (gss_krb5_copy_ccache): Lock the mutex in the source
credential.
* init_sec_context.c (get_credentials, new_connection): Check that the mutex is
locked.
(mutual_auth): Delete unused credential argument.
(krb5_gss_init_sec_context): Lock the mutex.
* inq_cred.c (krb5_gss_inquire_cred): Lock the mutex.
* rel_cred.c (krb5_gss_release_cred): Destroy the mutex.
* set_allowable_enctypes.c (gss_krb5_set_allowable_enctypes): Lock the mutex.
* val_cred.c (krb5_gss_validate_cred_1): New function.
(krb5_gss_validate_cred): Use it.
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@16630
dc483132-0cff-0310-8789-
dd5450dbe970
2004-07-28 Ken Raeburn <raeburn@mit.edu>
+ * gssapiP_krb5.h (struct _krb5_gss_cred_id_rec): Add a mutex.
+ (krb5_gss_validate_cred_1): Declare.
+ * accept_sec_context.c (rd_and_store_for_creds): Initialize mutex.
+ * acquire_cred.c (krb5_gss_acquire_cred): Initialize mutex.
+ * add_cred.c (krb5_gss_add_cred): Create the krb5 context
+ earlier. Call krb5_gss_validate_cred_1. Make sure the mutex is
+ locked.
+ * copy_ccache.c (gss_krb5_copy_ccache): Lock the mutex in the
+ source credential.
+ * init_sec_context.c (get_credentials, new_connection): Check that
+ the mutex is locked.
+ (mutual_auth): Delete unused credential argument.
+ (krb5_gss_init_sec_context): Lock the mutex.
+ * inq_cred.c (krb5_gss_inquire_cred): Lock the mutex.
+ * rel_cred.c (krb5_gss_release_cred): Destroy the mutex.
+ * set_allowable_enctypes.c (gss_krb5_set_allowable_enctypes): Lock
+ the mutex.
+ * val_cred.c (krb5_gss_validate_cred_1): New function, most of old
+ krb5_gss_validate_cred but requires that the krb5 context be
+ supplied, and returns with the credential mutex still locked if
+ successful, so the caller needn't re-lock it.
+ (krb5_gss_validate_cred): Use it.
+
* set_ccache.c (gss_krb5_ccache_name): Don't make a copy of the
string returned by kg_get_ccache_name. Simplify some calls using
a temporary error code variable.
/* zero it out... */
memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
+ retval = k5_mutex_init(&cred->lock);
+ if (retval) {
+ xfree(cred);
+ cred = NULL;
+ goto cleanup;
+ }
+
/* copy the client principle into it... */
if ((retval =
krb5_copy_principal(context, creds[0]->client, &(cred->princ)))) {
+ k5_mutex_destroy(&cred->lock);
retval = ENOMEM; /* out of memory? */
xfree(cred); /* clean up memory on failure */
cred = NULL;
cred->keytab = NULL;
cred->ccache = NULL;
+ code = k5_mutex_init(&cred->lock);
+ if (code) {
+ *minor_status = ret;
+ krb5_free_context(context);
+ return GSS_S_FAILURE;
+ }
+ /* Note that we don't need to lock this GSSAPI credential record
+ here, because no other thread can gain access to it until we
+ return it. */
+
if ((cred_usage != GSS_C_INITIATE) &&
(cred_usage != GSS_C_ACCEPT) &&
(cred_usage != GSS_C_BOTH)) {
return(GSS_S_DUPLICATE_ELEMENT);
}
- /* verify the credential */
- if (GSS_ERROR(major_status =
- krb5_gss_validate_cred(minor_status, input_cred_handle)))
- return(major_status);
+ code = krb5_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ major_status = krb5_gss_validate_cred_1(minor_status, input_cred_handle,
+ context);
+ if (GSS_ERROR(major_status)) {
+ krb5_free_context(context);
+ return major_status;
+ }
cred = (krb5_gss_cred_id_t) input_cred_handle;
+ k5_mutex_assert_locked(&cred->lock);
/* check if the cred_usage is equal or "less" than the passed-in cred
if copying */
((cred->usage == GSS_C_BOTH) &&
(output_cred_handle != NULL)))) {
*minor_status = (OM_uint32) G_BAD_USAGE;
+ krb5_free_context(context);
return(GSS_S_FAILURE);
}
if ((g_OID_equal(desired_mech, gss_mech_krb5_old) && cred->prerfc_mech) ||
(g_OID_equal(desired_mech, gss_mech_krb5) && cred->rfc_mech)) {
*minor_status = 0;
+ krb5_free_context(context);
return(GSS_S_DUPLICATE_ELEMENT);
}
- code = krb5_init_context(&context);
- if (code) {
- *minor_status = code;
+ if (GSS_ERROR(kg_sync_ccache_name(context, minor_status))) {
+ krb5_free_context(context);
return GSS_S_FAILURE;
}
- if (GSS_ERROR(kg_sync_ccache_name(context, minor_status)))
- return GSS_S_FAILURE;
/* verify the desired_name */
return(stat);
k5creds = (krb5_gss_cred_id_t) cred_handle;
+ code = k5_mutex_lock(&k5creds->lock);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
if (k5creds->usage == GSS_C_ACCEPT) {
+ k5_mutex_unlock(&k5creds->lock);
*minor_status = (OM_uint32) G_BAD_USAGE;
return(GSS_S_FAILURE);
}
code = krb5_init_context(&context);
if (code) {
+ k5_mutex_unlock(&k5creds->lock);
*minor_status = code;
return GSS_S_FAILURE;
}
code = krb5_cc_start_seq_get(context, k5creds->ccache, &cursor);
if (code) {
+ k5_mutex_unlock(&k5creds->lock);
*minor_status = code;
krb5_free_context(context);
return(GSS_S_FAILURE);
while (!code && !krb5_cc_next_cred(context, k5creds->ccache, &cursor, &creds))
code = krb5_cc_store_cred(context, out_ccache, &creds);
krb5_cc_end_seq_get(context, k5creds->ccache, &cursor);
-
+ k5_mutex_unlock(&k5creds->lock);
krb5_free_context(context);
if (code) {
*minor_status = code;
typedef krb5_principal krb5_gss_name_t;
typedef struct _krb5_gss_cred_id_rec {
+ /* protect against simultaneous accesses */
+ k5_mutex_t lock;
+
/* name/type of credential */
gss_cred_usage_t usage;
krb5_principal princ; /* this is not interned as a gss_name_t */
gss_cred_id_t /* cred */
);
-gss_OID krb5_gss_convert_static_mech_oid
-(gss_OID oid
- );
+OM_uint32
+krb5_gss_validate_cred_1(OM_uint32 * /* minor_status */,
+ gss_cred_id_t /* cred_handle */,
+ krb5_context /* context */);
+
+gss_OID krb5_gss_convert_static_mech_oid(gss_OID oid);
krb5_error_code gss_krb5int_make_seal_token_v3(krb5_context,
krb5_gss_ctx_id_rec *,
krb5_error_code code;
krb5_creds in_creds;
+ k5_mutex_assert_locked(&cred->lock);
memset((char *) &in_creds, 0, sizeof(krb5_creds));
if ((code = krb5_copy_principal(context, cred->princ, &in_creds.client)))
unsigned char *t;
unsigned int tlen;
-
+ k5_mutex_assert_locked(&cred->lock);
ap_req.data = 0;
/* compute the hash of the channel bindings */
krb5_timestamp now;
gss_buffer_desc token;
+ k5_mutex_assert_locked(&cred->lock);
major_status = GSS_S_FAILURE;
token.length = 0;
token.value = NULL;
static OM_uint32
mutual_auth(
OM_uint32 *minor_status,
- krb5_gss_cred_id_t cred,
gss_ctx_id_t *context_handle,
gss_name_t target_name,
gss_OID mech_type,
}
cred = (krb5_gss_cred_id_t) claimant_cred_handle;
}
+ kerr = k5_mutex_lock(&cred->lock);
+ if (kerr) {
+ krb5_free_context(context);
+ *minor_status = kerr;
+ return GSS_S_FAILURE;
+ }
/* verify the mech_type */
}
if (err) {
+ k5_mutex_unlock(&cred->lock);
if (claimant_cred_handle == GSS_C_NO_CREDENTIAL)
krb5_gss_release_cred(minor_status, (gss_cred_id_t)cred);
*minor_status = 0;
input_token, actual_mech_type,
output_token, ret_flags, time_rec,
context, default_mech);
+ k5_mutex_unlock(&cred->lock);
if (*context_handle == GSS_C_NO_CONTEXT)
krb5_free_context(context);
else
((krb5_gss_ctx_id_rec *) *context_handle)->k5_context = context;
} else {
- major_status = mutual_auth(minor_status, cred, context_handle,
+ /* mutual_auth doesn't care about the credentials */
+ k5_mutex_unlock(&cred->lock);
+ major_status = mutual_auth(minor_status, context_handle,
target_name, mech_type, req_flags,
time_req, input_chan_bindings,
input_token, actual_mech_type,
goto fail;
}
+ code = k5_mutex_lock(&cred->lock);
+ if (code != 0) {
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+ goto fail;
+ }
if (cred->tgt_expire > 0) {
if ((lifetime = cred->tgt_expire - now) < 0)
lifetime = 0;
if (name) {
if (cred->princ &&
(code = krb5_copy_principal(context, cred->princ, &ret_name))) {
+ k5_mutex_unlock(&cred->lock);
*minor_status = code;
ret = GSS_S_FAILURE;
goto fail;
GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
(gss_OID) gss_mech_krb5,
&mechs)))) {
+ k5_mutex_unlock(&cred->lock);
krb5_free_principal(context, ret_name);
/* *minor_status set above */
goto fail;
if (name) {
if (! kg_save_name((gss_name_t) ret_name)) {
+ k5_mutex_unlock(&cred->lock);
(void) gss_release_oid_set(minor_status, &mechs);
krb5_free_principal(context, ret_name);
*minor_status = (OM_uint32) G_VALIDATE_FAILED;
if (cred_usage)
*cred_usage = cred->usage;
+ k5_mutex_unlock(&cred->lock);
if (mechanisms)
*mechanisms = mechs;
cred = *cred_handle;
+ k5_mutex_destroy(&cred->lock);
+ /* ignore error destroying mutex */
+
if (cred->ccache)
code1 = krb5_cc_close(context, cred->ccache);
else
}
}
} else {
+ kerr = k5_mutex_lock(&cred->lock);
+ if (kerr)
+ goto error_out;
if (cred->req_enctypes)
free(cred->req_enctypes);
cred->req_enctypes = NULL;
+ k5_mutex_unlock(&cred->lock);
return GSS_S_COMPLETE;
}
kerr = ENOMEM;
goto error_out;
}
+ kerr = k5_mutex_lock(&cred->lock);
+ if (kerr)
+ goto error_out;
if (cred->req_enctypes)
free(cred->req_enctypes);
cred->req_enctypes = new_ktypes;
+ k5_mutex_unlock(&cred->lock);
/* Success! */
return GSS_S_COMPLETE;
*/
OM_uint32
-krb5_gss_validate_cred(minor_status, cred_handle)
- OM_uint32 *minor_status;
- gss_cred_id_t cred_handle;
+krb5_gss_validate_cred_1(OM_uint32 *minor_status, gss_cred_id_t cred_handle,
+ krb5_context context)
{
- krb5_context context;
krb5_gss_cred_id_t cred;
krb5_error_code code;
krb5_principal princ;
-
- code = krb5_init_context(&context);
- if (code) {
- *minor_status = code;
- return GSS_S_FAILURE;
- }
if (!kg_validate_cred_id(cred_handle)) {
*minor_status = (OM_uint32) G_VALIDATE_FAILED;
- krb5_free_context(context);
return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_DEFECTIVE_CREDENTIAL);
}
cred = (krb5_gss_cred_id_t) cred_handle;
+ code = k5_mutex_lock(&cred->lock);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
if (cred->ccache) {
if ((code = krb5_cc_get_principal(context, cred->ccache, &princ))) {
+ k5_mutex_unlock(&cred->lock);
*minor_status = code;
- krb5_free_context(context);
return(GSS_S_DEFECTIVE_CREDENTIAL);
}
if (!krb5_principal_compare(context, princ, cred->princ)) {
+ k5_mutex_unlock(&cred->lock);
*minor_status = KG_CCACHE_NOMATCH;
- krb5_free_context(context);
return(GSS_S_DEFECTIVE_CREDENTIAL);
}
(void)krb5_free_principal(context, princ);
}
- krb5_free_context(context);
*minor_status = 0;
return GSS_S_COMPLETE;
}
+OM_uint32
+krb5_gss_validate_cred(minor_status, cred_handle)
+ OM_uint32 *minor_status;
+ gss_cred_id_t cred_handle;
+{
+ krb5_context context;
+ krb5_error_code code;
+ OM_uint32 maj;
+
+ code = krb5_init_context(&context);
+ if (code) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ maj = krb5_gss_validate_cred_1(minor_status, cred_handle, context);
+ if (maj == 0) {
+ krb5_gss_cred_id_t cred = (krb5_gss_cred_id_t) cred_handle;
+ k5_mutex_assert_locked(&cred->lock);
+ k5_mutex_unlock(&cred->lock);
+ }
+ krb5_free_context(context);
+ return maj;
+}
+