client-common-auth.c revision e248fe370c4047cee921a91b48edc37944ab0526
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "common.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "istream.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "ostream.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "str.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "safe-memset.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "login-proxy.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "auth-client.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "client-common.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include <stdlib.h>
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen/* If we've been waiting auth server to respond for over this many milliseconds,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen send a "waiting" message. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#define AUTH_WAITING_TIMEOUT_MSECS (30*1000)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#define AUTH_FAILURE_DELAY_INCREASE_MSECS 5000
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#if CLIENT_LOGIN_IDLE_TIMEOUT_MSECS < AUTH_REQUEST_TIMEOUT*1000
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen# error client idle timeout must be larger than authentication timeout
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#endif
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void client_authfail_delay_timeout(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen timeout_remove(&client->to_authfail_delay);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* get back to normal client input. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(client->io == NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->io = io_add(client->fd, IO_READ, client_input, client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_input(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_auth_failed(struct client *client, bool nodelay)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen unsigned int delay_msecs;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free_and_null(client->master_data_prefix);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->auth_initializing)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->io != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen io_remove(&client->io);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (nodelay) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->io = io_add(client->fd, IO_READ, client_input, client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_input(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* increase the timeout after each unsuccessful attempt, but don't
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen increase it so high that the idle timeout would be triggered */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen delay_msecs = client->auth_attempts * AUTH_FAILURE_DELAY_INCREASE_MSECS;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (delay_msecs > CLIENT_LOGIN_IDLE_TIMEOUT_MSECS)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen delay_msecs = CLIENT_LOGIN_IDLE_TIMEOUT_MSECS - 1000;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(client->to_authfail_delay == NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->to_authfail_delay =
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen timeout_add(delay_msecs, client_authfail_delay_timeout, client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void client_auth_waiting_timeout(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_STATUS,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->master_tag == 0 ?
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen AUTH_SERVER_WAITING_MSG : AUTH_MASTER_WAITING_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen timeout_remove(&client->to_auth_waiting);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_set_auth_waiting(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(client->to_auth_waiting == NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->to_auth_waiting =
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen timeout_add(AUTH_WAITING_TIMEOUT_MSECS,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_auth_waiting_timeout, client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void client_auth_parse_args(struct client *client,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *const *args,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct client_auth_reply *reply_r)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *key, *value, *p;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen memset(reply_r, 0, sizeof(*reply_r));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->port = login_default_port;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (; *args != NULL; args++) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen p = strchr(*args, '=');
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (p == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen key = *args;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen value = "";
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen key = t_strdup_until(*args, p);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen value = p + 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strcmp(key, "nologin") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->nologin = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "nodelay") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->nodelay = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "proxy") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->proxy = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "temp") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->temp = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "authz") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->authz_failure = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "reason") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->reason = value;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "host") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->host = value;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "port") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->port = atoi(value);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "destuser") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->destuser = value;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "pass") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->password = value;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "master") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->master_user = value;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "ssl") == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strcmp(value, "yes") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_YES;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(value, "any-cert") == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_YES |
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen PROXY_SSL_FLAG_ANY_CERT;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else if (strcmp(key, "starttls") == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_STARTTLS;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else if (strcmp(key, "user") == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* already handled in login-common */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else if (client->set->auth_debug)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_info("Ignoring unknown passdb extra field: %s", key);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (reply_r->destuser == NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->destuser = client->virtual_user;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void proxy_free_password(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->proxy_password == NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free_and_null(client->proxy_password);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_proxy_finish_destroy_client(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen string_t *str = t_str_new(128);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_printfa(str, "proxy(%s): started proxying to %s:%u",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->virtual_user,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen login_proxy_get_host(client->login_proxy),
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen login_proxy_get_port(client->login_proxy));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strcmp(client->virtual_user, client->proxy_user) != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* remote username is different, log it */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append_c(str, '/');
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, client->proxy_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->proxy_master_user != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_printfa(str, " (master %s)", client->proxy_master_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen login_proxy_detach(client->login_proxy, client->input, client->output);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->login_proxy = NULL;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->input = NULL;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->output = NULL;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->fd = -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->proxying = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy_success(client, str_c(str));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_proxy_log_failure(struct client *client, const char *line)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen string_t *str = t_str_new(128);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_printfa(str, "proxy(%s): Login failed to %s:%u",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->virtual_user,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen login_proxy_get_host(client->login_proxy),
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen login_proxy_get_port(client->login_proxy));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strcmp(client->virtual_user, client->proxy_user) != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* remote username is different, log it */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append_c(str, '/');
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, client->proxy_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->proxy_master_user != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_printfa(str, " (master %s)", client->proxy_master_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, ": ");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, line);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_info("%s", str_c(str));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_proxy_failed(struct client *client, bool send_line)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (send_line) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen AUTH_TEMP_FAILED_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen login_proxy_free(&client->login_proxy);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen proxy_free_password(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free_and_null(client->proxy_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free_and_null(client->proxy_master_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* call this last - it may destroy the client */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_auth_failed(client, TRUE);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void proxy_input(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream *input;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *line;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->login_proxy == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* we're just freeing the proxy */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen input = login_proxy_get_istream(client->login_proxy);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (input == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->destroyed) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* we came here from client_destroy() */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* failed for some reason, probably server disconnected */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_failed(client, TRUE);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(!client->destroyed);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen switch (i_stream_read(input)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case -2:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(client, "proxy: Remote input buffer full");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_failed(client, TRUE);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case -1:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(client, "proxy: Remote disconnected");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_failed(client, TRUE);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen while ((line = i_stream_next_line(input)) != NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->v.proxy_parse_line(client, line) != 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int proxy_start(struct client *client,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const struct client_auth_reply *reply)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(reply->destuser != NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(!client->destroyed);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->v.proxy_reset(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (reply->password == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(client, "proxy: password not given");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen AUTH_TEMP_FAILED_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(client->refcount > 1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->destroyed) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* connection_queue_add() decided that we were the oldest
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen connection and killed us. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (login_proxy_is_ourself(client, reply->host, reply->port,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply->destuser)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(client, "Proxying loops to itself");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen AUTH_TEMP_FAILED_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->login_proxy =
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen login_proxy_new(client, reply->host, reply->port,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply->ssl_flags, proxy_input, client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->login_proxy == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen AUTH_TEMP_FAILED_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->proxy_user = i_strdup(reply->destuser);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->proxy_master_user = i_strdup(reply->master_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->proxy_password = i_strdup(reply->password);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* disable input until authentication is finished */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->io != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen io_remove(&client->io);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic bool
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenclient_auth_handle_reply(struct client *client,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const struct client_auth_reply *reply, bool success)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (reply->proxy) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* we want to proxy the connection to another server.
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen don't do this unless authentication succeeded. with
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen master user proxying we can get FAIL with proxy still set.
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen proxy host=.. [port=..] [destuser=..] pass=.. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!success)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (proxy_start(client, reply) < 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_auth_failed(client, TRUE);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return client->v.auth_handle_reply(client, reply);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void client_auth_input(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen char *line;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!client_read(client))
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* @UNSAFE */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen line = i_stream_next_line(client->input);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (line == NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strcmp(line, "*") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen sasl_server_auth_abort(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_set_auth_waiting(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen auth_client_request_continue(client->auth_request, line);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen io_remove(&client->io);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* clear sensitive data */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen safe_memset(line, 0, strlen(line));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainensasl_callback(struct client *client, enum sasl_server_reply sasl_reply,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *data, const char *const *args)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct const_iovec iov[3];
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct client_auth_reply reply;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size_t data_len;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(!client->destroyed ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen sasl_reply == SASL_SERVER_REPLY_MASTER_FAILED);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen switch (sasl_reply) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case SASL_SERVER_REPLY_SUCCESS:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->to_auth_waiting != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen timeout_remove(&client->to_auth_waiting);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (args != NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_auth_parse_args(client, args, &reply);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client_auth_handle_reply(client, &reply, TRUE))
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy_success(client, "Login");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case SASL_SERVER_REPLY_AUTH_FAILED:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case SASL_SERVER_REPLY_AUTH_ABORTED:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->to_auth_waiting != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen timeout_remove(&client->to_auth_waiting);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (args != NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_auth_parse_args(client, args, &reply);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply.nologin = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client_auth_handle_reply(client, &reply, FALSE))
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BAD,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Authentication aborted by client.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else if (data == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAILED,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen AUTH_FAILED_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen CLIENT_CMD_REPLY_AUTH_FAIL_REASON,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen data);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!client->destroyed)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_auth_failed(client, reply.nodelay);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case SASL_SERVER_REPLY_MASTER_FAILED:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (data == NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy_internal_failure(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen CLIENT_CMD_REPLY_AUTH_FAIL_TEMP, data);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* authentication itself succeeded, we just hit some
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen internal failure. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy_success(client, data);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case SASL_SERVER_REPLY_CONTINUE:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen data_len = strlen(data);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen iov[0].iov_base = "+ ";
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen iov[0].iov_len = 2;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen iov[1].iov_base = data;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen iov[1].iov_len = data_len;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen iov[2].iov_base = "\r\n";
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen iov[2].iov_len = 2;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* don't check return value here. it gets tricky if we try
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen to call client_destroy() in here. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen (void)o_stream_sendv(client->output, iov, 3);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->to_auth_waiting != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen timeout_remove(&client->to_auth_waiting);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(client->io == NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->io = io_add(client->fd, IO_READ,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_auth_input, client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_auth_input(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_unref(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenint client_auth_begin(struct client *client, const char *mech_name,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *init_resp)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_ref(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->auth_initializing = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen sasl_server_auth_begin(client, login_protocol, mech_name,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen init_resp, sasl_callback);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->auth_initializing = FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!client->authenticating)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* don't handle input until we get the initial auth reply */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->io != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen io_remove(&client->io);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_set_auth_waiting(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenbool client_check_plaintext_auth(struct client *client, bool pass_sent)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->secured || !client->set->disable_plaintext_auth)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->set->verbose_auth) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log(client, "Login failed: "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Plaintext authentication disabled");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (pass_sent) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_STATUS_BAD,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Plaintext authentication not allowed "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "without SSL/TLS, but your client did it anyway. "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "If anyone was listening, the password was exposed.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen AUTH_PLAINTEXT_DISABLED_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->auth_tried_disabled_plaintext = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->auth_attempts++;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid clients_notify_auth_connected(void)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct client *client;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (client = clients; client != NULL; client = client->next) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->to_auth_waiting != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen timeout_remove(&client->to_auth_waiting);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!client->greeting_sent)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->v.send_greeting(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->input_blocked) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->input_blocked = FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_input(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}