Postfix3.3.1
deliver_request.c
[詳解]
1 /*++
2 /* NAME
3 /* deliver_request 3
4 /* SUMMARY
5 /* mail delivery request protocol, server side
6 /* SYNOPSIS
7 /* #include <deliver_request.h>
8 /*
9 /* typedef struct DELIVER_REQUEST {
10 /* .in +5
11 /* VSTREAM *fp;
12 /* int flags;
13 /* char *queue_name;
14 /* char *queue_id;
15 /* long data_offset;
16 /* long data_size;
17 /* char *nexthop;
18 /* char *encoding;
19 /* char *sender;
20 /* MSG_STATS msg_stats;
21 /* RECIPIENT_LIST rcpt_list;
22 /* DSN *hop_status;
23 /* char *client_name;
24 /* char *client_addr;
25 /* char *client_port;
26 /* char *client_proto;
27 /* char *client_helo;
28 /* char *sasl_method;
29 /* char *sasl_username;
30 /* char *sasl_sender;
31 /* char *log_ident;
32 /* char *rewrite_context;
33 /* char *dsn_envid;
34 /* int dsn_ret;
35 /* .in -5
36 /* } DELIVER_REQUEST;
37 /*
38 /* DELIVER_REQUEST *deliver_request_read(stream)
39 /* VSTREAM *stream;
40 /*
41 /* void deliver_request_done(stream, request, status)
42 /* VSTREAM *stream;
43 /* DELIVER_REQUEST *request;
44 /* int status;
45 /* DESCRIPTION
46 /* This module implements the delivery agent side of the `queue manager
47 /* to delivery agent' protocol. In this game, the queue manager is
48 /* the client, while the delivery agent is the server.
49 /*
50 /* deliver_request_read() reads a client message delivery request,
51 /* opens the queue file, and acquires a shared lock.
52 /* A null result means that the client sent bad information or that
53 /* it went away unexpectedly.
54 /*
55 /* The \fBflags\fR structure member is the bit-wise OR of zero or more
56 /* of the following:
57 /* .IP \fBDEL_REQ_FLAG_SUCCESS\fR
58 /* Delete successful recipients from the queue file.
59 /*
60 /* Note: currently, this also controls whether bounced recipients
61 /* are deleted.
62 /*
63 /* Note: the deliver_completed() function ignores this request
64 /* when the recipient queue file offset is -1.
65 /* .IP \fBDEL_REQ_FLAG_BOUNCE\fR
66 /* Delete bounced recipients from the queue file. Currently,
67 /* this flag is non-functional.
68 /* .PP
69 /* The \fBDEL_REQ_FLAG_DEFLT\fR constant provides a convenient shorthand
70 /* for the most common case: delete successful and bounced recipients.
71 /*
72 /* The \fIhop_status\fR member must be updated by the caller
73 /* when all delivery to the destination in \fInexthop\fR should
74 /* be deferred. This member is passed to to dsn_free().
75 /*
76 /* deliver_request_done() reports the delivery status back to the
77 /* client, including the optional \fIhop_status\fR etc. information,
78 /* closes the queue file,
79 /* and destroys the DELIVER_REQUEST structure. The result is
80 /* non-zero when the status could not be reported to the client.
81 /* DIAGNOSTICS
82 /* Warnings: bad data sent by the client. Fatal errors: out of
83 /* memory, queue file open errors.
84 /* SEE ALSO
85 /* attr_scan(3) low-level intra-mail input routines
86 /* LICENSE
87 /* .ad
88 /* .fi
89 /* The Secure Mailer license must be distributed with this software.
90 /* AUTHOR(S)
91 /* Wietse Venema
92 /* IBM T.J. Watson Research
93 /* P.O. Box 704
94 /* Yorktown Heights, NY 10598, USA
95 /*--*/
96 
97 /* System library. */
98 
99 #include <sys_defs.h>
100 #include <sys/stat.h>
101 #include <string.h>
102 #include <unistd.h>
103 #include <errno.h>
104 
105 /* Utility library. */
106 
107 #include <msg.h>
108 #include <vstream.h>
109 #include <vstring.h>
110 #include <mymalloc.h>
111 #include <iostuff.h>
112 #include <myflock.h>
113 
114 /* Global library. */
115 
116 #include "mail_queue.h"
117 #include "mail_proto.h"
118 #include "mail_open_ok.h"
119 #include "recipient_list.h"
120 #include "dsn.h"
121 #include "dsn_print.h"
122 #include "deliver_request.h"
123 #include "rcpt_buf.h"
124 
125 /* deliver_request_initial - send initial status code */
126 
127 static int deliver_request_initial(VSTREAM *stream)
128 {
129  int err;
130 
131  /*
132  * The master processes runs a finite number of delivery agent processes
133  * to handle service requests. Thus, a delivery agent process must send
134  * something to inform the queue manager that it is ready to receive a
135  * delivery request; otherwise the queue manager could block in write().
136  */
137  if (msg_verbose)
138  msg_info("deliver_request_initial: send initial status");
139  attr_print(stream, ATTR_FLAG_NONE,
141  ATTR_TYPE_END);
142  if ((err = vstream_fflush(stream)) != 0)
143  if (msg_verbose)
144  msg_warn("send initial status: %m");
145  return (err);
146 }
147 
148 /* deliver_request_final - send final delivery request status */
149 
150 static int deliver_request_final(VSTREAM *stream, DELIVER_REQUEST *request,
151  int status)
152 {
153  DSN *hop_status;
154  int err;
155 
156  /* XXX This DSN structure initialization bypasses integrity checks. */
157  static DSN dummy_dsn = {"", "", "", "", "", "", ""};
158 
159  /*
160  * Send the status and the optional reason.
161  */
162  if ((hop_status = request->hop_status) == 0)
163  hop_status = &dummy_dsn;
164  if (msg_verbose)
165  msg_info("deliver_request_final: send: \"%s\" %d",
166  hop_status->reason, status);
167  attr_print(stream, ATTR_FLAG_NONE,
168  SEND_ATTR_FUNC(dsn_print, (void *) hop_status),
170  ATTR_TYPE_END);
171  if ((err = vstream_fflush(stream)) != 0)
172  if (msg_verbose)
173  msg_warn("send final status: %m");
174 
175  /*
176  * With some UNIX systems, stream sockets lose data when you close them
177  * immediately after writing to them. That is not how sockets are
178  * supposed to behave! The workaround is to wait until the receiver
179  * closes the connection. Calling VSTREAM_GETC() has the benefit of using
180  * whatever timeout is specified in the ipc_timeout parameter.
181  */
182  (void) VSTREAM_GETC(stream);
183  return (err);
184 }
185 
186 /* deliver_request_get - receive message delivery request */
187 
188 static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request)
189 {
190  const char *myname = "deliver_request_get";
191  const char *path;
192  struct stat st;
193  static VSTRING *queue_name;
194  static VSTRING *queue_id;
195  static VSTRING *nexthop;
196  static VSTRING *encoding;
197  static VSTRING *address;
198  static VSTRING *client_name;
199  static VSTRING *client_addr;
200  static VSTRING *client_port;
201  static VSTRING *client_proto;
202  static VSTRING *client_helo;
203  static VSTRING *sasl_method;
204  static VSTRING *sasl_username;
205  static VSTRING *sasl_sender;
206  static VSTRING *log_ident;
207  static VSTRING *rewrite_context;
208  static VSTRING *dsn_envid;
209  static RCPT_BUF *rcpt_buf;
210  int rcpt_count;
211  int smtputf8;
212  int dsn_ret;
213 
214  /*
215  * Initialize. For some reason I wanted to allow for multiple instances
216  * of a deliver_request structure, thus the hoopla with string
217  * initialization and copying.
218  */
219  if (queue_name == 0) {
220  queue_name = vstring_alloc(10);
221  queue_id = vstring_alloc(10);
222  nexthop = vstring_alloc(10);
223  encoding = vstring_alloc(10);
224  address = vstring_alloc(10);
225  client_name = vstring_alloc(10);
226  client_addr = vstring_alloc(10);
227  client_port = vstring_alloc(10);
228  client_proto = vstring_alloc(10);
229  client_helo = vstring_alloc(10);
230  sasl_method = vstring_alloc(10);
231  sasl_username = vstring_alloc(10);
232  sasl_sender = vstring_alloc(10);
233  log_ident = vstring_alloc(10);
234  rewrite_context = vstring_alloc(10);
235  dsn_envid = vstring_alloc(10);
236  rcpt_buf = rcpb_create();
237  }
238 
239  /*
240  * Extract the queue file name, data offset, and sender address. Abort
241  * the conversation when they send bad information.
242  */
243  if (attr_scan(stream, ATTR_FLAG_STRICT,
244  RECV_ATTR_INT(MAIL_ATTR_FLAGS, &request->flags),
245  RECV_ATTR_STR(MAIL_ATTR_QUEUE, queue_name),
246  RECV_ATTR_STR(MAIL_ATTR_QUEUEID, queue_id),
251  RECV_ATTR_INT(MAIL_ATTR_SMTPUTF8, &smtputf8),
254  RECV_ATTR_INT(MAIL_ATTR_DSN_RET, &dsn_ret),
255  RECV_ATTR_FUNC(msg_stats_scan, (void *) &request->msg_stats),
256  /* XXX Should be encapsulated with ATTR_TYPE_FUNC. */
262  /* XXX Should be encapsulated with ATTR_TYPE_FUNC. */
263  RECV_ATTR_STR(MAIL_ATTR_SASL_METHOD, sasl_method),
264  RECV_ATTR_STR(MAIL_ATTR_SASL_USERNAME, sasl_username),
265  RECV_ATTR_STR(MAIL_ATTR_SASL_SENDER, sasl_sender),
266  /* XXX Ditto if we want to pass TLS certificate info. */
268  RECV_ATTR_STR(MAIL_ATTR_RWR_CONTEXT, rewrite_context),
269  RECV_ATTR_INT(MAIL_ATTR_RCPT_COUNT, &rcpt_count),
270  ATTR_TYPE_END) != 23) {
271  msg_warn("%s: error receiving common attributes", myname);
272  return (-1);
273  }
274  if (mail_open_ok(vstring_str(queue_name),
275  vstring_str(queue_id), &st, &path) == 0)
276  return (-1);
277 
278  /* Don't override hand-off time after deliver_pass() delegation. */
279  if (request->msg_stats.agent_handoff.tv_sec == 0)
280  GETTIMEOFDAY(&request->msg_stats.agent_handoff);
281 
282  request->queue_name = mystrdup(vstring_str(queue_name));
283  request->queue_id = mystrdup(vstring_str(queue_id));
284  request->nexthop = mystrdup(vstring_str(nexthop));
285  request->encoding = mystrdup(vstring_str(encoding));
286  /* Fix 20140708: dedicated smtputf8 attribute with its own flags. */
287  request->smtputf8 = smtputf8;
288  request->sender = mystrdup(vstring_str(address));
289  request->client_name = mystrdup(vstring_str(client_name));
290  request->client_addr = mystrdup(vstring_str(client_addr));
291  request->client_port = mystrdup(vstring_str(client_port));
292  request->client_proto = mystrdup(vstring_str(client_proto));
293  request->client_helo = mystrdup(vstring_str(client_helo));
294  request->sasl_method = mystrdup(vstring_str(sasl_method));
295  request->sasl_username = mystrdup(vstring_str(sasl_username));
296  request->sasl_sender = mystrdup(vstring_str(sasl_sender));
297  request->log_ident = mystrdup(vstring_str(log_ident));
298  request->rewrite_context = mystrdup(vstring_str(rewrite_context));
299  request->dsn_envid = mystrdup(vstring_str(dsn_envid));
300  request->dsn_ret = dsn_ret;
301 
302  /*
303  * Extract the recipient offset and address list. Skip over any
304  * attributes from the sender that we do not understand.
305  */
306  while (rcpt_count-- > 0) {
307  if (attr_scan(stream, ATTR_FLAG_STRICT,
308  RECV_ATTR_FUNC(rcpb_scan, (void *) rcpt_buf),
309  ATTR_TYPE_END) != 1) {
310  msg_warn("%s: error receiving recipient attributes", myname);
311  return (-1);
312  }
313  recipient_list_add(&request->rcpt_list, rcpt_buf->offset,
314  vstring_str(rcpt_buf->dsn_orcpt),
315  rcpt_buf->dsn_notify,
316  vstring_str(rcpt_buf->orig_addr),
317  vstring_str(rcpt_buf->address));
318  }
319  if (request->rcpt_list.len <= 0) {
320  msg_warn("%s: no recipients in delivery request for destination %s",
321  request->queue_id, request->nexthop);
322  return (-1);
323  }
324 
325  /*
326  * Open the queue file and set a shared lock, in order to prevent
327  * duplicate deliveries when the queue is flushed immediately after queue
328  * manager restart.
329  *
330  * The queue manager locks the file exclusively when it enters the active
331  * queue, and releases the lock before starting deliveries from that
332  * file. The queue manager does not lock the file again when reading more
333  * recipients into memory. When the queue manager is restarted, the new
334  * process moves files from the active queue to the incoming queue to
335  * cool off for a while. Delivery agents should therefore never try to
336  * open a file that is locked by a queue manager process.
337  *
338  * Opening the queue file can fail for a variety of reasons, such as the
339  * system running out of resources. Instead of throwing away mail, we're
340  * raising a fatal error which forces the mail system to back off, and
341  * retry later.
342  */
343 #define DELIVER_LOCK_MODE (MYFLOCK_OP_SHARED | MYFLOCK_OP_NOWAIT)
344 
345  request->fp =
346  mail_queue_open(request->queue_name, request->queue_id, O_RDWR, 0);
347  if (request->fp == 0) {
348  if (errno != ENOENT)
349  msg_fatal("open %s %s: %m", request->queue_name, request->queue_id);
350  msg_warn("open %s %s: %m", request->queue_name, request->queue_id);
351  return (-1);
352  }
353  if (msg_verbose)
354  msg_info("%s: file %s", myname, VSTREAM_PATH(request->fp));
355  if (myflock(vstream_fileno(request->fp), INTERNAL_LOCK, DELIVER_LOCK_MODE) < 0)
356  msg_fatal("shared lock %s: %m", VSTREAM_PATH(request->fp));
358 
359  return (0);
360 }
361 
362 /* deliver_request_alloc - allocate delivery request structure */
363 
364 static DELIVER_REQUEST *deliver_request_alloc(void)
365 {
366  DELIVER_REQUEST *request;
367 
368  request = (DELIVER_REQUEST *) mymalloc(sizeof(*request));
369  request->fp = 0;
370  request->queue_name = 0;
371  request->queue_id = 0;
372  request->nexthop = 0;
373  request->encoding = 0;
374  request->sender = 0;
375  request->data_offset = 0;
376  request->data_size = 0;
378  request->hop_status = 0;
379  request->client_name = 0;
380  request->client_addr = 0;
381  request->client_port = 0;
382  request->client_proto = 0;
383  request->client_helo = 0;
384  request->sasl_method = 0;
385  request->sasl_username = 0;
386  request->sasl_sender = 0;
387  request->log_ident = 0;
388  request->rewrite_context = 0;
389  request->dsn_envid = 0;
390  return (request);
391 }
392 
393 /* deliver_request_free - clean up delivery request structure */
394 
395 static void deliver_request_free(DELIVER_REQUEST *request)
396 {
397  if (request->fp)
398  vstream_fclose(request->fp);
399  if (request->queue_name)
400  myfree(request->queue_name);
401  if (request->queue_id)
402  myfree(request->queue_id);
403  if (request->nexthop)
404  myfree(request->nexthop);
405  if (request->encoding)
406  myfree(request->encoding);
407  if (request->sender)
408  myfree(request->sender);
409  recipient_list_free(&request->rcpt_list);
410  if (request->hop_status)
411  dsn_free(request->hop_status);
412  if (request->client_name)
413  myfree(request->client_name);
414  if (request->client_addr)
415  myfree(request->client_addr);
416  if (request->client_port)
417  myfree(request->client_port);
418  if (request->client_proto)
419  myfree(request->client_proto);
420  if (request->client_helo)
421  myfree(request->client_helo);
422  if (request->sasl_method)
423  myfree(request->sasl_method);
424  if (request->sasl_username)
425  myfree(request->sasl_username);
426  if (request->sasl_sender)
427  myfree(request->sasl_sender);
428  if (request->log_ident)
429  myfree(request->log_ident);
430  if (request->rewrite_context)
431  myfree(request->rewrite_context);
432  if (request->dsn_envid)
433  myfree(request->dsn_envid);
434  myfree((void *) request);
435 }
436 
437 /* deliver_request_read - create and read delivery request */
438 
440 {
441  DELIVER_REQUEST *request;
442 
443  /*
444  * Tell the queue manager that we are ready for this request.
445  */
446  if (deliver_request_initial(stream) != 0)
447  return (0);
448 
449  /*
450  * Be prepared for the queue manager to change its mind after contacting
451  * us. This can happen when a transport or host goes bad.
452  */
453  (void) read_wait(vstream_fileno(stream), -1);
454  if (peekfd(vstream_fileno(stream)) <= 0)
455  return (0);
456 
457  /*
458  * Allocate and read the queue manager's delivery request.
459  */
460 #define XXX_DEFER_STATUS -1
461 
462  request = deliver_request_alloc();
463  if (deliver_request_get(stream, request) < 0) {
464  deliver_request_done(stream, request, XXX_DEFER_STATUS);
465  request = 0;
466  }
467  return (request);
468 }
469 
470 /* deliver_request_done - finish delivery request */
471 
472 int deliver_request_done(VSTREAM *stream, DELIVER_REQUEST *request, int status)
473 {
474  int err;
475 
476  err = deliver_request_final(stream, request, status);
477  deliver_request_free(request);
478  return (err);
479 }
int msg_verbose
Definition: msg.c:177
int dsn_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, int flags, void *ptr)
Definition: dsn_print.c:48
#define ATTR_FLAG_NONE
Definition: attr.h:98
void myfree(void *ptr)
Definition: mymalloc.c:207
RECIPIENT_LIST rcpt_list
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define MAIL_ATTR_ENCODING
Definition: mail_proto.h:202
const char * reason
Definition: dsn.h:20
#define vstring_str(vp)
Definition: vstring.h:71
#define stat(p, s)
Definition: warn_stat.h:18
#define VSTREAM_GETC(vp)
Definition: vstream.h:108
#define MAIL_ATTR_SIZE
Definition: mail_proto.h:139
int rcpb_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp, int flags, void *ptr)
Definition: rcpt_buf.c:118
#define MAIL_ATTR_RWR_CONTEXT
Definition: mail_proto.h:163
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
VSTRING * dsn_orcpt
Definition: rcpt_buf.h:33
#define MAIL_ATTR_SASL_METHOD
Definition: mail_proto.h:156
#define MAIL_ATTR_LOG_HELO_NAME
Definition: mail_proto.h:210
#define MAIL_ATTR_LOG_PROTO_NAME
Definition: mail_proto.h:211
#define RCPT_LIST_INIT_STATUS
MSG_STATS msg_stats
#define MAIL_ATTR_QUEUE
Definition: mail_proto.h:129
RCPT_BUF * rcpb_create(void)
Definition: rcpt_buf.c:80
#define attr_print
Definition: attr.h:109
void dsn_free(DSN *dsn)
Definition: dsn.c:179
int dsn_notify
Definition: rcpt_buf.h:34
VSTRING * address
Definition: rcpt_buf.h:31
int msg_stats_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *)
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
#define MAIL_ATTR_SMTPUTF8
Definition: mail_proto.h:277
#define RECV_ATTR_LONG(name, val)
Definition: attr.h:75
VSTREAM * mail_queue_open(const char *queue_name, const char *queue_id, int flags, mode_t mode)
Definition: mail_queue.c:424
#define MAIL_ATTR_SASL_SENDER
Definition: mail_proto.h:158
int mail_open_ok(const char *queue_name, const char *queue_id, struct stat *statp, const char **path)
Definition: mail_open_ok.c:77
#define read_wait(fd, timeout)
Definition: iostuff.h:39
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
int myflock(int fd, int lock_style, int operation)
Definition: myflock.c:87
#define MAIL_ATTR_DSN_RET
Definition: mail_proto.h:274
#define MAIL_ATTR_LOG_IDENT
Definition: mail_proto.h:162
#define MAIL_ATTR_DSN_ENVID
Definition: mail_proto.h:273
#define MAIL_ATTR_LOG_CLIENT_ADDR
Definition: mail_proto.h:208
#define MAIL_ATTR_STATUS
Definition: mail_proto.h:126
#define SEND_ATTR_INT(name, val)
Definition: attr.h:63
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
ssize_t peekfd(int)
Definition: peekfd.c:60
#define MAIL_ATTR_NEXTHOP
Definition: mail_proto.h:148
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
void recipient_list_init(RECIPIENT_LIST *list, int variant)
int deliver_request_done(VSTREAM *stream, DELIVER_REQUEST *request, int status)
VSTRING * orig_addr
Definition: rcpt_buf.h:32
#define MAIL_ATTR_SASL_USERNAME
Definition: mail_proto.h:157
#define MAIL_ATTR_RCPT_COUNT
Definition: mail_proto.h:132
#define SEND_ATTR_FUNC(func, val)
Definition: attr.h:69
#define XXX_DEFER_STATUS
#define DELIVER_LOCK_MODE
Definition: dsn.h:17
#define MAIL_ATTR_LOG_CLIENT_NAME
Definition: mail_proto.h:207
void recipient_list_free(RECIPIENT_LIST *list)
#define MAIL_ATTR_SENDER
Definition: mail_proto.h:131
#define vstream_fileno(vp)
Definition: vstream.h:115
#define RECV_ATTR_FUNC(func, val)
Definition: attr.h:77
#define CLOSE_ON_EXEC
Definition: iostuff.h:51
long offset
Definition: rcpt_buf.h:35
#define MAIL_ATTR_QUEUEID
Definition: mail_proto.h:130
#define attr_scan
Definition: attr.h:111
DELIVER_REQUEST * deliver_request_read(VSTREAM *stream)
void recipient_list_add(RECIPIENT_LIST *list, long offset, const char *dsn_orcpt, int dsn_notify, const char *orig_rcpt, const char *rcpt)
struct timeval agent_handoff
Definition: msg_stats.h:58
int close_on_exec(int fd, int on)
Definition: close_on_exec.c:49
#define MAIL_ATTR_FLAGS
Definition: mail_proto.h:128
#define MAIL_ATTR_LOG_CLIENT_PORT
Definition: mail_proto.h:209
#define MAIL_ATTR_OFFSET
Definition: mail_proto.h:138
#define RECV_ATTR_STR(name, val)
Definition: attr.h:72
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
#define ATTR_FLAG_STRICT
Definition: attr.h:103
void msg_info(const char *fmt,...)
Definition: msg.c:199