changeset 317:55b7bde95d37

reworked allowed and denied addrs for routes The following refactorings had been made: - allowed_mail_locals + allowed_return_paths -> allowed_senders - not_allowed_mail_locals + not_allowed_return_paths -> denied_senders - allowed_rcpt_domains -> allowed_recipients - not_allowed_rcpt_domains -> denied_recipients The new options allow more consistent and more flexible matching.
author meillo@marmaro.de
date Thu, 28 Apr 2011 09:55:06 +0200
parents d596ac8b5afb
children 290da1595311
files admin/config-transition examples/example.route examples/openssl.route man/masqmail.route.5 src/address.c src/conf.c src/deliver.c src/masqmail.h src/route.c
diffstat 9 files changed, 163 insertions(+), 136 deletions(-) [+]
line wrap: on
line diff
--- a/admin/config-transition	Mon Apr 25 15:17:30 2011 +0200
+++ b/admin/config-transition	Thu Apr 28 09:55:06 2011 +0200
@@ -67,7 +67,7 @@
 "
 
 check["online_detect"] = "conf" SUBSEP "Removed in 0.3.2" SUBSEP "\
-Destilled to online_query. \
+Distilled to online_query. \
 "
 
 check["online_file"] = "conf" SUBSEP "Removed in 0.3.2" SUBSEP "\
@@ -96,6 +96,34 @@
 If pipe is given, pipe will be used, otherwise smtp will be used. \
 "
 
+check["(^|[ 	])allowed_return_paths"] = "route" SUBSEP "Removed in 0.3.2" SUBSEP "\
+Replaced by 'allowed_senders'. \
+"
+
+check["not_allowed_return_paths"] = "route" SUBSEP "Removed in 0.3.2" SUBSEP "\
+Replaced by 'denied_senders'. \
+"
+
+check["(^|[ 	])allowed_mail_locals"] = "route" SUBSEP "Removed in 0.3.2" SUBSEP "\
+Replaced by 'allowed_senders', if neither wildcards nor '@' is used. \
+"
+
+check["not_allowed_mail_locals"] = "route" SUBSEP "Removed in 0.3.2" SUBSEP "\
+Replaced by 'denied_senders', if neither wildcards nor '@' is used. \
+"
+
+check["(^|[ 	])allowed_rcpt_domains"] = "route" SUBSEP "Removed in 0.3.2" SUBSEP "\
+Replaced by 'allowed_recipients', if the values are prepended with \
+'*@', because 'allowed_recipients' matches complete addresses not just \
+domains. \
+"
+
+check["not_allowed_rcpt_domains"] = "route" SUBSEP "Removed in 0.3.2" SUBSEP "\
+Replaced by 'denied_recipients', if the values are prepended with \
+'*@', because 'allowed_recipients' matches complete addresses not just \
+domains. \
+"
+
 # get files
 
 # already covered by the get.* and online_gets.* options in the conf
--- a/examples/example.route	Mon Apr 25 15:17:30 2011 +0200
+++ b/examples/example.route	Thu Apr 28 09:55:06 2011 +0200
@@ -6,10 +6,10 @@
 #
 
 # users that can send mail over this connection:
-# this is a list of the local parts of the original return addresses, as they are
+# this is a list of the envelope sender addresses, as they are
 # configured with your mail client. If not set, anybody may send.
 
-allowed_mail_locals = "okurth"
+allowed_senders = "okurth"
 
 # local_hosts and local_nets will be checked before this.
 # cpwright.com uses the dialup up list of dul.maps.vix.com,
@@ -20,7 +20,7 @@
 # You will find this necessary only if you send mail directly
 # (if mail_host is not set below)
 
-not_allowed_rcpt_domains = "cpwright.com"
+denied_recipients = "*@cpwright.com"
 
 #
 # settings:
