Home | History | Annotate | Line # | Download | only in verify
      1 /*	$NetBSD: verify.c,v 1.6 2026/05/09 18:49:23 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	verify 8
      6 /* SUMMARY
      7 /*	Postfix address verification server
      8 /* SYNOPSIS
      9 /*	\fBverify\fR [generic Postfix daemon options]
     10 /* DESCRIPTION
     11 /*	The \fBverify\fR(8) address verification server maintains a record
     12 /*	of what recipient addresses are known to be deliverable or
     13 /*	undeliverable.
     14 /*
     15 /*	Addresses are verified by injecting probe messages into the
     16 /*	Postfix queue. Probe messages are run through all the routing
     17 /*	and rewriting machinery except for final delivery, and are
     18 /*	discarded rather than being deferred or bounced.
     19 /*
     20 /*	Address verification relies on the answer from the nearest
     21 /*	MTA for the specified address, and will therefore not detect
     22 /*	all undeliverable addresses.
     23 /*
     24 /*	The \fBverify\fR(8) server is designed to run under control
     25 /*	by the Postfix
     26 /*	master server. It maintains an optional persistent database.
     27 /*	To avoid being interrupted by "postfix stop" in the middle
     28 /*	of a database update, the process runs in a separate process
     29 /*	group.
     30 /*
     31 /*	The \fBverify\fR(8) server implements the following requests:
     32 /* .IP "\fBupdate\fI address status text\fR"
     33 /*	Update the status and text of the specified address.
     34 /* .IP "\fBquery\fI address\fR"
     35 /*	Look up the \fIstatus\fR and \fItext\fR for the specified
     36 /*	\fIaddress\fR.
     37 /*	If the status is unknown, a probe is sent and an "in progress"
     38 /*	status is returned.
     39 /* SECURITY
     40 /* .ad
     41 /* .fi
     42 /*	The address verification server is not security-sensitive. It does
     43 /*	not talk to the network, and it does not talk to local users.
     44 /*	The verify server can run chrooted at fixed low privilege.
     45 /*
     46 /*	The address verification server can be coerced to store
     47 /*	unlimited amounts of garbage. Limiting the cache expiry
     48 /*	time
     49 /*	trades one problem (disk space exhaustion) for another
     50 /*	one (poor response time to client requests).
     51 /*
     52 /*	With Postfix version 2.5 and later, the \fBverify\fR(8)
     53 /*	server no longer uses root privileges when opening the
     54 /*	\fBaddress_verify_map\fR cache file. The file should now
     55 /*	be stored under the Postfix-owned \fBdata_directory\fR.  As
     56 /*	a migration aid, an attempt to open a cache file under a
     57 /*	non-Postfix directory is redirected to the Postfix-owned
     58 /*	\fBdata_directory\fR, and a warning is logged.
     59 /* DIAGNOSTICS
     60 /*	Problems and transactions are logged to \fBsyslogd\fR(8)
     61 /*	or \fBpostlogd\fR(8).
     62 /* BUGS
     63 /*	Address verification probe messages add additional traffic
     64 /*	to the mail queue.
     65 /*	Recipient verification may cause an increased load on
     66 /*	down-stream servers in the case of a dictionary attack or
     67 /*	a flood of backscatter bounces.
     68 /*	Sender address verification may cause your site to be
     69 /*	denylisted by some providers.
     70 /*
     71 /*	If the persistent database ever gets corrupted then the world
     72 /*	comes to an end and human intervention is needed. This violates
     73 /*	a basic Postfix principle.
     74 /* CONFIGURATION PARAMETERS
     75 /* .ad
     76 /* .fi
     77 /*	Changes to \fBmain.cf\fR are not picked up automatically,
     78 /*	as \fBverify\fR(8)
     79 /*	processes are long-lived. Use the command "\fBpostfix reload\fR" after
     80 /*	a configuration change.
     81 /*
     82 /*	The text below provides only a parameter summary. See
     83 /*	\fBpostconf\fR(5) for more details including examples.
     84 /* PROBE MESSAGE CONTROLS
     85 /* .ad
     86 /* .fi
     87 /* .IP "\fBaddress_verify_sender ($double_bounce_sender)\fR"
     88 /*	The sender address to use in address verification probes; prior
     89 /*	to Postfix 2.5 the default was "postmaster".
     90 /* .PP
     91 /*	Available with Postfix 2.9 and later:
     92 /* .IP "\fBaddress_verify_sender_ttl (0s)\fR"
     93 /*	The time between changes in the time-dependent portion of address
     94 /*	verification probe sender addresses.
     95 /* CACHE CONTROLS
     96 /* .ad
     97 /* .fi
     98 /* .IP "\fBaddress_verify_map (see 'postconf -d' output)\fR"
     99 /*	Lookup table for persistent address verification status
    100 /*	storage.
    101 /* .IP "\fBaddress_verify_positive_expire_time (31d)\fR"
    102 /*	The time after which a successful probe expires from the address
    103 /*	verification cache.
    104 /* .IP "\fBaddress_verify_positive_refresh_time (7d)\fR"
    105 /*	The time after which a successful address verification probe needs
    106 /*	to be refreshed.
    107 /* .IP "\fBaddress_verify_negative_cache (yes)\fR"
    108 /*	Enable caching of failed address verification probe results.
    109 /* .IP "\fBaddress_verify_negative_expire_time (3d)\fR"
    110 /*	The time after which a failed probe expires from the address
    111 /*	verification cache.
    112 /* .IP "\fBaddress_verify_negative_refresh_time (3h)\fR"
    113 /*	The time after which a failed address verification probe needs to
    114 /*	be refreshed.
    115 /* .PP
    116 /*	Available with Postfix 2.7 and later:
    117 /* .IP "\fBaddress_verify_cache_cleanup_interval (12h)\fR"
    118 /*	The amount of time between \fBverify\fR(8) address verification
    119 /*	database cleanup runs.
    120 /* PROBE MESSAGE ROUTING CONTROLS
    121 /* .ad
    122 /* .fi
    123 /*	By default, probe messages are delivered via the same route
    124 /*	as regular messages.  The following parameters can be used to
    125 /*	override specific message routing mechanisms.
    126 /* .IP "\fBaddress_verify_relayhost ($relayhost)\fR"
    127 /*	Overrides the relayhost parameter setting for address verification
    128 /*	probes.
    129 /* .IP "\fBaddress_verify_transport_maps ($transport_maps)\fR"
    130 /*	Overrides the transport_maps parameter setting for address verification
    131 /*	probes.
    132 /* .IP "\fBaddress_verify_local_transport ($local_transport)\fR"
    133 /*	Overrides the local_transport parameter setting for address
    134 /*	verification probes.
    135 /* .IP "\fBaddress_verify_virtual_transport ($virtual_transport)\fR"
    136 /*	Overrides the virtual_transport parameter setting for address
    137 /*	verification probes.
    138 /* .IP "\fBaddress_verify_relay_transport ($relay_transport)\fR"
    139 /*	Overrides the relay_transport parameter setting for address
    140 /*	verification probes.
    141 /* .IP "\fBaddress_verify_default_transport ($default_transport)\fR"
    142 /*	Overrides the default_transport parameter setting for address
    143 /*	verification probes.
    144 /* .PP
    145 /*	Available in Postfix 2.3 and later:
    146 /* .IP "\fBaddress_verify_sender_dependent_relayhost_maps ($sender_dependent_relayhost_maps)\fR"
    147 /*	Overrides the sender_dependent_relayhost_maps parameter setting for address
    148 /*	verification probes.
    149 /* .PP
    150 /*	Available in Postfix 2.7 and later:
    151 /* .IP "\fBaddress_verify_sender_dependent_default_transport_maps ($sender_dependent_default_transport_maps)\fR"
    152 /*	Overrides the sender_dependent_default_transport_maps parameter
    153 /*	setting for address verification probes.
    154 /* SMTPUTF8 CONTROLS
    155 /* .ad
    156 /* .fi
    157 /*	Preliminary SMTPUTF8 support is introduced with Postfix 3.0.
    158 /* .IP "\fBsmtputf8_autodetect_classes (sendmail, verify)\fR"
    159 /*	Detect that a message requires SMTPUTF8 support for the specified
    160 /*	mail origin classes.
    161 /* .PP
    162 /*	Available in Postfix version 3.2 and later:
    163 /* .IP "\fBenable_idna2003_compatibility (no)\fR"
    164 /*	Enable 'transitional' compatibility between IDNA2003 and IDNA2008,
    165 /*	when converting UTF-8 domain names to/from the ASCII form that is
    166 /*	used for DNS lookups.
    167 /* MISCELLANEOUS CONTROLS
    168 /* .ad
    169 /* .fi
    170 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
    171 /*	The default location of the Postfix main.cf and master.cf
    172 /*	configuration files.
    173 /* .IP "\fBdaemon_timeout (18000s)\fR"
    174 /*	How much time a Postfix daemon process may take to handle a
    175 /*	request before it is terminated by a built-in watchdog timer.
    176 /* .IP "\fBipc_timeout (3600s)\fR"
    177 /*	The time limit for sending or receiving information over an internal
    178 /*	communication channel.
    179 /* .IP "\fBprocess_id (read-only)\fR"
    180 /*	The process ID of a Postfix command or daemon process.
    181 /* .IP "\fBprocess_name (read-only)\fR"
    182 /*	The process name of a Postfix command or daemon process.
    183 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
    184 /*	The location of the Postfix top-level queue directory.
    185 /* .IP "\fBsyslog_facility (mail)\fR"
    186 /*	The syslog facility of Postfix logging.
    187 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
    188 /*	A prefix that is prepended to the process name in syslog
    189 /*	records, so that, for example, "smtpd" becomes "prefix/smtpd".
    190 /* .PP
    191 /*	Available in Postfix 3.3 and later:
    192 /* .IP "\fBservice_name (read-only)\fR"
    193 /*	The master.cf service name of a Postfix daemon process.
    194 /* SEE ALSO
    195 /*	smtpd(8), Postfix SMTP server
    196 /*	cleanup(8), enqueue Postfix message
    197 /*	postconf(5), configuration parameters
    198 /*	postlogd(8), Postfix logging
    199 /*	syslogd(8), system logging
    200 /* README FILES
    201 /* .ad
    202 /* .fi
    203 /*	Use "\fBpostconf readme_directory\fR" or
    204 /*	"\fBpostconf html_directory\fR" to locate this information.
    205 /* .na
    206 /* .nf
    207 /*	ADDRESS_VERIFICATION_README, address verification howto
    208 /* LICENSE
    209 /* .ad
    210 /* .fi
    211 /*	The Secure Mailer license must be distributed with this software.
    212 /* HISTORY
    213 /* .ad
    214 /* .fi
    215 /*	This service was introduced with Postfix version 2.1.
    216 /* AUTHOR(S)
    217 /*	Wietse Venema
    218 /*	IBM T.J. Watson Research
    219 /*	P.O. Box 704
    220 /*	Yorktown Heights, NY 10598, USA
    221 /*
    222 /*	Wietse Venema
    223 /*	Google, Inc.
    224 /*	111 8th Avenue
    225 /*	New York, NY 10011, USA
    226 /*--*/
    227 
    228 /* System library. */
    229 
    230 #include <sys_defs.h>
    231 #include <sys/stat.h>
    232 #include <time.h>
    233 #include <string.h>
    234 #include <stdlib.h>
    235 #include <unistd.h>
    236 
    237 /* Utility library. */
    238 
    239 #include <msg.h>
    240 #include <mymalloc.h>
    241 #include <htable.h>
    242 #include <dict_ht.h>
    243 #include <dict_cache.h>
    244 #include <split_at.h>
    245 #include <stringops.h>
    246 #include <set_eugid.h>
    247 #include <events.h>
    248 
    249 /* Global library. */
    250 
    251 #include <mail_conf.h>
    252 #include <mail_params.h>
    253 #include <mail_version.h>
    254 #include <mail_proto.h>
    255 #include <post_mail.h>
    256 #include <data_redirect.h>
    257 #include <verify_clnt.h>
    258 #include <verify_sender_addr.h>
    259 
    260 /* Server skeleton. */
    261 
    262 #include <mail_server.h>
    263 
    264 /* Application-specific. */
    265 
    266  /*
    267   * Tunable parameters.
    268   */
    269 char   *var_verify_map;
    270 int     var_verify_pos_exp;
    271 int     var_verify_pos_try;
    272 int     var_verify_neg_exp;
    273 int     var_verify_neg_try;
    274 int     var_verify_scan_cache;
    275 
    276  /*
    277   * State.
    278   */
    279 static DICT_CACHE *verify_map;
    280 
    281  /*
    282   * Silly little macros.
    283   */
    284 #define STR(x)			vstring_str(x)
    285 #define STREQ(x,y)		(strcmp(x,y) == 0)
    286 
    287  /*
    288   * The address verification database consists of (address, data) tuples. The
    289   * format of the data field is "status:probed:updated:text". The meaning of
    290   * each field is:
    291   *
    292   * status: one of the four recipient status codes (OK, DEFER, BOUNCE or TODO).
    293   * In the case of TODO, we have no information about the address, and the
    294   * address is being probed.
    295   *
    296   * probed: if non-zero, the time the currently outstanding address probe was
    297   * sent. If zero, there is no outstanding address probe.
    298   *
    299   * updated: if non-zero, the time the address probe result was received. If
    300   * zero, we have no information about the address, and the address is being
    301   * probed.
    302   *
    303   * text: descriptive text from delivery agents etc.
    304   */
    305 
    306  /*
    307   * Quick test to see status without parsing the whole entry.
    308   */
    309 #define STATUS_FROM_RAW_ENTRY(e) atoi(e)
    310 
    311 /* verify_make_entry - construct table entry */
    312 
    313 static void verify_make_entry(VSTRING *buf, int status, long probed,
    314 			              long updated, const char *text)
    315 {
    316     vstring_sprintf(buf, "%d:%ld:%ld:%s", status, probed, updated, text);
    317 }
    318 
    319 /* verify_parse_entry - parse table entry */
    320 
    321 static int verify_parse_entry(char *buf, int *status, long *probed,
    322 			              long *updated, char **text)
    323 {
    324     char   *probed_text;
    325     char   *updated_text;
    326 
    327     if ((probed_text = split_at(buf, ':')) != 0
    328 	&& (updated_text = split_at(probed_text, ':')) != 0
    329 	&& (*text = split_at(updated_text, ':')) != 0
    330 	&& alldig(buf)
    331 	&& alldig(probed_text)
    332 	&& alldig(updated_text)) {
    333 	*probed = atol(probed_text);
    334 	*updated = atol(updated_text);
    335 	*status = atoi(buf);
    336 
    337 	/*
    338 	 * Coverity 200604: the code incorrectly tested (probed || updated),
    339 	 * so that the sanity check never detected all-zero time stamps. Such
    340 	 * records are never written. If we read a record with all-zero time
    341 	 * stamps, then something is badly broken.
    342 	 */
    343 	if ((*status == DEL_RCPT_STAT_OK
    344 	     || *status == DEL_RCPT_STAT_DEFER
    345 	     || *status == DEL_RCPT_STAT_BOUNCE
    346 	     || *status == DEL_RCPT_STAT_TODO)
    347 	    && (*probed || *updated))
    348 	    return (0);
    349     }
    350     msg_warn("bad address verify table entry: %.100s", buf);
    351     return (-1);
    352 }
    353 
    354 /* verify_stat2name - status to name */
    355 
    356 static const char *verify_stat2name(int addr_status)
    357 {
    358     if (addr_status == DEL_RCPT_STAT_OK)
    359 	return ("deliverable");
    360     if (addr_status == DEL_RCPT_STAT_DEFER)
    361 	return ("undeliverable");
    362     if (addr_status == DEL_RCPT_STAT_BOUNCE)
    363 	return ("undeliverable");
    364     return (0);
    365 }
    366 
    367 /* verify_update_service - update address service */
    368 
    369 static void verify_update_service(VSTREAM *client_stream)
    370 {
    371     VSTRING *buf = vstring_alloc(10);
    372     VSTRING *addr = vstring_alloc(10);
    373     int     addr_status;
    374     VSTRING *text = vstring_alloc(10);
    375     const char *status_name;
    376     const char *raw_data;
    377     long    probed;
    378     long    updated;
    379 
    380     if (attr_scan(client_stream, ATTR_FLAG_STRICT,
    381 		  RECV_ATTR_STR(MAIL_ATTR_ADDR, addr),
    382 		  RECV_ATTR_INT(MAIL_ATTR_ADDR_STATUS, &addr_status),
    383 		  RECV_ATTR_STR(MAIL_ATTR_WHY, text),
    384 		  ATTR_TYPE_END) == 3) {
    385 	/* FIX 200501 IPv6 patch did not neuter ":" in address literals. */
    386 	translit(STR(addr), ":", "_");
    387 	if ((status_name = verify_stat2name(addr_status)) == 0) {
    388 	    msg_warn("bad recipient status %d for recipient %s",
    389 		     addr_status, STR(addr));
    390 	    attr_print(client_stream, ATTR_FLAG_NONE,
    391 		       SEND_ATTR_INT(MAIL_ATTR_STATUS, VRFY_STAT_BAD),
    392 		       ATTR_TYPE_END);
    393 	} else {
    394 
    395 	    /*
    396 	     * Robustness: don't allow a failed probe to clobber an OK
    397 	     * address before it expires. The failed probe is ignored so that
    398 	     * the address will be re-probed upon the next query. As long as
    399 	     * some probes succeed the address will remain cached as OK.
    400 	     */
    401 	    if (addr_status == DEL_RCPT_STAT_OK
    402 		|| (raw_data = dict_cache_lookup(verify_map, STR(addr))) == 0
    403 		|| STATUS_FROM_RAW_ENTRY(raw_data) != DEL_RCPT_STAT_OK) {
    404 		probed = 0;
    405 		updated = (long) time((time_t *) 0);
    406 		printable(STR(text), '?');
    407 		verify_make_entry(buf, addr_status, probed, updated, STR(text));
    408 		if (msg_verbose)
    409 		    msg_info("PUT %s status=%d probed=%ld updated=%ld text=%s",
    410 			STR(addr), addr_status, probed, updated, STR(text));
    411 		dict_cache_update(verify_map, STR(addr), STR(buf));
    412 	    }
    413 	    attr_print(client_stream, ATTR_FLAG_NONE,
    414 		       SEND_ATTR_INT(MAIL_ATTR_STATUS, VRFY_STAT_OK),
    415 		       ATTR_TYPE_END);
    416 	}
    417     }
    418     vstring_free(buf);
    419     vstring_free(addr);
    420     vstring_free(text);
    421 }
    422 
    423 /* verify_post_mail_fclose_action - callback */
    424 
    425 static void verify_post_mail_fclose_action(int unused_status,
    426 					           void *unused_context)
    427 {
    428     /* no code here, we just need to avoid blocking in post_mail_fclose() */
    429 }
    430 
    431 /* verify_post_mail_action - callback */
    432 
    433 static void verify_post_mail_action(VSTREAM *stream, void *context)
    434 {
    435 
    436     /*
    437      * Probe messages need no body content, because they are never delivered,
    438      * deferred, or bounced.
    439      */
    440     if (stream != 0)
    441 	post_mail_fclose_async(stream, verify_post_mail_fclose_action, context);
    442 }
    443 
    444 /* verify_query_service - query address status */
    445 
    446 static void verify_query_service(VSTREAM *client_stream)
    447 {
    448     VSTRING *addr = vstring_alloc(10);
    449     VSTRING *get_buf = 0;
    450     VSTRING *put_buf = 0;
    451     const char *raw_data;
    452     int     addr_status;
    453     long    probed;
    454     long    updated;
    455     char   *text;
    456 
    457     if (attr_scan(client_stream, ATTR_FLAG_STRICT,
    458 		  RECV_ATTR_STR(MAIL_ATTR_ADDR, addr),
    459 		  ATTR_TYPE_END) == 1) {
    460 	long    now = (long) time((time_t *) 0);
    461 
    462 	/*
    463 	 * Produce a default record when no usable record exists.
    464 	 *
    465 	 * If negative caching is disabled, purge an expired record from the
    466 	 * database.
    467 	 *
    468 	 * XXX Assume that a probe is lost if no response is received in 1000
    469 	 * seconds. If this number is too small the queue will slowly fill up
    470 	 * with delayed probes.
    471 	 *
    472 	 * XXX Maintain a moving average for the probe turnaround time, and
    473 	 * allow probe "retransmission" when a probe is outstanding for, say
    474 	 * some minimal amount of time (1000 sec) plus several times the
    475 	 * observed probe turnaround time. This causes probing to back off
    476 	 * when the mail system becomes congested.
    477 	 */
    478 #define POSITIVE_ENTRY_EXPIRED(addr_status, updated) \
    479     (addr_status == DEL_RCPT_STAT_OK && updated + var_verify_pos_exp < now)
    480 #define NEGATIVE_ENTRY_EXPIRED(addr_status, updated) \
    481     (addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_exp < now)
    482 #define PROBE_TTL	1000
    483 
    484 	/* FIX 200501 IPv6 patch did not neuter ":" in address literals. */
    485 	translit(STR(addr), ":", "_");
    486 	raw_data = dict_cache_lookup(verify_map, STR(addr));
    487 	if (dict_cache_error(verify_map) != 0) {
    488 	    addr_status = DEL_RCPT_STAT_DEFER;
    489 	    probed = 0;
    490 	    updated = 0;
    491 	    text = "Address verification status unavailable";
    492 	} else if (raw_data == 0		/* not found */
    493 		   || ((get_buf = vstring_alloc(10)),
    494 		       vstring_strcpy(get_buf, raw_data),	/* malformed */
    495 		     verify_parse_entry(STR(get_buf), &addr_status, &probed,
    496 					&updated, &text) < 0)
    497 		   || (now - probed > PROBE_TTL	/* safe to probe */
    498 		       && (POSITIVE_ENTRY_EXPIRED(addr_status, updated)
    499 			|| NEGATIVE_ENTRY_EXPIRED(addr_status, updated)))) {
    500 	    addr_status = DEL_RCPT_STAT_TODO;
    501 	    probed = 0;
    502 	    updated = 0;
    503 	    text = "Address verification in progress";
    504 	    if (raw_data != 0 && var_verify_neg_cache == 0)
    505 		dict_cache_delete(verify_map, STR(addr));
    506 	}
    507 	if (msg_verbose)
    508 	    msg_info("GOT %s status=%d probed=%ld updated=%ld text=%s",
    509 		     STR(addr), addr_status, probed, updated, text);
    510 
    511 	/*
    512 	 * Respond to the client.
    513 	 */
    514 	attr_print(client_stream, ATTR_FLAG_NONE,
    515 		   SEND_ATTR_INT(MAIL_ATTR_STATUS, VRFY_STAT_OK),
    516 		   SEND_ATTR_INT(MAIL_ATTR_ADDR_STATUS, addr_status),
    517 		   SEND_ATTR_STR(MAIL_ATTR_WHY, text),
    518 		   ATTR_TYPE_END);
    519 
    520 	/*
    521 	 * Send a new probe when the information needs to be refreshed.
    522 	 *
    523 	 * XXX For an initial proof of concept implementation, use synchronous
    524 	 * mail submission. This needs to be made async for high-volume
    525 	 * sites, which makes it even more interesting to eliminate duplicate
    526 	 * queries while a probe is being built.
    527 	 *
    528 	 * If negative caching is turned off, update the database only when
    529 	 * refreshing an existing entry.
    530 	 */
    531 #define POSITIVE_REFRESH_NEEDED(addr_status, updated) \
    532     (addr_status == DEL_RCPT_STAT_OK && updated + var_verify_pos_try < now)
    533 #define NEGATIVE_REFRESH_NEEDED(addr_status, updated) \
    534     (addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_try < now)
    535 
    536 	if (dict_cache_error(verify_map) == 0 && now - probed > PROBE_TTL
    537 	    && (POSITIVE_REFRESH_NEEDED(addr_status, updated)
    538 		|| NEGATIVE_REFRESH_NEEDED(addr_status, updated))) {
    539 	    if (msg_verbose)
    540 		msg_info("PROBE %s status=%d probed=%ld updated=%ld",
    541 			 STR(addr), addr_status, now, updated);
    542 	    post_mail_fopen_async(make_verify_sender_addr(), STR(addr),
    543 				  MAIL_SRC_MASK_VERIFY,
    544 				  DEL_REQ_FLAG_MTA_VRFY,
    545 	    /* TODO(wietse) disable REQUIRETLS? */
    546 				  SMTPUTF8_FLAG_NONE,
    547 				  (VSTRING *) 0,
    548 				  verify_post_mail_action,
    549 				  (void *) 0);
    550 	    if (updated != 0 || var_verify_neg_cache != 0) {
    551 		put_buf = vstring_alloc(10);
    552 		verify_make_entry(put_buf, addr_status, now, updated, text);
    553 		if (msg_verbose)
    554 		    msg_info("PUT %s status=%d probed=%ld updated=%ld text=%s",
    555 			     STR(addr), addr_status, now, updated, text);
    556 		dict_cache_update(verify_map, STR(addr), STR(put_buf));
    557 	    }
    558 	}
    559     }
    560     vstring_free(addr);
    561     if (get_buf)
    562 	vstring_free(get_buf);
    563     if (put_buf)
    564 	vstring_free(put_buf);
    565 }
    566 
    567 /* verify_cache_validator - cache cleanup validator */
    568 
    569 static int verify_cache_validator(const char *addr, const char *raw_data,
    570 				          void *context)
    571 {
    572     VSTRING *get_buf = (VSTRING *) context;
    573     int     addr_status;
    574     long    probed;
    575     long    updated;
    576     char   *text;
    577     long    now = (long) event_time();
    578 
    579 #define POS_OR_NEG_ENTRY_EXPIRED(stat, stamp) \
    580 	(POSITIVE_ENTRY_EXPIRED((stat), (stamp)) \
    581 	    || NEGATIVE_ENTRY_EXPIRED((stat), (stamp)))
    582 
    583     vstring_strcpy(get_buf, raw_data);
    584     return (verify_parse_entry(STR(get_buf), &addr_status,	/* syntax OK */
    585 			       &probed, &updated, &text) == 0
    586 	    && (now - probed < PROBE_TTL	/* probe in progress */
    587 		|| !POS_OR_NEG_ENTRY_EXPIRED(addr_status, updated)));
    588 }
    589 
    590 /* verify_service - perform service for client */
    591 
    592 static void verify_service(VSTREAM *client_stream, char *unused_service,
    593 			           char **argv)
    594 {
    595     VSTRING *request = vstring_alloc(10);
    596 
    597     /*
    598      * Sanity check. This service takes no command-line arguments.
    599      */
    600     if (argv[0])
    601 	msg_fatal("unexpected command-line argument: %s", argv[0]);
    602 
    603     /*
    604      * This routine runs whenever a client connects to the socket dedicated
    605      * to the address verification service. All connection-management stuff
    606      * is handled by the common code in multi_server.c.
    607      */
    608     if (attr_scan(client_stream,
    609 		  ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
    610 		  RECV_ATTR_STR(MAIL_ATTR_REQ, request),
    611 		  ATTR_TYPE_END) == 1) {
    612 	if (STREQ(STR(request), VRFY_REQ_UPDATE)) {
    613 	    verify_update_service(client_stream);
    614 	} else if (STREQ(STR(request), VRFY_REQ_QUERY)) {
    615 	    verify_query_service(client_stream);
    616 	} else {
    617 	    msg_warn("unrecognized request: \"%s\", ignored", STR(request));
    618 	    attr_print(client_stream, ATTR_FLAG_NONE,
    619 		       SEND_ATTR_INT(MAIL_ATTR_STATUS, VRFY_STAT_BAD),
    620 		       ATTR_TYPE_END);
    621 	}
    622     }
    623     vstream_fflush(client_stream);
    624     vstring_free(request);
    625 }
    626 
    627 /* verify_dump - dump some statistics */
    628 
    629 static void verify_dump(char *unused_name, char **unused_argv)
    630 {
    631 
    632     /*
    633      * Dump preliminary cache cleanup statistics when the process commits
    634      * suicide while a cache cleanup run is in progress. We can't currently
    635      * distinguish between "postfix reload" (we should restart) or "maximal
    636      * idle time reached" (we could finish the cache cleanup first).
    637      */
    638     dict_cache_close(verify_map);
    639     verify_map = 0;
    640 }
    641 
    642 /* post_jail_init - post-jail initialization */
    643 
    644 static void post_jail_init(char *unused_name, char **unused_argv)
    645 {
    646 
    647     /*
    648      * If the database is in volatile memory only, prevent automatic process
    649      * suicide after a limited number of client requests or after a limited
    650      * amount of idle time.
    651      */
    652     if (*var_verify_map == 0) {
    653 	var_use_limit = 0;
    654 	var_idle_limit = 0;
    655     }
    656 
    657     /*
    658      * Start the cache cleanup thread.
    659      */
    660     if (var_verify_scan_cache > 0) {
    661 	int     cache_flags;
    662 
    663 	cache_flags = DICT_CACHE_FLAG_STATISTICS;
    664 	if (msg_verbose)
    665 	    cache_flags |= DICT_CACHE_FLAG_VERBOSE;
    666 	dict_cache_control(verify_map,
    667 			   CA_DICT_CACHE_CTL_FLAGS(cache_flags),
    668 			   CA_DICT_CACHE_CTL_INTERVAL(var_verify_scan_cache),
    669 			CA_DICT_CACHE_CTL_VALIDATOR(verify_cache_validator),
    670 		     CA_DICT_CACHE_CTL_CONTEXT((void *) vstring_alloc(100)),
    671 			   CA_DICT_CACHE_CTL_END);
    672     }
    673 }
    674 
    675 /* pre_jail_init - pre-jail initialization */
    676 
    677 static void pre_jail_init(char *unused_name, char **unused_argv)
    678 {
    679     mode_t  saved_mask;
    680     VSTRING *redirect;
    681 
    682     /*
    683      * Never, ever, get killed by a master signal, as that would corrupt the
    684      * database when we're in the middle of an update.
    685      */
    686     setsid();
    687 
    688     /*
    689      * Security: don't create root-owned files that contain untrusted data.
    690      * And don't create Postfix-owned files in root-owned directories,
    691      * either. We want a correct relationship between (file/directory)
    692      * ownership and (file/directory) content.
    693      *
    694      * XXX Non-root open can violate the principle of least surprise: Postfix
    695      * can't open an *SQL config file for database read-write access, even
    696      * though it can open that same control file for database read-only
    697      * access.
    698      *
    699      * The solution is to query a map type and obtain its properties before
    700      * opening it. A clean solution is to add a dict_info() API that is
    701      * similar to dict_open() except it returns properties (dict flags) only.
    702      * A pragmatic solution is to overload the existing API and have
    703      * dict_open() return a dummy map when given a null map name.
    704      *
    705      * However, the proxymap daemon has been opening *SQL maps as non-root for
    706      * years now without anyone complaining, let's not solve a problem that
    707      * doesn't exist.
    708      */
    709     SAVE_AND_SET_EUGID(var_owner_uid, var_owner_gid);
    710     redirect = vstring_alloc(100);
    711 
    712     /*
    713      * Keep state in persistent (external) or volatile (internal) map.
    714      *
    715      * Start the cache cleanup thread after permanently dropping privileges.
    716      */
    717 #define VERIFY_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE \
    718 	    | DICT_FLAG_OPEN_LOCK | DICT_FLAG_UTF8_REQUEST)
    719 
    720     saved_mask = umask(022);
    721     verify_map =
    722 	dict_cache_open(*var_verify_map ?
    723 			data_redirect_map(redirect, var_verify_map) :
    724 			"internal:verify",
    725 			O_CREAT | O_RDWR, VERIFY_DICT_OPEN_FLAGS);
    726     (void) umask(saved_mask);
    727 
    728     /*
    729      * Clean up and restore privilege.
    730      */
    731     vstring_free(redirect);
    732     RESTORE_SAVED_EUGID();
    733 }
    734 
    735 /* post_accept_init - announce our protocol */
    736 
    737 static void post_accept_init(VSTREAM *stream, char *unused_name,
    738 			           char **unused_argv, HTABLE *unused_table)
    739 {
    740 
    741     /*
    742      * Announce the protocol.
    743      */
    744     attr_print(stream, ATTR_FLAG_NONE,
    745 	       SEND_ATTR_STR(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_VERIFY),
    746 	       ATTR_TYPE_END);
    747     (void) vstream_fflush(stream);
    748 }
    749 
    750 MAIL_VERSION_STAMP_DECLARE;
    751 
    752 /* main - pass control to the multi-threaded skeleton */
    753 
    754 int     main(int argc, char **argv)
    755 {
    756     static const CONFIG_STR_TABLE str_table[] = {
    757 	VAR_VERIFY_MAP, DEF_VERIFY_MAP, &var_verify_map, 0, 0,
    758 	VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender, 0, 0,
    759 	0,
    760     };
    761     static const CONFIG_TIME_TABLE time_table[] = {
    762 	VAR_VERIFY_POS_EXP, DEF_VERIFY_POS_EXP, &var_verify_pos_exp, 1, 0,
    763 	VAR_VERIFY_POS_TRY, DEF_VERIFY_POS_TRY, &var_verify_pos_try, 1, 0,
    764 	VAR_VERIFY_NEG_EXP, DEF_VERIFY_NEG_EXP, &var_verify_neg_exp, 1, 0,
    765 	VAR_VERIFY_NEG_TRY, DEF_VERIFY_NEG_TRY, &var_verify_neg_try, 1, 0,
    766 	VAR_VERIFY_SCAN_CACHE, DEF_VERIFY_SCAN_CACHE, &var_verify_scan_cache, 0, 0,
    767 	VAR_VERIFY_SENDER_TTL, DEF_VERIFY_SENDER_TTL, &var_verify_sender_ttl, 0, 0,
    768 	0,
    769     };
    770 
    771     /*
    772      * Fingerprint executables and core dumps.
    773      */
    774     MAIL_VERSION_STAMP_ALLOCATE;
    775 
    776     multi_server_main(argc, argv, verify_service,
    777 		      CA_MAIL_SERVER_STR_TABLE(str_table),
    778 		      CA_MAIL_SERVER_TIME_TABLE(time_table),
    779 		      CA_MAIL_SERVER_PRE_INIT(pre_jail_init),
    780 		      CA_MAIL_SERVER_POST_INIT(post_jail_init),
    781 		      CA_MAIL_SERVER_POST_ACCEPT(post_accept_init),
    782 		      CA_MAIL_SERVER_SOLITARY,
    783 		      CA_MAIL_SERVER_EXIT(verify_dump),
    784 		      0);
    785 }
    786