234 lines
5.8 KiB
C
234 lines
5.8 KiB
C
/*++
|
|
/* NAME
|
|
/* mail_addr_find 3
|
|
/* SUMMARY
|
|
/* generic address-based lookup
|
|
/* SYNOPSIS
|
|
/* #include <mail_addr_find.h>
|
|
/*
|
|
/* const char *mail_addr_find(maps, address, extension)
|
|
/* MAPS *maps;
|
|
/* const char *address;
|
|
/* char **extension;
|
|
/* DESCRIPTION
|
|
/* mail_addr_find() searches the specified maps for an entry with as
|
|
/* key the specified address, and derivations from that address.
|
|
/* The search is case insensitive.
|
|
/* The result is overwritten upon each call.
|
|
/*
|
|
/* An address that is in the form \fIuser\fR matches itself.
|
|
/*
|
|
/* Given an address of the form \fIuser@domain\fR, the following
|
|
/* lookups are done in the given order until one returns a result:
|
|
/* .IP user@domain
|
|
/* Look up the entire address.
|
|
/* .IP user
|
|
/* Look up \fIuser\fR when \fIdomain\fR is equal to $myorigin,
|
|
/* when \fIdomain\fR matches $mydestination, or when it matches
|
|
/* $inet_interfaces.
|
|
/* .IP @domain
|
|
/* Look for an entry that matches the domain specified in \fIaddress\fR.
|
|
/* .PP
|
|
/* With address extension enabled, the table lookup order is:
|
|
/* \fIuser+extension\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR,
|
|
/* \fIuser+extension\fR, \fIuser\fR, and @\fIdomain\fR.
|
|
/* .PP
|
|
/* Arguments:
|
|
/* .IP maps
|
|
/* Dictionary search path (see maps(3)).
|
|
/* .IP address
|
|
/* The address to be looked up.
|
|
/* .IP extension
|
|
/* A null pointer, or the address of a pointer that is set to
|
|
/* the address of a dynamic memory copy of the address extension
|
|
/* that had to be chopped off in order to match the lookup tables.
|
|
/* The copy includes the recipient address delimiter.
|
|
/* The caller is expected to pass the copy to myfree().
|
|
/* DIAGNOSTICS
|
|
/* The global \fIdict_errno\fR is non-zero when the lookup
|
|
/* should be tried again.
|
|
/* SEE ALSO
|
|
/* maps(3), multi-dictionary search
|
|
/* resolve_local(3), recognize local system
|
|
/* 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>
|
|
|
|
#ifdef STRCASECMP_IN_STRINGS_H
|
|
#include <strings.h>
|
|
#endif
|
|
|
|
/* Utility library. */
|
|
|
|
#include <msg.h>
|
|
#include <dict.h>
|
|
#include <stringops.h>
|
|
#include <mymalloc.h>
|
|
#include <vstring.h>
|
|
|
|
/* Global library. */
|
|
|
|
#include <mail_params.h>
|
|
#include <split_addr.h>
|
|
#include <mail_addr_find.h>
|
|
#include <resolve_local.h>
|
|
|
|
/* Application-specific. */
|
|
|
|
#define STR vstring_str
|
|
|
|
/* mail_addr_find - map a canonical address */
|
|
|
|
const char *mail_addr_find(MAPS *path, const char *address, char **extp)
|
|
{
|
|
char *myname = "mail_addr_find";
|
|
const char *result;
|
|
char *ratsign = 0;
|
|
char *full_key;
|
|
char *extent;
|
|
char *bare_key;
|
|
char *saved_ext;
|
|
|
|
/*
|
|
* Initialize.
|
|
*/
|
|
full_key = lowercase(mystrdup(address));
|
|
if (*var_rcpt_delim == 0) {
|
|
bare_key = saved_ext = 0;
|
|
} else {
|
|
bare_key = mystrdup(full_key);
|
|
if ((ratsign = strrchr(bare_key, '@')) != 0)
|
|
*ratsign = 0;
|
|
if ((extent = split_addr(bare_key, *var_rcpt_delim)) != 0) {
|
|
extent -= 1;
|
|
*extent = *var_rcpt_delim; /* XXX this is unclean */
|
|
saved_ext = mystrdup(extent); /* XXX maybe omit delimiter ? */
|
|
if (ratsign != 0) {
|
|
*ratsign = '@';
|
|
memmove(extent, ratsign, strlen(ratsign) + 1);
|
|
}
|
|
} else {
|
|
myfree(bare_key);
|
|
bare_key = saved_ext = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Try user+foo@domain and user@domain.
|
|
*
|
|
* Specify what keys are partial or full, to avoid matching partial
|
|
* addresses with regular expressions.
|
|
*/
|
|
#define FULL 0
|
|
#define PARTIAL DICT_FLAG_FIXED
|
|
|
|
if ((result = maps_find(path, full_key, FULL)) == 0 && dict_errno == 0
|
|
&& bare_key != 0 && (result = maps_find(path, bare_key, PARTIAL)) != 0
|
|
&& extp != 0) {
|
|
*extp = saved_ext;
|
|
saved_ext = 0;
|
|
}
|
|
|
|
/*
|
|
* Try user+foo@$myorigin, user+foo@$mydestination or
|
|
* user+foo@[$inet_interfaces]. Then try with +foo stripped off.
|
|
*/
|
|
if (result == 0 && dict_errno == 0
|
|
&& (ratsign = strrchr(full_key, '@')) != 0
|
|
&& (strcasecmp(ratsign + 1, var_myorigin) == 0
|
|
|| resolve_local(ratsign + 1))) {
|
|
*ratsign = 0;
|
|
result = maps_find(path, full_key, PARTIAL);
|
|
if (result == 0 && dict_errno == 0 && bare_key != 0) {
|
|
if ((ratsign = strrchr(bare_key, '@')) == 0)
|
|
msg_panic("%s: bare key botch", myname);
|
|
*ratsign = 0;
|
|
if ((result = maps_find(path, bare_key, PARTIAL)) != 0 && extp != 0) {
|
|
*extp = saved_ext;
|
|
saved_ext = 0;
|
|
}
|
|
}
|
|
*ratsign = '@';
|
|
}
|
|
|
|
/*
|
|
* Try @domain.
|
|
*/
|
|
if (result == 0 && dict_errno == 0 && ratsign)
|
|
result = maps_find(path, ratsign, PARTIAL);
|
|
|
|
/*
|
|
* Clean up.
|
|
*/
|
|
if (msg_verbose)
|
|
msg_info("%s: %s -> %s", myname, address,
|
|
result ? result :
|
|
dict_errno ? "(try again)" :
|
|
"(not found)");
|
|
myfree(full_key);
|
|
if (bare_key)
|
|
myfree(bare_key);
|
|
if (saved_ext)
|
|
myfree(saved_ext);
|
|
|
|
return (result);
|
|
}
|
|
|
|
#ifdef TEST
|
|
|
|
/*
|
|
* Proof-of-concept test program. Read an address from stdin, and spit out
|
|
* the lookup result.
|
|
*/
|
|
#include <vstream.h>
|
|
#include <vstring_vstream.h>
|
|
#include <mail_conf.h>
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
VSTRING *buffer = vstring_alloc(100);
|
|
MAPS *path;
|
|
const char *result;
|
|
char *extent;
|
|
|
|
/*
|
|
* Parse JCL.
|
|
*/
|
|
if (argc != 2)
|
|
msg_fatal("usage: %s database", argv[0]);
|
|
msg_verbose = 1;
|
|
|
|
/*
|
|
* Initialize.
|
|
*/
|
|
mail_conf_read();
|
|
path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK);
|
|
while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
|
|
extent = 0;
|
|
result = mail_addr_find(path, STR(buffer), &extent);
|
|
vstream_printf("%s -> %s (%s)\n", STR(buffer), result ? result :
|
|
dict_errno ? "(try again)" :
|
|
"(not found)", extent ? extent : "null extension");
|
|
vstream_fflush(VSTREAM_OUT);
|
|
if (extent)
|
|
myfree(extent);
|
|
}
|
|
vstring_free(buffer);
|
|
|
|
maps_free(path);
|
|
}
|
|
|
|
#endif
|