diff options
author | Dan Winship <danw@src.gnome.org> | 2000-10-31 01:00:06 +0800 |
---|---|---|
committer | Dan Winship <danw@src.gnome.org> | 2000-10-31 01:00:06 +0800 |
commit | dd50048ab4db6cf804c3fc59b55a8ed140f45631 (patch) | |
tree | 8e71092987d62fb400aec01e9ad6bc419ca92ae3 /camel/providers/imap/camel-imap-auth.c | |
parent | abe39be1720a9ae3fd3402a5a8b777473319fbdb (diff) | |
download | gsoc2013-evolution-dd50048ab4db6cf804c3fc59b55a8ed140f45631.tar.gz gsoc2013-evolution-dd50048ab4db6cf804c3fc59b55a8ed140f45631.tar.zst gsoc2013-evolution-dd50048ab4db6cf804c3fc59b55a8ed140f45631.zip |
New file with code for IMAP authentication mechanisms. (Currently just
* providers/imap/camel-imap-auth.c: New file with code for IMAP
authentication mechanisms. (Currently just krb4, and without
integrity/privacy protection).
* providers/imap/Makefile.am: Add camel-imap-auth.[ch] and krb4
CFLAGS/LDFLAGS
* providers/imap/camel-imap-store.c (connect_to_server): Split out
from imap_connect. Just does the basic connect and CAPABILITY
check. Redo the CAPABILITY code more robustly.
(query_auth_types_connected): Do this right rather than punting to
query_auth_types_generic. Check for KERBEROS_V4 if compiled with
krb4 support.
(query_auth_types_generic): Mention KERBEROS_V4 if compiled with
krb4 support.
(imap_connect): Use connect_to_server().
svn path=/trunk/; revision=6272
Diffstat (limited to 'camel/providers/imap/camel-imap-auth.c')
-rw-r--r-- | camel/providers/imap/camel-imap-auth.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/camel/providers/imap/camel-imap-auth.c b/camel/providers/imap/camel-imap-auth.c new file mode 100644 index 0000000000..3bf1af6535 --- /dev/null +++ b/camel/providers/imap/camel-imap-auth.c @@ -0,0 +1,195 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* camel-imap-auth.c: IMAP AUTHENTICATE implementations */ + +/* + * Authors: Dan Winship <danw@helixcode.com> + * + * Copyright 2000 Helix Code, Inc. (www.helixcode.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + */ + +#include <config.h> + +#include <string.h> + +#ifdef HAVE_KRB4 +#include <krb.h> +/* MIT krb4 des.h #defines _. Sigh. We don't need it. */ +#undef _ +#endif + +#include "camel-exception.h" +#include "camel-mime-utils.h" + +#include "camel-imap-auth.h" +#include "camel-imap-command.h" +#include "camel-imap-utils.h" + +static char * +base64_encode_simple (const char *data, int len) +{ + unsigned char *out; + int state = 0, outlen; + unsigned int save = 0; + + out = g_malloc (len * 4 / 3 + 5); + outlen = base64_encode_close ((unsigned char *)data, len, FALSE, + out, &state, &save); + out[outlen] = '\0'; + return (char *)out; +} + +static int +base64_decode_simple (char *data, int len) +{ + int state = 0; + unsigned int save = 0; + + return base64_decode_step ((unsigned char *)data, len, + (unsigned char *)data, &state, &save); +} + +#ifdef HAVE_KRB4 +#define IMAP_KERBEROS_V4_PROTECTION_NONE 1 +#define IMAP_KERBEROS_V4_PROTECTION_INTEGRITY 2 +#define IMAP_KERBEROS_V4_PROTECTION_PRIVACY 4 + +gboolean +imap_try_kerberos_v4_auth (CamelImapStore *store, CamelException *ex) +{ + CamelImapResponse *response; + char *resp, *data; + int status, len; + char *inst, *realm, *buf, *username; + guint32 nonce_n, nonce_h, plus1; + struct hostent *h; + KTEXT_ST authenticator; + CREDENTIALS credentials; + des_cblock session; + des_key_schedule schedule; + + /* The kickoff. */ + response = camel_imap_command (store, NULL, ex, + "AUTHENTICATE KERBEROS_V4"); + if (!response) + return FALSE; + resp = camel_imap_response_extract_continuation (response, ex); + if (!resp) + return FALSE; + data = imap_next_word (resp); + + /* First server response is a base64-encoded 32-bit random number + * ("nonce") in network byte order. + */ + if (strlen (data) != 8 || base64_decode_simple (data, 8) != 4) { + g_free (resp); + goto lose; + } + memcpy (&nonce_n, data, 4); + g_free (resp); + nonce_h = ntohl (nonce_n); + + /* Our response is an authenticator including that number. */ + h = camel_service_gethost (CAMEL_SERVICE (store), ex); + if (!h) + goto lose; + inst = g_strndup (h->h_name, strcspn (h->h_name, ".")); + g_strdown (inst); + realm = g_strdup (krb_realmofhost (h->h_name)); + status = krb_mk_req (&authenticator, "imap", inst, realm, nonce_h); + if (status == KSUCCESS) { + status = krb_get_cred ("imap", inst, realm, &credentials); + memcpy (session, credentials.session, sizeof (session)); + memset (&credentials, 0, sizeof (credentials)); + } + g_free (inst); + g_free (realm); + + if (status != KSUCCESS) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, + _("Could not get Kerberos ticket:\n%s"), + krb_err_txt[status]); + goto lose; + } + des_key_sched (&session, schedule); + + buf = base64_encode_simple (authenticator.dat, authenticator.length); + response = camel_imap_command_continuation (store, ex, buf); + g_free (buf); + if (!response) + goto lose; + resp = camel_imap_response_extract_continuation (response, ex); + if (!resp) + goto lose; + data = imap_next_word (resp); + + len = strlen (data); + base64_decode_simple (data, strlen (data)); + + /* This one is encrypted. */ + des_ecb_encrypt ((des_cblock *)data, (des_cblock *)data, schedule, 0); + + /* Check that the returned value is the original nonce plus one. */ + memcpy (&plus1, data, 4); + if (ntohl (plus1) != nonce_h + 1) { + g_free (resp); + goto lose; + } + + /* "the fifth octet contain[s] a bit-mask specifying the + * protection mechanisms supported by the server" + */ + if (!(data[4] & IMAP_KERBEROS_V4_PROTECTION_NONE)) { + g_warning ("Server does not support `no protection' :-("); + g_free (resp); + goto lose; + } + g_free (resp); + + username = CAMEL_SERVICE (store)->url->user; + len = strlen (username) + 9; + len += 8 - len % 8; + data = g_malloc0 (len); + memcpy (data, &nonce_n, 4); + data[4] = IMAP_KERBEROS_V4_PROTECTION_NONE; + data[5] = data[6] = data[7] = 0; + strcpy (data + 8, username); + + des_pcbc_encrypt ((des_cblock *)data, (des_cblock *)data, len, + schedule, &session, 1); + memset (&session, 0, sizeof (session)); + buf = base64_encode_simple (data, len); + g_free (data); + + response = camel_imap_command_continuation (store, ex, buf); + if (!response) + goto lose; + camel_imap_response_free (response); + return TRUE; + + lose: + memset (&session, 0, sizeof (session)); + + /* Get the server out of "waiting for continuation data" mode. + */ + response = camel_imap_command_continuation (store, NULL, "*"); + if (response) + camel_imap_response_free (response); + + return FALSE; +} +#endif /* HAVE_KRB4 */ |