commit 1e644fcbc93670fdc306141fd138903d90f7f295 Author: Самоукин Алексей Date: Mon Oct 11 15:44:19 2010 +0400 The initial project files. diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENCE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/README b/README new file mode 100644 index 0000000..6c9dcef --- /dev/null +++ b/README @@ -0,0 +1,15 @@ +AUTHOR: Calculate Ltd. + +INSTALL +------- + +calculate-server needs the following library version installed, in order to run: + python >= 2.5 + python-ldap >= 2.0.0 + pyxml >= 0.8 + calculate-lib >= 2.2.0.0 + +To install calculate-ldap, just execute the install script 'setup.py'. +Example: + + ./setup.py install diff --git a/i18n/cl_ldap_ru.mo b/i18n/cl_ldap_ru.mo new file mode 100644 index 0000000..8d12e9e Binary files /dev/null and b/i18n/cl_ldap_ru.mo differ diff --git a/ldif/base.ldif b/ldif/base.ldif new file mode 100644 index 0000000..105617a --- /dev/null +++ b/ldif/base.ldif @@ -0,0 +1,31 @@ +# Directory Server +dn: #-ld_base_dn-# +objectClass: dcObject +objectClass: organization +dc: #-ld_base_root-# +o: Calculate Directory Server + +# Services +dn: ou=Services,#-ld_base_dn-# +objectClass: top +objectClass: organizationalUnit +ou: Services + +# Admin +dn: #-ld_admin_dn-# +cn: #-ld_admin_login-# +sn: #-ld_admin_login-# +objectClass: person +objectClass: top +description: LDAP Administrator stuff +userPassword: #-ld_admin_hash-# + +# Bind +dn: #-ld_bind_dn-# +cn: #-ld_bind_login-# +sn: #-ld_bind_login-# +objectClass: person +objectClass: top +description: LDAP Proxy User +userPassword: #-ld_bind_hash-# + diff --git a/pym/__init__.py b/pym/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pym/cl_fill_ldap.py b/pym/cl_fill_ldap.py new file mode 100644 index 0000000..d472310 --- /dev/null +++ b/pym/cl_fill_ldap.py @@ -0,0 +1,81 @@ +#-*- 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 +from cl_datavars import glob_attr +from cl_utils import genpassword +from encrypt import encrypt + +class fillVars(glob_attr): + encryptObj = encrypt() + addDn = lambda x,*y: ",".join(y) + genDn = lambda x,*y: "=".join(y) + + def getHash(self, password, encrypt): + """Получить хеш пароля + + password - пароль + encrypt - алгоритм шифрования, например 'ssha' + """ + hashPwd = self.encryptObj.getHashPasswd(password, encrypt.lower()) + if hashPwd: + return hashPwd + else: + print "Error encrypt password, method getHash()" + exit(1) + + def get_ld_base_dn(self): + """базовый DN LDAP""" + return self.genDn("dc", self.Get('ld_base_root')) + + def get_ld_bind_dn(self): + """bind DN LDAP""" + return self.addDn(self.genDn("cn", self.Get('ld_bind_login')), + self.Get('ld_base_dn')) + + def get_ld_bind_hash(self): + """hash пароля для пользователя для чтения""" + return self.getHash(self.Get('ld_bind_pw'), self.Get('ld_encrypt')) + + def get_ld_temp_dn(self): + #DN временного пользователя root (для инициализации базы данных) + return self.addDn(self.genDn("cn", "ldaproot"), self.Get('ld_base_dn')) + + def get_ld_temp_pw(self): + """пароль временного пользователя root""" + return genpassword() + + def get_ld_temp_hash(self): + """hash пароля временного root""" + return self.getHash(self.Get('ld_temp_pw'), self.Get('ld_encrypt')) + + def get_ld_admin_dn(self): + """DN пользователя root""" + return self.addDn(self.genDn("cn", self.Get('ld_admin_login')), + self.Get('ld_base_dn')) + + def get_ld_admin_hash(self): + """hash пароля root""" + return self.getHash(self.Get('ld_admin_pw'), self.Get('ld_encrypt')) + + def get_ld_admin_pw(self): + """пароль root""" + return genpassword() + + def get_ld_services_dn(self): + """DN для всех сервисов""" + return self.addDn(self.genDn("ou", self.Get('ld_services')), + self.Get('ld_base_dn')) diff --git a/pym/cl_ldap_api.py b/pym/cl_ldap_api.py new file mode 100644 index 0000000..1057d3e --- /dev/null +++ b/pym/cl_ldap_api.py @@ -0,0 +1,184 @@ +#-*- 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_lang import lang +lang().setLanguage(sys.modules[__name__]) + +from cl_abstract import abs_api + +class DataVarsLdap(DataVars): + """Хранение переменных""" + # Имя секции в calculate2.env + envSection = "ldap" + + def importLdap(self, **args): + '''Импорт переменных для calculate-ldap''' + # Импорт переменных + self.importData(self.envSection, ('cl_vars_ldap','cl_fill_ldap')) + +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 True + +class serviceAPI(color_print, shareVars, abs_api): + '''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 getServiceName(self): + '''Get name service''' + return self.nameService + + def isSetup(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 isStart(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): + '''Запускает LDAP сервер''' + if execProg(self.cmdStart) is False: + self.printERROR(_("Can't execute '%s'") %self.cmdStart) + self.printNotOK(_("Starting LDAP") + " ...") + return False + else: + return True + + def restart(self): + '''Перезапускает LDAP сервер''' + if execProg(self.cmdReStart) is False: + self.printERROR(_("Can't execute '%s'") %self.cmdReStart) + self.printNotOK(_("Restarting LDAP")+ " ...") + return False + else: + return True + + def stop(self): + '''Останавливает LDAP сервер''' + if execProg(self.cmdStop) is False: + self.printERROR(_("Can't execute '%s'") %self.cmdStop) + self.printNotOK(_("Stopping LDAP")+ " ...") + return False + else: + return True + + def isRunlevel(self): + '''Находится ли LDAP в автозагрузке''' + daemons = self._getRunlevelDaemons() + if daemons is False: + return False + if self.nameDaemon in daemons: + return True + else: + return False + + def addRunlevel(self): + '''Add daemon to runlevel''' + if not self.isRunlevel(): + 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 delRunlevel(self): + '''Delete daemon from runlevel''' + if self.isRunlevel(): + 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 getRunPrioritet(self): + '''Get run daemon prioritet''' + return self.prioritet + + def delVarsFromEnv(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 diff --git a/pym/cl_ldap_service.py b/pym/cl_ldap_service.py new file mode 100644 index 0000000..3892d0a --- /dev/null +++ b/pym/cl_ldap_service.py @@ -0,0 +1,239 @@ +#-*- 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. + +__version__ = "2.2.0.0" +__app__ = "calculate-ldap" + +import os, sys + +from server.utils import dialogYesNo +from cl_print import color_print + +from cl_ldap_api import serviceAPI, shareVars +from cl_template import template +from server.services import services +from server.ldap import iniLdapParser, ldapFunction, shareldap +from server.utils import genSleep +from cl_utils import removeDir, _error, appendProgramToEnvFile,\ + removeProgramToEnvFile + +from cl_lang import lang +lang().setLanguage(sys.modules[__name__]) + +class ldapService(shareVars, 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' + APIObj = serviceAPI() + servObj = services() + + 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 + + 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) and os.listdir(pathDatabase): + removeDir(pathDatabase) + 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 installProg(self): + '''Install this program''' + apiDict = self.clVars.Get("cl_api") + apiDict.update({__app__:self.apiFile}) + self.clVars.Write("cl_api", force=True) + if not appendProgramToEnvFile(__app__, self.clVars): + self.printERROR(_("Can not save '%s'") %__app__ + " " +\ + _("to %s") %self.clVars.Get("cl_env_path")[0]) + return False + self.printOK(_("Save install variables")) + return True + + def uninstallProg(self): + '''Uninstall this program''' + apiDict = self.clVars.Get("cl_api") + if __app__ in apiDict: + apiDict.pop(__app__) + self.clVars.Write("cl_api", force=True) + if not removeProgramToEnvFile(__app__, self.clVars): + self.printERROR(_("Can not remove '%s' to %s")%(__app__, + self.clVars.Get("cl_env_path")[0])) + return False + self.printOK(_("Delete install variables")) + 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.APIObj.isStart(): + # Запускаем LDAP сервер + if not self.APIObj.start(): + return False + #if not self.backupServer(): + #return False + if self.APIObj.isRunlevel(): + # Удаляем из автозапуска демона + if not self.APIObj.delRunlevel(): + return False + # Останавливаем все установленные сервисы + if not self.servObj.stopAllServices(): + return False + # Останавливаем LDAP + if self.APIObj.isStart(): + self.APIObj.stop() + # Удаляем из автозагрузки все установленные сервисы + if not self.servObj.delRunlevelAllServices(): + return False + # Удаляем из крона скрипт для чистки удаленых пользователей + # создаем объект репликации + #objRepl = servRepl() + #if not objRepl.cronReplicationOFF(): + #return False + # Удаляем из share файл .replrun + #if not self.servSambaObj.delReplFile(self.clVars): + #return False + # Удаляем переменные + if not self.servObj.delVarsFromAllServices(): + 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("cl_ldap_setup_action","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.APIObj.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.APIObj.restart(): + return False + # Записываем данные администратора сервера + ldapParser.setVar("admin", + {"DN":self.clVars.Get("ld_admin_dn"), + "PASS":self.clVars.Get("ld_admin_pw")}) + # Устанавливаем автозапуск демона + if not self.APIObj.addRunlevel(): + return False + # Записываем переменные для пользователя + #clientVars = ["ur_organization", "ur_signature"] + #if not self.saveVarsClient(clientVars): + #return False + self.clVars.Write("sr_ldap_set","on",force=True) + self.printOK(_("LDAP service configured") + " ...") + return True diff --git a/pym/cl_ldap_setup_cmd.py b/pym/cl_ldap_setup_cmd.py new file mode 100644 index 0000000..14976e1 --- /dev/null +++ b/pym/cl_ldap_setup_cmd.py @@ -0,0 +1,108 @@ +#-*- coding: utf-8 -*- + +# Copyright 2010 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. +from cl_ldap_service import ldapService, __app__, __version__ +from cl_opt import opt +import sys +from cl_share_cmd import share_cmd + +# Перевод сообщений для программы +from cl_lang import lang +lang().setLanguage(sys.modules[__name__]) + +# Использование программы +USAGE = _("%prog [options]") + +# Коментарии к использованию программы +COMMENT_EXAMPLES = _("Create LDAP tree") + +# Пример использования программы +EXAMPLES = _("%prog") + +# Описание программы (что делает программа) +DESCRIPTION = _("Creating LDAP tree") + +# Опции командной строки +CMD_OPTIONS = [{'shortOption':"f", + 'longOption':"force", + 'help':_("forced setup service ldap")}, + {'longOption':"install", + 'help':_("configure the system to install this package")}, + {'longOption':"uninstall", + 'help':_("configure the system to uninstall this package")}] + +class ldap_setup_cmd(share_cmd): + def __init__(self): + # Объект опций командной строки + self.optobj = opt(package=__app__, + version=__version__, + usage=USAGE, + examples=EXAMPLES, + comment_examples=COMMENT_EXAMPLES, + description=DESCRIPTION, + option_list=CMD_OPTIONS +\ + opt.variable_control+opt.color_control, + check_values=self.checkOpts) + # Создаем объект логики + self.logicObj = ldapService() + # Создаем переменные + self.logicObj.createClVars() + # Названия несовместимых опций + self.optionsNamesIncompatible = ["install", "uninstall", "f"] + + def getIncompatibleOptions(self, optObj): + """Получаем несовместимые опции""" + retList = [] + for nameOpt in self.optionsNamesIncompatible: + retList.append(getattr(optObj, nameOpt)) + return retList + + def _getNamesAllSetOptions(self): + """Выдает словарь измененных опций""" + setOptDict = self.optobj.values.__dict__.items() + defaultOptDict = self.optobj.get_default_values().__dict__.items() + return dict(set(setOptDict) - set(defaultOptDict)).keys() + + def getStringIncompatibleOptions(self): + """Форматированная строка несовместимых опций разделенных ','""" + listOpt = list(set(self.optionsNamesIncompatible) &\ + set(self._getNamesAllSetOptions())) + return ", ".join(map(lambda x: len(x) == 1 and "'-%s'"%x or "'--%s'"%x,\ + listOpt)) + + def checkOpts(self, optObj, args): + """Check command line opt and arg""" + if len(filter(lambda x: x, self.getIncompatibleOptions(optObj)))>1: + errMsg = _("incompatible options")+":"+" %s"\ + %self.getStringIncompatibleOptions() + self.optobj.error(errMsg) + return False + if args: + errMsg = _("incorrect argument") + ":" + " %s" %" ".join(args) + self.optobj.error(errMsg) + return False + return optObj, args + + def setup(self, force=False): + """Setup program""" + return self.logicObj.setup(force=force) + + def install(self): + """Инсталяция программы""" + return self.logicObj.installProg() + + def uninstall(self): + """Удаление программы""" + return self.logicObj.uninstallProg() \ No newline at end of file diff --git a/pym/cl_share_cmd.py b/pym/cl_share_cmd.py new file mode 100644 index 0000000..df82189 --- /dev/null +++ b/pym/cl_share_cmd.py @@ -0,0 +1,78 @@ +#-*- coding: utf-8 -*- + +# Copyright 2010 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 sys + +from cl_print import color_print +from cl_utils import _error + +# Перевод сообщений для программы +from cl_lang import lang +lang().setLanguage(sys.modules[__name__]) + +class share_cmd(color_print, _error): + """Класс общих методов обработки опций командной строки""" + + def printVars(self, optObj): + """Печать переменных""" + if optObj.v: + varsFilter = None + varsNames = [] + format = "default" + # Фильтрование переменных + if optObj.filter: + optCmd = optObj.filter + if ',' in optCmd: + varsNames = optCmd.split(",") + elif '*' in optCmd: + varsFilter = optCmd.replace("*", ".*") + else: + varsNames.append(optCmd) + if optObj.xml: + format = "xml" + self.logicObj.printVars(varsFilter, varsNames, outFormat=format) + + def setVars(self, optObj): + """Установка переменных""" + if optObj.set: + for vals in optObj.set: + for val in vals.split(','): + k,o,v = val.partition('=') + if self.logicObj.clVars.exists(k): + if not self.logicObj.clVars.SetWriteVar(k,v): + return False + else: + self.printERROR(_('variable %s not found')%k) + return False + return True + + def writeVars(self, optObj): + """Запись переменных""" + if optObj.set: + if not self.logicObj.clVars.WriteVars(): + errMsg = self.getError() + if errMsg: + self.printERROR(errMsg.strip()) + self.printERROR(_('Can not write template variables')) + return False + return True + + def setPrintNoColor(self, optObj): + """Установка печати сообщений без цвета""" + if optObj.color and optObj.color=="never": + color_print.colorPrint = lambda *arg : sys.stdout.write(arg[-1]) or\ + sys.stdout.flush() + diff --git a/pym/cl_vars_ldap.py b/pym/cl_vars_ldap.py new file mode 100644 index 0000000..7bcb482 --- /dev/null +++ b/pym/cl_vars_ldap.py @@ -0,0 +1,77 @@ +#-*- 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. + + +class Data: + #базовый суффикс LDAP + ld_base_dn = {} + + #bind суффикс LDAP + ld_bind_dn = {} + + #пользователь только для чтения + ld_bind_login = {'value':'proxyuser'} + + #hash пароля для пользователя для чтения + ld_bind_hash = {} + + #пароль для пользователя для чтения + ld_bind_pw = {'value':'calculate'} + + #алгоритм шифрования паролей + ld_encrypt = {'value':'ssha'} + + #имя для базового суффикса LDAP + ld_base_root = {'value':'calculate'} + + #временный пользователь root для инициализации базы данных + ld_temp_dn = {} + + #hash пароля временного root + ld_temp_hash = {} + + #пароль временного пользователя root + ld_temp_pw = {} + + #DN пользователя root + ld_admin_dn = {} + + #имя пользователя root для LDAP + ld_admin_login = {'value':'ldapadmin'} + + #hash пароля root + ld_admin_hash = {} + + #пароль root + ld_admin_pw = {} + + #Имя для всех сервисов + ld_services= {'value' : 'Services'} + + #DN всех сервисов + ld_services_dn = {} + + #Настроен или нет сервис LDAP + sr_ldap_set = {'mode':"w",'value':'off'} + + # имя программы + cl_name = {'value':'calculate-ldap'} + + # версия программы + cl_ver = {'value':'2.2.0.0'} + + # действие программа устанавливает сервис + cl_ldap_setup_action = {'value':'down'} diff --git a/scripts/cl-ldap-setup b/scripts/cl-ldap-setup new file mode 100644 index 0000000..5343aa3 --- /dev/null +++ b/scripts/cl-ldap-setup @@ -0,0 +1,65 @@ +#!/usr/bin/python +#-*- coding: utf-8 -*- + +# Copyright 2010 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 sys +import os +sys.path.insert(0,os.path.abspath('/usr/lib/calculate-2.2/calculate-lib/pym')) +sys.path.insert(0,\ + os.path.abspath('/usr/lib/calculate-2.2/calculate-ldap/pym')) + +from cl_ldap_setup_cmd import ldap_setup_cmd + +from cl_lang import lang +tr = lang() +tr.setGlobalDomain('cl_ldap') +tr.setLanguage(sys.modules[__name__]) + +if __name__ == "__main__": + obj = ldap_setup_cmd() + ret = obj.optobj.parse_args() + if ret is False: + sys.exit(1) + opts, args = ret + # Установка цвета при печати сообщений + obj.setPrintNoColor(opts) + # Установка переменных + if not obj.setVars(opts): + sys.exit(1) + # Печать переменных + obj.printVars(opts) + # Если нет печати переменных выполняем логику программы + if not opts.v and not opts.filter and not opts.xml: + if not filter(lambda x: x[1], obj.optobj.values.__dict__.items()): + # Setup + if not obj.setup(): + sys.exit(1) + elif opts.f: + # Force setup + if not obj.setup(force=True): + sys.exit(1) + elif opts.install: + # Install + if not obj.install(): + sys.exit(1) + elif opts.uninstall: + # Uninstall + if not obj.uninstall(): + sys.exit(1) + # Запись переменных + if not obj.writeVars(opts): + sys.exit(1) + sys.exit(0) diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..b36081a --- /dev/null +++ b/setup.cfg @@ -0,0 +1,5 @@ +[install] +install-scripts=/usr/bin +install-purelib=/usr/lib/calculate-2.2 +install-platlib=/usr/lib/calculate-2.2 +install-data=/usr/lib/calculate-2.2/calculate-ldap \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..7b3ed0f --- /dev/null +++ b/setup.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# setup.py --- Setup script for calculate-client + +#Copyright 2010 Calculate Pack, 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 +import stat +from distutils.core import setup, Extension + + +__version__ = "2.2.0.0" +__app__ = "calculate-ldap" + + +data_files = [] + +var_data_files = [] + +data_dirs_template = ['templates'] +data_dirs_ldif = ['ldif'] +data_dirs_share = ['i18n'] +share_calculate_dir = "/usr/share/calculate" +template_calculate_dir = os.path.join(share_calculate_dir, "templates") +template_replace_dirname = "ldap" + +def __scanDir(scanDir, prefix, replace_dirname, dirData, flagDir=False): + """Scan directory""" + files = [] + dirs = [] + if flagDir or stat.S_ISDIR(os.stat(scanDir)[stat.ST_MODE]): + for fileOrDir in os.listdir(scanDir): + absPath = os.path.join(scanDir,fileOrDir) + statInfo = os.stat(absPath)[stat.ST_MODE] + if stat.S_ISREG(statInfo): + files.append(absPath) + elif stat.S_ISDIR(statInfo): + dirs.append(absPath) + if replace_dirname: + listDirs = list(scanDir.partition("/"))[1:] + listDirs.insert(0,replace_dirname) + scanDir = "".join(listDirs) + if prefix: + scanDir = os.path.join(prefix,scanDir) + dirData.append((scanDir, files)) + for sDir in dirs: + __scanDir(sDir, prefix, replace_dirname, dirData, True) + return dirData + +def create_data_files(data_dirs, prefix="", replace_dirname=""): + """Create data_files""" + data_files = [] + for data_dir in data_dirs: + data = [] + data_files += __scanDir(data_dir, prefix, replace_dirname, data) + return data_files + +data_files += create_data_files (data_dirs_template, template_calculate_dir, + template_replace_dirname) +data_files += create_data_files (data_dirs_share, share_calculate_dir) +data_files += create_data_files (data_dirs_ldif) + + +setup( + name = __app__, + version = __version__, + description = "The program for configuring LDAP server", + author = "Mir Calculate Ltd.", + author_email = "support@calculate.ru", + url = "http://calculate-linux.org", + license = "http://www.apache.org/licenses/LICENSE-2.0", + package_dir = {'calculate-ldap': "."}, + packages = ['calculate-ldap.pym'], + data_files = data_files, + scripts=["./scripts/cl-ldap-setup"] +) + diff --git a/templates/.calculate_directory b/templates/.calculate_directory new file mode 100644 index 0000000..6e78990 --- /dev/null +++ b/templates/.calculate_directory @@ -0,0 +1 @@ +# Calculate append=skip cl_name==calculate-ldap diff --git a/templates/setup/.calculate_directory b/templates/setup/.calculate_directory new file mode 100644 index 0000000..d57f195 --- /dev/null +++ b/templates/setup/.calculate_directory @@ -0,0 +1 @@ +# Calculate append=skip cl_ldap_setup_action==up diff --git a/templates/setup/openldap/.calculate_directory b/templates/setup/openldap/.calculate_directory new file mode 100644 index 0000000..0e18bc3 --- /dev/null +++ b/templates/setup/openldap/.calculate_directory @@ -0,0 +1,2 @@ +# Calculate belong()!=&&pkg(net-nds/openldap)!= path=/etc name=openldap + diff --git a/templates/setup/openldap/step-1/.calculate_directory b/templates/setup/openldap/step-1/.calculate_directory new file mode 100644 index 0000000..06514e4 --- /dev/null +++ b/templates/setup/openldap/step-1/.calculate_directory @@ -0,0 +1,2 @@ +# Calculate append=skip cl_pass_step==1 + diff --git a/templates/setup/openldap/step-1/slapd.conf b/templates/setup/openldap/step-1/slapd.conf new file mode 100644 index 0000000..97810b2 --- /dev/null +++ b/templates/setup/openldap/step-1/slapd.conf @@ -0,0 +1,60 @@ +# Calculate format=ldap chmod=0640 chown=root:ldap append=replace +include /etc/openldap/schema/core.schema +include /etc/openldap/schema/cosine.schema +include /etc/openldap/schema/nis.schema +include /etc/openldap/schema/inetorgperson.schema +include /etc/openldap/schema/misc.schema +#?pkg(net-nds/openldap)<2.4#schemacheck on#pkg# + +pidfile /var/run/openldap/slapd.pid +argsfile /var/run/openldap/slapd.arg + +# Уровень отладочных сообщений +loglevel 0 +allow bind_v2 +modulepath /usr/lib/openldap/openldap + +# Доступ к аттрибуту userPassword +access to attrs=userPassword + by self write + by dn="#-ld_admin_dn-#" write + by * auth + +# Доступ к администратору сервера LDAP +access to dn.base="#-ld_admin_dn-#" + by dn="#-ld_admin_dn-#" write + by * none + +# Закрываем доступ к веткам +access to dn.regex=".*,#-ld_services_dn-#" + by dn="#-ld_admin_dn-#" write + by * none + +# Доступ ко всем аттрибутам +access to * + by dn="#-ld_admin_dn-#" write + by self write + by * read + +# Доступ по умолчанию только для чтения +#?pkg(net-nds/openldap)<2.4#defaultaccess none#pkg# + +# Тип базы данных +#?pkg(net-nds/openldap)<2.4#database ldbm#pkg# +#?pkg(net-nds/openldap)>2.4#database bdb#pkg# +suffix "#-ld_base_dn-#" +rootdn "#-ld_temp_dn-#" +rootpw #-ld_temp_hash-# +checkpoint 1024 5 +cachesize 10000 +# Размер ответа на запрос +sizelimit unlimited +directory /var/lib/openldap-data + +index objectClass eq +index cn pres,sub,eq +index sn pres,sub,eq +index uid pres,sub,eq +index uidNumber eq +index gidNumber eq +index default sub \ No newline at end of file diff --git a/templates/setup/openldap/step-2/.calculate_directory b/templates/setup/openldap/step-2/.calculate_directory new file mode 100644 index 0000000..2605632 --- /dev/null +++ b/templates/setup/openldap/step-2/.calculate_directory @@ -0,0 +1,2 @@ +# Calculate append=skip cl_pass_step==2 + diff --git a/templates/setup/openldap/step-2/slapd.conf b/templates/setup/openldap/step-2/slapd.conf new file mode 100644 index 0000000..8a1c25d --- /dev/null +++ b/templates/setup/openldap/step-2/slapd.conf @@ -0,0 +1,3 @@ +# Calculate format=ldap chmod=0640 chown=root:ldap append=join +!rootdn del +!rootpw del \ No newline at end of file