data), and anything the fake KDC sends will not be trusted without
verification using some secret that it won't know.
+**err_fmt**
+ This relation allows for custom error message formatting. If a
+ value is set, error messages will be formatted by substituting a
+ normal error message for %M and an error code for %C in the value.
+
**extra_addresses**
This allows a computer to use multiple local addresses, in order
to allow Kerberos to work in a network that uses NATs while still
credentials will fail if the client machine does not have a
keytab. The default value is false.
-
.. _realms:
[realms]
#define KRB5_CONF_DNS_LOOKUP_REALM "dns_lookup_realm"
#define KRB5_CONF_DOMAIN_REALM "domain_realm"
#define KRB5_CONF_ENABLE_ONLY "enable_only"
+#define KRB5_CONF_ERR_FMT "err_fmt"
#define KRB5_CONF_EXTRA_ADDRESSES "extra_addresses"
#define KRB5_CONF_FORWARDABLE "forwardable"
#define KRB5_CONF_HOST_BASED_SERVICES "host_based_services"
/* error detail info */
struct errinfo err;
+ char *err_fmt;
/* For Sun iprop code; does this really have to be here? */
struct _kdb_log_context *kdblog_context;
nctx->kdblog_context = NULL;
nctx->trace_callback = NULL;
nctx->trace_callback_data = NULL;
+ nctx->err_fmt = NULL;
+ if (ctx->err_fmt != NULL)
+ nctx->err_fmt = strdup(ctx->err_fmt); /* It's OK if this fails */
nctx->plugin_base_dir = NULL;
nctx->os_context.default_ccname = NULL;
ctx->prompt_types = 0;
ctx->use_conf_ktypes = 0;
ctx->udp_pref_limit = -1;
+
+ /* It's OK if this fails */
+ (void)profile_get_string(ctx->profile, KRB5_CONF_LIBDEFAULTS,
+ KRB5_CONF_ERR_FMT, NULL, NULL, &ctx->err_fmt);
*context_out = ctx;
return 0;
}
krb5_clear_error_message(ctx);
+ free(ctx->err_fmt);
#ifndef DISABLE_TRACING
if (ctx->trace_callback)
}
}
+/* Re-format msg using the format string err_fmt. Return an allocated result,
+ * or NULL if err_fmt is NULL or on allocation failure. */
+static char *
+err_fmt_fmt(const char *err_fmt, long code, const char *msg)
+{
+ struct k5buf buf;
+ const char *p, *s;
+
+ if (err_fmt == NULL)
+ return NULL;
+
+ k5_buf_init_dynamic(&buf);
+
+ s = err_fmt;
+ while ((p = strchr(s, '%')) != NULL) {
+ k5_buf_add_len(&buf, s, p - s);
+ s = p;
+ if (p[1] == '\0')
+ break;
+ else if (p[1] == 'M')
+ k5_buf_add(&buf, msg);
+ else if (p[1] == 'C')
+ k5_buf_add_fmt(&buf, "%ld", code);
+ else if (p[1] == '%')
+ k5_buf_add(&buf, "%");
+ else
+ k5_buf_add_fmt(&buf, "%%%c", p[1]);
+ s += 2;
+ }
+ k5_buf_add(&buf, s); /* Remainder after last token */
+ return buf.data;
+}
+
const char * KRB5_CALLCONV
krb5_get_error_message(krb5_context ctx, krb5_error_code code)
{
+ const char *std, *custom;
+
#ifdef DEBUG
if (ERROR_MESSAGE_DEBUG())
fprintf(stderr, "krb5_get_error_message(%p, %ld)\n", ctx, (long)code);
#endif
if (ctx == NULL)
return error_message(code);
- return k5_get_error(&ctx->err, code);
+
+ std = k5_get_error(&ctx->err, code);
+ custom = err_fmt_fmt(ctx->err_fmt, code, std);
+ if (custom != NULL) {
+ free((char *)std);
+ return custom;
+ }
+ return std;
}
void KRB5_CALLCONV