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