src/login-common/ssl-proxy-openssl.c
author Timo Sirainen <tss@iki.fi>
Tue Oct 06 10:53:34 2009 -0400 (2009-10-06)
branchHEAD
changeset 9416 4add5c3f13ea
parent 9394 e7a973c0101b
child 9435 0aa7357761a5
permissions -rw-r--r--
Compiling fix for OpenSSL 0.9.7 and older.
tss@8590
     1
/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
tss@1049
     2
tss@1049
     3
#include "common.h"
tss@3888
     4
#include "array.h"
tss@1049
     5
#include "ioloop.h"
tss@1049
     6
#include "network.h"
tss@4474
     7
#include "ostream.h"
tss@3888
     8
#include "read-full.h"
tss@7119
     9
#include "llist.h"
tss@1049
    10
#include "ssl-proxy.h"
tss@1049
    11
tss@3888
    12
#include <fcntl.h>
tss@3888
    13
#include <unistd.h>
tss@3888
    14
#include <sys/stat.h>
tss@3888
    15
tss@1049
    16
#ifdef HAVE_OPENSSL
tss@1049
    17
tss@1049
    18
#include <openssl/crypto.h>
tss@1049
    19
#include <openssl/x509.h>
tss@1049
    20
#include <openssl/pem.h>
tss@1049
    21
#include <openssl/ssl.h>
tss@1049
    22
#include <openssl/err.h>
tss@1556
    23
#include <openssl/rand.h>
tss@1049
    24
tss@4696
    25
#define DOVECOT_SSL_DEFAULT_CIPHER_LIST "ALL:!LOW:!SSLv2"
tss@3888
    26
/* Check every 30 minutes if parameters file has been updated */
tss@3888
    27
#define SSL_PARAMFILE_CHECK_INTERVAL (60*30)
tss@1544
    28
tss@4538
    29
enum ssl_io_action {
tss@4538
    30
	SSL_ADD_INPUT,
tss@4538
    31
	SSL_REMOVE_INPUT,
tss@4538
    32
	SSL_ADD_OUTPUT,
tss@4538
    33
	SSL_REMOVE_OUTPUT
tss@1049
    34
};
tss@1049
    35
tss@1049
    36
struct ssl_proxy {
tss@1049
    37
	int refcount;
tss@7119
    38
	struct ssl_proxy *prev, *next;
tss@1049
    39
tss@1049
    40
	SSL *ssl;
tss@1235
    41
	struct ip_addr ip;
tss@1049
    42
tss@1049
    43
	int fd_ssl, fd_plain;
tss@4538
    44
	struct io *io_ssl_read, *io_ssl_write, *io_plain_read, *io_plain_write;
tss@1049
    45
tss@4538
    46
	unsigned char plainout_buf[1024];
tss@4538
    47
	unsigned int plainout_size;
tss@1049
    48
tss@1049
    49
	unsigned char sslout_buf[1024];
tss@1324
    50
	unsigned int sslout_size;
tss@1458
    51
tss@8985
    52
	ssl_handshake_callback_t *handshake_callback;
tss@8986
    53
	void *handshake_context;
tss@8985
    54
tss@7374
    55
	char *last_error;
tss@1458
    56
	unsigned int handshaked:1;
tss@1458
    57
	unsigned int destroyed:1;
tss@2027
    58
	unsigned int cert_received:1;
tss@2027
    59
	unsigned int cert_broken:1;
tss@8985
    60
	unsigned int client:1;
tss@1049
    61
};
tss@1049
    62
tss@3888
    63
struct ssl_parameters {
tss@3888
    64
	const char *fname;
tss@4505
    65
	time_t last_mtime, last_check;
tss@3888
    66
	int fd;
tss@3888
    67
tss@3888
    68
	DH *dh_512, *dh_1024;
tss@3888
    69
};
tss@3888
    70
tss@2027
    71
static int extdata_index;
tss@8985
    72
static SSL_CTX *ssl_server_ctx;
tss@8985
    73
static SSL_CTX *ssl_client_ctx;
tss@7119
    74
static unsigned int ssl_proxy_count;
tss@7119
    75
static struct ssl_proxy *ssl_proxies;
tss@3888
    76
static struct ssl_parameters ssl_params;
tss@6364
    77
static int ssl_username_nid;
tss@1049
    78
tss@4907
    79
static void plain_read(struct ssl_proxy *proxy);
tss@4538
    80
static void ssl_read(struct ssl_proxy *proxy);
tss@4538
    81
static void ssl_write(struct ssl_proxy *proxy);
tss@4907
    82
static void ssl_step(struct ssl_proxy *proxy);
tss@1458
    83
static void ssl_proxy_destroy(struct ssl_proxy *proxy);
tss@3863
    84
static void ssl_proxy_unref(struct ssl_proxy *proxy);
tss@1049
    85
tss@8621
    86
static void ssl_params_corrupted(const char *path)
tss@8621
    87
{
tss@8621
    88
	i_fatal("Corrupted SSL parameters file: %s/%s "
tss@8621
    89
		"(delete it and also the one in %s)",
tss@8621
    90
		getenv("LOGIN_DIR"), path, PKG_STATEDIR);
tss@8621
    91
}
tss@8621
    92
tss@3888
    93
static void read_next(struct ssl_parameters *params, void *data, size_t size)
tss@3888
    94
{
tss@3888
    95
	int ret;
tss@3888
    96
tss@3888
    97
	if ((ret = read_full(params->fd, data, size)) < 0)
tss@3888
    98
		i_fatal("read(%s) failed: %m", params->fname);
tss@3888
    99
	if (ret == 0)
tss@8621
   100
		ssl_params_corrupted(params->fname);
tss@3888
   101
}
tss@3888
   102
tss@3888
   103
