1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Authors: Jeffrey Stedfast <fejj@ximian.com>
5 * Copyright 2003 Ximian, Inc. (www.ximian.com)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
33 #include <gssapi/gssapi.h>
34 #include <gssapi/gssapi_generic.h>
35 #else /* HAVE_HEIMDAL_KRB5 */
40 #ifndef GSS_C_OID_KRBV5_DES
41 #define GSS_C_OID_KRBV5_DES GSS_C_NO_OID
44 #include "camel-sasl-gssapi.h"
46 CamelServiceAuthType camel_sasl_gssapi_authtype = {
49 N_("This option will connect to the server using "
50 "Kerberos 5 authentication."),
58 GSSAPI_STATE_CONTINUE_NEEDED,
59 GSSAPI_STATE_COMPLETE,
60 GSSAPI_STATE_AUTHENTICATED
63 #define GSSAPI_SECURITY_LAYER_NONE (1 << 0)
64 #define GSSAPI_SECURITY_LAYER_INTEGRITY (1 << 1)
65 #define GSSAPI_SECURITY_LAYER_PRIVACY (1 << 2)
67 #define DESIRED_SECURITY_LAYER GSSAPI_SECURITY_LAYER_NONE
69 struct _CamelSaslGssapiPrivate {
76 static GByteArray *gssapi_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex);
79 static CamelSaslClass *parent_class = NULL;
83 camel_sasl_gssapi_class_init (CamelSaslGssapiClass *klass)
85 CamelSaslClass *camel_sasl_class = CAMEL_SASL_CLASS (klass);
87 parent_class = CAMEL_SASL_CLASS (camel_type_get_global_classfuncs (camel_sasl_get_type ()));
89 /* virtual method overload */
90 camel_sasl_class->challenge = gssapi_challenge;
94 camel_sasl_gssapi_init (gpointer object, gpointer klass)
96 CamelSaslGssapi *gssapi = CAMEL_SASL_GSSAPI (object);
98 gssapi->priv = g_new (struct _CamelSaslGssapiPrivate, 1);
99 gssapi->priv->state = GSSAPI_STATE_INIT;
100 gssapi->priv->ctx = GSS_C_NO_CONTEXT;
101 gssapi->priv->target = GSS_C_NO_NAME;
105 camel_sasl_gssapi_finalize (CamelObject *object)
107 CamelSaslGssapi *gssapi = CAMEL_SASL_GSSAPI (object);
110 if (gssapi->priv->ctx != GSS_C_NO_CONTEXT)
111 gss_delete_sec_context (&status, gssapi->priv->ctx, GSS_C_NO_BUFFER);
113 if (gssapi->priv->target != GSS_C_NO_NAME)
114 gss_release_name (&status, gssapi->priv->target);
116 g_free (gssapi->priv);
121 camel_sasl_gssapi_get_type (void)
123 static CamelType type = CAMEL_INVALID_TYPE;
125 if (type == CAMEL_INVALID_TYPE) {
126 type = camel_type_register (
127 camel_sasl_get_type (),
129 sizeof (CamelSaslGssapi),
130 sizeof (CamelSaslGssapiClass),
131 (CamelObjectClassInitFunc) camel_sasl_gssapi_class_init,
133 (CamelObjectInitFunc) camel_sasl_gssapi_init,
134 (CamelObjectFinalizeFunc) camel_sasl_gssapi_finalize);
141 gssapi_set_exception (OM_uint32 major, OM_uint32 minor, CamelException *ex)
147 str = _("The specified mechanism is not supported by the "
148 "provided credential, or is unrecognized by the "
152 str = _("The provided target_name parameter was ill-formed.");
154 case GSS_S_BAD_NAMETYPE:
155 str = _("The provided target_name parameter contained an "
156 "invalid or unsupported type of name.");
158 case GSS_S_BAD_BINDINGS:
159 str = _("The input_token contains different channel "
160 "bindings to those specified via the "
161 "input_chan_bindings parameter.");
164 str = _("The input_token contains an invalid signature, or a "
165 "signature that could not be verified.");
168 str = _("The supplied credentials were not valid for context "
169 "initiation, or the credential handle did not "
170 "reference any credentials.");
172 case GSS_S_NO_CONTEXT:
173 str = _("The supplied context handle did not refer to a valid context.");
175 case GSS_S_DEFECTIVE_TOKEN:
176 str = _("The consistency checks performed on the input_token failed.");
178 case GSS_S_DEFECTIVE_CREDENTIAL:
179 str = _("The consistency checks performed on the credential failed.");
181 case GSS_S_CREDENTIALS_EXPIRED:
182 str = _("The referenced credentials have expired.");
185 str = error_message (minor);
188 str = _("Bad authentication response from server.");
191 camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, str);
195 gssapi_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex)
197 struct _CamelSaslGssapiPrivate *priv = CAMEL_SASL_GSSAPI (sasl)->priv;
198 OM_uint32 major, minor, flags, time;
199 gss_buffer_desc inbuf, outbuf;
200 GByteArray *challenge = NULL;
201 gss_buffer_t input_token;
208 switch (priv->state) {
209 case GSSAPI_STATE_INIT:
210 if (!(h = camel_service_gethost (sasl->service, ex))) {
211 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
212 _("Failed to resolve host `%s': %s"),
213 sasl->service->url->host, g_strerror (errno));
217 str = g_strdup_printf ("%s@%s", sasl->service_name, h->h_name);
218 printf ("FQDN: %s (%s)\n", h->h_name, str);
222 inbuf.length = strlen (str);
223 major = gss_import_name (&minor, &inbuf, gss_nt_service_name, &priv->target);
226 if (major != GSS_S_COMPLETE) {
227 gssapi_set_exception (major, minor, ex);
231 input_token = GSS_C_NO_BUFFER;
235 case GSSAPI_STATE_CONTINUE_NEEDED:
237 camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
238 _("Bad authentication response from server."));
242 inbuf.value = token->data;
243 inbuf.length = token->len;
244 input_token = &inbuf;
247 major = gss_init_sec_context (&minor, GSS_C_NO_CREDENTIAL, &priv->ctx, priv->target,
248 GSS_C_OID_KRBV5_DES, GSS_C_MUTUAL_FLAG |
249 GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
250 0, GSS_C_NO_CHANNEL_BINDINGS,
251 input_token, &mech, &outbuf, &flags, &time);
255 priv->state = GSSAPI_STATE_COMPLETE;
257 case GSS_S_CONTINUE_NEEDED:
258 priv->state = GSSAPI_STATE_CONTINUE_NEEDED;
261 gssapi_set_exception (major, minor, ex);
262 printf ("gss_init_sec_context() exception\n");
263 gss_release_buffer (&minor, &outbuf);
267 challenge = g_byte_array_new ();
268 g_byte_array_append (challenge, outbuf.value, outbuf.length);
269 gss_release_buffer (&minor, &outbuf);
271 case GSSAPI_STATE_COMPLETE:
273 camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
274 _("Bad authentication response from server."));
278 inbuf.value = token->data;
279 inbuf.length = token->len;
281 major = gss_unwrap (&minor, priv->ctx, &inbuf, &outbuf, &conf_state, &qop);
282 if (major != GSS_S_COMPLETE) {
283 gssapi_set_exception (major, minor, ex);
284 printf ("gss_unwrap() exception\n");
285 gss_release_buffer (&minor, &outbuf);
289 if (outbuf.length < 4) {
290 camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
291 _("Bad authentication response from server."));
292 gss_release_buffer (&minor, &outbuf);
296 /* check that our desired security layer is supported */
297 if ((((unsigned char *) outbuf.value)[0] & DESIRED_SECURITY_LAYER) != DESIRED_SECURITY_LAYER) {
298 camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
299 _("Unsupported security layer."));
300 gss_release_buffer (&minor, &outbuf);
304 inbuf.length = 4 + strlen (sasl->service->url->user);
305 inbuf.value = str = g_malloc (inbuf.length);
306 memcpy (inbuf.value, outbuf.value, 4);
307 str[0] = DESIRED_SECURITY_LAYER;
308 memcpy (str + 4, sasl->service->url->user, inbuf.length - 4);
309 gss_release_buffer (&minor, &outbuf);
311 major = gss_wrap (&minor, priv->ctx, FALSE, qop, &inbuf, &conf_state, &outbuf);
313 gssapi_set_exception (major, minor, ex);
314 printf ("gss_wrap() exception\n");
315 gss_release_buffer (&minor, &outbuf);
320 challenge = g_byte_array_new ();
321 g_byte_array_append (challenge, outbuf.value, outbuf.length);
322 gss_release_buffer (&minor, &outbuf);
324 priv->state = GSSAPI_STATE_AUTHENTICATED;
326 sasl->authenticated = TRUE;
329 printf ("unknown state exception\n");
336 #endif /* HAVE_KRB5 */