X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=imap%2Fauth.c;h=fd3b8ceb7cfb4df3704cba9d8b08163bc3c36d25;hp=0c56e851a022cef3de943993f3e973341b3f70c3;hb=819c071fa7efc8dffb4dd92f36f0111227ff692f;hpb=6833ce8bdca2d64e14485118f2a4417b7e1cb1b1 diff --git a/imap/auth.c b/imap/auth.c index 0c56e85..fd3b8ce 100644 --- a/imap/auth.c +++ b/imap/auth.c @@ -1,109 +1,195 @@ /* + * Copyright notice from original mutt: * Copyright (C) 1996-8 Michael R. Elkins * Copyright (C) 1996-9 Brandon Long * Copyright (C) 1999-2001 Brendan Cully - * - * 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. - */ + * + * This file is part of mutt-ng, see http://www.muttng.org/. + * It's licensed under the GNU General Public License, + * please see the file GPL in the top level source directory. + */ /* IMAP login/authentication code */ +#include + +#include +#include + #include "mutt.h" +#include "mutt_sasl.h" #include "imap_private.h" -#include "auth.h" - -static imap_auth_t imap_authenticators[] = { -#ifdef USE_SASL - { imap_auth_sasl, NULL }, -#else - { imap_auth_anon, "anonymous" }, -#endif -#ifdef USE_GSS - { imap_auth_gss, "gssapi" }, -#endif - /* SASL includes CRAM-MD5 (and GSSAPI, but that's not enabled by default) */ -#ifndef USE_SASL - { imap_auth_cram_md5, "cram-md5" }, -#endif - { imap_auth_login, "login" }, - - { NULL } + +enum { + IMAP_AUTH_SUCCESS = 0, + IMAP_AUTH_FAILURE, + IMAP_AUTH_UNAVAIL }; -/* imap_authenticate: Attempt to authenticate using either user-specified - * authentication method if specified, or any. */ -int imap_authenticate (IMAP_DATA* idata) +/* imap_auth_sasl: Default authenticator if available. */ +static int imap_auth_sasl(IMAP_DATA * idata, const char *method) { - imap_auth_t* authenticator; - char* methods; - char* method; - char* delim; - int r = -1; - - if (ImapAuthenticators && *ImapAuthenticators) - { - /* Try user-specified list of authentication methods */ - methods = safe_strdup (ImapAuthenticators); - - for (method = methods; method; method = delim) - { - delim = strchr (method, ':'); - if (delim) - *delim++ = '\0'; - if (! method[0]) - continue; - - dprint (2, (debugfile, "imap_authenticate: Trying method %s\n", method)); - authenticator = imap_authenticators; - - while (authenticator->authenticate) + sasl_conn_t *saslconn; + sasl_interact_t *interaction = NULL; + int rc, irc; + char buf[HUGE_STRING]; + const char *mech; + + const char *pc = NULL; + unsigned int len, olen; + unsigned char client_start; + + if (mutt_sasl_client_new (idata->conn, &saslconn) < 0) { + return IMAP_AUTH_FAILURE; + } + + rc = SASL_FAIL; + + /* If the user hasn't specified a method, use any available */ + if (!method) { + method = idata->capstr; + + /* hack for SASL ANONYMOUS support: + * 1. Fetch username. If it's "" or "anonymous" then + * 2. attempt sasl_client_start with only "AUTH=ANONYMOUS" capability + * 3. if sasl_client_start fails, fall through... */ + + if (mutt_account_getuser (&idata->conn->account)) + return IMAP_AUTH_FAILURE; + + if (mutt_bit_isset (idata->capabilities, AUTH_ANON) && + (!idata->conn->account.user[0] || + !m_strncmp(idata->conn->account.user, "anonymous", 9))) + rc = sasl_client_start (saslconn, "AUTH=ANONYMOUS", NULL, &pc, &olen, + &mech); + } + + if (rc != SASL_OK && rc != SASL_CONTINUE) + do { + rc = sasl_client_start (saslconn, method, &interaction, + &pc, &olen, &mech); + if (rc == SASL_INTERACT) + mutt_sasl_interact (interaction); + } + while (rc == SASL_INTERACT); + + client_start = (olen > 0); + + if (rc != SASL_OK && rc != SASL_CONTINUE) { + /* SASL doesn't support LOGIN, so fall back */ + return IMAP_AUTH_UNAVAIL; + } + + mutt_message (_("Authenticating (%s)..."), mech); + + snprintf (buf, sizeof (buf), "AUTHENTICATE %s", mech); + imap_cmd_start (idata, buf); + irc = IMAP_CMD_CONTINUE; + + /* looping protocol */ + while (rc == SASL_CONTINUE || olen > 0) { + do + irc = imap_cmd_step (idata); + while (irc == IMAP_CMD_CONTINUE); + + if (method && irc == IMAP_CMD_NO) { + sasl_dispose (&saslconn); + return IMAP_AUTH_UNAVAIL; + } + + if (irc == IMAP_CMD_BAD || irc == IMAP_CMD_NO) + goto bail; + + if (irc == IMAP_CMD_RESPOND) { + if (sasl_decode64(idata->cmd.buf.data + 2, idata->cmd.buf.len - 2, buf, + LONG_STRING - 1, &len) != SASL_OK) { - if (!authenticator->method || - !ascii_strcasecmp (authenticator->method, method)) - if ((r = authenticator->authenticate (idata, method)) != - IMAP_AUTH_UNAVAIL) - { - FREE (&methods); - return r; - } - - authenticator++; + goto bail; } } - FREE (&methods); - } - else - { - /* Fall back to default: any authenticator */ - dprint (2, (debugfile, "imap_authenticate: Using any available method.\n")); - authenticator = imap_authenticators; - - while (authenticator->authenticate) - { - if ((r = authenticator->authenticate (idata, NULL)) != IMAP_AUTH_UNAVAIL) - return r; - authenticator++; + /* client-start is only available with the SASL-IR extension, but + * SASL 2.1 seems to want to use it regardless, at least for DIGEST + * fast reauth. Override if the server sent an initial continuation */ + if (!client_start || buf[0]) { + do { + rc = sasl_client_step (saslconn, buf, len, &interaction, &pc, &olen); + if (rc == SASL_INTERACT) + mutt_sasl_interact (interaction); + } + while (rc == SASL_INTERACT); + } + else + client_start = 0; + + /* send out response, or line break if none needed */ + if (olen) { + if (sasl_encode64 (pc, olen, buf, sizeof (buf), &olen) != SASL_OK) { + goto bail; + } + } + + if (irc == IMAP_CMD_RESPOND) { + m_strcpy(buf + olen, sizeof(buf) - olen, "\r\n"); + mutt_socket_write (idata->conn, buf); } + + /* If SASL has errored out, send an abort string to the server */ + if (rc < 0) { + mutt_socket_write (idata->conn, "*\r\n"); + } + + olen = 0; + } + + while (irc != IMAP_CMD_OK) + if ((irc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) + break; + + if (rc != SASL_OK) + goto bail; + + if (imap_code(idata->cmd.buf.data)) { + mutt_sasl_setup_conn (idata->conn, saslconn); + return IMAP_AUTH_SUCCESS; } - if (r == IMAP_AUTH_UNAVAIL) - { +bail: + mutt_error _("SASL authentication failed."); + mutt_sleep (2); + sasl_dispose (&saslconn); + + return IMAP_AUTH_FAILURE; +} + +int imap_authenticate (IMAP_DATA * idata) +{ + int r = -1; + + if (!m_strisempty(ImapAuthenticators)) { + const char *p, *q; + char buf[STRING]; + + for (p = ImapAuthenticators;; p = q) { + while (*p == ':') + p++; + if (!*p) + break; + + q = strchrnul(p, ':'); + m_strncpy(buf, sizeof(buf), p, q - p); + + if ((r = imap_auth_sasl(idata, buf)) != IMAP_AUTH_UNAVAIL) { + return r; + } + } + } else { + if ((r = imap_auth_sasl(idata, NULL)) != IMAP_AUTH_UNAVAIL) { + return r; + } + } + mutt_error (_("No authenticators available")); mutt_sleep (1); - } - - return r; + return r; }