Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: [courier-users] hosteddomains and aliases capitalization

5 views
Skip to first unread message

charles uchu

unread,
Oct 26, 2006, 11:25:22 PM10/26/06
to
Sam Varshavchik wrote:
> Gordon Messmer writes:
>
>> It's come up before that "aliased" hosteddomains sometimes don't do
>> what users expect them to. The man page for "makehosteddomains"
>> indicates that if "mail.domain.com" is aliased to "domain.com", then
>> an address of the form <add...@mail.domain.com> will be rewritten as
>> <add...@domain.com> and delivered to the local mailbox for that
>> name. The consequence seems to be that if <add...@domain.com> is an
>> alias, delivery fails.
>
> Define an alias for add...@mail.domain.com
>
Sam and Gordon,

I think it is understood that based on the current code in courier that,
even if there is an aliased domain set in hosteddomains, that you must
again explicitly state this aliasing in the aliases file for addresses
that are not mailboxes.

The need to define the domain alias twice seems redundant and is a bit
confusing:

1) hosteddomains sample

domainprimary.com
domainalias.com<tab>domainprimary.com

2) aliases sample would need:

j...@domainprimary.com: som...@gmail.com
j...@domainalias.com: som...@gmail.com

It would be much simpler from an administration perspective for the
aliases file to follow the global setting for domain aliasing as set in
hostedomains, thus only needing this in the aliases file:

j...@domainprimary.com: som...@gmail.com

...

This same need for redundancy seems to also be necessary in regards to
the global setting to be case-insensitivivty.

For mailboxes, they are case-insensitive, but for aliases... it seems to
be necessary to include options for likely capitalization nuances. For
instance some strange person my decide to send email to
Mr...@domain.com. If mr...@domain.com is a mailbox it gets delivered
fine, but if it is an alias you have to define both of these in the
aliases file for delivery to succeed for the different capitalization
nuances:

mr...@domain.com
Mr...@domain.com

...

Now, what I truly wish is that I was educated in programming enough at
this point to figure out how to update the code to do this... or whether
it was just meant to run this way for some reason I'm not understanding
and thus needing to deal with this redundancy is necessary.

Thanks,

Charles

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
courier-users mailing list
courie...@lists.sourceforge.net
Unsubscribe: https://lists.sourceforge.net/lists/listinfo/courier-users

David Gomillion

unread,
Oct 27, 2006, 9:49:34 AM10/27/06
to
charles uchu wrote:
> Sam Varshavchik wrote:
>
>> Gordon Messmer writes:
>>
>>
>>> It's come up before that "aliased" hosteddomains sometimes don't do
>>> what users expect them to. The man page for "makehosteddomains"
>>> indicates that if "mail.domain.com" is aliased to "domain.com", then
>>> an address of the form <add...@mail.domain.com> will be rewritten as
>>> <add...@domain.com> and delivered to the local mailbox for that
>>> name. The consequence seems to be that if <add...@domain.com> is an
>>> alias, delivery fails.
>>>
>> Define an alias for add...@mail.domain.com
>>
>>
> Sam and Gordon,
>
> I think it is understood that based on the current code in courier that,
> even if there is an aliased domain set in hosteddomains, that you must
> again explicitly state this aliasing in the aliases file for addresses
> that are not mailboxes.
To cut down on the confusion, I always recommend creating a hosted
domain, and then create actual mailboxes for each alias I want to
create. In it I create a .courier file to forward the mail where ever I
want it to go. The ONLY aliases I create in the global alias file are
those required by the system (like root, postmaster, etc).

It's a little extra work, but in the end, I opt for simplicity and
maintainability. And it's very easy to script with bash...

Alessandro Vesely

unread,
Oct 27, 2006, 3:33:15 PM10/27/06
to
This is a multi-part message in MIME format.
--------------080907080602050203020303
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

David Gomillion wrote:


