# HG changeset patch # User markus schnalke # Date 1329564912 -3600 # Node ID a408411ff8dfb19f1449f70d5d8722accdcd76ef # Parent 13c9e0969054ddb7155e9a7a156b3bb5c2213058 Added a glob-pattern aliasing facility. One use-case is virtual hosting another catch-all maildrops, but you may use it as a more flexible aliasing mechanism as well. diff -r 13c9e0969054 -r a408411ff8df man/masqmail.aliases.5 --- a/man/masqmail.aliases.5 Sat Feb 18 11:43:06 2012 +0100 +++ b/man/masqmail.aliases.5 Sat Feb 18 12:35:12 2012 +0100 @@ -7,21 +7,44 @@ .SH DESCRIPTION This man page describes the format of the masqmail alias file. -Its usual location is \fI/etc/aliases\fR. +It's usual location is \fI/etc/aliases\fR. + +There exists also a variant of this format for glob patterns. +It's used with the \fIglobalias_file\fP config option. + +The difference between the two formats are only on the left-hand side. +A normal alias file has a local_part there that gets string-compared +against the local part; +whereas a glob alias file has a glob pattern that is matched against +the whole address. The right-hand side of the two aliasing kinds +has the same format. .SH FILE FORMAT -The alias file consists of lines of the form: +Normal alias files consist of lines of the form: + +.RS local_part: item1, item2, ... +.RE + +Glob-pattern alias files consist of lines of the form: + +.RS +glob_pattern: item1, item2, ... +.RE + Items can be surrounded by double quotes `"'. If within the quotes other quotes are needed for an address they can be escaped with a leading backslash `\\'. -A leading backslash `\\' indicates that this address shall not be further expanded. +A leading backslash `\\' indicates that this address shall not be +further expanded. -A leading pipe symbol `|' indicates that the item shall be treated as a pipe command. -The content of the message will then be sent to the standard input of the command. +A leading pipe symbol `|' indicates that the item shall be treated as a +pipe command. +The content of the message will then be sent to the standard input of the +command. The command will run under the user id and group id masqmail is running as. If quotes are needed, the pipe symbol must appear within the quotes. @@ -32,11 +55,15 @@ any alias which matches one of the recipient addresses, the change will have effect next time a delivery is attemped. -There is no need to restart masqmail or run any command when the alias file has been changed. +There is no need to restart masqmail or run any command when the alias +file has been changed. (`masqmail -bi' is a no-op.) .SH EXAMPLE +A normal alias file: + +.RS .nf # postmaster is required by RFC 2821 postmaster: root @@ -50,6 +77,28 @@ # pass mail to a script foo: |/usr/bin/foo .fi +.RE + + +A glob-pattern alias file: + +.RS +.nf +# the postmaster for any domain on this host +postmaster@*: ken + +# split virtual domains +info@foo.example.org: doug +info@bar.example.org: rob + +# the order of entries is important +# this must be before the catch-all line +list\-*@example.org: |/path/to/some/script + +# catch-all address forwarded to extern +*@example.org: brian@other.host.net +.fi +.RE .SH AUTHOR @@ -57,8 +106,10 @@ Masqmail was written by Oliver Kurth. It is now maintained by Markus Schnalke . -You will find the newest version of masqmail at \fBhttp://marmaro.de/prog/masqmail/\fR. -There is also a mailing list, you will find information about it at masqmail's main site. +You will find the newest version of masqmail at +\fBhttp://marmaro.de/prog/masqmail/\fR. +There is also a mailing list, you will find information about +it at masqmail's main site. .SH BUGS diff -r 13c9e0969054 -r a408411ff8df man/masqmail.conf.5 --- a/man/masqmail.conf.5 Sat Feb 18 11:43:06 2012 +0100 +++ b/man/masqmail.conf.5 Sat Feb 18 12:35:12 2012 +0100 @@ -276,6 +276,22 @@ Default: (i.e. no aliasing is done) .TP +\fBglobalias_file = \fIfile\fR + +Set this to the location of a glob-pattern alias file. +This kind of aliasing matches glob patterns against full email addresses, +not strings against local parts like in normal aliasing. +You can use this to handle catch-all maildrops (``*@example.org'') +and to split between virtual hosts on a single machine +(e.g. ``info@foo.ex.org'' and ``info@bar.ex.org''). + +Glob aliasing is done before normal aliasing. +If you have both kinds, glob and normal aliasing, then the results of the +glob aliasing may be expanded further by the normal aliasing mechanism. + +Default: (i.e. no glob aliasing is done) + +.TP \fBcaseless_matching = \fIboolean\fR If this is set, aliasing and the matching for \fBlocal_addresses\fP and diff -r 13c9e0969054 -r a408411ff8df src/alias.c --- a/src/alias.c Sat Feb 18 11:43:06 2012 +0100 +++ b/src/alias.c Sat Feb 18 12:35:12 2012 +0100 @@ -104,11 +104,28 @@ return list; } +static int +globaliascmp(const char *pattern, const char *addr) +{ + if (conf.localpartcmp==strcasecmp) { + return fnmatch(pattern, addr, FNM_CASEFOLD); + } else if (strncasecmp(addr, "postmaster", 10)==0) { + /* + ** postmaster must always be matched caseless + ** see RFC 822 and RFC 5321 + */ + return fnmatch(pattern, addr, FNM_CASEFOLD); + } else { + /* case-sensitive */ + return fnmatch(pattern, addr, 0); + } +} + /* ** addr is assumed to be local and no pipe address nor not-to-expand */ static GList* -expand_one(GList *alias_table, address *addr) +expand_one(GList *alias_table, address *addr, int doglob) { GList *val_list; GList *val_node; @@ -117,24 +134,33 @@ gchar *val; /* expand the local alias */ - DEBUG(6) debugf("alias: '%s' is local and will get expanded\n", addr->local_part); + DEBUG(6) debugf("alias: '%s' is local and will get expanded\n", + doglob ? addr->address : addr->local_part); - if (strcasecmp(addr->local_part, "postmaster") == 0) { + if (doglob) { + val = (gchar *) table_find_func(alias_table, addr->address, + globaliascmp); + + } else if (strcasecmp(addr->local_part, "postmaster") == 0) { /* ** postmaster must always be matched caseless ** see RFC 822 and RFC 5321 */ - val = (gchar *) table_find_func(alias_table, addr->local_part, strcasecmp); + val = (gchar *) table_find_func(alias_table, addr->local_part, + strcasecmp); } else { - val = (gchar *) table_find_func(alias_table, addr->local_part, conf.localpartcmp); + val = (gchar *) table_find_func(alias_table, addr->local_part, + conf.localpartcmp); } if (!val) { - DEBUG(5) debugf("alias: '%s' is fully expanded, hence completed\n", - addr->local_part); + DEBUG(5) debugf("alias: '%s' is fully expanded, hence " + "completed\n", + doglob ? addr->address : addr->local_part); return g_list_append(NULL, addr); } - DEBUG(5) debugf("alias: '%s' -> '%s'\n", addr->local_part, val); + DEBUG(5) debugf("alias: '%s' -> '%s'\n", + doglob ? addr->address : addr->local_part, val); val_list = parse_list(val); alias_list = NULL; @@ -149,7 +175,7 @@ alias_addr = create_address_qualified(val+1, TRUE, conf.host_name); g_free(val); DEBUG(6) debugf("alias: address generated: '%s'\n", - alias_addr->local_part); + alias_addr->address); alias_list = g_list_append(alias_list, alias_addr); continue; } @@ -168,8 +194,8 @@ g_free(val); if (!addr_is_local(alias_addr)) { - DEBUG(5) debugf("alias: '%s@%s' is non-local, hence completed\n", - alias_addr->local_part, alias_addr->domain); + DEBUG(5) debugf("alias: '%s' is non-local, hence completed\n", + alias_addr->address); alias_list = g_list_append(alias_list, alias_addr); continue; } @@ -186,7 +212,7 @@ /* recurse */ DEBUG(6) debugf("alias: >>\n"); - alias_node = expand_one(alias_table, alias_addr); + alias_node = expand_one(alias_table, alias_addr, doglob); DEBUG(6) debugf("alias: <<\n"); if (alias_node) { alias_list = g_list_concat(alias_list, alias_node); @@ -199,7 +225,8 @@ } GList* -alias_expand(GList *alias_table, GList *rcpt_list, GList *non_rcpt_list) +alias_expand(GList *alias_table, GList *rcpt_list, GList *non_rcpt_list, + int doglob) { GList *rcpt_node = NULL; GList *alias_list = NULL; @@ -214,14 +241,14 @@ addr = (address *) (rcpt_node->data); if (addr_is_local(addr)) { DEBUG(5) debugf("alias: (orig rcpt addr) expand local '%s'\n", - addr->local_part); - alias_list = expand_one(alias_table, addr); + doglob ? addr->address : addr->local_part); + alias_list = expand_one(alias_table, addr, doglob); if (alias_list) { done_list = g_list_concat(done_list, alias_list); } } else { - DEBUG(5) debugf("alias: (orig rcpt addr) don't expand non-local '%s@%s'\n", - addr->local_part, addr->domain); + DEBUG(5) debugf("alias: (orig rcpt addr) don't expand non-local '%s'\n", + addr->address); done_list = g_list_append(done_list, addr); } } diff -r 13c9e0969054 -r a408411ff8df src/conf.c --- a/src/conf.c Sat Feb 18 11:43:06 2012 +0100 +++ b/src/conf.c Sat Feb 18 12:35:12 2012 +0100 @@ -472,6 +472,8 @@ conf.do_relay = parse_boolean(rval); else if (strcmp(lval, "alias_file") == 0) { conf.alias_file = g_strdup(rval); + } else if (strcmp(lval, "globalias_file") == 0) { + conf.globalias_file = g_strdup(rval); } else if (strcmp(lval, "caseless_matching") == 0) { conf.localpartcmp = parse_boolean(rval) ? strcasecmp : strcmp; } else if (strcmp(lval, "mbox_default") == 0) { diff -r 13c9e0969054 -r a408411ff8df src/deliver.c --- a/src/deliver.c Sat Feb 18 11:43:06 2012 +0100 +++ b/src/deliver.c Sat Feb 18 12:35:12 2012 +0100 @@ -774,6 +774,7 @@ GList *remote_msgout_list = NULL; GList *msgout_node; GList *alias_table = NULL; + GList *globalias_table = NULL; gboolean ok = TRUE; /* create msgout_list */ @@ -782,6 +783,9 @@ msgout_list = g_list_append(msgout_list, create_msg_out(msg)); } + if (conf.globalias_file) { + globalias_table = table_read(conf.globalias_file, ':'); + } if (conf.alias_file) { alias_table = table_read(conf.alias_file, ':'); } @@ -808,9 +812,19 @@ logwrite(LOG_ALERT, "invalid log_user address `%s', ignoring\n", conf.log_user); } } + if (globalias_table) { + GList *globaliased_rcpt_list; + globaliased_rcpt_list = alias_expand(globalias_table, + rcpt_list, + msgout->msg->non_rcpt_list, 1); + g_list_free(rcpt_list); + rcpt_list = globaliased_rcpt_list; + } if (alias_table) { GList *aliased_rcpt_list; - aliased_rcpt_list = alias_expand(alias_table, rcpt_list, msgout->msg->non_rcpt_list); + aliased_rcpt_list = alias_expand(alias_table, + rcpt_list, + msgout->msg->non_rcpt_list, 0); g_list_free(rcpt_list); rcpt_list = aliased_rcpt_list; } @@ -838,6 +852,9 @@ if (alias_table) { destroy_table(alias_table); } + if (globalias_table) { + destroy_table(globalias_table); + } /* process local/remote msgout lists -> delivery */ diff -r 13c9e0969054 -r a408411ff8df src/masqmail.h --- a/src/masqmail.h Sat Feb 18 11:43:06 2012 +0100 +++ b/src/masqmail.h Sat Feb 18 12:35:12 2012 +0100 @@ -165,6 +165,7 @@ gchar *alias_file; int (*localpartcmp) (const char *, const char *); + gchar *globalias_file; GList *perma_routes; GList *query_routes; /* list of pairs which point to lists */ @@ -331,7 +332,8 @@ /* alias.c*/ gboolean addr_is_local(address *addr); -GList *alias_expand(GList *alias_table, GList *rcpt_list, GList *non_rcpt_list); +GList *alias_expand(GList *alias_table, GList *rcpt_list, GList *non_rcpt_list, + int doglob); /* child.c */ int child(const char *command);