From 8ca17b9a328732cac9ccd9e1c96c8d35777afe88 Mon Sep 17 00:00:00 2001 From: Clinton Ebadi Date: Tue, 6 May 2014 19:52:41 -0400 Subject: [PATCH] Disentangle vmail from the mail node, Prepare for dovecot support * Use new Slave.run and Connect.commandWorker where possible * Always reload vmail db in worker, never in dispatcher * Move non-courier-specific configuration variables to Config.Vmail. The master userdb is still managed using courier-authlib-userdb. * Manage vmail db in afs, syncing as needed. --- configDefault/courier.cfg | 2 - configDefault/courier.csg | 5 -- configDefault/vmail.cfg | 8 +++ configDefault/vmail.cfs | 1 + configDefault/vmail.csg | 8 +++ scripts/domtool-publish | 6 +++ src/mail/vmail.sml | 107 ++++++++++++++------------------------ 7 files changed, 63 insertions(+), 74 deletions(-) create mode 100644 configDefault/vmail.cfg create mode 100644 configDefault/vmail.cfs create mode 100644 configDefault/vmail.csg diff --git a/configDefault/courier.cfg b/configDefault/courier.cfg index a0da8b3..cc5f315 100644 --- a/configDefault/courier.cfg +++ b/configDefault/courier.cfg @@ -1,9 +1,7 @@ structure Courier :> COURIER_CONFIG = struct (* Non-daemon programs *) -val userdb = "/usr/sbin/userdb" val maildirmake = "/usr/bin/maildirmake.courier" -val userdbpw = "/usr/sbin/userdbpw" val makeuserdb = "/usr/sbin/makeuserdb" val userdbDir = "/etc/courier/userdb" diff --git a/configDefault/courier.csg b/configDefault/courier.csg index 15b382e..37ffac7 100644 --- a/configDefault/courier.csg +++ b/configDefault/courier.csg @@ -1,8 +1,6 @@ signature COURIER_CONFIG = sig - val userdb : string val maildirmake : string - val userdbpw : string val makeuserdb : string val userdbDir : string @@ -10,8 +8,5 @@ signature COURIER_CONFIG = sig val postReload : string val logFile : string - - val pushUserdb : string - val pullUserdb : string end diff --git a/configDefault/vmail.cfg b/configDefault/vmail.cfg new file mode 100644 index 0000000..9cc1963 --- /dev/null +++ b/configDefault/vmail.cfg @@ -0,0 +1,8 @@ +structure Vmail :> VMAIL_CONFIG = struct + +val userdb = "/usr/sbin/userdb" +val userdbpw = "/usr/sbin/userdbpw" + +val userDatabase = ConfigCore.sharedRoot ^ "/email/userdb" + +end diff --git a/configDefault/vmail.cfs b/configDefault/vmail.cfs new file mode 100644 index 0000000..31febf8 --- /dev/null +++ b/configDefault/vmail.cfs @@ -0,0 +1 @@ +structure Vmail : VMAIL_CONFIG diff --git a/configDefault/vmail.csg b/configDefault/vmail.csg new file mode 100644 index 0000000..bbce782 --- /dev/null +++ b/configDefault/vmail.csg @@ -0,0 +1,8 @@ +signature VMAIL_CONFIG = sig + + val userdb : string + val userdbpw : string + + val userDatabase : string + +end diff --git a/scripts/domtool-publish b/scripts/domtool-publish index 9a9a01a..9eea020 100755 --- a/scripts/domtool-publish +++ b/scripts/domtool-publish @@ -57,6 +57,12 @@ case $1 in redo_exim ;; courier) + VMAILDB=`domtool-config -path vmaildb` + if [ -z "$VMAILDB" ]; then + echo "domtool-config not found, not syncing courier vmail userdb" + exit 1 + fi + /usr/bin/rsync -r --delete ${VMAILDB}/ /etc/courier/userdb /usr/sbin/makeuserdb /bin/chown -R domtool.nogroup /etc/courier/userdb /bin/cat /etc/courier/userdb/* >/etc/courier/exim diff --git a/src/mail/vmail.sml b/src/mail/vmail.sml index 48d2287..8e92f60 100644 --- a/src/mail/vmail.sml +++ b/src/mail/vmail.sml @@ -1,5 +1,6 @@ (* HCoop Domtool (http://hcoop.sourceforge.net/) * Copyright (c) 2006-2009, Adam Chlipala + * Copyright (c) 2014 Clinton Ebadi * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,39 +27,13 @@ fun rebuild () = let fun doNode (site, ok) = (print ("New vmail data for node " ^ site ^ "\n"); - if site = Config.dispatcherName then - Slave.shell [Config.Courier.postReload] andalso ok - else let - val bio = OpenSSL.connect true (Domain.get_context (), - Domain.nodeIp site - ^ ":" - ^ Int.toString Config.slavePort) - in - Msg.send (bio, MsgVmailChanged); - (case Msg.recv bio of - NONE => (print "Slave closed connection unexpectedly\n"; - false) - | SOME m => - case m of - MsgOk => (print ("Slave " ^ site ^ " finished\n"); - ok) - | MsgError s => (print ("Slave " ^ site - ^ " returned error: " ^ - s ^ "\n"); - false) - | _ => (print ("Slave " ^ site - ^ " returned unexpected command\n"); - false)) - before OpenSSL.close bio - end) + Connect.commandWorker (Domain.get_context (), site, MsgVmailChanged)) in - Slave.shell [Config.Courier.pushUserdb] - andalso foldl doNode true Config.mailNodes_all + foldl doNode true Config.mailNodes_all end fun doChanged () = - Slave.shell [Config.Courier.pullUserdb] - andalso Slave.shell [Config.Courier.postReload] + Slave.shell [Config.Courier.postReload] datatype listing = Error of string @@ -66,7 +41,7 @@ datatype listing = fun list domain = let - val file = OS.Path.joinDirFile {dir = Config.Courier.userdbDir, + val file = OS.Path.joinDirFile {dir = Config.Vmail.userDatabase, file = domain} in if Posix.FileSys.access (file, []) then @@ -104,7 +79,7 @@ fun list domain = fun mailboxExists {domain, user} = let - val inf = TextIO.openIn (OS.Path.joinDirFile {dir = Config.Courier.userdbDir, + val inf = TextIO.openIn (OS.Path.joinDirFile {dir = Config.Vmail.userDatabase, file = domain}) fun loop () = @@ -124,6 +99,23 @@ fun mailboxExists {domain, user} = end handle IO.Io _ => false +fun setpassword {domain, user, passwd} = + let + val proc = Unix.execute ("/bin/sh", ["-c", + String.concat [Config.Vmail.userdbpw, " | ", Config.Vmail.userdb, + " -f ", Config.Vmail.userDatabase, "/", domain, + " \"", user, "@", domain, "\" set systempw"]]) + val outf = Unix.textOutstreamOf proc + in + TextIO.output (outf, String.concat [passwd, "\n", passwd, "\n"]); + TextIO.closeOut outf; + OS.Process.isSuccess (Unix.reap proc) + end + +fun deluser {domain, user} = + Slave.run (Config.Vmail.userdb, ["-f", Config.Vmail.userDatabase ^ "/" ^ domain, + user ^ "@" ^ domain, "del"]) + fun add {domain, requester, user, passwd, mailbox} = let val udb = Posix.SysDB.getpwnam requester @@ -133,53 +125,34 @@ fun add {domain, requester, user, passwd, mailbox} = in if mailboxExists {domain = domain, user = user} then SOME "Mailbox mapping already exists" - else if not (Slave.shell [Config.Courier.userdb, " \"", domain, "/", user, "@", domain, - "\" set home=", home, " mail=", mailbox, - " uid=", Int.toString uid, " gid=" ^ Int.toString gid]) then + else if not (Slave.run (Config.Vmail.userdb, ["-f", Config.Vmail.userDatabase ^ "/" ^ domain, + user ^ "@" ^ domain, + "set", "home=" ^ home, "mail=" ^ mailbox, "uid=" ^ Int.toString uid, "gid=" ^ Int.toString gid])) then SOME "Error running userdb" + else if not (setpassword {domain = domain, user = user, passwd = passwd}) then + (ignore (deluser {domain = domain, user = user}); + SOME "Error setting password") + else if not (rebuild ()) then + (ignore (deluser {domain = domain, user = user}); + SOME "Error reloading userdb") else - let - val proc = Unix.execute ("/bin/sh", ["-c", - String.concat [Config.Courier.userdbpw, " | ", Config.Courier.userdb, - " \"", domain, "/", user, "@", domain, "\" set systempw"]]) - val outf = Unix.textOutstreamOf proc - in - TextIO.output (outf, String.concat [passwd, "\n", passwd, "\n"]); - TextIO.closeOut outf; - if not (OS.Process.isSuccess (Unix.reap proc)) then - (ignore (Slave.shell [Config.Courier.userdb, " \"", domain, "/", user, "@", domain, "\" del"]); - SOME "Error setting password") - else if not (rebuild ()) then - (ignore (Slave.shell [Config.Courier.userdb, " \"", domain, "/", user, "@", domain, "\" del"]); - SOME "Error reloading userdb") - else - NONE - end + NONE end fun passwd {domain, user, passwd} = if not (mailboxExists {domain = domain, user = user}) then SOME "Mailbox doesn't exist" - else let - val proc = Unix.execute ("/bin/sh", ["-c", - String.concat [Config.Courier.userdbpw, " | ", Config.Courier.userdb, - " \"", domain, "/", user, "@", domain, "\" set systempw"]]) - val outf = Unix.textOutstreamOf proc - in - TextIO.output (outf, String.concat [passwd, "\n", passwd, "\n"]); - TextIO.closeOut outf; - if not (OS.Process.isSuccess (Unix.reap proc)) then - SOME "Error setting password" - else if not (rebuild ()) then - SOME "Error reloading userdb" - else - NONE - end + else if not (setpassword {domain = domain, user = user, passwd = passwd}) then + SOME "Error setting password" + else if not (rebuild ()) then + SOME "Error reloading userdb" + else + NONE fun rm {domain, user} = if not (mailboxExists {domain = domain, user = user}) then SOME "Mailbox doesn't exist" - else if not (Slave.shell [Config.Courier.userdb, " \"", domain, "/", user, "@", domain, "\" del"]) then + else if not (deluser {domain = domain, user = user}) then SOME "Error deleting password entry" else if not (rebuild ()) then SOME "Error reloading userdb" -- 2.20.1