static bool read_dh_parameters_next(struct ssl_parameters *params)
tss@3888
   104
{
tss@3888
   105
	unsigned char *buf;
tss@3888
   106
	const unsigned char *cbuf;
tss@3888
   107
	unsigned int len;
tss@3888
   108
	int bits;
tss@3888
   109
tss@3888
   110
	/* read bit size. 0 ends the DH parameters list. */
tss@3888
   111
	read_next(params, &bits, sizeof(bits));
tss@3888
   112
tss@3888
   113
	if (bits == 0)
tss@3888
   114
		return FALSE;
tss@3888
   115
tss@3888
   116
	/* read data size. */
tss@3888
   117
	read_next(params, &len, sizeof(len));
tss@3888
   118
	if (len > 1024*100) /* should be enough? */
tss@8621
   119
		ssl_params_corrupted(params->fname);
tss@3888
   120
tss@3888
   121
	buf = i_malloc(len);
tss@3888
   122
	read_next(params, buf, len);
tss@3888
   123
tss@3888
   124
	cbuf = buf;
tss@3888
   125
	switch (bits) {
tss@3888
   126
	case 512:
tss@3888
   127
		params->dh_512 = d2i_DHparams(NULL, &cbuf, len);
tss@3888
   128
		break;
tss@3888
   129
	case 1024:
tss@3888
   130
		params->dh_1024 = d2i_DHparams(NULL, &cbuf, len);
tss@3888
   131
		break;
tss@8621
   132
	default:
tss@8621
   133
		ssl_params_corrupted(params->fname);
tss@3888
   134
	}
tss@3888
   135
tss@3888
   136
	i_free(buf);
tss@3888
   137
	return TRUE;
tss@3888
   138
}
tss@3888
   139
tss@3888
   140
static void ssl_free_parameters(struct ssl_parameters *params)
tss@3888
   141
{
tss@3888
   142
	if (params->dh_512 != NULL) {
tss@3888
   143
		DH_free(params->dh_512);
tss@3888
   144
                params->dh_512 = NULL;
tss@3888
   145
	}
tss@3888
   146
	if (params->dh_1024 != NULL) {
tss@3888
   147
		DH_free(params->dh_1024);
tss@3888
   148
                params->dh_1024 = NULL;
tss@3888
   149
	}
tss@3888
   150
}
tss@3888
   151
tss@3888
   152
static void ssl_read_parameters(struct ssl_parameters *params)
tss@3888
   153
{
tss@4505
   154
	struct stat st;
tss@8621
   155
	ssize_t ret;
tss@8621
   156
	char c;
tss@3888
   157
	bool warned = FALSE;
tss@3888
   158
tss@3888
   159
	/* we'll wait until parameter file exists */
tss@3888
   160
	for (;;) {
tss@3888
   161
		params->fd = open(params->fname, O_RDONLY);
tss@3888
   162
		if (params->fd != -1)
tss@3888
   163
			break;
tss@3888
   164
tss@3888
   165
		if (errno != ENOENT) {
tss@3888
   166
			i_fatal("Can't open SSL parameter file %s: %m",
tss@3888
   167
				params->fname);
tss@3888
   168
		}
tss@3888
   169
tss@3888
   170
		if (!warned) {
tss@3888
   171
			i_warning("Waiting for SSL parameter file %s",
tss@3888
   172
				  params->fname);
tss@3888
   173
			warned = TRUE;
tss@3888
   174
		}
tss@3888
   175
		sleep(1);
tss@3888
   176
	}
tss@3888
   177
tss@4505
   178
	if (fstat(params->fd, &st) < 0)
tss@4505
   179
		i_error("fstat(%s) failed: %m", params->fname);
tss@4505
   180
	else
tss@4505
   181
		params->last_mtime = st.st_mtime;
tss@4505
   182
tss@3888
   183
	ssl_free_parameters(params);
tss@3888
   184
	while (read_dh_parameters_next(params)) ;
tss@3888
   185
tss@8621
   186
	if ((ret = read_full(params->fd, &c, 1)) < 0)
tss@8621
   187
		i_fatal("read(%s) failed: %m", params->fname);
tss@8621
   188
	else if (ret != 0) {
tss@8621
   189
		/* more data than expected */
tss@8621
   190
		ssl_params_corrupted(params->fname);
tss@8621
   191
	}
tss@8621
   192
tss@3888
   193
	if (close(params->fd) < 0)
tss@3888
   194
		i_error("close() failed: %m");
tss@3888
   195
	params->fd = -1;
tss@3888
   196
}
tss@3888
   197
tss@3888
   198
static void ssl_refresh_parameters(struct ssl_parameters *params)
tss@3888
   199
{
tss@3888
   200
	struct stat st;
tss@3888
   201
tss@4505
   202
	if (params->last_check > ioloop_time - SSL_PARAMFILE_CHECK_INTERVAL)
tss@3888
   203
		return;
tss@4505
   204
	params->last_check = ioloop_time;
tss@3888
   205
tss@3888
   206
	if (params->last_mtime == 0)
tss@3888
   207
		ssl_read_parameters(params);
tss@3888
   208
	else {
tss@3888
   209
		if (stat(params->fname, &st) < 0)
tss@3888
   210
			i_error("stat(%s) failed: %m", params->fname);
tss@3888
   211
		else if (st.st_mtime != params->last_mtime)
tss@3888
   212
			ssl_read_parameters(params);
tss@3888
   213
	}
tss@3888
   214
}
tss@3888
   215
tss@4538
   216
static void ssl_set_io(struct ssl_proxy *proxy, enum ssl_io_action action)
tss@4538
   217
{
tss@4538
   218
	switch (action) {
tss@4538
   219
	case SSL_ADD_INPUT:
tss@4538
   220
		if (proxy->io_ssl_read != NULL)
tss@4538
   221
			break;
tss@4538
   222
		proxy->io_ssl_read = io_add(proxy->fd_ssl, IO_READ,
tss@4538
   223
					    ssl_step, proxy);
tss@4538
   224
		break;
tss@4538
   225
	case SSL_REMOVE_INPUT:
tss@4538
   226
		if (proxy->io_ssl_read != NULL)
tss@4538
   227
			io_remove(&proxy->io_ssl_read);
tss@4538
   228
		break;
tss@4538
   229
	case SSL_ADD_OUTPUT:
tss@4538
   230
		if (proxy->io_ssl_write != NULL)
tss@4538
   231
			break;
tss@4538
   232
		proxy->io_ssl_write = io_add(proxy->fd_ssl, IO_WRITE,
tss@4538
   233
					     ssl_step, proxy);
tss@4538
   234
		break;
tss@4538
   235
	case SSL_REMOVE_OUTPUT:
tss@4538
   236
		if (proxy->io_ssl_write != NULL)
tss@4538
   237
			io_remove(&proxy->io_ssl_write);
tss@4538
   238
		break;
tss@4538
   239
	}
tss@4538
   240
}
tss@4538
   241
tss@4538
   242
static void plain_block_input(struct ssl_proxy *proxy, bool block)
tss@4538
   243
{
tss@4538
   244
	if (block) {
tss@4538
   245
		if (proxy->io_plain_read != NULL)
tss@4538
   246
			io_remove(&proxy->io_plain_read);
tss@4538
   247
	} else {
tss@4538
   248
		if (proxy->io_plain_read == NULL) {
tss@4538
   249
			proxy->io_plain_read = io_add(proxy->fd_plain, IO_READ,
tss@4538
   250
						      plain_read, proxy);
tss@4538
   251
		}
tss@4538
   252
	}
tss@4538
   253
}
tss@4538
   254
