178527Sassar/* 2233294Sstas * Copyright (c) 2001, 2003, 2005 - 2006 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 578527Sassar * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 978527Sassar * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1278527Sassar * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1678527Sassar * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2078527Sassar * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3278527Sassar */ 3378527Sassar 3478527Sassar#include "krb5_locl.h" 3578527Sassar 3678527Sassar#undef __attribute__ 37233294Sstas#define __attribute__(x) 3878527Sassar 39233294Sstas/** 40233294Sstas * Clears the error message from the Kerberos 5 context. 41233294Sstas * 42233294Sstas * @param context The Kerberos 5 context to clear 43233294Sstas * 44233294Sstas * @ingroup krb5_error 45233294Sstas */ 46233294Sstas 47233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL 48233294Sstaskrb5_clear_error_message(krb5_context context) 4978527Sassar{ 50178825Sdfr HEIMDAL_MUTEX_lock(context->mutex); 51233294Sstas if (context->error_string) 52233294Sstas free(context->error_string); 53233294Sstas context->error_code = 0; 54233294Sstas context->error_string = NULL; 55178825Sdfr HEIMDAL_MUTEX_unlock(context->mutex); 5678527Sassar} 5778527Sassar 58233294Sstas/** 59233294Sstas * Set the context full error string for a specific error code. 60233294Sstas * The error that is stored should be internationalized. 61233294Sstas * 62233294Sstas * The if context is NULL, no error string is stored. 63233294Sstas * 64233294Sstas * @param context Kerberos 5 context 65233294Sstas * @param ret The error code 66233294Sstas * @param fmt Error string for the error code 67233294Sstas * @param ... printf(3) style parameters. 68233294Sstas * 69233294Sstas * @ingroup krb5_error 70233294Sstas */ 71233294Sstas 72233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL 73233294Sstaskrb5_set_error_message(krb5_context context, krb5_error_code ret, 74233294Sstas const char *fmt, ...) 75233294Sstas __attribute__ ((format (printf, 3, 4))) 7678527Sassar{ 77233294Sstas va_list ap; 78233294Sstas 79233294Sstas va_start(ap, fmt); 80233294Sstas krb5_vset_error_message (context, ret, fmt, ap); 81233294Sstas va_end(ap); 82233294Sstas} 83233294Sstas 84233294Sstas/** 85233294Sstas * Set the context full error string for a specific error code. 86233294Sstas * 87233294Sstas * The if context is NULL, no error string is stored. 88233294Sstas * 89233294Sstas * @param context Kerberos 5 context 90233294Sstas * @param ret The error code 91233294Sstas * @param fmt Error string for the error code 92233294Sstas * @param args printf(3) style parameters. 93233294Sstas * 94233294Sstas * @ingroup krb5_error 95233294Sstas */ 96233294Sstas 97233294Sstas 98233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL 99233294Sstaskrb5_vset_error_message (krb5_context context, krb5_error_code ret, 100233294Sstas const char *fmt, va_list args) 101233294Sstas __attribute__ ((format (printf, 3, 0))) 102233294Sstas{ 103233294Sstas int r; 104233294Sstas 105233294Sstas if (context == NULL) 106233294Sstas return; 107233294Sstas 108178825Sdfr HEIMDAL_MUTEX_lock(context->mutex); 109233294Sstas if (context->error_string) { 11078527Sassar free(context->error_string); 111233294Sstas context->error_string = NULL; 112233294Sstas } 113233294Sstas context->error_code = ret; 114233294Sstas r = vasprintf(&context->error_string, fmt, args); 115233294Sstas if (r < 0) 116233294Sstas context->error_string = NULL; 117178825Sdfr HEIMDAL_MUTEX_unlock(context->mutex); 11878527Sassar} 11978527Sassar 120233294Sstas/** 121233294Sstas * Prepend the context full error string for a specific error code. 122233294Sstas * The error that is stored should be internationalized. 123233294Sstas * 124233294Sstas * The if context is NULL, no error string is stored. 125233294Sstas * 126233294Sstas * @param context Kerberos 5 context 127233294Sstas * @param ret The error code 128233294Sstas * @param fmt Error string for the error code 129233294Sstas * @param ... printf(3) style parameters. 130233294Sstas * 131233294Sstas * @ingroup krb5_error 132233294Sstas */ 133233294Sstas 134233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL 135233294Sstaskrb5_prepend_error_message(krb5_context context, krb5_error_code ret, 136233294Sstas const char *fmt, ...) 137233294Sstas __attribute__ ((format (printf, 3, 4))) 13878527Sassar{ 13978527Sassar va_list ap; 14078527Sassar 14178527Sassar va_start(ap, fmt); 142233294Sstas krb5_vprepend_error_message(context, ret, fmt, ap); 14378527Sassar va_end(ap); 14478527Sassar} 14578527Sassar 146233294Sstas/** 147233294Sstas * Prepend the contexts's full error string for a specific error code. 148233294Sstas * 149233294Sstas * The if context is NULL, no error string is stored. 150233294Sstas * 151233294Sstas * @param context Kerberos 5 context 152233294Sstas * @param ret The error code 153233294Sstas * @param fmt Error string for the error code 154233294Sstas * @param args printf(3) style parameters. 155233294Sstas * 156233294Sstas * @ingroup krb5_error 157233294Sstas */ 158233294Sstas 159233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL 160233294Sstaskrb5_vprepend_error_message(krb5_context context, krb5_error_code ret, 161233294Sstas const char *fmt, va_list args) 162233294Sstas __attribute__ ((format (printf, 3, 0))) 16378527Sassar{ 164233294Sstas char *str = NULL, *str2 = NULL; 165233294Sstas 166233294Sstas if (context == NULL) 167233294Sstas return; 168233294Sstas 169178825Sdfr HEIMDAL_MUTEX_lock(context->mutex); 170233294Sstas if (context->error_code != ret) { 171233294Sstas HEIMDAL_MUTEX_unlock(context->mutex); 172233294Sstas return; 17378527Sassar } 174233294Sstas if (vasprintf(&str, fmt, args) < 0 || str == NULL) { 175233294Sstas HEIMDAL_MUTEX_unlock(context->mutex); 176233294Sstas return; 177233294Sstas } 178233294Sstas if (context->error_string) { 179233294Sstas int e; 180233294Sstas 181233294Sstas e = asprintf(&str2, "%s: %s", str, context->error_string); 182233294Sstas free(context->error_string); 183233294Sstas if (e < 0 || str2 == NULL) 184233294Sstas context->error_string = NULL; 185233294Sstas else 186233294Sstas context->error_string = str2; 187233294Sstas free(str); 188233294Sstas } else 189233294Sstas context->error_string = str; 190178825Sdfr HEIMDAL_MUTEX_unlock(context->mutex); 19178527Sassar} 19278527Sassar 193233294Sstas 194178825Sdfr/** 195178825Sdfr * Return the error message in context. On error or no error string, 196178825Sdfr * the function returns NULL. 197178825Sdfr * 198178825Sdfr * @param context Kerberos 5 context 199178825Sdfr * 200178825Sdfr * @return an error string, needs to be freed with 201233294Sstas * krb5_free_error_message(). The functions return NULL on error. 202178825Sdfr * 203178825Sdfr * @ingroup krb5_error 204178825Sdfr */ 205178825Sdfr 206233294SstasKRB5_LIB_FUNCTION char * KRB5_LIB_CALL 20778527Sassarkrb5_get_error_string(krb5_context context) 20878527Sassar{ 209178825Sdfr char *ret = NULL; 210178825Sdfr 211178825Sdfr HEIMDAL_MUTEX_lock(context->mutex); 212178825Sdfr if (context->error_string) 213178825Sdfr ret = strdup(context->error_string); 214178825Sdfr HEIMDAL_MUTEX_unlock(context->mutex); 21578527Sassar return ret; 21678527Sassar} 21778527Sassar 218233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 21978527Sassarkrb5_have_error_string(krb5_context context) 22078527Sassar{ 221178825Sdfr char *str; 222178825Sdfr HEIMDAL_MUTEX_lock(context->mutex); 223178825Sdfr str = context->error_string; 224178825Sdfr HEIMDAL_MUTEX_unlock(context->mutex); 225178825Sdfr return str != NULL; 22678527Sassar} 227178825Sdfr 228178825Sdfr/** 229233294Sstas * Return the error message for `code' in context. On memory 230233294Sstas * allocation error the function returns NULL. 231178825Sdfr * 232178825Sdfr * @param context Kerberos 5 context 233178825Sdfr * @param code Error code related to the error 234178825Sdfr * 235178825Sdfr * @return an error string, needs to be freed with 236233294Sstas * krb5_free_error_message(). The functions return NULL on error. 237178825Sdfr * 238178825Sdfr * @ingroup krb5_error 239178825Sdfr */ 240178825Sdfr 241233294SstasKRB5_LIB_FUNCTION const char * KRB5_LIB_CALL 242178825Sdfrkrb5_get_error_message(krb5_context context, krb5_error_code code) 243178825Sdfr{ 244233294Sstas char *str = NULL; 245233294Sstas const char *cstr = NULL; 246233294Sstas char buf[128]; 247233294Sstas int free_context = 0; 248178825Sdfr 249233294Sstas if (code == 0) 250233294Sstas return strdup("Success"); 251178825Sdfr 252233294Sstas /* 253233294Sstas * The MIT version of this function ignores the krb5_context 254233294Sstas * and several widely deployed applications call krb5_get_error_message() 255233294Sstas * with a NULL context in order to translate an error code as a 256233294Sstas * replacement for error_message(). Another reason a NULL context 257233294Sstas * might be provided is if the krb5_init_context() call itself 258233294Sstas * failed. 259233294Sstas */ 260233294Sstas if (context) 261233294Sstas { 262233294Sstas HEIMDAL_MUTEX_lock(context->mutex); 263233294Sstas if (context->error_string && 264233294Sstas (code == context->error_code || context->error_code == 0)) 265233294Sstas { 266233294Sstas str = strdup(context->error_string); 267233294Sstas } 268233294Sstas HEIMDAL_MUTEX_unlock(context->mutex); 269233294Sstas 270233294Sstas if (str) 271233294Sstas return str; 272233294Sstas } 273233294Sstas else 274233294Sstas { 275233294Sstas if (krb5_init_context(&context) == 0) 276233294Sstas free_context = 1; 277233294Sstas } 278233294Sstas 279233294Sstas if (context) 280233294Sstas cstr = com_right_r(context->et_list, code, buf, sizeof(buf)); 281233294Sstas 282233294Sstas if (free_context) 283233294Sstas krb5_free_context(context); 284233294Sstas 285178825Sdfr if (cstr) 286233294Sstas return strdup(cstr); 287178825Sdfr 288233294Sstas cstr = error_message(code); 289233294Sstas if (cstr) 290233294Sstas return strdup(cstr); 291233294Sstas 292233294Sstas if (asprintf(&str, "<unknown error: %d>", (int)code) == -1 || str == NULL) 293178825Sdfr return NULL; 294178825Sdfr 295178825Sdfr return str; 296178825Sdfr} 297178825Sdfr 298233294Sstas 299233294Sstas/** 300233294Sstas * Free the error message returned by krb5_get_error_message(). 301233294Sstas * 302233294Sstas * @param context Kerberos context 303233294Sstas * @param msg error message to free, returned byg 304233294Sstas * krb5_get_error_message(). 305233294Sstas * 306233294Sstas * @ingroup krb5_error 307233294Sstas */ 308233294Sstas 309233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL 310233294Sstaskrb5_free_error_message(krb5_context context, const char *msg) 311233294Sstas{ 312233294Sstas free(rk_UNCONST(msg)); 313233294Sstas} 314233294Sstas 315233294Sstas 316233294Sstas/** 317233294Sstas * Return the error string for the error code. The caller must not 318233294Sstas * free the string. 319233294Sstas * 320233294Sstas * This function is deprecated since its not threadsafe. 321233294Sstas * 322233294Sstas * @param context Kerberos 5 context. 323233294Sstas * @param code Kerberos error code. 324233294Sstas * 325233294Sstas * @return the error message matching code 326233294Sstas * 327233294Sstas * @ingroup krb5 328233294Sstas */ 329233294Sstas 330233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 331233294Sstaskrb5_get_err_text(krb5_context context, krb5_error_code code) 332233294Sstas KRB5_DEPRECATED_FUNCTION("Use X instead") 333233294Sstas{ 334233294Sstas const char *p = NULL; 335233294Sstas if(context != NULL) 336233294Sstas p = com_right(context->et_list, code); 337233294Sstas if(p == NULL) 338233294Sstas p = strerror(code); 339233294Sstas if (p == NULL) 340233294Sstas p = "Unknown error"; 341233294Sstas return p; 342233294Sstas} 343