1/*
2 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "hx_locl.h"
35
36/**
37 * @page page_error Hx509 error reporting functions
38 *
39 * See the library functions here: @ref hx509_error
40 */
41
42struct hx509_error_data {
43    hx509_error next;
44    int code;
45    char *msg;
46};
47
48/**
49 * Resets the error strings the hx509 context.
50 *
51 * @param context A hx509 context.
52 *
53 * @ingroup hx509_error
54 */
55
56void
57hx509_clear_error_string(hx509_context context)
58{
59    if (context) {
60	heim_release(context->error);
61	context->error = NULL;
62    }
63}
64
65/**
66 * Add an error message to the hx509 context.
67 *
68 * @param context A hx509 context.
69 * @param flags
70 * - HX509_ERROR_APPEND appends the error string to the old messages
71     (code is updated).
72 * @param code error code related to error message
73 * @param fmt error message format
74 * @param ap arguments to error message format
75 *
76 * @ingroup hx509_error
77 */
78
79void
80hx509_set_error_stringv(hx509_context context, int flags, int code,
81			const char *fmt, va_list ap)
82{
83    heim_error_t msg;
84
85    if (context == NULL)
86	return;
87
88    msg = heim_error_createv(code, fmt, ap);
89    if (msg) {
90	if (flags & HX509_ERROR_APPEND)
91	    heim_error_append(msg, context->error);
92	heim_release(context->error);
93    }
94    context->error = msg;
95}
96
97/**
98 * See hx509_set_error_stringv().
99 *
100 * @param context A hx509 context.
101 * @param flags
102 * - HX509_ERROR_APPEND appends the error string to the old messages
103     (code is updated).
104 * @param code error code related to error message
105 * @param fmt error message format
106 * @param ... arguments to error message format
107 *
108 * @ingroup hx509_error
109 */
110
111void
112hx509_set_error_string(hx509_context context, int flags, int code,
113		       const char *fmt, ...)
114{
115    va_list ap;
116
117    va_start(ap, fmt);
118    hx509_set_error_stringv(context, flags, code, fmt, ap);
119    va_end(ap);
120}
121
122/**
123 * Get an error string from context associated with error_code.
124 *
125 * @param context A hx509 context.
126 * @param error_code Get error message for this error code.
127 *
128 * @return error string, free with hx509_free_error_string().
129 *
130 * @ingroup hx509_error
131 */
132
133char *
134hx509_get_error_string(hx509_context context, int error_code)
135{
136    heim_error_t msg = context->error;
137    heim_string_t s;
138    char *str = NULL;
139    const char *cstr;
140
141    if (msg == NULL || heim_error_get_code(msg) != error_code) {
142	char buf[256];
143
144	cstr = com_right_r(context->et_list, error_code, buf, sizeof(buf));
145	if (cstr)
146	    return strdup(cstr);
147	cstr = strerror(error_code);
148	if (cstr)
149	    return strdup(cstr);
150	if (asprintf(&str, "<unknown error: %d>", error_code) == -1)
151	    return NULL;
152	return str;
153    }
154
155    s = heim_error_copy_string(msg);
156    if (s) {
157	str = heim_string_copy_utf8(s);
158	heim_release(s);
159    }
160    return str;
161}
162
163/**
164 * Free error string returned by hx509_get_error_string().
165 *
166 * @param str error string to free.
167 *
168 * @ingroup hx509_error
169 */
170
171void
172hx509_free_error_string(char *str)
173{
174    free(str);
175}
176
177/**
178 * Print error message and fatally exit from error code
179 *
180 * @param context A hx509 context.
181 * @param exit_code exit() code from process.
182 * @param error_code Error code for the reason to exit.
183 * @param fmt format string with the exit message.
184 * @param ... argument to format string.
185 *
186 * @ingroup hx509_error
187 */
188
189void
190hx509_err(hx509_context context, int exit_code,
191	  int error_code, const char *fmt, ...)
192{
193    va_list ap;
194    const char *msg;
195    char *str;
196
197    va_start(ap, fmt);
198    vasprintf(&str, fmt, ap);
199    va_end(ap);
200    msg = hx509_get_error_string(context, error_code);
201    if (msg == NULL)
202	msg = "no error";
203
204    errx(exit_code, "%s: %s", str, msg);
205}
206