Fix gss_add_cred() (krb5)

gss_add_cred() with GSS_C_NO_CREDENTIAL as the input_cred_handle should
act like gss_acquire_cred() with desired_mechs containing just the
desired_mech.
This commit is contained in:
Nicolas Williams
2015-03-18 22:23:45 -05:00
parent 533578e726
commit df41d53c67

View File

@@ -47,7 +47,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred (
OM_uint32 *acceptor_time_rec) OM_uint32 *acceptor_time_rec)
{ {
krb5_context context; krb5_context context;
OM_uint32 ret, lifetime; OM_uint32 major, lifetime;
gsskrb5_cred cred, handle; gsskrb5_cred cred, handle;
krb5_const_principal dname; krb5_const_principal dname;
@@ -55,49 +55,79 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred (
cred = (gsskrb5_cred)input_cred_handle; cred = (gsskrb5_cred)input_cred_handle;
dname = (krb5_const_principal)desired_name; dname = (krb5_const_principal)desired_name;
if (cred == NULL && output_cred_handle == NULL) {
*minor_status = EINVAL;
return GSS_S_CALL_INACCESSIBLE_WRITE;
}
GSSAPI_KRB5_INIT (&context); GSSAPI_KRB5_INIT (&context);
if (gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) { if (desired_mech != GSS_C_NO_OID &&
gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) {
*minor_status = 0; *minor_status = 0;
return GSS_S_BAD_MECH; return GSS_S_BAD_MECH;
} }
if (cred == NULL && output_cred_handle == NULL) { if (cred == NULL) {
*minor_status = 0; /*
return GSS_S_NO_CRED; * Acquire a credential; output_cred_handle can't be NULL, see above.
} */
heim_assert(output_cred_handle != NULL,
"internal error in _gsskrb5_add_cred()");
if (cred == NULL) { /* XXX standard conformance failure */ major = _gsskrb5_acquire_cred(minor_status, desired_name,
*minor_status = 0; min(initiator_time_req,
return GSS_S_NO_CRED; acceptor_time_req),
} GSS_C_NO_OID_SET,
cred_usage,
output_cred_handle,
actual_mechs, &lifetime);
if (major != GSS_S_COMPLETE)
goto failure;
} else if (cred != NULL) {
/*
* Check that we're done or copy input to output if
* output_cred_handle != NULL.
*/
/* check if requested output usage is compatible with output usage */
if (output_cred_handle != NULL) {
HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); HEIMDAL_MUTEX_lock(&cred->cred_id_mutex);
/* Check if requested output usage is compatible with output usage */
if (cred->usage != cred_usage && cred->usage != GSS_C_BOTH) { if (cred->usage != cred_usage && cred->usage != GSS_C_BOTH) {
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
*minor_status = GSS_KRB5_S_G_BAD_USAGE; *minor_status = GSS_KRB5_S_G_BAD_USAGE;
return(GSS_S_FAILURE); return(GSS_S_FAILURE);
} }
}
/* check that we have the same name */ /* Check that we have the same name */
if (dname != NULL && if (dname != NULL &&
krb5_principal_compare(context, dname, krb5_principal_compare(context, dname,
cred->principal) != FALSE) { cred->principal) != FALSE) {
if (output_cred_handle)
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
*minor_status = 0; *minor_status = 0;
return GSS_S_BAD_NAME; return GSS_S_BAD_NAME;
} }
/* make a copy */ if (output_cred_handle == NULL) {
if (output_cred_handle) { /*
krb5_error_code kret; * This case is basically useless as we implement a single
* mechanism here, so we can't add elements to the
* input_cred_handle.
*/
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
*minor_status = 0;
return GSS_S_COMPLETE;
}
/*
* Copy input to output -- this works as if we were a
* GSS_Duplicate_cred() for one mechanism element.
*/
handle = calloc(1, sizeof(*handle)); handle = calloc(1, sizeof(*handle));
if (handle == NULL) { if (handle == NULL) {
if (cred != NULL)
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
*minor_status = ENOMEM; *minor_status = ENOMEM;
return (GSS_S_FAILURE); return (GSS_S_FAILURE);
@@ -111,42 +141,37 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred (
handle->mechanisms = NULL; handle->mechanisms = NULL;
HEIMDAL_MUTEX_init(&handle->cred_id_mutex); HEIMDAL_MUTEX_init(&handle->cred_id_mutex);
ret = GSS_S_FAILURE; major = GSS_S_FAILURE;
kret = krb5_copy_principal(context, cred->principal, *minor_status = krb5_copy_principal(context, cred->principal,
&handle->principal); &handle->principal);
if (kret) { if (*minor_status) {
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
free(handle); free(handle);
*minor_status = kret;
return GSS_S_FAILURE; return GSS_S_FAILURE;
} }
if (cred->keytab) { if (cred->keytab) {
char *name = NULL; char *name = NULL;
ret = GSS_S_FAILURE; major = GSS_S_FAILURE;
kret = krb5_kt_get_full_name(context, cred->keytab, &name); *minor_status = krb5_kt_get_full_name(context, cred->keytab,
if (kret) { &name);
*minor_status = kret; if (*minor_status)
goto failure; goto failure;
}
kret = krb5_kt_resolve(context, name, *minor_status = krb5_kt_resolve(context, name, &handle->keytab);
&handle->keytab);
krb5_xfree(name); krb5_xfree(name);
if (kret){ if (*minor_status)
*minor_status = kret;
goto failure; goto failure;
} }
}
if (cred->ccache) { if (cred->ccache) {
const char *type, *name; const char *type, *name;
char *type_name = NULL; char *type_name = NULL;
ret = GSS_S_FAILURE; major = GSS_S_FAILURE;
type = krb5_cc_get_type(context, cred->ccache); type = krb5_cc_get_type(context, cred->ccache);
if (type == NULL){ if (type == NULL){
@@ -155,19 +180,15 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred (
} }
if (strcmp(type, "MEMORY") == 0) { if (strcmp(type, "MEMORY") == 0) {
ret = krb5_cc_new_unique(context, type, *minor_status = krb5_cc_new_unique(context, type,
NULL, &handle->ccache); NULL, &handle->ccache);
if (ret) { if (*minor_status)
*minor_status = ret;
goto failure; goto failure;
}
ret = krb5_cc_copy_cache(context, cred->ccache, *minor_status = krb5_cc_copy_cache(context, cred->ccache,
handle->ccache); handle->ccache);
if (ret) { if (*minor_status)
*minor_status = ret;
goto failure; goto failure;
}
} else { } else {
name = krb5_cc_get_name(context, cred->ccache); name = krb5_cc_get_name(context, cred->ccache);
@@ -176,52 +197,47 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred (
goto failure; goto failure;
} }
kret = asprintf(&type_name, "%s:%s", type, name); if (asprintf(&type_name, "%s:%s", type, name) == -1 ||
if (kret < 0 || type_name == NULL) { type_name == NULL) {
*minor_status = ENOMEM; *minor_status = ENOMEM;
goto failure; goto failure;
} }
kret = krb5_cc_resolve(context, type_name, *minor_status = krb5_cc_resolve(context, type_name,
&handle->ccache); &handle->ccache);
free(type_name); free(type_name);
if (kret) { if (*minor_status)
*minor_status = kret;
goto failure; goto failure;
} }
} }
} major = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); if (major != GSS_S_COMPLETE)
if (ret)
goto failure; goto failure;
ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, major = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
&handle->mechanisms); &handle->mechanisms);
if (ret) if (major != GSS_S_COMPLETE)
goto failure; goto failure;
}
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred, major = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred,
NULL, &lifetime, NULL, actual_mechs); NULL, &lifetime, NULL, actual_mechs);
if (ret) if (major != GSS_S_COMPLETE)
goto failure; goto failure;
*output_cred_handle = (gss_cred_id_t)handle;
}
if (initiator_time_rec) if (initiator_time_rec)
*initiator_time_rec = lifetime; *initiator_time_rec = lifetime;
if (acceptor_time_rec) if (acceptor_time_rec)
*acceptor_time_rec = lifetime; *acceptor_time_rec = lifetime;
if (output_cred_handle) {
*output_cred_handle = (gss_cred_id_t)handle;
}
*minor_status = 0; *minor_status = 0;
return ret; return major;
failure: failure:
if (handle) { if (handle) {
if (handle->principal) if (handle->principal)
krb5_free_principal(context, handle->principal); krb5_free_principal(context, handle->principal);
@@ -233,7 +249,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred (
gss_release_oid_set(NULL, &handle->mechanisms); gss_release_oid_set(NULL, &handle->mechanisms);
free(handle); free(handle);
} }
if (output_cred_handle) if (cred && output_cred_handle)
HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex);
return ret; return major;
} }