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