From fd7960f790afc7e4ec3e0ec5622596131585ccca Mon Sep 17 00:00:00 2001 From: usmannasir Date: Thu, 5 Mar 2026 03:30:04 +0500 Subject: [PATCH] Automate Dovecot master user setup for webmail SSO in install and upgrade Adds master passdb config to dovecot.conf templates, setupWebmail() to the installer and upgrade paths to generate credentials and create /etc/dovecot/master-users and /etc/cyberpanel/webmail.conf automatically. The upgrade path is idempotent and patches existing dovecot.conf if needed. --- install/email-configs-one/dovecot.conf | 9 +++ install/email-configs/dovecot.conf | 9 +++ install/installCyberPanel.py | 47 ++++++++++++++ plogical/upgrade.py | 90 ++++++++++++++++++++++++++ 4 files changed, 155 insertions(+) diff --git a/install/email-configs-one/dovecot.conf b/install/email-configs-one/dovecot.conf index 9ec4b1a1c..682e5764d 100644 --- a/install/email-configs-one/dovecot.conf +++ b/install/email-configs-one/dovecot.conf @@ -53,6 +53,15 @@ protocol imap { mail_plugins = $mail_plugins zlib imap_zlib } +auth_master_user_separator = * + +passdb { + driver = passwd-file + master = yes + args = /etc/dovecot/master-users + result_success = continue +} + passdb { driver = sql args = /etc/dovecot/dovecot-sql.conf.ext diff --git a/install/email-configs/dovecot.conf b/install/email-configs/dovecot.conf index a7694b6ed..5f7188139 100644 --- a/install/email-configs/dovecot.conf +++ b/install/email-configs/dovecot.conf @@ -53,6 +53,15 @@ protocol imap { mail_plugins = $mail_plugins zlib imap_zlib } +auth_master_user_separator = * + +passdb { + driver = passwd-file + master = yes + args = /etc/dovecot/master-users + result_success = continue +} + passdb { driver = sql args = /etc/dovecot/dovecot-sql.conf.ext diff --git a/install/installCyberPanel.py b/install/installCyberPanel.py index 88a454496..90ef6a5ea 100644 --- a/install/installCyberPanel.py +++ b/install/installCyberPanel.py @@ -705,6 +705,50 @@ module cyberpanel_ols { logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [installSieve]") return 0 + def setupWebmail(self): + """Set up Dovecot master user and webmail config for SSO""" + try: + InstallCyberPanel.stdOut("Setting up webmail master user for SSO...", 1) + + from plogical.randomPassword import generate_pass + + master_password = generate_pass(32) + + # Hash the password using doveadm + result = subprocess.run( + ['doveadm', 'pw', '-s', 'SHA512-CRYPT', '-p', master_password], + capture_output=True, text=True + ) + if result.returncode != 0: + logging.InstallLog.writeToFile('[ERROR] doveadm pw failed: ' + result.stderr + " [setupWebmail]") + return 0 + + password_hash = result.stdout.strip() + + # Write /etc/dovecot/master-users + with open('/etc/dovecot/master-users', 'w') as f: + f.write('cyberpanel_master:' + password_hash + '\n') + os.chmod('/etc/dovecot/master-users', 0o600) + subprocess.call(['chown', 'dovecot:dovecot', '/etc/dovecot/master-users']) + + # Write /etc/cyberpanel/webmail.conf + import json as json_module + webmail_conf = { + 'master_user': 'cyberpanel_master', + 'master_password': master_password + } + with open('/etc/cyberpanel/webmail.conf', 'w') as f: + json_module.dump(webmail_conf, f) + os.chmod('/etc/cyberpanel/webmail.conf', 0o600) + subprocess.call(['chown', 'nobody:nobody', '/etc/cyberpanel/webmail.conf']) + + InstallCyberPanel.stdOut("Webmail master user setup complete!", 1) + return 1 + + except BaseException as msg: + logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [setupWebmail]") + return 0 + def installMySQL(self, mysql): ############## Install mariadb ###################### @@ -1320,6 +1364,9 @@ def Main(cwd, mysql, distro, ent, serial=None, port="8090", ftp=None, dns=None, logging.InstallLog.writeToFile('Installing Sieve for email filtering..,55') installer.installSieve() + logging.InstallLog.writeToFile('Setting up webmail master user..,57') + installer.setupWebmail() + logging.InstallLog.writeToFile('Installing MySQL,60') installer.installMySQL(mysql) installer.changeMYSQLRootPassword() diff --git a/plogical/upgrade.py b/plogical/upgrade.py index 20a0e9f3d..64b550628 100644 --- a/plogical/upgrade.py +++ b/plogical/upgrade.py @@ -2801,6 +2801,95 @@ CREATE TABLE `websiteFunctions_backupsv2` (`id` integer AUTO_INCREMENT NOT NULL except: pass + @staticmethod + def setupWebmail(): + """Set up Dovecot master user and webmail config for SSO (idempotent)""" + try: + # Skip if already configured + if os.path.exists('/etc/cyberpanel/webmail.conf'): + Upgrade.stdOut("Webmail master user already configured, skipping.", 0) + return + + # Skip if no mail server installed + if not os.path.exists('/etc/dovecot/dovecot.conf'): + Upgrade.stdOut("Dovecot not installed, skipping webmail setup.", 0) + return + + Upgrade.stdOut("Setting up webmail master user for SSO...", 0) + + from plogical.randomPassword import generate_pass + + master_password = generate_pass(32) + + # Hash the password using doveadm + result = subprocess.run( + ['doveadm', 'pw', '-s', 'SHA512-CRYPT', '-p', master_password], + capture_output=True, text=True + ) + if result.returncode != 0: + Upgrade.stdOut("doveadm pw failed: " + result.stderr, 0) + return + + password_hash = result.stdout.strip() + + # Write /etc/dovecot/master-users + with open('/etc/dovecot/master-users', 'w') as f: + f.write('cyberpanel_master:' + password_hash + '\n') + os.chmod('/etc/dovecot/master-users', 0o600) + subprocess.call(['chown', 'dovecot:dovecot', '/etc/dovecot/master-users']) + + # Write /etc/cyberpanel/webmail.conf + webmail_conf = { + 'master_user': 'cyberpanel_master', + 'master_password': master_password + } + with open('/etc/cyberpanel/webmail.conf', 'w') as f: + json.dump(webmail_conf, f) + os.chmod('/etc/cyberpanel/webmail.conf', 0o600) + subprocess.call(['chown', 'nobody:nobody', '/etc/cyberpanel/webmail.conf']) + + # Patch dovecot.conf if master user config not present + dovecot_conf_path = '/etc/dovecot/dovecot.conf' + with open(dovecot_conf_path, 'r') as f: + dovecot_content = f.read() + + if 'auth_master_user_separator' not in dovecot_content: + master_block = """auth_master_user_separator = * + +passdb { + driver = passwd-file + master = yes + args = /etc/dovecot/master-users + result_success = continue +} + +""" + dovecot_content = dovecot_content.replace( + 'passdb {', + master_block + 'passdb {', + 1 # Only replace the first occurrence + ) + with open(dovecot_conf_path, 'w') as f: + f.write(dovecot_content) + + # Run webmail migrations + Upgrade.executioner( + 'python /usr/local/CyberCP/manage.py makemigrations webmail', + 'Webmail makemigrations', shell=True + ) + Upgrade.executioner( + 'python /usr/local/CyberCP/manage.py migrate', + 'Webmail migrate', shell=True + ) + + # Restart Dovecot + subprocess.call(['systemctl', 'restart', 'dovecot']) + + Upgrade.stdOut("Webmail master user setup complete!", 0) + + except BaseException as msg: + Upgrade.stdOut("setupWebmail error: " + str(msg), 0) + @staticmethod def manageServiceMigrations(): try: @@ -4725,6 +4814,7 @@ pm.max_spare_servers = 3 Upgrade.s3BackupMigrations() Upgrade.containerMigrations() Upgrade.manageServiceMigrations() + Upgrade.setupWebmail() Upgrade.enableServices() Upgrade.installPHP73()