1 /* $NetBSD: error_string.c,v 1.1.1.2 2014/04/24 12:45:49 pettai Exp $ */ 2 3 /* 4 * Copyright (c) 2001, 2003, 2005 - 2006 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "krb5_locl.h" 37 38 #undef __attribute__ 39 #define __attribute__(x) 40 41 /** 42 * Clears the error message from the Kerberos 5 context. 43 * 44 * @param context The Kerberos 5 context to clear 45 * 46 * @ingroup krb5_error 47 */ 48 49 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 50 krb5_clear_error_message(krb5_context context) 51 { 52 HEIMDAL_MUTEX_lock(context->mutex); 53 if (context->error_string) 54 free(context->error_string); 55 context->error_code = 0; 56 context->error_string = NULL; 57 HEIMDAL_MUTEX_unlock(context->mutex); 58 } 59 60 /** 61 * Set the context full error string for a specific error code. 62 * The error that is stored should be internationalized. 63 * 64 * The if context is NULL, no error string is stored. 65 * 66 * @param context Kerberos 5 context 67 * @param ret The error code 68 * @param fmt Error string for the error code 69 * @param ... printf(3) style parameters. 70 * 71 * @ingroup krb5_error 72 */ 73 74 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 75 krb5_set_error_message(krb5_context context, krb5_error_code ret, 76 const char *fmt, ...) 77 __attribute__ ((format (printf, 3, 4))) 78 { 79 va_list ap; 80 81 va_start(ap, fmt); 82 krb5_vset_error_message (context, ret, fmt, ap); 83 va_end(ap); 84 } 85 86 /** 87 * Set the context full error string for a specific error code. 88 * 89 * The if context is NULL, no error string is stored. 90 * 91 * @param context Kerberos 5 context 92 * @param ret The error code 93 * @param fmt Error string for the error code 94 * @param args printf(3) style parameters. 95 * 96 * @ingroup krb5_error 97 */ 98 99 100 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 101 krb5_vset_error_message (krb5_context context, krb5_error_code ret, 102 const char *fmt, va_list args) 103 __attribute__ ((format (printf, 3, 0))) 104 { 105 int r; 106 107 if (context == NULL) 108 return; 109 110 HEIMDAL_MUTEX_lock(context->mutex); 111 if (context->error_string) { 112 free(context->error_string); 113 context->error_string = NULL; 114 } 115 context->error_code = ret; 116 r = vasprintf(&context->error_string, fmt, args); 117 if (r < 0) 118 context->error_string = NULL; 119 HEIMDAL_MUTEX_unlock(context->mutex); 120 } 121 122 /** 123 * Prepend the context full error string for a specific error code. 124 * The error that is stored should be internationalized. 125 * 126 * The if context is NULL, no error string is stored. 127 * 128 * @param context Kerberos 5 context 129 * @param ret The error code 130 * @param fmt Error string for the error code 131 * @param ... printf(3) style parameters. 132 * 133 * @ingroup krb5_error 134 */ 135 136 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 137 krb5_prepend_error_message(krb5_context context, krb5_error_code ret, 138 const char *fmt, ...) 139 __attribute__ ((format (printf, 3, 4))) 140 { 141 va_list ap; 142 143 va_start(ap, fmt); 144 krb5_vprepend_error_message(context, ret, fmt, ap); 145 va_end(ap); 146 } 147 148 /** 149 * Prepend the contexts's full error string for a specific error code. 150 * 151 * The if context is NULL, no error string is stored. 152 * 153 * @param context Kerberos 5 context 154 * @param ret The error code 155 * @param fmt Error string for the error code 156 * @param args printf(3) style parameters. 157 * 158 * @ingroup krb5_error 159 */ 160 161 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 162 krb5_vprepend_error_message(krb5_context context, krb5_error_code ret, 163 const char *fmt, va_list args) 164 __attribute__ ((format (printf, 3, 0))) 165 { 166 char *str = NULL, *str2 = NULL; 167 168 if (context == NULL) 169 return; 170 171 HEIMDAL_MUTEX_lock(context->mutex); 172 if (context->error_code != ret) { 173 HEIMDAL_MUTEX_unlock(context->mutex); 174 return; 175 } 176 if (vasprintf(&str, fmt, args) < 0 || str == NULL) { 177 HEIMDAL_MUTEX_unlock(context->mutex); 178 return; 179 } 180 if (context->error_string) { 181 int e; 182 183 e = asprintf(&str2, "%s: %s", str, context->error_string); 184 free(context->error_string); 185 if (e < 0 || str2 == NULL) 186 context->error_string = NULL; 187 else 188 context->error_string = str2; 189 free(str); 190 } else 191 context->error_string = str; 192 HEIMDAL_MUTEX_unlock(context->mutex); 193 } 194 195 196 /** 197 * Return the error message in context. On error or no error string, 198 * the function returns NULL. 199 * 200 * @param context Kerberos 5 context 201 * 202 * @return an error string, needs to be freed with 203 * krb5_free_error_message(). The functions return NULL on error. 204 * 205 * @ingroup krb5_error 206 */ 207 208 KRB5_LIB_FUNCTION char * KRB5_LIB_CALL 209 krb5_get_error_string(krb5_context context) 210 { 211 char *ret = NULL; 212 213 HEIMDAL_MUTEX_lock(context->mutex); 214 if (context->error_string) 215 ret = strdup(context->error_string); 216 HEIMDAL_MUTEX_unlock(context->mutex); 217 return ret; 218 } 219 220 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 221 krb5_have_error_string(krb5_context context) 222 { 223 char *str; 224 HEIMDAL_MUTEX_lock(context->mutex); 225 str = context->error_string; 226 HEIMDAL_MUTEX_unlock(context->mutex); 227 return str != NULL; 228 } 229 230 /** 231 * Return the error message for `code' in context. On memory 232 * allocation error the function returns NULL. 233 * 234 * @param context Kerberos 5 context 235 * @param code Error code related to the error 236 * 237 * @return an error string, needs to be freed with 238 * krb5_free_error_message(). The functions return NULL on error. 239 * 240 * @ingroup krb5_error 241 */ 242 243 KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL 244 krb5_get_error_message(krb5_context context, krb5_error_code code) 245 { 246 char *str = NULL; 247 const char *cstr = NULL; 248 char buf[128]; 249 int free_context = 0; 250 251 if (code == 0) 252 return strdup("Success"); 253 254 /* 255 * The MIT version of this function ignores the krb5_context 256 * and several widely deployed applications call krb5_get_error_message() 257 * with a NULL context in order to translate an error code as a 258 * replacement for error_message(). Another reason a NULL context 259 * might be provided is if the krb5_init_context() call itself 260 * failed. 261 */ 262 if (context) 263 { 264 HEIMDAL_MUTEX_lock(context->mutex); 265 if (context->error_string && 266 (code == context->error_code || context->error_code == 0)) 267 { 268 str = strdup(context->error_string); 269 } 270 HEIMDAL_MUTEX_unlock(context->mutex); 271 272 if (str) 273 return str; 274 } 275 else 276 { 277 if (krb5_init_context(&context) == 0) 278 free_context = 1; 279 } 280 281 if (context) 282 cstr = com_right_r(context->et_list, code, buf, sizeof(buf)); 283 284 if (free_context) 285 krb5_free_context(context); 286 287 if (cstr) 288 return strdup(cstr); 289 290 cstr = error_message(code); 291 if (cstr) 292 return strdup(cstr); 293 294 if (asprintf(&str, "<unknown error: %d>", (int)code) == -1 || str == NULL) 295 return NULL; 296 297 return str; 298 } 299 300 301 /** 302 * Free the error message returned by krb5_get_error_message(). 303 * 304 * @param context Kerberos context 305 * @param msg error message to free, returned byg 306 * krb5_get_error_message(). 307 * 308 * @ingroup krb5_error 309 */ 310 311 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 312 krb5_free_error_message(krb5_context context, const char *msg) 313 { 314 free(rk_UNCONST(msg)); 315 } 316 317 318 /** 319 * Return the error string for the error code. The caller must not 320 * free the string. 321 * 322 * This function is deprecated since its not threadsafe. 323 * 324 * @param context Kerberos 5 context. 325 * @param code Kerberos error code. 326 * 327 * @return the error message matching code 328 * 329 * @ingroup krb5 330 */ 331 332 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 333 krb5_get_err_text(krb5_context context, krb5_error_code code) 334 KRB5_DEPRECATED_FUNCTION("Use X instead") 335 { 336 const char *p = NULL; 337 if(context != NULL) 338 p = com_right(context->et_list, code); 339 if(p == NULL) 340 p = strerror(code); 341 if (p == NULL) 342 p = "Unknown error"; 343 return p; 344 } 345