/* $NetBSD: cleanup_masquerade.c,v 1.2 2017/02/14 01:16:44 christos Exp $ */
/*++
/* NAME
/* cleanup_masquerade 3
/* SUMMARY
/* address masquerading
/* SYNOPSIS
/* #include <cleanup.h>
/*
/* int cleanup_masquerade_external(addr, masq_domains)
/* VSTRING *addr;
/* ARGV *masq_domains;
/*
/* int cleanup_masquerade_internal(addr, masq_domains)
/* VSTRING *addr;
/* ARGV *masq_domains;
/*
/* int cleanup_masquerade_tree(tree, masq_domains)
/* TOK822 *tree;
/* ARGV *masq_domains;
/* DESCRIPTION
/* This module masquerades addresses, that is, it strips subdomains
/* below domain names that are listed in the masquerade_domains
/* configuration parameter, except for user names listed in the
/* masquerade_exceptions configuration parameter.
/* These functions return non-zero when the address was changed.
/*
/* cleanup_masquerade_external() rewrites the external (quoted) string
/* form of an address.
/*
/* cleanup_masquerade_internal() is a wrapper around the
/* cleanup_masquerade_external() routine that transforms from
/* internal (quoted) string form to external form and back.
/*
/* cleanup_masquerade_tree() is a wrapper around the
/* cleanup_masquerade_external() routine that transforms from
/* internal parse tree form to external form and back.
/* DIAGNOSTICS
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <string.h>
/* Utility library. */
#include <msg.h>
#include <vstring.h>
#include <argv.h>
#include <htable.h>
#include <mymalloc.h>
#include <stringops.h>
/* Global library. */
#include <mail_params.h>
#include <tok822.h>
#include <quote_822_local.h>
/* Application-specific. */
#include "cleanup.h"
#define STR vstring_str
/* cleanup_masquerade_external - masquerade address external form */
int cleanup_masquerade_external(CLEANUP_STATE *state, VSTRING *addr,
ARGV *masq_domains)
{
char *domain;
ssize_t domain_len;
char **masqp;
char *masq;
ssize_t masq_len;
char *parent;
int truncate;
int did_rewrite = 0;
/* Stuff for excluded names. */
char *name;
ssize_t name_len;
int excluded;
/*
* Find the domain part.
*/
if ((domain = strrchr(STR(addr), '@')) == 0)
return (0);
name_len = domain - STR(addr);
domain = casefold(state->temp2, domain + 1);
domain_len = strlen(domain);
/*
* Don't masquerade excluded names (regardless of domain).
*/
if (*var_masq_exceptions) {
name = mystrndup(STR(addr), name_len);
excluded = (string_list_match(cleanup_masq_exceptions, name) != 0);
myfree(name);
if (cleanup_masq_exceptions->error) {
msg_info("%s: %s map lookup problem -- "
"message not accepted, try again later",
state->queue_id, VAR_MASQ_EXCEPTIONS);
state->errs |= CLEANUP_STAT_WRITE;
}
if (excluded)
return (0);
}
/*
* If any parent domain matches the list of masquerade domains, replace
* the domain in the address and terminate. If the domain matches a
* masquerade domain, leave it alone. Order of specification matters.
*/
for (masqp = masq_domains->argv; (masq = *masqp) != 0; masqp++) {
for (truncate = 1; *masq == '!'; masq++)
truncate = !truncate;
masq = casefold(state->temp1, masq);
masq_len = strlen(masq);
if (masq_len == 0)
continue;
if (masq_len == domain_len) {
if (strcmp(masq, domain) == 0)
break;
} else if (masq_len < domain_len) {
parent = domain + domain_len - masq_len;
if (parent[-1] == '.' && strcmp(masq, parent) == 0) {
if (truncate) {
if (msg_verbose)
msg_info("masquerade: %s -> %s", domain, masq);
vstring_truncate(addr, name_len + 1);
vstring_strcat(addr, masq);
did_rewrite = 1;
}
break;
}
}
}
return (did_rewrite);
}
/* cleanup_masquerade_tree - masquerade address node */
int cleanup_masquerade_tree(CLEANUP_STATE *state, TOK822 *tree,
ARGV *masq_domains)
{
VSTRING *temp = vstring_alloc(100);
int did_rewrite;
tok822_externalize(temp, tree->head, TOK822_STR_DEFL);
did_rewrite = cleanup_masquerade_external(state, temp, masq_domains);
tok822_free_tree(tree->head);
tree->head = tok822_scan(STR(temp), &tree->tail);
vstring_free(temp);
return (did_rewrite);
}
/* cleanup_masquerade_internal - masquerade address internal form */
int cleanup_masquerade_internal(CLEANUP_STATE *state, VSTRING *addr,
ARGV *masq_domains)
{
VSTRING *temp = vstring_alloc(100);
int did_rewrite;
quote_822_local(temp, STR(addr));
did_rewrite = cleanup_masquerade_external(state, temp, masq_domains);
unquote_822_local(addr, STR(temp));
vstring_free(temp);
return (did_rewrite);
}
/*
* Code for stand-alone testing. Instead of using main.cf, specify the strip
* list and the candidate domain on the command line. Specify null arguments
* for data that should be empty.
*/
#ifdef TEST
#include <vstream.h>
char *var_masq_exceptions;
STRING_LIST *cleanup_masq_exceptions;
int main(int argc, char **argv)
{
VSTRING *addr;
ARGV *masq_domains;
CLEANUP_STATE state;
if (argc != 4)
msg_fatal("usage: %s exceptions masquerade_list address", argv[0]);
var_masq_exceptions = argv[1];
cleanup_masq_exceptions =
string_list_init(VAR_MASQ_EXCEPTIONS, MATCH_FLAG_RETURN,
var_masq_exceptions);
masq_domains = argv_split(argv[2], CHARS_COMMA_SP);
addr = vstring_alloc(1);
if (strchr(argv[3], '@') == 0)
msg_fatal("address must be in user@domain form");
vstring_strcpy(addr, argv[3]);
vstream_printf("----------\n");
vstream_printf("exceptions: %s\n", argv[1]);
vstream_printf("masq_list: %s\n", argv[2]);
vstream_printf("address: %s\n", argv[3]);
state.errs = 0;
state.queue_id = "NOQUEUE";
state.temp1 = vstring_alloc(100);
state.temp2 = vstring_alloc(100);
cleanup_masquerade_external(&state, addr, masq_domains);
vstream_printf("result: %s\n", STR(addr));
vstream_printf("errs: %d\n", state.errs);
vstream_fflush(VSTREAM_OUT);
vstring_free(state.temp1);
vstring_free(state.temp2);
vstring_free(addr);
argv_free(masq_domains);
return (0);
}
#endif