xref: /freebsd/crypto/krb5/src/util/et/error_message.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /*
3*7f2fe78bSCy Schubert  * Copyright 1997,2000,2001,2004,2008 by Massachusetts Institute of Technology
4*7f2fe78bSCy Schubert  *
5*7f2fe78bSCy Schubert  * Copyright 1987, 1988 by MIT Student Information Processing Board
6*7f2fe78bSCy Schubert  *
7*7f2fe78bSCy Schubert  * Permission to use, copy, modify, and distribute this software
8*7f2fe78bSCy Schubert  * and its documentation for any purpose and without fee is
9*7f2fe78bSCy Schubert  * hereby granted, provided that the above copyright notice
10*7f2fe78bSCy Schubert  * appear in all copies and that both that copyright notice and
11*7f2fe78bSCy Schubert  * this permission notice appear in supporting documentation,
12*7f2fe78bSCy Schubert  * and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
13*7f2fe78bSCy Schubert  * used in advertising or publicity pertaining to distribution
14*7f2fe78bSCy Schubert  * of the software without specific, written prior permission.
15*7f2fe78bSCy Schubert  * Furthermore if you modify this software you must label
16*7f2fe78bSCy Schubert  * your software as modified software and not distribute it in such a
17*7f2fe78bSCy Schubert  * fashion that it might be confused with the original M.I.T. software.
18*7f2fe78bSCy Schubert  * M.I.T. and the M.I.T. S.I.P.B. make no representations about
19*7f2fe78bSCy Schubert  * the suitability of this software for any purpose.  It is
20*7f2fe78bSCy Schubert  * provided "as is" without express or implied warranty.
21*7f2fe78bSCy Schubert  */
22*7f2fe78bSCy Schubert 
23*7f2fe78bSCy Schubert #include "k5-platform.h"
24*7f2fe78bSCy Schubert #include "com_err.h"
25*7f2fe78bSCy Schubert #include "error_table.h"
26*7f2fe78bSCy Schubert 
27*7f2fe78bSCy Schubert static struct et_list *et_list;
28*7f2fe78bSCy Schubert static k5_mutex_t et_list_lock = K5_MUTEX_PARTIAL_INITIALIZER;
29*7f2fe78bSCy Schubert static int terminated = 0;      /* for safety and finalization debugging */
30*7f2fe78bSCy Schubert 
31*7f2fe78bSCy Schubert MAKE_INIT_FUNCTION(com_err_initialize);
32*7f2fe78bSCy Schubert MAKE_FINI_FUNCTION(com_err_terminate);
33*7f2fe78bSCy Schubert 
com_err_initialize(void)34*7f2fe78bSCy Schubert int com_err_initialize(void)
35*7f2fe78bSCy Schubert {
36*7f2fe78bSCy Schubert     int err;
37*7f2fe78bSCy Schubert #ifdef SHOW_INITFINI_FUNCS
38*7f2fe78bSCy Schubert     printf("com_err_initialize\n");
39*7f2fe78bSCy Schubert #endif
40*7f2fe78bSCy Schubert     terminated = 0;
41*7f2fe78bSCy Schubert     err = k5_mutex_finish_init(&et_list_lock);
42*7f2fe78bSCy Schubert     if (err)
43*7f2fe78bSCy Schubert         return err;
44*7f2fe78bSCy Schubert     err = k5_mutex_finish_init(&com_err_hook_lock);
45*7f2fe78bSCy Schubert     if (err)
46*7f2fe78bSCy Schubert         return err;
47*7f2fe78bSCy Schubert     err = k5_key_register(K5_KEY_COM_ERR, free);
48*7f2fe78bSCy Schubert     if (err)
49*7f2fe78bSCy Schubert         return err;
50*7f2fe78bSCy Schubert     return 0;
51*7f2fe78bSCy Schubert }
52*7f2fe78bSCy Schubert 
com_err_terminate(void)53*7f2fe78bSCy Schubert void com_err_terminate(void)
54*7f2fe78bSCy Schubert {
55*7f2fe78bSCy Schubert     struct et_list *e, *enext;
56*7f2fe78bSCy Schubert     if (! INITIALIZER_RAN(com_err_initialize) || PROGRAM_EXITING()) {
57*7f2fe78bSCy Schubert #ifdef SHOW_INITFINI_FUNCS
58*7f2fe78bSCy Schubert         printf("com_err_terminate: skipping\n");
59*7f2fe78bSCy Schubert #endif
60*7f2fe78bSCy Schubert         return;
61*7f2fe78bSCy Schubert     }
62*7f2fe78bSCy Schubert #ifdef SHOW_INITFINI_FUNCS
63*7f2fe78bSCy Schubert     printf("com_err_terminate\n");
64*7f2fe78bSCy Schubert #endif
65*7f2fe78bSCy Schubert     k5_key_delete(K5_KEY_COM_ERR);
66*7f2fe78bSCy Schubert     k5_mutex_destroy(&com_err_hook_lock);
67*7f2fe78bSCy Schubert     k5_mutex_lock(&et_list_lock);
68*7f2fe78bSCy Schubert     for (e = et_list; e; e = enext) {
69*7f2fe78bSCy Schubert         enext = e->next;
70*7f2fe78bSCy Schubert         free(e);
71*7f2fe78bSCy Schubert     }
72*7f2fe78bSCy Schubert     et_list = NULL;
73*7f2fe78bSCy Schubert     k5_mutex_unlock(&et_list_lock);
74*7f2fe78bSCy Schubert     k5_mutex_destroy(&et_list_lock);
75*7f2fe78bSCy Schubert     terminated = 1;
76*7f2fe78bSCy Schubert }
77*7f2fe78bSCy Schubert 
78*7f2fe78bSCy Schubert #ifndef DEBUG_TABLE_LIST
79*7f2fe78bSCy Schubert #define dprintf(X)
80*7f2fe78bSCy Schubert #else
81*7f2fe78bSCy Schubert #define dprintf(X) printf X
82*7f2fe78bSCy Schubert #endif
83*7f2fe78bSCy Schubert 
84*7f2fe78bSCy Schubert static char *
get_thread_buffer()85*7f2fe78bSCy Schubert get_thread_buffer ()
86*7f2fe78bSCy Schubert {
87*7f2fe78bSCy Schubert     char *cp;
88*7f2fe78bSCy Schubert     cp = k5_getspecific(K5_KEY_COM_ERR);
89*7f2fe78bSCy Schubert     if (cp == NULL) {
90*7f2fe78bSCy Schubert         cp = malloc(ET_EBUFSIZ);
91*7f2fe78bSCy Schubert         if (cp == NULL) {
92*7f2fe78bSCy Schubert             return NULL;
93*7f2fe78bSCy Schubert         }
94*7f2fe78bSCy Schubert         if (k5_setspecific(K5_KEY_COM_ERR, cp) != 0) {
95*7f2fe78bSCy Schubert             free(cp);
96*7f2fe78bSCy Schubert             return NULL;
97*7f2fe78bSCy Schubert         }
98*7f2fe78bSCy Schubert     }
99*7f2fe78bSCy Schubert     return cp;
100*7f2fe78bSCy Schubert }
101*7f2fe78bSCy Schubert 
102*7f2fe78bSCy Schubert const char * KRB5_CALLCONV
error_message(long code)103*7f2fe78bSCy Schubert error_message(long code)
104*7f2fe78bSCy Schubert {
105*7f2fe78bSCy Schubert     unsigned long offset;
106*7f2fe78bSCy Schubert     unsigned long l_offset;
107*7f2fe78bSCy Schubert     struct et_list *e;
108*7f2fe78bSCy Schubert     unsigned long table_num;
109*7f2fe78bSCy Schubert     int started = 0;
110*7f2fe78bSCy Schubert     unsigned int divisor = 100;
111*7f2fe78bSCy Schubert     char *cp, *cp1;
112*7f2fe78bSCy Schubert     const struct error_table *table;
113*7f2fe78bSCy Schubert 
114*7f2fe78bSCy Schubert     if (CALL_INIT_FUNCTION(com_err_initialize))
115*7f2fe78bSCy Schubert         return 0;
116*7f2fe78bSCy Schubert 
117*7f2fe78bSCy Schubert     l_offset = (unsigned long)code & ((1<<ERRCODE_RANGE)-1);
118*7f2fe78bSCy Schubert     offset = l_offset;
119*7f2fe78bSCy Schubert     table_num = ((unsigned long)code - l_offset) & ERRCODE_MAX;
120*7f2fe78bSCy Schubert     if (table_num == 0
121*7f2fe78bSCy Schubert #ifdef __sgi
122*7f2fe78bSCy Schubert         /* Irix 6.5 uses a much bigger table than other UNIX
123*7f2fe78bSCy Schubert            systems I've looked at, but the table is sparse.  The
124*7f2fe78bSCy Schubert            sparse entries start around 500, but sys_nerr is only
125*7f2fe78bSCy Schubert            152.  */
126*7f2fe78bSCy Schubert         || (code > 0 && code <= 1600)
127*7f2fe78bSCy Schubert #endif
128*7f2fe78bSCy Schubert     ) {
129*7f2fe78bSCy Schubert         if (code == 0)
130*7f2fe78bSCy Schubert             goto oops;
131*7f2fe78bSCy Schubert 
132*7f2fe78bSCy Schubert         /* This could trip if int is 16 bits.  */
133*7f2fe78bSCy Schubert         if ((unsigned long)(int)code != (unsigned long)code)
134*7f2fe78bSCy Schubert             abort ();
135*7f2fe78bSCy Schubert         cp = get_thread_buffer();
136*7f2fe78bSCy Schubert         if (cp && strerror_r(code, cp, ET_EBUFSIZ) == 0)
137*7f2fe78bSCy Schubert             return cp;
138*7f2fe78bSCy Schubert         return strerror(code);
139*7f2fe78bSCy Schubert     }
140*7f2fe78bSCy Schubert 
141*7f2fe78bSCy Schubert     k5_mutex_lock(&et_list_lock);
142*7f2fe78bSCy Schubert     dprintf(("scanning list for %x\n", table_num));
143*7f2fe78bSCy Schubert     for (e = et_list; e != NULL; e = e->next) {
144*7f2fe78bSCy Schubert         dprintf(("\t%x = %s\n", e->table->base & ERRCODE_MAX,
145*7f2fe78bSCy Schubert                  e->table->msgs[0]));
146*7f2fe78bSCy Schubert         if ((e->table->base & ERRCODE_MAX) == table_num) {
147*7f2fe78bSCy Schubert             table = e->table;
148*7f2fe78bSCy Schubert             goto found;
149*7f2fe78bSCy Schubert         }
150*7f2fe78bSCy Schubert     }
151*7f2fe78bSCy Schubert     goto no_table_found;
152*7f2fe78bSCy Schubert 
153*7f2fe78bSCy Schubert found:
154*7f2fe78bSCy Schubert     k5_mutex_unlock(&et_list_lock);
155*7f2fe78bSCy Schubert     dprintf (("found it!\n"));
156*7f2fe78bSCy Schubert     /* This is the right table */
157*7f2fe78bSCy Schubert 
158*7f2fe78bSCy Schubert     /* This could trip if int is 16 bits.  */
159*7f2fe78bSCy Schubert     if ((unsigned long)(unsigned int)offset != offset)
160*7f2fe78bSCy Schubert         goto no_table_found;
161*7f2fe78bSCy Schubert 
162*7f2fe78bSCy Schubert     if (table->n_msgs <= (unsigned int) offset)
163*7f2fe78bSCy Schubert         goto no_table_found;
164*7f2fe78bSCy Schubert 
165*7f2fe78bSCy Schubert     /* If there's a string at the end of the table, it's a text domain. */
166*7f2fe78bSCy Schubert     if (table->msgs[table->n_msgs] != NULL)
167*7f2fe78bSCy Schubert         return dgettext(table->msgs[table->n_msgs], table->msgs[offset]);
168*7f2fe78bSCy Schubert     else
169*7f2fe78bSCy Schubert         return table->msgs[offset];
170*7f2fe78bSCy Schubert 
171*7f2fe78bSCy Schubert no_table_found:
172*7f2fe78bSCy Schubert     k5_mutex_unlock(&et_list_lock);
173*7f2fe78bSCy Schubert #if defined(_WIN32)
174*7f2fe78bSCy Schubert     /*
175*7f2fe78bSCy Schubert      * WinSock errors exist in the 10000 and 11000 ranges
176*7f2fe78bSCy Schubert      * but might not appear if WinSock is not initialized
177*7f2fe78bSCy Schubert      */
178*7f2fe78bSCy Schubert     if (code >= WSABASEERR && code < WSABASEERR + 1100) {
179*7f2fe78bSCy Schubert         table_num = 0;
180*7f2fe78bSCy Schubert         offset = code;
181*7f2fe78bSCy Schubert         divisor = WSABASEERR;
182*7f2fe78bSCy Schubert     }
183*7f2fe78bSCy Schubert #endif
184*7f2fe78bSCy Schubert #ifdef _WIN32
185*7f2fe78bSCy Schubert     {
186*7f2fe78bSCy Schubert         LPVOID msgbuf;
187*7f2fe78bSCy Schubert 
188*7f2fe78bSCy Schubert         if (! FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
189*7f2fe78bSCy Schubert                              NULL /* lpSource */,
190*7f2fe78bSCy Schubert                              (DWORD) code,
191*7f2fe78bSCy Schubert                              MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
192*7f2fe78bSCy Schubert                              (LPTSTR) &msgbuf,
193*7f2fe78bSCy Schubert                              (DWORD) 0 /*sizeof(buffer)*/,
194*7f2fe78bSCy Schubert                              NULL /* va_list */ )) {
195*7f2fe78bSCy Schubert             /*
196*7f2fe78bSCy Schubert              * WinSock errors exist in the 10000 and 11000 ranges
197*7f2fe78bSCy Schubert              * but might not appear if WinSock is not initialized
198*7f2fe78bSCy Schubert              */
199*7f2fe78bSCy Schubert             if (code >= WSABASEERR && code < WSABASEERR + 1100) {
200*7f2fe78bSCy Schubert                 table_num = 0;
201*7f2fe78bSCy Schubert                 offset = code;
202*7f2fe78bSCy Schubert                 divisor = 10000;
203*7f2fe78bSCy Schubert             }
204*7f2fe78bSCy Schubert 
205*7f2fe78bSCy Schubert             goto oops;
206*7f2fe78bSCy Schubert         } else {
207*7f2fe78bSCy Schubert             char *buffer;
208*7f2fe78bSCy Schubert             cp = get_thread_buffer();
209*7f2fe78bSCy Schubert             if (cp == NULL)
210*7f2fe78bSCy Schubert                 return "Unknown error code";
211*7f2fe78bSCy Schubert             buffer = cp;
212*7f2fe78bSCy Schubert             strncpy(buffer, msgbuf, ET_EBUFSIZ);
213*7f2fe78bSCy Schubert             buffer[ET_EBUFSIZ-1] = '\0';
214*7f2fe78bSCy Schubert             cp = buffer + strlen(buffer) - 1;
215*7f2fe78bSCy Schubert             if (*cp == '\n') *cp-- = '\0';
216*7f2fe78bSCy Schubert             if (*cp == '\r') *cp-- = '\0';
217*7f2fe78bSCy Schubert             if (*cp == '.') *cp-- = '\0';
218*7f2fe78bSCy Schubert 
219*7f2fe78bSCy Schubert             LocalFree(msgbuf);
220*7f2fe78bSCy Schubert             return buffer;
221*7f2fe78bSCy Schubert         }
222*7f2fe78bSCy Schubert     }
223*7f2fe78bSCy Schubert #endif
224*7f2fe78bSCy Schubert 
225*7f2fe78bSCy Schubert oops:
226*7f2fe78bSCy Schubert 
227*7f2fe78bSCy Schubert     cp = get_thread_buffer();
228*7f2fe78bSCy Schubert     if (cp == NULL)
229*7f2fe78bSCy Schubert         return "Unknown error code";
230*7f2fe78bSCy Schubert     cp1 = cp;
231*7f2fe78bSCy Schubert     strlcpy(cp, "Unknown code ", ET_EBUFSIZ);
232*7f2fe78bSCy Schubert     cp += sizeof("Unknown code ") - 1;
233*7f2fe78bSCy Schubert     if (table_num != 0L) {
234*7f2fe78bSCy Schubert         (void) error_table_name_r(table_num, cp);
235*7f2fe78bSCy Schubert         while (*cp != '\0')
236*7f2fe78bSCy Schubert             cp++;
237*7f2fe78bSCy Schubert         *cp++ = ' ';
238*7f2fe78bSCy Schubert     }
239*7f2fe78bSCy Schubert     while (divisor > 1) {
240*7f2fe78bSCy Schubert         if (started != 0 || offset >= divisor) {
241*7f2fe78bSCy Schubert             *cp++ = '0' + offset / divisor;
242*7f2fe78bSCy Schubert             offset %= divisor;
243*7f2fe78bSCy Schubert             started++;
244*7f2fe78bSCy Schubert         }
245*7f2fe78bSCy Schubert         divisor /= 10;
246*7f2fe78bSCy Schubert     }
247*7f2fe78bSCy Schubert     *cp++ = '0' + offset;
248*7f2fe78bSCy Schubert     *cp = '\0';
249*7f2fe78bSCy Schubert     return(cp1);
250*7f2fe78bSCy Schubert }
251*7f2fe78bSCy Schubert 
252*7f2fe78bSCy Schubert errcode_t KRB5_CALLCONV
add_error_table(const struct error_table * et)253*7f2fe78bSCy Schubert add_error_table(const struct error_table *et)
254*7f2fe78bSCy Schubert {
255*7f2fe78bSCy Schubert     struct et_list *e;
256*7f2fe78bSCy Schubert 
257*7f2fe78bSCy Schubert     if (CALL_INIT_FUNCTION(com_err_initialize))
258*7f2fe78bSCy Schubert         return 0;
259*7f2fe78bSCy Schubert 
260*7f2fe78bSCy Schubert     e = malloc(sizeof(struct et_list));
261*7f2fe78bSCy Schubert     if (e == NULL)
262*7f2fe78bSCy Schubert         return ENOMEM;
263*7f2fe78bSCy Schubert 
264*7f2fe78bSCy Schubert     e->table = et;
265*7f2fe78bSCy Schubert 
266*7f2fe78bSCy Schubert     k5_mutex_lock(&et_list_lock);
267*7f2fe78bSCy Schubert     e->next = et_list;
268*7f2fe78bSCy Schubert     et_list = e;
269*7f2fe78bSCy Schubert 
270*7f2fe78bSCy Schubert     /* If there are two strings at the end of the table, they are a text domain
271*7f2fe78bSCy Schubert      * and locale dir, and we are supposed to call bindtextdomain. */
272*7f2fe78bSCy Schubert     if (et->msgs[et->n_msgs] != NULL && et->msgs[et->n_msgs + 1] != NULL)
273*7f2fe78bSCy Schubert         bindtextdomain(et->msgs[et->n_msgs], et->msgs[et->n_msgs + 1]);
274*7f2fe78bSCy Schubert 
275*7f2fe78bSCy Schubert     k5_mutex_unlock(&et_list_lock);
276*7f2fe78bSCy Schubert     return 0;
277*7f2fe78bSCy Schubert }
278*7f2fe78bSCy Schubert 
279*7f2fe78bSCy Schubert errcode_t KRB5_CALLCONV
remove_error_table(const struct error_table * et)280*7f2fe78bSCy Schubert remove_error_table(const struct error_table *et)
281*7f2fe78bSCy Schubert {
282*7f2fe78bSCy Schubert     struct et_list **ep, *e;
283*7f2fe78bSCy Schubert 
284*7f2fe78bSCy Schubert     /* Safety check in case libraries are finalized in the wrong order. */
285*7f2fe78bSCy Schubert     if (terminated)
286*7f2fe78bSCy Schubert         return ENOENT;
287*7f2fe78bSCy Schubert 
288*7f2fe78bSCy Schubert     if (CALL_INIT_FUNCTION(com_err_initialize))
289*7f2fe78bSCy Schubert         return 0;
290*7f2fe78bSCy Schubert     k5_mutex_lock(&et_list_lock);
291*7f2fe78bSCy Schubert 
292*7f2fe78bSCy Schubert     /* Remove the entry that matches the error table instance. */
293*7f2fe78bSCy Schubert     for (ep = &et_list; *ep; ep = &(*ep)->next) {
294*7f2fe78bSCy Schubert         if ((*ep)->table == et) {
295*7f2fe78bSCy Schubert             e = *ep;
296*7f2fe78bSCy Schubert             *ep = e->next;
297*7f2fe78bSCy Schubert             free(e);
298*7f2fe78bSCy Schubert             k5_mutex_unlock(&et_list_lock);
299*7f2fe78bSCy Schubert             return 0;
300*7f2fe78bSCy Schubert         }
301*7f2fe78bSCy Schubert     }
302*7f2fe78bSCy Schubert     k5_mutex_unlock(&et_list_lock);
303*7f2fe78bSCy Schubert     return ENOENT;
304*7f2fe78bSCy Schubert }
305*7f2fe78bSCy Schubert 
com_err_finish_init()306*7f2fe78bSCy Schubert int com_err_finish_init()
307*7f2fe78bSCy Schubert {
308*7f2fe78bSCy Schubert     return CALL_INIT_FUNCTION(com_err_initialize);
309*7f2fe78bSCy Schubert }
310