> charles uchu wrote:
>>
>> I think it is understood that based on the current code in courier that,
>> even if there is an aliased domain set in hosteddomains, that you must
>> again explicitly state this aliasing in the aliases file for addresses
>> that are not mailboxes.
>
> To cut down on the confusion, I always recommend creating a hosted
> domain, and then create actual mailboxes for each alias I want to
> create. In it I create a .courier file to forward the mail where ever I
> want it to go.

That way one can trace which alias has been matched. Although technically
it is a full blown mailbox, it would be unfair to count it as such for
administrative purposes.

> The ONLY aliases I create in the global alias file are
> those required by the system (like root, postmaster, etc).

However,it is annoying to maintain a bunch of aliases for each domain.
I have a script structured more or less like so:

LCLOCAL=`echo $LOCAL | tr '[A-Z]' '[a-z]'`
case $LCLOCAL in
webmaster|postmaster|admin|abuse|operator|sys|system|root)
NEWADDR="m...@my.domain";;
*)
NEWADDR="";;
esac
if [ "$NEWADDR" = "" ]; then
case $HOST in
domain1*)
# per domain catchall policy...;;
# ...
esac
fi

if [ "$NEWADDR" = "" ]; then
exit 64
fi

printf "$NEWADDR\n"
exit 0

> It's a little extra work, but in the end, I opt for simplicity and
> maintainability. And it's very easy to script with bash...

Yes. After some years spent trying to match rcptfilters with a dynamic
delivery instruction calling the above script from .courier-default,
I finally coded the attached replacement for maildropfilter to run the
same script in either case.

I'd propose to drop it in a miscellanea "contrib" directory, if Courier
had one...


--------------080907080602050203020303
Content-Type: text/plain;
name="rcptfilter.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="rcptfilter.c"

/*
* rcptfilter.c - written by vesely in milan on 8 aug 2006
*
* Run rcptfilter.sh
* gcc -W -O -DNDEBUG -o /usr/local/sbin/rcptfilter rcptfilter.c
* gcc -W -Wall -Wno-parentheses -O0 -g -o rcptfilter rcptfilter.c
*/

#define SCRIPTFILE "rcptfilter.sh"

static char const usage[] =
"usage:\n"
"\trcptfilter -h\n"
"\trcptfilter -D uid/gid -M rcptfilter[-ext] ...\n"
"The first format is only useful to print this note.\n"
"The second format is used by Courier's local output module if the\n"
"maildropfilter configuration file contains the path of this executable.\n"
"In this case, rcptfilter changes directory to HOME and looks for file\n"
"\"" SCRIPTFILE "\" and runs it (with null input and output, logged error)\n"
"and then returns an exit code of 0 if the script exits rc < 50, 1 otherwise.\n"
"The script will have argument $1 set to \"RCPT\" and the other arguments\n"
"set to whatever was passed to rcptfilter as ellipsis (...). The variables\n"
"LOCAL and HOST will be set from ext. The rest of the environment remains.";

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <syslog.h>
#include <ctype.h>
#include <errno.h>
#include <assert.h>

static volatile int
signal_child = 0,
signal_timed_out = 0,
signal_break = 0;

static void sig_catcher(int sig)
{
#if !defined(NDEBUG)
char buf[80];
unsigned s = snprintf(buf, sizeof buf,
"rcptfilter[%d]: received signal %d\n",
(int)getpid(), sig);
if (s >= sizeof buf)
{
buf[sizeof buf - 1] = '\n';
s = sizeof buf;
}
write(2, buf, s);
#endif
switch(sig)
{
case SIGALRM:
signal_timed_out = 1;
break;

case SIGHUP:
case SIGPIPE:
case SIGINT:
case SIGQUIT:
case SIGTERM:
signal_break = 1;
break;

case SIGCHLD:
signal_child = 1;
break;

default:
break;
}
}

#if 0
static void reset_signal(void)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = SIG_DFL;

