Hi,

This is to (re)initiate discussion about implementing newaliases/makemap
as smtpctl subcommands (issue #354). This diff proposes a way to
track the tables used for alias and then generate the db. The
implementation is borrowed from makemap.c minus the global state.
Makemap isn't done yet as I would like to know if this the right
way to proceed.

diff --git a/smtpd/enqueue.c b/smtpd/enqueue.c
index d97620f..ed73a9b 100644
--- a/smtpd/enqueue.c
+++ b/smtpd/enqueue.c
@@ -97,10 +97,10 @@ struct {
 
 #define WSP(c)                 (c == ' ' || c == '\t')
 
-int      verbose = 0;
-char     host[SMTPD_MAXHOSTNAMELEN];
-char    *user = NULL;
-time_t   timestamp;
+int            verbose = 0;
+static char    host[SMTPD_MAXHOSTNAMELEN];
+char           *user = NULL;
+time_t         timestamp;
 
 struct {
        int       fd;
diff --git a/smtpd/parse.y b/smtpd/parse.y
index 887e864..718aeb8 100644
--- a/smtpd/parse.y
+++ b/smtpd/parse.y
@@ -759,6 +759,7 @@ tables              : tablenew                      { $$ = 
$1; }
                ;
 
 alias          : ALIAS tables                  {
+                       char            *association;
                        struct table   *t = $2;
 
                        if (! table_check_use(t, T_DYNAMIC|T_HASH, K_ALIAS)) {
@@ -767,6 +768,9 @@ alias               : ALIAS tables                  {
                                YYERROR;
                        }
 
+                       association = xmalloc(32 * sizeof(char), "parse_alias");
+                       strlcpy(association, "alias", sizeof(association));
+                       dict_xset(&t->t_dict, "association", association);
                        $$ = t;
                }
                ;
diff --git a/smtpd/smtpctl.c b/smtpd/smtpctl.c
index ee2aafc..52eb3ba 100644
--- a/smtpd/smtpctl.c
+++ b/smtpd/smtpctl.c
@@ -23,28 +23,35 @@
 
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <sys/queue.h>
 #include <sys/tree.h>
 #include <sys/un.h>
 #include <sys/wait.h>
 
+#include <ctype.h>
+#include <db.h>
 #include <err.h>
 #include <errno.h>
 #include <event.h>
+#include <fcntl.h>
 #include <fts.h>
 #include <imsg.h>
 #include <inttypes.h>
+#include <limits.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <util.h>
 #include <unistd.h>
 
 #include "smtpd.h"
 #include "parser.h"
 #include "log.h"
 
+#define        CONF_FILE       "/etc/mail/smtpd.conf"
 #define PATH_GZCAT     "/usr/bin/gzcat"
 #define        PATH_CAT        "/bin/cat"
 #define PATH_QUEUE     "/queue"
@@ -63,6 +70,10 @@ static int is_gzip_fp(FILE *);
 static int is_encrypted_fp(FILE *);
 static int is_encrypted_buffer(const char *);
 static int is_gzip_buffer(const char *);
+static int parse_table(struct table *, struct stat *);
+static int parse_file(DB *, const char *);
+static int parse_entry(DB *, const char *, char *, size_t , size_t);
+static int make_aliases(DBT *, char *);
 
 extern char    *__progname;
 int             sendmail;
@@ -405,6 +416,39 @@ do_log_verbose(int argc, struct parameter *argv)
 }
 
 static int
+do_newaliases(int argc, struct parameter *argv)
+{
+       struct smtpd    smtpd;
+       struct stat     sb;
+       int             nentries = 0;
+       struct table    *t;
+       const char      *conf = CONF_FILE, *key = "association";
+       char            *val;
+       void            *iter_tbl = NULL;
+
+       if (argc)
+               conf = argv[0].u.u_str;
+       
+       if (stat(conf, &sb) == -1)
+               err(1, "stat: %s", conf);
+
+       env = &smtpd;
+       if (parse_config(env, conf, 0))
+               errx(1, "failed to parse config file %s", conf);
+
+       while (dict_iter(env->sc_tables_dict, &iter_tbl, NULL, (void **)&t)) {
+               if (dict_check(&t->t_dict, key))
+                       if ((val = dict_get(&t->t_dict, key)) != NULL &&
+                           !strcmp(val, "alias")) {
+                               nentries = parse_table(t, &sb);
+                               printf("%s: %d aliases\n", t->t_name, nentries);
+                       }
+
+       }
+       return (0);
+}
+
+static int
 do_monitor(int argc, struct parameter *argv)
 {
        struct stat_digest      last, digest;
@@ -881,6 +925,8 @@ main(int argc, char **argv)
        cmd_install("log brief",                do_log_brief);
        cmd_install("log verbose",              do_log_verbose);
        cmd_install("monitor",                  do_monitor);
+       cmd_install("newaliases",               do_newaliases);
+       cmd_install("newaliases <str>",         do_newaliases);
        cmd_install("pause envelope <evpid>",   do_pause_envelope);
        cmd_install("pause envelope <msgid>",   do_pause_envelope);
        cmd_install("pause mda",                do_pause_mda);
@@ -1207,3 +1253,193 @@ end:
        fseek(fp, 0, SEEK_SET);
        return ret;
 }
+
+static int 
+parse_table(struct table *t, struct stat *sb)
+{
+       char            dbname[SMTPD_MAXPATHLEN], *p;
+       char            target[SMTPD_MAXPATHLEN];
+       int             nentries = 0;
+       DB              *db;
+       const char      *path;
+       mode_t          omode;
+
+       path = xstrdup(t->t_config, "parse_table");
+       p = strstr(path, ".db");
+       if (p && strcmp(p, ".db") == 0)
+               *p = '\0';
+
+       if (! bsnprintf(dbname, sizeof(dbname), "%s.XXXXXXXXXXX", path))
+               errx(1, "path too long");
+
+       omode = umask(7077);
+       if (mkstemp(dbname) == -1)
+               err(1, "mkstemp");
+       umask(omode);
+
+       db = dbopen(dbname, O_EXLOCK|O_RDWR|O_SYNC, 0644, DB_HASH, NULL);
+       if (db == NULL)
+               err(1, "dbopen");
+
+       if (fchmod(db->fd(db), sb->st_mode) == -1 ||
+           fchown(db->fd(db), sb->st_uid, sb->st_gid) == -1)
+               errx(1, "couldn't carry ownership and perms to %s", dbname);
+
+       if (! (nentries = parse_file(db, path)))
+               errx(1, "failed to parse %s", path);
+
+       if (db->close(db) == -1) {
+               warn("dbclose: %s", dbname);
+               goto bad;
+       }
+
+       snprintf(target, sizeof(target), "%s.db", path);
+       if (rename(dbname, target) == -1) {
+               warn("rename");
+               goto bad;
+       }
+
+bad:
+       unlink(dbname);
+
+       return (nentries);
+}
+
+static int
+parse_file(DB *db, const char *filename)
+{
+       FILE    *fp;
+       char    *line;
+       int     entries, nentries = 0;
+       size_t  len;
+       size_t  lineno = 0;
+       char    delim[] = { '\\', 0, 0 };
+
+       fp = fopen(filename, "r");
+       if (fp == NULL) {
+               warn("%s", filename);
+               return (0);
+       }
+
+       if (!isatty(fileno(fp)) && flock(fileno(fp), LOCK_SH|LOCK_NB) == -1) {
+               if (errno == EWOULDBLOCK)
+                       warnx("%s is locked", filename);
+               else
+                       warn("%s: flock", filename);
+               fclose(fp);
+               return (0);
+       }
+
+       while ((line = fparseln(fp, &len, &lineno, delim, 0)) != NULL) {
+               if (! (entries = parse_entry(db, filename,
+                   line, len, lineno))) {
+                       free(line);
+                       fclose(fp);
+                       return (0);
+               }
+               nentries += entries;
+               free(line);
+       }
+
+       fclose(fp);
+       return (nentries);
+}
+
+int
+parse_entry(DB *db, const char *source, char *line, size_t len, size_t lineno)
+{
+       DBT     key;
+       DBT     val;
+       int     dbputs = 0;
+       char    *keyp;
+       char    *valp;
+
+       keyp = line;
+       while (isspace((unsigned char)*keyp))
+               keyp++;
+       if (*keyp == '\0' || *keyp == '#')
+               return (1);
+
+       valp = keyp;
+       strsep(&valp, " \t:");
+       if (valp == NULL || valp == keyp)
+               goto bad;
+       while (*valp == ':' || isspace((unsigned char)*valp))
+               valp++;
+       if (*valp == '\0' || *valp == '#')
+               goto bad;
+
+       /* Check for dups. */
+       key.data = keyp;
+       key.size = strlen(keyp) + 1;
+
+       xlowercase(key.data, key.data, strlen(key.data) + 1);
+       if (db->get(db, &key, &val, 0) == 0) {
+               warnx("%s:%zd: duplicate entry for %s", source, lineno, keyp);
+               return (0);
+       }
+
+       if (! make_aliases(&val, valp))
+                       goto bad;
+
+       if (db->put(db, &key, &val, 0) == -1) {
+               warn("dbput");
+               return (0);
+       }
+
+       dbputs++;
+       free(val.data);
+       return (dbputs);
+
+bad:
+       warnx("%s:%zd: invalid entry", source, lineno);
+       return (0);
+}
+
+static int
+make_aliases(DBT *val, char *text)
+{
+       struct expandnode       xn;
+       char                   *subrcpt;
+       char                   *endp;
+       char                   *origtext;
+
+       val->data = NULL;
+       val->size = 0;
+
+       origtext = xstrdup(text, "make_aliases");
+
+       while ((subrcpt = strsep(&text, ",")) != NULL) {
+               /* subrcpt: strip initial whitespace. */
+               while (isspace((unsigned char)*subrcpt))
+                       ++subrcpt;
+               if (*subrcpt == '\0')
+                       goto error;
+
+               /* subrcpt: strip trailing whitespace. */
+               endp = subrcpt + strlen(subrcpt) - 1;
+               while (subrcpt < endp && isspace((unsigned char)*endp))
+                       *endp-- = '\0';
+
+               if (! text_to_expandnode(&xn, subrcpt))
+                       goto error;
+       }
+
+       val->data = origtext;
+       val->size = strlen(origtext) + 1;
+       return (val->size);
+
+error:
+       free(origtext);
+
+       return (0);
+}
+
+/*
+ * Stub function so that smtpctl compiles using minimum object files.
+ */
+void
+purge_config(uint8_t what)
+{
+       memset(env, 0, sizeof(struct smtpd));
+}
diff --git a/smtpd/smtpctl/Makefile b/smtpd/smtpctl/Makefile
index 44eef46..d358d97 100644
--- a/smtpd/smtpctl/Makefile
+++ b/smtpd/smtpctl/Makefile
@@ -31,6 +31,13 @@ SRCS+=               to.c
 SRCS+=         expand.c
 SRCS+=         tree.c
 SRCS+=         dict.c
+SRCS+=         table.c
+SRCS+=         parse.y
+SRCS+=         limit.c
+SRCS+=         table_static.c
+SRCS+=         table_db.c
+SRCS+=         table_getpwnam.c
+SRCS+=         table_proc.c
 
 LDADD+=        -lutil -lz -lcrypto
 DPADD+=        ${LIBUTIL} ${LIBZ} ${LIBCRYPTO}

-- 
You received this mail because you are subscribed to [email protected]
To unsubscribe, send a mail to: [email protected]

Reply via email to