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