verify_sender_addr.c [plain text]
#include <sys_defs.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <msg.h>
#include <vstring.h>
#include <events.h>
#include <stringops.h>
#include <mail_params.h>
#include <rewrite_clnt.h>
#include <safe_ultostr.h>
#include <verify_sender_addr.h>
#define VERIFY_BASE 31
char *var_verify_sender;
int var_verify_sender_ttl;
#ifdef TEST
#undef event_time
#define event_time() verify_time
static unsigned long verify_time;
#endif
#define VERIFY_SENDER_ADDR_EPOCH() (event_time() / var_verify_sender_ttl)
#define STR(x) vstring_str(x)
#define LEN(x) VSTRING_LEN(x)
const char *make_verify_sender_addr(void)
{
static VSTRING *verify_sender_buf;
static VSTRING *my_epoch_buf;
char *my_at_domain;
if (*var_verify_sender == 0 || strcmp(var_verify_sender, "<>") == 0)
return ("");
if (*var_verify_sender == '@')
msg_fatal("parameter %s: value \"%s\" must not start with '@'",
VAR_VERIFY_SENDER, var_verify_sender);
if ((my_at_domain = strchr(var_verify_sender, '@')) != 0 && my_at_domain[1] == 0)
msg_fatal("parameter %s: value \"%s\" must not end with '@'",
VAR_VERIFY_SENDER, var_verify_sender);
if (verify_sender_buf == 0) {
verify_sender_buf = vstring_alloc(10);
my_epoch_buf = vstring_alloc(10);
}
vstring_strcpy(verify_sender_buf, var_verify_sender);
if (var_verify_sender_ttl > 0) {
if (my_at_domain != 0)
vstring_truncate(verify_sender_buf,
(ssize_t) (my_at_domain - var_verify_sender));
vstring_sprintf_append(verify_sender_buf, "%s",
safe_ultostr(my_epoch_buf,
VERIFY_SENDER_ADDR_EPOCH(),
VERIFY_BASE, 0, 0));
if (my_at_domain != 0)
vstring_sprintf_append(verify_sender_buf, "%s", my_at_domain);
}
rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL, STR(verify_sender_buf),
verify_sender_buf);
return (STR(verify_sender_buf));
}
const char *valid_verify_sender_addr(const char *their_addr)
{
static VSTRING *time_indep_sender_buf;
ssize_t base_len;
unsigned long my_epoch;
unsigned long their_epoch;
char *my_at_domain;
char *their_at_domain;
char *cp;
if (*var_verify_sender == 0 || strcmp(var_verify_sender, "<>") == 0)
return (*their_addr ? 0 : "");
if (time_indep_sender_buf == 0) {
time_indep_sender_buf = vstring_alloc(10);
vstring_strcpy(time_indep_sender_buf, var_verify_sender);
rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL, STR(time_indep_sender_buf),
time_indep_sender_buf);
}
if ((my_at_domain = strchr(STR(time_indep_sender_buf), '@')) != 0)
base_len = my_at_domain - STR(time_indep_sender_buf);
else
base_len = LEN(time_indep_sender_buf);
if (strncasecmp_utf8(STR(time_indep_sender_buf), their_addr, base_len) != 0)
return (0);
if ((their_at_domain = strchr(their_addr, '@')) == 0 && my_at_domain != 0)
return (0);
if (their_at_domain != 0
&& (my_at_domain == 0
|| strcasecmp_utf8(their_at_domain, my_at_domain) != 0))
return (0);
if (var_verify_sender_ttl > 0) {
their_epoch = safe_strtoul(their_addr + base_len, &cp, VERIFY_BASE);
if ((*cp != '@' && *cp != 0)
|| (their_epoch == ULONG_MAX && errno == ERANGE))
return (0);
my_epoch = VERIFY_SENDER_ADDR_EPOCH();
if (their_epoch < my_epoch - 1 || their_epoch > my_epoch + 1)
return (0);
}
else {
if (their_addr[base_len] != '@' && their_addr[base_len] != 0)
return (0);
}
return (STR(time_indep_sender_buf));
}
#ifdef TEST
#include <stdlib.h>
#include <vstream.h>
#include <msg_vstream.h>
#include <vstring_vstream.h>
#include <mail_conf.h>
#include <conv_time.h>
int main(int argc, char **argv)
{
const char *verify_sender;
const char *valid_sender;
msg_vstream_init(argv[0], VSTREAM_ERR);
mail_conf_read();
vstream_printf("using config files in %s\n", var_config_dir);
if (chdir(var_queue_dir) < 0)
msg_fatal("chdir %s: %m", var_queue_dir);
if (argc != 3)
msg_fatal("usage: %s address_verify_sender address_verify_sender_ttl",
argv[0]);
var_verify_sender = argv[1];
if (conv_time(argv[2], &var_verify_sender_ttl, 's') == 0)
msg_fatal("bad time value: %s", argv[2]);
verify_time = time((time_t *) 0);
verify_sender = make_verify_sender_addr();
if (var_verify_sender_ttl > 0) {
verify_time -= 2 * var_verify_sender_ttl;
vstream_printf("\"%s\" matches prev2: \"%s\"\n", verify_sender,
(valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
valid_sender : "nope");
verify_time += var_verify_sender_ttl;
vstream_printf("\"%s\" matches prev1: \"%s\"\n", verify_sender,
(valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
valid_sender : "nope");
verify_time += var_verify_sender_ttl;
}
vstream_printf("\"%s\" matches self: \"%s\"\n", verify_sender,
(valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
valid_sender : "nope");
if (var_verify_sender_ttl > 0) {
verify_time += var_verify_sender_ttl;
vstream_printf("\"%s\" matches next1: \"%s\"\n", verify_sender,
(valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
valid_sender : "nope");
verify_time += var_verify_sender_ttl;
vstream_printf("\"%s\" matches next2: \"%s\"\n", verify_sender,
(valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
valid_sender : "nope");
}
vstream_fflush(VSTREAM_OUT);
exit(0);
}
#endif