mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2025-12-15 12:59:42 +01:00
Fix custom installation email components bug: Skip email operations when services not installed
This commit resolves the issue where CyberPanel attempts to configure email/DKIM settings even when email services were explicitly disabled during custom installation, causing hostname SSL setup and website creation to fail with "No such file or directory: '/etc/postfix/main.cf'" errors. Changes: - Added emailServicesInstalled() utility function to check for /home/cyberpanel/postfix marker - OnBoardingHostName(): Wrap email operations (issueSSLForMailServer, postfix commands) with checks - OnBoardingHostName(): Allow hostname setup to complete without email services - issueSSLForMailServer(): Add early return if email services not installed - issueSSLForMailServer(): Verify /etc/postfix directory exists before operations - issueSSLForMailServer(): Check /etc/postfix/main.cf exists before reading - setupAutoDiscover(): Add early return if email services not installed - setupAutoDiscover(): Check /etc/postfix/main.cf exists before accessing - mailUtilities.configureOpenDKIM(): Verify main.cf exists before configuration Impact: - Hostname SSL setup now completes successfully without email components - Website creation works correctly on custom installs without email - No more file not found errors for /etc/postfix/main.cf - Graceful degradation: operations skip email setup with log messages Fixes: Custom installation hostname SSL 404 error Fixes: Website creation DKIM failure on custom installs Related: Ticket #RMKRFFGKC
This commit is contained in:
@@ -582,6 +582,12 @@ InternalHosts refile:/etc/opendkim/TrustedHosts
|
||||
|
||||
postfixFilePath = "/etc/postfix/main.cf"
|
||||
|
||||
# Check if postfix main.cf exists before configuring
|
||||
if not os.path.exists(postfixFilePath):
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"configureOpenDKIM: {postfixFilePath} not found, skipping postfix DKIM configuration")
|
||||
print("1,Postfix not installed")
|
||||
return
|
||||
|
||||
configData = """
|
||||
smtpd_milters = inet:127.0.0.1:8891
|
||||
non_smtpd_milters = $smtpd_milters
|
||||
|
||||
@@ -53,7 +53,16 @@ class virtualHostUtilities:
|
||||
redisConf = '/usr/local/lsws/conf/dvhost_redis.conf'
|
||||
vhostConfPath = '/usr/local/lsws/conf'
|
||||
|
||||
@staticmethod
|
||||
def emailServicesInstalled():
|
||||
"""
|
||||
Check if email services (Postfix/OpenDKIM) are installed and configured.
|
||||
Returns True if email services are available, False otherwise.
|
||||
|
||||
This checks for the marker file /home/cyberpanel/postfix which is created
|
||||
during email services installation.
|
||||
"""
|
||||
return os.path.exists('/home/cyberpanel/postfix')
|
||||
|
||||
@staticmethod
|
||||
def OnBoardingHostName(Domain, tempStatusPath, skipRDNSCheck):
|
||||
@@ -82,29 +91,33 @@ class virtualHostUtilities:
|
||||
except:
|
||||
CurrentHostName = ''
|
||||
|
||||
if skipRDNSCheck:
|
||||
pass
|
||||
else:
|
||||
if os.path.exists('/home/cyberpanel/postfix'):
|
||||
pass
|
||||
else:
|
||||
message = 'This server does not come with postfix installed. [404]'
|
||||
print(message)
|
||||
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, message)
|
||||
logging.CyberCPLogFileWriter.writeToFile(message)
|
||||
return 0
|
||||
# Check if email services are installed
|
||||
# If not installed and rDNS check is required, log warning but continue
|
||||
# Email-specific operations will be skipped later
|
||||
emailServicesAvailable = virtualHostUtilities.emailServicesInstalled()
|
||||
|
||||
if not skipRDNSCheck and not emailServicesAvailable:
|
||||
message = 'Email services not installed. Hostname setup will continue without email configuration.'
|
||||
print(message)
|
||||
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, message)
|
||||
logging.CyberCPLogFileWriter.writeToFile(message)
|
||||
|
||||
|
||||
####
|
||||
|
||||
# Get postfix hostname with error handling
|
||||
try:
|
||||
PostFixHostname = mailUtilities.FetchPostfixHostname()
|
||||
except Exception as e:
|
||||
message = f'Failed to fetch postfix hostname: {str(e)} [404]'
|
||||
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, message)
|
||||
logging.CyberCPLogFileWriter.writeToFile(message)
|
||||
return 0
|
||||
# Get postfix hostname with error handling (only if email services are installed)
|
||||
PostFixHostname = None
|
||||
if emailServicesAvailable:
|
||||
try:
|
||||
PostFixHostname = mailUtilities.FetchPostfixHostname()
|
||||
except Exception as e:
|
||||
message = f'Failed to fetch postfix hostname: {str(e)}, continuing without email setup'
|
||||
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, message)
|
||||
logging.CyberCPLogFileWriter.writeToFile(message)
|
||||
emailServicesAvailable = False # Disable email operations if we can't fetch postfix hostname
|
||||
else:
|
||||
# Set a default hostname when email services are not available
|
||||
PostFixHostname = Domain
|
||||
|
||||
# Get server IP with error handling
|
||||
try:
|
||||
@@ -391,51 +404,66 @@ class virtualHostUtilities:
|
||||
|
||||
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, 'Hostname SSL issued,50')
|
||||
|
||||
# Only setup mail server SSL if email services are installed
|
||||
if emailServicesAvailable:
|
||||
virtualHostUtilities.issueSSLForMailServer(Domain, path)
|
||||
|
||||
virtualHostUtilities.issueSSLForMailServer(Domain, path)
|
||||
try:
|
||||
with open(filePath, 'r') as f:
|
||||
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, f.read())
|
||||
|
||||
try:
|
||||
with open(filePath, 'r') as f:
|
||||
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, f.read())
|
||||
|
||||
# Safely extract SSL provider from issuer components
|
||||
issuer_components = x509.get_issuer().get_components()
|
||||
SSLProvider = 'Denial' # Default to Denial if we can't find the provider
|
||||
|
||||
# Look for the Organization (O) field in the issuer
|
||||
for component in issuer_components:
|
||||
if component[0] == b'O': # Organization field
|
||||
SSLProvider = component[1].decode('utf-8')
|
||||
break
|
||||
elif component[0] == b'CN' and SSLProvider == 'Denial': # Fallback to CN if O not found
|
||||
SSLProvider = component[1].decode('utf-8')
|
||||
except (FileNotFoundError, IndexError, OpenSSL.crypto.Error) as e:
|
||||
SSLProvider = 'Denial'
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Mail server SSL check error: {str(e)}")
|
||||
# Safely extract SSL provider from issuer components
|
||||
issuer_components = x509.get_issuer().get_components()
|
||||
SSLProvider = 'Denial' # Default to Denial if we can't find the provider
|
||||
|
||||
if SSLProvider == 'Denial':
|
||||
message = 'Failed to issue Mail server SSL, either its DNS record is not propagated or the domain is behind Cloudflare. [404]'
|
||||
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, message)
|
||||
logging.CyberCPLogFileWriter.writeToFile(message)
|
||||
config['hostname'] = Domain
|
||||
config['onboarding'] = 3
|
||||
config['skipRDNSCheck'] = skipRDNSCheck
|
||||
admin.config = json.dumps(config)
|
||||
admin.save()
|
||||
return 0
|
||||
# Look for the Organization (O) field in the issuer
|
||||
for component in issuer_components:
|
||||
if component[0] == b'O': # Organization field
|
||||
SSLProvider = component[1].decode('utf-8')
|
||||
break
|
||||
elif component[0] == b'CN' and SSLProvider == 'Denial': # Fallback to CN if O not found
|
||||
SSLProvider = component[1].decode('utf-8')
|
||||
except (FileNotFoundError, IndexError, OpenSSL.crypto.Error) as e:
|
||||
SSLProvider = 'Denial'
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Mail server SSL check error: {str(e)}")
|
||||
|
||||
if SSLProvider == 'Denial':
|
||||
message = 'Failed to issue Mail server SSL, either its DNS record is not propagated or the domain is behind Cloudflare. [404]'
|
||||
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, message)
|
||||
logging.CyberCPLogFileWriter.writeToFile(message)
|
||||
config['hostname'] = Domain
|
||||
config['onboarding'] = 3
|
||||
config['skipRDNSCheck'] = skipRDNSCheck
|
||||
admin.config = json.dumps(config)
|
||||
admin.save()
|
||||
return 0
|
||||
else:
|
||||
config['hostname'] = Domain
|
||||
config['onboarding'] = 1
|
||||
config['skipRDNSCheck'] = skipRDNSCheck
|
||||
admin.config = json.dumps(config)
|
||||
admin.save()
|
||||
# First update the postfix hash database, then restart services
|
||||
command = 'postmap -F hash:/etc/postfix/vmail_ssl.map && systemctl restart postfix && systemctl restart dovecot'
|
||||
ProcessUtilities.executioner(command, 'root', True)
|
||||
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, 'Completed. [200]')
|
||||
else:
|
||||
# Email services not installed, skip mail server SSL setup
|
||||
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, 'Email services not installed, skipping mail server SSL setup.')
|
||||
config['hostname'] = Domain
|
||||
config['onboarding'] = 1
|
||||
config['skipRDNSCheck'] = skipRDNSCheck
|
||||
admin.config = json.dumps(config)
|
||||
admin.save()
|
||||
# First update the postfix hash database, then restart services
|
||||
command = 'postmap -F hash:/etc/postfix/vmail_ssl.map && systemctl restart postfix && systemctl restart dovecot'
|
||||
ProcessUtilities.executioner(command, 'root', True)
|
||||
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, 'Completed. [200]')
|
||||
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, 'Hostname setup completed (without email configuration). [200]')
|
||||
|
||||
@staticmethod
|
||||
def setupAutoDiscover(mailDomain, tempStatusPath, virtualHostName, admin):
|
||||
# Check if email services are installed before proceeding
|
||||
if not virtualHostUtilities.emailServicesInstalled():
|
||||
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, 'Email services not installed, skipping mail domain setup.')
|
||||
logging.CyberCPLogFileWriter.writeToFile('setupAutoDiscover: Email services not installed, skipping.')
|
||||
return
|
||||
|
||||
if mailDomain:
|
||||
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, 'Creating mail child domain..,80')
|
||||
@@ -479,6 +507,11 @@ local_name %s {
|
||||
|
||||
postFixPath = '/etc/postfix/main.cf'
|
||||
|
||||
# Check if main.cf exists before accessing it
|
||||
if not os.path.exists(postFixPath):
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"setupAutoDiscover: {postFixPath} not found, skipping postfix TLS SNI configuration")
|
||||
return
|
||||
|
||||
postFixContent = open(postFixPath, 'r').read()
|
||||
|
||||
if postFixContent.find('tls_server_sni_maps') == -1:
|
||||
@@ -1108,6 +1141,17 @@ local_name %s {
|
||||
@staticmethod
|
||||
def issueSSLForMailServer(virtualHost, path):
|
||||
try:
|
||||
# Check if email services are installed before proceeding
|
||||
if not virtualHostUtilities.emailServicesInstalled():
|
||||
logging.CyberCPLogFileWriter.writeToFile("Email services not installed, skipping mail server SSL setup")
|
||||
print("1,Email services not installed")
|
||||
return 1, 'Email services not installed'
|
||||
|
||||
# Verify critical email directories exist
|
||||
if not os.path.exists('/etc/postfix'):
|
||||
logging.CyberCPLogFileWriter.writeToFile("/etc/postfix directory not found, skipping mail server SSL")
|
||||
print("1,Postfix directory not found")
|
||||
return 1, 'Postfix directory not found'
|
||||
|
||||
srcFullChain = '/etc/letsencrypt/live/' + virtualHost + '/fullchain.pem'
|
||||
srcPrivKey = '/etc/letsencrypt/live/' + virtualHost + '/privkey.pem'
|
||||
@@ -1183,6 +1227,12 @@ local_name %s {
|
||||
|
||||
filePath = "/etc/postfix/main.cf"
|
||||
|
||||
# Check if main.cf exists before trying to read it
|
||||
if not os.path.exists(filePath):
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"{filePath} not found, skipping postfix hostname update")
|
||||
print("1,Postfix main.cf not found")
|
||||
return 1, 'Postfix main.cf not found'
|
||||
|
||||
data = open(filePath, 'r').readlines()
|
||||
|
||||
writeFile = open(filePath, 'w')
|
||||
|
||||
Reference in New Issue
Block a user