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.c258
1 files changed, 145 insertions, 113 deletions
diff --git a/usr.sbin/smtpd/makemap.c b/usr.sbin/smtpd/makemap.c
index a291b805301..d8870293d9e 100644
--- a/usr.sbin/smtpd/makemap.c
+++ b/usr.sbin/smtpd/makemap.c
@@ -1,3 +1,5 @@
+/* $OpenBSD: makemap.c,v 1.3 2008/12/17 22:59:36 jacekm Exp $ */
+
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
*
@@ -32,7 +34,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sysexits.h>
#include <unistd.h>
#include <util.h>
@@ -40,85 +41,85 @@
extern char *__progname;
-static int usage(void);
-int parse_map(const char *);
-int parse_entry(char *, size_t, size_t);
+__dead void usage(void);
+int parse_map(char *);
+int parse_entry(char *, size_t, size_t);
DB *db;
+char *source;
+
+enum program {
+ P_MAKEMAP,
+ P_NEWALIASES
+} mode;
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();
- }
+ char dest[MAXPATHLEN];
+
+ mode = strcmp(__progname, "newaliases") ? P_MAKEMAP : P_NEWALIASES;
+
+ switch (mode) {
+ case P_MAKEMAP:
+ if (argc != 2)
+ usage();
+ source = argv[1];
+ break;
+ case P_NEWALIASES:
+ if (argc != 1)
+ usage();
+ if (geteuid())
+ errx(1, "need root privileges");
+ source = PATH_ALIASES;
+ break;
+ default:
+ abort();
}
- argc -= optind;
- argv += optind;
- if (argc != 1)
- return usage();
+ if (! bsnprintf(dbname, MAXPATHLEN, "%s.db.XXXXXXXXXXX", source))
+ errx(1, "path too long");
+ if (mkstemp(dbname) == -1)
+ err(1, "mkstemp");
- 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);
+ db = dbopen(dbname, O_EXLOCK|O_RDWR|O_SYNC, 0644, DB_HASH, NULL);
if (db == NULL) {
- warn("dbopen");
+ warn("dbopen: %s", dbname);
goto bad;
}
- if (! parse_map(argv[0])) {
- warnx("syntax error in aliases file");
+ if (! parse_map(source))
+ goto bad;
+
+ if (db->close(db) == -1) {
+ warn("dbclose: %s", dbname);
goto bad;
}
- db->close(db);
+ if (chmod(dbname, 0644) == -1) {
+ warn("chmod: %s", dbname);
+ goto bad;
+ }
- snprintf(output, MAXPATHLEN, "%s.db", argv[0]);
+ if (! bsnprintf(dest, MAXPATHLEN, "%s.db", source)) {
+ warnx("path too long");
+ goto bad;
+ }
- if (rename(dbname, output) == -1) {
+ if (rename(dbname, dest) == -1) {
warn("rename");
goto bad;
}
- if (chmod(output, 0644) == -1)
- err(1, "chmod");
-
- if (rmdir(pathname) == -1)
- err(1, "rmdir");
-
- return EX_OK;
+ return 0;
bad:
- if (dbname[0] != '\0')
- if (unlink(dbname) == -1)
- err(1, "unlink: %s", dbname);
- if (rmdir(pathname) == -1)
- err(1, "rmdir: %s", pathname);
+ unlink(dbname);
return 1;
}
-static int
-usage(void)
-{
- fprintf(stderr, "usage: %s filename\n", __progname);
- return EX_USAGE;
-}
-
int
-parse_map(const char *filename)
+parse_map(char *filename)
{
FILE *fp;
char *line;
@@ -127,14 +128,19 @@ parse_map(const char *filename)
char delim[] = { '\\', '\\', '#' };
fp = fopen(filename, "r");
- if (fp == NULL)
- errx(1, "failed to open aliases file");
-
+ if (fp == NULL) {
+ warn("%s", filename);
+ return 0;
+ }
while ((line = fparseln(fp, &len, &lineno, delim, 0)) != NULL) {
if (len == 0)
continue;
- parse_entry(line, len, lineno);
+ if (! parse_entry(line, len, lineno)) {
+ free(line);
+ fclose(fp);
+ return 0;
+ }
free(line);
}
@@ -146,90 +152,116 @@ int
parse_entry(char *line, size_t len, size_t lineno)
{
char *name;
- char *delim;
char *rcpt;
+ char *endp;
char *subrcpt;
- struct alias alias;
- int ret;
DBT key;
DBT val;
name = line;
- while (*name && isspace(*name))
- ++name;
-
- rcpt = delim = strchr(name, ' ');
+ switch (mode) {
+ case P_MAKEMAP:
+ rcpt = strchr(line, ' ');
+ if (rcpt == NULL)
+ rcpt = strchr(line, '\t');
+ break;
+ case P_NEWALIASES:
+ rcpt = strchr(line, ':');
+ break;
+ default:
+ abort();
+ }
if (rcpt == NULL)
- rcpt = delim = strchr(name, '\t');
- if (rcpt == NULL || name == rcpt)
goto bad;
+ *rcpt++ = '\0';
-
- *delim-- = 0;
- while (isspace(*delim))
- *delim-- = '\0';
- rcpt++;
- while (*rcpt && isspace(*rcpt))
- ++rcpt;
- if (*rcpt == '\0')
+ /* name: strip initial whitespace. */
+ while (isspace(*name))
+ ++name;
+ if (*name == '\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';
+ /* name: strip trailing whitespace. */
+ endp = name + strlen(name) - 1;
+ while (name < endp && isspace(*endp))
+ *endp-- = '\0';
+
+ /* Check for dups. */
+ key.data = name;
+ key.size = strlen(name) + 1;
+ if (db->get(db, &key, &val, 0) == 0) {
+ warnx("%s:%zd: duplicate entry for %s", source, lineno,
+ key.data);
+ return 0;
+ }
- key.data = name;
- key.size = strlen(name) + 1;
+ /* At this point name and rcpt are non-zero nul-terminated strings. */
+ while ((subrcpt = strsep(&rcpt, ",")) != NULL) {
+ struct alias alias;
+ void *p;
- if ((ret = db->get(db, &key, &val, 0)) == -1)
- errx(1, "db->get()");
+ /* subrcpt: strip initial whitespace. */
+ while (isspace(*subrcpt))
+ ++subrcpt;
+ if (*subrcpt == '\0')
+ goto bad;
- if (ret == 1) {
- val.data = NULL;
- val.size = 0;
- }
+ /* subrcpt: strip trailing whitespace. */
+ endp = subrcpt + strlen(subrcpt) - 1;
+ while (subrcpt < endp && isspace(*endp))
+ *endp-- = '\0';
if (! alias_parse(&alias, 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()");
+ key.data = name;
+ key.size = strlen(name) + 1;
+ val.data = NULL;
+ val.size = 0;
+ if (db->get(db, &key, &val, 0) == -1) {
+ warn("dbget");
+ return 0;
}
- 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()");
+ p = calloc(1, val.size + sizeof(struct alias));
+ if (p == NULL) {
+ warn("calloc");
+ return 0;
+ }
+ memcpy(p, val.data, val.size);
+ memcpy((u_int8_t *)p + val.size, &alias, sizeof(struct alias));
+ val.data = p;
+ val.size += sizeof(struct alias);
+ if (db->put(db, &key, &val, 0) == -1) {
+ warn("dbput");
free(p);
+ return 0;
}
- db->sync(db, 0);
+
+ free(p);
}
return 1;
bad:
- warnx("line %zd: invalid entry: %s", lineno, line);
+ /* The actual line is not printed; it may be mangled by above code. */
+ warnx("%s:%zd: invalid entry", source, lineno);
return 0;
}
+
+void
+usage(void)
+{
+ switch (mode) {
+ case P_MAKEMAP:
+ fprintf(stderr, "usage: %s file\n", __progname);
+ break;
+ case P_NEWALIASES:
+ fprintf(stderr, "usage: %s\n", __progname);
+ break;
+ default:
+ abort();
+ }
+ exit(1);
+}