7 /* in-core message structures
11 /* int qmgr_message_count;
12 /* int qmgr_recipient_count;
14 /* QMGR_MESSAGE *qmgr_message_alloc(class, name, qflags, mode)
20 /* QMGR_MESSAGE *qmgr_message_realloc(message)
21 /* QMGR_MESSAGE *message;
23 /* void qmgr_message_free(message)
24 /* QMGR_MESSAGE *message;
26 /* void qmgr_message_update_warn(message)
27 /* QMGR_MESSAGE *message;
29 /* void qmgr_message_kill_record(message, offset)
30 /* QMGR_MESSAGE *message;
33 /* This module performs en-gross operations on queue messages.
35 /* qmgr_message_count is a global counter for the total number
36 /* of in-core message structures (i.e. the total size of the
37 /* `active' message queue).
39 /* qmgr_recipient_count is a global counter for the total number
40 /* of in-core recipient structures (i.e. the sum of all recipients
41 /* in all in-core message structures).
43 /* qmgr_message_alloc() creates an in-core message structure
44 /* with sender and recipient information taken from the named queue
45 /* file. A null result means the queue file could not be read or
46 /* that the queue file contained incorrect information. A result
47 /* QMGR_MESSAGE_LOCKED means delivery must be deferred. The number
48 /* of recipients read from a queue file is limited by the global
49 /* var_qmgr_rcpt_limit configuration parameter. When the limit
50 /* is reached, the \fIrcpt_offset\fR structure member is set to
51 /* the position where the read was terminated. Recipients are
52 /* run through the resolver, and are assigned to destination
53 /* queues. Recipients that cannot be assigned are deferred or
54 /* bounced. Mail that has bounced twice is silently absorbed.
55 /* A non-zero mode means change the queue file permissions.
57 /* qmgr_message_realloc() resumes reading recipients from the queue
58 /* file, and updates the recipient list and \fIrcpt_offset\fR message
59 /* structure members. A null result means that the file could not be
60 /* read or that the file contained incorrect information.
62 /* qmgr_message_free() destroys an in-core message structure and makes
63 /* the resources available for reuse. It is an error to destroy
64 /* a message structure that is still referenced by queue entry structures.
66 /* qmgr_message_update_warn() takes a closed message, opens it, updates
67 /* the warning field, and closes it again.
69 /* qmgr_message_kill_record() takes a closed message, opens it, updates
70 /* the record type at the given offset to "killed", and closes the file.
71 /* A killed envelope record is ignored. Killed records are not allowed
72 /* inside the message content.
74 /* Warnings: malformed message file. Fatal errors: out of memory.
76 /* envelope(3) message envelope parser
80 /* The Secure Mailer license must be distributed with this software.
83 /* IBM T.J. Watson Research
85 /* Yorktown Heights, NY 10598, USA
93 #include <stdio.h> /* sscanf() */
100 #ifdef STRCASECMP_IN_STRINGS_H
104 /* Utility library. */
107 #include <mymalloc.h>
110 #include <split_at.h>
111 #include <valid_hostname.h>
113 #include <stringops.h>
116 /* Global library. */
119 #include <mail_queue.h>
120 #include <mail_params.h>
121 #include <canon_addr.h>
123 #include <rec_type.h>
125 #include <deliver_completed.h>
127 #include <verp_sender.h>
128 #include <mail_proto.h>
129 #include <qmgr_user.h>
130 #include <split_addr.h>
131 #include <dsn_mask.h>
132 #include <rec_attr_map.h>
136 #include <rewrite_clnt.h>
137 #include <resolve_clnt.h>
139 /* Application-specific. */
143 int qmgr_message_count
;
144 int qmgr_recipient_count
;
146 /* qmgr_message_create - create in-core message structure */
148 static QMGR_MESSAGE
*qmgr_message_create(const char *queue_name
,
149 const char *queue_id
, int qflags
)
151 QMGR_MESSAGE
*message
;
153 message
= (QMGR_MESSAGE
*) mymalloc(sizeof(QMGR_MESSAGE
));
154 qmgr_message_count
++;
156 message
->qflags
= qflags
;
158 message
->tflags_offset
= 0;
159 message
->rflags
= QMGR_READ_FLAG_DEFAULT
;
161 message
->refcount
= 0;
162 message
->single_rcpt
= 0;
163 message
->arrival_time
.tv_sec
= message
->arrival_time
.tv_usec
= 0;
164 message
->create_time
= 0;
165 GETTIMEOFDAY(&message
->active_time
);
166 message
->data_offset
= 0;
167 message
->queue_id
= mystrdup(queue_id
);
168 message
->queue_name
= mystrdup(queue_name
);
169 message
->encoding
= 0;
171 message
->dsn_envid
= 0;
172 message
->dsn_ret
= 0;
173 message
->filter_xport
= 0;
174 message
->inspect_xport
= 0;
175 message
->redirect_addr
= 0;
176 message
->data_size
= 0;
177 message
->cont_length
= 0;
178 message
->warn_offset
= 0;
179 message
->warn_time
= 0;
180 message
->rcpt_offset
= 0;
181 message
->verp_delims
= 0;
182 message
->client_name
= 0;
183 message
->client_addr
= 0;
184 message
->client_port
= 0;
185 message
->client_proto
= 0;
186 message
->client_helo
= 0;
187 message
->sasl_method
= 0;
188 message
->sasl_username
= 0;
189 message
->sasl_sender
= 0;
190 message
->rewrite_context
= 0;
191 recipient_list_init(&message
->rcpt_list
, RCPT_LIST_INIT_QUEUE
);
195 /* qmgr_message_close - close queue file */
197 static void qmgr_message_close(QMGR_MESSAGE
*message
)
199 vstream_fclose(message
->fp
);
203 /* qmgr_message_open - open queue file */
205 static int qmgr_message_open(QMGR_MESSAGE
*message
)
212 msg_panic("%s: queue file is open", message
->queue_id
);
215 * Open this queue file. Skip files that we cannot open. Back off when
216 * the system appears to be running out of resources.
218 if ((message
->fp
= mail_queue_open(message
->queue_name
,
222 msg_fatal("open %s %s: %m", message
->queue_name
, message
->queue_id
);
223 msg_warn("open %s %s: %m", message
->queue_name
, message
->queue_id
);
229 /* qmgr_message_oldstyle_scan - support for Postfix < 1.0 queue files */
231 static void qmgr_message_oldstyle_scan(QMGR_MESSAGE
*message
)
234 long orig_offset
, extra_offset
;
239 * Initialize. No early returns or we have a memory leak.
241 buf
= vstring_alloc(100);
242 if ((orig_offset
= vstream_ftell(message
->fp
)) < 0)
243 msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message
->fp
));
246 * Rewind to the very beginning to make sure we see all records.
248 if (vstream_fseek(message
->fp
, 0, SEEK_SET
) < 0)
249 msg_fatal("seek file %s: %m", VSTREAM_PATH(message
->fp
));
252 * Scan through the old style queue file. Count the total number of
253 * recipients and find the data/extra sections offsets. Note that the new
254 * queue files require that data_size equals extra_offset - data_offset,
255 * so we set data_size to this as well and ignore the size record itself
259 rec_type
= rec_get(message
->fp
, buf
, 0);
261 /* Report missing end record later. */
263 start
= vstring_str(buf
);
265 msg_info("old-style scan record %c %s", rec_type
, start
);
266 if (rec_type
== REC_TYPE_END
)
268 if (rec_type
== REC_TYPE_MESG
) {
269 if (message
->data_offset
== 0) {
270 if ((message
->data_offset
= vstream_ftell(message
->fp
)) < 0)
271 msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message
->fp
));
272 if ((extra_offset
= atol(start
)) <= message
->data_offset
)
273 msg_fatal("bad extra offset %s file %s",
274 start
, VSTREAM_PATH(message
->fp
));
275 if (vstream_fseek(message
->fp
, extra_offset
, SEEK_SET
) < 0)
276 msg_fatal("seek file %s: %m", VSTREAM_PATH(message
->fp
));
277 message
->data_size
= extra_offset
- message
->data_offset
;
286 if (vstream_fseek(message
->fp
, orig_offset
, SEEK_SET
) < 0)
287 msg_fatal("seek file %s: %m", VSTREAM_PATH(message
->fp
));
291 * Sanity checks. Verify that all required information was found,
292 * including the queue file end marker.
294 if (message
->data_offset
== 0 || rec_type
!= REC_TYPE_END
)
295 msg_fatal("%s: envelope records out of order", message
->queue_id
);
298 /* qmgr_message_read - read envelope records */
300 static int qmgr_message_read(QMGR_MESSAGE
*message
)
305 long save_offset
= message
->rcpt_offset
; /* save a flag */
308 const char *error_text
;
316 int have_log_client_attr
= 0;
319 * Initialize. No early returns or we have a memory leak.
321 buf
= vstring_alloc(100);
324 * If we re-open this file, skip over on-file recipient records that we
325 * already looked at, and refill the in-core recipient address list.
327 if (message
->rcpt_offset
) {
328 if (message
->rcpt_list
.len
)
329 msg_panic("%s: recipient list not empty on recipient reload",
331 if (vstream_fseek(message
->fp
, message
->rcpt_offset
, SEEK_SET
) < 0)
332 msg_fatal("seek file %s: %m", VSTREAM_PATH(message
->fp
));
333 message
->rcpt_offset
= 0;
337 * Read envelope records. XXX Rely on the front-end programs to enforce
338 * record size limits. Read up to var_qmgr_rcpt_limit recipients from the
339 * queue file, to protect against memory exhaustion. Recipient records
340 * may appear before or after the message content, so we keep reading
341 * from the queue file until we have enough recipients (rcpt_offset != 0)
342 * and until we know all the non-recipient information.
344 * When reading recipients from queue file, stop reading when we reach a
345 * per-message in-core recipient limit rather than a global in-core
346 * recipient limit. Use the global recipient limit only in order to stop
347 * opening queue files. The purpose is to achieve equal delay for
348 * messages with recipient counts up to var_qmgr_rcpt_limit recipients.
350 * If we would read recipients up to a global recipient limit, the average
351 * number of in-core recipients per message would asymptotically approach
352 * (global recipient limit)/(active queue size limit), which gives equal
353 * delay per recipient rather than equal delay per message.
355 * On the first open, we must examine all non-recipient records.
357 * Optimization: when we know that recipient records are not mixed with
358 * non-recipient records, as is typical with mailing list mail, then we
359 * can avoid having to examine all the queue file records before we can
360 * start deliveries. This avoids some file system thrashing with huge
364 if ((curr_offset
= vstream_ftell(message
->fp
)) < 0)
365 msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message
->fp
));
366 if (curr_offset
== message
->data_offset
&& curr_offset
> 0) {
367 if (vstream_fseek(message
->fp
, message
->data_size
, SEEK_CUR
) < 0)
368 msg_fatal("seek file %s: %m", VSTREAM_PATH(message
->fp
));
369 curr_offset
+= message
->data_size
;
371 rec_type
= rec_get_raw(message
->fp
, buf
, 0, REC_FLAG_NONE
);
372 start
= vstring_str(buf
);
374 msg_info("record %c %s", rec_type
, start
);
375 if (rec_type
== REC_TYPE_PTR
) {
376 if ((rec_type
= rec_goto(message
->fp
, start
)) == REC_TYPE_ERROR
)
378 /* Need to update curr_offset after pointer jump. */
382 msg_warn("%s: message rejected: missing end record",
386 if (rec_type
== REC_TYPE_END
) {
387 message
->rflags
|= QMGR_READ_FLAG_SEEN_ALL_NON_RCPT
;
392 * Map named attributes to pseudo record types, so that we don't have
393 * to pollute the queue file with records that are incompatible with
394 * past Postfix versions. Preferably, people should be able to back
395 * out from an upgrade without losing mail.
397 if (rec_type
== REC_TYPE_ATTR
) {
398 if ((error_text
= split_nameval(start
, &name
, &value
)) != 0) {
399 msg_warn("%s: ignoring bad attribute: %s: %.200s",
400 message
->queue_id
, error_text
, start
);
401 rec_type
= REC_TYPE_ERROR
;
404 if ((n
= rec_attr_map(name
)) != 0) {
411 * Process recipient records.
413 if (rec_type
== REC_TYPE_RCPT
) {
414 /* See also below for code setting orig_rcpt etc. */
415 #define FUDGE(x) ((x) * (var_qmgr_fudge / 100.0))
416 if (message
->rcpt_offset
== 0) {
417 recipient_list_add(&message
->rcpt_list
, curr_offset
,
418 dsn_orcpt
? dsn_orcpt
: "",
419 dsn_notify
? dsn_notify
: 0,
420 orig_rcpt
? orig_rcpt
: "", start
);
431 if (message
->rcpt_list
.len
>= FUDGE(var_qmgr_rcpt_limit
)) {
432 if ((message
->rcpt_offset
= vstream_ftell(message
->fp
)) < 0)
433 msg_fatal("vstream_ftell %s: %m",
434 VSTREAM_PATH(message
->fp
));
435 if (message
->rflags
& QMGR_READ_FLAG_SEEN_ALL_NON_RCPT
)
436 /* We already examined all non-recipient records. */
438 if (message
->rflags
& QMGR_READ_FLAG_MIXED_RCPT_OTHER
)
439 /* Examine all remaining non-recipient records. */
441 /* Optimizations for "pure recipient" record sections. */
442 if (curr_offset
> message
->data_offset
) {
443 /* We already examined all non-recipient records. */
444 message
->rflags
|= QMGR_READ_FLAG_SEEN_ALL_NON_RCPT
;
447 /* Examine non-recipient records in extracted segment. */
448 if (vstream_fseek(message
->fp
, message
->data_offset
449 + message
->data_size
, SEEK_SET
) < 0)
450 msg_fatal("seek file %s: %m", VSTREAM_PATH(message
->fp
));
456 if (rec_type
== REC_TYPE_DONE
|| rec_type
== REC_TYPE_DRCP
) {
457 if (message
->rcpt_offset
== 0) {
471 if (rec_type
== REC_TYPE_DSN_ORCPT
) {
472 /* See also above for code clearing dsn_orcpt. */
473 if (dsn_orcpt
!= 0) {
474 msg_warn("%s: ignoring out-of-order DSN original recipient address <%.200s>",
475 message
->queue_id
, dsn_orcpt
);
479 if (message
->rcpt_offset
== 0)
480 dsn_orcpt
= mystrdup(start
);
483 if (rec_type
== REC_TYPE_DSN_NOTIFY
) {
484 /* See also above for code clearing dsn_notify. */
485 if (dsn_notify
!= 0) {
486 msg_warn("%s: ignoring out-of-order DSN notify flags <%d>",
487 message
->queue_id
, dsn_notify
);
490 if (message
->rcpt_offset
== 0) {
491 if (!alldig(start
) || (n
= atoi(start
)) == 0 || !DSN_NOTIFY_OK(n
))
492 msg_warn("%s: ignoring malformed DSN notify flags <%.200s>",
493 message
->queue_id
, start
);
499 if (rec_type
== REC_TYPE_ORCP
) {
500 /* See also above for code clearing orig_rcpt. */
501 if (orig_rcpt
!= 0) {
502 msg_warn("%s: ignoring out-of-order original recipient <%.200s>",
503 message
->queue_id
, orig_rcpt
);
507 if (message
->rcpt_offset
== 0)
508 orig_rcpt
= mystrdup(start
);
513 * Process non-recipient records.
515 if (message
->rflags
& QMGR_READ_FLAG_SEEN_ALL_NON_RCPT
)
516 /* We already examined all non-recipient records. */
518 if (rec_type
== REC_TYPE_SIZE
) {
519 if (message
->data_offset
== 0) {
520 if ((count
= sscanf(start
, "%ld %ld %d %d %ld",
521 &message
->data_size
, &message
->data_offset
,
522 &nrcpt
, &message
->rflags
,
523 &message
->cont_length
)) >= 3) {
524 /* Postfix >= 1.0 (a.k.a. 20010228). */
525 if (message
->data_offset
<= 0 || message
->data_size
<= 0) {
526 msg_warn("%s: invalid size record: %.100s",
527 message
->queue_id
, start
);
528 rec_type
= REC_TYPE_ERROR
;
531 if (message
->rflags
& ~QMGR_READ_FLAG_USER
) {
532 msg_warn("%s: invalid flags in size record: %.100s",
533 message
->queue_id
, start
);
534 rec_type
= REC_TYPE_ERROR
;
537 } else if (count
== 1) {
538 /* Postfix < 1.0 (a.k.a. 20010228). */
539 qmgr_message_oldstyle_scan(message
);
542 msg_warn("%s: message rejected: weird size record",
544 rec_type
= REC_TYPE_ERROR
;
548 /* Postfix < 2.4 compatibility. */
549 if (message
->cont_length
== 0) {
550 message
->cont_length
= message
->data_size
;
551 } else if (message
->cont_length
< 0) {
552 msg_warn("%s: invalid size record: %.100s",
553 message
->queue_id
, start
);
554 rec_type
= REC_TYPE_ERROR
;
559 if (rec_type
== REC_TYPE_TIME
) {
560 if (message
->arrival_time
.tv_sec
== 0)
561 REC_TYPE_TIME_SCAN(start
, message
->arrival_time
);
564 if (rec_type
== REC_TYPE_CTIME
) {
565 if (message
->create_time
== 0)
566 message
->create_time
= atol(start
);
569 if (rec_type
== REC_TYPE_FILT
) {
570 if (message
->filter_xport
!= 0)
571 myfree(message
->filter_xport
);
572 message
->filter_xport
= mystrdup(start
);
575 if (rec_type
== REC_TYPE_INSP
) {
576 if (message
->inspect_xport
!= 0)
577 myfree(message
->inspect_xport
);
578 message
->inspect_xport
= mystrdup(start
);
581 if (rec_type
== REC_TYPE_RDR
) {
582 if (message
->redirect_addr
!= 0)
583 myfree(message
->redirect_addr
);
584 message
->redirect_addr
= mystrdup(start
);
587 if (rec_type
== REC_TYPE_FROM
) {
588 if (message
->sender
== 0) {
589 message
->sender
= mystrdup(start
);
590 opened(message
->queue_id
, message
->sender
,
591 message
->cont_length
, nrcpt
,
592 "queue %s", message
->queue_name
);
596 if (rec_type
== REC_TYPE_DSN_ENVID
) {
597 if (message
->dsn_envid
== 0)
598 message
->dsn_envid
= mystrdup(start
);
600 if (rec_type
== REC_TYPE_DSN_RET
) {
601 if (message
->dsn_ret
== 0) {
602 if (!alldig(start
) || (n
= atoi(start
)) == 0 || !DSN_RET_OK(n
))
603 msg_warn("%s: ignoring malformed DSN RET flags in queue file record:%.100s",
604 message
->queue_id
, start
);
606 message
->dsn_ret
= n
;
609 if (rec_type
== REC_TYPE_ATTR
) {
610 /* Allow extra segment to override envelope segment info. */
611 if (strcmp(name
, MAIL_ATTR_ENCODING
) == 0) {
612 if (message
->encoding
!= 0)
613 myfree(message
->encoding
);
614 message
->encoding
= mystrdup(value
);
618 * Backwards compatibility. Before Postfix 2.3, the logging
619 * attributes were called client_name, etc. Now they are called
620 * log_client_name. etc., and client_name is used for the actual
621 * client information. To support old queue files, we accept both
622 * names for the purpose of logging; the new name overrides the
625 * XXX Do not use the "legacy" client_name etc. attribute values for
626 * initializing the logging attributes, when this file already
627 * contains the "modern" log_client_name etc. logging attributes.
628 * Otherwise, logging attributes that are not present in the
629 * queue file would be set with information from the real client.
631 else if (strcmp(name
, MAIL_ATTR_ACT_CLIENT_NAME
) == 0) {
632 if (have_log_client_attr
== 0 && message
->client_name
== 0)
633 message
->client_name
= mystrdup(value
);
634 } else if (strcmp(name
, MAIL_ATTR_ACT_CLIENT_ADDR
) == 0) {
635 if (have_log_client_attr
== 0 && message
->client_addr
== 0)
636 message
->client_addr
= mystrdup(value
);
637 } else if (strcmp(name
, MAIL_ATTR_ACT_CLIENT_PORT
) == 0) {
638 if (have_log_client_attr
== 0 && message
->client_port
== 0)
639 message
->client_port
= mystrdup(value
);
640 } else if (strcmp(name
, MAIL_ATTR_ACT_PROTO_NAME
) == 0) {
641 if (have_log_client_attr
== 0 && message
->client_proto
== 0)
642 message
->client_proto
= mystrdup(value
);
643 } else if (strcmp(name
, MAIL_ATTR_ACT_HELO_NAME
) == 0) {
644 if (have_log_client_attr
== 0 && message
->client_helo
== 0)
645 message
->client_helo
= mystrdup(value
);
647 /* Original client attributes. */
648 else if (strcmp(name
, MAIL_ATTR_LOG_CLIENT_NAME
) == 0) {
649 if (message
->client_name
!= 0)
650 myfree(message
->client_name
);
651 message
->client_name
= mystrdup(value
);
652 have_log_client_attr
= 1;
653 } else if (strcmp(name
, MAIL_ATTR_LOG_CLIENT_ADDR
) == 0) {
654 if (message
->client_addr
!= 0)
655 myfree(message
->client_addr
);
656 message
->client_addr
= mystrdup(value
);
657 have_log_client_attr
= 1;
658 } else if (strcmp(name
, MAIL_ATTR_LOG_CLIENT_PORT
) == 0) {
659 if (message
->client_port
!= 0)
660 myfree(message
->client_port
);
661 message
->client_port
= mystrdup(value
);
662 have_log_client_attr
= 1;
663 } else if (strcmp(name
, MAIL_ATTR_LOG_PROTO_NAME
) == 0) {
664 if (message
->client_proto
!= 0)
665 myfree(message
->client_proto
);
666 message
->client_proto
= mystrdup(value
);
667 have_log_client_attr
= 1;
668 } else if (strcmp(name
, MAIL_ATTR_LOG_HELO_NAME
) == 0) {
669 if (message
->client_helo
!= 0)
670 myfree(message
->client_helo
);
671 message
->client_helo
= mystrdup(value
);
672 have_log_client_attr
= 1;
673 } else if (strcmp(name
, MAIL_ATTR_SASL_METHOD
) == 0) {
674 if (message
->sasl_method
== 0)
675 message
->sasl_method
= mystrdup(value
);
677 msg_warn("%s: ignoring multiple %s attribute: %s",
678 message
->queue_id
, MAIL_ATTR_SASL_METHOD
, value
);
679 } else if (strcmp(name
, MAIL_ATTR_SASL_USERNAME
) == 0) {
680 if (message
->sasl_username
== 0)
681 message
->sasl_username
= mystrdup(value
);
683 msg_warn("%s: ignoring multiple %s attribute: %s",
684 message
->queue_id
, MAIL_ATTR_SASL_USERNAME
, value
);
685 } else if (strcmp(name
, MAIL_ATTR_SASL_SENDER
) == 0) {
686 if (message
->sasl_sender
== 0)
687 message
->sasl_sender
= mystrdup(value
);
689 msg_warn("%s: ignoring multiple %s attribute: %s",
690 message
->queue_id
, MAIL_ATTR_SASL_SENDER
, value
);
691 } else if (strcmp(name
, MAIL_ATTR_RWR_CONTEXT
) == 0) {
692 if (message
->rewrite_context
== 0)
693 message
->rewrite_context
= mystrdup(value
);
695 msg_warn("%s: ignoring multiple %s attribute: %s",
696 message
->queue_id
, MAIL_ATTR_RWR_CONTEXT
, value
);
700 * Optional tracing flags (verify, sendmail -v, sendmail -bv).
701 * This record is killed after a trace logfile report is sent and
702 * after the logfile is deleted.
704 else if (strcmp(name
, MAIL_ATTR_TRACE_FLAGS
) == 0) {
705 message
->tflags
= DEL_REQ_TRACE_FLAGS(atoi(value
));
706 if (message
->tflags
== DEL_REQ_FLAG_RECORD
)
707 message
->tflags_offset
= curr_offset
;
709 message
->tflags_offset
= 0;
713 if (rec_type
== REC_TYPE_WARN
) {
714 if (message
->warn_offset
== 0) {
715 message
->warn_offset
= curr_offset
;
716 REC_TYPE_WARN_SCAN(start
, message
->warn_time
);
720 if (rec_type
== REC_TYPE_VERP
) {
721 if (message
->verp_delims
== 0) {
722 if (message
->sender
== 0 || message
->sender
[0] == 0) {
723 msg_warn("%s: ignoring VERP request for null sender",
725 } else if (verp_delims_verify(start
) != 0) {
726 msg_warn("%s: ignoring bad VERP request: \"%.100s\"",
727 message
->queue_id
, start
);
729 message
->single_rcpt
= 1;
730 message
->verp_delims
= mystrdup(start
);
740 if (dsn_orcpt
!= 0) {
742 msg_warn("%s: ignoring out-of-order DSN original recipient <%.200s>",
743 message
->queue_id
, dsn_orcpt
);
746 if (orig_rcpt
!= 0) {
748 msg_warn("%s: ignoring out-of-order original recipient <%.200s>",
749 message
->queue_id
, orig_rcpt
);
754 * Avoid clumsiness elsewhere in the program. When sending data across an
755 * IPC channel, sending an empty string is more convenient than sending a
758 if (message
->dsn_envid
== 0)
759 message
->dsn_envid
= mystrdup("");
760 if (message
->encoding
== 0)
761 message
->encoding
= mystrdup(MAIL_ATTR_ENC_NONE
);
762 if (message
->client_name
== 0)
763 message
->client_name
= mystrdup("");
764 if (message
->client_addr
== 0)
765 message
->client_addr
= mystrdup("");
766 if (message
->client_port
== 0)
767 message
->client_port
= mystrdup("");
768 if (message
->client_proto
== 0)
769 message
->client_proto
= mystrdup("");
770 if (message
->client_helo
== 0)
771 message
->client_helo
= mystrdup("");
772 if (message
->sasl_method
== 0)
773 message
->sasl_method
= mystrdup("");
774 if (message
->sasl_username
== 0)
775 message
->sasl_username
= mystrdup("");
776 if (message
->sasl_sender
== 0)
777 message
->sasl_sender
= mystrdup("");
778 if (message
->rewrite_context
== 0)
779 message
->rewrite_context
= mystrdup(MAIL_ATTR_RWR_LOCAL
);
780 /* Postfix < 2.3 compatibility. */
781 if (message
->create_time
== 0)
782 message
->create_time
= message
->arrival_time
.tv_sec
;
790 * Sanity checks. Verify that all required information was found,
791 * including the queue file end marker.
794 /* Already logged warning. */
795 } else if (message
->arrival_time
.tv_sec
== 0) {
796 msg_warn("%s: message rejected: missing arrival time record",
798 } else if (message
->sender
== 0) {
799 msg_warn("%s: message rejected: missing sender record",
801 } else if (message
->data_offset
== 0) {
802 msg_warn("%s: message rejected: missing size record",
807 message
->rcpt_offset
= save_offset
; /* restore flag */
811 /* qmgr_message_update_warn - update the time of next delay warning */
813 void qmgr_message_update_warn(QMGR_MESSAGE
*message
)
817 * XXX eventually this should let us schedule multiple warnings, right
818 * now it just allows for one.
820 if (qmgr_message_open(message
)
821 || vstream_fseek(message
->fp
, message
->warn_offset
, SEEK_SET
) < 0
822 || rec_fprintf(message
->fp
, REC_TYPE_WARN
, REC_TYPE_WARN_FORMAT
,
823 REC_TYPE_WARN_ARG(0)) < 0
824 || vstream_fflush(message
->fp
))
825 msg_fatal("update queue file %s: %m", VSTREAM_PATH(message
->fp
));
826 qmgr_message_close(message
);
829 /* qmgr_message_kill_record - mark one message record as killed */
831 void qmgr_message_kill_record(QMGR_MESSAGE
*message
, long offset
)
834 msg_panic("qmgr_message_kill_record: bad offset 0x%lx", offset
);
835 if (qmgr_message_open(message
)
836 || rec_put_type(message
->fp
, REC_TYPE_KILL
, offset
) < 0
837 || vstream_fflush(message
->fp
))
838 msg_fatal("update queue file %s: %m", VSTREAM_PATH(message
->fp
));
839 qmgr_message_close(message
);
842 /* qmgr_message_sort_compare - compare recipient information */
844 static int qmgr_message_sort_compare(const void *p1
, const void *p2
)
846 RECIPIENT
*rcpt1
= (RECIPIENT
*) p1
;
847 RECIPIENT
*rcpt2
= (RECIPIENT
*) p2
;
855 * Compare most significant to least significant recipient attributes.
856 * The comparison function must be transitive, so NULL values need to be
857 * assigned an ordinal (we set NULL last).
860 queue1
= rcpt1
->u
.queue
;
861 queue2
= rcpt2
->u
.queue
;
862 if (queue1
!= 0 && queue2
== 0)
864 if (queue1
== 0 && queue2
!= 0)
866 if (queue1
!= 0 && queue2
!= 0) {
869 * Compare message transport.
871 if ((result
= strcmp(queue1
->transport
->name
,
872 queue2
->transport
->name
)) != 0)
876 * Compare queue name (nexthop or recipient@nexthop).
878 if ((result
= strcmp(queue1
->name
, queue2
->name
)) != 0)
883 * Compare recipient domain.
885 at1
= strrchr(rcpt1
->address
, '@');
886 at2
= strrchr(rcpt2
->address
, '@');
887 if (at1
== 0 && at2
!= 0)
889 if (at1
!= 0 && at2
== 0)
891 if (at1
!= 0 && at2
!= 0
892 && (result
= strcasecmp(at1
, at2
)) != 0)
896 * Compare recipient address.
898 return (strcasecmp(rcpt1
->address
, rcpt2
->address
));
901 /* qmgr_message_sort - sort message recipient addresses by domain */
903 static void qmgr_message_sort(QMGR_MESSAGE
*message
)
905 qsort((char *) message
->rcpt_list
.info
, message
->rcpt_list
.len
,
906 sizeof(message
->rcpt_list
.info
[0]), qmgr_message_sort_compare
);
908 RECIPIENT_LIST list
= message
->rcpt_list
;
911 msg_info("start sorted recipient list");
912 for (rcpt
= list
.info
; rcpt
< list
.info
+ list
.len
; rcpt
++)
913 msg_info("qmgr_message_sort: %s", rcpt
->address
);
914 msg_info("end sorted recipient list");
918 /* qmgr_resolve_one - resolve or skip one recipient */
920 static int qmgr_resolve_one(QMGR_MESSAGE
*message
, RECIPIENT
*recipient
,
921 const char *addr
, RESOLVE_REPLY
*reply
)
923 #define QMGR_REDIRECT(rp, tp, np) do { \
925 vstring_strcpy((rp)->transport, (tp)); \
926 vstring_strcpy((rp)->nexthop, (np)); \
929 if ((message
->tflags
& DEL_REQ_FLAG_MTA_VRFY
) == 0)
930 resolve_clnt_query_from(message
->sender
, addr
, reply
);
932 resolve_clnt_verify_from(message
->sender
, addr
, reply
);
933 if (reply
->flags
& RESOLVE_FLAG_FAIL
) {
934 QMGR_REDIRECT(reply
, MAIL_SERVICE_RETRY
,
935 "4.3.0 address resolver failure");
937 } else if (reply
->flags
& RESOLVE_FLAG_ERROR
) {
938 QMGR_REDIRECT(reply
, MAIL_SERVICE_ERROR
,
939 "5.1.3 bad address syntax");
946 /* qmgr_message_resolve - resolve recipients */
948 static void qmgr_message_resolve(QMGR_MESSAGE
*message
)
950 static ARGV
*defer_xport_argv
;
951 RECIPIENT_LIST list
= message
->rcpt_list
;
952 RECIPIENT
*recipient
;
953 QMGR_TRANSPORT
*transport
= 0;
954 QMGR_QUEUE
*queue
= 0;
966 #define STREQ(x,y) (strcmp(x,y) == 0)
967 #define STR vstring_str
968 #define LEN VSTRING_LEN
970 resolve_clnt_init(&reply
);
971 queue_name
= vstring_alloc(1);
972 for (recipient
= list
.info
; recipient
< list
.info
+ list
.len
; recipient
++) {
975 * Redirect overrides all else. But only once (per entire message).
976 * For consistency with the remainder of Postfix, rewrite the address
977 * to canonical form before resolving it.
979 if (message
->redirect_addr
) {
980 if (recipient
> list
.info
) {
981 recipient
->u
.queue
= 0;
984 message
->rcpt_offset
= 0;
985 rewrite_clnt_internal(REWRITE_CANON
, message
->redirect_addr
,
987 RECIPIENT_UPDATE(recipient
->address
, STR(reply
.recipient
));
988 if (qmgr_resolve_one(message
, recipient
,
989 recipient
->address
, &reply
) < 0)
991 if (!STREQ(recipient
->address
, STR(reply
.recipient
)))
992 RECIPIENT_UPDATE(recipient
->address
, STR(reply
.recipient
));
996 * Content filtering overrides the address resolver.
998 * XXX Bypass content_filter inspection for user-generated probes
999 * (sendmail -bv). MTA-generated probes never have the "please filter
1000 * me" bits turned on, but we handle them here anyway for the sake of
1003 else if (message
->filter_xport
1004 && (message
->tflags
& DEL_REQ_TRACE_ONLY_MASK
) == 0) {
1006 vstring_strcpy(reply
.transport
, message
->filter_xport
);
1007 if ((nexthop
= split_at(STR(reply
.transport
), ':')) == 0
1009 nexthop
= var_myhostname
;
1010 vstring_strcpy(reply
.nexthop
, nexthop
);
1011 vstring_strcpy(reply
.recipient
, recipient
->address
);
1015 * Resolve the destination to (transport, nexthop, address). The
1016 * result address may differ from the one specified by the sender.
1019 if (qmgr_resolve_one(message
, recipient
,
1020 recipient
->address
, &reply
) < 0)
1022 if (!STREQ(recipient
->address
, STR(reply
.recipient
)))
1023 RECIPIENT_UPDATE(recipient
->address
, STR(reply
.recipient
));
1027 * Bounce null recipients. This should never happen, but is most
1028 * likely the result of a fault in a different program, so aborting
1029 * the queue manager process does not help.
1031 if (recipient
->address
[0] == 0) {
1032 QMGR_REDIRECT(&reply
, MAIL_SERVICE_ERROR
,
1033 "5.1.3 null recipient address");
1037 * Discard mail to the local double bounce address here, so this
1038 * system can run without a local delivery agent. They'd still have
1039 * to configure something for mail directed to the local postmaster,
1040 * though, but that is an RFC requirement anyway.
1042 * XXX This lookup should be done in the resolver, and the mail should
1043 * be directed to a general-purpose null delivery agent.
1045 if (reply
.flags
& RESOLVE_CLASS_LOCAL
) {
1046 at
= strrchr(STR(reply
.recipient
), '@');
1047 len
= (at
? (at
- STR(reply
.recipient
))
1048 : strlen(STR(reply
.recipient
)));
1049 if (strncasecmp(STR(reply
.recipient
), var_double_bounce_sender
,
1051 && !var_double_bounce_sender
[len
]) {
1052 status
= sent(message
->tflags
, message
->queue_id
,
1053 QMGR_MSG_STATS(&stats
, message
), recipient
,
1054 "none", DSN_SIMPLE(&dsn
, "2.0.0",
1055 "undeliverable postmaster notification discarded"));
1057 deliver_completed(message
->fp
, recipient
->offset
);
1059 /* It's the default verification probe sender address. */
1060 msg_warn("%s: undeliverable postmaster notification discarded",
1064 message
->flags
|= status
;
1070 * Optionally defer deliveries over specific transports, unless the
1071 * restriction is lifted temporarily.
1073 if (*var_defer_xports
&& (message
->qflags
& QMGR_FLUSH_DFXP
) == 0) {
1074 if (defer_xport_argv
== 0)
1075 defer_xport_argv
= argv_split(var_defer_xports
, " \t\r\n,");
1076 for (cpp
= defer_xport_argv
->argv
; *cpp
; cpp
++)
1077 if (strcmp(*cpp
, STR(reply
.transport
)) == 0)
1080 QMGR_REDIRECT(&reply
, MAIL_SERVICE_RETRY
,
1081 "4.3.2 deferred transport");
1086 * Look up or instantiate the proper transport.
1088 if (transport
== 0 || !STREQ(transport
->name
, STR(reply
.transport
))) {
1089 if ((transport
= qmgr_transport_find(STR(reply
.transport
))) == 0)
1090 transport
= qmgr_transport_create(STR(reply
.transport
));
1095 * This message is being flushed. If need-be unthrottle the
1098 if ((message
->qflags
& QMGR_FLUSH_EACH
) != 0
1099 && QMGR_TRANSPORT_THROTTLED(transport
))
1100 qmgr_transport_unthrottle(transport
);
1103 * This transport is dead. Defer delivery to this recipient.
1105 if (QMGR_TRANSPORT_THROTTLED(transport
)) {
1106 saved_dsn
= transport
->dsn
;
1107 if ((transport
= qmgr_error_transport(MAIL_SERVICE_RETRY
)) != 0) {
1108 nexthop
= qmgr_error_nexthop(saved_dsn
);
1109 vstring_strcpy(reply
.nexthop
, nexthop
);
1113 qmgr_defer_recipient(message
, recipient
, saved_dsn
);
1119 * The nexthop destination provides the default name for the
1120 * per-destination queue. When the delivery agent accepts only one
1121 * recipient per delivery, give each recipient its own queue, so that
1122 * deliveries to different recipients of the same message can happen
1123 * in parallel, and so that we can enforce per-recipient concurrency
1124 * limits and prevent one recipient from tying up all the delivery
1125 * agent resources. We use recipient@nexthop as queue name rather
1126 * than the actual recipient domain name, so that one recipient in
1127 * multiple equivalent domains cannot evade the per-recipient
1128 * concurrency limit. Split the address on the recipient delimiter if
1129 * one is defined, so that extended addresses don't get extra
1132 * Fold the result to lower case so that we don't have multiple queues
1133 * for the same name.
1135 * Important! All recipients in a queue must have the same nexthop
1136 * value. It is OK to have multiple queues with the same nexthop
1137 * value, but only when those queues are named after recipients.
1139 * The single-recipient code below was written for local(8) like
1140 * delivery agents, and assumes that all domains that deliver to the
1141 * same (transport + nexthop) are aliases for $nexthop. Delivery
1142 * concurrency is changed from per-domain into per-recipient, by
1143 * changing the queue name from nexthop into localpart@nexthop.
1145 * XXX This assumption is incorrect when different destinations share
1146 * the same (transport + nexthop). In reality, such transports are
1147 * rarely configured to use single-recipient deliveries. The fix is
1148 * to decouple the per-destination recipient limit from the
1149 * per-destination concurrency.
1151 vstring_strcpy(queue_name
, STR(reply
.nexthop
));
1152 if (strcmp(transport
->name
, MAIL_SERVICE_ERROR
) != 0
1153 && strcmp(transport
->name
, MAIL_SERVICE_RETRY
) != 0
1154 && transport
->recipient_limit
== 1) {
1155 /* Copy the recipient localpart. */
1156 at
= strrchr(STR(reply
.recipient
), '@');
1157 len
= (at
? (at
- STR(reply
.recipient
))
1158 : strlen(STR(reply
.recipient
)));
1159 vstring_strncpy(queue_name
, STR(reply
.recipient
), len
);
1160 /* Remove the address extension from the recipient localpart. */
1161 if (*var_rcpt_delim
&& split_addr(STR(queue_name
), *var_rcpt_delim
))
1162 vstring_truncate(queue_name
, strlen(STR(queue_name
)));
1163 /* Assume the recipient domain is equivalent to nexthop. */
1164 vstring_sprintf_append(queue_name
, "@%s", STR(reply
.nexthop
));
1166 lowercase(STR(queue_name
));
1169 * This transport is alive. Find or instantiate a queue for this
1172 if (queue
== 0 || !STREQ(queue
->name
, STR(queue_name
))) {
1173 if ((queue
= qmgr_queue_find(transport
, STR(queue_name
))) == 0)
1174 queue
= qmgr_queue_create(transport
, STR(queue_name
),
1175 STR(reply
.nexthop
));
1179 * This message is being flushed. If need-be unthrottle the queue.
1181 if ((message
->qflags
& QMGR_FLUSH_EACH
) != 0
1182 && QMGR_QUEUE_THROTTLED(queue
))
1183 qmgr_queue_unthrottle(queue
);
1186 * This queue is dead. Defer delivery to this recipient.
1188 if (QMGR_QUEUE_THROTTLED(queue
)) {
1189 saved_dsn
= queue
->dsn
;
1190 if ((queue
= qmgr_error_queue(MAIL_SERVICE_RETRY
, saved_dsn
)) == 0) {
1191 qmgr_defer_recipient(message
, recipient
, saved_dsn
);
1197 * This queue is alive. Bind this recipient to this queue instance.
1199 recipient
->u
.queue
= queue
;
1201 resolve_clnt_free(&reply
);
1202 vstring_free(queue_name
);
1205 /* qmgr_message_assign - assign recipients to specific delivery requests */
1207 static void qmgr_message_assign(QMGR_MESSAGE
*message
)
1209 RECIPIENT_LIST list
= message
->rcpt_list
;
1210 RECIPIENT
*recipient
;
1211 QMGR_ENTRY
*entry
= 0;
1215 * Try to bundle as many recipients in a delivery request as we can. When
1216 * the recipient resolves to the same site and transport as the previous
1217 * recipient, do not create a new queue entry, just move that recipient
1218 * to the recipient list of the existing queue entry. All this provided
1219 * that we do not exceed the transport-specific limit on the number of
1220 * recipients per transaction. Skip recipients with a dead transport or
1223 #define LIMIT_OK(limit, count) ((limit) == 0 || ((count) < (limit)))
1225 for (recipient
= list
.info
; recipient
< list
.info
+ list
.len
; recipient
++) {
1226 if ((queue
= recipient
->u
.queue
) != 0) {
1227 if (message
->single_rcpt
|| entry
== 0 || entry
->queue
!= queue
1228 || !LIMIT_OK(entry
->queue
->transport
->recipient_limit
,
1229 entry
->rcpt_list
.len
)) {
1230 entry
= qmgr_entry_create(queue
, message
);
1232 recipient_list_add(&entry
->rcpt_list
, recipient
->offset
,
1233 recipient
->dsn_orcpt
, recipient
->dsn_notify
,
1234 recipient
->orig_addr
, recipient
->address
);
1235 qmgr_recipient_count
++;
1238 recipient_list_free(&message
->rcpt_list
);
1239 recipient_list_init(&message
->rcpt_list
, RCPT_LIST_INIT_QUEUE
);
1242 /* qmgr_message_free - release memory for in-core message structure */
1244 void qmgr_message_free(QMGR_MESSAGE
*message
)
1246 if (message
->refcount
!= 0)
1247 msg_panic("qmgr_message_free: reference len: %d", message
->refcount
);
1249 msg_panic("qmgr_message_free: queue file is open");
1250 myfree(message
->queue_id
);
1251 myfree(message
->queue_name
);
1252 if (message
->dsn_envid
)
1253 myfree(message
->dsn_envid
);
1254 if (message
->encoding
)
1255 myfree(message
->encoding
);
1256 if (message
->sender
)
1257 myfree(message
->sender
);
1258 if (message
->verp_delims
)
1259 myfree(message
->verp_delims
);
1260 if (message
->filter_xport
)
1261 myfree(message
->filter_xport
);
1262 if (message
->inspect_xport
)
1263 myfree(message
->inspect_xport
);
1264 if (message
->redirect_addr
)
1265 myfree(message
->redirect_addr
);
1266 if (message
->client_name
)
1267 myfree(message
->client_name
);
1268 if (message
->client_addr
)
1269 myfree(message
->client_addr
);
1270 if (message
->client_port
)
1271 myfree(message
->client_port
);
1272 if (message
->client_proto
)
1273 myfree(message
->client_proto
);
1274 if (message
->client_helo
)
1275 myfree(message
->client_helo
);
1276 if (message
->sasl_method
)
1277 myfree(message
->sasl_method
);
1278 if (message
->sasl_username
)
1279 myfree(message
->sasl_username
);
1280 if (message
->sasl_sender
)
1281 myfree(message
->sasl_sender
);
1282 if (message
->rewrite_context
)
1283 myfree(message
->rewrite_context
);
1284 recipient_list_free(&message
->rcpt_list
);
1285 qmgr_message_count
--;
1286 myfree((char *) message
);
1289 /* qmgr_message_alloc - create in-core message structure */
1291 QMGR_MESSAGE
*qmgr_message_alloc(const char *queue_name
, const char *queue_id
,
1292 int qflags
, mode_t mode
)
1294 const char *myname
= "qmgr_message_alloc";
1295 QMGR_MESSAGE
*message
;
1298 msg_info("%s: %s %s", myname
, queue_name
, queue_id
);
1301 * Create an in-core message structure.
1303 message
= qmgr_message_create(queue_name
, queue_id
, qflags
);
1306 * Extract message envelope information: time of arrival, sender address,
1307 * recipient addresses. Skip files with malformed envelope information.
1309 #define QMGR_LOCK_MODE (MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT)
1311 if (qmgr_message_open(message
) < 0) {
1312 qmgr_message_free(message
);
1315 if (myflock(vstream_fileno(message
->fp
), INTERNAL_LOCK
, QMGR_LOCK_MODE
) < 0) {
1316 msg_info("%s: skipped, still being delivered", queue_id
);
1317 qmgr_message_close(message
);
1318 qmgr_message_free(message
);
1319 return (QMGR_MESSAGE_LOCKED
);
1321 if (qmgr_message_read(message
) < 0) {
1322 qmgr_message_close(message
);
1323 qmgr_message_free(message
);
1328 * We have validated the queue file content, so it is safe to modify
1329 * the file properties now.
1331 if (mode
!= 0 && fchmod(vstream_fileno(message
->fp
), mode
) < 0)
1332 msg_fatal("fchmod %s: %m", VSTREAM_PATH(message
->fp
));
1335 * Reset the defer log. This code should not be here, but we must
1336 * reset the defer log *after* acquiring the exclusive lock on the
1337 * queue file and *before* resolving new recipients. Since all those
1338 * operations are encapsulated so nicely by this routine, the defer
1339 * log reset has to be done here as well.
1341 * Note: it is safe to remove the defer logfile from a previous queue
1342 * run of this queue file, because the defer log contains information
1343 * about recipients that still exist in this queue file.
1345 if (mail_queue_remove(MAIL_QUEUE_DEFER
, queue_id
) && errno
!= ENOENT
)
1346 msg_fatal("%s: %s: remove %s %s: %m", myname
,
1347 queue_id
, MAIL_QUEUE_DEFER
, queue_id
);
1348 qmgr_message_sort(message
);
1349 qmgr_message_resolve(message
);
1350 qmgr_message_sort(message
);
1351 qmgr_message_assign(message
);
1352 qmgr_message_close(message
);
1357 /* qmgr_message_realloc - refresh in-core message structure */
1359 QMGR_MESSAGE
*qmgr_message_realloc(QMGR_MESSAGE
*message
)
1361 const char *myname
= "qmgr_message_realloc";
1366 if (message
->rcpt_offset
<= 0)
1367 msg_panic("%s: invalid offset: %ld", myname
, message
->rcpt_offset
);
1369 msg_info("%s: %s %s offset %ld", myname
, message
->queue_name
,
1370 message
->queue_id
, message
->rcpt_offset
);
1373 * Extract recipient addresses. Skip files with malformed envelope
1376 if (qmgr_message_open(message
) < 0)
1378 if (qmgr_message_read(message
) < 0) {
1379 qmgr_message_close(message
);
1382 qmgr_message_sort(message
);
1383 qmgr_message_resolve(message
);
1384 qmgr_message_sort(message
);
1385 qmgr_message_assign(message
);
1386 qmgr_message_close(message
);