r19603: Make it easier to control the debug level of smbd.
[ira/wip.git] / source4 / heimdal / lib / gssapi / krb5 / display_status.c
1 /*
2  * Copyright (c) 1998 - 2005 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 "krb5/gsskrb5_locl.h"
35
36 RCSID("$Id: display_status.c,v 1.16 2006/10/07 22:14:33 lha Exp $");
37
38 static const char *
39 calling_error(OM_uint32 v)
40 {
41     static const char *msgs[] = {
42         NULL,                   /* 0 */
43         "A required input parameter could not be read.", /*  */
44         "A required output parameter could not be written.", /*  */
45         "A parameter was malformed"
46     };
47
48     v >>= GSS_C_CALLING_ERROR_OFFSET;
49
50     if (v == 0)
51         return "";
52     else if (v >= sizeof(msgs)/sizeof(*msgs))
53         return "unknown calling error";
54     else
55         return msgs[v];
56 }
57
58 static const char *
59 routine_error(OM_uint32 v)
60 {
61     static const char *msgs[] = {
62         NULL,                   /* 0 */
63         "An unsupported mechanism was requested",
64         "An invalid name was supplied",
65         "A supplied name was of an unsupported type",
66         "Incorrect channel bindings were supplied",
67         "An invalid status code was supplied",
68         "A token had an invalid MIC",
69         "No credentials were supplied, "
70         "or the credentials were unavailable or inaccessible.",
71         "No context has been established",
72         "A token was invalid",
73         "A credential was invalid",
74         "The referenced credentials have expired",
75         "The context has expired",
76         "Miscellaneous failure (see text)",
77         "The quality-of-protection requested could not be provide",
78         "The operation is forbidden by local security policy",
79         "The operation or option is not available",
80         "The requested credential element already exists",
81         "The provided name was not a mechanism name.",
82     };
83
84     v >>= GSS_C_ROUTINE_ERROR_OFFSET;
85
86     if (v == 0)
87         return "";
88     else if (v >= sizeof(msgs)/sizeof(*msgs))
89         return "unknown routine error";
90     else
91         return msgs[v];
92 }
93
94 static const char *
95 supplementary_error(OM_uint32 v)
96 {
97     static const char *msgs[] = {
98         "normal completion",
99         "continuation call to routine required",
100         "duplicate per-message token detected",
101         "timed-out per-message token detected",
102         "reordered (early) per-message token detected",
103         "skipped predecessor token(s) detected"
104     };
105
106     v >>= GSS_C_SUPPLEMENTARY_OFFSET;
107
108     if (v >= sizeof(msgs)/sizeof(*msgs))
109         return "unknown routine error";
110     else
111         return msgs[v];
112 }
113
114 void
115 _gsskrb5_clear_status (void)
116 {
117     struct gssapi_thr_context *ctx = _gsskrb5_get_thread_context(1);
118     if (ctx == NULL)
119         return;
120     HEIMDAL_MUTEX_lock(&ctx->mutex);
121     if (ctx->error_string)
122         free(ctx->error_string);
123     ctx->error_string = NULL;
124     HEIMDAL_MUTEX_unlock(&ctx->mutex);
125 }
126
127 void
128 _gsskrb5_set_status (const char *fmt, ...)
129 {
130     struct gssapi_thr_context *ctx = _gsskrb5_get_thread_context(1);
131     va_list args;
132
133     if (ctx == NULL)
134         return;
135     HEIMDAL_MUTEX_lock(&ctx->mutex);
136     va_start(args, fmt);
137     if (ctx->error_string)
138         free(ctx->error_string);
139     /* ignore failures, will use status code instead */
140     vasprintf(&ctx->error_string, fmt, args);
141     va_end(args);
142     HEIMDAL_MUTEX_unlock(&ctx->mutex);
143 }
144
145 void
146 _gsskrb5_set_error_string (void)
147 {
148     char *e;
149
150     e = krb5_get_error_string(_gsskrb5_context);
151     if (e) {
152         _gsskrb5_set_status("%s", e);
153         krb5_free_error_string(_gsskrb5_context, e);
154     } else
155         _gsskrb5_clear_status();
156 }
157
158 char *
159 _gsskrb5_get_error_string (void)
160 {
161     struct gssapi_thr_context *ctx = _gsskrb5_get_thread_context(0);
162     char *ret;
163
164     if (ctx == NULL)
165         return NULL;
166     HEIMDAL_MUTEX_lock(&ctx->mutex);
167     ret = ctx->error_string;
168     ctx->error_string = NULL;
169     HEIMDAL_MUTEX_unlock(&ctx->mutex);
170     return ret;
171 }
172
173 OM_uint32 _gsskrb5_display_status
174            (OM_uint32           *minor_status,
175             OM_uint32            status_value,
176             int                  status_type,
177             const gss_OID        mech_type,
178             OM_uint32           *message_context,
179             gss_buffer_t         status_string)
180 {
181   char *buf;
182
183   GSSAPI_KRB5_INIT ();
184
185   status_string->length = 0;
186   status_string->value = NULL;
187
188   if (gss_oid_equal(mech_type, GSS_C_NO_OID) == 0 &&
189       gss_oid_equal(mech_type, GSS_KRB5_MECHANISM) == 0) {
190       *minor_status = 0;
191       return GSS_C_GSS_CODE;
192   }
193
194   if (status_type == GSS_C_GSS_CODE) {
195       if (GSS_SUPPLEMENTARY_INFO(status_value))
196           asprintf(&buf, "%s", 
197                    supplementary_error(GSS_SUPPLEMENTARY_INFO(status_value)));
198       else
199           asprintf (&buf, "%s %s",
200                     calling_error(GSS_CALLING_ERROR(status_value)),
201                     routine_error(GSS_ROUTINE_ERROR(status_value)));
202   } else if (status_type == GSS_C_MECH_CODE) {
203       buf = _gsskrb5_get_error_string ();
204       if (buf == NULL) {
205           const char *tmp = krb5_get_err_text (_gsskrb5_context,
206                                                status_value);
207           if (tmp == NULL)
208               asprintf(&buf, "unknown mech error-code %u",
209                        (unsigned)status_value);
210           else
211               buf = strdup(tmp);
212       }
213   } else {
214       *minor_status = EINVAL;
215       return GSS_S_BAD_STATUS;
216   }
217
218   if (buf == NULL) {
219       *minor_status = ENOMEM;
220       return GSS_S_FAILURE;
221   }
222
223   *message_context = 0;
224   *minor_status = 0;
225
226   status_string->length = strlen(buf);
227   status_string->value  = buf;
228   
229   return GSS_S_COMPLETE;
230 }