tss@4907
   255
static void plain_read(struct ssl_proxy *proxy)
tss@4538
   256
{
tss@4538
   257
	ssize_t ret;
tss@4538
   258
	bool corked = FALSE;
tss@4538
   259
tss@4538
   260
	if (proxy->sslout_size == sizeof(proxy->sslout_buf)) {
tss@4538
   261
		/* buffer full, block input until it's written */
tss@4538
   262
		plain_block_input(proxy, TRUE);
tss@4538
   263
		return;
tss@4538
   264
	}
tss@4538
   265
tss@4538
   266
	proxy->refcount++;
tss@4538
   267
tss@4538
   268
	while (proxy->sslout_size < sizeof(proxy->sslout_buf) &&
tss@4538
   269
	       !proxy->destroyed) {
tss@4538
   270
		ret = net_receive(proxy->fd_plain,
tss@4538
   271
				  proxy->sslout_buf + proxy->sslout_size,
tss@4538
   272
				  sizeof(proxy->sslout_buf) -
tss@4538
   273
				  proxy->sslout_size);
tss@4538
   274
		if (ret <= 0) {
tss@4538
   275
			if (ret < 0)
tss@4538
   276
				ssl_proxy_destroy(proxy);
tss@4538
   277
			break;
tss@4538
   278
		} else {
tss@4538
   279
			proxy->sslout_size += ret;
tss@4538
   280
			if (!corked) {
tss@4538
   281
				net_set_cork(proxy->fd_ssl, TRUE);
tss@4538
   282
				corked = TRUE;
tss@4538
   283
			}
tss@4538
   284
			ssl_write(proxy);
tss@4538
   285
		}
tss@4538
   286
	}
tss@4538
   287
tss@4538
   288
	if (corked)
tss@4538
   289
		net_set_cork(proxy->fd_ssl, FALSE);
tss@4538
   290
tss@4538
   291
	ssl_proxy_unref(proxy);
tss@4538
   292
}
tss@4538
   293
tss@4907
   294
static void plain_write(struct ssl_proxy *proxy)
tss@4538
   295
{
tss@4538
   296
	ssize_t ret;
tss@4538
   297
tss@4538
   298
	proxy->refcount++;
tss@4538
   299
tss@4538
   300
	ret = net_transmit(proxy->fd_plain, proxy->plainout_buf,
tss@4538
   301
			   proxy->plainout_size);
tss@4538
   302
	if (ret < 0)
tss@4538
   303
		ssl_proxy_destroy(proxy);
tss@4538
   304
	else {
tss@4538
   305
		proxy->plainout_size -= ret;
tss@4538
   306
		memmove(proxy->plainout_buf, proxy->plainout_buf + ret,
tss@4538
   307
			proxy->plainout_size);
tss@4538
   308
tss@4538
   309
		if (proxy->plainout_size > 0) {
tss@4538
   310
			if (proxy->io_plain_write == NULL) {
tss@4538
   311
				proxy->io_plain_write =
tss@4538
   312
					io_add(proxy->fd_plain, IO_WRITE,
tss@4538
   313
					       plain_write, proxy);
tss@4538
   314
			}
tss@4538
   315
		} else {
tss@4538
   316
			if (proxy->io_plain_write != NULL)
tss@4538
   317
				io_remove(&proxy->io_plain_write);
tss@4538
   318
		}
tss@4538
   319
tss@4538
   320
		ssl_set_io(proxy, SSL_ADD_INPUT);
tss@4538
   321
		if (SSL_pending(proxy->ssl) > 0)
tss@4538
   322
			ssl_read(proxy);
tss@4538
   323
	}
tss@4538
   324
tss@4538
   325
	ssl_proxy_unref(proxy);
tss@4538
   326
}
tss@4538
   327
tss@1049
   328
static const char *ssl_last_error(void)
tss@1049
   329
{
tss@1049
   330
	unsigned long err;
tss@1049
   331
	char *buf;
tss@1049
   332
	size_t err_size = 256;
tss@1049
   333
tss@1049
   334
	err = ERR_get_error();
tss@7508
   335
	if (err == 0) {
tss@7508
   336
		if (errno != 0)
tss@7508
   337
			return strerror(errno);
tss@7508
   338
		return "Unknown error";
tss@7508
   339
	}
tss@1049
   340
tss@1049
   341
	buf = t_malloc(err_size);
tss@1049
   342
	buf[err_size-1] = '\0';
tss@1049
   343
	ERR_error_string_n(err, buf, err_size-1);
tss@1049
   344
	return buf;
tss@1049
   345
}
tss@1049
   346
tss@4538
   347
static void ssl_handle_error(struct ssl_proxy *proxy, int ret,
tss@4538
   348
			     const char *func_name)
tss@1049
   349
{
tss@7374
   350
	const char *errstr = NULL;
tss@1235
   351
	int err;
tss@1235
   352
tss@7374
   353
	proxy->refcount++;
tss@7374
   354
tss@7374
   355
	i_free_and_null(proxy->last_error);
tss@1235
   356
	err = SSL_get_error(proxy->ssl, ret);
tss@1049
   357
tss@1049
   358
	switch (err) {
tss@1049
   359
	case SSL_ERROR_WANT_READ:
tss@4538
   360
		ssl_set_io(proxy, SSL_ADD_INPUT);
tss@1049
   361
		break;
tss@1049
   362
	case SSL_ERROR_WANT_WRITE:
tss@4538
   363
		ssl_set_io(proxy, SSL_ADD_OUTPUT);
tss@1049
   364
		break;
tss@1049
   365
	case SSL_ERROR_SYSCALL:
tss@1049
   366
		/* eat up the error queue */
tss@7374
   367
		if (ERR_peek_error() != 0)
tss@7374
   368
			errstr = ssl_last_error();
tss@7374
   369
		else if (ret != 0)
tss@7374
   370
			errstr = strerror(errno);
tss@7374
   371
		else {
tss@7374
   372
			/* EOF. */
tss@7374
   373
			errstr = "Disconnected";
tss@7374
   374
			break;
tss@1235
   375
		}
tss@7374
   376
		errstr = t_strdup_printf("%s syscall failed: %s",
tss@7374
   377
					 func_name, errstr);
tss@1049
   378
		break;
tss@1049
   379
	case SSL_ERROR_ZERO_RETURN:
tss@1049
   380
		/* clean connection closing */
tss@1049
   381
		ssl_proxy_destroy(proxy);
tss@1049
   382
		break;
tss@1049
   383
	case SSL_ERROR_SSL:
tss@9305
   384
		if (ERR_GET_REASON(ERR_peek_error()) == ERR_R_MALLOC_FAILURE) {
tss@9288
   385
			i_error("OpenSSL malloc() failed. "
tss@9288
   386
				"You may need to increase login_process_size");
tss@9288
   387
		}
tss@7374
   388
		errstr = t_strdup_printf("%s failed: %s",
tss@7374
   389
					 func_name, ssl_last_error());
tss@1049
   390
		break;
tss@1049
   391
	default:
tss@7374
   392
		errstr = t_strdup_printf("%s failed: unknown failure %d (%s)",
tss@7374
   393
					 func_name, err, ssl_last_error());
tss@1049
   394
		break;
tss@1049
   395
	}
tss@7374
   396
tss@7374
   397
	if (errstr != NULL) {
tss@7374
   398
		proxy->last_error = i_strdup(errstr);
tss@7374
   399
		ssl_proxy_destroy(proxy);
tss@7374
   400
	}
tss@7374
   401
	ssl_proxy_unref(proxy);
tss@1049
   402
}
tss@1049
   403
