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
qmqpd_open_file(QMQPD_STATE * state)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
qmqpd_read_content(QMQPD_STATE * state)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
qmqpd_copy_sender(QMQPD_STATE * state)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
qmqpd_write_attributes(QMQPD_STATE * state)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
qmqpd_copy_recipients(QMQPD_STATE * state)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
qmqpd_next_line(VSTRING * message,char ** start,int * len,char ** next)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
qmqpd_write_content(QMQPD_STATE * state)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
qmqpd_close_file(QMQPD_STATE * state)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
qmqpd_reply(QMQPD_STATE * state,int log_message,int status_code,const char * fmt,...)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
qmqpd_send_status(QMQPD_STATE * state)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
qmqpd_receive(QMQPD_STATE * state)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
qmqpd_proto(QMQPD_STATE * state)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
qmqpd_service(VSTREAM * stream,char * unused_service,char ** argv)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
pre_accept(char * unused_name,char ** unused_argv)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
pre_jail_init(char * unused_name,char ** unused_argv)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
post_jail_init(char * unused_name,char ** unused_argv)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
main(int argc,char ** argv)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