/* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */
#include "login-common.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "iostream.h"
#include "iostream-proxy.h"
#include "iostream-ssl.h"
#include "llist.h"
#include "array.h"
#include "str.h"
#include "strescape.h"
#include "time-util.h"
#include "master-service.h"
#include "master-service-ssl-settings.h"
#include "ipc-server.h"
#include "mail-user-hash.h"
#include "client-common.h"
#include "login-proxy-state.h"
#include "login-proxy.h"
struct login_proxy {
int server_fd;
char *host;
unsigned int connect_timeout_msecs;
unsigned int notify_refresh_secs;
unsigned int reconnect_count;
};
static unsigned int detached_login_proxies_count = 0;
static void
ATTR_NULL(2);
static void
ATTR_NULL(2);
{
}
{
if (errstr[0] != '\0')
}
if (server)
else
}
{
/* we're already disconnected from server. either wait for
disconnection timeout or for client to disconnect itself. */
else {
}
}
{
}
{
}
{
/* there was a successful connection done since we started
connecting. perhaps this is just a temporary one-off
failure. */
} else {
}
}
static void
{
} else {
}
if (proxy->reconnect_count > 0)
}
}
{
if (login_proxy_connect(proxy) < 0)
}
{
if (since_started_msecs < 0)
return FALSE; /* time moved backwards */
if (left_msecs <= 0)
return FALSE;
proxy->reconnect_count++;
return TRUE;
}
{
if (errno != 0) {
if (!proxy_try_reconnect(proxy)) {
}
return;
}
if (login_proxy_starttls(proxy) < 0) {
return;
}
}
}
{
}
{
/* this needs to be done early, since login_proxy_free() shrinks
num_waiting_connections. */
"proxy(%s): BUG: host %s is not an IP "
"(auth should have changed it)",
return -1;
}
/* first connect to this IP. don't start immediately failing
the check below. */
}
/* the server is down. fail immediately */
"proxy(%s): Host %s:%u is down",
return -1;
}
return -1;
}
if (proxy->connect_timeout_msecs != 0) {
}
return 0;
}
const struct login_proxy_settings *set,
{
return -1;
}
"proxy(%s): TTL reached zero - "
return -1;
}
if (login_proxy_connect(proxy) < 0) {
return -1;
}
return 0;
}
{
if (!proxy->num_waiting_connections_updated) {
}
}
}
}
{
if (proxy->delayed_disconnect) {
}
}
{
const unsigned int max_delay =
int delay_msecs;
if (rec->num_disconnects_since_ts == 0) {
/* start from a slightly random timestamp. this way all proxy
processes will disconnect at slightly different times to
spread the load. */
}
/* we were already lazily disconnecting this */
return 0;
}
if (max_delay == 0) {
/* delaying is disabled */
return 0;
}
rec->num_delayed_client_disconnects == 0) {
/* wait delaying until we have 1 second's worth of clients
disconnected */
return 0;
}
/* see at which time we should be disconnecting the client.
do it in 100ms intervals so the timeouts are triggered together. */
if (delay_msecs <= 0) {
/* we already reached the time */
return 0;
}
return delay_msecs;
}
static void ATTR_NULL(2)
bool delayed)
{
const char *ipstr;
unsigned int delay_ms = 0;
if (proxy->destroying)
return;
/* we'll disconnect server side in any case. */
/* detached proxy */
if (delayed)
"proxy(%s): disconnecting %s%s%s",
} else {
}
if (delay_ms == 0)
else {
}
}
static void ATTR_NULL(2)
{
}
static void ATTR_NULL(2)
{
}
{
}
{
return FALSE;
return FALSE;
return FALSE;
}
{
}
{
return proxy->server_output;
}
{
}
{
}
{
}
static void
enum iostream_proxy_status status,
struct login_proxy *proxy)
{
const char *errstr;
bool server_side;
switch (status) {
/* success */
errstr = "";
break;
break;
break;
default:
i_unreached();
}
}
{
}
{
/* from now on, just do dummy proxying */
if (proxy->notify_refresh_secs != 0) {
}
if (login_proxy_ipc_server == NULL) {
}
}
{
const char *error;
&ssl_set);
/* NOTE: We're explicitly disabling ssl_client_ca_* settings for now
at least. The main problem is that we're chrooted, so we can't read
them at this point anyway. The second problem is that especially
ssl_client_ca_dir does blocking disk I/O, which could cause
unexpected hangs when login process handles multiple clients. */
"proxy: Failed to create SSL client context: %s", error));
return -1;
}
&error) < 0) {
"proxy: Failed to create SSL client to %s:%u: %s",
return -1;
}
"proxy: Failed to start SSL handshake to %s:%u: %s",
return -1;
}
return 0;
}
{
}
void login_proxy_kill_idle(void)
{
unsigned int stop_msecs;
if (last_io <= stop_timestamp)
else {
}
}
}
static bool
unsigned int key_idx ATTR_UNUSED)
{
}
static bool
unsigned int key_idx)
{
unsigned int i;
return FALSE;
for (i = 0; i < key_idx; i++) {
return FALSE;
}
}
static void
unsigned int), unsigned int key_idx)
{
unsigned int count = 0;
return;
}
count++;
}
}
count++;
}
}
}
static void
{
}
static void
{
char *const *fields;
unsigned int i, count;
return;
}
for (i = 0; i < count; i++) {
break;
}
if (i == count) {
/* field doesn't exist, but it's not an error necessarily */
return;
}
}
{
const char *error;
if (client->director_username_hash_cache != 0) {
/* already set */
&error)) {
i_error("Failed to expand director_username_hash=%s: %s",
return FALSE;
}
return TRUE;
}
static void
{
return;
}
/* optional except_ip parameter specifies that we're not killing the
connections that are proxying to the except_ip backend */
return;
}
proxy_hash == hash &&
count++;
}
}
proxy_hash == hash &&
count++;
}
}
}
static void
struct login_proxy *proxy)
{
str_truncate(str, 0);
i = 0;
}
}
for (; i < alt_count; i++)
}
static void
{
char *const *fieldp;
}
}
{
args++;
else
}
unsigned int login_proxies_get_detached_count(void)
{
return detached_login_proxies_count;
}
{
}
{
}
void login_proxy_deinit(void)
{
while (login_proxies != NULL) {
}
while (login_proxies_disconnecting != NULL)
if (login_proxy_ipc_server != NULL)
}