xref: /netbsd-src/external/ibm-public/postfix/dist/src/qmqpd/qmqpd.c (revision e7ac2a8b5bd66fa2e050809de09a075c36a7014d)
1 /*	$NetBSD: qmqpd.c,v 1.3 2020/03/18 19:05:19 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	qmqpd 8
6 /* SUMMARY
7 /*	Postfix QMQP server
8 /* SYNOPSIS
9 /*	\fBqmqpd\fR [generic Postfix daemon options]
10 /* DESCRIPTION
11 /*	The Postfix QMQP server receives one message per connection.
12 /*	Each message is piped through the \fBcleanup\fR(8)
13 /*	daemon, and is placed into the \fBincoming\fR queue as one
14 /*	single queue file.  The program expects to be run from the
15 /*	\fBmaster\fR(8) process manager.
16 /*
17 /*	The QMQP server implements one access policy: only explicitly
18 /*	authorized client hosts are allowed to use the service.
19 /* SECURITY
20 /* .ad
21 /* .fi
22 /*	The QMQP server is moderately security-sensitive. It talks to QMQP
23 /*	clients and to DNS servers on the network. The QMQP server can be
24 /*	run chrooted at fixed low privilege.
25 /* DIAGNOSTICS
26 /*	Problems and transactions are logged to \fBsyslogd\fR(8)
27 /*	or \fBpostlogd\fR(8).
28 /* BUGS
29 /*	The QMQP protocol provides only one server reply per message
30 /*	delivery. It is therefore not possible to reject individual
31 /*	recipients.
32 /*
33 /*	The QMQP protocol requires the server to receive the entire
34 /*	message before replying. If a message is malformed, or if any
35 /*	netstring component is longer than acceptable, Postfix replies
36 /*	immediately and closes the connection. It is left up to the
37 /*	client to handle the situation.
38 /* CONFIGURATION PARAMETERS
39 /* .ad
40 /* .fi
41 /*	Changes to \fBmain.cf\fR are picked up automatically, as \fBqmqpd\fR(8)
42 /*	processes run for only a limited amount of time. Use the command
43 /*	"\fBpostfix reload\fR" to speed up a change.
44 /*
45 /*	The text below provides only a parameter summary. See
46 /*	\fBpostconf\fR(5) for more details including examples.
47 /* CONTENT INSPECTION CONTROLS
48 /* .ad
49 /* .fi
50 /* .IP "\fBcontent_filter (empty)\fR"
51 /*	After the message is queued, send the entire message to the
52 /*	specified \fItransport:destination\fR.
53 /* .IP "\fBreceive_override_options (empty)\fR"
54 /*	Enable or disable recipient validation, built-in content
55 /*	filtering, or address mapping.
56 /* SMTPUTF8 CONTROLS
57 /* .ad
58 /* .fi
59 /*	Preliminary SMTPUTF8 support is introduced with Postfix 3.0.
60 /* .IP "\fBsmtputf8_enable (yes)\fR"
61 /*	Enable preliminary SMTPUTF8 support for the protocols described
62 /*	in RFC 6531..6533.
63 /* .IP "\fBsmtputf8_autodetect_classes (sendmail, verify)\fR"
64 /*	Detect that a message requires SMTPUTF8 support for the specified
65 /*	mail origin classes.
66 /* .PP
67 /*	Available in Postfix version 3.2 and later:
68 /* .IP "\fBenable_idna2003_compatibility (no)\fR"
69 /*	Enable 'transitional' compatibility between IDNA2003 and IDNA2008,
70 /*	when converting UTF-8 domain names to/from the ASCII form that is
71 /*	used for DNS lookups.
72 /* RESOURCE AND RATE CONTROLS
73 /* .ad
74 /* .fi
75 /* .IP "\fBline_length_limit (2048)\fR"
76 /*	Upon input, long lines are chopped up into pieces of at most
77 /*	this length; upon delivery, long lines are reconstructed.
78 /* .IP "\fBhopcount_limit (50)\fR"
79 /*	The maximal number of Received:  message headers that is allowed
80 /*	in the primary message headers.
81 /* .IP "\fBmessage_size_limit (10240000)\fR"
82 /*	The maximal size in bytes of a message, including envelope information.
83 /* .IP "\fBqmqpd_timeout (300s)\fR"
84 /*	The time limit for sending or receiving information over the network.
85 /* TROUBLE SHOOTING CONTROLS
86 /* .ad
87 /* .fi
88 /* .IP "\fBdebug_peer_level (2)\fR"
89 /*	The increment in verbose logging level when a remote client or
90 /*	server matches a pattern in the debug_peer_list parameter.
91 /* .IP "\fBdebug_peer_list (empty)\fR"
92 /*	Optional list of remote client or server hostname or network
93 /*	address patterns that cause the verbose logging level to increase
94 /*	by the amount specified in $debug_peer_level.
95 /* .IP "\fBsoft_bounce (no)\fR"
96 /*	Safety net to keep mail queued that would otherwise be returned to
97 /*	the sender.
98 /* TARPIT CONTROLS
99 /* .ad
100 /* .fi
101 /* .IP "\fBqmqpd_error_delay (1s)\fR"
102 /*	How long the Postfix QMQP server will pause before sending a negative
103 /*	reply to the remote QMQP client.
104 /* MISCELLANEOUS CONTROLS
105 /* .ad
106 /* .fi
107 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
108 /*	The default location of the Postfix main.cf and master.cf
109 /*	configuration files.
110 /* .IP "\fBdaemon_timeout (18000s)\fR"
111 /*	How much time a Postfix daemon process may take to handle a
112 /*	request before it is terminated by a built-in watchdog timer.
113 /* .IP "\fBipc_timeout (3600s)\fR"
114 /*	The time limit for sending or receiving information over an internal
115 /*	communication channel.
116 /* .IP "\fBmax_idle (100s)\fR"
117 /*	The maximum amount of time that an idle Postfix daemon process waits
118 /*	for an incoming connection before terminating voluntarily.
119 /* .IP "\fBmax_use (100)\fR"
120 /*	The maximal number of incoming connections that a Postfix daemon
121 /*	process will service before terminating voluntarily.
122 /* .IP "\fBprocess_id (read-only)\fR"
123 /*	The process ID of a Postfix command or daemon process.
124 /* .IP "\fBprocess_name (read-only)\fR"
125 /*	The process name of a Postfix command or daemon process.
126 /* .IP "\fBqmqpd_authorized_clients (empty)\fR"
127 /*	What remote QMQP clients are allowed to connect to the Postfix QMQP
128 /*	server port.
129 /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
130 /*	The location of the Postfix top-level queue directory.
131 /* .IP "\fBsyslog_facility (mail)\fR"
132 /*	The syslog facility of Postfix logging.
133 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
134 /*	A prefix that is prepended to the process name in syslog
135 /*	records, so that, for example, "smtpd" becomes "prefix/smtpd".
136 /* .IP "\fBverp_delimiter_filter (-=+)\fR"
137 /*	The characters Postfix accepts as VERP delimiter characters on the
138 /*	Postfix \fBsendmail\fR(1) command line and in SMTP commands.
139 /* .PP
140 /*	Available in Postfix version 2.5 and later:
141 /* .IP "\fBqmqpd_client_port_logging (no)\fR"
142 /*	Enable logging of the remote QMQP client port in addition to
143 /*	the hostname and IP address.
144 /* .PP
145 /*	Available in Postfix 3.3 and later:
146 /* .IP "\fBservice_name (read-only)\fR"
147 /*	The master.cf service name of a Postfix daemon process.
148 /* SEE ALSO
149 /*	http://cr.yp.to/proto/qmqp.html, QMQP protocol
150 /*	cleanup(8), message canonicalization
151 /*	master(8), process manager
152 /*	postlogd(8), Postfix logging
153 /*	syslogd(8), system logging
154 /* README FILES
155 /* .ad
156 /* .fi
157 /*	Use "\fBpostconf readme_directory\fR" or
158 /*	"\fBpostconf html_directory\fR" to locate this information.
159 /* .na
160 /* .nf
161 /*	QMQP_README, Postfix ezmlm-idx howto.
162 /* LICENSE
163 /* .ad
164 /* .fi
165 /*	The Secure Mailer license must be distributed with this software.
166 /* HISTORY
167 /* .ad
168 /* .fi
169 /*	The qmqpd service was introduced with Postfix version 1.1.
170 /* AUTHOR(S)
171 /*	Wietse Venema
172 /*	IBM T.J. Watson Research
173 /*	P.O. Box 704
174 /*	Yorktown Heights, NY 10598, USA
175 /*
176 /*	Wietse Venema
177 /*	Google, Inc.
178 /*	111 8th Avenue
179 /*	New York, NY 10011, USA
180 /*--*/
181 
182 /* System library. */
183 
184 #include <sys_defs.h>
185 #include <string.h>
186 #include <unistd.h>
187 #include <stdlib.h>
188 #include <ctype.h>
189 #include <stdarg.h>
190 
191 /* Utility library. */
192 
193 #include <msg.h>
194 #include <mymalloc.h>
195 #include <vstring.h>
196 #include <vstream.h>
197 #include <netstring.h>
198 #include <dict.h>
199 #include <inet_proto.h>
200 
201 /* Global library. */
202 
203 #include <mail_params.h>
204 #include <mail_version.h>
205 #include <record.h>
206 #include <rec_type.h>
207 #include <mail_proto.h>
208 #include <cleanup_user.h>
209 #include <mail_date.h>
210 #include <mail_conf.h>
211 #include <debug_peer.h>
212 #include <mail_stream.h>
213 #include <namadr_list.h>
214 #include <quote_822_local.h>
215 #include <match_parent_style.h>
216 #include <lex_822.h>
217 #include <verp_sender.h>
218 #include <input_transp.h>
219 #include <smtputf8.h>
220 
221 /* Single-threaded server skeleton. */
222 
223 #include <mail_server.h>
224 
225 /* Application-specific */
226 
227 #include <qmqpd.h>
228 
229  /*
230   * Tunable parameters. Make sure that there is some bound on the length of a
231   * netstring, so that the mail system stays in control even when a malicious
232   * client sends netstrings of unreasonable length. The recipient count limit
233   * is enforced by the message size limit.
234   */
235 int     var_qmqpd_timeout;
236 int     var_qmqpd_err_sleep;
237 char   *var_filter_xport;
238 char   *var_qmqpd_clients;
239 char   *var_input_transp;
240 bool    var_qmqpd_client_port_log;
241 
242  /*
243   * Silly little macros.
244   */
245 #define STR(x)	vstring_str(x)
246 #define LEN(x)	VSTRING_LEN(x)
247 
248 #define DO_LOG		1
249 #define DONT_LOG	0
250 
251  /*
252   * Access control. This service should be exposed only to explicitly
253   * authorized clients. There is no default authorization.
254   */
255 static NAMADR_LIST *qmqpd_clients;
256 
257  /*
258   * Transparency: before mail is queued, do we allow address mapping,
259   * automatic bcc, header/body checks?
260   */
261 int     qmqpd_input_transp_mask;
262 
263 /* qmqpd_open_file - open a queue file */
264 
265 static void qmqpd_open_file(QMQPD_STATE *state)
266 {
267     int     cleanup_flags;
268 
269     /*
270      * Connect to the cleanup server. Log client name/address with queue ID.
271      */
272     cleanup_flags = input_transp_cleanup(CLEANUP_FLAG_MASK_EXTERNAL,
273 					 qmqpd_input_transp_mask);
274     cleanup_flags |= smtputf8_autodetect(MAIL_SRC_MASK_QMQPD);
275     state->dest = mail_stream_service(MAIL_CLASS_PUBLIC, var_cleanup_service);
276     if (state->dest == 0
277 	|| attr_print(state->dest->stream, ATTR_FLAG_NONE,
278 		      SEND_ATTR_INT(MAIL_ATTR_FLAGS, cleanup_flags),
279 		      ATTR_TYPE_END) != 0)
280 	msg_fatal("unable to connect to the %s %s service",
281 		  MAIL_CLASS_PUBLIC, var_cleanup_service);
282     state->cleanup = state->dest->stream;
283     state->queue_id = mystrdup(state->dest->id);
284     msg_info("%s: client=%s", state->queue_id, state->namaddr);
285 
286     /*
287      * Record the time of arrival. Optionally, enable content filtering (not
288      * bloody likely, but present for the sake of consistency with all other
289      * Postfix points of entrance).
290      */
291     rec_fprintf(state->cleanup, REC_TYPE_TIME, REC_TYPE_TIME_FORMAT,
292 		REC_TYPE_TIME_ARG(state->arrival_time));
293     if (*var_filter_xport)
294 	rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport);
295 }
296 
297 /* qmqpd_read_content - receive message content */
298 
299 static void qmqpd_read_content(QMQPD_STATE *state)
300 {
301     state->where = "receiving message content";
302     netstring_get(state->client, state->message, var_message_limit);
303 }
304 
305 /* qmqpd_copy_sender - copy envelope sender */
306 
307 static void qmqpd_copy_sender(QMQPD_STATE *state)
308 {
309     char   *end_prefix;
310     char   *end_origin;
311     int     verp_requested;
312     static char verp_delims[] = "-=";
313 
314     /*
315      * If the sender address looks like prefix@origin-@[], then request
316      * variable envelope return path delivery, with an envelope sender
317      * address of prefi@origin, and with VERP delimiters of x and =. This
318      * way, the recipients will see envelope sender addresses that look like:
319      * prefixuser=domain@origin.
320      */
321     state->where = "receiving sender address";
322     netstring_get(state->client, state->buf, var_line_limit);
323     VSTRING_TERMINATE(state->buf);
324     verp_requested =
325 	((end_origin = vstring_end(state->buf) - 4) > STR(state->buf)
326 	 && strcmp(end_origin, "-@[]") == 0
327 	 && (end_prefix = strchr(STR(state->buf), '@')) != 0	/* XXX */
328 	 && --end_prefix < end_origin - 2	/* non-null origin */
329 	 && end_prefix > STR(state->buf));	/* non-null prefix */
330     if (verp_requested) {
331 	verp_delims[0] = end_prefix[0];
332 	if (verp_delims_verify(verp_delims) != 0) {
333 	    state->err |= CLEANUP_STAT_CONT;	/* XXX */
334 	    vstring_sprintf(state->why_rejected, "Invalid VERP delimiters: \"%s\". Need two characters from \"%s\"",
335 			    verp_delims, var_verp_filter);
336 	}
337 	memmove(end_prefix, end_prefix + 1, end_origin - end_prefix - 1);
338 	vstring_truncate(state->buf, end_origin - STR(state->buf) - 1);
339     }
340     if (state->err == CLEANUP_STAT_OK
341 	&& REC_PUT_BUF(state->cleanup, REC_TYPE_FROM, state->buf) < 0)
342 	state->err = CLEANUP_STAT_WRITE;
343     if (verp_requested)
344 	if (state->err == CLEANUP_STAT_OK
345 	    && rec_put(state->cleanup, REC_TYPE_VERP, verp_delims, 2) < 0)
346 	    state->err = CLEANUP_STAT_WRITE;
347     state->sender = mystrndup(STR(state->buf), LEN(state->buf));
348 }
349 
350 /* qmqpd_write_attributes - save session attributes */
351 
352 static void qmqpd_write_attributes(QMQPD_STATE *state)
353 {
354 
355     /*
356      * Logging attributes, also used for XFORWARD.
357      */
358     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
359 		MAIL_ATTR_LOG_CLIENT_NAME, state->name);
360     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
361 		MAIL_ATTR_LOG_CLIENT_ADDR, state->rfc_addr);
362     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
363 		MAIL_ATTR_LOG_CLIENT_PORT, state->port);
364     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
365 		MAIL_ATTR_LOG_ORIGIN, state->namaddr);
366     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
367 		MAIL_ATTR_LOG_PROTO_NAME, state->protocol);
368 
369     /*
370      * For consistency with the smtpd Milter client, we need to provide the
371      * real client attributes to the cleanup Milter client. This does not
372      * matter much with qmqpd which speaks to trusted clients only, but we
373      * want to be sure that the cleanup input protocol is ready when a new
374      * type of network daemon is added to receive mail from the Internet.
375      *
376      * See also the comments in smtpd.c.
377      */
378     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
379 		MAIL_ATTR_ACT_CLIENT_NAME, state->name);
380     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
381 		MAIL_ATTR_ACT_CLIENT_ADDR, state->addr);
382     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
383 		MAIL_ATTR_ACT_CLIENT_PORT, state->port);
384     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%u",
385 		MAIL_ATTR_ACT_CLIENT_AF, state->addr_family);
386     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
387 		MAIL_ATTR_ACT_PROTO_NAME, state->protocol);
388 
389     /* XXX What about the address rewriting context? */
390 }
391 
392 /* qmqpd_copy_recipients - copy message recipients */
393 
394 static void qmqpd_copy_recipients(QMQPD_STATE *state)
395 {
396     int     ch;
397 
398     /*
399      * Remember the first recipient. We are done when we read the over-all
400      * netstring terminator.
401      *
402      * XXX This approach violates abstractions, but it is a heck of a lot more
403      * convenient than counting the over-all byte count down to zero, like
404      * qmail does.
405      */
406     state->where = "receiving recipient address";
407     while ((ch = VSTREAM_GETC(state->client)) != ',') {
408 	vstream_ungetc(state->client, ch);
409 	netstring_get(state->client, state->buf, var_line_limit);
410 	if (state->err == CLEANUP_STAT_OK
411 	    && REC_PUT_BUF(state->cleanup, REC_TYPE_RCPT, state->buf) < 0)
412 	    state->err = CLEANUP_STAT_WRITE;
413 	state->rcpt_count++;
414 	if (state->recipient == 0)
415 	    state->recipient = mystrndup(STR(state->buf), LEN(state->buf));
416     }
417 }
418 
419 /* qmqpd_next_line - get line from buffer, return last char, newline, or -1 */
420 
421 static int qmqpd_next_line(VSTRING *message, char **start, int *len,
422 			           char **next)
423 {
424     char   *beyond = STR(message) + LEN(message);
425     char   *enough = *next + var_line_limit;
426     char   *cp;
427 
428     /*
429      * Stop at newline or at some limit. Don't look beyond the end of the
430      * buffer.
431      */
432 #define UCHARPTR(x) ((unsigned char *) (x))
433 
434     for (cp = *start = *next; /* void */ ; cp++) {
435 	if (cp >= beyond)
436 	    return ((*len = (*next = cp) - *start) > 0 ? UCHARPTR(cp)[-1] : -1);
437 	if (*cp == '\n')
438 	    return ((*len = cp - *start), (*next = cp + 1), '\n');
439 	if (cp >= enough)
440 	    return ((*len = cp - *start), (*next = cp), UCHARPTR(cp)[-1]);
441     }
442 }
443 
444 /* qmqpd_write_content - write the message content segment */
445 
446 static void qmqpd_write_content(QMQPD_STATE *state)
447 {
448     char   *start;
449     char   *next;
450     int     len;
451     int     rec_type;
452     int     first = 1;
453     int     ch;
454 
455     /*
456      * Start the message content segment. Prepend our own Received: header to
457      * the message content. List the recipient only when a message has one
458      * recipient. Otherwise, don't list the recipient to avoid revealing Bcc:
459      * recipients that are supposed to be invisible.
460      */
461     rec_fputs(state->cleanup, REC_TYPE_MESG, "");
462     rec_fprintf(state->cleanup, REC_TYPE_NORM, "Received: from %s (%s [%s])",
463 		state->name, state->name, state->rfc_addr);
464     if (state->rcpt_count == 1 && state->recipient) {
465 	rec_fprintf(state->cleanup, REC_TYPE_NORM,
466 		    "\tby %s (%s) with %s id %s",
467 		    var_myhostname, var_mail_name,
468 		    state->protocol, state->queue_id);
469 	quote_822_local(state->buf, state->recipient);
470 	rec_fprintf(state->cleanup, REC_TYPE_NORM,
471 		    "\tfor <%s>; %s", STR(state->buf),
472 		    mail_date(state->arrival_time.tv_sec));
473     } else {
474 	rec_fprintf(state->cleanup, REC_TYPE_NORM,
475 		    "\tby %s (%s) with %s",
476 		    var_myhostname, var_mail_name, state->protocol);
477 	rec_fprintf(state->cleanup, REC_TYPE_NORM,
478 		    "\tid %s; %s", state->queue_id,
479 		    mail_date(state->arrival_time.tv_sec));
480     }
481 #ifdef RECEIVED_ENVELOPE_FROM
482     quote_822_local(state->buf, state->sender);
483     rec_fprintf(state->cleanup, REC_TYPE_NORM,
484 		"\t(envelope-from <%s>)", STR(state->buf));
485 #endif
486 
487     /*
488      * Write the message content.
489      *
490      * XXX Force an empty record when the queue file content begins with
491      * whitespace, so that it won't be considered as being part of our own
492      * Received: header. What an ugly Kluge.
493      *
494      * XXX Deal with UNIX-style From_ lines at the start of message content just
495      * in case.
496      */
497     for (next = STR(state->message); /* void */ ; /* void */ ) {
498 	if ((ch = qmqpd_next_line(state->message, &start, &len, &next)) < 0)
499 	    break;
500 	if (ch == '\n')
501 	    rec_type = REC_TYPE_NORM;
502 	else
503 	    rec_type = REC_TYPE_CONT;
504 	if (first) {
505 	    if (strncmp(start + strspn(start, ">"), "From ", 5) == 0) {
506 		rec_fprintf(state->cleanup, rec_type,
507 			    "X-Mailbox-Line: %.*s", len, start);
508 		continue;
509 	    }
510 	    first = 0;
511 	    if (len > 0 && IS_SPACE_TAB(start[0]))
512 		rec_put(state->cleanup, REC_TYPE_NORM, "", 0);
513 	}
514 	if (rec_put(state->cleanup, rec_type, start, len) < 0) {
515 	    state->err = CLEANUP_STAT_WRITE;
516 	    return;
517 	}
518     }
519 }
520 
521 /* qmqpd_close_file - close queue file */
522 
523 static void qmqpd_close_file(QMQPD_STATE *state)
524 {
525 
526     /*
527      * Send the end-of-segment markers.
528      */
529     if (state->err == CLEANUP_STAT_OK)
530 	if (rec_fputs(state->cleanup, REC_TYPE_XTRA, "") < 0
531 	    || rec_fputs(state->cleanup, REC_TYPE_END, "") < 0
532 	    || vstream_fflush(state->cleanup))
533 	    state->err = CLEANUP_STAT_WRITE;
534 
535     /*
536      * Finish the queue file or finish the cleanup conversation.
537      */
538     if (state->err == 0)
539 	state->err = mail_stream_finish(state->dest, state->why_rejected);
540     else
541 	mail_stream_cleanup(state->dest);
542     state->dest = 0;
543 }
544 
545 /* qmqpd_reply - send status to client and optionally log message */
546 
547 static void qmqpd_reply(QMQPD_STATE *state, int log_message,
548 			        int status_code, const char *fmt,...)
549 {
550     va_list ap;
551 
552     /*
553      * Optionally change hard errors into retryable ones. Send the reply and
554      * optionally log it. Always insert a delay before reporting a problem.
555      * This slows down software run-away conditions.
556      */
557     if (status_code == QMQPD_STAT_HARD && var_soft_bounce)
558 	status_code = QMQPD_STAT_RETRY;
559     VSTRING_RESET(state->buf);
560     VSTRING_ADDCH(state->buf, status_code);
561     va_start(ap, fmt);
562     vstring_vsprintf_append(state->buf, fmt, ap);
563     va_end(ap);
564     NETSTRING_PUT_BUF(state->client, state->buf);
565     if (log_message)
566 	(status_code == QMQPD_STAT_OK ? msg_info : msg_warn) ("%s: %s: %s",
567 		      state->queue_id, state->namaddr, STR(state->buf) + 1);
568     if (status_code != QMQPD_STAT_OK)
569 	sleep(var_qmqpd_err_sleep);
570     netstring_fflush(state->client);
571 }
572 
573 /* qmqpd_send_status - send mail transaction completion status */
574 
575 static void qmqpd_send_status(QMQPD_STATE *state)
576 {
577 
578     /*
579      * One message may suffer from multiple errors, so complain only about
580      * the most severe error.
581      *
582      * See also: smtpd.c
583      */
584     state->where = "sending completion status";
585 
586     if (state->err == CLEANUP_STAT_OK) {
587 	qmqpd_reply(state, DONT_LOG, QMQPD_STAT_OK,
588 		    "Ok: queued as %s", state->queue_id);
589     } else if ((state->err & CLEANUP_STAT_DEFER) != 0) {
590 	qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY,
591 		    "Error: %s", STR(state->why_rejected));
592     } else if ((state->err & CLEANUP_STAT_BAD) != 0) {
593 	qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY,
594 		    "Error: internal error %d", state->err);
595     } else if ((state->err & CLEANUP_STAT_SIZE) != 0) {
596 	qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD,
597 		    "Error: message too large");
598     } else if ((state->err & CLEANUP_STAT_HOPS) != 0) {
599 	qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD,
600 		    "Error: too many hops");
601     } else if ((state->err & CLEANUP_STAT_CONT) != 0) {
602 	qmqpd_reply(state, DO_LOG, STR(state->why_rejected)[0] == '4' ?
603 		    QMQPD_STAT_RETRY : QMQPD_STAT_HARD,
604 		    "Error: %s", STR(state->why_rejected));
605     } else if ((state->err & CLEANUP_STAT_WRITE) != 0) {
606 	qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY,
607 		    "Error: queue file write error");
608     } else if ((state->err & CLEANUP_STAT_RCPT) != 0) {
609 	qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD,
610 		    "Error: no recipients specified");
611     } else {
612 	qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY,
613 		    "Error: internal error %d", state->err);
614     }
615 }
616 
617 /* qmqpd_receive - receive QMQP message+sender+recipients */
618 
619 static void qmqpd_receive(QMQPD_STATE *state)
620 {
621 
622     /*
623      * Open a queue file. This must be first so that we can simplify the
624      * error logging and always include the queue ID information.
625      */
626     qmqpd_open_file(state);
627 
628     /*
629      * Read and ignore the over-all netstring length indicator.
630      */
631     state->where = "receiving QMQP packet header";
632     (void) netstring_get_length(state->client);
633 
634     /*
635      * XXX Read the message content into memory, because Postfix expects to
636      * store the sender before storing the message content. Fixing that
637      * requires changes to pickup, cleanup, qmgr, and perhaps elsewhere, so
638      * that will have to happen later when I have more time. However, QMQP is
639      * used for mailing list distribution, so the bulk of the volume is
640      * expected to be not message content but recipients, and recipients are
641      * not accumulated in memory.
642      */
643     qmqpd_read_content(state);
644 
645     /*
646      * Read and write the envelope sender.
647      */
648     qmqpd_copy_sender(state);
649 
650     /*
651      * Record some session attributes.
652      */
653     qmqpd_write_attributes(state);
654 
655     /*
656      * Read and write the envelope recipients, including the optional big
657      * brother recipient.
658      */
659     qmqpd_copy_recipients(state);
660 
661     /*
662      * Start the message content segment, prepend our own Received: header,
663      * and write the message content.
664      */
665     if (state->err == 0)
666 	qmqpd_write_content(state);
667 
668     /*
669      * Close the queue file.
670      */
671     qmqpd_close_file(state);
672 
673     /*
674      * Report the completion status to the client.
675      */
676     qmqpd_send_status(state);
677 }
678 
679 /* qmqpd_proto - speak the QMQP "protocol" */
680 
681 static void qmqpd_proto(QMQPD_STATE *state)
682 {
683     int     status;
684 
685     netstring_setup(state->client, var_qmqpd_timeout);
686 
687     switch (status = vstream_setjmp(state->client)) {
688 
689     default:
690 	msg_panic("qmqpd_proto: unknown status %d", status);
691 
692     case NETSTRING_ERR_EOF:
693 	state->reason = "lost connection";
694 	break;
695 
696     case NETSTRING_ERR_TIME:
697 	state->reason = "read/write timeout";
698 	break;
699 
700     case NETSTRING_ERR_FORMAT:
701 	state->reason = "netstring format error";
702 	if (vstream_setjmp(state->client) == 0)
703 	    if (state->reason && state->where)
704 		qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, "%s while %s",
705 			    state->reason, state->where);
706 	break;
707 
708     case NETSTRING_ERR_SIZE:
709 	state->reason = "netstring length exceeds storage limit";
710 	if (vstream_setjmp(state->client) == 0)
711 	    if (state->reason && state->where)
712 		qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, "%s while %s",
713 			    state->reason, state->where);
714 	break;
715 
716     case 0:
717 
718 	/*
719 	 * See if we want to talk to this client at all.
720 	 */
721 	if (namadr_list_match(qmqpd_clients, state->name, state->addr) != 0) {
722 	    qmqpd_receive(state);
723 	} else if (qmqpd_clients->error == 0) {
724 	    qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD,
725 			"Error: %s is not authorized to use this service",
726 			state->namaddr);
727 	} else {
728 	    qmqpd_reply(state, DONT_LOG, QMQPD_STAT_RETRY,
729 			"Error: server configuration error");
730 	}
731 	break;
732     }
733 
734     /*
735      * Log abnormal session termination. Indicate the last recognized state
736      * before things went wrong.
737      */
738     if (state->reason && state->where)
739 	msg_info("%s: %s: %s while %s",
740 		 state->queue_id ? state->queue_id : "NOQUEUE",
741 		 state->namaddr, state->reason, state->where);
742 }
743 
744 /* qmqpd_service - service one client */
745 
746 static void qmqpd_service(VSTREAM *stream, char *unused_service, char **argv)
747 {
748     QMQPD_STATE *state;
749 
750     /*
751      * Sanity check. This service takes no command-line arguments.
752      */
753     if (argv[0])
754 	msg_fatal("unexpected command-line argument: %s", argv[0]);
755 
756     /*
757      * For sanity, require that at least one of INET or INET6 is enabled.
758      * Otherwise, we can't look up interface information, and we can't
759      * convert names or addresses.
760      */
761     if (inet_proto_info()->ai_family_list[0] == 0)
762 	msg_fatal("all network protocols are disabled (%s = %s)",
763 		  VAR_INET_PROTOCOLS, var_inet_protocols);
764 
765     /*
766      * This routine runs when a client has connected to our network port.
767      * Look up and sanitize the peer name and initialize some connection-
768      * specific state.
769      */
770     state = qmqpd_state_alloc(stream);
771 
772     /*
773      * See if we need to turn on verbose logging for this client.
774      */
775     debug_peer_check(state->name, state->addr);
776 
777     /*
778      * Provide the QMQP service.
779      */
780     msg_info("connect from %s", state->namaddr);
781     qmqpd_proto(state);
782     msg_info("disconnect from %s", state->namaddr);
783 
784     /*
785      * After the client has gone away, clean up whatever we have set up at
786      * connection time.
787      */
788     debug_peer_restore();
789     qmqpd_state_free(state);
790 }
791 
792 /* pre_accept - see if tables have changed */
793 
794 static void pre_accept(char *unused_name, char **unused_argv)
795 {
796     const char *table;
797 
798     if ((table = dict_changed_name()) != 0) {
799 	msg_info("table %s has changed -- restarting", table);
800 	exit(0);
801     }
802 }
803 
804 /* pre_jail_init - pre-jail initialization */
805 
806 static void pre_jail_init(char *unused_name, char **unused_argv)
807 {
808     debug_peer_init();
809     qmqpd_clients =
810 	namadr_list_init(VAR_QMQPD_CLIENTS, MATCH_FLAG_RETURN
811 			 | match_parent_style(VAR_QMQPD_CLIENTS),
812 			 var_qmqpd_clients);
813 }
814 
815 /* post_jail_init - post-jail initialization */
816 
817 static void post_jail_init(char *unused_name, char **unused_argv)
818 {
819 
820     /*
821      * Initialize the receive transparency options: do we want unknown
822      * recipient checks, do we want address mapping.
823      */
824     qmqpd_input_transp_mask =
825     input_transp_mask(VAR_INPUT_TRANSP, var_input_transp);
826 }
827 
828 MAIL_VERSION_STAMP_DECLARE;
829 
830 /* main - the main program */
831 
832 int     main(int argc, char **argv)
833 {
834     static const CONFIG_TIME_TABLE time_table[] = {
835 	VAR_QMTPD_TMOUT, DEF_QMTPD_TMOUT, &var_qmqpd_timeout, 1, 0,
836 	VAR_QMTPD_ERR_SLEEP, DEF_QMTPD_ERR_SLEEP, &var_qmqpd_err_sleep, 0, 0,
837 	0,
838     };
839     static const CONFIG_STR_TABLE str_table[] = {
840 	VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0,
841 	VAR_QMQPD_CLIENTS, DEF_QMQPD_CLIENTS, &var_qmqpd_clients, 0, 0,
842 	VAR_INPUT_TRANSP, DEF_INPUT_TRANSP, &var_input_transp, 0, 0,
843 	0,
844     };
845     static const CONFIG_BOOL_TABLE bool_table[] = {
846 	VAR_QMQPD_CLIENT_PORT_LOG, DEF_QMQPD_CLIENT_PORT_LOG, &var_qmqpd_client_port_log,
847 	0,
848     };
849 
850     /*
851      * Fingerprint executables and core dumps.
852      */
853     MAIL_VERSION_STAMP_ALLOCATE;
854 
855     /*
856      * Pass control to the single-threaded service skeleton.
857      */
858     single_server_main(argc, argv, qmqpd_service,
859 		       CA_MAIL_SERVER_TIME_TABLE(time_table),
860 		       CA_MAIL_SERVER_STR_TABLE(str_table),
861 		       CA_MAIL_SERVER_BOOL_TABLE(bool_table),
862 		       CA_MAIL_SERVER_PRE_INIT(pre_jail_init),
863 		       CA_MAIL_SERVER_PRE_ACCEPT(pre_accept),
864 		       CA_MAIL_SERVER_POST_INIT(post_jail_init),
865 		       0);
866 }
867