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