Commit Diff


commit - /dev/null
commit + 990faa37a29c3cde5e0f48336e712c6ad71c5fa4
blob - /dev/null
blob + 4e1fee443717b12634573d8c7ead23e2a1ff37d7 (mode 755)
--- /dev/null
+++ sync-userdb
@@ -0,0 +1,36 @@
+#!/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
@@ -0,0 +1,40 @@
+#!/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
@@ -0,0 +1,79 @@
+#!/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
@@ -0,0 +1,18 @@
+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>
+	# …