summaryrefslogtreecommitdiffstats
path: root/src/lib/kdb/err_handle.c
blob: 50b8a2a65e53afbb903e2eaff158f07c5a07dba7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/**********************************************************************
*
*	C %name:		err_handle.c %
*	Instance:		idc_sec_1
*	Description:	
*	%created_by:	spradeep %
*	%date_created:	Thu Apr  7 14:05:00 2005 %
*
**********************************************************************/
#ifndef lint
static char *_csrc =
    "@(#) %filespec: err_handle.c~1 %  (%full_filespec: err_handle.c~1:csrc:idc_sec#1 %)";
#endif

/* This file should be ideally be in util/et.  But, for now thread
   safety requirement stops me from putting there.  if I do, then all
   the applications have to link to pthread.  */

#include "autoconf.h"
#if defined(ENABLE_THREADS) && defined(HAVE_PTHREAD_H)
#include <pthread.h>
#endif
#include "err_handle.h"
#include <assert.h>

#ifdef NOVELL
krb5_errcode_2_string_func old_error_2_string = NULL;
#endif

typedef struct
{
    char    krb5_err_str[KRB5_MAX_ERR_STR + 1];
    long    err_code;
    krb5_err_subsystem subsystem;
    krb5_context kcontext;
} krb5_err_struct_t;

#if defined(ENABLE_THREADS) && defined(HAVE_PTHREAD_H)
static void
tsd_key_destructor(void *data)
{
    free(data);
}

static void
init_err_handling(void)
{
    assert(!k5_key_register(K5_KEY_KDB_ERR_HANDLER, tsd_key_destructor));
#ifdef NOVELL
    old_error_2_string = error_message;
    error_message = krb5_get_err_string;
#endif
}

static pthread_once_t krb5_key_create = PTHREAD_ONCE_INIT;

krb5_error_code
krb5_set_err(krb5_context kcontext, krb5_err_subsystem subsystem,
	     long err_code, char *str)
{
    int     ret;
    krb5_err_struct_t *err_struct;
    pthread_once(&krb5_key_create, init_err_handling);

    err_struct = (krb5_err_struct_t *) k5_getspecific(K5_KEY_KDB_ERR_HANDLER);
    if (err_struct == NULL) {
	err_struct = calloc(sizeof(krb5_err_struct_t), 1);
	if (err_struct == NULL)
	    return ENOMEM;

	if ((ret = k5_setspecific(K5_KEY_KDB_ERR_HANDLER, err_struct))) {
	    free(err_struct);
	    return ret;
	}
    }

    err_struct->subsystem = subsystem;
    err_struct->err_code = err_code;
    err_struct->kcontext = kcontext;
    if (err_struct->subsystem == krb5_err_have_str) {
	strncpy(err_struct->krb5_err_str, str,
		sizeof(err_struct->krb5_err_str));
	err_struct->krb5_err_str[KRB5_MAX_ERR_STR] = '\0';
    }

    return 0;
}

const char *KRB5_CALLCONV
krb5_get_err_string(long err_code)
{
    krb5_err_struct_t *err_struct;
    pthread_once(&krb5_key_create, init_err_handling);

    err_struct = (krb5_err_struct_t *) k5_getspecific(K5_KEY_KDB_ERR_HANDLER);
    if (err_struct && (err_struct->subsystem == krb5_err_have_str)
	&& (err_code == err_struct->err_code)) {
	/* Checking error code is for safety.
	   In case, the caller ignores a database error and calls
	   other calls before doing com_err.  Though not perfect,
	   caller should call krb5_clr_error before this.  */
	err_struct->subsystem = krb5_err_unknown;
	return err_struct->krb5_err_str;
    }

    if (err_struct && (err_struct->subsystem == krb5_err_db)
	&& (err_code == err_struct->err_code)) {
	err_struct->subsystem = krb5_err_unknown;
	return krb5_db_errcode2string(err_struct->kcontext, err_code);
    }

    /* Error strings are not generated here. the remaining two cases
       are handled by the default error string convertor.  */
#ifdef NOVELL
    return old_error_2_string(err_code);
#else
    return error_message(err_code);
#endif
}

void
krb5_clr_error()
{
    krb5_err_struct_t *err_struct;
    pthread_once(&krb5_key_create, init_err_handling);

    err_struct = (krb5_err_struct_t *) k5_getspecific(K5_KEY_KDB_ERR_HANDLER);
    if (err_struct)
	err_struct->subsystem = krb5_err_unknown;
}

#else
krb5_err_struct_t krb5_err = { {0}, 0, 0, 0 };
krb5_boolean krb5_init_once = TRUE;

static void
init_err_handling(void)
{
    if (krb5_init_once) {
#ifdef NOVELL
	old_error_2_string = error_message;
	error_message = krb5_get_err_string;
#endif
	krb5_init_once = FALSE;
    }
}

krb5_error_code
krb5_set_err(krb5_context kcontext, krb5_err_subsystem subsystem,
	     long err_code, char *str)
{
    krb5_err_struct_t *err_struct = &krb5_err;

    init_err_handling();	/* takes care for multiple inits */

    err_struct->subsystem = subsystem;
    err_struct->err_code = err_code;
    err_struct->kcontext = kcontext;
    if (err_struct->subsystem == krb5_err_have_str) {
	strncpy(err_struct->krb5_err_str, str,
		sizeof(err_struct->krb5_err_str));
	err_struct->krb5_err_str[KRB5_MAX_ERR_STR] = '\0';
    }

    return 0;
}

const char *KRB5_CALLCONV
krb5_get_err_string(long err_code)
{
    krb5_err_struct_t *err_struct = &krb5_err;

    init_err_handling();	/* takes care for multiple inits */

    if ((err_struct->subsystem == krb5_err_have_str)
	&& (err_code == err_struct->err_code)) {
	/* checking error code is for safety.
	   In case, the caller ignores a database error and calls
	   other calls before doing com_err.  Though not perfect,
	   caller should call krb5_clr_error before this.  */
	err_struct->subsystem = krb5_err_unknown;
	return err_struct->krb5_err_str;
    }

    if ((err_struct->subsystem == krb5_err_db)
	&& (err_code == err_struct->err_code)) {
	err_struct->subsystem = krb5_err_unknown;
	return krb5_db_errcode2string(err_struct->kcontext, err_code);
    }

    /* It is not generated here. the remaining two cases are handled
       by the default error string convertor.  */
#ifdef NOVELL
    return old_error_2_string(err_code);
#else
    return error_message(err_code);
#endif
}

void
krb5_clr_error()
{
    krb5_err_struct_t *err_struct = &krb5_err;

    init_err_handling();	/* takes care for multiple inits */

    err_struct->subsystem = krb5_err_unknown;
}

#endif