--- a/examples/openssl.route	Mon Apr 25 15:17:30 2011 +0200
+++ b/examples/openssl.route	Thu Apr 28 09:55:06 2011 +0200
@@ -14,8 +14,8 @@
 #wrapper="/usr/bin/openssl s_client -quiet -connect mail.gmx.net:465 2>/dev/null"
 
 
-# which addresses are allowed through this route?
-allowed_return_paths = "*@gmx.de;*@gmx.net"
+# which sender addresses are allowed for this route?
+allowed_senders = "*@gmx.de;*@gmx.net"
 
 # the authentication method
 #auth_name = "cram-md5"
--- a/man/masqmail.route.5	Mon Apr 25 15:17:30 2011 +0200
+++ b/man/masqmail.route.5	Thu Apr 28 09:55:06 2011 +0200
@@ -17,62 +17,65 @@
 .SH ROUTE CONDITIONS
 
 .TP
-\fBallowed_mail_locals\fR = \fIlist\fR
+\fBallowed_senders\fR = \fIlist\fR
 
-This is a semicolon `;' separated list of local parts of envelope
-senders (= mail from = return path) which will be allowed
-to send mail through this connection.
-If unset and \fBnot_allowed_mail_locals\fR is also unset, all users are allowed.
+This is a semicolon `;' separated list of envelope sender addresses.
+Messages which have one of these addresses as the return path (= mail
+from) are allowed to use this route
+(if not also in \fBdenied_senders\fR).
 
-.TP
-\fBnot_allowed_mail_locals\fR = \fIlist\fR
+Glob patterns containing `?' and `*' can be used.
+The special item "<>" matches the null sender address
+(eg. failure notices or delivery notifications).
+If the pattern doesn't contain an `@', it is seen as a pattern for the
+local part only.
 
-This is a semicolon `;' separated list of local parts of envelope
-senders (= mail from = return path) which will be not allowed
-to send mail through this connection.
-Local parts in this list will not be allowed to use this route even if they
-are part of \fBallowed_mail_locals\fR (see above).
+Example: \fImeillo;*@*example.org;web*@example.com\fP
+
+(``meillo'' equals ``meillo@*'', i.e. the local part.)
 
 .TP
-\fBallowed_return_paths\fR = \fIlist\fR
+\fBdenied_senders\fR = \fIlist\fR
 
-This is a semicolon `;' separated list of addresses.
+This is a semicolon `;' separated list of envelope sender addresses.
 Messages which have one of these addresses as the return path (=
-envelope sender = mail from) will be used using this route
-(if not also in \fBnot_allowed_return_paths\fR or an item in \fBnot_allowed_mail_locals\fR matches).
+mail from) will not
+be sent using this route (even if also in \fBallowed_senders\fR).
 
-Patterns containing `?' and `*' can be used.
-The special item "<>" matches the null sender address (eg. failure notices or delivery notifications).
+Glob patterns containing `?' and `*' can be used.
+The special item "<>" matches the null sender address
+(eg. failure notices or delivery notifications).
+If the pattern doesn't contain an `@', it is seen as a pattern for the
+local part only.
+
+Example: (see \fIallowed_senders\fP)
 
 .TP
-\fBnot_allowed_return_paths\fR = \fIlist\fR
+\fBallowed_recipients\fR = \fIlist\fR
 
-This is a semicolon `;' separated list of addresses.
-Messages which have one of these addresses as the return path (=
-envelope sender = mail from) will not
-be used using this route (even if also in \fBallowed_return_paths\fR
-or an item in \fBallowed_mail_locals\fR matches).
+A list of envelope recipient addresses where mail can be sent to using
+this route.
+This is for example useful if you use this route configuration when connected to another LAN via ppp.
+Glob patterns containing `?' and `*' can be used.
 
-Patterns containing `?' and `*' can be used.
-The special item "<>" matches the null sender address (eg. failure notices or delivery notifications).
+Example: \fI*@example.org;*@*foo.bar\fP
+
+(See also examples for \fIallowed_senders\fP)
 
 .TP
-\fBallowed_rcpt_domains\fR = \fIlist\fR
+\fBdenied_recipients\fR = \fIlist\fR
 
-A list of recipient domains (of envelope recipients) where mail will be sent to.
-This is for example useful if you use this route configuration when connected to another LAN via ppp.
-Patterns containing `?' and `*' can be used.
-
-.TP
-\fBnot_allowed_rcpt_domains\fR = \fIlist\fR
-
-A list of recipient domains (of envelope recipients) where mail will not be sent to.
+A list of envelope recipient addresses where mail will not be sent to
+using this route.
 This is for example useful if you send mail directly (\fBmail_host\fR is not set)
 and you know of hosts that will not accept mail from you because they use a dialup list
 (eg. \fBhttp://maps.vix.com/dul/\fR).
-If any domain matches both \fBallowed_rcpt_domains\fR and \fBnot_allowed_rcpt_domains\fR,
-mail will not be sent to this domain.
-Patterns containing `?' and `*' can be used.
+\fBdenied_recipients\fR overrules \fBallowed_recipients\fR.
+Glob patterns containing `?' and `*' can be used.
+
+Example: \fI*@spamblocker.example.org\fP
+
+(See also examples for \fIallowed_senders\fP)
 
 .TP
 \fBlast_route\fR = \fIboolean\fR
@@ -80,8 +83,9 @@
 If this is set, a mail which would have been delivered using this route,
 but has failed temporarily, will not be tried to be delivered using the next route.
 
-If you have set up a special route with filters using the lists `allowed_rcpt_domains',
-`allowed_return_paths', and `allowed_mail_locals' or their complements (not_),
+If you have set up a special route with filters using the lists
+`allowed_recipients' and `allowed_senders' or their complements
+(denied_),
 and the mail passing these rules should be delivered using this route only,
 you should set this to `true'.
 Otherwise the mail would be passed to the next route (if any),
--- a/src/address.c	Mon Apr 25 15:17:30 2011 +0200
+++ b/src/address.c	Thu Apr 28 09:55:06 2011 +0200
@@ -17,7 +17,6 @@
 */
 
 #include "masqmail.h"
-#include <fnmatch.h>
 
 address*
 create_address(gchar * path, gboolean is_rfc821)
@@ -186,15 +185,3 @@
 	}
 	return buffer;
 }
-
-gint
-addr_match(address * addr1, address * addr2)
-{
-	int res;
-
-	if ((res = fnmatch(addr1->local_part, addr2->local_part, 0)) == 0) {
-		if ((res = fnmatch(addr1->domain, addr2->domain, FNM_CASEFOLD)) == 0)
-			return 0;
-	}
-	return res;
-}
--- a/src/conf.c	Mon Apr 25 15:17:30 2011 +0200
+++ b/src/conf.c	Thu Apr 28 09:55:06 2011 +0200
@@ -142,8 +142,14 @@
 	return list;
 }
 
+/* Split the addrs at '@' into local_part and domain. Without an '@'
+   everything is local_part. Create address structs, which are put
+   into a list and returned.
+   This funktion is used for lists of addrs containing globbing chars (* and ?).
+   We don't need valid RFC821 addresses here, just patterns to match against.
+*/
 static GList*
-parse_address_list(gchar * line, gboolean read_file)
+parse_address_glob_list(gchar * line, gboolean read_file)
 {
 	GList *plain_list = parse_list(line, read_file);
 	GList *node;
@@ -151,13 +157,32 @@
 
 	foreach(plain_list, node) {
 		gchar *item = (gchar *) (node->data);
-		address *addr = create_address(item, TRUE);
-		if (addr)
-			list = g_list_append(list, addr);
+		char* at;
+		char* p;
+		address *addr = calloc(1, sizeof(address));
+
+		for (p=item+strlen(item)-1; isspace(*p) || *p=='>'; p--) {
+			*p = '\0';
+		}
+		for (p=item; isspace(*p) || *p=='<'; p++) {
+		}
+
+		addr->address = strdup(p);
+		at = strrchr(p, '@');
+		if (at) {
+			*at = '\0';
+			addr->local_part = strdup(p);
+			addr->domain = strdup(at+1);
+		} else {
+			addr->local_part = strdup(p);
+			addr->domain = "";
+		}
+		list = g_list_append(list, addr);
+		DEBUG(6) debugf("parse_address_glob_list: read pattern `%s' `%s'\n",
+		                addr->local_part, addr->domain);
 		g_free(item);
 	}
 	g_list_free(plain_list);
