xref: /netbsd-src/external/ibm-public/postfix/dist/src/verify/verify.c (revision 67b9b338a7386232ac596b5fd0cd5a9cc8a03c71)
1 /*	$NetBSD: verify.c,v 1.4 2022/10/08 16:12:50 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 
verify_make_entry(VSTRING * buf,int status,long probed,long updated,const char * text)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 
verify_parse_entry(char * buf,int * status,long * probed,long * updated,char ** text)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 
verify_stat2name(int addr_status)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 
verify_update_service(VSTREAM * client_stream)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 
verify_post_mail_fclose_action(int unused_status,void * unused_context)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 
verify_post_mail_action(VSTREAM * stream,void * context)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 
verify_query_service(VSTREAM * client_stream)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 	if ((raw_data = dict_cache_lookup(verify_map, STR(addr))) == 0	/* not found */
487 	    || ((get_buf = vstring_alloc(10)),
488 		vstring_strcpy(get_buf, raw_data),	/* malformed */
489 		verify_parse_entry(STR(get_buf), &addr_status, &probed,
490 				   &updated, &text) < 0)
491 	    || (now - probed > PROBE_TTL	/* safe to probe */
492 		&& (POSITIVE_ENTRY_EXPIRED(addr_status, updated)
493 		    || NEGATIVE_ENTRY_EXPIRED(addr_status, updated)))) {
494 	    addr_status = DEL_RCPT_STAT_TODO;
495 	    probed = 0;
496 	    updated = 0;
497 	    text = "Address verification in progress";
498 	    if (raw_data != 0 && var_verify_neg_cache == 0)
499 		dict_cache_delete(verify_map, STR(addr));
500 	}
501 	if (msg_verbose)
502 	    msg_info("GOT %s status=%d probed=%ld updated=%ld text=%s",
503 		     STR(addr), addr_status, probed, updated, text);
504 
505 	/*
506 	 * Respond to the client.
507 	 */
508 	attr_print(client_stream, ATTR_FLAG_NONE,
509 		   SEND_ATTR_INT(MAIL_ATTR_STATUS, VRFY_STAT_OK),
510 		   SEND_ATTR_INT(MAIL_ATTR_ADDR_STATUS, addr_status),
511 		   SEND_ATTR_STR(MAIL_ATTR_WHY, text),
512 		   ATTR_TYPE_END);
513 
514 	/*
515 	 * Send a new probe when the information needs to be refreshed.
516 	 *
517 	 * XXX For an initial proof of concept implementation, use synchronous
518 	 * mail submission. This needs to be made async for high-volume
519 	 * sites, which makes it even more interesting to eliminate duplicate
520 	 * queries while a probe is being built.
521 	 *
522 	 * If negative caching is turned off, update the database only when
523 	 * refreshing an existing entry.
524 	 */
525 #define POSITIVE_REFRESH_NEEDED(addr_status, updated) \
526     (addr_status == DEL_RCPT_STAT_OK && updated + var_verify_pos_try < now)
527 #define NEGATIVE_REFRESH_NEEDED(addr_status, updated) \
528     (addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_try < now)
529 
530 	if (now - probed > PROBE_TTL
531 	    && (POSITIVE_REFRESH_NEEDED(addr_status, updated)
532 		|| NEGATIVE_REFRESH_NEEDED(addr_status, updated))) {
533 	    if (msg_verbose)
534 		msg_info("PROBE %s status=%d probed=%ld updated=%ld",
535 			 STR(addr), addr_status, now, updated);
536 	    post_mail_fopen_async(make_verify_sender_addr(), STR(addr),
537 				  MAIL_SRC_MASK_VERIFY,
538 				  DEL_REQ_FLAG_MTA_VRFY,
539 				  SMTPUTF8_FLAG_NONE,
540 				  (VSTRING *) 0,
541 				  verify_post_mail_action,
542 				  (void *) 0);
543 	    if (updated != 0 || var_verify_neg_cache != 0) {
544 		put_buf = vstring_alloc(10);
545 		verify_make_entry(put_buf, addr_status, now, updated, text);
546 		if (msg_verbose)
547 		    msg_info("PUT %s status=%d probed=%ld updated=%ld text=%s",
548 			     STR(addr), addr_status, now, updated, text);
549 		dict_cache_update(verify_map, STR(addr), STR(put_buf));
550 	    }
551 	}
552     }
553     vstring_free(addr);
554     if (get_buf)
555 	vstring_free(get_buf);
556     if (put_buf)
557 	vstring_free(put_buf);
558 }
559 
560 /* verify_cache_validator - cache cleanup validator */
561 
verify_cache_validator(const char * addr,const char * raw_data,void * context)562 static int verify_cache_validator(const char *addr, const char *raw_data,
563 				          void *context)
564 {
565     VSTRING *get_buf = (VSTRING *) context;
566     int     addr_status;
567     long    probed;
568     long    updated;
569     char   *text;
570     long    now = (long) event_time();
571 
572 #define POS_OR_NEG_ENTRY_EXPIRED(stat, stamp) \
573 	(POSITIVE_ENTRY_EXPIRED((stat), (stamp)) \
574 	    || NEGATIVE_ENTRY_EXPIRED((stat), (stamp)))
575 
576     vstring_strcpy(get_buf, raw_data);
577     return (verify_parse_entry(STR(get_buf), &addr_status,	/* syntax OK */
578 			       &probed, &updated, &text) == 0
579 	    && (now - probed < PROBE_TTL	/* probe in progress */
580 		|| !POS_OR_NEG_ENTRY_EXPIRED(addr_status, updated)));
581 }
582 
583 /* verify_service - perform service for client */
584 
verify_service(VSTREAM * client_stream,char * unused_service,char ** argv)585 static void verify_service(VSTREAM *client_stream, char *unused_service,
586 			           char **argv)
587 {
588     VSTRING *request = vstring_alloc(10);
589 
590     /*
591      * Sanity check. This service takes no command-line arguments.
592      */
593     if (argv[0])
594 	msg_fatal("unexpected command-line argument: %s", argv[0]);
595 
596     /*
597      * This routine runs whenever a client connects to the socket dedicated
598      * to the address verification service. All connection-management stuff
599      * is handled by the common code in multi_server.c.
600      */
601     if (attr_scan(client_stream,
602 		  ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
603 		  RECV_ATTR_STR(MAIL_ATTR_REQ, request),
604 		  ATTR_TYPE_END) == 1) {
605 	if (STREQ(STR(request), VRFY_REQ_UPDATE)) {
606 	    verify_update_service(client_stream);
607 	} else if (STREQ(STR(request), VRFY_REQ_QUERY)) {
608 	    verify_query_service(client_stream);
609 	} else {
610 	    msg_warn("unrecognized request: \"%s\", ignored", STR(request));
611 	    attr_print(client_stream, ATTR_FLAG_NONE,
612 		       SEND_ATTR_INT(MAIL_ATTR_STATUS, VRFY_STAT_BAD),
613 		       ATTR_TYPE_END);
614 	}
615     }
616     vstream_fflush(client_stream);
617     vstring_free(request);
618 }
619 
620 /* verify_dump - dump some statistics */
621 
verify_dump(char * unused_name,char ** unused_argv)622 static void verify_dump(char *unused_name, char **unused_argv)
623 {
624 
625     /*
626      * Dump preliminary cache cleanup statistics when the process commits
627      * suicide while a cache cleanup run is in progress. We can't currently
628      * distinguish between "postfix reload" (we should restart) or "maximal
629      * idle time reached" (we could finish the cache cleanup first).
630      */
631     dict_cache_close(verify_map);
632     verify_map = 0;
633 }
634 
635 /* post_jail_init - post-jail initialization */
636 
post_jail_init(char * unused_name,char ** unused_argv)637 static void post_jail_init(char *unused_name, char **unused_argv)
638 {
639 
640     /*
641      * If the database is in volatile memory only, prevent automatic process
642      * suicide after a limited number of client requests or after a limited
643      * amount of idle time.
644      */
645     if (*var_verify_map == 0) {
646 	var_use_limit = 0;
647 	var_idle_limit = 0;
648     }
649 
650     /*
651      * Start the cache cleanup thread.
652      */
653     if (var_verify_scan_cache > 0) {
654 	int     cache_flags;
655 
656 	cache_flags = DICT_CACHE_FLAG_STATISTICS;
657 	if (msg_verbose)
658 	    cache_flags |= DICT_CACHE_FLAG_VERBOSE;
659 	dict_cache_control(verify_map,
660 			   CA_DICT_CACHE_CTL_FLAGS(cache_flags),
661 			   CA_DICT_CACHE_CTL_INTERVAL(var_verify_scan_cache),
662 			CA_DICT_CACHE_CTL_VALIDATOR(verify_cache_validator),
663 		     CA_DICT_CACHE_CTL_CONTEXT((void *) vstring_alloc(100)),
664 			   CA_DICT_CACHE_CTL_END);
665     }
666 }
667 
668 /* pre_jail_init - pre-jail initialization */
669 
pre_jail_init(char * unused_name,char ** unused_argv)670 static void pre_jail_init(char *unused_name, char **unused_argv)
671 {
672     mode_t  saved_mask;
673     VSTRING *redirect;
674 
675     /*
676      * Never, ever, get killed by a master signal, as that would corrupt the
677      * database when we're in the middle of an update.
678      */
679     setsid();
680 
681     /*
682      * Security: don't create root-owned files that contain untrusted data.
683      * And don't create Postfix-owned files in root-owned directories,
684      * either. We want a correct relationship between (file/directory)
685      * ownership and (file/directory) content.
686      *
687      * XXX Non-root open can violate the principle of least surprise: Postfix
688      * can't open an *SQL config file for database read-write access, even
689      * though it can open that same control file for database read-only
690      * access.
691      *
692      * The solution is to query a map type and obtain its properties before
693      * opening it. A clean solution is to add a dict_info() API that is
694      * similar to dict_open() except it returns properties (dict flags) only.
695      * A pragmatic solution is to overload the existing API and have
696      * dict_open() return a dummy map when given a null map name.
697      *
698      * However, the proxymap daemon has been opening *SQL maps as non-root for
699      * years now without anyone complaining, let's not solve a problem that
700      * doesn't exist.
701      */
702     SAVE_AND_SET_EUGID(var_owner_uid, var_owner_gid);
703     redirect = vstring_alloc(100);
704 
705     /*
706      * Keep state in persistent (external) or volatile (internal) map.
707      *
708      * Start the cache cleanup thread after permanently dropping privileges.
709      */
710 #define VERIFY_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE \
711 	    | DICT_FLAG_OPEN_LOCK | DICT_FLAG_UTF8_REQUEST)
712 
713     saved_mask = umask(022);
714     verify_map =
715 	dict_cache_open(*var_verify_map ?
716 			data_redirect_map(redirect, var_verify_map) :
717 			"internal:verify",
718 			O_CREAT | O_RDWR, VERIFY_DICT_OPEN_FLAGS);
719     (void) umask(saved_mask);
720 
721     /*
722      * Clean up and restore privilege.
723      */
724     vstring_free(redirect);
725     RESTORE_SAVED_EUGID();
726 }
727 
728 /* post_accept_init - announce our protocol */
729 
post_accept_init(VSTREAM * stream,char * unused_name,char ** unused_argv,HTABLE * unused_table)730 static void post_accept_init(VSTREAM *stream, char *unused_name,
731 			           char **unused_argv, HTABLE *unused_table)
732 {
733 
734     /*
735      * Announce the protocol.
736      */
737     attr_print(stream, ATTR_FLAG_NONE,
738 	       SEND_ATTR_STR(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_VERIFY),
739 	       ATTR_TYPE_END);
740     (void) vstream_fflush(stream);
741 }
742 
743 MAIL_VERSION_STAMP_DECLARE;
744 
745 /* main - pass control to the multi-threaded skeleton */
746 
main(int argc,char ** argv)747 int     main(int argc, char **argv)
748 {
749     static const CONFIG_STR_TABLE str_table[] = {
750 	VAR_VERIFY_MAP, DEF_VERIFY_MAP, &var_verify_map, 0, 0,
751 	VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender, 0, 0,
752 	0,
753     };
754     static const CONFIG_TIME_TABLE time_table[] = {
755 	VAR_VERIFY_POS_EXP, DEF_VERIFY_POS_EXP, &var_verify_pos_exp, 1, 0,
756 	VAR_VERIFY_POS_TRY, DEF_VERIFY_POS_TRY, &var_verify_pos_try, 1, 0,
757 	VAR_VERIFY_NEG_EXP, DEF_VERIFY_NEG_EXP, &var_verify_neg_exp, 1, 0,
758 	VAR_VERIFY_NEG_TRY, DEF_VERIFY_NEG_TRY, &var_verify_neg_try, 1, 0,
759 	VAR_VERIFY_SCAN_CACHE, DEF_VERIFY_SCAN_CACHE, &var_verify_scan_cache, 0, 0,
760 	VAR_VERIFY_SENDER_TTL, DEF_VERIFY_SENDER_TTL, &var_verify_sender_ttl, 0, 0,
761 	0,
762     };
763 
764     /*
765      * Fingerprint executables and core dumps.
766      */
767     MAIL_VERSION_STAMP_ALLOCATE;
768 
769     multi_server_main(argc, argv, verify_service,
770 		      CA_MAIL_SERVER_STR_TABLE(str_table),
771 		      CA_MAIL_SERVER_TIME_TABLE(time_table),
772 		      CA_MAIL_SERVER_PRE_INIT(pre_jail_init),
773 		      CA_MAIL_SERVER_POST_INIT(post_jail_init),
774 		      CA_MAIL_SERVER_POST_ACCEPT(post_accept_init),
775 		      CA_MAIL_SERVER_SOLITARY,
776 		      CA_MAIL_SERVER_EXIT(verify_dump),
777 		      0);
778 }
779