diff options
author | Eric Faurot <eric@faurot.net> | 2012-11-14 16:52:03 +0100 |
---|---|---|
committer | Eric Faurot <eric@faurot.net> | 2012-11-14 16:52:03 +0100 |
commit | 7e908dc30b1f664a74a82894cce8b07d20ddf014 (patch) | |
tree | bf1880f4fb867e8c873ee1f6eb91681b04173dc2 /smtpd | |
parent | fix regress makefile (diff) | |
parent | Merge branch 'master' of ssh.poolp.org:/git/opensmtpd (diff) | |
download | OpenSMTPD-7e908dc30b1f664a74a82894cce8b07d20ddf014.tar.xz OpenSMTPD-7e908dc30b1f664a74a82894cce8b07d20ddf014.zip |
Merge branch 'master' into portable
Conflicts:
smtpd/parse.y
Diffstat (limited to 'smtpd')
-rw-r--r-- | smtpd/envelope.c | 6 | ||||
-rw-r--r-- | smtpd/lka_session.c | 309 | ||||
-rw-r--r-- | smtpd/map.c | 29 | ||||
-rw-r--r-- | smtpd/map_file.c | 6 | ||||
-rw-r--r-- | smtpd/mda.c | 10 | ||||
-rw-r--r-- | smtpd/parse.y | 52 | ||||
-rw-r--r-- | smtpd/queue.c | 56 | ||||
-rw-r--r-- | smtpd/queue_backend.c | 32 | ||||
-rw-r--r-- | smtpd/queue_fsqueue.c | 42 | ||||
-rw-r--r-- | smtpd/queue_ram.c | 26 | ||||
-rw-r--r-- | smtpd/ruleset.c | 4 | ||||
-rw-r--r-- | smtpd/smtpctl.c | 15 | ||||
-rw-r--r-- | smtpd/smtpd.c | 4 | ||||
-rw-r--r-- | smtpd/smtpd.conf.5 | 31 | ||||
-rw-r--r-- | smtpd/smtpd.h | 70 | ||||
-rw-r--r-- | smtpd/user_pwd.c | 8 | ||||
-rw-r--r-- | smtpd/util.c | 2 |
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) |