client-authenticate.c revision 76b43e4417bab52e913da39b5f5bc2a130d3f149
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "common.h"
80c1d98d3638b71e57a39cafa88b9122bf8169c6Timo Sirainen#include "base64.h"
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen#include "buffer.h"
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream.h"
94a8cb0ee1d85569ad1a2acacd92d3ce22f8a1cbTimo Sirainen#include "ostream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "safe-memset.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "str.h"
50031a6b36a6051512bd18f39e4bbabe54acf565Timo Sirainen#include "str-sanitize.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-parser.h"
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen#include "auth-client.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "client.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "client-authenticate.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-proxy.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stdlib.h>
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
8887bf3757d51d73887dd20b1db3334d867d3817Timo Sirainen#define IMAP_SERVICE_NAME "imap"
8887bf3757d51d73887dd20b1db3334d867d3817Timo Sirainen
51b979b6414b940f04677a7e2d064be119345954Timo Sirainenconst char *client_authenticate_get_capabilities(bool secured)
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen{
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen const struct auth_mech_desc *mech;
589a9c6e8ee22071c14171c04bfc6bfe17121871Timo Sirainen unsigned int i, count;
589a9c6e8ee22071c14171c04bfc6bfe17121871Timo Sirainen string_t *str;
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen str = t_str_new(128);
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen mech = auth_client_get_available_mechs(auth_client, &count);
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen for (i = 0; i < count; i++) {
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen /* a) transport is secured
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen b) auth mechanism isn't plaintext
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen c) we allow insecure authentication
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (secured || !disable_plaintext_auth ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (mech[i].flags & MECH_SEC_PLAINTEXT) == 0)) {
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen str_append_c(str, ' ');
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen str_append(str, "AUTH=");
6ec7cf71ccd0eed1f9cc1b0bda8960796b04160bTimo Sirainen str_append(str, mech[i].name);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen
db5164c9a1129af0cfb11fc18d88da361a8011fbTimo Sirainen return str_c(str);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen}
db5164c9a1129af0cfb11fc18d88da361a8011fbTimo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainenstatic void client_auth_input(struct imap_client *client)
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen{
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen char *line;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!client_read(client))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->skip_line) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (i_stream_next_line(client->input) == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->skip_line = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen /* @UNSAFE */
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen line = i_stream_next_line(client->input);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen if (line == NULL)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen if (strcmp(line, "*") == 0) {
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen sasl_server_auth_client_error(&client->common,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Authentication aborted");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_client_request_continue(client->common.auth_request, line);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_remove(&client->io);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* clear sensitive data */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen safe_memset(line, 0, strlen(line));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool client_handle_args(struct imap_client *client,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *const *args, bool success)
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen{
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen string_t *reply;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int port = 143;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen bool proxy = FALSE, temp = FALSE, nologin = !success;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen for (; *args != NULL; args++) {
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen if (strcmp(*args, "nologin") == 0)
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen nologin = TRUE;
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen else if (strcmp(*args, "proxy") == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen proxy = TRUE;
b84451fa6ada675ae504725702e0815967124cbbTimo Sirainen else if (strcmp(*args, "temp") == 0)
b84451fa6ada675ae504725702e0815967124cbbTimo Sirainen temp = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strncmp(*args, "reason=", 7) == 0)
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen reason = *args + 7;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen else if (strncmp(*args, "host=", 5) == 0)
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen host = *args + 5;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strncmp(*args, "port=", 5) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen port = atoi(*args + 5);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strncmp(*args, "destuser=", 9) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen destuser = *args + 9;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen else if (strncmp(*args, "pass=", 5) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pass = *args + 5;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (destuser == NULL)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen destuser = client->common.virtual_user;
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (proxy &&
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen !login_proxy_is_ourself(&client->common, host, port, destuser)) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* we want to proxy the connection to another server.
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen don't do this unless authentication succeeded. with
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen master user proxying we can get FAIL with proxy still set.
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen proxy host=.. [port=..] [destuser=..] pass=.. */
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen if (!success)
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen return FALSE;
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen if (imap_proxy_new(client, host, port, destuser, pass) < 0)
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen client_destroy_internal_failure(client);
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen return TRUE;
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen }
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen if (!proxy && host != NULL) {
807b48fe1f6a57b01ed2cc20247d5b5e3facc562Timo Sirainen /* IMAP referral
807b48fe1f6a57b01ed2cc20247d5b5e3facc562Timo Sirainen
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen [nologin] referral host=.. [port=..] [destuser=..]
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen [reason=..]
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen NO [REFERRAL imap://destuser;AUTH=..@host:port/] Can't login.
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen OK [...] Logged in, but you should use this server instead.
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen .. [REFERRAL ..] (Reason from auth server)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen */
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen reply = t_str_new(128);
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen str_append(reply, nologin ? "NO " : "OK ");
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen str_printfa(reply, "[REFERRAL imap://%s;AUTH=%s@%s",
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen destuser, client->common.auth_mech_name, host);
250105a1440167ef000323cdb2721cd2a3688e1eTimo Sirainen if (port != 143)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_printfa(reply, ":%u", port);
6bc98d3898c475ba7615ba2b016e5142c8b2c09fTimo Sirainen str_append(reply, "/] ");
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen if (reason != NULL)
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen str_append(reply, reason);
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen else if (nologin)
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen str_append(reply, "Try this server instead.");
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen else {
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen str_append(reply, "Logged in, but you should use "
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen "this server instead.");
d6a1fa1d65c6d1996937802c2482c0f14dd821a7Timo Sirainen }
d6a1fa1d65c6d1996937802c2482c0f14dd821a7Timo Sirainen client_send_tagline(client, str_c(reply));
807b48fe1f6a57b01ed2cc20247d5b5e3facc562Timo Sirainen if (!nologin) {
807b48fe1f6a57b01ed2cc20247d5b5e3facc562Timo Sirainen client_destroy(client, "Login with referral");
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen return TRUE;
cfbacf6ea5fb39ae5304e4d95a78d9d4751bdfe1Timo Sirainen }
dc912088f84c263db1609435c2f5d7cb29bf1a33Timo Sirainen } else if (nologin) {
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen /* Authentication went ok, but for some reason user isn't
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen allowed to log in. Shouldn't probably happen. */
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen reply = t_str_new(128);
7761758f43d6150be4b07f4c54457ce662f78c4cTimo Sirainen if (reason != NULL)
6bc98d3898c475ba7615ba2b016e5142c8b2c09fTimo Sirainen str_printfa(reply, "NO %s", reason);
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen else if (temp)
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen str_append(reply, "NO "AUTH_TEMP_FAILED_MSG);
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen else
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen str_append(reply, "NO "AUTH_FAILED_MSG);
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen client_send_tagline(client, str_c(reply));
6bc98d3898c475ba7615ba2b016e5142c8b2c09fTimo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* normal login/failure */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(nologin);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!client->destroyed) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* get back to normal client input. */
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen if (client->io != NULL)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen io_remove(&client->io);
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen client_input, client);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen }
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainenstatic void sasl_callback(struct client *_client, enum sasl_server_reply reply,
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen const char *data, const char *const *args)
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen{
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen struct imap_client *client = (struct imap_client *)_client;
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen struct const_iovec iov[3];
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen const char *msg;
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen size_t data_len;
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen i_assert(!client->destroyed ||
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen reply == SASL_SERVER_REPLY_CLIENT_ERROR ||
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen reply == SASL_SERVER_REPLY_MASTER_FAILED);
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen switch (reply) {
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen case SASL_SERVER_REPLY_SUCCESS:
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen if (args != NULL) {
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen if (client_handle_args(client, args, TRUE))
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen break;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen }
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen client_send_tagline(client, "OK Logged in.");
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen client_destroy(client, "Login");
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen break;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen case SASL_SERVER_REPLY_AUTH_FAILED:
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen case SASL_SERVER_REPLY_CLIENT_ERROR:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (args != NULL) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (client_handle_args(client, args, FALSE))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen msg = reply == SASL_SERVER_REPLY_AUTH_FAILED ? "NO " : "BAD ";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen msg = t_strconcat(msg, data != NULL ? data : AUTH_FAILED_MSG,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen NULL);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen client_send_tagline(client, msg);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if (!client->destroyed) {
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen /* get back to normal client input. */
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if (client->io != NULL)
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen io_remove(&client->io);
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen client_input, client);
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen }
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen break;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen case SASL_SERVER_REPLY_MASTER_FAILED:
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen if (data == NULL)
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen client_destroy_internal_failure(client);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen else {
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen client_send_tagline(client,
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen t_strconcat("NO ", data, NULL));
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen client_destroy(client, data);
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen }
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen break;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen case SASL_SERVER_REPLY_CONTINUE:
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen data_len = strlen(data);
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen iov[0].iov_base = "+ ";
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen iov[0].iov_len = 2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen iov[1].iov_base = data;
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen iov[1].iov_len = data_len;
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen iov[2].iov_base = "\r\n";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen iov[2].iov_len = 2;
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen /* don't check return value here. it gets tricky if we try
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen to call client_destroy() in here. */
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen (void)o_stream_sendv(client->output, iov, 3);
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(client->io == NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen client_auth_input, client);
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen client_auth_input(client);
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen return;
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen }
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_unref(client);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint cmd_authenticate(struct imap_client *client, const struct imap_arg *args)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *mech_name, *init_resp = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we want only one argument: authentication mechanism name */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (args[1].type != IMAP_ARG_EOL) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* optional SASL initial response */
ec77cd41241208345efd51c1fcce9030be30aa9bTimo Sirainen if (args[1].type != IMAP_ARG_ATOM ||
ec77cd41241208345efd51c1fcce9030be30aa9bTimo Sirainen args[2].type != IMAP_ARG_EOL)
ec77cd41241208345efd51c1fcce9030be30aa9bTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen init_resp = IMAP_ARG_STR(&args[1]);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mech_name = IMAP_ARG_STR(&args[0]);
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen if (*mech_name == '\0')
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
7c95b03620a03a43dd72d39608cea5fc77393ad6Timo Sirainen
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen client_ref(client);
9404a7b90dcb80d31bd37ee2493f03751acdb1bdTimo Sirainen sasl_server_auth_begin(&client->common, IMAP_SERVICE_NAME, mech_name,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen init_resp, sasl_callback);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen if (!client->common.authenticating)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen return 1;
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen
2674b4f0cf8f3c203d8e56b29735f5e267038dafTimo Sirainen /* don't handle input until we get the initial auth reply */
48270badadd82279bfe50ae3d187aea8b0b2b30eTimo Sirainen if (client->io != NULL)
48270badadd82279bfe50ae3d187aea8b0b2b30eTimo Sirainen io_remove(&client->io);
48270badadd82279bfe50ae3d187aea8b0b2b30eTimo Sirainen return 0;
48270badadd82279bfe50ae3d187aea8b0b2b30eTimo Sirainen}
48270badadd82279bfe50ae3d187aea8b0b2b30eTimo Sirainen
48270badadd82279bfe50ae3d187aea8b0b2b30eTimo Sirainenint cmd_login(struct imap_client *client, const struct imap_arg *args)
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen{
48136ae5a0eb49daa44e343553f3688a500307e2Timo Sirainen const char *user, *pass;
48136ae5a0eb49daa44e343553f3688a500307e2Timo Sirainen string_t *plain_login, *base64;
2674b4f0cf8f3c203d8e56b29735f5e267038dafTimo Sirainen
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen /* two arguments: username and password */
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (args[1].type != IMAP_ARG_ATOM && args[1].type != IMAP_ARG_STRING)
97735b96d442568f65efa20f8c292a496498c17bTimo Sirainen return -1;
97735b96d442568f65efa20f8c292a496498c17bTimo Sirainen if (args[2].type != IMAP_ARG_EOL)
97735b96d442568f65efa20f8c292a496498c17bTimo Sirainen return -1;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen user = IMAP_ARG_STR(&args[0]);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen pass = IMAP_ARG_STR(&args[1]);
d6a1fa1d65c6d1996937802c2482c0f14dd821a7Timo Sirainen
d6a1fa1d65c6d1996937802c2482c0f14dd821a7Timo Sirainen if (!client->common.secured && disable_plaintext_auth) {
d6a1fa1d65c6d1996937802c2482c0f14dd821a7Timo Sirainen if (verbose_auth) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_syslog(&client->common, "Login failed: "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Plaintext authentication disabled");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen client->common.auth_tried_disabled_plaintext = TRUE;
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen client_send_line(client,
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen "* BAD [ALERT] Plaintext authentication is disabled, "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "but your client sent password in plaintext anyway. "
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen "If anyone was listening, the password was exposed.");
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen client_send_tagline(client, "NO "AUTH_PLAINTEXT_DISABLED_MSG);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
db5164c9a1129af0cfb11fc18d88da361a8011fbTimo Sirainen }
db5164c9a1129af0cfb11fc18d88da361a8011fbTimo Sirainen
db5164c9a1129af0cfb11fc18d88da361a8011fbTimo Sirainen /* authorization ID \0 authentication ID \0 pass */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen plain_login = buffer_create_dynamic(pool_datastack_create(), 64);
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen buffer_append_c(plain_login, '\0');
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen buffer_append(plain_login, user, strlen(user));
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen buffer_append_c(plain_login, '\0');
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen buffer_append(plain_login, pass, strlen(pass));
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen base64 = buffer_create_dynamic(pool_datastack_create(),
d152ccd0d29fae1bc6092bf198ee7eb843202f96Timo Sirainen MAX_BASE64_ENCODED_SIZE(plain_login->used));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen base64_encode(plain_login->data, plain_login->used, base64);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_ref(client);
aa0647f2debf0d48d504a321186f66c85596aaf4Timo Sirainen sasl_server_auth_begin(&client->common, IMAP_SERVICE_NAME, "PLAIN",
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen str_c(base64), sasl_callback);
8f8315e4b4e27ead12dd1c3da65bf4dee3762f18Timo Sirainen if (!client->common.authenticating)
8f8315e4b4e27ead12dd1c3da65bf4dee3762f18Timo Sirainen return 1;
8f8315e4b4e27ead12dd1c3da65bf4dee3762f18Timo Sirainen
8f8315e4b4e27ead12dd1c3da65bf4dee3762f18Timo Sirainen /* don't read any input from client until login is finished */
8f8315e4b4e27ead12dd1c3da65bf4dee3762f18Timo Sirainen if (client->io != NULL)
8f8315e4b4e27ead12dd1c3da65bf4dee3762f18Timo Sirainen io_remove(&client->io);
8f8315e4b4e27ead12dd1c3da65bf4dee3762f18Timo Sirainen
8f8315e4b4e27ead12dd1c3da65bf4dee3762f18Timo Sirainen return 0;
8f8315e4b4e27ead12dd1c3da65bf4dee3762f18Timo Sirainen}
8f8315e4b4e27ead12dd1c3da65bf4dee3762f18Timo Sirainen