Home | History | Annotate | Line # | Download | only in qmqpd
      1 /*	$NetBSD: qmqpd.c,v 1.5 2025/02/25 19:15:49 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, RFC 6532, and RFC 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 /*	https://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   */
    236 int     var_qmqpd_timeout;
    237 int     var_qmqpd_err_sleep;
    238 char   *var_filter_xport;
    239 char   *var_qmqpd_clients;
    240 char   *var_input_transp;
    241 bool    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   */
    256 static NAMADR_LIST *qmqpd_clients;
    257 
    258  /*
    259   * Transparency: before mail is queued, do we allow address mapping,
    260   * automatic bcc, header/body checks?
    261   */
    262 int     qmqpd_input_transp_mask;
    263 
    264 /* qmqpd_open_file - open a queue file */
    265 
    266 static 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     /* TODO(wietse) REQUIRETLS? */
    277     state->dest = mail_stream_service(MAIL_CLASS_PUBLIC, var_cleanup_service);
    278     if (state->dest == 0
    279 	|| attr_print(state->dest->stream, ATTR_FLAG_NONE,
    280 		      SEND_ATTR_INT(MAIL_ATTR_FLAGS, cleanup_flags),
    281 		      ATTR_TYPE_END) != 0)
    282 	msg_fatal("unable to connect to the %s %s service",
    283 		  MAIL_CLASS_PUBLIC, var_cleanup_service);
    284     state->cleanup = state->dest->stream;
    285     state->queue_id = mystrdup(state->dest->id);
    286     msg_info("%s: client=%s", state->queue_id, state->namaddr);
    287 
    288     /*
    289      * Record the time of arrival. Optionally, enable content filtering (not
    290      * bloody likely, but present for the sake of consistency with all other
    291      * Postfix points of entrance).
    292      */
    293     rec_fprintf(state->cleanup, REC_TYPE_TIME, REC_TYPE_TIME_FORMAT,
    294 		REC_TYPE_TIME_ARG(state->arrival_time));
    295     if (*var_filter_xport)
    296 	rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport);
    297 }
    298 
    299 /* qmqpd_read_content - receive message content */
    300 
    301 static void qmqpd_read_content(QMQPD_STATE *state)
    302 {
    303     state->where = "receiving message content";
    304     netstring_get(state->client, state->message, var_message_limit);
    305 }
    306 
    307 /* qmqpd_copy_sender - copy envelope sender */
    308 
    309 static void qmqpd_copy_sender(QMQPD_STATE *state)
    310 {
    311     char   *end_prefix;
    312     char   *end_origin;
    313     int     verp_requested;
    314     static char verp_delims[] = "-=";
    315 
    316     /*
    317      * If the sender address looks like prefix@origin-@[], then request
    318      * variable envelope return path delivery, with an envelope sender
    319      * address of prefi@origin, and with VERP delimiters of x and =. This
    320      * way, the recipients will see envelope sender addresses that look like:
    321      * prefixuser=domain@origin.
    322      */
    323     state->where = "receiving sender address";
    324     netstring_get(state->client, state->buf, var_line_limit);
    325     VSTRING_TERMINATE(state->buf);
    326     verp_requested =
    327 	((end_origin = vstring_end(state->buf) - 4) > STR(state->buf)
    328 	 && strcmp(end_origin, "-@[]") == 0
    329 	 && (end_prefix = strchr(STR(state->buf), '@')) != 0	/* XXX */
    330 	 && --end_prefix < end_origin - 2	/* non-null origin */
    331 	 && end_prefix > STR(state->buf));	/* non-null prefix */
    332     if (verp_requested) {
    333 	verp_delims[0] = end_prefix[0];
    334 	if (verp_delims_verify(verp_delims) != 0) {
    335 	    state->err |= CLEANUP_STAT_CONT;	/* XXX */
    336 	    vstring_sprintf(state->why_rejected, "Invalid VERP delimiters: \"%s\". Need two characters from \"%s\"",
    337 			    verp_delims, var_verp_filter);
    338 	}
    339 	memmove(end_prefix, end_prefix + 1, end_origin - end_prefix - 1);
    340 	vstring_truncate(state->buf, end_origin - STR(state->buf) - 1);
    341     }
    342     if (state->err == CLEANUP_STAT_OK
    343 	&& REC_PUT_BUF(state->cleanup, REC_TYPE_FROM, state->buf) < 0)
    344 	state->err = CLEANUP_STAT_WRITE;
    345     if (verp_requested)
    346 	if (state->err == CLEANUP_STAT_OK
    347 	    && rec_put(state->cleanup, REC_TYPE_VERP, verp_delims, 2) < 0)
    348 	    state->err = CLEANUP_STAT_WRITE;
    349     state->sender = mystrndup(STR(state->buf), LEN(state->buf));
    350 }
    351 
    352 /* qmqpd_write_attributes - save session attributes */
    353 
    354 static void qmqpd_write_attributes(QMQPD_STATE *state)
    355 {
    356 
    357     /*
    358      * Logging attributes, also used for XFORWARD.
    359      */
    360     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
    361 		MAIL_ATTR_LOG_CLIENT_NAME, state->name);
    362     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
    363 		MAIL_ATTR_LOG_CLIENT_ADDR, state->rfc_addr);
    364     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
    365 		MAIL_ATTR_LOG_CLIENT_PORT, state->port);
    366     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
    367 		MAIL_ATTR_LOG_ORIGIN, state->namaddr);
    368     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
    369 		MAIL_ATTR_LOG_PROTO_NAME, state->protocol);
    370 
    371     /*
    372      * For consistency with the smtpd Milter client, we need to provide the
    373      * real client attributes to the cleanup Milter client. This does not
    374      * matter much with qmqpd which speaks to trusted clients only, but we
    375      * want to be sure that the cleanup input protocol is ready when a new
    376      * type of network daemon is added to receive mail from the Internet.
    377      *
    378      * See also the comments in smtpd.c.
    379      */
    380     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
    381 		MAIL_ATTR_ACT_CLIENT_NAME, state->name);
    382     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
    383 		MAIL_ATTR_ACT_CLIENT_ADDR, state->addr);
    384     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
    385 		MAIL_ATTR_ACT_CLIENT_PORT, state->port);
    386     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%u",
    387 		MAIL_ATTR_ACT_CLIENT_AF, state->addr_family);
    388     rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
    389 		MAIL_ATTR_ACT_PROTO_NAME, state->protocol);
    390 
    391     /* XXX What about the address rewriting context? */
    392 }
    393 
    394 /* qmqpd_copy_recipients - copy message recipients */
    395 
    396 static void qmqpd_copy_recipients(QMQPD_STATE *state)
    397 {
    398     int     ch;
    399 
    400     /*
    401      * Remember the first recipient. We are done when we read the over-all
    402      * netstring terminator.
    403      *
    404      * XXX This approach violates abstractions, but it is a heck of a lot more
    405      * convenient than counting the over-all byte count down to zero, like
    406      * qmail does.
    407      */
    408     state->where = "receiving recipient address";
    409     while ((ch = VSTREAM_GETC(state->client)) != ',') {
    410 	vstream_ungetc(state->client, ch);
    411 	netstring_get(state->client, state->buf, var_line_limit);
    412 	if (state->err == CLEANUP_STAT_OK
    413 	    && REC_PUT_BUF(state->cleanup, REC_TYPE_RCPT, state->buf) < 0)
    414 	    state->err = CLEANUP_STAT_WRITE;
    415 	state->rcpt_count++;
    416 	if (state->recipient == 0)
    417 	    state->recipient = mystrndup(STR(state->buf), LEN(state->buf));
    418     }
    419 }
    420 
    421 /* qmqpd_next_line - get line from buffer, return last char, newline, or -1 */
    422 
    423 static int qmqpd_next_line(VSTRING *message, char **start, int *len,
    424 			           char **next)
    425 {
    426     char   *beyond = STR(message) + LEN(message);
    427     char   *enough = *next + var_line_limit;
    428     char   *cp;
    429 
    430     /*
    431      * Stop at newline or at some limit. Don't look beyond the end of the
    432      * buffer.
    433      */
    434 #define UCHARPTR(x) ((unsigned char *) (x))
    435 
    436     for (cp = *start = *next; /* void */ ; cp++) {
    437 	if (cp >= beyond)
    438 	    return ((*len = (*next = cp) - *start) > 0 ? UCHARPTR(cp)[-1] : -1);
    439 	if (*cp == '\n')
    440 	    return ((*len = cp - *start), (*next = cp + 1), '\n');
    441 	if (cp >= enough)
    442 	    return ((*len = cp - *start), (*next = cp), UCHARPTR(cp)[-1]);
    443     }
    444 }
    445 
    446 /* qmqpd_write_content - write the message content segment */
    447 
    448 static void qmqpd_write_content(QMQPD_STATE *state)
    449 {
    450     char   *start;
    451     char   *next;
    452     int     len;
    453     int     rec_type;
    454     int     first = 1;
    455     int     ch;
    456 
    457     /*
    458      * Start the message content segment. Prepend our own Received: header to
    459      * the message content. List the recipient only when a message has one
    460      * recipient. Otherwise, don't list the recipient to avoid revealing Bcc:
    461      * recipients that are supposed to be invisible.
    462      */
    463     rec_fputs(state->cleanup, REC_TYPE_MESG, "");
    464     rec_fprintf(state->cleanup, REC_TYPE_NORM, "Received: from %s (%s [%s])",
    465 		state->name, state->name, state->rfc_addr);
    466     if (state->rcpt_count == 1 && state->recipient) {
    467 	rec_fprintf(state->cleanup, REC_TYPE_NORM,
    468 		    "\tby %s (%s) with %s id %s",
    469 		    var_myhostname, var_mail_name,
    470 		    state->protocol, state->queue_id);
    471 	quote_822_local(state->buf, state->recipient);
    472 	rec_fprintf(state->cleanup, REC_TYPE_NORM,
    473 		    "\tfor <%s>; %s", STR(state->buf),
    474 		    mail_date(state->arrival_time.tv_sec));
    475     } else {
    476 	rec_fprintf(state->cleanup, REC_TYPE_NORM,
    477 		    "\tby %s (%s) with %s",
    478 		    var_myhostname, var_mail_name, state->protocol);
    479 	rec_fprintf(state->cleanup, REC_TYPE_NORM,
    480 		    "\tid %s; %s", state->queue_id,
    481 		    mail_date(state->arrival_time.tv_sec));
    482     }
    483 #ifdef RECEIVED_ENVELOPE_FROM
    484     quote_822_local(state->buf, state->sender);
    485     rec_fprintf(state->cleanup, REC_TYPE_NORM,
    486 		"\t(envelope-from <%s>)", STR(state->buf));
    487 #endif
    488 
    489     /*
    490      * Write the message content.
    491      *
    492      * XXX Force an empty record when the queue file content begins with
    493      * whitespace, so that it won't be considered as being part of our own
    494      * Received: header. What an ugly Kluge.
    495      *
    496      * XXX Deal with UNIX-style From_ lines at the start of message content just
    497      * in case.
    498      */
    499     for (next = STR(state->message); /* void */ ; /* void */ ) {
    500 	if ((ch = qmqpd_next_line(state->message, &start, &len, &next)) < 0)
    501 	    break;
    502 	if (ch == '\n')
    503 	    rec_type = REC_TYPE_NORM;
    504 	else
    505 	    rec_type = REC_TYPE_CONT;
    506 	if (first) {
    507 	    if (strncmp(start + strspn(start, ">"), "From ", 5) == 0) {
    508 		rec_fprintf(state->cleanup, rec_type,
    509 			    "X-Mailbox-Line: %.*s", len, start);
    510 		continue;
    511 	    }
    512 	    first = 0;
    513 	    if (len > 0 && IS_SPACE_TAB(start[0]))
    514 		rec_put(state->cleanup, REC_TYPE_NORM, "", 0);
    515 	}
    516 	if (rec_put(state->cleanup, rec_type, start, len) < 0) {
    517 	    state->err = CLEANUP_STAT_WRITE;
    518 	    return;
    519 	}
    520     }
    521 }
    522 
    523 /* qmqpd_close_file - close queue file */
    524 
    525 static void qmqpd_close_file(QMQPD_STATE *state)
    526 {
    527 
    528     /*
    529      * Send the end-of-segment markers.
    530      */
    531     if (state->err == CLEANUP_STAT_OK)
    532 	if (rec_fputs(state->cleanup, REC_TYPE_XTRA, "") < 0
    533 	    || rec_fputs(state->cleanup, REC_TYPE_END, "") < 0
    534 	    || vstream_fflush(state->cleanup))
    535 	    state->err = CLEANUP_STAT_WRITE;
    536 
    537     /*
    538      * Finish the queue file or finish the cleanup conversation.
    539      */
    540     if (state->err == 0)
    541 	state->err = mail_stream_finish(state->dest, state->why_rejected);
    542     else
    543 	mail_stream_cleanup(state->dest);
    544     state->dest = 0;
    545 }
    546 
    547 /* qmqpd_reply - send status to client and optionally log message */
    548 
    549 static void qmqpd_reply(QMQPD_STATE *state, int log_message,
    550 			        int status_code, const char *fmt,...)
    551 {
    552     va_list ap;
    553 
    554     /*
    555      * Optionally change hard errors into retryable ones. Send the reply and
    556      * optionally log it. Always insert a delay before reporting a problem.
    557      * This slows down software run-away conditions.
    558      */
    559     if (status_code == QMQPD_STAT_HARD && var_soft_bounce)
    560 	status_code = QMQPD_STAT_RETRY;
    561     VSTRING_RESET(state->buf);
    562     VSTRING_ADDCH(state->buf, status_code);
    563     va_start(ap, fmt);
    564     vstring_vsprintf_append(state->buf, fmt, ap);
    565     va_end(ap);
    566     NETSTRING_PUT_BUF(state->client, state->buf);
    567     if (log_message)
    568 	(status_code == QMQPD_STAT_OK ? msg_info : msg_warn) ("%s: %s: %s",
    569 		      state->queue_id, state->namaddr, STR(state->buf) + 1);
    570     if (status_code != QMQPD_STAT_OK)
    571 	sleep(var_qmqpd_err_sleep);
    572     netstring_fflush(state->client);
    573 }
    574 
    575 /* qmqpd_send_status - send mail transaction completion status */
    576 
    577 static void qmqpd_send_status(QMQPD_STATE *state)
    578 {
    579 
    580     /*
    581      * One message may suffer from multiple errors, so complain only about
    582      * the most severe error.
    583      *
    584      * See also: smtpd.c
    585      */
    586     state->where = "sending completion status";
    587 
    588     if (state->err == CLEANUP_STAT_OK) {
    589 	qmqpd_reply(state, DONT_LOG, QMQPD_STAT_OK,
    590 		    "Ok: queued as %s", state->queue_id);
    591     } else if ((state->err & CLEANUP_STAT_DEFER) != 0) {
    592 	qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY,
    593 		    "Error: %s", STR(state->why_rejected));
    594     } else if ((state->err & CLEANUP_STAT_BAD) != 0) {
    595 	qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY,
    596 		    "Error: internal error %d", state->err);
    597     } else if ((state->err & CLEANUP_STAT_SIZE) != 0) {
    598 	qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD,
    599 		    "Error: message too large");
    600     } else if ((state->err & CLEANUP_STAT_HOPS) != 0) {
    601 	qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD,
    602 		    "Error: too many hops");
    603     } else if ((state->err & CLEANUP_STAT_CONT) != 0) {
    604 	qmqpd_reply(state, DO_LOG, STR(state->why_rejected)[0] == '4' ?
    605 		    QMQPD_STAT_RETRY : QMQPD_STAT_HARD,
    606 		    "Error: %s", STR(state->why_rejected));
    607     } else if ((state->err & CLEANUP_STAT_WRITE) != 0) {
    608 	qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY,
    609 		    "Error: queue file write error");
    610     } else if ((state->err & CLEANUP_STAT_RCPT) != 0) {
    611 	qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD,
    612 		    "Error: no recipients specified");
    613     } else {
    614 	qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY,
    615 		    "Error: internal error %d", state->err);
    616     }
    617 }
    618 
    619 /* qmqpd_receive - receive QMQP message+sender+recipients */
    620 
    621 static void qmqpd_receive(QMQPD_STATE *state)
    622 {
    623 
    624     /*
    625      * Open a queue file. This must be first so that we can simplify the
    626      * error logging and always include the queue ID information.
    627      */
    628     qmqpd_open_file(state);
    629 
    630     /*
    631      * Read and ignore the over-all netstring length indicator.
    632      */
    633     state->where = "receiving QMQP packet header";
    634     (void) netstring_get_length(state->client);
    635 
    636     /*
    637      * XXX Read the message content into memory, because Postfix expects to
    638      * store the sender before storing the message content. Fixing that
    639      * requires changes to pickup, cleanup, qmgr, and perhaps elsewhere, so
    640      * that will have to happen later when I have more time. However, QMQP is
    641      * used for mailing list distribution, so the bulk of the volume is
    642      * expected to be not message content but recipients, and recipients are
    643      * not accumulated in memory.
    644      */
    645     qmqpd_read_content(state);
    646 
    647     /*
    648      * Read and write the envelope sender.
    649      */
    650     qmqpd_copy_sender(state);
    651 
    652     /*
    653      * Record some session attributes.
    654      */
    655     qmqpd_write_attributes(state);
    656 
    657     /*
    658      * Read and write the envelope recipients, including the optional big
    659      * brother recipient.
    660      */
    661     qmqpd_copy_recipients(state);
    662 
    663     /*
    664      * Start the message content segment, prepend our own Received: header,
    665      * and write the message content.
    666      */
    667     if (state->err == 0)
    668 	qmqpd_write_content(state);
    669 
    670     /*
    671      * Close the queue file.
    672      */
    673     qmqpd_close_file(state);
    674 
    675     /*
    676      * Report the completion status to the client.
    677      */
    678     qmqpd_send_status(state);
    679 }
    680 
    681 /* qmqpd_proto - speak the QMQP "protocol" */
    682 
    683 static void qmqpd_proto(QMQPD_STATE *state)
    684 {
    685     int     status;
    686 
    687     netstring_setup(state->client, var_qmqpd_timeout);
    688 
    689     switch (status = vstream_setjmp(state->client)) {
    690 
    691     default:
    692 	msg_panic("qmqpd_proto: unknown status %d", status);
    693 
    694     case NETSTRING_ERR_EOF:
    695 	state->reason = "lost connection";
    696 	break;
    697 
    698     case NETSTRING_ERR_TIME:
    699 	state->reason = "read/write timeout";
    700 	break;
    701 
    702     case NETSTRING_ERR_FORMAT:
    703 	state->reason = "netstring format error";
    704 	if (vstream_setjmp(state->client) == 0)
    705 	    if (state->reason && state->where)
    706 		qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, "%s while %s",
    707 			    state->reason, state->where);
    708 	break;
    709 
    710     case NETSTRING_ERR_SIZE:
    711 	state->reason = "netstring length exceeds storage limit";
    712 	if (vstream_setjmp(state->client) == 0)
    713 	    if (state->reason && state->where)
    714 		qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, "%s while %s",
    715 			    state->reason, state->where);
    716 	break;
    717 
    718     case 0:
    719 
    720 	/*
    721 	 * See if we want to talk to this client at all.
    722 	 */
    723 	if (namadr_list_match(qmqpd_clients, state->name, state->addr) != 0) {
    724 	    qmqpd_receive(state);
    725 	} else if (qmqpd_clients->error == 0) {
    726 	    qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD,
    727 			"Error: %s is not authorized to use this service",
    728 			state->namaddr);
    729 	} else {
    730 	    qmqpd_reply(state, DONT_LOG, QMQPD_STAT_RETRY,
    731 			"Error: server configuration error");
    732 	}
    733 	break;
    734     }
    735 
    736     /*
    737      * Log abnormal session termination. Indicate the last recognized state
    738      * before things went wrong.
    739      */
    740     if (state->reason && state->where)
    741 	msg_info("%s: %s: %s while %s",
    742 		 state->queue_id ? state->queue_id : "NOQUEUE",
    743 		 state->namaddr, state->reason, state->where);
    744 }
    745 
    746 /* qmqpd_service - service one client */
    747 
    748 static void qmqpd_service(VSTREAM *stream, char *unused_service, char **argv)
    749 {
    750     QMQPD_STATE *state;
    751 
    752     /*
    753      * Sanity check. This service takes no command-line arguments.
    754      */
    755     if (argv[0])
    756 	msg_fatal("unexpected command-line argument: %s", argv[0]);
    757 
    758     /*
    759      * For sanity, require that at least one of INET or INET6 is enabled.
    760      * Otherwise, we can't look up interface information, and we can't
    761      * convert names or addresses.
    762      */
    763     if (inet_proto_info()->ai_family_list[0] == 0)
    764 	msg_fatal("all network protocols are disabled (%s = %s)",
    765 		  VAR_INET_PROTOCOLS, var_inet_protocols);
    766 
    767     /*
    768      * This routine runs when a client has connected to our network port.
    769      * Look up and sanitize the peer name and initialize some connection-
    770      * specific state.
    771      */
    772     state = qmqpd_state_alloc(stream);
    773 
    774     /*
    775      * See if we need to turn on verbose logging for this client.
    776      */
    777     debug_peer_check(state->name, state->addr);
    778 
    779     /*
    780      * Provide the QMQP service.
    781      */
    782     msg_info("connect from %s", state->namaddr);
    783     qmqpd_proto(state);
    784     msg_info("disconnect from %s", state->namaddr);
    785 
    786     /*
    787      * After the client has gone away, clean up whatever we have set up at
    788      * connection time.
    789      */
    790     debug_peer_restore();
    791     qmqpd_state_free(state);
    792 }
    793 
    794 /* pre_accept - see if tables have changed */
    795 
    796 static void pre_accept(char *unused_name, char **unused_argv)
    797 {
    798     const char *table;
    799 
    800     if ((table = dict_changed_name()) != 0) {
    801 	msg_info("table %s has changed -- restarting", table);
    802 	exit(0);
    803     }
    804 }
    805 
    806 /* pre_jail_init - pre-jail initialization */
    807 
    808 static void pre_jail_init(char *unused_name, char **unused_argv)
    809 {
    810     debug_peer_init();
    811     qmqpd_clients =
    812 	namadr_list_init(VAR_QMQPD_CLIENTS, MATCH_FLAG_RETURN
    813 			 | match_parent_style(VAR_QMQPD_CLIENTS),
    814 			 var_qmqpd_clients);
    815 }
    816 
    817 /* post_jail_init - post-jail initialization */
    818 
    819 static void post_jail_init(char *unused_name, char **unused_argv)
    820 {
    821 
    822     /*
    823      * Initialize the receive transparency options: do we want unknown
    824      * recipient checks, do we want address mapping.
    825      */
    826     qmqpd_input_transp_mask =
    827     input_transp_mask(VAR_INPUT_TRANSP, var_input_transp);
    828 }
    829 
    830 MAIL_VERSION_STAMP_DECLARE;
    831 
    832 /* main - the main program */
    833 
    834 int     main(int argc, char **argv)
    835 {
    836     static const CONFIG_TIME_TABLE time_table[] = {
    837 	VAR_QMTPD_TMOUT, DEF_QMTPD_TMOUT, &var_qmqpd_timeout, 1, 0,
    838 	VAR_QMTPD_ERR_SLEEP, DEF_QMTPD_ERR_SLEEP, &var_qmqpd_err_sleep, 0, 0,
    839 	0,
    840     };
    841     static const CONFIG_STR_TABLE str_table[] = {
    842 	VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0,
    843 	VAR_QMQPD_CLIENTS, DEF_QMQPD_CLIENTS, &var_qmqpd_clients, 0, 0,
    844 	VAR_INPUT_TRANSP, DEF_INPUT_TRANSP, &var_input_transp, 0, 0,
    845 	0,
    846     };
    847     static const CONFIG_BOOL_TABLE bool_table[] = {
    848 	VAR_QMQPD_CLIENT_PORT_LOG, DEF_QMQPD_CLIENT_PORT_LOG, &var_qmqpd_client_port_log,
    849 	0,
    850     };
    851 
    852     /*
    853      * Fingerprint executables and core dumps.
    854      */
    855     MAIL_VERSION_STAMP_ALLOCATE;
    856 
    857     /*
    858      * Pass control to the single-threaded service skeleton.
    859      */
    860     single_server_main(argc, argv, qmqpd_service,
    861 		       CA_MAIL_SERVER_TIME_TABLE(time_table),
    862 		       CA_MAIL_SERVER_STR_TABLE(str_table),
    863 		       CA_MAIL_SERVER_BOOL_TABLE(bool_table),
    864 		       CA_MAIL_SERVER_PRE_INIT(pre_jail_init),
    865 		       CA_MAIL_SERVER_PRE_ACCEPT(pre_accept),
    866 		       CA_MAIL_SERVER_POST_INIT(post_jail_init),
    867 		       0);
    868 }
    869