diff options
author | Gilles Chehade <gilles@cvs.openbsd.org> | 2009-10-19 20:48:14 +0000 |
---|---|---|
committer | Gilles Chehade <gilles@cvs.openbsd.org> | 2009-10-19 20:48:14 +0000 |
commit | 6a01a88ab53f1ec7e855d1188bdea063f7c1c76a (patch) | |
tree | d6d7c2e8ff966aa7f5dff414f17d1ba935aa11ef /usr.sbin | |
parent | 5efe823e422d4650b1e9874563c04183d773f32b (diff) |
currently, smtpd is capable of having multiple listeners with different
options but they will all share the same ruleset. this means that there
is no way to have a rule apply to a session established on one listener
but not applied on another.
this commit brings initial support for tagging listeners and having the
rules able to match these specific listeners. The following will define
a rule which will only apply to interfaces tagged as "mynet":
listen on lo0 # implicit lo0 tag
listen on fxp0 tag mynet
listen on fxp1 tag mynet
accept on mynet for domain "example.org" deliver to mbox
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/smtpd/lka.c | 26 | ||||
-rw-r--r-- | usr.sbin/smtpd/parse.y | 92 | ||||
-rw-r--r-- | usr.sbin/smtpd/ruleset.c | 12 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtp_session.c | 3 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 7 |
5 files changed, 99 insertions, 41 deletions
diff --git a/usr.sbin/smtpd/lka.c b/usr.sbin/smtpd/lka.c index edbcb5869c2..4f77df73dd0 100644 --- a/usr.sbin/smtpd/lka.c +++ b/usr.sbin/smtpd/lka.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lka.c,v 1.70 2009/10/18 21:45:47 gilles Exp $ */ +/* $OpenBSD: lka.c,v 1.71 2009/10/19 20:48:13 gilles Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -57,19 +57,19 @@ int lka_forward_file(struct passwd *); size_t lka_expand(char *, size_t, struct path *); int aliases_exist(struct smtpd *, char *); int aliases_get(struct smtpd *, struct aliaseslist *, char *); -int lka_resolve_alias(struct smtpd *, struct path *, struct alias *); +int lka_resolve_alias(struct smtpd *, char *tag, struct path *, struct alias *); int lka_parse_include(char *); int lka_check_source(struct smtpd *, struct map *, struct sockaddr_storage *); int lka_match_mask(struct sockaddr_storage *, struct netaddr *); int lka_resolve_path(struct smtpd *, struct path *); void lka_expand_rcpt(struct smtpd *, struct aliaseslist *, struct lkasession *); int lka_expand_rcpt_iteration(struct smtpd *, struct aliaseslist *, struct lkasession *); -void lka_rcpt_action(struct smtpd *, struct path *); +void lka_rcpt_action(struct smtpd *, char *, struct path *); void lka_clear_aliaseslist(struct aliaseslist *); int lka_encode_credentials(char *, size_t, char *); struct lkasession *lka_session_init(struct smtpd *, struct submit_status *); void lka_request_forwardfile(struct smtpd *, struct lkasession *, char *); -struct rule *ruleset_match(struct smtpd *, struct path *, struct sockaddr_storage *); +struct rule *ruleset_match(struct smtpd *, char *, struct path *, struct sockaddr_storage *); void queue_submit_envelope(struct smtpd *, struct message *); void queue_commit_envelopes(struct smtpd *, struct message*); @@ -255,7 +255,7 @@ lka_dispatch_parent(int sig, short event, void *p) alias_parse(&alias, fwreq->pw_name); /* then resolve alias and get back to expanding the aliases list */ - lka_resolve_alias(env, &lkasession->message.recipient, &alias); + lka_resolve_alias(env, lkasession->message.tag, &lkasession->message.recipient, &alias); lka_expand_rcpt(env, &lkasession->aliaseslist, lkasession); break; } @@ -330,7 +330,7 @@ lka_dispatch_mfa(int sig, short event, void *p) ss->code = 530; - r = ruleset_match(env, &ss->u.path, &ss->ss); + r = ruleset_match(env, ss->msg.tag, &ss->u.path, &ss->ss); if (r != NULL) { ss->code = 250; ss->u.path.rule = *r; @@ -833,7 +833,7 @@ lka_expand(char *buf, size_t len, struct path *path) } int -lka_resolve_alias(struct smtpd *env, struct path *path, struct alias *alias) +lka_resolve_alias(struct smtpd *env, char *tag, struct path *path, struct alias *alias) { bzero(path, sizeof(struct path)); @@ -854,7 +854,7 @@ lka_resolve_alias(struct smtpd *env, struct path *path, struct alias *alias) return 0; } log_debug("RESOLVED TO %s@%s", path->user, path->domain); - lka_rcpt_action(env, path); + lka_rcpt_action(env, tag, path); break; case ALIAS_FILENAME: @@ -876,7 +876,7 @@ lka_resolve_alias(struct smtpd *env, struct path *path, struct alias *alias) log_debug("ADDRESS: %s@%s", alias->u.path.user, alias->u.path.domain); *path = alias->u.path; - lka_rcpt_action(env, path); + lka_rcpt_action(env, tag, path); break; case ALIAS_INCLUDE: fatalx("lka_resolve_alias: unexpected type"); @@ -929,7 +929,7 @@ lka_expand_rcpt(struct smtpd *env, struct aliaseslist *aliases, struct lkasessio message = lkasession->message; while ((alias = TAILQ_FIRST(&lkasession->aliaseslist)) != NULL) { - lka_resolve_alias(env, &message.recipient, alias); + lka_resolve_alias(env, message.tag, &message.recipient, alias); queue_submit_envelope(env, &message); TAILQ_REMOVE(&lkasession->aliaseslist, alias, entry); @@ -959,7 +959,7 @@ lka_expand_rcpt_iteration(struct smtpd *env, struct aliaseslist *aliases, struct } if (alias->type == ALIAS_ADDRESS) { - lka_rcpt_action(env, &alias->u.path); + lka_rcpt_action(env, lkasession->message.tag, &alias->u.path); if (aliases_virtual_get(env, alias->u.path.cond->c_match, aliases, &alias->u.path)) { rmalias = alias; done = 0; @@ -1041,7 +1041,7 @@ lka_resolve_path(struct smtpd *env, struct path *path){ } void -lka_rcpt_action(struct smtpd *env, struct path *path) +lka_rcpt_action(struct smtpd *env, char *tag, struct path *path) { struct rule *r; @@ -1049,7 +1049,7 @@ lka_rcpt_action(struct smtpd *env, struct path *path) (void)strlcpy(path->domain, env->sc_hostname, sizeof (path->domain)); - r = ruleset_match(env, path, NULL); + r = ruleset_match(env, tag, path, NULL); if (r == NULL) { path->rule.r_action = A_RELAY; return; diff --git a/usr.sbin/smtpd/parse.y b/usr.sbin/smtpd/parse.y index f92e7178e73..182ff251089 100644 --- a/usr.sbin/smtpd/parse.y +++ b/usr.sbin/smtpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.41 2009/10/19 20:00:46 gilles Exp $ */ +/* $OpenBSD: parse.y,v 1.42 2009/10/19 20:48:13 gilles Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> @@ -92,12 +92,12 @@ struct mapel_list *contents = NULL; struct listener *host_v4(const char *, in_port_t); struct listener *host_v6(const char *, in_port_t); -int host_dns(const char *, const char *, struct listenerlist *, - int, in_port_t, u_int8_t); -int host(const char *, const char *, struct listenerlist *, - int, in_port_t, u_int8_t); -int interface(const char *, const char *, struct listenerlist *, - int, in_port_t, u_int8_t); +int host_dns(const char *, const char *, const char *, + struct listenerlist *, int, in_port_t, u_int8_t); +int host(const char *, const char *, const char *, + struct listenerlist *, int, in_port_t, u_int8_t); +int interface(const char *, const char *, const char *, + struct listenerlist *, int, in_port_t, u_int8_t); void set_localaddrs(void); typedef struct { @@ -119,7 +119,7 @@ typedef struct { %token DNS DB TFILE 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 +%token ARROW ENABLE AUTH TLS LOCAL VIRTUAL USER TAG %token <v.string> STRING %token <v.number> NUMBER %type <v.map> map @@ -127,7 +127,7 @@ typedef struct { %type <v.cond> condition %type <v.tv> interval %type <v.object> mapref -%type <v.string> certname user +%type <v.string> certname user tag on %% @@ -232,15 +232,29 @@ auth : ENABLE AUTH { $$ = 1; } | /* empty */ { $$ = 0; } ; +tag : TAG STRING { + if (strlen($2) >= MAX_TAG_SIZE) { + yyerror("tag name too long"); + free($2); + YYERROR; + } + + $$ = $2; + } + | /* empty */ { $$ = NULL; } + ; + main : QUEUE INTERVAL interval { conf->sc_qintval = $3; } - | LISTEN ON STRING port ssl certname auth { + | LISTEN ON STRING port ssl certname auth tag { char *cert; + char *tag; u_int8_t flags; if ($5 == F_SSL) { yyerror("syntax error"); + free($8); free($6); free($3); YYERROR; @@ -248,6 +262,7 @@ main : QUEUE INTERVAL interval { if ($5 == 0 && ($6 != NULL || $7)) { yyerror("error: must specify tls or smtps"); + free($8); free($6); free($3); YYERROR; @@ -268,21 +283,28 @@ main : QUEUE INTERVAL interval { if ($5 && ssl_load_certfile(conf, cert, F_SCERT) < 0) { yyerror("cannot load certificate: %s", cert); + free($8); free($6); free($3); YYERROR; } - if (! interface($3, cert, conf->sc_listeners, + tag = $3; + if ($8 != NULL) + tag = $8; + + if (! interface($3, tag, cert, conf->sc_listeners, MAX_LISTEN, $4, flags)) { - if (host($3, cert, conf->sc_listeners, + if (host($3, tag, cert, conf->sc_listeners, MAX_LISTEN, $4, flags) <= 0) { yyerror("invalid virtual ip or interface: %s", $3); + free($8); free($6); free($3); YYERROR; } } + free($8); free($6); free($3); } @@ -885,17 +907,33 @@ from : FROM mapref { } ; -rule : decision from { +on : ON STRING { + if (strlen($2) >= MAX_TAG_SIZE) { + yyerror("interface, address or tag name too long"); + free($2); + YYERROR; + } + + $$ = $2; + } + | /* empty */ { $$ = NULL; } + +rule : decision on from { struct rule *r; if ((r = calloc(1, sizeof(*r))) == NULL) fatal("out of memory"); rule = r; - rule->r_sources = map_find(conf, $2); + rule->r_sources = map_find(conf, $3); + + if ($2) + (void)strlcpy(rule->r_tag, $2, sizeof(rule->r_tag)); + free($2); + TAILQ_INIT(&rule->r_conditions); TAILQ_INIT(&rule->r_options); - } FOR conditions action { + } FOR conditions action tag { TAILQ_INSERT_TAIL(conf->sc_rules, rule, r_entry); } ; @@ -966,6 +1004,7 @@ lookup(char *s) { "smtps", SMTPS }, { "source", SOURCE }, { "ssl", SSL }, + { "tag", TAG }, { "tls", TLS }, { "to", TO }, { "type", TYPE }, @@ -1531,8 +1570,8 @@ host_v6(const char *s, in_port_t port) } int -host_dns(const char *s, const char *cert, struct listenerlist *al, int max, in_port_t port, - u_int8_t flags) +host_dns(const char *s, const char *tag, const char *cert, + struct listenerlist *al, int max, in_port_t port, u_int8_t flags) { struct addrinfo hints, *res0, *res; int error, cnt = 0; @@ -1566,6 +1605,8 @@ host_dns(const char *s, const char *cert, struct listenerlist *al, int max, in_p h->ssl_cert_name[0] = '\0'; if (cert != NULL) (void)strlcpy(h->ssl_cert_name, cert, sizeof(h->ssl_cert_name)); + if (tag != NULL) + (void)strlcpy(h->tag, tag, sizeof(h->tag)); if (res->ai_family == AF_INET) { sain = (struct sockaddr_in *)&h->ss; @@ -1593,8 +1634,8 @@ host_dns(const char *s, const char *cert, struct listenerlist *al, int max, in_p } int -host(const char *s, const char *cert, struct listenerlist *al, int max, in_port_t port, - u_int8_t flags) +host(const char *s, const char *tag, const char *cert, struct listenerlist *al, + int max, in_port_t port, u_int8_t flags) { struct listener *h; @@ -1611,18 +1652,19 @@ host(const char *s, const char *cert, struct listenerlist *al, int max, in_port_ h->ssl_cert_name[0] = '\0'; if (cert != NULL) (void)strlcpy(h->ssl_cert_name, cert, sizeof(h->ssl_cert_name)); - + if (tag != NULL) + (void)strlcpy(h->tag, tag, sizeof(h->tag)); TAILQ_INSERT_HEAD(al, h, entry); return (1); } - return (host_dns(s, cert, al, max, port, flags)); + return (host_dns(s, tag, cert, al, max, port, flags)); } int -interface(const char *s, const char *cert, struct listenerlist *al, int max, in_port_t port, - u_int8_t flags) +interface(const char *s, const char *tag, const char *cert, + struct listenerlist *al, int max, in_port_t port, u_int8_t flags) { struct ifaddrs *ifap, *p; struct sockaddr_in *sain; @@ -1653,6 +1695,10 @@ interface(const char *s, const char *cert, struct listenerlist *al, int max, in_ h->ssl_cert_name[0] = '\0'; if (cert != NULL) (void)strlcpy(h->ssl_cert_name, cert, sizeof(h->ssl_cert_name)); + if (tag != NULL) + (void)strlcpy(h->tag, tag, sizeof(h->tag)); + if (tag != NULL) + (void)strlcpy(h->tag, tag, sizeof(h->tag)); ret = 1; TAILQ_INSERT_HEAD(al, h, entry); diff --git a/usr.sbin/smtpd/ruleset.c b/usr.sbin/smtpd/ruleset.c index 9162de7a7fc..2974c28161f 100644 --- a/usr.sbin/smtpd/ruleset.c +++ b/usr.sbin/smtpd/ruleset.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ruleset.c,v 1.4 2009/10/12 18:14:51 gilles Exp $ */ +/* $OpenBSD: ruleset.c,v 1.5 2009/10/19 20:48:13 gilles Exp $ */ /* * Copyright (c) 2009 Gilles Chehade <gilles@openbsd.org> @@ -35,21 +35,27 @@ #include "smtpd.h" -struct rule *ruleset_match(struct smtpd *, struct path *, struct sockaddr_storage *); +struct rule *ruleset_match(struct smtpd *, char *tag, struct path *, struct sockaddr_storage *); int ruleset_check_source(struct map *, struct sockaddr_storage *); int ruleset_match_mask(struct sockaddr_storage *, struct netaddr *); struct rule * -ruleset_match(struct smtpd *env, struct path *path, struct sockaddr_storage *ss) +ruleset_match(struct smtpd *env, char *tag, struct path *path, struct sockaddr_storage *ss) { struct rule *r; struct cond *cond; struct map *map; struct mapel *me; + if (tag) + log_debug("tag: %s", tag); + TAILQ_FOREACH(r, env->sc_rules, r_entry) { + if (r->r_tag[0] != '\0' && strcmp(r->r_tag, tag) != 0) + continue; + if (ss != NULL && (!(path->flags & F_PATH_AUTHENTICATED) && ! ruleset_check_source(r->r_sources, ss))) diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c index 2f94ff80f3e..928041e2650 100644 --- a/usr.sbin/smtpd/smtp_session.c +++ b/usr.sbin/smtpd/smtp_session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtp_session.c,v 1.121 2009/10/06 18:20:44 gilles Exp $ */ +/* $OpenBSD: smtp_session.c,v 1.122 2009/10/19 20:48:13 gilles Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> @@ -417,6 +417,7 @@ session_rfc5321_mail_handler(struct session *s, char *args) s->s_msg.id = s->s_id; s->s_msg.session_id = s->s_id; s->s_msg.session_ss = s->s_ss; + (void)strlcpy(s->s_msg.tag, s->s_l->tag, sizeof(s->s_msg.tag)); log_debug("session_rfc5321_mail_handler: sending notification to mfa"); diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h index 2b7920f9b24..90d517e9122 100644 --- a/usr.sbin/smtpd/smtpd.h +++ b/usr.sbin/smtpd/smtpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.h,v 1.148 2009/10/19 20:00:46 gilles Exp $ */ +/* $OpenBSD: smtpd.h,v 1.149 2009/10/19 20:48:13 gilles Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> @@ -41,6 +41,7 @@ #define MAX_LOCALPART_SIZE 65 #define MAX_DOMAINPART_SIZE MAXHOSTNAMELEN #define MAX_ID_SIZE 64 +#define MAX_TAG_SIZE 32 /* return and forward path size */ #define MAX_PATH_SIZE 256 @@ -321,6 +322,7 @@ enum action_type { struct rule { TAILQ_ENTRY(rule) r_entry; + char r_tag[MAX_TAG_SIZE]; int r_accept; struct map *r_sources; TAILQ_HEAD(condlist, cond) r_conditions; @@ -417,6 +419,8 @@ struct message { u_int64_t session_id; u_int64_t batch_id; + char tag[MAX_TAG_SIZE]; + char message_id[MAX_ID_SIZE]; char message_uid[MAX_ID_SIZE]; @@ -522,6 +526,7 @@ struct listener { char ssl_cert_name[PATH_MAX]; struct ssl *ssl; void *ssl_ctx; + char tag[MAX_TAG_SIZE]; TAILQ_ENTRY(listener) entry; }; |