client-authenticate.c revision 62ba819bc24e7eb197684998ccd4aa1ddd130aad
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "common.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "base64.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "buffer.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "ioloop.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "istream.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "ostream.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "safe-memset.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "str.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "str-sanitize.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "imap-parser.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "auth-client.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "client.h"
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include "client-authenticate.h"
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include "imap-proxy.h"
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include <stdlib.h>
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#define IMAP_SERVICE_NAME "imap"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenconst char *client_authenticate_get_capabilities(bool secured)
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen{
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen const struct auth_mech_desc *mech;
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen unsigned int i, count;
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen string_t *str;
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen str = t_str_new(128);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen mech = auth_client_get_available_mechs(auth_client, &count);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen for (i = 0; i < count; i++) {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen /* a) transport is secured
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen b) auth mechanism isn't plaintext
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen c) we allow insecure authentication
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen (secured || !disable_plaintext_auth ||
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen (mech[i].flags & MECH_SEC_PLAINTEXT) == 0)) {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen str_append_c(str, ' ');
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen str_append(str, "AUTH=");
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen str_append(str, mech[i].name);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen }
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen }
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return str_c(str);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen}
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic void client_auth_input(struct imap_client *client)
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen{
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen char *line;
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen if (!client_read(client))
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen return;
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen
59e26ff34b05cd971a111f8a42fc60c13d9f688bTimo Sirainen if (client->skip_line) {
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen if (i_stream_next_line(client->input) == NULL)
2d2ebe91d56e9a158de000c9d0026f65600fbcfaTimo Sirainen return;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
f988b93c2ef773987bcdcbfb4cca39b955e3a392Timo Sirainen client->skip_line = FALSE;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen }
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen /* @UNSAFE */
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen line = i_stream_next_line(client->input);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen if (line == NULL)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen return;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen if (strcmp(line, "*") == 0) {
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen sasl_server_auth_client_error(&client->common,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen "Authentication aborted");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (client->common.waiting_auth_reply) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen sasl_server_auth_client_error(&client->common,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen "Don't send unrequested data");
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen } else {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen auth_client_request_continue(client->common.auth_request, line);
571fd6ff94570ee11a72a20b649acfdac2495919Timo Sirainen client->common.waiting_auth_reply = TRUE;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen /* clear sensitive data */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen safe_memset(line, 0, strlen(line));
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainenstatic bool client_handle_args(struct imap_client *client,
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen const char *const *args, bool nologin)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen string_t *reply;
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen unsigned int port = 143;
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen bool proxy = FALSE, temp = FALSE;
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen for (; *args != NULL; args++) {
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen if (strcmp(*args, "nologin") == 0)
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen nologin = TRUE;
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen else if (strcmp(*args, "proxy") == 0)
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen proxy = TRUE;
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen else if (strcmp(*args, "temp") == 0)
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen temp = TRUE;
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen else if (strncmp(*args, "reason=", 7) == 0)
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen reason = *args + 7;
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen else if (strncmp(*args, "host=", 5) == 0)
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen host = *args + 5;
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen else if (strncmp(*args, "port=", 5) == 0)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen port = atoi(*args + 5);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen else if (strncmp(*args, "destuser=", 9) == 0)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen destuser = *args + 9;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen else if (strncmp(*args, "pass=", 5) == 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen pass = *args + 5;
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen if (destuser == NULL)
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen destuser = client->common.virtual_user;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (proxy) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* we want to proxy the connection to another server.
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen proxy host=.. [port=..] [destuser=..] pass=.. */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (imap_proxy_new(client, host, port, destuser, pass) < 0)
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen client_destroy_internal_failure(client);
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen return TRUE;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen }
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if (host != NULL) {
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen /* IMAP referral
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen [nologin] referral host=.. [port=..] [destuser=..]
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen [reason=..]
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen NO [REFERRAL imap://destuser;AUTH=..@host:port/] Can't login.
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen OK [...] Logged in, but you should use this server instead.
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen .. [REFERRAL ..] (Reason from auth server)
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen */
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen reply = t_str_new(128);
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen str_append(reply, nologin ? "NO " : "OK ");
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen str_printfa(reply, "[REFERRAL imap://%s;AUTH=%s@%s",
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen destuser, client->common.auth_mech_name, host);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (port != 143)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen str_printfa(reply, ":%u", port);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen str_append(reply, "/] ");
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen if (reason != NULL)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen str_append(reply, reason);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen else if (nologin)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen str_append(reply, "Try this server instead.");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen else {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen str_append(reply, "Logged in, but you should use "
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen "this server instead.");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen client_send_tagline(client, str_c(reply));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (!nologin) {
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen client_destroy(client, "Login with referral");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen } else if (nologin) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* Authentication went ok, but for some reason user isn't
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen allowed to log in. Shouldn't probably happen. */
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen reply = t_str_new(128);
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen if (reason != NULL)
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen str_printfa(reply, "NO %s", reason);
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen else if (temp)
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen str_append(reply, "NO "AUTH_TEMP_FAILED_MSG);
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen else
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen str_append(reply, "NO "AUTH_FAILED_MSG);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen client_send_tagline(client, str_c(reply));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen /* normal login/failure */
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen return FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen i_assert(nologin);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen if (!client->destroyed) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* get back to normal client input. */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (client->io != NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen io_remove(&client->io);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen client_input, client);
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainenstatic void sasl_callback(struct client *_client, enum sasl_server_reply reply,
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen const char *data, const char *const *args)
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen{
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen struct imap_client *client = (struct imap_client *)_client;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen struct const_iovec iov[3];
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen const char *msg;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen size_t data_len;
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen i_assert(!client->destroyed ||
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen reply == SASL_SERVER_REPLY_CLIENT_ERROR ||
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen reply == SASL_SERVER_REPLY_MASTER_FAILED);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen switch (reply) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen case SASL_SERVER_REPLY_SUCCESS:
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (args != NULL) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (client_handle_args(client, args, FALSE))
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen break;
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen }
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen client_send_tagline(client, "OK Logged in.");
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen client_destroy(client, "Login");
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen break;
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen case SASL_SERVER_REPLY_AUTH_FAILED:
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen case SASL_SERVER_REPLY_CLIENT_ERROR:
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (args != NULL) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (client_handle_args(client, args, TRUE))
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen break;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen msg = reply == SASL_SERVER_REPLY_AUTH_FAILED ? "NO " : "BAD ";
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg = t_strconcat(msg, data != NULL ? data : AUTH_FAILED_MSG,
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen client_send_tagline(client, msg);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (!client->destroyed) {
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen /* get back to normal client input. */
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen if (client->io != NULL)
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen io_remove(&client->io);
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen client_input, client);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainen break;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen case SASL_SERVER_REPLY_MASTER_FAILED:
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client_destroy_internal_failure(client);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen break;
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch case SASL_SERVER_REPLY_CONTINUE:
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen data_len = strlen(data);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen iov[0].iov_base = "+ ";
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen iov[0].iov_len = 2;
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen iov[1].iov_base = data;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen iov[1].iov_len = data_len;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen iov[2].iov_base = "\r\n";
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen iov[2].iov_len = 2;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen /* don't check return value here. it gets tricky if we try
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen to call client_destroy() in here. */
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen (void)o_stream_sendv(client->output, iov, 3);
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen return;
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen }
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen client_unref(client);
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainenint cmd_authenticate(struct imap_client *client, struct imap_arg *args)
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen{
0dbcf4026ff8471b4d6d2e14f7e52321396bf087Timo Sirainen const char *mech_name, *init_resp = NULL;
0dbcf4026ff8471b4d6d2e14f7e52321396bf087Timo Sirainen
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen /* we want only one argument: authentication mechanism name */
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen return -1;
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen if (args[1].type != IMAP_ARG_EOL) {
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen /* optional SASL initial response */
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen if (args[1].type != IMAP_ARG_ATOM ||
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen args[2].type != IMAP_ARG_EOL)
8b2cf1c1bd8ddcea0525b62fd35ba76e136828a1Timo Sirainen return -1;
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen init_resp = IMAP_ARG_STR(&args[1]);
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen }
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen mech_name = IMAP_ARG_STR(&args[0]);
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen if (*mech_name == '\0')
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen client_ref(client);
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen sasl_server_auth_begin(&client->common, IMAP_SERVICE_NAME, mech_name,
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen init_resp, sasl_callback);
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (!client->common.authenticating)
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen return 1;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen /* following input data will go to authentication */
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (client->io != NULL)
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen io_remove(&client->io);
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen client_auth_input, client);
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen return 0;
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainen}
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainenint cmd_login(struct imap_client *client, struct imap_arg *args)
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen{
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen const char *user, *pass;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen string_t *plain_login, *base64;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen /* two arguments: username and password */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch return -1;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (args[1].type != IMAP_ARG_ATOM && args[1].type != IMAP_ARG_STRING)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return -1;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (args[2].type != IMAP_ARG_EOL)
4e8d6d03c2ff85448df79b181a2ea850fb5d4199Timo Sirainen return -1;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen user = IMAP_ARG_STR(&args[0]);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen pass = IMAP_ARG_STR(&args[1]);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (!client->common.secured && disable_plaintext_auth) {
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (verbose_auth) {
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen client_syslog(&client->common, "Login failed: "
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen "Plaintext authentication disabled");
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen client_send_line(client,
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen "* BAD [ALERT] Plaintext authentication is disabled, "
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen "but your client sent password in plaintext anyway. "
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen "If anyone was listening, the password was exposed.");
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen client_send_tagline(client, "NO "AUTH_PLAINTEXT_DISABLED_MSG);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return 1;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen /* authorization ID \0 authentication ID \0 pass */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen plain_login = buffer_create_dynamic(pool_datastack_create(), 64);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen buffer_append_c(plain_login, '\0');
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen buffer_append(plain_login, user, strlen(user));
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen buffer_append_c(plain_login, '\0');
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen buffer_append(plain_login, pass, strlen(pass));
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen base64 = buffer_create_dynamic(pool_datastack_create(),
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen MAX_BASE64_ENCODED_SIZE(plain_login->used));
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen base64_encode(plain_login->data, plain_login->used, base64);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen client_ref(client);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen sasl_server_auth_begin(&client->common, IMAP_SERVICE_NAME, "PLAIN",
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen str_c(base64), sasl_callback);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (!client->common.authenticating)
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen return 1;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen /* don't read any input from client until login is finished */
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (client->io != NULL)
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen io_remove(&client->io);
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen return 0;
f988b93c2ef773987bcdcbfb4cca39b955e3a392Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen