c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat/* Disconnect client when it sends too many bad commands */
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic bool cmd_stls(struct pop3_client *client)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic bool cmd_quit(struct pop3_client *client)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(&client->common, POP3_CMD_REPLY_OK, "Logging out");
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_destroy(&client->common, "Aborted login");
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic bool cmd_xclient(struct pop3_client *client, const char *args)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(&client->common, POP3_CMD_REPLY_OK,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat "You are not from trusted IP - ignoring");
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat for (tmp = t_strsplit(args, " "); *tmp != NULL; tmp++) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (net_addr2ip(*tmp + 5, &client->common.ip) < 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat } else if (strncasecmp(*tmp, "PORT=", 5) == 0) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (net_str2port(*tmp + 5, &remote_port) < 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat } else if (strncasecmp(*tmp, "SESSION=", 8) == 0) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (strlen(value) <= LOGIN_MAX_SESSION_ID_LEN) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat } else if (strncasecmp(*tmp, "TTL=", 4) == 0) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (str_to_uint(*tmp + 4, &client->common.proxy_ttl) < 0)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat } else if (strncasecmp(*tmp, "FORWARD=", 8) == 0) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (base64_decode((*tmp)+8, value_len, NULL,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(&client->common, POP3_CMD_REPLY_ERROR,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat "Invalid parameters");
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat /* args ok, set them and reset the state */
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(&client->common, POP3_CMD_REPLY_OK, "Updated");
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic bool client_command_execute(struct pop3_client *client, const char *cmd,
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat /* Compatibility with Zimbra's patched nginx */
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat return cmd_xclient(client, t_strconcat("ADDR=", args, NULL));
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat client_send_reply(&client->common, POP3_CMD_REPLY_ERROR,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat "Unknown command.");
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic void pop3_client_input(struct client *client)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat /* if a command starts an authentication, stop processing further
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat commands until the authentication is finished. */
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat while (!client->output->closed && !client->authenticating &&
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat if (auth_client != NULL && !auth_client_is_connected(auth_client))
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic bool pop3_client_input_next_cmd(struct client *client)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat struct pop3_client *pop3_client = (struct pop3_client *)client;
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if ((line = i_stream_next_line(client->input)) == NULL)
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat if (client_command_execute(pop3_client, line,
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat else if (++client->bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat client_send_reply(client, POP3_CMD_REPLY_ERROR,
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat "Too many invalid bad commands.");
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat "Disconnected: Too many bad commands");
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozatstatic struct client *pop3_client_alloc(pool_t pool)
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat pop3_client = p_new(pool, struct pop3_client, 1);
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozatstatic void pop3_client_create(struct client *client ATTR_UNUSED,
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozatstatic void pop3_client_destroy(struct client *client)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat struct pop3_client *pop3_client = (struct pop3_client *)client;
44ee8a102e3d8052631fbb119f58a55ce678d039Frederic Crozat i_free_and_null(pop3_client->apop_challenge);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic char *get_apop_challenge(struct pop3_client *client)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat unsigned char buffer_base64[MAX_BASE64_ENCODED_SIZE(sizeof(buffer)) + 1];
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (auth_client_find_mech(auth_client, "APOP") == NULL) {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat /* disabled, no need to present the challenge */
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat auth_client_get_connect_id(auth_client, &client->apop_server_pid,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat buffer_create_from_data(&buf, buffer_base64, sizeof(buffer_base64));
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat base64_encode(buffer, sizeof(buffer), &buf);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat (unsigned long)ioloop_time,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic void pop3_client_notify_auth_ready(struct client *client)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat struct pop3_client *pop3_client = (struct pop3_client *)client;
add1d11833394aaa3a3497c2fdf548e5b14c80d4Serge Hallyn client->io = io_add_istream(client->input, client_input, client);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat /* Dovecot extension to avoid extra roundtrip for CAPA */
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat str_append(str, client->set->login_greeting);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat pop3_client->apop_challenge = get_apop_challenge(pop3_client);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat str_printfa(str, " %s", pop3_client->apop_challenge);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(client, POP3_CMD_REPLY_OK, str_c(str));
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatpop3_client_notify_starttls(struct client *client,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(client, POP3_CMD_REPLY_OK, text);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(client, POP3_CMD_REPLY_ERROR, text);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic void pop3_client_starttls(struct client *client ATTR_UNUSED)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatvoid client_send_reply(struct client *client, enum pop3_cmd_reply reply,
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_raw_data(client, str_data(line), str_len(line));
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatpop3_client_notify_disconnect(struct client *client,
80a881b232b8955b85b360d4def99e6e680ff61bSerge Hallyn const char *text)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat if (reason == CLIENT_DISCONNECT_INTERNAL_ERROR)
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(client, POP3_CMD_REPLY_TEMPFAIL, text);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat client_send_reply(client, POP3_CMD_REPLY_ERROR, text);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat /* do nothing. pop3 connections typically die pretty quick anyway. */
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozat /* override the default login_die() */
add1d11833394aaa3a3497c2fdf548e5b14c80d4Serge Hallyn master_service_set_die_callback(master_service, pop3_login_die);
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic struct client_vfuncs pop3_client_vfuncs = {
c840b37de865195a8742e219b4374d961a21d4d9Frederic Crozatstatic const struct login_binary pop3_login_binary = {