54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#pragma ident "%Z%%M% %I% %E% SMI"
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf/* Can't include krb5.h here, or k5-int.h which includes it, because
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf krb5.h needs to be generated with error tables, after util/et,
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf which builds after this directory. */
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#include <stdarg.h>
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#include <string.h>
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#include <stdlib.h>
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#include <stdio.h>
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#include <k5-err.h>
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#include "k5-thread.h"
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#include <k5-platform.h>
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#include "supp-int.h"
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#ifdef _WIN32
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#ifndef vsnprintf
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#define vsnprintf _vsnprintf
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#endif
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#endif
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf/* It would be nice to just use error_message() always. Pity that
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf it's defined in a library that depends on this one, and we're not
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf allowed to make circular dependencies. */
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf/* We really want a rwlock here, since we should hold it while calling
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf the function and copying out its results. But I haven't
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf implemented shims for rwlock yet. */
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfstatic k5_mutex_t krb5int_error_info_support_mutex =
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf K5_MUTEX_PARTIAL_INITIALIZER;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfstatic const char *(KRB5_CALLCONV *fptr)(long); /* = &error_message */
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfint
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfkrb5int_err_init (void)
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf{
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf return k5_mutex_finish_init (&krb5int_error_info_support_mutex);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf}
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#define initialize() krb5int_call_thread_support_init()
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#define lock() k5_mutex_lock(&krb5int_error_info_support_mutex)
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#define unlock() k5_mutex_unlock(&krb5int_error_info_support_mutex)
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfvoid
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfkrb5int_set_error (struct errinfo *ep, long code, const char *fmt, ...)
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf{
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf va_list args;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf va_start (args, fmt);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf krb5int_vset_error (ep, code, fmt, args);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf va_end (args);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf}
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfvoid
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfkrb5int_vset_error (struct errinfo *ep, long code,
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf const char *fmt, va_list args)
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf{
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf char *p;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (ep->msg && ep->msg != ep->scratch_buf) {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf free ((void *)ep->msg);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf ep->msg = NULL;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf }
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf ep->code = code;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#ifdef HAVE_VASPRINTF
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf char *str = NULL;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (vasprintf(&str, fmt, args) >= 0 && str != NULL) {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf ep->msg = str;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf return;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf }
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf }
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#endif
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf vsnprintf(ep->scratch_buf, sizeof(ep->scratch_buf), fmt, args);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf p = strdup(ep->scratch_buf);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf ep->msg = p ? p : ep->scratch_buf;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf}
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfconst char *
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfkrb5int_get_error (struct errinfo *ep, long code)
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf{
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf char *r, *r2;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (code == ep->code && ep->msg) {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf r = strdup(ep->msg);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (r == NULL) {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf strcpy(ep->scratch_buf, _("Out of memory"));
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf r = ep->scratch_buf;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf }
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf return r;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf }
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (initialize() != 0) {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf strncpy(ep->scratch_buf, _("Kerberos library initialization failure"),
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf sizeof(ep->scratch_buf));
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf ep->scratch_buf[sizeof(ep->scratch_buf)-1] = 0;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf ep->msg = NULL;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf return ep->scratch_buf;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf }
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf lock();
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (fptr == NULL) {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf unlock();
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#ifdef HAVE_STRERROR_R
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (strerror_r (code, ep->scratch_buf, sizeof(ep->scratch_buf)) == 0) {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf char *p = strdup(ep->scratch_buf);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (p)
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf return p;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf return ep->scratch_buf;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf }
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf /* If strerror_r didn't work with the 1K buffer, we can try a
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf really big one. This seems kind of gratuitous though. */
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#define BIG_ERR_BUFSIZ 8192
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf r = malloc(BIG_ERR_BUFSIZ);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (r) {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (strerror_r (code, r, BIG_ERR_BUFSIZ) == 0) {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf r2 = realloc (r, 1 + strlen(r));
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (r2)
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf return r2;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf return r;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf }
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf free (r);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf }
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf#endif
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf r = strerror (code);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (r) {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (strlen (r) < sizeof (ep->scratch_buf)
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf || (r2 = strdup (r)) == NULL) {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf strncpy (ep->scratch_buf, r, sizeof(ep->scratch_buf));
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf return ep->scratch_buf;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf } else
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf return r2;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf }
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf format_number:
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf sprintf (ep->scratch_buf, _("error %ld"), code);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf return ep->scratch_buf;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf }
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf r = (char *) fptr(code);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (r == NULL) {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf unlock();
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf goto format_number;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf }
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf r2 = strdup (r);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (r2 == NULL) {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf strncpy(ep->scratch_buf, r, sizeof(ep->scratch_buf));
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf unlock();
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf return ep->scratch_buf;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf } else {
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf unlock();
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf return r2;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf }
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf}
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfvoid
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfkrb5int_free_error (struct errinfo *ep, const char *msg)
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf{
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf if (msg != ep->scratch_buf)
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf free ((char *) msg);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf}
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfvoid
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfkrb5int_clear_error (struct errinfo *ep)
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf{
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf krb5int_free_error (ep, ep->msg);
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf ep->msg = NULL;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf}
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfvoid
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillfkrb5int_set_error_info_callout_fn (const char *(KRB5_CALLCONV *f)(long))
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf{
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf initialize();
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf lock();
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf fptr = f;
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf unlock();
54925bf60766fbb4f1f2d7c843721406a7b7a3fbwillf}