diff options
author | Gilles Chehade <gilles@cvs.openbsd.org> | 2011-05-21 18:43:09 +0000 |
---|---|---|
committer | Gilles Chehade <gilles@cvs.openbsd.org> | 2011-05-21 18:43:09 +0000 |
commit | 35f89f80ba55c80009486aebffad447798242689 (patch) | |
tree | ab9a9f3904eccf5d0d0191cd88e8d74e3c1a7451 | |
parent | a61dcf2a9a2624af763862c5913d08d9bab7ebab (diff) |
until now the map_backend API was not really useful for backends that are
not key/val stores. refactored a bit so that smtpd can really take
advantage of backends. preliminary work for ldap support ;-)
no functionnal change
-rw-r--r-- | usr.sbin/smtpd/makemap/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/smtpd/map.c | 17 | ||||
-rw-r--r-- | usr.sbin/smtpd/map_backend.c | 153 | ||||
-rw-r--r-- | usr.sbin/smtpd/map_backend_db.c | 258 | ||||
-rw-r--r-- | usr.sbin/smtpd/map_backend_stdio.c | 281 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 11 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd/Makefile | 14 |
7 files changed, 564 insertions, 174 deletions
diff --git a/usr.sbin/smtpd/makemap/Makefile b/usr.sbin/smtpd/makemap/Makefile index ed147393622..532b98ad8bf 100644 --- a/usr.sbin/smtpd/makemap/Makefile +++ b/usr.sbin/smtpd/makemap/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.9 2010/04/21 21:04:29 gilles Exp $ +# $OpenBSD: Makefile,v 1.10 2011/05/21 18:43:08 gilles Exp $ .PATH: ${.CURDIR}/.. @@ -16,7 +16,7 @@ CFLAGS+= -Wmissing-declarations CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual CFLAGS+= -Wsign-compare -Wbounded -SRCS= parse.y makemap.c aliases.c expand.c map.c map_backend.c map_parser.c log.c util.c +SRCS= parse.y makemap.c aliases.c expand.c map.c map_backend.c map_backend_db.c map_backend_stdio.c log.c util.c DPADD+= ${LIBUTIL} LDADD+= -lutil .include <bsd.prog.mk> diff --git a/usr.sbin/smtpd/map.c b/usr.sbin/smtpd/map.c index 4ce5a3c1943..57b56bf2b8e 100644 --- a/usr.sbin/smtpd/map.c +++ b/usr.sbin/smtpd/map.c @@ -1,4 +1,4 @@ -/* $OpenBSD: map.c,v 1.23 2011/05/01 12:57:11 eric Exp $ */ +/* $OpenBSD: map.c,v 1.24 2011/05/21 18:43:08 gilles Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> @@ -62,36 +62,23 @@ void * map_lookup(objid_t mapid, char *key, enum map_kind kind) { void *hdl = NULL; - char *result = NULL; char *ret = NULL; - size_t len; struct map *map; struct map_backend *backend = NULL; - struct map_parser *parser = NULL; map = map_find(mapid); if (map == NULL) return NULL; backend = map_backend_lookup(map->m_src); - parser = map_parser_lookup(kind); - hdl = backend->open(map->m_config); if (hdl == NULL) { log_warn("map_lookup: can't open %s", map->m_config); return NULL; } - ret = result = backend->get(hdl, key, &len); - if (ret == NULL) - goto end; - - if (parser->extract != NULL) { - ret = parser->extract(key, result, len); - free(result); - } + ret = backend->lookup(hdl, key, kind); -end: backend->close(hdl); return ret; } diff --git a/usr.sbin/smtpd/map_backend.c b/usr.sbin/smtpd/map_backend.c index c9634c0c09a..4413e4095d1 100644 --- a/usr.sbin/smtpd/map_backend.c +++ b/usr.sbin/smtpd/map_backend.c @@ -1,4 +1,4 @@ -/* $OpenBSD: map_backend.c,v 1.5 2011/04/17 13:36:07 gilles Exp $ */ +/* $OpenBSD: map_backend.c,v 1.6 2011/05/21 18:43:08 gilles Exp $ */ /* * Copyright (c) 2010 Gilles Chehade <gilles@openbsd.org> @@ -37,155 +37,22 @@ struct map_backend *map_backend_lookup(enum map_src); -/* db(3) backend */ -static void *map_db_open(char *); -static void map_db_close(void *); -static char *map_db_get(void *, char *, size_t *); -static int map_db_put(void *, char *, char *); - -/* stdio(3) backend */ -static void *map_stdio_open(char *); -static void map_stdio_close(void *); -static char *map_stdio_get(void *, char *, size_t *); -static int map_stdio_put(void *, char *, char *); - - -struct map_backend map_backends[] = { - { S_DB, - map_db_open, map_db_close, map_db_get, map_db_put }, - { S_PLAIN, - map_stdio_open, map_stdio_close, map_stdio_get, map_stdio_put }, -}; - +extern struct map_backend map_backend_db; +extern struct map_backend map_backend_stdio; struct map_backend * map_backend_lookup(enum map_src source) { - u_int8_t i; + switch (source) { + case S_DB: + return &map_backend_db; - for (i = 0; i < nitems(map_backends); ++i) - if (map_backends[i].source == source) - break; + case S_PLAIN: + return &map_backend_stdio; - if (i == nitems(map_backends)) + default: fatalx("invalid map type"); - - return &map_backends[i]; -} - - -/* db(3) backend */ -static void * -map_db_open(char *src) -{ - return dbopen(src, O_RDONLY, 0600, DB_HASH, NULL); -} - -static void -map_db_close(void *hdl) -{ - DB *db = hdl; - - db->close(db); -} - -static char * -map_db_get(void *hdl, char *key, size_t *len) -{ - int ret; - DBT dbk; - DBT dbv; - DB *db = hdl; - char *result = NULL; - - dbk.data = key; - dbk.size = strlen(dbk.data) + 1; - - if ((ret = db->get(db, &dbk, &dbv, 0)) != 0) - return NULL; - - result = calloc(dbv.size, 1); - if (result == NULL) - fatal("calloc"); - (void)strlcpy(result, dbv.data, dbv.size); - - *len = dbv.size; - - return result; -} - -static int -map_db_put(void *hdl, char *key, char *val) -{ - return 0; -} - - -/* stdio(3) backend */ -static void * -map_stdio_open(char *src) -{ - return fopen(src, "r"); -} - -static void -map_stdio_close(void *hdl) -{ - FILE *fp = hdl; - - fclose(fp); -} - -static char * -map_stdio_get(void *hdl, char *key, size_t *len) -{ - char *buf, *lbuf; - size_t flen; - char *keyp; - char *valp; - FILE *fp = hdl; - char *result = NULL; - - lbuf = NULL; - while ((buf = fgetln(fp, &flen))) { - if (buf[flen - 1] == '\n') - buf[flen - 1] = '\0'; - else { - if ((lbuf = malloc(flen + 1)) == NULL) - err(1, NULL); - memcpy(lbuf, buf, flen); - lbuf[flen] = '\0'; - buf = lbuf; - } - - keyp = buf; - while (isspace((int)*keyp)) - ++keyp; - if (*keyp == '\0' || *keyp == '#') - continue; - - valp = keyp; - strsep(&valp, " \t:"); - if (valp == NULL || valp == keyp) - continue; - - if (strcmp(keyp, key) != 0) - continue; - - result = strdup(valp); - if (result == NULL) - err(1, NULL); - *len = strlen(result); - - break; } - free(lbuf); - return result; -} - -static int -map_stdio_put(void *hdl, char *key, char *val) -{ - return 0; + return NULL; } diff --git a/usr.sbin/smtpd/map_backend_db.c b/usr.sbin/smtpd/map_backend_db.c new file mode 100644 index 00000000000..a74a69c19f9 --- /dev/null +++ b/usr.sbin/smtpd/map_backend_db.c @@ -0,0 +1,258 @@ +/* $OpenBSD: map_backend_db.c,v 1.1 2011/05/21 18:43:08 gilles Exp $ */ + +/* + * Copyright (c) 2011 Gilles Chehade <gilles@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/tree.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <db.h> +#include <ctype.h> +#include <err.h> +#include <event.h> +#include <fcntl.h> +#include <imsg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "smtpd.h" +#include "log.h" + + +/* db(3) backend */ +static void *map_db_open(char *); +static void *map_db_lookup(void *, char *, enum map_kind); +static void map_db_close(void *); + +static char *map_db_get_entry(void *, char *, size_t *); +static void *map_db_secret(char *, char *, size_t); +static void *map_db_alias(char *, char *, size_t); +static void *map_db_virtual(char *, char *, size_t); + + +struct map_backend map_backend_db = { + map_db_open, + map_db_close, + map_db_lookup +}; + + +static void * +map_db_open(char *src) +{ + return dbopen(src, O_RDONLY, 0600, DB_HASH, NULL); +} + +static void +map_db_close(void *hdl) +{ + DB *db = hdl; + + db->close(db); +} + +static void * +map_db_lookup(void *hdl, char *key, enum map_kind kind) +{ + char *line; + size_t len; + void *ret; + + line = map_db_get_entry(hdl, key, &len); + if (line == NULL) + return NULL; + + ret = 0; + switch (kind) { + case K_ALIAS: + ret = map_db_alias(key, line, len); + break; + + case K_SECRET: + ret = map_db_secret(key, line, len); + break; + + case K_VIRTUAL: + ret = map_db_virtual(key, line, len); + break; + + default: + break; + } + + free(line); + + return ret; +} + + +static char * +map_db_get_entry(void *hdl, char *key, size_t *len) +{ + int ret; + DBT dbk; + DBT dbv; + DB *db = hdl; + char *result = NULL; + + dbk.data = key; + dbk.size = strlen(dbk.data) + 1; + + if ((ret = db->get(db, &dbk, &dbv, 0)) != 0) + return NULL; + + result = calloc(dbv.size, 1); + if (result == NULL) + fatal("calloc"); + (void)strlcpy(result, dbv.data, dbv.size); + + *len = dbv.size; + + return result; +} + +static void * +map_db_secret(char *key, char *line, size_t len) +{ + struct map_secret *map_secret = NULL; + char *p; + + /* credentials are stored as user:password */ + if (len < 3) + return NULL; + + /* too big to fit in a smtp session line */ + if (len >= MAX_LINE_SIZE) + return NULL; + + p = strchr(line, ':'); + if (p == NULL) + return NULL; + + if (p == line || p == line + len - 1) + return NULL; + *p++ = '\0'; + + map_secret = calloc(1, sizeof(struct map_secret)); + if (map_secret == NULL) + fatalx("calloc"); + + if (strlcpy(map_secret->username, line, + sizeof(map_secret->username)) >= + sizeof(map_secret->username)) + goto err; + + if (strlcpy(map_secret->password, p, + sizeof(map_secret->password)) >= + sizeof(map_secret->password)) + goto err; + + return map_secret; + +err: + free(map_secret); + return NULL; +} + +static void * +map_db_alias(char *key, char *line, size_t len) +{ + char *subrcpt; + char *endp; + struct map_alias *map_alias = NULL; + struct expandnode expnode; + + map_alias = calloc(1, sizeof(struct map_alias)); + if (map_alias == NULL) + fatalx("calloc"); + + while ((subrcpt = strsep(&line, ",")) != NULL) { + /* subrcpt: strip initial whitespace. */ + while (isspace((int)*subrcpt)) + ++subrcpt; + if (*subrcpt == '\0') + goto error; + + /* subrcpt: strip trailing whitespace. */ + endp = subrcpt + strlen(subrcpt) - 1; + while (subrcpt < endp && isspace((int)*endp)) + *endp-- = '\0'; + + bzero(&expnode, sizeof (struct expandnode)); + if (! alias_parse(&expnode, subrcpt)) + goto error; + + expandtree_increment_node(&map_alias->expandtree, &expnode); + map_alias->nbnodes++; + } + + return map_alias; + +error: + /* free elements in map_alias->expandtree */ + expandtree_free_nodes(&map_alias->expandtree); + free(map_alias); + return NULL; +} + +static void * +map_db_virtual(char *key, char *line, size_t len) +{ + char *subrcpt; + char *endp; + struct map_virtual *map_virtual = NULL; + struct expandnode expnode; + + map_virtual = calloc(1, sizeof(struct map_virtual)); + if (map_virtual == NULL) + fatalx("calloc"); + + /* domain key, discard value */ + if (strchr(key, '@') == NULL) + return map_virtual; + + while ((subrcpt = strsep(&line, ",")) != NULL) { + /* subrcpt: strip initial whitespace. */ + while (isspace((int)*subrcpt)) + ++subrcpt; + if (*subrcpt == '\0') + goto error; + + /* subrcpt: strip trailing whitespace. */ + endp = subrcpt + strlen(subrcpt) - 1; + while (subrcpt < endp && isspace((int)*endp)) + *endp-- = '\0'; + + bzero(&expnode, sizeof (struct expandnode)); + if (! alias_parse(&expnode, subrcpt)) + goto error; + + expandtree_increment_node(&map_virtual->expandtree, &expnode); + map_virtual->nbnodes++; + } + + return map_virtual; + +error: + /* free elements in map_virtual->expandtree */ + expandtree_free_nodes(&map_virtual->expandtree); + free(map_virtual); + return NULL; +} diff --git a/usr.sbin/smtpd/map_backend_stdio.c b/usr.sbin/smtpd/map_backend_stdio.c new file mode 100644 index 00000000000..80c601d28af --- /dev/null +++ b/usr.sbin/smtpd/map_backend_stdio.c @@ -0,0 +1,281 @@ +/* $OpenBSD: map_backend_stdio.c,v 1.1 2011/05/21 18:43:08 gilles Exp $ */ + +/* + * Copyright (c) 2011 Gilles Chehade <gilles@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/tree.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <db.h> +#include <ctype.h> +#include <err.h> +#include <event.h> +#include <fcntl.h> +#include <imsg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "smtpd.h" +#include "log.h" + + +/* stdio(3) backend */ +static void *map_stdio_open(char *); +static void *map_stdio_lookup(void *, char *, enum map_kind); +static void map_stdio_close(void *); + +static char *map_stdio_get_entry(void *, char *, size_t *); +static void *map_stdio_secret(char *, char *, size_t); +static void *map_stdio_alias(char *, char *, size_t); +static void *map_stdio_virtual(char *, char *, size_t); + + +struct map_backend map_backend_stdio = { + map_stdio_open, + map_stdio_close, + map_stdio_lookup +}; + + +static void * +map_stdio_open(char *src) +{ + return fopen(src, "r"); +} + +static void +map_stdio_close(void *hdl) +{ + FILE *fp = hdl; + + fclose(fp); +} + +static void * +map_stdio_lookup(void *hdl, char *key, enum map_kind kind) +{ + char *line; + size_t len; + struct map_alias *ma; + + line = map_stdio_get_entry(hdl, key, &len); + if (line == NULL) + return NULL; + + ma = NULL; + switch (kind) { + case K_ALIAS: + ma = map_stdio_alias(key, line, len); + break; + + case K_SECRET: + ma = map_stdio_secret(key, line, len); + break; + + case K_VIRTUAL: + ma = map_stdio_virtual(key, line, len); + break; + + default: + break; + } + + free(line); + + return ma; +} + +static char * +map_stdio_get_entry(void *hdl, char *key, size_t *len) +{ + char *buf, *lbuf; + size_t flen; + char *keyp; + char *valp; + FILE *fp = hdl; + char *result = NULL; + + lbuf = NULL; + while ((buf = fgetln(fp, &flen))) { + if (buf[flen - 1] == '\n') + buf[flen - 1] = '\0'; + else { + if ((lbuf = malloc(flen + 1)) == NULL) + err(1, NULL); + memcpy(lbuf, buf, flen); + lbuf[flen] = '\0'; + buf = lbuf; + } + + keyp = buf; + while (isspace((int)*keyp)) + ++keyp; + if (*keyp == '\0' || *keyp == '#') + continue; + + valp = keyp; + strsep(&valp, " \t:"); + if (valp == NULL || valp == keyp) + continue; + + if (strcmp(keyp, key) != 0) + continue; + + result = strdup(valp); + if (result == NULL) + err(1, NULL); + *len = strlen(result); + + break; + } + free(lbuf); + + return result; +} + + +static void * +map_stdio_secret(char *key, char *line, size_t len) +{ + struct map_secret *map_secret = NULL; + char *p; + + /* credentials are stored as user:password */ + if (len < 3) + return NULL; + + /* too big to fit in a smtp session line */ + if (len >= MAX_LINE_SIZE) + return NULL; + + p = strchr(line, ':'); + if (p == NULL) + return NULL; + + if (p == line || p == line + len - 1) + return NULL; + *p++ = '\0'; + + map_secret = calloc(1, sizeof(struct map_secret)); + if (map_secret == NULL) + fatalx("calloc"); + + if (strlcpy(map_secret->username, line, + sizeof(map_secret->username)) >= + sizeof(map_secret->username)) + goto err; + + if (strlcpy(map_secret->password, p, + sizeof(map_secret->password)) >= + sizeof(map_secret->password)) + goto err; + + return map_secret; + +err: + free(map_secret); + return NULL; +} + +static void * +map_stdio_alias(char *key, char *line, size_t len) +{ + char *subrcpt; + char *endp; + struct map_alias *map_alias = NULL; + struct expandnode expnode; + + map_alias = calloc(1, sizeof(struct map_alias)); + if (map_alias == NULL) + fatalx("calloc"); + + while ((subrcpt = strsep(&line, ",")) != NULL) { + /* subrcpt: strip initial whitespace. */ + while (isspace((int)*subrcpt)) + ++subrcpt; + if (*subrcpt == '\0') + goto error; + + /* subrcpt: strip trailing whitespace. */ + endp = subrcpt + strlen(subrcpt) - 1; + while (subrcpt < endp && isspace((int)*endp)) + *endp-- = '\0'; + + bzero(&expnode, sizeof (struct expandnode)); + if (! alias_parse(&expnode, subrcpt)) + goto error; + + expandtree_increment_node(&map_alias->expandtree, &expnode); + map_alias->nbnodes++; + } + + return map_alias; + +error: + /* free elements in map_alias->expandtree */ + expandtree_free_nodes(&map_alias->expandtree); + free(map_alias); + return NULL; +} + +static void * +map_stdio_virtual(char *key, char *line, size_t len) +{ + char *subrcpt; + char *endp; + struct map_virtual *map_virtual = NULL; + struct expandnode expnode; + + map_virtual = calloc(1, sizeof(struct map_virtual)); + if (map_virtual == NULL) + fatalx("calloc"); + + /* domain key, discard value */ + if (strchr(key, '@') == NULL) + return map_virtual; + + while ((subrcpt = strsep(&line, ",")) != NULL) { + /* subrcpt: strip initial whitespace. */ + while (isspace((int)*subrcpt)) + ++subrcpt; + if (*subrcpt == '\0') + goto error; + + /* subrcpt: strip trailing whitespace. */ + endp = subrcpt + strlen(subrcpt) - 1; + while (subrcpt < endp && isspace((int)*endp)) + *endp-- = '\0'; + + bzero(&expnode, sizeof (struct expandnode)); + if (! alias_parse(&expnode, subrcpt)) + goto error; + + expandtree_increment_node(&map_virtual->expandtree, &expnode); + map_virtual->nbnodes++; + } + + return map_virtual; + +error: + /* free elements in map_virtual->expandtree */ + expandtree_free_nodes(&map_virtual->expandtree); + free(map_virtual); + return NULL; +} diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h index eeca47252b0..10cfdeeb6d3 100644 --- a/usr.sbin/smtpd/smtpd.h +++ b/usr.sbin/smtpd/smtpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.h,v 1.224 2011/05/17 18:54:32 gilles Exp $ */ +/* $OpenBSD: smtpd.h,v 1.225 2011/05/21 18:43:08 gilles Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> @@ -276,18 +276,13 @@ struct map { TAILQ_HEAD(mapel_list, mapel) m_contents; }; + struct map_backend { - enum map_src source; void *(*open)(char *); void (*close)(void *); - char *(*get)(void *, char *, size_t *); - int (*put)(void *, char *, char *); + void *(*lookup)(void *, char *, enum map_kind); }; -struct map_parser { - enum map_kind kind; - void *(*extract)(char *, char *, size_t); -}; enum cond_type { C_ALL, diff --git a/usr.sbin/smtpd/smtpd/Makefile b/usr.sbin/smtpd/smtpd/Makefile index 83d3e4f4cb4..758e3c00dc8 100644 --- a/usr.sbin/smtpd/smtpd/Makefile +++ b/usr.sbin/smtpd/smtpd/Makefile @@ -1,14 +1,16 @@ -# $OpenBSD: Makefile,v 1.27 2011/05/17 18:54:32 gilles Exp $ +# $OpenBSD: Makefile,v 1.28 2011/05/21 18:43:08 gilles Exp $ PROG= smtpd SRCS= aliases.c auth_backend.c bounce.c client.c \ config.c control.c dns.c expand.c forward.c \ lka.c lka_session.c log.c map.c map_backend.c \ - map_parser.c mda.c mfa.c mta.c parse.y queue.c \ - queue_shared.c ruleset.c runner.c smtp.c smtp_session.c \ - smtpd.c ssl.c ssl_privsep.c util.c asr.c print.c pack.c \ - dname.c res_random.c sockaddr.c ramqueue.c \ - queue_backend.c queue_fsqueue.c user_backend.c + map_backend_db.c map_backend_stdio.c \ + mda.c mfa.c mta.c parse.y \ + queue.c queue_shared.c ruleset.c runner.c smtp.c \ + smtp_session.c smtpd.c ssl.c ssl_privsep.c util.c asr.c \ + print.c pack.c dname.c res_random.c sockaddr.c \ + ramqueue.c queue_backend.c queue_fsqueue.c \ + user_backend.c MAN= smtpd.8 smtpd.conf.5 BINDIR= /usr/sbin |