commit - /dev/null
commit + 990faa37a29c3cde5e0f48336e712c6ad71c5fa4
blob - /dev/null
blob + 4e1fee443717b12634573d8c7ead23e2a1ff37d7 (mode 755)
--- /dev/null
+++ sync-userdb
+#!/bin/sh
+
+set -e
+
+# On OpenBSD these are only /etc/mail/…
+./userctl aliases > /usr/local/etc/mail/aliases
+./userctl virtuals > /usr/local/etc/mail/virtuals
+./userctl domains > /usr/local/etc/mail/domains
+./userctl users > /usr/local/etc/mail/passwd
+
+./userctl users.passwd > /usr/local/etc/dovecot/users
+
+m()
+{
+ if [ ! -d "$1" ]; then
+ mkdir "$1"
+ chown vmail:vmail "$1"
+ fi
+}
+
+# ensure the maildirs exists
+for dir in $(./userctl users.mdirs); do
+ homedir=$(dirname "$dir")
+ domdir=$(dirname "$homedir")
+
+ m "$domdir"
+ m "$homedir"
+ m "$dir"
+done
+
+# eventually add something like
+# service dovecot restart
+# service smtpd restart
+# for FreeBSD or
+# rcctl restart dovecot smtpd
+# for OpenBSD.
blob - /dev/null
blob + 2242e9676b5a4c2afb64f0170794d39c051c7a94 (mode 755)
--- /dev/null
+++ userctl
+#!/bin/sh
+
+if [ ! -f "userctl.awk" ]; then
+ echo "Can't find userctl.awk!" >&2
+ exit 1
+fi
+
+if [ ! -f "userdb" ]; then
+ echo "Can't find userdb!" >&2
+ exit 1
+fi
+
+# run <action>
+run()
+{
+ awk -f userctl.awk -v action="$1" userdb
+}
+
+case "$1" in
+ aliases) run "aliases" ;;
+ virtuals) run "virtuals" ;;
+ domains) run "domains" ;;
+ users) run "users" ;;
+ users.passwd) run "users.passwd" ;;
+ users.mdirs) run "users.mdirs" ;;
+ help)
+ echo "USAGE: $0 <action>"
+ echo "where action is one of"
+ echo " - aliases"
+ echo " - virtuals"
+ echo " - domains"
+ echo " - users"
+ echo " - users.passwd"
+ echo " - users.mdirs"
+ ;;
+ *)
+ echo "Unknown action $1" >&2
+ exit 1
+ ;;
+esac
blob - /dev/null
blob + e2508111640881847ba987c5a6d714afcd4031d0 (mode 644)
--- /dev/null
+++ userctl.awk
+#!/usr/bin/env awk
+
+# expects action to be defined, like -v action=aliases
+
+/^[[:space:]]*$/ { next }
+/^[[:space:]]*#/ { next }
+
+/:$/ {
+ # drop the :
+ gsub(":", "", $1);
+ domain = $1;
+ domains[domainslen++] = domain;
+ next;
+}
+
+$1 == "user" {
+ user = sprintf("%s@%s", $2, domain);
+ users[user] = $3
+
+ # change “vmail” to match the local user that
+ # delivers the mail
+ aliases[user] = "vmail";
+ next;
+}
+
+$1 == "alias" {
+ if ($3 != "") {
+ target = $3;
+ } else {
+ target = user;
+ }
+
+ if (domain != "") {
+ alias = sprintf("%s@%s", $2, domain);
+ } else {
+ alias = $2;
+ }
+ aliases[alias] = target;
+}
+
+# output in the correct format
+END {
+ if (action == "aliases") {
+ for (alias in aliases) {
+ if (match(alias, "@"))
+ continue;
+ printf("%s: %s\n", alias, aliases[alias]);
+ }
+ } else if (action == "virtuals") {
+ for (alias in aliases) {
+ if (!match(alias, "@"))
+ continue;
+ printf("%s %s\n", alias, aliases[alias]);
+ }
+ } else if (action == "domains") {
+ for (domain in domains) {
+ printf("%s\n", domains[domain]);
+ }
+ } else if (action == "users") {
+ for (user in users) {
+ printf("%s %s\n", user, users[user]);
+ }
+ } else if (action == "users.passwd") {
+ for (user in users) {
+ # user@doma.in:hash::::::
+ # user@doma.in:hash::::::userdb_quota_rule=*:storage=1G
+ printf("%s:%s::::::\n", user, users[user]);
+ }
+ } else if (action == "users.mdirs") {
+ for (user in users) {
+ split(user, m, "@");
+ # adjust the maildir path
+ printf("/var/vmail/%s/%s/Maildir\n", m[2], m[1]);
+ }
+ } else {
+ print "unknown action!\n" > "/dev/stderr"
+ exit 1
+ }
+}
blob - /dev/null
blob + 4de2010aed3ade02bf2b912a1a31d33c326ed9a2 (mode 644)
--- /dev/null
+++ userdb.sample
+example.com:
+ # Indentation is optional, but improves legibility.
+ # The following defines the user op@example.com;
+ # <hash> is the hash of the password computed
+ # with `smtpctl encrypt`
+ user op <hash>
+ # and define an arbitrary number of aliases
+ alias service1
+ alias other-alias
+
+ user otheruser <hash>
+
+ # aliases can be to virtual users on other hosts
+ alias abuse someone@example2.com
+
+example2.com:
+ user someone <hash>
+ # …