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