.. [REFERRAL ..] (Reason from auth server)
*/
reply = t_str_new(128);
+ str_append(reply, client->cmd_tag);
+ str_append_c(reply, ' ');
str_append(reply, nologin ? "NO " : "OK ");
str_printfa(reply, "[REFERRAL imap://%s;AUTH=%s@%s",
destuser, client->common.auth_mech_name, host);
str_append(reply, "Logged in, but you should use "
"this server instead.");
}
- client_send_tagline(client, str_c(reply));
+ str_append(reply, "\r\n");
+ client_send_raw(client, str_c(reply));
if (!nologin) {
client_destroy_success(client, "Login with referral");
return TRUE;
} else if (nologin) {
/* Authentication went ok, but for some reason user isn't
allowed to log in. Shouldn't probably happen. */
- reply = t_str_new(128);
- if (reason != NULL)
- str_printfa(reply, "NO [ALERT] %s", reason);
- else if (temp) {
- str_append(reply, "NO ["IMAP_RESP_CODE_UNAVAILABLE"] "
- AUTH_TEMP_FAILED_MSG);
+ if (reason != NULL) {
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_REASON,
+ reason);
+ } else if (temp) {
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
+ AUTH_TEMP_FAILED_MSG);
} else if (authz_failure) {
- str_append(reply, "NO "IMAP_AUTHZ_FAILED_MSG);
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTHZ_FAILED,
+ "Authorization failed");
} else {
- str_append(reply, "NO "IMAP_AUTH_FAILED_MSG);
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAILED,
+ AUTH_FAILED_MSG);
}
- client_send_tagline(client, str_c(reply));
} else {
/* normal login/failure */
return FALSE;
{
struct imap_client *client = (struct imap_client *)_client;
struct const_iovec iov[3];
- const char *msg;
size_t data_len;
bool nodelay;
break;
}
- if (reply == SASL_SERVER_REPLY_AUTH_ABORTED)
- msg = "BAD Authentication aborted by client.";
- else if (data == NULL)
- msg = "NO "IMAP_AUTH_FAILED_MSG;
- else
- msg = t_strconcat("NO [ALERT] ", data, NULL);
- client_send_tagline(client, msg);
+ if (reply == SASL_SERVER_REPLY_AUTH_ABORTED) {
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
+ "Authentication aborted by client.");
+ } else if (data == NULL) {
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAILED,
+ AUTH_FAILED_MSG);
+ } else {
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_REASON,
+ data);
+ }
if (!client->destroyed)
client_auth_failed(client, nodelay);
if (data == NULL)
client_destroy_internal_failure(client);
else {
- client_send_tagline(client,
- t_strconcat("NO ", data, NULL));
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_TEMP, data);
/* authentication itself succeeded, we just hit some
internal failure. */
client_destroy_success(client, data);
"SSL required for authentication");
}
client->common.auth_attempts++;
- client_send_tagline(client,
- "NO ["IMAP_RESP_CODE_PRIVACYREQUIRED"] "
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL,
"Authentication not allowed until SSL/TLS is enabled.");
return 1;
}
}
client->common.auth_tried_disabled_plaintext = TRUE;
client->common.auth_attempts++;
- client_send_line(client,
+ client_send_raw(client,
"* BAD [ALERT] Plaintext authentication not allowed "
"without SSL/TLS, but your client did it anyway. "
- "If anyone was listening, the password was exposed.");
- client_send_tagline(client, "NO ["IMAP_RESP_CODE_CLIENTBUG"] "
- AUTH_PLAINTEXT_DISABLED_MSG);
+ "If anyone was listening, the password was exposed.\r\n");
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL,
+ AUTH_PLAINTEXT_DISABLED_MSG);
return 1;
}
struct imap_arg;
-#define IMAP_AUTH_FAILED_MSG \
- "["IMAP_RESP_CODE_AUTHFAILED"] "AUTH_FAILED_MSG
-#define IMAP_AUTHZ_FAILED_MSG \
- "["IMAP_RESP_CODE_AUTHZFAILED"] Authorization failed"
-
const char *client_authenticate_get_capabilities(struct imap_client *client);
int cmd_login(struct imap_client *client, const struct imap_arg *args);
#include "strescape.h"
#include "imap-parser.h"
#include "imap-id.h"
+#include "imap-resp-code.h"
#include "master-service.h"
#include "master-auth.h"
#include "client.h"
#endif
#define AUTH_SERVER_WAITING_MSG \
- "* OK Waiting for authentication process to respond.."
+ "Waiting for authentication process to respond.."
#define AUTH_MASTER_WAITING_MSG \
- "* OK Waiting for authentication master process to respond.."
+ "Waiting for authentication master process to respond.."
const char *login_protocol = "imap";
const char *login_process_name = "imap-login";
CAPABILITY commands. */
if (!client->starttls)
client->client_ignores_capability_resp_code = TRUE;
- client_send_line(client, t_strconcat(
- "* CAPABILITY ", get_capability(client), NULL));
- client_send_tagline(client, "OK Capability completed.");
+ client_send_raw(client, t_strconcat(
+ "* CAPABILITY ", get_capability(client), "\r\n", NULL));
+ client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
+ "Capability completed.");
return 1;
}
fd_ssl = ssl_proxy_new(client->common.fd, &client->common.ip,
client->common.set, &client->common.proxy);
if (fd_ssl == -1) {
- client_send_line(client, "* BYE TLS initialization failed.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
+ "TLS initialization failed.");
client_destroy(client,
"Disconnected: TLS initialization failed.");
return;
static int cmd_starttls(struct imap_client *client)
{
if (client->common.tls) {
- client_send_tagline(client, "BAD TLS is already active.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
+ "TLS is already active.");
return 1;
}
if (!ssl_initialized) {
- client_send_tagline(client, "BAD TLS support isn't enabled.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
+ "TLS support isn't enabled.");
return 1;
}
if (client->io != NULL)
io_remove(&client->io);
- client_send_tagline(client, "OK Begin TLS negotiation now.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
+ "Begin TLS negotiation now.");
/* uncork the old fd */
o_stream_uncork(client->output);
}
env = getenv("IMAP_ID_SEND");
- client_send_line(client, t_strdup_printf("* ID %s",
- imap_id_reply_generate(env)));
- client_send_tagline(client, "OK ID completed.");
+ client_send_raw(client,
+ t_strdup_printf("* ID %s\r\n", imap_id_reply_generate(env)));
+ client_send_line(&client->common, CLIENT_CMD_REPLY_OK, "ID completed.");
return 1;
}
static int cmd_noop(struct imap_client *client)
{
- client_send_tagline(client, "OK NOOP completed.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
+ "NOOP completed.");
return 1;
}
static int cmd_logout(struct imap_client *client)
{
- client_send_line(client, "* BYE Logging out");
- client_send_tagline(client, "OK Logout completed.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
+ "Logging out");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
+ "Logout completed.");
client_destroy(client, "Aborted login");
return 1;
}
static int cmd_enable(struct imap_client *client)
{
- client_send_line(client, "* ENABLED");
- client_send_tagline(client,
- "OK ENABLE ignored in non-authenticated state.");
+ client_send_raw(client, "* ENABLED\r\n");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
+ "ENABLE ignored in non-authenticated state.");
return 1;
}
/* error */
msg = imap_parser_get_error(client->parser, &fatal);
if (fatal) {
- client_send_line(client, t_strconcat("* BYE ",
- msg, NULL));
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_BYE, msg);
client_destroy(client,
t_strconcat("Disconnected: ", msg, NULL));
return FALSE;
}
- client_send_tagline(client, t_strconcat("BAD ", msg, NULL));
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BAD, msg);
client->cmd_finished = TRUE;
client->skip_line = TRUE;
return TRUE;
if (*client->cmd_tag == '\0')
client->cmd_tag = "*";
if (++client->bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
- client_send_line(client,
- "* BYE Too many invalid IMAP commands.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
+ "Too many invalid IMAP commands.");
client_destroy(client,
"Disconnected: Too many invalid commands");
return FALSE;
}
- client_send_tagline(client,
- "BAD Error in IMAP command received by server.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
+ "Error in IMAP command received by server.");
}
return ret != 0;
switch (i_stream_read(client->common.input)) {
case -2:
/* buffer full */
- client_send_line(client, "* BYE Input buffer full, aborting");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
+ "Input buffer full, aborting");
client_destroy(client, "Disconnected: Input buffer full");
return FALSE;
case -1:
if (!auth_client_is_connected(auth_client)) {
/* we're not yet connected to auth process -
don't allow any commands */
- client_send_line(client, AUTH_SERVER_WAITING_MSG);
+ client_send_line(&client->common, CLIENT_CMD_REPLY_STATUS,
+ AUTH_SERVER_WAITING_MSG);
if (client->to_auth_waiting != NULL)
timeout_remove(&client->to_auth_waiting);
str_append(greet, "* OK ");
str_printfa(greet, "[CAPABILITY %s] ", get_capability(client));
str_append(greet, client->common.set->login_greeting);
+ str_append(greet, "\r\n");
- client_send_line(client, str_c(greet));
+ client_send_raw(client, str_c(greet));
client->greeting_sent = TRUE;
}
static void client_idle_disconnect_timeout(struct imap_client *client)
{
- client_send_line(client, "* BYE Disconnected for inactivity.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
+ "Disconnected for inactivity.");
client_destroy(client, "Disconnected: Inactivity");
}
static void client_auth_waiting_timeout(struct imap_client *client)
{
- client_send_line(client, client->common.master_tag == 0 ?
+ client_send_line(&client->common, CLIENT_CMD_REPLY_STATUS,
+ client->common.master_tag == 0 ?
AUTH_SERVER_WAITING_MSG : AUTH_MASTER_WAITING_MSG);
timeout_remove(&client->to_auth_waiting);
}
void client_destroy_internal_failure(struct imap_client *client)
{
- client_send_line(client, "* BYE Internal login failure. "
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
+ "Internal login failure. "
"Refer to server log for more information.");
client_destroy(client, "Internal login failure");
}
return FALSE;
}
-void client_send_line(struct imap_client *client, const char *line)
+static void
+client_send_raw_data(struct imap_client *client, const void *data, size_t size)
{
- struct const_iovec iov[2];
ssize_t ret;
- iov[0].iov_base = line;
- iov[0].iov_len = strlen(line);
- iov[1].iov_base = "\r\n";
- iov[1].iov_len = 2;
-
- ret = o_stream_sendv(client->output, iov, 2);
- if (ret < 0 || (size_t)ret != iov[0].iov_len + iov[1].iov_len) {
- /* either disconnection or buffer full. in either case we
- want this connection destroyed. however destroying it here
- might break things if client is still tried to be accessed
- without being referenced.. */
+ ret = o_stream_send(client->output, data, size);
+ if (ret < 0 || (size_t)ret != size) {
+ /* either disconnection or buffer full. in either case we want
+ this connection destroyed. however destroying it here might
+ break things if client is still tried to be accessed without
+ being referenced.. */
i_stream_close(client->common.input);
}
}
-void client_send_tagline(struct imap_client *client, const char *line)
-{
- client_send_line(client, t_strconcat(client->cmd_tag, " ", line, NULL));
+void client_send_raw(struct imap_client *client, const char *data)
+{
+ client_send_raw_data(client, data, strlen(data));
+}
+
+void client_send_line(struct client *client, enum client_cmd_reply reply,
+ const char *text)
+{
+ struct imap_client *imap_client = (struct imap_client *)client;
+ const char *resp_code = NULL;
+ const char *prefix = "NO";
+ bool tagged = TRUE;
+
+ switch (reply) {
+ case CLIENT_CMD_REPLY_OK:
+ prefix = "OK";
+ break;
+ case CLIENT_CMD_REPLY_AUTH_FAILED:
+ resp_code = IMAP_RESP_CODE_AUTHFAILED;
+ break;
+ case CLIENT_CMD_REPLY_AUTHZ_FAILED:
+ resp_code = IMAP_RESP_CODE_AUTHZFAILED;
+ break;
+ case CLIENT_CMD_REPLY_AUTH_FAIL_TEMP:
+ resp_code = IMAP_RESP_CODE_UNAVAILABLE;
+ break;
+ case CLIENT_CMD_REPLY_AUTH_FAIL_REASON:
+ resp_code = "ALERT";
+ break;
+ case CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL:
+ resp_code = IMAP_RESP_CODE_PRIVACYREQUIRED;
+ break;
+ case CLIENT_CMD_REPLY_BAD:
+ prefix = "BAD";
+ break;
+ case CLIENT_CMD_REPLY_BYE:
+ prefix = "BYE";
+ tagged = FALSE;
+ break;
+ case CLIENT_CMD_REPLY_STATUS:
+ prefix = "OK";
+ tagged = FALSE;
+ break;
+ }
+
+ 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(imap_client, str_data(line),
+ str_len(line));
+ } T_END;
}
void clients_notify_auth_connected(void)
void client_destroy_success(struct imap_client *client, const char *reason);
void client_destroy_internal_failure(struct imap_client *client);
-void client_send_line(struct imap_client *client, const char *line);
-void client_send_tagline(struct imap_client *client, const char *line);
-
bool client_read(struct imap_client *client);
bool client_skip_line(struct imap_client *client);
void client_input(struct imap_client *client);
+void client_send_raw(struct imap_client *client, const char *data);
void client_ref(struct imap_client *client);
bool client_unref(struct imap_client *client);
#include <stdlib.h>
-#define PROXY_FAILURE_MSG \
- "NO ["IMAP_RESP_CODE_UNAVAILABLE"] "AUTH_TEMP_FAILED_MSG
-
static void proxy_write_id(struct imap_client *client, string_t *str)
{
str_printfa(str, "I ID ("
static void proxy_failed(struct imap_client *client, bool send_tagline)
{
- if (send_tagline)
- client_send_tagline(client, PROXY_FAILURE_MSG);
+ if (send_tagline) {
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
+ AUTH_TEMP_FAILED_MSG);
+ }
login_proxy_free(&client->proxy);
proxy_free_password(client);
the remote is sending a different error message
an attacker can't find out what users exist in
the system. */
- line = "NO "IMAP_AUTH_FAILED_MSG;
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAILED,
+ AUTH_FAILED_MSG);
} else if (strncmp(line, "NO [", 4) == 0) {
/* remote sent some other resp-code. forward it. */
+ client_send_raw(client, t_strconcat(
+ client->cmd_tag, " ", line, "\r\n", NULL));
} else {
/* there was no [resp-code], so remote isn't Dovecot
v1.2+. we could either forward the line as-is and
failures. since other errors are pretty rare,
it's safer to just hide them. they're still
available in logs though. */
- line = "NO "IMAP_AUTH_FAILED_MSG;
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAILED,
+ AUTH_FAILED_MSG);
}
- client_send_tagline(client, line);
proxy_failed(client, FALSE);
return -1;
return 0;
} else if (strncmp(line, "* ", 2) == 0) {
/* untagged reply. just foward it. */
- client_send_line(client, line);
+ client_send_raw(client, t_strconcat(line, "\r\n", NULL));
return 0;
} else {
/* tagged reply, shouldn't happen. */
if (password == NULL) {
client_syslog_err(&client->common, "proxy: password not given");
- client_send_tagline(client, PROXY_FAILURE_MSG);
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
+ AUTH_TEMP_FAILED_MSG);
return -1;
}
}
if (login_proxy_is_ourself(&client->common, host, port, user)) {
client_syslog_err(&client->common, "Proxying loops to itself");
- client_send_tagline(client, PROXY_FAILURE_MSG);
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
+ AUTH_TEMP_FAILED_MSG);
return -1;
}
client->proxy = login_proxy_new(&client->common, host, port, ssl_flags,
proxy_input, client);
if (client->proxy == NULL) {
- client_send_tagline(client, PROXY_FAILURE_MSG);
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
+ AUTH_TEMP_FAILED_MSG);
return -1;
}
*/
#define LOGIN_MAX_INBUF_SIZE 4096
+enum client_cmd_reply {
+ CLIENT_CMD_REPLY_OK,
+ CLIENT_CMD_REPLY_AUTH_FAILED,
+ CLIENT_CMD_REPLY_AUTHZ_FAILED,
+ CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
+ CLIENT_CMD_REPLY_AUTH_FAIL_REASON,
+ CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL,
+ CLIENT_CMD_REPLY_BAD,
+ CLIENT_CMD_REPLY_BYE,
+ CLIENT_CMD_REPLY_STATUS
+};
+
struct client {
struct client *prev, *next;
pool_t pool;
void client_unlink(struct client *client);
unsigned int clients_get_count(void) ATTR_PURE;
+void client_send_line(struct client *client, enum client_cmd_reply reply,
+ const char *text);
+
void client_syslog(struct client *client, const char *msg);
void client_syslog_err(struct client *client, const char *msg);
const char *client_get_extra_disconnect_reason(struct client *client);
str_append_c(str, ' ');
str_append(str, mech[i].name);
}
- str_append(str, "\r\n.");
+ str_append(str, "\r\n.\r\n");
- client_send_line(client, str_c(str));
+ client_send_raw(client, str_c(str));
return TRUE;
}
const char *master_user = NULL;
const char *key, *value, *p;
enum login_proxy_ssl_flags ssl_flags = 0;
- string_t *reply;
unsigned int port = 110;
bool proxy = FALSE, temp = FALSE, nologin = !success;
if (!nologin)
return FALSE;
- reply = t_str_new(128);
- str_append(reply, "-ERR ");
- if (reason != NULL)
- str_append(reply, reason);
- else if (temp)
- str_append(reply, "[IN-USE] "AUTH_TEMP_FAILED_MSG);
- else
- str_append(reply, AUTH_FAILED_MSG);
-
- client_send_line(client, str_c(reply));
+ if (reason != NULL) {
+ client_send_line(&client->common, CLIENT_CMD_REPLY_AUTH_FAILED,
+ reason);
+ } else if (temp) {
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
+ AUTH_TEMP_FAILED_MSG);
+ } else {
+ client_send_line(&client->common, CLIENT_CMD_REPLY_AUTH_FAILED,
+ AUTH_FAILED_MSG);
+ }
if (!client->destroyed)
client_auth_failed(client, *nodelay_r);
{
struct pop3_client *client = (struct pop3_client *)_client;
struct const_iovec iov[3];
- const char *msg;
size_t data_len;
bool nodelay;
break;
}
- if (reply == SASL_SERVER_REPLY_AUTH_ABORTED)
- msg = "-ERR Authentication aborted by client.";
- else if (data == NULL)
- msg = "-ERR "AUTH_FAILED_MSG;
- else
- msg = t_strconcat("-ERR ", data, NULL);
- client_send_line(client, msg);
+ if (reply == SASL_SERVER_REPLY_AUTH_ABORTED) {
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
+ "Authentication aborted by client.");
+ } else if (data == NULL) {
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAILED,
+ AUTH_FAILED_MSG);
+ } else {
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_REASON,
+ data);
+ }
if (!client->destroyed)
client_auth_failed(client, nodelay);
if (data == NULL)
client_destroy_internal_failure(client);
else {
- client_send_line(client,
- t_strconcat("-ERR [IN-USE] ", data, NULL));
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_TEMP, data);
+ /* authentication itself succeeded, we just hit some
+ internal failure. */
client_destroy_success(client, data);
}
break;
"SSL required for authentication");
}
client->common.auth_attempts++;
- client_send_line(client, "-ERR Authentication not allowed "
- "until SSL/TLS is enabled.");
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL,
+ "Authentication not allowed until SSL/TLS is enabled.");
return TRUE;
}
/* Old-style SASL discovery, used by MS Outlook */
unsigned int i, count;
- client_send_line(client, "+OK");
+ client_send_raw(client, "+OK\r\n");
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 ||
client->common.set->disable_plaintext_auth ||
- (mech[i].flags & MECH_SEC_PLAINTEXT) == 0))
- client_send_line(client, mech[i].name);
+ (mech[i].flags & MECH_SEC_PLAINTEXT) == 0)) {
+ client_send_raw(client, mech[i].name);
+ client_send_raw(client, "\r\n");
+ }
}
- client_send_line(client, ".");
+ client_send_raw(client, ".\r\n");
return TRUE;
}
client_syslog(&client->common, "Login failed: "
"Plaintext authentication disabled");
}
- client_send_line(client, "-ERR "AUTH_PLAINTEXT_DISABLED_MSG);
+ client_send_line(&client->common, CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL,
+ AUTH_PLAINTEXT_DISABLED_MSG);
client->common.auth_tried_disabled_plaintext = TRUE;
client->common.auth_attempts++;
return FALSE;
i_free(client->last_user);
client->last_user = i_strdup(args);
- client_send_line(client, "+OK");
+ client_send_raw(client, "+OK\r\n");
return TRUE;
}
if (!check_plaintext_auth(client))
return TRUE;
- client_send_line(client, "-ERR No username given.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
+ "No username given.");
return TRUE;
}
client_syslog(&client->common,
"APOP failed: APOP not enabled");
}
- client_send_line(client, "-ERR APOP not enabled.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
+ "APOP not enabled.");
return TRUE;
}
client_syslog(&client->common,
"APOP failed: Invalid parameters");
}
- client_send_line(client, "-ERR Invalid parameters.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
+ "Invalid parameters.");
return TRUE;
}
client_syslog(&client->common, "APOP failed: "
"Invalid characters in MD5 response");
}
- client_send_line(client,
- "-ERR Invalid characters in MD5 response.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
+ "Invalid characters in MD5 response.");
return TRUE;
}
#include "randgen.h"
#include "process-title.h"
#include "safe-memset.h"
+#include "str.h"
#include "strescape.h"
#include "master-service.h"
#include "master-auth.h"
fd_ssl = ssl_proxy_new(client->common.fd, &client->common.ip,
client->common.set, &client->common.proxy);
if (fd_ssl == -1) {
- client_send_line(client, "-ERR TLS initialization failed.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
+ "TLS initialization failed.");
client_destroy(client,
"Disconnected: TLS initialization failed.");
return;
static bool cmd_stls(struct pop3_client *client)
{
if (client->common.tls) {
- client_send_line(client, "-ERR TLS is already active.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
+ "TLS is already active.");
return TRUE;
}
if (!ssl_initialized) {
- client_send_line(client, "-ERR TLS support isn't enabled.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
+ "TLS support isn't enabled.");
return TRUE;
}
if (client->io != NULL)
io_remove(&client->io);
- client_send_line(client, "+OK Begin TLS negotiation now.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
+ "Begin TLS negotiation now.");
/* uncork the old fd */
o_stream_uncork(client->output);
static bool cmd_quit(struct pop3_client *client)
{
- client_send_line(client, "+OK Logging out");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_OK, "Logging out");
client_destroy(client, "Aborted login");
return TRUE;
}
if (strcmp(cmd, "QUIT") == 0)
return cmd_quit(client);
- client_send_line(client, "-ERR Unknown command.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BAD,
+ "Unknown command.");
return FALSE;
}
switch (i_stream_read(client->common.input)) {
case -2:
/* buffer full */
- client_send_line(client, "-ERR Input line too long, aborting");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
+ "Input buffer full, aborting");
client_destroy(client, "Disconnected: Input buffer full");
return FALSE;
case -1:
args != NULL ? args : ""))
client->bad_counter = 0;
else if (++client->bad_counter > CLIENT_MAX_BAD_COMMANDS) {
- client_send_line(client, "-ERR Too many bad commands.");
+ client_send_line(&client->common, CLIENT_CMD_REPLY_BYE,
+ "Too many invalid IMAP commands.");
client_destroy(client,
"Disconnected: Too many bad commands");
}
client->io = io_add(client->common.fd, IO_READ, client_input, client);
client->apop_challenge = get_apop_challenge(client);
- client_send_line(client, t_strconcat("+OK ",
- client->common.set->login_greeting,
- client->apop_challenge != NULL ?
- " " : NULL,
- client->apop_challenge, NULL));
+ if (client->apop_challenge == NULL) {
+ client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
+ client->common.set->login_greeting);
+ } else {
+ client_send_line(&client->common, CLIENT_CMD_REPLY_OK,
+ t_strconcat(client->common.set->login_greeting, " ",
+ client->apop_challenge, NULL));
+ }
}
static void client_idle_disconnect_timeout(struct pop3_client *client)
void client_destroy_internal_failure(struct pop3_client *client)
{
- client_send_line(client, "-ERR [IN-USE] Internal login failure. "
+ client_send_line(&client->common, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
+ "Internal login failure. "
"Refer to server log for more information.");
client_destroy(client, "Internal login failure");
}
return FALSE;
}
-void client_send_line(struct pop3_client *client, const char *line)
+static void
+client_send_raw_data(struct pop3_client *client, const void *data, size_t size)
{
- struct const_iovec iov[2];
ssize_t ret;
- iov[0].iov_base = line;
- iov[0].iov_len = strlen(line);
- iov[1].iov_base = "\r\n";
- iov[1].iov_len = 2;
-
- ret = o_stream_sendv(client->output, iov, 2);
- if (ret < 0 || (size_t)ret != iov[0].iov_len + iov[1].iov_len) {
- /* either disconnection or buffer full. in either case we
- want this connection destroyed. however destroying it here
- might break things if client is still tried to be accessed
- without being referenced.. */
+ ret = o_stream_send(client->output, data, size);
+ if (ret < 0 || (size_t)ret != size) {
+ /* either disconnection or buffer full. in either case we want
+ this connection destroyed. however destroying it here might
+ break things if client is still tried to be accessed without
+ being referenced.. */
i_stream_close(client->common.input);
}
}
+void client_send_raw(struct pop3_client *client, const char *data)
+{
+ client_send_raw_data(client, data, strlen(data));
+}
+
+void client_send_line(struct client *client, enum client_cmd_reply reply,
+ const char *text)
+{
+ struct pop3_client *pop3_client = (struct pop3_client *)client;
+ const char *prefix = "-ERR";
+
+ switch (reply) {
+ case CLIENT_CMD_REPLY_OK:
+ prefix = "+OK";
+ break;
+ case CLIENT_CMD_REPLY_AUTH_FAIL_TEMP:
+ prefix = "-ERR [IN-USE]";
+ break;
+ case CLIENT_CMD_REPLY_AUTH_FAILED:
+ case CLIENT_CMD_REPLY_AUTHZ_FAILED:
+ case CLIENT_CMD_REPLY_AUTH_FAIL_REASON:
+ case CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL:
+ case CLIENT_CMD_REPLY_BAD:
+ case CLIENT_CMD_REPLY_BYE:
+ break;
+ case CLIENT_CMD_REPLY_STATUS:
+ /* can't send status notifications */
+ return;
+ }
+
+ T_BEGIN {
+ string_t *line = t_str_new(256);
+
+ str_append(line, prefix);
+ str_append_c(line, ' ');
+ str_append(line, text);
+ str_append(line, "\r\n");
+
+ client_send_raw_data(pop3_client, str_data(line),
+ str_len(line));
+ } T_END;
+}
+
+
void clients_notify_auth_connected(void)
{
struct client *client;
void client_destroy_success(struct pop3_client *client, const char *reason);
void client_destroy_internal_failure(struct pop3_client *client);
-void client_send_line(struct pop3_client *client, const char *line);
-
bool client_read(struct pop3_client *client);
void client_input(struct pop3_client *client);
+void client_send_raw(struct pop3_client *client, const char *data);
+
void client_ref(struct pop3_client *client);
bool client_unref(struct pop3_client *client);
#include "client.h"
#include "pop3-proxy.h"
-#define PROXY_FAILURE_MSG "-ERR [IN-USE] "AUTH_TEMP_FAILED_MSG
-
static void proxy_free_password(struct pop3_client *client)
{
if (client->proxy_password == NULL)
static void proxy_failed(struct pop3_client *client, bool send_line)
{
- if (send_line)
- client_send_line(client, PROXY_FAILURE_MSG);
+ if (send_line) {
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
+ AUTH_TEMP_FAILED_MSG);
+ }
login_proxy_free(&client->proxy);
proxy_free_password(client);
shouldn't be a real problem since of course everyone will
be using only Dovecot as their backend :) */
if (strncmp(line, "-ERR ", 5) != 0)
- client_send_line(client, "-ERR "AUTH_FAILED_MSG);
- else
- client_send_line(client, line);
+ client_send_line(&client->common, CLIENT_CMD_REPLY_AUTH_FAILED,
+ AUTH_FAILED_MSG);
+ else {
+ client_send_raw(client, t_strconcat(line, "\r\n", NULL));
+ }
if (client->common.set->verbose_auth) {
str = t_str_new(128);
if (password == NULL) {
client_syslog_err(&client->common, "proxy: password not given");
- client_send_line(client, PROXY_FAILURE_MSG);
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
+ AUTH_TEMP_FAILED_MSG);
return -1;
}
}
if (login_proxy_is_ourself(&client->common, host, port, user)) {
client_syslog_err(&client->common, "Proxying loops to itself");
- client_send_line(client, PROXY_FAILURE_MSG);
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
+ AUTH_TEMP_FAILED_MSG);
return -1;
}
client->proxy = login_proxy_new(&client->common, host, port, ssl_flags,
proxy_input, client);
if (client->proxy == NULL) {
- client_send_line(client, PROXY_FAILURE_MSG);
+ client_send_line(&client->common,
+ CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
+ AUTH_TEMP_FAILED_MSG);
return -1;
}