diff options
-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; }; |