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