sigaction(SIGALRM, &act, NULL);
sigaction(SIGPIPE, &act, NULL);
sigaction(SIGINT, &act, NULL);
sigaction(SIGTERM, &act, NULL);
sigaction(SIGHUP, &act, NULL);
sigaction(SIGCHLD, &act, NULL);
}
#endif

static void set_signal(void)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);

act.sa_handler = sig_catcher;
sigaction(SIGALRM, &act, NULL);
sigaction(SIGPIPE, &act, NULL);
sigaction(SIGINT, &act, NULL);
sigaction(SIGTERM, &act, NULL);
sigaction(SIGHUP, &act, NULL);
sigaction(SIGCHLD, &act, NULL);
}

static void addtoenv(char const *name, char const *value)
{
char *freeonexit = (char*)malloc(strlen(name) + strlen(value) + 1);
if (freeonexit)
putenv(strcat(strcpy(freeonexit, name), value));
}

static int run_script(char const *ext, char *argv[], char const *home)
{
int rtc = 0;
char *local = strdup(ext);
if (local)
{
int err[2];
char *host = strchr(local, '@');

if (host)
*host++ = 0;
else
host = "";
addtoenv("HOST=", host);
addtoenv("LOCAL=", local);
free(local);

if (pipe(err) < 0)
syslog(LOG_CRIT, "Cannot open pipe: %s\n", strerror(errno));
else
{
pid_t const pid = fork();
if (pid < 0)
syslog(LOG_CRIT, "Cannot fork: %s\n", strerror(errno));
else if (pid)
{
char buf[2048], *next = &buf[0];
char *const first = &buf[0], *const last = &buf[sizeof buf - 2];

close(err[1]);
alarm(30);
last[1] = 0; // terminator on forced newline
while (signal_timed_out == 0 &&
signal_break == 0 &&
signal_child == 0)
{
int rd = read(err[0], next, last - next);
#if !defined NDEBUG
printf("rd=%2d, next=%2d\n", rd, next - first);
#endif
if (rd > 0)
{
char *p = first, *br;
next += rd;

*next = next == last? '\n': 0; // force newline if full

while ((br = strchr(p, '\n')) != NULL)
{
int level = LOG_CRIT;
*br = 0;

/*
* e.g., "##This is a warning\n"
*/
while (*p == '#' && level < LOG_DEBUG)
++p, ++level;

if (*p) syslog(level, "script: %s\n", p);
p = br + (br < last); // +1 if not forced newline
assert(first <= p && p <= next);
}

memmove(first, p, next - p);
next -= p - first;
assert(first <= next && next < last);
}
else if (rd == 0 || errno != EINTR && errno != EAGAIN)
{
if (rd)
syslog(LOG_CRIT, "Pipe broken: %s\n", strerror(errno));
break;
}
}
alarm(0);
if (signal_timed_out || signal_break)
{
kill(pid, SIGTERM);
}
close(err[0]);

for (;;)
{
int status;
pid_t wpid = wait(&status);
if (wpid < 0 && errno != EAGAIN && errno != EINTR)
{
syslog(LOG_CRIT,
"Cannot wait %s/" SCRIPTFILE "[%u]: %s\n",
home, (unsigned)wpid, strerror(errno));
break;
}
else if (wpid == pid)
{
if (WIFEXITED(status))
{
int level, s_rtc = WEXITSTATUS(status);
switch (s_rtc)
{
case 0: case 64: case 99: level = LOG_DEBUG; break;
default: level = LOG_CRIT; break;
}
rtc = s_rtc > 50;
syslog(level,
"%s/" SCRIPTFILE " with %s exited %d, rtc=%d\n",
home, ext, s_rtc, rtc);
}
else if (WIFSIGNALED(status))
{
syslog(LOG_CRIT,
"%s/" SCRIPTFILE " terminated with signal %d, rtc=%d\n",
home, WTERMSIG(status), rtc);
}
else continue; // stopped?

break;
}
}
}
else // child process
{
close(0);
open("/dev/null", O_RDONLY);
close(1);
open("/dev/null", O_WRONLY);
close(2);
dup(err[1]);
close(err[0]);
close(err[1]);
closelog();
execv(SCRIPTFILE, argv);
syslog(LOG_MAIL|LOG_CRIT, "rcptfilter: cannot execv: %s\n",
strerror(errno));
exit(0);
}
}

}
return rtc;
}

