2N/A/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2N/A/* Can't include krb5.h here, or k5-int.h which includes it, because
2N/A krb5.h needs to be generated with error tables, after util/et,
2N/A which builds after this directory. */
2N/A#include <stdarg.h>
2N/A#include <string.h>
2N/A#include <stdlib.h>
2N/A#include <stdio.h>
2N/A#include "k5-err.h"
2N/A
2N/A#include "k5-thread.h"
2N/A#include "k5-platform.h"
2N/A#include "supp-int.h"
2N/A
2N/A#ifdef USE_KIM
2N/A#include "kim_string_private.h"
2N/A#endif
2N/A
2N/A/* It would be nice to just use error_message() always. Pity that
2N/A it's defined in a library that depends on this one, and we're not
2N/A allowed to make circular dependencies. */
2N/A/* We really want a rwlock here, since we should hold it while calling
2N/A the function and copying out its results. But I haven't
2N/A implemented shims for rwlock yet. */
2N/Astatic k5_mutex_t krb5int_error_info_support_mutex =
2N/A K5_MUTEX_PARTIAL_INITIALIZER;
2N/Astatic const char *(KRB5_CALLCONV *fptr)(long); /* = &error_message */
2N/A
2N/Aint
2N/Akrb5int_err_init (void)
2N/A{
2N/A return k5_mutex_finish_init (&krb5int_error_info_support_mutex);
2N/A}
2N/A#define initialize() krb5int_call_thread_support_init()
2N/A#define lock() k5_mutex_lock(&krb5int_error_info_support_mutex)
2N/A#define unlock() k5_mutex_unlock(&krb5int_error_info_support_mutex)
2N/A
2N/A/* Solaris Kerberos */
2N/Avoid
2N/Akrb5int_vset_error_fl (struct errinfo *, long, const char *, int, const char *,
2N/A va_list);
2N/A
2N/A#undef krb5int_set_error
2N/Avoid
2N/Akrb5int_set_error (struct errinfo *ep, long code, const char *fmt, ...)
2N/A{
2N/A va_list args;
2N/A va_start (args, fmt);
2N/A krb5int_vset_error_fl (ep, code, NULL, 0, fmt, args);
2N/A va_end (args);
2N/A}
2N/A
2N/Avoid
2N/Akrb5int_set_error_fl (struct errinfo *ep, long code,
2N/A const char *file, int line, const char *fmt, ...)
2N/A{
2N/A va_list args;
2N/A va_start (args, fmt);
2N/A krb5int_vset_error_fl (ep, code, file, line, fmt, args);
2N/A va_end (args);
2N/A}
2N/A
2N/Avoid
2N/Akrb5int_vset_error (struct errinfo *ep, long code,
2N/A const char *fmt, va_list args)
2N/A{
2N/A krb5int_vset_error_fl(ep, code, NULL, 0, fmt, args);
2N/A}
2N/A
2N/Avoid
2N/Akrb5int_vset_error_fl (struct errinfo *ep, long code,
2N/A const char *file, int line,
2N/A const char *fmt, va_list args)
2N/A{
2N/A va_list args2;
2N/A char *str = NULL, *str2, *slash;
2N/A#ifdef USE_KIM
2N/A kim_string loc_fmt = NULL;
2N/A
2N/A /* Try to localize the format string */
2N/A if (kim_os_string_create_localized(&loc_fmt, fmt) == KIM_NO_ERROR)
2N/A fmt = loc_fmt;
2N/A#endif
2N/A
2N/A /* try vasprintf first */
2N/A va_copy(args2, args);
2N/A if (vasprintf(&str, fmt, args2) < 0) {
2N/A str = NULL;
2N/A }
2N/A va_end(args2);
2N/A
2N/A if (str && line) {
2N/A /* Try to add file and line suffix. */
2N/A slash = strrchr(file, '/');
2N/A if (slash)
2N/A file = slash + 1;
2N/A if (asprintf(&str2, "%s (%s: %d)", str, file, line) > 0) {
2N/A free(str);
2N/A str = str2;
2N/A }
2N/A }
2N/A
2N/A /* If that failed, try using scratch_buf */
2N/A if (str == NULL) {
2N/A vsnprintf(ep->scratch_buf, sizeof(ep->scratch_buf), fmt, args);
2N/A str = strdup(ep->scratch_buf); /* try allocating again */
2N/A }
2N/A
2N/A /* free old string before setting new one */
2N/A if (ep->msg && ep->msg != ep->scratch_buf) {
2N/A krb5int_free_error (ep, ep->msg);
2N/A ep->msg = NULL;
2N/A }
2N/A ep->code = code;
2N/A ep->msg = str ? str : ep->scratch_buf;
2N/A
2N/A#ifdef USE_KIM
2N/A kim_string_free(&loc_fmt);
2N/A#endif
2N/A}
2N/A
2N/Aconst char *
2N/Akrb5int_get_error (struct errinfo *ep, long code)
2N/A{
2N/A const char *r, *r2;
2N/A if (code == ep->code && ep->msg) {
2N/A r = strdup(ep->msg);
2N/A if (r == NULL) {
2N/A strlcpy(ep->scratch_buf, _("Out of memory"),
2N/A sizeof(ep->scratch_buf));
2N/A r = ep->scratch_buf;
2N/A }
2N/A return r;
2N/A }
2N/A if (initialize() != 0) {
2N/A strncpy(ep->scratch_buf, _("Kerberos library initialization failure"),
2N/A sizeof(ep->scratch_buf));
2N/A ep->scratch_buf[sizeof(ep->scratch_buf)-1] = 0;
2N/A ep->msg = NULL;
2N/A return ep->scratch_buf;
2N/A }
2N/A if (lock())
2N/A goto no_fptr;
2N/A if (fptr == NULL) {
2N/A unlock();
2N/A no_fptr:
2N/A /* Theoretically, according to ISO C, strerror should be able
2N/A to give us a message back for any int value. However, on
2N/A UNIX at least, the errno codes strerror will actually be
2N/A useful for are positive, so a negative value here would be
2N/A kind of weird.
2N/A
2N/A Coverity Prevent thinks we shouldn't be passing negative
2N/A values to strerror, and it's not likely to be useful, so
2N/A let's not do it.
2N/A
2N/A Besides, normally we shouldn't get here; fptr should take
2N/A us to a callback function in the com_err library. */
2N/A if (code < 0)
2N/A goto format_number;
2N/A#ifdef HAVE_STRERROR_R
2N/A if (strerror_r(code, ep->scratch_buf, sizeof(ep->scratch_buf)) == 0) {
2N/A char *p = strdup(ep->scratch_buf);
2N/A if (p)
2N/A return p;
2N/A return ep->scratch_buf;
2N/A }
2N/A#endif
2N/A r = strerror(code);
2N/A if (r) {
2N/A strlcpy(ep->scratch_buf, r, sizeof(ep->scratch_buf));
2N/A return ep->scratch_buf;
2N/A }
2N/A format_number:
2N/A snprintf (ep->scratch_buf, sizeof(ep->scratch_buf),
2N/A _("error %ld"), code);
2N/A return ep->scratch_buf;
2N/A }
2N/A r = fptr(code);
2N/A if (r == NULL) {
2N/A unlock();
2N/A goto format_number;
2N/A }
2N/A
2N/A r2 = strdup(r);
2N/A if (r2 == NULL) {
2N/A strlcpy(ep->scratch_buf, r, sizeof(ep->scratch_buf));
2N/A unlock();
2N/A return ep->scratch_buf;
2N/A } else {
2N/A unlock();
2N/A return r2;
2N/A }
2N/A}
2N/A
2N/Avoid
2N/Akrb5int_free_error (struct errinfo *ep, const char *msg)
2N/A{
2N/A if (msg != ep->scratch_buf)
2N/A free ((char *) msg);
2N/A}
2N/A
2N/Avoid
2N/Akrb5int_clear_error (struct errinfo *ep)
2N/A{
2N/A krb5int_free_error (ep, ep->msg);
2N/A ep->msg = NULL;
2N/A}
2N/A
2N/Avoid
2N/Akrb5int_set_error_info_callout_fn (const char *(KRB5_CALLCONV *f)(long))
2N/A{
2N/A initialize();
2N/A if (lock() == 0) {
2N/A fptr = f;
2N/A unlock();
2N/A }
2N/A}