summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreric <eric@openbsd.org>2014-07-09 09:53:37 +0000
committereric <eric@openbsd.org>2014-07-09 09:53:37 +0000
commitbf397b351e8bd1e0668f10b72e93b2cd6fb0eed3 (patch)
tree8a0d4e20f7f4aeff645e065d0e8f48d5aa1ab63d
parentHopefully we are calculating the pkg size correctly by now; (diff)
downloadwireguard-openbsd-bf397b351e8bd1e0668f10b72e93b2cd6fb0eed3.tar.xz
wireguard-openbsd-bf397b351e8bd1e0668f10b72e93b2cd6fb0eed3.zip
config parser improvements:
- fail if the same option is specified multiple times on a listener - prompt for queue encryption key after config parsing, not during. - add ip addresses to localnames table - prepare for filters
-rw-r--r--usr.sbin/smtpd/parse.y273
-rw-r--r--usr.sbin/smtpd/smtpd.c40
-rw-r--r--usr.sbin/smtpd/smtpd.h3
3 files changed, 252 insertions, 64 deletions
diff --git a/usr.sbin/smtpd/parse.y b/usr.sbin/smtpd/parse.y
index 6a964aaf8f6..a3f6d38737e 100644
--- a/usr.sbin/smtpd/parse.y
+++ b/usr.sbin/smtpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.144 2014/07/08 21:58:33 eric Exp $ */
+/* $OpenBSD: parse.y,v 1.145 2014/07/09 09:53:37 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -98,18 +98,34 @@ struct listener l;
struct mta_limits *limits;
static struct pki *pki;
+enum listen_options {
+ LO_FAMILY = 0x01,
+ LO_PORT = 0x02,
+ LO_SSL = 0x04,
+ LO_FILTER = 0x08,
+ LO_PKI = 0x10,
+ LO_AUTH = 0x20,
+ LO_TAG = 0x40,
+ LO_HOSTNAME = 0x80,
+ LO_HOSTNAMES = 0x100,
+ LO_MASKSOURCE = 0x200,
+};
+
static struct listen_opts {
char *ifx;
int family;
in_port_t port;
uint16_t ssl;
+ char *filtername;
char *pki;
uint16_t auth;
struct table *authtable;
char *tag;
char *hostname;
struct table *hostnametable;
- uint16_t flags;
+ uint16_t flags;
+
+ uint16_t options;
} listen_opts;
static void create_listener(struct listenerlist *, struct listen_opts *);
@@ -120,7 +136,8 @@ struct listener *host_v6(const char *, in_port_t);
int host_dns(struct listenerlist *, struct listen_opts *);
int host(struct listenerlist *, struct listen_opts *);
int interface(struct listenerlist *, struct listen_opts *);
-void set_localaddrs(void);
+void set_local(const char *);
+void set_localaddrs(struct table *);
int delaytonum(char *);
int is_if_in_group(const char *, const char *);
@@ -349,11 +366,31 @@ pki : opt_pki pki
| /* empty */
;
-opt_listen : INET4 { listen_opts.family = AF_INET; }
- | INET6 { listen_opts.family = AF_INET6; }
+opt_listen : INET4 {
+ if (listen_opts.options & LO_FAMILY) {
+ yyerror("address family already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_FAMILY;
+ listen_opts.family = AF_INET;
+ }
+ | INET6 {
+ if (listen_opts.options & LO_FAMILY) {
+ yyerror("address family already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_FAMILY;
+ listen_opts.family = AF_INET6;
+ }
| PORT STRING {
struct servent *servent;
+ if (listen_opts.options & LO_PORT) {
+ yyerror("port already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_PORT;
+
servent = getservbyname($2, "tcp");
if (servent == NULL) {
yyerror("invalid port: %s", $2);
@@ -364,30 +401,123 @@ opt_listen : INET4 { listen_opts.family = AF_INET; }
listen_opts.port = ntohs(servent->s_port);
}
| PORT NUMBER {
+ if (listen_opts.options & LO_PORT) {
+ yyerror("port already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_PORT;
+
if ($2 <= 0 || $2 >= (int)USHRT_MAX) {
yyerror("invalid port: %" PRId64, $2);
YYERROR;
}
listen_opts.port = $2;
}
- | SMTPS { listen_opts.ssl = F_SMTPS; }
- | SMTPS VERIFY { listen_opts.ssl = F_SMTPS|F_TLS_VERIFY; }
- | TLS { listen_opts.ssl = F_STARTTLS; }
- | SECURE { listen_opts.ssl = F_SSL; }
- | TLS_REQUIRE { listen_opts.ssl = F_STARTTLS|F_STARTTLS_REQUIRE; }
- | TLS_REQUIRE VERIFY { listen_opts.ssl = F_STARTTLS|F_STARTTLS_REQUIRE|F_TLS_VERIFY; }
- | PKI STRING { listen_opts.pki = $2; }
- | AUTH { listen_opts.auth = F_AUTH|F_AUTH_REQUIRE; }
- | AUTH_OPTIONAL { listen_opts.auth = F_AUTH; }
+ | FILTER STRING {
+ if (listen_opts.options & LO_FILTER) {
+ yyerror("filter already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_FILTER;
+ listen_opts.filtername = $2;
+ }
+ | SMTPS {
+ if (listen_opts.options & LO_SSL) {
+ yyerror("TLS mode already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_SSL;
+ listen_opts.ssl = F_SMTPS;
+ }
+ | SMTPS VERIFY {
+ if (listen_opts.options & LO_SSL) {
+ yyerror("TLS mode already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_SSL;
+ listen_opts.ssl = F_SMTPS|F_TLS_VERIFY;
+ }
+ | TLS {
+ if (listen_opts.options & LO_SSL) {
+ yyerror("TLS mode already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_SSL;
+ listen_opts.ssl = F_STARTTLS;
+ }
+ | SECURE {
+ if (listen_opts.options & LO_SSL) {
+ yyerror("TLS mode already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_SSL;
+ listen_opts.ssl = F_SSL;
+ }
+ | TLS_REQUIRE {
+ if (listen_opts.options & LO_SSL) {
+ yyerror("TLS mode already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_SSL;
+ listen_opts.ssl = F_STARTTLS|F_STARTTLS_REQUIRE;
+ }
+ | TLS_REQUIRE VERIFY {
+ if (listen_opts.options & LO_SSL) {
+ yyerror("TLS mode already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_SSL;
+ listen_opts.ssl = F_STARTTLS|F_STARTTLS_REQUIRE|F_TLS_VERIFY;
+ }
+ | PKI STRING {
+ if (listen_opts.options & LO_PKI) {
+ yyerror("pki already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_PKI;
+ listen_opts.pki = $2;
+ }
+ | AUTH {
+ if (listen_opts.options & LO_AUTH) {
+ yyerror("auth already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_AUTH;
+ listen_opts.auth = F_AUTH|F_AUTH_REQUIRE;
+ }
+ | AUTH_OPTIONAL {
+ if (listen_opts.options & LO_AUTH) {
+ yyerror("auth already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_AUTH;
+ listen_opts.auth = F_AUTH;
+ }
| AUTH tables {
+ if (listen_opts.options & LO_AUTH) {
+ yyerror("auth already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_AUTH;
listen_opts.authtable = $2;
listen_opts.auth = F_AUTH|F_AUTH_REQUIRE;
}
| AUTH_OPTIONAL tables {
+ if (listen_opts.options & LO_AUTH) {
+ yyerror("auth already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_AUTH;
listen_opts.authtable = $2;
listen_opts.auth = F_AUTH;
}
| TAG STRING {
+ if (listen_opts.options & LO_TAG) {
+ yyerror("tag already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_TAG;
+
if (strlen($2) >= MAX_TAG_SIZE) {
yyerror("tag name too long");
free($2);
@@ -395,9 +525,24 @@ opt_listen : INET4 { listen_opts.family = AF_INET; }
}
listen_opts.tag = $2;
}
- | HOSTNAME STRING { listen_opts.hostname = $2; }
+ | HOSTNAME STRING {
+ if (listen_opts.options & LO_HOSTNAME) {
+ yyerror("hostname already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_HOSTNAME;
+
+ listen_opts.hostname = $2;
+ }
| HOSTNAMES tables {
struct table *t = $2;
+
+ if (listen_opts.options & LO_HOSTNAMES) {
+ yyerror("hostnames already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_HOSTNAMES;
+
if (! table_check_use(t, T_DYNAMIC|T_HASH, K_ADDRNAME)) {
yyerror("invalid use of table \"%s\" as "
"HOSTNAMES parameter", t->t_name);
@@ -405,7 +550,14 @@ opt_listen : INET4 { listen_opts.family = AF_INET; }
}
listen_opts.hostnametable = t;
}
- | MASK_SOURCE { listen_opts.flags |= F_MASK_SOURCE; }
+ | MASK_SOURCE {
+ if (listen_opts.options & LO_MASKSOURCE) {
+ yyerror("mask-source already specified");
+ YYERROR;
+ }
+ listen_opts.options |= LO_MASKSOURCE;
+ listen_opts.flags |= F_MASK_SOURCE;
+ }
;
listen : opt_listen listen
@@ -541,40 +693,12 @@ main : BOUNCEWARN {
conf->sc_queue_flags |= QUEUE_COMPRESSION;
}
| QUEUE ENCRYPTION {
- char *password;
-
- password = getpass("queue key: ");
- if (password == NULL) {
- yyerror("getpass() error");
- YYERROR;
- }
- conf->sc_queue_key = strdup(password);
- memset(password, 0, strlen(password));
- if (conf->sc_queue_key == NULL) {
- yyerror("memory exhausted");
- YYERROR;
- }
conf->sc_queue_flags |= QUEUE_ENCRYPTION;
-
}
| QUEUE ENCRYPTION KEY STRING {
- char *buf;
- char *lbuf;
- size_t len;
-
- if (strcasecmp($4, "stdin") == 0 ||
- strcasecmp($4, "-") == 0) {
- lbuf = NULL;
- buf = fgetln(stdin, &len);
- if (buf[len - 1] == '\n') {
- lbuf = calloc(len, 1);
- memcpy(lbuf, buf, len-1);
- }
- else {
- lbuf = calloc(len+1, 1);
- memcpy(lbuf, buf, len);
- }
- conf->sc_queue_key = lbuf;
+ if (strcasecmp($4, "stdin") == 0 || strcasecmp($4, "-") == 0) {
+ conf->sc_queue_key = "stdin";
+ free($4);
}
else
conf->sc_queue_key = $4;
@@ -839,6 +963,13 @@ deliver_action : DELIVER TO MAILDIR {
fatal("pathname too long");
free($4);
}
+ | DELIVER TO MBOX {
+ rule->r_action = A_MBOX;
+ if (strlcpy(rule->r_value.buffer, _PATH_MAILDIR "/%u",
+ sizeof(rule->r_value.buffer))
+ >= sizeof(rule->r_value.buffer))
+ fatal("pathname too long");
+ }
| DELIVER TO LMTP STRING {
rule->r_action = A_LMTP;
if (strchr($4, ':') || $4[0] == '/') {
@@ -850,14 +981,7 @@ deliver_action : DELIVER TO MAILDIR {
fatal("invalid lmtp destination");
free($4);
}
- | DELIVER TO MBOX {
- rule->r_action = A_MBOX;
- if (strlcpy(rule->r_value.buffer, _PATH_MAILDIR "/%u",
- sizeof(rule->r_value.buffer))
- >= sizeof(rule->r_value.buffer))
- fatal("pathname too long");
- }
- | DELIVER TO MDA STRING {
+ | DELIVER TO MDA STRING {
rule->r_action = A_MDA;
if (strlcpy(rule->r_value.buffer, $4,
sizeof(rule->r_value.buffer))
@@ -1597,12 +1721,7 @@ parse_config(struct smtpd *x_conf, const char *filename, int opts)
/*
* declare special "localhost", "anyhost" and "localnames" tables
*/
- set_localaddrs();
-
- t = table_create("static", "<localnames>", NULL, NULL);
- t->t_type = T_LIST;
- table_add(t, "localhost", NULL);
- table_add(t, hostname, NULL);
+ set_local(hostname);
t = table_create("static", "<anydestination>", NULL, NULL);
t->t_type = T_LIST;
@@ -1781,6 +1900,14 @@ config_listener(struct listener *h, struct listen_opts *lo)
if (lo->hostname == NULL)
lo->hostname = conf->sc_hostname;
+ if (lo->filtername) {
+ if (dict_get(&conf->sc_filters, lo->filtername) == NULL) {
+ log_warnx("undefined filter: %s", lo->filtername);
+ fatalx(NULL);
+ }
+ (void)strlcpy(h->filter, lo->filtername, sizeof(h->filter));
+ }
+
h->pki_name[0] = '\0';
if (lo->authtable != NULL)
@@ -1974,13 +2101,27 @@ interface(struct listenerlist *al, struct listen_opts *lo)
}
void
-set_localaddrs(void)
+set_local(const char *hostname)
+{
+ struct table *t;
+
+ t = table_create("static", "<localnames>", NULL, NULL);
+ t->t_type = T_LIST;
+ table_add(t, "localhost", NULL);
+ table_add(t, hostname, NULL);
+
+ set_localaddrs(t);
+}
+
+void
+set_localaddrs(struct table *localnames)
{
struct ifaddrs *ifap, *p;
struct sockaddr_storage ss;
struct sockaddr_in *sain;
struct sockaddr_in6 *sin6;
struct table *t;
+ char buf[NI_MAXHOST + 5];
t = table_create("static", "<anyhost>", NULL, NULL);
table_add(t, "local", NULL);
@@ -2002,6 +2143,9 @@ set_localaddrs(void)
*sain = *(struct sockaddr_in *)p->ifa_addr;
sain->sin_len = sizeof(struct sockaddr_in);
table_add(t, ss_to_text(&ss), NULL);
+ table_add(localnames, ss_to_text(&ss), NULL);
+ (void)snprintf(buf, sizeof buf, "[%s]", ss_to_text(&ss));
+ table_add(localnames, buf, NULL);
break;
case AF_INET6:
@@ -2009,6 +2153,11 @@ set_localaddrs(void)
*sin6 = *(struct sockaddr_in6 *)p->ifa_addr;
sin6->sin6_len = sizeof(struct sockaddr_in6);
table_add(t, ss_to_text(&ss), NULL);
+ table_add(localnames, ss_to_text(&ss), NULL);
+ (void)snprintf(buf, sizeof buf, "[%s]", ss_to_text(&ss));
+ table_add(localnames, buf, NULL);
+ (void)snprintf(buf, sizeof buf, "[ipv6:%s]", ss_to_text(&ss));
+ table_add(localnames, buf, NULL);
break;
}
}
diff --git a/usr.sbin/smtpd/smtpd.c b/usr.sbin/smtpd/smtpd.c
index ebfb1cd373a..3a11a2a49eb 100644
--- a/usr.sbin/smtpd/smtpd.c
+++ b/usr.sbin/smtpd/smtpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.c,v 1.231 2014/07/08 21:55:53 eric Exp $ */
+/* $OpenBSD: smtpd.c,v 1.232 2014/07/09 09:53:37 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -613,6 +613,44 @@ main(int argc, char *argv[])
if (env->sc_stat == NULL)
errx(1, "could not find stat backend \"%s\"", backend_stat);
+ if (env->sc_queue_flags & QUEUE_ENCRYPTION) {
+ if (env->sc_queue_key == NULL) {
+ char *password;
+
+ password = getpass("queue key: ");
+ if (password == NULL)
+ err(1, "getpass");
+
+ env->sc_queue_key = strdup(password);
+ memset(password, 0, strlen(password));
+ if (env->sc_queue_key == NULL)
+ err(1, "strdup");
+ }
+ else {
+ char *buf;
+ char *lbuf;
+ size_t len;
+
+ if (strcasecmp(env->sc_queue_key, "stdin") == 0) {
+ lbuf = NULL;
+ buf = fgetln(stdin, &len);
+ if (buf[len - 1] == '\n') {
+ lbuf = calloc(len, 1);
+ if (lbuf == NULL)
+ err(1, "calloc");
+ memcpy(lbuf, buf, len-1);
+ }
+ else {
+ lbuf = calloc(len+1, 1);
+ if (lbuf == NULL)
+ err(1, "calloc");
+ memcpy(lbuf, buf, len);
+ }
+ env->sc_queue_key = lbuf;
+ }
+ }
+ }
+
if (env->sc_queue_flags & QUEUE_COMPRESSION)
env->sc_comp = compress_backend_lookup("gzip");
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 9b0cb2ef9e0..c4eabaedf9a 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.465 2014/07/08 21:58:33 eric Exp $ */
+/* $OpenBSD: smtpd.h,v 1.466 2014/07/09 09:53:37 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -520,6 +520,7 @@ struct listener {
struct event ev;
char pki_name[SMTPD_MAXPATHLEN];
char tag[MAX_TAG_SIZE];
+ char filter[SMTPD_MAXPATHLEN];
char authtable[SMTPD_MAXLINESIZE];
char hostname[SMTPD_MAXHOSTNAMELEN];
char hostnametable[SMTPD_MAXPATHLEN];