tss@4538
   404
static void ssl_handshake(struct ssl_proxy *proxy)
tss@1049
   405
{
tss@4538
   406
	int ret;
tss@1049
   407
tss@8985
   408
	if (proxy->client) {
tss@8985
   409
		ret = SSL_connect(proxy->ssl);
tss@8985
   410
		if (ret != 1) {
tss@8985
   411
			ssl_handle_error(proxy, ret, "SSL_connect()");
tss@8985
   412
			return;
tss@8985
   413
		}
tss@8985
   414
	} else {
tss@8985
   415
		ret = SSL_accept(proxy->ssl);
tss@8985
   416
		if (ret != 1) {
tss@8985
   417
			ssl_handle_error(proxy, ret, "SSL_accept()");
tss@8985
   418
			return;
tss@8985
   419
		}
tss@8985
   420
	}
tss@8985
   421
	i_free_and_null(proxy->last_error);
tss@8985
   422
	proxy->handshaked = TRUE;
tss@4538
   423
tss@8985
   424
	ssl_set_io(proxy, SSL_ADD_INPUT);
tss@8985
   425
	plain_block_input(proxy, FALSE);
tss@8985
   426
tss@8986
   427
	if (proxy->handshake_callback != NULL) {
tss@8986
   428
		if (proxy->handshake_callback(proxy->handshake_context) < 0)
tss@8986
   429
			ssl_proxy_destroy(proxy);
tss@8986
   430
	}
tss@4538
   431
}
tss@1324
   432
tss@4538
   433
static void ssl_read(struct ssl_proxy *proxy)
tss@4538
   434
{
tss@4538
   435
	int ret;
tss@4538
   436
tss@4538
   437
	while (proxy->plainout_size < sizeof(proxy->plainout_buf) &&
tss@4538
   438
	       !proxy->destroyed) {
tss@4538
   439
		ret = SSL_read(proxy->ssl,
tss@4538
   440
			       proxy->plainout_buf + proxy->plainout_size,
tss@4538
   441
			       sizeof(proxy->plainout_buf) -
tss@4538
   442
			       proxy->plainout_size);
tss@4538
   443
		if (ret <= 0) {
tss@4538
   444
			ssl_handle_error(proxy, ret, "SSL_read()");
tss@4538
   445
			break;
tss@4538
   446
		} else {
tss@7374
   447
			i_free_and_null(proxy->last_error);
tss@4538
   448
			proxy->plainout_size += ret;
tss@4538
   449
			plain_write(proxy);
tss@4131
   450
		}
tss@4127
   451
	}
tss@4127
   452
}
tss@4127
   453
tss@4538
   454
static void ssl_write(struct ssl_proxy *proxy)
tss@4127
   455
{
tss@1049
   456
	int ret;
tss@1049
   457
tss@4538
   458
	ret = SSL_write(proxy->ssl, proxy->sslout_buf, proxy->sslout_size);
tss@4538
   459
	if (ret <= 0)
tss@4538
   460
		ssl_handle_error(proxy, ret, "SSL_write()");
tss@4538
   461
	else {
tss@7374
   462
		i_free_and_null(proxy->last_error);
tss@4538
   463
		proxy->sslout_size -= ret;
tss@4538
   464
		memmove(proxy->sslout_buf, proxy->sslout_buf + ret,
tss@4538
   465
			proxy->sslout_size);
tss@4474
   466
tss@4538
   467
		ssl_set_io(proxy, proxy->sslout_size > 0 ?
tss@4538
   468
			   SSL_ADD_OUTPUT : SSL_REMOVE_OUTPUT);
tss@4538
   469
		plain_block_input(proxy, FALSE);
tss@1049
   470
	}
tss@1049
   471
}
tss@1049
   472
tss@4907
   473
static void ssl_step(struct ssl_proxy *proxy)
tss@1049
   474
{
tss@4538
   475
	proxy->refcount++;
tss@4538
   476
tss@4538
   477
	if (!proxy->handshaked)
tss@4538
   478
		ssl_handshake(proxy);
tss@4538
   479
tss@4538
   480
	if (proxy->handshaked) {
tss@4538
   481
		if (proxy->plainout_size == sizeof(proxy->plainout_buf))
tss@4538
   482
			ssl_set_io(proxy, SSL_REMOVE_INPUT);
tss@4538
   483
		else
tss@4538
   484
			ssl_read(proxy);
tss@4538
   485
tss@4538
   486
		if (proxy->sslout_size == 0)
tss@4538
   487
			ssl_set_io(proxy, SSL_REMOVE_OUTPUT);
tss@4538
   488
		else {
tss@4538
   489
			net_set_cork(proxy->fd_ssl, TRUE);
tss@4538
   490
			ssl_write(proxy);
tss@4538
   491
			net_set_cork(proxy->fd_ssl, FALSE);
tss@4538
   492
		}
tss@4538
   493
	}
tss@4538
   494
tss@4538
   495
	ssl_proxy_unref(proxy);
tss@1049
   496
}
tss@1049
   497
tss@8985
   498
static int ssl_proxy_new_common(SSL_CTX *ssl_ctx, int fd, struct ip_addr *ip,
tss@8985
   499
				struct ssl_proxy **proxy_r)
