Home | History | Annotate | Line # | Download | only in tlsmgr
      1 /*	$NetBSD: tlsmgr.c,v 1.5 2025/02/25 19:15:50 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	tlsmgr 8
      6 /* SUMMARY
      7 /*	Postfix TLS session cache and PRNG manager
      8 /* SYNOPSIS
      9 /*	\fBtlsmgr\fR [generic Postfix daemon options]
     10 /* DESCRIPTION
     11 /*	The \fBtlsmgr\fR(8) manages the Postfix TLS session caches.
     12 /*	It stores and retrieves cache entries on request by
     13 /*	\fBsmtpd\fR(8) and \fBsmtp\fR(8) processes, and periodically
     14 /*	removes entries that have expired.
     15 /*
     16 /*	The \fBtlsmgr\fR(8) also manages the PRNG (pseudo random number
     17 /*	generator) pool. It answers queries by the \fBsmtpd\fR(8)
     18 /*	and \fBsmtp\fR(8)
     19 /*	processes to seed their internal PRNG pools.
     20 /*
     21 /*	The \fBtlsmgr\fR(8)'s PRNG pool is initially seeded from
     22 /*	an external source (EGD, /dev/urandom, or regular file).
     23 /*	It is updated at configurable pseudo-random intervals with
     24 /*	data from the external source. It is updated periodically
     25 /*	with data from TLS session cache entries and with the time
     26 /*	of day, and is updated with the time of day whenever a
     27 /*	process requests \fBtlsmgr\fR(8) service.
     28 /*
     29 /*	The \fBtlsmgr\fR(8) saves the PRNG state to an exchange file
     30 /*	periodically and when the process terminates, and reads
     31 /*	the exchange file when initializing its PRNG.
     32 /* SECURITY
     33 /* .ad
     34 /* .fi
     35 /*	The \fBtlsmgr\fR(8) is not security-sensitive. The code that maintains
     36 /*	the external and internal PRNG pools does not "trust" the
     37 /*	data that it manipulates, and the code that maintains the
     38 /*	TLS session cache does not touch the contents of the cached
     39 /*	entries, except for seeding its internal PRNG pool.
     40 /*
     41 /*	The \fBtlsmgr\fR(8) can be run chrooted and with reduced privileges.
     42 /*	At process startup it connects to the entropy source and
     43 /*	exchange file, and creates or truncates the optional TLS
     44 /*	session cache files.
     45 /*
     46 /*	With Postfix version 2.5 and later, the \fBtlsmgr\fR(8) no
     47 /*	longer uses root privileges when opening cache files. These
     48 /*	files should now be stored under the Postfix-owned
     49 /*	\fBdata_directory\fR.  As a migration aid, an attempt to
     50 /*	open a cache file under a non-Postfix directory is redirected
     51 /*	to the Postfix-owned \fBdata_directory\fR, and a warning
     52 /*	is logged.
     53 /* DIAGNOSTICS
     54 /*	Problems and transactions are logged to \fBsyslogd\fR(8)
     55 /*	or \fBpostlogd\fR(8).
     56 /* BUGS
     57 /*	There is no automatic means to limit the number of entries in the
     58 /*	TLS session caches and/or the size of the TLS cache files.
     59 /* CONFIGURATION PARAMETERS
     60 /* .ad
     61 /* .fi
     62 /*	Changes to \fBmain.cf\fR are not picked up automatically,
     63 /*	because \fBtlsmgr\fR(8) is a persistent processes.  Use the
     64 /*	command "\fBpostfix reload\fR" after a configuration change.
     65 /*
     66 /*	The text below provides only a parameter summary. See
     67 /*	\fBpostconf\fR(5) for more details including examples.
     68 /* TLS SESSION CACHE
     69 /* .ad
     70 /* .fi
     71 /* .IP "\fBlmtp_tls_loglevel (0)\fR"
     72 /*	The LMTP-specific version of the smtp_tls_loglevel
     73 /*	configuration parameter.
     74 /* .IP "\fBlmtp_tls_session_cache_database (empty)\fR"
     75 /*	The LMTP-specific version of the smtp_tls_session_cache_database
     76 /*	configuration parameter.
     77 /* .IP "\fBlmtp_tls_session_cache_timeout (3600s)\fR"
     78 /*	The LMTP-specific version of the smtp_tls_session_cache_timeout
     79 /*	configuration parameter.
     80 /* .IP "\fBsmtp_tls_loglevel (0)\fR"
     81 /*	Enable additional Postfix SMTP client logging of TLS activity.
     82 /* .IP "\fBsmtp_tls_session_cache_database (empty)\fR"
     83 /*	Name of the file containing the optional Postfix SMTP client
     84 /*	TLS session cache.
     85 /* .IP "\fBsmtp_tls_session_cache_timeout (3600s)\fR"
     86 /*	The expiration time of Postfix SMTP client TLS session cache
     87 /*	information.
     88 /* .IP "\fBsmtpd_tls_loglevel (0)\fR"
     89 /*	Enable additional Postfix SMTP server logging of TLS activity.
     90 /* .IP "\fBsmtpd_tls_session_cache_database (empty)\fR"
     91 /*	Name of the file containing the optional Postfix SMTP server
     92 /*	TLS session cache.
     93 /* .IP "\fBsmtpd_tls_session_cache_timeout (3600s)\fR"
     94 /*	The expiration time of Postfix SMTP server TLS session cache
     95 /*	information.
     96 /* PSEUDO RANDOM NUMBER GENERATOR
     97 /* .ad
     98 /* .fi
     99 /* .IP "\fBtls_random_source (see 'postconf -d' output)\fR"
    100 /*	The external entropy source for the in-memory \fBtlsmgr\fR(8) pseudo
    101 /*	random number generator (PRNG) pool.
    102 /* .IP "\fBtls_random_bytes (32)\fR"
    103 /*	The number of bytes that \fBtlsmgr\fR(8) reads from $tls_random_source
    104 /*	when (re)seeding the in-memory pseudo random number generator (PRNG)
    105 /*	pool.
    106 /* .IP "\fBtls_random_exchange_name (see 'postconf -d' output)\fR"
    107 /*	Name of the pseudo random number generator (PRNG) state file
    108 /*	that is maintained by \fBtlsmgr\fR(8).
    109 /* .IP "\fBtls_random_prng_update_period (3600s)\fR"
    110 /*	The time between attempts by \fBtlsmgr\fR(8) to save the state of
    111 /*	the pseudo random number generator (PRNG) to the file specified
    112 /*	with $tls_random_exchange_name.
    113 /* .IP "\fBtls_random_reseed_period (3600s)\fR"
    114 /*	The maximal time between attempts by \fBtlsmgr\fR(8) to re-seed the
    115 /*	in-memory pseudo random number generator (PRNG) pool from external
    116 /*	sources.
    117 /* MISCELLANEOUS CONTROLS
    118 /* .ad
    119 /* .fi
    120 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
    121 /*	The default location of the Postfix main.cf and master.cf
    122 /*	configuration files.
    123 /* .IP "\fBdata_directory (see 'postconf -d' output)\fR"
    124 /*	The directory with Postfix-writable data files (for example:
    125 /*	caches, pseudo-random numbers).
    126 /* .IP "\fBdaemon_timeout (18000s)\fR"
    127 /*	How much time a Postfix daemon process may take to handle a
    128 /*	request before it is terminated by a built-in watchdog timer.
    129 /* .IP "\fBprocess_id (read-only)\fR"
    130 /*	The process ID of a Postfix command or daemon process.
    131 /* .IP "\fBprocess_name (read-only)\fR"
    132 /*	The process name of a Postfix command or daemon process.
    133 /* .IP "\fBsyslog_facility (mail)\fR"
    134 /*	The syslog facility of Postfix logging.
    135 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
    136 /*	A prefix that is prepended to the process name in syslog
    137 /*	records, so that, for example, "smtpd" becomes "prefix/smtpd".
    138 /* .PP
    139 /*	Available in Postfix 3.3 and later:
    140 /* .IP "\fBservice_name (read-only)\fR"
    141 /*	The master.cf service name of a Postfix daemon process.
    142 /* SEE ALSO
    143 /*	smtp(8), Postfix SMTP client
    144 /*	smtpd(8), Postfix SMTP server
    145 /*	postconf(5), configuration parameters
    146 /*	master(5), generic daemon options
    147 /*	master(8), process manager
    148 /*	postlogd(8), Postfix logging
    149 /*	syslogd(8), system logging
    150 /* README FILES
    151 /* .ad
    152 /* .fi
    153 /*	Use "\fBpostconf readme_directory\fR" or
    154 /*	"\fBpostconf html_directory\fR" to locate this information.
    155 /* .na
    156 /* .nf
    157 /*	TLS_README, Postfix TLS configuration and operation
    158 /* LICENSE
    159 /* .ad
    160 /* .fi
    161 /*	The Secure Mailer license must be distributed with this software.
    162 /* HISTORY
    163 /*	This service was introduced with Postfix version 2.2.
    164 /* AUTHOR(S)
    165 /*	Lutz Jaenicke
    166 /*	BTU Cottbus
    167 /*	Allgemeine Elektrotechnik
    168 /*	Universitaetsplatz 3-4
    169 /*	D-03044 Cottbus, Germany
    170 /*
    171 /*	Adapted by:
    172 /*	Wietse Venema
    173 /*	IBM T.J. Watson Research
    174 /*	P.O. Box 704
    175 /*	Yorktown Heights, NY 10598, USA
    176 /*
    177 /*	Wietse Venema
    178 /*	Google, Inc.
    179 /*	111 8th Avenue
    180 /*	New York, NY 10011, USA
    181 /*--*/
    182 
    183 /* System library. */
    184 
    185 #include <sys_defs.h>
    186 #include <sys/stat.h>
    187 #include <stdlib.h>
    188 #include <unistd.h>
    189 #include <ctype.h>
    190 #include <errno.h>
    191 #include <string.h>
    192 #include <sys/time.h>			/* gettimeofday, not POSIX */
    193 #include <limits.h>
    194 
    195 #ifndef UCHAR_MAX
    196 #define UCHAR_MAX 0xff
    197 #endif
    198 
    199 /* OpenSSL library. */
    200 
    201 #ifdef USE_TLS
    202 #include <openssl/rand.h>		/* For the PRNG */
    203 #endif
    204 
    205 /* Utility library. */
    206 
    207 #include <msg.h>
    208 #include <events.h>
    209 #include <stringops.h>
    210 #include <mymalloc.h>
    211 #include <iostuff.h>
    212 #include <vstream.h>
    213 #include <vstring.h>
    214 #include <vstring_vstream.h>
    215 #include <attr.h>
    216 #include <set_eugid.h>
    217 #include <htable.h>
    218 #include <warn_stat.h>
    219 
    220 /* Global library. */
    221 
    222 #include <mail_conf.h>
    223 #include <mail_params.h>
    224 #include <mail_version.h>
    225 #include <mail_proto.h>
    226 #include <data_redirect.h>
    227 
    228 /* Master process interface. */
    229 
    230 #include <master_proto.h>
    231 #include <mail_server.h>
    232 
    233 /* TLS library. */
    234 
    235 #ifdef USE_TLS
    236 #include <tls_mgr.h>
    237 #define TLS_INTERNAL
    238 #include <tls.h>			/* TLS_MGR_SCACHE_<type> */
    239 #include <tls_prng.h>
    240 #include <tls_scache.h>
    241 
    242 /* Application-specific. */
    243 
    244  /*
    245   * Tunables.
    246   */
    247 char   *var_tls_rand_source;
    248 int     var_tls_rand_bytes;
    249 int     var_tls_reseed_period;
    250 int     var_tls_prng_exch_period;
    251 char   *var_smtpd_tls_loglevel;
    252 char   *var_smtpd_tls_scache_db;
    253 int     var_smtpd_tls_scache_timeout;
    254 char   *var_smtp_tls_loglevel;
    255 char   *var_smtp_tls_scache_db;
    256 int     var_smtp_tls_scache_timeout;
    257 char   *var_lmtp_tls_loglevel;
    258 char   *var_lmtp_tls_scache_db;
    259 int     var_lmtp_tls_scache_timeout;
    260 char   *var_tls_rand_exch_name;
    261 
    262  /*
    263   * Bound the time that we are willing to wait for an I/O operation. This
    264   * produces better error messages than waiting until the watchdog timer
    265   * kills the process.
    266   */
    267 #define TLS_MGR_TIMEOUT	10
    268 
    269  /*
    270   * State for updating the PRNG exchange file.
    271   */
    272 static TLS_PRNG_SRC *rand_exch;
    273 
    274  /*
    275   * State for seeding the internal PRNG from external source.
    276   */
    277 static TLS_PRNG_SRC *rand_source_dev;
    278 static TLS_PRNG_SRC *rand_source_egd;
    279 static TLS_PRNG_SRC *rand_source_file;
    280 
    281  /*
    282   * The external entropy source type is encoded in the source name. The
    283   * obvious alternative is to have separate configuration parameters per
    284   * source type, so that one process can query multiple external sources.
    285   */
    286 #define DEV_PREF "dev:"
    287 #define DEV_PREF_LEN (sizeof((DEV_PREF)) - 1)
    288 #define DEV_PATH(dev) ((dev) + EGD_PREF_LEN)
    289 
    290 #define EGD_PREF "egd:"
    291 #define EGD_PREF_LEN (sizeof((EGD_PREF)) - 1)
    292 #define EGD_PATH(egd) ((egd) + EGD_PREF_LEN)
    293 
    294  /*
    295   * State for TLS session caches.
    296   */
    297 typedef struct {
    298     char   *cache_label;		/* cache short-hand name */
    299     TLS_SCACHE *cache_info;		/* cache handle */
    300     int     cache_active;		/* cache status */
    301     char  **cache_db;			/* main.cf parameter value */
    302     const char *log_param;		/* main.cf parameter name */
    303     char  **log_level;			/* main.cf parameter value */
    304     int    *cache_timeout;		/* main.cf parameter value */
    305 } TLSMGR_SCACHE;
    306 
    307 static TLSMGR_SCACHE cache_table[] = {
    308     TLS_MGR_SCACHE_SMTPD, 0, 0, &var_smtpd_tls_scache_db,
    309     VAR_SMTPD_TLS_LOGLEVEL,
    310     &var_smtpd_tls_loglevel, &var_smtpd_tls_scache_timeout,
    311     TLS_MGR_SCACHE_SMTP, 0, 0, &var_smtp_tls_scache_db,
    312     VAR_SMTP_TLS_LOGLEVEL,
    313     &var_smtp_tls_loglevel, &var_smtp_tls_scache_timeout,
    314     TLS_MGR_SCACHE_LMTP, 0, 0, &var_lmtp_tls_scache_db,
    315     VAR_LMTP_TLS_LOGLEVEL,
    316     &var_lmtp_tls_loglevel, &var_lmtp_tls_scache_timeout,
    317     0,
    318 };
    319 
    320 #define	smtpd_cache	(cache_table[0])
    321 
    322  /*
    323   * SLMs.
    324   */
    325 #define STR(x)		vstring_str(x)
    326 #define LEN(x)		VSTRING_LEN(x)
    327 #define STREQ(x, y)	(strcmp((x), (y)) == 0)
    328 
    329 /* tlsmgr_prng_exch_event - update PRNG exchange file */
    330 
    331 static void tlsmgr_prng_exch_event(int unused_event, void *dummy)
    332 {
    333     const char *myname = "tlsmgr_prng_exch_event";
    334     unsigned char randbyte;
    335     int     next_period;
    336     struct stat st;
    337 
    338     if (msg_verbose)
    339 	msg_info("%s: update PRNG exchange file", myname);
    340 
    341     /*
    342      * Sanity check. If the PRNG exchange file was removed, there is no point
    343      * updating it further. Restart the process and update the new file.
    344      */
    345     if (fstat(rand_exch->fd, &st) < 0)
    346 	msg_fatal("cannot fstat() the PRNG exchange file: %m");
    347     if (st.st_nlink == 0) {
    348 	msg_warn("PRNG exchange file was removed -- exiting to reopen");
    349 	sleep(1);
    350 	exit(0);
    351     }
    352     tls_prng_exch_update(rand_exch);
    353 
    354     /*
    355      * Make prediction difficult for outsiders and calculate the time for the
    356      * next execution randomly.
    357      */
    358     RAND_bytes(&randbyte, 1);
    359     next_period = (var_tls_prng_exch_period * randbyte) / UCHAR_MAX;
    360     event_request_timer(tlsmgr_prng_exch_event, dummy, next_period);
    361 }
    362 
    363 /* tlsmgr_reseed_event - re-seed the internal PRNG pool */
    364 
    365 static void tlsmgr_reseed_event(int unused_event, void *dummy)
    366 {
    367     int     next_period;
    368     unsigned char randbyte;
    369     int     must_exit = 0;
    370 
    371     /*
    372      * Reseed the internal PRNG from external source. Errors are recoverable.
    373      * We simply restart and reconnect without making a fuss. This is OK
    374      * because we do require that exchange file updates succeed. The exchange
    375      * file is the only entropy source that really matters in the long term.
    376      *
    377      * If the administrator specifies an external randomness source that we
    378      * could not open upon start-up, restart to see if we can open it now
    379      * (and log a nagging warning if we can't).
    380      */
    381     if (*var_tls_rand_source) {
    382 
    383 	/*
    384 	 * Source is a random device.
    385 	 */
    386 	if (rand_source_dev) {
    387 	    if (tls_prng_dev_read(rand_source_dev, var_tls_rand_bytes) <= 0) {
    388 		msg_info("cannot read from entropy device %s: %m -- "
    389 			 "exiting to reopen", DEV_PATH(var_tls_rand_source));
    390 		must_exit = 1;
    391 	    }
    392 	}
    393 
    394 	/*
    395 	 * Source is an EGD compatible socket.
    396 	 */
    397 	else if (rand_source_egd) {
    398 	    if (tls_prng_egd_read(rand_source_egd, var_tls_rand_bytes) <= 0) {
    399 		msg_info("lost connection to EGD server %s -- "
    400 		     "exiting to reconnect", EGD_PATH(var_tls_rand_source));
    401 		must_exit = 1;
    402 	    }
    403 	}
    404 
    405 	/*
    406 	 * Source is a regular file. Read the content once and close the
    407 	 * file.
    408 	 */
    409 	else if (rand_source_file) {
    410 	    if (tls_prng_file_read(rand_source_file, var_tls_rand_bytes) <= 0)
    411 		msg_warn("cannot read from entropy file %s: %m",
    412 			 var_tls_rand_source);
    413 	    tls_prng_file_close(rand_source_file);
    414 	    rand_source_file = 0;
    415 	    var_tls_rand_source[0] = 0;
    416 	}
    417 
    418 	/*
    419 	 * Could not open the external source upon start-up. See if we can
    420 	 * open it this time. Save PRNG state before we exit.
    421 	 */
    422 	else {
    423 	    msg_info("exiting to reopen external entropy source %s",
    424 		     var_tls_rand_source);
    425 	    must_exit = 1;
    426 	}
    427     }
    428 
    429     /*
    430      * Save PRNG state in case we must exit.
    431      */
    432     if (must_exit) {
    433 	if (rand_exch)
    434 	    tls_prng_exch_update(rand_exch);
    435 	sleep(1);
    436 	exit(0);
    437     }
    438 
    439     /*
    440      * Make prediction difficult for outsiders and calculate the time for the
    441      * next execution randomly.
    442      */
    443     RAND_bytes(&randbyte, 1);
    444     next_period = (var_tls_reseed_period * randbyte) / UCHAR_MAX;
    445     event_request_timer(tlsmgr_reseed_event, dummy, next_period);
    446 }
    447 
    448 /* tlsmgr_cache_run_event - start TLS session cache scan */
    449 
    450 static void tlsmgr_cache_run_event(int unused_event, void *ctx)
    451 {
    452     const char *myname = "tlsmgr_cache_run_event";
    453     TLSMGR_SCACHE *cache = (TLSMGR_SCACHE *) ctx;
    454 
    455     /*
    456      * This routine runs when it is time for another TLS session cache scan.
    457      * Make sure this routine gets called again in the future.
    458      *
    459      * Don't start a new scan when the timer goes off while cache cleanup is
    460      * still in progress.
    461      */
    462     if (cache->cache_info->verbose)
    463 	msg_info("%s: start TLS %s session cache cleanup",
    464 		 myname, cache->cache_label);
    465 
    466     if (cache->cache_active == 0)
    467 	cache->cache_active =
    468 	    tls_scache_sequence(cache->cache_info, DICT_SEQ_FUN_FIRST,
    469 				TLS_SCACHE_SEQUENCE_NOTHING);
    470 
    471     event_request_timer(tlsmgr_cache_run_event, (void *) cache,
    472 			cache->cache_info->timeout);
    473 }
    474 
    475 /* tlsmgr_key - return matching or current RFC 5077 session ticket keys */
    476 
    477 static int tlsmgr_key(VSTRING *buffer, int timeout)
    478 {
    479     TLS_TICKET_KEY *key;
    480     TLS_TICKET_KEY tmp;
    481     unsigned char *name;
    482     time_t  now = time((time_t *) 0);
    483 
    484     /* In tlsmgr requests we encode null key names as empty strings. */
    485     name = LEN(buffer) ? (unsigned char *) STR(buffer) : 0;
    486 
    487     /*
    488      * Each key's encrypt and subsequent decrypt-only timeout is half of the
    489      * total session timeout.
    490      */
    491     timeout /= 2;
    492 
    493     /* Attempt to locate existing key */
    494     if ((key = tls_scache_key(name, now, timeout)) == 0) {
    495 	if (name == 0) {
    496 	    /* Create new encryption key */
    497 	    if (RAND_bytes(tmp.name, TLS_TICKET_NAMELEN) <= 0
    498 		|| RAND_bytes(tmp.bits, TLS_TICKET_KEYLEN) <= 0
    499 		|| RAND_bytes(tmp.hmac, TLS_TICKET_MACLEN) <= 0)
    500 		return (TLS_MGR_STAT_ERR);
    501 	    tmp.tout = now + timeout - 1;
    502 	    key = tls_scache_key_rotate(&tmp);
    503 	} else {
    504 	    /* No matching decryption key found */
    505 	    return (TLS_MGR_STAT_ERR);
    506 	}
    507     }
    508     /* Return value overwrites name buffer */
    509     vstring_memcpy(buffer, (char *) key, sizeof(*key));
    510     return (TLS_MGR_STAT_OK);
    511 }
    512 
    513 /* tlsmgr_loop - TLS manager main loop */
    514 
    515 static int tlsmgr_loop(char *unused_name, char **unused_argv)
    516 {
    517     struct timeval tv;
    518     int     active = 0;
    519     TLSMGR_SCACHE *ent;
    520 
    521     /*
    522      * Update the PRNG pool with the time of day. We do it here after every
    523      * event (including internal timer events and external client request
    524      * events), instead of doing it in individual event call-back routines.
    525      */
    526     GETTIMEOFDAY(&tv);
    527     RAND_seed(&tv, sizeof(struct timeval));
    528 
    529     /*
    530      * This routine runs as part of the event handling loop, after the event
    531      * manager has delivered a timer or I/O event, or after it has waited for
    532      * a specified amount of time. The result value of tlsmgr_loop()
    533      * specifies how long the event manager should wait for the next event.
    534      *
    535      * We use this loop to interleave TLS session cache cleanup with other
    536      * activity. Interleaved processing is needed when we use a client-server
    537      * protocol for entropy and session state exchange with smtp(8) and
    538      * smtpd(8) processes.
    539      */
    540 #define DONT_WAIT	0
    541 #define WAIT_FOR_EVENT	(-1)
    542 
    543     for (ent = cache_table; ent->cache_label; ++ent) {
    544 	if (ent->cache_info && ent->cache_active)
    545 	    active |= ent->cache_active =
    546 		tls_scache_sequence(ent->cache_info, DICT_SEQ_FUN_NEXT,
    547 				    TLS_SCACHE_SEQUENCE_NOTHING);
    548     }
    549 
    550     return (active ? DONT_WAIT : WAIT_FOR_EVENT);
    551 }
    552 
    553 /* tlsmgr_request_receive - receive request */
    554 
    555 static int tlsmgr_request_receive(VSTREAM *client_stream, VSTRING *request)
    556 {
    557     int     count;
    558 
    559     /*
    560      * Kluge: choose the protocol depending on the request size.
    561      */
    562     if (read_wait(vstream_fileno(client_stream), var_ipc_timeout) < 0) {
    563 	msg_warn("timeout while waiting for data from %s",
    564 		 VSTREAM_PATH(client_stream));
    565 	return (-1);
    566     }
    567     if ((count = peekfd(vstream_fileno(client_stream))) < 0) {
    568 	msg_warn("cannot examine read buffer of %s: %m",
    569 		 VSTREAM_PATH(client_stream));
    570 	return (-1);
    571     }
    572 
    573     /*
    574      * Short request: master trigger. Use the string+null protocol.
    575      */
    576     if (count <= 2) {
    577 	if (vstring_get_null(request, client_stream) == VSTREAM_EOF) {
    578 	    msg_warn("end-of-input while reading request from %s: %m",
    579 		     VSTREAM_PATH(client_stream));
    580 	    return (-1);
    581 	}
    582     }
    583 
    584     /*
    585      * Long request: real tlsmgr client. Use the attribute list protocol.
    586      */
    587     else {
    588 	if (attr_scan(client_stream,
    589 		      ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
    590 		      RECV_ATTR_STR(TLS_MGR_ATTR_REQ, request),
    591 		      ATTR_TYPE_END) != 1) {
    592 	    return (-1);
    593 	}
    594     }
    595     return (0);
    596 }
    597 
    598 /* tlsmgr_service - respond to external request */
    599 
    600 static void tlsmgr_service(VSTREAM *client_stream, char *unused_service,
    601 			           char **argv)
    602 {
    603     static VSTRING *request = 0;
    604     static VSTRING *cache_type = 0;
    605     static VSTRING *cache_id = 0;
    606     static VSTRING *buffer = 0;
    607     int     len;
    608     static char wakeup[] = {		/* master wakeup request */
    609 	TRIGGER_REQ_WAKEUP,
    610 	0,
    611     };
    612     TLSMGR_SCACHE *ent;
    613     int     status = TLS_MGR_STAT_FAIL;
    614 
    615     /*
    616      * Sanity check. This service takes no command-line arguments.
    617      */
    618     if (argv[0])
    619 	msg_fatal("unexpected command-line argument: %s", argv[0]);
    620 
    621     /*
    622      * Initialize. We're select threaded, so we can use static buffers.
    623      */
    624     if (request == 0) {
    625 	request = vstring_alloc(10);
    626 	cache_type = vstring_alloc(10);
    627 	cache_id = vstring_alloc(10);
    628 	buffer = vstring_alloc(10);
    629     }
    630 
    631     /*
    632      * This routine runs whenever a client connects to the socket dedicated
    633      * to the tlsmgr service (including wake up events sent by the master).
    634      * All connection-management stuff is handled by the common code in
    635      * multi_server.c.
    636      */
    637     if (tlsmgr_request_receive(client_stream, request) == 0) {
    638 
    639 	/*
    640 	 * Load session from cache.
    641 	 */
    642 	if (STREQ(STR(request), TLS_MGR_REQ_LOOKUP)) {
    643 	    if (attr_scan(client_stream, ATTR_FLAG_STRICT,
    644 			  RECV_ATTR_STR(TLS_MGR_ATTR_CACHE_TYPE, cache_type),
    645 			  RECV_ATTR_STR(TLS_MGR_ATTR_CACHE_ID, cache_id),
    646 			  ATTR_TYPE_END) == 2) {
    647 		for (ent = cache_table; ent->cache_label; ++ent)
    648 		    if (strcmp(ent->cache_label, STR(cache_type)) == 0)
    649 			break;
    650 		if (ent->cache_label == 0) {
    651 		    msg_warn("bogus cache type \"%s\" in \"%s\" request",
    652 			     STR(cache_type), TLS_MGR_REQ_LOOKUP);
    653 		    VSTRING_RESET(buffer);
    654 		} else if (ent->cache_info == 0) {
    655 
    656 		    /*
    657 		     * Cache type valid, but not enabled
    658 		     */
    659 		    VSTRING_RESET(buffer);
    660 		} else {
    661 		    status = tls_scache_lookup(ent->cache_info,
    662 					       STR(cache_id), buffer) ?
    663 			TLS_MGR_STAT_OK : TLS_MGR_STAT_ERR;
    664 		}
    665 	    }
    666 	    attr_print(client_stream, ATTR_FLAG_NONE,
    667 		       SEND_ATTR_INT(MAIL_ATTR_STATUS, status),
    668 		       SEND_ATTR_DATA(TLS_MGR_ATTR_SESSION,
    669 				      LEN(buffer), STR(buffer)),
    670 		       ATTR_TYPE_END);
    671 	}
    672 
    673 	/*
    674 	 * Save session to cache.
    675 	 */
    676 	else if (STREQ(STR(request), TLS_MGR_REQ_UPDATE)) {
    677 	    if (attr_scan(client_stream, ATTR_FLAG_STRICT,
    678 			  RECV_ATTR_STR(TLS_MGR_ATTR_CACHE_TYPE, cache_type),
    679 			  RECV_ATTR_STR(TLS_MGR_ATTR_CACHE_ID, cache_id),
    680 			  RECV_ATTR_DATA(TLS_MGR_ATTR_SESSION, buffer),
    681 			  ATTR_TYPE_END) == 3) {
    682 		for (ent = cache_table; ent->cache_label; ++ent)
    683 		    if (strcmp(ent->cache_label, STR(cache_type)) == 0)
    684 			break;
    685 		if (ent->cache_label == 0) {
    686 		    msg_warn("bogus cache type \"%s\" in \"%s\" request",
    687 			     STR(cache_type), TLS_MGR_REQ_UPDATE);
    688 		} else if (ent->cache_info != 0) {
    689 		    status =
    690 			tls_scache_update(ent->cache_info, STR(cache_id),
    691 					  STR(buffer), LEN(buffer)) ?
    692 			TLS_MGR_STAT_OK : TLS_MGR_STAT_ERR;
    693 		}
    694 	    }
    695 	    attr_print(client_stream, ATTR_FLAG_NONE,
    696 		       SEND_ATTR_INT(MAIL_ATTR_STATUS, status),
    697 		       ATTR_TYPE_END);
    698 	}
    699 
    700 	/*
    701 	 * Delete session from cache.
    702 	 */
    703 	else if (STREQ(STR(request), TLS_MGR_REQ_DELETE)) {
    704 	    if (attr_scan(client_stream, ATTR_FLAG_STRICT,
    705 			  RECV_ATTR_STR(TLS_MGR_ATTR_CACHE_TYPE, cache_type),
    706 			  RECV_ATTR_STR(TLS_MGR_ATTR_CACHE_ID, cache_id),
    707 			  ATTR_TYPE_END) == 2) {
    708 		for (ent = cache_table; ent->cache_label; ++ent)
    709 		    if (strcmp(ent->cache_label, STR(cache_type)) == 0)
    710 			break;
    711 		if (ent->cache_label == 0) {
    712 		    msg_warn("bogus cache type \"%s\" in \"%s\" request",
    713 			     STR(cache_type), TLS_MGR_REQ_DELETE);
    714 		} else if (ent->cache_info != 0) {
    715 		    status = tls_scache_delete(ent->cache_info,
    716 					       STR(cache_id)) ?
    717 			TLS_MGR_STAT_OK : TLS_MGR_STAT_ERR;
    718 		}
    719 	    }
    720 	    attr_print(client_stream, ATTR_FLAG_NONE,
    721 		       SEND_ATTR_INT(MAIL_ATTR_STATUS, status),
    722 		       ATTR_TYPE_END);
    723 	}
    724 
    725 	/*
    726 	 * RFC 5077 TLS session ticket keys
    727 	 */
    728 	else if (STREQ(STR(request), TLS_MGR_REQ_TKTKEY)) {
    729 	    if (attr_scan(client_stream, ATTR_FLAG_STRICT,
    730 			  RECV_ATTR_DATA(TLS_MGR_ATTR_KEYNAME, buffer),
    731 			  ATTR_TYPE_END) == 1) {
    732 		if (LEN(buffer) != 0 && LEN(buffer) != TLS_TICKET_NAMELEN) {
    733 		    msg_warn("invalid session ticket key name length: %ld",
    734 			     (long) LEN(buffer));
    735 		    VSTRING_RESET(buffer);
    736 		} else if (*smtpd_cache.cache_timeout <= 0) {
    737 		    status = TLS_MGR_STAT_ERR;
    738 		    VSTRING_RESET(buffer);
    739 		} else {
    740 		    status = tlsmgr_key(buffer, *smtpd_cache.cache_timeout);
    741 		}
    742 	    }
    743 	    attr_print(client_stream, ATTR_FLAG_NONE,
    744 		       SEND_ATTR_INT(MAIL_ATTR_STATUS, status),
    745 		       SEND_ATTR_DATA(TLS_MGR_ATTR_KEYBUF,
    746 				      LEN(buffer), STR(buffer)),
    747 		       ATTR_TYPE_END);
    748 	}
    749 
    750 	/*
    751 	 * Entropy request.
    752 	 */
    753 	else if (STREQ(STR(request), TLS_MGR_REQ_SEED)) {
    754 	    if (attr_scan(client_stream, ATTR_FLAG_STRICT,
    755 			  RECV_ATTR_INT(TLS_MGR_ATTR_SIZE, &len),
    756 			  ATTR_TYPE_END) == 1) {
    757 		VSTRING_RESET(buffer);
    758 		if (len <= 0 || len > 255) {
    759 		    msg_warn("bogus seed length \"%d\" in \"%s\" request",
    760 			     len, TLS_MGR_REQ_SEED);
    761 		} else {
    762 		    VSTRING_SPACE(buffer, len);
    763 		    RAND_bytes((unsigned char *) STR(buffer), len);
    764 		    vstring_set_payload_size(buffer, len);
    765 		    status = TLS_MGR_STAT_OK;
    766 		}
    767 	    }
    768 	    attr_print(client_stream, ATTR_FLAG_NONE,
    769 		       SEND_ATTR_INT(MAIL_ATTR_STATUS, status),
    770 		       SEND_ATTR_DATA(TLS_MGR_ATTR_SEED,
    771 				      LEN(buffer), STR(buffer)),
    772 		       ATTR_TYPE_END);
    773 	}
    774 
    775 	/*
    776 	 * Caching policy request.
    777 	 */
    778 	else if (STREQ(STR(request), TLS_MGR_REQ_POLICY)) {
    779 	    int     cachable = 0;
    780 	    int     timeout = 0;
    781 
    782 	    if (attr_scan(client_stream, ATTR_FLAG_STRICT,
    783 			  RECV_ATTR_STR(TLS_MGR_ATTR_CACHE_TYPE, cache_type),
    784 			  ATTR_TYPE_END) == 1) {
    785 		for (ent = cache_table; ent->cache_label; ++ent)
    786 		    if (strcmp(ent->cache_label, STR(cache_type)) == 0)
    787 			break;
    788 		if (ent->cache_label == 0) {
    789 		    msg_warn("bogus cache type \"%s\" in \"%s\" request",
    790 			     STR(cache_type), TLS_MGR_REQ_POLICY);
    791 		} else {
    792 		    cachable = (ent->cache_info != 0) ? 1 : 0;
    793 		    timeout = *ent->cache_timeout;
    794 		    status = TLS_MGR_STAT_OK;
    795 		}
    796 	    }
    797 	    attr_print(client_stream, ATTR_FLAG_NONE,
    798 		       SEND_ATTR_INT(MAIL_ATTR_STATUS, status),
    799 		       SEND_ATTR_INT(TLS_MGR_ATTR_CACHABLE, cachable),
    800 		       SEND_ATTR_INT(TLS_MGR_ATTR_SESSTOUT, timeout),
    801 		       ATTR_TYPE_END);
    802 	}
    803 
    804 	/*
    805 	 * Master trigger. Normally, these triggers arrive only after some
    806 	 * other process requested the tlsmgr's service. The purpose is to
    807 	 * restart the tlsmgr after it aborted due to a fatal run-time error,
    808 	 * so that it can continue its housekeeping even while nothing is
    809 	 * using TLS.
    810 	 *
    811 	 * XXX Which begs the question, if TLS isn't used often, do we need a
    812 	 * tlsmgr background process? It could terminate when the session
    813 	 * caches are empty.
    814 	 */
    815 	else if (STREQ(STR(request), wakeup)) {
    816 	    if (msg_verbose)
    817 		msg_info("received master trigger");
    818 	    multi_server_disconnect(client_stream);
    819 	    return;				/* NOT: vstream_fflush */
    820 	}
    821     }
    822 
    823     /*
    824      * Workaround: some OS lies under load. It tells the Postfix event
    825      * handler that a server socket is readable, then it tells peekfd() that
    826      * the socket has unread data, and then it tells vstring_get_null() that
    827      * there is none, causing Postfix to spam the log with warning messages.
    828      * Close the stream to stop such nonsense; the client can reconnect if it
    829      * still wants to talk to us.
    830      *
    831      * XXX Why is this problem not reported for the other five
    832      * multi_server-based Postfix services?
    833      */
    834     else if (vstream_ferror(client_stream) || vstream_feof(client_stream)) {
    835 	multi_server_disconnect(client_stream);
    836 	return;
    837 	/* Note: client_stream is now a dangling pointer. */
    838     }
    839 
    840     /*
    841      * Protocol error.
    842      */
    843     else {
    844 	attr_print(client_stream, ATTR_FLAG_NONE,
    845 		   SEND_ATTR_INT(MAIL_ATTR_STATUS, TLS_MGR_STAT_FAIL),
    846 		   ATTR_TYPE_END);
    847     }
    848     vstream_fflush(client_stream);
    849 }
    850 
    851 /* tlsmgr_pre_init - pre-jail initialization */
    852 
    853 static void tlsmgr_pre_init(char *unused_name, char **unused_argv)
    854 {
    855     char   *path;
    856     struct timeval tv;
    857     TLSMGR_SCACHE *ent;
    858     VSTRING *redirect;
    859     HTABLE *dup_filter;
    860     const char *dup_label;
    861 
    862     /*
    863      * If nothing else works then at least this will get us a few bits of
    864      * entropy.
    865      *
    866      * XXX This is our first call into the OpenSSL library. We should find out
    867      * if this can be moved to the post-jail initialization phase, without
    868      * breaking compatibility with existing installations.
    869      */
    870     GETTIMEOFDAY(&tv);
    871     tv.tv_sec ^= getpid();
    872     RAND_seed(&tv, sizeof(struct timeval));
    873 
    874     /*
    875      * Open the external entropy source. We will not be able to open it again
    876      * after we are sent to chroot jail, so we keep it open. Errors are not
    877      * fatal. The exchange file (see below) is the only entropy source that
    878      * really matters in the long run.
    879      *
    880      * Security note: we open the entropy source while privileged, but we don't
    881      * access the source until after we release privileges. This way, none of
    882      * the OpenSSL code gets to execute while we are privileged.
    883      */
    884     if (*var_tls_rand_source) {
    885 
    886 	/*
    887 	 * Source is a random device.
    888 	 */
    889 	if (!strncmp(var_tls_rand_source, DEV_PREF, DEV_PREF_LEN)) {
    890 	    path = DEV_PATH(var_tls_rand_source);
    891 	    rand_source_dev = tls_prng_dev_open(path, TLS_MGR_TIMEOUT);
    892 	    if (rand_source_dev == 0)
    893 		msg_warn("cannot open entropy device %s: %m", path);
    894 	}
    895 
    896 	/*
    897 	 * Source is an EGD compatible socket.
    898 	 */
    899 	else if (!strncmp(var_tls_rand_source, EGD_PREF, EGD_PREF_LEN)) {
    900 	    path = EGD_PATH(var_tls_rand_source);
    901 	    rand_source_egd = tls_prng_egd_open(path, TLS_MGR_TIMEOUT);
    902 	    if (rand_source_egd == 0)
    903 		msg_warn("cannot connect to EGD server %s: %m", path);
    904 	}
    905 
    906 	/*
    907 	 * Source is regular file. We read this only once.
    908 	 */
    909 	else {
    910 	    rand_source_file =
    911 		tls_prng_file_open(var_tls_rand_source, TLS_MGR_TIMEOUT);
    912 	}
    913     } else {
    914 	msg_warn("no entropy source specified with parameter %s",
    915 		 VAR_TLS_RAND_SOURCE);
    916 	msg_warn("encryption keys etc. may be predictable");
    917     }
    918 
    919     /*
    920      * Security: don't create root-owned files that contain untrusted data.
    921      * And don't create Postfix-owned files in root-owned directories,
    922      * either. We want a correct relationship between (file/directory)
    923      * ownership and (file/directory) content.
    924      */
    925     SAVE_AND_SET_EUGID(var_owner_uid, var_owner_gid);
    926     redirect = vstring_alloc(100);
    927 
    928     /*
    929      * Open the PRNG exchange file before going to jail, but don't use root
    930      * privileges. Start the exchange file read/update pseudo thread after
    931      * dropping privileges.
    932      */
    933     if (*var_tls_rand_exch_name) {
    934 	rand_exch =
    935 	    tls_prng_exch_open(data_redirect_file(redirect,
    936 						  var_tls_rand_exch_name));
    937 	if (rand_exch == 0)
    938 	    msg_fatal("cannot open PRNG exchange file %s: %m",
    939 		      var_tls_rand_exch_name);
    940     }
    941 
    942     /*
    943      * Open the session cache files and discard old information before going
    944      * to jail, but don't use root privilege. Start the cache maintenance
    945      * pseudo threads after dropping privileges.
    946      */
    947     dup_filter = htable_create(sizeof(cache_table) / sizeof(cache_table[0]));
    948     for (ent = cache_table; ent->cache_label; ++ent) {
    949 	/* Sanitize session timeout */
    950 	if (*ent->cache_timeout > 0) {
    951 	    if (*ent->cache_timeout < TLS_SESSION_LIFEMIN)
    952 		*ent->cache_timeout = TLS_SESSION_LIFEMIN;
    953 	} else {
    954 	    *ent->cache_timeout = 0;
    955 	}
    956 	/* External cache database disabled if timeout is non-positive */
    957 	if (*ent->cache_timeout > 0 && **ent->cache_db) {
    958 	    if ((dup_label = htable_find(dup_filter, *ent->cache_db)) != 0)
    959 		msg_fatal("do not use the same TLS cache file %s for %s and %s",
    960 			  *ent->cache_db, dup_label, ent->cache_label);
    961 	    htable_enter(dup_filter, *ent->cache_db, ent->cache_label);
    962 	    ent->cache_info =
    963 		tls_scache_open(data_redirect_map(redirect, *ent->cache_db),
    964 				ent->cache_label,
    965 				tls_log_mask(ent->log_param,
    966 					   *ent->log_level) & TLS_LOG_CACHE,
    967 				*ent->cache_timeout);
    968 	}
    969     }
    970     htable_free(dup_filter, (void (*) (void *)) 0);
    971 
    972     /*
    973      * Clean up and restore privilege.
    974      */
    975     vstring_free(redirect);
    976     RESTORE_SAVED_EUGID();
    977 }
    978 
    979 /* tlsmgr_post_init - post-jail initialization */
    980 
    981 static void tlsmgr_post_init(char *unused_name, char **unused_argv)
    982 {
    983     TLSMGR_SCACHE *ent;
    984 
    985 #define NULL_EVENT	(0)
    986 #define NULL_CONTEXT	((char *) 0)
    987 
    988     /*
    989      * This routine runs after the skeleton code has entered the chroot jail,
    990      * but before any client requests are serviced. Prevent automatic process
    991      * suicide after a limited number of client requests or after a limited
    992      * amount of idle time.
    993      */
    994     var_use_limit = 0;
    995     var_idle_limit = 0;
    996 
    997     /*
    998      * Start the internal PRNG re-seeding pseudo thread first.
    999      */
   1000     if (*var_tls_rand_source) {
   1001 	if (var_tls_reseed_period > INT_MAX / UCHAR_MAX)
   1002 	    var_tls_reseed_period = INT_MAX / UCHAR_MAX;
   1003 	tlsmgr_reseed_event(NULL_EVENT, NULL_CONTEXT);
   1004     }
   1005 
   1006     /*
   1007      * Start the exchange file read/update pseudo thread.
   1008      */
   1009     if (*var_tls_rand_exch_name) {
   1010 	if (var_tls_prng_exch_period > INT_MAX / UCHAR_MAX)
   1011 	    var_tls_prng_exch_period = INT_MAX / UCHAR_MAX;
   1012 	tlsmgr_prng_exch_event(NULL_EVENT, NULL_CONTEXT);
   1013     }
   1014 
   1015     /*
   1016      * Start the cache maintenance pseudo threads last. Strictly speaking
   1017      * there is nothing to clean up after we truncate the database to zero
   1018      * length, but early cleanup makes verbose logging more informative (we
   1019      * get positive confirmation that the cleanup threads are running).
   1020      */
   1021     for (ent = cache_table; ent->cache_label; ++ent)
   1022 	if (ent->cache_info)
   1023 	    tlsmgr_cache_run_event(NULL_EVENT, (void *) ent);
   1024 }
   1025 
   1026 /* tlsmgr_post_accept - announce our protocol */
   1027 
   1028 static void tlsmgr_post_accept(VSTREAM *stream, char *unused_name,
   1029 			           char **unused_argv, HTABLE *unused_table)
   1030 {
   1031 
   1032     /*
   1033      * Announce the protocol.
   1034      */
   1035     attr_print(stream, ATTR_FLAG_NONE,
   1036 	       SEND_ATTR_STR(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_TLSMGR),
   1037 	       ATTR_TYPE_END);
   1038     (void) vstream_fflush(stream);
   1039 }
   1040 
   1041 
   1042 /* tlsmgr_before_exit - save PRNG state before exit */
   1043 
   1044 static void tlsmgr_before_exit(char *unused_service_name, char **unused_argv)
   1045 {
   1046 
   1047     /*
   1048      * Save state before we exit after "postfix reload".
   1049      */
   1050     if (rand_exch)
   1051 	tls_prng_exch_update(rand_exch);
   1052 }
   1053 
   1054 MAIL_VERSION_STAMP_DECLARE;
   1055 
   1056 /* main - the main program */
   1057 
   1058 int     main(int argc, char **argv)
   1059 {
   1060     static const CONFIG_STR_TABLE str_table[] = {
   1061 	VAR_TLS_RAND_SOURCE, DEF_TLS_RAND_SOURCE, &var_tls_rand_source, 0, 0,
   1062 	VAR_TLS_RAND_EXCH_NAME, DEF_TLS_RAND_EXCH_NAME, &var_tls_rand_exch_name, 0, 0,
   1063 	VAR_SMTPD_TLS_SCACHE_DB, DEF_SMTPD_TLS_SCACHE_DB, &var_smtpd_tls_scache_db, 0, 0,
   1064 	VAR_SMTP_TLS_SCACHE_DB, DEF_SMTP_TLS_SCACHE_DB, &var_smtp_tls_scache_db, 0, 0,
   1065 	VAR_LMTP_TLS_SCACHE_DB, DEF_LMTP_TLS_SCACHE_DB, &var_lmtp_tls_scache_db, 0, 0,
   1066 	VAR_SMTPD_TLS_LOGLEVEL, DEF_SMTPD_TLS_LOGLEVEL, &var_smtpd_tls_loglevel, 0, 0,
   1067 	VAR_SMTP_TLS_LOGLEVEL, DEF_SMTP_TLS_LOGLEVEL, &var_smtp_tls_loglevel, 0, 0,
   1068 	VAR_LMTP_TLS_LOGLEVEL, DEF_LMTP_TLS_LOGLEVEL, &var_lmtp_tls_loglevel, 0, 0,
   1069 	0,
   1070     };
   1071     static const CONFIG_TIME_TABLE time_table[] = {
   1072 	VAR_TLS_RESEED_PERIOD, DEF_TLS_RESEED_PERIOD, &var_tls_reseed_period, 1, 0,
   1073 	VAR_TLS_PRNG_UPD_PERIOD, DEF_TLS_PRNG_UPD_PERIOD, &var_tls_prng_exch_period, 1, 0,
   1074 	VAR_SMTPD_TLS_SCACHTIME, DEF_SMTPD_TLS_SCACHTIME, &var_smtpd_tls_scache_timeout, 0, MAX_SMTPD_TLS_SCACHETIME,
   1075 	VAR_SMTP_TLS_SCACHTIME, DEF_SMTP_TLS_SCACHTIME, &var_smtp_tls_scache_timeout, 0, MAX_SMTP_TLS_SCACHETIME,
   1076 	VAR_LMTP_TLS_SCACHTIME, DEF_LMTP_TLS_SCACHTIME, &var_lmtp_tls_scache_timeout, 0, MAX_LMTP_TLS_SCACHETIME,
   1077 	0,
   1078     };
   1079     static const CONFIG_INT_TABLE int_table[] = {
   1080 	VAR_TLS_RAND_BYTES, DEF_TLS_RAND_BYTES, &var_tls_rand_bytes, 1, 0,
   1081 	0,
   1082     };
   1083 
   1084     /*
   1085      * Fingerprint executables and core dumps.
   1086      */
   1087     MAIL_VERSION_STAMP_ALLOCATE;
   1088 
   1089     /*
   1090      * Use the multi service skeleton, and require that no-one else is
   1091      * monitoring our service port while this process runs.
   1092      */
   1093     multi_server_main(argc, argv, tlsmgr_service,
   1094 		      CA_MAIL_SERVER_TIME_TABLE(time_table),
   1095 		      CA_MAIL_SERVER_INT_TABLE(int_table),
   1096 		      CA_MAIL_SERVER_STR_TABLE(str_table),
   1097 		      CA_MAIL_SERVER_PRE_INIT(tlsmgr_pre_init),
   1098 		      CA_MAIL_SERVER_POST_INIT(tlsmgr_post_init),
   1099 		      CA_MAIL_SERVER_POST_ACCEPT(tlsmgr_post_accept),
   1100 		      CA_MAIL_SERVER_EXIT(tlsmgr_before_exit),
   1101 		      CA_MAIL_SERVER_LOOP(tlsmgr_loop),
   1102 		      CA_MAIL_SERVER_SOLITARY,
   1103 		      0);
   1104 }
   1105 
   1106 #else
   1107 
   1108 /* tlsmgr_service - respond to external trigger(s), non-TLS version */
   1109 
   1110 static void tlsmgr_service(VSTREAM *unused_stream, char *unused_service,
   1111 			           char **unused_argv)
   1112 {
   1113     msg_info("TLS support is not compiled in -- exiting");
   1114 }
   1115 
   1116 /* main - the main program, non-TLS version */
   1117 
   1118 int     main(int argc, char **argv)
   1119 {
   1120 
   1121     /*
   1122      * 200411 We can't simply use msg_fatal() here, because the logging
   1123      * hasn't been initialized. The text would disappear because stderr is
   1124      * redirected to /dev/null.
   1125      *
   1126      * We invoke multi_server_main() to complete program initialization
   1127      * (including logging) and then invoke the tlsmgr_service() routine to
   1128      * log the message that says why this program will not run.
   1129      */
   1130     multi_server_main(argc, argv, tlsmgr_service,
   1131 		      0);
   1132 }
   1133 
   1134 #endif
   1135