1/* $NetBSD: error_string.c,v 1.3 2019/12/15 22:50:50 christos 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 49KRB5_LIB_FUNCTION void KRB5_LIB_CALL 50krb5_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 74KRB5_LIB_FUNCTION void KRB5_LIB_CALL 75krb5_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 100KRB5_LIB_FUNCTION void KRB5_LIB_CALL 101krb5_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 if (context->error_string) 121 _krb5_debug(context, 100, "error message: %s: %d", context->error_string, ret); 122} 123 124/** 125 * Prepend the context full error string for a specific error code. 126 * The error that is stored should be internationalized. 127 * 128 * The if context is NULL, no error string is stored. 129 * 130 * @param context Kerberos 5 context 131 * @param ret The error code 132 * @param fmt Error string for the error code 133 * @param ... printf(3) style parameters. 134 * 135 * @ingroup krb5_error 136 */ 137 138KRB5_LIB_FUNCTION void KRB5_LIB_CALL 139krb5_prepend_error_message(krb5_context context, krb5_error_code ret, 140 const char *fmt, ...) 141 __attribute__ ((__format__ (__printf__, 3, 4))) 142{ 143 va_list ap; 144 145 va_start(ap, fmt); 146 krb5_vprepend_error_message(context, ret, fmt, ap); 147 va_end(ap); 148} 149 150/** 151 * Prepend the contexts's full error string for a specific error code. 152 * 153 * The if context is NULL, no error string is stored. 154 * 155 * @param context Kerberos 5 context 156 * @param ret The error code 157 * @param fmt Error string for the error code 158 * @param args printf(3) style parameters. 159 * 160 * @ingroup krb5_error 161 */ 162 163KRB5_LIB_FUNCTION void KRB5_LIB_CALL 164krb5_vprepend_error_message(krb5_context context, krb5_error_code ret, 165 const char *fmt, va_list args) 166 __attribute__ ((__format__ (__printf__, 3, 0))) 167{ 168 char *str = NULL, *str2 = NULL; 169 170 if (context == NULL) 171 return; 172 173 HEIMDAL_MUTEX_lock(&context->mutex); 174 if (context->error_code != ret) { 175 HEIMDAL_MUTEX_unlock(&context->mutex); 176 return; 177 } 178 if (vasprintf(&str, fmt, args) < 0 || str == NULL) { 179 HEIMDAL_MUTEX_unlock(&context->mutex); 180 return; 181 } 182 if (context->error_string) { 183 int e; 184 185 e = asprintf(&str2, "%s: %s", str, context->error_string); 186 free(context->error_string); 187 if (e < 0 || str2 == NULL) 188 context->error_string = NULL; 189 else 190 context->error_string = str2; 191 free(str); 192 } else 193 context->error_string = str; 194 HEIMDAL_MUTEX_unlock(&context->mutex); 195} 196 197/** 198 * Return the error message for `code' in context. On memory 199 * allocation error the function returns NULL. 200 * 201 * @param context Kerberos 5 context 202 * @param code Error code related to the error 203 * 204 * @return an error string, needs to be freed with 205 * krb5_free_error_message(). The functions return NULL on error. 206 * 207 * @ingroup krb5_error 208 */ 209 210KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL 211krb5_get_error_message(krb5_context context, krb5_error_code code) 212{ 213 char *str = NULL; 214 const char *cstr = NULL; 215 char buf[128]; 216 int free_context = 0; 217 218 if (code == 0) 219 return strdup("Success"); 220 221 /* 222 * The MIT version of this function ignores the krb5_context 223 * and several widely deployed applications call krb5_get_error_message() 224 * with a NULL context in order to translate an error code as a 225 * replacement for error_message(). Another reason a NULL context 226 * might be provided is if the krb5_init_context() call itself 227 * failed. 228 */ 229 if (context) 230 { 231 HEIMDAL_MUTEX_lock(&context->mutex); 232 if (context->error_string && 233 (code == context->error_code || context->error_code == 0)) 234 { 235 str = strdup(context->error_string); 236 } 237 HEIMDAL_MUTEX_unlock(&context->mutex); 238 239 if (str) 240 return str; 241 } 242 else 243 { 244 if (krb5_init_context(&context) == 0) 245 free_context = 1; 246 } 247 248 if (context) 249 cstr = com_right_r(context->et_list, code, buf, sizeof(buf)); 250 251 if (free_context) 252 krb5_free_context(context); 253 254 if (cstr) 255 return strdup(cstr); 256 257 cstr = error_message(code); 258 if (cstr) 259 return strdup(cstr); 260 261 if (asprintf(&str, "<unknown error: %d>", (int)code) == -1 || str == NULL) 262 return NULL; 263 264 return str; 265} 266 267 268/** 269 * Free the error message returned by krb5_get_error_message(). 270 * 271 * @param context Kerberos context 272 * @param msg error message to free, returned byg 273 * krb5_get_error_message(). 274 * 275 * @ingroup krb5_error 276 */ 277 278KRB5_LIB_FUNCTION void KRB5_LIB_CALL 279krb5_free_error_message(krb5_context context, const char *msg) 280{ 281 free(rk_UNCONST(msg)); 282} 283 284 285/** 286 * Return the error string for the error code. The caller must not 287 * free the string. 288 * 289 * This function is deprecated since its not threadsafe. 290 * 291 * @param context Kerberos 5 context. 292 * @param code Kerberos error code. 293 * 294 * @return the error message matching code 295 * 296 * @ingroup krb5 297 */ 298 299KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 300krb5_get_err_text(krb5_context context, krb5_error_code code) 301 KRB5_DEPRECATED_FUNCTION("Use krb5_get_error_message instead") 302{ 303 const char *p = NULL; 304 if(context != NULL) 305 p = com_right(context->et_list, code); 306 if(p == NULL) 307 p = strerror(code); 308 if (p == NULL) 309 p = "Unknown error"; 310 return p; 311} 312 313