client-authenticate.c revision f30577ff7cf29858f1878abe963b4f40a436434f
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (C) 2002-2004 Timo Sirainen */
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "common.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "base64.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "buffer.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "hex-binary.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "ioloop.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "istream.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "ostream.h"
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen#include "safe-memset.h"
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen#include "str.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "str-sanitize.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "auth-client.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "../pop3/capability.h"
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen#include "ssl-proxy.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "client.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "client-authenticate.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "pop3-proxy.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include <stdlib.h>
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainenint cmd_capa(struct pop3_client *client, const char *args __attr_unused__)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen{
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen const struct auth_mech_desc *mech;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen unsigned int i, count;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen string_t *str;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen str = t_str_new(128);
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen str_append(str, "SASL");
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen mech = auth_client_get_available_mechs(auth_client, &count);
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen for (i = 0; i < count; i++) {
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen /* a) transport is secured
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen b) auth mechanism isn't plaintext
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen c) we allow insecure authentication
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen */
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen (client->common.secured || disable_plaintext_auth ||
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen (mech[i].flags & MECH_SEC_PLAINTEXT) == 0)) {
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen str_append_c(str, ' ');
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen str_append(str, mech[i].name);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen client_send_line(client,
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen t_strconcat("+OK\r\n" POP3_CAPABILITY_REPLY,
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen (ssl_initialized && !client->common.tls) ?
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen "STLS\r\n" : "",
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen str_c(str), "\r\n.", NULL));
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen return TRUE;
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen}
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainenstatic void client_auth_input(void *context)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen{
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen struct pop3_client *client = context;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen char *line;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (!client_read(client))
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen return;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen /* @UNSAFE */
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen line = i_stream_next_line(client->input);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (line == NULL)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen return;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (strcmp(line, "*") == 0) {
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen sasl_server_auth_cancel(&client->common,
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen "Authentication aborted");
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen return;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (client->common.auth_request == NULL) {
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen sasl_server_auth_cancel(&client->common,
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen "Don't send unrequested data");
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen } else {
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen auth_client_request_continue(client->common.auth_request, line);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen /* clear sensitive data */
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen safe_memset(line, 0, strlen(line));
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen}
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainenstatic int client_handle_args(struct pop3_client *client,
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen const char *const *args, int nologin)
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen{
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL;
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen string_t *reply;
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen unsigned int port = 110;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen int proxy = FALSE;
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen for (; *args != NULL; args++) {
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen if (strcmp(*args, "nologin") == 0)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen nologin = TRUE;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen else if (strcmp(*args, "proxy") == 0)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen proxy = TRUE;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen else if (strncmp(*args, "reason=", 7) == 0)
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen reason = *args + 7;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen else if (strncmp(*args, "host=", 5) == 0)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen host = *args + 5;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen else if (strncmp(*args, "port=", 5) == 0)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen port = atoi(*args + 5);
74f810327aca91b3375d3fc963bce8076785b1cbTimo Sirainen else if (strncmp(*args, "destuser=", 9) == 0)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen destuser = *args + 9;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen else if (strncmp(*args, "pass=", 5) == 0)
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen pass = *args + 5;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (destuser == NULL)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen destuser = client->common.virtual_user;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (proxy) {
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen /* we want to proxy the connection to another server.
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen proxy host=.. [port=..] [destuser=..] pass=.. */
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (pop3_proxy_new(client, host, port, destuser, pass) < 0)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen client_destroy_internal_failure(client);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen return TRUE;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (!nologin)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen return FALSE;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen reply = t_str_new(128);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen str_append(reply, "-ERR ");
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (reason != NULL)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen str_append(reply, reason);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen else
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen str_append(reply, AUTH_FAILED_MSG);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen client_send_line(client, str_c(reply));
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen /* get back to normal client input. */
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (client->io != NULL)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen io_remove(client->io);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen client_input, client);
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen return TRUE;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen}
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainenstatic void sasl_callback(struct client *_client, enum sasl_server_reply reply,
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen const char *data, const char *const *args)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen{
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct pop3_client *client = (struct pop3_client *)_client;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct const_iovec iov[3];
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen size_t data_len;
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen ssize_t ret;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen switch (reply) {
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen case SASL_SERVER_REPLY_SUCCESS:
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (args != NULL) {
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (client_handle_args(client, args, FALSE))
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen break;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen }
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen client_send_line(client, "+OK Logged in.");
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen client_destroy(client, t_strconcat(
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen "Login: ", client->common.virtual_user, NULL));
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen break;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen case SASL_SERVER_REPLY_AUTH_FAILED:
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (args != NULL) {
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (client_handle_args(client, args, TRUE))
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen break;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen client_send_line(client, "-ERR "AUTH_FAILED_MSG);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen /* get back to normal client input. */
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (client->io != NULL)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen io_remove(client->io);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen client_input, client);
74f810327aca91b3375d3fc963bce8076785b1cbTimo Sirainen break;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen case SASL_SERVER_REPLY_MASTER_FAILED:
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen client_destroy_internal_failure(client);
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen break;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen case SASL_SERVER_REPLY_CONTINUE:
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen data_len = strlen(data);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen iov[0].iov_base = "+ ";
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen iov[0].iov_len = 2;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen iov[1].iov_base = data;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen iov[1].iov_len = data_len;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen iov[2].iov_base = "\r\n";
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen iov[2].iov_len = 2;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen ret = o_stream_sendv(client->output, iov, 3);
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen if (ret < 0)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen client_destroy(client, "Disconnected");
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen else if ((size_t)ret != 2 + data_len + 2)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen client_destroy(client, "Transmit buffer full");
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen else {
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen /* continue */
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen return;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen }
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen break;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen }
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen client_unref(client);
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen}
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenint cmd_auth(struct pop3_client *client, const char *args)
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen{
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen const struct auth_mech_desc *mech;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen const char *mech_name, *p;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (*args == '\0') {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen /* Old-style SASL discovery, used by MS Outlook */
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen int i, count;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen client_send_line(client, "+OK");
mech = auth_client_get_available_mechs(auth_client, &count);
for (i = 0; i < count; i++) {
if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
(client->common.secured || disable_plaintext_auth ||
(mech[i].flags & MECH_SEC_PLAINTEXT) == 0))
client_send_line(client, mech[i].name);
}
client_send_line(client, ".");
return TRUE;
}
/* <mechanism name> <initial response> */
p = strchr(args, ' ');
if (p == NULL) {
mech_name = args;
args = "";
} else {
mech_name = t_strdup_until(args, p);
args = p+1;
}
client_ref(client);
sasl_server_auth_begin(&client->common, "POP3", mech_name,
args, sasl_callback);
if (!client->common.authenticating)
return TRUE;
/* following input data will go to authentication */
if (client->io != NULL)
io_remove(client->io);
client->io = io_add(client->common.fd, IO_READ,
client_auth_input, client);
return TRUE;
}
int cmd_user(struct pop3_client *client, const char *args)
{
if (!client->common.secured && disable_plaintext_auth) {
if (verbose_auth) {
client_syslog(&client->common, "Login failed: "
"Plaintext authentication disabled");
}
client_send_line(client,
"-ERR Plaintext authentication disabled.");
return TRUE;
}
i_free(client->last_user);
client->last_user = i_strdup(args);
client_send_line(client, "+OK");
return TRUE;
}
int cmd_pass(struct pop3_client *client, const char *args)
{
string_t *plain_login, *base64;
if (client->last_user == NULL) {
client_send_line(client, "-ERR No username given.");
return TRUE;
}
/* authorization ID \0 authentication ID \0 pass */
plain_login = t_str_new(128);
str_append_c(plain_login, '\0');
str_append(plain_login, client->last_user);
str_append_c(plain_login, '\0');
str_append(plain_login, args);
base64 = buffer_create_dynamic(pool_datastack_create(),
MAX_BASE64_ENCODED_SIZE(plain_login->used));
base64_encode(plain_login->data, plain_login->used, base64);
client_ref(client);
sasl_server_auth_begin(&client->common, "POP3", "PLAIN",
str_c(base64), sasl_callback);
if (!client->common.authenticating)
return TRUE;
/* don't read any input from client until login is finished */
if (client->io != NULL) {
io_remove(client->io);
client->io = NULL;
}
return TRUE;
}
int cmd_apop(struct pop3_client *client, const char *args)
{
buffer_t *apop_data, *base64;
const char *p;
if (client->apop_challenge == NULL) {
if (verbose_auth) {
client_syslog(&client->common,
"APOP failed: APOP not enabled");
}
client_send_line(client, "-ERR APOP not enabled.");
return TRUE;
}
/* <username> <md5 sum in hex> */
p = strchr(args, ' ');
if (p == NULL || strlen(p+1) != 32) {
if (verbose_auth) {
client_syslog(&client->common,
"APOP failed: Invalid parameters");
}
client_send_line(client, "-ERR Invalid parameters.");
return TRUE;
}
/* APOP challenge \0 username \0 APOP response */
apop_data = buffer_create_dynamic(pool_datastack_create(), 128);
buffer_append(apop_data, client->apop_challenge,
strlen(client->apop_challenge)+1);
buffer_append(apop_data, args, (size_t)(p-args));
buffer_append_c(apop_data, '\0');
if (hex_to_binary(p+1, apop_data) < 0) {
if (verbose_auth) {
client_syslog(&client->common, "APOP failed: "
"Invalid characters in MD5 response");
}
client_send_line(client,
"-ERR Invalid characters in MD5 response.");
return TRUE;
}
base64 = buffer_create_dynamic(pool_datastack_create(),
MAX_BASE64_ENCODED_SIZE(apop_data->used));
base64_encode(apop_data->data, apop_data->used, base64);
client_ref(client);
sasl_server_auth_begin(&client->common, "POP3", "APOP",
str_c(base64), sasl_callback);
if (!client->common.authenticating)
return TRUE;
/* don't read any input from client until login is finished */
if (client->io != NULL) {
io_remove(client->io);
client->io = NULL;
}
return TRUE;
}