Postfix3.3.1
bounce_append_service.c
[詳解]
1 /*++
2 /* NAME
3 /* bounce_append_service 3
4 /* SUMMARY
5 /* append record to bounce log, server side
6 /* SYNOPSIS
7 /* #include "bounce_service.h"
8 /*
9 /* int bounce_append_service(flags, service, queue_id, rcpt, dsn),
10 /* int flags;
11 /* char *service;
12 /* char *queue_id;
13 /* RECIPIENT *rcpt;
14 /* DSN *dsn;
15 /* DESCRIPTION
16 /* This module implements the server side of the bounce_append()
17 /* (append bounce log) request. This routine either succeeds or
18 /* it raises a fatal error.
19 /* DIAGNOSTICS
20 /* Fatal errors: all file access errors; memory allocation errors.
21 /* BUGS
22 /* SEE ALSO
23 /* bounce(3) basic bounce service client interface
24 /* LICENSE
25 /* .ad
26 /* .fi
27 /* The Secure Mailer license must be distributed with this software.
28 /* AUTHOR(S)
29 /* Wietse Venema
30 /* IBM T.J. Watson Research
31 /* P.O. Box 704
32 /* Yorktown Heights, NY 10598, USA
33 /*--*/
34 
35 /* System library. */
36 
37 #include <sys_defs.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <errno.h>
41 #include <ctype.h>
42 #include <string.h>
43 
44 /* Utility library. */
45 
46 #include <msg.h>
47 #include <vstring.h>
48 #include <vstream.h>
49 #include <stringops.h>
50 
51 /* Global library. */
52 
53 #include <mail_params.h>
54 #include <mail_queue.h>
55 #include <quote_822_local.h>
56 #include <deliver_flock.h>
57 #include <mail_proto.h>
58 
59 /* Application-specific. */
60 
61 #include "bounce_service.h"
62 
63 /* bounce_append_service - append bounce log */
64 
65 int bounce_append_service(int unused_flags, char *service, char *queue_id,
66  RECIPIENT *rcpt, DSN *dsn)
67 {
68  VSTRING *in_buf = vstring_alloc(100);
69  VSTREAM *log;
70  long orig_length;
71 
72  /*
73  * This code is paranoid for a good reason. Once the bounce service takes
74  * responsibility, the mail system will make no further attempts to
75  * deliver this recipient. Whenever file access fails, assume that the
76  * system is under stress or that something has been mis-configured, and
77  * force a backoff by raising a fatal run-time error.
78  */
79  log = mail_queue_open(service, queue_id,
80  O_WRONLY | O_APPEND | O_CREAT, 0600);
81  if (log == 0)
82  msg_fatal("open file %s %s: %m", service, queue_id);
83 
84  /*
85  * Lock out other processes to avoid truncating someone else's data in
86  * case of trouble.
87  */
88  if (deliver_flock(vstream_fileno(log), INTERNAL_LOCK, (VSTRING *) 0) < 0)
89  msg_fatal("lock file %s %s: %m", service, queue_id);
90 
91  /*
92  * Now, go for it. Append a record. Truncate the log to the original
93  * length when the append operation fails. We use the plain stream-lf
94  * file format because we do not need anything more complicated. As a
95  * benefit, we can still recover some data when the file is a little
96  * garbled.
97  *
98  * XXX addresses in defer logfiles are in printable quoted form, while
99  * addresses in message envelope records are in raw unquoted form. This
100  * may change once we replace the present ad-hoc bounce/defer logfile
101  * format by one that is transparent for control etc. characters. See
102  * also: showq/showq.c.
103  *
104  * While migrating from old format to new format, allow backwards
105  * compatibility by writing an old-style record before the new-style
106  * records.
107  */
108  if ((orig_length = vstream_fseek(log, 0L, SEEK_END)) < 0)
109  msg_fatal("seek file %s %s: %m", service, queue_id);
110 
111 #define NOT_NULL_EMPTY(s) ((s) != 0 && *(s) != 0)
112 #define STR(x) vstring_str(x)
113 
114  vstream_fputs("\n", log);
115  if (var_oldlog_compat) {
116  vstream_fprintf(log, "<%s>: %s\n", *rcpt->address == 0 ? "" :
117  STR(quote_822_local(in_buf, rcpt->address)),
118  dsn->reason);
119  }
120  vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_RECIP, *rcpt->address ?
121  STR(quote_822_local(in_buf, rcpt->address)) : "<>");
122  if (NOT_NULL_EMPTY(rcpt->orig_addr)
123  && strcasecmp_utf8(rcpt->address, rcpt->orig_addr) != 0)
124  vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_ORCPT,
125  STR(quote_822_local(in_buf, rcpt->orig_addr)));
126  if (rcpt->offset > 0)
127  vstream_fprintf(log, "%s=%ld\n", MAIL_ATTR_OFFSET, rcpt->offset);
128  if (NOT_NULL_EMPTY(rcpt->dsn_orcpt))
129  vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_ORCPT, rcpt->dsn_orcpt);
130  if (rcpt->dsn_notify != 0)
131  vstream_fprintf(log, "%s=%d\n", MAIL_ATTR_DSN_NOTIFY, rcpt->dsn_notify);
132 
133  if (NOT_NULL_EMPTY(dsn->status))
134  vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_STATUS, dsn->status);
135  if (NOT_NULL_EMPTY(dsn->action))
136  vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_ACTION, dsn->action);
137  if (NOT_NULL_EMPTY(dsn->dtype) && NOT_NULL_EMPTY(dsn->dtext)) {
138  vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_DTYPE, dsn->dtype);
139  vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_DTEXT, dsn->dtext);
140  }
141  if (NOT_NULL_EMPTY(dsn->mtype) && NOT_NULL_EMPTY(dsn->mname)) {
142  vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_MTYPE, dsn->mtype);
143  vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_MNAME, dsn->mname);
144  }
145  if (NOT_NULL_EMPTY(dsn->reason))
146  vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_WHY, dsn->reason);
147  vstream_fputs("\n", log);
148 
149  if (vstream_fflush(log) != 0 || fsync(vstream_fileno(log)) < 0) {
150 #ifndef NO_TRUNCATE
151  if (ftruncate(vstream_fileno(log), (off_t) orig_length) < 0)
152  msg_fatal("truncate file %s %s: %m", service, queue_id);
153 #endif
154  msg_fatal("append file %s %s: %m", service, queue_id);
155  }
156 
157  /*
158  * Darn. If closing the log detects a problem, the only way to undo the
159  * damage is to open the log once more, and to truncate the log to the
160  * original length. But, this could happen only when the log is kept on a
161  * remote file system, and that is not recommended practice anyway.
162  */
163  if (vstream_fclose(log) != 0)
164  msg_warn("append file %s %s: %m", service, queue_id);
165 
166  vstring_free(in_buf);
167  return (0);
168 }
const char * orig_addr
#define MAIL_ATTR_DSN_NOTIFY
Definition: mail_proto.h:275
const char * dtext
Definition: dsn.h:22
#define MAIL_ATTR_ORCPT
Definition: mail_proto.h:133
const char * address
const char * action
Definition: dsn.h:19
const char * reason
Definition: dsn.h:20
#define STR(x)
#define strcasecmp_utf8(s1, s2)
Definition: stringops.h:75
#define MAIL_ATTR_DSN_ACTION
Definition: mail_proto.h:272
int deliver_flock(int fd, int lock_style, VSTRING *why)
Definition: deliver_flock.c:67
#define MAIL_ATTR_DSN_STATUS
Definition: mail_proto.h:267
#define MAIL_ATTR_DSN_ORCPT
Definition: mail_proto.h:276
VSTREAM * vstream_fprintf(VSTREAM *stream, const char *fmt,...)
Definition: vstream.c:1348
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
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_DSN_MNAME
Definition: mail_proto.h:271
#define MAIL_ATTR_WHY
Definition: mail_proto.h:135
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
const char * mname
Definition: dsn.h:24
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
off_t vstream_fseek(VSTREAM *stream, off_t offset, int whence)
Definition: vstream.c:1093
const char * status
Definition: dsn.h:18
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define NOT_NULL_EMPTY(s)
int bounce_append_service(int unused_flags, char *service, char *queue_id, RECIPIENT *rcpt, DSN *dsn)
#define quote_822_local(dst, src)
#define MAIL_ATTR_RECIP
Definition: mail_proto.h:134
const char * dsn_orcpt
Definition: dsn.h:17
int var_oldlog_compat
Definition: mail_params.c:329
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define vstream_fileno(vp)
Definition: vstream.h:115
const char * mtype
Definition: dsn.h:23
#define MAIL_ATTR_DSN_MTYPE
Definition: mail_proto.h:270
#define MAIL_ATTR_DSN_DTEXT
Definition: mail_proto.h:269
const char * dtype
Definition: dsn.h:21
#define MAIL_ATTR_OFFSET
Definition: mail_proto.h:138
#define MAIL_ATTR_DSN_DTYPE
Definition: mail_proto.h:268
int vstream_fputs(const char *str, VSTREAM *stream)
Definition: vstream.c:1360