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