summaryrefslogtreecommitdiff
path: root/usr.sbin/smtpd/makemap.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/smtpd/makemap.c')
-rw-r--r--usr.sbin/smtpd/makemap.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/usr.sbin/smtpd/makemap.c b/usr.sbin/smtpd/makemap.c
new file mode 100644
index 00000000000..27841b43fa6
--- /dev/null
+++ b/usr.sbin/smtpd/makemap.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2008 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/stat.h>
+#include <sys/tree.h>
+#include <sys/queue.h>
+#include <sys/param.h>
+
+#include <sys/socket.h>
+
+#include <ctype.h>
+#include <db.h>
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <util.h>
+
+#include "smtpd.h"
+
+extern char *__progname;
+
+static int usage(void);
+int parse_map(const char *);
+int parse_entry(char *, size_t, size_t);
+
+int alias_parse(struct alias *, char *, size_t);
+
+DB *db;
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ char pathname[MAXPATHLEN];
+ char dbname[MAXPATHLEN];
+ char output[MAXPATHLEN];
+
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch (ch) {
+ default:
+ return usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ return usage();
+
+ bzero(pathname, MAXPATHLEN);
+ snprintf(pathname, MAXPATHLEN, "%s.XXXXX", argv[0]);
+ if (mkdtemp(pathname) == NULL)
+ errx(1, "failed to create temporary directory");
+
+ bzero(dbname, MAXPATHLEN);
+ snprintf(dbname, MAXPATHLEN, "%s/map", pathname);
+ db = dbopen(dbname, O_CREAT|O_EXLOCK|O_RDWR|O_SYNC, 0644, DB_HASH,
+ NULL);
+ if (db == NULL) {
+ warn("dbopen");
+ goto bad;
+ }
+
+ if (! parse_map(argv[0])) {
+ warnx("syntax error in aliases file");
+ goto bad;
+ }
+
+ db->close(db);
+
+ snprintf(output, MAXPATHLEN, "%s.db", argv[0]);
+
+ if (rename(dbname, output) == -1) {
+ warn("rename");
+ goto bad;
+ }
+
+ if (chmod(output, 0644) == -1)
+ err(1, "chmod");
+
+ if (rmdir(pathname) == -1)
+ err(1, "rmdir");
+
+ return EX_OK;
+bad:
+ if (dbname[0] != '\0')
+ if (unlink(dbname) == -1)
+ err(1, "unlink: %s", dbname);
+ if (rmdir(pathname) == -1)
+ err(1, "rmdir: %s", pathname);
+ return 1;
+}
+
+static int
+usage(void)
+{
+ fprintf(stderr, "usage: %s filename\n", __progname);
+ return EX_USAGE;
+}
+
+int
+parse_map(const char *filename)
+{
+ FILE *fp;
+ char *line;
+ size_t len;
+ size_t lineno = 0;
+ char delim[] = { '\\', '\\', '#' };
+
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ errx(1, "failed to open aliases file");
+
+
+ while ((line = fparseln(fp, &len, &lineno, delim, 0)) != NULL) {
+ if (len == 0)
+ continue;
+ parse_entry(line, len, lineno);
+ free(line);
+ }
+
+ fclose(fp);
+ return 1;
+}
+
+int
+parse_entry(char *line, size_t len, size_t lineno)
+{
+ char *name;
+ char *delim;
+ char *rcpt;
+ char *subrcpt;
+ struct alias alias;
+ int ret;
+ DBT key;
+ DBT val;
+
+ name = line;
+ while (*name && isspace(*name))
+ ++name;
+
+ rcpt = delim = strchr(name, ' ');
+ if (rcpt == NULL)
+ rcpt = delim = strchr(name, '\t');
+ if (rcpt == NULL || name == rcpt)
+ goto bad;
+
+
+ *delim-- = 0;
+ while (isspace(*delim))
+ *delim-- = '\0';
+ rcpt++;
+ while (*rcpt && isspace(*rcpt))
+ ++rcpt;
+ if (*rcpt == '\0')
+ goto bad;
+
+ /* At this point, name points to nul-terminate name */
+ for (; (subrcpt = strsep(&rcpt, ",")) != NULL;) {
+ while (*subrcpt && isspace(*subrcpt))
+ ++subrcpt;
+ if (*subrcpt == '\0')
+ continue;
+
+ delim = subrcpt + strlen(subrcpt);
+ delim--;
+ while (isspace(*delim))
+ *delim-- = '\0';
+
+ key.data = name;
+ key.size = strlen(name) + 1;
+
+ if ((ret = db->get(db, &key, &val, 0)) == -1)
+ errx(1, "db->get()");
+
+ if (ret == 1) {
+ val.data = NULL;
+ val.size = 0;
+ }
+
+ if (! alias_parse(&alias, subrcpt, strlen(subrcpt)))
+ goto bad;
+
+ if (val.size == 0) {
+ val.size = sizeof(struct alias);
+ val.data = &alias;
+
+ if ((ret = db->put(db, &key, &val, 0)) == -1)
+ errx(1, "db->get()");
+ }
+ else {
+ void *p;
+
+ p = calloc(val.size + sizeof(alias), 1);
+ if (p == NULL)
+ errx(1, "calloc: memory exhausted");
+ memcpy(p, val.data, val.size);
+ memcpy((u_int8_t *)p + val.size, &alias, sizeof(alias));
+
+ val.data = p;
+ val.size += sizeof(alias);
+
+ if ((ret = db->put(db, &key, &val, 0)) == -1)
+ errx(1, "db->get()");
+
+ free(p);
+ }
+ db->sync(db, 0);
+ }
+
+ return 1;
+
+bad:
+ warnx("line %zd: invalid entry: %s", lineno, line);
+ return 0;
+}