-
 	return list;
 }
 
@@ -648,18 +673,16 @@
 			route->instant_helo = parse_boolean(rval);
 		else if (strcmp(lval, "do_pipelining") == 0)
 			route->do_pipelining = parse_boolean(rval);
-		else if (strcmp(lval, "allowed_return_paths") == 0)
-			route->allowed_return_paths = parse_address_list(rval, TRUE);
-		else if (strcmp(lval, "allowed_mail_locals") == 0)
-			route->allowed_mail_locals = parse_list(rval, TRUE);
-		else if (strcmp(lval, "not_allowed_return_paths") == 0)
-			route->not_allowed_return_paths = parse_address_list(rval, TRUE);
-		else if (strcmp(lval, "not_allowed_mail_locals") == 0)
-			route->not_allowed_mail_locals = parse_list(rval, TRUE);
-		else if (strcmp(lval, "allowed_rcpt_domains") == 0)
-			route->allowed_rcpt_domains = parse_list(rval, TRUE);
-		else if (strcmp(lval, "not_allowed_rcpt_domains") == 0)
-			route->not_allowed_rcpt_domains = parse_list(rval, TRUE);
+
+		else if (strcmp(lval, "allowed_senders") == 0)
+			route->allowed_senders = parse_address_glob_list(rval, TRUE);
+		else if (strcmp(lval, "denied_senders") == 0)
+			route->denied_senders = parse_address_glob_list(rval, TRUE);
+		else if (strcmp(lval, "allowed_recipients") == 0)
+			route->allowed_recipients = parse_address_glob_list(rval, TRUE);
+		else if (strcmp(lval, "denied_recipients") == 0)
+			route->denied_recipients = parse_address_glob_list(rval, TRUE);
+
 		else if (strcmp(lval, "set_h_from_domain") == 0)
 			route->set_h_from_domain = g_strdup(rval);
 		else if (strcmp(lval, "set_h_reply_to_domain") == 0)
@@ -808,10 +831,10 @@
 		g_free(r->wrapper);
 	if (r->helo_name)
 		g_free(r->helo_name);
-	_g_list_free_all(r->allowed_mail_locals);
-	_g_list_free_all(r->not_allowed_mail_locals);
-	_g_list_free_all(r->allowed_rcpt_domains);
-	_g_list_free_all(r->not_allowed_rcpt_domains);
+	_g_list_free_all(r->allowed_senders);
+	_g_list_free_all(r->denied_senders);
+	_g_list_free_all(r->allowed_recipients);
+	_g_list_free_all(r->denied_recipients);
 	if (r->set_h_from_domain)
 		g_free(r->set_h_from_domain);
 	if (r->set_h_reply_to_domain)
--- a/src/deliver.c	Mon Apr 25 15:17:30 2011 +0200
+++ b/src/deliver.c	Thu Apr 28 09:55:06 2011 +0200
@@ -560,21 +560,21 @@
 			continue;
 		}
 
