|
|
#-*- coding: utf-8 -*-
|
|
|
|
|
|
# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org
|
|
|
#
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
# You may obtain a copy of the License at
|
|
|
#
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
#
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
# See the License for the specific language governing permissions and
|
|
|
# limitations under the License.
|
|
|
|
|
|
import os, sys, re
|
|
|
#from cl_print import color_print
|
|
|
from cl_datavars import DataVars
|
|
|
from server.utils import execProg
|
|
|
from cl_template import template
|
|
|
from cl_api import packagesAPI, APIError
|
|
|
from server.ldap import iniLdapParser, ldapFunction, shareldap
|
|
|
from server.utils import genSleep
|
|
|
from cl_utils import removeDir, _error
|
|
|
from cl_lang import lang
|
|
|
tr = lang()
|
|
|
tr.setLocalDomain('cl_ldap')
|
|
|
tr.setLanguage(sys.modules[__name__])
|
|
|
|
|
|
__version__ = "2.2.0.0"
|
|
|
__app__ = "calculate-ldap"
|
|
|
|
|
|
from cl_abstract import abs_api_service
|
|
|
|
|
|
class DataVarsLdap(DataVars):
|
|
|
"""Хранение переменных"""
|
|
|
# Имя секции в calculate2.env
|
|
|
envSection = "ldap"
|
|
|
def importLdap(self, **args):
|
|
|
'''Импорт переменных для calculate-ldap'''
|
|
|
# Импорт переменных
|
|
|
self.importData(self.envSection, ('cl_vars_ldap','cl_fill_ldap'))
|
|
|
|
|
|
class Template:
|
|
|
"""Templates methods"""
|
|
|
|
|
|
def applyTemplates(self):
|
|
|
"""Apply templates"""
|
|
|
clTempl = template(self.clVars)
|
|
|
dirsFiles = clTempl.applyTemplates()
|
|
|
if clTempl.getError():
|
|
|
self.printERROR(clTempl.getError().strip())
|
|
|
return False
|
|
|
else:
|
|
|
return dirsFiles
|
|
|
|
|
|
class shareVars:
|
|
|
"""share methods template vars"""
|
|
|
# template variables
|
|
|
clVars = False
|
|
|
|
|
|
def createClVars(self, clVars=False):
|
|
|
"""Создает объект Vars"""
|
|
|
if not clVars:
|
|
|
clVars = DataVarsLdap()
|
|
|
# Импортируем переменные
|
|
|
clVars.importLdap()
|
|
|
# Заменяем значения переменных переменными из env файлов
|
|
|
clVars.flIniFile()
|
|
|
# Устанавливаем у объекта атрибут объект переменных
|
|
|
self.clVars = clVars
|
|
|
return self.clVars
|
|
|
|
|
|
class internalMethods(abs_api_service, shareVars, Template):
|
|
|
'''Methods ldap service'''
|
|
|
prioritet = 25
|
|
|
nameService = "ldap"
|
|
|
nameDaemon = 'slapd'
|
|
|
_templDict = {'name':nameDaemon}
|
|
|
# files
|
|
|
pidFile = '/var/run/openldap/%(name)s.pid' %_templDict
|
|
|
# command
|
|
|
cmdPath = '/etc/init.d/%(name)s' %_templDict
|
|
|
_templDict.update({'cmd':cmdPath})
|
|
|
cmdStart = '%(cmd)s start' %_templDict
|
|
|
cmdReStart = '%(cmd)s restart' %_templDict
|
|
|
cmdStop = '%(cmd)s stop' %_templDict
|
|
|
cmdShowDaemons = 'rc-update show default'
|
|
|
reShowDaemons = re.compile("(.+)\s+\|\s+.+")
|
|
|
cmdAddRunlevel = 'rc-update add %(name)s default' %_templDict
|
|
|
cmdDelRunlevel = 'rc-update del %(name)s default' %_templDict
|
|
|
|
|
|
def get_service_name(self):
|
|
|
'''Get name service'''
|
|
|
return self.nameService
|
|
|
|
|
|
def get_pkg_name(self):
|
|
|
'''Get name service'''
|
|
|
return __app__
|
|
|
|
|
|
def get_vars(self):
|
|
|
'''Get Service vars'''
|
|
|
return self.createClVars(self.clVars)
|
|
|
|
|
|
def is_setup(self):
|
|
|
'''Is setup service (True/False)'''
|
|
|
self.createClVars(self.clVars)
|
|
|
return self.clVars.Get('sr_ldap_set') == "on"
|
|
|
|
|
|
def _getRunlevelDaemons(self):
|
|
|
"""Получаем всех демонов в default уровне"""
|
|
|
textLines = execProg(self.cmdShowDaemons)
|
|
|
if textLines is False:
|
|
|
self.printERROR(_("ERROR") + ": " + self.cmdShowDaemons)
|
|
|
return False
|
|
|
else:
|
|
|
daemons = []
|
|
|
for line in textLines:
|
|
|
res = self.reShowDaemons.search(line)
|
|
|
if res:
|
|
|
daemon = res.groups(0)[0]
|
|
|
daemons.append(daemon)
|
|
|
return daemons
|
|
|
|
|
|
def is_start(self):
|
|
|
'''Run ldap server (True/False)'''
|
|
|
if os.access(self.pidFile, os.R_OK):
|
|
|
pid = open(self.pidFile).read().strip()
|
|
|
if pid:
|
|
|
procDir = "/proc"+"/"+pid
|
|
|
if os.access(procDir, os.F_OK):
|
|
|
return True
|
|
|
return False
|
|
|
|
|
|
def start(self):
|
|
|
'''Start LDAP server'''
|
|
|
if not self.is_start():
|
|
|
if execProg(self.cmdStart) is False:
|
|
|
self.printERROR(_("Can't execute '%s'") %self.cmdStart)
|
|
|
self.printNotOK(_("Starting LDAP") + " ...")
|
|
|
return False
|
|
|
return True
|
|
|
|
|
|
def restart(self):
|
|
|
'''Restart LDAP server'''
|
|
|
if self.is_start():
|
|
|
if execProg(self.cmdReStart) is False:
|
|
|
self.printERROR(_("Can't execute '%s'") %self.cmdReStart)
|
|
|
self.printNotOK(_("Restarting LDAP")+ " ...")
|
|
|
return False
|
|
|
else:
|
|
|
return self.start()
|
|
|
return True
|
|
|
|
|
|
def stop(self):
|
|
|
'''Stop LDAP server'''
|
|
|
if self.is_start():
|
|
|
if execProg(self.cmdStop) is False:
|
|
|
self.printERROR(_("Can't execute '%s'") %self.cmdStop)
|
|
|
self.printNotOK(_("Stopping LDAP")+ " ...")
|
|
|
return False
|
|
|
return True
|
|
|
|
|
|
def is_runlevel(self):
|
|
|
'''Находится ли LDAP в автозагрузке'''
|
|
|
daemons = self._getRunlevelDaemons()
|
|
|
if daemons is False:
|
|
|
return False
|
|
|
if self.nameDaemon in daemons:
|
|
|
return True
|
|
|
else:
|
|
|
return False
|
|
|
|
|
|
def add_runlevel(self):
|
|
|
'''Add daemon to runlevel'''
|
|
|
if not self.is_runlevel():
|
|
|
if execProg(self.cmdAddRunlevel) is False:
|
|
|
self.printERROR(_("Can't execute '%s'") %self.cmdAddRunlevel)
|
|
|
self.printNotOK(_("service %(name)s added to runlevel")\
|
|
|
%self._templDict + " ...")
|
|
|
return False
|
|
|
return True
|
|
|
|
|
|
def del_runlevel(self):
|
|
|
'''Delete daemon from runlevel'''
|
|
|
if self.is_runlevel():
|
|
|
if execProg(self.cmdDelRunlevel) is False:
|
|
|
self.printERROR(_("Can't execute '%s'") %self.cmdDelRunlevel)
|
|
|
self.printNotOK(_("service %(name)s removed from runlevel")\
|
|
|
%self._templDict + " ...")
|
|
|
return False
|
|
|
return True
|
|
|
|
|
|
def get_prioritet(self):
|
|
|
'''Get run daemon prioritet'''
|
|
|
return self.prioritet
|
|
|
|
|
|
def del_vars_from_env(self):
|
|
|
'''Delete template vars in env files'''
|
|
|
self.createClVars(self.clVars)
|
|
|
deleteVariables = ("sr_ldap_set",)
|
|
|
locations = map(lambda x: x[0], self.clVars.Get("cl_env_data"))
|
|
|
for varName in deleteVariables:
|
|
|
for locate in locations:
|
|
|
if not self.clVars.Delete(varName, location=locate,
|
|
|
header=self.clVars.envSection):
|
|
|
fileName = filter(lambda x: x[0] == locate,
|
|
|
self.clVars.Get("cl_env_data"))[0][1]
|
|
|
self.printERROR(_("Can't delete variable '%(name)s' "
|
|
|
"in file %(file)s") %{'name':varName,
|
|
|
'file':fileName})
|
|
|
return False
|
|
|
return True
|
|
|
|
|
|
def updateVars(self):
|
|
|
self.createClVars()
|
|
|
return True
|
|
|
|
|
|
def get_service_info(self, request):
|
|
|
'''Get service information'''
|
|
|
res = ""
|
|
|
if request == "scheme":
|
|
|
self.createClVars(self.clVars)
|
|
|
res = self.clVars.Get('ld_ldap_scheme_conf')
|
|
|
elif request == "access_pw":
|
|
|
self.createClVars(self.clVars)
|
|
|
res = self.clVars.Get('ld_ldap_access_pw_conf')
|
|
|
elif request == "access_dn":
|
|
|
self.createClVars(self.clVars)
|
|
|
res = self.clVars.Get('ld_ldap_access_dn_conf')
|
|
|
return res
|
|
|
|
|
|
def scheme(self):
|
|
|
'''include lines in slapd.conf'''
|
|
|
return self.get_service_info('scheme')
|
|
|
|
|
|
def access_pw(self):
|
|
|
'''Access userPasswod lines in slapd.conf'''
|
|
|
return self.get_service_info('access_pw')
|
|
|
|
|
|
def access_dn(self):
|
|
|
'''Access DN lines in slapd.conf'''
|
|
|
return self.get_service_info('access_dn')
|
|
|
|
|
|
def apply_templates(self):
|
|
|
'''Apply package templates'''
|
|
|
if self.is_setup():
|
|
|
self.clVars.Set("ac_ldap_update","up", force=True)
|
|
|
return Template.applyTemplates(self)
|
|
|
return True
|
|
|
|
|
|
class Singleton(object):
|
|
|
_instance = None
|
|
|
def __new__(cls, *args, **kwargs):
|
|
|
if not cls._instance:
|
|
|
cls._instance = super(Singleton, cls).__new__(
|
|
|
cls, *args, **kwargs)
|
|
|
return cls._instance
|
|
|
|
|
|
class allMethods(Singleton, internalMethods, shareldap):
|
|
|
"""Методы севисa Ldap"""
|
|
|
# Базовый ldif файл
|
|
|
ldifFileBase = '/usr/lib/calculate-2.2/calculate-ldap/ldif/base.ldif'
|
|
|
apiFile = '/usr/lib/calculate-2.2/calculate-ldap/pym/cl_ldap_api.py'
|
|
|
libAPIObj = packagesAPI()
|
|
|
|
|
|
def removeLdapDatabase(self):
|
|
|
"""Удаляем предыдущую базу данных"""
|
|
|
pathDatabase = "/var/lib/openldap-data"
|
|
|
#if os.path.exists(pathDatabase) and os.listdir(pathDatabase):
|
|
|
#if os.system("rm /var/lib/openldap-data/* &>/dev/null") !=0:
|
|
|
#self.printERROR("Can't remove /var/lib/openldap-data/*")
|
|
|
#return False
|
|
|
#return True
|
|
|
if os.path.exists(pathDatabase):
|
|
|
fileOrDirNames = os.listdir(pathDatabase)
|
|
|
if fileOrDirNames:
|
|
|
for fileOrDirName in fileOrDirNames:
|
|
|
fullFileOrDirName = os.path.join(pathDatabase,
|
|
|
fileOrDirName)
|
|
|
if os.path.isdir(fullFileOrDirName):
|
|
|
try:
|
|
|
removeDir(pathDatabase)
|
|
|
except:
|
|
|
self.printERROR(_("Can't remove directory %s")\
|
|
|
%fullFileOrDirName)
|
|
|
return False
|
|
|
else:
|
|
|
try:
|
|
|
os.remove(fullFileOrDirName)
|
|
|
except:
|
|
|
self.printERROR(_("Can't remove file %s")\
|
|
|
%fullFileOrDirName)
|
|
|
return False
|
|
|
self.printOK(_("Erased LDAP Database") + " ...")
|
|
|
return True
|
|
|
|
|
|
def connectLdapServer(self):
|
|
|
"""Соединяемся с LDAP сервером
|
|
|
|
|
|
используем DN и пароль временного админстратора
|
|
|
"""
|
|
|
# Если раннее была ошибка то выходим
|
|
|
if self.getError():
|
|
|
self.printERROR (_("ERROR") + ": " +\
|
|
|
self.getError().strip())
|
|
|
return False
|
|
|
tmpDn = self.clVars.Get("ld_temp_dn")
|
|
|
tmpPw = self.clVars.Get("ld_temp_pw")
|
|
|
ldapObj = ldapFunction(tmpDn, tmpPw)
|
|
|
# Генератор задержек
|
|
|
wait = genSleep()
|
|
|
while ldapObj.getError():
|
|
|
try:
|
|
|
# Задержка
|
|
|
wait.next()
|
|
|
except StopIteration:
|
|
|
break
|
|
|
# Очистка ошибки
|
|
|
_error.error = []
|
|
|
ldapObj = ldapFunction(tmpDn, tmpPw)
|
|
|
self.ldapObj = ldapObj
|
|
|
self.conLdap = ldapObj.conLdap
|
|
|
if ldapObj.getError():
|
|
|
# Удаляем одинаковые ошибки
|
|
|
listError = []
|
|
|
for e in ldapObj.error:
|
|
|
if not e in listError:
|
|
|
listError.append(e)
|
|
|
_error.error = listError
|
|
|
self.printERROR(_("Can not connected to LDAP server"))
|
|
|
return False
|
|
|
return True
|
|
|
|
|
|
def setup(self, force=False):
|
|
|
"""Настройка LDAP сервиса (создание дерева)"""
|
|
|
# Принудительная установка
|
|
|
if self.clVars.Get("sr_ldap_set") == "on" and not force:
|
|
|
self.printWARNING (_("WARNING") + ": " +\
|
|
|
_("LDAP server is configured")+ ".")
|
|
|
return True
|
|
|
if not force:
|
|
|
# предупреждение при выполнении этой программы будут изменены
|
|
|
# конфигурационные файлы и база данных сервиса LDAP а также
|
|
|
# конфигурационные файлы установленных сервисов
|
|
|
self.printWARNING (_("WARNING") + ": " +\
|
|
|
_("Executing of the program will change") + " " +\
|
|
|
_("the configuration files and database of LDAP service")+\
|
|
|
".")
|
|
|
# если вы готовы продолжить работу программы нажмите Y если нет n
|
|
|
messDialog = \
|
|
|
_("If you are ready to continue executing the program")+", "+\
|
|
|
_("input 'yes'") +", "+ _("if not 'no'")
|
|
|
if not dialogYesNo(messDialog):
|
|
|
return True
|
|
|
else:
|
|
|
# делаем backup
|
|
|
# Проверим запущен ли ldap
|
|
|
if not self.is_start():
|
|
|
# Запускаем LDAP сервер
|
|
|
if not self.start():
|
|
|
return False
|
|
|
#if not self.backupServer():
|
|
|
#return False
|
|
|
if self.is_runlevel():
|
|
|
# Удаляем из автозапуска демона
|
|
|
if not self.del_runlevel():
|
|
|
return False
|
|
|
listAPIObj = self.libAPIObj.all.APIList()
|
|
|
listAPIObjReverse = self.libAPIObj.all.APIListReverse()
|
|
|
if filter(lambda x:\
|
|
|
x.api.get_pkg_name()=="calculate_ldap",listAPIObj):
|
|
|
self.printERROR(_("Can not found API module in package "
|
|
|
"calculate-ldap"))
|
|
|
self.printWARNING(_("Run: cl-ldap-setup --install"))
|
|
|
return False
|
|
|
# Останавливаем все установленные сервисы
|
|
|
for obj in listAPIObjReverse:
|
|
|
apiObj = obj.api
|
|
|
if hasattr(apiObj, 'stop') and not apiObj.stop():
|
|
|
return False
|
|
|
# Удаляем из автозагрузки все установленные сервисы
|
|
|
for obj in listAPIObjReverse:
|
|
|
apiObj = obj.api
|
|
|
if hasattr(apiObj, 'del_runlevel') and not apiObj.del_runlevel():
|
|
|
return False
|
|
|
# Удаляем из крона скрипт для чистки удаленых пользователей
|
|
|
# создаем объект репликации
|
|
|
#objRepl = servRepl()
|
|
|
#if not objRepl.cronReplicationOFF():
|
|
|
#return False
|
|
|
# Удаляем из share файл .replrun
|
|
|
#if not self.servSambaObj.delReplFile(self.clVars):
|
|
|
#return False
|
|
|
# Удаляем переменные
|
|
|
for obj in listAPIObjReverse:
|
|
|
apiObj = obj.api
|
|
|
if hasattr(apiObj,'del_vars_from_env') and \
|
|
|
not apiObj.del_vars_from_env():
|
|
|
return False
|
|
|
# Получим путь к ldap файлу
|
|
|
ldapParser = iniLdapParser()
|
|
|
ldapFile = ldapParser.nameIniFile
|
|
|
# Удаляем ldap файл
|
|
|
if os.path.exists(ldapFile):
|
|
|
os.remove(ldapFile)
|
|
|
self.clVars.Write("sr_ldap_set", "off",force=True)
|
|
|
self.clVars.Set("sr_ldap_set", "on", force=True)
|
|
|
self.clVars.Set("ac_ldap_setup","up", force=True)
|
|
|
# Первый проход
|
|
|
self.clVars.Set("cl_pass_step", "1", True)
|
|
|
if self.applyTemplates() is False:
|
|
|
self.printERROR(_("Can not apply templates") + ":" + " " +\
|
|
|
_("first pass"))
|
|
|
return False
|
|
|
# Удаляем старую базу данных
|
|
|
if not self.removeLdapDatabase():
|
|
|
return False
|
|
|
# Запускаем LDAP сервер
|
|
|
if not self.start():
|
|
|
return False
|
|
|
# Соединяемся с LDAP временным пользователем
|
|
|
if not self.connectLdapServer():
|
|
|
return False
|
|
|
# Получаем текст нужного ldif-a
|
|
|
baseLdif = self.createLdif(self.ldifFileBase)
|
|
|
# Если нет ошибок при соединении применяем ldif
|
|
|
if not self.ldapObj.getError():
|
|
|
self.ldapObj.ldapAdd(baseLdif)
|
|
|
if self.ldapObj.getError():
|
|
|
print _("LDAP Error") + ": " + self.ldapObj.getError().strip()
|
|
|
return False
|
|
|
self.printOK(_("Added ldif file") + " ...")
|
|
|
# Второй проход,
|
|
|
# удаляем временного пользователя root из конфигурационного файла
|
|
|
self.clVars.Set("cl_pass_step","2",True)
|
|
|
if self.applyTemplates() is False:
|
|
|
self.printERROR(_("Can not apply profiles") +":"+ _("second pass"))
|
|
|
return False
|
|
|
# Перезапускаем LDAP сервер
|
|
|
if not self.restart():
|
|
|
return False
|
|
|
# Записываем данные администратора сервера
|
|
|
ldapParser.setVar("admin",
|
|
|
{"DN":self.clVars.Get("ld_admin_dn"),
|
|
|
"PASS":self.clVars.Get("ld_admin_pw")})
|
|
|
# Устанавливаем автозапуск демона
|
|
|
if not self.add_runlevel():
|
|
|
return False
|
|
|
# Записываем переменные для пользователя
|
|
|
#clientVars = ["ur_organization", "ur_signature"]
|
|
|
#if not self.saveVarsClient(clientVars):
|
|
|
#return False
|
|
|
#self.apply_templates()
|
|
|
self.clVars.Write("sr_ldap_set","on",force=True)
|
|
|
self.printOK(_("LDAP service configured") + " ...")
|
|
|
return True
|
|
|
|
|
|
REGISTERED_METHODS = ['access_pw', 'access_pw', 'add_runlevel',
|
|
|
'apply_templates', 'get_pkg_name', 'get_prioritet', 'get_service_info',
|
|
|
'get_service_name', 'get_vars', 'is_runlevel', 'is_setup', 'is_start',
|
|
|
'restart', 'scheme', 'setup', 'start', 'stop']
|
|
|
|
|
|
class serviceAPI(object):
|
|
|
"""Proxy object"""
|
|
|
def __init__(self):
|
|
|
self.__subject = allMethods()
|
|
|
for attr in dir(self.__subject):
|
|
|
if attr in REGISTERED_METHODS:
|
|
|
object.__setattr__(self, attr, getattr(self.__subject, attr))
|
|
|
|
|
|
|
|
|
|