client-authenticate.c revision cd94aeaa294f7cc507206b4b2075852f00e14d61
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include "common.h"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include "base64.h"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include "buffer.h"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include "ioloop.h"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include "istream.h"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include "ostream.h"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include "safe-memset.h"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include "str.h"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include "str-sanitize.h"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include "imap-parser.h"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include "auth-client.h"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include "client.h"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include "client-authenticate.h"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include "imap-proxy.h"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#include <stdlib.h>
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#define IMAP_SERVICE_NAME "imap"
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forteconst char *client_authenticate_get_capabilities(bool secured)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte{
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const struct auth_mech_desc *mech;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte unsigned int i, count;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte string_t *str;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte str = t_str_new(128);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mech = auth_client_get_available_mechs(auth_client, &count);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (i = 0; i < count; i++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* a) transport is secured
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte b) auth mechanism isn't plaintext
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte c) we allow insecure authentication
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (secured || !disable_plaintext_auth ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (mech[i].flags & MECH_SEC_PLAINTEXT) == 0)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte str_append_c(str, ' ');
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte str_append(str, "AUTH=");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte str_append(str, mech[i].name);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return str_c(str);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte}
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic void client_auth_input(struct imap_client *client)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte{
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte char *line;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!client_read(client))
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (client->skip_line) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (i_stream_next_line(client->common.input) == NULL)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client->skip_line = FALSE;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* @UNSAFE */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte line = i_stream_next_line(client->common.input);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (line == NULL)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (strcmp(line, "*") == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sasl_server_auth_client_error(&client->common,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Authentication aborted");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte } else {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte auth_client_request_continue(client->common.auth_request, line);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte io_remove(&client->io);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* clear sensitive data */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte safe_memset(line, 0, strlen(line));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte}
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic void client_auth_failed(struct imap_client *client)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte{
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* get back to normal client input. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (client->io != NULL)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte io_remove(&client->io);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client->io = io_add(client->common.fd, IO_READ,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_input, client);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte}
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic bool client_handle_args(struct imap_client *client,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *const *args, bool success)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte{
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte string_t *reply;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte unsigned int port = 143;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte bool proxy = FALSE, temp = FALSE, nologin = !success, proxy_self;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (; *args != NULL; args++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (strcmp(*args, "nologin") == 0)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte nologin = TRUE;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else if (strcmp(*args, "proxy") == 0)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte proxy = TRUE;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else if (strcmp(*args, "temp") == 0)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte temp = TRUE;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else if (strncmp(*args, "reason=", 7) == 0)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte reason = *args + 7;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else if (strncmp(*args, "host=", 5) == 0)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte host = *args + 5;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else if (strncmp(*args, "port=", 5) == 0)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte port = atoi(*args + 5);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else if (strncmp(*args, "destuser=", 9) == 0)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte destuser = *args + 9;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else if (strncmp(*args, "pass=", 5) == 0)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte pass = *args + 5;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (destuser == NULL)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte destuser = client->common.virtual_user;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte proxy_self = proxy &&
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte login_proxy_is_ourself(&client->common, host, port, destuser);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (proxy && !proxy_self) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* we want to proxy the connection to another server.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte don't do this unless authentication succeeded. with
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte master user proxying we can get FAIL with proxy still set.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte proxy host=.. [port=..] [destuser=..] pass=.. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!success)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return FALSE;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (imap_proxy_new(client, host, port, destuser, pass) < 0)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_destroy_internal_failure(client);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return TRUE;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!proxy && host != NULL) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* IMAP referral
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte [nologin] referral host=.. [port=..] [destuser=..]
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte [reason=..]
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte NO [REFERRAL imap://destuser;AUTH=..@host:port/] Can't login.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte OK [...] Logged in, but you should use this server instead.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte .. [REFERRAL ..] (Reason from auth server)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte reply = t_str_new(128);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte str_append(reply, nologin ? "NO " : "OK ");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte str_printfa(reply, "[REFERRAL imap://%s;AUTH=%s@%s",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte destuser, client->common.auth_mech_name, host);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (port != 143)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte str_printfa(reply, ":%u", port);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte str_append(reply, "/] ");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (reason != NULL)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte str_append(reply, reason);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else if (nologin)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte str_append(reply, "Try this server instead.");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte str_append(reply, "Logged in, but you should use "
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "this server instead.");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_send_tagline(client, str_c(reply));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!nologin) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_destroy_success(client, "Login with referral");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return TRUE;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte } else if (nologin || proxy_self) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Authentication went ok, but for some reason user isn't
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte allowed to log in. Shouldn't probably happen. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (proxy_self) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_syslog(&client->common,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Proxying loops to itself");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte reply = t_str_new(128);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (reason != NULL)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte str_printfa(reply, "NO %s", reason);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else if (temp || proxy_self)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte str_append(reply, "NO "AUTH_TEMP_FAILED_MSG);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte str_append(reply, "NO "AUTH_FAILED_MSG);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_send_tagline(client, str_c(reply));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte } else {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* normal login/failure */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return FALSE;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte i_assert(nologin || proxy_self);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!client->destroyed)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_auth_failed(client);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return TRUE;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte}
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic void sasl_callback(struct client *_client, enum sasl_server_reply reply,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *data, const char *const *args)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte{
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte struct imap_client *client = (struct imap_client *)_client;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte struct const_iovec iov[3];
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *msg;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte size_t data_len;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte i_assert(!client->destroyed ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte reply == SASL_SERVER_REPLY_CLIENT_ERROR ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte reply == SASL_SERVER_REPLY_MASTER_FAILED);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte switch (reply) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte case SASL_SERVER_REPLY_SUCCESS:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (client->to_auth_waiting != NULL)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte timeout_remove(&client->to_auth_waiting);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (args != NULL) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (client_handle_args(client, args, TRUE))
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte break;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (client->full_capability_sent)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_send_tagline(client, "OK Logged in.");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_send_tagline(client, t_strdup_printf(
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "OK [CAPABILITY %s] Logged in.",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte capability_string));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_destroy_success(client, "Login");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte break;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte case SASL_SERVER_REPLY_AUTH_FAILED:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte case SASL_SERVER_REPLY_CLIENT_ERROR:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (client->to_auth_waiting != NULL)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte timeout_remove(&client->to_auth_waiting);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (args != NULL) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (client_handle_args(client, args, FALSE))
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte break;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte msg = reply == SASL_SERVER_REPLY_AUTH_FAILED ? "NO " : "BAD ";
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte msg = t_strconcat(msg, data != NULL ? data : AUTH_FAILED_MSG,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_send_tagline(client, msg);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!client->destroyed)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_auth_failed(client);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte break;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte case SASL_SERVER_REPLY_MASTER_FAILED:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (data == NULL)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_destroy_internal_failure(client);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte else {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_send_tagline(client,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte t_strconcat("NO ", data, NULL));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* authentication itself succeeded, we just hit some
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte internal failure. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_destroy_success(client, data);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte break;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte case SASL_SERVER_REPLY_CONTINUE:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte data_len = strlen(data);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte iov[0].iov_base = "+ ";
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte iov[0].iov_len = 2;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte iov[1].iov_base = data;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte iov[1].iov_len = data_len;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte iov[2].iov_base = "\r\n";
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte iov[2].iov_len = 2;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* don't check return value here. it gets tricky if we try
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte to call client_destroy() in here. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (void)o_stream_sendv(client->output, iov, 3);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte i_assert(client->io == NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client->io = io_add(client->common.fd, IO_READ,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_auth_input, client);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_auth_input(client);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_unref(client);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte}
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int client_auth_begin(struct imap_client *client, const char *mech_name,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *init_resp)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte{
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_ref(client);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sasl_server_auth_begin(&client->common, IMAP_SERVICE_NAME, mech_name,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte init_resp, sasl_callback);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!client->common.authenticating)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return 1;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* don't handle input until we get the initial auth reply */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (client->io != NULL)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte io_remove(&client->io);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_set_auth_waiting(client);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return 0;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte}
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forteint cmd_authenticate(struct imap_client *client, const struct imap_arg *args)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte{
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *mech_name, *init_resp = NULL;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* we want only one argument: authentication mechanism name */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return -1;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (args[1].type != IMAP_ARG_EOL) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* optional SASL initial response */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (args[1].type != IMAP_ARG_ATOM ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte args[2].type != IMAP_ARG_EOL)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return -1;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte init_resp = IMAP_ARG_STR(&args[1]);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mech_name = IMAP_ARG_STR(&args[0]);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (*mech_name == '\0')
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return -1;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return client_auth_begin(client, mech_name, init_resp);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte}
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forteint cmd_login(struct imap_client *client, const struct imap_arg *args)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte{
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *user, *pass;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte string_t *plain_login, *base64;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* two arguments: username and password */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return -1;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (args[1].type != IMAP_ARG_ATOM && args[1].type != IMAP_ARG_STRING)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return -1;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (args[2].type != IMAP_ARG_EOL)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return -1;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte user = IMAP_ARG_STR(&args[0]);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte pass = IMAP_ARG_STR(&args[1]);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!client->common.secured && disable_plaintext_auth) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (verbose_auth) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_syslog(&client->common, "Login failed: "
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Plaintext authentication disabled");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client->common.auth_tried_disabled_plaintext = TRUE;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_send_line(client,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "* BAD [ALERT] Plaintext authentication is disabled, "
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "but your client sent password in plaintext anyway. "
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "If anyone was listening, the password was exposed.");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte client_send_tagline(client, "NO "AUTH_PLAINTEXT_DISABLED_MSG);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return 1;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte }
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* authorization ID \0 authentication ID \0 pass */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte plain_login = buffer_create_dynamic(pool_datastack_create(), 64);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte buffer_append_c(plain_login, '\0');
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte buffer_append(plain_login, user, strlen(user));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte buffer_append_c(plain_login, '\0');
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte buffer_append(plain_login, pass, strlen(pass));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte base64 = buffer_create_dynamic(pool_datastack_create(),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte MAX_BASE64_ENCODED_SIZE(plain_login->used));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte base64_encode(plain_login->data, plain_login->used, base64);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return client_auth_begin(client, "PLAIN", str_c(base64));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte}
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte