summaryrefslogtreecommitdiffstats
path: root/src/lib/gssapi
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/gssapi')
-rw-r--r--src/lib/gssapi/krb5/acquire_cred.c117
-rw-r--r--src/lib/gssapi/krb5/gssapiP_krb5.h4
-rw-r--r--src/lib/gssapi/krb5/iakerb.c20
-rw-r--r--src/lib/gssapi/krb5/init_sec_context.c37
-rw-r--r--src/lib/gssapi/krb5/inq_cred.c49
-rw-r--r--src/lib/gssapi/krb5/s4u_gss_glue.c5
6 files changed, 149 insertions, 83 deletions
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
index 50c8ef4ad2..c815b3590a 100644
--- a/src/lib/gssapi/krb5/acquire_cred.c
+++ b/src/lib/gssapi/krb5/acquire_cred.c
@@ -368,12 +368,25 @@ prep_ccache(krb5_context context, krb5_gss_cred_id_rec *cred,
krb5_error_code code;
krb5_principal ccache_princ;
krb5_data password_data = make_data(password->value, password->length);
+ krb5_boolean eq;
+ const char *cctype;
+ krb5_ccache newcache = NULL;
/* Check the ccache principal or initialize a new cache. */
code = krb5_cc_get_principal(context, ccache, &ccache_princ);
if (code == 0) {
- if (!krb5_principal_compare(context, ccache_princ, desired_princ))
- return KG_CCACHE_NOMATCH;
+ eq = krb5_principal_compare(context, ccache_princ, desired_princ);
+ krb5_free_principal(context, ccache_princ);
+ if (!eq) {
+ cctype = krb5_cc_get_type(context, ccache);
+ if (krb5_cc_support_switch(context, cctype)) {
+ /* Make a new ccache within the collection. */
+ code = krb5_cc_new_unique(context, cctype, NULL, &newcache);
+ if (code)
+ return code;
+ } else
+ return KG_CCACHE_NOMATCH;
+ }
} else if (code == KRB5_FCC_NOFILE) {
/* Cache file does not exist; create and initialize one. */
code = krb5_cc_initialize(context, ccache, desired_princ);
@@ -396,7 +409,11 @@ prep_ccache(krb5_context context, krb5_gss_cred_id_rec *cred,
if (code)
return code;
- cred->ccache = ccache;
+ if (newcache) {
+ krb5_cc_close(context, ccache);
+ cred->ccache = newcache;
+ } else
+ cred->ccache = ccache;
return 0;
}
@@ -523,7 +540,13 @@ acquire_init_cred(krb5_context context,
#elif defined(USE_LEASH)
code = get_ccache_leash(context, desired_princ, &ccache);
#else
- code = 0;
+ code = krb5_cc_cache_match(context, desired_princ, &ccache);
+ if (code == KRB5_CC_NOTFOUND && password != GSS_C_NO_BUFFER) {
+ /* Grab the default ccache for now; if it's not empty, prep_ccache
+ * will create a new one of the default type or error out. */
+ krb5_clear_error_message(context);
+ code = krb5_cc_default(context, &ccache);
+ }
#endif
} else
code = 0;
@@ -531,25 +554,26 @@ acquire_init_cred(krb5_context context,
*minor_status = code;
return GSS_S_CRED_UNAVAIL;
}
- if (ccache == NULL) {
- code = krb5int_cc_default(context, &ccache);
+
+ if (ccache != NULL) {
+ if (password != GSS_C_NO_BUFFER && desired_princ != NULL)
+ code = prep_ccache(context, cred, ccache, desired_princ, password);
+ else
+ code = scan_ccache(context, cred, ccache, desired_princ);
if (code != 0) {
+ krb5_cc_close(context, ccache);
*minor_status = code;
return GSS_S_CRED_UNAVAIL;
}
+ cred->ccache = ccache;
}
- if (password != GSS_C_NO_BUFFER && desired_princ != NULL)
- code = prep_ccache(context, cred, ccache, desired_princ, password);
- else
- code = scan_ccache(context, cred, ccache, desired_princ);
- if (code != 0) {
- krb5_cc_close(context, ccache);
- *minor_status = code;
- return GSS_S_CRED_UNAVAIL;
- }
+ /*
+ * If the caller specified no ccache and no desired principal, leave
+ * cred->ccache and cred->name NULL. They will be resolved later by
+ * kg_cred_resolve(), possibly using the target principal name.
+ */
- cred->ccache = ccache;
*minor_status = 0;
return GSS_S_COMPLETE;
}
@@ -692,6 +716,67 @@ error_out:
return ret;
}
+/*
+ * Resolve the name and ccache for an initiator credential if it has not yet
+ * been done. If specified, use the target name to pick an appropriate ccache
+ * within the collection. Validates cred_handle and leaves it locked on
+ * success.
+ */
+OM_uint32
+kg_cred_resolve(OM_uint32 *minor_status, krb5_context context,
+ gss_cred_id_t cred_handle, gss_name_t target_name)
+{
+ OM_uint32 maj;
+ krb5_error_code code;
+ krb5_gss_cred_id_t cred = (krb5_gss_cred_id_t)cred_handle;
+ krb5_gss_name_t tname = (krb5_gss_name_t)target_name;
+ krb5_ccache ccache = NULL;
+ krb5_principal client_princ = NULL;
+
+ *minor_status = 0;
+
+ maj = krb5_gss_validate_cred_1(minor_status, cred_handle, context);
+ if (maj != 0)
+ return maj;
+ k5_mutex_assert_locked(&cred->lock);
+
+ if (cred->ccache != NULL || cred->usage == GSS_C_ACCEPT)
+ return GSS_S_COMPLETE;
+
+ /* Pick a credential cache. */
+ if (tname != NULL) {
+ code = krb5_cc_select(context, tname->princ, &ccache, &client_princ);
+ if (code && code != KRB5_CC_NOTFOUND)
+ goto kerr;
+ }
+ if (ccache == NULL) {
+ /*
+ * Ideally we would get credentials for client_princ if it is set. At
+ * the moment, we just get the default ccache (obtaining credentials if
+ * the platform supports it) and check it against client_princ below.
+ */
+ code = krb5int_cc_default(context, &ccache);
+ if (code)
+ goto kerr;
+ }
+
+ code = scan_ccache(context, cred, ccache, client_princ);
+ if (code) {
+ krb5_cc_close(context, ccache);
+ goto kerr;
+ }
+
+ krb5_free_principal(context, client_princ);
+ return GSS_S_COMPLETE;
+
+kerr:
+ krb5_free_principal(context, client_princ);
+ k5_mutex_unlock(&cred->lock);
+ save_error_info(code, context);
+ *minor_status = code;
+ return GSS_S_CRED_UNAVAIL;
+}
+
OM_uint32
gss_krb5int_set_cred_rcache(OM_uint32 *minor_status,
gss_cred_id_t *cred_handle,
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index f7aab88b82..08155e820f 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -478,6 +478,10 @@ krb5_to_gss_cred(krb5_context context,
krb5_creds *creds,
krb5_gss_cred_id_t *out_cred);
+OM_uint32
+kg_cred_resolve(OM_uint32 *minor_status, krb5_context context,
+ gss_cred_id_t cred_handle, gss_name_t target_name);
+
/** declarations of internal name mechanism functions **/
OM_uint32 KRB5_CALLCONV krb5_gss_acquire_cred
diff --git a/src/lib/gssapi/krb5/iakerb.c b/src/lib/gssapi/krb5/iakerb.c
index e0aede9fb2..84a96ac1bf 100644
--- a/src/lib/gssapi/krb5/iakerb.c
+++ b/src/lib/gssapi/krb5/iakerb.c
@@ -914,16 +914,7 @@ iakerb_gss_init_sec_context(OM_uint32 *minor_status,
kname = (krb5_gss_name_t)target_name;
- if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) {
- major_status = krb5_gss_validate_cred_1(minor_status,
- claimant_cred_handle,
- ctx->k5c);
- if (GSS_ERROR(major_status))
- goto cleanup;
-
- cred_locked = TRUE;
- kcred = (krb5_gss_cred_id_t)claimant_cred_handle;
- } else {
+ if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
major_status = krb5_gss_acquire_cred(minor_status, NULL,
GSS_C_INDEFINITE,
GSS_C_NULL_OID_SET,
@@ -931,9 +922,16 @@ iakerb_gss_init_sec_context(OM_uint32 *minor_status,
&defcred, NULL, NULL);
if (GSS_ERROR(major_status))
goto cleanup;
- kcred = (krb5_gss_cred_id_t)defcred;
+ claimant_cred_handle = defcred;
}
+ major_status = kg_cred_resolve(minor_status, ctx->k5c,
+ claimant_cred_handle, target_name);
+ if (GSS_ERROR(major_status))
+ goto cleanup;
+ cred_locked = TRUE;
+ kcred = (krb5_gss_cred_id_t)claimant_cred_handle;
+
major_status = GSS_S_FAILURE;
if (initialContextToken) {
diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c
index 0133bf084b..d62822e2d4 100644
--- a/src/lib/gssapi/krb5/init_sec_context.c
+++ b/src/lib/gssapi/krb5/init_sec_context.c
@@ -930,6 +930,7 @@ krb5_gss_init_sec_context_ext(
krb5_gss_ctx_ext_t exts)
{
krb5_context context;
+ gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL;
krb5_gss_cred_id_t cred;
krb5_error_code kerr;
OM_uint32 major_status;
@@ -961,30 +962,25 @@ krb5_gss_init_sec_context_ext(
/* verify the credential, or use the default */
/*SUPPRESS 29*/
if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
- major_status = kg_get_defcred(minor_status, (gss_cred_id_t *)&cred);
+ major_status = kg_get_defcred(minor_status, &defcred);
if (major_status && GSS_ERROR(major_status)) {
if (*context_handle == GSS_C_NO_CONTEXT)
krb5_free_context(context);
return(major_status);
}
- } else {
- major_status = krb5_gss_validate_cred(minor_status, claimant_cred_handle);
- if (GSS_ERROR(major_status)) {
- save_error_info(*minor_status, context);
- if (*context_handle == GSS_C_NO_CONTEXT)
- krb5_free_context(context);
- return(major_status);
- }
- cred = (krb5_gss_cred_id_t) claimant_cred_handle;
+ claimant_cred_handle = defcred;
}
- kerr = k5_mutex_lock(&cred->lock);
- if (kerr) {
- if (claimant_cred_handle == GSS_C_NO_CREDENTIAL)
- krb5_gss_release_cred(minor_status, (gss_cred_id_t *)&cred);
- krb5_free_context(context);
- *minor_status = kerr;
- return GSS_S_FAILURE;
+
+ major_status = kg_cred_resolve(minor_status, context, claimant_cred_handle,
+ target_name);
+ if (GSS_ERROR(major_status)) {
+ save_error_info(*minor_status, context);
+ krb5_gss_release_cred(&tmp_min_stat, &defcred);
+ if (*context_handle == GSS_C_NO_CONTEXT)
+ krb5_free_context(context);
+ return(major_status);
}
+ cred = (krb5_gss_cred_id_t)claimant_cred_handle;
/* verify the mech_type */
@@ -998,8 +994,7 @@ krb5_gss_init_sec_context_ext(
mech_type = (gss_OID) gss_mech_iakerb;
} else {
k5_mutex_unlock(&cred->lock);
- if (claimant_cred_handle == GSS_C_NO_CREDENTIAL)
- krb5_gss_release_cred(minor_status, (gss_cred_id_t *)&cred);
+ krb5_gss_release_cred(minor_status, &defcred);
*minor_status = 0;
if (*context_handle == GSS_C_NO_CONTEXT)
krb5_free_context(context);
@@ -1036,9 +1031,7 @@ krb5_gss_init_sec_context_ext(
too. */
}
- if (claimant_cred_handle == GSS_C_NO_CREDENTIAL)
- krb5_gss_release_cred(&tmp_min_stat, (gss_cred_id_t *)&cred);
-
+ krb5_gss_release_cred(&tmp_min_stat, &defcred);
return(major_status);
}
diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c
index cc24e7a903..f523a545cf 100644
--- a/src/lib/gssapi/krb5/inq_cred.c
+++ b/src/lib/gssapi/krb5/inq_cred.c
@@ -83,14 +83,14 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret,
gss_OID_set *mechanisms;
{
krb5_context context;
- krb5_gss_cred_id_t cred;
+ krb5_gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL, cred;
krb5_error_code code;
krb5_timestamp now;
krb5_deltat lifetime;
krb5_gss_name_t ret_name;
krb5_principal princ;
gss_OID_set mechs;
- OM_uint32 ret;
+ OM_uint32 major, tmpmin, ret;
ret = GSS_S_FAILURE;
ret_name = NULL;
@@ -104,39 +104,31 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret,
if (name) *name = NULL;
if (mechanisms) *mechanisms = NULL;
+ if ((code = krb5_timeofday(context, &now))) {
+ *minor_status = code;
+ ret = GSS_S_FAILURE;
+ goto fail;
+ }
+
/* check for default credential */
/*SUPPRESS 29*/
if (cred_handle == GSS_C_NO_CREDENTIAL) {
- OM_uint32 major;
-
- if ((major = kg_get_defcred(minor_status, (gss_cred_id_t *)&cred)) &&
- GSS_ERROR(major)) {
- krb5_free_context(context);
- return(major);
- }
- } else {
- OM_uint32 major;
-
- major = krb5_gss_validate_cred(minor_status, cred_handle);
+ major = kg_get_defcred(minor_status, &defcred);
if (GSS_ERROR(major)) {
krb5_free_context(context);
return(major);
}
- cred = (krb5_gss_cred_id_t) cred_handle;
+ cred_handle = defcred;
}
- if ((code = krb5_timeofday(context, &now))) {
- *minor_status = code;
- ret = GSS_S_FAILURE;
- goto fail;
+ major = krb5_gss_validate_cred(minor_status, cred_handle);
+ if (GSS_ERROR(major)) {
+ krb5_gss_release_cred(minor_status, &defcred);
+ krb5_free_context(context);
+ return(major);
}
+ cred = (krb5_gss_cred_id_t)cred_handle;
- 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;
@@ -161,7 +153,6 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret,
code = 0;
}
if (code) {
- k5_mutex_unlock(&cred->lock);
*minor_status = code;
save_error_info(*minor_status, context);
ret = GSS_S_FAILURE;
@@ -178,7 +169,6 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret,
GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
gss_mech_krb5,
&mechs))) {
- k5_mutex_unlock(&cred->lock);
if (ret_name)
kg_release_name(context, &ret_name);
/* *minor_status set above */
@@ -210,11 +200,8 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret,
*minor_status = 0;
return((lifetime == 0)?GSS_S_CREDENTIALS_EXPIRED:GSS_S_COMPLETE);
fail:
- if (cred_handle == GSS_C_NO_CREDENTIAL) {
- OM_uint32 tmp_min_stat;
-
- krb5_gss_release_cred(&tmp_min_stat, (gss_cred_id_t *)&cred);
- }
+ k5_mutex_unlock(&cred->lock);
+ krb5_gss_release_cred(&tmpmin, &defcred);
krb5_free_context(context);
return ret;
}
diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c
index 70fbfbce6a..4ac2ce3015 100644
--- a/src/lib/gssapi/krb5/s4u_gss_glue.c
+++ b/src/lib/gssapi/krb5/s4u_gss_glue.c
@@ -144,9 +144,8 @@ krb5_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
return GSS_S_FAILURE;
}
- major_status = krb5_gss_validate_cred_1(minor_status,
- impersonator_cred_handle,
- context);
+ major_status = kg_cred_resolve(minor_status, context,
+ impersonator_cred_handle, NULL);
if (GSS_ERROR(major_status)) {
krb5_free_context(context);
return major_status;