tss@1049
   500
{
tss@1049
   501
	struct ssl_proxy *proxy;
tss@1049
   502
	SSL *ssl;
tss@1049
   503
	int sfd[2];
tss@1049
   504
tss@4664
   505
	i_assert(fd != -1);
tss@4664
   506
tss@2027
   507
	*proxy_r = NULL;
tss@2027
   508
tss@2679
   509
	if (!ssl_initialized) {
tss@2679
   510
		i_error("SSL support not enabled in configuration");
tss@1049
   511
		return -1;
tss@2679
   512
	}
tss@1049
   513
tss@3888
   514
	ssl_refresh_parameters(&ssl_params);
tss@3888
   515
tss@1049
   516
	ssl = SSL_new(ssl_ctx);
tss@1049
   517
	if (ssl == NULL) {
tss@1049
   518
		i_error("SSL_new() failed: %s", ssl_last_error());
tss@1049
   519
		return -1;
tss@1049
   520
	}
tss@1049
   521
tss@1049
   522
	if (SSL_set_fd(ssl, fd) != 1) {
tss@1049
   523
		i_error("SSL_set_fd() failed: %s", ssl_last_error());
tss@1457
   524
		SSL_free(ssl);
tss@1049
   525
		return -1;
tss@1049
   526
	}
tss@1049
   527
tss@4664
   528
	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) < 0) {
tss@1049
   529
		i_error("socketpair() failed: %m");
tss@1049
   530
		SSL_free(ssl);
tss@1049
   531
		return -1;
tss@1049
   532
	}
tss@1049
   533
tss@1049
   534
	net_set_nonblock(sfd[0], TRUE);
tss@1049
   535
	net_set_nonblock(sfd[1], TRUE);
tss@1268
   536
	net_set_nonblock(fd, TRUE);
tss@1049
   537
tss@1049
   538
	proxy = i_new(struct ssl_proxy, 1);
tss@2027
   539
	proxy->refcount = 2;
tss@1049
   540
	proxy->ssl = ssl;
tss@1049
   541
	proxy->fd_ssl = fd;
tss@1049
   542
	proxy->fd_plain = sfd[0];
tss@1235
   543
	proxy->ip = *ip;
tss@2027
   544
        SSL_set_ex_data(ssl, extdata_index, proxy);
tss@1049
   545
tss@7119
   546
	ssl_proxy_count++;
tss@7119
   547
	DLLIST_PREPEND(&ssl_proxies, proxy);
tss@1544
   548
tss@4474
   549
	main_ref();
tss@1049
   550
tss@2027
   551
	*proxy_r = proxy;
tss@1049
   552
	return sfd[1];
tss@1049
   553
}
tss@1049
   554
tss@8985
   555
int ssl_proxy_new(int fd, struct ip_addr *ip, struct ssl_proxy **proxy_r)
tss@8985
   556
{
tss@8985
   557
	int ret;
tss@8985
   558
tss@8985
   559
	if ((ret = ssl_proxy_new_common(ssl_server_ctx, fd, ip, proxy_r)) < 0)
tss@8985
   560
		return -1;
tss@8985
   561
tss@8985
   562
	ssl_step(*proxy_r);
tss@8985
   563
	return ret;
tss@8985
   564
}
tss@8985
   565
tss@8985
   566
int ssl_proxy_client_new(int fd, struct ip_addr *ip,
tss@8985
   567
			 ssl_handshake_callback_t *callback, void *context,
tss@8985
   568
			 struct ssl_proxy **proxy_r)
tss@8985
   569
{
tss@8985
   570
	int ret;
tss@8985
   571
tss@8985
   572
	if ((ret = ssl_proxy_new_common(ssl_client_ctx, fd, ip, proxy_r)) < 0)
tss@8985
   573
		return -1;
tss@8985
   574
tss@8985
   575
	(*proxy_r)->handshake_callback = callback;
tss@8986
   576
	(*proxy_r)->handshake_context = context;
tss@8985
   577
	(*proxy_r)->client = TRUE;
tss@8985
   578
	ssl_step(*proxy_r);
tss@8985
   579
	return ret;
tss@8985
   580
}
tss@8985
   581
tss@7912
   582
bool ssl_proxy_has_valid_client_cert(const struct ssl_proxy *proxy)
tss@2027
   583
{
tss@2027
   584
	return proxy->cert_received && !proxy->cert_broken;
tss@2027
   585
}
tss@2027
   586
tss@8302
   587
bool ssl_proxy_has_broken_client_cert(struct ssl_proxy *proxy)
tss@8302
   588
{
tss@8302
   589
	return proxy->cert_received && proxy->cert_broken;
tss@8302
   590
}
tss@8302
   591
tss@3635
   592
const char *ssl_proxy_get_peer_name(struct ssl_proxy *proxy)
tss@3635
   593
{
tss@3635
   594
	X509 *x509;
tss@9283
   595
	char *name;
tss@9283
   596
	int len;
tss@3635
   597
tss@3635
   598
	if (!ssl_proxy_has_valid_client_cert(proxy))
tss@3635
   599
		return NULL;
tss@3635
   600
tss@3635
   601
	x509 = SSL_get_peer_certificate(proxy->ssl);
tss@3635
   602
	if (x509 == NULL)
tss@3635
   603
		return NULL; /* we should have had it.. */
tss@3635
   604
tss@9283
   605
	len = X509_NAME_get_text_by_NID(X509_get_subject_name(x509),
tss@9283
   606
					ssl_username_nid, NULL, 0);
tss@9283
   607
	if (len < 0)
tss@4352
   608
		name = "";
tss@9283
   609
	else {
tss@9283
   610
		name = t_malloc(len + 1);
tss@9283
   611
		if (X509_NAME_get_text_by_NID(X509_get_subject_name(x509),
tss@9283
   612
					ssl_username_nid, name, len + 1) < 0)
tss@9283
   613
			name = "";
tss@9283
   614
		else if (strlen(name) != (size_t)len) {
tss@9283
   615
			/* NUL characters in name. Someone's trying to fake
tss@9283
   616
			   being another user? Don't allow it. */
tss@9283
   617
			name = "";
tss@9283
   618
		}
tss@9283
   619
	}
tss@3635
   620
	X509_free(x509);
tss@4352
   621
	
tss@3635
   622
	return *name == '\0' ? NULL : name;
tss@3635
   623
}
tss@3635
   624
tss@7912
   625
