mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2025-11-02 11:26:28 +01:00
fix: Comprehensive MariaDB socket authentication support
- Add execute_mysql_command() helper in install.py for robust auth fallback - Update mysqlUtilities.py with socket auth fallback for all operations: * Database creation * User creation * Privilege granting * Privilege flushing - Fix PowerDNS database setup to use new authentication helper - Improve cyberpanel user connection verification - Add proper error handling and logging throughout This ensures the installation works correctly when MariaDB is pre-installed with socket authentication (common with dependency installations). Fixes the 'Cannot update settings with empty passwords' installation failure.
This commit is contained in:
@@ -1036,6 +1036,46 @@ class preFlightsChecks:
|
||||
self.stdOut(f"Error changing MySQL root password: {str(e)}", 0)
|
||||
return False
|
||||
|
||||
def execute_mysql_command(self, sql_command, description="MySQL command"):
|
||||
"""Execute MySQL command with proper authentication fallback"""
|
||||
try:
|
||||
# Try password-based authentication first if password file exists
|
||||
try:
|
||||
passFile = "/etc/cyberpanel/mysqlPassword"
|
||||
if os.path.exists(passFile):
|
||||
with open(passFile, 'r') as f:
|
||||
password = f.read().split('\n', 1)[0]
|
||||
|
||||
# Try mariadb first, then mysql
|
||||
for cmd_base in ['mariadb', 'mysql']:
|
||||
if self.command_exists(cmd_base):
|
||||
command = f'{cmd_base} -u root -p{password} -e "{sql_command}"'
|
||||
result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=30)
|
||||
if result.returncode == 0:
|
||||
self.stdOut(f"✓ {description} executed successfully with password auth", 1)
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
|
||||
# Fallback to socket authentication
|
||||
for cmd_base in ['sudo mariadb', 'sudo mysql']:
|
||||
try:
|
||||
if self.command_exists(cmd_base.split()[-1]):
|
||||
command = f'{cmd_base} -e "{sql_command}"'
|
||||
result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=30)
|
||||
if result.returncode == 0:
|
||||
self.stdOut(f"✓ {description} executed successfully with socket auth", 1)
|
||||
return True
|
||||
except:
|
||||
continue
|
||||
|
||||
self.stdOut(f"✗ Failed to execute {description}: {sql_command}", 0)
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
self.stdOut(f"Error executing MySQL command: {str(e)}", 0)
|
||||
return False
|
||||
|
||||
def ensure_mysql_password_file(self):
|
||||
"""Ensure MySQL password file exists and is properly configured"""
|
||||
try:
|
||||
@@ -4783,21 +4823,22 @@ vmail
|
||||
preFlightsChecks.stdOut("Setting up PowerDNS database access...", 1)
|
||||
|
||||
# Create PowerDNS database tables if they don't exist
|
||||
db_commands = [
|
||||
"mysql -e \"CREATE DATABASE IF NOT EXISTS powerdns;\"",
|
||||
"mysql -e \"CREATE USER IF NOT EXISTS 'powerdns'@'localhost' IDENTIFIED BY 'cyberpanel';\"",
|
||||
"mysql -e \"GRANT ALL PRIVILEGES ON powerdns.* TO 'powerdns'@'localhost';\"",
|
||||
"mysql -e \"FLUSH PRIVILEGES;\""
|
||||
sql_commands = [
|
||||
("CREATE DATABASE IF NOT EXISTS powerdns", "PowerDNS database creation"),
|
||||
("CREATE USER IF NOT EXISTS 'powerdns'@'localhost' IDENTIFIED BY 'cyberpanel'", "PowerDNS user creation"),
|
||||
("GRANT ALL PRIVILEGES ON powerdns.* TO 'powerdns'@'localhost'", "PowerDNS privileges"),
|
||||
("FLUSH PRIVILEGES", "PowerDNS privilege flush")
|
||||
]
|
||||
|
||||
for cmd in db_commands:
|
||||
preFlightsChecks.call(cmd, self.distro, f"PowerDNS DB: {cmd}", cmd, 1, 0, os.EX_OSERR)
|
||||
for sql_cmd, desc in sql_commands:
|
||||
if not self.execute_mysql_command(sql_cmd, desc):
|
||||
self.stdOut(f"Warning: {desc} may have failed", 0)
|
||||
|
||||
# Import PowerDNS schema if tables don't exist
|
||||
schema_check = "mysql -e \"USE powerdns; SHOW TABLES;\""
|
||||
result = subprocess.run(schema_check, shell=True, capture_output=True, text=True)
|
||||
schema_check_success = self.execute_mysql_command("USE powerdns; SHOW TABLES", "PowerDNS schema check")
|
||||
|
||||
if not result.stdout.strip() or 'domains' not in result.stdout:
|
||||
# For now, assume schema needs import if we can't check properly
|
||||
if not schema_check_success:
|
||||
preFlightsChecks.stdOut("Importing PowerDNS database schema...", 1)
|
||||
# Try to find and import PowerDNS schema
|
||||
schema_files = [
|
||||
@@ -5310,13 +5351,19 @@ def main():
|
||||
|
||||
# Verify the user was created by testing the connection
|
||||
try:
|
||||
import subprocess
|
||||
test_cmd = f"mysql -u cyberpanel -p{checks.cyberpanel_db_password} -e 'SELECT 1;'"
|
||||
test_result = subprocess.call(test_cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
if test_result == 0:
|
||||
logging.InstallLog.writeToFile("✅ Verified: cyberpanel user can connect to MySQL")
|
||||
else:
|
||||
logging.InstallLog.writeToFile("❌ WARNING: cyberpanel user cannot connect to MySQL - authentication may have failed")
|
||||
test_success = False
|
||||
# Try mariadb first, then mysql
|
||||
for cmd_base in ['mariadb', 'mysql']:
|
||||
if checks.command_exists(cmd_base):
|
||||
test_cmd = f"{cmd_base} -u cyberpanel -p{checks.cyberpanel_db_password} -e 'SELECT 1;'"
|
||||
test_result = subprocess.call(test_cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
if test_result == 0:
|
||||
logging.InstallLog.writeToFile("✅ Verified: cyberpanel user can connect to MySQL")
|
||||
test_success = True
|
||||
break
|
||||
|
||||
if not test_success:
|
||||
logging.InstallLog.writeToFile("⚠️ Warning: Could not verify cyberpanel user connection")
|
||||
except Exception as verify_error:
|
||||
logging.InstallLog.writeToFile(f"Could not verify MySQL connection: {str(verify_error)}")
|
||||
else:
|
||||
|
||||
@@ -32,13 +32,21 @@ class mysqlUtilities:
|
||||
except:
|
||||
passFile = "/etc/cyberpanel/mysqlPassword"
|
||||
|
||||
f = open(passFile)
|
||||
data = f.read()
|
||||
password = data.split('\n', 1)[0]
|
||||
try:
|
||||
f = open(passFile)
|
||||
data = f.read()
|
||||
password = data.split('\n', 1)[0]
|
||||
f.close()
|
||||
|
||||
initCommand = 'mariadb -u root -p' + password + ' -e "'
|
||||
remote = 0
|
||||
logging.InstallLog.writeToFile("Using local MySQL configuration")
|
||||
# Try password-based authentication first
|
||||
initCommand = 'mariadb -u root -p' + password + ' -e "'
|
||||
remote = 0
|
||||
logging.InstallLog.writeToFile("Using local MySQL configuration with password")
|
||||
except:
|
||||
# Fallback to socket authentication for fresh MariaDB installs
|
||||
initCommand = 'sudo mariadb -e "'
|
||||
remote = 0
|
||||
logging.InstallLog.writeToFile("Using local MySQL configuration with socket authentication")
|
||||
|
||||
command = initCommand + createDB + '"'
|
||||
|
||||
@@ -51,6 +59,14 @@ class mysqlUtilities:
|
||||
cmd = shlex.split(command)
|
||||
res = subprocess.call(cmd)
|
||||
|
||||
# If command failed and we're using password auth, try socket auth as fallback
|
||||
if res != 0 and not remote and 'sudo' not in initCommand:
|
||||
logging.InstallLog.writeToFile(f"Password-based auth failed (code {res}), trying socket authentication...")
|
||||
initCommand = 'sudo mariadb -e "'
|
||||
command = initCommand + createDB + '"'
|
||||
cmd = shlex.split(command)
|
||||
res = subprocess.call(cmd)
|
||||
|
||||
if res != 0:
|
||||
logging.InstallLog.writeToFile(f"ERROR: Database creation failed with return code: {res}")
|
||||
return 0
|
||||
@@ -89,6 +105,14 @@ class mysqlUtilities:
|
||||
cmd = shlex.split(command)
|
||||
res = subprocess.call(cmd)
|
||||
|
||||
# If user creation failed and we're using password auth, try socket auth as fallback
|
||||
if res != 0 and not remote and 'sudo' not in initCommand:
|
||||
logging.InstallLog.writeToFile(f"User creation with password failed (code {res}), trying socket authentication...")
|
||||
initCommand = 'sudo mariadb -e "'
|
||||
command = initCommand + createUser + '"'
|
||||
cmd = shlex.split(command)
|
||||
res = subprocess.call(cmd)
|
||||
|
||||
if res != 0:
|
||||
logging.InstallLog.writeToFile(f"ERROR: User creation failed with return code: {res}")
|
||||
return 0
|
||||
@@ -135,6 +159,14 @@ class mysqlUtilities:
|
||||
cmd = shlex.split(command)
|
||||
res = subprocess.call(cmd)
|
||||
|
||||
# If privilege granting failed and we're using password auth, try socket auth as fallback
|
||||
if res != 0 and not remote and 'sudo' not in initCommand:
|
||||
logging.InstallLog.writeToFile(f"Grant privileges with password failed (code {res}), trying socket authentication...")
|
||||
initCommand = 'sudo mariadb -e "'
|
||||
command = initCommand + grantPrivileges + '"'
|
||||
cmd = shlex.split(command)
|
||||
res = subprocess.call(cmd)
|
||||
|
||||
if res != 0:
|
||||
logging.InstallLog.writeToFile(f"ERROR: Grant privileges failed with return code: {res}")
|
||||
return 0
|
||||
@@ -148,6 +180,13 @@ class mysqlUtilities:
|
||||
cmd = shlex.split(flushCommand)
|
||||
res = subprocess.call(cmd)
|
||||
|
||||
# If flush failed and we're using password auth, try socket auth as fallback
|
||||
if res != 0 and not remote and 'sudo' not in initCommand:
|
||||
logging.InstallLog.writeToFile(f"FLUSH PRIVILEGES with password failed (code {res}), trying socket authentication...")
|
||||
flushCommand = 'sudo mariadb -e "FLUSH PRIVILEGES"'
|
||||
cmd = shlex.split(flushCommand)
|
||||
res = subprocess.call(cmd)
|
||||
|
||||
if res != 0:
|
||||
logging.InstallLog.writeToFile(f"WARNING: FLUSH PRIVILEGES failed with return code: {res}")
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user