gss: merge enhanced Apple mechglue logging

Add _gss_mg_log() and friends for logging from within the mechanism glue and
SPNEGO. These APIs wrap around the libkrb5 logging APIs.
This commit is contained in:
Luke Howard
2019-12-28 16:45:47 +11:00
parent 31af9ba703
commit 6af3ea9099
13 changed files with 315 additions and 15 deletions

View File

@@ -1205,6 +1205,9 @@ gss_release_cred_by_mech(
gss_cred_id_t /* cred_handle */,
gss_const_OID /* mech */);
GSSAPI_LIB_FUNCTION void GSSAPI_LIB_CALL
gss_set_log_function(void *ctx, void (*func)(void * ctx, int level, const char *fmt, va_list));
GSSAPI_CPP_END
#if defined(__APPLE__) && (defined(__ppc__) || defined(__ppc64__) || defined(__i386__) || defined(__x86_64__))

View File

@@ -519,6 +519,9 @@ typedef OM_uint32 GSSAPI_CALLCONV _gss_authorize_localname_t (
gss_const_OID /* user_name_type */
);
struct _gss_name;
struct _gss_cred;
/* mechglue internal */
struct gss_mech_compat_desc_struct;
@@ -623,4 +626,41 @@ struct _gss_oid_name_table {
extern struct _gss_oid_name_table _gss_ont_mech[];
extern struct _gss_oid_name_table _gss_ont_ma[];
int
_gss_mg_log_level(int level);
void
_gss_mg_log(int level, const char *fmt, ...)
HEIMDAL_PRINTF_ATTRIBUTE((printf, 2, 3));
void
_gss_mg_log_name(int level,
struct _gss_name *name,
gss_OID mech_type,
const char *fmt, ...);
void
_gss_mg_log_cred(int level,
struct _gss_cred *cred,
const char *fmt, ...);
void
_gss_load_plugins(void);
gss_iov_buffer_desc *
_gss_mg_find_buffer(gss_iov_buffer_desc *iov,
int iov_count,
OM_uint32 type);
OM_uint32
_gss_mg_allocate_buffer(OM_uint32 *minor_status,
gss_iov_buffer_desc *buffer,
size_t size);
OM_uint32
gss_mg_set_error_string(gss_OID mech,
OM_uint32 maj, OM_uint32 min,
const char *fmt, ...);
#endif /* GSSAPI_MECH_H */

View File

@@ -90,6 +90,7 @@ EXPORTS
gss_seal
gss_set_cred_option
gss_set_name_attribute
gss_set_log_function
gss_set_neg_mechs
gss_set_sec_context_option
gss_sign

View File

@@ -42,6 +42,7 @@ struct mg_thread_ctx {
gss_OID mech;
OM_uint32 min_stat;
gss_buffer_desc min_error;
krb5_context context;
};
static HEIMDAL_MUTEX context_mutex = HEIMDAL_MUTEX_INITIALIZER;
@@ -60,6 +61,9 @@ destroy_context(void *ptr)
gss_release_buffer(&junk, &mg->min_error);
if (mg->context)
krb5_free_context(mg->context);
free(mg);
}
@@ -88,8 +92,16 @@ _gss_mechglue_thread(void)
ctx = calloc(1, sizeof(*ctx));
if (ctx == NULL)
return NULL;
ret = krb5_init_context(&ctx->context);
if (ret) {
free(ctx);
return NULL;
}
HEIMDAL_setspecific(context_key, ctx, ret);
if (ret) {
krb5_free_context(ctx->context);
free(ctx);
return NULL;
}
@@ -151,8 +163,13 @@ _gss_mg_error(struct gssapi_mech_interface_desc *m, OM_uint32 min)
&m->gm_mech_oid,
&message_content,
&mg->min_error);
if (major_status != GSS_S_COMPLETE)
if (major_status != GSS_S_COMPLETE) {
_mg_buffer_zero(&mg->min_error);
} else {
_gss_mg_log(5, "_gss_mg_error: captured %.*s (%d) from underlying mech %s",
(int)mg->min_error.length, (const char *)mg->min_error.value,
(int)min, m->gm_name);
}
}
void
@@ -163,3 +180,165 @@ gss_mg_collect_error(gss_OID mech, OM_uint32 maj, OM_uint32 min)
return;
_gss_mg_error(m, min);
}
OM_uint32
gss_mg_set_error_string(gss_OID mech,
OM_uint32 maj, OM_uint32 min,
const char *fmt, ...)
{
struct mg_thread_ctx *mg;
char *str = NULL;
OM_uint32 junk;
va_list ap;
mg = _gss_mechglue_thread();
if (mg == NULL)
return maj;
va_start(ap, fmt);
(void) vasprintf(&str, fmt, ap);
va_end(ap);
if (str) {
gss_release_buffer(&junk, &mg->min_error);
mg->mech = mech;
mg->min_stat = min;
mg->min_error.value = str;
mg->min_error.length = strlen(str);
_gss_mg_log(5, "gss_mg_set_error_string: %.*s (%d/%d)",
(int)mg->min_error.length, (const char *)mg->min_error.value,
(int)maj, (int)min);
}
return maj;
}
static void *log_ctx = NULL;
static void (*log_func)(void *ctx, int level, const char *fmt, va_list) = NULL;
void
gss_set_log_function(void *ctx, void (*func)(void * ctx, int level, const char *fmt, va_list))
{
if (log_func == NULL) {
log_func = func;
log_ctx = ctx;
}
}
int
_gss_mg_log_level(int level)
{
struct mg_thread_ctx *mg;
mg = _gss_mechglue_thread();
if (mg == NULL)
return 0;
return _krb5_have_debug(mg->context, level);
}
/*
* TODO: refactor logging so that it no longer depends on libkrb5
* and can be configured independently.
*/
void
_gss_mg_log(int level, const char *fmt, ...)
{
struct mg_thread_ctx *mg;
va_list ap;
if (!_gss_mg_log_level(level))
return;
mg = _gss_mechglue_thread();
if (mg == NULL)
return;
if (mg->context && _krb5_have_debug(mg->context, level)) {
va_start(ap, fmt);
krb5_vlog(mg->context, mg->context->debug_dest, level, fmt, ap);
va_end(ap);
}
if (log_func) {
va_start(ap, fmt);
log_func(log_ctx, level, fmt, ap);
va_end(ap);
}
}
void
_gss_mg_log_name(int level,
struct _gss_name *name,
gss_OID mech_type,
const char *fmt, ...)
{
struct _gss_mechanism_name *mn = NULL;
gssapi_mech_interface m;
OM_uint32 junk;
if (!_gss_mg_log_level(level))
return;
m = __gss_get_mechanism(mech_type);
if (m == NULL)
return;
if (_gss_find_mn(&junk, name, mech_type, &mn) == GSS_S_COMPLETE) {
OM_uint32 maj_stat = GSS_S_COMPLETE;
gss_buffer_desc namebuf;
if (mn == NULL) {
namebuf.value = "no name";
namebuf.length = strlen((char *)namebuf.value);
} else {
maj_stat = m->gm_display_name(&junk, mn->gmn_name,
&namebuf, NULL);
}
if (maj_stat == GSS_S_COMPLETE) {
char *str = NULL;
va_list ap;
va_start(ap, fmt);
(void) vasprintf(&str, fmt, ap);
va_end(ap);
if (str)
_gss_mg_log(level, "%s %.*s", str,
(int)namebuf.length, (char *)namebuf.value);
free(str);
if (mn != NULL)
gss_release_buffer(&junk, &namebuf);
}
}
}
void
_gss_mg_log_cred(int level,
struct _gss_cred *cred,
const char *fmt, ...)
{
struct _gss_mechanism_cred *mc;
char *str;
va_list ap;
if (!_gss_mg_log_level(level))
return;
va_start(ap, fmt);
(void) vasprintf(&str, fmt, ap);
va_end(ap);
if (cred) {
HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) {
_gss_mg_log(1, "%s: %s", str, mc->gmc_mech->gm_name);
}
} else {
_gss_mg_log(1, "%s: GSS_C_NO_CREDENTIAL", str);
}
free(str);
}

