Sindbad~EG File Manager
# -*- coding: utf-8 -*-
# Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2018 All Rights Reserved
#
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENSE.TXT
#
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
import os
import pwd
import subprocess
from collections import namedtuple
import shutil
import logging
from clcommon.utils import get_file_lines, write_file_lines, mod_makedirs
from clcommon.public_hooks import CLOUDLINUX_HOOKS, CONTACT_SUPPORT_MESSAGE_FOOTER
from clcommon.cpapi import get_cp_description
from distutils.version import StrictVersion
BIN_DIR = os.path.join(CLOUDLINUX_HOOKS, 'directadmin/')
Hook = namedtuple('Hook', ['path', 'hook'])
HookPath = namedtuple('HookPath', ['min_version', 'max_version', 'path'])
HOOKS = { # None means +inf or -int depending on positions
Hook(BIN_DIR + 'user_create_post', (HookPath(None, '1.60', 'user_create_post.sh'),
HookPath('1.60', None, 'user_create_post/CL_user_create_post.sh'))),
Hook(BIN_DIR + 'user_destroy_post', (HookPath(None, '1.60', 'user_destroy_post.sh'),
HookPath('1.60', None, 'user_destroy_post/CL_user_destroy_post.sh'))),
Hook(BIN_DIR + 'user_destroy_pre', (HookPath(None, '1.60', 'user_destroy_pre.sh'),
HookPath('1.60', None, 'user_destroy_pre/CL_user_destroy_pre.sh'))),
Hook(BIN_DIR + 'user_restore_post', (HookPath(None, '1.60', 'user_restore_post.sh'),
HookPath('1.60', None, 'user_restore_post/CL_user_restore_post.sh'))),
Hook(BIN_DIR + 'domain_change_post', (HookPath(None, '1.60', 'domain_change_post.sh'),
HookPath('1.60', None, 'domain_change_post/CL_domain_change_post.sh'))),
}
DA_HOOK_DEST_DIR = '/usr/local/directadmin/scripts/custom'
if get_cp_description() is None:
DA_VERSION = '1.0' # in case we can't determine version we set default old
else:
DA_VERSION = get_cp_description()["version"]
logger = logging.getLogger(__name__)
def _folder_hooks_compatibility():
"""
Check that DA has compatibility with folder-based hooks
:return: Bool
"""
return StrictVersion(DA_VERSION) >= StrictVersion('1.60')
def _get_hook_from_structure(hook):
"""
hook = HookPath stucture
return suitable hook name depending on version
if return None - suitable hook not found
"""
for version_hook in hook:
if version_hook.min_version is None:
min_version = True
else: # if DA bigger than the min val
min_version = StrictVersion(DA_VERSION) >= StrictVersion(version_hook.min_version)
if version_hook.max_version is None:
max_version = True
else: # if DA lesser that the max val
max_version = StrictVersion(DA_VERSION) < StrictVersion(version_hook.max_version)
if min_version and max_version:
return version_hook.path
return None
def create_da_hook(da_hook_filename, command, da_hook_default_dir=DA_HOOK_DEST_DIR):
"""
Creates DA hook
Example args:
da_hook_filename = user_create_post.sh
da_hook_src = /usr/share/cagefs-plugins/hooks/directadmin/user_create_post.sh - command
:param string da_hook_filename: How to name that hook in DA panel
:param command: what we should run on hook
:param string da_hook_default_dir:
:return: None
"""
hook_fullname = os.path.join(da_hook_default_dir, da_hook_filename)
logger.debug('Registering %s action hook', hook_fullname)
try:
da_user = pwd.getpwnam('diradmin')
except (KeyError,) as e:
logger.error("failed to find 'diradmin' user: %s", str(e))
return
da_user_uid = da_user.pw_uid
da_user_gid = da_user.pw_gid
try:
# if hook file already in system
if os.path.isfile(hook_fullname):
# get hook content
content = get_file_lines(hook_fullname)
content = [line for line in content if line != '\n']
# Flags for check if hook installed and if hook on bash
hook_installed = False
hook_on_bash = False
for line in content:
# check if hook installed
if line.find(command) != -1:
hook_installed = True
break
# check if hook on bash
if line.startswith('#!/') and (line.find('/sh') != -1 or line.find('/bash') != -1):
hook_on_bash = True
# if hook not installed
if not hook_installed:
# if hook on bash
if hook_on_bash:
# add command for cagefs hook
content.append('\n' + command + '\n')
write_file_lines(hook_fullname, content, 'w')
else: # if hook not on bash
try:
# backup old hook filename
dirname, fname = os.path.split(hook_fullname)
old_hook_backup = os.path.join(dirname, 'old_'+fname)
# copy backup old hook
shutil.copyfile(hook_fullname, old_hook_backup)
os.chmod(old_hook_backup, 0o700)
os.chown(old_hook_backup, da_user_uid, da_user_gid)
# replace old hook by new hook on bash
write_file_lines(hook_fullname,
'#!/bin/bash\n' + command + '\n' + old_hook_backup + '\n', 'w')
os.chmod(hook_fullname, 0o700)
os.chown(hook_fullname, da_user_uid, da_user_gid)
except (OSError, shutil.Error) as e:
logger.error('Failed to create hook for DirectAdmin: %s: %s. %s',
hook_fullname, str(e), CONTACT_SUPPORT_MESSAGE_FOOTER)
except (OSError, IOError) as e:
logger.error('Failed to install hook for DirectAdmin: %s. %s',
str(e), CONTACT_SUPPORT_MESSAGE_FOOTER)
# Install hook if it's not installed
if not os.path.isfile(hook_fullname):
try:
if not os.path.isdir(os.path.dirname(hook_fullname)):
mod_makedirs(os.path.dirname(hook_fullname), 0o700)
os.chmod(os.path.dirname(hook_fullname), 0o700)
os.chown(os.path.dirname(hook_fullname), da_user_uid, da_user_gid)
write_file_lines(hook_fullname, '#!/bin/bash\n' + command + '\n', 'w')
os.chmod(hook_fullname, 0o700)
os.chown(hook_fullname, da_user_uid, da_user_gid)
except (OSError, IOError) as e:
logger.error('Failed to install hook for DirectAdmin: %s. %s',
str(e), CONTACT_SUPPORT_MESSAGE_FOOTER)
# DO NOT CHANGE THIS METHOD
# STILL USED IN LVEMANAGER & CAGEFS
def remove_da_hook(da_hook_filename, command, da_hook_default_dir=DA_HOOK_DEST_DIR):
"""
Removes DA hook
da_hook_default_dir = DA_HOOK_DEST_DIR = /usr/local/directadmin/scripts/custom
da_hook_filename = user_create_post.sh
command = /usr/share/cagefs-plugins/hooks/directadmin/user_create_post.sh
:param string da_hook_filename: How to name that hook in DA panel
:param command: what we should run on hook
:param da_hook_default_dir: default dir for hooks
:return: None
"""
logger.debug('Unregistering %s action hook', da_hook_filename)
hook_fullname = os.path.join(da_hook_default_dir, da_hook_filename)
# check if hook exist in system
if not os.path.isfile(hook_fullname):
logger.info('Hook %s is not installed; skip', hook_fullname)
return
try:
content = get_file_lines(hook_fullname)
new_content = []
for line in content:
# check for hook execution command in hook
if line != '\n' and line.find(command) == -1:
new_content.append(line)
# write changes to hook
write_file_lines(hook_fullname, new_content, 'w')
except IOError as e:
logger.error('Failed to remove hook for DirectAdmin: %s. %s',
str(e), CONTACT_SUPPORT_MESSAGE_FOOTER)
def install_hooks():
if not _folder_hooks_compatibility():
subprocess.run("touch {}/.old_hooks_present".format(DA_HOOK_DEST_DIR), shell=True, executable='/bin/bash')
else:
if os.path.isfile("{}/.old_hooks_present".format(DA_HOOK_DEST_DIR)):
remove_hooks()
for hook_structure in HOOKS:
hook_name = _get_hook_from_structure(hook_structure.hook)
if hook_name is None:
logger.error('Failed to install hook for DirectAdmin: %s. %s',
"Can't find suitable version", CONTACT_SUPPORT_MESSAGE_FOOTER)
continue
create_da_hook(hook_name, hook_structure.path)
def remove_hooks():
if _folder_hooks_compatibility and os.path.isfile("{}/.old_hooks_present".format(DA_HOOK_DEST_DIR)):
subprocess.run("rm -f {}/.old_hooks_present".format(DA_HOOK_DEST_DIR), shell=True, executable='/bin/bash')
for hook_structure in HOOKS:
hook_names = [version_hook.path for version_hook in hook_structure.hook]
for name in hook_names:
remove_da_hook(name, hook_structure.path)
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists