Mini Shell
#!/usr/bin/python
# -*- coding: utf-8 -*-
import glob
import os
import pwd
import subprocess
import sys
from ConfigParser import ConfigParser, NoOptionError, NoSectionError
__cpname__ = 'cPanel'
DBMAPPING_SCRIPT = os.path.join(os.path.dirname(sys.executable), "cpanel-dbmapping")
def detect():
return os.path.isfile('/usr/local/cpanel/cpanel')
from clcommon.clconfpars import load as loadconfig
#from .universal import _dblogin_cplogin_pairs
from clcommon.cpapi.cpapiexceptions import NoDBAccessData, CpApiTypeError, NoDomain
from clcommon import ClPwd
CPANEL_DB_CONF = '/root/.my.cnf'
CPANEL_USERPLANS_PATH = '/etc/userplans'
CPANEL_DATABASES_PATH = '/var/cpanel/databases/'
CPANEL_USERS_DIR = '/var/cpanel/users/'
CPANEL_RESELLERS_PATH = '/var/cpanel/resellers'
CPANEL_USERDATADOMAINS_PATH = '/etc/userdatadomains;/var/cpanel/userdata/{user}/cache'
CPANEL_ACCT_CONF_PATH = '/etc/wwwacct.conf'
SYSCONF_CLOUDLINUX_PATH = '/etc/sysconfig/cloudlinux'
USERCONF_PARAM_MAP = {
'dns': 'dns',
'package': 'plan',
'reseller': 'owner',
'mail': 'contactemail',
'locale': 'locale',
'cplogin': 'user'
}
SUPPORTED_CPANEL_CPINFO = ('cplogin', 'package', 'mail', 'reseller', 'dns', 'locale')
def db_access(_conf_path=CPANEL_DB_CONF):
access = dict()
reg_data_config = ConfigParser()
opened_files = reg_data_config.read(_conf_path)
if not opened_files:
raise NoDBAccessData('Can not find database access data for localhost. No such file %s' % _conf_path)
try:
if reg_data_config.has_option(section='client', option='password'):
access['pass'] = reg_data_config.get(section='client', option='password', raw=True).strip('\"')
else:
access['pass'] = reg_data_config.get(section='client', option='pass', raw=True).strip('\"')
access['login'] = reg_data_config.get(section='client', option='user', raw=True)
except (NoOptionError, NoSectionError), e:
raise NoDBAccessData('Can not find database access data for localhost from config file %s; '
'%s' % (_conf_path, e.message))
access['db'] = 'mysql'
return access
def cpusers(_userplans_path=CPANEL_USERPLANS_PATH):
stream = open(_userplans_path)
users_list = [line.split(':')[0].strip() for line in stream
if not line.startswith('#') and line.count(':') == 1 and len(line.strip()) > 3]
stream.close()
return tuple(users_list)
def resellers(_resellers_path=CPANEL_RESELLERS_PATH):
if not os.path.isfile(_resellers_path): # on a clean system, this file may not be
return tuple()
stream = open(_resellers_path)
resellers_list = [line.split(':')[0].strip() for line in stream
if not line.startswith('#') and (':' in line) and len(line.strip()) > 3]
return tuple(resellers_list)
def dblogin_cplogin_pairs(cplogin_lst=None, with_system_users=False):
"""
Get mapping between system and DB users
@param cplogin_lst :list: list with usernames for generate mapping
@param with_system_users :bool: add system users to result list or no.
default: False
"""
# initialize results list
results = []
# accept only list and tuple parameters
uid_list = []
for username in (cplogin_lst or []):
try:
uid_list.append(str(pwd.getpwnam(username).pw_uid))
except KeyError:
# no user exists - skip it
uid_list.append("-1")
# generate system command
params = [DBMAPPING_SCRIPT]
if not with_system_users:
params.append("--nosys")
params += uid_list
output = subprocess.Popen(params, stdout=subprocess.PIPE,
stderr=subprocess.PIPE).stdout.read()
# output format: "DBuser user UID"
for line in output.split("\n"):
line = line.strip()
if not line:
continue
results.append(line.split(" ")[:2])
return tuple(results)
def cpinfo(cpuser=None, keyls=('cplogin', 'package', 'mail', 'reseller', 'dns', 'locale'),
_cpanel_users_dir=CPANEL_USERS_DIR):
returned = list()
if isinstance(cpuser, (str, unicode)):
cpusers_list = [cpuser]
elif isinstance(cpuser, (list, tuple)):
cpusers_list = tuple(cpuser)
elif cpuser is None:
cpusers_list = glob.glob(os.path.join(_cpanel_users_dir, '*'))
else:
raise CpApiTypeError(funcname='cpinfo', supportettypes='str|unicode|list|tuple',
received_type=type(cpuser).__name__)
for cpuser in cpusers_list:
user_config_path = os.path.join(_cpanel_users_dir, cpuser)
if not os.path.exists(user_config_path):
print('WARNING: Can not load data to the user "%s"; Perhaps there is no such user in cPanel' % (cpuser,))
continue
cpuser_data = loadconfig(user_config_path)
user_data = [cpuser_data.get(USERCONF_PARAM_MAP.get(data_key)) for data_key in keyls]
returned.append(tuple(user_data))
if 'mail' in keyls: # checking the presence of an additional e-mail
additional_mail = cpuser_data.get('contactemail2')
if additional_mail:
user_data[list(keyls).index('mail')] = additional_mail
user_data_tuple = tuple(user_data)
if user_data_tuple not in returned:
returned.append(tuple(user_data))
return tuple(returned)
def get_admin_email(_conf1=None, _conf2=None, _hostname=None):
"""
:param str|None _conf1: for testing
:param str|None _conf2: for testing
:param str|None _hostname: for testing
:return:
"""
# 1. Try to get admin email from /etc/sysconfig/cloudlinux
lines = []
try:
f = open(_conf1 or SYSCONF_CLOUDLINUX_PATH, 'r')
lines = f.readlines()
f.close()
except (OSError, IOError):
pass
for line in lines:
if line.startswith('EMAIL'):
parts = line.split('=')
if len(parts) == 2 and '@' in parts[1].strip():
return parts[1].strip()
# 2. Try to get admin email from /etc/wwwacct.conf
lines = []
try:
f = open(_conf2 or CPANEL_ACCT_CONF_PATH, 'r')
lines = f.readlines()
f.close()
except (OSError, IOError):
pass
host = ''
for line in lines:
if line.startswith('CONTACTEMAIL'):
s = line.replace('CONTACTEMAIL', '').strip()
if s:
return s
if line.startswith('HOST'):
s = line.replace('HOST', '').strip()
if s:
host = s
if host:
return 'root@' + host
# Admin email not found in system files, use common address
from clcommon.cpapi.plugins.universal import get_admin_email
return get_admin_email(_hostname=_hostname)
def docroot(domain, _path=CPANEL_USERDATADOMAINS_PATH):
domain = domain.strip()
except_list = list()
if '{user}' in _path:
call_as_user = pwd.getpwuid(os.getuid()).pw_name
_path = _path.replace('{user}', call_as_user)
path_list = _path.split(';')
for path_ in path_list:
if not os.path.exists(path_):
continue
try:
file_ = open(path_)
except IOError, e:
except_list.append(str(e))
continue
# example line:
#test.russianguns.ru: russianguns==root==sub==russianguns.ru==/home/russianguns/fla==192.168.122.40:80======0
for line in file_:
if line.startswith(domain + ':'):
domain_raw_data = line[len(domain) + 1:].strip()
domain_data = domain_raw_data.split('==')
docroot_path = domain_data[4]
user = domain_data[0]
file_.close()
return docroot_path, user
except_list.append('Can\'t find record "%s" in file "%s"' % (domain, path_))
file_.close()
raise NoDomain("Can't obtain document root for domain '%s'; %s"
% (domain, '; '.join(except_list)))
def userdomains(cpuser, _path=CPANEL_USERDATADOMAINS_PATH):
domains_order = []
result_list = []
domains_dict = {}
def ordered_insert(key, value, position=None):
if key in domains_dict:
return
elif position is not None:
domains_order.insert(position, domain)
else:
domains_order.append(domain)
domains_dict.update({key: value})
if '{user}' in _path:
call_as_user = pwd.getpwuid(os.getuid()).pw_name
_path = _path.replace('{user}', call_as_user)
path_list = _path.split(';')
for path_ in path_list:
try:
file_ = open(path_)
except IOError:
continue
for line_numb, line in enumerate(file_):
# example line:
#test.russianguns.ru: russianguns==root==sub==russianguns.ru==/home/russianguns/fla==192.168.122.40:80======0
if not line.strip(): # ignore the empty string
continue
if line.count(': ') != 1:
print 'Can\'t pars %s line in file "%s"; line was ignored' % (line_numb, path_)
continue
domain, domain_raw_data = line.split(': ')
domain_data = domain_raw_data.strip().split('==')
user_ = domain_data[0]
if cpuser == user_:
document_root = domain_data[4]
main_domain = 'main' == domain_data[2]
if main_domain:
ordered_insert(domain, document_root, 0) # main domain must be first in list
else:
ordered_insert(domain, document_root)
file_.close()
for key in domains_order:
result_list.append((key, domains_dict[key]))
return result_list
def homedirs(_sysusers=None, _conf_path = CPANEL_ACCT_CONF_PATH):
"""
Detects and returns list of folders contained the home dirs of users of the cPanel
:param str|None _sysusers: for testing
:param str|None _conf_path: for testing
:return: list of folders, which are parent of home dirs of users of the panel
"""
HOMEDIR = 'HOMEDIR '
HOMEMATCH = 'HOMEMATCH '
homedirs = []
users_homedir = ''
users_home_match = ''
if (os.path.exists(_conf_path)):
lines = open(_conf_path, 'r')
for line in lines:
if line.startswith(HOMEDIR):
users_homedir = line.split(HOMEDIR)[1].strip()
elif line.startswith(HOMEMATCH):
users_home_match = line.split(HOMEMATCH)[1].strip()
if users_homedir:
homedirs.append(users_homedir)
clpwd = ClPwd()
users_dict = clpwd.get_user_dict()
# for testing only
if isinstance(_sysusers, (list, tuple)):
class pw(object):
def __init__(self, name, dir):
self.pw_name = name
self.pw_dir = dir
users_dict = {}
for (name,dir) in _sysusers:
users_dict[name] = pw(name, dir)
for user_name in users_dict:
userdir = users_dict[user_name].pw_dir
if os.path.exists(userdir + '/public_html') or os.path.exists(userdir + '/www'):
homedir = os.path.dirname(userdir)
if users_home_match and homedir.find('/'+users_home_match) == -1:
continue
if homedir not in homedirs:
homedirs.append(homedir)
return homedirs
#TODO: You can extract the data from the database but it needs that will automatically install the package MySQL-python
# cPanel repository in MySQL-python disabled
#def dblogin_cplogin_pairs(cplogin_lst=None):
# access = db_access()
# data = _dblogin_cplogin_pairs(cplogin_lst=cplogin_lst, access=access)
# return data
Zerion Mini Shell 1.0