1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Can't include krb5.h here, or k5-int.h which includes it, because krb5.h 4 * needs to be generated with error tables, after util/et, which builds after 5 * this directory. 6 */ 7 #include "k5-platform.h" 8 #include "k5-err.h" 9 #include "k5-thread.h" 10 #include "supp-int.h" 11 12 /* 13 * It would be nice to just use error_message() always. Pity that it's defined 14 * in a library that depends on this one, and we're not allowed to make 15 * circular dependencies. 16 */ 17 /* 18 * We really want a rwlock here, since we should hold it while calling the 19 * function and copying out its results. But I haven't implemented shims for 20 * rwlock yet. 21 */ 22 static k5_mutex_t krb5int_error_info_support_mutex = 23 K5_MUTEX_PARTIAL_INITIALIZER; 24 static const char *(KRB5_CALLCONV *fptr)(long); /* = &error_message */ 25 26 /* Fallback error message if we cannot allocate a copy of the real one. */ 27 static char *oom_msg = "Out of memory"; 28 29 int 30 krb5int_err_init (void) 31 { 32 return k5_mutex_finish_init(&krb5int_error_info_support_mutex); 33 } 34 #define initialize() krb5int_call_thread_support_init() 35 #define lock() k5_mutex_lock(&krb5int_error_info_support_mutex) 36 #define unlock() k5_mutex_unlock(&krb5int_error_info_support_mutex) 37 38 void 39 k5_set_error(struct errinfo *ep, long code, const char *fmt, ...) 40 { 41 va_list args; 42 43 va_start(args, fmt); 44 k5_vset_error(ep, code, fmt, args); 45 va_end(args); 46 } 47 48 void 49 k5_vset_error(struct errinfo *ep, long code, const char *fmt, va_list args) 50 { 51 char *str; 52 53 k5_clear_error(ep); 54 ep->code = code; 55 56 if (vasprintf(&str, fmt, args) < 0) 57 return; 58 ep->msg = str; 59 } 60 61 static inline const char * 62 oom_check(const char *str) 63 { 64 return (str == NULL) ? oom_msg : str; 65 } 66 67 const char * 68 k5_get_error(struct errinfo *ep, long code) 69 { 70 const char *r; 71 char buf[128]; 72 73 if (code == ep->code && ep->msg != NULL) 74 return oom_check(strdup(ep->msg)); 75 76 if (initialize()) 77 return oom_check(strdup(_("Kerberos library initialization failure"))); 78 79 lock(); 80 if (fptr == NULL) { 81 /* Should be rare; fptr should be set whenever libkrb5 is loaded. */ 82 unlock(); 83 return oom_check(strdup(_("Error code translation unavailable"))); 84 } 85 r = fptr(code); 86 #ifndef HAVE_COM_ERR_INTL 87 /* Translate com_err results here if libcom_err won't do it. */ 88 r = _(r); 89 #endif 90 if (r == NULL) { 91 unlock(); 92 snprintf(buf, sizeof(buf), _("error %ld"), code); 93 return oom_check(strdup(buf)); 94 } 95 96 r = strdup(r); 97 unlock(); 98 return oom_check(r); 99 } 100 101 void 102 k5_free_error(struct errinfo *ep, const char *msg) 103 { 104 if (msg != oom_msg) 105 free((char *)msg); 106 } 107 108 void 109 k5_clear_error(struct errinfo *ep) 110 { 111 k5_free_error(ep, ep->msg); 112 ep->msg = NULL; 113 } 114 115 void 116 k5_set_error_info_callout_fn(const char *(KRB5_CALLCONV *f)(long)) 117 { 118 initialize(); 119 lock(); 120 fptr = f; 121 unlock(); 122 } 123