-SRS (Sender Rewriting Scheme) Support (using libsrs_alt)
---------------------------------------------------------------
-See also the main docs, for an alternative native support implementation.
-
-Exim can be built with SRS support using Miles Wilton's
-libsrs_alt library. The current version of the supported
-library is 0.5, there are reports of 1.0 working.
-
-In order to use SRS, you must get a copy of libsrs_alt from
-
-https://opsec.eu/src/srs/
-
-(not the original source, which has disappeared.)
-
-Unpack the tarball, then refer to MTAs/README.EXIM
-to proceed. You need to set
-
-EXPERIMENTAL_SRS_ALT=yes
-
-in your Local/Makefile.
-
-The built-in support, included by SUPPORT_SRS,
-shuold *not* be enabled if you wish to use the libsrs_alt
-version.
-
-The following main-section options become available:
- srs_config string
- srs_hashlength int
- srs_hashmin int
- srs_maxage int
- srs_secrets string
- srs_usehash bool
- srs_usetimestamp bool
-
-The redirect router gains these options (all of type string, unset by default):
- srs
- srs_alias
- srs_condition
- srs_dbinsert
- srs_dbselect
-
-The following variables become available:
- $srs_db_address
- $srs_db_key
- $srs_orig_recipient
- $srs_orig_sender
- $srs_recipient
- $srs_status
-
-The predefined feature-macro _HAVE_SRS will be present.
-Additional delivery log line elements, tagged with "SRS=" will show the srs sender.
-For configuration information see https://github.com/Exim/exim/wiki/SRS .
-
-
-
-
DCC Support
--------------------------------------------------------------
Distributed Checksum Clearinghouse; http://www.rhyolite.com/dcc/
dmarc.o \
imap_utf7.o \
spf.o \
- srs.o \
utf8.o
# Targets for final binaries; the main one has a build number which is
dmarc.o: $(HDRS) pdkim/pdkim.h dmarc.h dmarc.c
imap_utf7.o: $(HDRS) imap_utf7.c
spf.o: $(HDRS) spf.h spf.c
-srs.o: $(HDRS) srs.h srs.c
utf8.o: $(HDRS) utf8.c
# The module containing tables of available lookups, routers, auths, and
# DISABLE_QUEUE_RAMP=yes
# Uncomment the following lines to add SRS (Sender Rewriting Scheme) support
-# using only native facilities. See EXPERIMENTAL_SRS_ALT for an alternative.
+# using only native facilities.
# SUPPORT_SRS=yes
# EXPERIMENTAL_DCC=yes
-# Uncomment the following lines to add SRS (Sender rewriting scheme) support
-# using the implementation in linbsrs_alt.
-# You need to have libsrs_alt installed on your system (srs.mirtol.com).
-# Depending on where it is installed you may have to edit the CFLAGS and
-# LDFLAGS lines.
-
-# EXPERIMENTAL_SRS_ALT=yes
-# CFLAGS += -I/usr/local/include
-# LDFLAGS += -lsrs_alt
-
# Uncomment the following line to add DMARC checking capability, implemented
# using libopendmarc libraries. You must have SPF and DKIM support enabled also.
# Library version libopendmarc-1.4.1-1.fc33.x86_64 (on Fedora 33) is known broken;
#define EXPERIMENTAL_DSN_INFO
#define EXPERIMENTAL_ESMTP_LIMITS
#define EXPERIMENTAL_QUEUEFILE
-#define EXPERIMENTAL_SRS_ALT
/* For developers */
if (*queue_name)
g = string_append(g, 2, US" Q=", queue_name);
-#ifdef EXPERIMENTAL_SRS_ALT
-if(addr->prop.srs_sender)
- g = string_append(g, 3, US" SRS=<", addr->prop.srs_sender, US">");
-#endif
-
/* You might think that the return path must always be set for a successful
delivery; indeed, I did for some time, until this statement crashed. The case
when it is not set is for a delivery to /dev/null which is optimised by not
if(addr->prop.errors_address)
return_path = addr->prop.errors_address;
-#ifdef EXPERIMENTAL_SRS_ALT
-else if (addr->prop.srs_sender)
- return_path = addr->prop.srs_sender;
-#endif
else
return_path = sender_address;
if(addr->prop.errors_address)
return_path = addr->prop.errors_address;
-#ifdef EXPERIMENTAL_SRS_ALT
- else if(addr->prop.srs_sender)
- return_path = addr->prop.srs_sender;
-#endif
else
return_path = sender_address;
#ifdef EXPERIMENTAL_QUEUEFILE
g = string_cat(g, US" Experimental_QUEUEFILE");
#endif
-#if defined(EXPERIMENTAL_SRS_ALT)
- g = string_cat(g, US" Experimental_SRS");
-#endif
g = string_cat(g, US"\n");
g = string_cat(g, US"Lookups (built-in):");
#ifdef SUPPORT_SPF
# include "spf.h"
#endif
-#ifdef EXPERIMENTAL_SRS_ALT
-# include "srs.h"
-#endif
#ifndef DISABLE_DKIM
# include "dkim.h"
#endif
{ "spool_directory", vtype_stringptr, &spool_directory },
{ "spool_inodes", vtype_pinodes, (void *)TRUE },
{ "spool_space", vtype_pspace, (void *)TRUE },
-#ifdef EXPERIMENTAL_SRS_ALT
- { "srs_db_address", vtype_stringptr, &srs_db_address },
- { "srs_db_key", vtype_stringptr, &srs_db_key },
- { "srs_orig_recipient", vtype_stringptr, &srs_orig_recipient },
- { "srs_orig_sender", vtype_stringptr, &srs_orig_sender },
-#endif
-#if defined(EXPERIMENTAL_SRS_ALT) || defined(SUPPORT_SRS)
+#ifdef SUPPORT_SRS
{ "srs_recipient", vtype_stringptr, &srs_recipient },
-#endif
-#ifdef EXPERIMENTAL_SRS_ALT
- { "srs_status", vtype_stringptr, &srs_status },
#endif
{ "thisaddress", vtype_stringptr, &filter_thisaddress },
#endif
BOOL split_spool_directory = FALSE;
BOOL spool_wireformat = FALSE;
-#ifdef EXPERIMENTAL_SRS_ALT
-BOOL srs_usehash = TRUE;
-BOOL srs_usetimestamp = TRUE;
-#endif
BOOL strict_acl_vars = FALSE;
BOOL strip_excess_angle_brackets = FALSE;
BOOL strip_trailing_dot = FALSE;
.extra_headers = NULL,
.remove_headers = NULL,
.variables = NULL,
-#ifdef EXPERIMENTAL_SRS_ALT
- .srs_sender = NULL,
-#endif
.ignore_error = FALSE,
#ifdef SUPPORT_I18N
.utf8_msg = FALSE,
FILE *spool_data_file = NULL;
uschar *spool_directory = US SPOOL_DIRECTORY
"\0<--------------Space to patch spool_directory->";
-#ifdef EXPERIMENTAL_SRS_ALT
-uschar *srs_config = NULL;
-uschar *srs_db_address = NULL;
-uschar *srs_db_key = NULL;
-int srs_hashlength = 6;
-int srs_hashmin = -1;
-int srs_maxage = 31;
-uschar *srs_orig_recipient = NULL;
-uschar *srs_orig_sender = NULL;
-uschar *srs_recipient = NULL;
-uschar *srs_secrets = NULL;
-uschar *srs_status = NULL;
-#endif
#ifdef SUPPORT_SRS
uschar *srs_recipient = NULL;
#endif
extern FILE *spool_data_file; /* handle for -D file */
extern uschar *spool_directory; /* Name of spool directory */
extern BOOL spool_wireformat; /* can write wireformat -D files */
-#ifdef EXPERIMENTAL_SRS_ALT
-extern uschar *srs_config; /* SRS config secret:max age:hash length:use timestamp:use hash */
-extern uschar *srs_db_address; /* SRS db address */
-extern uschar *srs_db_key; /* SRS db key */
-extern int srs_hashlength; /* SRS hash length */
-extern int srs_hashmin; /* SRS minimum hash length */
-extern int srs_maxage; /* SRS max age */
-extern uschar *srs_orig_sender; /* SRS original sender */
-extern uschar *srs_orig_recipient; /* SRS original recipient */
-extern uschar *srs_recipient; /* SRS recipient */
-extern uschar *srs_secrets; /* SRS secrets list */
-extern uschar *srs_status; /* SRS staus */
-extern BOOL srs_usehash; /* SRS use hash flag */
-extern BOOL srs_usetimestamp; /* SRS use timestamp flag */
-#endif
#ifdef SUPPORT_SRS
extern uschar *srs_recipient; /* SRS recipient */
#endif
#ifdef SUPPORT_SPF
builtin_macro_create(US"_HAVE_SPF");
#endif
-#if defined(EXPERIMENTAL_SRS_ALT) || defined(SUPPORT_SRS)
+#ifdef SUPPORT_SRS
builtin_macro_create(US"_HAVE_SRS");
#endif
#ifdef EXPERIMENTAL_ARC
#ifdef EXPERIMENTAL_QUEUEFILE
builtin_macro_create(US"_EXP_QUEUEFILE");
#endif
-#if defined(EXPERIMENTAL_SRS_ALT)
- builtin_macro_create(US"_EXP_SRS");
-#endif
}
#ifdef LOOKUP_SQLITE
{ "sqlite_dbfile", opt_stringptr, {&sqlite_dbfile} },
{ "sqlite_lock_timeout", opt_int, {&sqlite_lock_timeout} },
-#endif
-#ifdef EXPERIMENTAL_SRS_ALT
- { "srs_config", opt_stringptr, {&srs_config} },
- { "srs_hashlength", opt_int, {&srs_hashlength} },
- { "srs_hashmin", opt_int, {&srs_hashmin} },
- { "srs_maxage", opt_int, {&srs_maxage} },
- { "srs_secrets", opt_stringptr, {&srs_secrets} },
- { "srs_usehash", opt_bool, {&srs_usehash} },
- { "srs_usetimestamp", opt_bool, {&srs_usetimestamp} },
#endif
{ "strict_acl_vars", opt_bool, {&strict_acl_vars} },
{ "strip_excess_angle_brackets", opt_bool, {&strip_excess_angle_brackets} },
&addr_prop.remove_headers);
if (rc != OK) return rc;
-#ifdef EXPERIMENTAL_SRS_ALT
-addr_prop.srs_sender = NULL;
-#endif
-
/* Get the fixed or expanded uid under which the command is to run
(initialization ensures that one or the other is set). */
{ "sieve_useraddress", opt_stringptr, LOFF(sieve_useraddress) },
{ "sieve_vacation_directory", opt_stringptr, LOFF(sieve_vacation_directory) },
{ "skip_syntax_errors", opt_bool, LOFF(skip_syntax_errors) },
-#ifdef EXPERIMENTAL_SRS_ALT
- { "srs", opt_stringptr, LOFF(srs) },
- { "srs_alias", opt_stringptr, LOFF(srs_alias) },
- { "srs_condition", opt_stringptr, LOFF(srs_condition) },
- { "srs_dbinsert", opt_stringptr, LOFF(srs_dbinsert) },
- { "srs_dbselect", opt_stringptr, LOFF(srs_dbselect) },
-#endif
{ "syntax_errors_text", opt_stringptr, LOFF(syntax_errors_text) },
{ "syntax_errors_to", opt_stringptr, LOFF(syntax_errors_to) }
};
NULL, /* qualify_domain */
NULL, /* owners */
NULL, /* owngroups */
-#ifdef EXPERIMENTAL_SRS_ALT
- NULL, /* srs */
- NULL, /* srs_alias */
- NULL, /* srs_condition */
- NULL, /* srs_dbinsert */
- NULL, /* srs_dbselect */
-#endif
022, /* modemask */
RDO_REWRITE | RDO_PREPEND_HOME, /* bit_options */
FALSE, /* check_ancestor */
addr_prop.variables = NULL;
tree_dup((tree_node **)&addr_prop.variables, addr->prop.variables);
-#ifdef EXPERIMENTAL_SRS_ALT
-addr_prop.srs_sender = NULL;
-#endif
#ifdef SUPPORT_I18N
addr_prop.utf8_msg = addr->prop.utf8_msg;
addr_prop.utf8_downcvt = addr->prop.utf8_downcvt;
ugid.gid_set = TRUE;
}
-#ifdef EXPERIMENTAL_SRS_ALT
- /* Perform SRS on recipient/return-path as required */
-
- if(ob->srs != NULL)
- {
- BOOL usesrs = TRUE;
-
- if(ob->srs_condition != NULL)
- usesrs = expand_check_condition(ob->srs_condition, "srs_condition expansion failed", NULL);
-
- if(usesrs)
- {
- int srs_action = 0, n_srs;
- uschar *res;
- uschar *usedomain;
-
- /* What are we doing? */
- if(Ustrcmp(ob->srs, "forward") == 0)
- srs_action = 1;
- else if(Ustrcmp(ob->srs, "reverseandforward") == 0)
- {
- srs_action = 3;
-
- if((ob->srs_dbinsert == NULL) ^ (ob->srs_dbselect == NULL))
- return DEFER;
- }
- else if(Ustrcmp(ob->srs, "reverse") == 0)
- srs_action = 2;
-
- /* Reverse SRS */
- if(srs_action & 2)
- {
- srs_orig_recipient = addr->address;
-
- eximsrs_init();
- if(ob->srs_dbselect)
- eximsrs_db_set(TRUE, ob->srs_dbselect);
-/* Comment this out for now...
-// else
-// eximsrs_db_set(TRUE, NULL);
-*/
-
- if((n_srs = eximsrs_reverse(&res, addr->address)) == OK)
- {
- srs_recipient = res;
- DEBUG(D_any)
- debug_printf("SRS (reverse): Recipient '%s' rewritten to '%s'\n", srs_orig_recipient, srs_recipient);
- }
-
- eximsrs_done();
-
- if(n_srs != OK)
- return n_srs;
- }
-
- /* Forward SRS */
- /* No point in actually performing SRS if we are just verifying a recipient */
- if((srs_action & 1) && verify == v_none &&
- (sender_address ? sender_address[0] != 0 : FALSE))
- {
-
- srs_orig_sender = sender_address;
- eximsrs_init();
- if(ob->srs_dbinsert)
- eximsrs_db_set(FALSE, ob->srs_dbinsert);
-/* Comment this out for now...
-// else
-// eximsrs_db_set(FALSE, NULL);
-*/
-
- if (!(usedomain = ob->srs_alias ? expand_string(ob->srs_alias) : NULL))
- usedomain = string_copy(deliver_domain);
-
- if((n_srs = eximsrs_forward(&res, sender_address, usedomain)) == OK)
- {
- addr_prop.srs_sender = res;
- DEBUG(D_any)
- debug_printf("SRS (forward): Sender '%s' rewritten to '%s'\n", srs_orig_sender, res);
- }
-
- eximsrs_done();
-
- if(n_srs != OK)
- return n_srs;
- }
- }
- }
-#endif
-
/* Call the function that interprets redirection data, either inline or from a
file. This is a separate function so that the system filter can use it. It will
run the function in a subprocess if necessary. If qualify_preserve_domain is
uid_t *owners;
gid_t *owngroups;
-#ifdef EXPERIMENTAL_SRS_ALT
- uschar *srs;
- uschar *srs_alias;
- uschar *srs_condition;
- uschar *srs_dbinsert;
- uschar *srs_dbselect;
-#endif
-
int modemask;
int bit_options;
BOOL check_ancestor;
+++ /dev/null
-/*************************************************
-* Exim - an Internet mail transport agent *
-*************************************************/
-
-/* SRS - Sender rewriting scheme support
- (C)2004 Miles Wilton <miles@mirtol.com>
- Copyright (c) The Exim Maintainers 2016 - 2021
-
- SRS Support Version: 1.0a
-
- License: GPL */
-
-#include "exim.h"
-#ifdef EXPERIMENTAL_SRS_ALT
-
-#include <srs_alt.h>
-#include "srs.h"
-
-srs_t *srs = NULL;
-uschar *srs_db_forward = NULL;
-uschar *srs_db_reverse = NULL;
-
-
-/* srs_init just initialises libsrs and creates (if necessary)
- an srs object to use for all srs calls in this instance */
-
-int
-eximsrs_init()
-{
-const uschar *list = srs_config;
-uschar secret_buf[SRS_MAX_SECRET_LENGTH];
-uschar *secret = NULL;
-uschar sbuf[4];
-uschar *sbufp;
-
-/* Check if this instance of Exim has not initialized SRS */
-if (srs == NULL)
- {
- int co = 0;
- int hashlen, maxage;
- BOOL usetimestamp, usehash;
-
- /* Copy config vars */
- hashlen = srs_hashlength;
- maxage = srs_maxage;
- usetimestamp = srs_usetimestamp;
- usehash = srs_usehash;
-
- /* Pass srs_config var (overrides new config vars) */
- co = 0;
- if (srs_config != NULL)
- {
- /* looks like list not expanded, so cannot be tainted */
- secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH);
-
- if ((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))))
- maxage = atoi(sbuf);
-
- if ((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))))
- hashlen = atoi(sbuf);
-
- if ((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))))
- usetimestamp = atoi(sbuf);
-
- if ((sbufp = string_nextinlist(&list, &co, sbuf, sizeof(sbuf))))
- usehash = atoi(sbuf);
- }
-
- if (srs_hashmin == -1)
- srs_hashmin = hashlen;
-
- /* First secret specified in secrets? */
- co = 0;
- list = srs_secrets;
- if (secret == NULL || *secret == '\0')
- /* looks like list not expanded so cannot be tainted */
- if (!(secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH)))
- {
- log_write(0, LOG_MAIN | LOG_PANIC,
- "SRS Configuration Error: No secret specified");
- return DEFER;
- }
-
- /* Check config */
- if (maxage < 0 || maxage > 365)
- {
- log_write(0, LOG_MAIN | LOG_PANIC,
- "SRS Configuration Error: Invalid maximum timestamp age");
- return DEFER;
- }
- if (hashlen < 1 || hashlen > 20 || srs_hashmin < 1 || srs_hashmin > 20)
- {
- log_write(0, LOG_MAIN | LOG_PANIC,
- "SRS Configuration Error: Invalid hash length");
- return DEFER;
- }
-
- if (!(srs = srs_open(secret, Ustrlen(secret), maxage, hashlen, srs_hashmin)))
- {
- log_write(0, LOG_MAIN | LOG_PANIC,
- "Failed to allocate SRS memory");
- return DEFER;
- }
-
- srs_set_option(srs, SRS_OPTION_USETIMESTAMP, usetimestamp);
- srs_set_option(srs, SRS_OPTION_USEHASH, usehash);
-
- /* Extra secrets? */
- /* looks like list not expanded so cannot be tainted */
- while((secret = string_nextinlist(&list, &co, secret_buf, SRS_MAX_SECRET_LENGTH)))
- srs_add_secret(srs, secret,
- Ustrlen(secret) > SRS_MAX_SECRET_LENGTH ? SRS_MAX_SECRET_LENGTH : Ustrlen(secret));
-
- DEBUG(D_any)
- debug_printf("SRS initialized\n");
- }
-
-return OK;
-}
-
-
-int
-eximsrs_done()
-{
-if (srs) srs_close(srs);
-srs = NULL;
-return OK;
-}
-
-
-int
-eximsrs_forward(uschar **result, uschar *orig_sender, uschar *domain)
-{
-char res[512];
-int n;
-
-if ((n = srs_forward(srs, orig_sender, domain, res, sizeof(res))) & SRS_RESULT_FAIL)
- {
- DEBUG(D_any)
- debug_printf("srs_forward failed (%s, %s): %s\n", orig_sender, domain, srs_geterrormsg(n));
- return DEFER;
- }
-
-*result = string_copy(res);
-return OK;
-}
-
-
-int
-eximsrs_reverse(uschar **result, uschar *address)
-{
-char res[512];
-int n;
-
-if ((n = srs_reverse(srs, address, res, sizeof(res))) & SRS_RESULT_FAIL)
- {
- DEBUG(D_any)
- debug_printf("srs_reverse failed (%s): %s\n", address, srs_geterrormsg(n));
- if (n == SRS_RESULT_NOTSRS || n == SRS_RESULT_BADSRS)
- return DECLINE;
- if (n == SRS_RESULT_BADHASH || n == SRS_RESULT_BADTIMESTAMP || n == SRS_RESULT_TIMESTAMPEXPIRED)
- return FAIL;
- return DEFER;
- }
-
-*result = string_copy(res);
-return OK;
-}
-
-
-int
-eximsrs_db_set(BOOL reverse, uschar *srs_db)
-{
-if (reverse)
- srs_db_reverse = (srs_db == NULL ? NULL : string_copy(srs_db));
-else
- srs_db_forward = (srs_db == NULL ? NULL : string_copy(srs_db));
-
-if (srs_set_db_functions(srs, (srs_db_forward ? eximsrs_db_insert : NULL),
- (srs_db_reverse ? eximsrs_db_lookup : NULL)) & SRS_RESULT_FAIL)
- return DEFER;
-
-return OK;
-}
-
-
-srs_result
-eximsrs_db_insert(srs_t *srs, char *data, uint data_len, char *result, uint result_len)
-{
-uschar *res;
-uschar buf[64];
-
-if (srs_db_forward == NULL)
- return SRS_RESULT_DBERROR;
-
-srs_db_address = string_copyn(data, data_len);
-if (srs_generate_unique_id(srs, srs_db_address, buf, 64) & SRS_RESULT_FAIL)
- return SRS_RESULT_DBERROR;
-
-srs_db_key = string_copyn(buf, 16);
-
-if ((res = expand_string(srs_db_forward)) == NULL)
- return SRS_RESULT_DBERROR;
-
-if (result_len < 17)
- return SRS_RESULT_DBERROR;
-
-Ustrncpy(result, srs_db_key, result_len);
-
-return SRS_RESULT_OK;
-}
-
-
-srs_result
-eximsrs_db_lookup(srs_t *srs, char *data, uint data_len, char *result, uint result_len)
-{
-uschar *res;
-
-if (srs_db_reverse == NULL)
- return SRS_RESULT_DBERROR;
-
-srs_db_key = string_copyn(data, data_len);
-if ((res = expand_string(srs_db_reverse)) == NULL)
- return SRS_RESULT_DBERROR;
-
-if (Ustrlen(res) >= result_len)
- return SRS_RESULT_ADDRESSTOOLONG;
-
-strncpy(result, res, result_len);
-
-return SRS_RESULT_OK;
-}
-
-
-#endif
-
+++ /dev/null
-/*************************************************
-* Exim - an Internet mail transport agent *
-*************************************************/
-
-/* SRS - Sender rewriting scheme support
- ©2004 Miles Wilton <miles@mirtol.com>
- Copyright (c) The Exim Maintainers 2021
- License: GPL */
-
-#ifndef __SRS_H__
-
-#define __SRS_H__ 1
-
-#ifdef EXPERIMENTAL_SRS_ALT
-
-#include "mytypes.h"
-#include <srs_alt.h>
-
-int eximsrs_init();
-int eximsrs_done();
-int eximsrs_forward(uschar **result, uschar *orig_sender, uschar *domain);
-int eximsrs_reverse(uschar **result, uschar *address);
-int eximsrs_db_set(BOOL reverse, uschar *srs_db);
-
-srs_result eximsrs_db_insert(srs_t *srs, char *data, uint data_len, char *result, uint result_len);
-srs_result eximsrs_db_lookup(srs_t *srs, char *data, uint data_len, char *result, uint result_len);
-
-#endif
-
-#endif
uschar *remove_headers; /* list of those to remove */
void *variables; /* router-vasriables */
-#ifdef EXPERIMENTAL_SRS_ALT
- uschar *srs_sender; /* Change return path when delivering */
-#endif
BOOL ignore_error:1; /* ignore delivery error */
#ifdef SUPPORT_I18N
BOOL utf8_msg:1; /* requires SMTPUTF8 processing */
addr_list = addr->next;
fprintf(fp, "%s", CS addr->address);
-#ifdef EXPERIMENTAL_SRS_ALT
- if(addr->prop.srs_sender)
- fprintf(fp, " [srs = %s]", addr->prop.srs_sender);
-#endif
/* If the address is a duplicate, show something about it. */