Home | History | Annotate | Download | only in support
      1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
      2 
      3 /* Can't include krb5.h here, or k5-int.h which includes it, because
      4    krb5.h needs to be generated with error tables, after util/et,
      5    which builds after this directory.  */
      6 #include <stdarg.h>
      7 #include <string.h>
      8 #include <stdlib.h>
      9 #include <stdio.h>
     10 #include <k5-err.h>
     11 
     12 #include "k5-thread.h"
     13 #include <k5-platform.h>
     14 #include "supp-int.h"
     15 
     16 #ifdef _WIN32
     17 #ifndef vsnprintf
     18 #define vsnprintf _vsnprintf
     19 #endif
     20 #endif
     21 
     22 /* It would be nice to just use error_message() always.  Pity that
     23    it's defined in a library that depends on this one, and we're not
     24    allowed to make circular dependencies.  */
     25 /* We really want a rwlock here, since we should hold it while calling
     26    the function and copying out its results.  But I haven't
     27    implemented shims for rwlock yet.  */
     28 static k5_mutex_t krb5int_error_info_support_mutex =
     29     K5_MUTEX_PARTIAL_INITIALIZER;
     30 static const char *(KRB5_CALLCONV *fptr)(long); /* = &error_message */
     31 
     32 int
     33 krb5int_err_init (void)
     34 {
     35     return k5_mutex_finish_init (&krb5int_error_info_support_mutex);
     36 }
     37 #define initialize()	krb5int_call_thread_support_init()
     38 #define lock()		k5_mutex_lock(&krb5int_error_info_support_mutex)
     39 #define unlock()	k5_mutex_unlock(&krb5int_error_info_support_mutex)
     40 
     41 void
     42 krb5int_set_error (struct errinfo *ep, long code, const char *fmt, ...)
     43 {
     44     va_list args;
     45     va_start (args, fmt);
     46     krb5int_vset_error (ep, code, fmt, args);
     47     va_end (args);
     48 }
     49 
     50 void
     51 krb5int_vset_error (struct errinfo *ep, long code,
     52 		    const char *fmt, va_list args)
     53 {
     54     char *p;
     55 
     56     if (ep->msg && ep->msg != ep->scratch_buf) {
     57 	free ((void *)ep->msg);
     58 	ep->msg = NULL;
     59     }
     60     ep->code = code;
     61 #ifdef HAVE_VASPRINTF
     62     {
     63 	char *str = NULL;
     64 	if (vasprintf(&str, fmt, args) >= 0 && str != NULL) {
     65 	    ep->msg = str;
     66 	    return;
     67 	}
     68     }
     69 #endif
     70     vsnprintf(ep->scratch_buf, sizeof(ep->scratch_buf), fmt, args);
     71     p = strdup(ep->scratch_buf);
     72     ep->msg = p ? p : ep->scratch_buf;
     73 }
     74 
     75 const char *
     76 krb5int_get_error (struct errinfo *ep, long code)
     77 {
     78     char *r, *r2;
     79     if (code == ep->code && ep->msg) {
     80 	r = strdup(ep->msg);
     81 	if (r == NULL) {
     82 	    strcpy(ep->scratch_buf, _("Out of memory"));
     83 	    r = ep->scratch_buf;
     84 	}
     85 	return r;
     86     }
     87     if (initialize() != 0) {
     88 	strncpy(ep->scratch_buf, _("Kerberos library initialization failure"),
     89 		sizeof(ep->scratch_buf));
     90 	ep->scratch_buf[sizeof(ep->scratch_buf)-1] = 0;
     91 	ep->msg = NULL;
     92 	return ep->scratch_buf;
     93     }
     94     lock();
     95     if (fptr == NULL) {
     96 	unlock();
     97 #ifdef HAVE_STRERROR_R
     98 	if (strerror_r (code, ep->scratch_buf, sizeof(ep->scratch_buf)) == 0) {
     99 	    char *p = strdup(ep->scratch_buf);
    100 	    if (p)
    101 		return p;
    102 	    return ep->scratch_buf;
    103 	}
    104 	/* If strerror_r didn't work with the 1K buffer, we can try a
    105 	   really big one.  This seems kind of gratuitous though.  */
    106 #define BIG_ERR_BUFSIZ 8192
    107 	r = malloc(BIG_ERR_BUFSIZ);
    108 	if (r) {
    109 	    if (strerror_r (code, r, BIG_ERR_BUFSIZ) == 0) {
    110 		r2 = realloc (r, 1 + strlen(r));
    111 		if (r2)
    112 		    return r2;
    113 		return r;
    114 	    }
    115 	    free (r);
    116 	}
    117 #endif
    118 	r = strerror (code);
    119 	if (r) {
    120 	    if (strlen (r) < sizeof (ep->scratch_buf)
    121 		|| (r2 = strdup (r)) == NULL) {
    122 		strncpy (ep->scratch_buf, r, sizeof(ep->scratch_buf));
    123 		return ep->scratch_buf;
    124 	    } else
    125 		return r2;
    126 	}
    127     format_number:
    128 	sprintf (ep->scratch_buf, _("error %ld"), code);
    129 	return ep->scratch_buf;
    130     }
    131     r = (char *) fptr(code);
    132     if (r == NULL) {
    133 	unlock();
    134 	goto format_number;
    135     }
    136     r2 = strdup (r);
    137     if (r2 == NULL) {
    138 	strncpy(ep->scratch_buf, r, sizeof(ep->scratch_buf));
    139 	unlock();
    140 	return ep->scratch_buf;
    141     } else {
    142 	unlock();
    143 	return r2;
    144     }
    145 }
    146 
    147 void
    148 krb5int_free_error (struct errinfo *ep, const char *msg)
    149 {
    150     if (msg != ep->scratch_buf)
    151 	free ((char *) msg);
    152 }
    153 
    154 void
    155 krb5int_clear_error (struct errinfo *ep)
    156 {
    157     krb5int_free_error (ep, ep->msg);
    158     ep->msg = NULL;
    159 }
    160 
    161 void
    162 krb5int_set_error_info_callout_fn (const char *(KRB5_CALLCONV *f)(long))
    163 {
    164     initialize();
    165     lock();
    166     fptr = f;
    167     unlock();
    168 }
    169