imap-login-client.c revision 2f7c73483ff5474a74a83a646f82e1b60f687680
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "login-common.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "buffer.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "ioloop.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "istream.h"
00d58fcfe8191d6ce7efa801d289a5c0fe88d1aeTimo Sirainen#include "ostream.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "safe-memset.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "str.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "strescape.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "imap-parser.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "imap-id.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "imap-resp-code.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "master-service.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "master-service-ssl-settings.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "master-auth.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "imap-login-client.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "client-authenticate.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "auth-client.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "ssl-proxy.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "imap-proxy.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "imap-quote.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "imap-login-commands.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "imap-login-settings.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#if LOGIN_MAX_INBUF_SIZE < 1024+2
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen# error LOGIN_MAX_INBUF_SIZE too short to fit all ID command parameters
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#endif
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen/* maximum length for IMAP command line. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#define MAX_IMAP_LINE 8192
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen/* Disconnect client when it sends too many bad commands */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define CLIENT_MAX_BAD_COMMANDS 3
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic const char *const imap_login_reserved_id_keys[] = {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "x-originating-ip",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "x-originating-port",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "x-connected-ip",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "x-connected-port",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "x-proxy-ttl",
f6c1297c26b355c4aec2a08978f51ec3efecb351Timo Sirainen "x-session-id",
f6c1297c26b355c4aec2a08978f51ec3efecb351Timo Sirainen "x-session-ext-id",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen NULL
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen};
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen/* Skip incoming data until newline is found,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen returns TRUE if newline was found. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenbool client_skip_line(struct imap_client *client)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen{
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen const unsigned char *data;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen size_t i, data_size;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen data = i_stream_get_data(client->common.input, &data_size);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen for (i = 0; i < data_size; i++) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (data[i] == '\n') {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen i_stream_skip(client->common.input, i+1);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return TRUE;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return FALSE;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen}
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstatic bool client_handle_parser_error(struct imap_client *client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen struct imap_parser *parser)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen{
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen const char *msg;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen enum imap_parser_error parse_error;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen msg = imap_parser_get_error(parser, &parse_error);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen switch (parse_error) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen case IMAP_PARSE_ERROR_NONE:
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen i_unreached();
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen case IMAP_PARSE_ERROR_LITERAL_TOO_BIG:
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_send_reply(&client->common,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen IMAP_CMD_REPLY_BYE, msg);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen client_destroy(&client->common,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen t_strconcat("Disconnected: ", msg, NULL));
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return FALSE;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen default:
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen break;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen client_send_reply(&client->common, IMAP_CMD_REPLY_BAD, msg);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen client->cmd_finished = TRUE;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client->skip_line = TRUE;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return TRUE;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen}
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
b04e691711fd026fc82ba3e0b411420e7da4ec7eTimo Sirainenstatic bool is_login_cmd_disabled(struct client *client)
4d2211dac61c615c5bdfd501ea54d46c89d41b0fTimo Sirainen{
4d2211dac61c615c5bdfd501ea54d46c89d41b0fTimo Sirainen if (client->secured) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (auth_client_find_mech(auth_client, "PLAIN") == NULL) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* no PLAIN authentication, can't use LOGIN command */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return TRUE;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return FALSE;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (client->set->disable_plaintext_auth)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return TRUE;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (strcmp(client->ssl_set->ssl, "required") == 0)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return TRUE;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen return FALSE;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen}
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic const char *get_capability(struct client *client)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen{
4d2211dac61c615c5bdfd501ea54d46c89d41b0fTimo Sirainen struct imap_client *imap_client = (struct imap_client *)client;
63f36c2b47217fc2dc4ed49cfc1907311d5ed366Timo Sirainen string_t *cap_str = t_str_new(256);
b04e691711fd026fc82ba3e0b411420e7da4ec7eTimo Sirainen bool explicit_capability = FALSE;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (*imap_client->set->imap_capability == '\0')
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_append(cap_str, CAPABILITY_BANNER_STRING);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen else if (*imap_client->set->imap_capability != '+') {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen explicit_capability = TRUE;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen str_append(cap_str, imap_client->set->imap_capability);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen } else {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen str_append(cap_str, CAPABILITY_BANNER_STRING);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen str_append_c(cap_str, ' ');
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen str_append(cap_str, imap_client->set->imap_capability + 1);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (!explicit_capability) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (imap_client->set->imap_literal_minus)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen str_append(cap_str, " LITERAL-");
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen else
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen str_append(cap_str, " LITERAL+");
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (client_is_tls_enabled(client) && !client->tls)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_append(cap_str, " STARTTLS");
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (is_login_cmd_disabled(client))
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_append(cap_str, " LOGINDISABLED");
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen client_authenticate_get_capabilities(client, cap_str);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return str_c(cap_str);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstatic int cmd_capability(struct imap_client *imap_client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen const struct imap_arg *args ATTR_UNUSED)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen{
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen struct client *client = &imap_client->common;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* Client is required to send CAPABILITY after STARTTLS, so the
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen capability resp-code workaround checks only pre-STARTTLS
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen CAPABILITY commands. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (!client->starttls)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen imap_client->client_ignores_capability_resp_code = TRUE;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_send_raw(client, t_strconcat(
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "* CAPABILITY ", get_capability(client), "\r\n", NULL));
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen client_send_reply(client, IMAP_CMD_REPLY_OK,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "Pre-login capabilities listed, post-login capabilities have more.");
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return 1;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen}
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic int cmd_starttls(struct imap_client *client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen const struct imap_arg *args ATTR_UNUSED)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen{
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_cmd_starttls(&client->common);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return 1;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen}
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenimap_client_notify_starttls(struct client *client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen bool success, const char *text)
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen{
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (success)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_send_reply(client, IMAP_CMD_REPLY_OK, text);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen else
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_send_reply(client, IMAP_CMD_REPLY_BAD, text);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen}
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic bool
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenclient_update_info(struct imap_client *client,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen const char *key, const char *value)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen{
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* do not try to process NIL value */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (value == NULL)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return FALSE;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* SYNC WITH imap_login_reserved_id_keys */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (strcasecmp(key, "x-originating-ip") == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen (void)net_addr2ip(value, &client->common.ip);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else if (strcasecmp(key, "x-originating-port") == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen (void)net_str2port(value, &client->common.remote_port);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen } else if (strcasecmp(key, "x-connected-ip") == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen (void)net_addr2ip(value, &client->common.local_ip);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else if (strcasecmp(key, "x-connected-port") == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen (void)net_str2port(value, &client->common.local_port);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else if (strcasecmp(key, "x-proxy-ttl") == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (str_to_uint(value, &client->common.proxy_ttl) < 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* nothing */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else if (strcasecmp(key, "x-session-id") == 0 ||
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen strcasecmp(key, "x-session-ext-id") == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (strlen(value) <= LOGIN_MAX_SESSION_ID_LEN) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client->common.session_id =
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen p_strdup(client->common.pool, value);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return FALSE;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return TRUE;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen}
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic bool client_id_reserved_word(const char *key)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen{
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen i_assert(key != NULL);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return str_array_icase_find(imap_login_reserved_id_keys, key);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen}
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void cmd_id_handle_keyvalue(struct imap_client *client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen const char *key, const char *value)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen{
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen bool client_id_str;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* length of key + length of value (NIL for NULL) and two set of
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen quotes and space */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen size_t kvlen = strlen(key) + 2 + 1 +
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen (value == NULL ? 3 : strlen(value)) + 2;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (client->common.trusted && !client->id_logged) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_id_str = !client_update_info(client, key, value);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen i_assert(client_id_str == !client_id_reserved_word(key));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_id_str = !client_id_reserved_word(key);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (client_id_str &&
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen (client->common.client_id == NULL ||
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_len(client->common.client_id) + kvlen < LOGIN_MAX_CLIENT_ID_LEN)) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (client->common.client_id == NULL) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client->common.client_id = str_new(client->common.preproxy_pool, 64);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_append_c(client->common.client_id, ' ');
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen imap_append_quoted(client->common.client_id, key);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_append_c(client->common.client_id, ' ');
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (value == NULL)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen str_append(client->common.client_id, "NIL");
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen else
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen imap_append_quoted(client->common.client_id, value);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (client->cmd_id->log_reply != NULL &&
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen (client->cmd_id->log_keys == NULL ||
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_array_icase_find((void *)client->cmd_id->log_keys, key)))
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen imap_id_log_reply_append(client->cmd_id->log_reply, key, value);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen}
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic int cmd_id_handle_args(struct imap_client *client,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen const struct imap_arg *arg)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen{
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen struct imap_client_cmd_id *id = client->cmd_id;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen const char *key, *value;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen switch (id->state) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen case IMAP_CLIENT_ID_STATE_LIST:
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (arg->type == IMAP_ARG_NIL)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return 1;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (arg->type != IMAP_ARG_LIST)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return -1;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (client->set->imap_id_log[0] == '\0') {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* no ID logging */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else if (client->id_logged) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* already logged the ID reply */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen id->log_reply = str_new(default_pool, 64);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (strcmp(client->set->imap_id_log, "*") == 0) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* log all keys */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen } else {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* log only specified keys */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen id->log_keys = p_strsplit_spaces(default_pool,
00d58fcfe8191d6ce7efa801d289a5c0fe88d1aeTimo Sirainen client->set->imap_id_log, " ");
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen id->state = IMAP_CLIENT_ID_STATE_KEY;
00d58fcfe8191d6ce7efa801d289a5c0fe88d1aeTimo Sirainen break;
00d58fcfe8191d6ce7efa801d289a5c0fe88d1aeTimo Sirainen case IMAP_CLIENT_ID_STATE_KEY:
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (!imap_arg_get_string(arg, &key))
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return -1;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (i_strocpy(id->key, key, sizeof(id->key)) < 0)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return -1;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen id->state = IMAP_CLIENT_ID_STATE_VALUE;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen break;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen case IMAP_CLIENT_ID_STATE_VALUE:
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (!imap_arg_get_nstring(arg, &value))
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return -1;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen cmd_id_handle_keyvalue(client, id->key, value);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen id->state = IMAP_CLIENT_ID_STATE_KEY;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen break;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return 0;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void cmd_id_finish(struct imap_client *client)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* finished handling the parameters */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (!client->id_logged) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client->id_logged = TRUE;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (client->cmd_id->log_reply != NULL) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_log(&client->common, t_strdup_printf(
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "ID sent: %s", str_c(client->cmd_id->log_reply)));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_send_raw(&client->common,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen t_strdup_printf("* ID %s\r\n",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen imap_id_reply_generate(client->set->imap_id_send)));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_send_reply(&client->common, IMAP_CMD_REPLY_OK, "ID completed.");
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen}
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void cmd_id_free(struct imap_client *client)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen{
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen struct imap_client_cmd_id *id = client->cmd_id;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (id->log_reply != NULL)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_free(&id->log_reply);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (id->log_keys != NULL)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen p_strsplit_free(default_pool, id->log_keys);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen imap_parser_unref(&id->parser);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen i_free_and_null(client->cmd_id);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client->skip_line = TRUE;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen}
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic int cmd_id(struct imap_client *client)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen{
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen struct imap_client_cmd_id *id;
enum imap_parser_flags parser_flags;
const struct imap_arg *args;
int ret;
if (client->common.client_id != NULL)
str_truncate(client->common.client_id, 0);
if (client->cmd_id == NULL) {
client->cmd_id = id = i_new(struct imap_client_cmd_id, 1);
id->parser = imap_parser_create(client->common.input,
client->common.output,
MAX_IMAP_LINE);
if (client->set->imap_literal_minus)
imap_parser_enable_literal_minus(id->parser);
parser_flags = IMAP_PARSE_FLAG_STOP_AT_LIST;
} else {
id = client->cmd_id;
parser_flags = IMAP_PARSE_FLAG_INSIDE_LIST;
}
while ((ret = imap_parser_read_args(id->parser, 1, parser_flags, &args)) > 0) {
i_assert(ret == 1);
if ((ret = cmd_id_handle_args(client, args)) < 0) {
client_send_reply(&client->common,
IMAP_CMD_REPLY_BAD,
"Invalid ID parameters");
cmd_id_free(client);
return -1;
}
if (ret > 0) {
/* NIL parameter */
ret = 0;
break;
}
imap_parser_reset(id->parser);
parser_flags = IMAP_PARSE_FLAG_INSIDE_LIST;
}
if (ret == 0) {
/* finished the line */
cmd_id_finish(client);
cmd_id_free(client);
return 1;
} else if (ret == -1) {
if (!client_handle_parser_error(client, id->parser))
return 0;
cmd_id_free(client);
return -1;
} else {
i_assert(ret == -2);
return 0;
}
}
static int cmd_noop(struct imap_client *client,
const struct imap_arg *args ATTR_UNUSED)
{
client_send_reply(&client->common, IMAP_CMD_REPLY_OK,
"NOOP completed.");
return 1;
}
static int cmd_logout(struct imap_client *client,
const struct imap_arg *args ATTR_UNUSED)
{
client_send_reply(&client->common, IMAP_CMD_REPLY_BYE, "Logging out");
client_send_reply(&client->common, IMAP_CMD_REPLY_OK,
"Logout completed.");
client_destroy(&client->common, "Aborted login");
return 1;
}
static int cmd_enable(struct imap_client *client,
const struct imap_arg *args ATTR_UNUSED)
{
client_send_raw(&client->common, "* ENABLED\r\n");
client_send_reply(&client->common, IMAP_CMD_REPLY_OK,
"ENABLE ignored in non-authenticated state.");
return 1;
}
static int client_command_execute(struct imap_client *client, const char *cmd,
const struct imap_arg *args)
{
struct imap_login_command *login_cmd;
login_cmd = imap_login_command_lookup(cmd);
if (login_cmd == NULL)
return -2;
return login_cmd->func(client, args);
}
static bool imap_is_valid_tag(const char *tag)
{
for (; *tag != '\0'; tag++) {
switch (*tag) {
case '+':
/* atom-specials: */
case '(':
case ')':
case '{':
case '/':
case ' ':
/* list-wildcards: */
case '%':
case '*':
/* quoted-specials: */
case '"':
case '\\':
return FALSE;
default:
if (*tag < ' ') /* CTL */
return FALSE;
break;
}
}
return TRUE;
}
static int client_parse_command(struct imap_client *client,
const struct imap_arg **args_r)
{
switch (imap_parser_read_args(client->parser, 0, 0, args_r)) {
case -1:
/* error */
if (!client_handle_parser_error(client, client->parser)) {
/* client destroyed */
return 0;
}
return -1;
case -2:
/* not enough data */
return 0;
default:
/* we read the entire line - skip over the CRLF */
if (!client_skip_line(client))
i_unreached();
return 1;
}
}
static bool client_handle_input(struct imap_client *client)
{
const struct imap_arg *args;
bool parsed;
int ret;
i_assert(!client->common.authenticating);
if (client->cmd_finished) {
/* clear the previous command from memory. don't do this
immediately after handling command since we need the
cmd_tag to stay some time after authentication commands. */
client->cmd_tag = NULL;
client->cmd_name = NULL;
imap_parser_reset(client->parser);
/* remove \r\n */
if (client->skip_line) {
if (!client_skip_line(client))
return FALSE;
client->skip_line = FALSE;
}
client->cmd_finished = FALSE;
}
if (client->cmd_tag == NULL) {
client->cmd_tag = imap_parser_read_word(client->parser);
if (client->cmd_tag == NULL)
return FALSE; /* need more data */
if (!imap_is_valid_tag(client->cmd_tag) ||
strlen(client->cmd_tag) > IMAP_TAG_MAX_LEN) {
/* the tag is invalid, don't allow it and don't
send it back. this attempts to prevent any
potentially dangerous replies in case someone tries
to access us using HTTP protocol. */
client->cmd_tag = "";
}
}
if (client->cmd_name == NULL) {
client->cmd_name = imap_parser_read_word(client->parser);
if (client->cmd_name == NULL)
return FALSE; /* need more data */
}
if (strcasecmp(client->cmd_name, "AUTHENTICATE") == 0) {
/* SASL-IR may need more space than input buffer's size,
so we'll handle it as a special case. */
ret = cmd_authenticate(client, &parsed);
if (ret == 0 && !parsed)
return FALSE;
} else if (strcasecmp(client->cmd_name, "ID") == 0) {
/* ID extensions allows max. 30 parameters,
each max. 1024 bytes long. that brings us over the input
buffer's size, so handle the parameters one at a time */
ret = cmd_id(client);
if (ret == 0)
return FALSE;
if (ret < 0)
ret = 1; /* don't send the error reply again */
} else {
ret = client_parse_command(client, &args);
if (ret < 0)
return TRUE;
if (ret == 0)
return FALSE;
ret = *client->cmd_tag == '\0' ? -1 :
client_command_execute(client, client->cmd_name, args);
}
client->cmd_finished = TRUE;
if (ret == -2 && strcasecmp(client->cmd_tag, "LOGIN") == 0) {
client_send_reply(&client->common, IMAP_CMD_REPLY_BAD,
"First parameter in line is IMAP's command tag, "
"not the command name. Add that before the command, "
"like: a login user pass");
} else if (ret < 0) {
if (*client->cmd_tag == '\0')
client->cmd_tag = "*";
if (++client->common.bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
client_send_reply(&client->common, IMAP_CMD_REPLY_BYE,
"Too many invalid IMAP commands.");
client_destroy(&client->common,
"Disconnected: Too many invalid commands");
return FALSE;
}
client_send_reply(&client->common, IMAP_CMD_REPLY_BAD,
"Error in IMAP command received by server.");
}
return ret != 0 && !client->common.destroyed;
}
static void imap_client_input(struct client *client)
{
struct imap_client *imap_client = (struct imap_client *)client;
if (!client_read(client))
return;
client_ref(client);
o_stream_cork(imap_client->common.output);
for (;;) {
if (!auth_client_is_connected(auth_client)) {
/* we're not currently connected to auth process -
don't allow any commands */
client_notify_status(client, FALSE,
AUTH_SERVER_WAITING_MSG);
if (client->to_auth_waiting != NULL)
timeout_remove(&client->to_auth_waiting);
client->input_blocked = TRUE;
break;
} else {
if (!client_handle_input(imap_client))
break;
}
}
o_stream_uncork(imap_client->common.output);
client_unref(&client);
}
static struct client *imap_client_alloc(pool_t pool)
{
struct imap_client *imap_client;
imap_client = p_new(pool, struct imap_client, 1);
return &imap_client->common;
}
static void imap_client_create(struct client *client, void **other_sets)
{
struct imap_client *imap_client = (struct imap_client *)client;
imap_client->set = other_sets[0];
imap_client->parser =
imap_parser_create(imap_client->common.input,
imap_client->common.output, MAX_IMAP_LINE);
if (imap_client->set->imap_literal_minus)
imap_parser_enable_literal_minus(imap_client->parser);
client->io = io_add(client->fd, IO_READ, client_input, client);
}
static void imap_client_destroy(struct client *client)
{
struct imap_client *imap_client = (struct imap_client *)client;
i_free_and_null(imap_client->proxy_backend_capability);
imap_parser_unref(&imap_client->parser);
}
static void imap_client_notify_auth_ready(struct client *client)
{
string_t *greet;
greet = t_str_new(128);
str_append(greet, "* OK ");
str_printfa(greet, "[CAPABILITY %s] ", get_capability(client));
str_append(greet, client->set->login_greeting);
str_append(greet, "\r\n");
client_send_raw(client, str_c(greet));
}
static void imap_client_starttls(struct client *client)
{
struct imap_client *imap_client = (struct imap_client *)client;
imap_parser_unref(&imap_client->parser);
imap_client->parser =
imap_parser_create(imap_client->common.input,
imap_client->common.output, MAX_IMAP_LINE);
/* CRLF is lost from buffer when streams are reopened. */
imap_client->skip_line = FALSE;
}
static void ATTR_NULL(3)
client_send_reply_raw(struct client *client,
const char *prefix, const char *resp_code,
const char *text, bool tagged)
{
struct imap_client *imap_client = (struct imap_client *)client;
T_BEGIN {
string_t *line = t_str_new(256);
if (tagged)
str_append(line, imap_client->cmd_tag);
else
str_append_c(line, '*');
str_append_c(line, ' ');
str_append(line, prefix);
str_append_c(line, ' ');
if (resp_code != NULL)
str_printfa(line, "[%s] ", resp_code);
str_append(line, text);
str_append(line, "\r\n");
client_send_raw_data(client, str_data(line), str_len(line));
} T_END;
}
void client_send_reply_code(struct client *client, enum imap_cmd_reply reply,
const char *resp_code, const char *text)
{
const char *prefix = "NO";
bool tagged = TRUE;
switch (reply) {
case IMAP_CMD_REPLY_OK:
prefix = "OK";
break;
case IMAP_CMD_REPLY_NO:
break;
case IMAP_CMD_REPLY_BAD:
prefix = "BAD";
break;
case IMAP_CMD_REPLY_BYE:
prefix = "BYE";
tagged = FALSE;
break;
}
client_send_reply_raw(client, prefix, resp_code, text, tagged);
}
void client_send_reply(struct client *client, enum imap_cmd_reply reply,
const char *text)
{
client_send_reply_code(client, reply, NULL, text);
}
static void
imap_client_notify_status(struct client *client, bool bad, const char *text)
{
if (bad)
client_send_reply_raw(client, "BAD", "ALERT", text, FALSE);
else
client_send_reply_raw(client, "OK", NULL, text, FALSE);
}
static void
imap_client_notify_disconnect(struct client *client,
enum client_disconnect_reason reason,
const char *text)
{
if (reason == CLIENT_DISCONNECT_INTERNAL_ERROR) {
client_send_reply_code(client, IMAP_CMD_REPLY_BYE,
IMAP_RESP_CODE_UNAVAILABLE, text);
} else {
client_send_reply_code(client, IMAP_CMD_REPLY_BYE, NULL, text);
}
}
static void imap_login_preinit(void)
{
login_set_roots = imap_login_setting_roots;
}
static const struct imap_login_command imap_login_commands[] = {
{ "LOGIN", cmd_login },
{ "CAPABILITY", cmd_capability },
{ "STARTTLS", cmd_starttls },
{ "NOOP", cmd_noop },
{ "LOGOUT", cmd_logout },
{ "ENABLE", cmd_enable }
};
static void imap_login_init(void)
{
imap_login_commands_init();
imap_login_commands_register(imap_login_commands,
N_ELEMENTS(imap_login_commands));
}
static void imap_login_deinit(void)
{
clients_destroy_all();
imap_login_commands_deinit();
}
static struct client_vfuncs imap_client_vfuncs = {
imap_client_alloc,
imap_client_create,
imap_client_destroy,
imap_client_notify_auth_ready,
imap_client_notify_disconnect,
imap_client_notify_status,
imap_client_notify_starttls,
imap_client_starttls,
imap_client_input,
NULL,
NULL,
imap_client_auth_result,
imap_proxy_reset,
imap_proxy_parse_line,
imap_proxy_error,
imap_proxy_get_state,
};
static const struct login_binary imap_login_binary = {
.protocol = "imap",
.process_name = "imap-login",
.default_port = 143,
.default_ssl_port = 993,
.client_vfuncs = &imap_client_vfuncs,
.preinit = imap_login_preinit,
.init = imap_login_init,
.deinit = imap_login_deinit,
.sasl_support_final_reply = FALSE
};
int main(int argc, char *argv[])
{
return login_binary_run(&imap_login_binary, argc, argv);
}