-		/* filter by allowed return paths (= envelope sender) */
-		if (!route_is_allowed_mail_local(route, msgout->msg->return_path)
-		   || !route_is_allowed_return_path(route, msgout->msg->return_path)) {
+		/* filter by allowed envelope sender */
+		if (!route_sender_is_allowed(route, msgout->msg->return_path)) {
 			destroy_msg_out(msgout_cloned);
 			continue;
 		}
 
-		/* filter by allowed rcpt addrs (= envelope rcpts) */
-		GList *rcpt_list_allowed = NULL, *rcpt_list_notallowed = NULL;
-		msg_rcptlist_route(route, msgout_cloned->rcpt_list, &rcpt_list_allowed, &rcpt_list_notallowed);
-
+		/* filter by allowed envelope rcpts */
+		GList* rcpt_list_allowed = NULL;
+		GList* rcpt_list_notallowed = NULL;
+		route_split_rcpts(route, msgout_cloned->rcpt_list, &rcpt_list_allowed, &rcpt_list_notallowed);
 		if (!rcpt_list_allowed) {
 			destroy_msg_out(msgout_cloned);
 			continue;
 		}
+
 		logwrite(LOG_NOTICE, "%s using '%s'\n", msgout->msg->uid, route->name);
 
 		g_list_free(msgout_cloned->rcpt_list);
--- a/src/masqmail.h	Mon Apr 25 15:17:30 2011 +0200
+++ b/src/masqmail.h	Thu Apr 28 09:55:06 2011 +0200
@@ -84,12 +84,10 @@
 	gboolean is_local_net;
 	gboolean last_route;
 
-	GList *allowed_return_paths;
-	GList *not_allowed_return_paths;
-	GList *allowed_mail_locals;
-	GList *not_allowed_mail_locals;
-	GList *allowed_rcpt_domains;
-	GList *not_allowed_rcpt_domains;
+	GList *allowed_senders;
+	GList *denied_senders;
+	GList *allowed_recipients;
+	GList *denied_recipients;
 
 	interface *mail_host;
 	gchar *wrapper;
@@ -390,7 +388,6 @@
 gboolean addr_is_delivered_children(address * addr);
 gboolean addr_is_finished_children(address * addr);
 gchar *addr_string(address * addr);
-gint addr_match(address * addr1, address * addr2);
 
 /* accept.c */
 accept_error accept_message(FILE * in, message * msg, guint flags);
@@ -493,9 +490,8 @@
 gboolean route_strip_msgout(connect_route * route, msg_out * msgout);
 msg_out *route_prepare_msgout(connect_route * route, msg_out * msgout);
 GList *route_msgout_list(connect_route * route, GList * msgout_list);
-gboolean route_is_allowed_return_path(connect_route * route, address * ret_path);
-gboolean route_is_allowed_mail_local(connect_route * route, address * ret_path);
-void msg_rcptlist_route(connect_route * route, GList * rcpt_list, GList ** p_rcpt_list, GList ** p_non_rcpt_list);
+gboolean route_sender_is_allowed(connect_route * route, address * ret_path);
+void route_split_rcpts(connect_route * route, GList * rcpt_list, GList ** p_rcpt_list, GList ** p_non_rcpt_list);
 
 /* tables.c */
 table_pair *create_pair(gchar * key, gpointer value);
--- a/src/route.c	Mon Apr 25 15:17:30 2011 +0200
+++ b/src/route.c	Thu Apr 28 09:55:06 2011 +0200
@@ -238,21 +238,34 @@
 }
 
 static gint
-_g_list_addrcmp(gconstpointer a, gconstpointer b)
+_g_list_addrcmp(gconstpointer pattern, gconstpointer addr)
 {
-	return addr_match((address *) a, (address *) b);
+	int res;
+	address* patternaddr = (address*) pattern;
+	address* stringaddr = (address*) addr;
+
+	DEBUG(6) debugf("_g_list_addrcmp: pattern `%s' `%s' on string `%s' `%s'\n",
+	                patternaddr->local_part, patternaddr->domain,
+	                stringaddr->local_part, stringaddr->domain);
+	/* TODO: check if we should match here dependent on caseless_matching */
+	res = fnmatch(patternaddr->local_part, stringaddr->local_part, 0);
+	if (res != 0) {
+		DEBUG(6) debugf("_g_list_addrcmp: ... failed on local_part\n");
+		return res;
+	}
+	res = fnmatch(patternaddr->domain, stringaddr->domain, FNM_CASEFOLD);
+	DEBUG(6) debugf("_g_list_addrcmp: ... %s\n", (res==0) ? "matched" : "failed on domain");
+	return res;
 }
 
 gboolean
