1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Authors: Jeffrey Stedfast <fejj@ximian.com>
5 * Copyright 2001 Ximian, Inc. (www.ximian.com)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
30 /* MIT krb4 des.h #defines _. Sigh. We don't need it. #undef it here
31 * so we get the gettexty _ definition later.
39 #include <glib/gi18n-lib.h>
41 #include "camel-net-utils.h"
42 #include "camel-sasl-kerberos4.h"
43 #include "camel-service.h"
44 #include "camel-string-utils.h"
46 CamelServiceAuthType camel_sasl_kerberos4_authtype = {
49 N_("This option will connect to the server using "
50 "Kerberos 4 authentication."),
56 #define KERBEROS_V4_PROTECTION_NONE 1
57 #define KERBEROS_V4_PROTECTION_INTEGRITY 2
58 #define KERBEROS_V4_PROTECTION_PRIVACY 4
60 static CamelSaslClass *parent_class = NULL;
62 /* Returns the class for a CamelSaslKerberos4 */
63 #define CSK4_CLASS(so) CAMEL_SASL_KERBEROS4_CLASS (CAMEL_OBJECT_GET_CLASS (so))
65 static GByteArray *krb4_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex);
67 struct _CamelSaslKerberos4Private {
74 des_key_schedule schedule;
78 camel_sasl_kerberos4_class_init (CamelSaslKerberos4Class *camel_sasl_kerberos4_class)
80 CamelSaslClass *camel_sasl_class = CAMEL_SASL_CLASS (camel_sasl_kerberos4_class);
82 parent_class = CAMEL_SASL_CLASS (camel_type_get_global_classfuncs (camel_sasl_get_type ()));
84 /* virtual method overload */
85 camel_sasl_class->challenge = krb4_challenge;
89 camel_sasl_kerberos4_init (gpointer object, gpointer klass)
91 CamelSaslKerberos4 *sasl_krb4 = CAMEL_SASL_KERBEROS4 (object);
93 sasl_krb4->priv = g_new0 (struct _CamelSaslKerberos4Private, 1);
97 camel_sasl_kerberos4_finalize (CamelObject *object)
99 CamelSaslKerberos4 *sasl = CAMEL_SASL_KERBEROS4 (object);
102 memset (sasl->priv, 0, sizeof (sasl->priv));
109 camel_sasl_kerberos4_get_type (void)
111 static CamelType type = CAMEL_INVALID_TYPE;
113 if (type == CAMEL_INVALID_TYPE) {
114 type = camel_type_register (camel_sasl_get_type (),
115 "CamelSaslKerberos4",
116 sizeof (CamelSaslKerberos4),
117 sizeof (CamelSaslKerberos4Class),
118 (CamelObjectClassInitFunc) camel_sasl_kerberos4_class_init,
120 (CamelObjectInitFunc) camel_sasl_kerberos4_init,
121 (CamelObjectFinalizeFunc) camel_sasl_kerberos4_finalize);
128 krb4_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex)
130 struct _CamelSaslKerberos4Private *priv = CAMEL_SASL_KERBEROS4 (sasl)->priv;
131 GByteArray *ret = NULL;
132 char *inst, *realm, *username;
135 KTEXT_ST authenticator;
136 CREDENTIALS credentials;
138 struct addrinfo *ai, hints;
140 /* Need to wait for the server */
144 switch (priv->state) {
149 memcpy (&priv->nonce_n, token->data, 4);
150 priv->nonce_h = ntohl (priv->nonce_n);
152 memset(&hints, 0, sizeof(hints));
153 hints.ai_flags = AI_CANONNAME;
154 ai = camel_getaddrinfo(sasl->service->url->host?sasl->service->url->host:"localhost", NULL, &hints, ex);
158 /* Our response is an authenticator including that number. */
159 inst = g_strndup (ai->ai_canonname, strcspn (ai->ai_canonname, "."));
160 camel_strdown (inst);
161 realm = g_strdup (krb_realmofhost (ai->ai_canonname));
162 camel_freeaddrinfo(ai);
163 status = krb_mk_req (&authenticator, sasl->service_name, inst, realm, priv->nonce_h);
164 if (status == KSUCCESS) {
165 status = krb_get_cred (sasl->service_name, inst, realm, &credentials);
166 memcpy (priv->session, credentials.session, sizeof (priv->session));
167 memset (&credentials, 0, sizeof (credentials));
172 if (status != KSUCCESS) {
173 camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
174 _("Could not get Kerberos ticket:\n%s"),
175 krb_err_txt[status]);
178 des_key_sched (&priv->session, priv->schedule);
180 ret = g_byte_array_new ();
181 g_byte_array_append (ret, (const guint8 *)authenticator.dat, authenticator.length);
188 /* This one is encrypted. */
189 des_ecb_encrypt ((des_cblock *)token->data, (des_cblock *)token->data, priv->schedule, 0);
191 /* Check that the returned value is the original nonce plus one. */
192 memcpy (&plus1, token->data, 4);
193 if (ntohl (plus1) != priv->nonce_h + 1)
196 /* "the fifth octet contain[s] a bit-mask specifying the
197 * protection mechanisms supported by the server"
199 if (!(token->data[4] & KERBEROS_V4_PROTECTION_NONE)) {
200 g_warning ("Server does not support `no protection' :-(");
204 username = sasl->service->url->user;
205 len = strlen (username) + 9;
207 ret = g_byte_array_new ();
208 g_byte_array_set_size (ret, len);
209 memset (ret->data, 0, len);
210 memcpy (ret->data, &priv->nonce_n, 4);
211 ret->data[4] = KERBEROS_V4_PROTECTION_NONE;
212 ret->data[5] = ret->data[6] = ret->data[7] = 0;
213 strcpy (ret->data + 8, username);
215 des_pcbc_encrypt ((void *)ret->data, (void *)ret->data, len,
216 priv->schedule, &priv->session, 1);
217 memset (&priv->session, 0, sizeof (priv->session));
219 sasl->authenticated = TRUE;
227 memset (&priv->session, 0, sizeof (priv->session));
229 if (!camel_exception_is_set (ex)) {
230 camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
231 _("Bad authentication response from server."));
236 #endif /* HAVE_KRB4 */