aboutsummaryrefslogtreecommitdiff
path: root/src/lib/kdb/err_handle.c
blob: 61f720eea20b4d1b5c820e110d3a77da71a812fb (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
/**********************************************************************
*
*	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 */

#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
#include "err_handle.h"
#include <assert.h>

krb5_errcode_2_string_func old_error_2_string = NULL;

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;

#ifdef HAVE_PTHREAD_H
static void tsd_key_destructor(void *data)
{
    free(data);
}

static pthread_key_t krb5_err_key;

static void init_err_handling( void )
{
    assert(!pthread_key_create(&krb5_err_key, tsd_key_destructor));
    old_error_2_string = error_message;
    error_message = krb5_get_err_string;
}

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*) pthread_getspecific(krb5_err_key);
    if( err_struct == NULL )
    {
	err_struct = calloc(sizeof(krb5_err_struct_t), 1);
	if( err_struct == NULL )
	    return ENOMEM;

	if((ret = pthread_setspecific(krb5_err_key, 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*) pthread_getspecific(krb5_err_key);
    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 */
    return old_error_2_string(err_code);
    
}

void krb5_clr_error()
{
    krb5_err_struct_t *err_struct;
    pthread_once(&krb5_key_create, init_err_handling);
    
    err_struct = (krb5_err_struct_t*) pthread_getspecific(krb5_err_key);
    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 )
    {
	old_error_2_string = error_message;
	error_message = krb5_get_err_string;
	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 */
    return old_error_2_string(err_code);
    
}

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