int main(int argc, char *argv[])
{
int rtc = 0;
int i, uid = 0, gid = 0, err = 0;
char *ext = NULL, *home = getenv("HOME");
static char const argerror[] = "invoked with wrong argument: ";

char *xargv[32];
size_t xargc = 0;

openlog("rcptfilter", LOG_PID, LOG_MAIL);
xargv[xargc++] = SCRIPTFILE;
xargv[xargc++] = "RCPT";

for (i = 1; i < argc; ++i)
{
char *a = argv[i];
int pass_it = 1;

if (*a == '-')
{
pass_it = 0;
switch (*++a)
{
case 'D':
if (i + 1 >= argc)
{
syslog(LOG_CRIT, "%s-D requires a value\n", argerror);
++err;
}
else
{
char *t = NULL;
a = argv[++i];
uid = strtoul(a, &t, 10);
if (t && *t == '/')
{
gid = strtoul(t + 1, &t, 10);
if (t && *t) t = NULL;
}
else t = NULL;
if (t == NULL)
{
syslog(LOG_CRIT, "%suidgid is %s\n", argerror, a);
++err;
}
}
break;

case 'M':
if (i + 1 >= argc)
{
syslog(LOG_CRIT, "%s-M requires a value\n", argerror);
++err;
}
else if (strncmp(a = argv[++i],
"rcptfilter" , sizeof "rcptfilter" - 1) != 0)
{
syslog(LOG_CRIT, "%s-M with value %s\n", argerror, a);
++err;
}
else
{
ext = strchr(a, '-');
if (ext)
++ext;
else
ext = "";
}
break;

case 'h':
puts(usage);
return 0;

default:
pass_it = 1;
break;
}
}

if (pass_it && xargc + 1 < sizeof xargv/ sizeof xargv[0])
{
xargv[xargc++] = a;
}
}

xargv[xargc] = NULL;

if (geteuid() == 0 && (uid || gid))
{
if (gid) setgid(gid);
setuid(uid);
}

set_signal();
if (home && ext)
{
struct stat buf;
uid_t const me = geteuid();
gid_t const myg = getegid();

if (chdir(home))
{
syslog(LOG_CRIT, "Cannot chdir to %s: %s\n",
home, strerror(errno));
}
else if (stat(SCRIPTFILE, &buf) != 0)
{
if (errno != ENOENT)
syslog(LOG_CRIT, "Cannot stat %s/" SCRIPTFILE ": %s\n",
home, strerror(errno));
}
else if (!S_ISREG(buf.st_mode) || !(
((S_IXUSR & buf.st_mode) && (me == 0 || me == buf.st_uid)) ||
((S_IXGRP & buf.st_mode) && (me == 0 || myg == buf.st_gid)) ||
(S_IXOTH & buf.st_mode)))
{
syslog(LOG_INFO, "%s/" SCRIPTFILE " not executable by %d/%d\n",
home, (int)me, (int)myg);
}
else
{
rtc = run_script(ext, xargv, home);
}
}
else
{
syslog(LOG_CRIT, "%smissing %s%s%s\n", argerror,
home ? "" : "HOME env variable",
home || ext ? "" : " and ",
ext ? "" : "-M argument");
}

return rtc;
}

--------------080907080602050203020303
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

--------------080907080602050203020303
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
courier-users mailing list
courie...@lists.sourceforge.net
Unsubscribe: https://lists.sourceforge.net/lists/listinfo/courier-users

--------------080907080602050203020303--

0 new messages