1/*++
2/* NAME
3/*	qmgr_message 3
4/* SUMMARY
5/*	in-core message structures
6/* SYNOPSIS
7/*	#include "qmgr.h"
8/*
9/*	int	qmgr_message_count;
10/*	int	qmgr_recipient_count;
11/*
12/*	QMGR_MESSAGE *qmgr_message_alloc(class, name, qflags, mode)
13/*	const char *class;
14/*	const char *name;
15/*	int	qflags;
16/*	mode_t	mode;
17/*
18/*	QMGR_MESSAGE *qmgr_message_realloc(message)
19/*	QMGR_MESSAGE *message;
20/*
21/*	void	qmgr_message_free(message)
22/*	QMGR_MESSAGE *message;
23/*
24/*	void	qmgr_message_update_warn(message)
25/*	QMGR_MESSAGE *message;
26/*
27/*	void	qmgr_message_kill_record(message, offset)
28/*	QMGR_MESSAGE *message;
29/*	long	offset;
30/* DESCRIPTION
31/*	This module performs en-gross operations on queue messages.
32/*
33/*	qmgr_message_count is a global counter for the total number
34/*	of in-core message structures (i.e. the total size of the
35/*	`active' message queue).
36/*
37/*	qmgr_recipient_count is a global counter for the total number
38/*	of in-core recipient structures (i.e. the sum of all recipients
39/*	in all in-core message structures).
40/*
41/*	qmgr_message_alloc() creates an in-core message structure
42/*	with sender and recipient information taken from the named queue
43/*	file. A null result means the queue file could not be read or
44/*	that the queue file contained incorrect information. A result
45/*	QMGR_MESSAGE_LOCKED means delivery must be deferred. The number
46/*	of recipients read from a queue file is limited by the global
47/*	var_qmgr_rcpt_limit configuration parameter. When the limit
48/*	is reached, the \fIrcpt_offset\fR structure member is set to
49/*	the position where the read was terminated. Recipients are
50/*	run through the resolver, and are assigned to destination
51/*	queues. Recipients that cannot be assigned are deferred or
52/*	bounced. Mail that has bounced twice is silently absorbed.
53/*	A non-zero mode means change the queue file permissions.
54/*
55/*	qmgr_message_realloc() resumes reading recipients from the queue
56/*	file, and updates the recipient list and \fIrcpt_offset\fR message
57/*	structure members. A null result means that the file could not be
58/*	read or that the file contained incorrect information.
59/*
60/*	qmgr_message_free() destroys an in-core message structure and makes
61/*	the resources available for reuse. It is an error to destroy
62/*	a message structure that is still referenced by queue entry structures.
63/*
64/*	qmgr_message_update_warn() takes a closed message, opens it, updates
65/*	the warning field, and closes it again.
66/*
67/*	qmgr_message_kill_record() takes a closed message, opens it, updates
68/*	the record type at the given offset to "killed", and closes the file.
69/*	A killed envelope record is ignored. Killed records are not allowed
70/*	inside the message content.
71/* DIAGNOSTICS
72/*	Warnings: malformed message file. Fatal errors: out of memory.
73/* SEE ALSO
74/*	envelope(3) message envelope parser
75/* LICENSE
76/* .ad
77/* .fi
78/*	The Secure Mailer license must be distributed with this software.
79/* AUTHOR(S)
80/*	Wietse Venema
81/*	IBM T.J. Watson Research
82/*	P.O. Box 704
83/*	Yorktown Heights, NY 10598, USA
84/*--*/
85
86/* System library. */
87
88#include <sys_defs.h>
89#include <sys/stat.h>
90#include <stdlib.h>
91#include <stdio.h>			/* sscanf() */
92#include <fcntl.h>
93#include <errno.h>
94#include <unistd.h>
95#include <string.h>
96#include <ctype.h>
97
98#ifdef STRCASECMP_IN_STRINGS_H
99#include <strings.h>
100#endif
101
102/* Utility library. */
103
104#include <msg.h>
105#include <mymalloc.h>
106#include <vstring.h>
107#include <vstream.h>
108#include <split_at.h>
109#include <valid_hostname.h>
110#include <argv.h>
111#include <stringops.h>
112#include <myflock.h>
113
114/* Global library. */
115
116#include <dict.h>
117#include <mail_queue.h>
118#include <mail_params.h>
119#include <canon_addr.h>
120#include <record.h>
121#include <rec_type.h>
122#include <sent.h>
123#include <deliver_completed.h>
124#include <opened.h>
125#include <verp_sender.h>
126#include <mail_proto.h>
127#include <qmgr_user.h>
128#include <split_addr.h>
129#include <dsn_mask.h>
130#include <rec_attr_map.h>
131
132/* Client stubs. */
133
134#include <rewrite_clnt.h>
135#include <resolve_clnt.h>
136
137/* Application-specific. */
138
139#include "qmgr.h"
140
141int     qmgr_message_count;
142int     qmgr_recipient_count;
143
144/* qmgr_message_create - create in-core message structure */
145
146static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
147				           const char *queue_id, int qflags)
148{
149    QMGR_MESSAGE *message;
150
151    message = (QMGR_MESSAGE *) mymalloc(sizeof(QMGR_MESSAGE));
152    qmgr_message_count++;
153    message->flags = 0;
154    message->qflags = qflags;
155    message->tflags = 0;
156    message->tflags_offset = 0;
157    message->rflags = QMGR_READ_FLAG_DEFAULT;
158    message->fp = 0;
159    message->refcount = 0;
160    message->single_rcpt = 0;
161    message->arrival_time.tv_sec = message->arrival_time.tv_usec = 0;
162    message->create_time = 0;
163    GETTIMEOFDAY(&message->active_time);
164    message->data_offset = 0;
165    message->queue_id = mystrdup(queue_id);
166    message->queue_name = mystrdup(queue_name);
167    message->encoding = 0;
168    message->sender = 0;
169    message->dsn_envid = 0;
170    message->dsn_ret = 0;
171    message->filter_xport = 0;
172    message->inspect_xport = 0;
173    message->redirect_addr = 0;
174    message->data_size = 0;
175    message->cont_length = 0;
176    message->warn_offset = 0;
177    message->warn_time = 0;
178    message->rcpt_offset = 0;
179    message->verp_delims = 0;
180    message->client_name = 0;
181    message->client_addr = 0;
182    message->client_port = 0;
183    message->client_proto = 0;
184    message->client_helo = 0;
185    message->sasl_method = 0;
186    message->sasl_username = 0;
187    message->sasl_sender = 0;
188    message->log_ident = 0;
189    message->rewrite_context = 0;
190    recipient_list_init(&message->rcpt_list, RCPT_LIST_INIT_QUEUE);
191    return (message);
192}
193
194/* qmgr_message_close - close queue file */
195
196static void qmgr_message_close(QMGR_MESSAGE *message)
197{
198    vstream_fclose(message->fp);
199    message->fp = 0;
200}
201
202/* qmgr_message_open - open queue file */
203
204static int qmgr_message_open(QMGR_MESSAGE *message)
205{
206
207    /*
208     * Sanity check.
209     */
210    if (message->fp)
211	msg_panic("%s: queue file is open", message->queue_id);
212
213    /*
214     * Open this queue file. Skip files that we cannot open. Back off when
215     * the system appears to be running out of resources.
216     */
217    if ((message->fp = mail_queue_open(message->queue_name,
218				       message->queue_id,
219				       O_RDWR, 0)) == 0) {
220	if (errno != ENOENT)
221	    msg_fatal("open %s %s: %m", message->queue_name, message->queue_id);
222	msg_warn("open %s %s: %m", message->queue_name, message->queue_id);
223	return (-1);
224    }
225    return (0);
226}
227
228/* qmgr_message_oldstyle_scan - support for Postfix < 1.0 queue files */
229
230static void qmgr_message_oldstyle_scan(QMGR_MESSAGE *message)
231{
232    VSTRING *buf;
233    long    orig_offset, extra_offset;
234    int     rec_type;
235    char   *start;
236
237    /*
238     * Initialize. No early returns or we have a memory leak.
239     */
240    buf = vstring_alloc(100);
241    if ((orig_offset = vstream_ftell(message->fp)) < 0)
242	msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
243
244    /*
245     * Rewind to the very beginning to make sure we see all records.
246     */
247    if (vstream_fseek(message->fp, 0, SEEK_SET) < 0)
248	msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
249
250    /*
251     * Scan through the old style queue file. Count the total number of
252     * recipients and find the data/extra sections offsets. Note that the new
253     * queue files require that data_size equals extra_offset - data_offset,
254     * so we set data_size to this as well and ignore the size record itself
255     * completely.
256     */
257    for (;;) {
258	rec_type = rec_get(message->fp, buf, 0);
259	if (rec_type <= 0)
260	    /* Report missing end record later. */
261	    break;
262	start = vstring_str(buf);
263	if (msg_verbose > 1)
264	    msg_info("old-style scan record %c %s", rec_type, start);
265	if (rec_type == REC_TYPE_END)
266	    break;
267	if (rec_type == REC_TYPE_MESG) {
268	    if (message->data_offset == 0) {
269		if ((message->data_offset = vstream_ftell(message->fp)) < 0)
270		    msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
271		if ((extra_offset = atol(start)) <= message->data_offset)
272		    msg_fatal("bad extra offset %s file %s",
273			      start, VSTREAM_PATH(message->fp));
274		if (vstream_fseek(message->fp, extra_offset, SEEK_SET) < 0)
275		    msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
276		message->data_size = extra_offset - message->data_offset;
277	    }
278	    continue;
279	}
280    }
281
282    /*
283     * Clean up.
284     */
285    if (vstream_fseek(message->fp, orig_offset, SEEK_SET) < 0)
286	msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
287    vstring_free(buf);
288
289    /*
290     * Sanity checks. Verify that all required information was found,
291     * including the queue file end marker.
292     */
293    if (message->data_offset == 0 || rec_type != REC_TYPE_END)
294	msg_fatal("%s: envelope records out of order", message->queue_id);
295}
296
297/* qmgr_message_read - read envelope records */
298
299static int qmgr_message_read(QMGR_MESSAGE *message)
300{
301    VSTRING *buf;
302    int     rec_type;
303    long    curr_offset;
304    long    save_offset = message->rcpt_offset;	/* save a flag */
305    char   *start;
306    int     nrcpt = 0;
307    const char *error_text;
308    char   *name;
309    char   *value;
310    char   *orig_rcpt = 0;
311    int     count;
312    int     dsn_notify = 0;
313    char   *dsn_orcpt = 0;
314    int     n;
315    int     have_log_client_attr = 0;
316
317    /*
318     * Initialize. No early returns or we have a memory leak.
319     */
320    buf = vstring_alloc(100);
321
322    /*
323     * If we re-open this file, skip over on-file recipient records that we
324     * already looked at, and refill the in-core recipient address list.
325     */
326    if (message->rcpt_offset) {
327	if (message->rcpt_list.len)
328	    msg_panic("%s: recipient list not empty on recipient reload",
329		      message->queue_id);
330	if (vstream_fseek(message->fp, message->rcpt_offset, SEEK_SET) < 0)
331	    msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
332	message->rcpt_offset = 0;
333    }
334
335    /*
336     * Read envelope records. XXX Rely on the front-end programs to enforce
337     * record size limits. Read up to var_qmgr_rcpt_limit recipients from the
338     * queue file, to protect against memory exhaustion. Recipient records
339     * may appear before or after the message content, so we keep reading
340     * from the queue file until we have enough recipients (rcpt_offset != 0)
341     * and until we know all the non-recipient information.
342     *
343     * When reading recipients from queue file, stop reading when we reach a
344     * per-message in-core recipient limit rather than a global in-core
345     * recipient limit. Use the global recipient limit only in order to stop
346     * opening queue files. The purpose is to achieve equal delay for
347     * messages with recipient counts up to var_qmgr_rcpt_limit recipients.
348     *
349     * If we would read recipients up to a global recipient limit, the average
350     * number of in-core recipients per message would asymptotically approach
351     * (global recipient limit)/(active queue size limit), which gives equal
352     * delay per recipient rather than equal delay per message.
353     *
354     * On the first open, we must examine all non-recipient records.
355     *
356     * Optimization: when we know that recipient records are not mixed with
357     * non-recipient records, as is typical with mailing list mail, then we
358     * can avoid having to examine all the queue file records before we can
359     * start deliveries. This avoids some file system thrashing with huge
360     * mailing lists.
361     */
362    for (;;) {
363	if ((curr_offset = vstream_ftell(message->fp)) < 0)
364	    msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
365	if (curr_offset == message->data_offset && curr_offset > 0) {
366	    if (vstream_fseek(message->fp, message->data_size, SEEK_CUR) < 0)
367		msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
368	    curr_offset += message->data_size;
369	}
370	rec_type = rec_get_raw(message->fp, buf, 0, REC_FLAG_NONE);
371	start = vstring_str(buf);
372	if (msg_verbose > 1)
373	    msg_info("record %c %s", rec_type, start);
374	if (rec_type == REC_TYPE_PTR) {
375	    if ((rec_type = rec_goto(message->fp, start)) == REC_TYPE_ERROR)
376		break;
377	    /* Need to update curr_offset after pointer jump. */
378	    continue;
379	}
380	if (rec_type <= 0) {
381	    msg_warn("%s: message rejected: missing end record",
382		     message->queue_id);
383	    break;
384	}
385	if (rec_type == REC_TYPE_END) {
386	    message->rflags |= QMGR_READ_FLAG_SEEN_ALL_NON_RCPT;
387	    break;
388	}
389
390	/*
391	 * Map named attributes to pseudo record types, so that we don't have
392	 * to pollute the queue file with records that are incompatible with
393	 * past Postfix versions. Preferably, people should be able to back
394	 * out from an upgrade without losing mail.
395	 */
396	if (rec_type == REC_TYPE_ATTR) {
397	    if ((error_text = split_nameval(start, &name, &value)) != 0) {
398		msg_warn("%s: ignoring bad attribute: %s: %.200s",
399			 message->queue_id, error_text, start);
400		rec_type = REC_TYPE_ERROR;
401		break;
402	    }
403	    if ((n = rec_attr_map(name)) != 0) {
404		start = value;
405		rec_type = n;
406	    }
407	}
408
409	/*
410	 * Process recipient records.
411	 */
412	if (rec_type == REC_TYPE_RCPT) {
413	    /* See also below for code setting orig_rcpt etc. */
414#define FUDGE(x)	((x) * (var_qmgr_fudge / 100.0))
415	    if (message->rcpt_offset == 0) {
416		recipient_list_add(&message->rcpt_list, curr_offset,
417				   dsn_orcpt ? dsn_orcpt : "",
418				   dsn_notify ? dsn_notify : 0,
419				   orig_rcpt ? orig_rcpt : "", start);
420		if (dsn_orcpt) {
421		    myfree(dsn_orcpt);
422		    dsn_orcpt = 0;
423		}
424		if (orig_rcpt) {
425		    myfree(orig_rcpt);
426		    orig_rcpt = 0;
427		}
428		if (dsn_notify)
429		    dsn_notify = 0;
430		if (message->rcpt_list.len >= FUDGE(var_qmgr_rcpt_limit)) {
431		    if ((message->rcpt_offset = vstream_ftell(message->fp)) < 0)
432			msg_fatal("vstream_ftell %s: %m",
433				  VSTREAM_PATH(message->fp));
434		    if (message->rflags & QMGR_READ_FLAG_SEEN_ALL_NON_RCPT)
435			/* We already examined all non-recipient records. */
436			break;
437		    if (message->rflags & QMGR_READ_FLAG_MIXED_RCPT_OTHER)
438			/* Examine all remaining non-recipient records. */
439			continue;
440		    /* Optimizations for "pure recipient" record sections. */
441		    if (curr_offset > message->data_offset) {
442			/* We already examined all non-recipient records. */
443			message->rflags |= QMGR_READ_FLAG_SEEN_ALL_NON_RCPT;
444			break;
445		    }
446		    /* Examine non-recipient records in extracted segment. */
447		    if (vstream_fseek(message->fp, message->data_offset
448				      + message->data_size, SEEK_SET) < 0)
449			msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
450		    continue;
451		}
452	    }
453	    continue;
454	}
455	if (rec_type == REC_TYPE_DONE || rec_type == REC_TYPE_DRCP) {
456	    if (message->rcpt_offset == 0) {
457		if (dsn_orcpt) {
458		    myfree(dsn_orcpt);
459		    dsn_orcpt = 0;
460		}
461		if (orig_rcpt) {
462		    myfree(orig_rcpt);
463		    orig_rcpt = 0;
464		}
465		if (dsn_notify)
466		    dsn_notify = 0;
467	    }
468	    continue;
469	}
470	if (rec_type == REC_TYPE_DSN_ORCPT) {
471	    /* See also above for code clearing dsn_orcpt. */
472	    if (dsn_orcpt != 0) {
473		msg_warn("%s: ignoring out-of-order DSN original recipient address <%.200s>",
474			 message->queue_id, dsn_orcpt);
475		myfree(dsn_orcpt);
476		dsn_orcpt = 0;
477	    }
478	    if (message->rcpt_offset == 0)
479		dsn_orcpt = mystrdup(start);
480	    continue;
481	}
482	if (rec_type == REC_TYPE_DSN_NOTIFY) {
483	    /* See also above for code clearing dsn_notify. */
484	    if (dsn_notify != 0) {
485		msg_warn("%s: ignoring out-of-order DSN notify flags <%d>",
486			 message->queue_id, dsn_notify);
487		dsn_notify = 0;
488	    }
489	    if (message->rcpt_offset == 0) {
490		if (!alldig(start) || (n = atoi(start)) == 0 || !DSN_NOTIFY_OK(n))
491		    msg_warn("%s: ignoring malformed DSN notify flags <%.200s>",
492			     message->queue_id, start);
493		else
494		    dsn_notify = n;
495		continue;
496	    }
497	}
498	if (rec_type == REC_TYPE_ORCP) {
499	    /* See also above for code clearing orig_rcpt. */
500	    if (orig_rcpt != 0) {
501		msg_warn("%s: ignoring out-of-order original recipient <%.200s>",
502			 message->queue_id, orig_rcpt);
503		myfree(orig_rcpt);
504		orig_rcpt = 0;
505	    }
506	    if (message->rcpt_offset == 0)
507		orig_rcpt = mystrdup(start);
508	    continue;
509	}
510
511	/*
512	 * Process non-recipient records.
513	 */
514	if (message->rflags & QMGR_READ_FLAG_SEEN_ALL_NON_RCPT)
515	    /* We already examined all non-recipient records. */
516	    continue;
517	if (rec_type == REC_TYPE_SIZE) {
518	    if (message->data_offset == 0) {
519		if ((count = sscanf(start, "%ld %ld %d %d %ld",
520				 &message->data_size, &message->data_offset,
521				    &nrcpt, &message->rflags,
522				    &message->cont_length)) >= 3) {
523		    /* Postfix >= 1.0 (a.k.a. 20010228). */
524		    if (message->data_offset <= 0 || message->data_size <= 0) {
525			msg_warn("%s: invalid size record: %.100s",
526				 message->queue_id, start);
527			rec_type = REC_TYPE_ERROR;
528			break;
529		    }
530		    if (message->rflags & ~QMGR_READ_FLAG_USER) {
531			msg_warn("%s: invalid flags in size record: %.100s",
532				 message->queue_id, start);
533			rec_type = REC_TYPE_ERROR;
534			break;
535		    }
536		} else if (count == 1) {
537		    /* Postfix < 1.0 (a.k.a. 20010228). */
538		    qmgr_message_oldstyle_scan(message);
539		} else {
540		    /* Can't happen. */
541		    msg_warn("%s: message rejected: weird size record",
542			     message->queue_id);
543		    rec_type = REC_TYPE_ERROR;
544		    break;
545		}
546	    }
547	    /* Postfix < 2.4 compatibility. */
548	    if (message->cont_length == 0) {
549		message->cont_length = message->data_size;
550	    } else if (message->cont_length < 0) {
551		msg_warn("%s: invalid size record: %.100s",
552			 message->queue_id, start);
553		rec_type = REC_TYPE_ERROR;
554		break;
555	    }
556	    continue;
557	}
558	if (rec_type == REC_TYPE_TIME) {
559	    if (message->arrival_time.tv_sec == 0)
560		REC_TYPE_TIME_SCAN(start, message->arrival_time);
561	    continue;
562	}
563	if (rec_type == REC_TYPE_CTIME) {
564	    if (message->create_time == 0)
565		message->create_time = atol(start);
566	    continue;
567	}
568	if (rec_type == REC_TYPE_FILT) {
569	    if (message->filter_xport != 0)
570		myfree(message->filter_xport);
571	    message->filter_xport = mystrdup(start);
572	    continue;
573	}
574	if (rec_type == REC_TYPE_INSP) {
575	    if (message->inspect_xport != 0)
576		myfree(message->inspect_xport);
577	    message->inspect_xport = mystrdup(start);
578	    continue;
579	}
580	if (rec_type == REC_TYPE_RDR) {
581	    if (message->redirect_addr != 0)
582		myfree(message->redirect_addr);
583	    message->redirect_addr = mystrdup(start);
584	    continue;
585	}
586	if (rec_type == REC_TYPE_FROM) {
587	    if (message->sender == 0) {
588		message->sender = mystrdup(start);
589		opened(message->queue_id, message->sender,
590		       message->cont_length, nrcpt,
591		       "queue %s", message->queue_name);
592	    }
593	    continue;
594	}
595	if (rec_type == REC_TYPE_DSN_ENVID) {
596	    if (message->dsn_envid == 0)
597		message->dsn_envid = mystrdup(start);
598	}
599	if (rec_type == REC_TYPE_DSN_RET) {
600	    if (message->dsn_ret == 0) {
601		if (!alldig(start) || (n = atoi(start)) == 0 || !DSN_RET_OK(n))
602		    msg_warn("%s: ignoring malformed DSN RET flags in queue file record:%.100s",
603			     message->queue_id, start);
604		else
605		    message->dsn_ret = n;
606	    }
607	}
608	if (rec_type == REC_TYPE_ATTR) {
609	    /* Allow extra segment to override envelope segment info. */
610	    if (strcmp(name, MAIL_ATTR_ENCODING) == 0) {
611		if (message->encoding != 0)
612		    myfree(message->encoding);
613		message->encoding = mystrdup(value);
614	    }
615
616	    /*
617	     * Backwards compatibility. Before Postfix 2.3, the logging
618	     * attributes were called client_name, etc. Now they are called
619	     * log_client_name. etc., and client_name is used for the actual
620	     * client information. To support old queue files, we accept both
621	     * names for the purpose of logging; the new name overrides the
622	     * old one.
623	     *
624	     * XXX Do not use the "legacy" client_name etc. attribute values for
625	     * initializing the logging attributes, when this file already
626	     * contains the "modern" log_client_name etc. logging attributes.
627	     * Otherwise, logging attributes that are not present in the
628	     * queue file would be set with information from the real client.
629	     */
630	    else if (strcmp(name, MAIL_ATTR_ACT_CLIENT_NAME) == 0) {
631		if (have_log_client_attr == 0 && message->client_name == 0)
632		    message->client_name = mystrdup(value);
633	    } else if (strcmp(name, MAIL_ATTR_ACT_CLIENT_ADDR) == 0) {
634		if (have_log_client_attr == 0 && message->client_addr == 0)
635		    message->client_addr = mystrdup(value);
636	    } else if (strcmp(name, MAIL_ATTR_ACT_CLIENT_PORT) == 0) {
637		if (have_log_client_attr == 0 && message->client_port == 0)
638		    message->client_port = mystrdup(value);
639	    } else if (strcmp(name, MAIL_ATTR_ACT_PROTO_NAME) == 0) {
640		if (have_log_client_attr == 0 && message->client_proto == 0)
641		    message->client_proto = mystrdup(value);
642	    } else if (strcmp(name, MAIL_ATTR_ACT_HELO_NAME) == 0) {
643		if (have_log_client_attr == 0 && message->client_helo == 0)
644		    message->client_helo = mystrdup(value);
645	    }
646	    /* Original client attributes. */
647	    else if (strcmp(name, MAIL_ATTR_LOG_CLIENT_NAME) == 0) {
648		if (message->client_name != 0)
649		    myfree(message->client_name);
650		message->client_name = mystrdup(value);
651		have_log_client_attr = 1;
652	    } else if (strcmp(name, MAIL_ATTR_LOG_CLIENT_ADDR) == 0) {
653		if (message->client_addr != 0)
654		    myfree(message->client_addr);
655		message->client_addr = mystrdup(value);
656		have_log_client_attr = 1;
657	    } else if (strcmp(name, MAIL_ATTR_LOG_CLIENT_PORT) == 0) {
658		if (message->client_port != 0)
659		    myfree(message->client_port);
660		message->client_port = mystrdup(value);
661		have_log_client_attr = 1;
662	    } else if (strcmp(name, MAIL_ATTR_LOG_PROTO_NAME) == 0) {
663		if (message->client_proto != 0)
664		    myfree(message->client_proto);
665		message->client_proto = mystrdup(value);
666		have_log_client_attr = 1;
667	    } else if (strcmp(name, MAIL_ATTR_LOG_HELO_NAME) == 0) {
668		if (message->client_helo != 0)
669		    myfree(message->client_helo);
670		message->client_helo = mystrdup(value);
671		have_log_client_attr = 1;
672	    } else if (strcmp(name, MAIL_ATTR_SASL_METHOD) == 0) {
673		if (message->sasl_method == 0)
674		    message->sasl_method = mystrdup(value);
675		else
676		    msg_warn("%s: ignoring multiple %s attribute: %s",
677			   message->queue_id, MAIL_ATTR_SASL_METHOD, value);
678	    } else if (strcmp(name, MAIL_ATTR_SASL_USERNAME) == 0) {
679		if (message->sasl_username == 0)
680		    message->sasl_username = mystrdup(value);
681		else
682		    msg_warn("%s: ignoring multiple %s attribute: %s",
683			 message->queue_id, MAIL_ATTR_SASL_USERNAME, value);
684	    } else if (strcmp(name, MAIL_ATTR_SASL_SENDER) == 0) {
685		if (message->sasl_sender == 0)
686		    message->sasl_sender = mystrdup(value);
687		else
688		    msg_warn("%s: ignoring multiple %s attribute: %s",
689			   message->queue_id, MAIL_ATTR_SASL_SENDER, value);
690	    } else if (strcmp(name, MAIL_ATTR_LOG_IDENT) == 0) {
691		if (message->log_ident == 0)
692		    message->log_ident = mystrdup(value);
693		else
694		    msg_warn("%s: ignoring multiple %s attribute: %s",
695			     message->queue_id, MAIL_ATTR_LOG_IDENT, value);
696	    } else if (strcmp(name, MAIL_ATTR_RWR_CONTEXT) == 0) {
697		if (message->rewrite_context == 0)
698		    message->rewrite_context = mystrdup(value);
699		else
700		    msg_warn("%s: ignoring multiple %s attribute: %s",
701			   message->queue_id, MAIL_ATTR_RWR_CONTEXT, value);
702	    }
703
704	    /*
705	     * Optional tracing flags (verify, sendmail -v, sendmail -bv).
706	     * This record is killed after a trace logfile report is sent and
707	     * after the logfile is deleted.
708	     */
709	    else if (strcmp(name, MAIL_ATTR_TRACE_FLAGS) == 0) {
710		message->tflags = DEL_REQ_TRACE_FLAGS(atoi(value));
711		if (message->tflags == DEL_REQ_FLAG_RECORD)
712		    message->tflags_offset = curr_offset;
713		else
714		    message->tflags_offset = 0;
715	    }
716	    continue;
717	}
718	if (rec_type == REC_TYPE_WARN) {
719	    if (message->warn_offset == 0) {
720		message->warn_offset = curr_offset;
721		REC_TYPE_WARN_SCAN(start, message->warn_time);
722	    }
723	    continue;
724	}
725	if (rec_type == REC_TYPE_VERP) {
726	    if (message->verp_delims == 0) {
727		if (message->sender == 0 || message->sender[0] == 0) {
728		    msg_warn("%s: ignoring VERP request for null sender",
729			     message->queue_id);
730		} else if (verp_delims_verify(start) != 0) {
731		    msg_warn("%s: ignoring bad VERP request: \"%.100s\"",
732			     message->queue_id, start);
733		} else {
734		    if (msg_verbose)
735			msg_info("%s: enabling VERP for sender \"%.100s\"",
736				 message->queue_id, message->sender);
737		    message->single_rcpt = 1;
738		    message->verp_delims = mystrdup(start);
739		}
740	    }
741	    continue;
742	}
743    }
744
745    /*
746     * Grr.
747     */
748    if (dsn_orcpt != 0) {
749	if (rec_type > 0)
750	    msg_warn("%s: ignoring out-of-order DSN original recipient <%.200s>",
751		     message->queue_id, dsn_orcpt);
752	myfree(orig_rcpt);
753    }
754    if (orig_rcpt != 0) {
755	if (rec_type > 0)
756	    msg_warn("%s: ignoring out-of-order original recipient <%.200s>",
757		     message->queue_id, orig_rcpt);
758	myfree(orig_rcpt);
759    }
760
761    /*
762     * Avoid clumsiness elsewhere in the program. When sending data across an
763     * IPC channel, sending an empty string is more convenient than sending a
764     * null pointer.
765     */
766    if (message->dsn_envid == 0)
767	message->dsn_envid = mystrdup("");
768    if (message->encoding == 0)
769	message->encoding = mystrdup(MAIL_ATTR_ENC_NONE);
770    if (message->client_name == 0)
771	message->client_name = mystrdup("");
772    if (message->client_addr == 0)
773	message->client_addr = mystrdup("");
774    if (message->client_port == 0)
775	message->client_port = mystrdup("");
776    if (message->client_proto == 0)
777	message->client_proto = mystrdup("");
778    if (message->client_helo == 0)
779	message->client_helo = mystrdup("");
780    if (message->sasl_method == 0)
781	message->sasl_method = mystrdup("");
782    if (message->sasl_username == 0)
783	message->sasl_username = mystrdup("");
784    if (message->sasl_sender == 0)
785	message->sasl_sender = mystrdup("");
786    if (message->log_ident == 0)
787	message->log_ident = mystrdup("");
788    if (message->rewrite_context == 0)
789	message->rewrite_context = mystrdup(MAIL_ATTR_RWR_LOCAL);
790    /* Postfix < 2.3 compatibility. */
791    if (message->create_time == 0)
792	message->create_time = message->arrival_time.tv_sec;
793
794    /*
795     * Clean up.
796     */
797    vstring_free(buf);
798
799    /*
800     * Sanity checks. Verify that all required information was found,
801     * including the queue file end marker.
802     */
803    if (rec_type <= 0) {
804	/* Already logged warning. */
805    } else if (message->arrival_time.tv_sec == 0) {
806	msg_warn("%s: message rejected: missing arrival time record",
807		 message->queue_id);
808    } else if (message->sender == 0) {
809	msg_warn("%s: message rejected: missing sender record",
810		 message->queue_id);
811    } else if (message->data_offset == 0) {
812	msg_warn("%s: message rejected: missing size record",
813		 message->queue_id);
814    } else {
815	return (0);
816    }
817    message->rcpt_offset = save_offset;		/* restore flag */
818    return (-1);
819}
820
821/* qmgr_message_update_warn - update the time of next delay warning */
822
823void    qmgr_message_update_warn(QMGR_MESSAGE *message)
824{
825
826    /*
827     * XXX eventually this should let us schedule multiple warnings, right
828     * now it just allows for one.
829     */
830    if (qmgr_message_open(message)
831	|| vstream_fseek(message->fp, message->warn_offset, SEEK_SET) < 0
832	|| rec_fprintf(message->fp, REC_TYPE_WARN, REC_TYPE_WARN_FORMAT,
833		       REC_TYPE_WARN_ARG(0)) < 0
834	|| vstream_fflush(message->fp))
835	msg_fatal("update queue file %s: %m", VSTREAM_PATH(message->fp));
836    qmgr_message_close(message);
837}
838
839/* qmgr_message_kill_record - mark one message record as killed */
840
841void    qmgr_message_kill_record(QMGR_MESSAGE *message, long offset)
842{
843    if (offset <= 0)
844	msg_panic("qmgr_message_kill_record: bad offset 0x%lx", offset);
845    if (qmgr_message_open(message)
846	|| rec_put_type(message->fp, REC_TYPE_KILL, offset) < 0
847	|| vstream_fflush(message->fp))
848	msg_fatal("update queue file %s: %m", VSTREAM_PATH(message->fp));
849    qmgr_message_close(message);
850}
851
852/* qmgr_message_sort_compare - compare recipient information */
853
854static int qmgr_message_sort_compare(const void *p1, const void *p2)
855{
856    RECIPIENT *rcpt1 = (RECIPIENT *) p1;
857    RECIPIENT *rcpt2 = (RECIPIENT *) p2;
858    QMGR_QUEUE *queue1;
859    QMGR_QUEUE *queue2;
860    char   *at1;
861    char   *at2;
862    int     result;
863
864    /*
865     * Compare most significant to least significant recipient attributes.
866     * The comparison function must be transitive, so NULL values need to be
867     * assigned an ordinal (we set NULL last).
868     */
869
870    queue1 = rcpt1->u.queue;
871    queue2 = rcpt2->u.queue;
872    if (queue1 != 0 && queue2 == 0)
873	return (-1);
874    if (queue1 == 0 && queue2 != 0)
875	return (1);
876    if (queue1 != 0 && queue2 != 0) {
877
878	/*
879	 * Compare message transport.
880	 */
881	if ((result = strcmp(queue1->transport->name,
882			     queue2->transport->name)) != 0)
883	    return (result);
884
885	/*
886	 * Compare queue name (nexthop or recipient@nexthop).
887	 */
888	if ((result = strcmp(queue1->name, queue2->name)) != 0)
889	    return (result);
890    }
891
892    /*
893     * Compare recipient domain.
894     */
895    at1 = strrchr(rcpt1->address, '@');
896    at2 = strrchr(rcpt2->address, '@');
897    if (at1 == 0 && at2 != 0)
898	return (1);
899    if (at1 != 0 && at2 == 0)
900	return (-1);
901    if (at1 != 0 && at2 != 0
902	&& (result = strcasecmp(at1, at2)) != 0)
903	return (result);
904
905    /*
906     * Compare recipient address.
907     */
908    return (strcasecmp(rcpt1->address, rcpt2->address));
909}
910
911/* qmgr_message_sort - sort message recipient addresses by domain */
912
913static void qmgr_message_sort(QMGR_MESSAGE *message)
914{
915    qsort((char *) message->rcpt_list.info, message->rcpt_list.len,
916	  sizeof(message->rcpt_list.info[0]), qmgr_message_sort_compare);
917    if (msg_verbose) {
918	RECIPIENT_LIST list = message->rcpt_list;
919	RECIPIENT *rcpt;
920
921	msg_info("start sorted recipient list");
922	for (rcpt = list.info; rcpt < list.info + list.len; rcpt++)
923	    msg_info("qmgr_message_sort: %s", rcpt->address);
924	msg_info("end sorted recipient list");
925    }
926}
927
928/* qmgr_resolve_one - resolve or skip one recipient */
929
930static int qmgr_resolve_one(QMGR_MESSAGE *message, RECIPIENT *recipient,
931			            const char *addr, RESOLVE_REPLY *reply)
932{
933#define QMGR_REDIRECT(rp, tp, np) do { \
934	(rp)->flags = 0; \
935	vstring_strcpy((rp)->transport, (tp)); \
936	vstring_strcpy((rp)->nexthop, (np)); \
937    } while (0)
938
939    if ((message->tflags & DEL_REQ_FLAG_MTA_VRFY) == 0)
940	resolve_clnt_query_from(message->sender, addr, reply);
941    else
942	resolve_clnt_verify_from(message->sender, addr, reply);
943    if (reply->flags & RESOLVE_FLAG_FAIL) {
944	QMGR_REDIRECT(reply, MAIL_SERVICE_RETRY,
945		      "4.3.0 address resolver failure");
946	return (0);
947    } else if (reply->flags & RESOLVE_FLAG_ERROR) {
948	QMGR_REDIRECT(reply, MAIL_SERVICE_ERROR,
949		      "5.1.3 bad address syntax");
950	return (0);
951    } else {
952	return (0);
953    }
954}
955
956/* qmgr_message_resolve - resolve recipients */
957
958static void qmgr_message_resolve(QMGR_MESSAGE *message)
959{
960    static ARGV *defer_xport_argv;
961    RECIPIENT_LIST list = message->rcpt_list;
962    RECIPIENT *recipient;
963    QMGR_TRANSPORT *transport = 0;
964    QMGR_QUEUE *queue = 0;
965    RESOLVE_REPLY reply;
966    VSTRING *queue_name;
967    char   *at;
968    char  **cpp;
969    char   *nexthop;
970    ssize_t len;
971    int     status;
972    DSN     dsn;
973    MSG_STATS stats;
974    DSN    *saved_dsn;
975
976#define STREQ(x,y)	(strcmp(x,y) == 0)
977#define STR		vstring_str
978#define LEN		VSTRING_LEN
979
980    resolve_clnt_init(&reply);
981    queue_name = vstring_alloc(1);
982    for (recipient = list.info; recipient < list.info + list.len; recipient++) {
983
984	/*
985	 * Redirect overrides all else. But only once (per entire message).
986	 * For consistency with the remainder of Postfix, rewrite the address
987	 * to canonical form before resolving it.
988	 */
989	if (message->redirect_addr) {
990	    if (recipient > list.info) {
991		recipient->u.queue = 0;
992		continue;
993	    }
994	    message->rcpt_offset = 0;
995	    rewrite_clnt_internal(REWRITE_CANON, message->redirect_addr,
996				  reply.recipient);
997	    RECIPIENT_UPDATE(recipient->address, STR(reply.recipient));
998	    if (qmgr_resolve_one(message, recipient,
999				 recipient->address, &reply) < 0)
1000		continue;
1001	    if (!STREQ(recipient->address, STR(reply.recipient)))
1002		RECIPIENT_UPDATE(recipient->address, STR(reply.recipient));
1003	}
1004
1005	/*
1006	 * Content filtering overrides the address resolver.
1007	 *
1008	 * XXX Bypass content_filter inspection for user-generated probes
1009	 * (sendmail -bv). MTA-generated probes never have the "please filter
1010	 * me" bits turned on, but we handle them here anyway for the sake of
1011	 * future proofing.
1012	 */
1013#define FILTER_WITHOUT_NEXTHOP(filter, next) \
1014	(((next) = split_at((filter), ':')) == 0 || *(next) == 0)
1015
1016#define RCPT_WITHOUT_DOMAIN(rcpt, next) \
1017	((next = strrchr(rcpt, '@')) == 0 || *++(next) == 0)
1018
1019	else if (message->filter_xport
1020		 && (message->tflags & DEL_REQ_TRACE_ONLY_MASK) == 0) {
1021	    reply.flags = 0;
1022	    vstring_strcpy(reply.transport, message->filter_xport);
1023	    if (FILTER_WITHOUT_NEXTHOP(STR(reply.transport), nexthop)
1024		&& *(nexthop = var_def_filter_nexthop) == 0
1025		&& RCPT_WITHOUT_DOMAIN(recipient->address, nexthop))
1026		nexthop = var_myhostname;
1027	    vstring_strcpy(reply.nexthop, nexthop);
1028	    vstring_strcpy(reply.recipient, recipient->address);
1029	}
1030
1031	/*
1032	 * Resolve the destination to (transport, nexthop, address). The
1033	 * result address may differ from the one specified by the sender.
1034	 */
1035	else {
1036	    if (qmgr_resolve_one(message, recipient,
1037				 recipient->address, &reply) < 0)
1038		continue;
1039	    if (!STREQ(recipient->address, STR(reply.recipient)))
1040		RECIPIENT_UPDATE(recipient->address, STR(reply.recipient));
1041	}
1042
1043	/*
1044	 * Bounce null recipients. This should never happen, but is most
1045	 * likely the result of a fault in a different program, so aborting
1046	 * the queue manager process does not help.
1047	 */
1048	if (recipient->address[0] == 0) {
1049	    QMGR_REDIRECT(&reply, MAIL_SERVICE_ERROR,
1050			  "5.1.3 null recipient address");
1051	}
1052
1053	/*
1054	 * Discard mail to the local double bounce address here, so this
1055	 * system can run without a local delivery agent. They'd still have
1056	 * to configure something for mail directed to the local postmaster,
1057	 * though, but that is an RFC requirement anyway.
1058	 *
1059	 * XXX This lookup should be done in the resolver, and the mail should
1060	 * be directed to a general-purpose null delivery agent.
1061	 */
1062	if (reply.flags & RESOLVE_CLASS_LOCAL) {
1063	    at = strrchr(STR(reply.recipient), '@');
1064	    len = (at ? (at - STR(reply.recipient))
1065		   : strlen(STR(reply.recipient)));
1066	    if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
1067			    len) == 0
1068		&& !var_double_bounce_sender[len]) {
1069		status = sent(message->tflags, message->queue_id,
1070			      QMGR_MSG_STATS(&stats, message), recipient,
1071			      "none", DSN_SIMPLE(&dsn, "2.0.0",
1072			"undeliverable postmaster notification discarded"));
1073		if (status == 0) {
1074		    deliver_completed(message->fp, recipient->offset);
1075#if 0
1076		    /* It's the default verification probe sender address. */
1077		    msg_warn("%s: undeliverable postmaster notification discarded",
1078			     message->queue_id);
1079#endif
1080		} else
1081		    message->flags |= status;
1082		continue;
1083	    }
1084	}
1085
1086	/*
1087	 * Optionally defer deliveries over specific transports, unless the
1088	 * restriction is lifted temporarily.
1089	 */
1090	if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DFXP) == 0) {
1091	    if (defer_xport_argv == 0)
1092		defer_xport_argv = argv_split(var_defer_xports, " \t\r\n,");
1093	    for (cpp = defer_xport_argv->argv; *cpp; cpp++)
1094		if (strcmp(*cpp, STR(reply.transport)) == 0)
1095		    break;
1096	    if (*cpp) {
1097		QMGR_REDIRECT(&reply, MAIL_SERVICE_RETRY,
1098			      "4.3.2 deferred transport");
1099	    }
1100	}
1101
1102	/*
1103	 * Look up or instantiate the proper transport.
1104	 */
1105	if (transport == 0 || !STREQ(transport->name, STR(reply.transport))) {
1106	    if ((transport = qmgr_transport_find(STR(reply.transport))) == 0)
1107		transport = qmgr_transport_create(STR(reply.transport));
1108	    queue = 0;
1109	}
1110
1111	/*
1112	 * This message is being flushed. If need-be unthrottle the
1113	 * transport.
1114	 */
1115	if ((message->qflags & QMGR_FLUSH_EACH) != 0
1116	    && QMGR_TRANSPORT_THROTTLED(transport))
1117	    qmgr_transport_unthrottle(transport);
1118
1119	/*
1120	 * This transport is dead. Defer delivery to this recipient.
1121	 */
1122	if (QMGR_TRANSPORT_THROTTLED(transport)) {
1123	    saved_dsn = transport->dsn;
1124	    if ((transport = qmgr_error_transport(MAIL_SERVICE_RETRY)) != 0) {
1125		nexthop = qmgr_error_nexthop(saved_dsn);
1126		vstring_strcpy(reply.nexthop, nexthop);
1127		myfree(nexthop);
1128		queue = 0;
1129	    } else {
1130		qmgr_defer_recipient(message, recipient, saved_dsn);
1131		continue;
1132	    }
1133	}
1134
1135	/*
1136	 * The nexthop destination provides the default name for the
1137	 * per-destination queue. When the delivery agent accepts only one
1138	 * recipient per delivery, give each recipient its own queue, so that
1139	 * deliveries to different recipients of the same message can happen
1140	 * in parallel, and so that we can enforce per-recipient concurrency
1141	 * limits and prevent one recipient from tying up all the delivery
1142	 * agent resources. We use recipient@nexthop as queue name rather
1143	 * than the actual recipient domain name, so that one recipient in
1144	 * multiple equivalent domains cannot evade the per-recipient
1145	 * concurrency limit. Split the address on the recipient delimiter if
1146	 * one is defined, so that extended addresses don't get extra
1147	 * delivery slots.
1148	 *
1149	 * Fold the result to lower case so that we don't have multiple queues
1150	 * for the same name.
1151	 *
1152	 * Important! All recipients in a queue must have the same nexthop
1153	 * value. It is OK to have multiple queues with the same nexthop
1154	 * value, but only when those queues are named after recipients.
1155	 *
1156	 * The single-recipient code below was written for local(8) like
1157	 * delivery agents, and assumes that all domains that deliver to the
1158	 * same (transport + nexthop) are aliases for $nexthop. Delivery
1159	 * concurrency is changed from per-domain into per-recipient, by
1160	 * changing the queue name from nexthop into localpart@nexthop.
1161	 *
1162	 * XXX This assumption is incorrect when different destinations share
1163	 * the same (transport + nexthop). In reality, such transports are
1164	 * rarely configured to use single-recipient deliveries. The fix is
1165	 * to decouple the per-destination recipient limit from the
1166	 * per-destination concurrency.
1167	 */
1168	vstring_strcpy(queue_name, STR(reply.nexthop));
1169	if (strcmp(transport->name, MAIL_SERVICE_ERROR) != 0
1170	    && strcmp(transport->name, MAIL_SERVICE_RETRY) != 0
1171	    && transport->recipient_limit == 1) {
1172	    /* Copy the recipient localpart. */
1173	    at = strrchr(STR(reply.recipient), '@');
1174	    len = (at ? (at - STR(reply.recipient))
1175		   : strlen(STR(reply.recipient)));
1176	    vstring_strncpy(queue_name, STR(reply.recipient), len);
1177	    /* Remove the address extension from the recipient localpart. */
1178	    if (*var_rcpt_delim && split_addr(STR(queue_name), *var_rcpt_delim))
1179		vstring_truncate(queue_name, strlen(STR(queue_name)));
1180	    /* Assume the recipient domain is equivalent to nexthop. */
1181	    vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop));
1182	}
1183	lowercase(STR(queue_name));
1184
1185	/*
1186	 * This transport is alive. Find or instantiate a queue for this
1187	 * recipient.
1188	 */
1189	if (queue == 0 || !STREQ(queue->name, STR(queue_name))) {
1190	    if ((queue = qmgr_queue_find(transport, STR(queue_name))) == 0)
1191		queue = qmgr_queue_create(transport, STR(queue_name),
1192					  STR(reply.nexthop));
1193	}
1194
1195	/*
1196	 * This message is being flushed. If need-be unthrottle the queue.
1197	 */
1198	if ((message->qflags & QMGR_FLUSH_EACH) != 0
1199	    && QMGR_QUEUE_THROTTLED(queue))
1200	    qmgr_queue_unthrottle(queue);
1201
1202	/*
1203	 * This queue is dead. Defer delivery to this recipient.
1204	 */
1205	if (QMGR_QUEUE_THROTTLED(queue)) {
1206	    saved_dsn = queue->dsn;
1207	    if ((queue = qmgr_error_queue(MAIL_SERVICE_RETRY, saved_dsn)) == 0) {
1208		qmgr_defer_recipient(message, recipient, saved_dsn);
1209		continue;
1210	    }
1211	}
1212
1213	/*
1214	 * This queue is alive. Bind this recipient to this queue instance.
1215	 */
1216	recipient->u.queue = queue;
1217    }
1218    resolve_clnt_free(&reply);
1219    vstring_free(queue_name);
1220}
1221
1222/* qmgr_message_assign - assign recipients to specific delivery requests */
1223
1224static void qmgr_message_assign(QMGR_MESSAGE *message)
1225{
1226    RECIPIENT_LIST list = message->rcpt_list;
1227    RECIPIENT *recipient;
1228    QMGR_ENTRY *entry = 0;
1229    QMGR_QUEUE *queue;
1230
1231    /*
1232     * Try to bundle as many recipients in a delivery request as we can. When
1233     * the recipient resolves to the same site and transport as the previous
1234     * recipient, do not create a new queue entry, just move that recipient
1235     * to the recipient list of the existing queue entry. All this provided
1236     * that we do not exceed the transport-specific limit on the number of
1237     * recipients per transaction. Skip recipients with a dead transport or
1238     * destination.
1239     */
1240#define LIMIT_OK(limit, count) ((limit) == 0 || ((count) < (limit)))
1241
1242    for (recipient = list.info; recipient < list.info + list.len; recipient++) {
1243	if ((queue = recipient->u.queue) != 0) {
1244	    if (message->single_rcpt || entry == 0 || entry->queue != queue
1245		|| !LIMIT_OK(entry->queue->transport->recipient_limit,
1246			     entry->rcpt_list.len)) {
1247		entry = qmgr_entry_create(queue, message);
1248	    }
1249	    recipient_list_add(&entry->rcpt_list, recipient->offset,
1250			       recipient->dsn_orcpt, recipient->dsn_notify,
1251			       recipient->orig_addr, recipient->address);
1252	    qmgr_recipient_count++;
1253	}
1254    }
1255    recipient_list_free(&message->rcpt_list);
1256    recipient_list_init(&message->rcpt_list, RCPT_LIST_INIT_QUEUE);
1257}
1258
1259/* qmgr_message_free - release memory for in-core message structure */
1260
1261void    qmgr_message_free(QMGR_MESSAGE *message)
1262{
1263    if (message->refcount != 0)
1264	msg_panic("qmgr_message_free: reference len: %d", message->refcount);
1265    if (message->fp)
1266	msg_panic("qmgr_message_free: queue file is open");
1267    myfree(message->queue_id);
1268    myfree(message->queue_name);
1269    if (message->dsn_envid)
1270	myfree(message->dsn_envid);
1271    if (message->encoding)
1272	myfree(message->encoding);
1273    if (message->sender)
1274	myfree(message->sender);
1275    if (message->verp_delims)
1276	myfree(message->verp_delims);
1277    if (message->filter_xport)
1278	myfree(message->filter_xport);
1279    if (message->inspect_xport)
1280	myfree(message->inspect_xport);
1281    if (message->redirect_addr)
1282	myfree(message->redirect_addr);
1283    if (message->client_name)
1284	myfree(message->client_name);
1285    if (message->client_addr)
1286	myfree(message->client_addr);
1287    if (message->client_port)
1288	myfree(message->client_port);
1289    if (message->client_proto)
1290	myfree(message->client_proto);
1291    if (message->client_helo)
1292	myfree(message->client_helo);
1293    if (message->sasl_method)
1294	myfree(message->sasl_method);
1295    if (message->sasl_username)
1296	myfree(message->sasl_username);
1297    if (message->sasl_sender)
1298	myfree(message->sasl_sender);
1299    if (message->log_ident)
1300	myfree(message->log_ident);
1301    if (message->rewrite_context)
1302	myfree(message->rewrite_context);
1303    recipient_list_free(&message->rcpt_list);
1304    qmgr_message_count--;
1305    myfree((char *) message);
1306}
1307
1308/* qmgr_message_alloc - create in-core message structure */
1309
1310QMGR_MESSAGE *qmgr_message_alloc(const char *queue_name, const char *queue_id,
1311				         int qflags, mode_t mode)
1312{
1313    const char *myname = "qmgr_message_alloc";
1314    QMGR_MESSAGE *message;
1315
1316    if (msg_verbose)
1317	msg_info("%s: %s %s", myname, queue_name, queue_id);
1318
1319    /*
1320     * Create an in-core message structure.
1321     */
1322    message = qmgr_message_create(queue_name, queue_id, qflags);
1323
1324    /*
1325     * Extract message envelope information: time of arrival, sender address,
1326     * recipient addresses. Skip files with malformed envelope information.
1327     */
1328#define QMGR_LOCK_MODE (MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT)
1329
1330    if (qmgr_message_open(message) < 0) {
1331	qmgr_message_free(message);
1332	return (0);
1333    }
1334    if (myflock(vstream_fileno(message->fp), INTERNAL_LOCK, QMGR_LOCK_MODE) < 0) {
1335	msg_info("%s: skipped, still being delivered", queue_id);
1336	qmgr_message_close(message);
1337	qmgr_message_free(message);
1338	return (QMGR_MESSAGE_LOCKED);
1339    }
1340    if (qmgr_message_read(message) < 0) {
1341	qmgr_message_close(message);
1342	qmgr_message_free(message);
1343	return (0);
1344    } else {
1345
1346	/*
1347	 * We have validated the queue file content, so it is safe to modify
1348	 * the file properties now.
1349	 */
1350	if (mode != 0 && fchmod(vstream_fileno(message->fp), mode) < 0)
1351	    msg_fatal("fchmod %s: %m", VSTREAM_PATH(message->fp));
1352
1353	/*
1354	 * Reset the defer log. This code should not be here, but we must
1355	 * reset the defer log *after* acquiring the exclusive lock on the
1356	 * queue file and *before* resolving new recipients. Since all those
1357	 * operations are encapsulated so nicely by this routine, the defer
1358	 * log reset has to be done here as well.
1359	 *
1360	 * Note: it is safe to remove the defer logfile from a previous queue
1361	 * run of this queue file, because the defer log contains information
1362	 * about recipients that still exist in this queue file.
1363	 */
1364	if (mail_queue_remove(MAIL_QUEUE_DEFER, queue_id) && errno != ENOENT)
1365	    msg_fatal("%s: %s: remove %s %s: %m", myname,
1366		      queue_id, MAIL_QUEUE_DEFER, queue_id);
1367	qmgr_message_sort(message);
1368	qmgr_message_resolve(message);
1369	qmgr_message_sort(message);
1370	qmgr_message_assign(message);
1371	qmgr_message_close(message);
1372	return (message);
1373    }
1374}
1375
1376/* qmgr_message_realloc - refresh in-core message structure */
1377
1378QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *message)
1379{
1380    const char *myname = "qmgr_message_realloc";
1381
1382    /*
1383     * Sanity checks.
1384     */
1385    if (message->rcpt_offset <= 0)
1386	msg_panic("%s: invalid offset: %ld", myname, message->rcpt_offset);
1387    if (msg_verbose)
1388	msg_info("%s: %s %s offset %ld", myname, message->queue_name,
1389		 message->queue_id, message->rcpt_offset);
1390
1391    /*
1392     * Extract recipient addresses. Skip files with malformed envelope
1393     * information.
1394     */
1395    if (qmgr_message_open(message) < 0)
1396	return (0);
1397    if (qmgr_message_read(message) < 0) {
1398	qmgr_message_close(message);
1399	return (0);
1400    } else {
1401	qmgr_message_sort(message);
1402	qmgr_message_resolve(message);
1403	qmgr_message_sort(message);
1404	qmgr_message_assign(message);
1405	qmgr_message_close(message);
1406	return (message);
1407    }
1408}
1409