Hi tech@, Below is a diff to teach smtpd how to rewrite the sender of outgoing messages *at the SMTP level* (no From: rewrite).
# all outoging mails originate from b...@example.com accept for all relay as "b...@example.com" # local domain is preserved, user is rewritten accept for all relay as "bleh" # local user is preserved, domain is rewritten accept for all relay as "@example.com" Again, this takes place at the SMTP level, it does not allow the rewriting of messages and headers, but makes it possible for smtpd to fake the domain advertised with MAIL FROM and stop being rejected by strict hosts. As a side change, I did a minor change so that: accept for local deliver to mbox user "vdom" becomes: accept for local deliver to mbox as "vdom" Please report regressions ;) Index: lka_session.c =================================================================== RCS file: /cvs/src/usr.sbin/smtpd/lka_session.c,v retrieving revision 1.6 diff -u -p -r1.6 lka_session.c --- lka_session.c 21 May 2011 18:11:40 -0000 1.6 +++ lka_session.c 25 May 2011 21:46:50 -0000 @@ -392,6 +392,10 @@ lka_session_deliver(struct lka_session * break; } } + else if (new_ep->delivery.type == D_MTA) { + if (ep->rule.r_as) + new_ep->delivery.from = *ep->rule.r_as; + } TAILQ_INSERT_TAIL(&lks->deliverylist, new_ep, entry); } Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/smtpd/parse.y,v retrieving revision 1.75 diff -u -p -r1.75 parse.y --- parse.y 22 May 2011 21:03:14 -0000 1.75 +++ parse.y 25 May 2011 21:46:51 -0000 @@ -111,18 +111,19 @@ typedef struct { struct cond *cond; char *string; struct host *host; + struct mailaddr *maddr; } v; int lineno; } YYSTYPE; %} -%token QUEUE INTERVAL SIZE LISTEN ON ALL PORT EXPIRE +%token AS QUEUE INTERVAL SIZE LISTEN ON ALL PORT EXPIRE %token MAP TYPE HASH LIST SINGLE SSL SMTPS CERTIFICATE %token DNS DB PLAIN EXTERNAL DOMAIN CONFIG SOURCE %token RELAY VIA DELIVER TO MAILDIR MBOX HOSTNAME %token ACCEPT REJECT INCLUDE NETWORK ERROR MDA FROM FOR -%token ARROW ENABLE AUTH TLS LOCAL VIRTUAL USER TAG ALIAS +%token ARROW ENABLE AUTH TLS LOCAL VIRTUAL TAG ALIAS %token <v.string> STRING %token <v.number> NUMBER %type <v.map> map @@ -130,6 +131,7 @@ typedef struct { %type <v.cond> condition %type <v.tv> interval %type <v.object> mapref +%type <v.maddr> relay_as %type <v.string> certname user tag on alias %% @@ -845,7 +847,7 @@ conditions : condition { | '{' condition_list '}' ; -user : USER STRING { +user : AS STRING { struct passwd *pw; pw = getpwnam($2); @@ -859,6 +861,76 @@ user : USER STRING { | /* empty */ { $$ = NULL; } ; +relay_as : AS STRING { + struct mailaddr maddr, *maddrp; + char *p; + + bzero(&maddr, sizeof (maddr)); + + p = strrchr($2, '@'); + if (p == NULL) { + if (strlcpy(maddr.user, $2, sizeof (maddr.user)) + >= sizeof (maddr.user)) + yyerror("user-part too long"); + free($2); + YYERROR; + } + else { + if (p == $2) { + /* domain only */ + p++; + if (strlcpy(maddr.domain, p, sizeof (maddr.domain)) + >= sizeof (maddr.domain)) { + yyerror("user-part too long"); + free($2); + YYERROR; + } + } + else { + *p++ = '\0'; + if (strlcpy(maddr.user, $2, sizeof (maddr.user)) + >= sizeof (maddr.user)) { + yyerror("user-part too long"); + free($2); + YYERROR; + } + if (strlcpy(maddr.domain, p, sizeof (maddr.domain)) + >= sizeof (maddr.domain)) { + yyerror("domain-part too long"); + free($2); + YYERROR; + } + } + } + + if (maddr.user[0] == '\0' && maddr.domain[0] == '\0') { + yyerror("invalid 'relay as' value"); + free($2); + YYERROR; + } + + if (maddr.domain[0] == '\0') { + if (strlcpy(maddr.domain, conf->sc_hostname, + sizeof (maddr.domain)) + >= sizeof (maddr.domain)) { + fatalx("domain too long"); + yyerror("domain-part too long"); + free($2); + YYERROR; + } + } + + maddrp = calloc(1, sizeof (*maddrp)); + if (maddrp == NULL) + fatal("calloc"); + *maddrp = maddr; + free($2); + + $$ = maddrp; + } + | /* empty */ { $$ = NULL; } + ; + action : DELIVER TO MAILDIR user { rule->r_user = $4; rule->r_action = A_MAILDIR; @@ -892,11 +964,13 @@ action : DELIVER TO MAILDIR user { fatal("command too long"); free($4); } - | RELAY { + | RELAY relay_as { rule->r_action = A_RELAY; + rule->r_as = $2; } - | RELAY VIA STRING port ssl certname credentials { + | RELAY VIA STRING port ssl certname credentials relay_as { rule->r_action = A_RELAYVIA; + rule->r_as = $8; if ($5 == 0 && ($6 != NULL || $7)) { yyerror("error: must specify tls, smtps, or ssl"); @@ -1110,6 +1184,7 @@ lookup(char *s) { "accept", ACCEPT }, { "alias", ALIAS }, { "all", ALL }, + { "as", AS }, { "auth", AUTH }, { "certificate", CERTIFICATE }, { "config", CONFIG }, @@ -1149,7 +1224,6 @@ lookup(char *s) { "tls", TLS }, { "to", TO }, { "type", TYPE }, - { "user", USER }, { "via", VIA }, { "virtual", VIRTUAL }, }; Index: smtpd.h =================================================================== RCS file: /cvs/src/usr.sbin/smtpd/smtpd.h,v retrieving revision 1.226 diff -u -p -r1.226 smtpd.h --- smtpd.h 21 May 2011 19:57:34 -0000 1.226 +++ smtpd.h 25 May 2011 21:46:51 -0000 @@ -324,6 +324,7 @@ struct rule { } r_value; char *r_user; + struct mailaddr *r_as; objid_t r_amap; time_t r_qexpire; }; @@ -376,6 +377,7 @@ struct delivery_mda { struct delivery_mta { struct relayhost relay; + struct mailaddr relay_as; }; struct delivery { -- Gilles Chehade http://www.poolp.org