bool ssl_proxy_is_handshaked(const struct ssl_proxy *proxy)
tss@4570
   626
{
tss@4570
   627
	return proxy->handshaked;
tss@4570
   628
}
tss@4570
   629
tss@7912
   630
const char *ssl_proxy_get_last_error(const struct ssl_proxy *proxy)
tss@7374
   631
{
tss@7374
   632
	return proxy->last_error;
tss@7374
   633
}
tss@7374
   634
tss@8122
   635
const char *ssl_proxy_get_security_string(struct ssl_proxy *proxy)
tss@8122
   636
{
tss@8122
   637
	SSL_CIPHER *cipher;
tss@9416
   638
#ifdef HAVE_SSL_COMPRESSION
tss@9389
   639
	const COMP_METHOD *comp;
tss@9416
   640
#endif
tss@8122
   641
	int bits, alg_bits;
tss@9389
   642
	const char *comp_str;
tss@8122
   643
tss@8122
   644
	if (!proxy->handshaked)
tss@8122
   645
		return "";
tss@8122
   646
tss@8122
   647
	cipher = SSL_get_current_cipher(proxy->ssl);
tss@8122
   648
	bits = SSL_CIPHER_get_bits(cipher, &alg_bits);
tss@9416
   649
#ifdef HAVE_SSL_COMPRESSION
tss@9389
   650
	comp = SSL_get_current_compression(proxy->ssl);
tss@9389
   651
	comp_str = comp == NULL ? "" :
tss@9389
   652
		t_strconcat(" ", SSL_COMP_get_name(comp), NULL);
tss@9416
   653
#else
tss@9416
   654
	comp_str = NULL;
tss@9416
   655
#endif
tss@9389
   656
	return t_strdup_printf("%s with cipher %s (%d/%d bits)%s",
tss@8122
   657
			       SSL_get_version(proxy->ssl),
tss@8122
   658
			       SSL_CIPHER_get_name(cipher),
tss@9389
   659
			       bits, alg_bits, comp_str);
tss@8122
   660
}
tss@8122
   661
tss@2027
   662
void ssl_proxy_free(struct ssl_proxy *proxy)
tss@2027
   663
{
tss@2027
   664
	ssl_proxy_unref(proxy);
tss@2027
   665
}
tss@2027
   666
tss@3863
   667
static void ssl_proxy_unref(struct ssl_proxy *proxy)
tss@1049
   668
{
tss@1049
   669
	if (--proxy->refcount > 0)
tss@3863
   670
		return;
tss@1490
   671
	i_assert(proxy->refcount == 0);
tss@1049
   672
tss@2302
   673
	SSL_free(proxy->ssl);
tss@2302
   674
	i_free(proxy);
tss@2302
   675
tss@2302
   676
	main_unref();
tss@2302
   677
}
tss@2302
   678
tss@2302
   679
static void ssl_proxy_destroy(struct ssl_proxy *proxy)
tss@2302
   680
{
tss@2302
   681
	if (proxy->destroyed)
tss@2302
   682
		return;
tss@2302
   683
	proxy->destroyed = TRUE;
tss@2302
   684
tss@7119
   685
	ssl_proxy_count--;
tss@7119
   686
	DLLIST_REMOVE(&ssl_proxies, proxy);
tss@1230
   687
tss@4538
   688
	if (proxy->io_ssl_read != NULL)
tss@4538
   689
		io_remove(&proxy->io_ssl_read);
tss@4538
   690
	if (proxy->io_ssl_write != NULL)
tss@4538
   691
		io_remove(&proxy->io_ssl_write);
tss@4538
   692
	if (proxy->io_plain_read != NULL)
tss@4538
   693
		io_remove(&proxy->io_plain_read);
tss@4538
   694
	if (proxy->io_plain_write != NULL)
tss@4538
   695
		io_remove(&proxy->io_plain_write);
tss@1049
   696
tss@7346
   697
	(void)SSL_shutdown(proxy->ssl);
tss@7346
   698
tss@3960
   699
	(void)net_disconnect(proxy->fd_ssl);
tss@3960
   700
	(void)net_disconnect(proxy->fd_plain);
tss@3960
   701
tss@2302
   702
	ssl_proxy_unref(proxy);
tss@4538
   703
tss@4538
   704
	main_listen_start();
tss@1458
   705
}
tss@1458
   706
tss@6411
   707
static RSA *ssl_gen_rsa_key(SSL *ssl ATTR_UNUSED,
tss@6411
   708
			    int is_export ATTR_UNUSED, int keylength)
tss@1492
   709
{
tss@1492
   710
	return RSA_generate_key(keylength, RSA_F4, NULL, NULL);
tss@1492
   711
}
tss@1492
   712
tss@6411
   713
static DH *ssl_tmp_dh_callback(SSL *ssl ATTR_UNUSED,
tss@3888
   714
			       int is_export, int keylength)
tss@3888
   715
{
tss@3888
   716
	/* Well, I'm not exactly sure why the logic in here is this.
tss@3888
   717
	   It's the same as in Postfix, so it can't be too wrong. */
tss@3888
   718
	if (is_export && keylength == 512 && ssl_params.dh_512 != NULL)
tss@3888
   719
		return ssl_params.dh_512;
tss@3888
   720
tss@3888
   721
	return ssl_params.dh_1024;
tss@3888
   722
}
tss@3888
   723
tss@4471
   724
static void ssl_info_callback(const SSL *ssl, int where, int ret)
tss@4471
   725
{
tss@4471
   726
	struct ssl_proxy *proxy;
tss@4471
   727
tss@4471
   728
	proxy = SSL_get_ex_data(ssl, extdata_index);
tss@4471
   729
tss@4471
   730
	if ((where & SSL_CB_ALERT) != 0) {
tss@4471
   731
		i_warning("SSL alert: where=0x%x, ret=%d: %s %s [%s]",
tss@4471
   732
			  where, ret, SSL_alert_type_string_long(ret),
tss@4471
   733
			  SSL_alert_desc_string_long(ret),
tss@4471
   734
			  net_ip2addr(&proxy->ip));
tss@4471
   735
	} else {
tss@4471
   736
		i_warning("SSL BIO failed: where=0x%x, ret=%d: %s [%s]",
tss@4471
   737
			  where, ret, SSL_state_string_long(ssl),
tss@4471
   738
			  net_ip2addr(&proxy->ip));
tss@4471
   739
	}
tss@4471
   740
}
tss@4471
   741
tss@2027
   742
