Postfix3.3.1
verify_sender_addr.c
[詳解]
1 /*++
2 /* NAME
3 /* verify_sender_addr 3
4 /* SUMMARY
5 /* time-dependent probe sender addresses
6 /* SYNOPSIS
7 /* #include <verify_sender_addr.h>
8 /*
9 /* char *var_verify_sender;
10 /* int var_verify_sender_ttl;
11 /*
12 /* const char *make_verify_sender_addr()
13 /*
14 /* const char *valid_verify_sender_addr(addr)
15 /* const char *addr;
16 /* DESCRIPTION
17 /* This module computes or verifies a constant or time-dependent
18 /* sender address for an address verification probe. The
19 /* time-dependent portion is appended to the address localpart
20 /* specified with the address_verify_sender parameter.
21 /*
22 /* When the address_verify_sender parameter is empty or <>,
23 /* the sender address is always the empty address (i.e. always
24 /* time-independent).
25 /*
26 /* The caller must initialize the address_verify_sender and
27 /* address_verify_sender_ttl parameter values.
28 /*
29 /* make_verify_sender_addr() generates an envelope sender
30 /* address for an address verification probe.
31 /*
32 /* valid_verify_sender_addr() verifies that the given address
33 /* is a valid sender address for address verification probes.
34 /* When probe sender addresses are configured to be time-dependent,
35 /* the given address is allowed to differ by +/-1 TTL unit
36 /* from the expected address. The result is a null pointer
37 /* when no match is found. Otherwise, the result is the sender
38 /* address without the time-dependent portion; this is the
39 /* address that should be used for further delivery.
40 /* DIAGNOSTICS
41 /* Fatal errors: malformed address_verify_sender value; out
42 /* of memory.
43 /* LICENSE
44 /* .ad
45 /* .fi
46 /* The Secure Mailer license must be distributed with this software.
47 /* AUTHOR(S)
48 /* Wietse Venema
49 /* IBM T.J. Watson Research
50 /* P.O. Box 704
51 /* Yorktown Heights, NY 10598, USA
52 /*--*/
53 
54 /* System library. */
55 
56 #include <sys_defs.h>
57 #include <errno.h>
58 #include <string.h>
59 #include <stdlib.h>
60 
61 /* Utility library. */
62 
63 #include <msg.h>
64 #include <vstring.h>
65 #include <events.h>
66 #include <stringops.h>
67 
68 /* Global library */
69 
70 #include <mail_params.h>
71 #include <rewrite_clnt.h>
72 #include <safe_ultostr.h>
73 #include <verify_sender_addr.h>
74 
75 /* Application-specific. */
76 
77  /*
78  * We convert the time-dependent portion to a safe string (no vowels) in a
79  * reversible manner, so that we can check an incoming address against the
80  * current and +/-1 TTL time slot. This allows for some time slippage
81  * between multiple MTAs that handle mail for the same site. We use base 31
82  * so that the time stamp contains B-Z0-9. This simplifies regression tests.
83  */
84 #define VERIFY_BASE 31
85 
86  /*
87  * We append the time-dependent portion to the localpart of the the address
88  * verification probe sender address, so that the result has the form
89  * ``fixed1variable@fixed2''. There is no delimiter between ``fixed1'' and
90  * ``variable'', because that could make "old" time stamps valid depending
91  * on how the recipient_delimiter feature is configured. The fixed text is
92  * taken from var_verify_sender with perhaps domain information appended
93  * during address canonicalization. The variable part of the address changes
94  * every var_verify_sender_ttl seconds.
95  */
96 char *var_verify_sender; /* "bare" probe sender address */
97 int var_verify_sender_ttl; /* time between address changes */
98 
99  /*
100  * Scaffolding for stand-alone testing.
101  */
102 #ifdef TEST
103 #undef event_time
104 #define event_time() verify_time
105 static unsigned long verify_time;
106 
107 #endif
108 
109 #define VERIFY_SENDER_ADDR_EPOCH() (event_time() / var_verify_sender_ttl)
110 
111  /*
112  * SLMs.
113  */
114 #define STR(x) vstring_str(x)
115 #define LEN(x) VSTRING_LEN(x)
116 
117 /* make_verify_sender_addr - generate address_verify_sender address */
118 
119 const char *make_verify_sender_addr(void)
120 {
121  static VSTRING *verify_sender_buf; /* the complete sender address */
122  static VSTRING *my_epoch_buf; /* scratch space */
123  char *my_at_domain;
124 
125  /*
126  * The null sender is always time-independent.
127  */
128  if (*var_verify_sender == 0 || strcmp(var_verify_sender, "<>") == 0)
129  return ("");
130 
131  /*
132  * Sanity check.
133  */
134  if (*var_verify_sender == '@')
135  msg_fatal("parameter %s: value \"%s\" must not start with '@'",
137  if ((my_at_domain = strchr(var_verify_sender, '@')) != 0 && my_at_domain[1] == 0)
138  msg_fatal("parameter %s: value \"%s\" must not end with '@'",
140 
141  /*
142  * One-time initialization.
143  */
144  if (verify_sender_buf == 0) {
145  verify_sender_buf = vstring_alloc(10);
146  my_epoch_buf = vstring_alloc(10);
147  }
148 
149  /*
150  * Start with the bare sender address.
151  */
152  vstring_strcpy(verify_sender_buf, var_verify_sender);
153 
154  /*
155  * Append the time stamp to the address localpart, encoded in some
156  * non-decimal form for obscurity.
157  *
158  * XXX It would be nice to have safe_ultostr() append-only support.
159  */
160  if (var_verify_sender_ttl > 0) {
161  /* Strip the @domain portion, if applicable. */
162  if (my_at_domain != 0)
163  vstring_truncate(verify_sender_buf,
164  (ssize_t) (my_at_domain - var_verify_sender));
165  /* Append the time stamp to the address localpart. */
166  vstring_sprintf_append(verify_sender_buf, "%s",
167  safe_ultostr(my_epoch_buf,
169  VERIFY_BASE, 0, 0));
170  /* Add back the @domain, if applicable. */
171  if (my_at_domain != 0)
172  vstring_sprintf_append(verify_sender_buf, "%s", my_at_domain);
173  }
174 
175  /*
176  * Rewrite the address to canonical form.
177  */
178  rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL, STR(verify_sender_buf),
179  verify_sender_buf);
180 
181  return (STR(verify_sender_buf));
182 }
183 
184 /* valid_verify_sender_addr - decide if address matches time window +/-1 */
185 
186 const char *valid_verify_sender_addr(const char *their_addr)
187 {
188  static VSTRING *time_indep_sender_buf; /* sender without time stamp */
189  ssize_t base_len;
190  unsigned long my_epoch;
191  unsigned long their_epoch;
192  char *my_at_domain;
193  char *their_at_domain;
194  char *cp;
195 
196  /*
197  * The null address is always time-independent.
198  */
199  if (*var_verify_sender == 0 || strcmp(var_verify_sender, "<>") == 0)
200  return (*their_addr ? 0 : "");
201 
202  /*
203  * One-time initialization. Generate the time-independent address that we
204  * will return if the match is successful. This address is also used as a
205  * matching template.
206  */
207  if (time_indep_sender_buf == 0) {
208  time_indep_sender_buf = vstring_alloc(10);
209  vstring_strcpy(time_indep_sender_buf, var_verify_sender);
210  rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL, STR(time_indep_sender_buf),
211  time_indep_sender_buf);
212  }
213 
214  /*
215  * Check the time-independent sender localpart.
216  */
217  if ((my_at_domain = strchr(STR(time_indep_sender_buf), '@')) != 0)
218  base_len = my_at_domain - STR(time_indep_sender_buf);
219  else
220  base_len = LEN(time_indep_sender_buf);
221  if (strncasecmp_utf8(STR(time_indep_sender_buf), their_addr, base_len) != 0)
222  return (0); /* sender localpart mis-match */
223 
224  /*
225  * Check the time-independent domain.
226  */
227  if ((their_at_domain = strchr(their_addr, '@')) == 0 && my_at_domain != 0)
228  return (0); /* sender domain mis-match */
229  if (their_at_domain != 0
230  && (my_at_domain == 0
231  || strcasecmp_utf8(their_at_domain, my_at_domain) != 0))
232  return (0); /* sender domain mis-match */
233 
234  /*
235  * Check the time-dependent portion.
236  */
237  if (var_verify_sender_ttl > 0) {
238  their_epoch = safe_strtoul(their_addr + base_len, &cp, VERIFY_BASE);
239  if ((*cp != '@' && *cp != 0)
240  || (their_epoch == ULONG_MAX && errno == ERANGE))
241  return (0); /* malformed time stamp */
242  my_epoch = VERIFY_SENDER_ADDR_EPOCH();
243  if (their_epoch < my_epoch - 1 || their_epoch > my_epoch + 1)
244  return (0); /* outside time window */
245  }
246 
247  /*
248  * No time-dependent portion.
249  */
250  else {
251  if (their_addr[base_len] != '@' && their_addr[base_len] != 0)
252  return (0); /* garbage after sender base */
253  }
254  return (STR(time_indep_sender_buf));
255 }
256 
257  /*
258  * Proof-of-concept test program. Read test address_verify_sender and
259  * address_verify_sender_ttl values from stdin, and report results that we
260  * would get on stdout.
261  */
262 #ifdef TEST
263 
264 #include <stdlib.h>
265 #include <vstream.h>
266 #include <msg_vstream.h>
267 #include <vstring_vstream.h>
268 #include <mail_conf.h>
269 #include <conv_time.h>
270 
271 int main(int argc, char **argv)
272 {
273  const char *verify_sender;
274  const char *valid_sender;
275 
276  msg_vstream_init(argv[0], VSTREAM_ERR);
277 
278  /*
279  * Prepare to talk to the address rewriting service.
280  */
281  mail_conf_read();
282  vstream_printf("using config files in %s\n", var_config_dir);
283  if (chdir(var_queue_dir) < 0)
284  msg_fatal("chdir %s: %m", var_queue_dir);
285 
286  /*
287  * Parse JCL.
288  */
289  if (argc != 3)
290  msg_fatal("usage: %s address_verify_sender address_verify_sender_ttl",
291  argv[0]);
292  var_verify_sender = argv[1];
293  if (conv_time(argv[2], &var_verify_sender_ttl, 's') == 0)
294  msg_fatal("bad time value: %s", argv[2]);
295  verify_time = time((time_t *) 0);
296 
297  /*
298  * Compute the current probe sender address.
299  */
300  verify_sender = make_verify_sender_addr();
301 
302  /*
303  * Check two past time slots.
304  */
305  if (var_verify_sender_ttl > 0) {
306  verify_time -= 2 * var_verify_sender_ttl;
307  vstream_printf("\"%s\" matches prev2: \"%s\"\n", verify_sender,
308  (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
309  valid_sender : "nope");
310  verify_time += var_verify_sender_ttl;
311  vstream_printf("\"%s\" matches prev1: \"%s\"\n", verify_sender,
312  (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
313  valid_sender : "nope");
314  verify_time += var_verify_sender_ttl;
315  }
316 
317  /*
318  * Check the current time slot.
319  */
320  vstream_printf("\"%s\" matches self: \"%s\"\n", verify_sender,
321  (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
322  valid_sender : "nope");
323 
324  /*
325  * Check two future time slots.
326  */
327  if (var_verify_sender_ttl > 0) {
328  verify_time += var_verify_sender_ttl;
329  vstream_printf("\"%s\" matches next1: \"%s\"\n", verify_sender,
330  (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
331  valid_sender : "nope");
332  verify_time += var_verify_sender_ttl;
333  vstream_printf("\"%s\" matches next2: \"%s\"\n", verify_sender,
334  (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
335  valid_sender : "nope");
336  }
338  exit(0);
339 }
340 
341 #endif
#define STR(x)
#define VSTREAM_OUT
Definition: vstream.h:67
int main(int argc, char **argv)
Definition: anvil.c:1010
VSTRING * rewrite_clnt_internal(const char *ruleset, const char *addr, VSTRING *result)
Definition: rewrite_clnt.c:175
int conv_time(const char *strval, int *timval, int def_unit)
Definition: conv_time.c:67
VSTRING * vstring_truncate(VSTRING *vp, ssize_t len)
Definition: vstring.c:415
#define MAIL_ATTR_RWR_LOCAL
Definition: mail_proto.h:166
char * var_config_dir
Definition: mail_params.c:241
#define strcasecmp_utf8(s1, s2)
Definition: stringops.h:75
int var_verify_sender_ttl
const char * valid_verify_sender_addr(const char *their_addr)
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
void mail_conf_read(void)
Definition: mail_conf.c:178
VSTRING * vstring_sprintf_append(VSTRING *vp, const char *format,...)
Definition: vstring.c:624
#define VERIFY_SENDER_ADDR_EPOCH()
#define LEN(x)
#define VERIFY_BASE
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
unsigned long safe_strtoul(const char *start, char **end, int base)
Definition: safe_ultostr.c:137
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
const char * make_verify_sender_addr(void)
char * var_verify_sender
char * safe_ultostr(VSTRING *buf, unsigned long ulval, int base, int padlen, int padchar)
Definition: safe_ultostr.c:99
#define strncasecmp_utf8(s1, s2, l)
Definition: stringops.h:77
#define VAR_VERIFY_SENDER
Definition: mail_params.h:2822
char * var_queue_dir
Definition: mail_params.c:246
void msg_vstream_init(const char *name, VSTREAM *vp)
Definition: msg_vstream.c:77
#define VSTREAM_ERR
Definition: vstream.h:68