Postfix3.3.1
smtpd_proxy.c
[詳解]
1 /*++
2 /* NAME
3 /* smtpd_proxy 3
4 /* SUMMARY
5 /* SMTP server pass-through proxy client
6 /* SYNOPSIS
7 /* #include <smtpd.h>
8 /* #include <smtpd_proxy.h>
9 /*
10 /* typedef struct {
11 /* .in +4
12 /* VSTREAM *stream; /* SMTP proxy or replay log */
13 /* VSTRING *buffer; /* last SMTP proxy response */
14 /* /* other fields... */
15 /* .in -4
16 /* } SMTPD_PROXY;
17 /*
18 /* int smtpd_proxy_create(state, flags, service, timeout,
19 /* ehlo_name, mail_from)
20 /* SMTPD_STATE *state;
21 /* int flags;
22 /* const char *service;
23 /* int timeout;
24 /* const char *ehlo_name;
25 /* const char *mail_from;
26 /*
27 /* int proxy->cmd(state, expect, format, ...)
28 /* SMTPD_PROXY *proxy;
29 /* SMTPD_STATE *state;
30 /* int expect;
31 /* const char *format;
32 /*
33 /* void smtpd_proxy_free(state)
34 /* SMTPD_STATE *state;
35 /*
36 /* int smtpd_proxy_parse_opts(param_name, param_val)
37 /* const char *param_name;
38 /* const char *param_val;
39 /* RECORD-LEVEL ROUTINES
40 /* int proxy->rec_put(proxy->stream, rec_type, data, len)
41 /* SMTPD_PROXY *proxy;
42 /* int rec_type;
43 /* const char *data;
44 /* ssize_t len;
45 /*
46 /* int proxy->rec_fprintf(proxy->stream, rec_type, format, ...)
47 /* SMTPD_PROXY *proxy;
48 /* int rec_type;
49 /* cont char *format;
50 /* DESCRIPTION
51 /* The functions in this module implement a pass-through proxy
52 /* client.
53 /*
54 /* In order to minimize the intrusiveness of pass-through
55 /* proxying, 1) the proxy server must support the same MAIL
56 /* FROM/RCPT syntax that Postfix supports, 2) the record-level
57 /* routines for message content proxying have the same interface
58 /* as the routines that are used for non-proxied mail.
59 /*
60 /* smtpd_proxy_create() takes a description of a before-queue
61 /* filter. Depending on flags, it either arranges to buffer
62 /* up commands and message content until the entire message
63 /* is received, or it immediately connects to the proxy service,
64 /* sends EHLO, sends client information with the XFORWARD
65 /* command if possible, sends the MAIL FROM command, and
66 /* receives the reply.
67 /* A non-zero result value means trouble: either the proxy is
68 /* unavailable, or it did not send the expected reply.
69 /* All results are reported via the proxy->buffer field in a
70 /* form that can be sent to the SMTP client. An unexpected
71 /* 2xx or 3xx proxy server response is replaced by a generic
72 /* error response to avoid support problems.
73 /* In case of error, smtpd_proxy_create() updates the
74 /* state->error_mask and state->err fields, and leaves the
75 /* SMTPD_PROXY handle in an unconnected state. Destroy the
76 /* handle after reporting the error reply in the proxy->buffer
77 /* field.
78 /*
79 /* proxy->cmd() formats and either buffers up the command and
80 /* expected response until the entire message is received, or
81 /* it immediately sends the specified command to the proxy
82 /* server, and receives the proxy server reply.
83 /* A non-zero result value means trouble: either the proxy is
84 /* unavailable, or it did not send the expected reply.
85 /* All results are reported via the proxy->buffer field in a
86 /* form that can be sent to the SMTP client. An unexpected
87 /* 2xx or 3xx proxy server response is replaced by a generic
88 /* error response to avoid support problems.
89 /* In case of error, proxy->cmd() updates the state->error_mask
90 /* and state->err fields.
91 /*
92 /* smtpd_proxy_free() destroys a proxy server handle and resets
93 /* the state->proxy field.
94 /*
95 /* smtpd_proxy_parse_opts() parses main.cf processing options.
96 /*
97 /* proxy->rec_put() is a rec_put() clone that either buffers
98 /* up arbitrary message content records until the entire message
99 /* is received, or that immediately sends it to the proxy
100 /* server.
101 /* All data is expected to be in SMTP dot-escaped form.
102 /* All errors are reported as a REC_TYPE_ERROR result value,
103 /* with the state->error_mask, state->err and proxy-buffer
104 /* fields given appropriate values.
105 /*
106 /* proxy->rec_fprintf() is a rec_fprintf() clone that formats
107 /* message content and either buffers up the record until the
108 /* entire message is received, or that immediately sends it
109 /* to the proxy server.
110 /* All data is expected to be in SMTP dot-escaped form.
111 /* All errors are reported as a REC_TYPE_ERROR result value,
112 /* with the state->error_mask, state->err and proxy-buffer
113 /* fields given appropriate values.
114 /*
115 /* Arguments:
116 /* .IP flags
117 /* Zero, or SMTPD_PROXY_FLAG_SPEED_ADJUST to buffer up the entire
118 /* message before contacting a before-queue content filter.
119 /* Note: when this feature is requested, the before-queue
120 /* filter MUST use the same 2xx, 4xx or 5xx reply code for all
121 /* recipients of a multi-recipient message.
122 /* .IP server
123 /* The SMTP proxy server host:port. The host or host: part is optional.
124 /* This argument is not duplicated.
125 /* .IP timeout
126 /* Time limit for connecting to the proxy server and for
127 /* sending and receiving proxy server commands and replies.
128 /* .IP ehlo_name
129 /* The EHLO Hostname that will be sent to the proxy server.
130 /* This argument is not duplicated.
131 /* .IP mail_from
132 /* The MAIL FROM command. This argument is not duplicated.
133 /* .IP state
134 /* SMTP server state.
135 /* .IP expect
136 /* Expected proxy server reply status code range. A warning is logged
137 /* when an unexpected reply is received. Specify one of the following:
138 /* .RS
139 /* .IP SMTPD_PROX_WANT_OK
140 /* The caller expects a reply in the 200 range.
141 /* .IP SMTPD_PROX_WANT_MORE
142 /* The caller expects a reply in the 300 range.
143 /* .IP SMTPD_PROX_WANT_ANY
144 /* The caller has no expectation. Do not warn for unexpected replies.
145 /* .IP SMTPD_PROX_WANT_NONE
146 /* Do not bother waiting for a reply.
147 /* .RE
148 /* .IP format
149 /* A format string.
150 /* .IP stream
151 /* Connection to proxy server.
152 /* .IP data
153 /* Pointer to the content of one message content record.
154 /* .IP len
155 /* The length of a message content record.
156 /* SEE ALSO
157 /* smtpd(8) Postfix smtp server
158 /* DIAGNOSTICS
159 /* Panic: internal API violations.
160 /*
161 /* Fatal errors: memory allocation problem.
162 /*
163 /* Warnings: unexpected response from proxy server, unable
164 /* to connect to proxy server, proxy server read/write error,
165 /* proxy speed-adjust buffer read/write error.
166 /* LICENSE
167 /* .ad
168 /* .fi
169 /* The Secure Mailer license must be distributed with this software.
170 /* AUTHOR(S)
171 /* Wietse Venema
172 /* IBM T.J. Watson Research
173 /* P.O. Box 704
174 /* Yorktown Heights, NY 10598, USA
175 /*--*/
176 
177 /* System library. */
178 
179 #include <sys_defs.h>
180 #include <ctype.h>
181 #include <unistd.h>
182 
183 #ifdef STRCASECMP_IN_STRINGS_H
184 #include <strings.h>
185 #endif
186 
187 /* Utility library. */
188 
189 #include <msg.h>
190 #include <vstream.h>
191 #include <vstring.h>
192 #include <stringops.h>
193 #include <connect.h>
194 #include <name_code.h>
195 #include <mymalloc.h>
196 
197 /* Global library. */
198 
199 #include <mail_error.h>
200 #include <smtp_stream.h>
201 #include <cleanup_user.h>
202 #include <mail_params.h>
203 #include <rec_type.h>
204 #include <mail_proto.h>
205 #include <xtext.h>
206 #include <record.h>
207 #include <mail_queue.h>
208 
209 /* Application-specific. */
210 
211 #include <smtpd.h>
212 #include <smtpd_proxy.h>
213 
214  /*
215  * XFORWARD server features, recognized by the pass-through proxy client.
216  */
217 #define SMTPD_PROXY_XFORWARD_NAME (1<<0) /* client name */
218 #define SMTPD_PROXY_XFORWARD_ADDR (1<<1) /* client address */
219 #define SMTPD_PROXY_XFORWARD_PROTO (1<<2) /* protocol */
220 #define SMTPD_PROXY_XFORWARD_HELO (1<<3) /* client helo */
221 #define SMTPD_PROXY_XFORWARD_IDENT (1<<4) /* message identifier */
222 #define SMTPD_PROXY_XFORWARD_DOMAIN (1<<5) /* origin type */
223 #define SMTPD_PROXY_XFORWARD_PORT (1<<6) /* client port */
224 
225  /*
226  * Spead-matching: we use an unlinked file for transient storage.
227  */
228 static VSTREAM *smtpd_proxy_replay_stream;
229 
230  /*
231  * Forward declarations.
232  */
233 static void smtpd_proxy_fake_server_reply(SMTPD_STATE *, int);
234 static int smtpd_proxy_rdwr_error(SMTPD_STATE *, int);
235 static int PRINTFLIKE(3, 4) smtpd_proxy_cmd(SMTPD_STATE *, int, const char *,...);
236 static int smtpd_proxy_rec_put(VSTREAM *, int, const char *, ssize_t);
237 
238  /*
239  * SLMs.
240  */
241 #define STR(x) vstring_str(x)
242 #define LEN(x) VSTRING_LEN(x)
243 #define STREQ(x, y) (strcmp((x), (y)) == 0)
244 
245 /* smtpd_proxy_xforward_flush - flush forwarding information */
246 
247 static int smtpd_proxy_xforward_flush(SMTPD_STATE *state, VSTRING *buf)
248 {
249  int ret;
250 
251  if (VSTRING_LEN(buf) > 0) {
252  ret = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK,
253  XFORWARD_CMD "%s", STR(buf));
254  VSTRING_RESET(buf);
255  return (ret);
256  }
257  return (0);
258 }
259 
260 /* smtpd_proxy_xforward_send - send forwarding information */
261 
262 static int smtpd_proxy_xforward_send(SMTPD_STATE *state, VSTRING *buf,
263  const char *name,
264  int value_available,
265  const char *value)
266 {
267  size_t new_len;
268  int ret;
269 
270 #define CONSTR_LEN(s) (sizeof(s) - 1)
271 #define PAYLOAD_LIMIT (512 - CONSTR_LEN("250 " XFORWARD_CMD "\r\n"))
272 
273  if (!value_available)
274  value = XFORWARD_UNAVAILABLE;
275 
276  /*
277  * Encode the attribute value.
278  */
279  if (state->expand_buf == 0)
280  state->expand_buf = vstring_alloc(100);
281  xtext_quote(state->expand_buf, value, "");
282 
283  /*
284  * How much space does this attribute need? SPACE name = value.
285  */
286  new_len = strlen(name) + strlen(STR(state->expand_buf)) + 2;
287  if (new_len > PAYLOAD_LIMIT)
288  msg_warn("%s command payload %s=%.10s... exceeds SMTP protocol limit",
289  XFORWARD_CMD, name, value);
290 
291  /*
292  * Flush the buffer if we need to, and store the attribute.
293  */
294  if (VSTRING_LEN(buf) > 0 && VSTRING_LEN(buf) + new_len > PAYLOAD_LIMIT)
295  if ((ret = smtpd_proxy_xforward_flush(state, buf)) < 0)
296  return (ret);
297  vstring_sprintf_append(buf, " %s=%s", name, STR(state->expand_buf));
298 
299  return (0);
300 }
301 
302 /* smtpd_proxy_connect - open proxy connection */
303 
304 static int smtpd_proxy_connect(SMTPD_STATE *state)
305 {
306  SMTPD_PROXY *proxy = state->proxy;
307  int fd;
308  char *lines;
309  char *words;
310  VSTRING *buf;
311  int bad;
312  char *word;
313  static const NAME_CODE known_xforward_features[] = {
321  0, 0,
322  };
323  int server_xforward_features;
324  int (*connect_fn) (const char *, int, int);
325  const char *endpoint;
326 
327  /*
328  * Find connection method (default inet)
329  */
330  if (strncasecmp("unix:", proxy->service_name, 5) == 0) {
331  endpoint = proxy->service_name + 5;
332  connect_fn = unix_connect;
333  } else {
334  if (strncasecmp("inet:", proxy->service_name, 5) == 0)
335  endpoint = proxy->service_name + 5;
336  else
337  endpoint = proxy->service_name;
338  connect_fn = inet_connect;
339  }
340 
341  /*
342  * Connect to proxy.
343  */
344  if ((fd = connect_fn(endpoint, BLOCKING, proxy->timeout)) < 0) {
345  msg_warn("connect to proxy filter %s: %m", proxy->service_name);
346  return (smtpd_proxy_rdwr_error(state, 0));
347  }
348  proxy->service_stream = vstream_fdopen(fd, O_RDWR);
349  /* Needed by our DATA-phase record emulation routines. */
351  CA_VSTREAM_CTL_CONTEXT((void *) state),
353  /* Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE. */
354  if (connect_fn == inet_connect)
356  smtp_timeout_setup(proxy->service_stream, proxy->timeout);
357 
358  /*
359  * Get server greeting banner.
360  *
361  * If this fails then we have a problem because the proxy should always
362  * accept our connection. Make up our own response instead of passing
363  * back a negative greeting banner: the proxy open is delayed to the
364  * point that the client expects a MAIL FROM or RCPT TO reply.
365  */
366  if (smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK, "%s", "")) {
367  smtpd_proxy_fake_server_reply(state, CLEANUP_STAT_PROXY);
368  smtpd_proxy_close(state);
369  return (-1);
370  }
371 
372  /*
373  * Send our own EHLO command. If this fails then we have a problem
374  * because the proxy should always accept our EHLO command. Make up our
375  * own response instead of passing back a negative EHLO reply: the proxy
376  * open is delayed to the point that the remote SMTP client expects a
377  * MAIL FROM or RCPT TO reply.
378  */
379  if (smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK, "EHLO %s",
380  proxy->ehlo_name)) {
381  smtpd_proxy_fake_server_reply(state, CLEANUP_STAT_PROXY);
382  smtpd_proxy_close(state);
383  return (-1);
384  }
385 
386  /*
387  * Parse the EHLO reply and see if we can forward logging information.
388  */
389  server_xforward_features = 0;
390  lines = STR(proxy->reply);
391  while ((words = mystrtok(&lines, "\n")) != 0) {
392  if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t")) != 0) {
393  if (strcasecmp(word, XFORWARD_CMD) == 0)
394  while ((word = mystrtok(&words, " \t")) != 0)
395  server_xforward_features |=
396  name_code(known_xforward_features,
397  NAME_CODE_FLAG_NONE, word);
398  }
399  }
400 
401  /*
402  * Send XFORWARD attributes. For robustness, explicitly specify what SMTP
403  * session attributes are known and unknown. Make up our own response
404  * instead of passing back a negative XFORWARD reply: the proxy open is
405  * delayed to the point that the remote SMTP client expects a MAIL FROM
406  * or RCPT TO reply.
407  */
408  if (server_xforward_features) {
409  buf = vstring_alloc(100);
410  bad =
411  (((server_xforward_features & SMTPD_PROXY_XFORWARD_NAME)
412  && smtpd_proxy_xforward_send(state, buf, XFORWARD_NAME,
414  FORWARD_NAME(state)))
415  || ((server_xforward_features & SMTPD_PROXY_XFORWARD_ADDR)
416  && smtpd_proxy_xforward_send(state, buf, XFORWARD_ADDR,
418  FORWARD_ADDR(state)))
419  || ((server_xforward_features & SMTPD_PROXY_XFORWARD_PORT)
420  && smtpd_proxy_xforward_send(state, buf, XFORWARD_PORT,
422  FORWARD_PORT(state)))
423  || ((server_xforward_features & SMTPD_PROXY_XFORWARD_HELO)
424  && smtpd_proxy_xforward_send(state, buf, XFORWARD_HELO,
426  FORWARD_HELO(state)))
427  || ((server_xforward_features & SMTPD_PROXY_XFORWARD_IDENT)
428  && smtpd_proxy_xforward_send(state, buf, XFORWARD_IDENT,
430  FORWARD_IDENT(state)))
431  || ((server_xforward_features & SMTPD_PROXY_XFORWARD_PROTO)
432  && smtpd_proxy_xforward_send(state, buf, XFORWARD_PROTO,
434  FORWARD_PROTO(state)))
435  || ((server_xforward_features & SMTPD_PROXY_XFORWARD_DOMAIN)
436  && smtpd_proxy_xforward_send(state, buf, XFORWARD_DOMAIN, 1,
439  || smtpd_proxy_xforward_flush(state, buf));
440  vstring_free(buf);
441  if (bad) {
442  smtpd_proxy_fake_server_reply(state, CLEANUP_STAT_PROXY);
443  smtpd_proxy_close(state);
444  return (-1);
445  }
446  }
447 
448  /*
449  * Pass-through the remote SMTP client's MAIL FROM command. If this
450  * fails, then we have a problem because the proxy should always accept
451  * any MAIL FROM command that was accepted by us.
452  */
453  if (smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK, "%s",
454  proxy->mail_from) != 0) {
455  /* NOT: smtpd_proxy_fake_server_reply(state, CLEANUP_STAT_PROXY); */
456  smtpd_proxy_close(state);
457  return (-1);
458  }
459  return (0);
460 }
461 
462 /* smtpd_proxy_fake_server_reply - produce generic error response */
463 
464 static void smtpd_proxy_fake_server_reply(SMTPD_STATE *state, int status)
465 {
466  const CLEANUP_STAT_DETAIL *detail;
467 
468  /*
469  * Either we have no server reply (connection refused), or we have an
470  * out-of-protocol server reply, so we make up a generic server error
471  * response instead.
472  */
473  detail = cleanup_stat_detail(status);
474  vstring_sprintf(state->proxy->reply,
475  "%d %s Error: %s",
476  detail->smtp, detail->dsn, detail->text);
477 }
478 
479 /* smtpd_proxy_replay_rdwr_error - report replay log I/O error */
480 
481 static int smtpd_proxy_replay_rdwr_error(SMTPD_STATE *state)
482 {
483 
484  /*
485  * Log an appropriate warning message.
486  */
487  msg_warn("proxy speed-adjust log I/O error: %m");
488 
489  /*
490  * Set the appropriate flags and server reply.
491  */
493  /* Update state->err in case we are past the client's DATA command. */
494  state->err |= CLEANUP_STAT_PROXY;
495  smtpd_proxy_fake_server_reply(state, CLEANUP_STAT_PROXY);
496  return (-1);
497 }
498 
499 /* smtpd_proxy_rdwr_error - report proxy communication error */
500 
501 static int smtpd_proxy_rdwr_error(SMTPD_STATE *state, int err)
502 {
503  const char *myname = "smtpd_proxy_rdwr_error";
504  SMTPD_PROXY *proxy = state->proxy;
505 
506  /*
507  * Sanity check.
508  */
509  if (err != 0 && err != SMTP_ERR_NONE && proxy == 0)
510  msg_panic("%s: proxy error %d without proxy handle", myname, err);
511 
512  /*
513  * Log an appropriate warning message.
514  */
515  switch (err) {
516  case 0:
517  case SMTP_ERR_NONE:
518  break;
519  case SMTP_ERR_EOF:
520  msg_warn("lost connection with proxy %s", proxy->service_name);
521  break;
522  case SMTP_ERR_TIME:
523  msg_warn("timeout talking to proxy %s", proxy->service_name);
524  break;
525  default:
526  msg_panic("%s: unknown proxy %s error %d",
527  myname, proxy->service_name, err);
528  }
529 
530  /*
531  * Set the appropriate flags and server reply.
532  */
534  /* Update state->err in case we are past the client's DATA command. */
535  state->err |= CLEANUP_STAT_PROXY;
536  smtpd_proxy_fake_server_reply(state, CLEANUP_STAT_PROXY);
537  return (-1);
538 }
539 
540 /* smtpd_proxy_replay_send - replay saved SMTP session from speed-match log */
541 
542 static int smtpd_proxy_replay_send(SMTPD_STATE *state)
543 {
544  const char *myname = "smtpd_proxy_replay_send";
545  static VSTRING *replay_buf = 0;
546  SMTPD_PROXY *proxy = state->proxy;
547  int rec_type;
548  int expect = SMTPD_PROX_WANT_BAD;
549 
550  /*
551  * Sanity check.
552  */
553  if (smtpd_proxy_replay_stream == 0)
554  msg_panic("%s: no before-queue filter speed-adjust log", myname);
555 
556  /*
557  * Errors first.
558  */
559  if (vstream_ferror(smtpd_proxy_replay_stream)
560  || vstream_feof(smtpd_proxy_replay_stream)
561  || rec_put(smtpd_proxy_replay_stream, REC_TYPE_END, "", 0) != REC_TYPE_END
562  || vstream_fflush(smtpd_proxy_replay_stream))
563  /* NOT: fsync(vstream_fileno(smtpd_proxy_replay_stream)) */
564  return (smtpd_proxy_replay_rdwr_error(state));
565 
566  /*
567  * Delayed connection to the before-queue filter.
568  */
569  if (smtpd_proxy_connect(state) < 0)
570  return (-1);
571 
572  /*
573  * Replay the speed-match log. We do sanity check record content, but we
574  * don't implement a protocol state engine here, since we are reading
575  * from a file that we just wrote ourselves.
576  *
577  * This is different than the MailChannels patented solution that
578  * multiplexes a large number of slowed-down inbound connections over a
579  * small number of fast connections to a local MTA.
580  *
581  * - MailChannels receives mail directly from the Internet. It uses one
582  * connection to the local MTA to reject invalid recipients before
583  * receiving the entire email message at reduced bit rates, and then uses
584  * a different connection to quickly deliver the message to the local
585  * MTA.
586  *
587  * - Postfix receives mail directly from the Internet. The Postfix SMTP
588  * server rejects invalid recipients before receiving the entire message
589  * over the Internet, and then delivers the message quickly to a local
590  * SMTP-based content filter.
591  */
592  if (replay_buf == 0)
593  replay_buf = vstring_alloc(100);
594  if (vstream_fseek(smtpd_proxy_replay_stream, (off_t) 0, SEEK_SET) < 0)
595  return (smtpd_proxy_replay_rdwr_error(state));
596 
597  for (;;) {
598  switch (rec_type = rec_get(smtpd_proxy_replay_stream, replay_buf,
599  REC_FLAG_NONE)) {
600 
601  /*
602  * Message content.
603  */
604  case REC_TYPE_NORM:
605  case REC_TYPE_CONT:
606  if (smtpd_proxy_rec_put(proxy->service_stream, rec_type,
607  STR(replay_buf), LEN(replay_buf)) < 0)
608  return (-1);
609  break;
610 
611  /*
612  * Expected server reply type.
613  */
614  case REC_TYPE_RCPT:
615  if (!alldig(STR(replay_buf))
616  || (expect = atoi(STR(replay_buf))) == SMTPD_PROX_WANT_BAD)
617  msg_panic("%s: malformed server reply type: %s",
618  myname, STR(replay_buf));
619  break;
620 
621  /*
622  * Client command, or void. Bail out on the first negative proxy
623  * response. This is OK, because the filter must use the same
624  * reply code for all recipients of a multi-recipient message.
625  */
626  case REC_TYPE_FROM:
627  if (expect == SMTPD_PROX_WANT_BAD)
628  msg_panic("%s: missing server reply type", myname);
629  if (smtpd_proxy_cmd(state, expect, "%s", STR(replay_buf)) < 0)
630  return (-1);
631  expect = SMTPD_PROX_WANT_BAD;
632  break;
633 
634  /*
635  * Explicit end marker, instead of implicit EOF.
636  */
637  case REC_TYPE_END:
638  return (0);
639 
640  /*
641  * Errors.
642  */
643  case REC_TYPE_ERROR:
644  return (smtpd_proxy_replay_rdwr_error(state));
645  default:
646  msg_panic("%s: unexpected record type; %d", myname, rec_type);
647  }
648  }
649 }
650 
651 /* smtpd_proxy_save_cmd - save SMTP command + expected response to replay log */
652 
653 static int PRINTFLIKE(3, 4) smtpd_proxy_save_cmd(SMTPD_STATE *state, int expect, const char *fmt,...)
654 {
655  va_list ap;
656 
657  /*
658  * Errors first.
659  */
660  if (vstream_ferror(smtpd_proxy_replay_stream)
661  || vstream_feof(smtpd_proxy_replay_stream))
662  return (smtpd_proxy_replay_rdwr_error(state));
663 
664  /*
665  * Save the expected reply first, so that the replayer can safely
666  * overwrite the input buffer with the command.
667  */
668  rec_fprintf(smtpd_proxy_replay_stream, REC_TYPE_RCPT, "%d", expect);
669 
670  /*
671  * The command can be omitted at the start of an SMTP session. This is
672  * not documented as part of the official interface because it is used
673  * only internally to this module.
674  */
675 
676  /*
677  * Save the command to the replay log, and send it to the before-queue
678  * filter after we have received the entire message.
679  */
680  va_start(ap, fmt);
681  rec_vfprintf(smtpd_proxy_replay_stream, REC_TYPE_FROM, fmt, ap);
682  va_end(ap);
683 
684  /*
685  * If we just saved the "." command, replay the log.
686  */
687  return (strcmp(fmt, ".") ? 0 : smtpd_proxy_replay_send(state));
688 }
689 
690 /* smtpd_proxy_cmd - send command to proxy, receive reply */
691 
692 static int smtpd_proxy_cmd(SMTPD_STATE *state, int expect, const char *fmt,...)
693 {
694  SMTPD_PROXY *proxy = state->proxy;
695  va_list ap;
696  char *cp;
697  int last_char;
698  int err = 0;
699  static VSTRING *buffer = 0;
700 
701  /*
702  * Errors first. Be prepared for delayed errors from the DATA phase.
703  */
704  if (vstream_ferror(proxy->service_stream)
705  || vstream_feof(proxy->service_stream)
706  || (err = vstream_setjmp(proxy->service_stream)) != 0) {
707  return (smtpd_proxy_rdwr_error(state, err));
708  }
709 
710  /*
711  * Format the command.
712  */
713  va_start(ap, fmt);
714  vstring_vsprintf(proxy->request, fmt, ap);
715  va_end(ap);
716 
717  /*
718  * The command can be omitted at the start of an SMTP session. This is
719  * not documented as part of the official interface because it is used
720  * only internally to this module.
721  */
722  if (LEN(proxy->request) > 0) {
723 
724  /*
725  * Optionally log the command first, so that we can see in the log
726  * what the program is trying to do.
727  */
728  if (msg_verbose)
729  msg_info("> %s: %s", proxy->service_name, STR(proxy->request));
730 
731  /*
732  * Send the command to the proxy server. Since we're going to read a
733  * reply immediately, there is no need to flush buffers.
734  */
735  smtp_fputs(STR(proxy->request), LEN(proxy->request),
736  proxy->service_stream);
737  }
738 
739  /*
740  * Early return if we don't want to wait for a server reply (such as
741  * after sending QUIT).
742  */
743  if (expect == SMTPD_PROX_WANT_NONE)
744  return (0);
745 
746  /*
747  * Censor out non-printable characters in server responses and save
748  * complete multi-line responses if possible.
749  *
750  * We can't parse or store input that exceeds var_line_limit, so we just
751  * skip over it to simplify the remainder of the code below.
752  */
753  VSTRING_RESET(proxy->reply);
754  if (buffer == 0)
755  buffer = vstring_alloc(10);
756  for (;;) {
757  last_char = smtp_get(buffer, proxy->service_stream, var_line_limit,
759  printable(STR(buffer), '?');
760  if (last_char != '\n')
761  msg_warn("%s: response longer than %d: %.30s...",
763  STR(buffer));
764  if (msg_verbose)
765  msg_info("< %s: %.100s", proxy->service_name, STR(buffer));
766 
767  /*
768  * Defend against a denial of service attack by limiting the amount
769  * of multi-line text that we are willing to store.
770  */
771  if (LEN(proxy->reply) < var_line_limit) {
772  if (VSTRING_LEN(proxy->reply))
773  vstring_strcat(proxy->reply, "\r\n");
774  vstring_strcat(proxy->reply, STR(buffer));
775  }
776 
777  /*
778  * Parse the response into code and text. Ignore unrecognized
779  * garbage. This means that any character except space (or end of
780  * line) will have the same effect as the '-' line continuation
781  * character.
782  */
783  for (cp = STR(buffer); *cp && ISDIGIT(*cp); cp++)
784  /* void */ ;
785  if (cp - STR(buffer) == 3) {
786  if (*cp == '-')
787  continue;
788  if (*cp == ' ' || *cp == 0)
789  break;
790  }
791  msg_warn("received garbage from proxy %s: %.100s",
792  proxy->service_name, STR(buffer));
793  }
794 
795  /*
796  * Log a warning in case the proxy does not send the expected response.
797  * Silently accept any response when the client expressed no expectation.
798  *
799  * Starting with Postfix 2.6 we don't pass through unexpected 2xx or 3xx
800  * proxy replies. They are a source of support problems, so we replace
801  * them by generic server error replies.
802  */
803  if (expect != SMTPD_PROX_WANT_ANY && expect != *STR(proxy->reply)) {
804  msg_warn("proxy %s rejected \"%s\": \"%s\"",
805  proxy->service_name, LEN(proxy->request) == 0 ?
806  "connection request" : STR(proxy->request),
807  STR(proxy->reply));
808  if (*STR(proxy->reply) == SMTPD_PROX_WANT_OK
809  || *STR(proxy->reply) == SMTPD_PROX_WANT_MORE) {
810  smtpd_proxy_rdwr_error(state, 0);
811  }
812  return (-1);
813  } else {
814  return (0);
815  }
816 }
817 
818 /* smtpd_proxy_save_rec_put - save message content to replay log */
819 
820 static int smtpd_proxy_save_rec_put(VSTREAM *stream, int rec_type,
821  const char *data, ssize_t len)
822 {
823  const char *myname = "smtpd_proxy_save_rec_put";
824  int ret;
825 
826 #define VSTREAM_TO_SMTPD_STATE(s) ((SMTPD_STATE *) vstream_context(s))
827 
828  /*
829  * Sanity check.
830  */
831  if (stream == 0)
832  msg_panic("%s: attempt to use closed stream", myname);
833 
834  /*
835  * Send one content record. Errors and results must be as with rec_put().
836  */
837  if (rec_type == REC_TYPE_NORM || rec_type == REC_TYPE_CONT)
838  ret = rec_put(stream, rec_type, data, len);
839  else
840  msg_panic("%s: need REC_TYPE_NORM or REC_TYPE_CONT", myname);
841 
842  /*
843  * Errors last.
844  */
845  if (ret != rec_type) {
846  (void) smtpd_proxy_replay_rdwr_error(VSTREAM_TO_SMTPD_STATE(stream));
847  return (REC_TYPE_ERROR);
848  }
849  return (rec_type);
850 }
851 
852 /* smtpd_proxy_rec_put - send message content, rec_put() clone */
853 
854 static int smtpd_proxy_rec_put(VSTREAM *stream, int rec_type,
855  const char *data, ssize_t len)
856 {
857  const char *myname = "smtpd_proxy_rec_put";
858  int err = 0;
859 
860  /*
861  * Errors first.
862  */
863  if (vstream_ferror(stream) || vstream_feof(stream)
864  || (err = vstream_setjmp(stream)) != 0) {
865  (void) smtpd_proxy_rdwr_error(VSTREAM_TO_SMTPD_STATE(stream), err);
866  return (REC_TYPE_ERROR);
867  }
868 
869  /*
870  * Send one content record. Errors and results must be as with rec_put().
871  */
872  if (rec_type == REC_TYPE_NORM)
873  smtp_fputs(data, len, stream);
874  else if (rec_type == REC_TYPE_CONT)
875  smtp_fwrite(data, len, stream);
876  else
877  msg_panic("%s: need REC_TYPE_NORM or REC_TYPE_CONT", myname);
878  return (rec_type);
879 }
880 
881 /* smtpd_proxy_save_rec_fprintf - save message content to replay log */
882 
883 static int smtpd_proxy_save_rec_fprintf(VSTREAM *stream, int rec_type,
884  const char *fmt,...)
885 {
886  const char *myname = "smtpd_proxy_save_rec_fprintf";
887  va_list ap;
888  int ret;
889 
890  /*
891  * Sanity check.
892  */
893  if (stream == 0)
894  msg_panic("%s: attempt to use closed stream", myname);
895 
896  /*
897  * Save one content record. Errors and results must be as with
898  * rec_fprintf().
899  */
900  va_start(ap, fmt);
901  if (rec_type == REC_TYPE_NORM)
902  ret = rec_vfprintf(stream, rec_type, fmt, ap);
903  else
904  msg_panic("%s: need REC_TYPE_NORM", myname);
905  va_end(ap);
906 
907  /*
908  * Errors last.
909  */
910  if (ret != rec_type) {
911  (void) smtpd_proxy_replay_rdwr_error(VSTREAM_TO_SMTPD_STATE(stream));
912  return (REC_TYPE_ERROR);
913  }
914  return (rec_type);
915 }
916 
917 /* smtpd_proxy_rec_fprintf - send message content, rec_fprintf() clone */
918 
919 static int smtpd_proxy_rec_fprintf(VSTREAM *stream, int rec_type,
920  const char *fmt,...)
921 {
922  const char *myname = "smtpd_proxy_rec_fprintf";
923  va_list ap;
924  int err = 0;
925 
926  /*
927  * Errors first.
928  */
929  if (vstream_ferror(stream) || vstream_feof(stream)
930  || (err = vstream_setjmp(stream)) != 0) {
931  (void) smtpd_proxy_rdwr_error(VSTREAM_TO_SMTPD_STATE(stream), err);
932  return (REC_TYPE_ERROR);
933  }
934 
935  /*
936  * Send one content record. Errors and results must be as with
937  * rec_fprintf().
938  */
939  va_start(ap, fmt);
940  if (rec_type == REC_TYPE_NORM)
941  smtp_vprintf(stream, fmt, ap);
942  else
943  msg_panic("%s: need REC_TYPE_NORM", myname);
944  va_end(ap);
945  return (rec_type);
946 }
947 
948 #ifndef NO_TRUNCATE
949 
950 /* smtpd_proxy_replay_setup - prepare the replay logfile */
951 
952 static int smtpd_proxy_replay_setup(SMTPD_STATE *state)
953 {
954  const char *myname = "smtpd_proxy_replay_setup";
955  off_t file_offs;
956 
957  /*
958  * Where possible reuse an existing replay logfile, because creating a
959  * file is expensive compared to reading or writing. For security reasons
960  * we must truncate the file before reuse. For performance reasons we
961  * should truncate the file immediately after the end of a mail
962  * transaction. We enforce the security guarantee upon reuse, by
963  * requiring that no I/O happened since the file was truncated. This is
964  * less expensive than truncating the file redundantly.
965  */
966  if (smtpd_proxy_replay_stream != 0) {
967  /* vstream_ftell() won't invoke the kernel, so all errors are mine. */
968  if ((file_offs = vstream_ftell(smtpd_proxy_replay_stream)) != 0)
969  msg_panic("%s: bad before-queue filter speed-adjust log offset %lu",
970  myname, (unsigned long) file_offs);
971  vstream_clearerr(smtpd_proxy_replay_stream);
972  if (msg_verbose)
973  msg_info("%s: reuse speed-adjust stream fd=%d", myname,
974  vstream_fileno(smtpd_proxy_replay_stream));
975  /* Here, smtpd_proxy_replay_stream != 0 */
976  }
977 
978  /*
979  * Create a new replay logfile.
980  */
981  if (smtpd_proxy_replay_stream == 0) {
982  smtpd_proxy_replay_stream = mail_queue_enter(MAIL_QUEUE_INCOMING, 0,
983  (struct timeval *) 0);
984  if (smtpd_proxy_replay_stream == 0)
985  return (smtpd_proxy_replay_rdwr_error(state));
986  if (unlink(VSTREAM_PATH(smtpd_proxy_replay_stream)) < 0)
987  msg_warn("remove before-queue filter speed-adjust log %s: %m",
988  VSTREAM_PATH(smtpd_proxy_replay_stream));
989  if (msg_verbose)
990  msg_info("%s: new speed-adjust stream fd=%d", myname,
991  vstream_fileno(smtpd_proxy_replay_stream));
992  }
993 
994  /*
995  * Needed by our DATA-phase record emulation routines.
996  */
997  vstream_control(smtpd_proxy_replay_stream,
998  CA_VSTREAM_CTL_CONTEXT((void *) state),
1000  return (0);
1001 }
1002 
1003 #endif
1004 
1005 /* smtpd_proxy_create - set up smtpd proxy handle */
1006 
1007 int smtpd_proxy_create(SMTPD_STATE *state, int flags, const char *service,
1008  int timeout, const char *ehlo_name,
1009  const char *mail_from)
1010 {
1011  SMTPD_PROXY *proxy;
1012 
1013  /*
1014  * When an operation has many arguments it is safer to use named
1015  * parameters, and have the compiler enforce the argument count.
1016  */
1017 #define SMTPD_PROXY_ALLOC(p, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) \
1018  ((p) = (SMTPD_PROXY *) mymalloc(sizeof(*(p))), (p)->a1, (p)->a2, \
1019  (p)->a3, (p)->a4, (p)->a5, (p)->a6, (p)->a7, (p)->a8, (p)->a9, \
1020  (p)->a10, (p)->a11, (p)->a12, (p))
1021 
1022  /*
1023  * Sanity check.
1024  */
1025  if (state->proxy != 0)
1026  msg_panic("smtpd_proxy_create: handle still exists");
1027 
1028  /*
1029  * Connect to the before-queue filter immediately.
1030  */
1031  if ((flags & SMTPD_PROXY_FLAG_SPEED_ADJUST) == 0) {
1032  state->proxy =
1033  SMTPD_PROXY_ALLOC(proxy, stream = 0, request = vstring_alloc(10),
1034  reply = vstring_alloc(10),
1035  cmd = smtpd_proxy_cmd,
1036  rec_fprintf = smtpd_proxy_rec_fprintf,
1037  rec_put = smtpd_proxy_rec_put,
1038  flags = flags, service_stream = 0,
1039  service_name = service, timeout = timeout,
1040  ehlo_name = ehlo_name, mail_from = mail_from);
1041  if (smtpd_proxy_connect(state) < 0) {
1042  /* NOT: smtpd_proxy_free(state); we still need proxy->reply. */
1043  return (-1);
1044  }
1045  proxy->stream = proxy->service_stream;
1046  return (0);
1047  }
1048 
1049  /*
1050  * Connect to the before-queue filter after we receive the entire
1051  * message. Open the replay logfile early to simplify code. The file is
1052  * reused for multiple mail transactions, so there is no need to minimize
1053  * its life time.
1054  */
1055  else {
1056 #ifdef NO_TRUNCATE
1057  msg_panic("smtpd_proxy_create: speed-adjust support is not available");
1058 #else
1059  if (smtpd_proxy_replay_setup(state) < 0)
1060  return (-1);
1061  state->proxy =
1062  SMTPD_PROXY_ALLOC(proxy, stream = smtpd_proxy_replay_stream,
1063  request = vstring_alloc(10),
1064  reply = vstring_alloc(10),
1065  cmd = smtpd_proxy_save_cmd,
1066  rec_fprintf = smtpd_proxy_save_rec_fprintf,
1067  rec_put = smtpd_proxy_save_rec_put,
1068  flags = flags, service_stream = 0,
1069  service_name = service, timeout = timeout,
1070  ehlo_name = ehlo_name, mail_from = mail_from);
1071  return (0);
1072 #endif
1073  }
1074 }
1075 
1076 /* smtpd_proxy_close - close proxy connection without destroying handle */
1077 
1078 void smtpd_proxy_close(SMTPD_STATE *state)
1079 {
1080  SMTPD_PROXY *proxy = state->proxy;
1081 
1082  /*
1083  * Specify SMTPD_PROX_WANT_NONE so that the server reply will not clobber
1084  * the END-OF-DATA reply.
1085  */
1086  if (proxy->service_stream != 0) {
1087  if (vstream_feof(proxy->service_stream) == 0
1088  && vstream_ferror(proxy->service_stream) == 0)
1089  (void) smtpd_proxy_cmd(state, SMTPD_PROX_WANT_NONE,
1090  SMTPD_CMD_QUIT);
1091  (void) vstream_fclose(proxy->service_stream);
1092  if (proxy->stream == proxy->service_stream)
1093  proxy->stream = 0;
1094  proxy->service_stream = 0;
1095  }
1096 }
1097 
1098 /* smtpd_proxy_free - destroy smtpd proxy handle */
1099 
1100 void smtpd_proxy_free(SMTPD_STATE *state)
1101 {
1102  SMTPD_PROXY *proxy = state->proxy;
1103 
1104  /*
1105  * Clean up.
1106  */
1107  if (proxy->service_stream != 0)
1108  (void) smtpd_proxy_close(state);
1109  if (proxy->request != 0)
1110  vstring_free(proxy->request);
1111  if (proxy->reply != 0)
1112  vstring_free(proxy->reply);
1113  myfree((void *) proxy);
1114  state->proxy = 0;
1115 
1116  /*
1117  * Reuse the replay logfile if possible. For security reasons we must
1118  * truncate the replay logfile before reuse. For performance reasons we
1119  * should truncate the replay logfile immediately after the end of a mail
1120  * transaction. We truncate the file here, and enforce the security
1121  * guarantee by requiring that no I/O happens before the file is reused.
1122  */
1123  if (smtpd_proxy_replay_stream == 0)
1124  return;
1125  if (vstream_ferror(smtpd_proxy_replay_stream)) {
1126  /* Errors are already reported. */
1127  (void) vstream_fclose(smtpd_proxy_replay_stream);
1128  smtpd_proxy_replay_stream = 0;
1129  return;
1130  }
1131  /* Flush output from aborted transaction before truncating the file!! */
1132  if (vstream_fseek(smtpd_proxy_replay_stream, (off_t) 0, SEEK_SET) < 0) {
1133  msg_warn("seek before-queue filter speed-adjust log: %m");
1134  (void) vstream_fclose(smtpd_proxy_replay_stream);
1135  smtpd_proxy_replay_stream = 0;
1136  return;
1137  }
1138  if (ftruncate(vstream_fileno(smtpd_proxy_replay_stream), (off_t) 0) < 0) {
1139  msg_warn("truncate before-queue filter speed-adjust log: %m");
1140  (void) vstream_fclose(smtpd_proxy_replay_stream);
1141  smtpd_proxy_replay_stream = 0;
1142  return;
1143  }
1144 }
1145 
1146 /* smtpd_proxy_parse_opts - parse main.cf options */
1147 
1148 int smtpd_proxy_parse_opts(const char *param_name, const char *param_val)
1149 {
1150  static const NAME_MASK proxy_opts_table[] = {
1152  0, 0,
1153  };
1154  int flags;
1155 
1156  /*
1157  * The optional before-filter speed-adjust buffers use disk space.
1158  * However, we don't know if they compete for storage space with the
1159  * after-filter queue, so we can't simply bump up the free space
1160  * requirement to 2.5 * message_size_limit.
1161  */
1162  flags = name_mask(param_name, proxy_opts_table, param_val);
1163  if (flags & SMTPD_PROXY_FLAG_SPEED_ADJUST) {
1164 #ifdef NO_TRUNCATE
1165  msg_warn("smtpd_proxy %s support is not available",
1167  flags &= ~SMTPD_PROXY_FLAG_SPEED_ADJUST;
1168 #endif
1169  }
1170  return (flags);
1171 }
int msg_verbose
Definition: msg.c:177
#define SMTPD_PROX_WANT_ANY
Definition: smtpd_proxy.h:48
#define XFORWARD_NAME
Definition: mail_proto.h:252
const CLEANUP_STAT_DETAIL * cleanup_stat_detail(unsigned status)
void myfree(void *ptr)
Definition: mymalloc.c:207
int rec_vfprintf(VSTREAM *stream, int type, const char *format, va_list ap)
Definition: record.c:374
#define MAIL_ERROR_RESOURCE
Definition: mail_error.h:26
#define SMTPD_PROXY_XFORWARD_PORT
Definition: smtpd_proxy.c:223
#define IS_AVAIL_CLIENT_PORT(v)
Definition: smtpd.h:295
#define FORWARD_PORT(s)
Definition: smtpd.h:360
#define IS_AVAIL_CLIENT_HELO(v)
Definition: smtpd.h:297
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define IS_AVAIL_CLIENT_ADDR(v)
Definition: smtpd.h:294
#define VSTREAM_TO_SMTPD_STATE(s)
off_t vstream_ftell(VSTREAM *stream)
Definition: vstream.c:1157
#define XFORWARD_DOM_LOCAL
Definition: mail_proto.h:259
#define SMTP_ERR_TIME
Definition: smtp_stream.h:31
void smtpd_proxy_close(SMTPD_STATE *state)
Definition: smtpd_proxy.c:1078
int smtpd_proxy_create(SMTPD_STATE *state, int flags, const char *service, int timeout, const char *ehlo_name, const char *mail_from)
Definition: smtpd_proxy.c:1007
const char * text
Definition: cleanup_user.h:87
int smtpd_proxy_parse_opts(const char *param_name, const char *param_val)
Definition: smtpd_proxy.c:1148
#define vstream_clearerr(vp)
Definition: vstream.h:125
#define IS_AVAIL_CLIENT_IDENT(v)
Definition: smtpd.h:299
#define REC_FLAG_NONE
Definition: record.h:45
#define XFORWARD_PORT
Definition: mail_proto.h:254
VSTREAM * service_stream
Definition: smtpd_proxy.h:35
#define STREQ(x, y)
#define SMTPD_PROX_WANT_MORE
Definition: smtpd_proxy.h:50
#define CA_VSTREAM_CTL_CONTEXT(v)
Definition: vstream.h:165
#define MAIL_ATTR_RWR_LOCAL
Definition: mail_proto.h:166
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
VSTRING * request
Definition: smtpd_proxy.h:28
int smtp_get(VSTRING *vp, VSTREAM *stream, ssize_t bound, int flags)
Definition: smtp_stream.c:305
#define REC_TYPE_FROM
Definition: rec_type.h:43
#define REC_TYPE_END
Definition: rec_type.h:77
int alldig(const char *string)
Definition: alldig.c:38
#define vstream_setjmp(stream)
Definition: vstream.h:248
#define SMTPD_PROX_WANT_BAD
Definition: smtpd_proxy.h:46
char * mystrtok(char **src, const char *sep)
Definition: mystrtok.c:54
#define SMTPD_PROXY_FLAG_SPEED_ADJUST
Definition: smtpd_proxy.h:42
#define VSTRING_LEN(vp)
Definition: vstring.h:72
#define STR(x)
int strncasecmp(const char *s1, const char *s2, size_t n)
Definition: strcasecmp.c:52
VSTRING * expand_buf
Definition: smtpd.h:148
#define XFORWARD_PROTO
Definition: mail_proto.h:255
#define FORWARD_NAME(s)
Definition: smtpd.h:356
#define SMTPD_PROXY_NAME_SPEED_ADJUST
Definition: smtpd_proxy.h:44
#define IS_AVAIL_CLIENT_PROTO(v)
Definition: smtpd.h:298
#define SMTPD_PROXY_XFORWARD_IDENT
Definition: smtpd_proxy.c:221
int const char * fmt
void smtp_vprintf(VSTREAM *stream, const char *fmt, va_list ap)
Definition: smtp_stream.c:249
VSTRING * vstring_sprintf_append(VSTRING *vp, const char *format,...)
Definition: vstring.c:624
VSTRING * vstring_vsprintf(VSTRING *vp, const char *format, va_list ap)
Definition: vstring.c:614
#define LEN(x)
#define SMTP_ERR_EOF
Definition: smtp_stream.h:30
#define ISDIGIT(c)
Definition: sys_defs.h:1748
#define REC_TYPE_CONT
Definition: rec_type.h:58
#define CLEANUP_STAT_PROXY
Definition: cleanup_user.h:63
int inet_connect(const char *, int, int)
Definition: inet_connect.c:77
const char * ehlo_name
Definition: smtpd_proxy.h:38
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
const char * service_name
Definition: smtpd_proxy.h:36
#define REC_TYPE_RCPT
Definition: rec_type.h:45
int unix_connect(const char *, int, int)
Definition: unix_connect.c:59
const char * mail_from
Definition: smtpd_proxy.h:39
#define SMTPD_PROXY_XFORWARD_NAME
Definition: smtpd_proxy.c:217
#define VSTRING_RESET(vp)
Definition: vstring.h:77
#define SMTPD_PROX_WANT_OK
Definition: smtpd_proxy.h:49
#define MAIL_QUEUE_INCOMING
Definition: mail_queue.h:30
VSTREAM * mail_queue_enter(const char *queue_name, mode_t mode, struct timeval *tp)
Definition: mail_queue.c:319
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define MAIL_ERROR_SOFTWARE
Definition: mail_error.h:25
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
void smtp_fputs(const char *cp, ssize_t todo, VSTREAM *stream)
Definition: smtp_stream.c:383
void smtpd_proxy_free(SMTPD_STATE *state)
Definition: smtpd_proxy.c:1100
#define smtp_timeout_setup(stream, timeout)
Definition: smtp_stream.h:47
#define NAME_CODE_FLAG_NONE
Definition: name_code.h:22
#define name_mask(tag, table, str)
Definition: name_mask.h:49
#define FORWARD_IDENT(s)
Definition: smtpd.h:368
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
#define XFORWARD_CMD
Definition: mail_proto.h:251
void smtp_fwrite(const char *cp, ssize_t todo, VSTREAM *stream)
Definition: smtp_stream.c:408
#define SMTPD_PROXY_ALLOC(p, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12)
#define XFORWARD_HELO
Definition: mail_proto.h:256
#define FORWARD_DOMAIN(s)
Definition: smtpd.h:375
int rec_put(VSTREAM *stream, int type, const char *data, ssize_t len)
Definition: record.c:194
int name_code(const NAME_CODE *table, int flags, const char *name)
Definition: name_code.c:65
int var_line_limit
Definition: mail_params.c:263
#define PAYLOAD_LIMIT
#define XFORWARD_DOM_REMOTE
Definition: mail_proto.h:260
VSTREAM * stream
Definition: smtpd_proxy.h:27
off_t vstream_fseek(VSTREAM *stream, off_t offset, int whence)
Definition: vstream.c:1093
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
int error_mask
Definition: smtpd.h:93
#define FORWARD_ADDR(s)
Definition: smtpd.h:355
#define SMTPD_PROX_WANT_NONE
Definition: smtpd_proxy.h:47
struct SMTPD_PROXY * proxy
Definition: smtpd.h:161
int vstream_tweak_tcp(VSTREAM *)
Definition: vstream_tweak.c:86
#define FORWARD_HELO(s)
Definition: smtpd.h:359
int int
Definition: smtpd_proxy.h:21
#define vstream_feof(vp)
Definition: vstream.h:121
VSTRING * reply
Definition: smtpd_proxy.h:29
#define SMTP_ERR_NONE
Definition: smtp_stream.h:33
int strcasecmp(const char *s1, const char *s2)
Definition: strcasecmp.c:41
#define XFORWARD_DOMAIN
Definition: mail_proto.h:258
#define SMTPD_CMD_QUIT
Definition: smtpd.h:244
#define SMTPD_PROXY_XFORWARD_ADDR
Definition: smtpd_proxy.c:218
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
int err
Definition: smtpd.h:69
#define vstream_fileno(vp)
Definition: vstream.h:115
VSTRING * xtext_quote(VSTRING *quoted, const char *unquoted, const char *special)
Definition: xtext.c:98
#define FORWARD_PROTO(s)
Definition: smtpd.h:358
#define REC_TYPE_ERROR
Definition: rec_type.h:24
#define CA_VSTREAM_CTL_END
Definition: vstream.h:155
#define REC_TYPE_NORM
Definition: rec_type.h:59
#define PRINTFLIKE(x, y)
Definition: sys_defs.h:1600
#define SMTP_GET_FLAG_SKIP
Definition: smtp_stream.h:51
#define XFORWARD_ADDR
Definition: mail_proto.h:253
#define XFORWARD_IDENT
Definition: mail_proto.h:257
char * printable(char *string, int replacement)
Definition: printable.c:49
void vstream_control(VSTREAM *stream, int name,...)
Definition: vstream.c:1372
#define SMTPD_PROXY_XFORWARD_PROTO
Definition: smtpd_proxy.c:219
#define IS_AVAIL_CLIENT_NAME(v)
Definition: smtpd.h:293
#define rec_get(fp, buf, limit)
Definition: record.h:56
#define vstream_ferror(vp)
Definition: vstream.h:120
int rec_fprintf(VSTREAM *stream, int type, const char *format,...)
Definition: record.c:391
#define BLOCKING
Definition: iostuff.h:48
VSTRING * vstring_strcat(VSTRING *vp, const char *src)
Definition: vstring.c:459
VSTREAM * vstream_fdopen(int fd, int flags)
Definition: vstream.c:1204
#define SMTPD_PROXY_XFORWARD_HELO
Definition: smtpd_proxy.c:220
#define SMTPD_PROXY_XFORWARD_DOMAIN
Definition: smtpd_proxy.c:222
const char * dsn
Definition: cleanup_user.h:86
#define XFORWARD_UNAVAILABLE
Definition: mail_proto.h:262
void msg_info(const char *fmt,...)
Definition: msg.c:199