static int ssl_verify_client_cert(int preverify_ok, X509_STORE_CTX *ctx)
tss@2027
   743
{
tss@2027
   744
	SSL *ssl;
tss@2027
   745
        struct ssl_proxy *proxy;
tss@2027
   746
tss@2027
   747
	ssl = X509_STORE_CTX_get_ex_data(ctx,
tss@2027
   748
					 SSL_get_ex_data_X509_STORE_CTX_idx());
tss@2027
   749
	proxy = SSL_get_ex_data(ssl, extdata_index);
tss@4352
   750
	proxy->cert_received = TRUE;
tss@2027
   751
tss@4352
   752
	if (verbose_ssl || (verbose_auth && !preverify_ok)) {
tss@4352
   753
		char buf[1024];
tss@4352
   754
		X509_NAME *subject;
tss@4352
   755
tss@4352
   756
		subject = X509_get_subject_name(ctx->current_cert);
tss@4352
   757
		(void)X509_NAME_oneline(subject, buf, sizeof(buf));
tss@4352
   758
		buf[sizeof(buf)-1] = '\0'; /* just in case.. */
tss@4352
   759
		if (!preverify_ok)
tss@4695
   760
			i_info("Invalid certificate: %s: %s", X509_verify_cert_error_string(ctx->error),buf);
tss@4352
   761
		else
tss@4352
   762
			i_info("Valid certificate: %s", buf);
tss@4352
   763
	}
tss@2027
   764
	if (!preverify_ok)
tss@2027
   765
		proxy->cert_broken = TRUE;
tss@2027
   766
tss@4352
   767
	/* Return success anyway, because if ssl_require_client_cert=no we
tss@4352
   768
	   could still allow authentication. */
tss@2027
   769
	return 1;
tss@2027
   770
}
tss@2027
   771
tss@3889
   772
static int
tss@6411
   773
pem_password_callback(char *buf, int size, int rwflag ATTR_UNUSED,
tss@3889
   774
		      void *userdata)
tss@3889
   775
{
tss@3889
   776
	if (userdata == NULL) {
tss@3889
   777
		i_error("SSL private key file is password protected, "
tss@3889
   778
			"but password isn't given");
tss@3889
   779
		return 0;
tss@3889
   780
	}
tss@3889
   781
tss@6422
   782
	if (i_strocpy(buf, userdata, size) < 0)
tss@3889
   783
		return 0;
tss@3889
   784
	return strlen(buf);
tss@3889
   785
}
tss@3889
   786
tss@4538
   787
unsigned int ssl_proxy_get_count(void)
tss@4538
   788
{
tss@7119
   789
	return ssl_proxy_count;
tss@4538
   790
}
tss@4538
   791
tss@8224
   792
static bool is_pem_key_file(const char *path)
tss@8224
   793
{
tss@8224
   794
	char buf[4096];
tss@8224
   795
	int fd, ret;
tss@8224
   796
tss@8224
   797
	/* this code is used only for giving a better error message,
tss@8224
   798
	   so it needs to catch only the normal key files */
tss@8224
   799
	fd = open(path, O_RDONLY);
tss@8224
   800
	if (fd == -1)
tss@8224
   801
		return FALSE;
tss@8224
   802
	ret = read(fd, buf, sizeof(buf)-1);
tss@8224
   803
	close(fd);
tss@8224
   804
	if (ret <= 0)
tss@8224
   805
		return FALSE;
tss@8224
   806
	buf[ret] = '\0';
tss@8224
   807
	return strstr(buf, "PRIVATE KEY---") != NULL;
tss@8224
   808
}
tss@8224
   809
tss@8985
   810
static void ssl_proxy_ctx_init(SSL_CTX *ssl_ctx)
tss@1049
   811
{
tss@8985
   812
	const char *cafile;
tss@1049
   813
tss@1544
   814
	SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL);
tss@1544
   815
tss@8985
   816
	cafile = getenv("SSL_CA_FILE");
tss@1907
   817
	if (cafile != NULL) {
tss@1907
   818
		if (SSL_CTX_load_verify_locations(ssl_ctx, cafile, NULL) != 1) {
tss@1907
   819
			i_fatal("Can't load CA file %s: %s",
tss@1907
   820
				cafile, ssl_last_error());
tss@1907
   821
		}
tss@1907
   822
	}
tss@8985
   823
	if (verbose_ssl)
tss@8985
   824
		SSL_CTX_set_info_callback(ssl_ctx, ssl_info_callback);
tss@8985
   825
	if (SSL_CTX_need_tmp_RSA(ssl_ctx))
tss@8985
   826
		SSL_CTX_set_tmp_rsa_callback(ssl_ctx, ssl_gen_rsa_key);
tss@8985
   827
	SSL_CTX_set_tmp_dh_callback(ssl_ctx, ssl_tmp_dh_callback);
tss@8985
   828
}
tss@1907
   829
tss@8985
   830
static void ssl_proxy_ctx_verify_client(SSL_CTX *ssl_ctx)
tss@8985
   831
{
tss@8985
   832
	const char *cafile;
tss@8985
   833
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
tss@8985
   834
	X509_STORE *store;
tss@8985
   835
tss@8985
   836
	store = SSL_CTX_get_cert_store(ssl_ctx);
tss@8985
   837
	X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
tss@8985
   838
			     X509_V_FLAG_CRL_CHECK_ALL);
tss@8985
   839
#endif
tss@8985
   840
	cafile = getenv("SSL_CA_FILE");
tss@8985
   841
	SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE,
tss@8985
   842
			   ssl_verify_client_cert);
tss@8985
   843
	SSL_CTX_set_client_CA_list(ssl_ctx, SSL_load_client_CA_file(cafile));
tss@8985
   844
}
tss@8985
   845
tss@8985
   846
