contrib/pgp2.rc contrib/pgp5.rc contrib/gpg.rc \
imap/imap_ssl.c imap/imap_ssl.h README.SSL
-EXTRA_mutt_SOURCES = account.c mutt_socket.c pop.c pgp.c pgpinvoke.c pgpkey.c \
- pgplib.c sha1dgst.c gnupgparse.c resize.c dotlock.c remailer.c \
- browser.h mbyte.h remailer.h
+EXTRA_mutt_SOURCES = account.c mutt_sasl.c mutt_socket.c pop.c pgp.c \
+ pgpinvoke.c pgpkey.c pgplib.c sha1dgst.c gnupgparse.c resize.c \
+ dotlock.c remailer.c browser.h mbyte.h remailer.h
EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP TODO configure acconfig.h account.h \
attach.h buffy.h charset.h copy.h dotlock.h functions.h gen_defs \
globals.h hash.h history.h init.h keymap.h \
mailbox.h mapping.h mime.h mutt.h mutt_curses.h mutt_menu.h \
- mutt_regex.h mutt_socket.h mx.h pager.h pgp.h protos.h \
+ mutt_regex.h mutt_sasl.h mutt_socket.h mx.h pager.h pgp.h protos.h \
reldate.h rfc1524.h rfc2047.h rfc2231.h rfc822.h sha.h sha_locl.h \
sort.h mime.types VERSION prepare _regex.h OPS.MIX \
README.SECURITY remailer.c remailer.h browser.h \
/* Do you want support for the IMAP protocol? (--enable-imap) */
#undef USE_IMAP
+/* Do you want to use the Cyrus SASL library for POP/IMAP authentication?
+ * (--with-sasl) */
+#undef USE_SASL
+
/* Do you want support for IMAP GSSAPI authentication? (--with-gss) */
#undef USE_GSS
/* Do you have the Heimdal version of Kerberos V? (for gss support) */
#undef HAVE_HEIMDAL
-/* Do you want support for SSL? (--enable-ssl) */
+/* Do you want support for SSL? (--with-ssl) */
#undef USE_SSL
/* Avoid SSL routines which used patent-encumbered RC5 algorithms */
return 1;
}
+
+/* mutt_account_getuser: retrieve username into ACCOUNT, if neccessary */
+int mutt_account_getuser (ACCOUNT* account)
+{
+ /* already set */
+ if (account->flags & M_ACCT_USER)
+ return 0;
+#ifdef USE_IMAP
+ else if ((account->type == M_ACCT_TYPE_IMAP) && ImapUser)
+ strfcpy (account->user, ImapUser, sizeof (account->user));
+#endif
+#ifdef USE_POP
+ else if ((account->type == M_ACCT_TYPE_POP) && PopUser)
+ strfcpy (account->user, PopUser, sizeof (account->user));
+#endif
+ /* prompt (defaults to unix username), copy into account->user */
+ else
+ {
+ strfcpy (account->user, NONULL (Username), sizeof (account->user));
+ if (mutt_get_field (_("Username: "), account->user,
+ sizeof (account->user), 0))
+ return -1;
+ }
+
+ account->flags |= M_ACCT_USER;
+
+ return 0;
+}
+
+/* mutt_account_getpass: fetch password into ACCOUNT, if neccessary */
+int mutt_account_getpass (ACCOUNT* account)
+{
+ if (account->flags & M_ACCT_PASS)
+ return 0;
+#ifdef USE_IMAP
+ else if ((account->type == M_ACCT_TYPE_IMAP) && ImapPass)
+ strfcpy (account->pass, ImapPass, sizeof (account->pass));
+#endif
+#ifdef USE_POP
+ else if ((account->type == M_ACCT_TYPE_POP) && PopPass)
+ strfcpy (account->pass, PopPass, sizeof (account->pass));
+#endif
+ else
+ {
+ account->pass[0] = '\0';
+ if (mutt_get_field (_("Password: "), account->pass,
+ sizeof (account->pass), M_PASS))
+ return -1;
+ }
+
+ account->flags |= M_ACCT_PASS;
+
+ return 0;
+}
/* account flags */
#define M_ACCT_PORT (1<<0)
#define M_ACCT_USER (1<<1)
-#define M_ACCT_SSL (1<<2)
-#define M_ACCT_CRAM (1<<3)
-#define M_ACCT_PASS (1<<4)
+#define M_ACCT_PASS (1<<2)
+#define M_ACCT_SSL (1<<3)
typedef struct
{
unsigned char flags;
} ACCOUNT;
-/* imap_account_match: compare account info (host/port/user) */
int mutt_account_match (const ACCOUNT* a1, const ACCOUNT* m2);
+int mutt_account_getuser (ACCOUNT* account);
+int mutt_account_getpass (ACCOUNT* account);
#endif /* _MUTT_ACCOUNT_H_ */
dnl -- end imap dependencies --
+AC_ARG_WITH(sasl, [ --with-sasl[=DIR] Use Cyrus SASL library for POP/IMAP authentication],
+ [
+ if test "$need_socket" != "yes"
+ then
+ AC_MSG_ERROR([SASL support is only useful with POP or IMAP support])
+ fi
+
+ if test "$with_sasl" != "no"
+ then
+ if test "$with_sasl" != "yes"
+ then
+ CPPFLAGS="$CPPFLAGS -I$with_sasl/include"
+ LDFLAGS="$LDFLAGS -L$with_sasl/lib"
+ fi
+
+ saved_LIBS="$LIBS"
+
+ AC_CHECK_LIB(sasl, sasl_client_init,,
+ AC_MSG_ERROR([could not find libsasl]),)
+
+ MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS mutt_sasl.o"
+ MUTTLIBS="$MUTTLIBS -lsasl"
+ LIBS="$saved_LIBS"
+ AC_DEFINE(USE_SASL)
+ need_sasl=yes
+ fi
+ ])
+AM_CONDITIONAL(USE_SASL, test x$need_sasl = xyes)
+
+dnl -- end socket --
+
AC_ARG_ENABLE(debug, [ --enable-debug Enable debugging support],
[ if test x$enableval = xyes ; then
AC_DEFINE(DEBUG)
AC_DEFINE(BUFFY_SIZE)
fi])
-AC_ARG_ENABLE(mailtool, [ --enable-mailtool Enable Sun mailtool attachments support ],
+AC_ARG_ENABLE(mailtool, [ --enable-mailtool Enable Sun mailtool attachments support ],
[if test x$enableval = xyes; then
AC_DEFINE(SUN_ATTACHMENT)
fi])
AC_DEFINE_UNQUOTED(EXECSHELL, "$withval")
fi])
-AC_ARG_ENABLE(exact-address, [ --enable-exact-address enable regeneration of email addresses],
+AC_ARG_ENABLE(exact-address, [ --enable-exact-address Enable regeneration of email addresses],
[if test $enableval = yes; then
AC_DEFINE(EXACT_ADDRESS)
fi])
WHERE char *Hostname;
#ifdef USE_IMAP
WHERE char *ImapUser INITVAL (NULL);
-WHERE char *ImapCRAMKey INITVAL (NULL);
WHERE char *ImapPass INITVAL (NULL);
WHERE short ImapCheckTimeout;
WHERE char *ImapHomeNamespace INITVAL (NULL);
GSSSOURCES = auth_gss.c
endif
+if USE_SASL
+SASLSOURCES = auth_sasl.c
+else
+CRAMSOURCES = auth_cram.c
+endif
+
if USE_SSL
SSLSOURCES = imap_ssl.c
SSLHEADERS = imap_ssl.h
INCLUDES = -I$(top_srcdir) -I../intl
noinst_LIBRARIES = libimap.a
-noinst_HEADERS = imap_private.h md5.h message.h $(SSLHEADERS)
+noinst_HEADERS = auth.h imap_private.h md5.h message.h $(SSLHEADERS)
-libimap_a_SOURCES = auth.c browse.c command.c imap.c imap.h md5c.c message.c \
- utf7.c util.c $(GSSSOURCES) $(SSLSOURCES)
+libimap_a_SOURCES = auth.c auth_anon.c auth_login.c c browse.c \
+ command.c imap.c imap.h md5c.c message.c utf7.c \
+ util.c $(GSSSOURCES) $(SASLSOURCES) $(CRAMSOURCES) $(SSLSOURCES)
#include "mutt.h"
#include "imap_private.h"
-#include "md5.h"
+#include "auth.h"
-#define MD5_BLOCK_LEN 64
-#define MD5_DIGEST_LEN 16
-
-/* external authenticator prototypes */
+static imap_auth_t imap_authenticators[] = {
+ imap_auth_anon,
+#ifdef USE_SASL
+ imap_auth_sasl,
+#endif
#ifdef USE_GSS
-int imap_auth_gss (IMAP_DATA* idata, const char* user);
+ imap_auth_gss,
#endif
+ /* SASL includes CRAM-MD5 (and GSSAPI, but that's not enabled by default) */
+#ifndef USE_SASL
+ imap_auth_cram_md5,
+#endif
+ imap_auth_login,
-/* forward declarations */
-static void hmac_md5 (const char* password, char* challenge,
- unsigned char* response);
-static int imap_auth_cram_md5 (IMAP_DATA* idata, const char* user,
- const char* pass);
-static int imap_auth_anon (IMAP_DATA *idata);
-
-/* hmac_md5: produce CRAM-MD5 challenge response. */
-static void hmac_md5 (const char* password, char* challenge,
- unsigned char* response)
-{
- MD5_CTX ctx;
- unsigned char ipad[MD5_BLOCK_LEN], opad[MD5_BLOCK_LEN];
- unsigned char secret[MD5_BLOCK_LEN+1];
- unsigned char hash_passwd[MD5_DIGEST_LEN];
- unsigned int secret_len, chal_len;
- int i;
-
- secret_len = strlen (password);
- chal_len = strlen (challenge);
-
- /* passwords longer than MD5_BLOCK_LEN bytes are substituted with their MD5
- * digests */
- if (secret_len > MD5_BLOCK_LEN)
- {
- MD5Init (&ctx);
- MD5Update (&ctx, (unsigned char*) password, secret_len);
- MD5Final (hash_passwd, &ctx);
- strfcpy ((char*) secret, (char*) hash_passwd, MD5_DIGEST_LEN);
- secret_len = MD5_DIGEST_LEN;
- }
- else
- strfcpy ((char *) secret, password, sizeof (secret));
-
- memset (ipad, 0, sizeof (ipad));
- memset (opad, 0, sizeof (opad));
- memcpy (ipad, secret, secret_len);
- memcpy (opad, secret, secret_len);
-
- for (i = 0; i < MD5_BLOCK_LEN; i++)
- {
- ipad[i] ^= 0x36;
- opad[i] ^= 0x5c;
- }
-
- /* inner hash: challenge and ipadded secret */
- MD5Init (&ctx);
- MD5Update (&ctx, ipad, MD5_BLOCK_LEN);
- MD5Update (&ctx, (unsigned char*) challenge, chal_len);
- MD5Final (response, &ctx);
-
- /* outer hash: inner hash and opadded secret */
- MD5Init (&ctx);
- MD5Update (&ctx, opad, MD5_BLOCK_LEN);
- MD5Update (&ctx, response, MD5_DIGEST_LEN);
- MD5Final (response, &ctx);
-}
-
-/* imap_auth_cram_md5: AUTH=CRAM-MD5 support. Used unconditionally if the
- * server supports it */
-static int imap_auth_cram_md5 (IMAP_DATA* idata, const char* user,
- const char* pass)
-{
- char ibuf[LONG_STRING], obuf[LONG_STRING];
- unsigned char hmac_response[MD5_DIGEST_LEN];
- int len;
-
- dprint (2, (debugfile, "Attempting CRAM-MD5 login...\n"));
- mutt_message _("Authenticating (CRAM-MD5)...");
-
- imap_cmd_start (idata, "AUTHENTICATE CRAM-MD5");
-
- /* From RFC 2195:
- * The data encoded in the first ready response contains a presumptively
- * arbitrary string of random digits, a timestamp, and the fully-qualified
- * primary host name of the server. The syntax of the unencoded form must
- * correspond to that of an RFC 822 'msg-id' [RFC822] as described in [POP3].
- */
- if (mutt_socket_readln (ibuf, sizeof (ibuf), idata->conn) < 0)
- {
- dprint (1, (debugfile, "Error receiving server response.\n"));
-
- return -1;
- }
-
- if (ibuf[0] != '+')
- {
- dprint (1, (debugfile, "Invalid response from server: %s\n", ibuf));
-
- return -1;
- }
-
- if ((len = mutt_from_base64 (obuf, ibuf + 2)) == -1)
- {
- dprint (1, (debugfile, "Error decoding base64 response.\n"));
-
- return -1;
- }
-
- obuf[len] = '\0';
- dprint (2, (debugfile, "CRAM challenge: %s\n", obuf));
-
- /* The client makes note of the data and then responds with a string
- * consisting of the user name, a space, and a 'digest'. The latter is
- * computed by applying the keyed MD5 algorithm from [KEYED-MD5] where the
- * key is a shared secret and the digested text is the timestamp (including
- * angle-brackets).
- *
- * Note: The user name shouldn't be quoted. Since the digest can't contain
- * spaces, there is no ambiguity. Some servers get this wrong, we'll work
- * around them when the bug report comes in. Until then, we'll remain
- * blissfully RFC-compliant.
- */
- hmac_md5 (pass, obuf, hmac_response);
- /* dubious optimisation I saw elsewhere: make the whole string in one call */
- snprintf (obuf, sizeof (obuf),
- "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
- user,
- hmac_response[0], hmac_response[1], hmac_response[2], hmac_response[3],
- hmac_response[4], hmac_response[5], hmac_response[6], hmac_response[7],
- hmac_response[8], hmac_response[9], hmac_response[10], hmac_response[11],
- hmac_response[12], hmac_response[13], hmac_response[14], hmac_response[15]);
- dprint(2, (debugfile, "CRAM response: %s\n", obuf));
-
- mutt_to_base64 ((unsigned char*) ibuf, (unsigned char*) obuf, strlen (obuf));
- strcpy (ibuf + strlen (ibuf), "\r\n");
- mutt_socket_write (idata->conn, ibuf);
-
- if (mutt_socket_readln (ibuf, LONG_STRING, idata->conn) < 0)
- {
- dprint (1, (debugfile, "Error receiving server response.\n"));
-
- return -1;
- }
-
- if (imap_code (ibuf))
- {
- dprint (2, (debugfile, "CRAM login complete.\n"));
-
- return 0;
- }
-
- dprint (2, (debugfile, "CRAM login failed.\n"));
- return -1;
-}
-
-/* this is basically a stripped-down version of the cram-md5 method. */
-
-static int imap_auth_anon (IMAP_DATA* idata)
-{
- char buf[LONG_STRING];
-
- dprint (2, (debugfile, "Attempting anonymous login...\n"));
- mutt_message _("Authenticating (anonymous)...");
-
- imap_cmd_start (idata, "AUTHENTICATE ANONYMOUS");
-
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
- {
- dprint (1, (debugfile, "Error receiving server response.\n"));
-
- return -1;
- }
-
- if (buf[0] != '+')
- {
- dprint (1, (debugfile, "Invalid response from server.\n"));
-
- return -1;
- }
-
- strfcpy (buf, "ZHVtbXkK\r\n", sizeof (buf)); /* base64 ("dummy") */
-
- mutt_socket_write (idata->conn, buf);
-
- if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
- {
- dprint (1, (debugfile, "Error receiving server response.\n"));
-
- return -1;
- }
-
- if (imap_code (buf))
- {
- dprint (2, (debugfile, "Anonymous login complete.\n"));
-
- return 0;
- }
-
- dprint (2, (debugfile, "Anonymous login failed.\n"));
+ NULL
+};
- return -1;
-}
-
-/* imap_authenticate: loop until success or user abort. At each loop, all
- * supported authentication methods are tried, from strongest to weakest.
- * Currently available:
- * GSSAPI: strongest available form, requires Kerberos V infrastructure,
- * or possibly alternatively Heimdal.
- * CRAM-MD5: like APOP or CHAP. Safe against replay and sniffing, but
- * requires that your key be stored on the server, readable by the
- * server account. UW-IMAP supports this method since at least 4.5, if
- * the key file exists on the server.
- * LOGIN: ugh. Don't use this if you can help it. Uses cleartext password
- * exchange, furthermore uses unix login techniques so this same password
- * can be used to log in to the server or others that share the
- * credentials database.
- * Unavailable:
- * KERBEROS_V4. Superceded by GSSAPI.
- */
+/* imap_authenticate: oh how simple! loops through authenticators. */
int imap_authenticate (IMAP_DATA* idata)
{
- char buf[LONG_STRING];
- char user[SHORT_STRING], q_user[SHORT_STRING];
- char ckey[SHORT_STRING];
- char pass[SHORT_STRING], q_pass[SHORT_STRING];
-
- CONNECTION* conn = idata->conn;
-
- int r = 1;
+ imap_auth_t* authenticator = imap_authenticators;
+ int r = -1;
- while (r != 0)
+ while (authenticator)
{
- if (! (conn->account.flags & M_ACCT_USER))
- {
- if (!ImapUser)
- {
- strfcpy (user, NONULL(Username), sizeof (user));
- if (mutt_get_field (_("IMAP Username: "), user, sizeof (user), 0) != 0)
- {
- user[0] = 0;
- return (-1);
- }
- }
- else
- strfcpy (user, ImapUser, sizeof (user));
- }
- else
- strfcpy (user, conn->account.user, sizeof (user));
-
- if (!user[0])
- {
- if (!mutt_bit_isset (idata->capabilities, AUTH_ANON))
- {
- mutt_error _("Anonymous authentication not supported.");
- return -1;
- }
-
- return imap_auth_anon (idata);
- }
-
-#ifdef USE_GSS
- /* attempt GSSAPI authentication, if available */
- if (mutt_bit_isset (idata->capabilities, AGSSAPI))
- {
- if ((r = imap_auth_gss (idata, user)))
- {
- mutt_error _("GSSAPI authentication failed.");
- sleep (1);
- }
- else
- return 0;
- }
- else
- dprint (2, (debugfile, "GSSAPI authentication is not available\n"));
-#endif
-
- /* attempt CRAM-MD5 if available */
- if (mutt_bit_isset (idata->capabilities, ACRAM_MD5))
- {
- if (!(conn->account.flags & M_ACCT_CRAM))
- {
- if (!ImapCRAMKey)
- {
- ckey[0] = '\0';
- snprintf (buf, sizeof (buf), _("CRAM key for %s@%s: "), user,
- conn->account.host);
- if (mutt_get_field (buf, ckey, sizeof (ckey), M_PASS) != 0)
- return -1;
- }
- else
- strfcpy (ckey, ImapCRAMKey, sizeof (ckey));
- }
- else
- strfcpy (ckey, conn->account.pass, sizeof (ckey));
-
- if (*ckey)
- {
- if ((r = imap_auth_cram_md5 (idata, user, ckey)))
- {
- mutt_error _("CRAM-MD5 authentication failed.");
- sleep (1);
- if (!(conn->account.flags & M_ACCT_CRAM))
- FREE (&ImapCRAMKey);
- conn->account.flags &= ~M_ACCT_CRAM;
- }
- else
- {
- strfcpy (conn->account.pass, ckey, sizeof (conn->account.pass));
- conn->account.flags |= M_ACCT_CRAM;
- return 0;
- }
- }
- else
- {
- mutt_message _("Skipping CRAM-MD5 authentication.");
- sleep (1);
- }
- }
- else
- dprint (2, (debugfile, "CRAM-MD5 authentication is not available\n"));
-
- if (! (conn->account.flags & M_ACCT_PASS))
- {
- if (!ImapPass)
- {
- pass[0]=0;
- snprintf (buf, sizeof (buf), _("Password for %s@%s: "), user,
- conn->account.host);
- if (mutt_get_field (buf, pass, sizeof (pass), M_PASS) != 0 ||
- !pass[0])
- return -1;
- }
- else
- strfcpy (pass, ImapPass, sizeof (pass));
- }
- else
- strfcpy (pass, conn->account.pass, sizeof (pass));
-
- imap_quote_string (q_user, sizeof (q_user), user);
- imap_quote_string (q_pass, sizeof (q_pass), pass);
-
- mutt_message _("Logging in...");
-
-#ifdef DEBUG
- /* don't print the password unless we're at the ungodly debugging level
- * of 5 or higher */
-
- if (debuglevel < IMAP_LOG_PASS)
- dprint (2, (debugfile, "Sending LOGIN command for %s...\n", user));
-#endif
-
- snprintf (buf, sizeof (buf), "LOGIN %s %s", q_user, q_pass);
- r = imap_exec (buf, sizeof (buf), idata, buf,
- IMAP_CMD_FAIL_OK | IMAP_CMD_PASS);
- if (r == -1)
- {
- /* connection or protocol problem */
- imap_error ("imap_authenticate", buf);
- return (-1);
- }
- else if (r == -2)
- {
- /* Login failed, try again */
- mutt_error _("Login failed.");
- sleep (1);
-
- if (!(conn->account.flags & M_ACCT_USER))
- FREE (&ImapUser);
- if (!(conn->account.flags & M_ACCT_PASS))
- FREE (&ImapPass);
- conn->account.flags &= ~M_ACCT_PASS;
- }
- else
- {
- /* If they have a successful login, we may as well cache the
- * user/password. */
- if (!(conn->account.flags & M_ACCT_USER))
- strfcpy (conn->account.user, user, sizeof (conn->account.user));
- if (!(conn->account.flags & M_ACCT_PASS))
- strfcpy (conn->account.pass, pass, sizeof (conn->account.pass));
-
- conn->account.flags |= (M_ACCT_USER | M_ACCT_PASS);
- }
+ if ((r = (*authenticator)(idata)) != IMAP_AUTH_UNAVAIL)
+ return r;
+ authenticator++;
}
- return 0;
+
+ return r;
}
--- /dev/null
+/*
+ * Copyright (C) 2000 Brendan Cully <brendan@kublai.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 Place - Suite 330, Boston, MA 02111, USA.
+ */
+
+/* common defs for authenticators. A good place to set up a generic callback
+ * system */
+
+#ifndef _IMAP_AUTH_H
+#define _IMAP_AUTH_H 1
+
+typedef enum
+{
+ IMAP_AUTH_SUCCESS = 0,
+ IMAP_AUTH_FAILURE,
+ IMAP_AUTH_UNAVAIL
+} imap_auth_res_t;
+
+typedef imap_auth_res_t (*imap_auth_t)(IMAP_DATA* idata);
+
+/* external authenticator prototypes */
+imap_auth_res_t imap_auth_anon (IMAP_DATA* idata);
+imap_auth_res_t imap_auth_cram_md5 (IMAP_DATA* idata);
+imap_auth_res_t imap_auth_login (IMAP_DATA* idata);
+#ifdef USE_GSS
+imap_auth_res_t imap_auth_gss (IMAP_DATA* idata);
+#endif
+#ifdef USE_SASL
+imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata);
+#endif
+
+#endif /* _IMAP_AUTH_H */
--- /dev/null
+/*
+ * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.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 Place - Suite 330, Boston, MA 02111, USA.
+ */
+
+/* IMAP login/authentication code */
+
+#include "mutt.h"
+#include "imap_private.h"
+#include "auth.h"
+
+/* this is basically a stripped-down version of the cram-md5 method. */
+imap_auth_res_t imap_auth_anon (IMAP_DATA* idata)
+{
+ char buf[LONG_STRING];
+
+ if (!mutt_bit_isset (idata->capabilities, AUTH_ANON))
+ return IMAP_AUTH_UNAVAIL;
+
+ if (mutt_account_getuser (&idata->conn->account))
+ return IMAP_AUTH_FAILURE;
+
+ if (idata->conn->account.user[0] != '\0')
+ return IMAP_AUTH_UNAVAIL;
+
+ mutt_message _("Authenticating (anonymous)...");
+
+ imap_cmd_start (idata, "AUTHENTICATE ANONYMOUS");
+
+ if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
+ {
+ dprint (1, (debugfile, "Error receiving server response.\n"));
+ goto bail;
+ }
+
+ if (buf[0] != '+')
+ {
+ dprint (1, (debugfile, "Invalid response from server.\n"));
+ goto bail;
+ }
+
+ strfcpy (buf, "ZHVtbXkK\r\n", sizeof (buf)); /* base64 ("dummy") */
+
+ mutt_socket_write (idata->conn, buf);
+
+ if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
+ {
+ dprint (1, (debugfile, "Error receiving server response.\n"));
+ goto bail;
+ }
+
+ if (imap_code (buf))
+ return IMAP_AUTH_SUCCESS;
+
+ bail:
+ mutt_error _("Anonymous authentication failed.");
+ sleep (2);
+ return IMAP_AUTH_FAILURE;
+}
--- /dev/null
+/*
+ * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.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 Place - Suite 330, Boston, MA 02111, USA.
+ */
+
+/* IMAP login/authentication code */
+
+#include "mutt.h"
+#include "imap_private.h"
+#include "auth.h"
+#include "md5.h"
+
+#define MD5_BLOCK_LEN 64
+#define MD5_DIGEST_LEN 16
+
+/* forward declarations */
+static void hmac_md5 (const char* password, char* challenge,
+ unsigned char* response);
+
+/* imap_auth_cram_md5: AUTH=CRAM-MD5 support. */
+imap_auth_res_t imap_auth_cram_md5 (IMAP_DATA* idata)
+{
+ char ibuf[LONG_STRING], obuf[LONG_STRING];
+ unsigned char hmac_response[MD5_DIGEST_LEN];
+ int len;
+
+ if (!mutt_bit_isset (idata->capabilities, ACRAM_MD5))
+ return IMAP_AUTH_UNAVAIL;
+
+ mutt_message _("Authenticating (CRAM-MD5)...");
+
+ /* get auth info */
+ if (mutt_account_getuser (&idata->conn->account))
+ return IMAP_AUTH_FAILURE;
+ if (mutt_account_getpass (&idata->conn->account))
+ return IMAP_AUTH_FAILURE;
+
+ imap_cmd_start (idata, "AUTHENTICATE CRAM-MD5");
+
+ /* From RFC 2195:
+ * The data encoded in the first ready response contains a presumptively
+ * arbitrary string of random digits, a timestamp, and the fully-qualified
+ * primary host name of the server. The syntax of the unencoded form must
+ * correspond to that of an RFC 822 'msg-id' [RFC822] as described in [POP3].
+ */
+ if (mutt_socket_readln (ibuf, sizeof (ibuf), idata->conn) < 0)
+ {
+ dprint (1, (debugfile, "Error receiving server response.\n"));
+ goto bail;
+ }
+
+ if (ibuf[0] != '+')
+ {
+ dprint (1, (debugfile, "Invalid response from server: %s\n", ibuf));
+ goto bail;
+ }
+
+ if ((len = mutt_from_base64 (obuf, ibuf + 2)) == -1)
+ {
+ dprint (1, (debugfile, "Error decoding base64 response.\n"));
+ goto bail;
+ }
+
+ obuf[len] = '\0';
+ dprint (2, (debugfile, "CRAM challenge: %s\n", obuf));
+
+ /* The client makes note of the data and then responds with a string
+ * consisting of the user name, a space, and a 'digest'. The latter is
+ * computed by applying the keyed MD5 algorithm from [KEYED-MD5] where the
+ * key is a shared secret and the digested text is the timestamp (including
+ * angle-brackets).
+ *
+ * Note: The user name shouldn't be quoted. Since the digest can't contain
+ * spaces, there is no ambiguity. Some servers get this wrong, we'll work
+ * around them when the bug report comes in. Until then, we'll remain
+ * blissfully RFC-compliant.
+ */
+ hmac_md5 (idata->conn->account.pass, obuf, hmac_response);
+ /* dubious optimisation I saw elsewhere: make the whole string in one call */
+ snprintf (obuf, sizeof (obuf),
+ "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ idata->conn->account.user,
+ hmac_response[0], hmac_response[1], hmac_response[2], hmac_response[3],
+ hmac_response[4], hmac_response[5], hmac_response[6], hmac_response[7],
+ hmac_response[8], hmac_response[9], hmac_response[10], hmac_response[11],
+ hmac_response[12], hmac_response[13], hmac_response[14], hmac_response[15]);
+ dprint(2, (debugfile, "CRAM response: %s\n", obuf));
+
+ mutt_to_base64 ((unsigned char*) ibuf, (unsigned char*) obuf, strlen (obuf));
+ strcpy (ibuf + strlen (ibuf), "\r\n");
+ mutt_socket_write (idata->conn, ibuf);
+
+ if (mutt_socket_readln (ibuf, LONG_STRING, idata->conn) < 0)
+ {
+ dprint (1, (debugfile, "Error receiving server response.\n"));
+ goto bail;
+ }
+
+ if (imap_code (ibuf))
+ return IMAP_AUTH_SUCCESS;
+
+ bail:
+ mutt_error _("CRAM-MD5 authentication failed.");
+ sleep (2);
+ return IMAP_AUTH_FAILURE;
+}
+
+/* hmac_md5: produce CRAM-MD5 challenge response. */
+static void hmac_md5 (const char* password, char* challenge,
+ unsigned char* response)
+{
+ MD5_CTX ctx;
+ unsigned char ipad[MD5_BLOCK_LEN], opad[MD5_BLOCK_LEN];
+ unsigned char secret[MD5_BLOCK_LEN+1];
+ unsigned char hash_passwd[MD5_DIGEST_LEN];
+ unsigned int secret_len, chal_len;
+ int i;
+
+ secret_len = strlen (password);
+ chal_len = strlen (challenge);
+
+ /* passwords longer than MD5_BLOCK_LEN bytes are substituted with their MD5
+ * digests */
+ if (secret_len > MD5_BLOCK_LEN)
+ {
+ MD5Init (&ctx);
+ MD5Update (&ctx, (unsigned char*) password, secret_len);
+ MD5Final (hash_passwd, &ctx);
+ strfcpy ((char*) secret, (char*) hash_passwd, MD5_DIGEST_LEN);
+ secret_len = MD5_DIGEST_LEN;
+ }
+ else
+ strfcpy ((char *) secret, password, sizeof (secret));
+
+ memset (ipad, 0, sizeof (ipad));
+ memset (opad, 0, sizeof (opad));
+ memcpy (ipad, secret, secret_len);
+ memcpy (opad, secret, secret_len);
+
+ for (i = 0; i < MD5_BLOCK_LEN; i++)
+ {
+ ipad[i] ^= 0x36;
+ opad[i] ^= 0x5c;
+ }
+
+ /* inner hash: challenge and ipadded secret */
+ MD5Init (&ctx);
+ MD5Update (&ctx, ipad, MD5_BLOCK_LEN);
+ MD5Update (&ctx, (unsigned char*) challenge, chal_len);
+ MD5Final (response, &ctx);
+
+ /* outer hash: inner hash and opadded secret */
+ MD5Init (&ctx);
+ MD5Update (&ctx, opad, MD5_BLOCK_LEN);
+ MD5Update (&ctx, response, MD5_DIGEST_LEN);
+ MD5Final (response, &ctx);
+}
#include "mutt.h"
#include "imap_private.h"
+#include "auth.h"
#include <netinet/in.h>
#define GSS_AUTH_P_INTEGRITY 2
#define GSS_AUTH_P_PRIVACY 4
-/* imap_auth_gss: AUTH=GSSAPI support. Used unconditionally if the server
- * supports it */
-int imap_auth_gss (IMAP_DATA* idata, const char* user)
+/* imap_auth_gss: AUTH=GSSAPI support. */
+imap_auth_res_t imap_auth_gss (IMAP_DATA* idata)
{
gss_buffer_desc request_buf, send_token;
gss_buffer_t sec_token;
char buf1[GSS_BUFSIZE], buf2[GSS_BUFSIZE], server_conf_flags;
unsigned long buf_size;
- dprint (2, (debugfile, "Attempting GSS login...\n"));
+ if (!mutt_bit_isset (idata->capabilities, AGSSAPI))
+ return IMAP_AUTH_UNAVAIL;
+ mutt_message _("Authenticating (GSS)...");
+
+ if (mutt_account_getuser (&idata->conn->account))
+ return IMAP_AUTH_FAILURE;
+
/* get an IMAP service ticket for the server */
snprintf (buf1, sizeof (buf1), "imap@%s", idata->conn->account.host);
request_buf.value = buf1;
if (maj_stat != GSS_S_COMPLETE)
{
dprint (2, (debugfile, "Couldn't get service name for [%s]\n", buf1));
- return -1;
+ goto bail;
}
#ifdef DEBUG
else if (debuglevel >= 2)
{
dprint (1, (debugfile, "Error receiving server response.\n"));
gss_release_name (&min_stat, &target_name);
-
- return -1;
+ goto bail;
}
if (buf1[0] != '+')
{
dprint (2, (debugfile, "Invalid response from server: %s\n", buf1));
gss_release_name (&min_stat, &target_name);
-
- return -1;
+ goto bail;
}
/* now start the security context initialisation loop... */
/* end authentication attempt */
mutt_socket_write (idata->conn, "*\r\n");
mutt_socket_readln (buf1, sizeof (buf1), idata->conn);
-
- return -1;
+ goto bail;
}
/* send token */
{
dprint (1, (debugfile, "Error receiving server response.\n"));
gss_release_name (&min_stat, &target_name);
-
- return -1;
+ goto bail;
}
request_buf.length = mutt_from_base64 (buf2, buf1 + 2);
if (mutt_socket_readln (buf1, sizeof (buf1), idata->conn) < 0)
{
dprint (1, (debugfile, "Error receiving server response.\n"));
-
- return -1;
+ goto bail;
}
request_buf.length = mutt_from_base64 (buf2, buf1 + 2);
request_buf.value = buf2;
{
dprint (2, (debugfile, "Couldn't unwrap security level data\n"));
gss_release_buffer (&min_stat, &send_token);
-
mutt_socket_write(idata->conn, "*\r\n");
- return -1;
+ goto bail;
}
dprint (2, (debugfile, "Credential exchange complete\n"));
{
dprint (2, (debugfile, "Server requires integrity or privace\n"));
gss_release_buffer (&min_stat, &send_token);
-
mutt_socket_write(idata->conn, "*\r\n");
- return -1;
+ goto bail;
}
/* we don't care about buffer size if we don't wrap content. But here it is */
memcpy (buf1, &buf_size, 4);
buf1[0] = GSS_AUTH_P_NONE;
/* server decides if principal can log in as user */
- strncpy (buf1 + 4, user, sizeof (buf1) - 4);
+ strncpy (buf1 + 4, idata->conn->account.user, sizeof (buf1) - 4);
request_buf.value = buf1;
- request_buf.length = 4 + strlen (user) + 1;
+ request_buf.length = 4 + strlen (idata->conn->account.user) + 1;
maj_stat = gss_wrap (&min_stat, context, 0, GSS_C_QOP_DEFAULT, &request_buf,
&cflags, &send_token);
if (maj_stat != GSS_S_COMPLETE)
{
dprint (2, (debugfile, "Error creating login request\n"));
-
mutt_socket_write(idata->conn, "*\r\n");
- return -1;
+ goto bail;
}
mutt_to_base64 ((unsigned char*) buf1, send_token.value, send_token.length);
- dprint (2, (debugfile, "Requesting authorisation as %s\n", user));
+ dprint (2, (debugfile, "Requesting authorisation as %s\n",
+ idata->conn->account.user));
strncat (buf1, "\r\n", sizeof (buf1));
mutt_socket_write (idata->conn, buf1);
if (mutt_socket_readln (buf1, GSS_BUFSIZE, idata->conn) < 0)
{
dprint (1, (debugfile, "Error receiving server response.\n"));
-
mutt_socket_write(idata->conn, "*\r\n");
- return -1;
+ goto bail;
}
if (imap_code (buf1))
{
if (maj_stat != GSS_S_COMPLETE)
{
dprint (1, (debugfile, "Error releasing credentials\n"));
-
- return -1;
+ goto bail;
}
/* send_token may contain a notification to the server to flush
* credentials. RFC 1731 doesn't specify what to do, and since this
* enough to flush its own credentials */
gss_release_buffer (&min_stat, &send_token);
- dprint (2, (debugfile, "GSS login complete\n"));
-
- return 0;
+ return IMAP_AUTH_SUCCESS;
}
- /* logon failed */
- dprint (2, (debugfile, "GSS login failed.\n"));
-
- return -1;
+ bail:
+ mutt_error _("GSS authentication failed.");
+ sleep (2);
+ return IMAP_AUTH_FAILURE;
}
--- /dev/null
+/*
+ * Copyright (C) 1999-2000 Brendan Cully <brendan@kublai.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 Place - Suite 330, Boston, MA 02111, USA.
+ */
+
+/* plain LOGIN support */
+
+#include "mutt.h"
+#include "imap_private.h"
+#include "auth.h"
+
+/* imap_auth_login: Plain LOGIN support */
+imap_auth_res_t imap_auth_login (IMAP_DATA* idata)
+{
+ char q_user[SHORT_STRING], q_pass[SHORT_STRING];
+ char buf[LONG_STRING];
+ int rc;
+
+ if (mutt_account_getuser (&idata->conn->account))
+ return IMAP_AUTH_FAILURE;
+ if (mutt_account_getpass (&idata->conn->account))
+ return IMAP_AUTH_FAILURE;
+
+ mutt_message _("Logging in...");
+
+ imap_quote_string (q_user, sizeof (q_user), idata->conn->account.user);
+ imap_quote_string (q_pass, sizeof (q_pass), idata->conn->account.pass);
+
+#ifdef DEBUG
+ /* don't print the password unless we're at the ungodly debugging level
+ * of 5 or higher */
+
+ if (debuglevel < IMAP_LOG_PASS)
+ dprint (2, (debugfile, "Sending LOGIN command for %s...\n",
+ idata->conn->account.user));
+#endif
+
+ snprintf (buf, sizeof (buf), "LOGIN %s %s", q_user, q_pass);
+ rc = imap_exec (buf, sizeof (buf), idata, buf,
+ IMAP_CMD_FAIL_OK | IMAP_CMD_PASS);
+
+ if (!rc)
+ return IMAP_AUTH_SUCCESS;
+
+ else if (rc == -1)
+ dprint (1, (debugfile, "imap_auth_login: Error logging in.\n"));
+
+ mutt_error _("Login failed.");
+ sleep (2);
+ return IMAP_AUTH_FAILURE;
+}
--- /dev/null
+/*
+ * Copyright (C) 2000 Brendan Cully <brendan@kublai.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 Place - Suite 330, Boston, MA 02111, USA.
+ */
+
+/* SASL login/authentication code */
+
+#include "mutt.h"
+#include "mutt_sasl.h"
+#include "imap_private.h"
+#include "auth.h"
+
+#include <sasl.h>
+#include <saslutil.h>
+
+/* imap_auth_sasl: Default authenticator if available. */
+imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata)
+{
+ sasl_conn_t* saslconn;
+ int rc;
+ char buf[LONG_STRING];
+ const char* mech;
+ char* pc;
+ unsigned int len;
+
+ if (mutt_sasl_start () != SASL_OK)
+ return IMAP_AUTH_FAILURE;
+
+ /* TODO: set fourth option to SASL_SECURITY_LAYER once we have a wrapper
+ * (ie more than auth code) for SASL. */
+ rc = sasl_client_new ("imap", idata->conn->account.host,
+ mutt_sasl_get_callbacks (&idata->conn->account), 0, &saslconn);
+
+ if (rc != SASL_OK)
+ {
+ dprint (1, (debugfile, "imap_auth_sasl: Error allocating SASL connection.\n"));
+ return IMAP_AUTH_FAILURE;
+ }
+
+ rc = sasl_client_start (saslconn, idata->capstr, NULL, NULL, &pc, &len,
+ &mech);
+
+ if (rc != SASL_OK && rc != SASL_CONTINUE)
+ {
+ dprint (1, (debugfile, "imap_auth_sasl: Failure starting authentication exchange. No shared mechanisms?\n"));
+ /* SASL doesn't support LOGIN, so fall back */
+
+ return IMAP_AUTH_UNAVAIL;
+ }
+
+ mutt_message _("Authenticating (SASL)...");
+
+ snprintf (buf, sizeof (buf), "AUTHENTICATE %s", mech);
+ imap_cmd_start (idata, buf);
+
+ /* I believe IMAP requires a server response (even if empty) before the
+ * client can send data, so len should always be zero at this point */
+ if (len != 0)
+ {
+ dprint (1, (debugfile, "imap_auth_sasl: SASL produced invalid exchange!\n"));
+ goto bail;
+ }
+
+ while (rc == SASL_CONTINUE)
+ {
+ if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
+ goto bail;
+
+ if (!mutt_strncmp (buf, "+ ", 2))
+ if (sasl_decode64 (buf+2, strlen (buf+2), buf, &len) != SASL_OK)
+ {
+ dprint (1, (debugfile, "imap_auth_sasl: error base64-decoding server response.\n"));
+ goto bail;
+ }
+
+ rc = sasl_client_step (saslconn, buf, len, NULL, &pc, &len);
+
+ if (rc != SASL_CONTINUE)
+ break;
+
+ /* send out response, or line break if none needed */
+ if (sasl_encode64 (pc, len, buf, sizeof (buf), &len) != SASL_OK)
+ {
+ dprint (1, (debugfile, "imap_auth_sasl: error base64-encoding client response.\n"));
+ goto bail;
+ }
+
+ strfcpy (buf + len, "\r\n", sizeof (buf) - len);
+ mutt_socket_write (idata->conn, buf);
+ }
+
+ if (rc != SASL_OK)
+ goto bail;
+
+ if (imap_code (buf))
+ {
+ /* later we'll want to keep saslconn, when we support a protection layer.
+ * For now it shouldn't hurt to dispose of it at this point. */
+ sasl_dispose (&saslconn);
+ return IMAP_AUTH_SUCCESS;
+ }
+
+ bail:
+ mutt_error _("SASL authentication failed.");
+ sleep(2);
+ sasl_dispose (&saslconn);
+
+ return IMAP_AUTH_FAILURE;
+}
{
int x;
+ idata->capstr = safe_strdup (imap_next_word (s));
+
while (*s)
{
for (x = 0; x < CAPMAX; x++)
break;
}
s = imap_next_word (s);
- }
+ }
}
/* cmd_parse_expunge: mark headers with new sequence ID and mark idata to
static int imap_get_delim (IMAP_DATA *idata);
static char* imap_get_flags (LIST** hflags, char* s);
static int imap_check_acl (IMAP_DATA *idata);
-static int imap_check_capabilities (IMAP_DATA *idata);
+static int imap_check_capabilities (IMAP_DATA* idata);
static void imap_set_flag (IMAP_DATA* idata, int aclbit, int flag,
const char* str, char* flags);
{
tmp = conn;
- if (conn->account.type == M_ACCT_TYPE_IMAP && conn->up)
+ if (conn->account.type == M_ACCT_TYPE_IMAP && conn->fd >= 0)
{
mutt_message (_("Closing connection to %s..."), conn->account.host);
imap_logout ((IMAP_DATA*) conn->data);
return 0;
}
-static int imap_check_capabilities (IMAP_DATA *idata)
+/* imap_check_capabilities: make sure we can log in to this server. */
+static int imap_check_capabilities (IMAP_DATA* idata)
{
char buf[LONG_STRING];
imap_error ("imap_check_capabilities", buf);
return -1;
}
+
if (!(mutt_bit_isset(idata->capabilities,IMAP4)
||mutt_bit_isset(idata->capabilities,IMAP4REV1)))
{
mutt_error _("This IMAP server is ancient. Mutt does not work with it.");
sleep (5); /* pause a moment to let the user see the error */
+
return -1;
}
+
return 0;
}
idata->state = IMAP_CONNECTED;
if (mutt_socket_readln (buf, sizeof (buf), idata->conn) < 0)
- {
- mutt_socket_close (idata->conn);
- idata->state = IMAP_DISCONNECTED;
-
- return -1;
- }
+ goto bail;
if (mutt_strncmp ("* OK", buf, 4) == 0)
{
- if (imap_check_capabilities(idata) != 0
- || imap_authenticate (idata) != 0)
- {
- mutt_socket_close (idata->conn);
- idata->state = IMAP_DISCONNECTED;
- return -1;
- }
+ if (imap_check_capabilities (idata) || imap_authenticate (idata))
+ goto bail;
}
else if (mutt_strncmp ("* PREAUTH", buf, 9) == 0)
{
if (imap_check_capabilities(idata) != 0)
- {
- mutt_socket_close (idata->conn);
- idata->state = IMAP_DISCONNECTED;
- return -1;
- }
+ goto bail;
}
else
{
imap_error ("imap_open_connection()", buf);
- mutt_socket_close (idata->conn);
- idata->state = IMAP_DISCONNECTED;
- return -1;
+ goto bail;
}
+ FREE (&idata->capstr);
idata->state = IMAP_AUTHENTICATED;
imap_get_delim (idata);
return 0;
+
+ bail:
+ FREE (&idata->capstr);
+ mutt_socket_close (idata->conn);
+ idata->state = IMAP_DISCONNECTED;
+ return -1;
}
/* imap_get_flags: Make a simple list out of a FLAGS response.
TORDEREDSUBJECT, /* THREAD=ORDEREDSUBJECT */
UIDPLUS, /* RFC 2859: IMAP4 UIDPLUS extension */
AUTH_ANON, /* AUTH=ANONYMOUS */
-
+
CAPMAX
};
unsigned char status;
unsigned char check_status;
unsigned char capabilities[(CAPMAX + 7)/8];
+ /* let me explain capstr: SASL needs the capability string (not bits).
+ * we have 3 options:
+ * 1. rerun CAPABILITY inside SASL function.
+ * 2. build appropriate CAPABILITY string by reverse-engineering from bits.
+ * 3. keep a copy until after authentication.
+ * I've chosen (3) for now. (2) might not be too bad, but it involves
+ * tracking all possible capabilities. bah. (1) I don't like because
+ * it's just no fun to get the same information twice */
+ char* capstr;
char seq[SEQLEN+1];
/* The following data is all specific to the currently SELECTED mbox */
** .pp
** This variable defaults to your user name on the local machine.
*/
- { "imap_cramkey", DT_STR, R_NONE, UL &ImapCRAMKey, UL 0 },
- /*
- ** .pp
- ** Sets your CRAM secret, for use with the CRAM-MD5 IMAP authentication
- ** method (this is the IMAP equivelent of APOP). This method will be
- ** attempted automatically if the server supports it, in preference to the
- ** less secure login technique. If you use CRAM-MD5, you do not need to set
- ** \fIimap_pass\fP.
- */
{ "imap_pass", DT_STR, R_NONE, UL &ImapPass, UL 0 },
/*
** .pp
[AC_MSG_CHECKING([whether NLS is requested])
dnl Default is enabled NLS
AC_ARG_ENABLE(nls,
- [ --disable-nls do not use Native Language Support],
+ [ --disable-nls Do not use Native Language Support],
USE_NLS=$enableval, USE_NLS=yes)
AC_MSG_RESULT($USE_NLS)
AC_SUBST(USE_NLS)
AC_DEFINE(ENABLE_NLS)
AC_MSG_CHECKING([whether included gettext is requested])
AC_ARG_WITH(included-gettext,
- [ --with-included-gettext use the GNU gettext library included here],
+ [ --with-included-gettext Use the GNU gettext library included here],
nls_cv_force_use_gnu_gettext=$withval,
nls_cv_force_use_gnu_gettext=no)
AC_MSG_RESULT($nls_cv_force_use_gnu_gettext)
if test "$CATOBJEXT" = "NONE"; then
AC_MSG_CHECKING([whether catgets can be used])
AC_ARG_WITH(catgets,
- [ --with-catgets use catgets functions if available],
+ [ --with-catgets Use catgets functions if available],
nls_cv_use_catgets=$withval, nls_cv_use_catgets=no)
AC_MSG_RESULT($nls_cv_use_catgets)
#endif
);
puts (
+#ifdef USE_POP
+ "+USE_POP "
+#else
+ "-USE_POP "
+#endif
+
#ifdef USE_IMAP
"+USE_IMAP "
#else
"-USE_GSS "
#endif
-#ifdef HAVE_HEIMDAHL
- "+HAVE_HEIMDAHL "
-#else
- "-HAVE_HEIMDAHL "
-#endif
-
#ifdef USE_SSL
"+USE_SSL "
"-USE_SSL "
#endif
- "\n"
-
-#ifdef USE_POP
- "+USE_POP "
+#ifdef USE_SASL
+ "+USE_SASL "
#else
- "-USE_POP "
+ "-USE_SASL "
#endif
-
+ "\n"
+
#ifdef HAVE_REGCOMP
"+HAVE_REGCOMP "
#else
--- /dev/null
+/*
+ * Copyright (C) 2000 Brendan Cully <brendan@kublai.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 Place - Suite 330, Boston, MA 02111, USA.
+ */
+
+/* common SASL helper routines */
+
+#include "mutt.h"
+#include "account.h"
+#include "mutt_sasl.h"
+#include "mutt_socket.h"
+
+#include <sasl.h>
+
+static sasl_callback_t mutt_sasl_callbacks[3];
+
+/* callbacks */
+static int mutt_sasl_cb_log (void* context, int priority, const char* message);
+static int mutt_sasl_cb_authname (void* context, int id, const char** result,
+ unsigned int* len);
+static int mutt_sasl_cb_pass (sasl_conn_t* conn, void* context, int id,
+ sasl_secret_t** psecret);
+
+/* mutt_sasl_start: called before doing a SASL exchange - initialises library
+ * (if neccessary). */
+int mutt_sasl_start (void)
+{
+ static unsigned char sasl_init = 0;
+
+ sasl_callback_t* callback, callbacks[2];
+ int rc;
+
+ if (!sasl_init) {
+ /* set up default logging callback */
+ callback = callbacks;
+
+ callback->id = SASL_CB_LOG;
+ callback->proc = mutt_sasl_cb_log;
+ callback->context = NULL;
+ callback++;
+
+ callback->id = SASL_CB_LIST_END;
+ callback->proc = NULL;
+ callback->context = NULL;
+
+ rc = sasl_client_init (callbacks);
+
+ if (rc != SASL_OK)
+ {
+ dprint (1, (debugfile, "mutt_sasl_start: libsasl initialisation failed.\n"));
+ return SASL_FAIL;
+ }
+
+ sasl_init = 1;
+ }
+
+ return SASL_OK;
+}
+
+sasl_callback_t* mutt_sasl_get_callbacks (ACCOUNT* account)
+{
+ sasl_callback_t* callback;
+
+ callback = mutt_sasl_callbacks;
+
+ callback->id = SASL_CB_AUTHNAME;
+ callback->proc = mutt_sasl_cb_authname;
+ callback->context = account;
+ callback++;
+
+ callback->id = SASL_CB_PASS;
+ callback->proc = mutt_sasl_cb_pass;
+ callback->context = account;
+ callback++;
+
+ callback->id = SASL_CB_LIST_END;
+ callback->proc = NULL;
+ callback->context = NULL;
+
+ return mutt_sasl_callbacks;
+}
+
+/* mutt_sasl_cb_log: callback to log SASL messages */
+static int mutt_sasl_cb_log (void* context, int priority, const char* message)
+{
+ dprint (priority, (debugfile, "SASL: %s\n", message));
+
+ return SASL_OK;
+}
+
+/* mutt_sasl_cb_authname: callback to retrieve authname from ACCOUNT */
+static int mutt_sasl_cb_authname (void* context, int id, const char** result,
+ unsigned* len)
+{
+ ACCOUNT* account = (ACCOUNT*) context;
+
+ *result = NULL;
+ if (len)
+ *len = 0;
+
+ if (!account)
+ return SASL_BADPARAM;
+
+ dprint (2, (debugfile, "mutt_sasl_cb_authname: getting user for %s:%u\n",
+ account->host, account->port));
+
+ if (mutt_account_getuser (account))
+ return SASL_FAIL;
+
+ *result = account->user;
+
+ if (len)
+ *len = strlen (*result);
+
+ return SASL_OK;
+}
+
+static int mutt_sasl_cb_pass (sasl_conn_t* conn, void* context, int id,
+ sasl_secret_t** psecret)
+{
+ ACCOUNT* account = (ACCOUNT*) context;
+ int len;
+
+ if (!account || !psecret)
+ return SASL_BADPARAM;
+
+ dprint (2, (debugfile,
+ "mutt_sasl_cb_pass: getting password for %s@%s:%u\n", account->user,
+ account->host, account->port));
+
+ if (mutt_account_getpass (account))
+ return SASL_FAIL;
+
+ len = strlen (account->pass);
+
+ *psecret = (sasl_secret_t*) malloc (sizeof (sasl_secret_t) + len);
+ (*psecret)->len = len;
+ strcpy ((*psecret)->data, account->pass);
+
+ return SASL_OK;
+}
--- /dev/null
+/*
+ * Copyright (C) 2000 Brendan Cully <brendan@kublai.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 Place - Suite 330, Boston, MA 02111, USA.
+ */
+
+/* common SASL helper routines */
+
+#ifndef _MUTT_SASL_H_
+#define _MUTT_SASL_H_ 1
+
+#include "mutt_socket.h"
+
+#include <sasl.h>
+
+int mutt_sasl_start (void);
+sasl_callback_t* mutt_sasl_get_callbacks (ACCOUNT* account);
+
+#endif /* _MUTT_SASL_H_ */
#include "globals.h"
#include "mutt_socket.h"
#ifdef USE_SSL
-#include "imap_ssl.h"
+# include "imap_ssl.h"
#endif
#include <unistd.h>
/* Wrappers */
int mutt_socket_open (CONNECTION* conn)
{
- int rc;
-
- rc = conn->open (conn);
- if (!rc)
- conn->up = 1;
-
- return rc;
+ return conn->open (conn);
}
int mutt_socket_close (CONNECTION* conn)
{
- conn->up = 0;
+ int rc;
+
+ rc = conn->close (conn);
+ conn->fd = -1;
- return conn->close (conn);
+ return rc;
}
int mutt_socket_write_d (CONNECTION *conn, const char *buf, int dbg)
}
/* mutt_conn_find: find a connection off the list of connections whose
- * account matches account. If newconn is true, don't reuse one, but add
- * it to the list. If start is not null, only search for connections after
- * the given connection (allows higher level socket code to make more
- * fine-grained searches than account info - eg in IMAP we may wish
- * to find a connection which is not in IMAP_SELECTED state) */
+ * account matches account. If start is not null, only search for
+ * connections after the given connection (allows higher level socket code
+ * to make more fine-grained searches than account info - eg in IMAP we may
+ * wish to find a connection which is not in IMAP_SELECTED state) */
CONNECTION* mutt_conn_find (const CONNECTION* start, const ACCOUNT* account)
{
CONNECTION* conn;
#define _MUTT_SOCKET_H_ 1
#include "account.h"
+#include "lib.h"
/* logging levels */
#define M_SOCK_LOG_CMD 2
int (*write) (struct _connection *conn, const char *buf);
int (*open) (struct _connection *conn);
int (*close) (struct _connection *conn);
-
- /* status bits */
-
- int up : 1; /* is the connection up? */
} CONNECTION;
int mutt_socket_open (CONNECTION* conn);