-route_is_allowed_return_path(connect_route * route, address * ret_path)
+route_sender_is_allowed(connect_route * route, address * ret_path)
 {
-	if (route->not_allowed_return_paths != NULL) {
-		if (g_list_find_custom(route->not_allowed_return_paths, ret_path, _g_list_addrcmp) != NULL) {
-			return FALSE;
-		}
+	if (route->denied_senders && g_list_find_custom(route->denied_senders, ret_path, _g_list_addrcmp)) {
+		return FALSE;
 	}
-	if (route->allowed_return_paths != NULL) {
-		if (g_list_find_custom(route->allowed_return_paths, ret_path, _g_list_addrcmp) != NULL) {
+	if (route->allowed_senders) {
+		if (g_list_find_custom(route->allowed_senders, ret_path, _g_list_addrcmp)) {
 			return TRUE;
 		} else {
 			return FALSE;
@@ -261,49 +274,25 @@
 	return TRUE;
 }
 
-static gint
-_g_list_strcmp(gconstpointer a, gconstpointer b)
-{
-	return (gint) strcmp(a, b);
-}
-
-gboolean
-route_is_allowed_mail_local(connect_route * route, address * ret_path)
-{
-	gchar *loc_part = ret_path->local_part;
-
-	if (route->not_allowed_mail_locals != NULL) {
-		if (g_list_find_custom(route->not_allowed_mail_locals, loc_part, _g_list_strcmp) != NULL)
-			return FALSE;
-	}
-	if (route->allowed_mail_locals != NULL) {
-		if (g_list_find_custom(route->allowed_mail_locals, loc_part, _g_list_strcmp) != NULL)
-			return TRUE;
-		else
-			return FALSE;
-	}
-	return TRUE;
-}
-
 /*
    Make lists of matching/not matching rcpts.
    Local domains are NOT regared here, these should be sorted out previously
 */
 void
-msg_rcptlist_route(connect_route * route, GList * rcpt_list, GList ** p_rcpt_list, GList ** p_non_rcpt_list)
+route_split_rcpts(connect_route * route, GList * rcpt_list, GList ** p_rcpt_list, GList ** p_non_rcpt_list)
 {
 	GList *tmp_list = NULL;
 	/* sort out those domains that can be sent over this connection: */
-	if (route->allowed_rcpt_domains) {
-		DEBUG(5) debugf("testing for route->allowed_rcpt_domains\n");
-		split_rcpts(rcpt_list, route->allowed_rcpt_domains, NULL, &tmp_list, p_non_rcpt_list);
+	if (route->allowed_recipients) {
+		DEBUG(5) debugf("testing for route->allowed_recipients\n");
+		split_rcpts(rcpt_list, route->allowed_recipients, NULL, &tmp_list, p_non_rcpt_list);
 	} else {
-		DEBUG(5) debugf("route->allowed_rcpt_domains == NULL\n");
+		DEBUG(5) debugf("route->allowed_recipients == NULL\n");
 		tmp_list = g_list_copy(rcpt_list);
 	}
 
 	/* sort out those domains that cannot be sent over this connection: */
-	split_rcpts(tmp_list, route->not_allowed_rcpt_domains, NULL, p_non_rcpt_list, p_rcpt_list);
+	split_rcpts(tmp_list, route->denied_recipients, NULL, p_non_rcpt_list, p_rcpt_list);
 	g_list_free(tmp_list);
 }