static void ssl_proxy_init_server(const char *certfile, const char *keyfile)
tss@8985
   847
{
tss@8985
   848
	const char *cipher_list, *username_field;
tss@8985
   849
	char *password;
tss@8985
   850
	unsigned long err;
tss@8985
   851
tss@8985
   852
	password = getenv("SSL_KEY_PASSWORD");
tss@8985
   853
tss@8985
   854
	if ((ssl_server_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL)
tss@8985
   855
		i_fatal("SSL_CTX_new() failed");
tss@8985
   856
	ssl_proxy_ctx_init(ssl_server_ctx);
tss@8985
   857
tss@8985
   858
	cipher_list = getenv("SSL_CIPHER_LIST");
tss@8985
   859
	if (cipher_list == NULL)
tss@8985
   860
		cipher_list = DOVECOT_SSL_DEFAULT_CIPHER_LIST;
tss@8985
   861
	if (SSL_CTX_set_cipher_list(ssl_server_ctx, cipher_list) != 1) {
tss@8985
   862
		i_fatal("Can't set cipher list to '%s': %s",
tss@8985
   863
			cipher_list, ssl_last_error());
tss@8985
   864
	}
tss@8985
   865
tss@8985
   866
	if (SSL_CTX_use_certificate_chain_file(ssl_server_ctx, certfile) != 1) {
tss@8224
   867
		err = ERR_peek_error();
tss@8224
   868
		if (ERR_GET_LIB(err) != ERR_LIB_PEM ||
tss@8224
   869
		    ERR_GET_REASON(err) != PEM_R_NO_START_LINE) {
tss@8224
   870
			i_fatal("Can't load certificate file %s: %s",
tss@8224
   871
				certfile, ssl_last_error());
tss@8224
   872
		} else if (is_pem_key_file(certfile)) {
tss@8224
   873
			i_fatal("Can't load certificate file %s: "
tss@8224
   874
				"The file contains a private key "
tss@8224
   875
				"(you've mixed ssl_cert_file and ssl_key_file settings)",
tss@8224
   876
				certfile);
tss@8224
   877
		} else {
tss@8224
   878
			i_fatal("Can't load certificate file %s: "
tss@8224
   879
				"The file doesn't contain a certificate.",
tss@8224
   880
				certfile);
tss@8224
   881
		}
tss@1049
   882
	}
tss@1049
   883
tss@8985
   884
        SSL_CTX_set_default_passwd_cb(ssl_server_ctx, pem_password_callback);
tss@8985
   885
        SSL_CTX_set_default_passwd_cb_userdata(ssl_server_ctx, password);
tss@8985
   886
	if (SSL_CTX_use_PrivateKey_file(ssl_server_ctx, keyfile,
tss@3584
   887
					SSL_FILETYPE_PEM) != 1) {
tss@9394
   888
		err = ERR_peek_error();
tss@9394
   889
		if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
tss@9394
   890
		    ERR_GET_REASON(err) == X509_R_KEY_VALUES_MISMATCH) {
tss@9394
   891
			i_fatal("Can't load private key file %s: "
tss@9394
   892
				"Key is for a different cert than %s",
tss@9394
   893
				keyfile, certfile);
tss@9394
   894
		} else {
tss@9394
   895
			i_fatal("Can't load private key file %s: %s",
tss@9394
   896
				keyfile, ssl_last_error());
tss@9394
   897
		}
tss@1049
   898
	}
tss@1049
   899
tss@8985
   900
	if (getenv("SSL_VERIFY_CLIENT_CERT") != NULL)
tss@8985
   901
		ssl_proxy_ctx_verify_client(ssl_server_ctx);
tss@1997
   902
tss@6364
   903
	username_field = getenv("SSL_CERT_USERNAME_FIELD");
tss@6364
   904
	if (username_field == NULL)
tss@6364
   905
		ssl_username_nid = NID_commonName;
tss@6364
   906
	else {
tss@6364
   907
		ssl_username_nid = OBJ_txt2nid(username_field);
tss@6364
   908
		if (ssl_username_nid == NID_undef) {
tss@6364
   909
			i_fatal("Invalid ssl_cert_username_field: %s",
tss@6364
   910
				username_field);
tss@6364
   911
		}
tss@6364
   912
	}
tss@8985
   913
}
tss@8985
   914
tss@8985
   915
static void ssl_proxy_init_client(void)
tss@8985
   916
{
tss@8985
   917
	if ((ssl_client_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL)
tss@8985
   918
		i_fatal("SSL_CTX_new() failed");
tss@8985
   919
	ssl_proxy_ctx_init(ssl_client_ctx);
tss@8985
   920
	ssl_proxy_ctx_verify_client(ssl_client_ctx);
tss@8985
   921
}
tss@8985
   922
tss@8985
   923
void ssl_proxy_init(void)
tss@8985
   924
{
tss@8985
   925
	static char dovecot[] = "dovecot";
tss@8985
   926
	const char *certfile, *keyfile;
tss@8985
   927
	unsigned char buf;
tss@8985
   928
tss@8985
   929
	memset(&ssl_params, 0, sizeof(ssl_params));
tss@8985
   930
tss@8985
   931
	certfile = getenv("SSL_CERT_FILE");
tss@8985
   932
	keyfile = getenv("SSL_KEY_FILE");
tss@8985
   933
	ssl_params.fname = getenv("SSL_PARAM_FILE");
tss@8985
   934
tss@8985
   935
	if (certfile == NULL || keyfile == NULL || ssl_params.fname == NULL) {
tss@8985
   936
		/* SSL support is disabled */
tss@8985
   937
		return;
tss@8985
   938
	}
tss@8985
   939
tss@8985
   940
	SSL_library_init();
tss@8985
   941
	SSL_load_error_strings();
tss@8985
   942
tss@8985
   943
	extdata_index = SSL_get_ex_new_index(0, dovecot, NULL, NULL, NULL);
tss@8985
   944
	ssl_proxy_init_server(certfile, keyfile);
tss@8985
   945
	ssl_proxy_init_client();
tss@6364
   946
tss@1556
   947
	/* PRNG initialization might want to use /dev/urandom, make sure it
tss@2007
   948
	   does it before chrooting. We might not have enough entropy at
tss@2007
   949
	   the first try, so this function may fail. It's still been
tss@2007
   950
	   initialized though. */
tss@2007
   951
	(void)RAND_bytes(&buf, 1);
tss@1556
   952
tss@7119
   953
	ssl_proxy_count = 0;
tss@7119
   954
        ssl_proxies = NULL;
tss@1049
   955
	ssl_initialized = TRUE;
tss@1049
   956
}
tss@1049
   957
tss@1049
   958
void ssl_proxy_deinit(void)
tss@1049
   959
{
tss@1230
   960
	if (!ssl_initialized)
tss@1230
   961
		return;
tss@1230
   962
tss@7119
   963
	while (ssl_proxies != NULL)
tss@7119
   964
		ssl_proxy_destroy(ssl_proxies);
tss@1232
   965
tss@3888
   966
	ssl_free_parameters(&ssl_params);
tss@8985
   967
	SSL_CTX_free(ssl_server_ctx);
tss@8985
   968
	SSL_CTX_free(ssl_client_ctx);
tss@7500
   969
	EVP_cleanup();
tss@7500
   970
	ERR_free_strings();
tss@1049
   971
}
tss@1049
   972
tss@1049
   973
#endif