xref: /freebsd/crypto/krb5/src/lib/krb5/krb/kerrs.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/kerrs.c - Error message functions */
3 /*
4  * Copyright 2006 Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26 
27 #include "k5-int.h"
28 #include "int-proto.h"
29 
30 #ifdef DEBUG
31 static int error_message_debug = 0;
32 #ifndef ERROR_MESSAGE_DEBUG
33 #define ERROR_MESSAGE_DEBUG() (error_message_debug != 0)
34 #endif
35 #endif
36 
37 void KRB5_CALLCONV_C
krb5_set_error_message(krb5_context ctx,krb5_error_code code,const char * fmt,...)38 krb5_set_error_message(krb5_context ctx, krb5_error_code code,
39                        const char *fmt, ...)
40 {
41     va_list args;
42 
43     if (ctx == NULL)
44         return;
45     va_start(args, fmt);
46 #ifdef DEBUG
47     if (ERROR_MESSAGE_DEBUG()) {
48         fprintf(stderr,
49                 "krb5_set_error_message(ctx=%p/err=%p, code=%ld, ...)\n",
50                 ctx, &ctx->err, (long)code);
51     }
52 #endif
53     k5_vset_error(&ctx->err, code, fmt, args);
54 #ifdef DEBUG
55     if (ERROR_MESSAGE_DEBUG())
56         fprintf(stderr, "->%s\n", ctx->err.msg);
57 #endif
58     va_end(args);
59 }
60 
61 void KRB5_CALLCONV
krb5_vset_error_message(krb5_context ctx,krb5_error_code code,const char * fmt,va_list args)62 krb5_vset_error_message(krb5_context ctx, krb5_error_code code,
63                         const char *fmt, va_list args)
64 {
65 #ifdef DEBUG
66     if (ERROR_MESSAGE_DEBUG()) {
67         fprintf(stderr, "krb5_vset_error_message(ctx=%p, code=%ld, ...)\n",
68                 ctx, (long)code);
69     }
70 #endif
71     if (ctx == NULL)
72         return;
73     k5_vset_error(&ctx->err, code, fmt, args);
74 #ifdef DEBUG
75     if (ERROR_MESSAGE_DEBUG())
76         fprintf(stderr, "->%s\n", ctx->err.msg);
77 #endif
78 }
79 
80 void KRB5_CALLCONV
krb5_prepend_error_message(krb5_context ctx,krb5_error_code code,const char * fmt,...)81 krb5_prepend_error_message(krb5_context ctx, krb5_error_code code,
82                            const char *fmt, ...)
83 {
84     va_list ap;
85 
86     va_start(ap, fmt);
87     krb5_vwrap_error_message(ctx, code, code, fmt, ap);
88     va_end(ap);
89 }
90 
91 void KRB5_CALLCONV
krb5_vprepend_error_message(krb5_context ctx,krb5_error_code code,const char * fmt,va_list ap)92 krb5_vprepend_error_message(krb5_context ctx, krb5_error_code code,
93                             const char *fmt, va_list ap)
94 {
95     krb5_wrap_error_message(ctx, code, code, fmt, ap);
96 }
97 
98 void KRB5_CALLCONV
krb5_wrap_error_message(krb5_context ctx,krb5_error_code old_code,krb5_error_code code,const char * fmt,...)99 krb5_wrap_error_message(krb5_context ctx, krb5_error_code old_code,
100                         krb5_error_code code, const char *fmt, ...)
101 {
102     va_list ap;
103 
104     va_start(ap, fmt);
105     krb5_vwrap_error_message(ctx, old_code, code, fmt, ap);
106     va_end(ap);
107 }
108 
109 void KRB5_CALLCONV
krb5_vwrap_error_message(krb5_context ctx,krb5_error_code old_code,krb5_error_code code,const char * fmt,va_list ap)110 krb5_vwrap_error_message(krb5_context ctx, krb5_error_code old_code,
111                          krb5_error_code code, const char *fmt, va_list ap)
112 {
113     const char *prev_msg;
114     char *prepend;
115 
116     if (ctx == NULL || vasprintf(&prepend, fmt, ap) < 0)
117         return;
118     prev_msg = k5_get_error(&ctx->err, old_code);
119     k5_set_error(&ctx->err, code, "%s: %s", prepend, prev_msg);
120     k5_free_error(&ctx->err, prev_msg);
121     free(prepend);
122 }
123 
124 /* Set the error message state of dest_ctx to that of src_ctx. */
125 void KRB5_CALLCONV
krb5_copy_error_message(krb5_context dest_ctx,krb5_context src_ctx)126 krb5_copy_error_message(krb5_context dest_ctx, krb5_context src_ctx)
127 {
128     if (dest_ctx == src_ctx)
129         return;
130     if (src_ctx->err.msg != NULL) {
131         k5_set_error(&dest_ctx->err, src_ctx->err.code, "%s",
132                      src_ctx->err.msg);
133     } else {
134         k5_clear_error(&dest_ctx->err);
135     }
136 }
137 
138 /* Re-format msg using the format string err_fmt.  Return an allocated result,
139  * or NULL if err_fmt is NULL or on allocation failure. */
140 static char *
err_fmt_fmt(const char * err_fmt,long code,const char * msg)141 err_fmt_fmt(const char *err_fmt, long code, const char *msg)
142 {
143     struct k5buf buf;
144     const char *p, *s;
145 
146     if (err_fmt == NULL)
147         return NULL;
148 
149     k5_buf_init_dynamic(&buf);
150 
151     s = err_fmt;
152     while ((p = strchr(s, '%')) != NULL) {
153         k5_buf_add_len(&buf, s, p - s);
154         s = p;
155         if (p[1] == '\0')
156             break;
157         else if (p[1] == 'M')
158             k5_buf_add(&buf, msg);
159         else if (p[1] == 'C')
160             k5_buf_add_fmt(&buf, "%ld", code);
161         else if (p[1] == '%')
162             k5_buf_add(&buf, "%");
163         else
164             k5_buf_add_fmt(&buf, "%%%c", p[1]);
165         s += 2;
166     }
167     k5_buf_add(&buf, s);        /* Remainder after last token */
168     return k5_buf_cstring(&buf);
169 }
170 
171 const char * KRB5_CALLCONV
krb5_get_error_message(krb5_context ctx,krb5_error_code code)172 krb5_get_error_message(krb5_context ctx, krb5_error_code code)
173 {
174     const char *std, *custom;
175 
176 #ifdef DEBUG
177     if (ERROR_MESSAGE_DEBUG())
178         fprintf(stderr, "krb5_get_error_message(%p, %ld)\n", ctx, (long)code);
179 #endif
180     if (ctx == NULL)
181         return error_message(code);
182 
183     std = k5_get_error(&ctx->err, code);
184     custom = err_fmt_fmt(ctx->err_fmt, code, std);
185     if (custom != NULL) {
186         free((char *)std);
187         return custom;
188     }
189     return std;
190 }
191 
192 void KRB5_CALLCONV
krb5_free_error_message(krb5_context ctx,const char * msg)193 krb5_free_error_message(krb5_context ctx, const char *msg)
194 {
195 #ifdef DEBUG
196     if (ERROR_MESSAGE_DEBUG())
197         fprintf(stderr, "krb5_free_error_message(%p, %p)\n", ctx, msg);
198 #endif
199     if (ctx == NULL)
200         return;
201     k5_free_error(&ctx->err, msg);
202 }
203 
204 void KRB5_CALLCONV
krb5_clear_error_message(krb5_context ctx)205 krb5_clear_error_message(krb5_context ctx)
206 {
207 #ifdef DEBUG
208     if (ERROR_MESSAGE_DEBUG())
209         fprintf(stderr, "krb5_clear_error_message(%p)\n", ctx);
210 #endif
211     if (ctx == NULL)
212         return;
213     k5_clear_error(&ctx->err);
214 }
215 
216 void
k5_save_ctx_error(krb5_context ctx,krb5_error_code code,struct errinfo * out)217 k5_save_ctx_error(krb5_context ctx, krb5_error_code code, struct errinfo *out)
218 {
219     out->code = code;
220     out->msg = NULL;
221     if (ctx != NULL && ctx->err.code == code) {
222         out->msg = ctx->err.msg;
223         ctx->err.code = 0;
224         ctx->err.msg = NULL;
225     }
226 }
227 
228 krb5_error_code
k5_restore_ctx_error(krb5_context ctx,struct errinfo * in)229 k5_restore_ctx_error(krb5_context ctx, struct errinfo *in)
230 {
231     krb5_error_code code = in->code;
232 
233     if (ctx != NULL) {
234         k5_clear_error(&ctx->err);
235         ctx->err.code = in->code;
236         ctx->err.msg = in->msg;
237         in->msg = NULL;
238     } else {
239         k5_clear_error(in);
240     }
241     return code;
242 }
243 
244 /* If ctx contains an extended error message for oldcode, change it to be an
245  * extended error message for newcode. */
246 void
k5_change_error_message_code(krb5_context ctx,krb5_error_code oldcode,krb5_error_code newcode)247 k5_change_error_message_code(krb5_context ctx, krb5_error_code oldcode,
248                              krb5_error_code newcode)
249 {
250     if (ctx != NULL && ctx->err.msg != NULL && ctx->err.code == oldcode)
251         ctx->err.code = newcode;
252 }
253