mirror of
https://github.com/mail-in-a-box/mailinabox.git
synced 2026-03-04 15:54:48 +01:00
move management into a daemon service running as root
* Created a new Python/flask-based management daemon. * Moved the mail user management core code from tools/mail.py to the new daemon. * tools/mail.py is a wrapper around the daemon and can be run as a non-root user. * Adding a new initscript for the management daemon. * Moving dns_update.sh to the management daemon, called via curl'ing the daemon's API. This also now runs the DNS update after mail users and aliases are added/removed, which sets up new domains' DNS as needed.
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import sys, sqlite3, subprocess, shutil, os
|
||||
import sys, urllib.request, urllib.error
|
||||
|
||||
# Load STORAGE_ROOT setting from /etc/mailinabox.conf.
|
||||
env = { }
|
||||
for line in open("/etc/mailinabox.conf"): env.setdefault(*line.strip().split("=", 1))
|
||||
|
||||
# Connect to database.
|
||||
conn = sqlite3.connect(env["STORAGE_ROOT"] + "/mail/users.sqlite")
|
||||
c = conn.cursor()
|
||||
def mgmt(cmd, data=None):
|
||||
req = urllib.request.Request('http://localhost:10222' + cmd, urllib.parse.urlencode(data).encode("utf8") if data else None)
|
||||
try:
|
||||
response = urllib.request.urlopen(req)
|
||||
except urllib.error.HTTPError as e:
|
||||
print(e.read().decode('utf8'))
|
||||
sys.exit(1)
|
||||
return response.read().decode('utf8')
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: ")
|
||||
@@ -24,9 +25,7 @@ if len(sys.argv) < 2:
|
||||
print()
|
||||
|
||||
elif sys.argv[1] == "user" and len(sys.argv) == 2:
|
||||
c.execute('SELECT email FROM users')
|
||||
for row in c.fetchall():
|
||||
print(row[0])
|
||||
print(mgmt("/mail/users"))
|
||||
|
||||
elif sys.argv[1] == "user" and sys.argv[2] in ("add", "password"):
|
||||
if len(sys.argv) < 5:
|
||||
@@ -38,68 +37,23 @@ elif sys.argv[1] == "user" and sys.argv[2] in ("add", "password"):
|
||||
else:
|
||||
email, pw = sys.argv[3:5]
|
||||
|
||||
# hash the password
|
||||
pw = subprocess.check_output(["/usr/bin/doveadm", "pw", "-s", "SHA512-CRYPT", "-p", pw]).strip()
|
||||
|
||||
if sys.argv[2] == "add":
|
||||
try:
|
||||
c.execute("INSERT INTO users (email, password) VALUES (?, ?)", (email, pw))
|
||||
except sqlite3.IntegrityError:
|
||||
print("User already exists.")
|
||||
sys.exit(1)
|
||||
|
||||
conn.commit() # write it before next step
|
||||
|
||||
# Create the user's INBOX and Spam folders and subscribe them.
|
||||
|
||||
# Check if the mailboxes exist before creating them. When creating a user that had previously
|
||||
# been deleted, the mailboxes will still exist because they are still on disk.
|
||||
existing_mboxes = subprocess.check_output(["doveadm", "mailbox", "list", "-u", email, "-8"]).decode("utf8").split("\n")
|
||||
|
||||
if "INBOX" not in existing_mboxes: subprocess.check_call(["doveadm", "mailbox", "create", "-u", email, "-s", "INBOX"])
|
||||
if "Spam" not in existing_mboxes: subprocess.check_call(["doveadm", "mailbox", "create", "-u", email, "-s", "Spam"])
|
||||
|
||||
# Create the user's sieve script to move spam into the Spam folder, and make it owned by mail.
|
||||
maildirstat = os.stat(env["STORAGE_ROOT"] + "/mail/mailboxes")
|
||||
(em_user, em_domain) = email.split("@", 1)
|
||||
user_mail_dir = env["STORAGE_ROOT"] + ("/mail/mailboxes/%s/%s" % (em_domain, em_user))
|
||||
if not os.path.exists(user_mail_dir):
|
||||
os.makedirs(user_mail_dir)
|
||||
os.chown(user_mail_dir, maildirstat.st_uid, maildirstat.st_gid)
|
||||
shutil.copyfile("conf/dovecot_sieve.txt", user_mail_dir + "/.dovecot.sieve")
|
||||
os.chown(user_mail_dir + "/.dovecot.sieve", maildirstat.st_uid, maildirstat.st_gid)
|
||||
|
||||
print(mgmt("/mail/users/add", { "email": email, "password": pw }))
|
||||
elif sys.argv[2] == "password":
|
||||
c.execute("UPDATE users SET password=? WHERE email=?", (pw, email))
|
||||
if c.rowcount != 1:
|
||||
print("That's not a user.")
|
||||
sys.exit(1)
|
||||
print(mgmt("/mail/users/password", { "email": email, "password": pw }))
|
||||
|
||||
elif sys.argv[1] == "user" and sys.argv[2] == "remove" and len(sys.argv) == 4:
|
||||
c.execute("DELETE FROM users WHERE email=?", (sys.argv[3],))
|
||||
if c.rowcount != 1:
|
||||
print("That's not a user.")
|
||||
sys.exit(1)
|
||||
print(mgmt("/mail/users/remove", { "email": sys.argv[3] }))
|
||||
|
||||
elif sys.argv[1] == "alias" and len(sys.argv) == 2:
|
||||
c.execute('SELECT source, destination FROM aliases')
|
||||
for row in c.fetchall():
|
||||
print(row[0], "=>", row[1])
|
||||
print(mgmt("/mail/aliases"))
|
||||
|
||||
elif sys.argv[1] == "alias" and sys.argv[2] == "add" and len(sys.argv) == 5:
|
||||
try:
|
||||
c.execute("INSERT INTO aliases (source, destination) VALUES (?, ?)", (sys.argv[3], sys.argv[4]))
|
||||
except sqlite3.IntegrityError:
|
||||
print("Alias already exists.")
|
||||
sys.exit(1)
|
||||
print(mgmt("/mail/aliases/add", { "source": sys.argv[3], "destination": sys.argv[4] }))
|
||||
|
||||
elif sys.argv[1] == "alias" and sys.argv[2] == "remove" and len(sys.argv) == 4:
|
||||
c.execute("DELETE FROM aliases WHERE source=?", (sys.argv[3],))
|
||||
if c.rowcount != 1:
|
||||
print("That's not an alias.")
|
||||
sys.exit(1)
|
||||
print(mgmt("/mail/aliases/remove", { "source": sys.argv[3] }))
|
||||
|
||||
else:
|
||||
print("Invalid command-line arguments.")
|
||||
|
||||
conn.commit()
|
||||
|
||||
Reference in New Issue
Block a user