File: //proc/self/root/usr/local/CyberCP/plogical/mailUtilities.py
import json
import os,sys
import time
from django.http import HttpResponse
sys.path.append('/usr/local/CyberCP')
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings")
try:
django.setup()
except:
pass
import os.path
import shutil
from plogical import CyberCPLogFileWriter as logging
import subprocess
import argparse
import shlex
from plogical.processUtilities import ProcessUtilities
import os
import bcrypt
import getpass
import smtplib
import threading as multi
try:
from mailServer.models import Domains, EUsers
from emailPremium.models import DomainLimits, EmailLimits
from websiteFunctions.models import Websites, ChildDomains
except:
pass
class mailUtilities:
installLogPath = "/home/cyberpanel/openDKIMInstallLog"
spamassassinInstallLogPath = "/home/cyberpanel/spamassassinInstallLogPath"
RspamdInstallLogPath = "/home/cyberpanel/RspamdInstallLogPath"
RspamdUnInstallLogPath = "/home/cyberpanel/RspamdUnInstallLogPath"
cyberPanelHome = "/home/cyberpanel"
mailScannerInstallLogPath = "/home/cyberpanel/mailScannerInstallLogPath"
RSpamdLogPath = '/var/log/rspamd/rspamd.log'
@staticmethod
def SendEmail(sender, receivers, message):
try:
smtpObj = smtplib.SMTP('localhost')
smtpObj.sendmail(sender, receivers, message)
print("Successfully sent email")
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg))
@staticmethod
def AfterEffects(domain):
path = "/usr/local/CyberCP/install/rainloop/cyberpanel.net.ini"
if not os.path.exists("/usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/domains/"):
os.makedirs("/usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/domains/")
finalPath = "/usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/domains/" + domain + ".ini"
finalPathJson = "/usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/domains/" + domain + ".json"
if not os.path.exists(finalPath):
shutil.copy(path, finalPath)
contentJSON = """
{
"name": "%s",
"IMAP": {
"host": "localhost",
"port": 993,
"type": 1,
"timeout": 300,
"shortLogin": false,
"sasl": [
"SCRAM-SHA3-512",
"SCRAM-SHA-512",
"SCRAM-SHA-256",
"SCRAM-SHA-1",
"PLAIN",
"LOGIN"
],
"ssl": {
"verify_peer": false,
"verify_peer_name": false,
"allow_self_signed": false,
"SNI_enabled": true,
"disable_compression": true,
"security_level": 1
},
"use_expunge_all_on_delete": false,
"fast_simple_search": true,
"force_select": false,
"message_all_headers": false,
"message_list_limit": 10000,
"search_filter": "",
"disabled_capabilities": []
},
"SMTP": {
"host": "localhost",
"port": 587,
"type": 2,
"timeout": 60,
"shortLogin": false,
"sasl": [
"SCRAM-SHA3-512",
"SCRAM-SHA-512",
"SCRAM-SHA-256",
"SCRAM-SHA-1",
"PLAIN",
"LOGIN"
],
"ssl": {
"verify_peer": false,
"verify_peer_name": false,
"allow_self_signed": false,
"SNI_enabled": true,
"disable_compression": true,
"security_level": 1
},
"useAuth": true,
"setSender": false,
"usePhpMail": false,
"authPlainLine": false
},
"Sieve": {
"host": "",
"port": 4190,
"type": 0,
"timeout": 10,
"shortLogin": false,
"sasl": [
"SCRAM-SHA3-512",
"SCRAM-SHA-512",
"SCRAM-SHA-256",
"SCRAM-SHA-1",
"PLAIN",
"LOGIN"
],
"ssl": {
"verify_peer": false,
"verify_peer_name": false,
"allow_self_signed": false,
"SNI_enabled": true,
"disable_compression": true,
"security_level": 1
},
"enabled": false
},
"whiteList": ""
}
""" % (domain)
WriteToFile = open(finalPathJson, 'w')
WriteToFile.write(contentJSON)
WriteToFile.close()
command = 'chown -R lscpd:lscpd /usr/local/lscp/cyberpanel/rainloop/data/'
ProcessUtilities.normalExecutioner(command)
@staticmethod
def InstallMailBoxFoldersPlugin():
### now download and install actual plugin
labsPath = '/usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/configs/application.ini'
command = f'mkdir /usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/plugins/mailbox-detect'
ProcessUtilities.executioner(command)
command = f'chmod 700 /usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/plugins/mailbox-detect'
ProcessUtilities.executioner(command)
command = f'chown lscpd:lscpd /usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/plugins/mailbox-detect'
ProcessUtilities.executioner(command)
command = f'wget -O /usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/plugins/mailbox-detect/index.php https://raw.githubusercontent.com/the-djmaze/snappymail/master/plugins/mailbox-detect/index.php'
ProcessUtilities.executioner(command)
command = f'chmod 644 /usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/plugins/mailbox-detect/index.php'
ProcessUtilities.executioner(command)
command = f'chown lscpd:lscpd /usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/plugins/mailbox-detect/index.php'
ProcessUtilities.executioner(command)
### Enable plugins and enable mailbox creation plugin
labsDataLines = open(labsPath, 'r').readlines()
PluginsActivator = 0
WriteToFile = open(labsPath, 'w')
for lines in labsDataLines:
if lines.find('[plugins]') > -1:
PluginsActivator = 1
WriteToFile.write(lines)
elif PluginsActivator and lines.find('enable = ') > -1:
WriteToFile.write(f'enable = On\n')
elif PluginsActivator and lines.find('enabled_list = ') > -1:
WriteToFile.write(f'enabled_list = "mailbox-detect"\n')
elif PluginsActivator == 1 and lines.find('[defaults]') > -1:
PluginsActivator = 0
WriteToFile.write(lines)
else:
WriteToFile.write(lines)
WriteToFile.close()
## enable auto create in the enabled plugin
PluginsFilePath = '/usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/configs/plugin-mailbox-detect.json'
WriteToFile = open(PluginsFilePath, 'w')
WriteToFile.write("""{
"plugin": {
"autocreate_system_folders": true
}
}
""")
WriteToFile.close()
command = f'chown lscpd:lscpd {PluginsFilePath}'
ProcessUtilities.executioner(command)
command = f'chmod 600 {PluginsFilePath}'
ProcessUtilities.executioner(command)
@staticmethod
def createEmailAccount(domain, userName, password, restore = None):
try:
## Check if already exists
finalEmailUsername = userName + "@" + domain
if EUsers.objects.filter(email=finalEmailUsername).exists():
raise BaseException("This account already exists!")
## Check for email limits.
ChildCheck = 0
try:
website = Websites.objects.get(domain=domain)
except:
website = ChildDomains.objects.get(domain=domain)
ChildCheck = 1
try:
if not Domains.objects.filter(domain=domain).exists():
if ChildCheck == 0:
newEmailDomain = Domains(domainOwner=website, domain=domain)
else:
newEmailDomain = Domains(childOwner=website, domain=domain)
newEmailDomain.save()
if not DomainLimits.objects.filter(domain=newEmailDomain).exists():
domainLimits = DomainLimits(domain=newEmailDomain)
domainLimits.save()
if ChildCheck == 0:
if website.package.emailAccounts == 0 or (
newEmailDomain.eusers_set.all().count() < website.package.emailAccounts):
pass
else:
raise BaseException("Exceeded maximum amount of email accounts allowed for the package.")
else:
if website.master.package.emailAccounts == 0 or (
newEmailDomain.eusers_set.all().count() < website.master.package.emailAccounts):
pass
else:
raise BaseException("Exceeded maximum amount of email accounts allowed for the package.")
except:
emailDomain = Domains.objects.get(domain=domain)
if ChildCheck == 0:
if website.package.emailAccounts == 0 or (
emailDomain.eusers_set.all().count() < website.package.emailAccounts):
pass
else:
raise BaseException("Exceeded maximum amount of email accounts allowed for the package.")
else:
if website.master.package.emailAccounts == 0 or (
emailDomain.eusers_set.all().count() < website.master.package.emailAccounts):
pass
else:
raise BaseException("Exceeded maximum amount of email accounts allowed for the package.")
## After effects
execPath = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/mailUtilities.py"
execPath = execPath + " AfterEffects --domain " + domain
if getpass.getuser() == 'root':
## This is the case when cPanel Importer is running and token is not present in enviroment.
ProcessUtilities.normalExecutioner(execPath)
else:
ProcessUtilities.executioner(execPath, 'lscpd')
## After effects ends
emailDomain = Domains.objects.get(domain=domain)
#emailAcct = EUsers(emailOwner=emailDomain, email=finalEmailUsername, password=hash.hexdigest())
CentOSPath = '/etc/redhat-release'
if os.path.exists(CentOSPath):
if restore == None:
password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
password = '{CRYPT}%s' % (password.decode())
emailAcct = EUsers(emailOwner=emailDomain, email=finalEmailUsername, password=password)
emailAcct.mail = 'maildir:/home/vmail/%s/%s/Maildir' % (domain, userName)
emailAcct.save()
else:
if restore == None:
password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
password = '{CRYPT}%s' % (password.decode())
emailAcct = EUsers(emailOwner=emailDomain, email=finalEmailUsername, password=password)
emailAcct.mail = 'maildir:/home/vmail/%s/%s/Maildir' % (domain, userName)
emailAcct.save()
emailLimits = EmailLimits(email=emailAcct)
emailLimits.save()
### Create maildir structure if it doesn't exist
# Create base maildir path
maildir_base = f"/home/vmail/{domain}/{userName}"
maildir_path = f"{maildir_base}/Maildir"
# Create the main maildir structure
if not os.path.exists(maildir_path):
command = f"mkdir -p '{maildir_path}/cur' '{maildir_path}/new' '{maildir_path}/tmp'"
ProcessUtilities.executioner(command, 'vmail')
# Set proper permissions
command = f"chmod -R 700 '{maildir_base}'"
ProcessUtilities.executioner(command, 'vmail')
# Ensure ownership is correct
command = f"chown -R vmail:vmail '{maildir_base}'"
ProcessUtilities.executioner(command, 'root')
# Create standard IMAP folders
standard_folders = [
".Archive",
".Deleted Items",
".Drafts",
".Sent",
".Junk E-mail"
]
for folder in standard_folders:
folder_path = f"{maildir_path}/{folder}"
if not os.path.exists(folder_path):
command = f"mkdir -p '{folder_path}/cur' '{folder_path}/new' '{folder_path}/tmp'"
ProcessUtilities.executioner(command, 'vmail')
# Set permissions for all folders
command = f"chmod -R 700 '{maildir_path}'"
ProcessUtilities.executioner(command, 'vmail')
# Ensure final ownership
command = f"chown -R vmail:vmail '{maildir_base}'"
ProcessUtilities.executioner(command, 'root')
#if not os.path.exists('/usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/plugins/mailbox-detect'):
# mailUtilities.InstallMailBoxFoldersPlugin()
print("1,None")
return 1,"None"
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(
str(msg) + " [createEmailAccount]")
print("0," + str(msg))
return 0, str(msg)
@staticmethod
def deleteEmailAccount(email):
try:
email = EUsers(email=email)
email.delete()
return 1, 'None'
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(
str(msg) + " [deleteEmailAccount]")
return 0, str(msg)
@staticmethod
def getEmailAccounts(virtualHostName):
try:
emailDomain = Domains.objects.get(domain=virtualHostName)
return emailDomain.eusers_set.all()
except:
return 0
@staticmethod
def changeEmailPassword(email, newPassword, encrypt = None):
try:
changePass = EUsers.objects.get(email=email)
if encrypt == None:
# Always use bcrypt hashing regardless of OS
password = bcrypt.hashpw(newPassword.encode('utf-8'), bcrypt.gensalt())
password = '{CRYPT}%s' % (password.decode())
changePass.password = password
else:
changePass.password = newPassword
changePass.save()
return 0,'None'
except BaseException as msg:
return 0, str(msg)
@staticmethod
def setupDKIM(virtualHostName):
try:
## Generate DKIM Keys
import tldextract
no_cache_extract = tldextract.TLDExtract(cache_dir=None)
actualDomain = virtualHostName
extractDomain = no_cache_extract(virtualHostName)
virtualHostName = extractDomain.domain + '.' + extractDomain.suffix
if not os.path.exists("/etc/opendkim/keys/" + virtualHostName + "/default.txt"):
path = '/etc/opendkim/keys/%s' % (virtualHostName)
command = 'mkdir %s' % (path)
ProcessUtilities.normalExecutioner(command)
## Generate keys
if ProcessUtilities.decideDistro() == ProcessUtilities.centos or ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
command = "/usr/sbin/opendkim-genkey -D /etc/opendkim/keys/%s -d %s -s default" % (virtualHostName, virtualHostName)
else:
command = "opendkim-genkey -D /etc/opendkim/keys/%s -d %s -s default" % (
virtualHostName, virtualHostName)
ProcessUtilities.normalExecutioner(command)
## Fix permissions
command = "chown -R root:opendkim /etc/opendkim/keys/" + virtualHostName
ProcessUtilities.normalExecutioner(command)
command = "chmod 640 /etc/opendkim/keys/" + virtualHostName + "/default.private"
ProcessUtilities.normalExecutioner(command)
command = "chmod 644 /etc/opendkim/keys/" + virtualHostName + "/default.txt"
ProcessUtilities.normalExecutioner(command)
## Edit key file
keyTable = "/etc/opendkim/KeyTable"
configToWrite = "default._domainkey." + actualDomain + " " + actualDomain + ":default:/etc/opendkim/keys/" + virtualHostName + "/default.private\n"
if not os.path.exists(keyTable):
writeToFile = open(keyTable, 'a')
writeToFile.write("##### CyberPanel Generated File - Do not edit if you don't know what you are doing.\n")
writeToFile.close()
data = open(keyTable, 'r').read()
if data.find("default._domainkey." + actualDomain) == -1:
writeToFile = open(keyTable, 'a')
writeToFile.write(configToWrite)
writeToFile.close()
## Edit signing table
signingTable = "/etc/opendkim/SigningTable"
configToWrite = "*@" + actualDomain + " default._domainkey." + actualDomain + "\n"
if not os.path.exists(signingTable):
writeToFile = open(signingTable, 'a')
writeToFile.write("##### CyberPanel Generated File - Do not edit if you don't know what you are doing.\n")
writeToFile.close()
data = open(signingTable, 'r').read()
if data.find("default._domainkey." + actualDomain) == -1:
writeToFile = open(signingTable, 'a')
writeToFile.write(configToWrite)
writeToFile.close()
## Trusted hosts
trustedHosts = "/etc/opendkim/TrustedHosts"
configToWrite = actualDomain + "\n"
if not os.path.exists(trustedHosts):
writeToFile = open(trustedHosts, 'a')
writeToFile.write("##### CyberPanel Generated File - Do not edit if you don't know what you are doing.\n")
writeToFile.close()
data = open(trustedHosts, 'r').read()
if data.find(actualDomain) == -1:
writeToFile = open(trustedHosts, 'a')
writeToFile.write(configToWrite)
writeToFile.close()
## Restart Postfix and OpenDKIM
command = "systemctl restart opendkim"
subprocess.call(shlex.split(command))
command = "systemctl restart postfix"
subprocess.call(shlex.split(command))
return 1, "None"
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(
str(msg) + " [setupDKIM:275]")
return 0, str(msg)
@staticmethod
def checkIfDKIMInstalled():
try:
path = "/etc/opendkim.conf"
command = "sudo cat " + path
return ProcessUtilities.executioner(command)
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(
str(msg) + " [checkIfDKIMInstalled]")
return 0
@staticmethod
def generateKeys(domain):
try:
result = mailUtilities.setupDKIM(domain)
if result[0] == 0:
raise BaseException(result[1])
else:
print("1,None")
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(
str(msg) + " [generateKeys]")
print("0," + str(msg))
@staticmethod
def configureOpenDKIM():
try:
## Configure OpenDKIM specific settings
openDKIMConfigurePath = "/etc/opendkim.conf"
configData = """
Mode sv
Canonicalization relaxed/simple
KeyTable refile:/etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts
"""
writeToFile = open(openDKIMConfigurePath, 'a')
writeToFile.write(configData)
writeToFile.close()
## Configure postfix specific settings
postfixFilePath = "/etc/postfix/main.cf"
configData = """
smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept
"""
writeToFile = open(postfixFilePath, 'a')
writeToFile.write(configData)
writeToFile.close()
#### Restarting Postfix and OpenDKIM
command = "systemctl start opendkim"
subprocess.call(shlex.split(command))
command = "systemctl enable opendkim"
subprocess.call(shlex.split(command))
##
command = "systemctl start postfix"
subprocess.call(shlex.split(command))
print("1,None")
return
except OSError as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [configureOpenDKIM]")
print("0," + str(msg))
return
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [configureOpenDKIM]")
print("0," + str(msg))
return
@staticmethod
def checkHome():
try:
try:
FNULL = open(os.devnull, 'w')
if getpass.getuser() == 'root':
if not os.path.exists(mailUtilities.cyberPanelHome):
command = "mkdir " + mailUtilities.cyberPanelHome
subprocess.call(shlex.split(command), stdout=FNULL)
command = "sudo chown -R cyberpanel:cyberpanel " + mailUtilities.cyberPanelHome
subprocess.call(shlex.split(command), stdout=FNULL)
else:
if not os.path.exists(mailUtilities.cyberPanelHome):
command = "mkdir " + mailUtilities.cyberPanelHome
ProcessUtilities.executioner(command)
command = "chown -R cyberpanel:cyberpanel " + mailUtilities.cyberPanelHome
ProcessUtilities.executioner(command)
except:
FNULL = open(os.devnull, 'w')
command = "chown -R cyberpanel:cyberpanel " + mailUtilities.cyberPanelHome
subprocess.call(shlex.split(command), stdout=FNULL)
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [checkHome]")
@staticmethod
def installOpenDKIM(install, openDKIMINstall):
try:
mailUtilities.checkHome()
command = 'sudo yum install opendkim -y'
cmd = shlex.split(command)
with open(mailUtilities.installLogPath, 'w') as f:
res = subprocess.call(cmd, stdout=f)
if res == 1:
writeToFile = open(mailUtilities.installLogPath, 'a')
writeToFile.writelines("Can not be installed.[404]\n")
writeToFile.close()
logging.CyberCPLogFileWriter.writeToFile("[Could not Install OpenDKIM.]")
return 0
else:
writeToFile = open(mailUtilities.installLogPath, 'a')
writeToFile.writelines("OpenDKIM Installed.[200]\n")
writeToFile.close()
return 1
except BaseException as msg:
writeToFile = open(mailUtilities.installLogPath, 'a')
writeToFile.writelines("Can not be installed.[404]\n")
writeToFile.close()
logging.CyberCPLogFileWriter.writeToFile(str(msg) + "[installOpenDKIM]")
@staticmethod
def restartServices():
try:
command = 'systemctl restart postfix'
subprocess.call(shlex.split(command))
command = 'systemctl restart dovecot'
subprocess.call(shlex.split(command))
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [restartServices]")
@staticmethod
def installSpamAssassin(install, SpamAssassin):
try:
if os.path.exists(mailUtilities.spamassassinInstallLogPath):
os.remove(mailUtilities.spamassassinInstallLogPath)
if ProcessUtilities.decideDistro() == ProcessUtilities.centos or ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
command = 'sudo yum install spamassassin -y'
else:
command = 'sudo apt-get install spamassassin spamc -y'
cmd = shlex.split(command)
with open(mailUtilities.spamassassinInstallLogPath, 'w') as f:
res = subprocess.call(cmd, stdout=f)
if res == 1:
writeToFile = open(mailUtilities.spamassassinInstallLogPath, 'a')
writeToFile.writelines("Can not be installed.[404]\n")
writeToFile.close()
logging.CyberCPLogFileWriter.writeToFile("[Could not Install SpamAssassin.]")
return 0
else:
writeToFile = open(mailUtilities.spamassassinInstallLogPath, 'a')
writeToFile.writelines("SpamAssassin Installed.[200]\n")
writeToFile.close()
return 1
except BaseException as msg:
writeToFile = open(mailUtilities.spamassassinInstallLogPath, 'a')
writeToFile.writelines("Can not be installed.[404]\n")
writeToFile.close()
logging.CyberCPLogFileWriter.writeToFile(str(msg) + "[installSpamAssassin]")
@staticmethod
def SetupEmailLimits():
rlFile = '/etc/rspamd/override.d/ratelimit.conf'
rlContent = '''
custom_keywords = "/etc/rspamd/custom_ratelimit.lua";
'''
if not os.path.exists(rlFile):
WriteToFile = open(rlFile, 'w')
WriteToFile.write(rlContent)
WriteToFile.close()
rlLUA = '/etc/rspamd/custom_ratelimit.lua'
rlLUAContent = '''
local custom_keywords = {}
local d = {}
-- create map
d['badusers'] = rspamd_config:add_map({
['url']= '/etc/rspamd/badusers.map',
['type'] = 'map',
['description'] = 'Bad users'
})
custom_keywords.customrl = function(task)
local rspamd_logger = require "rspamd_logger"
-- get authenticated user
local user = task:get_user()
-- define a default ratelimit
local default_rl = "10 / 1m"
if not user then return end -- no user, return nil
local user_rl = d['badusers']:get_key(user)
if user_rl then
local limit, duration, unit = string.match(user_rl, "(%d+)%s-/%s-(%d+)(%a*)")
if limit and duration then
duration = tonumber(duration)
if unit == 'm' then
duration = duration * 60 -- convert minutes to seconds
elseif unit == 'h' then
duration = duration * 3600 -- convert hours to seconds
elseif unit == 'd' then
duration = duration * 86400 -- convert days to seconds
end
local custom_rl = limit .. " / " .. duration .. "s"
rspamd_logger.infox(rspamd_config, "User %s has custom ratelimit: %s", user, custom_rl)
return "rs_customrl_" .. user, custom_rl
else
rspamd_logger.errx(rspamd_config, "Invalid ratelimit format for user %s, using default: %s", user, default_rl)
return "rs_customrl_" .. user, default_rl
end
else
rspamd_logger.infox(rspamd_config, "User %s not found in bad users map, using default ratelimit: %s", user, default_rl)
return "rs_customrl_" .. user, default_rl
end
end
return custom_keywords
'''
WriteToFile = open(rlLUA, 'w')
WriteToFile.write(rlLUAContent)
WriteToFile.close()
@staticmethod
def installRspamd(install, rspamd):
from manageServices.serviceManager import ServiceManager
try:
if os.path.exists(mailUtilities.RspamdInstallLogPath):
os.remove(mailUtilities.RspamdInstallLogPath)
####Frist install redis
ServiceManager.InstallRedis()
if ProcessUtilities.decideDistro() == ProcessUtilities.centos:
writeToFile = open(mailUtilities.RspamdInstallLogPath, 'a')
writeToFile.writelines("Configuring RSPAMD repo..\n")
writeToFile.close()
command = 'curl https://rspamd.com/rpm-stable/centos-7/rspamd.repo > /etc/yum.repos.d/rspamd.repo'
ProcessUtilities.normalExecutioner(command, True)
command = 'rpm --import https://rspamd.com/rpm-stable/gpg.key'
ProcessUtilities.normalExecutioner(command, True)
command = 'yum update'
ProcessUtilities.normalExecutioner(command, True)
command = 'sudo yum install rspamd clamav-server clamav-data clamav-update clamav-filesystem clamav clamav-scanner-systemd clamav-devel clamav-lib clamav-server-systemd -y'
elif ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
writeToFile = open(mailUtilities.RspamdInstallLogPath, 'a')
writeToFile.writelines("Configuring RSPAMD repo..\n")
writeToFile.close()
command = 'curl https://rspamd.com/rpm-stable/centos-8/rspamd.repo > /etc/yum.repos.d/rspamd.repo'
ProcessUtilities.normalExecutioner(command, True)
command = 'rpm --import https://rspamd.com/rpm-stable/gpg.key'
ProcessUtilities.normalExecutioner(command, True)
command = 'yum update'
ProcessUtilities.normalExecutioner(command, True)
command = 'sudo yum install rspamd clamav clamd clamav-update -y'
else:
command = 'DEBIAN_FRONTEND=noninteractive apt-get install rspamd clamav clamav-daemon -y'
with open(mailUtilities.RspamdInstallLogPath, 'w') as f:
res = subprocess.call(command, stdout=f, shell=True)
###### makefile
path = "/etc/rspamd/local.d/antivirus.conf"
content ="""# ================= DO NOT MODIFY THIS FILE =================
#
# Manual changes will be lost when this file is regenerated.
#
# Please read the developer's guide, which is available
# at NethServer official site: https://www.nethserver.org
#
#
#Enable or disable the module
enabled = true
# multiple scanners could be checked, for each we create a configuration block with an arbitrary name
clamav {
# If set force this action if any virus is found (default unset: no action is forced, 'rewrite_subject' to tag as spam)
action = "reject";
# if `true` only messages with non-image attachments will be checked (default true)
scan_mime_parts = false;
# If `max_size` is set, messages > n bytes in size are not scanned
max_size = 20000000;
# type of scanner: "clamav", "fprot", "sophos" or "savapi"
type = "clamav";
# If set true, log message is emitted for clean messages
log_clean = false;
# Timeout and retransmits increased in case of clamav is reloading its database
# It takes a lot of time (25 to 60 seconds), after rspamd answers a temporally failure
#timeout = 5;
#retransmits = 2;
# servers to query (if port is unspecified, scanner-specific default is used)
# can be specified multiple times to pool servers
# can be set to a path to a unix socket
servers = "127.0.0.1:3310";
# if `patterns` is specified virus name will be matched against provided regexes and the related
# symbol will be yielded if a match is found. If no match is found, default symbol is yielded.
patterns {
# symbol_name = "pattern";
CLAMAV_VIRUS = "^Eicar-Test-Signature$";
}
# In version 1.7.0+ patterns could be a list for ordered matching
#patterns = [{SANE_MAL = "Sanesecurity.Malware.*"}, {CLAM_UNOFFICIAL = "UNOFFICIAL$"}];
# `whitelist` points to a map of IP addresses. Mail from these addresses is not scanned.
whitelist = "/etc/rspamd/antivirus.wl";
}
"""
wirtedata = open(path, 'w')
wirtedata.writelines(content)
wirtedata.close()
### disable dkim signing in rspamd in ref to https://github.com/usmannasir/cyberpanel/issues/1176
DKIMPath = '/etc/rspamd/local.d/dkim_signing.conf'
WriteToFile = open(DKIMPath, 'w')
WriteToFile.write('enabled = false;\n')
WriteToFile.close()
appendpath = "/etc/postfix/main.cf"
lines = open(appendpath, 'r').readlines()
WriteToFile = open(appendpath, 'w')
for line in lines:
if line.find('inet:127.0.0.1:8891') > -1:
cLine = line.rstrip('\n')
content = f'{cLine}, inet:127.0.0.1:11332\n'
WriteToFile.write('### Please do not edit this line, editing this line could break configurations\n')
WriteToFile.write(content)
elif line.find('non_smtpd_milters') > -1:
WriteToFile.write('non_smtpd_milters = $smtpd_milters\n')
else:
WriteToFile.write(line)
WriteToFile.close()
wpath = "/etc/rspamd/local.d/redis.conf"
wdata = """
write_servers = "127.0.0.1";
read_servers = "127.0.0.1";
"""
wirtedata2 = open(wpath, 'w')
wirtedata2.writelines(wdata)
wirtedata2.close()
if res == 1:
writeToFile = open(mailUtilities.RspamdInstallLogPath, 'a')
writeToFile.writelines("Can not be installed.[404]\n")
writeToFile.close()
logging.CyberCPLogFileWriter.writeToFile("[Could not Install Rspamd.]")
return 0
else:
if ProcessUtilities.decideDistro() == ProcessUtilities.centos or ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
command = 'setsebool -P antivirus_can_scan_system 1'
cmd = shlex.split(command)
with open(mailUtilities.RspamdInstallLogPath, 'a') as f:
res = subprocess.call(cmd, stdout=f)
command = 'setsebool -P clamd_use_jit 1'
cmd = shlex.split(command)
with open(mailUtilities.RspamdInstallLogPath, 'a') as f:
res = subprocess.call(cmd, stdout=f)
command = 'usermod -a -G clamscan _rspamd'
cmd = shlex.split(command)
with open(mailUtilities.RspamdInstallLogPath, 'a') as f:
res = subprocess.call(cmd, stdout=f)
clamavcontent = """
User clamscan
PidFile /var/run/clamd.scan/clamd.pid
TCPSocket 3310
TCPAddr 127.0.0.1
ConcurrentDatabaseReload no
Debug false
FixStaleSocket true
LocalSocketMode 666
ScanMail true
ScanArchive true
#LogFile /var/log/clamd.scan/clamav.log
"""
writeToFile = open('/etc/clamd.d/scan.conf', 'w')
writeToFile.write(clamavcontent)
writeToFile.close()
command = 'touch /var/log/clamd.scan/clamav.log'
ProcessUtilities.normalExecutioner(command, False, 'clamscan')
writeToFile = open(mailUtilities.RspamdInstallLogPath, 'a')
writeToFile.writelines("Updating Freshclam database..\n")
writeToFile.close()
command = 'freshclam'
cmd = shlex.split(command)
with open(mailUtilities.RspamdInstallLogPath, 'a') as f:
res = subprocess.call(cmd, stdout=f)
command = 'systemctl start clamd@scan'
cmd = shlex.split(command)
with open(mailUtilities.RspamdInstallLogPath, 'a') as f:
res = subprocess.call(cmd, stdout=f)
command = 'systemctl restart rspamd'
cmd = shlex.split(command)
with open(mailUtilities.RspamdInstallLogPath, 'a') as f:
res = subprocess.call(cmd, stdout=f)
elif ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu or ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu20:
command = 'usermod -a -G clamav _rspamd'
cmd = shlex.split(command)
with open(mailUtilities.RspamdInstallLogPath, 'a') as f:
res = subprocess.call(cmd, stdout=f)
command = 'chown -R clamav:clamav /var/run/clamav'
cmd = shlex.split(command)
with open(mailUtilities.RspamdInstallLogPath, 'a') as f:
res = subprocess.call(cmd, stdout=f)
clamavcontent = """
User clamav
PidFile /var/run/clamav/clamd.pid
TCPSocket 3310
TCPAddr 127.0.0.1
ConcurrentDatabaseReload no
Debug false
FixStaleSocket true
LocalSocketMode 666
ScanMail true
ScanArchive true
LogFile /var/log/clamav/clamav.log
"""
writeToFile = open('/etc/clamav/clamd.conf', 'w')
writeToFile.write(clamavcontent)
writeToFile.close()
writeToFile = open(mailUtilities.RspamdInstallLogPath, 'a')
writeToFile.writelines("Updating Freshclam database..\n")
writeToFile.close()
command = 'freshclam'
cmd = shlex.split(command)
with open(mailUtilities.RspamdInstallLogPath, 'a') as f:
res = subprocess.call(cmd, stdout=f)
command = 'systemctl restart clamav-daemon'
cmd = shlex.split(command)
with open(mailUtilities.RspamdInstallLogPath, 'a') as f:
res = subprocess.call(cmd, stdout=f)
command = 'systemctl restart rspamd'
cmd = shlex.split(command)
with open(mailUtilities.RspamdInstallLogPath, 'a') as f:
res = subprocess.call(cmd, stdout=f)
time.sleep(5)
writeToFile = open(mailUtilities.RspamdInstallLogPath, 'a')
writeToFile.writelines("Rspamd Installed.[200]\n")
writeToFile.close()
return 1
except BaseException as msg:
writeToFile = open(mailUtilities.RspamdInstallLogPath, 'a')
writeToFile.writelines("Can not be installed.[404]\n")
writeToFile.close()
logging.CyberCPLogFileWriter.writeToFile(str(msg) + "[installRspamd]")
@staticmethod
def uninstallRspamd(install, rspamd):
from manageServices.serviceManager import ServiceManager
try:
logging.CyberCPLogFileWriter.writeToFile( "start................[uninstallRspamd]")
if os.path.exists(mailUtilities.RspamdUnInstallLogPath):
os.remove(mailUtilities.RspamdUnInstallLogPath)
if ProcessUtilities.decideDistro() == ProcessUtilities.centos or ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
command = 'sudo yum remove rspamd clamav clamav-daemon -y'
else:
command = 'sudo apt purge rspamd clamav clamav-daemon -y'
cmd = shlex.split(command)
with open(mailUtilities.RspamdUnInstallLogPath, 'w') as f:
res = subprocess.call(cmd, stdout=f)
if res == 1:
writeToFile = open(mailUtilities.RspamdUnInstallLogPath, 'a')
writeToFile.writelines("Can not be uninstalled.[404]\n")
writeToFile.close()
logging.CyberCPLogFileWriter.writeToFile("[Could not Install Rspamd.]")
return 0
else:
cmdd = 'systemctl stop rspamd'
ProcessUtilities.normalExecutioner(cmdd)
cmmd = 'systemctl disable rspamd'
ProcessUtilities.normalExecutioner(cmmd)
writeToFile = open(mailUtilities.RspamdUnInstallLogPath, 'a')
writeToFile.writelines("Rspamd unInstalled.[200]\n")
writeToFile.close()
return 1
except BaseException as msg:
writeToFile = open(mailUtilities.RspamdUnInstallLogPath, 'a')
writeToFile.writelines("Can not be installed.[404]\n")
writeToFile.close()
logging.CyberCPLogFileWriter.writeToFile(str(msg) + "[uninstallRspamd]")
@staticmethod
def changeRspamdConfig(install, changeRspamdConfig):
try:
tempfilepath = "/home/cyberpanel/tempfilerspamdconfigs"
file= open(tempfilepath, "r")
jsondata1 = file.read()
jsondata = json.loads(jsondata1)
file.close()
status = jsondata['status']
scan_mime_parts = jsondata['scan_mime_parts']
log_clean = jsondata['log_clean']
max_size = jsondata['max_size']
server = jsondata['Rspamdserver']
CLAMAV_VIRUS = jsondata['CLAMAV_VIRUS']
action_rspamd = jsondata['action_rspamd']
confPath = "/etc/rspamd/local.d/antivirus.conf"
f = open(confPath, "r")
dataa = f.read()
f.close()
data = dataa.splitlines()
writeDataToFile = open(confPath, "w")
for items in data:
if items.find('enabled ') > -1:
if status == True:
command = 'systemctl start rspamd'
ProcessUtilities.executioner(command)
newitem = 'enabled = true'
writeDataToFile.writelines(newitem + '\n')
elif status == False:
command = 'systemctl stop rspamd'
ProcessUtilities.executioner(command)
newitem = 'enabled = false'
writeDataToFile.writelines(newitem + '\n')
elif items.find('action =') > -1:
if action_rspamd == 'Reject':
newitem = ' action = "reject";'
writeDataToFile.writelines(newitem + '\n')
elif action_rspamd == 'Unset':
newitem = ' action = "unset";'
writeDataToFile.writelines(newitem + '\n')
elif items.find('scan_mime_parts') > -1:
if scan_mime_parts == True:
newitem = ' scan_mime_parts = true;'
writeDataToFile.writelines(newitem + '\n')
elif scan_mime_parts == False:
newitem = ' scan_mime_parts = false;'
writeDataToFile.writelines(newitem + '\n')
elif items.find('log_clean =') > -1:
if log_clean == True:
newitem = ' log_clean = true;'
writeDataToFile.writelines(newitem + '\n')
elif log_clean == False:
newitem = ' log_clean = false;'
writeDataToFile.writelines(newitem + '\n')
elif items.find('max_size =') > -1:
newitem = ' max_size = %s;'%max_size
writeDataToFile.writelines(newitem + '\n')
elif items.find('CLAMAV_VIRUS =') > -1:
newitem = ' CLAMAV_VIRUS = "%s";' % CLAMAV_VIRUS
writeDataToFile.writelines(newitem + '\n')
elif items.find('servers =') > -1:
newitem = ' servers = "%s";' % server
writeDataToFile.writelines(newitem + '\n')
else:
writeDataToFile.writelines(items + '\n')
print("1,None")
return 1, 'None'
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg) + "[changeRspamdConfig]")
str((msg) + " [changeRspamdConfig]")
print(0, str(msg))
return [0, str(msg) + " [changeRspamdConfig]"]
@staticmethod
def changePostfixConfig(install , changePostfixConfig):
try:
tempfilepath = "/home/cyberpanel/tempfilepostfixconfigs"
file = open(tempfilepath, "r")
jsondata1 = file.read()
jsondata = json.loads(jsondata1)
file.close()
non_smtpd_milters = jsondata['non_smtpd_milters']
smtpd_milters = jsondata['smtpd_milters']
postfixpath = "/etc/postfix/main.cf"
f = open(postfixpath, "r")
dataa = f.read()
f.close()
data = dataa.splitlines()
writeDataToFile = open(postfixpath, "w")
for i in data:
if (i.find('smtpd_milters=') > -1 or i.find('smtpd_milters =') > -1) and i.find('non_smtpd_milters') < 0:
newitem = f'smtpd_milters = inet:127.0.0.1:8891, {smtpd_milters}\n'
writeDataToFile.writelines(newitem + '\n')
elif i.find('non_smtpd_milters=') > -1 or i.find('non_smtpd_milters =') > -1:
#newitem = 'non_smtpd_milters=%s' % non_smtpd_milters
writeDataToFile.writelines('non_smtpd_milters = $smtpd_milters\n')
else:
writeDataToFile.writelines(i + '\n')
print("1,None")
return 1, 'None'
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg) + "[changePostfixConfig]")
str((msg) + " [changePostfixConfig]")
print(0, str(msg))
return [0, str(msg) + " [changePostfixConfig]"]
@staticmethod
def changeRedisxConfig(install, changeRedisxConfig):
try:
tempfilepath = "/home/cyberpanel/saveRedisConfigurations"
file = open(tempfilepath, "r")
jsondata1 = file.read()
jsondata = json.loads(jsondata1)
file.close()
write_servers = jsondata['write_servers']
read_servers = jsondata['read_servers']
Redispath = "/etc/rspamd/local.d/redis.conf"
f = open(Redispath, "r")
dataa = f.read()
f.close()
data = dataa.splitlines()
writeDataToFile = open(Redispath, "w")
for i in data:
if i.find('write_servers =') > -1:
newitem = 'write_servers = "%s";' % write_servers
writeDataToFile.writelines(newitem + '\n')
elif i.find('read_servers =') > -1:
newitem = 'read_servers = "%s";' % read_servers
writeDataToFile.writelines(newitem + '\n')
else:
writeDataToFile.writelines(i + '\n')
print("1,None")
return 1, 'None'
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg) + "[changeRedisxConfig]")
str((msg) + " [changeRedisxConfig]")
print(0, str(msg))
return [0, str(msg) + " [changeRedisxConfig]"]
@staticmethod
def changeclamavConfig(install, changeclamavConfig):
try:
tempfilepath = "/home/cyberpanel/saveclamavConfigurations"
file = open(tempfilepath, "r")
jsondata1 = file.read()
jsondata = json.loads(jsondata1)
file.close()
LogFile= jsondata['LogFile']
TCPAddr= jsondata['TCPAddr']
TCPSocket= jsondata['TCPSocket']
clamav_Debug= jsondata['clamav_Debug']
if ProcessUtilities.decideDistro() == ProcessUtilities.centos or ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
clamavconfpath = '/etc/clamd.d/scan.conf'
elif ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu or ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu20:
clamavconfpath = "/etc/clamav/clamd.conf"
f = open(clamavconfpath, "r")
dataa = f.read()
f.close()
data = dataa.splitlines()
writeDataToFile = open(clamavconfpath, "w")
for i in data:
if i.find('TCPSocket') > -1:
newitem = 'TCPSocket %s' % TCPSocket
writeDataToFile.writelines(newitem + '\n')
elif i.find('TCPAddr') > -1:
newitem = 'TCPAddr %s' % TCPAddr
writeDataToFile.writelines(newitem + '\n')
elif i.find('LogFile') > -1:
newitem = 'LogFile %s' % LogFile
writeDataToFile.writelines(newitem + '\n')
elif i.find('Debug =') > -1:
if clamav_Debug == True:
newitem = 'Debug true'
writeDataToFile.writelines(newitem + '\n')
elif clamav_Debug == False:
newitem = 'Debug false'
writeDataToFile.writelines(newitem + '\n')
else:
writeDataToFile.writelines(i + '\n')
return 1, 'None'
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg) + "[changeclamavConfig]")
str((msg) + " [changeclamavConfig]")
print(0, str(msg))
return [0, str(msg) + " [changeclamavConfig]"]
@staticmethod
def installMailScanner(install, SpamAssassin):
try:
if os.path.exists(mailUtilities.mailScannerInstallLogPath):
os.remove(mailUtilities.mailScannerInstallLogPath)
if mailUtilities.checkIfSpamAssassinInstalled():
command = 'chmod +x /usr/local/CyberCP/CPScripts/mailscannerinstaller.sh'
ProcessUtilities.executioner(command)
command = '/usr/local/CyberCP/CPScripts/mailscannerinstaller.sh'
cmd = shlex.split(command)
with open(mailUtilities.mailScannerInstallLogPath, 'w') as f:
res = subprocess.call(cmd, stdout=f, shell=True)
if res == 1:
writeToFile = open(mailUtilities.mailScannerInstallLogPath, 'a')
writeToFile.writelines("Can not be installed.[404]\n")
writeToFile.close()
logging.CyberCPLogFileWriter.writeToFile("[Could not Install MailScanner.]")
return 0
else:
writeToFile = open(mailUtilities.mailScannerInstallLogPath, 'a')
writeToFile.writelines("MailScanner Installed.[200]\n")
writeToFile.close()
return 1
else:
writeToFile = open(mailUtilities.mailScannerInstallLogPath, 'a')
writeToFile.writelines("Please install SpamAssassin from CyberPanel before installing MailScanner.[404]\n")
writeToFile.close()
except BaseException as msg:
writeToFile = open(mailUtilities.mailScannerInstallLogPath, 'a')
writeToFile.writelines("Can not be installed.[404]\n")
writeToFile.close()
logging.CyberCPLogFileWriter.writeToFile(str(msg) + "[installSpamAssassin]")
@staticmethod
def checkIfSpamAssassinInstalled():
try:
path = "/etc/postfix/master.cf"
command = "cat " + path
output = ProcessUtilities.outputExecutioner(command)
if output.find('spamassassin') > -1 and output.find('user=spamd') > -1:
return 1
else:
return 0
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(
str(msg) + " [checkIfSpamAssassinInstalled]")
return 0
@staticmethod
def configureSpamAssassin():
try:
if ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu or ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu20:
confFile = "/etc/mail/spamassassin/local.cf"
confData = open(confFile).readlines()
conf = open(confFile, 'w')
for items in confData:
if items.find('report_safe') > -1 or items.find('rewrite_header') > -1 or items.find('required_score') > -1 or items.find('required_hits') > -1:
conf.write(items.strip('#').strip(' '))
else:
conf.write(items)
conf.close()
command = "groupadd spamd"
ProcessUtilities.normalExecutioner(command)
command = "useradd -g spamd -s /bin/false -d /var/log/spamassassin spamd"
ProcessUtilities.normalExecutioner(command)
##
command = "chown spamd:spamd /var/log/spamassassin"
ProcessUtilities.normalExecutioner(command)
command = "systemctl enable spamassassin"
ProcessUtilities.normalExecutioner(command)
command = "systemctl start spamassassin"
ProcessUtilities.normalExecutioner(command)
## Configuration to postfix
postfixConf = '/etc/postfix/master.cf'
data = open(postfixConf, 'r').readlines()
writeToFile = open(postfixConf, 'w')
checker = 1
for items in data:
if items.find('smtp') > - 1 and items.find('inet') > - 1 and items.find('smtpd') > - 1 and checker == 1:
writeToFile.writelines(items.strip('\n') + ' -o content_filter=spamassassin\n')
checker = 0
else:
writeToFile.writelines(items)
writeToFile.writelines('spamassassin unix - n n - - pipe flags=R user=spamd argv=/usr/bin/spamc -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}')
writeToFile.close()
command = 'systemctl restart postfix'
ProcessUtilities.normalExecutioner(command)
print("1,None")
return
except OSError as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [configureSpamAssassin]")
print("0," + str(msg))
return
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [configureSpamAssassin]")
print("0," + str(msg))
return
@staticmethod
def saveSpamAssassinConfigs(tempConfigPath):
try:
data = open(tempConfigPath).readlines()
os.remove(tempConfigPath)
confFile = "/etc/mail/spamassassin/local.cf"
confData = open(confFile).readlines()
conf = open(confFile, 'w')
rsCheck = 0
for items in confData:
if items.find('report_safe ') > -1:
conf.writelines(data[0])
continue
elif items.find('required_hits ') > -1:
conf.writelines(data[1])
continue
elif items.find('rewrite_header ') > -1:
conf.writelines(data[2])
continue
elif items.find('required_score ') > -1:
conf.writelines(data[3])
rsCheck = 1
continue
if rsCheck == 0:
conf.writelines(data[3])
conf.close()
command = 'systemctl restart spamassassin'
subprocess.call(shlex.split(command))
print("1,None")
return
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(
str(msg) + " [saveSpamAssassinConfigs]")
print("0," + str(msg))
@staticmethod
def savePolicyServerStatus(install):
try:
postfixPath = '/etc/postfix/main.cf'
if install == '1':
if not os.path.exists('/etc/systemd/system/cpecs.service'):
shutil.copy("/usr/local/CyberCP/postfixSenderPolicy/cpecs.service", "/etc/systemd/system/cpecs.service")
command = 'systemctl enable cpecs'
subprocess.call(shlex.split(command))
command = 'systemctl start cpecs'
subprocess.call(shlex.split(command))
writeToFile = open(postfixPath, 'a')
writeToFile.writelines('smtpd_data_restrictions = check_policy_service unix:/var/log/policyServerSocket\n')
writeToFile.writelines('smtpd_policy_service_default_action = DUNNO\n')
writeToFile.close()
command = 'systemctl restart postfix'
subprocess.call(shlex.split(command))
else:
data = open(postfixPath, 'r').readlines()
writeToFile = open(postfixPath, 'w')
for items in data:
if items.find('check_policy_service unix:/var/log/policyServerSocket') > -1:
continue
elif items.find('smtpd_policy_service_default_action = DUNNO') > -1:
continue
else:
writeToFile.writelines(items)
writeToFile.close()
command = 'systemctl stop cpecs'
subprocess.call(shlex.split(command))
command = 'systemctl restart postfix'
subprocess.call(shlex.split(command))
print("1,None")
return
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(
str(msg) + " [savePolicyServerStatus]")
print("0," + str(msg))
@staticmethod
def checkIfMailScannerInstalled():
try:
path = "/usr/local/CyberCP/public/mailwatch"
if os .path.exists(path):
return 1
else:
return 0
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(
str(msg) + " [checkIfMailScannerInstalled]")
return 0
@staticmethod
def checkIfRspamdInstalled():
try:
if os.path.exists('/etc/rspamd/rspamd.conf'):
return 1
else:
return 0
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(
str(msg) + " [checkIfMailScannerInstalled]")
return 0
@staticmethod
def FetchPostfixHostname():
try:
PostfixPath = '/etc/postfix/main.cf'
if os.path.exists(PostfixPath):
PostFixConf = open(PostfixPath, 'r').readlines()
for line in PostFixConf:
if line.find('myhostname') > -1:
hostname = line.split('=')[1].strip(' ').rstrip('\n')
return hostname
else:
return 'localhost'
except:
return 'localhost'
@staticmethod
def reverse_dns_lookup(ip_address):
try:
import requests
fetchURLs = requests.get('https://cyberpanel.net/dnsServers.txt')
if fetchURLs.status_code == 200:
urls = fetchURLs.json()['urls']
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(f'DNS urls {urls}.')
results = []
###
for url in urls:
try:
response = requests.get(f'{url}/index.php?ip={ip_address}', timeout=5)
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(f'url to call {ip_address} is {url}')
if response.status_code == 200:
data = response.json()
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(f'response from dns system {str(data)}')
if data['status'] == 1:
results.append(data['results']['8.8.8.8'])
results.append(data['results']['1.1.1.1'])
results.append(data['results']['9.9.9.9'])
except:
pass
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(f'rDNS result of {ip_address} is {str(results)}')
###
return results
except BaseException as e:
logging.CyberCPLogFileWriter.writeToFile(f'Error in fetch rDNS {str(msg)}')
# Handle errors, e.g., if reverse DNS lookup fails
return []
@staticmethod
def SaveEmailLimitsNew(tempPath):
try:
content = open(tempPath, 'r').read()
email = content.split(' ')[0]
path = '/etc/rspamd/badusers.map'
WriteCheck = 0
if os.path.exists(path):
data = open(path, 'r').readlines()
WriteToFile = open(path, 'w')
for line in data:
if line.find(email) > -1:
WriteToFile.write(content)
WriteCheck = 1
else:
WriteToFile.write(line)
if WriteCheck == 0:
WriteToFile.write(content)
WriteToFile.close()
else:
WriteToFile = open(path, 'w')
WriteToFile.write(content)
WriteToFile.close()
command = 'systemctl restart rspamd'
ProcessUtilities.executioner(command)
print(f'1,None')
except BaseException as msg:
print(f'0,{str(msg)}')
####### Imported below functions from mailserver/mailservermanager, need to refactor later
class MailServerManagerUtils(multi.Thread):
def __init__(self, request=None, function=None, extraArgs=None):
multi.Thread.__init__(self)
self.request = request
self.function = function
self.extraArgs = extraArgs
self.MailSSL = 0
def checkIfMailServerSSLIssued(self):
postfixPath = '/etc/postfix/main.cf'
postFixData = ProcessUtilities.outputExecutioner('cat %s' % (postfixPath))
if postFixData.find('myhostname = server.example.com') > -1:
self.MailSSL = 0
return 0
else:
try:
postFixLines = ProcessUtilities.outputExecutioner('cat %s' % (postfixPath)).splitlines()
for items in postFixLines:
if items.find('myhostname') > -1 and items[0] != '#':
self.mailHostName = items.split('=')[1].strip(' ')
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(f'Mail server SSL is issued with value: {self.mailHostName}')
self.MailSSL = 1
except BaseException as msg:
self.MailSSL = 0
logging.CyberCPLogFileWriter.writeToFile('%s. [checkIfMailServerSSLIssued:864]' % (str(msg)))
ipFile = "/etc/cyberpanel/machineIP"
f = open(ipFile)
ipData = f.read()
ipAddress = ipData.split('\n', 1)[0]
command = 'openssl s_client -connect %s:465' % (ipAddress)
result = ProcessUtilities.outputExecutioner(command)
if result.find('18 (self signed certificate)') > -1:
return 0
else:
return 1
def RunServerLevelEmailChecks(self):
try:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Checking if MailServer SSL issued..,10')
reportFile = self.extraArgs['reportFile']
report = {}
report['MailSSL'] = self.checkIfMailServerSSLIssued()
writeToFile = open(reportFile, 'w')
writeToFile.write(json.dumps(report))
writeToFile.close()
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], 'Completed [200].')
except BaseException as msg:
final_dic = {'installOpenDKIM': 0, 'error_message': str(msg)}
final_json = json.dumps(final_dic)
return HttpResponse(final_json)
def FetchCloudLinuxAlmaVersionVersion(self):
if os.path.exists('/etc/os-release'):
data = open('/etc/os-release', 'r').read()
if (data.find('CloudLinux') > -1 or data.find('cloudlinux') > -1) and (
data.find('8.9') > -1 or data.find('Anatoly Levchenko') > -1 or data.find('VERSION="8.') > -1):
return 'cl-89'
elif (data.find('CloudLinux') > -1 or data.find('cloudlinux') > -1) and (
data.find('8.8') > -1 or data.find('Anatoly Filipchenko') > -1):
return 'cl-88'
elif (data.find('CloudLinux') > -1 or data.find('cloudlinux') > -1) and (
data.find('9.4') > -1 or data.find('VERSION="9.') > -1):
return 'cl-88'
elif (data.find('AlmaLinux') > -1 or data.find('almalinux') > -1) and (
data.find('8.9') > -1 or data.find('Midnight Oncilla') > -1 or data.find('VERSION="8.') > -1):
return 'al-88'
elif (data.find('AlmaLinux') > -1 or data.find('almalinux') > -1) and (
data.find('8.7') > -1 or data.find('Stone Smilodon') > -1):
return 'al-87'
elif (data.find('AlmaLinux') > -1 or data.find('almalinux') > -1) and (
data.find('9.4') > -1 or data.find('9.3') > -1 or data.find('Shamrock Pampas') > -1 or data.find(
'Seafoam Ocelot') > -1 or data.find('VERSION="9.') > -1):
return 'al-93'
else:
return -1
def install_postfix_dovecot(self):
try:
if ProcessUtilities.decideDistro() == ProcessUtilities.centos or ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
command = 'yum remove postfix* dovecot* -y'
ProcessUtilities.executioner(command, None, True)
elif ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu or ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu20:
command = 'apt-get -y remove postfix* dovecot*'
ProcessUtilities.executioner(command, None, True)
### On Ubuntu 18 find if old dovecot and remove
if ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu:
try:
command = 'apt-get purge dovecot* -y'
ProcessUtilities.executioner(command, None, True)
command = 'apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 18A348AEED409DA1'
ProcessUtilities.executioner(command)
writeToFile = open('/etc/apt/sources.list.d/dovecot.list', 'a')
writeToFile.writelines('deb [arch=amd64] https://repo.dovecot.org/ce-2.3-latest/ubuntu/bionic bionic main\n')
writeToFile.close()
command = 'apt update'
ProcessUtilities.executioner(command)
except:
pass
##
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], 'Re-installing postfix..,10')
if ProcessUtilities.decideDistro() == ProcessUtilities.centos:
command = 'yum --nogpg install https://mirror.ghettoforge.net/distributions/gf/gf-release-latest.gf.el7.noarch.rpm -y'
ProcessUtilities.executioner(command)
command = 'yum install --enablerepo=gf-plus -y postfix3 postfix3-ldap postfix3-mysql postfix3-pcre'
elif ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
clAPVersion = self.FetchCloudLinuxAlmaVersionVersion()
type = clAPVersion.split('-')[0]
version = int(clAPVersion.split('-')[1])
if type == 'al' and version >= 90:
command = 'dnf --nogpg install -y https://mirror.ghettoforge.net/distributions/gf/gf-release-latest.gf.el9.noarch.rpm'
ProcessUtilities.executioner(command)
else:
command = 'dnf --nogpg install -y https://mirror.ghettoforge.net/distributions/gf/gf-release-latest.gf.el8.noarch.rpm'
ProcessUtilities.executioner(command)
command = 'dnf install --enablerepo=gf-plus postfix3 postfix3-mysql -y'
else:
import socket
command = 'apt-get install -y debconf-utils'
ProcessUtilities.executioner(command)
file_name = 'pf.unattend.text'
pf = open(file_name, 'w')
pf.write('postfix postfix/mailname string ' + str(socket.getfqdn() + '\n'))
pf.write('postfix postfix/main_mailer_type string "Internet Site"\n')
pf.close()
command = 'debconf-set-selections ' + file_name
ProcessUtilities.executioner(command)
command = 'apt-get -y install postfix postfix-mysql'
# os.remove(file_name)
ProcessUtilities.executioner(command)
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], 'Re-installing Dovecot..,15')
##
if ProcessUtilities.decideDistro() == ProcessUtilities.centos:
command = 'yum --enablerepo=gf-plus -y install dovecot23 dovecot23-mysql'
ProcessUtilities.executioner(command)
elif ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
command = 'dnf install --enablerepo=gf-plus dovecot23 dovecot23-mysql -y'
ProcessUtilities.executioner(command)
else:
command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install dovecot-mysql dovecot-imapd dovecot-pop3d'
os.system(command)
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Postfix/dovecot reinstalled.,40')
except BaseException as msg:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'%s [install_postfix_dovecot][404]' % (str(msg)), 10)
return 0
return 1
def setup_email_Passwords(self, mysqlPassword):
try:
mysql_virtual_domains = "/usr/local/CyberCP/install/email-configs-one/mysql-virtual_domains.cf"
mysql_virtual_forwardings = "/usr/local/CyberCP/install/email-configs-one/mysql-virtual_forwardings.cf"
mysql_virtual_mailboxes = "/usr/local/CyberCP/install/email-configs-one/mysql-virtual_mailboxes.cf"
mysql_virtual_email2email = "/usr/local/CyberCP/install/email-configs-one/mysql-virtual_email2email.cf"
dovecotmysql = "/usr/local/CyberCP/install/email-configs-one/dovecot-sql.conf.ext"
### update password:
data = open(dovecotmysql, "r").readlines()
writeDataToFile = open(dovecotmysql, "w")
dataWritten = "connect = host=localhost dbname=cyberpanel user=cyberpanel password=" + mysqlPassword + " port=3306\n"
for items in data:
if items.find("connect") > -1:
writeDataToFile.writelines(dataWritten)
else:
writeDataToFile.writelines(items)
# if self.distro == ubuntu:
# os.fchmod(writeDataToFile.fileno(), stat.S_IRUSR | stat.S_IWUSR)
writeDataToFile.close()
### update password:
data = open(mysql_virtual_domains, "r").readlines()
writeDataToFile = open(mysql_virtual_domains, "w")
dataWritten = "password = " + mysqlPassword + "\n"
for items in data:
if items.find("password") > -1:
writeDataToFile.writelines(dataWritten)
else:
writeDataToFile.writelines(items)
# if self.distro == ubuntu:
# os.fchmod(writeDataToFile.fileno(), stat.S_IRUSR | stat.S_IWUSR)
writeDataToFile.close()
### update password:
data = open(mysql_virtual_forwardings, "r").readlines()
writeDataToFile = open(mysql_virtual_forwardings, "w")
dataWritten = "password = " + mysqlPassword + "\n"
for items in data:
if items.find("password") > -1:
writeDataToFile.writelines(dataWritten)
else:
writeDataToFile.writelines(items)
# if self.distro == ubuntu:
# os.fchmod(writeDataToFile.fileno(), stat.S_IRUSR | stat.S_IWUSR)
writeDataToFile.close()
### update password:
data = open(mysql_virtual_mailboxes, "r").readlines()
writeDataToFile = open(mysql_virtual_mailboxes, "w")
dataWritten = "password = " + mysqlPassword + "\n"
for items in data:
if items.find("password") > -1:
writeDataToFile.writelines(dataWritten)
else:
writeDataToFile.writelines(items)
# if self.distro == ubuntu:
# os.fchmod(writeDataToFile.fileno(), stat.S_IRUSR | stat.S_IWUSR)
writeDataToFile.close()
### update password:
data = open(mysql_virtual_email2email, "r").readlines()
writeDataToFile = open(mysql_virtual_email2email, "w")
dataWritten = "password = " + mysqlPassword + "\n"
for items in data:
if items.find("password") > -1:
writeDataToFile.writelines(dataWritten)
else:
writeDataToFile.writelines(items)
# if self.distro == ubuntu:
# os.fchmod(writeDataToFile.fileno(), stat.S_IRUSR | stat.S_IWUSR)
writeDataToFile.close()
if self.remotemysql == 'ON':
command = "sed -i 's|host=localhost|host=%s|g' %s" % (self.mysqlhost, dovecotmysql)
ProcessUtilities.executioner(command)
command = "sed -i 's|port=3306|port=%s|g' %s" % (self.mysqlport, dovecotmysql)
ProcessUtilities.executioner(command)
##
command = "sed -i 's|localhost|%s:%s|g' %s" % (self.mysqlhost, self.mysqlport, mysql_virtual_domains)
ProcessUtilities.executioner(command)
command = "sed -i 's|localhost|%s:%s|g' %s" % (
self.mysqlhost, self.mysqlport, mysql_virtual_forwardings)
ProcessUtilities.executioner(command)
command = "sed -i 's|localhost|%s:%s|g' %s" % (
self.mysqlhost, self.mysqlport, mysql_virtual_mailboxes)
ProcessUtilities.executioner(command)
command = "sed -i 's|localhost|%s:%s|g' %s" % (
self.mysqlhost, self.mysqlport, mysql_virtual_email2email)
ProcessUtilities.executioner(command)
except BaseException as msg:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'%s [setup_email_Passwords][404]' % (str(msg)), 10)
return 0
return 1
def centos_lib_dir_to_ubuntu(self, filename, old, new):
try:
#command = "sed -i 's|%s|%s|g' %s" % (old, new, filename)
#ProcessUtilities.executioner(command, None, True)
fd = open(filename, 'r')
lines = fd.readlines()
fd.close()
fd = open(filename, 'w')
centos_prefix = old
ubuntu_prefix = new
for line in lines:
index = line.find(centos_prefix)
if index != -1:
line = line[:index] + ubuntu_prefix + line[index + len(centos_prefix):]
fd.write(line)
fd.close()
except BaseException as msg:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'%s [centos_lib_dir_to_ubuntu][404]' % (str(msg)), 10)
def setup_postfix_dovecot_config(self):
try:
mysql_virtual_domains = "/etc/postfix/mysql-virtual_domains.cf"
mysql_virtual_forwardings = "/etc/postfix/mysql-virtual_forwardings.cf"
mysql_virtual_mailboxes = "/etc/postfix/mysql-virtual_mailboxes.cf"
mysql_virtual_email2email = "/etc/postfix/mysql-virtual_email2email.cf"
main = "/etc/postfix/main.cf"
master = "/etc/postfix/master.cf"
dovecot = "/etc/dovecot/dovecot.conf"
dovecotmysql = "/etc/dovecot/dovecot-sql.conf.ext"
if os.path.exists(mysql_virtual_domains):
os.remove(mysql_virtual_domains)
if os.path.exists(mysql_virtual_forwardings):
os.remove(mysql_virtual_forwardings)
if os.path.exists(mysql_virtual_mailboxes):
os.remove(mysql_virtual_mailboxes)
if os.path.exists(mysql_virtual_email2email):
os.remove(mysql_virtual_email2email)
if os.path.exists(main):
os.remove(main)
if os.path.exists(master):
os.remove(master)
if os.path.exists(dovecot):
os.remove(dovecot)
if os.path.exists(dovecotmysql):
os.remove(dovecotmysql)
###############Getting SSL
command = 'openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" -keyout /etc/postfix/key.pem -out /etc/postfix/cert.pem'
ProcessUtilities.executioner(command)
##
command = 'openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" -keyout /etc/dovecot/key.pem -out /etc/dovecot/cert.pem'
ProcessUtilities.executioner(command)
# Cleanup config files for ubuntu
if ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu or ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu20:
self.centos_lib_dir_to_ubuntu("/usr/local/CyberCP/install/email-configs-one/master.cf", "/usr/libexec/",
"/usr/lib/")
self.centos_lib_dir_to_ubuntu("/usr/local/CyberCP/install/email-configs-one/main.cf",
"/usr/libexec/postfix",
"/usr/lib/postfix/sbin")
########### Copy config files
import shutil
shutil.copy("/usr/local/CyberCP/install/email-configs-one/mysql-virtual_domains.cf",
"/etc/postfix/mysql-virtual_domains.cf")
shutil.copy("/usr/local/CyberCP/install/email-configs-one/mysql-virtual_forwardings.cf",
"/etc/postfix/mysql-virtual_forwardings.cf")
shutil.copy("/usr/local/CyberCP/install/email-configs-one/mysql-virtual_mailboxes.cf",
"/etc/postfix/mysql-virtual_mailboxes.cf")
shutil.copy("/usr/local/CyberCP/install/email-configs-one/mysql-virtual_email2email.cf",
"/etc/postfix/mysql-virtual_email2email.cf")
shutil.copy("/usr/local/CyberCP/install/email-configs-one/main.cf", main)
shutil.copy("/usr/local/CyberCP/install/email-configs-one/master.cf", master)
shutil.copy("/usr/local/CyberCP/install/email-configs-one/dovecot.conf", dovecot)
shutil.copy("/usr/local/CyberCP/install/email-configs-one/dovecot-sql.conf.ext", dovecotmysql)
######################################## Permissions
command = 'chmod o= /etc/postfix/mysql-virtual_domains.cf'
ProcessUtilities.executioner(command)
##
command = 'chmod o= /etc/postfix/mysql-virtual_forwardings.cf'
ProcessUtilities.executioner(command)
##
command = 'chmod o= /etc/postfix/mysql-virtual_mailboxes.cf'
ProcessUtilities.executioner(command)
##
command = 'chmod o= /etc/postfix/mysql-virtual_email2email.cf'
ProcessUtilities.executioner(command)
##
command = 'chmod o= ' + main
ProcessUtilities.executioner(command)
##
command = 'chmod o= ' + master
ProcessUtilities.executioner(command)
#######################################
command = 'chgrp postfix /etc/postfix/mysql-virtual_domains.cf'
ProcessUtilities.executioner(command)
##
command = 'chgrp postfix /etc/postfix/mysql-virtual_forwardings.cf'
ProcessUtilities.executioner(command)
##
command = 'chgrp postfix /etc/postfix/mysql-virtual_mailboxes.cf'
ProcessUtilities.executioner(command)
##
command = 'chgrp postfix /etc/postfix/mysql-virtual_email2email.cf'
ProcessUtilities.executioner(command)
##
command = 'chgrp postfix ' + main
ProcessUtilities.executioner(command)
##
command = 'chgrp postfix ' + master
ProcessUtilities.executioner(command)
######################################## users and groups
command = 'groupadd -g 5000 vmail'
ProcessUtilities.executioner(command)
##
command = 'useradd -g vmail -u 5000 vmail -d /home/vmail -m'
ProcessUtilities.executioner(command)
######################################## Further configurations
# hostname = socket.gethostname()
################################### Restart postix
command = 'systemctl enable postfix.service'
ProcessUtilities.executioner(command)
##
command = 'systemctl start postfix.service'
ProcessUtilities.executioner(command)
######################################## Permissions
command = 'chgrp dovecot /etc/dovecot/dovecot-sql.conf.ext'
ProcessUtilities.executioner(command)
##
command = 'chmod o= /etc/dovecot/dovecot-sql.conf.ext'
ProcessUtilities.executioner(command)
################################### Restart dovecot
command = 'systemctl enable dovecot.service'
ProcessUtilities.executioner(command)
##
command = 'systemctl start dovecot.service'
ProcessUtilities.executioner(command)
##
command = 'systemctl restart postfix.service'
ProcessUtilities.executioner(command)
## changing permissions for main.cf
command = "chmod 755 " + main
ProcessUtilities.executioner(command)
if ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu or ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu20:
command = "mkdir -p /etc/pki/dovecot/private/"
ProcessUtilities.executioner(command)
command = "mkdir -p /etc/pki/dovecot/certs/"
ProcessUtilities.executioner(command)
command = "mkdir -p /etc/opendkim/keys/"
ProcessUtilities.executioner(command)
command = "sed -i 's/auth_mechanisms = plain/#auth_mechanisms = plain/g' /etc/dovecot/conf.d/10-auth.conf"
ProcessUtilities.executioner(command)
## Ubuntu 18.10 ssl_dh for dovecot 2.3.2.1
if ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu:
dovecotConf = '/etc/dovecot/dovecot.conf'
data = open(dovecotConf, 'r').readlines()
writeToFile = open(dovecotConf, 'w')
for items in data:
if items.find('ssl_key = <key.pem') > -1:
writeToFile.writelines(items)
writeToFile.writelines('ssl_dh = </usr/share/dovecot/dh.pem\n')
else:
writeToFile.writelines(items)
writeToFile.close()
command = "systemctl restart dovecot"
ProcessUtilities.executioner(command)
## For ubuntu 20
if ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu20:
command = "sed -i 's|daemon_directory = /usr/libexec/postfix|daemon_directory = /usr/lib/postfix/sbin|g' /etc/postfix/main.cf"
ProcessUtilities.executioner(command)
except BaseException as msg:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'%s [setup_postfix_dovecot_config][404]' % (
str(msg)), 10)
return 0
return 1
def fixCyberPanelPermissions(self):
###### fix Core CyberPanel permissions
command = "find /usr/local/CyberCP -type d -exec chmod 0755 {} \;"
ProcessUtilities.executioner(command)
command = "find /usr/local/CyberCP -type f -exec chmod 0644 {} \;"
ProcessUtilities.executioner(command)
command = "chmod -R 755 /usr/local/CyberCP/bin"
ProcessUtilities.executioner(command)
## change owner
command = "chown -R root:root /usr/local/CyberCP"
ProcessUtilities.executioner(command)
########### Fix LSCPD
command = "find /usr/local/lscp -type d -exec chmod 0755 {} \;"
ProcessUtilities.executioner(command)
command = "find /usr/local/lscp -type f -exec chmod 0644 {} \;"
ProcessUtilities.executioner(command)
command = "chmod -R 755 /usr/local/lscp/bin"
ProcessUtilities.executioner(command)
command = "chmod -R 755 /usr/local/lscp/fcgi-bin"
ProcessUtilities.executioner(command)
command = "chown -R lscpd:lscpd /usr/local/CyberCP/public/phpmyadmin/tmp"
ProcessUtilities.executioner(command)
## change owner
command = "chown -R root:root /usr/local/lscp"
ProcessUtilities.executioner(command)
command = "chown -R lscpd:lscpd /usr/local/lscp/cyberpanel/rainloop/data"
ProcessUtilities.executioner(command)
command = "chmod 700 /usr/local/CyberCP/cli/cyberPanel.py"
ProcessUtilities.executioner(command)
command = "chmod 700 /usr/local/CyberCP/plogical/upgradeCritical.py"
ProcessUtilities.executioner(command)
command = "chmod 755 /usr/local/CyberCP/postfixSenderPolicy/client.py"
ProcessUtilities.executioner(command)
command = "chmod 640 /usr/local/CyberCP/CyberCP/settings.py"
ProcessUtilities.executioner(command)
command = "chown root:cyberpanel /usr/local/CyberCP/CyberCP/settings.py"
ProcessUtilities.executioner(command)
files = ['/etc/yum.repos.d/MariaDB.repo', '/etc/pdns/pdns.conf', '/etc/systemd/system/lscpd.service',
'/etc/pure-ftpd/pure-ftpd.conf', '/etc/pure-ftpd/pureftpd-pgsql.conf',
'/etc/pure-ftpd/pureftpd-mysql.conf', '/etc/pure-ftpd/pureftpd-ldap.conf',
'/etc/dovecot/dovecot.conf', '/usr/local/lsws/conf/httpd_config.xml',
'/usr/local/lsws/conf/modsec.conf', '/usr/local/lsws/conf/httpd.conf']
for items in files:
command = 'chmod 644 %s' % (items)
ProcessUtilities.executioner(command)
impFile = ['/etc/pure-ftpd/pure-ftpd.conf', '/etc/pure-ftpd/pureftpd-pgsql.conf',
'/etc/pure-ftpd/pureftpd-mysql.conf', '/etc/pure-ftpd/pureftpd-ldap.conf',
'/etc/dovecot/dovecot.conf', '/etc/pdns/pdns.conf', '/etc/pure-ftpd/db/mysql.conf',
'/etc/powerdns/pdns.conf']
for items in impFile:
command = 'chmod 600 %s' % (items)
ProcessUtilities.executioner(command)
command = 'chmod 640 /etc/postfix/*.cf'
subprocess.call(command, shell=True)
command = 'chmod 644 /etc/postfix/main.cf'
subprocess.call(command, shell=True)
command = 'chmod 640 /etc/dovecot/*.conf'
subprocess.call(command, shell=True)
command = 'chmod 644 /etc/dovecot/dovecot.conf'
subprocess.call(command, shell=True)
command = 'chmod 640 /etc/dovecot/dovecot-sql.conf.ext'
subprocess.call(command, shell=True)
command = 'chmod 644 /etc/postfix/dynamicmaps.cf'
subprocess.call(command, shell=True)
fileM = ['/usr/local/lsws/FileManager/', '/usr/local/CyberCP/install/FileManager',
'/usr/local/CyberCP/serverStatus/litespeed/FileManager', '/usr/local/lsws/Example/html/FileManager']
for items in fileM:
try:
import shutil
shutil.rmtree(items)
except:
pass
command = 'chmod 755 /etc/pure-ftpd/'
subprocess.call(command, shell=True)
command = 'chmod +x /usr/local/CyberCP/plogical/renew.py'
ProcessUtilities.executioner(command)
command = 'chmod +x /usr/local/CyberCP/CLManager/CLPackages.py'
ProcessUtilities.executioner(command)
clScripts = ['/usr/local/CyberCP/CLScript/panel_info.py', '/usr/local/CyberCP/CLScript/CloudLinuxPackages.py',
'/usr/local/CyberCP/CLScript/CloudLinuxUsers.py',
'/usr/local/CyberCP/CLScript/CloudLinuxDomains.py'
, '/usr/local/CyberCP/CLScript/CloudLinuxResellers.py', '/usr/local/CyberCP/CLScript/CloudLinuxAdmins.py',
'/usr/local/CyberCP/CLScript/CloudLinuxDB.py', '/usr/local/CyberCP/CLScript/UserInfo.py']
for items in clScripts:
command = 'chmod +x %s' % (items)
ProcessUtilities.executioner(command)
command = 'chmod 600 /usr/local/CyberCP/plogical/adminPass.py'
ProcessUtilities.executioner(command)
command = 'chmod 600 /etc/cagefs/exclude/cyberpanelexclude'
ProcessUtilities.executioner(command)
command = "find /usr/local/CyberCP/ -name '*.pyc' -delete"
ProcessUtilities.executioner(command)
if ProcessUtilities.decideDistro() == ProcessUtilities.centos or ProcessUtilities.cent8:
command = 'chown root:pdns /etc/pdns/pdns.conf'
ProcessUtilities.executioner(command)
command = 'chmod 640 /etc/pdns/pdns.conf'
ProcessUtilities.executioner(command)
command = 'chmod 640 /usr/local/lscp/cyberpanel/logs/access.log'
ProcessUtilities.executioner(command)
###
def installOpenDKIMNew(self):
try:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Installing opendkim..,40')
if ProcessUtilities.decideDistro() == ProcessUtilities.centos:
command = 'yum -y erase opendkim*'
os.system(command)
command = 'yum -y install opendkim'
elif ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
command = 'yum -y erase opendkim*'
os.system(command)
command = 'dnf install opendkim -y'
else:
command = 'apt-get -y purge opendkim'
os.system(command)
command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install opendkim'
os.system(command)
if ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
command = 'dnf install opendkim-tools -y'
ProcessUtilities.executioner(command)
if ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu or ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu20:
command = 'apt install opendkim-tools -y'
ProcessUtilities.executioner(command)
command = 'mkdir -p /etc/opendkim/keys/'
ProcessUtilities.executioner(command)
except BaseException as msg:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'%s [installOpenDKIM][404]' % (str(msg)), 10)
return 0
return 1
def SetupDKIMFromResetMail(self):
from plogical.dnsUtilities import DNS
for website in Websites.objects.all():
mailUtilities.setupDKIM(website.domain)
DNS.createDKIMRecords(website.domain)
for website in ChildDomains.objects.all():
mailUtilities.setupDKIM(website.domain)
DNS.createDKIMRecords(website.domain)
def ResetEmailConfigurations(self):
try:
### Check if remote or local mysql
passFile = "/etc/cyberpanel/mysqlPassword"
try:
jsonData = json.loads(ProcessUtilities.outputExecutioner('cat %s' % (passFile)))
self.mysqluser = jsonData['mysqluser']
self.mysqlpassword = jsonData['mysqlpassword']
self.mysqlport = jsonData['mysqlport']
self.mysqlhost = jsonData['mysqlhost']
self.remotemysql = 'ON'
if self.mysqlhost.find('rds.amazon') > -1:
self.RDS = 1
## Also set localhost to this server
ipFile = "/etc/cyberpanel/machineIP"
f = open(ipFile)
ipData = f.read()
ipAddressLocal = ipData.split('\n', 1)[0]
self.LOCALHOST = ipAddressLocal
except BaseException as msg:
self.remotemysql = 'OFF'
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile('%s. [setupConnection:75]' % (str(msg)))
###
self.checkIfMailServerSSLIssued()
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Removing and re-installing postfix/dovecot..,5')
if self.install_postfix_dovecot() == 0:
return 0
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], 'Resetting configurations..,40')
import sys
sys.path.append('/usr/local/CyberCP')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings")
from CyberCP import settings
if self.setup_email_Passwords(settings.DATABASES['default']['PASSWORD']) == 0:
return 0
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], 'Configurations reset..,70')
if self.setup_postfix_dovecot_config() == 0:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'setup_postfix_dovecot_config failed. [404].')
return 0
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Restoring OpenDKIM configurations..,70')
if self.installOpenDKIMNew() == 0:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Install OpenDKIM failed. [404].')
return 0
if self.configureOpenDKIM() == 0:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'configureOpenDKIM failed. [404].')
return 0
self.SetupDKIMFromResetMail()
if self.MailSSL:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Setting up Mail Server SSL if any..,75')
from plogical.virtualHostUtilities import virtualHostUtilities
virtualHostUtilities.issueSSLForMailServer(self.mailHostName,
'/home/%s/public_html' % (self.mailHostName))
MailServerSSLCheck = 0
from websiteFunctions.models import ChildDomains
from plogical.virtualHostUtilities import virtualHostUtilities
for websites in Websites.objects.all():
try:
child = ChildDomains.objects.get(domain='mail.%s' % (websites.domain))
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Creating mail domain for %s..,80' % (websites.domain))
virtualHostUtilities.setupAutoDiscover(1, '/dev/null', websites.domain, websites.admin)
except:
pass
if self.MailSSL == 0 and MailServerSSLCheck == 0:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Setting up Mail Server SSL as no hostname SSL found..,80')
from plogical.virtualHostUtilities import virtualHostUtilities
virtualHostUtilities.issueSSLForMailServer(websites.domain,
'/home/%s/public_html' % (websites.domain))
MailServerSSLCheck = 1
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], 'Fixing permissions..,90')
self.fixCyberPanelPermissions()
command = '/usr/local/CyberCP/bin/python /usr/local/CyberCP/dns/dnsManager.py ResetDNSConfigurations --tempStatusPath /home/cyberpanel/dnscheck'
ProcessUtilities.executioner(command)
command = 'touch /home/cyberpanel/postfix'
ProcessUtilities.executioner(command)
###
etcResolve = '/etc/resolv.conf'
if os.path.exists(etcResolve):
dataEtcResolv = open(etcResolve, 'r').read()
else:
dataEtcResolv = ''
if len(dataEtcResolv) < 4:
writeToFile = open(etcResolve, 'w')
writeToFile.write('nameserver 8.8.8.8\n')
writeToFile.close()
command = 'systemctl restart postfix'
ProcessUtilities.executioner(command)
command = 'systemctl restart dovecot'
ProcessUtilities.executioner(command)
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], 'Completed [200].')
except BaseException as msg:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'Failed. Error %s [404].' % str(msg))
def configureOpenDKIM(self):
try:
if ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
command = 'dnf install opendkim-tools -y'
ProcessUtilities.executioner(command)
## Configure OpenDKIM specific settings
openDKIMConfigurePath = "/etc/opendkim.conf"
configData = """
Mode sv
Canonicalization relaxed/simple
KeyTable refile:/etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts
"""
writeToFile = open(openDKIMConfigurePath, 'a')
writeToFile.write(configData)
writeToFile.close()
## Configure postfix specific settings
postfixFilePath = "/etc/postfix/main.cf"
configData = """
smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept
"""
writeToFile = open(postfixFilePath, 'a')
writeToFile.write(configData)
writeToFile.close()
if ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu or ProcessUtilities.decideDistro() == ProcessUtilities.ubuntu20 or ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
data = open(openDKIMConfigurePath, 'r').readlines()
writeToFile = open(openDKIMConfigurePath, 'w')
for items in data:
if items.find('Socket') > -1 and items.find('local:') > -1:
writeToFile.writelines('Socket inet:8891@localhost\n')
else:
writeToFile.writelines(items)
writeToFile.close()
#### Restarting Postfix and OpenDKIM
command = "systemctl start opendkim"
ProcessUtilities.executioner(command)
command = "systemctl enable opendkim"
ProcessUtilities.executioner(command)
##
command = "systemctl restart postfix"
ProcessUtilities.executioner(command)
return 1
except BaseException as msg:
logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
'configureOpenDKIM failed. Error %s [404].' % str(msg))
return 0
def debugEmailForSite(self, websiteName):
ipFile = "/etc/cyberpanel/machineIP"
f = open(ipFile)
ipData = f.read()
ipAddress = ipData.split('\n', 1)[0]
try:
import socket
siteIPAddr = socket.gethostbyname('mail.%s' % (websiteName))
if siteIPAddr != ipAddress:
return 0, 'mail.%s does not point to %s.' % (websiteName, ipAddress)
except:
return 0, 'mail.%s does not point to %s.' % (websiteName, ipAddress)
command = 'openssl s_client -connect mail.%s:993' % (websiteName)
result = ProcessUtilities.outputExecutioner(command)
if result.find('18 (self signed certificate)') > -1:
return 0, 'No valid SSL on port 993.'
else:
return 1, 'All checks are OK.'
def main():
parser = argparse.ArgumentParser(description='CyberPanel Installer')
parser.add_argument('function', help='Specific a function to call!')
parser.add_argument('--domain', help='Domain name!')
parser.add_argument('--userName', help='Email Username!')
parser.add_argument('--password', help='Email password!')
parser.add_argument('--tempConfigPath', help='Temporary Configuration Path!')
parser.add_argument('--install', help='Enable/Disable Policy Server!')
parser.add_argument('--tempStatusPath', help='Path of temporary status file.')
args = parser.parse_args()
if args.function == "createEmailAccount":
mailUtilities.createEmailAccount(args.domain, args.userName, args.password)
elif args.function == "generateKeys":
mailUtilities.generateKeys(args.domain)
elif args.function == "configureOpenDKIM":
mailUtilities.configureOpenDKIM()
elif args.function == "configureSpamAssassin":
mailUtilities.configureSpamAssassin()
elif args.function == "saveSpamAssassinConfigs":
mailUtilities.saveSpamAssassinConfigs(args.tempConfigPath)
elif args.function == 'savePolicyServerStatus':
mailUtilities.savePolicyServerStatus(args.install)
elif args.function == 'installSpamAssassin':
mailUtilities.installSpamAssassin("install", "SpamAssassin")
elif args.function == 'installRspamd':
mailUtilities.installRspamd("install", "rspamd")
elif args.function == 'uninstallRspamd':
mailUtilities.uninstallRspamd("install", "rspamd")
elif args.function == 'installMailScanner':
mailUtilities.installMailScanner("install", "installMailScanner")
elif args.function == 'changeRspamdConfig':
mailUtilities.changeRspamdConfig("install", "changeRspamdConfig")
elif args.function == 'changePostfixConfig':
mailUtilities.changePostfixConfig("install", "changePostfixConfig")
elif args.function == 'changeRedisxConfig':
mailUtilities.changeRedisxConfig("install", "changeRedisxConfig")
elif args.function == 'changeclamavConfig':
mailUtilities.changeclamavConfig("install", "changeclamavConfig")
elif args.function == 'AfterEffects':
mailUtilities.AfterEffects(args.domain)
elif args.function == "ResetEmailConfigurations":
extraArgs = {'tempStatusPath': args.tempStatusPath}
background = MailServerManagerUtils(None, 'ResetEmailConfigurations', extraArgs)
background.ResetEmailConfigurations()
elif args.function == 'SetupEmailLimits':
mailUtilities.SetupEmailLimits()
elif args.function == 'SaveEmailLimitsNew':
mailUtilities.SaveEmailLimitsNew(args.tempConfigPath)
if __name__ == "__main__":
main()