Coverage Report

Created: 2026-08-31 06:25

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