CasperSecurity
#!/usr/bin/env python3
# This file is used to migrate SQL table `vmail.alias` for SQL backends.
#
# Requirements:
#
# * Python 3
# * Make sure you have new SQL tables ready: alias_moderators, forwardings.
# * For PostgreSQL, please make sure SQL user 'vmail' has 'SELECT' privilege on
# newly created sql tables.
import sys
import web
web.config.debug = False
# Read iRedAdmin config file `settings.py` from one of expected paths
sys.path.insert(0, '/usr/local/www/iredadmin') # FreeBSD
sys.path.insert(0, '/opt/www/iredadmin') # Debian/Ubuntu
sys.path.insert(0, '/var/www/iredadmin') # CentOS/OpenBSD
sys.path.insert(0, '/usr/share/apache2/iredadmin') # Debian/Ubuntu (old iRedMail releases)
import settings
print("* Read SQL username/password from iRedAdmin config file:", settings.__file__)
print("* Backend:", settings.backend)
if settings.backend in ['ldap', 'mysql']:
sql_dbn = 'mysql'
elif settings.backend in ['pgsql']:
sql_dbn = 'postgres'
else:
sys.exit('* << ERROR >>: Unsupported backend (%s).' % settings.backend)
try:
if sql_dbn == 'postgres':
db = web.database(dbn=sql_dbn,
host=settings.vmail_db_host,
port=int(settings.vmail_db_port),
db=settings.vmail_db_name,
user=settings.vmail_db_user,
pw=settings.vmail_db_password)
else:
db = web.database(dbn=sql_dbn,
host=settings.vmail_db_host,
port=int(settings.vmail_db_port),
db=settings.vmail_db_name,
user=settings.vmail_db_user,
pw=settings.vmail_db_password,
charset='utf8',
use_unicode=False)
db.supports_multiple_insert = True
except Exception as e:
print("<< ERROR >> Cannot connecting to SQL server:", e)
sys.exit()
def __bytes2str(b) -> str:
"""Convert object `b` to string."""
if isinstance(b, str):
return b
if isinstance(b, (bytes, bytearray)):
return b.decode()
elif isinstance(b, memoryview):
return b.tobytes().decode()
else:
return repr(b)
def bytes2str(b):
"""Convert `b` from bytes-like type to string."""
if isinstance(b, (list, web.db.ResultSet)):
s = [bytes2str(i) for i in b]
elif isinstance(b, tuple):
s = tuple([bytes2str(i) for i in b])
elif isinstance(b, set):
s = {bytes2str(i) for i in b}
elif isinstance(b, (dict, web.utils.Storage)):
new_dict = {}
for (k, v) in list(b.items()):
new_dict[k] = bytes2str(v) # v could be list/tuple/dict
s = new_dict
else:
s = __bytes2str(b)
return s
# Check required tables
for tbl in ['forwardings', 'alias_moderators']:
try:
db.select(tbl, limit=1)
except:
print("<<< ERROR >>> SQL table '%s' doesn't exist. Please create it first." % tbl)
sys.exit()
# Get all existing accounts
records = db.select('alias', what='address,goto,moderators,domain,active,islist,is_alias')
total = len(records)
counter = 1
for r in records:
# standard mail alias account
is_list = 0
# per-account alias address
is_alias = 0
# forwarding addresses of mail user
is_forwarding = 0
if r.islist == 1:
is_list = 1
_type = 'mail alias'
elif r.is_alias == 1:
is_alias = 1
_type = 'per-account alias address'
else:
is_forwarding = 1
_type = 'mail user'
account = bytes2str(r.address).lower()
active = int(r.active)
domain = bytes2str(r.domain).lower()
goto = bytes2str(r.goto).strip(' ')
goto = goto.replace(' ', '')
goto = goto.replace(';', ',')
members = list(set([i.strip().lower() for i in goto.strip(' ').split(',')]))
# Migrating forwardings
print("* [%d/%d] Migrating %s %s" % (counter, total, _type, account))
for m in members:
if m:
try:
dest_domain = m.split('@', 1)[-1]
db.insert('forwardings',
address=account,
forwarding=m,
domain=domain,
dest_domain=dest_domain,
active=active,
is_list=is_list,
is_alias=is_alias,
is_forwarding=is_forwarding)
except Exception as e:
if e[0] == 1062 or 'duplicate' in repr(e):
# Duplicate record
pass
else:
print("Error while migrating %s %s: %s" % (_type, m, repr(e)))
# Migrating moderators of mail alias account
moderators = []
if is_list == 1:
if r.moderators:
moderators = [i.lower() for i in set(r.moderators.strip(' ').split(','))]
if moderators:
for m in moderators:
try:
dest_domain = m.split('@', 1)[-1]
db.insert('alias_moderators',
address=account,
moderator=m,
domain=domain,
dest_domain=dest_domain)
except Exception as e:
if e[0] == 1062 or 'duplicate' in repr(e):
# Duplicate record
pass
else:
print("Error while migrating moderators of alias account %s: %s" % (m, repr(e)))
counter += 1
print("* DONE.")