View File

@@ -48,9 +48,6 @@ _gss_mg_release_cred(struct _gss_cred *cred);
struct _gss_mechanism_cred *
_gss_copy_cred(struct _gss_mechanism_cred *mc);
void
_gss_mg_check_credential(gss_const_cred_id_t credential);
struct _gss_mechanism_name;
OM_uint32

View File

@@ -136,6 +136,8 @@ choose_mech(const gss_buffer_t input, gss_OID *mech_oid)
return GSS_S_COMPLETE;
}
_gss_mg_log(10, "Don't have client request mech");
return status;
}
@@ -176,7 +178,6 @@ gss_accept_sec_context(OM_uint32 *minor_status,
*delegated_cred_handle = GSS_C_NO_CREDENTIAL;
_mg_buffer_zero(output_token);
/*
* If this is the first call (*context_handle is NULL), we must
* parse the input token to figure out the mechanism to use.
@@ -201,6 +202,7 @@ gss_accept_sec_context(OM_uint32 *minor_status,
m = ctx->gc_mech = __gss_get_mechanism(mech_oid);
if (!m) {
free(ctx);
_gss_mg_log(10, "mechanism client used is unknown");
return (GSS_S_BAD_MECH);
}
*context_handle = (gss_ctx_id_t) ctx;
@@ -214,6 +216,11 @@ gss_accept_sec_context(OM_uint32 *minor_status,
break;
if (!mc) {
gss_delete_sec_context(&junk, context_handle, NULL);
_gss_mg_log(10, "gss-asc: client sent mech %s "
"but no credential was matching",
m->gm_name);
HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link)
_gss_mg_log(10, "gss-asc: available creds were %s", mc->gmc_mech->gm_name);
return (GSS_S_BAD_MECH);
}
acceptor_mc = mc->gmc_cred;
@@ -301,6 +308,8 @@ gss_accept_sec_context(OM_uint32 *minor_status,
}
}
_gss_mg_log(10, "gss-asc: return %d/%d", (int)major_status, (int)*minor_status);
if (ret_flags)
*ret_flags = mech_ret_flags;
return (major_status);

View File

@@ -219,6 +219,11 @@ gss_acquire_cred_from(OM_uint32 *minor_status,
continue;
}
_gss_mg_log_name(10, name, &mechs->elements[i],
"gss_acquire_cred %s name: %ld/%ld",
m->gm_name,
(long)major_status, (long)*minor_status);
HEIM_TAILQ_INSERT_TAIL(&cred->gc_mc, mc, gmc_link);
if (cred_time < min_time)
@@ -253,6 +258,8 @@ gss_acquire_cred_from(OM_uint32 *minor_status,
if (time_rec)
*time_rec = min_time;
_gss_mg_log_cred(10, cred, "gss_acquire_cred_from");
cleanup:
if (major_status != GSS_S_COMPLETE) {
gss_release_cred(&minor, (gss_cred_id_t *)&cred);

View File

@@ -66,6 +66,9 @@ gss_export_cred(OM_uint32 * minor_status,
HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) {
if (mc->gmc_mech->gm_export_cred == NULL) {
*minor_status = 0;
gss_mg_set_error_string(&mc->gmc_mech->gm_mech_oid,
GSS_S_NO_CRED, *minor_status,
"Credential doesn't support exporting");
return GSS_S_NO_CRED;
}
}
@@ -77,7 +80,6 @@ gss_export_cred(OM_uint32 * minor_status,
}
HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) {
major = mc->gmc_mech->gm_export_cred(minor_status,
mc->gmc_cred, &buffer);
if (major) {
@@ -85,12 +87,14 @@ gss_export_cred(OM_uint32 * minor_status,
return major;
}
bytes = krb5_storage_write(sp, buffer.value, buffer.length);
if (bytes < 0 || (size_t)bytes != buffer.length) {
gss_release_buffer(minor_status, &buffer);
krb5_storage_free(sp);
*minor_status = EINVAL;
return GSS_S_FAILURE;
if (buffer.length) {
bytes = krb5_storage_write(sp, buffer.value, buffer.length);
if (bytes < 0 || (size_t)bytes != buffer.length) {
gss_release_buffer(minor_status, &buffer);
krb5_storage_free(sp);
*minor_status = EINVAL;
return GSS_S_FAILURE;
}
}
gss_release_buffer(minor_status, &buffer);
}
@@ -102,6 +106,14 @@ gss_export_cred(OM_uint32 * minor_status,
return GSS_S_FAILURE;
}
if (data.length == 0) {
*minor_status = 0;
gss_mg_set_error_string(GSS_C_NO_OID,
GSS_S_NO_CRED, *minor_status,
"Credential was not exportable");
return GSS_S_NO_CRED;
}
token->value = data.data;
token->length = data.length;

View File

@@ -46,6 +46,38 @@ _gss_mech_cred_find(gss_const_cred_id_t cred_handle, gss_OID mech_type)
return GSS_C_NO_CREDENTIAL;
}
static void
log_init_sec_context(struct _gss_context *ctx,
struct _gss_name *target,
OM_uint32 req_flags,
struct _gss_cred *cred,
gss_OID mech_type,
gss_buffer_t input_token)
{
gssapi_mech_interface m;
if (ctx)
m = ctx->gc_mech;
else
m = __gss_get_mechanism(mech_type);
if (m == NULL)
return;
mech_type = &m->gm_mech_oid;
_gss_mg_log(1, "gss_isc: %s %sfirst flags %08x, %s cred, %stoken",
m->gm_name,
(ctx == NULL) ? "" : "not ",
req_flags,
(cred != NULL) ? "specific" : "default",
(input_token != NULL && input_token->length) ? "" : "no ");
_gss_mg_log_cred(1, cred, "gss_isc cred");
/* print target name */
_gss_mg_log_name(1, target, mech_type, "gss_isc: target");
}
/**
* As the initiator build a context with an acceptor.
*
@@ -141,6 +173,11 @@ gss_init_sec_context(OM_uint32 * minor_status,
if (time_rec)
*time_rec = 0;
if (_gss_mg_log_level(1))
log_init_sec_context(ctx, name, req_flags,
(struct _gss_cred *)initiator_cred_handle,
input_mech_type, input_token);
/*
* If we haven't allocated a context yet, do so now and lookup
* the mechanism switch table. If we have one already, make
@@ -159,6 +196,10 @@ gss_init_sec_context(OM_uint32 * minor_status,
m = ctx->gc_mech = __gss_get_mechanism(mech_type);
if (!m) {
free(ctx);
*minor_status = 0;
gss_mg_set_error_string(mech_type, GSS_S_BAD_MECH,
*minor_status,
"Unsupported mechanism requested");
return (GSS_S_BAD_MECH);
}
allocated_ctx = 1;
@@ -188,9 +229,14 @@ gss_init_sec_context(OM_uint32 * minor_status,
if (initiator_cred_handle != GSS_C_NO_CREDENTIAL &&
cred_handle == NULL) {
*minor_status = 0;
if (allocated_ctx)
free(ctx);
return GSS_S_NO_CRED;
gss_mg_set_error_string(mech_type, GSS_S_UNAVAILABLE,
*minor_status,
"Credential for the requested mechanism "
"not found in credential handle");
return GSS_S_UNAVAILABLE;
}
major_status = m->gm_init_sec_context(minor_status,
@@ -217,5 +263,8 @@ gss_init_sec_context(OM_uint32 * minor_status,
*context_handle = (gss_ctx_id_t) ctx;
}
_gss_mg_log(1, "gss_isc: %s maj_stat: %d/%d",
m->gm_name, (int)major_status, (int)*minor_status);
return (major_status);
}

View File

@@ -167,7 +167,7 @@ do { \
m->gm_mech.gm_ ## name = (_gss_##name##_t *)dlsym(so, "gss_" #name); \
if (!m->gm_mech.gm_ ## name || \
m->gm_mech.gm_ ##name == gss_ ## name) { \
fprintf(stderr, "can't find symbol gss_" #name "\n"); \
_gss_mg_log(1, "can't find symbol gss_" #name "\n"); \
goto bad; \
} \
} while (0)
@@ -326,7 +326,7 @@ _gss_load_mech(void)
so = dlopen(lib, RTLD_LAZY | RTLD_LOCAL | RTLD_GROUP);
if (so == NULL) {
/* fprintf(stderr, "dlopen: %s\n", dlerror()); */
_gss_mg_log(1, "dlopen: %s\n", dlerror());
goto bad;
}

View File

@@ -84,6 +84,7 @@ HEIMDAL_GSS_2.0 {
gss_seal;
gss_set_cred_option;
gss_set_name_attribute;
gss_set_log_function;
gss_set_neg_mechs;
gss_set_sec_context_option;
gss_sign;

View File

@@ -776,6 +776,7 @@ EXPORTS
_krb5_get_krbtgt
_krb5_build_authenticator
_krb5_kt_client_default_name
_krb5_have_debug
; Shared with libkadm5
_krb5_load_plugins

View File

@@ -768,6 +768,7 @@ HEIMDAL_KRB5_2.0 {
_krb5_get_krbtgt;
_krb5_build_authenticator;
_krb5_kt_client_default_name;
_krb5_have_debug;
# Shared with libkadm5
_krb5_load_plugins;