6
/* Postfix TLS session cache and PRNG handling manager
8
/* \fBtlsmgr\fR [generic Postfix daemon options]
10
/* The tlsmgr process does housekeeping on the session cache database
11
/* files. It runs through the databases and removes expired entries
12
/* and entries written by older (incompatible) versions.
14
/* The tlsmgr is responsible for the PRNG handling. The used internal
15
/* OpenSSL PRNG has a pool size of 8192 bits (= 1024 bytes). The pool
16
/* is initially seeded at startup from an external source (EGD or
17
/* /dev/urandom) and additional seed is obtained later during program
18
/* run at a configurable period. The exact time of seed query is
19
/* using random information and is equally distributed in the range of
20
/* [0-\fBtls_random_reseed_period\fR] with a \fBtls_random_reseed_period\fR
21
/* having a default of 1 hour.
23
/* Tlsmgr can be run chrooted and with dropped privileges, as it will
24
/* connect to the entropy source at startup.
26
/* The PRNG is additionally seeded internally by the data found in the
27
/* session cache and timevalues.
29
/* Tlsmgr reads the old value of the exchange file at startup to keep
30
/* entropy already collected during previous runs.
32
/* From the PRNG random pool a cryptographically strong 1024 byte random
33
/* sequence is written into the PRNG exchange file. The file is updated
34
/* periodically with the time changing randomly from
35
/* [0-\fBtls_random_prng_update_period\fR].
40
/* Tlsmgr is not security-sensitive. It only deals with external data
41
/* to be fed into the PRNG, the contents is never trusted. The session
42
/* cache housekeeping will only remove entries if expired and will never
43
/* touch the contents of the cached data.
45
/* Problems and transactions are logged to the syslog daemon.
47
/* There is no automatic means to limit the number of entries in the
48
/* session caches and/or the size of the session cache files.
49
/* CONFIGURATION PARAMETERS
52
/* The following \fBmain.cf\fR parameters are especially relevant to
53
/* this program. See the Postfix \fBmain.cf\fR file for syntax details
54
/* and for default values. Use the \fBpostfix reload\fR command after
55
/* a configuration change.
59
/* .IP \fBsmtpd_tls_session_cache_database\fR
60
/* Name of the SDBM file (type sdbm:) containing the SMTP server session
61
/* cache. If the file does not exist, it is created.
62
/* .IP \fBsmtpd_tls_session_cache_timeout\fR
63
/* Expiry time of SMTP server session cache entries in seconds. Entries
64
/* older than this are removed from the session cache. A cleanup-run is
65
/* performed periodically every \fBsmtpd_tls_session_cache_timeout\fR
66
/* seconds. Default is 3600 (= 1 hour).
67
/* .IP \fBsmtp_tls_session_cache_database\fR
68
/* Name of the SDBM file (type sdbm:) containing the SMTP client session
69
/* cache. If the file does not exist, it is created.
70
/* .IP \fBsmtp_tls_session_cache_timeout\fR
71
/* Expiry time of SMTP client session cache entries in seconds. Entries
72
/* older than this are removed from the session cache. A cleanup-run is
73
/* performed periodically every \fBsmtp_tls_session_cache_timeout\fR
74
/* seconds. Default is 3600 (= 1 hour).
75
/* .SH Pseudo Random Number Generator
78
/* .IP \fBtls_random_source\fR
79
/* Name of the EGD socket or device or regular file to obtain entropy
80
/* from. The type of entropy source must be specified by preceding the
81
/* name with the appropriate type: egd:/path/to/egd_socket,
82
/* dev:/path/to/devicefile, or /path/to/regular/file.
83
/* tlsmgr opens \fBtls_random_source\fR and tries to read
84
/* \fBtls_random_bytes\fR from it.
85
/* .IP \fBtls_random_bytes\fR
86
/* Number of bytes to be read from \fBtls_random_source\fR.
87
/* Default value is 32 bytes. If using EGD, a maximum of 255 bytes is read.
88
/* .IP \fBtls_random_exchange_name\fR
89
/* Name of the file written by tlsmgr and read by smtp and smtpd at
90
/* startup. The length is 1024 bytes. Default value is
91
/* /etc/postfix/prng_exch.
92
/* .IP \fBtls_random_reseed_period\fR
93
/* Time in seconds until the next reseed from external sources is due.
94
/* This is the maximum value. The actual point in time is calculated
95
/* with a random factor equally distributed between 0 and this maximum
96
/* value. Default is 3600 (= 60 minutes).
97
/* .IP \fBtls_random_prng_update_period\fR
98
/* Time in seconds until the PRNG exchange file is updated with new
99
/* pseude random values. This is the maximum value. The actual point
100
/* in time is calculated with a random factor equally distributed
101
/* between 0 and this maximum value. Default is 60 (= 1 minute).
103
/* smtp(8) SMTP client
104
/* smtpd(8) SMTP server
108
/* The Secure Mailer license must be distributed with this software.
112
/* System library. */
114
#include <sys_defs.h>
120
#include <sys/time.h> /* gettimeofday, not POSIX */
122
/* OpenSSL library. */
124
#include <openssl/rand.h> /* For the PRNG */
127
/* Utility library. */
132
#include <stringops.h>
133
#include <mymalloc.h>
137
/* Global library. */
139
#include <mail_conf.h>
140
#include <mail_params.h>
143
/* Master process interface */
145
#include <master_proto.h>
146
#include <mail_server.h>
148
/* Application-specific. */
154
char *var_tls_rand_source;
155
int var_tls_rand_bytes;
156
int var_tls_reseed_period;
157
int var_tls_prng_upd_period;
159
static int rand_exch_fd;
160
static int rand_source_dev_fd = -1;
161
static int rand_source_socket_fd = -1;
162
static int srvr_scache_db_active;
163
static int clnt_scache_db_active;
164
static DICT *srvr_scache_db = NULL;
165
static DICT *clnt_scache_db = NULL;
167
static void tlsmgr_prng_upd_event(int unused_event, char *dummy)
170
unsigned char buffer[1024];
174
* It is time to update the PRNG exchange file. Since other processes might
175
* have added entropy, we do this in a read_stir-back_write cycle.
178
RAND_seed(&tv, sizeof(struct timeval));
180
if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) != 0)
181
msg_fatal("Could not lock random exchange file: %s",
184
lseek(rand_exch_fd, 0, SEEK_SET);
185
if (read(rand_exch_fd, buffer, 1024) < 0)
186
msg_fatal("reading exchange file failed");
187
RAND_seed(buffer, 1024);
189
RAND_bytes(buffer, 1024);
190
lseek(rand_exch_fd, 0, SEEK_SET);
191
if (write(rand_exch_fd, buffer, 1024) != 1024)
192
msg_fatal("Writing exchange file failed");
194
if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) != 0)
195
msg_fatal("Could not unlock random exchange file: %s",
199
* Make prediction difficult for outsiders and calculate the time for the
200
* next execution randomly.
202
next_period = (var_tls_prng_upd_period * buffer[0]) / 255;
203
event_request_timer(tlsmgr_prng_upd_event, dummy, next_period);
207
static void tlsmgr_reseed_event(int unused_event, char *dummy)
214
unsigned char randbyte;
217
* It is time to reseed the PRNG.
221
RAND_seed(&tv, sizeof(struct timeval));
222
if (rand_source_dev_fd != -1) {
223
rand_bytes = read(rand_source_dev_fd, buffer, var_tls_rand_bytes);
225
RAND_seed(buffer, rand_bytes);
226
else if (rand_bytes < 0) {
227
msg_fatal("Read from entropy device %s failed",
228
var_tls_rand_source);
230
} else if (rand_source_socket_fd != -1) {
233
buffer[1] = var_tls_rand_bytes;
234
if (write(rand_source_socket_fd, buffer, 2) != 2)
235
msg_info("Could not talk to %s", var_tls_rand_source);
236
else if (read(rand_source_socket_fd, buffer, 1) != 1)
237
msg_info("Could not read info from %s", var_tls_rand_source);
239
rand_bytes = buffer[0];
240
if (read(rand_source_socket_fd, buffer, rand_bytes) != rand_bytes)
241
msg_info("Could not read data from %s", var_tls_rand_source);
244
RAND_seed(buffer, rand_bytes);
248
msg_info("Lost connection to EGD-device, exiting to reconnect.");
251
} else if (*var_tls_rand_source) {
252
rand_bytes = RAND_load_file(var_tls_rand_source, var_tls_rand_bytes);
256
* Make prediction difficult for outsiders and calculate the time for the
257
* next execution randomly.
259
RAND_bytes(&randbyte, 1);
260
next_period = (var_tls_reseed_period * randbyte) / 255;
261
event_request_timer(tlsmgr_reseed_event, dummy, next_period);
265
static int tlsmgr_do_scache_check(DICT *scache_db, int scache_timeout,
277
unsigned char nibble, *data;
278
pfixtls_scache_info_t scache_info;
281
RAND_seed(&tv, sizeof(struct timeval));
284
* Run through the given dictionary and check the stored sessions.
285
* If "start" is set to 1, a new run is initiated, otherwise the next
286
* item is accessed. The state is internally kept in the DICT.
289
func = DICT_SEQ_FUN_FIRST;
291
func = DICT_SEQ_FUN_NEXT;
292
result = dict_seq(scache_db, func, &member, &value);
295
return 0; /* End of list reached */
297
msg_fatal("Database fault, should already be caught.");
299
member_copy = mystrdup(member);
301
RAND_seed(value, len); /* Use it to increase entropy */
302
if (len < 2 * sizeof(pfixtls_scache_info_t))
303
delete = 1; /* Messed up, delete */
304
else if (len > 2 * sizeof(pfixtls_scache_info_t))
305
len = 2 * sizeof(pfixtls_scache_info_t);
307
data = (unsigned char *)(&scache_info);
308
memset(data, 0, len / 2);
309
for (n = 0; n < len; n++) {
310
if ((value[n] >= '0') && (value[n] <= '9'))
311
nibble = value[n] - '0';
313
nibble = value[n] - 'A' + 10;
315
data[n / 2] |= nibble;
317
data[n / 2] |= (nibble << 4);
320
if ((scache_info.scache_db_version != scache_db_version) ||
321
(scache_info.openssl_version != openssl_version) ||
322
(scache_info.timestamp + scache_timeout < time(NULL)))
326
result = dict_del(scache_db, member_copy);
330
if (delete && result)
331
msg_info("Could not delete %s", member);
336
static void tlsmgr_clnt_cache_run_event(int unused_event, char *dummy)
340
* This routine runs when it is time for another tls session cache scan.
341
* Make sure this routine gets called again in the future.
343
clnt_scache_db_active = tlsmgr_do_scache_check(clnt_scache_db,
344
var_smtp_tls_scache_timeout, 1);
345
event_request_timer(tlsmgr_clnt_cache_run_event, dummy,
346
var_smtp_tls_scache_timeout);
350
static void tlsmgr_srvr_cache_run_event(int unused_event, char *dummy)
354
* This routine runs when it is time for another tls session cache scan.
355
* Make sure this routine gets called again in the future.
357
srvr_scache_db_active = tlsmgr_do_scache_check(srvr_scache_db,
358
var_smtpd_tls_scache_timeout, 1);
359
event_request_timer(tlsmgr_srvr_cache_run_event, dummy,
360
var_smtpd_tls_scache_timeout);
364
static DICT *tlsmgr_cache_open(const char *dbname)
371
* First, try to find out the real name of the database file, so that
374
if (!strncmp(dbname, "sdbm:", 5)) {
375
dbpagname = concatenate(dbname + 5, ".pag", NULL);
378
dbdirname = concatenate(dbname + 5, ".dir", NULL);
383
msg_warn("Only type sdbm: supported: %s", dbname);
388
* Now open the dictionary. Do it with O_EXCL, so that we only open a
389
* fresh file. If we cannot open it with a fresh file, then we won't
392
retval = dict_open(dbname, O_RDWR | O_CREAT | O_EXCL,
393
DICT_FLAG_DUP_REPLACE | DICT_FLAG_LOCK | DICT_FLAG_SYNC_UPDATE);
395
msg_warn("Could not create dictionary %s", dbname);
399
/* tlsmgr_trigger_event - respond to external trigger(s) */
401
static void tlsmgr_trigger_event(char *buf, int len,
402
char *unused_service, char **argv)
405
* Sanity check. This service takes no command-line arguments.
408
msg_fatal("unexpected command-line argument: %s", argv[0]);
412
/* tlsmgr_loop - queue manager main loop */
414
static int tlsmgr_loop(char *unused_name, char **unused_argv)
417
* This routine runs as part of the event handling loop, after the event
418
* manager has delivered a timer or I/O event (including the completion
419
* of a connection to a delivery process), or after it has waited for a
420
* specified amount of time. The result value of qmgr_loop() specifies
421
* how long the event manager should wait for the next event.
424
#define WAIT_FOR_EVENT (-1)
426
if (clnt_scache_db_active)
427
clnt_scache_db_active = tlsmgr_do_scache_check(clnt_scache_db,
428
var_smtp_tls_scache_timeout, 0);
429
if (srvr_scache_db_active)
430
srvr_scache_db_active = tlsmgr_do_scache_check(srvr_scache_db,
431
var_smtpd_tls_scache_timeout, 0);
432
if (clnt_scache_db_active || srvr_scache_db_active)
434
return (WAIT_FOR_EVENT);
437
/* pre_accept - see if tables have changed */
439
static void pre_accept(char *unused_name, char **unused_argv)
441
if (dict_changed()) {
442
msg_info("table has changed -- exiting");
447
/* tlsmgr_pre_init - pre-jail initialization */
449
static void tlsmgr_pre_init(char *unused_name, char **unused_argv)
452
unsigned char buffer[255];
455
* Access the external sources for random seed. We may not be able to
456
* access them again if we are sent to chroot jail, so we must leave
457
* dev: and egd: type sources open.
459
if (*var_tls_rand_source) {
460
if (!strncmp(var_tls_rand_source, "dev:", 4)) {
462
* Source is a random device
464
rand_source_dev_fd = open(var_tls_rand_source + 4, 0, 0);
465
if (rand_source_dev_fd == -1)
466
msg_fatal("Could not open entropy device %s",
467
var_tls_rand_source);
468
if (var_tls_rand_bytes > 255)
469
var_tls_rand_bytes = 255;
470
rand_bytes = read(rand_source_dev_fd, buffer, var_tls_rand_bytes);
471
RAND_seed(buffer, rand_bytes);
472
} else if (!strncmp(var_tls_rand_source, "egd:", 4)) {
474
* Source is a EGD compatible socket
476
rand_source_socket_fd = unix_connect(var_tls_rand_source +4,
478
if (rand_source_socket_fd == -1)
479
msg_fatal("Could not connect to %s", var_tls_rand_source);
480
if (var_tls_rand_bytes > 255)
481
var_tls_rand_bytes = 255;
483
buffer[1] = var_tls_rand_bytes;
484
if (write(rand_source_socket_fd, buffer, 2) != 2)
485
msg_fatal("Could not talk to %s", var_tls_rand_source);
486
if (read(rand_source_socket_fd, buffer, 1) != 1)
487
msg_fatal("Could not read info from %s", var_tls_rand_source);
488
rand_bytes = buffer[0];
489
if (read(rand_source_socket_fd, buffer, rand_bytes) != rand_bytes)
490
msg_fatal("Could not read data from %s", var_tls_rand_source);
491
RAND_seed(buffer, rand_bytes);
493
rand_bytes = RAND_load_file(var_tls_rand_source,
499
* Now open the PRNG exchange file
501
if (*var_tls_rand_exch_name) {
502
rand_exch_fd = open(var_tls_rand_exch_name, O_RDWR | O_CREAT, 0600);
506
* Finally, open the session cache files. Remove old files, if still there.
507
* If we could not remove the old files, something is pretty wrong and we
510
if (*var_smtp_tls_scache_db)
511
clnt_scache_db = tlsmgr_cache_open(var_smtp_tls_scache_db);
512
if (*var_smtpd_tls_scache_db)
513
srvr_scache_db = tlsmgr_cache_open(var_smtpd_tls_scache_db);
516
/* qmgr_post_init - post-jail initialization */
518
static void tlsmgr_post_init(char *unused_name, char **unused_argv)
520
unsigned char buffer[1024];
523
* This routine runs after the skeleton code has entered the chroot jail.
524
* Prevent automatic process suicide after a limited number of client
525
* requests or after a limited amount of idle time.
531
* Complete thie initialization by reading the additional seed from the
532
* PRNG exchange file. Don't care how many bytes were actually read, just
533
* seed buffer into the PRNG, regardless of its contents.
535
if (rand_exch_fd >= 0) {
536
if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) == -1)
537
msg_fatal("Could not lock random exchange file: %s",
539
read(rand_exch_fd, buffer, 1024);
540
if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) == -1)
541
msg_fatal("Could not unlock random exchange file: %s",
543
RAND_seed(buffer, 1024);
544
tlsmgr_prng_upd_event(0, (char *) 0);
545
tlsmgr_reseed_event(0, (char *) 0);
548
clnt_scache_db_active = 0;
549
srvr_scache_db_active = 0;
551
tlsmgr_clnt_cache_run_event(0, (char *) 0);
553
tlsmgr_srvr_cache_run_event(0, (char *) 0);
557
/* main - the main program */
559
int main(int argc, char **argv)
561
static CONFIG_STR_TABLE str_table[] = {
562
VAR_TLS_RAND_SOURCE, DEF_TLS_RAND_SOURCE, &var_tls_rand_source, 0, 0,
565
static CONFIG_TIME_TABLE time_table[] = {
566
VAR_TLS_RESEED_PERIOD, DEF_TLS_RESEED_PERIOD, &var_tls_reseed_period, 0, 0,
567
VAR_TLS_PRNG_UPD_PERIOD, DEF_TLS_PRNG_UPD_PERIOD, &var_tls_prng_upd_period, 0, 0,
570
static CONFIG_INT_TABLE int_table[] = {
571
VAR_TLS_RAND_BYTES, DEF_TLS_RAND_BYTES, &var_tls_rand_bytes, 0, 0,
576
* Use the trigger service skeleton, because no-one else should be
577
* monitoring our service port while this process runs, and because we do
578
* not talk back to the client.
580
trigger_server_main(argc, argv, tlsmgr_trigger_event,
581
MAIL_SERVER_TIME_TABLE, time_table,
582
MAIL_SERVER_INT_TABLE, int_table,
583
MAIL_SERVER_STR_TABLE, str_table,
584
MAIL_SERVER_PRE_INIT, tlsmgr_pre_init,
585
MAIL_SERVER_POST_INIT, tlsmgr_post_init,
586
MAIL_SERVER_LOOP, tlsmgr_loop,
587
MAIL_SERVER_PRE_ACCEPT, pre_accept,
589
trigger_server_main(argc, argv, tlsmgr_trigger_event,
590
MAIL_SERVER_PRE_INIT, tlsmgr_pre_init,
595
int main(int argc, char **argv)
597
msg_fatal("Do not run tlsmgr with TLS support compiled in\n");