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)
|
self.stdOut(f"Error changing MySQL root password: {str(e)}", 0)
|
||||||
return False
|
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):
|
def ensure_mysql_password_file(self):
|
||||||
"""Ensure MySQL password file exists and is properly configured"""
|
"""Ensure MySQL password file exists and is properly configured"""
|
||||||
try:
|
try:
|
||||||
@@ -4783,21 +4823,22 @@ vmail
|
|||||||
preFlightsChecks.stdOut("Setting up PowerDNS database access...", 1)
|
preFlightsChecks.stdOut("Setting up PowerDNS database access...", 1)
|
||||||
|
|
||||||
# Create PowerDNS database tables if they don't exist
|
# Create PowerDNS database tables if they don't exist
|
||||||
db_commands = [
|
sql_commands = [
|
||||||
"mysql -e \"CREATE DATABASE IF NOT EXISTS powerdns;\"",
|
("CREATE DATABASE IF NOT EXISTS powerdns", "PowerDNS database creation"),
|
||||||
"mysql -e \"CREATE USER IF NOT EXISTS 'powerdns'@'localhost' IDENTIFIED BY 'cyberpanel';\"",
|
("CREATE USER IF NOT EXISTS 'powerdns'@'localhost' IDENTIFIED BY 'cyberpanel'", "PowerDNS user creation"),
|
||||||
"mysql -e \"GRANT ALL PRIVILEGES ON powerdns.* TO 'powerdns'@'localhost';\"",
|
("GRANT ALL PRIVILEGES ON powerdns.* TO 'powerdns'@'localhost'", "PowerDNS privileges"),
|
||||||
"mysql -e \"FLUSH PRIVILEGES;\""
|
("FLUSH PRIVILEGES", "PowerDNS privilege flush")
|
||||||
]
|
]
|
||||||
|
|
||||||
for cmd in db_commands:
|
for sql_cmd, desc in sql_commands:
|
||||||
preFlightsChecks.call(cmd, self.distro, f"PowerDNS DB: {cmd}", cmd, 1, 0, os.EX_OSERR)
|
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
|
# Import PowerDNS schema if tables don't exist
|
||||||
schema_check = "mysql -e \"USE powerdns; SHOW TABLES;\""
|
schema_check_success = self.execute_mysql_command("USE powerdns; SHOW TABLES", "PowerDNS schema check")
|
||||||
result = subprocess.run(schema_check, shell=True, capture_output=True, text=True)
|
|
||||||
|
# For now, assume schema needs import if we can't check properly
|
||||||
if not result.stdout.strip() or 'domains' not in result.stdout:
|
if not schema_check_success:
|
||||||
preFlightsChecks.stdOut("Importing PowerDNS database schema...", 1)
|
preFlightsChecks.stdOut("Importing PowerDNS database schema...", 1)
|
||||||
# Try to find and import PowerDNS schema
|
# Try to find and import PowerDNS schema
|
||||||
schema_files = [
|
schema_files = [
|
||||||
@@ -5310,13 +5351,19 @@ def main():
|
|||||||
|
|
||||||
# Verify the user was created by testing the connection
|
# Verify the user was created by testing the connection
|
||||||
try:
|
try:
|
||||||
import subprocess
|
test_success = False
|
||||||
test_cmd = f"mysql -u cyberpanel -p{checks.cyberpanel_db_password} -e 'SELECT 1;'"
|
# Try mariadb first, then mysql
|
||||||
test_result = subprocess.call(test_cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
for cmd_base in ['mariadb', 'mysql']:
|
||||||
if test_result == 0:
|
if checks.command_exists(cmd_base):
|
||||||
logging.InstallLog.writeToFile("✅ Verified: cyberpanel user can connect to MySQL")
|
test_cmd = f"{cmd_base} -u cyberpanel -p{checks.cyberpanel_db_password} -e 'SELECT 1;'"
|
||||||
else:
|
test_result = subprocess.call(test_cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
logging.InstallLog.writeToFile("❌ WARNING: cyberpanel user cannot connect to MySQL - authentication may have failed")
|
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:
|
except Exception as verify_error:
|
||||||
logging.InstallLog.writeToFile(f"Could not verify MySQL connection: {str(verify_error)}")
|
logging.InstallLog.writeToFile(f"Could not verify MySQL connection: {str(verify_error)}")
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -32,13 +32,21 @@ class mysqlUtilities:
|
|||||||
except:
|
except:
|
||||||
passFile = "/etc/cyberpanel/mysqlPassword"
|
passFile = "/etc/cyberpanel/mysqlPassword"
|
||||||
|
|
||||||
f = open(passFile)
|
try:
|
||||||
data = f.read()
|
f = open(passFile)
|
||||||
password = data.split('\n', 1)[0]
|
data = f.read()
|
||||||
|
password = data.split('\n', 1)[0]
|
||||||
|
f.close()
|
||||||
|
|
||||||
initCommand = 'mariadb -u root -p' + password + ' -e "'
|
# Try password-based authentication first
|
||||||
remote = 0
|
initCommand = 'mariadb -u root -p' + password + ' -e "'
|
||||||
logging.InstallLog.writeToFile("Using local MySQL configuration")
|
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 + '"'
|
command = initCommand + createDB + '"'
|
||||||
|
|
||||||
@@ -51,6 +59,14 @@ class mysqlUtilities:
|
|||||||
cmd = shlex.split(command)
|
cmd = shlex.split(command)
|
||||||
res = subprocess.call(cmd)
|
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:
|
if res != 0:
|
||||||
logging.InstallLog.writeToFile(f"ERROR: Database creation failed with return code: {res}")
|
logging.InstallLog.writeToFile(f"ERROR: Database creation failed with return code: {res}")
|
||||||
return 0
|
return 0
|
||||||
@@ -89,6 +105,14 @@ class mysqlUtilities:
|
|||||||
cmd = shlex.split(command)
|
cmd = shlex.split(command)
|
||||||
res = subprocess.call(cmd)
|
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:
|
if res != 0:
|
||||||
logging.InstallLog.writeToFile(f"ERROR: User creation failed with return code: {res}")
|
logging.InstallLog.writeToFile(f"ERROR: User creation failed with return code: {res}")
|
||||||
return 0
|
return 0
|
||||||
@@ -135,6 +159,14 @@ class mysqlUtilities:
|
|||||||
cmd = shlex.split(command)
|
cmd = shlex.split(command)
|
||||||
res = subprocess.call(cmd)
|
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:
|
if res != 0:
|
||||||
logging.InstallLog.writeToFile(f"ERROR: Grant privileges failed with return code: {res}")
|
logging.InstallLog.writeToFile(f"ERROR: Grant privileges failed with return code: {res}")
|
||||||
return 0
|
return 0
|
||||||
@@ -148,6 +180,13 @@ class mysqlUtilities:
|
|||||||
cmd = shlex.split(flushCommand)
|
cmd = shlex.split(flushCommand)
|
||||||
res = subprocess.call(cmd)
|
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:
|
if res != 0:
|
||||||
logging.InstallLog.writeToFile(f"WARNING: FLUSH PRIVILEGES failed with return code: {res}")
|
logging.InstallLog.writeToFile(f"WARNING: FLUSH PRIVILEGES failed with return code: {res}")
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user