aboutsummaryrefslogtreecommitdiffstats
path: root/smtpd
diff options
context:
space:
mode:
authorEric Faurot <eric@faurot.net>2012-11-14 16:52:03 +0100
committerEric Faurot <eric@faurot.net>2012-11-14 16:52:03 +0100
commit7e908dc30b1f664a74a82894cce8b07d20ddf014 (patch)
treebf1880f4fb867e8c873ee1f6eb91681b04173dc2 /smtpd
parentfix regress makefile (diff)
parentMerge branch 'master' of ssh.poolp.org:/git/opensmtpd (diff)
downloadOpenSMTPD-7e908dc30b1f664a74a82894cce8b07d20ddf014.tar.xz
OpenSMTPD-7e908dc30b1f664a74a82894cce8b07d20ddf014.zip
Merge branch 'master' into portable
Conflicts: smtpd/parse.y
Diffstat (limited to 'smtpd')
-rw-r--r--smtpd/envelope.c6
-rw-r--r--smtpd/lka_session.c309
-rw-r--r--smtpd/map.c29
-rw-r--r--smtpd/map_file.c6
-rw-r--r--smtpd/mda.c10
-rw-r--r--smtpd/parse.y52
-rw-r--r--smtpd/queue.c56
-rw-r--r--smtpd/queue_backend.c32
-rw-r--r--smtpd/queue_fsqueue.c42
-rw-r--r--smtpd/queue_ram.c26
-rw-r--r--smtpd/ruleset.c4
-rw-r--r--smtpd/smtpctl.c15
-rw-r--r--smtpd/smtpd.c4
-rw-r--r--smtpd/smtpd.conf.531
-rw-r--r--smtpd/smtpd.h70
-rw-r--r--smtpd/user_pwd.c8
-rw-r--r--smtpd/util.c2
17 files changed, 360 insertions, 342 deletions
diff --git a/smtpd/envelope.c b/smtpd/envelope.c
index eccec8af..f56b32e4 100644
--- a/smtpd/envelope.c
+++ b/smtpd/envelope.c
@@ -345,8 +345,8 @@ envelope_ascii_load(enum envelope_field field, struct envelope *ep, char *buf)
return ascii_load_string(ep->agent.mda.buffer, buf,
sizeof ep->agent.mda.buffer);
case EVP_MDA_USER:
- return ascii_load_string(ep->agent.mda.user, buf,
- sizeof ep->agent.mda.user);
+ return ascii_load_string(ep->agent.mda.user.username, buf,
+ sizeof ep->agent.mda.user.username);
case EVP_MTA_RELAY_HOST:
return ascii_load_string(ep->agent.mta.relay.hostname, buf,
sizeof ep->agent.mta.relay.hostname);
@@ -411,7 +411,7 @@ envelope_ascii_dump(enum envelope_field field, struct envelope *ep,
case EVP_MDA_BUFFER:
return ascii_dump_string(ep->agent.mda.buffer, buf, len);
case EVP_MDA_USER:
- return ascii_dump_string(ep->agent.mda.user, buf, len);
+ return ascii_dump_string(ep->agent.mda.user.username, buf, len);
case EVP_MTA_RELAY_HOST:
return ascii_dump_string(ep->agent.mta.relay.hostname,
buf, len);
diff --git a/smtpd/lka_session.c b/smtpd/lka_session.c
index ab00c357..aa7080e2 100644
--- a/smtpd/lka_session.c
+++ b/smtpd/lka_session.c
@@ -74,6 +74,18 @@ static const char * mailaddr_tag(const struct mailaddr *);
static struct tree sessions = SPLAY_INITIALIZER(&sessions);
+#define MAXTOKENLEN 128
+static char *tokens[] = {
+ "sender.user",
+ "sender.domain",
+ "user.username",
+ "user.directory",
+ "dest.user",
+ "dest.domain",
+ "rcpt.user",
+ "rcpt.domain"
+};
+
void
lka_session(struct submit_status *ss)
{
@@ -198,7 +210,8 @@ lka_expand(struct lka_session *lks, struct rule *rule, struct expandnode *xn)
struct forward_req fwreq;
struct envelope ep;
struct expandnode node;
- struct passwd *pw;
+ struct user_backend *ub;
+ struct userinfo u;
int r;
if (xn->depth >= EXPAND_DEPTH) {
@@ -294,8 +307,9 @@ lka_expand(struct lka_session *lks, struct rule *rule, struct expandnode *xn)
break;
}
- pw = getpwnam(xn->u.user);
- if (pw == NULL) {
+ bzero(&u, sizeof (u));
+ ub = user_backend_lookup(USER_PWD);
+ if (! ub->getbyname(&u, xn->u.user)) {
log_debug("debug: lka_expand: user-part does not match system user");
lks->flags |= F_ERROR;
lks->ss.code = 530;
@@ -344,6 +358,7 @@ lka_find_ancestor(struct expandnode *xn, enum expand_type type)
static void
lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn)
{
+ struct user_backend *ub;
struct envelope *ep;
struct expandnode *xn2;
const char *tag;
@@ -376,13 +391,21 @@ lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn)
/* set username */
if ((xn->type == EXPAND_FILTER || xn->type == EXPAND_FILENAME)
&& xn->alias) {
- strlcpy(ep->agent.mda.user, SMTPD_USER,
- sizeof (ep->agent.mda.user));
+ strlcpy(ep->agent.mda.user.username, SMTPD_USER,
+ sizeof (ep->agent.mda.user.username));
}
else {
xn2 = lka_find_ancestor(xn, EXPAND_USERNAME);
- strlcpy(ep->agent.mda.user, xn2->u.user,
- sizeof (ep->agent.mda.user));
+ strlcpy(ep->agent.mda.user.username, xn2->u.user,
+ sizeof (ep->agent.mda.user.username));
+ }
+
+ ub = user_backend_lookup(USER_PWD);
+ if (! ub->getbyname(&ep->agent.mda.user, ep->agent.mda.user.username)) {
+ lks->flags |= F_ERROR;
+ lks->ss.code = 451;
+ free(ep);
+ return;
}
if (xn->type == EXPAND_FILENAME) {
@@ -414,8 +437,8 @@ lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn)
sizeof(ep->agent.mda.buffer), ep)) {
lks->flags |= F_ERROR;
lks->ss.code = 451;
- log_warnx("warn: format string result too long while "
- " expanding for user %s", ep->agent.mda.user);
+ log_warnx("warn: format string error while"
+ " expanding for user %s", ep->agent.mda.user.username);
free(ep);
return;
}
@@ -427,127 +450,177 @@ lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn)
TAILQ_INSERT_TAIL(&lks->deliverylist, ep, entry);
}
+
static size_t
-lka_expand_format(char *buf, size_t len, const struct envelope *ep)
+lka_expand_token(char *dest, size_t len, const char *token, const struct envelope *ep)
{
- char *p, *pbuf;
- size_t ret, lret = 0;
- struct user_backend *ub;
- struct mta_user u;
- char lbuffer[MAX_RULEBUFFER_LEN];
- char tmpbuf[MAX_RULEBUFFER_LEN];
-
- if (len < sizeof lbuffer)
+ char rtoken[MAXTOKENLEN];
+ const char *string;
+ char *lbracket, *rbracket, *content, *sep;
+ ssize_t i;
+ ssize_t begoff, endoff;
+ const char *errstr;
+
+ begoff = endoff = 0;
+
+ if (strlcpy(rtoken, token, sizeof rtoken) >= sizeof rtoken)
return 0;
- bzero(lbuffer, sizeof (lbuffer));
- pbuf = lbuffer;
-
- ret = 0;
- for (p = buf; *p != '\0' && ret < sizeof (lbuffer);
- ++p, len -= lret, pbuf += lret, ret += lret) {
- if (p == buf && *p == '~') {
- if (*(p + 1) == '/' || *(p + 1) == '\0') {
-
- bzero(&u, sizeof (u));
- ub = user_backend_lookup(USER_PWD);
- if (! ub->getbyname(&u, ep->agent.mda.user))
- return 0;
-
- lret = strlcat(pbuf, u.directory, len);
- if (lret >= len)
- return 0;
- continue;
- }
-
- if (*(p + 1) != '/') {
- char username[MAXLOGNAME];
- char *delim;
-
- lret = strlcpy(username, p + 1,
- sizeof(username));
- if (lret >= sizeof(username))
- return 0;
-
- delim = strchr(username, '/');
- if (delim == NULL)
- goto copy;
- *delim = '\0';
-
- bzero(&u, sizeof (u));
- ub = user_backend_lookup(USER_PWD);
- if (! ub->getbyname(&u, username))
- return 0;
-
- lret = strlcat(pbuf, u.directory, len);
- if (lret >= len)
- return 0;
- p += strlen(username);
- continue;
- }
+ /* token[x[:y]] -> extracts optional x and y, converts into offsets */
+ if ((lbracket = strchr(rtoken, '[')) && (rbracket = strchr(rtoken, ']'))) {
+ /* ] before [ ... or empty */
+ if (rbracket < lbracket || rbracket - lbracket <= 1)
+ return 0;
+ *lbracket = *rbracket = '\0';
+ content = lbracket + 1;
+
+ if ((sep = strchr(content, ':')) == NULL)
+ begoff = strtonum(content, -EXPAND_BUFFER, EXPAND_BUFFER, &errstr);
+ else {
+ *sep = '\0';
+ if (content != sep)
+ begoff = strtonum(content, -EXPAND_BUFFER, EXPAND_BUFFER, &errstr);
+ sep++;
+ if (*sep) {
+ if (errstr == NULL)
+ endoff = strtonum(sep, -EXPAND_BUFFER, EXPAND_BUFFER,
+ &errstr);
+ if (endoff == 0)
+ return 0;
+ }
+ }
+ if (errstr)
+ return 0;
+ }
+
+ /* token -> searches token in table and maps to expand string */
+ for (i = 0; i < (int)nitems(tokens); ++i)
+ if (strcasecmp(rtoken, tokens[i]) == 0)
+ break;
+ if (i == (int)nitems(tokens))
+ return 0;
+ if (! strcasecmp("sender.user", tokens[i]))
+ string = ep->sender.user;
+ else if (! strcasecmp("sender.domain", tokens[i]))
+ string = ep->sender.domain;
+ else if (! strcasecmp("user.username", tokens[i]))
+ string = ep->agent.mda.user.username;
+ else if (! strcasecmp("user.directory", tokens[i]))
+ string = ep->agent.mda.user.directory;
+ else if (! strcasecmp("dest.user", tokens[i]))
+ string = ep->dest.user;
+ else if (! strcasecmp("dest.domain", tokens[i]))
+ string = ep->dest.domain;
+ else if (! strcasecmp("rcpt.user", tokens[i]))
+ string = ep->rcpt.user;
+ else if (! strcasecmp("rcpt.domain", tokens[i]))
+ string = ep->rcpt.domain;
+ else
+ fatalx("lka_expand_token: missing token handler");
+
+ /* expanded string is empty */
+ i = strlen(string);
+ if (i == 0)
+ return 0;
+
+ /* begin offset beyond end of string */
+ if (begoff >= i)
+ return 0;
+
+ /* end offset beyond end of string or unspecified, make it end of string */
+ if (endoff >= i || endoff == 0)
+ endoff = i;
+
+ /* negative begin offset, make it relative to end of string */
+ if (begoff < 0)
+ begoff += i;
+ /* negative end offset, make it relative to end of string */
+ if (endoff < 0)
+ endoff += i - 1;
+
+ /* check that final offsets are valid */
+ if (begoff < 0 || endoff <= 0 || endoff <= begoff)
+ return 0;
+
+ /* check that substring does not exceed destination buffer length */
+ i = endoff - begoff + 1;
+ if ((size_t)i + 1 >= len)
+ return 0;
+
+ return strlcpy(dest, string + begoff, i + 1);
+}
+
+
+static size_t
+lka_expand_format(char *buf, size_t len, const struct envelope *ep)
+{
+ char tmpbuf[EXPAND_BUFFER], *ptmp, *pbuf, *ebuf;
+ char exptok[EXPAND_BUFFER];
+ size_t exptoklen;
+ char token[MAXTOKENLEN];
+ size_t ret, tmpret;
+
+ if (len < sizeof tmpbuf)
+ fatalx("lka_expand_format: tmp buffer smaller than rule buffer");
+
+ bzero(tmpbuf, sizeof tmpbuf);
+ pbuf = buf;
+ ptmp = tmpbuf;
+ ret = tmpret = 0;
+
+ /* special case: ~/ only allowed expanded at the beginning */
+ if (strncmp(pbuf, "~/", 2) == 0) {
+ tmpret = snprintf(ptmp, sizeof tmpbuf, "%s/", ep->agent.mda.user.directory);
+ if (tmpret >= sizeof tmpbuf) {
+ log_warnx("warn: user directory for %s too large",
+ ep->agent.mda.user.directory);
+ return 0;
}
- if (*p == '%') {
- const char *string, *tmp = p + 1;
- int digit = 0;
+ ret += tmpret;
+ ptmp += tmpret;
+ pbuf += 2;
+ }
- if (isdigit((int)*tmp)) {
- digit = 1;
- tmp++;
- }
- switch (*tmp) {
- case 'A':
- string = ep->sender.user;
- break;
- case 'D':
- string = ep->sender.domain;
- break;
- case 'u':
- string = ep->agent.mda.user;
- break;
- case 'a':
- string = ep->dest.user;
- break;
- case 'd':
- string = ep->dest.domain;
- break;
- default:
- goto copy;
- }
- if (! lowercase(tmpbuf, string, sizeof tmpbuf))
- return 0;
- string = tmpbuf;
-
- if (digit == 1) {
- size_t idx = *(tmp - 1) - '0';
-
- lret = 1;
- if (idx < strlen(string))
- *pbuf++ = string[idx];
- else { /* fail */
- return 0;
- }
-
- p += 2; /* loop only does ++ */
- continue;
- }
- lret = strlcat(pbuf, string, len);
- if (lret >= len)
- return 0;
- p++;
+ /* expansion loop */
+ for (; *pbuf && ret < sizeof tmpbuf; ret += tmpret) {
+ if (*pbuf == '%' && *(pbuf + 1) == '%') {
+ *ptmp++ = *pbuf++;
+ pbuf += 1;
+ tmpret = 1;
continue;
}
-copy:
- lret = 1;
- *pbuf = *p;
- }
- /* we aborted loop because we reached max buffer size, fail. */
- if (ret == sizeof (lbuffer))
+ if (*pbuf != '%' || *(pbuf + 1) != '{') {
+ *ptmp++ = *pbuf++;
+ tmpret = 1;
+ continue;
+ }
+
+ /* %{...} otherwise fail */
+ if (*(pbuf+1) != '{' || (ebuf = strchr(pbuf+1, '}')) == NULL)
+ return 0;
+
+ /* extract token from %{token} */
+ if ((size_t)(ebuf - pbuf) - 1 >= sizeof token)
+ return 0;
+ *strchr(memcpy(token, pbuf+2, ebuf-pbuf-1), '}') = '\0';
+
+ if ((exptoklen = lka_expand_token(exptok, sizeof exptok, token, ep)) == 0)
+ return 0;
+
+ if (! lowercase(exptok, exptok, sizeof exptok))
+ return 0;
+
+ memcpy(ptmp, exptok, exptoklen);
+ pbuf = ebuf + 1;
+ ptmp += exptoklen;
+ tmpret = exptoklen;
+ }
+ if (ret >= sizeof tmpbuf)
return 0;
- /* shouldn't happen but better be safe ... */
- if (strlcpy(buf, lbuffer, len) >= len)
+ if ((ret = strlcpy(buf, tmpbuf, len)) >= len)
return 0;
return ret;
diff --git a/smtpd/map.c b/smtpd/map.c
index f007002e..4a2a0be9 100644
--- a/smtpd/map.c
+++ b/smtpd/map.c
@@ -35,7 +35,7 @@
#include "smtpd.h"
#include "log.h"
-struct map_backend *map_backend_lookup(enum map_src);
+struct map_backend *map_backend_lookup(const char *);
extern struct map_backend map_backend_static;
@@ -45,21 +45,14 @@ extern struct map_backend map_backend_file;
static objid_t last_map_id = 0;
struct map_backend *
-map_backend_lookup(enum map_src source)
+map_backend_lookup(const char *source)
{
- switch (source) {
- case S_NONE:
+ if (!strcmp(source, "static"))
return &map_backend_static;
-
- case S_DB:
+ if (!strcmp(source, "db"))
return &map_backend_db;
-
- case S_FILE:
+ if (!strcmp(source, "file"))
return &map_backend_file;
-
- default:
- fatalx("invalid map type");
- }
return NULL;
}
@@ -149,7 +142,7 @@ map_compare(objid_t mapid, const char *key, enum map_kind kind,
}
struct map *
-map_create(enum map_src src, const char *name)
+map_create(const char *source, const char *name)
{
struct map *m;
size_t n;
@@ -158,7 +151,9 @@ map_create(enum map_src src, const char *name)
errx(1, "map_create: map \"%s\" already defined", name);
m = xcalloc(1, sizeof(*m), "map_create");
- m->m_src = src;
+ if (strlcpy(m->m_src, source, sizeof m->m_src) >= sizeof m->m_src)
+ errx(1, "map_create: map source \"%s\" too large", m->m_src);
+
m->m_id = ++last_map_id;
if (m->m_id == INT_MAX)
errx(1, "map_create: too many maps defined");
@@ -183,7 +178,7 @@ map_destroy(struct map *m)
{
struct mapel *me;
- if (m->m_src != S_NONE)
+ if (strcmp(m->m_src, "static") != 0)
errx(1, "map_add: cannot delete all from map");
while ((me = TAILQ_FIRST(&m->m_contents))) {
@@ -201,7 +196,7 @@ map_add(struct map *m, const char *key, const char * val)
struct mapel *me;
size_t n;
- if (m->m_src != S_NONE)
+ if (strcmp(m->m_src, "static") != 0)
errx(1, "map_add: cannot add to map");
me = xcalloc(1, sizeof(*me), "map_add");
@@ -224,7 +219,7 @@ map_delete(struct map *m, const char *key)
{
struct mapel *me;
- if (m->m_src != S_NONE)
+ if (strcmp(m->m_src, "static") != 0)
errx(1, "map_add: cannot delete from map");
TAILQ_FOREACH(me, &m->m_contents, me_entry) {
diff --git a/smtpd/map_file.c b/smtpd/map_file.c
index 53334033..2ce6d811 100644
--- a/smtpd/map_file.c
+++ b/smtpd/map_file.c
@@ -47,7 +47,7 @@ static int map_file_compare(void *, const char *, enum map_kind,
int (*)(const char *, const char *));
static void map_file_close(void *);
-struct map_backend *map_backend_lookup(enum map_src);
+struct map_backend *map_backend_lookup(const char *);
struct map_backend map_backend_file = {
map_file_open,
@@ -104,7 +104,7 @@ map_file_open(struct map *map)
if (map->m_handle)
return map->m_handle;
- mp = map_create(S_NONE, NULL);
+ mp = map_create("static", NULL);
fp = fopen(map->m_config, "r");
if (fp == NULL)
@@ -142,7 +142,7 @@ map_file_update(struct map *map)
return;
}
- mp = map_create(S_NONE, NULL);
+ mp = map_create("static", NULL);
file_load(mp, fp);
fclose(fp);
diff --git a/smtpd/mda.c b/smtpd/mda.c
index 887af4ce..83a4995f 100644
--- a/smtpd/mda.c
+++ b/smtpd/mda.c
@@ -126,7 +126,7 @@ mda_imsg(struct imsgev *iev, struct imsg *imsg)
return;
}
- name = ep->agent.mda.user;
+ name = ep->agent.mda.user.username;
TAILQ_FOREACH(u, &users, entry)
if (!strcmp(name, u->name))
break;
@@ -215,7 +215,7 @@ mda_imsg(struct imsgev *iev, struct imsg *imsg)
switch (d_mda->method) {
case A_MDA:
deliver.mode = A_MDA;
- strlcpy(deliver.user, d_mda->user,
+ strlcpy(deliver.user, d_mda->user.username,
sizeof (deliver.user));
strlcpy(deliver.to, d_mda->buffer,
sizeof deliver.to);
@@ -225,7 +225,7 @@ mda_imsg(struct imsgev *iev, struct imsg *imsg)
deliver.mode = A_MBOX;
strlcpy(deliver.user, "root",
sizeof (deliver.user));
- strlcpy(deliver.to, d_mda->user,
+ strlcpy(deliver.to, d_mda->user.username,
sizeof (deliver.to));
snprintf(deliver.from, sizeof(deliver.from),
"%s@%s", ep->sender.user,
@@ -234,7 +234,7 @@ mda_imsg(struct imsgev *iev, struct imsg *imsg)
case A_MAILDIR:
deliver.mode = A_MAILDIR;
- strlcpy(deliver.user, d_mda->user,
+ strlcpy(deliver.user, d_mda->user.username,
sizeof deliver.user);
strlcpy(deliver.to, d_mda->buffer,
sizeof deliver.to);
@@ -242,7 +242,7 @@ mda_imsg(struct imsgev *iev, struct imsg *imsg)
case A_FILENAME:
deliver.mode = A_FILENAME;
- strlcpy(deliver.user, d_mda->user,
+ strlcpy(deliver.user, d_mda->user.username,
sizeof deliver.user);
strlcpy(deliver.to, d_mda->buffer,
sizeof deliver.to);
diff --git a/smtpd/parse.y b/smtpd/parse.y
index e0733f0e..b8ef9a6e 100644
--- a/smtpd/parse.y
+++ b/smtpd/parse.y
@@ -114,7 +114,6 @@ typedef struct {
union {
int64_t number;
objid_t object;
- struct timeval tv;
struct cond *cond;
char *string;
struct host *host;
@@ -135,9 +134,8 @@ typedef struct {
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.map> map
-%type <v.number> quantifier port from auth ssl size expire
+%type <v.number> port from auth ssl size expire
%type <v.cond> condition
-%type <v.tv> interval
%type <v.object> mapref
%type <v.maddr> relay_as
%type <v.string> certname tag on alias credentials compression
@@ -196,22 +194,6 @@ optrbracket : '}'
nl : '\n' optnl
;
-quantifier : /* empty */ { $$ = 1; }
- | 'm' { $$ = 60; }
- | 'h' { $$ = 3600; }
- | 'd' { $$ = 86400; }
- ;
-
-interval : NUMBER quantifier {
- if ($1 < 0) {
- yyerror("invalid interval: %" PRId64, $1);
- YYERROR;
- }
- $$.tv_usec = 0;
- $$.tv_sec = $1 * $2;
- }
- ;
-
size : NUMBER {
if ($1 < 0) {
yyerror("invalid size: %" PRId64, $1);
@@ -444,40 +426,32 @@ main : QUEUE compression {
;
mapsource : SOURCE FILE_ STRING {
- map->m_src = S_FILE;
+ strlcpy(map->m_src, "file", sizeof map->m_src);
if (strlcpy(map->m_config, $3, sizeof(map->m_config))
>= sizeof(map->m_config))
err(1, "pathname too long");
}
| STRING {
- map->m_src = S_FILE;
+ strlcpy(map->m_src, "file", sizeof map->m_src);
if (strlcpy(map->m_config, $1, sizeof(map->m_config))
>= sizeof(map->m_config))
err(1, "pathname too long");
}
| SOURCE DB STRING {
- map->m_src = S_DB;
- if (strlcpy(map->m_config, $3, sizeof(map->m_config))
- >= sizeof(map->m_config))
- err(1, "pathname too long");
- }
-/*
- | SOURCE LDAP STRING {
- map->m_src = S_LDAP;
+ strlcpy(map->m_src, "db", sizeof map->m_src);
if (strlcpy(map->m_config, $3, sizeof(map->m_config))
>= sizeof(map->m_config))
err(1, "pathname too long");
}
-*/
;
mapopt : mapsource { }
map : MAP STRING {
- map = map_create(S_NONE, $2);
+ map = map_create("static", $2);
free($2);
} optlbracket mapopt optrbracket {
- if (map->m_src == S_NONE) {
+ if (!strcmp(map->m_src, "static")) {
yyerror("map %s has no source defined", $2);
free(map);
map = NULL;
@@ -511,17 +485,17 @@ string_list : stringel
mapref : STRING {
struct map *m;
- m = map_create(S_NONE, NULL);
+ m = map_create("static", NULL);
map_add(m, $1, NULL);
$$ = m->m_id;
}
| '(' {
- map = map_create(S_NONE, NULL);
+ map = map_create("static", NULL);
} string_list ')' {
$$ = map->m_id;
}
| '{' {
- map = map_create(S_NONE, NULL);
+ map = map_create("static", NULL);
} keyval_list '}' {
$$ = map->m_id;
}
@@ -565,7 +539,7 @@ condition : DOMAIN mapref alias {
struct map *m;
m = map_find($2);
- if (m->m_src == S_NONE) {
+ if (!strcmp(m->m_src, "static")) {
yyerror("virtual parameter MUST be a map");
YYERROR;
}
@@ -594,7 +568,7 @@ condition : DOMAIN mapref alias {
rule->r_amap = m->m_id;
}
- m = map_create(S_NONE, NULL);
+ m = map_create("static", NULL);
map_add(m, "localhost", NULL);
map_add(m, hostname, NULL);
@@ -1698,7 +1672,7 @@ set_localaddrs(void)
struct sockaddr_in6 *sin6;
struct map *m;
- m = map_create(S_NONE, "<anyhost>");
+ m = map_create("static", "<anyhost>");
map_add(m, "local", NULL);
map_add(m, "0.0.0.0/0", NULL);
map_add(m, "::/0", NULL);
@@ -1710,7 +1684,7 @@ set_localaddrs(void)
if (getifaddrs(&ifap) == -1)
fatal("getifaddrs");
- m = map_create(S_NONE, "<localhost>");
+ m = map_create("static", "<localhost>");
map_add(m, "local", NULL);
for (p = ifap; p != NULL; p = p->ifa_next) {
diff --git a/smtpd/queue.c b/smtpd/queue.c
index 375b5dda..f021d069 100644
--- a/smtpd/queue.c
+++ b/smtpd/queue.c
@@ -452,51 +452,33 @@ queue(void)
static void
queue_timeout(int fd, short event, void *p)
{
- static struct qwalk *q = NULL;
- static uint32_t msgid = 0;
- static size_t evpcount = 0;
- struct event *ev = p;
- struct envelope envelope;
- struct timeval tv;
- uint64_t evpid;
-
- if (q == NULL) {
- log_debug("debug: queue: loading queue into scheduler");
- q = qwalk_new(0);
- }
-
- while (qwalk(q, &evpid)) {
+ static uint32_t msgid = 0;
+ struct envelope evp;
+ struct event *ev = p;
+ struct timeval tv;
+ int r;
- if (msgid && evpid_to_msgid(evpid) != msgid && evpcount) {
+ r = queue_envelope_learn(&evp);
+ if (r == -1) {
+ if (msgid)
imsg_compose_event(env->sc_ievs[PROC_SCHEDULER],
IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1, &msgid,
sizeof msgid);
- evpcount = 0;
- }
- msgid = evpid_to_msgid(evpid);
-
- if (!queue_envelope_load(evpid, &envelope))
- log_warnx("warn: Failed to load envelope %016"PRIx64,
- evpid);
- else {
- imsg_compose_event(env->sc_ievs[PROC_SCHEDULER],
- IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1, &envelope,
- sizeof envelope);
- evpcount++;
- }
-
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- evtimer_add(ev, &tv);
+ log_debug("debug: queue: done loading queue into scheduler");
return;
}
- if (msgid && evpcount) {
+ if (r) {
+ if (msgid && evpid_to_msgid(evp.id) != msgid)
+ imsg_compose_event(env->sc_ievs[PROC_SCHEDULER],
+ IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1, &msgid,
+ sizeof msgid);
+ msgid = evpid_to_msgid(evp.id);
imsg_compose_event(env->sc_ievs[PROC_SCHEDULER],
- IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1, &msgid, sizeof msgid);
- evpcount = 0;
+ IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1, &evp, sizeof evp);
}
- log_debug("debug: queue: done loading queue into scheduler");
- qwalk_close(q);
+ tv.tv_sec = 0;
+ tv.tv_usec = 10;
+ evtimer_add(ev, &tv);
}
diff --git a/smtpd/queue_backend.c b/smtpd/queue_backend.c
index 403df622..55ab56fd 100644
--- a/smtpd/queue_backend.c
+++ b/smtpd/queue_backend.c
@@ -310,22 +310,26 @@ queue_envelope_update(struct envelope *ep)
return env->sc_queue->envelope(QOP_UPDATE, &ep->id, evpbuf, evplen);
}
-void *
-qwalk_new(uint32_t msgid)
-{
- return env->sc_queue->qwalk_new(msgid);
-}
-
int
-qwalk(void *hdl, uint64_t *evpid)
+queue_envelope_learn(struct envelope *ep)
{
- return env->sc_queue->qwalk(hdl, evpid);
-}
+ const char *e;
+ uint64_t evpid;
+ char evpbuf[sizeof(struct envelope)];
+ int r;
-void
-qwalk_close(void *hdl)
-{
- return env->sc_queue->qwalk_close(hdl);
+ r = env->sc_queue->envelope(QOP_LEARN, &evpid, evpbuf, sizeof evpbuf);
+ if (r == -1 || r == 0)
+ return (r);
+
+ if (queue_envelope_load_buffer(ep, evpbuf, (size_t)r)) {
+ if ((e = envelope_validate(ep)) == NULL) {
+ ep->id = evpid;
+ return (1);
+ }
+ log_debug("debug: invalid envelope %016" PRIx64 ": %s", ep->id, e);
+ }
+ return (0);
}
uint32_t
@@ -355,8 +359,6 @@ queue_generate_evpid(uint32_t msgid)
return evpid;
}
-
-/**/
static const char*
envelope_validate(struct envelope *ep)
{
diff --git a/smtpd/queue_fsqueue.c b/smtpd/queue_fsqueue.c
index ddc428fd..65da871a 100644
--- a/smtpd/queue_fsqueue.c
+++ b/smtpd/queue_fsqueue.c
@@ -48,6 +48,7 @@ static int fsqueue_envelope_create(uint64_t *, char *, size_t);
static int fsqueue_envelope_load(uint64_t, char *, size_t);
static int fsqueue_envelope_update(uint64_t, char *, size_t);
static int fsqueue_envelope_delete(uint64_t);
+static int fsqueue_envelope_learn(uint64_t *, char *, size_t);
static int fsqueue_message_create(uint32_t *);
static int fsqueue_message_commit(uint32_t);
@@ -63,7 +64,7 @@ static int fsqueue_init(int);
static int fsqueue_message(enum queue_op, uint32_t *);
static int fsqueue_envelope(enum queue_op , uint64_t *, char *, size_t);
-static void *fsqueue_qwalk_new(uint32_t);
+static void *fsqueue_qwalk_new(void);
static int fsqueue_qwalk(void *, uint64_t *);
static void fsqueue_qwalk_close(void *);
@@ -76,9 +77,6 @@ struct queue_backend queue_backend_fs = {
fsqueue_init,
fsqueue_message,
fsqueue_envelope,
- fsqueue_qwalk_new,
- fsqueue_qwalk,
- fsqueue_qwalk_close
};
static struct timespec startup;
@@ -244,6 +242,26 @@ fsqueue_envelope_delete(uint64_t evpid)
}
static int
+fsqueue_envelope_learn(uint64_t *evpid, char *buf, size_t len)
+{
+ static int done = 0;
+ static void *hdl = NULL;
+
+ if (done)
+ return (-1);
+
+ if (hdl == NULL)
+ hdl = fsqueue_qwalk_new();
+
+ if (fsqueue_qwalk(hdl, evpid))
+ return (fsqueue_envelope_load(*evpid, buf, len));
+
+ fsqueue_qwalk_close(hdl);
+ done = 1;
+ return (-1);
+}
+
+static int
fsqueue_message_create(uint32_t *msgid)
{
char rootdir[MAXPATHLEN];
@@ -439,6 +457,9 @@ fsqueue_envelope(enum queue_op qop, uint64_t *evpid, char *buf, size_t len)
case QOP_UPDATE:
return fsqueue_envelope_update(*evpid, buf, len);
+ case QOP_LEARN:
+ return fsqueue_envelope_learn(evpid, buf, len);
+
default:
fatalx("queue_fsqueue_envelope: unsupported operation.");
}
@@ -448,19 +469,17 @@ fsqueue_envelope(enum queue_op qop, uint64_t *evpid, char *buf, size_t len)
struct qwalk {
FTS *fts;
- uint32_t msgid;
int depth;
};
static void *
-fsqueue_qwalk_new(uint32_t msgid)
+fsqueue_qwalk_new(void)
{
char path[MAXPATHLEN];
char * const path_argv[] = { path, NULL };
struct qwalk *q;
q = xcalloc(1, sizeof(*q), "fsqueue_qwalk_new");
- q->msgid = msgid;
strlcpy(path, PATH_QUEUE, sizeof(path));
q->fts = fts_open(path_argv,
FTS_PHYSICAL | FTS_NOCHDIR, NULL);
@@ -487,7 +506,6 @@ fsqueue_qwalk(void *hdl, uint64_t *evpid)
struct qwalk *q = hdl;
FTSENT *e;
char *tmp;
- uint32_t msgid;
while ((e = fts_read(q->fts)) != NULL) {
@@ -506,14 +524,6 @@ fsqueue_qwalk(void *hdl, uint64_t *evpid)
fts_set(q->fts, e, FTS_SKIP);
break;
}
- if (q->msgid && (q->depth == 2 || q->depth == 3)) {
- msgid = strtoull(e->fts_name, &tmp, 16);
- if (msgid != (q->depth == 1) ?
- (q->msgid & 0xff) : q->msgid) {
- fts_set(q->fts, e, FTS_SKIP);
- break;
- }
- }
break;
case FTS_DP:
diff --git a/smtpd/queue_ram.c b/smtpd/queue_ram.c
index b86888af..d979611c 100644
--- a/smtpd/queue_ram.c
+++ b/smtpd/queue_ram.c
@@ -46,17 +46,11 @@
static int queue_ram_init(int);
static int queue_ram_message(enum queue_op, uint32_t *);
static int queue_ram_envelope(enum queue_op , uint64_t *, char *, size_t);
-static void *queue_ram_qwalk_new(uint32_t);
-static int queue_ram_qwalk(void *, uint64_t *);
-static void queue_ram_qwalk_close(void *);
struct queue_backend queue_backend_ram = {
queue_ram_init,
queue_ram_message,
queue_ram_envelope,
- queue_ram_qwalk_new,
- queue_ram_qwalk,
- queue_ram_qwalk_close
};
struct qr_envelope {
@@ -231,26 +225,12 @@ queue_ram_envelope(enum queue_op qop, uint64_t *evpid, char *buf, size_t len)
evp->buf = xmemdup(buf, len, "queue_ram_envelope: update");
return (1);
+ case QOP_LEARN:
+ return (-1);
+
default:
fatalx("queue_queue_ram_envelope: unsupported operation.");
}
return (0);
}
-
-static void *
-queue_ram_qwalk_new(uint32_t msgid)
-{
- return (NULL);
-}
-
-static void
-queue_ram_qwalk_close(void *hdl)
-{
-}
-
-static int
-queue_ram_qwalk(void *hdl, uint64_t *evpid)
-{
- return (0);
-}
diff --git a/smtpd/ruleset.c b/smtpd/ruleset.c
index d90bc29b..23b224e0 100644
--- a/smtpd/ruleset.c
+++ b/smtpd/ruleset.c
@@ -78,7 +78,7 @@ ruleset_match(const struct envelope *evp)
if (map == NULL)
fatal("failed to lookup map.");
- if (map->m_src == S_NONE) {
+ if (! strcmp(map->m_src, "static")) {
TAILQ_FOREACH(me, &map->m_contents, me_entry) {
if (hostname_match(maddr->domain, me->me_key))
return r;
@@ -141,7 +141,7 @@ ruleset_check_source(struct map *map, const struct sockaddr_storage *ss)
return 1;
}
- if (map->m_src == S_NONE) {
+ if (! strcmp(map->m_src, "static")) {
TAILQ_FOREACH(me, &map->m_contents, me_entry) {
if (ss->ss_family == AF_LOCAL) {
if (!strcmp(me->me_key, "local"))
diff --git a/smtpd/smtpctl.c b/smtpd/smtpctl.c
index 01f7dc19..a2b72d91 100644
--- a/smtpd/smtpctl.c
+++ b/smtpd/smtpctl.c
@@ -528,24 +528,17 @@ show_stats_output(void)
static void
show_queue(flags)
{
- struct qwalk *q;
struct envelope envelope;
- uint64_t evpid;
+ int r;
log_init(1);
if (chroot(PATH_SPOOL) == -1 || chdir(".") == -1)
err(1, "%s", PATH_SPOOL);
- q = qwalk_new(0);
-
- while (qwalk(q, &evpid)) {
- if (! queue_envelope_load(evpid, &envelope))
- continue;
- show_queue_envelope(&envelope, flags);
- }
-
- qwalk_close(q);
+ while((r = queue_envelope_learn(&envelope)) != -1)
+ if (r)
+ show_queue_envelope(&envelope, flags);
}
static void
diff --git a/smtpd/smtpd.c b/smtpd/smtpd.c
index 70d14e11..101cae3a 100644
--- a/smtpd/smtpd.c
+++ b/smtpd/smtpd.c
@@ -918,7 +918,7 @@ forkmda(struct imsgev *iev, uint32_t id,
char ebuf[128], sfn[32];
struct user_backend *ub;
struct delivery_backend *db;
- struct mta_user u;
+ struct userinfo u;
struct child *child;
pid_t pid;
int n, allout, pipefd[2];
@@ -1212,7 +1212,7 @@ static int
parent_forward_open(char *username)
{
struct user_backend *ub;
- struct mta_user u;
+ struct userinfo u;
char pathname[MAXPATHLEN];
int fd;
diff --git a/smtpd/smtpd.conf.5 b/smtpd/smtpd.conf.5
index f034504b..b229c15a 100644
--- a/smtpd/smtpd.conf.5
+++ b/smtpd/smtpd.conf.5
@@ -56,21 +56,32 @@ listen on $lan_addr
listen on $lan_addr tls auth
.Ed
.Pp
-Some configuration directives expect expansion of their parameters at runtime.
+Some configuration directives support expansion of their parameters at runtime.
Such directives (for example
.Ar deliver to maildir ,
-.Ar deliver to mda ,
-.Ar relay via )
+.Ar deliver to mda )
may use format specifiers which will be expanded before delivery or
relaying.
The following formats are currently supported:
-%a expands to the user part of the email address prior to the
-resolution of aliases;
-%u expands to the user part after aliases
-resolution and will typically be the system account;
-%d expands to the domain part of the email address;
-%A expands to the user part of the sender email address;
-%D expands to the domain part of the sender email address.
+.Bd -literal -offset indent
+%{sender.user} user part of the sender email address
+%{sender.domain} domain part of the sender email address
+%{rcpt.user} user part of the recipient email address
+%{rcpt.domain} domain part of the recipient email address
+%{dest.user} user part after expansion
+%{dest.domain} domain part after expansion
+%{user.username} local user
+%{user.directory} home directory of the local user
+.Ed
+.Pp
+Expansion formats also support partial expansion using the optional bracket notations
+with substring offset. For example, with recipient domain "example.org":
+.Bd -literal -offset indent
+%{rcpt.domain[8]} expands to "org"
+%{rcpt.domain[-3]} expands to "org"
+%{rcpt.domain[0:6]} expands to "example"
+%{rcpt.domain[0:-4]} expands to "example"
+.Ed
.Pp
Additional configuration files can be included with the
.Ic include
diff --git a/smtpd/smtpd.h b/smtpd/smtpd.h
index b6f92b62..d7a6dc29 100644
--- a/smtpd/smtpd.h
+++ b/smtpd/smtpd.h
@@ -50,11 +50,13 @@
#define MAX_TAG_SIZE 32
+#define MAX_MAPSOURCE_SIZE 32
/* return and forward path size */
#define MAX_FILTER_NAME 32
#define MAX_PATH_SIZE 256
-#define MAX_RULEBUFFER_LEN 512
+/*#define MAX_RULEBUFFER_LEN 512*/
+#define EXPAND_BUFFER 1024
#define SMTPD_QUEUE_INTERVAL (15 * 60)
#define SMTPD_QUEUE_MAXINTERVAL (4 * 60 * 60)
@@ -117,6 +119,26 @@
typedef uint32_t objid_t;
+
+/* user structures */
+enum user_type {
+ USER_PWD,
+};
+
+#define MAXPASSWORDLEN 128
+struct userinfo {
+ char username[MAXLOGNAME];
+ char directory[MAXPATHLEN];
+ char password[MAXPASSWORDLEN];
+ uid_t uid;
+ gid_t gid;
+};
+
+struct user_backend {
+ int (*getbyname)(struct userinfo *, const char *);
+};
+
+
struct netaddr {
struct sockaddr_storage ss;
int bits;
@@ -255,12 +277,13 @@ struct peer {
void (*cb)(int, short, void *);
};
+/*
enum map_src {
S_NONE,
S_FILE,
- S_DB /*,
- S_LDAP*/
+ S_DB
};
+*/
enum map_kind {
K_NONE,
@@ -280,7 +303,7 @@ struct map {
TAILQ_ENTRY(map) m_entry;
char m_name[MAX_LINE_SIZE];
objid_t m_id;
- enum map_src m_src;
+ char m_src[MAX_MAPSOURCE_SIZE];
char m_config[MAXPATHLEN];
TAILQ_HEAD(mapel_list, mapel) m_contents;
void *m_handle;
@@ -332,7 +355,7 @@ struct rule {
struct cond r_condition;
enum action_type r_action;
union rule_dest {
- char buffer[MAX_RULEBUFFER_LEN];
+ char buffer[EXPAND_BUFFER];
struct relayhost relayhost;
} r_value;
@@ -370,8 +393,8 @@ enum delivery_flags {
struct delivery_mda {
enum action_type method;
- char user[MAXLOGNAME];
- char buffer[MAX_RULEBUFFER_LEN];
+ struct userinfo user;
+ char buffer[EXPAND_BUFFER];
};
struct delivery_mta {
@@ -402,7 +425,7 @@ struct expandnode {
* so we MUST make it large enough to fit a mailaddr user
*/
char user[MAX_LOCALPART_SIZE];
- char buffer[MAX_RULEBUFFER_LEN];
+ char buffer[EXPAND_BUFFER];
struct mailaddr mailaddr;
} u;
};
@@ -779,10 +802,10 @@ struct map_netaddr {
};
enum queue_op {
- QOP_INVALID=0,
QOP_CREATE,
QOP_DELETE,
QOP_UPDATE,
+ QOP_LEARN,
QOP_COMMIT,
QOP_LOAD,
QOP_FD_R,
@@ -793,10 +816,6 @@ struct queue_backend {
int (*init)(int);
int (*message)(enum queue_op, uint32_t *);
int (*envelope)(enum queue_op, uint64_t *, char *, size_t);
-
- void *(*qwalk_new)(uint32_t);
- int (*qwalk)(void *, uint64_t *);
- void (*qwalk_close)(void *);
};
struct compress_backend {
@@ -817,25 +836,6 @@ struct auth_backend {
};
-/* user structures */
-enum user_type {
- USER_PWD,
-};
-
-#define MAXPASSWORDLEN 128
-struct mta_user {
- char username[MAXLOGNAME];
- char directory[MAXPATHLEN];
- char password[MAXPASSWORDLEN];
- uid_t uid;
- gid_t gid;
-};
-
-struct user_backend {
- int (*getbyname)(struct mta_user *, const char *);
-};
-
-
/* delivery_backend */
struct delivery_backend {
int allow_root;
@@ -1044,7 +1044,7 @@ int map_compare(objid_t, const char *, enum map_kind,
int (*)(const char *, const char *));
struct map *map_find(objid_t);
struct map *map_findbyname(const char *);
-struct map *map_create(enum map_src, const char *);
+struct map *map_create(const char *, const char *);
void map_destroy(struct map *);
void map_add(struct map *, const char *, const char *);
void map_delete(struct map *, const char *);
@@ -1102,9 +1102,7 @@ int queue_envelope_create(struct envelope *);
int queue_envelope_delete(struct envelope *);
int queue_envelope_load(uint64_t, struct envelope *);
int queue_envelope_update(struct envelope *);
-void *qwalk_new(uint32_t);
-int qwalk(void *, uint64_t *);
-void qwalk_close(void *);
+int queue_envelope_learn(struct envelope *);
/* compress_backend.c */
struct compress_backend *compress_backend_lookup(const char *);
diff --git a/smtpd/user_pwd.c b/smtpd/user_pwd.c
index 1fb78c52..33dec408 100644
--- a/smtpd/user_pwd.c
+++ b/smtpd/user_pwd.c
@@ -37,15 +37,15 @@
#include "smtpd.h"
#include "log.h"
-static int user_getpw_ret(struct mta_user *, struct passwd *); /* helper */
-static int user_getpwnam(struct mta_user *, const char *);
+static int user_getpw_ret(struct userinfo *, struct passwd *); /* helper */
+static int user_getpwnam(struct userinfo *, const char *);
struct user_backend user_backend_pwd = {
user_getpwnam
};
static int
-user_getpw_ret(struct mta_user *u, struct passwd *pw)
+user_getpw_ret(struct userinfo *u, struct passwd *pw)
{
if (strlcpy(u->username, pw->pw_name, sizeof (u->username))
>= sizeof (u->username))
@@ -66,7 +66,7 @@ user_getpw_ret(struct mta_user *u, struct passwd *pw)
}
static int
-user_getpwnam(struct mta_user *u, const char *username)
+user_getpwnam(struct userinfo *u, const char *username)
{
struct passwd *pw;
diff --git a/smtpd/util.c b/smtpd/util.c
index e8ff4644..d2a92cb1 100644
--- a/smtpd/util.c
+++ b/smtpd/util.c
@@ -1106,7 +1106,7 @@ log_envelope(const struct envelope *evp, const char *extra, const char *prefix,
else
fatalx("log_envelope: bad method");
snprintf(tmp, sizeof tmp, "user=%s, method=%s, ",
- evp->agent.mda.user, method);
+ evp->agent.mda.user.username, method);
}
if (extra == NULL)